fixed subscription table
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import pathlib
|
||||
from typing import Sequence
|
||||
|
||||
|
||||
# vestigal things from IPython_genutils.
|
||||
def cast_unicode(s: str | bytes, encoding: str = "utf-8") -> str:
|
||||
if isinstance(s, bytes):
|
||||
return s.decode(encoding, "replace")
|
||||
return s
|
||||
|
||||
|
||||
def filefind(filename: str, path_dirs: Sequence[str] | None = None) -> str:
|
||||
"""Find a file by looking through a sequence of paths.
|
||||
|
||||
This iterates through a sequence of paths looking for a file and returns
|
||||
the full, absolute path of the first occurrence of the file. If no set of
|
||||
path dirs is given, the filename is tested as is, after running through
|
||||
:func:`expandvars` and :func:`expanduser`. Thus a simple call::
|
||||
|
||||
filefind('myfile.txt')
|
||||
|
||||
will find the file in the current working dir, but::
|
||||
|
||||
filefind('~/myfile.txt')
|
||||
|
||||
Will find the file in the users home directory. This function does not
|
||||
automatically try any paths, such as the cwd or the user's home directory.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
filename : str
|
||||
The filename to look for.
|
||||
path_dirs : str, None or sequence of str
|
||||
The sequence of paths to look for the file in. If None, the filename
|
||||
need to be absolute or be in the cwd. If a string, the string is
|
||||
put into a sequence and the searched. If a sequence, walk through
|
||||
each element and join with ``filename``, calling :func:`expandvars`
|
||||
and :func:`expanduser` before testing for existence.
|
||||
|
||||
Returns
|
||||
-------
|
||||
Raises :exc:`IOError` or returns absolute path to file.
|
||||
"""
|
||||
|
||||
# If paths are quoted, abspath gets confused, strip them...
|
||||
filename = filename.strip('"').strip("'")
|
||||
# If the input is an absolute path, just check it exists
|
||||
if os.path.isabs(filename) and os.path.isfile(filename):
|
||||
return filename
|
||||
|
||||
if path_dirs is None:
|
||||
path_dirs = ("",)
|
||||
elif isinstance(path_dirs, str):
|
||||
path_dirs = (path_dirs,)
|
||||
elif isinstance(path_dirs, pathlib.Path):
|
||||
path_dirs = (str(path_dirs),)
|
||||
|
||||
for path in path_dirs:
|
||||
if path == ".":
|
||||
path = os.getcwd()
|
||||
testname = expand_path(os.path.join(path, filename))
|
||||
if os.path.isfile(testname):
|
||||
return os.path.abspath(testname)
|
||||
|
||||
raise OSError(f"File {filename!r} does not exist in any of the search paths: {path_dirs!r}")
|
||||
|
||||
|
||||
def expand_path(s: str) -> str:
|
||||
"""Expand $VARS and ~names in a string, like a shell
|
||||
|
||||
:Examples:
|
||||
|
||||
In [2]: os.environ['FOO']='test'
|
||||
|
||||
In [3]: expand_path('variable FOO is $FOO')
|
||||
Out[3]: 'variable FOO is test'
|
||||
"""
|
||||
# This is a pretty subtle hack. When expand user is given a UNC path
|
||||
# on Windows (\\server\share$\%username%), os.path.expandvars, removes
|
||||
# the $ to get (\\server\share\%username%). I think it considered $
|
||||
# alone an empty var. But, we need the $ to remains there (it indicates
|
||||
# a hidden share).
|
||||
if os.name == "nt":
|
||||
s = s.replace("$\\", "IPYTHON_TEMP")
|
||||
s = os.path.expandvars(os.path.expanduser(s))
|
||||
if os.name == "nt":
|
||||
s = s.replace("IPYTHON_TEMP", "$\\")
|
||||
return s
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
29
.venv/lib/python3.12/site-packages/traitlets/utils/bunch.py
Normal file
29
.venv/lib/python3.12/site-packages/traitlets/utils/bunch.py
Normal file
@@ -0,0 +1,29 @@
|
||||
"""Yet another implementation of bunch
|
||||
|
||||
attribute-access of items on a dict.
|
||||
"""
|
||||
|
||||
# Copyright (c) Jupyter Development Team.
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
|
||||
class Bunch(dict): # type:ignore[type-arg]
|
||||
"""A dict with attribute-access"""
|
||||
|
||||
def __getattr__(self, key: str) -> Any:
|
||||
try:
|
||||
return self.__getitem__(key)
|
||||
except KeyError as e:
|
||||
raise AttributeError(key) from e
|
||||
|
||||
def __setattr__(self, key: str, value: Any) -> None:
|
||||
self.__setitem__(key, value)
|
||||
|
||||
def __dir__(self) -> list[str]:
|
||||
# py2-compat: can't use super because dict doesn't have __dir__
|
||||
names = dir({})
|
||||
names.extend(self.keys())
|
||||
return names
|
@@ -0,0 +1,86 @@
|
||||
"""Useful decorators for Traitlets users."""
|
||||
from __future__ import annotations
|
||||
|
||||
import copy
|
||||
from inspect import Parameter, Signature, signature
|
||||
from typing import Any, Type, TypeVar
|
||||
|
||||
from ..traitlets import HasTraits, Undefined
|
||||
|
||||
|
||||
def _get_default(value: Any) -> Any:
|
||||
"""Get default argument value, given the trait default value."""
|
||||
return Parameter.empty if value == Undefined else value
|
||||
|
||||
|
||||
T = TypeVar("T", bound=HasTraits)
|
||||
|
||||
|
||||
def signature_has_traits(cls: Type[T]) -> Type[T]:
|
||||
"""Return a decorated class with a constructor signature that contain Trait names as kwargs."""
|
||||
traits = [
|
||||
(name, _get_default(value.default_value))
|
||||
for name, value in cls.class_traits().items()
|
||||
if not name.startswith("_")
|
||||
]
|
||||
|
||||
# Taking the __init__ signature, as the cls signature is not initialized yet
|
||||
old_signature = signature(cls.__init__)
|
||||
old_parameter_names = list(old_signature.parameters)
|
||||
|
||||
old_positional_parameters = []
|
||||
old_var_positional_parameter = None # This won't be None if the old signature contains *args
|
||||
old_keyword_only_parameters = []
|
||||
old_var_keyword_parameter = None # This won't be None if the old signature contains **kwargs
|
||||
|
||||
for parameter_name in old_signature.parameters:
|
||||
# Copy the parameter
|
||||
parameter = copy.copy(old_signature.parameters[parameter_name])
|
||||
|
||||
if (
|
||||
parameter.kind is Parameter.POSITIONAL_ONLY
|
||||
or parameter.kind is Parameter.POSITIONAL_OR_KEYWORD
|
||||
):
|
||||
old_positional_parameters.append(parameter)
|
||||
|
||||
elif parameter.kind is Parameter.VAR_POSITIONAL:
|
||||
old_var_positional_parameter = parameter
|
||||
|
||||
elif parameter.kind is Parameter.KEYWORD_ONLY:
|
||||
old_keyword_only_parameters.append(parameter)
|
||||
|
||||
elif parameter.kind is Parameter.VAR_KEYWORD:
|
||||
old_var_keyword_parameter = parameter
|
||||
|
||||
# Unfortunately, if the old signature does not contain **kwargs, we can't do anything,
|
||||
# because it can't accept traits as keyword arguments
|
||||
if old_var_keyword_parameter is None:
|
||||
raise RuntimeError(
|
||||
f"The {cls} constructor does not take **kwargs, which means that the signature can not be expanded with trait names"
|
||||
)
|
||||
|
||||
new_parameters = []
|
||||
|
||||
# Append the old positional parameters (except `self` which is the first parameter)
|
||||
new_parameters += old_positional_parameters[1:]
|
||||
|
||||
# Append *args if the old signature had it
|
||||
if old_var_positional_parameter is not None:
|
||||
new_parameters.append(old_var_positional_parameter)
|
||||
|
||||
# Append the old keyword only parameters
|
||||
new_parameters += old_keyword_only_parameters
|
||||
|
||||
# Append trait names as keyword only parameters in the signature
|
||||
new_parameters += [
|
||||
Parameter(name, kind=Parameter.KEYWORD_ONLY, default=default)
|
||||
for name, default in traits
|
||||
if name not in old_parameter_names
|
||||
]
|
||||
|
||||
# Append **kwargs
|
||||
new_parameters.append(old_var_keyword_parameter)
|
||||
|
||||
cls.__signature__ = Signature(new_parameters) # type:ignore[attr-defined]
|
||||
|
||||
return cls
|
@@ -0,0 +1,182 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import inspect
|
||||
import re
|
||||
import types
|
||||
from typing import Any
|
||||
|
||||
|
||||
def describe(
|
||||
article: str | None,
|
||||
value: Any,
|
||||
name: str | None = None,
|
||||
verbose: bool = False,
|
||||
capital: bool = False,
|
||||
) -> str:
|
||||
"""Return string that describes a value
|
||||
|
||||
Parameters
|
||||
----------
|
||||
article : str or None
|
||||
A definite or indefinite article. If the article is
|
||||
indefinite (i.e. "a" or "an") the appropriate one
|
||||
will be inferred. Thus, the arguments of ``describe``
|
||||
can themselves represent what the resulting string
|
||||
will actually look like. If None, then no article
|
||||
will be prepended to the result. For non-articled
|
||||
description, values that are instances are treated
|
||||
definitely, while classes are handled indefinitely.
|
||||
value : any
|
||||
The value which will be named.
|
||||
name : str or None (default: None)
|
||||
Only applies when ``article`` is "the" - this
|
||||
``name`` is a definite reference to the value.
|
||||
By default one will be inferred from the value's
|
||||
type and repr methods.
|
||||
verbose : bool (default: False)
|
||||
Whether the name should be concise or verbose. When
|
||||
possible, verbose names include the module, and/or
|
||||
class name where an object was defined.
|
||||
capital : bool (default: False)
|
||||
Whether the first letter of the article should
|
||||
be capitalized or not. By default it is not.
|
||||
|
||||
Examples
|
||||
--------
|
||||
Indefinite description:
|
||||
|
||||
>>> describe("a", object())
|
||||
'an object'
|
||||
>>> describe("a", object)
|
||||
'an object'
|
||||
>>> describe("a", type(object))
|
||||
'a type'
|
||||
|
||||
Definite description:
|
||||
|
||||
>>> describe("the", object())
|
||||
"the object at '...'"
|
||||
>>> describe("the", object)
|
||||
'the object object'
|
||||
>>> describe("the", type(object))
|
||||
'the type type'
|
||||
|
||||
Definitely named description:
|
||||
|
||||
>>> describe("the", object(), "I made")
|
||||
'the object I made'
|
||||
>>> describe("the", object, "I will use")
|
||||
'the object I will use'
|
||||
"""
|
||||
if isinstance(article, str):
|
||||
article = article.lower()
|
||||
|
||||
if not inspect.isclass(value):
|
||||
typename = type(value).__name__
|
||||
else:
|
||||
typename = value.__name__
|
||||
if verbose:
|
||||
typename = _prefix(value) + typename
|
||||
|
||||
if article == "the" or (article is None and not inspect.isclass(value)):
|
||||
if name is not None:
|
||||
result = f"{typename} {name}"
|
||||
if article is not None:
|
||||
return add_article(result, True, capital)
|
||||
else:
|
||||
return result
|
||||
else:
|
||||
tick_wrap = False
|
||||
if inspect.isclass(value):
|
||||
name = value.__name__
|
||||
elif isinstance(value, types.FunctionType):
|
||||
name = value.__name__
|
||||
tick_wrap = True
|
||||
elif isinstance(value, types.MethodType):
|
||||
name = value.__func__.__name__
|
||||
tick_wrap = True
|
||||
elif type(value).__repr__ in (
|
||||
object.__repr__,
|
||||
type.__repr__,
|
||||
): # type:ignore[comparison-overlap]
|
||||
name = "at '%s'" % hex(id(value))
|
||||
verbose = False
|
||||
else:
|
||||
name = repr(value)
|
||||
verbose = False
|
||||
if verbose:
|
||||
name = _prefix(value) + name
|
||||
if tick_wrap:
|
||||
name = name.join("''")
|
||||
return describe(article, value, name=name, verbose=verbose, capital=capital)
|
||||
elif article in ("a", "an") or article is None:
|
||||
if article is None:
|
||||
return typename
|
||||
return add_article(typename, False, capital)
|
||||
else:
|
||||
raise ValueError(
|
||||
"The 'article' argument should be 'the', 'a', 'an', or None not %r" % article
|
||||
)
|
||||
|
||||
|
||||
def _prefix(value: Any) -> str:
|
||||
if isinstance(value, types.MethodType):
|
||||
name = describe(None, value.__self__, verbose=True) + "."
|
||||
else:
|
||||
module = inspect.getmodule(value)
|
||||
if module is not None and module.__name__ != "builtins":
|
||||
name = module.__name__ + "."
|
||||
else:
|
||||
name = ""
|
||||
return name
|
||||
|
||||
|
||||
def class_of(value: Any) -> Any:
|
||||
"""Returns a string of the value's type with an indefinite article.
|
||||
|
||||
For example 'an Image' or 'a PlotValue'.
|
||||
"""
|
||||
if inspect.isclass(value):
|
||||
return add_article(value.__name__)
|
||||
else:
|
||||
return class_of(type(value))
|
||||
|
||||
|
||||
def add_article(name: str, definite: bool = False, capital: bool = False) -> str:
|
||||
"""Returns the string with a prepended article.
|
||||
|
||||
The input does not need to begin with a character.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name : str
|
||||
Name to which to prepend an article
|
||||
definite : bool (default: False)
|
||||
Whether the article is definite or not.
|
||||
Indefinite articles being 'a' and 'an',
|
||||
while 'the' is definite.
|
||||
capital : bool (default: False)
|
||||
Whether the added article should have
|
||||
its first letter capitalized or not.
|
||||
"""
|
||||
if definite:
|
||||
result = "the " + name
|
||||
else:
|
||||
first_letters = re.compile(r"[\W_]+").sub("", name)
|
||||
if first_letters[:1].lower() in "aeiou":
|
||||
result = "an " + name
|
||||
else:
|
||||
result = "a " + name
|
||||
if capital:
|
||||
return result[0].upper() + result[1:]
|
||||
else:
|
||||
return result
|
||||
|
||||
|
||||
def repr_type(obj: Any) -> str:
|
||||
"""Return a string representation of a value and its type for readable
|
||||
|
||||
error messages.
|
||||
"""
|
||||
the_type = type(obj)
|
||||
return f"{obj!r} {the_type!r}"
|
@@ -0,0 +1,51 @@
|
||||
"""
|
||||
getargspec excerpted from:
|
||||
|
||||
sphinx.util.inspect
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
Helpers for inspecting Python modules.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import inspect
|
||||
from functools import partial
|
||||
from typing import Any
|
||||
|
||||
# Unmodified from sphinx below this line
|
||||
|
||||
|
||||
def getargspec(func: Any) -> inspect.FullArgSpec:
|
||||
"""Like inspect.getargspec but supports functools.partial as well."""
|
||||
if inspect.ismethod(func):
|
||||
func = func.__func__
|
||||
if type(func) is partial:
|
||||
orig_func = func.func
|
||||
argspec = getargspec(orig_func)
|
||||
args = list(argspec[0])
|
||||
defaults = list(argspec[3] or ())
|
||||
kwoargs = list(argspec[4])
|
||||
kwodefs = dict(argspec[5] or {})
|
||||
if func.args:
|
||||
args = args[len(func.args) :]
|
||||
for arg in func.keywords or ():
|
||||
try:
|
||||
i = args.index(arg) - len(args)
|
||||
del args[i]
|
||||
try:
|
||||
del defaults[i]
|
||||
except IndexError:
|
||||
pass
|
||||
except ValueError: # must be a kwonly arg
|
||||
i = kwoargs.index(arg)
|
||||
del kwoargs[i]
|
||||
del kwodefs[arg]
|
||||
return inspect.FullArgSpec(
|
||||
args, argspec[1], argspec[2], tuple(defaults), kwoargs, kwodefs, argspec[6]
|
||||
)
|
||||
while hasattr(func, "__wrapped__"):
|
||||
func = func.__wrapped__
|
||||
if not inspect.isfunction(func):
|
||||
raise TypeError("%r is not a Python function" % func)
|
||||
return inspect.getfullargspec(func)
|
@@ -0,0 +1,41 @@
|
||||
"""
|
||||
A simple utility to import something by its string name.
|
||||
"""
|
||||
# Copyright (c) IPython Development Team.
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
|
||||
def import_item(name: str) -> Any:
|
||||
"""Import and return ``bar`` given the string ``foo.bar``.
|
||||
|
||||
Calling ``bar = import_item("foo.bar")`` is the functional equivalent of
|
||||
executing the code ``from foo import bar``.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name : string
|
||||
The fully qualified name of the module/package being imported.
|
||||
|
||||
Returns
|
||||
-------
|
||||
mod : module object
|
||||
The module that was imported.
|
||||
"""
|
||||
if not isinstance(name, str):
|
||||
raise TypeError("import_item accepts strings, not '%s'." % type(name))
|
||||
parts = name.rsplit(".", 1)
|
||||
if len(parts) == 2:
|
||||
# called with 'foo.bar....'
|
||||
package, obj = parts
|
||||
module = __import__(package, fromlist=[obj])
|
||||
try:
|
||||
pak = getattr(module, obj)
|
||||
except AttributeError as e:
|
||||
raise ImportError("No module named %s" % obj) from e
|
||||
return pak
|
||||
else:
|
||||
# called with un-dotted string
|
||||
return __import__(parts[0])
|
@@ -0,0 +1,41 @@
|
||||
# Copyright (c) IPython Development Team.
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any, Dict
|
||||
|
||||
|
||||
def nested_update(this: Dict[Any, Any], that: Dict[Any, Any]) -> Dict[Any, Any]:
|
||||
"""Merge two nested dictionaries.
|
||||
|
||||
Effectively a recursive ``dict.update``.
|
||||
|
||||
Examples
|
||||
--------
|
||||
Merge two flat dictionaries:
|
||||
>>> nested_update(
|
||||
... {'a': 1, 'b': 2},
|
||||
... {'b': 3, 'c': 4}
|
||||
... )
|
||||
{'a': 1, 'b': 3, 'c': 4}
|
||||
|
||||
Merge two nested dictionaries:
|
||||
>>> nested_update(
|
||||
... {'x': {'a': 1, 'b': 2}, 'y': 5, 'z': 6},
|
||||
... {'x': {'b': 3, 'c': 4}, 'z': 7, '0': 8},
|
||||
... )
|
||||
{'x': {'a': 1, 'b': 3, 'c': 4}, 'y': 5, 'z': 7, '0': 8}
|
||||
|
||||
"""
|
||||
for key, value in this.items():
|
||||
if isinstance(value, dict):
|
||||
if key in that and isinstance(that[key], dict):
|
||||
nested_update(this[key], that[key])
|
||||
elif key in that:
|
||||
this[key] = that[key]
|
||||
|
||||
for key, value in that.items():
|
||||
if key not in this:
|
||||
this[key] = value
|
||||
|
||||
return this
|
@@ -0,0 +1,24 @@
|
||||
"""Sentinel class for constants with useful reprs"""
|
||||
|
||||
# Copyright (c) IPython Development Team.
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
from __future__ import annotations
|
||||
|
||||
import typing as t
|
||||
|
||||
|
||||
class Sentinel:
|
||||
def __init__(self, name: str, module: t.Any, docstring: str | None = None) -> None:
|
||||
self.name = name
|
||||
self.module = module
|
||||
if docstring:
|
||||
self.__doc__ = docstring
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return str(self.module) + "." + self.name
|
||||
|
||||
def __copy__(self) -> Sentinel:
|
||||
return self
|
||||
|
||||
def __deepcopy__(self, memo: t.Any) -> Sentinel:
|
||||
return self
|
40
.venv/lib/python3.12/site-packages/traitlets/utils/text.py
Normal file
40
.venv/lib/python3.12/site-packages/traitlets/utils/text.py
Normal file
@@ -0,0 +1,40 @@
|
||||
"""
|
||||
Utilities imported from ipython_genutils
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
import textwrap
|
||||
from textwrap import dedent
|
||||
from textwrap import indent as _indent
|
||||
from typing import List
|
||||
|
||||
|
||||
def indent(val: str) -> str:
|
||||
return _indent(val, " ")
|
||||
|
||||
|
||||
def wrap_paragraphs(text: str, ncols: int = 80) -> List[str]:
|
||||
"""Wrap multiple paragraphs to fit a specified width.
|
||||
|
||||
This is equivalent to textwrap.wrap, but with support for multiple
|
||||
paragraphs, as separated by empty lines.
|
||||
|
||||
Returns
|
||||
-------
|
||||
|
||||
list of complete paragraphs, wrapped to fill `ncols` columns.
|
||||
"""
|
||||
paragraph_re = re.compile(r"\n(\s*\n)+", re.MULTILINE)
|
||||
text = dedent(text).strip()
|
||||
paragraphs = paragraph_re.split(text)[::2] # every other entry is space
|
||||
out_ps = []
|
||||
indent_re = re.compile(r"\n\s+", re.MULTILINE)
|
||||
for p in paragraphs:
|
||||
# presume indentation that survives dedent is meaningful formatting,
|
||||
# so don't fill unless text is flush.
|
||||
if indent_re.search(p) is None:
|
||||
# wrap paragraph
|
||||
p = textwrap.fill(p, ncols)
|
||||
out_ps.append(p)
|
||||
return out_ps
|
@@ -0,0 +1,64 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import inspect
|
||||
import os
|
||||
import typing as t
|
||||
import warnings
|
||||
|
||||
|
||||
def warn(msg: str, category: t.Any, *, stacklevel: int, source: t.Any = None) -> None:
|
||||
"""Like warnings.warn(), but category and stacklevel are required.
|
||||
|
||||
You pretty much never want the default stacklevel of 1, so this helps
|
||||
encourage setting it explicitly."""
|
||||
warnings.warn(msg, category=category, stacklevel=stacklevel, source=source)
|
||||
|
||||
|
||||
def deprecated_method(method: t.Any, cls: t.Any, method_name: str, msg: str) -> None:
|
||||
"""Show deprecation warning about a magic method definition.
|
||||
|
||||
Uses warn_explicit to bind warning to method definition instead of triggering code,
|
||||
which isn't relevant.
|
||||
"""
|
||||
warn_msg = f"{cls.__name__}.{method_name} is deprecated in traitlets 4.1: {msg}"
|
||||
|
||||
for parent in inspect.getmro(cls):
|
||||
if method_name in parent.__dict__:
|
||||
cls = parent
|
||||
break
|
||||
# limit deprecation messages to once per package
|
||||
package_name = cls.__module__.split(".", 1)[0]
|
||||
key = (package_name, msg)
|
||||
if not should_warn(key):
|
||||
return
|
||||
try:
|
||||
fname = inspect.getsourcefile(method) or "<unknown>"
|
||||
lineno = inspect.getsourcelines(method)[1] or 0
|
||||
except (OSError, TypeError) as e:
|
||||
# Failed to inspect for some reason
|
||||
warn(
|
||||
warn_msg + ("\n(inspection failed) %s" % e),
|
||||
DeprecationWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
else:
|
||||
warnings.warn_explicit(warn_msg, DeprecationWarning, fname, lineno)
|
||||
|
||||
|
||||
_deprecations_shown = set()
|
||||
|
||||
|
||||
def should_warn(key: t.Any) -> bool:
|
||||
"""Add our own checks for too many deprecation warnings.
|
||||
|
||||
Limit to once per package.
|
||||
"""
|
||||
env_flag = os.environ.get("TRAITLETS_ALL_DEPRECATIONS")
|
||||
if env_flag and env_flag != "0":
|
||||
return True
|
||||
|
||||
if key not in _deprecations_shown:
|
||||
_deprecations_shown.add(key)
|
||||
return True
|
||||
else:
|
||||
return False
|
Reference in New Issue
Block a user