diff options
Diffstat (limited to 'contrib/python')
25 files changed, 273 insertions, 203 deletions
diff --git a/contrib/python/markdown-it-py/.dist-info/METADATA b/contrib/python/markdown-it-py/.dist-info/METADATA index 488e089b08e..c44604a6677 100644 --- a/contrib/python/markdown-it-py/.dist-info/METADATA +++ b/contrib/python/markdown-it-py/.dist-info/METADATA @@ -1,6 +1,6 @@ Metadata-Version: 2.4 Name: markdown-it-py -Version: 4.1.0 +Version: 4.2.0 Summary: Python port of markdown-it. Markdown parsing, done right! Keywords: markdown,lexer,parser,commonmark,markdown-it Author-email: Chris Sewell <[email protected]> diff --git a/contrib/python/markdown-it-py/markdown_it/__init__.py b/contrib/python/markdown-it-py/markdown_it/__init__.py index 523d92ef4ba..58dfa3bcc46 100644 --- a/contrib/python/markdown-it-py/markdown_it/__init__.py +++ b/contrib/python/markdown-it-py/markdown_it/__init__.py @@ -1,6 +1,6 @@ """A Python port of Markdown-It""" __all__ = ("MarkdownIt",) -__version__ = "4.1.0" +__version__ = "4.2.0" from .main import MarkdownIt diff --git a/contrib/python/markdown-it-py/markdown_it/rules_block/__init__.py b/contrib/python/markdown-it-py/markdown_it/rules_block/__init__.py index 517da2312aa..2c5efa85ccf 100644 --- a/contrib/python/markdown-it-py/markdown_it/rules_block/__init__.py +++ b/contrib/python/markdown-it-py/markdown_it/rules_block/__init__.py @@ -8,6 +8,7 @@ __all__ = ( "html_block", "lheading", "list_block", + "make_fence_rule", "paragraph", "reference", "table", @@ -15,7 +16,7 @@ __all__ = ( from .blockquote import blockquote from .code import code -from .fence import fence +from .fence import fence, make_fence_rule from .heading import heading from .hr import hr from .html_block import html_block diff --git a/contrib/python/markdown-it-py/markdown_it/rules_block/fence.py b/contrib/python/markdown-it-py/markdown_it/rules_block/fence.py index 263f1b8de8d..0d7e651eb06 100644 --- a/contrib/python/markdown-it-py/markdown_it/rules_block/fence.py +++ b/contrib/python/markdown-it-py/markdown_it/rules_block/fence.py @@ -1,4 +1,7 @@ # fences (``` lang, ~~~ lang) +from __future__ import annotations + +from collections.abc import Callable import logging from .state_block import StateBlock @@ -6,96 +9,138 @@ from .state_block import StateBlock LOGGER = logging.getLogger(__name__) -def fence(state: StateBlock, startLine: int, endLine: int, silent: bool) -> bool: - LOGGER.debug("entering fence: %s, %s, %s, %s", state, startLine, endLine, silent) +def make_fence_rule( + *, + markers: tuple[str, ...] = ("~", "`"), + token_type: str = "fence", + exact_match: bool = False, + disallow_marker_in_info: tuple[str, ...] = ("`",), + min_markers: int = 3, +) -> Callable[[StateBlock, int, int, bool], bool]: + """Create a fence parsing rule with configurable options. - haveEndMarker = False - pos = state.bMarks[startLine] + state.tShift[startLine] - maximum = state.eMarks[startLine] + :param markers: Tuple of single characters that can be used as fence markers. + :param token_type: The token type name to emit (e.g. "fence", "colon_fence"). + :param exact_match: If True, the closing fence must have exactly the same + number of marker characters as the opening fence (not "at least as many"). + This enables nesting of fences with different marker counts. + :param disallow_marker_in_info: Tuple of marker characters that are not allowed + to appear in the info string. The check only applies when the actual opening + marker is in this tuple (e.g. a tilde fence is unaffected by ``"`"`` being + listed). Per CommonMark, backtick fences cannot have backticks in the info + string. Use ``()`` to disable this restriction. + :param min_markers: Minimum number of marker characters to form a fence. + :return: A block rule function with signature + ``(state, startLine, endLine, silent) -> bool``. + """ - if state.is_code_block(startLine): - return False + closing_matcher: Callable[[int, int], bool] + if exact_match: + # closing code fence must have exactly the same number of markers as the opening one + closing_matcher = lambda opening_len, closing_len: closing_len == opening_len # noqa: E731 + else: + # closing code fence must be at least as long as the opening one + closing_matcher = lambda opening_len, closing_len: closing_len >= opening_len # noqa: E731 - if pos + 3 > maximum: - return False + def _fence_rule( + state: StateBlock, startLine: int, endLine: int, silent: bool + ) -> bool: + LOGGER.debug( + "entering fence: %s, %s, %s, %s", state, startLine, endLine, silent + ) - marker = state.src[pos] + haveEndMarker = False + pos = state.bMarks[startLine] + state.tShift[startLine] + maximum = state.eMarks[startLine] - if marker not in ("~", "`"): - return False + if state.is_code_block(startLine): + return False - # scan marker length - mem = pos - pos = state.skipCharsStr(pos, marker) + if pos + min_markers > maximum: + return False - length = pos - mem + marker = state.src[pos] - if length < 3: - return False + if marker not in markers: + return False - markup = state.src[mem:pos] - params = state.src[pos:maximum] + # scan marker length + mem = pos + pos = state.skipCharsStr(pos, marker) - if marker == "`" and marker in params: - return False + length = pos - mem - # Since start is found, we can report success here in validation mode - if silent: - return True + if length < min_markers: + return False - # search end of block - nextLine = startLine + markup = state.src[mem:pos] + params = state.src[pos:maximum] - while True: - nextLine += 1 - if nextLine >= endLine: - # unclosed block should be autoclosed by end of document. - # also block seems to be autoclosed by end of parent - break + if marker in disallow_marker_in_info and marker in params: + return False - pos = mem = state.bMarks[nextLine] + state.tShift[nextLine] - maximum = state.eMarks[nextLine] + # Since start is found, we can report success here in validation mode + if silent: + return True - if pos < maximum and state.sCount[nextLine] < state.blkIndent: - # non-empty line with negative indent should stop the list: - # - ``` - # test - break + # search end of block + nextLine = startLine + + while True: + nextLine += 1 + if nextLine >= endLine: + # unclosed block should be autoclosed by end of document. + # also block seems to be autoclosed by end of parent + break + + pos = mem = state.bMarks[nextLine] + state.tShift[nextLine] + maximum = state.eMarks[nextLine] + + if pos < maximum and state.sCount[nextLine] < state.blkIndent: + # non-empty line with negative indent should stop the list: + # - ``` + # test + break + + try: + if state.src[pos] != marker: + continue + except IndexError: + break - try: - if state.src[pos] != marker: + if state.is_code_block(nextLine): continue - except IndexError: - break - if state.is_code_block(nextLine): - continue + pos = state.skipCharsStr(pos, marker) - pos = state.skipCharsStr(pos, marker) + if not closing_matcher(length, pos - mem): + continue - # closing code fence must be at least as long as the opening one - if pos - mem < length: - continue + # make sure tail has spaces only + pos = state.skipSpaces(pos) - # make sure tail has spaces only - pos = state.skipSpaces(pos) + if pos < maximum: + continue - if pos < maximum: - continue + haveEndMarker = True + # found! + break + + # If a fence has heading spaces, they should be removed from its inner block + length = state.sCount[startLine] - haveEndMarker = True - # found! - break + state.line = nextLine + (1 if haveEndMarker else 0) - # If a fence has heading spaces, they should be removed from its inner block - length = state.sCount[startLine] + token = state.push(token_type, "code", 0) + token.info = params + token.content = state.getLines(startLine + 1, nextLine, length, True) + token.markup = markup + token.map = [startLine, state.line] + + return True - state.line = nextLine + (1 if haveEndMarker else 0) + return _fence_rule - token = state.push("fence", "code", 0) - token.info = params - token.content = state.getLines(startLine + 1, nextLine, length, True) - token.markup = markup - token.map = [startLine, state.line] - return True +#: The default fence rule (backtick and tilde markers, CommonMark compliant). +fence = make_fence_rule() diff --git a/contrib/python/markdown-it-py/ya.make b/contrib/python/markdown-it-py/ya.make index dd380e6d343..bdbb0a782c7 100644 --- a/contrib/python/markdown-it-py/ya.make +++ b/contrib/python/markdown-it-py/ya.make @@ -2,7 +2,7 @@ PY3_LIBRARY() -VERSION(4.1.0) +VERSION(4.2.0) LICENSE(MIT) diff --git a/contrib/python/matplotlib-inline/.dist-info/METADATA b/contrib/python/matplotlib-inline/.dist-info/METADATA index c0aef502d2e..fe86ee74a23 100644 --- a/contrib/python/matplotlib-inline/.dist-info/METADATA +++ b/contrib/python/matplotlib-inline/.dist-info/METADATA @@ -1,11 +1,12 @@ Metadata-Version: 2.4 Name: matplotlib-inline -Version: 0.2.1 +Version: 0.2.2 Summary: Inline Matplotlib backend for Jupyter Keywords: ipython,jupyter,matplotlib,python Author-email: IPython Development Team <[email protected]> Requires-Python: >=3.9 Description-Content-Type: text/markdown +License-Expression: BSD-3-Clause Classifier: Development Status :: 5 - Production/Stable Classifier: Framework :: IPython Classifier: Framework :: Jupyter :: JupyterLab :: 3 @@ -30,6 +31,7 @@ Requires-Dist: nbdime ; extra == "test" Requires-Dist: nbval ; extra == "test" Requires-Dist: notebook ; extra == "test" Requires-Dist: pytest ; extra == "test" +Requires-Dist: matplotlib ; extra == "test" Project-URL: Homepage, https://github.com/ipython/matplotlib-inline Provides-Extra: test diff --git a/contrib/python/matplotlib-inline/matplotlib_inline/__init__.py b/contrib/python/matplotlib-inline/matplotlib_inline/__init__.py index d275175ecd9..2c03285e778 100644 --- a/contrib/python/matplotlib-inline/matplotlib_inline/__init__.py +++ b/contrib/python/matplotlib-inline/matplotlib_inline/__init__.py @@ -1,6 +1,6 @@ from . import backend_inline, config # noqa -__version__ = "0.2.1" +__version__ = "0.2.2" # we can't ''.join(...) otherwise finding the version number at build time requires # import which introduces IPython and matplotlib at build time, and thus circular diff --git a/contrib/python/matplotlib-inline/ya.make b/contrib/python/matplotlib-inline/ya.make index 718e1ebacab..979b055fb22 100644 --- a/contrib/python/matplotlib-inline/ya.make +++ b/contrib/python/matplotlib-inline/ya.make @@ -2,7 +2,7 @@ PY3_LIBRARY() -VERSION(0.2.1) +VERSION(0.2.2) LICENSE(BSD-3-Clause) diff --git a/contrib/python/traitlets/py3/.dist-info/METADATA b/contrib/python/traitlets/py3/.dist-info/METADATA index 777822558d1..379f2d9c97b 100644 --- a/contrib/python/traitlets/py3/.dist-info/METADATA +++ b/contrib/python/traitlets/py3/.dist-info/METADATA @@ -1,6 +1,6 @@ -Metadata-Version: 2.3 +Metadata-Version: 2.4 Name: traitlets -Version: 5.14.3 +Version: 5.15.0 Summary: Traitlets Python configuration system Project-URL: Homepage, https://github.com/ipython/traitlets Project-URL: Documentation, https://traitlets.readthedocs.io @@ -49,13 +49,14 @@ Classifier: License :: OSI Approved :: BSD License Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 Classifier: Typing :: Typed -Requires-Python: >=3.8 +Requires-Python: >=3.9 Provides-Extra: docs Requires-Dist: myst-parser; extra == 'docs' Requires-Dist: pydata-sphinx-theme; extra == 'docs' Requires-Dist: sphinx; extra == 'docs' Provides-Extra: test Requires-Dist: argcomplete>=3.0.3; extra == 'test' +Requires-Dist: mypy<1.19,>=1.7.0; (platform_python_implementation == 'PyPy') and extra == 'test' Requires-Dist: mypy>=1.7.0; extra == 'test' Requires-Dist: pre-commit; extra == 'test' Requires-Dist: pytest-mock; extra == 'test' diff --git a/contrib/python/traitlets/py3/patches/e3d5c5a66de52c623da02b4cafd9c34f5b0ff3bb.patch b/contrib/python/traitlets/py3/patches/e3d5c5a66de52c623da02b4cafd9c34f5b0ff3bb.patch deleted file mode 100644 index d610cde18d7..00000000000 --- a/contrib/python/traitlets/py3/patches/e3d5c5a66de52c623da02b4cafd9c34f5b0ff3bb.patch +++ /dev/null @@ -1,24 +0,0 @@ -From e3d5c5a66de52c623da02b4cafd9c34f5b0ff3bb Mon Sep 17 00:00:00 2001 -From: M Bussonnier <[email protected]> -Date: Tue, 14 Oct 2025 08:55:52 +0200 -Subject: [PATCH] start testing on 3.14 and 3.14t (#929) - ---- - .github/workflows/tests.yml | 2 +- - traitlets/config/application.py | 3 ++- - 2 files changed, 3 insertions(+), 2 deletions(-) - -diff --git a/traitlets/config/application.py b/traitlets/config/application.py -index 672fa1c9..b07ca818 100644 ---- a/traitlets/config/application.py -+++ b/traitlets/config/application.py -@@ -215,7 +215,8 @@ def _classes_inc_parents( - _log_formatter_cls = LevelFormatter - - log_datefmt = Unicode( -- "%Y-%m-%d %H:%M:%S", help="The date format used by logging formatters for %(asctime)s" -+ "%Y-%m-%d %H:%M:%S", -+ help="The date format used by logging formatters for `asctime`", - ).tag(config=True) - - log_format = Unicode( diff --git a/contrib/python/traitlets/py3/tests/test_traitlets.py b/contrib/python/traitlets/py3/tests/test_traitlets.py index f9f623b4ae6..665422cd9d2 100644 --- a/contrib/python/traitlets/py3/tests/test_traitlets.py +++ b/contrib/python/traitlets/py3/tests/test_traitlets.py @@ -7,6 +7,7 @@ # also under the terms of the Modified BSD License. from __future__ import annotations +import decimal import pickle import re import typing as t @@ -1391,7 +1392,7 @@ class TestLong(TraitTestBase): obj = LongTrait() _default_value = 99 - _good_values = [10, -10] + _good_values = [10, -10, 10.0, decimal.Decimal("10.0")] _bad_values = [ "ten", [10], @@ -1401,6 +1402,7 @@ class TestLong(TraitTestBase): 1j, 10.1, -10.1, + decimal.Decimal("10.1"), "10", "-10", "10L", diff --git a/contrib/python/traitlets/py3/tests/test_typing.py b/contrib/python/traitlets/py3/tests/test_typing.py index 8329feb8375..940447478dc 100644 --- a/contrib/python/traitlets/py3/tests/test_typing.py +++ b/contrib/python/traitlets/py3/tests/test_typing.py @@ -407,27 +407,27 @@ def mypy_tcp_typing() -> None: otcp = TCPAddress(None, allow_none=True) t = T() - reveal_type(t.tcp) # R: Tuple[builtins.str, builtins.int] + reveal_type(t.tcp) # R: tuple[builtins.str, builtins.int] reveal_type( - T.tcp # R: traitlets.traitlets.TCPAddress[Tuple[builtins.str, builtins.int], Tuple[builtins.str, builtins.int]] + T.tcp # R: traitlets.traitlets.TCPAddress[tuple[builtins.str, builtins.int], tuple[builtins.str, builtins.int]] ) reveal_type( - T.tcp.tag( # R:traitlets.traitlets.TCPAddress[Tuple[builtins.str, builtins.int], Tuple[builtins.str, builtins.int]] + T.tcp.tag( # R:traitlets.traitlets.TCPAddress[tuple[builtins.str, builtins.int], tuple[builtins.str, builtins.int]] sync=True ) ) - reveal_type(t.otcp) # R: Union[Tuple[builtins.str, builtins.int], None] + reveal_type(t.otcp) # R: Union[tuple[builtins.str, builtins.int], None] reveal_type( - T.otcp # R: traitlets.traitlets.TCPAddress[Union[Tuple[builtins.str, builtins.int], None], Union[Tuple[builtins.str, builtins.int], None]] + T.otcp # R: traitlets.traitlets.TCPAddress[Union[tuple[builtins.str, builtins.int], None], Union[tuple[builtins.str, builtins.int], None]] ) reveal_type( - T.otcp.tag( # R: traitlets.traitlets.TCPAddress[Union[Tuple[builtins.str, builtins.int], None], Union[Tuple[builtins.str, builtins.int], None]] + T.otcp.tag( # R: traitlets.traitlets.TCPAddress[Union[tuple[builtins.str, builtins.int], None], Union[tuple[builtins.str, builtins.int], None]] sync=True ) ) - t.tcp = "foo" # E: Incompatible types in assignment (expression has type "str", variable has type "Tuple[str, int]") [assignment] - t.otcp = "foo" # E: Incompatible types in assignment (expression has type "str", variable has type "Optional[Tuple[str, int]]") [assignment] - t.tcp = None # E: Incompatible types in assignment (expression has type "None", variable has type "Tuple[str, int]") [assignment] + t.tcp = "foo" # E: Incompatible types in assignment (expression has type "str", variable has type "tuple[str, int]") [assignment] + t.otcp = "foo" # E: Incompatible types in assignment (expression has type "str", variable has type "Optional[tuple[str, int]]") [assignment] + t.tcp = None # E: Incompatible types in assignment (expression has type "None", variable has type "tuple[str, int]") [assignment] @pytest.mark.mypy_testing diff --git a/contrib/python/traitlets/py3/tests/utils/test_bunch.py b/contrib/python/traitlets/py3/tests/utils/test_bunch.py index 90efe982739..98bf262016a 100644 --- a/contrib/python/traitlets/py3/tests/utils/test_bunch.py +++ b/contrib/python/traitlets/py3/tests/utils/test_bunch.py @@ -14,5 +14,8 @@ def test_bunch(): def test_bunch_dir(): b = Bunch(x=5, y=10) - assert "x" in dir(b) assert "keys" in dir(b) + assert "x" in dir(b) + assert "z" not in dir(b) + b.z = 15 + assert "z" in dir(b) diff --git a/contrib/python/traitlets/py3/traitlets/__init__.py b/contrib/python/traitlets/py3/traitlets/__init__.py index e27ecf1a451..da56f5c663d 100644 --- a/contrib/python/traitlets/py3/traitlets/__init__.py +++ b/contrib/python/traitlets/py3/traitlets/__init__.py @@ -1,4 +1,5 @@ """Traitlets Python configuration system""" + from __future__ import annotations import typing as _t @@ -12,14 +13,15 @@ from .utils.importstring import import_item from .utils.warnings import warn __all__ = [ - "traitlets", - "__version__", - "version_info", "Bunch", - "signature_has_traits", - "import_item", "Sentinel", + "__version__", + "import_item", + "signature_has_traits", + "traitlets", + "version_info", ] +__all__ += traitlets.__all__ class Sentinel(traitlets.Sentinel): # type:ignore[name-defined, misc] diff --git a/contrib/python/traitlets/py3/traitlets/_version.py b/contrib/python/traitlets/py3/traitlets/_version.py index fea66b5e0ad..fb2dbc36d16 100644 --- a/contrib/python/traitlets/py3/traitlets/_version.py +++ b/contrib/python/traitlets/py3/traitlets/_version.py @@ -4,16 +4,15 @@ handle the current version info of traitlets. from __future__ import annotations import re -from typing import List # Version string must appear intact for hatch versioning -__version__ = "5.14.3" +__version__ = "5.15.0" # Build up version_info tuple for backwards compatibility pattern = r"(?P<major>\d+).(?P<minor>\d+).(?P<patch>\d+)(?P<rest>.*)" match = re.match(pattern, __version__) assert match is not None -parts: List[object] = [int(match[part]) for part in ["major", "minor", "patch"]] +parts: list[object] = [int(match[part]) for part in ["major", "minor", "patch"]] if match["rest"]: parts.append(match["rest"]) version_info = tuple(parts) diff --git a/contrib/python/traitlets/py3/traitlets/config/application.py b/contrib/python/traitlets/py3/traitlets/config/application.py index 2860de722b8..b07ca818fc8 100644 --- a/contrib/python/traitlets/py3/traitlets/config/application.py +++ b/contrib/python/traitlets/py3/traitlets/config/application.py @@ -900,6 +900,8 @@ class Application(SingletonConfigurable): yield each config object in turn. """ + if os.path.isabs(basefilename): + path = [None] if isinstance(path, str) or path is None: path = [path] for current in reversed(path): @@ -1063,7 +1065,11 @@ class Application(SingletonConfigurable): sys.exit(exit_status) def __del__(self) -> None: - self.close_handlers() + # __del__ may be called during process teardown, + # at which point any fraction of attributes and modules may have been cleared, + # e.g. even _accessing_ self.log may fail. + with suppress(Exception): + self.close_handlers() @classmethod def launch_instance(cls, argv: ArgvType = None, **kwargs: t.Any) -> None: diff --git a/contrib/python/traitlets/py3/traitlets/config/configurable.py b/contrib/python/traitlets/py3/traitlets/config/configurable.py index 44b4793ebd5..9740311513b 100644 --- a/contrib/python/traitlets/py3/traitlets/config/configurable.py +++ b/contrib/python/traitlets/py3/traitlets/config/configurable.py @@ -300,7 +300,7 @@ class Configurable(HasTraits): if helptext is None: helptext = trait.help if helptext != "": - helptext = "\n".join(wrap_paragraphs(helptext, 76)) + helptext = "\n\n".join(wrap_paragraphs(helptext, 76)) lines.append(indent(helptext)) if "Enum" in trait.__class__.__name__: diff --git a/contrib/python/traitlets/py3/traitlets/tests/utils.py b/contrib/python/traitlets/py3/traitlets/tests/utils.py index 254d46a758a..fb587a24d17 100644 --- a/contrib/python/traitlets/py3/traitlets/tests/utils.py +++ b/contrib/python/traitlets/py3/traitlets/tests/utils.py @@ -1,8 +1,9 @@ from __future__ import annotations import sys +from collections.abc import Sequence from subprocess import PIPE, Popen -from typing import Any, Sequence +from typing import Any def get_output_error_code(cmd: str | Sequence[str]) -> tuple[str, str, Any]: diff --git a/contrib/python/traitlets/py3/traitlets/traitlets.py b/contrib/python/traitlets/py3/traitlets/traitlets.py index ecd0d7cc399..4aa08cf3d02 100644 --- a/contrib/python/traitlets/py3/traitlets/traitlets.py +++ b/contrib/python/traitlets/py3/traitlets/traitlets.py @@ -44,6 +44,7 @@ from __future__ import annotations import contextlib import enum import inspect +import numbers import os import re import sys @@ -169,8 +170,13 @@ class TraitError(Exception): # ----------------------------------------------------------------------------- -def isidentifier(s: t.Any) -> bool: - return t.cast(bool, s.isidentifier()) +def isidentifier(s: str) -> bool: + warn( + "traitlets.traitlets.isidentifier(s) is deprecated since traitlets 5.14.4 Use `s.isidentifier()`.", + DeprecationWarning, + stacklevel=2, + ) + return s.isidentifier() def _safe_literal_eval(s: str) -> t.Any: @@ -293,13 +299,21 @@ class link: updating = False - def __init__(self, source: t.Any, target: t.Any, transform: t.Any = None) -> None: + def __init__( + self, source: t.Any, target: t.Any, transform: t.Iterable[FuncT] | None = None + ) -> None: _validate_link(source, target) self.source, self.target = source, target - self._transform, self._transform_inv = transform if transform else (lambda x: x,) * 2 - + if transform: + self._transform, self._transform_inv = transform # type:ignore[method-assign] self.link() + def _transform(self, x: T) -> T: + """default transform: no-op""" + return x + + _transform_inv = _transform + def link(self) -> None: try: setattr( @@ -491,6 +505,11 @@ if t.TYPE_CHECKING: K = TypeVar("K", default=str) V = TypeVar("V", default=t.Any) +else: + # This is required to avoid warnings about unresolved references when generating + # the documentation of downstream projects. + K = TypeVar("K") + V = TypeVar("V") # We use a type for the getter (G) and setter (G) because we allow @@ -597,12 +616,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 t.cast(G, self.default_value) + return self.default_value # type:ignore[no-any-return] elif hasattr(self, "make_dynamic_default"): - return t.cast(G, self.make_dynamic_default()) + return self.make_dynamic_default() # type:ignore[no-any-return] else: # Undefined will raise in TraitType.get - return t.cast(G, self.default_value) + return self.default_value # type:ignore[no-any-return] def get_default_value(self) -> G | None: """DEPRECATED: Retrieve the static default value for this trait. @@ -613,7 +632,7 @@ class TraitType(BaseDescriptor, t.Generic[G, S]): DeprecationWarning, stacklevel=2, ) - return t.cast(G, self.default_value) + return self.default_value # type:ignore[no-any-return] def init_default_value(self, obj: t.Any) -> G | None: """DEPRECATED: Set the static default value for the trait type.""" @@ -658,12 +677,12 @@ class TraitType(BaseDescriptor, t.Generic[G, S]): type="default", ) ) - return t.cast(G, value) + return value # type:ignore[no-any-return] except Exception as e: # This should never be reached. raise TraitError("Unexpected error in TraitType: default value not set properly") from e else: - return t.cast(G, value) + return value # type:ignore[no-any-return] @t.overload def __get__(self, obj: None, cls: type[t.Any]) -> Self: @@ -684,7 +703,7 @@ class TraitType(BaseDescriptor, t.Generic[G, S]): if obj is None: return self else: - return t.cast(G, self.get(obj, cls)) # the G should encode the Optional + return self.get(obj, cls) # type:ignore[return-value] def set(self, obj: HasTraits, value: S) -> None: new_value = self._validate(obj, value) @@ -722,7 +741,7 @@ class TraitType(BaseDescriptor, t.Generic[G, S]): value = self.validate(obj, value) if obj._cross_validation_lock is False: value = self._cross_validate(obj, value) - return t.cast(G, value) + return value # type:ignore[no-any-return] def _cross_validate(self, obj: t.Any, value: t.Any) -> G | None: if self.name in obj._trait_validators: @@ -738,7 +757,7 @@ class TraitType(BaseDescriptor, t.Generic[G, S]): "use @validate decorator instead.", ) value = cross_validate(value, self) - return t.cast(G, value) + return value # type:ignore[no-any-return] def __or__(self, other: TraitType[t.Any, t.Any]) -> Union: if isinstance(other, Union): @@ -1142,7 +1161,7 @@ def observe_compat(func: FuncT) -> FuncT: ) return func(self, change) - return t.cast(FuncT, compatible_observer) + return compatible_observer # type:ignore[return-value] def validate(*names: Sentinel | str) -> ValidateHandler: @@ -1277,11 +1296,7 @@ class DefaultHandler(EventHandler): class HasDescriptors(metaclass=MetaHasDescriptors): """The base class for all classes that have descriptors.""" - def __new__(*args: t.Any, **kwargs: t.Any) -> t.Any: - # Pass cls as args[0] to allow "cls" as keyword argument - cls = args[0] - args = args[1:] - + def __new__(cls, /, *args: t.Any, **kwargs: t.Any) -> Self: # This is needed because object.__new__ only accepts # the cls argument. new_meth = super(HasDescriptors, cls).__new__ @@ -1292,13 +1307,10 @@ class HasDescriptors(metaclass=MetaHasDescriptors): inst.setup_instance(*args, **kwargs) return inst - def setup_instance(*args: t.Any, **kwargs: t.Any) -> None: + def setup_instance(self, /, *args: t.Any, **kwargs: t.Any) -> None: """ This is called **before** self.__init__ is called. """ - # Pass self as args[0] to allow "self" as keyword argument - self = args[0] - args = args[1:] self._cross_validation_lock = False cls = self.__class__ @@ -1320,11 +1332,7 @@ class HasTraits(HasDescriptors, metaclass=MetaHasTraits): _traits: dict[str, t.Any] _all_trait_default_generators: dict[str, t.Any] - 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:] - + def setup_instance(self, /, *args: t.Any, **kwargs: t.Any) -> None: # although we'd prefer to set only the initial values not present # in kwargs, we will overwrite them in `__init__`, and simply making # a copy of a dict is faster than checking for each key. @@ -1894,7 +1902,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 t.cast(Sentinel, self._get_trait_default_generator(names[0])(self)) + return self._get_trait_default_generator(names[0])(self) # type:ignore[no-any-return] trait_names = self.trait_names(**metadata) trait_names.extend(names) @@ -2144,7 +2152,7 @@ class Type(ClassBasedTraitType[G, S]): ) from e try: if issubclass(value, self.klass): # type:ignore[arg-type] - return t.cast(G, value) + return value # type:ignore[no-any-return] except Exception: pass @@ -2306,7 +2314,7 @@ class Instance(ClassBasedTraitType[T, T]): if self.allow_none and value is None: return value if isinstance(value, self.klass): # type:ignore[arg-type] - return t.cast(T, value) + return value # type:ignore[no-any-return] else: self.error(obj, value) @@ -2338,7 +2346,7 @@ class Instance(ClassBasedTraitType[T, T]): return repr(self.make_dynamic_default()) def from_string(self, s: str) -> T | None: - return t.cast(T, _safe_literal_eval(s)) + return _safe_literal_eval(s) # type:ignore[no-any-return] class ForwardDeclaredMixin: @@ -2633,14 +2641,23 @@ class Int(TraitType[G, S]): ) def validate(self, obj: t.Any, value: t.Any) -> G: + if not isinstance(value, int) and isinstance(value, numbers.Number): + # allow casting integer-valued numbers to int + # allows for more concise assignment like `4e9` which is a float + try: + int_value = int(value) + if int_value == value: + value = int_value + except Exception: + pass if not isinstance(value, int): self.error(obj, value) - return t.cast(G, _validate_bounds(self, obj, value)) + return _validate_bounds(self, obj, value) # type:ignore[no-any-return] def from_string(self, s: str) -> G: if self.allow_none and s == "None": - return t.cast(G, None) - return t.cast(G, int(s)) + return None # type:ignore[return-value] + return int(s) # type:ignore[return-value] def subclass_init(self, cls: type[t.Any]) -> None: pass # fully opt out of instance_init @@ -2691,7 +2708,7 @@ class CInt(Int[G, S]): value = int(value) except Exception: self.error(obj, value) - return t.cast(G, _validate_bounds(self, obj, value)) + return _validate_bounds(self, obj, value) # type:ignore[no-any-return] Long, CLong = Int, CInt @@ -2753,12 +2770,12 @@ class Float(TraitType[G, S]): value = float(value) if not isinstance(value, float): self.error(obj, value) - return t.cast(G, _validate_bounds(self, obj, value)) + return _validate_bounds(self, obj, value) # type:ignore[no-any-return] def from_string(self, s: str) -> G: if self.allow_none and s == "None": - return t.cast(G, None) - return t.cast(G, float(s)) + return None # type:ignore[return-value] + return float(s) # type:ignore[return-value] def subclass_init(self, cls: type[t.Any]) -> None: pass # fully opt out of instance_init @@ -2809,7 +2826,7 @@ class CFloat(Float[G, S]): value = float(value) except Exception: self.error(obj, value) - return t.cast(G, _validate_bounds(self, obj, value)) + return _validate_bounds(self, obj, value) # type:ignore[no-any-return] class Complex(TraitType[complex, t.Union[complex, float, int]]): @@ -2935,10 +2952,10 @@ class Unicode(TraitType[G, S]): def validate(self, obj: t.Any, value: t.Any) -> G: if isinstance(value, str): - return t.cast(G, value) + return value # type:ignore[return-value] if isinstance(value, bytes): try: - return t.cast(G, value.decode("ascii", "strict")) + return value.decode("ascii", "strict") # type:ignore[return-value] 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 @@ -2946,7 +2963,7 @@ class Unicode(TraitType[G, S]): def from_string(self, s: str) -> G: if self.allow_none and s == "None": - return t.cast(G, None) + return None # type:ignore[return-value] s = os.path.expanduser(s) if len(s) >= 2: # handle deprecated "1" @@ -2960,7 +2977,7 @@ class Unicode(TraitType[G, S]): DeprecationWarning, stacklevel=2, ) - return t.cast(G, s) + return s # type:ignore[return-value] def subclass_init(self, cls: type[t.Any]) -> None: pass # fully opt out of instance_init @@ -3008,7 +3025,7 @@ class CUnicode(Unicode[G, S], TraitType[str, t.Any]): def validate(self, obj: t.Any, value: t.Any) -> G: try: - return t.cast(G, str(value)) + return str(value) # type:ignore[return-value] except Exception: self.error(obj, value) @@ -3025,7 +3042,7 @@ class ObjectName(TraitType[str, str]): def validate(self, obj: t.Any, value: t.Any) -> str: value = self.coerce_str(obj, value) - if isinstance(value, str) and isidentifier(value): + if isinstance(value, str) and value.isidentifier(): return value self.error(obj, value) @@ -3041,7 +3058,7 @@ class DottedObjectName(ObjectName): 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(".")): + if isinstance(value, str) and all(a.isidentifier() for a in value.split(".")): return value self.error(obj, value) @@ -3091,22 +3108,22 @@ class Bool(TraitType[G, S]): def validate(self, obj: t.Any, value: t.Any) -> G: if isinstance(value, bool): - return t.cast(G, value) + return value # type:ignore[return-value] elif isinstance(value, int): if value == 1: - return t.cast(G, True) + return True # type:ignore[return-value] elif value == 0: - return t.cast(G, False) + return False # type:ignore[return-value] self.error(obj, value) def from_string(self, s: str) -> G: if self.allow_none and s == "None": - return t.cast(G, None) + return None # type:ignore[return-value] s = s.lower() if s in {"true", "1"}: - return t.cast(G, True) + return True # type:ignore[return-value] elif s in {"false", "0"}: - return t.cast(G, False) + return False # type:ignore[return-value] else: raise ValueError("%r is not 1, 0, true, or false") @@ -3163,7 +3180,7 @@ class CBool(Bool[G, S]): def validate(self, obj: t.Any, value: t.Any) -> G: try: - return t.cast(G, bool(value)) + return bool(value) # type:ignore[return-value] except Exception: self.error(obj, value) @@ -3220,7 +3237,7 @@ class Enum(TraitType[G, G]): def validate(self, obj: t.Any, value: t.Any) -> G: if self.values and value in self.values: - return t.cast(G, value) + return value # type:ignore[no-any-return] self.error(obj, value) def _choices_str(self, as_rst: bool = False) -> str: @@ -3247,7 +3264,7 @@ class Enum(TraitType[G, G]): try: return self.validate(None, s) except TraitError: - return t.cast(G, _safe_literal_eval(s)) + return _safe_literal_eval(s) # type:ignore[no-any-return] def subclass_init(self, cls: type[t.Any]) -> None: pass # fully opt out of instance_init @@ -3275,7 +3292,7 @@ class CaselessStrEnum(Enum[G]): for v in self.values or []: assert isinstance(v, str) if v.lower() == value.lower(): - return t.cast(G, v) + return v # type:ignore[return-value] self.error(obj, value) def _info(self, as_rst: bool = False) -> str: @@ -3479,14 +3496,12 @@ class Container(Instance[T]): if value is None: return value - value = self.validate_elements(obj, value) - - return t.cast(T, value) + return self.validate_elements(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 t.cast(T, value) + return value # type:ignore[no-any-return] for v in value: try: v = self._trait._validate(obj, v) @@ -3553,7 +3568,7 @@ class Container(Instance[T]): else: # backward-compat: allow item_from_string to ignore index arg def item_from_string(s: str, index: int | None = None) -> T | str: - return t.cast(T, self.item_from_string(s)) + return 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)] @@ -3565,7 +3580,7 @@ class Container(Instance[T]): Evaluated when parsing CLI configuration from a string """ if self._trait: - return t.cast(T, self._trait.from_string(s)) + return self._trait.from_string(s) # type:ignore[no-any-return] else: return s @@ -4051,7 +4066,7 @@ class Dict(Instance["dict[K, V]"]): if not isinstance(s, str): raise TypeError(f"from_string expects a string, got {s!r} of type {type(s)}") try: - return t.cast("dict[K, V]", self.from_string_list([s])) + return self.from_string_list([s]) # type:ignore[no-any-return] except Exception: test = _safe_literal_eval(s) if isinstance(test, dict): @@ -4109,7 +4124,7 @@ class Dict(Instance["dict[K, V]"]): value_trait = (self._per_key_traits or {}).get(key, self._value_trait) if value_trait: value = value_trait.from_string(value) - return t.cast("dict[K, V]", {key: value}) + return {key: value} # type:ignore[dict-item] class TCPAddress(TraitType[G, S]): @@ -4165,17 +4180,17 @@ class TCPAddress(TraitType[G, S]): if isinstance(value[0], str) and isinstance(value[1], int): port = value[1] if port >= 0 and port <= 65535: - return t.cast(G, value) + return value # type:ignore[return-value] self.error(obj, value) def from_string(self, s: str) -> G: if self.allow_none and s == "None": - return t.cast(G, None) + return None # type:ignore[return-value] if ":" not in s: raise ValueError("Require `ip:port`, got %r" % s) ip, port_str = s.split(":", 1) port = int(port_str) - return t.cast(G, (ip, port)) + return (ip, port) # type:ignore[return-value] class CRegExp(TraitType["re.Pattern[t.Any]", t.Union["re.Pattern[t.Any]", str]]): diff --git a/contrib/python/traitlets/py3/traitlets/utils/__init__.py b/contrib/python/traitlets/py3/traitlets/utils/__init__.py index 2695dc73357..10d6a80fa54 100644 --- a/contrib/python/traitlets/py3/traitlets/utils/__init__.py +++ b/contrib/python/traitlets/py3/traitlets/utils/__init__.py @@ -2,7 +2,7 @@ from __future__ import annotations import os import pathlib -from typing import Sequence +from collections.abc import Sequence # vestigal things from IPython_genutils. diff --git a/contrib/python/traitlets/py3/traitlets/utils/bunch.py b/contrib/python/traitlets/py3/traitlets/utils/bunch.py index 498563e0b5b..b1eb6c28de9 100644 --- a/contrib/python/traitlets/py3/traitlets/utils/bunch.py +++ b/contrib/python/traitlets/py3/traitlets/utils/bunch.py @@ -23,7 +23,7 @@ class Bunch(dict): # type:ignore[type-arg] self.__setitem__(key, value) def __dir__(self) -> list[str]: - # py2-compat: can't use super because dict doesn't have __dir__ - names = dir({}) + names: list[str] = [] + names.extend(super().__dir__()) names.extend(self.keys()) return names diff --git a/contrib/python/traitlets/py3/traitlets/utils/decorators.py b/contrib/python/traitlets/py3/traitlets/utils/decorators.py index 5b77d701dee..923959a7e9e 100644 --- a/contrib/python/traitlets/py3/traitlets/utils/decorators.py +++ b/contrib/python/traitlets/py3/traitlets/utils/decorators.py @@ -3,7 +3,7 @@ from __future__ import annotations import copy from inspect import Parameter, Signature, signature -from typing import Any, Type, TypeVar +from typing import Any, TypeVar from ..traitlets import HasTraits, Undefined @@ -16,7 +16,7 @@ def _get_default(value: Any) -> Any: T = TypeVar("T", bound=HasTraits) -def signature_has_traits(cls: Type[T]) -> Type[T]: +def signature_has_traits(cls: type[T]) -> type[T]: """Return a decorated class with a constructor signature that contain Trait names as kwargs.""" traits = [ (name, _get_default(value.default_value)) diff --git a/contrib/python/traitlets/py3/traitlets/utils/nested_update.py b/contrib/python/traitlets/py3/traitlets/utils/nested_update.py index 33a5ab8a77b..976beff6025 100644 --- a/contrib/python/traitlets/py3/traitlets/utils/nested_update.py +++ b/contrib/python/traitlets/py3/traitlets/utils/nested_update.py @@ -2,10 +2,10 @@ # Distributed under the terms of the Modified BSD License. from __future__ import annotations -from typing import Any, Dict +from typing import Any -def nested_update(this: Dict[Any, Any], that: Dict[Any, Any]) -> Dict[Any, Any]: +def nested_update(this: dict[Any, Any], that: dict[Any, Any]) -> dict[Any, Any]: """Merge two nested dictionaries. Effectively a recursive ``dict.update``. diff --git a/contrib/python/traitlets/py3/traitlets/utils/text.py b/contrib/python/traitlets/py3/traitlets/utils/text.py index 1c1ac208150..a177c2ca3e7 100644 --- a/contrib/python/traitlets/py3/traitlets/utils/text.py +++ b/contrib/python/traitlets/py3/traitlets/utils/text.py @@ -5,16 +5,33 @@ from __future__ import annotations import re import textwrap -from textwrap import dedent from textwrap import indent as _indent -from typing import List def indent(val: str) -> str: return _indent(val, " ") -def wrap_paragraphs(text: str, ncols: int = 80) -> List[str]: +def _dedent(text: str) -> str: + """Equivalent of textwrap.dedent that ignores unindented first line.""" + + if text.startswith("\n"): + # text starts with blank line, don't ignore the first line + return textwrap.dedent(text) + + # split first line + splits = text.split("\n", 1) + if len(splits) == 1: + # only one line + return textwrap.dedent(text) + + first, rest = splits + # dedent everything but the first line + rest = textwrap.dedent(rest) + return "\n".join([first, rest]) + + +def wrap_paragraphs(text: str, ncols: int = 80) -> list[str]: """Wrap multiple paragraphs to fit a specified width. This is equivalent to textwrap.wrap, but with support for multiple @@ -26,7 +43,7 @@ def wrap_paragraphs(text: str, ncols: int = 80) -> List[str]: list of complete paragraphs, wrapped to fill `ncols` columns. """ paragraph_re = re.compile(r"\n(\s*\n)+", re.MULTILINE) - text = dedent(text).strip() + text = _dedent(text).strip() paragraphs = paragraph_re.split(text)[::2] # every other entry is space out_ps = [] indent_re = re.compile(r"\n\s+", re.MULTILINE) diff --git a/contrib/python/traitlets/py3/ya.make b/contrib/python/traitlets/py3/ya.make index ed5c06a2c06..545b7dcfca3 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.14.3) +VERSION(5.15.0) LICENSE(BSD-3-Clause) |
