summaryrefslogtreecommitdiffstats
path: root/contrib/python/traitlets/py3
diff options
context:
space:
mode:
authorrobot-contrib <[email protected]>2023-10-19 17:11:31 +0300
committerrobot-contrib <[email protected]>2023-10-19 18:26:04 +0300
commitb9fe236a503791a3a7b37d4ef5f466225218996c (patch)
treec2f80019399b393ddf0450d0f91fc36478af8bea /contrib/python/traitlets/py3
parent44dd27d0a2ae37c80d97a95581951d1d272bd7df (diff)
Update contrib/python/traitlets/py3 to 5.11.2
Diffstat (limited to 'contrib/python/traitlets/py3')
-rw-r--r--contrib/python/traitlets/py3/.dist-info/METADATA2
-rw-r--r--contrib/python/traitlets/py3/tests/__init__.py0
-rw-r--r--contrib/python/traitlets/py3/tests/_warnings.py (renamed from contrib/python/traitlets/py3/traitlets/tests/_warnings.py)0
-rw-r--r--contrib/python/traitlets/py3/tests/config/__init__.py0
-rw-r--r--contrib/python/traitlets/py3/tests/config/test_application.py (renamed from contrib/python/traitlets/py3/traitlets/config/tests/test_application.py)4
-rw-r--r--contrib/python/traitlets/py3/tests/config/test_argcomplete.py219
-rw-r--r--contrib/python/traitlets/py3/tests/config/test_configurable.py (renamed from contrib/python/traitlets/py3/traitlets/config/tests/test_configurable.py)3
-rw-r--r--contrib/python/traitlets/py3/tests/config/test_loader.py (renamed from contrib/python/traitlets/py3/traitlets/config/tests/test_loader.py)0
-rw-r--r--contrib/python/traitlets/py3/tests/test_traitlets.py (renamed from contrib/python/traitlets/py3/traitlets/tests/test_traitlets.py)2
-rw-r--r--contrib/python/traitlets/py3/tests/test_traitlets_docstring.py84
-rw-r--r--contrib/python/traitlets/py3/tests/test_traitlets_enum.py (renamed from contrib/python/traitlets/py3/traitlets/tests/test_traitlets_enum.py)0
-rw-r--r--contrib/python/traitlets/py3/tests/test_typing.py395
-rw-r--r--contrib/python/traitlets/py3/tests/utils/__init__.py0
-rw-r--r--contrib/python/traitlets/py3/tests/utils/test_bunch.py (renamed from contrib/python/traitlets/py3/traitlets/utils/tests/test_bunch.py)0
-rw-r--r--contrib/python/traitlets/py3/tests/utils/test_decorators.py (renamed from contrib/python/traitlets/py3/traitlets/utils/tests/test_decorators.py)2
-rw-r--r--contrib/python/traitlets/py3/tests/utils/test_importstring.py (renamed from contrib/python/traitlets/py3/traitlets/utils/tests/test_importstring.py)0
-rw-r--r--contrib/python/traitlets/py3/tests/ya.make27
-rw-r--r--contrib/python/traitlets/py3/traitlets/__init__.py4
-rw-r--r--contrib/python/traitlets/py3/traitlets/_version.py2
-rw-r--r--contrib/python/traitlets/py3/traitlets/config/application.py223
-rw-r--r--contrib/python/traitlets/py3/traitlets/config/argcomplete_config.py6
-rw-r--r--contrib/python/traitlets/py3/traitlets/config/configurable.py79
-rw-r--r--contrib/python/traitlets/py3/traitlets/config/loader.py28
-rw-r--r--contrib/python/traitlets/py3/traitlets/config/manager.py15
-rw-r--r--contrib/python/traitlets/py3/traitlets/config/sphinxdoc.py1
-rw-r--r--contrib/python/traitlets/py3/traitlets/log.py5
-rw-r--r--contrib/python/traitlets/py3/traitlets/tests/utils.py17
-rw-r--r--contrib/python/traitlets/py3/traitlets/traitlets.py41
-rw-r--r--contrib/python/traitlets/py3/traitlets/utils/__init__.py9
-rw-r--r--contrib/python/traitlets/py3/traitlets/utils/bunch.py9
-rw-r--r--contrib/python/traitlets/py3/traitlets/utils/decorators.py4
-rw-r--r--contrib/python/traitlets/py3/traitlets/utils/descriptions.py19
-rw-r--r--contrib/python/traitlets/py3/traitlets/utils/getargspec.py4
-rw-r--r--contrib/python/traitlets/py3/traitlets/utils/nested_update.py3
-rw-r--r--contrib/python/traitlets/py3/traitlets/utils/text.py2
-rw-r--r--contrib/python/traitlets/py3/ya.make3
36 files changed, 986 insertions, 226 deletions
diff --git a/contrib/python/traitlets/py3/.dist-info/METADATA b/contrib/python/traitlets/py3/.dist-info/METADATA
index 5ef59abe28f..fb63430a4c1 100644
--- a/contrib/python/traitlets/py3/.dist-info/METADATA
+++ b/contrib/python/traitlets/py3/.dist-info/METADATA
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: traitlets
-Version: 5.10.1
+Version: 5.11.2
Summary: Traitlets Python configuration system
Project-URL: Homepage, https://github.com/ipython/traitlets
Author-email: IPython Development Team <[email protected]>
diff --git a/contrib/python/traitlets/py3/tests/__init__.py b/contrib/python/traitlets/py3/tests/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/contrib/python/traitlets/py3/tests/__init__.py
diff --git a/contrib/python/traitlets/py3/traitlets/tests/_warnings.py b/contrib/python/traitlets/py3/tests/_warnings.py
index e3c3a0ac6d6..e3c3a0ac6d6 100644
--- a/contrib/python/traitlets/py3/traitlets/tests/_warnings.py
+++ b/contrib/python/traitlets/py3/tests/_warnings.py
diff --git a/contrib/python/traitlets/py3/tests/config/__init__.py b/contrib/python/traitlets/py3/tests/config/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/contrib/python/traitlets/py3/tests/config/__init__.py
diff --git a/contrib/python/traitlets/py3/traitlets/config/tests/test_application.py b/contrib/python/traitlets/py3/tests/config/test_application.py
index 084ff6f0325..610cafc3cd5 100644
--- a/contrib/python/traitlets/py3/traitlets/config/tests/test_application.py
+++ b/contrib/python/traitlets/py3/tests/config/test_application.py
@@ -601,7 +601,7 @@ class TestApplication(TestCase):
with self.assertRaises(SyntaxError):
app.load_config_file(name, path=[td])
- def test_subcommands_instanciation(self):
+ def test_subcommands_instantiation(self):
"""Try all ways to specify how to create sub-apps."""
app = Root.instance()
app.parse_command_line(["sub1"])
@@ -695,7 +695,7 @@ def test_cli_multi_scalar(caplog):
class Root(Application):
subcommands = {
- "sub1": ("__tests__.config.tests.test_application.Sub1", "import string"),
+ "sub1": ("__tests__.config.test_application.Sub1", "import string"),
}
diff --git a/contrib/python/traitlets/py3/tests/config/test_argcomplete.py b/contrib/python/traitlets/py3/tests/config/test_argcomplete.py
new file mode 100644
index 00000000000..52ed6d2bb2c
--- /dev/null
+++ b/contrib/python/traitlets/py3/tests/config/test_argcomplete.py
@@ -0,0 +1,219 @@
+"""
+Tests for argcomplete handling by traitlets.config.application.Application
+"""
+
+# Copyright (c) IPython Development Team.
+# Distributed under the terms of the Modified BSD License.
+
+import io
+import os
+import typing as t
+
+import pytest
+
+argcomplete = pytest.importorskip("argcomplete")
+
+from traitlets import Unicode
+from traitlets.config.application import Application
+from traitlets.config.configurable import Configurable
+from traitlets.config.loader import KVArgParseConfigLoader
+
+
+class ArgcompleteApp(Application):
+ """Override loader to pass through kwargs for argcomplete testing"""
+
+ argcomplete_kwargs: t.Dict[str, t.Any]
+
+ def __init__(self, *args, **kwargs):
+ # For subcommands, inherit argcomplete_kwargs from parent app
+ parent = kwargs.get("parent")
+ super().__init__(*args, **kwargs)
+ if parent:
+ argcomplete_kwargs = getattr(parent, "argcomplete_kwargs", None)
+ if argcomplete_kwargs:
+ self.argcomplete_kwargs = argcomplete_kwargs
+
+ def _create_loader(self, argv, aliases, flags, classes):
+ loader = KVArgParseConfigLoader(
+ argv, aliases, flags, classes=classes, log=self.log, subcommands=self.subcommands
+ )
+ loader._argcomplete_kwargs = self.argcomplete_kwargs # type: ignore[attr-defined]
+ return loader
+
+
+class SubApp1(ArgcompleteApp):
+ pass
+
+
+class SubApp2(ArgcompleteApp):
+ @classmethod
+ def get_subapp_instance(cls, app: Application) -> Application:
+ app.clear_instance() # since Application is singleton, need to clear main app
+ return cls.instance(parent=app) # type: ignore[no-any-return]
+
+
+class MainApp(ArgcompleteApp):
+ subcommands = {
+ "subapp1": (SubApp1, "First subapp"),
+ "subapp2": (SubApp2.get_subapp_instance, "Second subapp"),
+ }
+
+
+class CustomError(Exception):
+ """Helper for exit hook for testing argcomplete"""
+
+ @classmethod
+ def exit(cls, code):
+ raise cls(str(code))
+
+
+class TestArgcomplete:
+ IFS = "\013"
+ COMP_WORDBREAKS = " \t\n\"'><=;|&(:"
+
+ @pytest.fixture
+ def argcomplete_on(self, mocker):
+ """Mostly borrowed from argcomplete's unit test fixtures
+
+ Set up environment variables to mimic those passed by argcomplete
+ """
+ _old_environ = os.environ
+ os.environ = os.environ.copy() # type: ignore[assignment]
+ os.environ["_ARGCOMPLETE"] = "1"
+ os.environ["_ARC_DEBUG"] = "yes"
+ os.environ["IFS"] = self.IFS
+ os.environ["_ARGCOMPLETE_COMP_WORDBREAKS"] = self.COMP_WORDBREAKS
+
+ # argcomplete==2.0.0 always calls fdopen(9, "w") to open a debug stream,
+ # however this could conflict with file descriptors used by pytest
+ # and lead to obscure errors. Since we are not looking at debug stream
+ # in these tests, just mock this fdopen call out.
+ mocker.patch("os.fdopen")
+ try:
+ yield
+ finally:
+ os.environ = _old_environ
+
+ def run_completer(
+ self,
+ app: ArgcompleteApp,
+ command: str,
+ point: t.Union[str, int, None] = None,
+ **kwargs: t.Any,
+ ) -> t.List[str]:
+ """Mostly borrowed from argcomplete's unit tests
+
+ Modified to take an application instead of an ArgumentParser
+
+ Command is the current command being completed and point is the index
+ into the command where the completion is triggered.
+ """
+ if point is None:
+ point = str(len(command))
+ # Flushing tempfile was leading to CI failures with Bad file descriptor, not sure why.
+ # Fortunately we can just write to a StringIO instead.
+ # print("Writing completions to temp file with mode=", write_mode)
+ # from tempfile import TemporaryFile
+ # with TemporaryFile(mode=write_mode) as t:
+ strio = io.StringIO()
+ os.environ["COMP_LINE"] = command
+ os.environ["COMP_POINT"] = str(point)
+
+ with pytest.raises(CustomError) as cm:
+ app.argcomplete_kwargs = dict(
+ output_stream=strio, exit_method=CustomError.exit, **kwargs
+ )
+ app.initialize()
+
+ if str(cm.value) != "0":
+ raise RuntimeError(f"Unexpected exit code {cm.value}")
+ out = strio.getvalue()
+ return out.split(self.IFS)
+
+ def test_complete_simple_app(self, argcomplete_on):
+ app = ArgcompleteApp()
+ expected = [
+ '--help',
+ '--debug',
+ '--show-config',
+ '--show-config-json',
+ '--log-level',
+ '--Application.',
+ '--ArgcompleteApp.',
+ ]
+ assert set(self.run_completer(app, "app --")) == set(expected)
+
+ # completing class traits
+ assert set(self.run_completer(app, "app --App")) > {
+ '--Application.show_config',
+ '--Application.log_level',
+ '--Application.log_format',
+ }
+
+ def test_complete_custom_completers(self, argcomplete_on):
+ app = ArgcompleteApp()
+ # test pre-defined completers for Bool/Enum
+ assert set(self.run_completer(app, "app --Application.log_level=")) > {"DEBUG", "INFO"}
+ assert set(self.run_completer(app, "app --ArgcompleteApp.show_config ")) == {
+ "0",
+ "1",
+ "true",
+ "false",
+ }
+
+ # test custom completer and mid-command completions
+ class CustomCls(Configurable):
+ val = Unicode().tag(
+ config=True, argcompleter=argcomplete.completers.ChoicesCompleter(["foo", "bar"])
+ )
+
+ class CustomApp(ArgcompleteApp):
+ classes = [CustomCls]
+ aliases = {("v", "val"): "CustomCls.val"}
+
+ app = CustomApp()
+ assert self.run_completer(app, "app --val ") == ["foo", "bar"]
+ assert self.run_completer(app, "app --val=") == ["foo", "bar"]
+ assert self.run_completer(app, "app -v ") == ["foo", "bar"]
+ assert self.run_completer(app, "app -v=") == ["foo", "bar"]
+ assert self.run_completer(app, "app --CustomCls.val ") == ["foo", "bar"]
+ assert self.run_completer(app, "app --CustomCls.val=") == ["foo", "bar"]
+ completions = self.run_completer(app, "app --val= abc xyz", point=10)
+ # fixed in argcomplete >= 2.0 to return latter below
+ assert completions == ["--val=foo", "--val=bar"] or completions == ["foo", "bar"]
+ assert self.run_completer(app, "app --val --log-level=", point=10) == ["foo", "bar"]
+
+ def test_complete_subcommands(self, argcomplete_on):
+ app = MainApp()
+ assert set(self.run_completer(app, "app ")) >= {"subapp1", "subapp2"}
+ assert set(self.run_completer(app, "app sub")) == {"subapp1", "subapp2"}
+ assert set(self.run_completer(app, "app subapp1")) == {"subapp1"}
+
+ def test_complete_subcommands_subapp1(self, argcomplete_on):
+ # subcommand handling modifies _ARGCOMPLETE env var global state, so
+ # only can test one completion per unit test
+ app = MainApp()
+ try:
+ assert set(self.run_completer(app, "app subapp1 --Sub")) > {
+ '--SubApp1.show_config',
+ '--SubApp1.log_level',
+ '--SubApp1.log_format',
+ }
+ finally:
+ SubApp1.clear_instance()
+
+ def test_complete_subcommands_subapp2(self, argcomplete_on):
+ app = MainApp()
+ try:
+ assert set(self.run_completer(app, "app subapp2 --")) > {
+ '--Application.',
+ '--SubApp2.',
+ }
+ finally:
+ SubApp2.clear_instance()
+
+ def test_complete_subcommands_main(self, argcomplete_on):
+ app = MainApp()
+ completions = set(self.run_completer(app, "app --"))
+ assert completions > {'--Application.', '--MainApp.'}
+ assert "--SubApp1." not in completions and "--SubApp2." not in completions
diff --git a/contrib/python/traitlets/py3/traitlets/config/tests/test_configurable.py b/contrib/python/traitlets/py3/tests/config/test_configurable.py
index 357aede78a9..f6499ea29d1 100644
--- a/contrib/python/traitlets/py3/traitlets/config/tests/test_configurable.py
+++ b/contrib/python/traitlets/py3/tests/config/test_configurable.py
@@ -8,6 +8,7 @@ from unittest import TestCase
from pytest import mark
+from .._warnings import expected_warnings
from traitlets.config.application import Application
from traitlets.config.configurable import Configurable, LoggingConfigurable, SingletonConfigurable
from traitlets.config.loader import Config
@@ -26,8 +27,6 @@ from traitlets.traitlets import (
)
from traitlets.utils.warnings import _deprecations_shown
-from traitlets.tests._warnings import expected_warnings
-
class MyConfigurable(Configurable):
a = Integer(1, help="The integer a.").tag(config=True)
diff --git a/contrib/python/traitlets/py3/traitlets/config/tests/test_loader.py b/contrib/python/traitlets/py3/tests/config/test_loader.py
index 3a1f96120f7..3a1f96120f7 100644
--- a/contrib/python/traitlets/py3/traitlets/config/tests/test_loader.py
+++ b/contrib/python/traitlets/py3/tests/config/test_loader.py
diff --git a/contrib/python/traitlets/py3/traitlets/tests/test_traitlets.py b/contrib/python/traitlets/py3/tests/test_traitlets.py
index dab1f6ddc79..62fa726f19b 100644
--- a/contrib/python/traitlets/py3/traitlets/tests/test_traitlets.py
+++ b/contrib/python/traitlets/py3/tests/test_traitlets.py
@@ -62,7 +62,7 @@ from traitlets import (
)
from traitlets.utils import cast_unicode
-from traitlets.tests._warnings import expected_warnings
+from ._warnings import expected_warnings
def change_dict(*ordered_values):
diff --git a/contrib/python/traitlets/py3/tests/test_traitlets_docstring.py b/contrib/python/traitlets/py3/tests/test_traitlets_docstring.py
new file mode 100644
index 00000000000..700199108f1
--- /dev/null
+++ b/contrib/python/traitlets/py3/tests/test_traitlets_docstring.py
@@ -0,0 +1,84 @@
+"""Tests for traitlets.traitlets."""
+
+# Copyright (c) IPython Development Team.
+# Distributed under the terms of the Modified BSD License.
+#
+from traitlets import Dict, Instance, Integer, Unicode, Union
+from traitlets.config import Configurable
+
+
+def test_handle_docstring():
+ class SampleConfigurable(Configurable):
+ pass
+
+ class TraitTypesSampleConfigurable(Configurable):
+ """TraitTypesSampleConfigurable docstring"""
+
+ trait_integer = Integer(
+ help="""trait_integer help text""",
+ config=True,
+ )
+ trait_integer_nohelp = Integer(
+ config=True,
+ )
+ trait_integer_noconfig = Integer(
+ help="""trait_integer_noconfig help text""",
+ )
+
+ trait_unicode = Unicode(
+ help="""trait_unicode help text""",
+ config=True,
+ )
+ trait_unicode_nohelp = Unicode(
+ config=True,
+ )
+ trait_unicode_noconfig = Unicode(
+ help="""trait_unicode_noconfig help text""",
+ )
+
+ trait_dict = Dict(
+ help="""trait_dict help text""",
+ config=True,
+ )
+ trait_dict_nohelp = Dict(
+ config=True,
+ )
+ trait_dict_noconfig = Dict(
+ help="""trait_dict_noconfig help text""",
+ )
+
+ trait_instance = Instance(
+ klass=SampleConfigurable,
+ help="""trait_instance help text""",
+ config=True,
+ )
+ trait_instance_nohelp = Instance(
+ klass=SampleConfigurable,
+ config=True,
+ )
+ trait_instance_noconfig = Instance(
+ klass=SampleConfigurable,
+ help="""trait_instance_noconfig help text""",
+ )
+
+ trait_union = Union(
+ [Integer(), Unicode()],
+ help="""trait_union help text""",
+ config=True,
+ )
+ trait_union_nohelp = Union(
+ [Integer(), Unicode()],
+ config=True,
+ )
+ trait_union_noconfig = Union(
+ [Integer(), Unicode()],
+ help="""trait_union_noconfig help text""",
+ )
+
+ base_names = SampleConfigurable().trait_names()
+ for name in TraitTypesSampleConfigurable().trait_names():
+ if name in base_names:
+ continue
+ doc = getattr(TraitTypesSampleConfigurable, name).__doc__
+ if "nohelp" not in name:
+ assert doc == f"{name} help text"
diff --git a/contrib/python/traitlets/py3/traitlets/tests/test_traitlets_enum.py b/contrib/python/traitlets/py3/tests/test_traitlets_enum.py
index c39007e8a05..c39007e8a05 100644
--- a/contrib/python/traitlets/py3/traitlets/tests/test_traitlets_enum.py
+++ b/contrib/python/traitlets/py3/tests/test_traitlets_enum.py
diff --git a/contrib/python/traitlets/py3/tests/test_typing.py b/contrib/python/traitlets/py3/tests/test_typing.py
new file mode 100644
index 00000000000..2b4073ecf72
--- /dev/null
+++ b/contrib/python/traitlets/py3/tests/test_typing.py
@@ -0,0 +1,395 @@
+from __future__ import annotations
+
+import typing
+
+import pytest
+
+from traitlets import (
+ Any,
+ Bool,
+ CInt,
+ Dict,
+ HasTraits,
+ Instance,
+ Int,
+ List,
+ Set,
+ TCPAddress,
+ Type,
+ Unicode,
+ Union,
+ default,
+ observe,
+ validate,
+)
+from traitlets.config import Config
+
+if not typing.TYPE_CHECKING:
+
+ def reveal_type(*args, **kwargs):
+ pass
+
+
+# mypy: disallow-untyped-calls
+
+
+class Foo:
+ def __init__(self, c):
+ self.c = c
+
+
+def mypy_decorator_typing():
+ class T(HasTraits):
+ foo = Unicode("").tag(config=True)
+
+ @default("foo")
+ def _default_foo(self) -> str:
+ return "hi"
+
+ @observe("foo")
+ def _foo_observer(self, change: typing.Any) -> bool:
+ return True
+
+ @validate("foo")
+ def _foo_validate(self, commit: typing.Any) -> bool:
+ return True
+
+ t = T()
+ reveal_type(t.foo) # R: builtins.str
+ reveal_type(t._foo_observer) # R: Any
+ reveal_type(t._foo_validate) # R: Any
+
+
+def mypy_config_typing():
+ c = Config(
+ {
+ "ExtractOutputPreprocessor": {"enabled": True},
+ }
+ )
+ reveal_type(c) # R: traitlets.config.loader.Config
+
+
+def mypy_union_typing():
+ class T(HasTraits):
+ style = Union(
+ [Unicode("default"), Type(klass=object)],
+ help="Name of the pygments style to use",
+ default_value="hi",
+ ).tag(config=True)
+
+ t = T()
+ reveal_type(Union("foo")) # R: traitlets.traitlets.Union
+ reveal_type(Union("").tag(sync=True)) # R: traitlets.traitlets.Union
+ reveal_type(Union(None, allow_none=True)) # R: traitlets.traitlets.Union
+ reveal_type(Union(None, allow_none=True).tag(sync=True)) # R: traitlets.traitlets.Union
+ reveal_type(T.style) # R: traitlets.traitlets.Union
+ reveal_type(t.style) # R: Any
+
+
+def mypy_list_typing():
+ class T(HasTraits):
+ latex_command = List(
+ ["xelatex", "{filename}", "-quiet"], help="Shell command used to compile latex."
+ ).tag(config=True)
+
+ t = T()
+ reveal_type(List("foo")) # R: traitlets.traitlets.List
+ reveal_type(List("").tag(sync=True)) # R: traitlets.traitlets.List
+ reveal_type(List(None, allow_none=True)) # R: traitlets.traitlets.List
+ reveal_type(List(None, allow_none=True).tag(sync=True)) # R: traitlets.traitlets.List
+ reveal_type(T.latex_command) # R: traitlets.traitlets.List
+ reveal_type(t.latex_command) # R: builtins.list[Any]
+
+
+def mypy_dict_typing():
+ class T(HasTraits):
+ foo = Dict({}, help="Shell command used to compile latex.").tag(config=True)
+
+ t = T()
+ reveal_type(Dict("foo")) # R: traitlets.traitlets.Dict
+ reveal_type(Dict("").tag(sync=True)) # R: traitlets.traitlets.Dict
+ reveal_type(Dict(None, allow_none=True)) # R: traitlets.traitlets.Dict
+ reveal_type(Dict(None, allow_none=True).tag(sync=True)) # R: traitlets.traitlets.Dict
+ reveal_type(T.foo) # R: traitlets.traitlets.Dict
+ reveal_type(t.foo) # R: builtins.dict[Any, Any]
+
+
+def mypy_type_typing():
+ class KernelSpec:
+ item = Unicode("foo")
+
+ class KernelSpecManager(HasTraits):
+ """A manager for kernel specs."""
+
+ kernel_spec_class = Type(
+ KernelSpec,
+ config=True,
+ help="""The kernel spec class. This is configurable to allow
+ subclassing of the KernelSpecManager for customized behavior.
+ """,
+ )
+ other_class = Type("foo.bar.baz")
+
+ t = KernelSpecManager()
+ reveal_type(t.kernel_spec_class) # R: def () -> tests.test_typing.KernelSpec@124
+ reveal_type(t.kernel_spec_class()) # R: tests.test_typing.KernelSpec@124
+ reveal_type(t.kernel_spec_class().item) # R: builtins.str
+ reveal_type(t.other_class) # R: builtins.type
+ reveal_type(t.other_class()) # R: Any
+
+
+def mypy_unicode_typing():
+ class T(HasTraits):
+ export_format = Unicode(
+ allow_none=False,
+ help="""The export format to be used, either one of the built-in formats
+ or a dotted object name that represents the import path for an
+ ``Exporter`` class""",
+ ).tag(config=True)
+
+ t = T()
+ reveal_type(
+ Unicode( # R: traitlets.traitlets.Unicode[builtins.str, Union[builtins.str, builtins.bytes]]
+ "foo"
+ )
+ )
+ reveal_type(
+ Unicode( # R: traitlets.traitlets.Unicode[builtins.str, Union[builtins.str, builtins.bytes]]
+ ""
+ ).tag(
+ sync=True
+ )
+ )
+ reveal_type(
+ Unicode( # R: traitlets.traitlets.Unicode[Union[builtins.str, None], Union[builtins.str, builtins.bytes, None]]
+ None, allow_none=True
+ )
+ )
+ reveal_type(
+ Unicode( # R: traitlets.traitlets.Unicode[Union[builtins.str, None], Union[builtins.str, builtins.bytes, None]]
+ None, allow_none=True
+ ).tag(
+ sync=True
+ )
+ )
+ reveal_type(
+ T.export_format # R: traitlets.traitlets.Unicode[builtins.str, Union[builtins.str, builtins.bytes]]
+ )
+ reveal_type(t.export_format) # R: builtins.str
+
+
+def mypy_set_typing():
+ class T(HasTraits):
+ remove_cell_tags = Set(
+ Unicode(),
+ default_value=[],
+ help=(
+ "Tags indicating which cells are to be removed,"
+ "matches tags in ``cell.metadata.tags``."
+ ),
+ ).tag(config=True)
+
+ safe_output_keys = Set(
+ config=True,
+ default_value={
+ "metadata", # Not a mimetype per-se, but expected and safe.
+ "text/plain",
+ "text/latex",
+ "application/json",
+ "image/png",
+ "image/jpeg",
+ },
+ help="Cell output mimetypes to render without modification",
+ )
+
+ t = T()
+ reveal_type(Set("foo")) # R: traitlets.traitlets.Set
+ reveal_type(Set("").tag(sync=True)) # R: traitlets.traitlets.Set
+ reveal_type(Set(None, allow_none=True)) # R: traitlets.traitlets.Set
+ reveal_type(Set(None, allow_none=True).tag(sync=True)) # R: traitlets.traitlets.Set
+ reveal_type(T.remove_cell_tags) # R: traitlets.traitlets.Set
+ reveal_type(t.remove_cell_tags) # R: builtins.set[Any]
+ reveal_type(T.safe_output_keys) # R: traitlets.traitlets.Set
+ reveal_type(t.safe_output_keys) # R: builtins.set[Any]
+
+
+def mypy_any_typing():
+ class T(HasTraits):
+ attributes = Any(
+ config=True,
+ default_value={
+ "a": ["href", "title"],
+ "abbr": ["title"],
+ "acronym": ["title"],
+ },
+ help="Allowed HTML tag attributes",
+ )
+
+ t = T()
+ reveal_type(Any("foo")) # R: traitlets.traitlets.Any
+ reveal_type(Any("").tag(sync=True)) # R: traitlets.traitlets.Any
+ reveal_type(Any(None, allow_none=True)) # R: traitlets.traitlets.Any
+ reveal_type(Any(None, allow_none=True).tag(sync=True)) # R: traitlets.traitlets.Any
+ reveal_type(T.attributes) # R: traitlets.traitlets.Any
+ reveal_type(t.attributes) # R: Any
+
+
+def mypy_bool_typing():
+ class T(HasTraits):
+ b = Bool(True).tag(sync=True)
+ ob = Bool(None, allow_none=True).tag(sync=True)
+
+ t = T()
+ reveal_type(
+ Bool(True) # R: traitlets.traitlets.Bool[builtins.bool, Union[builtins.bool, builtins.int]]
+ )
+ reveal_type(
+ Bool( # R: traitlets.traitlets.Bool[builtins.bool, Union[builtins.bool, builtins.int]]
+ True
+ ).tag(sync=True)
+ )
+ reveal_type(
+ Bool( # R: traitlets.traitlets.Bool[Union[builtins.bool, None], Union[builtins.bool, builtins.int, None]]
+ None, allow_none=True
+ )
+ )
+ reveal_type(
+ Bool( # R: traitlets.traitlets.Bool[Union[builtins.bool, None], Union[builtins.bool, builtins.int, None]]
+ None, allow_none=True
+ ).tag(
+ sync=True
+ )
+ )
+ reveal_type(
+ T.b # R: traitlets.traitlets.Bool[builtins.bool, Union[builtins.bool, builtins.int]]
+ )
+ reveal_type(t.b) # R: builtins.bool
+ reveal_type(t.ob) # R: Union[builtins.bool, None]
+ reveal_type(
+ T.b # R: traitlets.traitlets.Bool[builtins.bool, Union[builtins.bool, builtins.int]]
+ )
+ reveal_type(
+ T.ob # R: traitlets.traitlets.Bool[Union[builtins.bool, None], Union[builtins.bool, builtins.int, None]]
+ )
+ # we would expect this to be Optional[Union[bool, int]], but...
+ t.b = "foo" # E: Incompatible types in assignment (expression has type "str", variable has type "Union[bool, int]") [assignment]
+ t.b = None # E: Incompatible types in assignment (expression has type "None", variable has type "Union[bool, int]") [assignment]
+
+
+def mypy_int_typing():
+ class T(HasTraits):
+ i: Int[int, int] = Int(42).tag(sync=True)
+ oi: Int[int | None, int | None] = Int(42, allow_none=True).tag(sync=True)
+
+ t = T()
+ reveal_type(Int(True)) # R: traitlets.traitlets.Int[builtins.int, builtins.int]
+ reveal_type(Int(True).tag(sync=True)) # R: traitlets.traitlets.Int[builtins.int, builtins.int]
+ reveal_type(
+ Int( # R: traitlets.traitlets.Int[Union[builtins.int, None], Union[builtins.int, None]]
+ None, allow_none=True
+ )
+ )
+ reveal_type(
+ Int( # R: traitlets.traitlets.Int[Union[builtins.int, None], Union[builtins.int, None]]
+ None, allow_none=True
+ ).tag(sync=True)
+ )
+ reveal_type(T.i) # R: traitlets.traitlets.Int[builtins.int, builtins.int]
+ reveal_type(t.i) # R: builtins.int
+ reveal_type(t.oi) # R: Union[builtins.int, None]
+ reveal_type(T.i) # R: traitlets.traitlets.Int[builtins.int, builtins.int]
+ reveal_type(
+ T.oi # R: traitlets.traitlets.Int[Union[builtins.int, None], Union[builtins.int, None]]
+ )
+ t.i = "foo" # E: Incompatible types in assignment (expression has type "str", variable has type "int") [assignment]
+ t.i = None # E: Incompatible types in assignment (expression has type "None", variable has type "int") [assignment]
+ t.i = 1.2 # E: Incompatible types in assignment (expression has type "float", variable has type "int") [assignment]
+
+
+def mypy_cint_typing():
+ class T(HasTraits):
+ i = CInt(42).tag(sync=True)
+ oi = CInt(42, allow_none=True).tag(sync=True)
+
+ t = T()
+ reveal_type(CInt(42)) # R: traitlets.traitlets.CInt[builtins.int, Any]
+ reveal_type(CInt(42).tag(sync=True)) # R: traitlets.traitlets.CInt[builtins.int, Any]
+ reveal_type(
+ CInt(None, allow_none=True) # R: traitlets.traitlets.CInt[Union[builtins.int, None], Any]
+ )
+ reveal_type(
+ CInt( # R: traitlets.traitlets.CInt[Union[builtins.int, None], Any]
+ None, allow_none=True
+ ).tag(sync=True)
+ )
+ reveal_type(T.i) # R: traitlets.traitlets.CInt[builtins.int, Any]
+ reveal_type(t.i) # R: builtins.int
+ reveal_type(t.oi) # R: Union[builtins.int, None]
+ reveal_type(T.i) # R: traitlets.traitlets.CInt[builtins.int, Any]
+ reveal_type(T.oi) # R: traitlets.traitlets.CInt[Union[builtins.int, None], Any]
+
+
+def mypy_tcp_typing():
+ class T(HasTraits):
+ tcp = TCPAddress()
+ otcp = TCPAddress(None, allow_none=True)
+
+ t = T()
+ reveal_type(t.tcp) # R: Tuple[builtins.str, builtins.int]
+ reveal_type(
+ T.tcp # R: traitlets.traitlets.TCPAddress[Tuple[builtins.str, builtins.int], Tuple[builtins.str, builtins.int]]
+ )
+ reveal_type(
+ T.tcp.tag( # R:traitlets.traitlets.TCPAddress[Tuple[builtins.str, builtins.int], Tuple[builtins.str, builtins.int]]
+ sync=True
+ )
+ )
+ reveal_type(t.otcp) # R: Union[Tuple[builtins.str, builtins.int], None]
+ reveal_type(
+ T.otcp # R: traitlets.traitlets.TCPAddress[Union[Tuple[builtins.str, builtins.int], None], Union[Tuple[builtins.str, builtins.int], None]]
+ )
+ reveal_type(
+ T.otcp.tag( # R: traitlets.traitlets.TCPAddress[Union[Tuple[builtins.str, builtins.int], None], Union[Tuple[builtins.str, builtins.int], None]]
+ sync=True
+ )
+ )
+ t.tcp = "foo" # E: Incompatible types in assignment (expression has type "str", variable has type "Tuple[str, int]") [assignment]
+ t.otcp = "foo" # E: Incompatible types in assignment (expression has type "str", variable has type "Optional[Tuple[str, int]]") [assignment]
+ t.tcp = None # E: Incompatible types in assignment (expression has type "None", variable has type "Tuple[str, int]") [assignment]
+
+
+def mypy_instance_typing():
+ class T(HasTraits):
+ inst = Instance(Foo)
+ oinst = Instance(Foo, allow_none=True)
+ oinst_string = Instance("Foo", allow_none=True)
+
+ t = T()
+ reveal_type(t.inst) # R: tests.test_typing.Foo
+ reveal_type(T.inst) # R: traitlets.traitlets.Instance[tests.test_typing.Foo]
+ reveal_type(T.inst.tag(sync=True)) # R: traitlets.traitlets.Instance[tests.test_typing.Foo]
+ reveal_type(t.oinst) # R: Union[tests.test_typing.Foo, None]
+ reveal_type(t.oinst_string) # R: Union[Any, None]
+ reveal_type(T.oinst) # R: traitlets.traitlets.Instance[Union[tests.test_typing.Foo, None]]
+ reveal_type(
+ T.oinst.tag( # R: traitlets.traitlets.Instance[Union[tests.test_typing.Foo, None]]
+ sync=True
+ )
+ )
+ t.inst = "foo" # E: Incompatible types in assignment (expression has type "str", variable has type "Foo") [assignment]
+ t.oinst = "foo" # E: Incompatible types in assignment (expression has type "str", variable has type "Optional[Foo]") [assignment]
+ t.inst = None # E: Incompatible types in assignment (expression has type "None", variable has type "Foo") [assignment]
diff --git a/contrib/python/traitlets/py3/tests/utils/__init__.py b/contrib/python/traitlets/py3/tests/utils/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/contrib/python/traitlets/py3/tests/utils/__init__.py
diff --git a/contrib/python/traitlets/py3/traitlets/utils/tests/test_bunch.py b/contrib/python/traitlets/py3/tests/utils/test_bunch.py
index 223124d7d5e..223124d7d5e 100644
--- a/contrib/python/traitlets/py3/traitlets/utils/tests/test_bunch.py
+++ b/contrib/python/traitlets/py3/tests/utils/test_bunch.py
diff --git a/contrib/python/traitlets/py3/traitlets/utils/tests/test_decorators.py b/contrib/python/traitlets/py3/tests/utils/test_decorators.py
index 5410c201371..d6bf8414e5a 100644
--- a/contrib/python/traitlets/py3/traitlets/utils/tests/test_decorators.py
+++ b/contrib/python/traitlets/py3/tests/utils/test_decorators.py
@@ -1,7 +1,7 @@
from inspect import Parameter, signature
from unittest import TestCase
-from traitlets.traitlets import HasTraits, Int, Unicode
+from traitlets import HasTraits, Int, Unicode
from traitlets.utils.decorators import signature_has_traits
diff --git a/contrib/python/traitlets/py3/traitlets/utils/tests/test_importstring.py b/contrib/python/traitlets/py3/tests/utils/test_importstring.py
index 8ce28add41e..8ce28add41e 100644
--- a/contrib/python/traitlets/py3/traitlets/utils/tests/test_importstring.py
+++ b/contrib/python/traitlets/py3/tests/utils/test_importstring.py
diff --git a/contrib/python/traitlets/py3/tests/ya.make b/contrib/python/traitlets/py3/tests/ya.make
index 6a5cd7cf463..6ffd29993d5 100644
--- a/contrib/python/traitlets/py3/tests/ya.make
+++ b/contrib/python/traitlets/py3/tests/ya.make
@@ -1,20 +1,27 @@
PY3TEST()
PEERDIR(
+ contrib/python/argcomplete
contrib/python/traitlets
+ contrib/python/pytest-mock
)
-SRCDIR(contrib/python/traitlets/py3/traitlets)
-
TEST_SRCS(
- config/tests/test_application.py
- config/tests/test_configurable.py
- config/tests/test_loader.py
- tests/test_traitlets.py
- tests/test_traitlets_enum.py
- utils/tests/test_bunch.py
- utils/tests/test_decorators.py
- utils/tests/test_importstring.py
+ __init__.py
+ _warnings.py
+ config/__init__.py
+ config/test_application.py
+ config/test_argcomplete.py
+ config/test_configurable.py
+ config/test_loader.py
+ test_traitlets.py
+ test_traitlets_docstring.py
+ test_traitlets_enum.py
+ test_typing.py
+ utils/__init__.py
+ utils/test_bunch.py
+ utils/test_decorators.py
+ utils/test_importstring.py
)
NO_LINT()
diff --git a/contrib/python/traitlets/py3/traitlets/__init__.py b/contrib/python/traitlets/py3/traitlets/__init__.py
index 96ebe57f1be..2641c443e9d 100644
--- a/contrib/python/traitlets/py3/traitlets/__init__.py
+++ b/contrib/python/traitlets/py3/traitlets/__init__.py
@@ -1,4 +1,6 @@
"""Traitlets Python configuration system"""
+import typing as _t
+
from . import traitlets
from ._version import __version__, version_info
from .traitlets import *
@@ -19,7 +21,7 @@ __all__ = [
class Sentinel(traitlets.Sentinel): # type:ignore[name-defined]
- def __init__(self, *args, **kwargs):
+ def __init__(self, *args: _t.Any, **kwargs: _t.Any) -> None:
super().__init__(*args, **kwargs)
warn(
"""
diff --git a/contrib/python/traitlets/py3/traitlets/_version.py b/contrib/python/traitlets/py3/traitlets/_version.py
index d477cb8ce1b..5fbb9a25992 100644
--- a/contrib/python/traitlets/py3/traitlets/_version.py
+++ b/contrib/python/traitlets/py3/traitlets/_version.py
@@ -5,7 +5,7 @@ import re
from typing import List
# Version string must appear intact for hatch versioning
-__version__ = "5.10.1"
+__version__ = "5.11.2"
# Build up version_info tuple for backwards compatibility
pattern = r"(?P<major>\d+).(?P<minor>\d+).(?P<patch>\d+)(?P<rest>.*)"
diff --git a/contrib/python/traitlets/py3/traitlets/config/application.py b/contrib/python/traitlets/py3/traitlets/config/application.py
index fb185f0ae57..5993b4c7f24 100644
--- a/contrib/python/traitlets/py3/traitlets/config/application.py
+++ b/contrib/python/traitlets/py3/traitlets/config/application.py
@@ -2,7 +2,7 @@
# Copyright (c) IPython Development Team.
# Distributed under the terms of the Modified BSD License.
-
+from __future__ import annotations
import functools
import json
@@ -17,7 +17,6 @@ from contextlib import suppress
from copy import deepcopy
from logging.config import dictConfig
from textwrap import dedent
-from typing import Any, Callable, TypeVar, cast
from traitlets.config.configurable import Configurable, SingletonConfigurable
from traitlets.config.loader import (
@@ -40,6 +39,7 @@ from traitlets.traitlets import (
observe,
observe_compat,
)
+from traitlets.utils.bunch import Bunch
from traitlets.utils.nested_update import nested_update
from traitlets.utils.text import indent, wrap_paragraphs
@@ -95,7 +95,11 @@ else:
IS_PYTHONW = sys.executable and sys.executable.endswith("pythonw.exe")
-T = TypeVar("T", bound=Callable[..., Any])
+T = t.TypeVar("T", bound=t.Callable[..., t.Any])
+AnyLogger = t.Union[logging.Logger, logging.LoggerAdapter]
+StrDict = t.Dict[str, t.Any]
+ArgvType = t.Optional[t.List[str]]
+ClassesType = t.List[t.Type[Configurable]]
def catch_config_error(method: T) -> T:
@@ -108,7 +112,7 @@ def catch_config_error(method: T) -> T:
"""
@functools.wraps(method)
- def inner(app, *args, **kwargs):
+ def inner(app: Application, *args: t.Any, **kwargs: t.Any) -> t.Any:
try:
return method(app, *args, **kwargs)
except (TraitError, ArgumentError) as e:
@@ -116,7 +120,7 @@ def catch_config_error(method: T) -> T:
app.log.debug("Config at the time: %s", app.config)
app.exit(1)
- return cast(T, inner)
+ return t.cast(T, inner)
class ApplicationError(Exception):
@@ -136,7 +140,7 @@ class LevelFormatter(logging.Formatter):
highlevel_limit = logging.WARN
highlevel_format = " %(levelname)s |"
- def format(self, record):
+ def format(self, record: logging.LogRecord) -> str:
if record.levelno >= self.highlevel_limit:
record.highlevel = self.highlevel_format % record.__dict__
else:
@@ -149,35 +153,29 @@ class Application(SingletonConfigurable):
# The name of the application, will usually match the name of the command
# line application
- name: t.Union[str, Unicode[str, t.Union[str, bytes]]] = Unicode("application")
+ name: str | Unicode[str, str | bytes] = Unicode("application")
# The description of the application that is printed at the beginning
# of the help.
- description: t.Union[str, Unicode[str, t.Union[str, bytes]]] = Unicode(
- "This is an application."
- )
+ description: str | Unicode[str, str | bytes] = Unicode("This is an application.")
# default section descriptions
- option_description: t.Union[str, Unicode[str, t.Union[str, bytes]]] = Unicode(
- option_description
- )
- keyvalue_description: t.Union[str, Unicode[str, t.Union[str, bytes]]] = Unicode(
- keyvalue_description
- )
- subcommand_description: t.Union[str, Unicode[str, t.Union[str, bytes]]] = Unicode(
- subcommand_description
- )
+ option_description: str | Unicode[str, str | bytes] = Unicode(option_description)
+ keyvalue_description: str | Unicode[str, str | bytes] = Unicode(keyvalue_description)
+ subcommand_description: str | Unicode[str, str | bytes] = Unicode(subcommand_description)
python_config_loader_class = PyFileConfigLoader
json_config_loader_class = JSONFileConfigLoader
# The usage and example string that goes at the end of the help string.
- examples: t.Union[str, Unicode[str, t.Union[str, bytes]]] = Unicode()
+ examples: str | Unicode[str, str | bytes] = Unicode()
# A sequence of Configurable subclasses whose config=True attributes will
# be exposed at the command line.
- classes: t.List[t.Type[t.Any]] = []
+ classes: ClassesType = []
- def _classes_inc_parents(self, classes=None):
+ def _classes_inc_parents(
+ self, classes: ClassesType | None = None
+ ) -> t.Generator[type[Configurable], None, None]:
"""Iterate through configurable classes, including configurable parents
:param classes:
@@ -198,18 +196,16 @@ class Application(SingletonConfigurable):
yield parent
# The version string of this application.
- version: t.Union[str, Unicode[str, t.Union[str, bytes]]] = Unicode("0.0")
+ version: str | Unicode[str, str | bytes] = Unicode("0.0")
# the argv used to initialize the application
- argv: t.Union[t.List[str], List] = List()
+ argv = List()
# Whether failing to load config files should prevent startup
- raise_config_file_errors: t.Union[bool, Bool[bool, t.Union[bool, int]]] = Bool(
- TRAITLETS_APPLICATION_RAISE_CONFIG_FILE_ERROR
- )
+ raise_config_file_errors = Bool(TRAITLETS_APPLICATION_RAISE_CONFIG_FILE_ERROR)
# The log level for the application
- log_level: t.Union[str, int, Enum[t.Any, t.Any]] = Enum(
+ log_level = Enum(
(0, 10, 20, 30, 40, 50, "DEBUG", "INFO", "WARN", "ERROR", "CRITICAL"),
default_value=logging.WARN,
help="Set the log level by value or name.",
@@ -217,16 +213,16 @@ class Application(SingletonConfigurable):
_log_formatter_cls = LevelFormatter
- log_datefmt: t.Union[str, Unicode[str, t.Union[str, bytes]]] = Unicode(
+ log_datefmt = Unicode(
"%Y-%m-%d %H:%M:%S", help="The date format used by logging formatters for %(asctime)s"
).tag(config=True)
- log_format: t.Union[str, Unicode[str, t.Union[str, bytes]]] = Unicode(
+ log_format = Unicode(
"[%(name)s]%(highlevel)s %(message)s",
help="The Logging format template",
).tag(config=True)
- def get_default_logging_config(self):
+ def get_default_logging_config(self) -> StrDict:
"""Return the base logging configuration.
The default is to log to stderr using a StreamHandler, if no default
@@ -239,7 +235,7 @@ class Application(SingletonConfigurable):
control of logging.
"""
- config: t.Dict[str, t.Any] = {
+ config: StrDict = {
"version": 1,
"handlers": {
"console": {
@@ -278,7 +274,7 @@ class Application(SingletonConfigurable):
return config
@observe("log_datefmt", "log_format", "log_level", "logging_config")
- def _observe_logging_change(self, change):
+ def _observe_logging_change(self, change: Bunch) -> None:
# convert log level strings to ints
log_level = self.log_level
if isinstance(log_level, str):
@@ -286,10 +282,10 @@ class Application(SingletonConfigurable):
self._configure_logging()
@observe("log", type="default")
- def _observe_logging_default(self, change):
+ def _observe_logging_default(self, change: Bunch) -> None:
self._configure_logging()
- def _configure_logging(self):
+ def _configure_logging(self) -> None:
config = self.get_default_logging_config()
nested_update(config, self.logging_config or {})
dictConfig(config)
@@ -297,7 +293,7 @@ class Application(SingletonConfigurable):
self._logging_configured = True
@default("log")
- def _log_default(self):
+ def _log_default(self) -> AnyLogger:
"""Start logging for this application."""
log = logging.getLogger(self.__class__.__name__)
log.propagate = False
@@ -366,17 +362,13 @@ class Application(SingletonConfigurable):
#: Values might be like "Class.trait" strings of two-tuples: (Class.trait, help-text),
# or just the "Class.trait" string, in which case the help text is inferred from the
# corresponding trait
- aliases: t.Dict[t.Union[str, t.Tuple[str, ...]], t.Union[str, t.Tuple[str, str]]] = {
- "log-level": "Application.log_level"
- }
+ aliases: StrDict = {"log-level": "Application.log_level"}
# flags for loading Configurables or store_const style flags
# flags are loaded from this dict by '--key' flags
# this must be a dict of two-tuples, the first element being the Config/dict
# and the second being the help string for the flag
- flags: t.Dict[
- t.Union[str, t.Tuple[str, ...]], t.Tuple[t.Union[t.Dict[str, t.Any], Config], str]
- ] = {
+ flags: StrDict = {
"debug": (
{
"Application": {
@@ -408,12 +400,12 @@ class Application(SingletonConfigurable):
# this must be a dict of two-tuples,
# the first element being the application class/import string
# and the second being the help string for the subcommand
- subcommands: t.Union[t.Dict[str, t.Tuple[t.Any, str]], Dict] = Dict()
+ subcommands: dict[str, t.Any] | Dict = Dict()
# parse_command_line will initialize a subapp, if requested
subapp = Instance("traitlets.config.application.Application", allow_none=True)
# extra command-line arguments that don't set config values
- extra_args: t.Union[t.List[str], List] = List(Unicode())
+ extra_args = List(Unicode())
cli_config = Instance(
Config,
@@ -428,20 +420,20 @@ class Application(SingletonConfigurable):
_loaded_config_files = List()
- show_config: t.Union[bool, Bool[bool, t.Union[bool, int]]] = Bool(
+ show_config = Bool(
help="Instead of starting the Application, dump configuration to stdout"
).tag(config=True)
- show_config_json: t.Union[bool, Bool[bool, t.Union[bool, int]]] = Bool(
+ show_config_json = Bool(
help="Instead of starting the Application, dump configuration to stdout (as JSON)"
).tag(config=True)
@observe("show_config_json")
- def _show_config_json_changed(self, change):
+ def _show_config_json_changed(self, change: Bunch) -> None:
self.show_config = change.new
@observe("show_config")
- def _show_config_changed(self, change):
+ def _show_config_changed(self, change: Bunch) -> None:
if change.new:
self._save_start = self.start
self.start = self.start_show_config # type:ignore[method-assign]
@@ -460,27 +452,28 @@ class Application(SingletonConfigurable):
@observe("config")
@observe_compat
- def _config_changed(self, change):
+ def _config_changed(self, change: Bunch) -> None:
super()._config_changed(change)
self.log.debug("Config changed: %r", change.new)
@catch_config_error
- def initialize(self, argv=None):
+ def initialize(self, argv: ArgvType = None) -> None:
"""Do the basic steps to configure me.
Override in subclasses.
"""
self.parse_command_line(argv)
- def start(self):
+ def start(self) -> None:
"""Start the app mainloop.
Override in subclasses.
"""
if self.subapp is not None:
+ assert isinstance(self.subapp, Application)
return self.subapp.start()
- def start_show_config(self):
+ def start_show_config(self) -> None:
"""start function used when show_config is True"""
config = self.config.copy()
# exclude show_config flags from displayed config
@@ -507,28 +500,28 @@ class Application(SingletonConfigurable):
if not class_config:
continue
print(classname)
- pformat_kwargs: t.Dict[str, t.Any] = dict(indent=4, compact=True)
+ pformat_kwargs: StrDict = dict(indent=4, compact=True)
for traitname in sorted(class_config):
value = class_config[traitname]
print(f" .{traitname} = {pprint.pformat(value, **pformat_kwargs)}")
- def print_alias_help(self):
+ def print_alias_help(self) -> None:
"""Print the alias parts of the help."""
print("\n".join(self.emit_alias_help()))
- def emit_alias_help(self):
+ def emit_alias_help(self) -> t.Generator[str, None, None]:
"""Yield the lines for alias part of the help."""
if not self.aliases:
return
- classdict = {}
+ classdict: dict[str, type[Configurable]] = {}
for cls in self.classes:
# include all parents (up to, but excluding Configurable) in available names
for c in cls.mro()[:-3]:
- classdict[c.__name__] = c
+ classdict[c.__name__] = t.cast(t.Type[Configurable], c)
- fhelp: t.Optional[str]
+ fhelp: str | None
for alias, longname in self.aliases.items():
try:
if isinstance(longname, tuple):
@@ -540,27 +533,26 @@ class Application(SingletonConfigurable):
cls = classdict[classname]
trait = cls.class_traits(config=True)[traitname]
- fhelp = cls.class_get_trait_help(trait, helptext=fhelp).splitlines()
+ fhelp_lines = cls.class_get_trait_help(trait, helptext=fhelp).splitlines()
if not isinstance(alias, tuple):
- alias = (alias,)
+ alias = (alias,) # type:ignore[assignment]
alias = sorted(alias, key=len) # type:ignore[assignment]
alias = ", ".join(("--%s" if len(m) > 1 else "-%s") % m for m in alias)
# reformat first line
- assert fhelp is not None
- fhelp[0] = fhelp[0].replace("--" + longname, alias) # type:ignore
- yield from fhelp
+ fhelp_lines[0] = fhelp_lines[0].replace("--" + longname, alias)
+ yield from fhelp_lines
yield indent("Equivalent to: [--%s]" % longname)
except Exception as ex:
self.log.error("Failed collecting help-message for alias %r, due to: %s", alias, ex)
raise
- def print_flag_help(self):
+ def print_flag_help(self) -> None:
"""Print the flag part of the help."""
print("\n".join(self.emit_flag_help()))
- def emit_flag_help(self):
+ def emit_flag_help(self) -> t.Generator[str, None, None]:
"""Yield the lines for the flag part of the help."""
if not self.flags:
return
@@ -568,7 +560,7 @@ class Application(SingletonConfigurable):
for flags, (cfg, fhelp) in self.flags.items():
try:
if not isinstance(flags, tuple):
- flags = (flags,)
+ flags = (flags,) # type:ignore[assignment]
flags = sorted(flags, key=len) # type:ignore[assignment]
flags = ", ".join(("--%s" if len(m) > 1 else "-%s") % m for m in flags)
yield flags
@@ -584,11 +576,11 @@ class Application(SingletonConfigurable):
self.log.error("Failed collecting help-message for flag %r, due to: %s", flags, ex)
raise
- def print_options(self):
+ def print_options(self) -> None:
"""Print the options part of the help."""
print("\n".join(self.emit_options_help()))
- def emit_options_help(self):
+ def emit_options_help(self) -> t.Generator[str, None, None]:
"""Yield the lines for the options part of the help."""
if not self.flags and not self.aliases:
return
@@ -603,11 +595,11 @@ class Application(SingletonConfigurable):
yield from self.emit_alias_help()
yield ""
- def print_subcommands(self):
+ def print_subcommands(self) -> None:
"""Print the subcommand part of the help."""
print("\n".join(self.emit_subcommands_help()))
- def emit_subcommands_help(self):
+ def emit_subcommands_help(self) -> t.Generator[str, None, None]:
"""Yield the lines for the subcommand part of the help."""
if not self.subcommands:
return
@@ -624,7 +616,7 @@ class Application(SingletonConfigurable):
yield indent(dedent(help.strip()))
yield ""
- def emit_help_epilogue(self, classes):
+ def emit_help_epilogue(self, classes: bool) -> t.Generator[str, None, None]:
"""Yield the very bottom lines of the help message.
If classes=False (the default), print `--help-all` msg.
@@ -633,14 +625,14 @@ class Application(SingletonConfigurable):
yield "To see all available configurables, use `--help-all`."
yield ""
- def print_help(self, classes=False):
+ def print_help(self, classes: bool = False) -> None:
"""Print the help for each Configurable class in self.classes.
If classes=False (the default), only flags and aliases are printed.
"""
print("\n".join(self.emit_help(classes=classes)))
- def emit_help(self, classes=False):
+ def emit_help(self, classes: bool = False) -> t.Generator[str, None, None]:
"""Yield the help-lines for each Configurable class in self.classes.
If classes=False (the default), only flags and aliases are printed.
@@ -665,28 +657,28 @@ class Application(SingletonConfigurable):
yield from self.emit_help_epilogue(classes)
- def document_config_options(self):
+ def document_config_options(self) -> str:
"""Generate rST format documentation for the config options this application
Returns a multiline string.
"""
return "\n".join(c.class_config_rst_doc() for c in self._classes_inc_parents())
- def print_description(self):
+ def print_description(self) -> None:
"""Print the application description."""
print("\n".join(self.emit_description()))
- def emit_description(self):
+ def emit_description(self) -> t.Generator[str, None, None]:
"""Yield lines with the application description."""
for p in wrap_paragraphs(self.description or self.__doc__ or ""):
yield p
yield ""
- def print_examples(self):
+ def print_examples(self) -> None:
"""Print usage and examples (see `emit_examples()`)."""
print("\n".join(self.emit_examples()))
- def emit_examples(self):
+ def emit_examples(self) -> t.Generator[str, None, None]:
"""Yield lines with the usage and examples.
This usage string goes at the end of the command line help string
@@ -699,12 +691,12 @@ class Application(SingletonConfigurable):
yield indent(dedent(self.examples.strip()))
yield ""
- def print_version(self):
+ def print_version(self) -> None:
"""Print the version string."""
print(self.version)
@catch_config_error
- def initialize_subcommand(self, subc, argv=None):
+ def initialize_subcommand(self, subc: str, argv: ArgvType = None) -> None:
"""Initialize a subcommand with argv."""
val = self.subcommands.get(subc)
assert val is not None
@@ -726,9 +718,9 @@ class Application(SingletonConfigurable):
raise AssertionError("Invalid mappings for subcommand '%s'!" % subc)
# ... and finally initialize subapp.
- self.subapp.initialize(argv)
+ self.subapp.initialize(argv) # type:ignore[union-attr]
- def flatten_flags(self):
+ def flatten_flags(self) -> tuple[dict[str, t.Any], dict[str, t.Any]]:
"""Flatten flags and aliases for loaders, so cl-args override as expected.
This prevents issues such as an alias pointing to InteractiveShell,
@@ -751,11 +743,11 @@ class Application(SingletonConfigurable):
mro_tree[parent.__name__].append(clsname)
# flatten aliases, which have the form:
# { 'alias' : 'Class.trait' }
- aliases: t.Dict[str, str] = {}
+ aliases: dict[str, str] = {}
for alias, longname in self.aliases.items():
if isinstance(longname, tuple):
longname, _ = longname
- cls, trait = longname.split(".", 1) # type:ignore
+ cls, trait = longname.split(".", 1)
children = mro_tree[cls] # type:ignore[index]
if len(children) == 1:
# exactly one descendent, promote alias
@@ -769,8 +761,8 @@ class Application(SingletonConfigurable):
# { 'key' : ({'Cls' : {'trait' : value}}, 'help')}
flags = {}
for key, (flagdict, help) in self.flags.items():
- newflag: t.Dict[t.Any, t.Any] = {}
- for cls, subdict in flagdict.items(): # type:ignore
+ newflag: dict[t.Any, t.Any] = {}
+ for cls, subdict in flagdict.items():
children = mro_tree[cls] # type:ignore[index]
# exactly one descendent, promote flag section
if len(children) == 1:
@@ -782,18 +774,24 @@ class Application(SingletonConfigurable):
newflag[cls] = subdict
if not isinstance(key, tuple):
- key = (key,)
+ key = (key,) # type:ignore[assignment]
for k in key:
flags[k] = (newflag, help)
return flags, aliases
- def _create_loader(self, argv, aliases, flags, classes):
+ def _create_loader(
+ self,
+ argv: list[str] | None,
+ aliases: StrDict,
+ flags: StrDict,
+ classes: ClassesType | None,
+ ) -> KVArgParseConfigLoader:
return KVArgParseConfigLoader(
argv, aliases, flags, classes=classes, log=self.log, subcommands=self.subcommands
)
@classmethod
- def _get_sys_argv(cls, check_argcomplete: bool = False) -> t.List[str]:
+ def _get_sys_argv(cls, check_argcomplete: bool = False) -> list[str]:
"""Get `sys.argv` or equivalent from `argcomplete`
`argcomplete`'s strategy is to call the python script with no arguments,
@@ -819,7 +817,7 @@ class Application(SingletonConfigurable):
return sys.argv
@classmethod
- def _handle_argcomplete_for_subcommand(cls):
+ def _handle_argcomplete_for_subcommand(cls) -> None:
"""Helper for `argcomplete` to recognize `traitlets` subcommands
`argcomplete` does not know that `traitlets` has already consumed subcommands,
@@ -839,7 +837,7 @@ class Application(SingletonConfigurable):
pass
@catch_config_error
- def parse_command_line(self, argv=None):
+ def parse_command_line(self, argv: ArgvType = None) -> None:
"""Parse the command line arguments."""
assert not isinstance(argv, str)
if argv is None:
@@ -877,7 +875,7 @@ class Application(SingletonConfigurable):
# flatten flags&aliases, so cl-args get appropriate priority:
flags, aliases = self.flatten_flags()
- classes = tuple(self._classes_with_config_traits())
+ classes = list(self._classes_with_config_traits())
loader = self._create_loader(argv, aliases, flags, classes=classes)
try:
self.cli_config = deepcopy(loader.load_config())
@@ -890,13 +888,18 @@ class Application(SingletonConfigurable):
self.extra_args = loader.extra_args
@classmethod
- def _load_config_files(cls, basefilename, path=None, log=None, raise_config_file_errors=False):
+ def _load_config_files(
+ cls,
+ basefilename: str,
+ path: str | t.Sequence[str | None] | None,
+ log: AnyLogger | None = None,
+ raise_config_file_errors: bool = False,
+ ) -> t.Generator[t.Any, None, None]:
"""Load config files (py,json) by filename and path.
yield each config object in turn.
"""
-
- if not isinstance(path, list):
+ if isinstance(path, str) or path is None:
path = [path]
for current in reversed(path):
# path list is in descending priority order, so load files backwards:
@@ -904,8 +907,8 @@ class Application(SingletonConfigurable):
if log:
log.debug("Looking for %s in %s", basefilename, current or os.getcwd())
jsonloader = cls.json_config_loader_class(basefilename + ".json", path=current, log=log)
- loaded: t.List[t.Any] = []
- filenames: t.List[str] = []
+ loaded: list[t.Any] = []
+ filenames: list[str] = []
for loader in [pyloader, jsonloader]:
config = None
try:
@@ -941,12 +944,14 @@ class Application(SingletonConfigurable):
filenames.append(loader.full_filename)
@property
- def loaded_config_files(self):
+ def loaded_config_files(self) -> list[str]:
"""Currently loaded configuration files"""
return self._loaded_config_files[:]
@catch_config_error
- def load_config_file(self, filename, path=None):
+ def load_config_file(
+ self, filename: str, path: str | t.Sequence[str | None] | None = None
+ ) -> None:
"""Load config files by filename and path."""
filename, ext = os.path.splitext(filename)
new_config = Config()
@@ -965,7 +970,9 @@ class Application(SingletonConfigurable):
new_config.merge(self.cli_config)
self.update_config(new_config)
- def _classes_with_config_traits(self, classes=None):
+ def _classes_with_config_traits(
+ self, classes: ClassesType | None = None
+ ) -> t.Generator[type[Configurable], None, None]:
"""
Yields only classes with configurable traits, and their subclasses.
@@ -987,7 +994,7 @@ class Application(SingletonConfigurable):
for cls in self._classes_inc_parents(classes)
)
- def is_any_parent_included(cls):
+ def is_any_parent_included(cls: t.Any) -> bool:
return any(b in cls_to_config and cls_to_config[b] for b in cls.__bases__)
# Mark "empty" classes for inclusion if their parents own-traits,
@@ -1005,7 +1012,7 @@ class Application(SingletonConfigurable):
if inc_yes:
yield cl
- def generate_config_file(self, classes=None):
+ def generate_config_file(self, classes: ClassesType | None = None) -> str:
"""generate default config file from Configurables"""
lines = ["# Configuration file for %s." % self.name]
lines.append("")
@@ -1017,7 +1024,7 @@ class Application(SingletonConfigurable):
lines.append(cls.class_config_section(config_classes))
return "\n".join(lines)
- def close_handlers(self):
+ def close_handlers(self) -> None:
if getattr(self, "_logging_configured", False):
# don't attempt to close handlers unless they have been opened
# (note accessing self.log.handlers will create handlers if they
@@ -1027,16 +1034,16 @@ class Application(SingletonConfigurable):
handler.close()
self._logging_configured = False
- def exit(self, exit_status=0):
+ def exit(self, exit_status: int | str | None = 0) -> None:
self.log.debug("Exiting application: %s" % self.name)
self.close_handlers()
sys.exit(exit_status)
- def __del__(self):
+ def __del__(self) -> None:
self.close_handlers()
@classmethod
- def launch_instance(cls, argv=None, **kwargs):
+ def launch_instance(cls, argv: ArgvType = None, **kwargs: t.Any) -> None:
"""Launch a global instance of this Application
If a global instance already exists, this reinitializes and starts it
@@ -1054,7 +1061,7 @@ default_aliases = Application.aliases
default_flags = Application.flags
-def boolean_flag(name, configurable, set_help="", unset_help=""):
+def boolean_flag(name: str, configurable: str, set_help: str = "", unset_help: str = "") -> StrDict:
"""Helper for building basic --trait, --no-trait flags.
Parameters
@@ -1085,7 +1092,7 @@ def boolean_flag(name, configurable, set_help="", unset_help=""):
return {name: (setter, set_help), "no-" + name: (unsetter, unset_help)}
-def get_config():
+def get_config() -> Config:
"""Get the config object for the global Application instance, if there is one
otherwise return an empty config object
diff --git a/contrib/python/traitlets/py3/traitlets/config/argcomplete_config.py b/contrib/python/traitlets/py3/traitlets/config/argcomplete_config.py
index ee1e51b4924..82112aaf6b3 100644
--- a/contrib/python/traitlets/py3/traitlets/config/argcomplete_config.py
+++ b/contrib/python/traitlets/py3/traitlets/config/argcomplete_config.py
@@ -15,7 +15,7 @@ except ImportError:
# This module and its utility methods are written to not crash even
# if argcomplete is not installed.
class StubModule:
- def __getattr__(self, attr):
+ def __getattr__(self, attr: str) -> t.Any:
if not attr.startswith("__"):
raise ModuleNotFoundError("No module named 'argcomplete'")
raise AttributeError(f"argcomplete stub module has no attribute '{attr}'")
@@ -63,7 +63,7 @@ def get_argcomplete_cwords() -> t.Optional[t.List[str]]:
return comp_words
-def increment_argcomplete_index():
+def increment_argcomplete_index() -> None:
"""Assumes ``$_ARGCOMPLETE`` is set and `argcomplete` is importable
Increment the index pointed to by ``$_ARGCOMPLETE``, which is used to
@@ -122,7 +122,7 @@ class ExtendedCompletionFinder(CompletionFinder):
]
return matched_completions
- def inject_class_to_parser(self, cls):
+ def inject_class_to_parser(self, cls: t.Any) -> None:
"""Add dummy arguments to our ArgumentParser for the traits of this class
The argparse-based loader currently does not actually add any class traits to
diff --git a/contrib/python/traitlets/py3/traitlets/config/configurable.py b/contrib/python/traitlets/py3/traitlets/config/configurable.py
index f448e696b8e..77b4214e452 100644
--- a/contrib/python/traitlets/py3/traitlets/config/configurable.py
+++ b/contrib/python/traitlets/py3/traitlets/config/configurable.py
@@ -2,7 +2,7 @@
# Copyright (c) IPython Development Team.
# Distributed under the terms of the Modified BSD License.
-
+from __future__ import annotations
import logging
import typing as t
@@ -15,12 +15,14 @@ from traitlets.traitlets import (
Dict,
HasTraits,
Instance,
+ TraitType,
default,
observe,
observe_compat,
validate,
)
from traitlets.utils import warnings
+from traitlets.utils.bunch import Bunch
from traitlets.utils.text import indent, wrap_paragraphs
from .loader import Config, DeferredConfig, LazyConfigValue, _is_section_key
@@ -29,6 +31,11 @@ from .loader import Config, DeferredConfig, LazyConfigValue, _is_section_key
# Helper classes for Configurables
# -----------------------------------------------------------------------------
+if t.TYPE_CHECKING:
+ LoggerType = t.Union[logging.Logger, logging.LoggerAdapter[t.Any]]
+else:
+ LoggerType = t.Any
+
class ConfigurableError(Exception):
pass
@@ -87,7 +94,7 @@ class Configurable(HasTraits):
# record traits set by config
config_override_names = set()
- def notice_config_override(change):
+ def notice_config_override(change: Bunch) -> None:
"""Record traits set by both config and kwargs.
They will need to be overridden again after loading config.
@@ -120,7 +127,7 @@ class Configurable(HasTraits):
# -------------------------------------------------------------------------
@classmethod
- def section_names(cls):
+ def section_names(cls) -> list[str]:
"""return section names as a list"""
return [
c.__name__
@@ -128,7 +135,7 @@ class Configurable(HasTraits):
if issubclass(c, Configurable) and issubclass(cls, c)
]
- def _find_my_config(self, cfg):
+ def _find_my_config(self, cfg: Config) -> t.Any:
"""extract my config from a global Config object
will construct a Config object of only the config values that apply to me
@@ -153,7 +160,9 @@ class Configurable(HasTraits):
my_config.merge(c[sname])
return my_config
- def _load_config(self, cfg, section_names=None, traits=None):
+ def _load_config(
+ self, cfg: Config, section_names: list[str] | None = None, traits: list[str] | None = None
+ ) -> None:
"""load traits from a Config object"""
if traits is None:
@@ -187,7 +196,7 @@ class Configurable(HasTraits):
warn = self.log.warning
else:
- def warn(msg):
+ def warn(msg: t.Any) -> None:
return warnings.warn(msg, UserWarning, stacklevel=9)
matches = get_close_matches(name, traits)
@@ -203,7 +212,7 @@ class Configurable(HasTraits):
@observe("config")
@observe_compat
- def _config_changed(self, change):
+ def _config_changed(self, change: Bunch) -> None:
"""Update all the class traits having ``config=True`` in metadata.
For any class trait with a ``config`` metadata attribute that is
@@ -219,7 +228,7 @@ class Configurable(HasTraits):
section_names = self.section_names()
self._load_config(change.new, traits=traits, section_names=section_names)
- def update_config(self, config):
+ def update_config(self, config: Config) -> None:
"""Update config and load the new values"""
# traitlets prior to 4.2 created a copy of self.config in order to trigger change events.
# Some projects (IPython < 5) relied upon one side effect of this,
@@ -236,7 +245,7 @@ class Configurable(HasTraits):
# DO NOT trigger full trait-change
@classmethod
- def class_get_help(cls, inst=None):
+ def class_get_help(cls, inst: HasTraits | None = None) -> str:
"""Get the help string for this class in ReST format.
If `inst` is given, its current trait values will be used in place of
@@ -253,7 +262,12 @@ class Configurable(HasTraits):
return "\n".join(final_help)
@classmethod
- def class_get_trait_help(cls, trait, inst=None, helptext=None):
+ def class_get_trait_help(
+ cls,
+ trait: TraitType[t.Any, t.Any],
+ inst: HasTraits | None = None,
+ helptext: str | None = None,
+ ) -> str:
"""Get the helptext string for a single trait.
:param inst:
@@ -291,7 +305,7 @@ class Configurable(HasTraits):
lines.append(indent("Choices: %s" % trait.info()))
if inst is not None:
- lines.append(indent(f"Current: {getattr(inst, trait.name)!r}"))
+ lines.append(indent(f"Current: {getattr(inst, trait.name or '')!r}"))
else:
try:
dvr = trait.default_value_repr()
@@ -305,12 +319,14 @@ class Configurable(HasTraits):
return "\n".join(lines)
@classmethod
- def class_print_help(cls, inst=None):
+ def class_print_help(cls, inst: HasTraits | None = None) -> None:
"""Get the help string for a single trait and print it."""
print(cls.class_get_help(inst))
@classmethod
- def _defining_class(cls, trait, classes):
+ def _defining_class(
+ cls, trait: TraitType[t.Any, t.Any], classes: t.Sequence[type[HasTraits]]
+ ) -> type[Configurable]:
"""Get the class that defines a trait
For reducing redundant help output in config files.
@@ -338,7 +354,7 @@ class Configurable(HasTraits):
return defining_cls
@classmethod
- def class_config_section(cls, classes=None):
+ def class_config_section(cls, classes: t.Sequence[type[HasTraits]] | None = None) -> str:
"""Get the config section for this class.
Parameters
@@ -348,7 +364,7 @@ class Configurable(HasTraits):
Used to reduce redundant information.
"""
- def c(s):
+ def c(s: str) -> str:
"""return a commented, wrapped block."""
s = "\n\n".join(wrap_paragraphs(s, 78))
@@ -398,7 +414,7 @@ class Configurable(HasTraits):
return "\n".join(lines)
@classmethod
- def class_config_rst_doc(cls):
+ def class_config_rst_doc(cls) -> str:
"""Generate rST documentation for this class' config options.
Excludes traits defined on parent classes.
@@ -447,10 +463,10 @@ class LoggingConfigurable(Configurable):
is to get the logger from the currently running Application.
"""
- log = Any(help="Logger or LoggerAdapter instance")
+ log = Any(help="Logger or LoggerAdapter instance", allow_none=False)
@validate("log")
- def _validate_log(self, proposal):
+ def _validate_log(self, proposal: Bunch) -> LoggerType:
if not isinstance(proposal.value, (logging.Logger, logging.LoggerAdapter)):
# warn about unsupported type, but be lenient to allow for duck typing
warnings.warn(
@@ -459,18 +475,18 @@ class LoggingConfigurable(Configurable):
UserWarning,
stacklevel=2,
)
- return proposal.value
+ return proposal.value # type:ignore[no-any-return]
@default("log")
- def _log_default(self):
+ def _log_default(self) -> LoggerType:
if isinstance(self.parent, LoggingConfigurable):
assert self.parent is not None
- return self.parent.log
+ return t.cast(logging.Logger, self.parent.log)
from traitlets import log
return log.get_logger()
- def _get_log_handler(self):
+ def _get_log_handler(self) -> logging.Handler | None:
"""Return the default Handler
Returns None if none can be found
@@ -478,13 +494,16 @@ class LoggingConfigurable(Configurable):
Deprecated, this now returns the first log handler which may or may
not be the default one.
"""
- logger = self.log
- if isinstance(logger, logging.LoggerAdapter):
- logger = logger.logger
+ if not self.log:
+ return None
+ logger = self.log if isinstance(self.log, logging.Logger) else self.log.logger
if not getattr(logger, "handlers", None):
# no handlers attribute or empty handlers list
return None
- return logger.handlers[0]
+ return logger.handlers[0] # type:ignore[no-any-return]
+
+
+CT = t.TypeVar('CT', bound='SingletonConfigurable')
class SingletonConfigurable(LoggingConfigurable):
@@ -498,7 +517,7 @@ class SingletonConfigurable(LoggingConfigurable):
_instance = None
@classmethod
- def _walk_mro(cls):
+ def _walk_mro(cls) -> t.Generator[type[SingletonConfigurable], None, None]:
"""Walk the cls.mro() for parent classes that are also singletons
For use in instance()
@@ -513,7 +532,7 @@ class SingletonConfigurable(LoggingConfigurable):
yield subclass
@classmethod
- def clear_instance(cls):
+ def clear_instance(cls) -> None:
"""unset _instance for this class and singleton parents."""
if not cls.initialized():
return
@@ -524,7 +543,7 @@ class SingletonConfigurable(LoggingConfigurable):
subclass._instance = None
@classmethod
- def instance(cls, *args, **kwargs):
+ def instance(cls: type[CT], *args: t.Any, **kwargs: t.Any) -> CT:
"""Returns a global instance of this class.
This method create a new instance if none have previously been created
@@ -568,6 +587,6 @@ class SingletonConfigurable(LoggingConfigurable):
)
@classmethod
- def initialized(cls):
+ def initialized(cls) -> bool:
"""Has an instance been created?"""
return hasattr(cls, "_instance") and cls._instance is not None
diff --git a/contrib/python/traitlets/py3/traitlets/config/loader.py b/contrib/python/traitlets/py3/traitlets/config/loader.py
index 34d62e5a502..437c8c17cda 100644
--- a/contrib/python/traitlets/py3/traitlets/config/loader.py
+++ b/contrib/python/traitlets/py3/traitlets/config/loader.py
@@ -2,6 +2,7 @@
# Copyright (c) IPython Development Team.
# Distributed under the terms of the Modified BSD License.
+# ruff: noqa: ANN201, ANN001, ANN204, ANN102, ANN003, ANN206, ANN002
from __future__ import annotations
import argparse
@@ -50,10 +51,10 @@ class ArgumentError(ConfigLoaderError):
class _Sentinel:
- def __repr__(self):
+ def __repr__(self) -> str:
return "<Sentinel deprecated>"
- def __str__(self):
+ def __str__(self) -> str:
return "<deprecated>"
@@ -208,7 +209,7 @@ class LazyConfigValue(HasTraits):
d["inserts"] = self._inserts
return d
- def __repr__(self):
+ def __repr__(self) -> str:
if self._value is not None:
return f"<{self.__class__.__name__} value={self._value!r}>"
else:
@@ -294,7 +295,7 @@ class Config(dict): # type:ignore[type-arg]
collisions[section][key] = f"{mine[key]!r} ignored, using {theirs[key]!r}"
return collisions
- def __contains__(self, key):
+ def __contains__(self, key: t.Any) -> bool:
# allow nested contains of the form `"Section.key" in config`
if "." in key:
first, remainder = key.split(".", 1)
@@ -344,7 +345,7 @@ class Config(dict): # type:ignore[type-arg]
else:
raise
- def __setitem__(self, key, value):
+ def __setitem__(self, key: str, value: t.Any) -> None:
if _is_section_key(key):
if not isinstance(value, Config):
raise ValueError(
@@ -361,7 +362,7 @@ class Config(dict): # type:ignore[type-arg]
except KeyError as e:
raise AttributeError(e) from e
- def __setattr__(self, key, value):
+ def __setattr__(self, key: str, value: t.Any) -> None:
if key.startswith("__"):
return dict.__setattr__(self, key, value)
try:
@@ -369,7 +370,7 @@ class Config(dict): # type:ignore[type-arg]
except KeyError as e:
raise AttributeError(e) from e
- def __delattr__(self, key):
+ def __delattr__(self, key: str) -> None:
if key.startswith("__"):
return dict.__delattr__(self, key)
try:
@@ -420,7 +421,7 @@ class DeferredConfigString(str, DeferredConfig):
# this will raise a more informative error when config is loaded.
return s
- def __repr__(self):
+ def __repr__(self) -> str:
return f"{self.__class__.__name__}({self._super_repr()})"
@@ -462,7 +463,7 @@ class DeferredConfigList(list, DeferredConfig): # type:ignore[type-arg]
# this will raise a more informative error when config is loaded.
return src
- def __repr__(self):
+ def __repr__(self) -> str:
return f"{self.__class__.__name__}({self._super_repr()})"
@@ -749,7 +750,7 @@ class _DefaultOptionDict(dict): # type:ignore[type-arg]
metavar=key.lstrip("-"),
)
- def __contains__(self, key):
+ def __contains__(self, key: t.Any) -> bool:
if "=" in key:
return False
if super().__contains__(key):
@@ -785,7 +786,6 @@ class _KVArgParser(argparse.ArgumentParser):
# type aliases
-Flags = t.Union[str, t.Tuple[str, ...]]
SubcommandsDict = t.Dict[str, t.Any]
@@ -797,8 +797,8 @@ class ArgParseConfigLoader(CommandLineConfigLoader):
def __init__(
self,
argv: list[str] | None = None,
- aliases: dict[Flags, str] | None = None,
- flags: dict[Flags, str] | None = None,
+ aliases: dict[str, str] | None = None,
+ flags: dict[str, str] | None = None,
log: t.Any = None,
classes: list[type[t.Any]] | None = None,
subcommands: SubcommandsDict | None = None,
@@ -915,7 +915,7 @@ class ArgParseConfigLoader(CommandLineConfigLoader):
if alias in self.flags:
continue
if not isinstance(alias, tuple):
- alias = (alias,)
+ alias = (alias,) # type:ignore[assignment]
for al in alias:
if len(al) == 1:
unpacked_aliases["-" + al] = "--" + alias_target
diff --git a/contrib/python/traitlets/py3/traitlets/config/manager.py b/contrib/python/traitlets/py3/traitlets/config/manager.py
index 728cd2f22cc..9102544e509 100644
--- a/contrib/python/traitlets/py3/traitlets/config/manager.py
+++ b/contrib/python/traitlets/py3/traitlets/config/manager.py
@@ -2,15 +2,18 @@
"""
# Copyright (c) IPython Development Team.
# Distributed under the terms of the Modified BSD License.
+from __future__ import annotations
+
import errno
import json
import os
+from typing import Any
from traitlets.config import LoggingConfigurable
from traitlets.traitlets import Unicode
-def recursive_update(target, new):
+def recursive_update(target: dict[Any, Any], new: dict[Any, Any]) -> None:
"""Recursively update one dictionary using another.
None values will delete their keys.
@@ -39,17 +42,17 @@ class BaseJSONConfigManager(LoggingConfigurable):
config_dir = Unicode(".")
- def ensure_config_dir_exists(self):
+ def ensure_config_dir_exists(self) -> None:
try:
os.makedirs(self.config_dir, 0o755)
except OSError as e:
if e.errno != errno.EEXIST:
raise
- def file_name(self, section_name):
+ def file_name(self, section_name: str) -> str:
return os.path.join(self.config_dir, section_name + ".json")
- def get(self, section_name):
+ def get(self, section_name: str) -> Any:
"""Retrieve the config data for the specified section.
Returns the data as a dictionary, or an empty dictionary if the file
@@ -62,7 +65,7 @@ class BaseJSONConfigManager(LoggingConfigurable):
else:
return {}
- def set(self, section_name, data):
+ def set(self, section_name: str, data: Any) -> None:
"""Store the given config data."""
filename = self.file_name(section_name)
self.ensure_config_dir_exists()
@@ -71,7 +74,7 @@ class BaseJSONConfigManager(LoggingConfigurable):
with f:
json.dump(data, f, indent=2)
- def update(self, section_name, new_data):
+ def update(self, section_name: str, new_data: Any) -> Any:
"""Modify the config section by recursively updating it with new_data.
Returns the modified config data as a dictionary.
diff --git a/contrib/python/traitlets/py3/traitlets/config/sphinxdoc.py b/contrib/python/traitlets/py3/traitlets/config/sphinxdoc.py
index a69d89f9e48..300c0a0b03d 100644
--- a/contrib/python/traitlets/py3/traitlets/config/sphinxdoc.py
+++ b/contrib/python/traitlets/py3/traitlets/config/sphinxdoc.py
@@ -32,6 +32,7 @@ The generated rST syntax looks like this::
Cross reference like this: :configtrait:`Application.log_datefmt`.
"""
+# ruff: noqa: ANN201, ANN001, ANN204, ANN102, ANN003, ANN206, ANN002
from collections import defaultdict
from textwrap import dedent
diff --git a/contrib/python/traitlets/py3/traitlets/log.py b/contrib/python/traitlets/py3/traitlets/log.py
index 468c7c3c24e..d90a9c5284c 100644
--- a/contrib/python/traitlets/py3/traitlets/log.py
+++ b/contrib/python/traitlets/py3/traitlets/log.py
@@ -5,11 +5,12 @@
from __future__ import annotations
import logging
+from typing import Any
-_logger: logging.Logger | None = None
+_logger: logging.Logger | logging.LoggerAdapter[Any] | None = None
-def get_logger() -> logging.Logger:
+def get_logger() -> logging.Logger | logging.LoggerAdapter[Any]:
"""Grab the global logger instance.
If a global Application is instantiated, grab its logger.
diff --git a/contrib/python/traitlets/py3/traitlets/tests/utils.py b/contrib/python/traitlets/py3/traitlets/tests/utils.py
index c39d86942a5..9552a5c786c 100644
--- a/contrib/python/traitlets/py3/traitlets/tests/utils.py
+++ b/contrib/python/traitlets/py3/traitlets/tests/utils.py
@@ -1,20 +1,23 @@
+from __future__ import annotations
+
import sys
from subprocess import PIPE, Popen
-import os
+from typing import Any, Sequence
-def get_output_error_code(cmd):
+def get_output_error_code(cmd: str | Sequence[str]) -> tuple[str, str, Any]:
"""Get stdout, stderr, and exit code from running a command"""
+ import os
env = os.environ.copy()
env["Y_PYTHON_ENTRY_POINT"] = ":main"
p = Popen(cmd, stdout=PIPE, stderr=PIPE, env=env) # noqa
out, err = p.communicate()
- out = out.decode("utf8", "replace") # type:ignore
- err = err.decode("utf8", "replace") # type:ignore
- return out, err, p.returncode
+ out_str = out.decode("utf8", "replace")
+ err_str = err.decode("utf8", "replace")
+ return out_str, err_str, p.returncode
-def check_help_output(pkg, subcommand=None):
+def check_help_output(pkg: str, subcommand: Sequence[str] | None = None) -> tuple[str, str]:
"""test that `python -m PKG [subcommand] -h` works"""
cmd = [sys.executable, "-m", pkg]
if subcommand:
@@ -28,7 +31,7 @@ def check_help_output(pkg, subcommand=None):
return out, err
-def check_help_all_output(pkg, subcommand=None):
+def check_help_all_output(pkg: str, subcommand: Sequence[str] | None = None) -> tuple[str, str]:
"""test that `python -m PKG --help-all` works"""
cmd = [sys.executable, "-m", pkg]
if subcommand:
diff --git a/contrib/python/traitlets/py3/traitlets/traitlets.py b/contrib/python/traitlets/py3/traitlets/traitlets.py
index 036f51aac1d..50d6face52e 100644
--- a/contrib/python/traitlets/py3/traitlets/traitlets.py
+++ b/contrib/python/traitlets/py3/traitlets/traitlets.py
@@ -38,6 +38,9 @@ Inheritance diagram:
#
# Adapted from enthought.traits, Copyright (c) Enthought, Inc.,
# also under the terms of the Modified BSD License.
+
+# ruff: noqa: ANN001, ANN204, ANN201, ANN003, ANN206, ANN002
+
from __future__ import annotations
import contextlib
@@ -213,16 +216,16 @@ def parse_notifier_name(names: Sentinel | str | t.Iterable[Sentinel | str]) -> t
class _SimpleTest:
- def __init__(self, value):
+ def __init__(self, value: t.Any) -> None:
self.value = value
- def __call__(self, test):
- return test == self.value
+ def __call__(self, test: t.Any) -> bool:
+ return bool(test == self.value)
- def __repr__(self):
+ def __repr__(self) -> str:
return "<SimpleTest(%r)" % self.value
- def __str__(self):
+ def __str__(self) -> str:
return self.__repr__()
@@ -294,7 +297,7 @@ class link:
self.link()
- def link(self):
+ def link(self) -> None:
try:
setattr(
self.target[0],
@@ -334,7 +337,7 @@ class link:
f"Broken link {self}: the target value changed while updating " "the source."
)
- def unlink(self):
+ def unlink(self) -> None:
self.source[0].unobserve(self._update_target, names=self.source[1])
self.target[0].unobserve(self._update_source, names=self.target[1])
@@ -378,7 +381,7 @@ class directional_link:
self.source, self.target = source, target
self.link()
- def link(self):
+ def link(self) -> None:
try:
setattr(
self.target[0],
@@ -402,7 +405,7 @@ class directional_link:
with self._busy_updating():
setattr(self.target[0], self.target[1], self._transform(change.new))
- def unlink(self):
+ def unlink(self) -> None:
self.source[0].unobserve(self._update, names=self.source[1])
@@ -1123,7 +1126,7 @@ def observe(*names: Sentinel | str, type: str = "change") -> ObserveHandler:
return ObserveHandler(names, type=type)
-def observe_compat(func):
+def observe_compat(func: FuncT) -> FuncT:
"""Backward-compatibility shim decorator for observers
Use with:
@@ -1137,9 +1140,11 @@ def observe_compat(func):
Allows adoption of new observer API without breaking subclasses that override and super.
"""
- def compatible_observer(self, change_or_name, old=Undefined, new=Undefined):
+ def compatible_observer(
+ self: t.Any, change_or_name: str, old: t.Any = Undefined, new: t.Any = Undefined
+ ) -> t.Any:
if isinstance(change_or_name, dict):
- change = change_or_name
+ change = Bunch(change_or_name)
else:
clsname = self.__class__.__name__
warn(
@@ -1156,7 +1161,7 @@ def observe_compat(func):
)
return func(self, change)
- return compatible_observer
+ return t.cast(FuncT, compatible_observer)
def validate(*names: Sentinel | str) -> ValidateHandler:
@@ -2027,7 +2032,7 @@ class Type(ClassBasedTraitType[G, S]):
@t.overload
def __init__(
- self: Type[object, object],
+ self: Type[type, type],
default_value: Sentinel | None | str = ...,
klass: None | str = ...,
allow_none: Literal[False] = ...,
@@ -2040,8 +2045,8 @@ class Type(ClassBasedTraitType[G, S]):
@t.overload
def __init__(
- self: Type[object | None, object | None],
- default_value: S | Sentinel | None | str = ...,
+ self: Type[type | None, type | None],
+ default_value: Sentinel | None | str = ...,
klass: None | str = ...,
allow_none: Literal[True] = ...,
read_only: bool | None = ...,
@@ -2054,7 +2059,7 @@ class Type(ClassBasedTraitType[G, S]):
@t.overload
def __init__(
self: Type[S, S],
- default_value: S | Sentinel | str = ...,
+ default_value: S = ...,
klass: type[S] = ...,
allow_none: Literal[False] = ...,
read_only: bool | None = ...,
@@ -2067,7 +2072,7 @@ class Type(ClassBasedTraitType[G, S]):
@t.overload
def __init__(
self: Type[S | None, S | None],
- default_value: S | Sentinel | None | str = ...,
+ default_value: S | None = ...,
klass: type[S] = ...,
allow_none: Literal[True] = ...,
read_only: bool | None = ...,
diff --git a/contrib/python/traitlets/py3/traitlets/utils/__init__.py b/contrib/python/traitlets/py3/traitlets/utils/__init__.py
index dfec4ee322e..e8ee7f98561 100644
--- a/contrib/python/traitlets/py3/traitlets/utils/__init__.py
+++ b/contrib/python/traitlets/py3/traitlets/utils/__init__.py
@@ -1,15 +1,18 @@
+from __future__ import annotations
+
import os
import pathlib
+from typing import Sequence
# vestigal things from IPython_genutils.
-def cast_unicode(s, encoding="utf-8"):
+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, path_dirs=None):
+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
@@ -65,7 +68,7 @@ def filefind(filename, path_dirs=None):
raise OSError(f"File {filename!r} does not exist in any of the search paths: {path_dirs!r}")
-def expand_path(s):
+def expand_path(s: str) -> str:
"""Expand $VARS and ~names in a string, like a shell
:Examples:
diff --git a/contrib/python/traitlets/py3/traitlets/utils/bunch.py b/contrib/python/traitlets/py3/traitlets/utils/bunch.py
index 6b3fffeb12a..498563e0b5b 100644
--- a/contrib/python/traitlets/py3/traitlets/utils/bunch.py
+++ b/contrib/python/traitlets/py3/traitlets/utils/bunch.py
@@ -5,21 +5,24 @@ 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):
+ def __getattr__(self, key: str) -> Any:
try:
return self.__getitem__(key)
except KeyError as e:
raise AttributeError(key) from e
- def __setattr__(self, key, value):
+ def __setattr__(self, key: str, value: Any) -> None:
self.__setitem__(key, value)
- def __dir__(self):
+ def __dir__(self) -> list[str]:
# py2-compat: can't use super because dict doesn't have __dir__
names = dir({})
names.extend(self.keys())
diff --git a/contrib/python/traitlets/py3/traitlets/utils/decorators.py b/contrib/python/traitlets/py3/traitlets/utils/decorators.py
index a59e8167b0a..dedbaad193f 100644
--- a/contrib/python/traitlets/py3/traitlets/utils/decorators.py
+++ b/contrib/python/traitlets/py3/traitlets/utils/decorators.py
@@ -2,12 +2,12 @@
import copy
from inspect import Parameter, Signature, signature
-from typing import Type, TypeVar
+from typing import Any, Type, TypeVar
from ..traitlets import HasTraits, Undefined
-def _get_default(value):
+def _get_default(value: Any) -> Any:
"""Get default argument value, given the trait default value."""
return Parameter.empty if value == Undefined else value
diff --git a/contrib/python/traitlets/py3/traitlets/utils/descriptions.py b/contrib/python/traitlets/py3/traitlets/utils/descriptions.py
index 232eb0e728b..c068ecdba5a 100644
--- a/contrib/python/traitlets/py3/traitlets/utils/descriptions.py
+++ b/contrib/python/traitlets/py3/traitlets/utils/descriptions.py
@@ -1,9 +1,18 @@
+from __future__ import annotations
+
import inspect
import re
import types
+from typing import Any
-def describe(article, value, name=None, verbose=False, capital=False):
+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
@@ -110,7 +119,7 @@ def describe(article, value, name=None, verbose=False, capital=False):
)
-def _prefix(value):
+def _prefix(value: Any) -> str:
if isinstance(value, types.MethodType):
name = describe(None, value.__self__, verbose=True) + "."
else:
@@ -122,7 +131,7 @@ def _prefix(value):
return name
-def class_of(value):
+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'.
@@ -133,7 +142,7 @@ def class_of(value):
return class_of(type(value))
-def add_article(name, definite=False, capital=False):
+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 charater.
@@ -164,7 +173,7 @@ def add_article(name, definite=False, capital=False):
return result
-def repr_type(obj):
+def repr_type(obj: Any) -> str:
"""Return a string representation of a value and its type for readable
error messages.
diff --git a/contrib/python/traitlets/py3/traitlets/utils/getargspec.py b/contrib/python/traitlets/py3/traitlets/utils/getargspec.py
index e2b1f235c83..7cbc82659c4 100644
--- a/contrib/python/traitlets/py3/traitlets/utils/getargspec.py
+++ b/contrib/python/traitlets/py3/traitlets/utils/getargspec.py
@@ -7,14 +7,14 @@
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
-
import inspect
from functools import partial
+from typing import Any
# Unmodified from sphinx below this line
-def getargspec(func):
+def getargspec(func: Any) -> inspect.FullArgSpec:
"""Like inspect.getargspec but supports functools.partial as well."""
if inspect.ismethod(func):
func = func.__func__
diff --git a/contrib/python/traitlets/py3/traitlets/utils/nested_update.py b/contrib/python/traitlets/py3/traitlets/utils/nested_update.py
index 7f09e171a31..37e2d27cd20 100644
--- a/contrib/python/traitlets/py3/traitlets/utils/nested_update.py
+++ b/contrib/python/traitlets/py3/traitlets/utils/nested_update.py
@@ -1,8 +1,9 @@
# Copyright (c) IPython Development Team.
# Distributed under the terms of the Modified BSD License.
+from typing import Any, Dict
-def nested_update(this, that):
+def nested_update(this: Dict[Any, Any], that: Dict[Any, Any]) -> Dict[Any, Any]:
"""Merge two nested dictionaries.
Effectively a recursive ``dict.update``.
diff --git a/contrib/python/traitlets/py3/traitlets/utils/text.py b/contrib/python/traitlets/py3/traitlets/utils/text.py
index c7d49edece6..72ad98fc2ae 100644
--- a/contrib/python/traitlets/py3/traitlets/utils/text.py
+++ b/contrib/python/traitlets/py3/traitlets/utils/text.py
@@ -9,7 +9,7 @@ from textwrap import indent as _indent
from typing import List
-def indent(val):
+def indent(val: str) -> str:
res = _indent(val, " ")
return res
diff --git a/contrib/python/traitlets/py3/ya.make b/contrib/python/traitlets/py3/ya.make
index 2d9cfeae1b0..ff8ebca152a 100644
--- a/contrib/python/traitlets/py3/ya.make
+++ b/contrib/python/traitlets/py3/ya.make
@@ -4,7 +4,7 @@ PY3_LIBRARY()
PROVIDES(python_traitlets)
-VERSION(5.10.1)
+VERSION(5.11.2)
LICENSE(BSD-3-Clause)
@@ -23,7 +23,6 @@ PY_SRCS(
traitlets/config/sphinxdoc.py
traitlets/log.py
traitlets/tests/__init__.py
- traitlets/tests/_warnings.py
traitlets/tests/utils.py
traitlets/traitlets.py
traitlets/utils/__init__.py