From f0f447827a5cf7001b56a3fe05b7701d0bc921d8 Mon Sep 17 00:00:00 2001 From: M Bussonnier Date: Fri, 29 May 2026 13:43:20 +0200 Subject: [PATCH 1/8] Fix docs build error on nbclients. single backticks did not resolve. --- traitlets/config/application.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/traitlets/config/application.py b/traitlets/config/application.py index b07ca818..1d475c58 100644 --- a/traitlets/config/application.py +++ b/traitlets/config/application.py @@ -216,7 +216,7 @@ def _classes_inc_parents( log_datefmt = Unicode( "%Y-%m-%d %H:%M:%S", - help="The date format used by logging formatters for `asctime`", + help="The date format used by logging formatters for `logging.Formatter` ``datefmt`` parameter", ).tag(config=True) log_format = Unicode( From 964e8398ff13c2a9b8cda8dd031865b115545c9b Mon Sep 17 00:00:00 2001 From: M Bussonnier Date: Wed, 3 Jun 2026 11:52:28 +0200 Subject: [PATCH 2/8] mypy must be >= 3.10 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 923d17f1..d52475a6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -88,7 +88,7 @@ build = [ [tool.mypy] files = "traitlets" -python_version = "3.9" +python_version = "3.10" strict = true enable_error_code = ["ignore-without-code", "redundant-expr", "truthy-bool"] pretty = true From 636f57fef7f982793d3c994c3c9825225b927cea Mon Sep 17 00:00:00 2001 From: krassowski <5832902+krassowski@users.noreply.github.com> Date: Wed, 3 Jun 2026 12:19:16 +0100 Subject: [PATCH 3/8] Add ceiling for mypy version --- pyproject.toml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index d52475a6..91a391a2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -33,9 +33,11 @@ Tracker = "https://github.com/ipython/traitlets/issues" [project.optional-dependencies] test = [ "argcomplete>=3.0.3", - "mypy>=1.7.0", - # see https://github.com/python/mypy/issues/20454 - "mypy>=1.7.0,<1.19 ; platform_python_implementation == 'PyPy'", + # See https://github.com/python/mypy/issues/20329 for PyPy support issue. + # Also, test assertiosn will need to be updated for 1.20+ because + # `reveal_type()` representations were simplified in + # https://github.com/python/mypy/pull/20929 + "mypy>=1.7.0,<1.19", "pre-commit", "pytest-mock", "pytest-mypy-testing", From b621c365032ee4024f271af885daa137b6805e78 Mon Sep 17 00:00:00 2001 From: krassowski <5832902+krassowski@users.noreply.github.com> Date: Wed, 3 Jun 2026 12:26:22 +0100 Subject: [PATCH 4/8] Update expectations for new optional/union syntax --- tests/test_typing.py | 66 ++++++++++++++++++++++---------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/tests/test_typing.py b/tests/test_typing.py index 94044747..b1090928 100644 --- a/tests/test_typing.py +++ b/tests/test_typing.py @@ -185,27 +185,27 @@ class T(HasTraits): t = T() reveal_type( - Unicode( # R: traitlets.traitlets.Unicode[builtins.str, Union[builtins.str, builtins.bytes]] + Unicode( # R: traitlets.traitlets.Unicode[builtins.str, builtins.str | builtins.bytes] "foo" ) ) reveal_type( - Unicode( # R: traitlets.traitlets.Unicode[builtins.str, Union[builtins.str, builtins.bytes]] + Unicode( # R: traitlets.traitlets.Unicode[builtins.str, builtins.str | builtins.bytes] "" ).tag(sync=True) ) reveal_type( - Unicode( # R: traitlets.traitlets.Unicode[Union[builtins.str, None], Union[builtins.str, builtins.bytes, None]] + Unicode( # R: traitlets.traitlets.Unicode[builtins.str | None, builtins.str | builtins.bytes | None] None, allow_none=True ) ) reveal_type( - Unicode( # R: traitlets.traitlets.Unicode[Union[builtins.str, None], Union[builtins.str, builtins.bytes, None]] + Unicode( # R: traitlets.traitlets.Unicode[builtins.str | None, builtins.str | builtins.bytes | None] None, allow_none=True ).tag(sync=True) ) reveal_type( - T.export_format # R: traitlets.traitlets.Unicode[builtins.str, Union[builtins.str, builtins.bytes]] + T.export_format # R: traitlets.traitlets.Unicode[builtins.str, builtins.str | builtins.bytes] ) reveal_type(t.export_format) # R: builtins.str @@ -312,37 +312,37 @@ class T(HasTraits): t = T() reveal_type( - Bool(True) # R: traitlets.traitlets.Bool[builtins.bool, Union[builtins.bool, builtins.int]] + Bool(True) # R: traitlets.traitlets.Bool[builtins.bool, builtins.bool | builtins.int] ) reveal_type( - Bool( # R: traitlets.traitlets.Bool[builtins.bool, Union[builtins.bool, builtins.int]] + Bool( # R: traitlets.traitlets.Bool[builtins.bool, builtins.bool | builtins.int] True ).tag(sync=True) ) reveal_type( - Bool( # R: traitlets.traitlets.Bool[Union[builtins.bool, None], Union[builtins.bool, builtins.int, None]] + Bool( # R: traitlets.traitlets.Bool[builtins.bool | None, builtins.bool | builtins.int | None] None, allow_none=True ) ) reveal_type( - Bool( # R: traitlets.traitlets.Bool[Union[builtins.bool, None], Union[builtins.bool, builtins.int, None]] + Bool( # R: traitlets.traitlets.Bool[builtins.bool | None, builtins.bool | builtins.int | None] None, allow_none=True ).tag(sync=True) ) reveal_type( - T.b # R: traitlets.traitlets.Bool[builtins.bool, Union[builtins.bool, builtins.int]] + T.b # R: traitlets.traitlets.Bool[builtins.bool, builtins.bool | builtins.int] ) reveal_type(t.b) # R: builtins.bool - reveal_type(t.ob) # R: Union[builtins.bool, None] + reveal_type(t.ob) # R: builtins.bool | None reveal_type( - T.b # R: traitlets.traitlets.Bool[builtins.bool, Union[builtins.bool, builtins.int]] + T.b # R: traitlets.traitlets.Bool[builtins.bool, builtins.bool | builtins.int] ) reveal_type( - T.ob # R: traitlets.traitlets.Bool[Union[builtins.bool, None], Union[builtins.bool, builtins.int, None]] + T.ob # R: traitlets.traitlets.Bool[builtins.bool | None, builtins.bool | builtins.int | None] ) - # we would expect this to be Optional[Union[bool, int]], but... - t.b = "foo" # E: Incompatible types in assignment (expression has type "str", variable has type "Union[bool, int]") [assignment] - t.b = None # E: Incompatible types in assignment (expression has type "None", variable has type "Union[bool, int]") [assignment] + # we would expect this to be Optional[bool | int], but... + t.b = "foo" # E: Incompatible types in assignment (expression has type "str", variable has type "bool | int") [assignment] + t.b = None # E: Incompatible types in assignment (expression has type "None", variable has type "bool | int") [assignment] @pytest.mark.mypy_testing @@ -355,21 +355,21 @@ class T(HasTraits): reveal_type(Int(True)) # R: traitlets.traitlets.Int[builtins.int, builtins.int] reveal_type(Int(True).tag(sync=True)) # R: traitlets.traitlets.Int[builtins.int, builtins.int] reveal_type( - Int( # R: traitlets.traitlets.Int[Union[builtins.int, None], Union[builtins.int, None]] + Int( # R: traitlets.traitlets.Int[builtins.int | None, builtins.int | None] None, allow_none=True ) ) reveal_type( - Int( # R: traitlets.traitlets.Int[Union[builtins.int, None], Union[builtins.int, None]] + Int( # R: traitlets.traitlets.Int[builtins.int | None, builtins.int | None] None, allow_none=True ).tag(sync=True) ) reveal_type(T.i) # R: traitlets.traitlets.Int[builtins.int, builtins.int] reveal_type(t.i) # R: builtins.int - reveal_type(t.oi) # R: Union[builtins.int, None] + reveal_type(t.oi) # R: builtins.int | None reveal_type(T.i) # R: traitlets.traitlets.Int[builtins.int, builtins.int] reveal_type( - T.oi # R: traitlets.traitlets.Int[Union[builtins.int, None], Union[builtins.int, None]] + T.oi # R: traitlets.traitlets.Int[builtins.int | None, builtins.int | None] ) t.i = "foo" # E: Incompatible types in assignment (expression has type "str", variable has type "int") [assignment] t.i = None # E: Incompatible types in assignment (expression has type "None", variable has type "int") [assignment] @@ -386,18 +386,18 @@ class T(HasTraits): reveal_type(CInt(42)) # R: traitlets.traitlets.CInt[builtins.int, Any] reveal_type(CInt(42).tag(sync=True)) # R: traitlets.traitlets.CInt[builtins.int, Any] reveal_type( - CInt(None, allow_none=True) # R: traitlets.traitlets.CInt[Union[builtins.int, None], Any] + CInt(None, allow_none=True) # R: traitlets.traitlets.CInt[builtins.int | None, Any] ) reveal_type( - CInt( # R: traitlets.traitlets.CInt[Union[builtins.int, None], Any] + CInt( # R: traitlets.traitlets.CInt[builtins.int | None, Any] None, allow_none=True ).tag(sync=True) ) reveal_type(T.i) # R: traitlets.traitlets.CInt[builtins.int, Any] reveal_type(t.i) # R: builtins.int - reveal_type(t.oi) # R: Union[builtins.int, None] + reveal_type(t.oi) # R: builtins.int | None reveal_type(T.i) # R: traitlets.traitlets.CInt[builtins.int, Any] - reveal_type(T.oi) # R: traitlets.traitlets.CInt[Union[builtins.int, None], Any] + reveal_type(T.oi) # R: traitlets.traitlets.CInt[builtins.int | None, Any] @pytest.mark.mypy_testing @@ -416,17 +416,17 @@ class T(HasTraits): sync=True ) ) - reveal_type(t.otcp) # R: Union[tuple[builtins.str, builtins.int], None] + reveal_type(t.otcp) # R: 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[tuple[builtins.str, builtins.int] | None, 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[tuple[builtins.str, builtins.int] | None, 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.otcp = "foo" # E: Incompatible types in assignment (expression has type "str", variable has type "tuple[str, int] | None") [assignment] t.tcp = None # E: Incompatible types in assignment (expression has type "None", variable has type "tuple[str, int]") [assignment] @@ -441,14 +441,14 @@ class T(HasTraits): reveal_type(t.inst) # R: tests.test_typing.Foo reveal_type(T.inst) # R: traitlets.traitlets.Instance[tests.test_typing.Foo] reveal_type(T.inst.tag(sync=True)) # R: traitlets.traitlets.Instance[tests.test_typing.Foo] - reveal_type(t.oinst) # R: Union[tests.test_typing.Foo, None] - reveal_type(t.oinst_string) # R: Union[Any, None] - reveal_type(T.oinst) # R: traitlets.traitlets.Instance[Union[tests.test_typing.Foo, None]] + reveal_type(t.oinst) # R: tests.test_typing.Foo | None + reveal_type(t.oinst_string) # R: Any | None + reveal_type(T.oinst) # R: traitlets.traitlets.Instance[tests.test_typing.Foo | None] reveal_type( - T.oinst.tag( # R: traitlets.traitlets.Instance[Union[tests.test_typing.Foo, None]] + T.oinst.tag( # R: traitlets.traitlets.Instance[tests.test_typing.Foo | None] sync=True ) ) t.inst = "foo" # E: Incompatible types in assignment (expression has type "str", variable has type "Foo") [assignment] - t.oinst = "foo" # E: Incompatible types in assignment (expression has type "str", variable has type "Optional[Foo]") [assignment] + t.oinst = "foo" # E: Incompatible types in assignment (expression has type "str", variable has type "Foo | None") [assignment] t.inst = None # E: Incompatible types in assignment (expression has type "None", variable has type "Foo") [assignment] From d27c7fbd36a9c2579f6906ca02ca19a84a3b420b Mon Sep 17 00:00:00 2001 From: krassowski <5832902+krassowski@users.noreply.github.com> Date: Wed, 3 Jun 2026 12:46:03 +0100 Subject: [PATCH 5/8] Narrow down the range --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 91a391a2..38345414 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -34,10 +34,10 @@ Tracker = "https://github.com/ipython/traitlets/issues" test = [ "argcomplete>=3.0.3", # See https://github.com/python/mypy/issues/20329 for PyPy support issue. - # Also, test assertiosn will need to be updated for 1.20+ because + # Also, test assertions will need to be updated for 1.20+ because # `reveal_type()` representations were simplified in # https://github.com/python/mypy/pull/20929 - "mypy>=1.7.0,<1.19", + "mypy>=1.18.0,<1.19", "pre-commit", "pytest-mock", "pytest-mypy-testing", From a9d9c222c0b18b45c2802a0a714627e4598b1cfd Mon Sep 17 00:00:00 2001 From: krassowski <5832902+krassowski@users.noreply.github.com> Date: Wed, 3 Jun 2026 12:47:57 +0100 Subject: [PATCH 6/8] Fix downstream --- .github/workflows/downstream.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/downstream.yml b/.github/workflows/downstream.yml index 92b13b82..f0f87e14 100644 --- a/.github/workflows/downstream.yml +++ b/.github/workflows/downstream.yml @@ -19,7 +19,7 @@ jobs: - uses: jupyterlab/maintainer-tools/.github/actions/downstream-test@v1 with: package_name: ipython - package_spec: -e ".[test]" + package_spec: -e .[test] nbconvert: runs-on: ubuntu-latest @@ -30,7 +30,7 @@ jobs: - uses: jupyterlab/maintainer-tools/.github/actions/downstream-test@v1 with: package_name: nbconvert - package_spec: -e ".[test]" + package_spec: -e .[test] jupyter_server: runs-on: ubuntu-latest From 2637ae7ba1db96c177a8bcfad15e7fe6d0e6a859 Mon Sep 17 00:00:00 2001 From: krassowski <5832902+krassowski@users.noreply.github.com> Date: Wed, 3 Jun 2026 12:51:44 +0100 Subject: [PATCH 7/8] Try .17 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 38345414..c10c76e2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -37,7 +37,7 @@ test = [ # Also, test assertions will need to be updated for 1.20+ because # `reveal_type()` representations were simplified in # https://github.com/python/mypy/pull/20929 - "mypy>=1.18.0,<1.19", + "mypy>=1.17.0,<1.19", "pre-commit", "pytest-mock", "pytest-mypy-testing", From d17a968efb413a40cc93ead68a57cc6c5cda1582 Mon Sep 17 00:00:00 2001 From: krassowski <5832902+krassowski@users.noreply.github.com> Date: Wed, 3 Jun 2026 13:05:48 +0100 Subject: [PATCH 8/8] Test with newer pypy? --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index dcbe96b0..adec8cac 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -31,7 +31,7 @@ jobs: - os: ubuntu-latest python-version: "3.12" - os: ubuntu-latest - python-version: "pypy-3.10" + python-version: "pypy-3.11" steps: - uses: actions/checkout@v4