diff options
author | robot-contrib <robot-contrib@yandex-team.com> | 2023-11-14 19:18:35 +0300 |
---|---|---|
committer | robot-contrib <robot-contrib@yandex-team.com> | 2023-11-14 20:27:03 +0300 |
commit | 4eb8b66b95f8ec1535b20a7da702a992b07671ca (patch) | |
tree | de40079b443e5d159d7b199ad9ee4e22a26ae97c | |
parent | 874ef51d3d3edfa25f5a505ec6ab50e172965d1e (diff) | |
download | ydb-4eb8b66b95f8ec1535b20a7da702a992b07671ca.tar.gz |
Update contrib/python/traitlets/py3 to 5.13.0
13 files changed, 583 insertions, 464 deletions
diff --git a/contrib/python/traitlets/py3/.dist-info/METADATA b/contrib/python/traitlets/py3/.dist-info/METADATA index 8d2ecd4ba3..2e66ab27bc 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.12.0 +Version: 5.13.0 Summary: Traitlets Python configuration system Project-URL: Homepage, https://github.com/ipython/traitlets Project-URL: Documentation, https://traitlets.readthedocs.io diff --git a/contrib/python/traitlets/py3/tests/config/test_application.py b/contrib/python/traitlets/py3/tests/config/test_application.py index 94427d6b38..61ad751c6b 100644 --- a/contrib/python/traitlets/py3/tests/config/test_application.py +++ b/contrib/python/traitlets/py3/tests/config/test_application.py @@ -130,7 +130,7 @@ class TestApplication(TestCase): self.assertEqual(app.config_file, "") def test_app_name_set_via_constructor(self): - app = MyApp(name='set_via_constructor') + app = MyApp(name="set_via_constructor") assert app.name == "set_via_constructor" def test_mro_discovery(self): diff --git a/contrib/python/traitlets/py3/tests/config/test_argcomplete.py b/contrib/python/traitlets/py3/tests/config/test_argcomplete.py index 52ed6d2bb2..0cd992c612 100644 --- a/contrib/python/traitlets/py3/tests/config/test_argcomplete.py +++ b/contrib/python/traitlets/py3/tests/config/test_argcomplete.py @@ -133,21 +133,21 @@ class TestArgcomplete: def test_complete_simple_app(self, argcomplete_on): app = ArgcompleteApp() expected = [ - '--help', - '--debug', - '--show-config', - '--show-config-json', - '--log-level', - '--Application.', - '--ArgcompleteApp.', + "--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', + "--Application.show_config", + "--Application.log_level", + "--Application.log_format", } def test_complete_custom_completers(self, argcomplete_on): @@ -195,9 +195,9 @@ class TestArgcomplete: app = MainApp() try: assert set(self.run_completer(app, "app subapp1 --Sub")) > { - '--SubApp1.show_config', - '--SubApp1.log_level', - '--SubApp1.log_format', + "--SubApp1.show_config", + "--SubApp1.log_level", + "--SubApp1.log_format", } finally: SubApp1.clear_instance() @@ -206,8 +206,8 @@ class TestArgcomplete: app = MainApp() try: assert set(self.run_completer(app, "app subapp2 --")) > { - '--Application.', - '--SubApp2.', + "--Application.", + "--SubApp2.", } finally: SubApp2.clear_instance() @@ -215,5 +215,5 @@ class TestArgcomplete: def test_complete_subcommands_main(self, argcomplete_on): app = MainApp() completions = set(self.run_completer(app, "app --")) - assert completions > {'--Application.', '--MainApp.'} + assert completions > {"--Application.", "--MainApp."} assert "--SubApp1." not in completions and "--SubApp2." not in completions diff --git a/contrib/python/traitlets/py3/tests/test_typing.py b/contrib/python/traitlets/py3/tests/test_typing.py index 2b4073ecf7..04f027af12 100644 --- a/contrib/python/traitlets/py3/tests/test_typing.py +++ b/contrib/python/traitlets/py3/tests/test_typing.py @@ -1,6 +1,8 @@ from __future__ import annotations -import typing +import logging +import typing as t +from abc import ABC import pytest @@ -9,6 +11,7 @@ from traitlets import ( Bool, CInt, Dict, + Enum, HasTraits, Instance, Int, @@ -24,9 +27,9 @@ from traitlets import ( ) from traitlets.config import Config -if not typing.TYPE_CHECKING: +if not t.TYPE_CHECKING: - def reveal_type(*args, **kwargs): + def reveal_type(*args: t.Any, **kwargs: t.Any) -> None: pass @@ -34,12 +37,12 @@ if not typing.TYPE_CHECKING: class Foo: - def __init__(self, c): + def __init__(self, c: t.Any) -> None: self.c = c @pytest.mark.mypy_testing -def mypy_decorator_typing(): +def mypy_decorator_typing() -> None: class T(HasTraits): foo = Unicode("").tag(config=True) @@ -48,11 +51,11 @@ def mypy_decorator_typing(): return "hi" @observe("foo") - def _foo_observer(self, change: typing.Any) -> bool: + def _foo_observer(self, change: t.Any) -> bool: return True @validate("foo") - def _foo_validate(self, commit: typing.Any) -> bool: + def _foo_validate(self, commit: t.Any) -> bool: return True t = T() @@ -62,7 +65,7 @@ def mypy_decorator_typing(): @pytest.mark.mypy_testing -def mypy_config_typing(): +def mypy_config_typing() -> None: c = Config( { "ExtractOutputPreprocessor": {"enabled": True}, @@ -72,7 +75,7 @@ def mypy_config_typing(): @pytest.mark.mypy_testing -def mypy_union_typing(): +def mypy_union_typing() -> None: class T(HasTraits): style = Union( [Unicode("default"), Type(klass=object)], @@ -90,40 +93,48 @@ def mypy_union_typing(): @pytest.mark.mypy_testing -def mypy_list_typing(): +def mypy_list_typing() -> None: 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] + reveal_type(List(["foo"])) # R: traitlets.traitlets.List[builtins.str] + reveal_type(List([""]).tag(sync=True)) # R: traitlets.traitlets.List[builtins.str] + reveal_type(List(None, allow_none=True)) # R: traitlets.traitlets.List[<nothing>] + reveal_type( + List(None, allow_none=True).tag(sync=True) # R: traitlets.traitlets.List[<nothing>] + ) + reveal_type(T.latex_command) # R: traitlets.traitlets.List[builtins.str] + reveal_type(t.latex_command) # R: builtins.list[builtins.str] @pytest.mark.mypy_testing -def mypy_dict_typing(): +def mypy_dict_typing() -> None: 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] + reveal_type(Dict(None, allow_none=True)) # R: traitlets.traitlets.Dict[builtins.str, Any] + reveal_type( + Dict(None, allow_none=True).tag(sync=True) # R: traitlets.traitlets.Dict[builtins.str, Any] + ) + reveal_type(T.foo) # R: traitlets.traitlets.Dict[builtins.str, Any] + reveal_type(t.foo) # R: builtins.dict[builtins.str, Any] @pytest.mark.mypy_testing -def mypy_type_typing(): +def mypy_type_typing() -> None: class KernelSpec: item = Unicode("foo") + class KernelSpecSubclass(KernelSpec): + other = Unicode("bar") + + class GatewayTokenRenewerBase(ABC): + item = Unicode("foo") + class KernelSpecManager(HasTraits): """A manager for kernel specs.""" @@ -136,16 +147,34 @@ def mypy_type_typing(): ) other_class = Type("foo.bar.baz") + other_kernel_spec_class = Type( + default_value=KernelSpecSubclass, + klass=KernelSpec, + config=True, + ) + + gateway_token_renewer_class = Type( + klass=GatewayTokenRenewerBase, + config=True, + help="""The class to use for Gateway token renewal. (JUPYTER_GATEWAY_TOKEN_RENEWER_CLASS env var)""", + ) + 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) # R: def () -> tests.test_typing.KernelSpec@129 + reveal_type(t.kernel_spec_class()) # R: tests.test_typing.KernelSpec@129 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 + reveal_type(t.other_kernel_spec_class) # R: def () -> tests.test_typing.KernelSpec@129 + reveal_type(t.other_kernel_spec_class()) # R: tests.test_typing.KernelSpec@129 + reveal_type( + t.gateway_token_renewer_class # R: def () -> tests.test_typing.GatewayTokenRenewerBase@135 + ) + reveal_type(t.gateway_token_renewer_class()) # R: tests.test_typing.GatewayTokenRenewerBase@135 @pytest.mark.mypy_testing -def mypy_unicode_typing(): +def mypy_unicode_typing() -> None: class T(HasTraits): export_format = Unicode( allow_none=False, @@ -163,9 +192,7 @@ def mypy_unicode_typing(): reveal_type( Unicode( # R: traitlets.traitlets.Unicode[builtins.str, Union[builtins.str, builtins.bytes]] "" - ).tag( - sync=True - ) + ).tag(sync=True) ) reveal_type( Unicode( # R: traitlets.traitlets.Unicode[Union[builtins.str, None], Union[builtins.str, builtins.bytes, None]] @@ -175,9 +202,7 @@ def mypy_unicode_typing(): reveal_type( Unicode( # R: traitlets.traitlets.Unicode[Union[builtins.str, None], Union[builtins.str, builtins.bytes, None]] None, allow_none=True - ).tag( - sync=True - ) + ).tag(sync=True) ) reveal_type( T.export_format # R: traitlets.traitlets.Unicode[builtins.str, Union[builtins.str, builtins.bytes]] @@ -186,7 +211,43 @@ def mypy_unicode_typing(): @pytest.mark.mypy_testing -def mypy_set_typing(): +def mypy_enum_typing() -> None: + class T(HasTraits): + log_level = Enum( + (0, 10, 20, 30, 40, 50), + default_value=logging.WARN, + help="Set the log level by value or name.", + ).tag(config=True) + + t = T() + reveal_type( + Enum( # R: traitlets.traitlets.Enum[builtins.str] + ("foo",) + ) + ) + reveal_type( + Enum( # R: traitlets.traitlets.Enum[builtins.str] + [""] + ).tag(sync=True) + ) + reveal_type( + Enum( # R: traitlets.traitlets.Enum[None] + None, allow_none=True + ) + ) + reveal_type( + Enum( # R: traitlets.traitlets.Enum[None] + None, allow_none=True + ).tag(sync=True) + ) + reveal_type( + T.log_level # R: traitlets.traitlets.Enum[builtins.int] + ) + reveal_type(t.log_level) # R: builtins.int + + +@pytest.mark.mypy_testing +def mypy_set_typing() -> None: class T(HasTraits): remove_cell_tags = Set( Unicode(), @@ -222,7 +283,7 @@ def mypy_set_typing(): @pytest.mark.mypy_testing -def mypy_any_typing(): +def mypy_any_typing() -> None: class T(HasTraits): attributes = Any( config=True, @@ -244,7 +305,7 @@ def mypy_any_typing(): @pytest.mark.mypy_testing -def mypy_bool_typing(): +def mypy_bool_typing() -> None: class T(HasTraits): b = Bool(True).tag(sync=True) ob = Bool(None, allow_none=True).tag(sync=True) @@ -266,9 +327,7 @@ def mypy_bool_typing(): reveal_type( Bool( # R: traitlets.traitlets.Bool[Union[builtins.bool, None], Union[builtins.bool, builtins.int, None]] None, allow_none=True - ).tag( - sync=True - ) + ).tag(sync=True) ) reveal_type( T.b # R: traitlets.traitlets.Bool[builtins.bool, Union[builtins.bool, builtins.int]] @@ -287,7 +346,7 @@ def mypy_bool_typing(): @pytest.mark.mypy_testing -def mypy_int_typing(): +def mypy_int_typing() -> None: 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) @@ -318,7 +377,7 @@ def mypy_int_typing(): @pytest.mark.mypy_testing -def mypy_cint_typing(): +def mypy_cint_typing() -> None: class T(HasTraits): i = CInt(42).tag(sync=True) oi = CInt(42, allow_none=True).tag(sync=True) @@ -342,7 +401,7 @@ def mypy_cint_typing(): @pytest.mark.mypy_testing -def mypy_tcp_typing(): +def mypy_tcp_typing() -> None: class T(HasTraits): tcp = TCPAddress() otcp = TCPAddress(None, allow_none=True) @@ -372,7 +431,7 @@ def mypy_tcp_typing(): @pytest.mark.mypy_testing -def mypy_instance_typing(): +def mypy_instance_typing() -> None: class T(HasTraits): inst = Instance(Foo) oinst = Instance(Foo, allow_none=True) diff --git a/contrib/python/traitlets/py3/traitlets/__init__.py b/contrib/python/traitlets/py3/traitlets/__init__.py index 2641c443e9..70ed818aca 100644 --- a/contrib/python/traitlets/py3/traitlets/__init__.py +++ b/contrib/python/traitlets/py3/traitlets/__init__.py @@ -20,7 +20,7 @@ __all__ = [ ] -class Sentinel(traitlets.Sentinel): # type:ignore[name-defined] +class Sentinel(traitlets.Sentinel): # type:ignore[name-defined, misc] 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 aed118ffe6..6c7ba3eff1 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.12.0" +__version__ = "5.13.0" # 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 bf7308dc5e..a62701a504 100644 --- a/contrib/python/traitlets/py3/traitlets/config/application.py +++ b/contrib/python/traitlets/py3/traitlets/config/application.py @@ -199,7 +199,7 @@ class Application(SingletonConfigurable): version: str | Unicode[str, str | bytes] = Unicode("0.0") # the argv used to initialize the application - argv = List() + argv: list[str] | List[str] = List() # Whether failing to load config files should prevent startup raise_config_file_errors = Bool(TRAITLETS_APPLICATION_RAISE_CONFIG_FILE_ERROR) @@ -241,7 +241,7 @@ class Application(SingletonConfigurable): "console": { "class": "logging.StreamHandler", "formatter": "console", - "level": logging.getLevelName(self.log_level), + "level": logging.getLevelName(self.log_level), # type:ignore[arg-type] "stream": "ext://sys.stderr", }, }, @@ -278,7 +278,7 @@ class Application(SingletonConfigurable): # convert log level strings to ints log_level = self.log_level if isinstance(log_level, str): - self.log_level = getattr(logging, log_level) + self.log_level = t.cast(int, getattr(logging, log_level)) self._configure_logging() @observe("log", type="default") @@ -400,7 +400,7 @@ 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: dict[str, t.Any] | Dict = Dict() + subcommands: dict[str, t.Any] | Dict[str, t.Any] = Dict() # parse_command_line will initialize a subapp, if requested subapp = Instance("traitlets.config.application.Application", allow_none=True) @@ -418,7 +418,7 @@ class Application(SingletonConfigurable): """, ) - _loaded_config_files = List() + _loaded_config_files: List[str] = List() show_config = Bool( help="Instead of starting the Application, dump configuration to stdout" diff --git a/contrib/python/traitlets/py3/traitlets/config/argcomplete_config.py b/contrib/python/traitlets/py3/traitlets/config/argcomplete_config.py index 9588b88985..0d63e75fbe 100644 --- a/contrib/python/traitlets/py3/traitlets/config/argcomplete_config.py +++ b/contrib/python/traitlets/py3/traitlets/config/argcomplete_config.py @@ -10,7 +10,7 @@ import typing as t try: import argcomplete - from argcomplete import CompletionFinder + from argcomplete import CompletionFinder # type:ignore[attr-defined] except ImportError: # This module and its utility methods are written to not crash even # if argcomplete is not installed. @@ -45,7 +45,7 @@ def get_argcomplete_cwords() -> t.Optional[t.List[str]]: cword_suffix, comp_words, last_wordbreak_pos, - ) = argcomplete.split_line(comp_line, comp_point) + ) = argcomplete.split_line(comp_line, comp_point) # type:ignore[attr-defined] except ModuleNotFoundError: return None @@ -73,7 +73,7 @@ def increment_argcomplete_index() -> None: os.environ["_ARGCOMPLETE"] = str(int(os.environ["_ARGCOMPLETE"]) + 1) except Exception: try: - argcomplete.debug("Unable to increment $_ARGCOMPLETE", os.environ["_ARGCOMPLETE"]) + argcomplete.debug("Unable to increment $_ARGCOMPLETE", os.environ["_ARGCOMPLETE"]) # type:ignore[attr-defined] except (KeyError, ModuleNotFoundError): pass @@ -188,7 +188,7 @@ class ExtendedCompletionFinder(CompletionFinder): break completions: t.List[str] - completions = super()._get_completions(comp_words, cword_prefix, *args) + completions = super()._get_completions(comp_words, cword_prefix, *args) # type:ignore[no-untyped-call] # For subcommand-handling: it is difficult to get this to work # using argparse subparsers, because the ArgumentParser accepts @@ -196,7 +196,7 @@ class ExtendedCompletionFinder(CompletionFinder): # Instead, check if comp_words only consists of the script, # if so check if any subcommands start with cword_prefix. if self.subcommands and len(comp_words) == 1: - argcomplete.debug("Adding subcommands for", cword_prefix) + argcomplete.debug("Adding subcommands for", cword_prefix) # type:ignore[attr-defined] completions.extend(subc for subc in self.subcommands if subc.startswith(cword_prefix)) return completions @@ -206,7 +206,7 @@ class ExtendedCompletionFinder(CompletionFinder): ) -> t.List[str]: """Overridden to add --Class. completions when appropriate""" completions: t.List[str] - completions = super()._get_option_completions(parser, cword_prefix) + completions = super()._get_option_completions(parser, cword_prefix) # type:ignore[no-untyped-call] if cword_prefix.endswith("."): return completions diff --git a/contrib/python/traitlets/py3/traitlets/config/configurable.py b/contrib/python/traitlets/py3/traitlets/config/configurable.py index 776138f4b3..3e8c868ce0 100644 --- a/contrib/python/traitlets/py3/traitlets/config/configurable.py +++ b/contrib/python/traitlets/py3/traitlets/config/configurable.py @@ -164,7 +164,7 @@ class Configurable(HasTraits): self, cfg: Config, section_names: list[str] | None = None, - traits: dict[str, TraitType] | None = None, + traits: dict[str, TraitType[t.Any, t.Any]] | None = None, ) -> None: """load traits from a Config object""" @@ -481,7 +481,7 @@ class LoggingConfigurable(Configurable): UserWarning, stacklevel=2, ) - return proposal.value # type:ignore[no-any-return] + return t.cast(LoggerType, proposal.value) @default("log") def _log_default(self) -> LoggerType: @@ -502,14 +502,16 @@ class LoggingConfigurable(Configurable): """ if not self.log: return None - logger = self.log if isinstance(self.log, logging.Logger) else self.log.logger + logger: logging.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] # type:ignore[no-any-return] + return logger.handlers[0] -CT = t.TypeVar('CT', bound='SingletonConfigurable') +CT = t.TypeVar("CT", bound="SingletonConfigurable") class SingletonConfigurable(LoggingConfigurable): diff --git a/contrib/python/traitlets/py3/traitlets/config/loader.py b/contrib/python/traitlets/py3/traitlets/config/loader.py index dc0add5704..2b0932a98e 100644 --- a/contrib/python/traitlets/py3/traitlets/config/loader.py +++ b/contrib/python/traitlets/py3/traitlets/config/loader.py @@ -2,7 +2,6 @@ # 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 @@ -13,8 +12,9 @@ import os import re import sys import typing as t +from logging import Logger -from traitlets.traitlets import Any, Container, Dict, HasTraits, List, Undefined +from traitlets.traitlets import Any, Container, Dict, HasTraits, List, TraitType, Undefined from ..utils import cast_unicode, filefind, warnings @@ -64,7 +64,7 @@ _deprecated = _Sentinel() class ArgumentParser(argparse.ArgumentParser): """Simple argparse subclass that prints help to stdout by default.""" - def print_help(self, file=None): + def print_help(self, file: t.Any = None) -> None: if file is None: file = sys.stdout return super().print_help(file) @@ -77,7 +77,7 @@ class ArgumentParser(argparse.ArgumentParser): # ----------------------------------------------------------------------------- -def execfile(fname, glob): +def execfile(fname: str, glob: dict[str, Any]) -> None: with open(fname, "rb") as f: exec(compile(f.read(), fname, "exec"), glob, glob) # noqa @@ -98,23 +98,23 @@ class LazyConfigValue(HasTraits): _value = None # list methods - _extend: List = List() - _prepend: List = List() - _inserts: List = List() + _extend: List[t.Any] = List() + _prepend: List[t.Any] = List() + _inserts: List[t.Any] = List() - def append(self, obj): + def append(self, obj: t.Any) -> None: """Append an item to a List""" self._extend.append(obj) - def extend(self, other): + def extend(self, other: t.Any) -> None: """Extend a list""" self._extend.extend(other) - def prepend(self, other): + def prepend(self, other: t.Any) -> None: """like list.extend, but for the front""" self._prepend[:0] = other - def merge_into(self, other): + def merge_into(self, other: t.Any) -> t.Any: """ Merge with another earlier LazyConfigValue or an earlier container. This is useful when having global system-wide configuration files. @@ -147,7 +147,7 @@ class LazyConfigValue(HasTraits): # other is a container, reify now. return self.get_value(other) - def insert(self, index, other): + def insert(self, index: int, other: t.Any) -> None: if not isinstance(index, int): raise TypeError("An integer is required") self._inserts.append((index, other)) @@ -156,7 +156,7 @@ class LazyConfigValue(HasTraits): # update is used for both dict and set _update = Any() - def update(self, other): + def update(self, other: t.Any) -> None: """Update either a set or dict""" if self._update is None: if isinstance(other, dict): @@ -166,11 +166,11 @@ class LazyConfigValue(HasTraits): self._update.update(other) # set methods - def add(self, obj): + def add(self, obj: t.Any) -> None: """Add an item to a set""" self.update({obj}) - def get_value(self, initial): + def get_value(self, initial: t.Any) -> t.Any: """construct the value from the initial one after applying any insert / extend / update changes @@ -193,7 +193,7 @@ class LazyConfigValue(HasTraits): self._value = value return value - def to_dict(self): + def to_dict(self) -> dict[str, t.Any]: """return JSONable dict form of my data Currently update as dict or set, extend, prepend as lists, and inserts as list of tuples. @@ -216,7 +216,7 @@ class LazyConfigValue(HasTraits): return f"<{self.__class__.__name__} {self.to_dict()!r}>" -def _is_section_key(key): +def _is_section_key(key: str) -> bool: """Is a Config key a section name (does it start with a capital)?""" if key and key[0].upper() == key[0] and not key.startswith("_"): return True @@ -242,7 +242,7 @@ class Config(dict): # type:ignore[type-arg] dict.__init__(self, *args, **kwds) self._ensure_subconfig() - def _ensure_subconfig(self): + def _ensure_subconfig(self) -> None: """ensure that sub-dicts that should be Config objects are casts dicts that are under section keys to Config objects, @@ -253,11 +253,11 @@ class Config(dict): # type:ignore[type-arg] if _is_section_key(key) and isinstance(obj, dict) and not isinstance(obj, Config): setattr(self, key, Config(obj)) - def _merge(self, other): + def _merge(self, other: t.Any) -> None: """deprecated alias, use Config.merge()""" self.merge(other) - def merge(self, other): + def merge(self, other: t.Any) -> None: """merge another config object into this one""" to_update = {} for k, v in other.items(): @@ -308,16 +308,16 @@ class Config(dict): # type:ignore[type-arg] # .has_key is deprecated for dictionaries. has_key = __contains__ - def _has_section(self, key): + def _has_section(self, key: str) -> bool: return _is_section_key(key) and key in self - def copy(self): + def copy(self) -> dict[str, t.Any]: return type(self)(dict.copy(self)) - def __copy__(self): + def __copy__(self) -> dict[str, t.Any]: return self.copy() - def __deepcopy__(self, memo): + def __deepcopy__(self, memo: t.Any) -> Config: new_config = type(self)() for key, value in self.items(): if isinstance(value, (Config, LazyConfigValue)): @@ -329,7 +329,7 @@ class Config(dict): # type:ignore[type-arg] new_config[key] = value return new_config - def __getitem__(self, key): + def __getitem__(self, key: str) -> t.Any: try: return dict.__getitem__(self, key) except KeyError: @@ -354,7 +354,7 @@ class Config(dict): # type:ignore[type-arg] ) dict.__setitem__(self, key, value) - def __getattr__(self, key): + def __getattr__(self, key: str) -> t.Any: if key.startswith("__"): return dict.__getattr__(self, key) # type:ignore[attr-defined] try: @@ -384,10 +384,10 @@ class DeferredConfig: pass - def get_value(self, trait): + def get_value(self, trait: TraitType[t.Any, t.Any]) -> t.Any: raise NotImplementedError("Implement in subclasses") - def _super_repr(self): + def _super_repr(self) -> str: # explicitly call super on direct parent return super(self.__class__, self).__repr__() @@ -410,7 +410,7 @@ class DeferredConfigString(str, DeferredConfig): .. versionadded:: 5.0 """ - def get_value(self, trait): + def get_value(self, trait: TraitType[t.Any, t.Any]) -> t.Any: """Get the value stored in this string""" s = str(self) try: @@ -425,7 +425,7 @@ class DeferredConfigString(str, DeferredConfig): return f"{self.__class__.__name__}({self._super_repr()})" -class DeferredConfigList(list, DeferredConfig): # type:ignore[type-arg] +class DeferredConfigList(t.List[t.Any], DeferredConfig): """Config value for loading config from a list of strings Interpretation is deferred until it is loaded into the trait. @@ -441,7 +441,7 @@ class DeferredConfigList(list, DeferredConfig): # type:ignore[type-arg] .. versionadded:: 5.0 """ - def get_value(self, trait): + def get_value(self, trait: TraitType[t.Any, t.Any]) -> t.Any: """Get the value stored in this string""" if hasattr(trait, "from_string_list"): src = list(self) @@ -487,12 +487,12 @@ class ConfigLoader: handled elsewhere. """ - def _log_default(self): + def _log_default(self) -> Logger: from traitlets.log import get_logger - return get_logger() + return t.cast(Logger, get_logger()) - def __init__(self, log: t.Any = None) -> None: + def __init__(self, log: Logger | None = None) -> None: """A base class for config loaders. log : instance of :class:`logging.Logger` to use. @@ -513,10 +513,10 @@ class ConfigLoader: else: self.log = log - def clear(self): + def clear(self) -> None: self.config = Config() - def load_config(self): + def load_config(self) -> Config: """Load a config from somewhere, return a :class:`Config` instance. Usually, this will cause self.config to be set and then returned. @@ -550,7 +550,7 @@ class FileConfigLoader(ConfigLoader): self.path = path self.full_filename = "" - def _find_file(self): + def _find_file(self) -> None: """Try to find the file by searching the paths.""" self.full_filename = filefind(self.filename, self.path) @@ -567,7 +567,7 @@ class JSONFileConfigLoader(FileConfigLoader): """ - def load_config(self): + def load_config(self) -> Config: """Load the config from a file and return it as a Config object.""" self.clear() try: @@ -578,11 +578,11 @@ class JSONFileConfigLoader(FileConfigLoader): self.config = self._convert_to_config(dct) return self.config - def _read_file_as_dict(self): + def _read_file_as_dict(self) -> dict[str, t.Any]: with open(self.full_filename) as f: - return json.load(f) + return t.cast("dict[str, t.Any]", json.load(f)) - def _convert_to_config(self, dictionary): + def _convert_to_config(self, dictionary: dict[str, t.Any]) -> Config: if "version" in dictionary: version = dictionary.pop("version") else: @@ -593,11 +593,11 @@ class JSONFileConfigLoader(FileConfigLoader): else: raise ValueError(f"Unknown version of JSON config file: {version}") - def __enter__(self): + def __enter__(self) -> Config: self.load_config() return self.config - def __exit__(self, exc_type, exc_value, traceback): + def __exit__(self, exc_type: t.Any, exc_value: t.Any, traceback: t.Any) -> None: """ Exit the context manager but do not handle any errors. @@ -617,7 +617,7 @@ class PyFileConfigLoader(FileConfigLoader): path, then executing it to construct a Config object. """ - def load_config(self): + def load_config(self) -> Config: """Load the config from a file and return it as a Config object.""" self.clear() try: @@ -627,7 +627,7 @@ class PyFileConfigLoader(FileConfigLoader): self._read_file_as_dict() return self.config - def load_subconfig(self, fname, path=None): + def load_subconfig(self, fname: str, path: str | None = None) -> None: """Injected into config file namespace as load_subconfig""" if path is None: path = self.path @@ -642,10 +642,10 @@ class PyFileConfigLoader(FileConfigLoader): else: self.config.merge(sub_config) - def _read_file_as_dict(self): + def _read_file_as_dict(self) -> None: """Load the config file into self.config, with recursive loading.""" - def get_config(): + def get_config() -> Config: """Unnecessary now, but a deprecation warning is more trouble than it's worth.""" return self.config @@ -667,7 +667,9 @@ class CommandLineConfigLoader(ConfigLoader): here. """ - def _exec_config_str(self, lhs, rhs, trait=None): + def _exec_config_str( + self, lhs: t.Any, rhs: t.Any, trait: TraitType[t.Any, t.Any] | None = None + ) -> None: """execute self.config.<lhs> = <rhs> * expands ~ with expanduser @@ -694,7 +696,7 @@ class CommandLineConfigLoader(ConfigLoader): section[key] = value return - def _load_flag(self, cfg): + def _load_flag(self, cfg: t.Any) -> None: """update self.config from a flag, which can be a dict or Config""" if isinstance(cfg, (dict, Config)): # don't clobber whole config sections, update @@ -723,7 +725,13 @@ class _KVAction(argparse.Action): Always """ - def __call__(self, parser, namespace, values, option_string=None): + def __call__( # type:ignore[override] + self, + parser: argparse.ArgumentParser, + namespace: dict[str, t.Any], + values: t.Sequence[t.Any], + option_string: str | None = None, + ) -> None: if isinstance(values, str): values = [values] values = ["-" if v is _DASH_REPLACEMENT else v for v in values] @@ -742,7 +750,7 @@ class _DefaultOptionDict(dict): # type:ignore[type-arg] but acts as if all --Class.trait options are predefined """ - def _add_kv_action(self, key): + def _add_kv_action(self, key: str) -> None: self[key] = _KVAction( option_strings=[key], dest=key.lstrip("-").replace(".", _DOT_REPLACEMENT), @@ -761,13 +769,13 @@ class _DefaultOptionDict(dict): # type:ignore[type-arg] return True return False - def __getitem__(self, key): + def __getitem__(self, key: str) -> t.Any: if key in self: return super().__getitem__(key) else: raise KeyError(key) - def get(self, key, default=None): + def get(self, key: str, default: t.Any = None) -> t.Any: try: return self[key] except KeyError: @@ -777,7 +785,9 @@ class _DefaultOptionDict(dict): # type:ignore[type-arg] class _KVArgParser(argparse.ArgumentParser): """subclass of ArgumentParser where any --Class.trait option is implicitly defined""" - def parse_known_args(self, args=None, namespace=None): + def parse_known_args( # type:ignore[override] + self, args: t.Sequence[str] | None = None, namespace: argparse.Namespace | None = None + ) -> tuple[argparse.Namespace | None, list[str]]: # must be done immediately prior to parsing because if we do it in init, # registration of explicit actions via parser.add_option will fail during setup for container in (self, self._optionals): @@ -850,7 +860,13 @@ class ArgParseConfigLoader(CommandLineConfigLoader): kwargs.update(parser_kw) self.parser_kw = kwargs - def load_config(self, argv=None, aliases=None, flags=_deprecated, classes=None): + def load_config( + self, + argv: list[str] | None = None, + aliases: t.Any = None, + flags: t.Any = _deprecated, + classes: t.Any = None, + ) -> Config: """Parse command line arguments and return as a Config object. Parameters @@ -885,26 +901,27 @@ class ArgParseConfigLoader(CommandLineConfigLoader): self._convert_to_config() return self.config - def get_extra_args(self): + def get_extra_args(self) -> list[str]: if hasattr(self, "extra_args"): return self.extra_args else: return [] - def _create_parser(self): + def _create_parser(self) -> None: self.parser = self.parser_class( - *self.parser_args, **self.parser_kw # type:ignore[arg-type] + *self.parser_args, + **self.parser_kw, # type:ignore[arg-type] ) self._add_arguments(self.aliases, self.flags, self.classes) - def _add_arguments(self, aliases, flags, classes): + def _add_arguments(self, aliases: t.Any, flags: t.Any, classes: t.Any) -> None: raise NotImplementedError("subclasses must implement _add_arguments") def _argcomplete(self, classes: list[t.Any], subcommands: SubcommandsDict | None) -> None: """If argcomplete is enabled, allow triggering command-line autocompletion""" pass - def _parse_args(self, args): + def _parse_args(self, args: t.Any) -> t.Any: """self.parser->self.parsed_data""" uargs = [cast_unicode(a) for a in args] @@ -921,7 +938,7 @@ class ArgParseConfigLoader(CommandLineConfigLoader): unpacked_aliases["-" + al] = "--" + alias_target unpacked_aliases["--" + al] = "--" + alias_target - def _replace(arg): + def _replace(arg: str) -> str: if arg == "-": return _DASH_REPLACEMENT for k, v in unpacked_aliases.items(): @@ -943,7 +960,7 @@ class ArgParseConfigLoader(CommandLineConfigLoader): self.parsed_data = self.parser.parse_args(to_parse) self.extra_args = extra_args - def _convert_to_config(self): + def _convert_to_config(self) -> None: """self.parsed_data->self.config""" for k, v in vars(self.parsed_data).items(): *path, key = k.split(".") @@ -964,7 +981,9 @@ class _FlagAction(argparse.Action): kwargs["nargs"] = 0 super().__init__(*args, **kwargs) - def __call__(self, parser, namespace, values, option_string=None): + def __call__( + self, parser: t.Any, namespace: t.Any, values: t.Any, option_string: str | None = None + ) -> None: if self.nargs == 0 or values is Undefined: if not hasattr(namespace, "_flags"): namespace._flags = [] @@ -981,9 +1000,10 @@ class KVArgParseConfigLoader(ArgParseConfigLoader): parser_class = _KVArgParser # type:ignore[assignment] - def _add_arguments(self, aliases, flags, classes): + def _add_arguments(self, aliases: t.Any, flags: t.Any, classes: t.Any) -> None: alias_flags: dict[str, t.Any] = {} argparse_kwds: dict[str, t.Any] + argparse_traits: dict[str, t.Any] paa = self.parser.add_argument self.parser.set_defaults(_flags=[]) paa("extra_args", nargs="*") @@ -1061,7 +1081,7 @@ class KVArgParseConfigLoader(ArgParseConfigLoader): argcompleter, key=key ) - def _convert_to_config(self): + def _convert_to_config(self) -> None: """self.parsed_data->self.config, parse unrecognized extra args via KVLoader.""" extra_args = self.extra_args @@ -1118,7 +1138,7 @@ class KVArgParseConfigLoader(ArgParseConfigLoader): from . import argcomplete_config - finder = argcomplete_config.ExtendedCompletionFinder() + finder = argcomplete_config.ExtendedCompletionFinder() # type:ignore[no-untyped-call] finder.config_classes = classes finder.subcommands = list(subcommands or []) # for ease of testing, pass through self._argcomplete_kwargs if set @@ -1141,7 +1161,7 @@ class KeyValueConfigLoader(KVArgParseConfigLoader): super().__init__(*args, **kwargs) -def load_pyconfig_files(config_files, path): +def load_pyconfig_files(config_files: list[str], path: str) -> Config: """Load multiple Python config files, merging each of them in turn. Parameters diff --git a/contrib/python/traitlets/py3/traitlets/config/sphinxdoc.py b/contrib/python/traitlets/py3/traitlets/config/sphinxdoc.py index 300c0a0b03..635b6bdfa3 100644 --- a/contrib/python/traitlets/py3/traitlets/config/sphinxdoc.py +++ b/contrib/python/traitlets/py3/traitlets/config/sphinxdoc.py @@ -32,15 +32,18 @@ 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 __future__ import annotations + +import typing as t from collections import defaultdict from textwrap import dedent -from traitlets import Undefined +from traitlets import HasTraits, Undefined +from traitlets.config.application import Application from traitlets.utils.text import indent -def setup(app): +def setup(app: t.Any) -> dict[str, t.Any]: """Registers the Sphinx extension. You shouldn't need to call this directly; configure Sphinx to use this @@ -51,7 +54,7 @@ def setup(app): return metadata -def interesting_default_value(dv): +def interesting_default_value(dv: t.Any) -> bool: if (dv is None) or (dv is Undefined): return False if isinstance(dv, (str, list, tuple, dict, set)): @@ -59,7 +62,7 @@ def interesting_default_value(dv): return True -def format_aliases(aliases): +def format_aliases(aliases: list[str]) -> str: fmted = [] for a in aliases: dashes = "-" if len(a) == 1 else "--" @@ -67,7 +70,7 @@ def format_aliases(aliases): return ", ".join(fmted) -def class_config_rst_doc(cls, trait_aliases): +def class_config_rst_doc(cls: type[HasTraits], trait_aliases: dict[str, t.Any]) -> str: """Generate rST documentation for this class' config options. Excludes traits defined on parent classes. @@ -77,7 +80,7 @@ def class_config_rst_doc(cls, trait_aliases): for _, trait in sorted(cls.class_traits(config=True).items()): ttype = trait.__class__.__name__ - fullname = classname + "." + trait.name + fullname = classname + "." + (trait.name or "") lines += [".. configtrait:: " + fullname, ""] help = trait.help.rstrip() or "No description" @@ -86,7 +89,7 @@ def class_config_rst_doc(cls, trait_aliases): # Choices or type if "Enum" in ttype: # include Enum choices - lines.append(indent(":options: " + ", ".join("``%r``" % x for x in trait.values))) + lines.append(indent(":options: " + ", ".join("``%r``" % x for x in trait.values))) # type:ignore[attr-defined] else: lines.append(indent(":trait type: " + ttype)) @@ -115,7 +118,7 @@ def class_config_rst_doc(cls, trait_aliases): return "\n".join(lines) -def reverse_aliases(app): +def reverse_aliases(app: Application) -> dict[str, list[str]]: """Produce a mapping of trait names to lists of command line aliases.""" res = defaultdict(list) for alias, trait in app.aliases.items(): @@ -135,7 +138,7 @@ def reverse_aliases(app): return res -def write_doc(path, title, app, preamble=None): +def write_doc(path: str, title: str, app: Application, preamble: str | None = None) -> None: """Write a rst file documenting config options for a traitlets application. Parameters diff --git a/contrib/python/traitlets/py3/traitlets/traitlets.py b/contrib/python/traitlets/py3/traitlets/traitlets.py index 55628c2393..b3657ab950 100644 --- a/contrib/python/traitlets/py3/traitlets/traitlets.py +++ b/contrib/python/traitlets/py3/traitlets/traitlets.py @@ -39,8 +39,6 @@ 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 @@ -65,6 +63,11 @@ SequenceTypes = (list, tuple, set, frozenset) # backward compatibility, use to differ between Python 2 and 3. ClassTypes = (type,) +if t.TYPE_CHECKING: + from typing_extensions import TypeVar +else: + from typing import TypeVar + # exports: __all__ = [ @@ -166,11 +169,11 @@ class TraitError(Exception): # ----------------------------------------------------------------------------- -def isidentifier(s): - return s.isidentifier() +def isidentifier(s: t.Any) -> bool: + return t.cast(bool, s.isidentifier()) -def _safe_literal_eval(s): +def _safe_literal_eval(s: str) -> t.Any: """Safely evaluate an expression Returns original string if eval fails. @@ -183,7 +186,7 @@ def _safe_literal_eval(s): return s -def is_trait(t): +def is_trait(t: t.Any) -> bool: """Returns whether the given value is an instance or subclass of TraitType.""" return isinstance(t, TraitType) or (isinstance(t, type) and issubclass(t, TraitType)) @@ -229,7 +232,7 @@ class _SimpleTest: return self.__repr__() -def getmembers(object, predicate=None): +def getmembers(object: t.Any, predicate: t.Any = None) -> list[tuple[str, t.Any]]: """A safe version of inspect.getmembers that handles missing attributes. This is useful when there are descriptor based attributes that for @@ -249,7 +252,7 @@ def getmembers(object, predicate=None): return results -def _validate_link(*tuples): +def _validate_link(*tuples: t.Any) -> None: """Validate arguments for traitlet link functions""" for tup in tuples: if not len(tup) == 2: @@ -310,14 +313,14 @@ class link: self.target[0].observe(self._update_source, names=self.target[1]) @contextlib.contextmanager - def _busy_updating(self): + def _busy_updating(self) -> t.Any: self.updating = True try: yield finally: self.updating = False - def _update_target(self, change): + def _update_target(self, change: t.Any) -> None: if self.updating: return with self._busy_updating(): @@ -327,7 +330,7 @@ class link: f"Broken link {self}: the source value changed while updating " "the target." ) - def _update_source(self, change): + def _update_source(self, change: t.Any) -> None: if self.updating: return with self._busy_updating(): @@ -392,14 +395,14 @@ class directional_link: self.source[0].observe(self._update, names=self.source[1]) @contextlib.contextmanager - def _busy_updating(self): + def _busy_updating(self) -> t.Any: self.updating = True try: yield finally: self.updating = False - def _update(self, change): + def _update(self, change: t.Any) -> None: if self.updating: return with self._busy_updating(): @@ -476,9 +479,9 @@ class BaseDescriptor: pass -G = t.TypeVar("G") -S = t.TypeVar("S") -T = t.TypeVar("T") +G = TypeVar("G") +S = TypeVar("S") +T = TypeVar("T") # Self from typing extension doesn't work well with mypy https://github.com/python/mypy/pull/14041 @@ -487,6 +490,9 @@ T = t.TypeVar("T") if t.TYPE_CHECKING: from typing_extensions import Literal, Self + K = TypeVar("K", default=str) + V = TypeVar("V", default=t.Any) + # We use a type for the getter (G) and setter (G) because we allow # for traits to cast (for instance CInt will use G=int, S=t.Any) @@ -592,12 +598,12 @@ class TraitType(BaseDescriptor, t.Generic[G, S]): in the same way that dynamic defaults defined by ``@default`` are. """ if self.default_value is not Undefined: - return self.default_value + return t.cast(G, self.default_value) elif hasattr(self, "make_dynamic_default"): - return self.make_dynamic_default() + return t.cast(G, self.make_dynamic_default()) else: # Undefined will raise in TraitType.get - return self.default_value + return t.cast(G, self.default_value) def get_default_value(self) -> G | None: """DEPRECATED: Retrieve the static default value for this trait. @@ -608,9 +614,9 @@ class TraitType(BaseDescriptor, t.Generic[G, S]): DeprecationWarning, stacklevel=2, ) - return self.default_value + return t.cast(G, self.default_value) - def init_default_value(self, obj: t.Any) -> G: + def init_default_value(self, obj: t.Any) -> G | None: """DEPRECATED: Set the static default value for the trait type.""" warn( "init_default_value is deprecated in traitlets 4.0, and may be removed in the future", @@ -621,10 +627,10 @@ class TraitType(BaseDescriptor, t.Generic[G, S]): obj._trait_values[self.name] = value return value - def get(self, obj: HasTraits, cls: t.Any = None) -> G | None: + def get(self, obj: HasTraits, cls: type[t.Any] | None = None) -> G | None: assert self.name is not None try: - value = obj._trait_values[self.name] # type: ignore[index] + value = obj._trait_values[self.name] except KeyError: # Check for a dynamic initializer. default = obj.trait_defaults(self.name) @@ -644,7 +650,7 @@ class TraitType(BaseDescriptor, t.Generic[G, S]): value = self._validate(obj, default) finally: obj._cross_validation_lock = _cross_validation_lock - obj._trait_values[self.name] = value # type: ignore[index] + obj._trait_values[self.name] = value obj._notify_observers( Bunch( name=self.name, @@ -653,50 +659,12 @@ class TraitType(BaseDescriptor, t.Generic[G, S]): type="default", ) ) - return value + return t.cast(G, value) except Exception as e: # This should never be reached. raise TraitError("Unexpected error in TraitType: default value not set properly") from e else: - return value - - if t.TYPE_CHECKING: - # This gives ok type information, but not specific enough (e.g. it will) - # always be a TraitType, not a subclass, like Bool. - @t.overload - def __new__( # type: ignore[misc] - cls, - default_value: S | Sentinel = Undefined, - allow_none: Literal[False] = ..., - read_only: bool | None = None, - help: str | None = None, - config: t.Any = None, - **kwargs: t.Any, - ) -> TraitType[G, S]: - ... - - @t.overload - def __new__( - cls, - default_value: S | None | Sentinel = Undefined, - allow_none: Literal[True] = ..., - read_only: bool | None = None, - help: str | None = None, - config: t.Any = None, - **kwargs: t.Any, - ) -> TraitType[G | None, S]: - ... - - def __new__( # type: ignore[no-untyped-def, misc] - cls, - default_value: S | None | Sentinel = Undefined, - allow_none: Literal[True, False] = False, - read_only=None, - help=None, - config=None, - **kwargs, - ) -> TraitType[G | None, S] | TraitType[G, S]: - ... + return t.cast(G, value) @t.overload def __get__(self, obj: None, cls: type[t.Any]) -> Self: @@ -749,16 +717,16 @@ class TraitType(BaseDescriptor, t.Generic[G, S]): else: self.set(obj, value) - def _validate(self, obj, value): + def _validate(self, obj: t.Any, value: t.Any) -> G | None: if value is None and self.allow_none: return value if hasattr(self, "validate"): value = self.validate(obj, value) if obj._cross_validation_lock is False: value = self._cross_validate(obj, value) - return value + return t.cast(G, value) - def _cross_validate(self, obj, value): + def _cross_validate(self, obj: t.Any, value: t.Any) -> G | None: if self.name in obj._trait_validators: proposal = Bunch({"trait": self, "value": value, "owner": obj}) value = obj._trait_validators[self.name](obj, proposal) @@ -772,18 +740,24 @@ class TraitType(BaseDescriptor, t.Generic[G, S]): "use @validate decorator instead.", ) value = cross_validate(value, self) - return value + return t.cast(G, value) - def __or__(self, other): + def __or__(self, other: TraitType[t.Any, t.Any]) -> Union: if isinstance(other, Union): return Union([self, *other.trait_types]) else: return Union([self, other]) - def info(self): + def info(self) -> str: return self.info_text - def error(self, obj, value, error=None, info=None): + def error( + self, + obj: HasTraits | None, + value: t.Any, + error: Exception | None = None, + info: str | None = None, + ) -> t.NoReturn: """Raise a TraitError Parameters @@ -828,8 +802,7 @@ class TraitType(BaseDescriptor, t.Generic[G, S]): ) else: error.args = ( - "The '{}' trait contains {} which " - "expected {}, not {}.".format( + "The '{}' trait contains {} which " "expected {}, not {}.".format( self.name, chain, error.args[1], @@ -848,18 +821,18 @@ class TraitType(BaseDescriptor, t.Generic[G, S]): e = "The '{}' trait of {} instance expected {}, not {}.".format( self.name, class_of(obj), - self.info(), + info or self.info(), describe("the", value), ) else: e = "The '{}' trait expected {}, not {}.".format( self.name, - self.info(), + info or self.info(), describe("the", value), ) raise TraitError(e) - def get_metadata(self, key, default=None): + def get_metadata(self, key: str, default: t.Any = None) -> t.Any: """DEPRECATED: Get a metadata value. Use .metadata[key] or .metadata.get(key, default) instead. @@ -871,7 +844,7 @@ class TraitType(BaseDescriptor, t.Generic[G, S]): warn("Deprecated in traitlets 4.1, " + msg, DeprecationWarning, stacklevel=2) return self.metadata.get(key, default) - def set_metadata(self, key, value): + def set_metadata(self, key: str, value: t.Any) -> None: """DEPRECATED: Set a metadata key/value. Use .metadata[key] = value instead. @@ -908,7 +881,7 @@ class TraitType(BaseDescriptor, t.Generic[G, S]): self.metadata.update(metadata) return self - def default_value_repr(self): + def default_value_repr(self) -> str: return repr(self.default_value) @@ -932,14 +905,14 @@ class _CallbackWrapper: if self.nargs > 4: raise TraitError("a trait changed callback must have 0-4 arguments.") - def __eq__(self, other): + def __eq__(self, other: t.Any) -> bool: # The wrapper is equal to the wrapped element if isinstance(other, _CallbackWrapper): - return self.cb == other.cb + return bool(self.cb == other.cb) else: - return self.cb == other + return bool(self.cb == other) - def __call__(self, change): + def __call__(self, change: Bunch) -> None: # The wrapper is callable if self.nargs == 0: self.cb() @@ -953,7 +926,7 @@ class _CallbackWrapper: self.cb(change.name, change.old, change.new, change.owner) -def _callback_wrapper(cb): +def _callback_wrapper(cb: t.Any) -> _CallbackWrapper: if isinstance(cb, _CallbackWrapper): return cb else: @@ -967,7 +940,13 @@ class MetaHasDescriptors(type): instantiated and sets their name attribute. """ - def __new__(mcls, name, bases, classdict, **kwds): # noqa + def __new__( + mcls: type[MetaHasDescriptors], # noqa: N804 + name: str, + bases: tuple[type, ...], + classdict: dict[str, t.Any], + **kwds: t.Any, + ) -> MetaHasDescriptors: """Create the HasDescriptors class.""" for k, v in classdict.items(): # ---------------------------------------------------------------- @@ -985,12 +964,14 @@ class MetaHasDescriptors(type): return super().__new__(mcls, name, bases, classdict, **kwds) - def __init__(cls, name: str, bases: t.Any, classdict: t.Any, **kwds) -> None: + def __init__( + cls, name: str, bases: tuple[type, ...], classdict: dict[str, t.Any], **kwds: t.Any + ) -> None: """Finish initializing the HasDescriptors class.""" super().__init__(name, bases, classdict, **kwds) cls.setup_class(classdict) - def setup_class(cls, classdict): + def setup_class(cls: MetaHasDescriptors, classdict: dict[str, t.Any]) -> None: """Setup descriptor instance on the class This sets the :attr:`this_class` and :attr:`name` attributes of each @@ -998,7 +979,7 @@ class MetaHasDescriptors(type): calling their :attr:`class_init` method. """ cls._descriptors = [] - cls._instance_inits = [] + cls._instance_inits: list[t.Any] = [] for k, v in classdict.items(): if isinstance(v, BaseDescriptor): v.class_init(cls, k) # type:ignore[arg-type] @@ -1012,9 +993,9 @@ class MetaHasDescriptors(type): class MetaHasTraits(MetaHasDescriptors): """A metaclass for HasTraits.""" - def setup_class(cls, classdict): # noqa + def setup_class(cls: MetaHasTraits, classdict: dict[str, t.Any]) -> None: # noqa # for only the current class - cls._trait_default_generators = {} + cls._trait_default_generators: dict[str, t.Any] = {} # also looking at base classes cls._all_trait_default_generators = {} cls._traits = {} @@ -1263,26 +1244,26 @@ class EventHandler(BaseDescriptor): else: return self._init_call(*args, **kwargs) - def __get__(self, inst, cls=None): + def __get__(self, inst: t.Any, cls: t.Any = None) -> types.MethodType | EventHandler: if inst is None: return self return types.MethodType(self.func, inst) class ObserveHandler(EventHandler): - def __init__(self, names: t.Any, type: t.Any) -> None: + def __init__(self, names: tuple[Sentinel | str, ...], type: str = "") -> None: self.trait_names = names self.type = type - def instance_init(self, inst): + def instance_init(self, inst: HasTraits) -> None: inst.observe(self, self.trait_names, type=self.type) class ValidateHandler(EventHandler): - def __init__(self, names: t.Any) -> None: + def __init__(self, names: tuple[Sentinel | str, ...]) -> None: self.trait_names = names - def instance_init(self, inst): + def instance_init(self, inst: HasTraits) -> None: inst._register_validator(self, self.trait_names) @@ -1290,7 +1271,7 @@ class DefaultHandler(EventHandler): def __init__(self, name: str) -> None: self.trait_name = name - def class_init(self, cls, name): + def class_init(self, cls: type[HasTraits], name: str | None) -> None: super().class_init(cls, name) cls._trait_default_generators[self.trait_name] = self @@ -1313,7 +1294,7 @@ class HasDescriptors(metaclass=MetaHasDescriptors): inst.setup_instance(*args, **kwargs) return inst - def setup_instance(*args, **kwargs): + def setup_instance(*args: t.Any, **kwargs: t.Any) -> None: """ This is called **before** self.__init__ is called. """ @@ -1321,7 +1302,7 @@ class HasDescriptors(metaclass=MetaHasDescriptors): self = args[0] args = args[1:] - self._cross_validation_lock = False # type:ignore[attr-defined] + self._cross_validation_lock = False cls = self.__class__ # Let descriptors performance initialization when a HasDescriptor # instance is created. This allows registration of observers and @@ -1335,13 +1316,13 @@ class HasDescriptors(metaclass=MetaHasDescriptors): class HasTraits(HasDescriptors, metaclass=MetaHasTraits): _trait_values: dict[str, t.Any] _static_immutable_initial_values: dict[str, t.Any] - _trait_notifiers: dict[str, t.Any] - _trait_validators: dict[str, t.Any] + _trait_notifiers: dict[str | Sentinel, t.Any] + _trait_validators: dict[str | Sentinel, t.Any] _cross_validation_lock: bool _traits: dict[str, t.Any] _all_trait_default_generators: dict[str, t.Any] - def setup_instance(*args, **kwargs): + def setup_instance(*args: t.Any, **kwargs: t.Any) -> None: # Pass self as args[0] to allow "self" as keyword argument self = args[0] args = args[1:] @@ -1365,7 +1346,7 @@ class HasTraits(HasDescriptors, metaclass=MetaHasTraits): if kwargs: # this is a simplified (and faster) version of # the hold_trait_notifications(self) context manager - def ignore(*_ignore_args): + def ignore(change: Bunch) -> None: pass self.notify_change = ignore # type:ignore[method-assign] @@ -1389,7 +1370,7 @@ class HasTraits(HasDescriptors, metaclass=MetaHasTraits): for key in changed: value = self._traits[key]._cross_validate(self, getattr(self, key)) self.set_trait(key, value) - changes[key]['new'] = value + changes[key]["new"] = value self._cross_validation_lock = False # Restore method retrieval from class del self.notify_change @@ -1447,7 +1428,7 @@ class HasTraits(HasDescriptors, metaclass=MetaHasTraits): @property @contextlib.contextmanager - def cross_validation_lock(self): + def cross_validation_lock(self) -> t.Any: """ A contextmanager for running a block with our cross validation lock set to True. @@ -1466,7 +1447,7 @@ class HasTraits(HasDescriptors, metaclass=MetaHasTraits): self._cross_validation_lock = False @contextlib.contextmanager - def hold_trait_notifications(self): + def hold_trait_notifications(self) -> t.Any: """Context manager for bundling trait change notifications and cross validation. @@ -1478,9 +1459,9 @@ class HasTraits(HasDescriptors, metaclass=MetaHasTraits): yield return else: - cache: dict[str, t.Any] = {} + cache: dict[str, list[Bunch]] = {} - def compress(past_changes, change): + def compress(past_changes: list[Bunch] | None, change: Bunch) -> list[Bunch]: """Merges the provided change with the last if possible.""" if past_changes is None: return [change] @@ -1492,7 +1473,7 @@ class HasTraits(HasDescriptors, metaclass=MetaHasTraits): past_changes.append(change) return past_changes - def hold(change): + def hold(change: Bunch) -> None: name = change.name cache[name] = compress(cache.get(name), change) @@ -1530,7 +1511,7 @@ class HasTraits(HasDescriptors, metaclass=MetaHasTraits): for change in changes: self.notify_change(change) - def _notify_trait(self, name, old_value, new_value): + def _notify_trait(self, name: str, old_value: t.Any, new_value: t.Any) -> None: self.notify_change( Bunch( name=name, @@ -1550,23 +1531,19 @@ class HasTraits(HasDescriptors, metaclass=MetaHasTraits): if not isinstance(event, Bunch): # cast to bunch if given a dict event = Bunch(event) # type:ignore[unreachable] - name, type = event['name'], event['type'] + name, type = event["name"], event["type"] callables = [] if name in self._trait_notifiers: callables.extend(self._trait_notifiers.get(name, {}).get(type, [])) callables.extend(self._trait_notifiers.get(name, {}).get(All, [])) - if All in self._trait_notifiers: # type:ignore[comparison-overlap] - callables.extend( - self._trait_notifiers.get(All, {}).get(type, []) # type:ignore[call-overload] - ) - callables.extend( - self._trait_notifiers.get(All, {}).get(All, []) # type:ignore[call-overload] - ) + if All in self._trait_notifiers: + callables.extend(self._trait_notifiers.get(All, {}).get(type, [])) + callables.extend(self._trait_notifiers.get(All, {}).get(All, [])) # Now static ones magic_name = "_%s_changed" % name - if event['type'] == "change" and hasattr(self, magic_name): + if event["type"] == "change" and hasattr(self, magic_name): class_value = getattr(self.__class__, magic_name) if not isinstance(class_value, ObserveHandler): deprecated_method( @@ -1592,7 +1569,9 @@ class HasTraits(HasDescriptors, metaclass=MetaHasTraits): c(event) - def _add_notifiers(self, handler, name, type): + def _add_notifiers( + self, handler: t.Callable[..., t.Any], name: Sentinel | str, type: str | Sentinel + ) -> None: if name not in self._trait_notifiers: nlist: list[t.Any] = [] self._trait_notifiers[name] = {type: nlist} @@ -1605,7 +1584,9 @@ class HasTraits(HasDescriptors, metaclass=MetaHasTraits): if handler not in nlist: nlist.append(handler) - def _remove_notifiers(self, handler, name, type): + def _remove_notifiers( + self, handler: t.Callable[..., t.Any] | None, name: Sentinel | str, type: str | Sentinel + ) -> None: try: if handler is None: del self._trait_notifiers[name][type] @@ -1614,7 +1595,12 @@ class HasTraits(HasDescriptors, metaclass=MetaHasTraits): except KeyError: pass - def on_trait_change(self, handler=None, name=None, remove=False): + def on_trait_change( + self, + handler: EventHandler | None = None, + name: Sentinel | str | None = None, + remove: bool = False, + ) -> None: """DEPRECATED: Setup a handler to be called when a trait changes. This is used to setup dynamic notifications of trait changes. @@ -1717,14 +1703,16 @@ class HasTraits(HasDescriptors, metaclass=MetaHasTraits): """Remove trait change handlers of any type for the specified name. If name is not specified, removes all trait notifiers.""" if name is All: - self._trait_notifiers: dict[str, t.Any] = {} + self._trait_notifiers = {} else: try: del self._trait_notifiers[name] except KeyError: pass - def _register_validator(self, handler, names): + def _register_validator( + self, handler: t.Callable[..., None], names: tuple[str | Sentinel, ...] + ) -> None: """Setup a handler to be called when a trait should be cross validated. This is used to setup dynamic notifications for cross-validation. @@ -1788,7 +1776,7 @@ class HasTraits(HasDescriptors, metaclass=MetaHasTraits): return list(cls.class_traits(**metadata)) @classmethod - def class_traits(cls: type[HasTraits], **metadata: t.Any) -> dict[str, TraitType]: + def class_traits(cls: type[HasTraits], **metadata: t.Any) -> dict[str, TraitType[t.Any, t.Any]]: """Get a ``dict`` of all the traits of this class. The dictionary is keyed on the name and the values are the TraitType objects. @@ -1822,7 +1810,9 @@ class HasTraits(HasDescriptors, metaclass=MetaHasTraits): return result @classmethod - def class_own_traits(cls: type[HasTraits], **metadata: t.Any) -> dict[str, TraitType]: + def class_own_traits( + cls: type[HasTraits], **metadata: t.Any + ) -> dict[str, TraitType[t.Any, t.Any]]: """Get a dict of all the traitlets defined on this class, not a parent. Works like `class_traits`, except for excluding traits from parents. @@ -1883,7 +1873,7 @@ class HasTraits(HasDescriptors, metaclass=MetaHasTraits): """ return {name: getattr(self, name) for name in self.trait_names(**metadata)} - def _get_trait_default_generator(self, name): + def _get_trait_default_generator(self, name: str) -> t.Any: """Return default generator for a given trait Walk the MRO to resolve the correct default generator according to inheritance. @@ -1895,7 +1885,7 @@ class HasTraits(HasDescriptors, metaclass=MetaHasTraits): return getattr(self.__class__, method_name) return self._all_trait_default_generators[name] - def trait_defaults(self, *names: str, **metadata: t.Any) -> dict[str, t.Any]: + def trait_defaults(self, *names: str, **metadata: t.Any) -> dict[str, t.Any] | Sentinel: """Return a trait's default value or a dictionary of them Notes @@ -1907,7 +1897,7 @@ class HasTraits(HasDescriptors, metaclass=MetaHasTraits): raise TraitError(f"'{n}' is not a trait of '{type(self).__name__}' instances") if len(names) == 1 and len(metadata) == 0: - return self._get_trait_default_generator(names[0])(self) + return t.cast(Sentinel, self._get_trait_default_generator(names[0])(self)) trait_names = self.trait_names(**metadata) trait_names.extend(names) @@ -1921,7 +1911,7 @@ class HasTraits(HasDescriptors, metaclass=MetaHasTraits): """Get a list of all the names of this class' traits.""" return list(self.traits(**metadata)) - def traits(self, **metadata: t.Any) -> dict[str, TraitType]: + def traits(self, **metadata: t.Any) -> dict[str, TraitType[t.Any, t.Any]]: """Get a ``dict`` of all the traits of this class. The dictionary is keyed on the name and the values are the TraitType objects. @@ -2021,7 +2011,7 @@ class ClassBasedTraitType(TraitType[G, S]): Instance and This. """ - def _resolve_string(self, string): + def _resolve_string(self, string: str) -> t.Any: """ Resolve a string supplied for a type into an actual object. """ @@ -2063,7 +2053,7 @@ class Type(ClassBasedTraitType[G, S]): def __init__( self: Type[S, S], default_value: S = ..., - klass: type[S] = ..., + klass: S = ..., allow_none: Literal[False] = ..., read_only: bool | None = ..., help: str | None = ..., @@ -2076,7 +2066,7 @@ class Type(ClassBasedTraitType[G, S]): def __init__( self: Type[S | None, S | None], default_value: S | None = ..., - klass: type[S] = ..., + klass: S = ..., allow_none: Literal[True] = ..., read_only: bool | None = ..., help: str | None = ..., @@ -2145,7 +2135,7 @@ class Type(ClassBasedTraitType[G, S]): **kwargs, ) - def validate(self, obj, value): + def validate(self, obj: t.Any, value: t.Any) -> G: """Validates that the value is a valid object instance.""" if isinstance(value, str): try: @@ -2157,13 +2147,13 @@ class Type(ClassBasedTraitType[G, S]): ) from e try: if issubclass(value, self.klass): # type:ignore[arg-type] - return value + return t.cast(G, value) except Exception: pass self.error(obj, value) - def info(self): + def info(self) -> str: """Returns a description of the trait.""" if isinstance(self.klass, str): klass = self.klass @@ -2174,18 +2164,18 @@ class Type(ClassBasedTraitType[G, S]): return result + " or None" return result - def instance_init(self, obj): + def instance_init(self, obj: t.Any) -> None: # we can't do this in subclass_init because that # might be called before all imports are done. self._resolve_classes() - def _resolve_classes(self): + def _resolve_classes(self) -> None: if isinstance(self.klass, str): self.klass = self._resolve_string(self.klass) if isinstance(self.default_value, str): self.default_value = self._resolve_string(self.default_value) - def default_value_repr(self): + def default_value_repr(self) -> str: value = self.default_value assert value is not None if isinstance(value, str): @@ -2314,14 +2304,16 @@ class Instance(ClassBasedTraitType[T, T]): super().__init__(allow_none=allow_none, read_only=read_only, help=help, **kwargs) - def validate(self, obj, value): + def validate(self, obj: t.Any, value: t.Any) -> T | None: assert self.klass is not None - if isinstance(value, self.klass): # type:ignore[arg-type] + if self.allow_none and value is None: return value + if isinstance(value, self.klass): # type:ignore[arg-type] + return t.cast(T, value) else: self.error(obj, value) - def info(self): + def info(self) -> str: if isinstance(self.klass, str): result = add_article(self.klass) else: @@ -2330,28 +2322,26 @@ class Instance(ClassBasedTraitType[T, T]): result += " or None" return result - def instance_init(self, obj): + def instance_init(self, obj: t.Any) -> None: # we can't do this in subclass_init because that # might be called before all imports are done. self._resolve_classes() - def _resolve_classes(self): + def _resolve_classes(self) -> None: if isinstance(self.klass, str): self.klass = self._resolve_string(self.klass) - def make_dynamic_default(self): + def make_dynamic_default(self) -> T | None: if (self.default_args is None) and (self.default_kwargs is None): return None assert self.klass is not None - return self.klass( - *(self.default_args or ()), **(self.default_kwargs or {}) - ) # type:ignore[operator] + return self.klass(*(self.default_args or ()), **(self.default_kwargs or {})) # type:ignore[operator] - def default_value_repr(self): + def default_value_repr(self) -> str: return repr(self.make_dynamic_default()) - def from_string(self, s): - return _safe_literal_eval(s) + def from_string(self, s: str) -> T | None: + return t.cast(T, _safe_literal_eval(s)) class ForwardDeclaredMixin: @@ -2359,7 +2349,7 @@ class ForwardDeclaredMixin: Mixin for forward-declared versions of Instance and Type. """ - def _resolve_string(self, string): + def _resolve_string(self, string: str) -> t.Any: """ Find the specified class name by looking for it in the module in which our this_class attribute was defined. @@ -2397,7 +2387,7 @@ class This(ClassBasedTraitType[t.Optional[T], t.Optional[T]]): def __init__(self, **kwargs: t.Any) -> None: super().__init__(None, **kwargs) - def validate(self, obj, value): + def validate(self, obj: t.Any, value: t.Any) -> HasTraits | None: # What if value is a superclass of obj.__class__? This is # complicated if it was the superclass that defined the This # trait. @@ -2443,7 +2433,7 @@ class Union(TraitType[t.Any, t.Any]): self.info_text = " or ".join([tt.info() for tt in self.trait_types]) super().__init__(**kwargs) - def default(self, obj=None): + def default(self, obj: t.Any = None) -> t.Any: default = super().default(obj) for trait in self.trait_types: if default is Undefined: @@ -2452,18 +2442,18 @@ class Union(TraitType[t.Any, t.Any]): break return default - def class_init(self, cls, name): + def class_init(self, cls: type[HasTraits], name: str | None) -> None: for trait_type in reversed(self.trait_types): trait_type.class_init(cls, None) super().class_init(cls, name) - def subclass_init(self, cls): + def subclass_init(self, cls: type[t.Any]) -> None: for trait_type in reversed(self.trait_types): trait_type.subclass_init(cls) # explicitly not calling super().subclass_init(cls) # to opt out of instance_init - def validate(self, obj, value): + def validate(self, obj: t.Any, value: t.Any) -> t.Any: with obj.cross_validation_lock: for trait_type in self.trait_types: try: @@ -2476,13 +2466,13 @@ class Union(TraitType[t.Any, t.Any]): continue self.error(obj, value) - def __or__(self, other): + def __or__(self, other: t.Any) -> Union: if isinstance(other, Union): return Union(self.trait_types + other.trait_types) else: return Union([*self.trait_types, other]) - def from_string(self, s): + def from_string(self, s: str) -> t.Any: for trait_type in self.trait_types: try: v = trait_type.from_string(s) @@ -2568,11 +2558,13 @@ class Any(TraitType[t.Optional[t.Any], t.Optional[t.Any]]): allow_none = True info_text = "any value" - def subclass_init(self, cls): + def subclass_init(self, cls: type[t.Any]) -> None: pass # fully opt out of instance_init -def _validate_bounds(trait, obj, value): +def _validate_bounds( + trait: Int[t.Any, t.Any] | Float[t.Any, t.Any], obj: t.Any, value: t.Any +) -> t.Any: """ Validate that a number to be applied to a trait is between bounds. @@ -2647,17 +2639,17 @@ class Int(TraitType[G, S]): **kwargs, ) - def validate(self, obj, value): + def validate(self, obj: t.Any, value: t.Any) -> G: if not isinstance(value, int): self.error(obj, value) - return _validate_bounds(self, obj, value) + return t.cast(G, _validate_bounds(self, obj, value)) - def from_string(self, s): + def from_string(self, s: str) -> G: if self.allow_none and s == "None": - return None - return int(s) + return t.cast(G, None) + return t.cast(G, int(s)) - def subclass_init(self, cls): + def subclass_init(self, cls: type[t.Any]) -> None: pass # fully opt out of instance_init @@ -2701,12 +2693,12 @@ class CInt(Int[G, S]): ) -> None: ... - def validate(self, obj, value): + def validate(self, obj: t.Any, value: t.Any) -> G: try: value = int(value) except Exception: self.error(obj, value) - return _validate_bounds(self, obj, value) + return t.cast(G, _validate_bounds(self, obj, value)) Long, CLong = Int, CInt @@ -2763,19 +2755,19 @@ class Float(TraitType[G, S]): **kwargs, ) - def validate(self, obj, value): + def validate(self, obj: t.Any, value: t.Any) -> G: if isinstance(value, int): value = float(value) if not isinstance(value, float): self.error(obj, value) - return _validate_bounds(self, obj, value) + return t.cast(G, _validate_bounds(self, obj, value)) - def from_string(self, s): + def from_string(self, s: str) -> G: if self.allow_none and s == "None": - return None - return float(s) + return t.cast(G, None) + return t.cast(G, float(s)) - def subclass_init(self, cls): + def subclass_init(self, cls: type[t.Any]) -> None: pass # fully opt out of instance_init @@ -2819,12 +2811,12 @@ class CFloat(Float[G, S]): ) -> None: ... - def validate(self, obj, value): + def validate(self, obj: t.Any, value: t.Any) -> G: try: value = float(value) except Exception: self.error(obj, value) - return _validate_bounds(self, obj, value) + return t.cast(G, _validate_bounds(self, obj, value)) class Complex(TraitType[complex, t.Union[complex, float, int]]): @@ -2833,26 +2825,26 @@ class Complex(TraitType[complex, t.Union[complex, float, int]]): default_value = 0.0 + 0.0j info_text = "a complex number" - def validate(self, obj, value): + def validate(self, obj: t.Any, value: t.Any) -> complex | None: if isinstance(value, complex): return value if isinstance(value, (float, int)): return complex(value) self.error(obj, value) - def from_string(self, s): + def from_string(self, s: str) -> complex | None: if self.allow_none and s == "None": return None return complex(s) - def subclass_init(self, cls): + def subclass_init(self, cls: type[t.Any]) -> None: pass # fully opt out of instance_init class CComplex(Complex, TraitType[complex, t.Any]): """A casting version of the complex number trait.""" - def validate(self, obj, value): + def validate(self, obj: t.Any, value: t.Any) -> complex | None: try: return complex(value) except Exception: @@ -2868,12 +2860,12 @@ class Bytes(TraitType[bytes, bytes]): default_value = b"" info_text = "a bytes object" - def validate(self, obj, value): + def validate(self, obj: t.Any, value: t.Any) -> bytes | None: if isinstance(value, bytes): return value self.error(obj, value) - def from_string(self, s): + def from_string(self, s: str) -> bytes | None: if self.allow_none and s == "None": return None if len(s) >= 3: @@ -2891,14 +2883,14 @@ class Bytes(TraitType[bytes, bytes]): break return s.encode("utf8") - def subclass_init(self, cls): + def subclass_init(self, cls: type[t.Any]) -> None: pass # fully opt out of instance_init class CBytes(Bytes, TraitType[bytes, t.Any]): """A casting version of the byte string trait.""" - def validate(self, obj, value): + def validate(self, obj: t.Any, value: t.Any) -> bytes | None: try: return bytes(value) except Exception: @@ -2948,20 +2940,20 @@ class Unicode(TraitType[G, S]): ) -> None: ... - def validate(self, obj, value): + def validate(self, obj: t.Any, value: t.Any) -> G: if isinstance(value, str): - return value + return t.cast(G, value) if isinstance(value, bytes): try: - return value.decode("ascii", "strict") + return t.cast(G, value.decode("ascii", "strict")) except UnicodeDecodeError as e: msg = "Could not decode {!r} for unicode trait '{}' of {} instance." raise TraitError(msg.format(value, self.name, class_of(obj))) from e self.error(obj, value) - def from_string(self, s): + def from_string(self, s: str) -> G: if self.allow_none and s == "None": - return None + return t.cast(G, None) s = os.path.expanduser(s) if len(s) >= 2: # handle deprecated "1" @@ -2975,9 +2967,9 @@ class Unicode(TraitType[G, S]): DeprecationWarning, stacklevel=2, ) - return s + return t.cast(G, s) - def subclass_init(self, cls): + def subclass_init(self, cls: type[t.Any]) -> None: pass # fully opt out of instance_init @@ -3021,9 +3013,9 @@ class CUnicode(Unicode[G, S], TraitType[str, t.Any]): ) -> None: ... - def validate(self, obj, value): + def validate(self, obj: t.Any, value: t.Any) -> G: try: - return str(value) + return t.cast(G, str(value)) except Exception: self.error(obj, value) @@ -3037,14 +3029,14 @@ class ObjectName(TraitType[str, str]): coerce_str = staticmethod(lambda _, s: s) - def validate(self, obj, value): + def validate(self, obj: t.Any, value: t.Any) -> str: value = self.coerce_str(obj, value) if isinstance(value, str) and isidentifier(value): return value self.error(obj, value) - def from_string(self, s): + def from_string(self, s: str) -> str | None: if self.allow_none and s == "None": return None return s @@ -3053,7 +3045,7 @@ class ObjectName(TraitType[str, str]): class DottedObjectName(ObjectName): """A string holding a valid dotted object name in Python, such as A.b3._c""" - def validate(self, obj, value): + def validate(self, obj: t.Any, value: t.Any) -> str: value = self.coerce_str(obj, value) if isinstance(value, str) and all(isidentifier(a) for a in value.split(".")): @@ -3104,31 +3096,31 @@ class Bool(TraitType[G, S]): ) -> None: ... - def validate(self, obj, value): + def validate(self, obj: t.Any, value: t.Any) -> G: if isinstance(value, bool): - return value + return t.cast(G, value) elif isinstance(value, int): if value == 1: - return True + return t.cast(G, True) elif value == 0: - return False + return t.cast(G, False) self.error(obj, value) - def from_string(self, s): + def from_string(self, s: str) -> G: if self.allow_none and s == "None": - return None + return t.cast(G, None) s = s.lower() if s in {"true", "1"}: - return True + return t.cast(G, True) elif s in {"false", "0"}: - return False + return t.cast(G, False) else: raise ValueError("%r is not 1, 0, true, or false") - def subclass_init(self, cls): + def subclass_init(self, cls: type[t.Any]) -> None: pass # fully opt out of instance_init - def argcompleter(self, **kwargs): + def argcompleter(self, **kwargs: t.Any) -> list[str]: """Completion hints for argcomplete""" completions = ["true", "1", "false", "0"] if self.allow_none: @@ -3176,96 +3168,136 @@ class CBool(Bool[G, S]): ) -> None: ... - def validate(self, obj, value): + def validate(self, obj: t.Any, value: t.Any) -> G: try: - return bool(value) + return t.cast(G, bool(value)) except Exception: self.error(obj, value) -class Enum(TraitType[G, S]): +class Enum(TraitType[G, G]): """An enum whose value must be in a given sequence.""" + if t.TYPE_CHECKING: + + @t.overload + def __init__( + self: Enum[G], + values: t.Sequence[G], + default_value: G | Sentinel = ..., + allow_none: Literal[False] = ..., + read_only: bool | None = ..., + help: str | None = ..., + config: t.Any = ..., + **kwargs: t.Any, + ) -> None: + ... + + @t.overload + def __init__( + self: Enum[G | None], + values: t.Sequence[G] | None, + default_value: G | Sentinel | None = ..., + allow_none: Literal[True] = ..., + read_only: bool | None = ..., + help: str | None = ..., + config: t.Any = ..., + **kwargs: t.Any, + ) -> None: + ... + def __init__( - self: Enum[t.Any, t.Any], values: t.Any, default_value: t.Any = Undefined, **kwargs: t.Any + self: Enum[G], + values: t.Sequence[G] | None, + default_value: G | Sentinel | None = Undefined, + allow_none: bool = False, + read_only: bool | None = None, + help: str | None = None, + config: t.Any = None, + **kwargs: t.Any, ) -> None: self.values = values - if kwargs.get("allow_none", False) and default_value is Undefined: + if allow_none is True and default_value is Undefined: default_value = None + kwargs["allow_none"] = allow_none + kwargs["read_only"] = read_only + kwargs["help"] = help + kwargs["config"] = config super().__init__(default_value, **kwargs) - def validate(self, obj, value): - if value in self.values: - return value + def validate(self, obj: t.Any, value: t.Any) -> G: + if self.values and value in self.values: + return t.cast(G, value) self.error(obj, value) - def _choices_str(self, as_rst=False): + def _choices_str(self, as_rst: bool = False) -> str: """Returns a description of the trait choices (not none).""" - choices = self.values + choices = self.values or [] if as_rst: - choices = "|".join("``%r``" % x for x in choices) + choice_str = "|".join("``%r``" % x for x in choices) else: - choices = repr(list(choices)) - return choices + choice_str = repr(list(choices)) + return choice_str - def _info(self, as_rst=False): + def _info(self, as_rst: bool = False) -> str: """Returns a description of the trait.""" none = " or %s" % ("`None`" if as_rst else "None") if self.allow_none else "" return f"any of {self._choices_str(as_rst)}{none}" - def info(self): + def info(self) -> str: return self._info(as_rst=False) - def info_rst(self): + def info_rst(self) -> str: return self._info(as_rst=True) - def from_string(self, s): + def from_string(self, s: str) -> G: try: return self.validate(None, s) except TraitError: - return _safe_literal_eval(s) + return t.cast(G, _safe_literal_eval(s)) - def subclass_init(self, cls): + def subclass_init(self, cls: type[t.Any]) -> None: pass # fully opt out of instance_init - def argcompleter(self, **kwargs): + def argcompleter(self, **kwargs: t.Any) -> list[str]: """Completion hints for argcomplete""" - return [str(v) for v in self.values] + return [str(v) for v in self.values or []] -class CaselessStrEnum(Enum[G, S]): +class CaselessStrEnum(Enum[G]): """An enum of strings where the case should be ignored.""" def __init__( - self: CaselessStrEnum[t.Any, t.Any], + self: CaselessStrEnum[t.Any], values: t.Any, default_value: t.Any = Undefined, **kwargs: t.Any, ) -> None: super().__init__(values, default_value=default_value, **kwargs) - def validate(self, obj, value): + def validate(self, obj: t.Any, value: t.Any) -> G: if not isinstance(value, str): self.error(obj, value) - for v in self.values: + for v in self.values or []: + assert isinstance(v, str) if v.lower() == value.lower(): - return v + return t.cast(G, v) self.error(obj, value) - def _info(self, as_rst=False): + def _info(self, as_rst: bool = False) -> str: """Returns a description of the trait.""" none = " or %s" % ("`None`" if as_rst else "None") if self.allow_none else "" return f"any of {self._choices_str(as_rst)} (case-insensitive){none}" - def info(self): + def info(self) -> str: return self._info(as_rst=False) - def info_rst(self): + def info_rst(self) -> str: return self._info(as_rst=True) -class FuzzyEnum(Enum[G, S]): +class FuzzyEnum(Enum[G]): """An case-ignoring enum matching choices by unique prefixes/substrings.""" case_sensitive = False @@ -3273,7 +3305,7 @@ class FuzzyEnum(Enum[G, S]): substring_matching = False def __init__( - self: FuzzyEnum[t.Any, t.Any], + self: FuzzyEnum[t.Any], values: t.Any, default_value: t.Any = Undefined, case_sensitive: bool = False, @@ -3284,16 +3316,16 @@ class FuzzyEnum(Enum[G, S]): self.substring_matching = substring_matching super().__init__(values, default_value=default_value, **kwargs) - def validate(self, obj, value): + def validate(self, obj: t.Any, value: t.Any) -> G: if not isinstance(value, str): self.error(obj, value) conv_func = (lambda c: c) if self.case_sensitive else lambda c: c.lower() substring_matching = self.substring_matching match_func = (lambda v, c: v in c) if substring_matching else (lambda v, c: c.startswith(v)) - value = conv_func(value) - choices = self.values - matches = [match_func(value, conv_func(c)) for c in choices] + value = conv_func(value) # type:ignore[no-untyped-call] + choices = self.values or [] + matches = [match_func(value, conv_func(c)) for c in choices] # type:ignore[no-untyped-call] if sum(matches) == 1: for v, m in zip(choices, matches): if m: @@ -3301,17 +3333,17 @@ class FuzzyEnum(Enum[G, S]): self.error(obj, value) - def _info(self, as_rst=False): + def _info(self, as_rst: bool = False) -> str: """Returns a description of the trait.""" none = " or %s" % ("`None`" if as_rst else "None") if self.allow_none else "" case = "sensitive" if self.case_sensitive else "insensitive" substr = "substring" if self.substring_matching else "prefix" return f"any case-{case} {substr} of {self._choices_str(as_rst)}{none}" - def info(self): + def info(self) -> str: return self._info(as_rst=False) - def info_rst(self): + def info_rst(self) -> str: return self._info(as_rst=True) @@ -3324,7 +3356,7 @@ class Container(Instance[T]): klass: type[T] | None = None _cast_types: t.Any = () _valid_defaults = SequenceTypes - _trait = None + _trait: t.Any = None _literal_from_string_pairs: t.Any = ("[]", "()") @t.overload @@ -3446,7 +3478,7 @@ class Container(Instance[T]): klass=self.klass, args=args, help=help, read_only=read_only, config=config, **kwargs ) - def validate(self, obj, value): + def validate(self, obj: t.Any, value: t.Any) -> T | None: if isinstance(value, self._cast_types): assert self.klass is not None value = self.klass(value) # type:ignore[call-arg] @@ -3456,12 +3488,12 @@ class Container(Instance[T]): value = self.validate_elements(obj, value) - return value + return t.cast(T, value) - def validate_elements(self, obj, value): + def validate_elements(self, obj: t.Any, value: t.Any) -> T | None: validated = [] if self._trait is None or isinstance(self._trait, Any): - return value + return t.cast(T, value) for v in value: try: v = self._trait._validate(obj, v) @@ -3472,18 +3504,18 @@ class Container(Instance[T]): assert self.klass is not None return self.klass(validated) # type:ignore[call-arg] - def class_init(self, cls, name): + def class_init(self, cls: type[t.Any], name: str | None) -> None: if isinstance(self._trait, TraitType): self._trait.class_init(cls, None) super().class_init(cls, name) - def subclass_init(self, cls): + def subclass_init(self, cls: type[t.Any]) -> None: if isinstance(self._trait, TraitType): self._trait.subclass_init(cls) # explicitly not calling super().subclass_init(cls) # to opt out of instance_init - def from_string(self, s): + def from_string(self, s: str) -> T | None: """Load value from a single string""" if not isinstance(s, str): raise TraitError(f"Expected string, got {s!r}") @@ -3493,7 +3525,7 @@ class Container(Instance[T]): test = None return self.validate(None, test) - def from_string_list(self, s_list): + def from_string_list(self, s_list: list[str]) -> T | None: """Return the value from a list of config strings This is where we parse CLI configuration @@ -3527,34 +3559,34 @@ class Container(Instance[T]): item_from_string = self.item_from_string else: # backward-compat: allow item_from_string to ignore index arg - def item_from_string(s, index=None): - return self.item_from_string(s) + def item_from_string(s: str, index: int | None = None) -> T | str: + return t.cast(T, self.item_from_string(s)) return self.klass( # type:ignore[call-arg] [item_from_string(s, index=idx) for idx, s in enumerate(s_list)] ) - def item_from_string(self, s, index=None): + def item_from_string(self, s: str, index: int | None = None) -> T | str: """Cast a single item from a string Evaluated when parsing CLI configuration from a string """ if self._trait: - return self._trait.from_string(s) + return t.cast(T, self._trait.from_string(s)) else: return s -class List(Container[t.List[t.Any]]): +class List(Container[t.List[T]]): """An instance of a Python list.""" - klass = list + klass = list # type:ignore[assignment] _cast_types: t.Any = (tuple,) def __init__( self, - trait: t.Any = None, - default_value: t.Any = Undefined, + trait: t.List[T] | t.Tuple[T] | t.Set[T] | Sentinel | TraitType[T, t.Any] | None = None, + default_value: t.List[T] | t.Tuple[T] | t.Set[T] | Sentinel | None = Undefined, minlen: int = 0, maxlen: int = sys.maxsize, **kwargs: t.Any, @@ -3589,23 +3621,23 @@ class List(Container[t.List[t.Any]]): self._minlen = minlen super().__init__(trait=trait, default_value=default_value, **kwargs) - def length_error(self, obj, value): + def length_error(self, obj: t.Any, value: t.Any) -> None: e = ( "The '%s' trait of %s instance must be of length %i <= L <= %i, but a value of %s was specified." % (self.name, class_of(obj), self._minlen, self._maxlen, value) ) raise TraitError(e) - def validate_elements(self, obj, value): + def validate_elements(self, obj: t.Any, value: t.Any) -> t.Any: length = len(value) if length < self._minlen or length > self._maxlen: self.length_error(obj, value) return super().validate_elements(obj, value) - def set(self, obj, value): + def set(self, obj: t.Any, value: t.Any) -> None: if isinstance(value, str): - return super().set(obj, [value]) + return super().set(obj, [value]) # type:ignore[list-item] else: return super().set(obj, value) @@ -3657,21 +3689,21 @@ class Set(Container[t.Set[t.Any]]): self._minlen = minlen super().__init__(trait=trait, default_value=default_value, **kwargs) - def length_error(self, obj, value): + def length_error(self, obj: t.Any, value: t.Any) -> None: e = ( "The '%s' trait of %s instance must be of length %i <= L <= %i, but a value of %s was specified." % (self.name, class_of(obj), self._minlen, self._maxlen, value) ) raise TraitError(e) - def validate_elements(self, obj, value): + def validate_elements(self, obj: t.Any, value: t.Any) -> t.Any: length = len(value) if length < self._minlen or length > self._maxlen: self.length_error(obj, value) return super().validate_elements(obj, value) - def set(self, obj, value): + def set(self, obj: t.Any, value: t.Any) -> None: if isinstance(value, str): return super().set( obj, @@ -3682,9 +3714,9 @@ class Set(Container[t.Set[t.Any]]): else: return super().set(obj, value) - def default_value_repr(self): + def default_value_repr(self) -> str: # Ensure default value is sorted for a reproducible build - list_repr = repr(sorted(self.make_dynamic_default())) + list_repr = repr(sorted(self.make_dynamic_default() or [])) if list_repr == "[]": return "set()" return "{" + list_repr[1:-1] + "}" @@ -3773,7 +3805,7 @@ class Tuple(Container[t.Tuple[t.Any, ...]]): args = None super(Container, self).__init__(klass=self.klass, args=args, **kwargs) - def item_from_string(self, s, index): + def item_from_string(self, s: str, index: int) -> t.Any: # type:ignore[override] """Cast a single item from a string Evaluated when parsing CLI configuration from a string @@ -3784,7 +3816,7 @@ class Tuple(Container[t.Tuple[t.Any, ...]]): return s return self._traits[index].from_string(s) - def validate_elements(self, obj, value): + def validate_elements(self, obj: t.Any, value: t.Any) -> t.Any: if not self._traits: # nothing to validate return value @@ -3805,13 +3837,13 @@ class Tuple(Container[t.Tuple[t.Any, ...]]): validated.append(v) return tuple(validated) - def class_init(self, cls, name): + def class_init(self, cls: type[t.Any], name: str | None) -> None: for trait in self._traits: if isinstance(trait, TraitType): trait.class_init(cls, None) super(Container, self).class_init(cls, name) - def subclass_init(self, cls): + def subclass_init(self, cls: type[t.Any]) -> None: for trait in self._traits: if isinstance(trait, TraitType): trait.subclass_init(cls) @@ -3819,7 +3851,7 @@ class Tuple(Container[t.Tuple[t.Any, ...]]): # to opt out of instance_init -class Dict(Instance[t.Dict[t.Any, t.Any]]): +class Dict(Instance["dict[K, V]"]): """An instance of a Python dict. One or more traits can be passed to the constructor @@ -3839,10 +3871,10 @@ class Dict(Instance[t.Dict[t.Any, t.Any]]): def __init__( self, - value_trait: t.Any = None, + value_trait: TraitType[t.Any, t.Any] | dict[K, V] | Sentinel | None = None, per_key_traits: t.Any = None, - key_trait: t.Any = None, - default_value: t.Any = Undefined, + key_trait: TraitType[t.Any, t.Any] | None = None, + default_value: dict[K, V] | Sentinel | None = Undefined, **kwargs: t.Any, ) -> None: """Create a dict trait type from a Python dict. @@ -3911,6 +3943,7 @@ class Dict(Instance[t.Dict[t.Any, t.Any]]): # Handling positional arguments if default_value is Undefined and value_trait is not None: if not is_trait(value_trait): + assert not isinstance(value_trait, TraitType) default_value = value_trait value_trait = None @@ -3934,7 +3967,7 @@ class Dict(Instance[t.Dict[t.Any, t.Any]]): # Case where a type of TraitType is provided rather than an instance if is_trait(value_trait): if isinstance(value_trait, type): - warn( + warn( # type:ignore[unreachable] "Traits should be given as instances, not types (for example, `Int()`, not `Int`)" " Passing types is deprecated in traitlets 4.1.", DeprecationWarning, @@ -3949,7 +3982,7 @@ class Dict(Instance[t.Dict[t.Any, t.Any]]): if is_trait(key_trait): if isinstance(key_trait, type): - warn( + warn( # type:ignore[unreachable] "Traits should be given as instances, not types (for example, `Int()`, not `Int`)" " Passing types is deprecated in traitlets 4.1.", DeprecationWarning, @@ -3964,21 +3997,23 @@ class Dict(Instance[t.Dict[t.Any, t.Any]]): super().__init__(klass=dict, args=args, **kwargs) - def element_error(self, obj, element, validator, side="Values"): + def element_error( + self, obj: t.Any, element: t.Any, validator: t.Any, side: str = "Values" + ) -> None: e = ( side + f" of the '{self.name}' trait of {class_of(obj)} instance must be {validator.info()}, but a value of {repr_type(element)} was specified." ) raise TraitError(e) - def validate(self, obj, value): + def validate(self, obj: t.Any, value: t.Any) -> dict[K, V] | None: value = super().validate(obj, value) if value is None: return value - value = self.validate_elements(obj, value) - return value + value_dict = self.validate_elements(obj, value) + return value_dict - def validate_elements(self, obj, value): + def validate_elements(self, obj: t.Any, value: dict[t.Any, t.Any]) -> dict[K, V] | None: per_key_override = self._per_key_traits or {} key_trait = self._key_trait value_trait = self._value_trait @@ -4003,7 +4038,7 @@ class Dict(Instance[t.Dict[t.Any, t.Any]]): return self.klass(validated) # type:ignore[misc,operator] - def class_init(self, cls, name): + def class_init(self, cls: type[t.Any], name: str | None) -> None: if isinstance(self._value_trait, TraitType): self._value_trait.class_init(cls, None) if isinstance(self._key_trait, TraitType): @@ -4013,7 +4048,7 @@ class Dict(Instance[t.Dict[t.Any, t.Any]]): trait.class_init(cls, None) super().class_init(cls, name) - def subclass_init(self, cls): + def subclass_init(self, cls: type[t.Any]) -> None: if isinstance(self._value_trait, TraitType): self._value_trait.subclass_init(cls) if isinstance(self._key_trait, TraitType): @@ -4024,19 +4059,19 @@ class Dict(Instance[t.Dict[t.Any, t.Any]]): # explicitly not calling super().subclass_init(cls) # to opt out of instance_init - def from_string(self, s): + def from_string(self, s: str) -> dict[K, V] | None: """Load value from a single string""" if not isinstance(s, str): raise TypeError(f"from_string expects a string, got {s!r} of type {type(s)}") try: - return self.from_string_list([s]) + return t.cast("dict[K, V]", self.from_string_list([s])) except Exception: test = _safe_literal_eval(s) if isinstance(test, dict): return test raise - def from_string_list(self, s_list): + def from_string_list(self, s_list: list[str]) -> t.Any: """Return a dict from a list of config strings. This is where we parse CLI configuration. @@ -4062,7 +4097,7 @@ class Dict(Instance[t.Dict[t.Any, t.Any]]): combined.update(d) return combined - def item_from_string(self, s): + def item_from_string(self, s: str) -> dict[K, V]: """Cast a single-key dict from a string. Evaluated when parsing CLI configuration from a string. @@ -4087,7 +4122,7 @@ class Dict(Instance[t.Dict[t.Any, t.Any]]): value_trait = (self._per_key_traits or {}).get(key, self._value_trait) if value_trait: value = value_trait.from_string(value) - return {key: value} + return t.cast("dict[K, V]", {key: value}) class TCPAddress(TraitType[G, S]): @@ -4137,23 +4172,23 @@ class TCPAddress(TraitType[G, S]): ) -> None: ... - def validate(self, obj, value): + def validate(self, obj: t.Any, value: t.Any) -> G: if isinstance(value, tuple): if len(value) == 2: if isinstance(value[0], str) and isinstance(value[1], int): port = value[1] if port >= 0 and port <= 65535: - return value + return t.cast(G, value) self.error(obj, value) - def from_string(self, s): + def from_string(self, s: str) -> G: if self.allow_none and s == "None": - return None + return t.cast(G, None) if ":" not in s: raise ValueError("Require `ip:port`, got %r" % s) - ip, port = s.split(":", 1) - port = int(port) - return (ip, port) + ip, port_str = s.split(":", 1) + port = int(port_str) + return t.cast(G, (ip, port)) class CRegExp(TraitType["re.Pattern[t.Any]", t.Union["re.Pattern[t.Any]", str]]): @@ -4164,7 +4199,7 @@ class CRegExp(TraitType["re.Pattern[t.Any]", t.Union["re.Pattern[t.Any]", str]]) info_text = "a regular expression" - def validate(self, obj, value): + def validate(self, obj: t.Any, value: t.Any) -> re.Pattern[t.Any] | None: try: return re.compile(value) except Exception: @@ -4215,7 +4250,7 @@ class UseEnum(TraitType[t.Any, t.Any]): self.enum_class = enum_class self.name_prefix = enum_class.__name__ + "." - def select_by_number(self, value, default=Undefined): + def select_by_number(self, value: int, default: t.Any = Undefined) -> t.Any: """Selects enum-value by using its number-constant.""" assert isinstance(value, int) enum_members = self.enum_class.__members__ @@ -4225,7 +4260,7 @@ class UseEnum(TraitType[t.Any, t.Any]): # -- NOT FOUND: return default - def select_by_name(self, value, default=Undefined): + def select_by_name(self, value: str, default: t.Any = Undefined) -> t.Any: """Selects enum-value by using its name or scoped-name.""" assert isinstance(value, str) if value.startswith(self.name_prefix): @@ -4233,7 +4268,7 @@ class UseEnum(TraitType[t.Any, t.Any]): value = value.replace(self.name_prefix, "", 1) return self.enum_class.__members__.get(value, default) - def validate(self, obj, value): + def validate(self, obj: t.Any, value: t.Any) -> t.Any: if isinstance(value, self.enum_class): return value elif isinstance(value, int): @@ -4253,7 +4288,7 @@ class UseEnum(TraitType[t.Any, t.Any]): return self.default_value self.error(obj, value) - def _choices_str(self, as_rst=False): + def _choices_str(self, as_rst: bool = False) -> str: """Returns a description of the trait choices (not none).""" choices = self.enum_class.__members__.keys() if as_rst: @@ -4261,15 +4296,15 @@ class UseEnum(TraitType[t.Any, t.Any]): else: return repr(list(choices)) # Listify because py3.4- prints odict-class - def _info(self, as_rst=False): + def _info(self, as_rst: bool = False) -> str: """Returns a description of the trait.""" none = " or %s" % ("`None`" if as_rst else "None") if self.allow_none else "" return f"any of {self._choices_str(as_rst)}{none}" - def info(self): + def info(self) -> str: return self._info(as_rst=False) - def info_rst(self): + def info_rst(self) -> str: return self._info(as_rst=True) @@ -4283,7 +4318,7 @@ class Callable(TraitType[t.Callable[..., t.Any], t.Callable[..., t.Any]]): info_text = "a callable" - def validate(self, obj, value): + def validate(self, obj: t.Any, value: t.Any) -> t.Any: if callable(value): return value else: diff --git a/contrib/python/traitlets/py3/ya.make b/contrib/python/traitlets/py3/ya.make index 50dfd2c1bd..6bd3d32e7c 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.12.0) +VERSION(5.13.0) LICENSE(BSD-3-Clause) |