about summary refs log tree commit diff
path: root/.venv/lib/python3.12/site-packages/networkx/utils/configs.py
diff options
context:
space:
mode:
authorS. Solomon Darnell2025-03-28 21:52:21 -0500
committerS. Solomon Darnell2025-03-28 21:52:21 -0500
commit4a52a71956a8d46fcb7294ac71734504bb09bcc2 (patch)
treeee3dc5af3b6313e921cd920906356f5d4febc4ed /.venv/lib/python3.12/site-packages/networkx/utils/configs.py
parentcc961e04ba734dd72309fb548a2f97d67d578813 (diff)
downloadgn-ai-master.tar.gz
two version of R2R are here HEAD master
Diffstat (limited to '.venv/lib/python3.12/site-packages/networkx/utils/configs.py')
-rw-r--r--.venv/lib/python3.12/site-packages/networkx/utils/configs.py387
1 files changed, 387 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/networkx/utils/configs.py b/.venv/lib/python3.12/site-packages/networkx/utils/configs.py
new file mode 100644
index 00000000..24c80f88
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/networkx/utils/configs.py
@@ -0,0 +1,387 @@
+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["<TAB>
+
+    # 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