From bff3011b9cb499ff2dd688c0037686198583c630 Mon Sep 17 00:00:00 2001 From: "Michael J. Sullivan" Date: Wed, 18 Mar 2026 14:28:20 -0700 Subject: [PATCH] Pin a dev version of the mypy-typemap prototype, run some tests against it --- README.md | 25 ++++++++----- pyproject.toml | 2 +- scripts/update-mypy-pin | 19 ++++++++++ tests/test_astlike_1.py | 2 ++ tests/test_call.py | 3 +- tests/test_cqa.py | 43 ++++++++++------------ tests/test_dataclass_like.py | 8 ++--- tests/test_eval_call_with_types.py | 2 ++ tests/test_fastapilike_1.py | 7 +++- tests/test_fastapilike_2.py | 3 ++ tests/test_model_like.py | 4 +-- tests/test_mypy_proto.py | 56 +++++++++++++++++++++++++++++ tests/test_qblike.py | 3 +- tests/test_qblike_3.py | 3 ++ tests/test_schemalike.py | 2 +- tests/test_type_dir.py | 3 ++ tests/test_type_eval.py | 2 ++ uv.lock | 57 +++++++++++++++++++++--------- 18 files changed, 184 insertions(+), 60 deletions(-) create mode 100755 scripts/update-mypy-pin create mode 100644 tests/test_mypy_proto.py diff --git a/README.md b/README.md index 35432eb5..1f45816a 100644 --- a/README.md +++ b/README.md @@ -5,12 +5,19 @@ This is the development repository for which proposes TypeScript-inspired type-level introspection and construction facilities for the Python type system. +This repository contains an implementation of the proposed additions +to ``typing`` ([typemap/typing.py](typemap/typing.py)), exported as +the module ``typemap_extensions``. + +It also contains a **prototype** runtime evaluator +([typemap/type_eval](typemap/type_eval)). + Discussion of the PEP is at the [PEP 827 discussion thread](https://discuss.python.org/t/pep-827-type-manipulation/106353). -This repository also contains an implementation of the proposed -additions to ``typing`` ([typemap/typing.py](typemap/typing.py)), as well as a -**prototype** runtime evaluator ([typemap/type_eval](typemap/type_eval)). +A prototype typechecker implementation lives at +https://github.com/msullivan/mypy-typemap and is a test dependency of +this repo. ## Development @@ -21,9 +28,11 @@ additions to ``typing`` ([typemap/typing.py](typemap/typing.py)), as well as a ## Running the typechecker -If you have https://github.com/msullivan/mypy/tree/typemap active in a -venv, you can run it against at least some of the tests with -invocations like: - `mypy --python-version=3.14 tests/test_qblike_2.py` +The prototype mypy can be run from this repo with `uv run mypy`. +Stubs are set up so that importing ``typemap_extensions`` will do the +right thing. + +`uv run pytest tests/test_mypy_proto.py` will run the mypy prototype +against a supported subset of test files. -Not all of them run cleanly yet though. +You can also run the prototype mypy directly on a file with `uv run mypy ` diff --git a/pyproject.toml b/pyproject.toml index 088f9420..d15988d1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,7 +13,7 @@ include = ["typemap", "typemap_extensions"] test = [ "pytest>=7.0", "ruff", - "mypy==1.18.1", + "mypy @ git+https://github.com/msullivan/mypy-typemap@f49083e5cd7124df93ea1a0a844d60adf901c250", ] [tool.uv] diff --git a/scripts/update-mypy-pin b/scripts/update-mypy-pin new file mode 100755 index 00000000..2313046a --- /dev/null +++ b/scripts/update-mypy-pin @@ -0,0 +1,19 @@ +#!/bin/bash +set -e + +MYPY_DIR="${1:-../mypy}" + +if [ ! -d "$MYPY_DIR/.git" ]; then + echo "error: $MYPY_DIR is not a git repository" >&2 + exit 1 +fi + +REV=$(git -C "$MYPY_DIR" rev-parse HEAD) +echo "Pinning mypy to $REV (from $MYPY_DIR)" + +sed -i "s|mypy @ git+https://github.com/msullivan/mypy-typemap@[a-f0-9]*|mypy @ git+https://github.com/msullivan/mypy-typemap@$REV|" pyproject.toml + +uv sync + +git add pyproject.toml uv.lock +git commit -m "Pin mypy to mypy-typemap@${REV:0:12}" diff --git a/tests/test_astlike_1.py b/tests/test_astlike_1.py index a9bdf42d..957253b7 100644 --- a/tests/test_astlike_1.py +++ b/tests/test_astlike_1.py @@ -1,3 +1,5 @@ +# SKIP MYPY: runs forever! must debug + import pytest import typing diff --git a/tests/test_call.py b/tests/test_call.py index 8add338a..8aae6352 100644 --- a/tests/test_call.py +++ b/tests/test_call.py @@ -17,7 +17,8 @@ def func[*T, K: BaseTypedDict]( *args: Unpack[T], **kwargs: Unpack[K], -) -> NewProtocol[*[Member[c.name, int] for c in Iter[Attrs[K]]]]: ... +) -> NewProtocol[*[Member[c.name, int] for c in Iter[Attrs[K]]]]: + raise NotImplementedError def test_call_1(): diff --git a/tests/test_cqa.py b/tests/test_cqa.py index 278ee478..c14a3e4e 100644 --- a/tests/test_cqa.py +++ b/tests/test_cqa.py @@ -15,7 +15,6 @@ def project_root() -> pathlib.Path: def test_cqa_ruff_check(project_root): """Test that code passes ruff linting checks.""" - # Ruff respects pyproject.toml configuration and exclusions result = subprocess.run( [sys.executable, "-m", "ruff", "check", "."], capture_output=True, @@ -32,7 +31,6 @@ def test_cqa_ruff_check(project_root): def test_cqa_ruff_format_check(project_root): """Test that code is properly formatted according to ruff.""" - # Ruff format respects pyproject.toml exclusions result = subprocess.run( [sys.executable, "-m", "ruff", "format", "--check", "."], capture_output=True, @@ -48,26 +46,23 @@ def test_cqa_ruff_format_check(project_root): def test_cqa_mypy(project_root): - """Test that code passes mypy type checking.""" - # Mypy uses configuration from pyproject.toml - # Run on typemap -- tests not ready yet - for subdir in ["typemap"]: - result = subprocess.run( - [ - sys.executable, - "-m", - "mypy", - "--config-file", - project_root / "pyproject.toml", - subdir, - ], - capture_output=True, - text=True, - cwd=project_root, - ) + """Test that typemap/ passes mypy type checking.""" + result = subprocess.run( + [ + sys.executable, + "-m", + "mypy", + "--config-file", + project_root / "pyproject.toml", + "typemap", + ], + capture_output=True, + text=True, + cwd=project_root, + ) - if result.returncode != 0: - output = result.stdout - if result.stderr: - output += "\n\n" + result.stderr - pytest.fail(f"mypy validation failed:\n{output}", pytrace=False) + if result.returncode != 0: + output = result.stdout + if result.stderr: + output += "\n\n" + result.stderr + pytest.fail(f"mypy validation failed:\n{output}", pytrace=False) diff --git a/tests/test_dataclass_like.py b/tests/test_dataclass_like.py index ee6b7c68..73489f5f 100644 --- a/tests/test_dataclass_like.py +++ b/tests/test_dataclass_like.py @@ -4,7 +4,6 @@ ReadOnly, TypedDict, Never, - Self, ) import typemap_extensions as typing @@ -54,7 +53,7 @@ class Field[T: FieldArgs](typing.InitField[T]): Literal["__init__"], Callable[ typing.Params[ - typing.Param[Literal["self"], Self], + typing.Param[Literal["self"], T], *[ typing.Param[ p.name, @@ -80,7 +79,6 @@ class Field[T: FieldArgs](typing.InitField[T]): *[x for x in typing.Iter[typing.Members[T]]], ] - """ ``UpdateClass`` can then be used to create a class decorator (a la @@ -95,7 +93,7 @@ def dataclass_ish[T]( # Add the computed __init__ function InitFnType[T], ]: - pass + raise NotImplementedError """ @@ -112,7 +110,7 @@ def __init_subclass__[T]( # Add the computed __init__ function InitFnType[T], ]: - super().__init_subclass__() + pass # End PEP section diff --git a/tests/test_eval_call_with_types.py b/tests/test_eval_call_with_types.py index 8419e1a6..1c953b8e 100644 --- a/tests/test_eval_call_with_types.py +++ b/tests/test_eval_call_with_types.py @@ -1,3 +1,5 @@ +# SKIP MYPY + import pytest from typing import Callable, Generic, Literal, Self, TypeVar diff --git a/tests/test_fastapilike_1.py b/tests/test_fastapilike_1.py index d2d3e55d..4be7b523 100644 --- a/tests/test_fastapilike_1.py +++ b/tests/test_fastapilike_1.py @@ -1,3 +1,6 @@ +# SKIP MYPY: Invalid use of Self +# TODO: resolve + # We should have at least *one* test with this... from __future__ import annotations @@ -71,7 +74,9 @@ class _Default: type AddInit[T] = NewProtocol[ InitFnType[T], - *Members[T], + # TODO: mypy rejects this -- should it work? + # *Members[T], + *[t for t in Iter[Members[T]]], ] # Strip `| None` from a type by iterating over its union components diff --git a/tests/test_fastapilike_2.py b/tests/test_fastapilike_2.py index 54aa59c3..0d0d644f 100644 --- a/tests/test_fastapilike_2.py +++ b/tests/test_fastapilike_2.py @@ -1,3 +1,6 @@ +# SKIP MYPY: Invalid use of Self +# TODO: resolve + from typing import ( Callable, Literal, diff --git a/tests/test_model_like.py b/tests/test_model_like.py index 16e6bd48..39a65699 100644 --- a/tests/test_model_like.py +++ b/tests/test_model_like.py @@ -3,7 +3,7 @@ import pytest -from typing import _GenericAlias +from typing import _GenericAlias # type: ignore[attr-defined] import typemap_extensions as typing @@ -44,7 +44,7 @@ def __repr__(self): return f'{type(self).__name__}(**{self.__dict__})' -class _BaseModelAlias(_GenericAlias, _root=True): +class _BaseModelAlias(_GenericAlias, _root=True): # type: ignore[call-arg] def __call__(self, *args, **kwargs): return self.__origin__(*args, **kwargs, _alias=self) diff --git a/tests/test_mypy_proto.py b/tests/test_mypy_proto.py new file mode 100644 index 00000000..cd82a35f --- /dev/null +++ b/tests/test_mypy_proto.py @@ -0,0 +1,56 @@ +"""Run mypy on each test file that doesn't have # SKIP MYPY.""" + +import os +import pathlib +import subprocess +import sys + +import pytest + +PROJECT_ROOT = pathlib.Path(__file__).parent.parent + +# Set MYPY_SOURCE_DIR to use a local mypy source checkout. +_mypy_source = os.environ.get("MYPY_SOURCE_DIR") +MYPY_SOURCE_DIR = pathlib.Path(_mypy_source).resolve() if _mypy_source else None + + +def _collect_mypy_test_files(): + """Collect test files that don't have # SKIP MYPY.""" + tests_dir = pathlib.Path(__file__).parent + for path in sorted(tests_dir.glob("test_*.py")): + if path.name in ("test_cqa.py", "test_mypy_proto.py"): + continue + text = path.read_text() + if "# SKIP MYPY" not in text: + yield pytest.param(path, id=path.stem) + + +@pytest.mark.parametrize("test_file", _collect_mypy_test_files()) +def test_mypy(test_file): + """Test that individual test files pass mypy.""" + env = None + if MYPY_SOURCE_DIR: + env = {**os.environ, "PYTHONPATH": str(MYPY_SOURCE_DIR)} + cmd = [ + sys.executable, + "-m", + "mypy", + "--config-file", + str(PROJECT_ROOT / "pyproject.toml"), + str(test_file), + ] + result = subprocess.run( + cmd, + capture_output=True, + text=True, + cwd=PROJECT_ROOT, + env=env, + ) + + if result.returncode != 0: + output = result.stdout + if result.stderr: + output += "\n\n" + result.stderr + pytest.fail( + f"mypy failed on {test_file.name}:\n{output}", pytrace=False + ) diff --git a/tests/test_qblike.py b/tests/test_qblike.py index 85cbd395..95fbb317 100644 --- a/tests/test_qblike.py +++ b/tests/test_qblike.py @@ -51,7 +51,8 @@ def select[K: BaseTypedDict]( ] for c in Iter[Attrs[K]] ] -]: ... +]: + raise NotImplementedError # Basic filtering diff --git a/tests/test_qblike_3.py b/tests/test_qblike_3.py index 796c1e5d..724f9702 100644 --- a/tests/test_qblike_3.py +++ b/tests/test_qblike_3.py @@ -1,3 +1,6 @@ +# SKIP MYPY: a *lot* of errors +# TODO: investigate + import dataclasses import enum import textwrap diff --git a/tests/test_schemalike.py b/tests/test_schemalike.py index 1563799d..485baf22 100644 --- a/tests/test_schemalike.py +++ b/tests/test_schemalike.py @@ -49,7 +49,7 @@ class Property: Callable[ Params[ Param[Literal["self"], Schemaify[T]], - NamedParam[Literal["schema"], Schema, Literal["keyword"]], + NamedParam[Literal["schema"], Schema], ], p.type, ], diff --git a/tests/test_type_dir.py b/tests/test_type_dir.py index 18deaf8c..1ecdeb3d 100644 --- a/tests/test_type_dir.py +++ b/tests/test_type_dir.py @@ -1,3 +1,6 @@ +# SKIP MYPY: lots of weird testing stuff +# but TODO: some failures seem bad + import textwrap import typing from typing import Literal, Never, TypeVar, TypedDict, Union, ReadOnly diff --git a/tests/test_type_eval.py b/tests/test_type_eval.py index 6a42c47c..62d8e33b 100644 --- a/tests/test_type_eval.py +++ b/tests/test_type_eval.py @@ -1,3 +1,5 @@ +# SKIP MYPY + from __future__ import annotations import collections diff --git a/uv.lock b/uv.lock index c3bbda2f..6f3c9a48 100644 --- a/uv.lock +++ b/uv.lock @@ -21,24 +21,49 @@ wheels = [ ] [[package]] -name = "mypy" -version = "1.18.1" +name = "librt" +version = "0.8.1" source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/56/9c/b4b0c54d84da4a94b37bd44151e46d5e583c9534c7e02250b961b1b6d8a8/librt-0.8.1.tar.gz", hash = "sha256:be46a14693955b3bd96014ccbdb8339ee8c9346fbe11c1b78901b55125f14c73", size = 177471, upload-time = "2026-02-17T16:13:06.101Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c9/6a/907ef6800f7bca71b525a05f1839b21f708c09043b1c6aa77b6b827b3996/librt-0.8.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:6cfa7fe54fd4d1f47130017351a959fe5804bda7a0bc7e07a2cdbc3fdd28d34f", size = 66081, upload-time = "2026-02-17T16:12:12.766Z" }, + { url = "https://files.pythonhosted.org/packages/1b/18/25e991cd5640c9fb0f8d91b18797b29066b792f17bf8493da183bf5caabe/librt-0.8.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:228c2409c079f8c11fb2e5d7b277077f694cb93443eb760e00b3b83cb8b3176c", size = 68309, upload-time = "2026-02-17T16:12:13.756Z" }, + { url = "https://files.pythonhosted.org/packages/a4/36/46820d03f058cfb5a9de5940640ba03165ed8aded69e0733c417bb04df34/librt-0.8.1-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:7aae78ab5e3206181780e56912d1b9bb9f90a7249ce12f0e8bf531d0462dd0fc", size = 196804, upload-time = "2026-02-17T16:12:14.818Z" }, + { url = "https://files.pythonhosted.org/packages/59/18/5dd0d3b87b8ff9c061849fbdb347758d1f724b9a82241aa908e0ec54ccd0/librt-0.8.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:172d57ec04346b047ca6af181e1ea4858086c80bdf455f61994c4aa6fc3f866c", size = 206907, upload-time = "2026-02-17T16:12:16.513Z" }, + { url = "https://files.pythonhosted.org/packages/d1/96/ef04902aad1424fd7299b62d1890e803e6ab4018c3044dca5922319c4b97/librt-0.8.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6b1977c4ea97ce5eb7755a78fae68d87e4102e4aaf54985e8b56806849cc06a3", size = 221217, upload-time = "2026-02-17T16:12:17.906Z" }, + { url = "https://files.pythonhosted.org/packages/6d/ff/7e01f2dda84a8f5d280637a2e5827210a8acca9a567a54507ef1c75b342d/librt-0.8.1-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:10c42e1f6fd06733ef65ae7bebce2872bcafd8d6e6b0a08fe0a05a23b044fb14", size = 214622, upload-time = "2026-02-17T16:12:19.108Z" }, + { url = "https://files.pythonhosted.org/packages/1e/8c/5b093d08a13946034fed57619742f790faf77058558b14ca36a6e331161e/librt-0.8.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:4c8dfa264b9193c4ee19113c985c95f876fae5e51f731494fc4e0cf594990ba7", size = 221987, upload-time = "2026-02-17T16:12:20.331Z" }, + { url = "https://files.pythonhosted.org/packages/d3/cc/86b0b3b151d40920ad45a94ce0171dec1aebba8a9d72bb3fa00c73ab25dd/librt-0.8.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:01170b6729a438f0dedc4a26ed342e3dc4f02d1000b4b19f980e1877f0c297e6", size = 215132, upload-time = "2026-02-17T16:12:21.54Z" }, + { url = "https://files.pythonhosted.org/packages/fc/be/8588164a46edf1e69858d952654e216a9a91174688eeefb9efbb38a9c799/librt-0.8.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:7b02679a0d783bdae30d443025b94465d8c3dc512f32f5b5031f93f57ac32071", size = 215195, upload-time = "2026-02-17T16:12:23.073Z" }, + { url = "https://files.pythonhosted.org/packages/f5/f2/0b9279bea735c734d69344ecfe056c1ba211694a72df10f568745c899c76/librt-0.8.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:190b109bb69592a3401fe1ffdea41a2e73370ace2ffdc4a0e8e2b39cdea81b78", size = 237946, upload-time = "2026-02-17T16:12:24.275Z" }, + { url = "https://files.pythonhosted.org/packages/e9/cc/5f2a34fbc8aeb35314a3641f9956fa9051a947424652fad9882be7a97949/librt-0.8.1-cp314-cp314-win32.whl", hash = "sha256:e70a57ecf89a0f64c24e37f38d3fe217a58169d2fe6ed6d70554964042474023", size = 50689, upload-time = "2026-02-17T16:12:25.766Z" }, + { url = "https://files.pythonhosted.org/packages/a0/76/cd4d010ab2147339ca2b93e959c3686e964edc6de66ddacc935c325883d7/librt-0.8.1-cp314-cp314-win_amd64.whl", hash = "sha256:7e2f3edca35664499fbb36e4770650c4bd4a08abc1f4458eab9df4ec56389730", size = 57875, upload-time = "2026-02-17T16:12:27.465Z" }, + { url = "https://files.pythonhosted.org/packages/84/0f/2143cb3c3ca48bd3379dcd11817163ca50781927c4537345d608b5045998/librt-0.8.1-cp314-cp314-win_arm64.whl", hash = "sha256:0d2f82168e55ddefd27c01c654ce52379c0750ddc31ee86b4b266bcf4d65f2a3", size = 48058, upload-time = "2026-02-17T16:12:28.556Z" }, + { url = "https://files.pythonhosted.org/packages/d2/0e/9b23a87e37baf00311c3efe6b48d6b6c168c29902dfc3f04c338372fd7db/librt-0.8.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2c74a2da57a094bd48d03fa5d196da83d2815678385d2978657499063709abe1", size = 68313, upload-time = "2026-02-17T16:12:29.659Z" }, + { url = "https://files.pythonhosted.org/packages/db/9a/859c41e5a4f1c84200a7d2b92f586aa27133c8243b6cac9926f6e54d01b9/librt-0.8.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a355d99c4c0d8e5b770313b8b247411ed40949ca44e33e46a4789b9293a907ee", size = 70994, upload-time = "2026-02-17T16:12:31.516Z" }, + { url = "https://files.pythonhosted.org/packages/4c/28/10605366ee599ed34223ac2bf66404c6fb59399f47108215d16d5ad751a8/librt-0.8.1-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:2eb345e8b33fb748227409c9f1233d4df354d6e54091f0e8fc53acdb2ffedeb7", size = 220770, upload-time = "2026-02-17T16:12:33.294Z" }, + { url = "https://files.pythonhosted.org/packages/af/8d/16ed8fd452dafae9c48d17a6bc1ee3e818fd40ef718d149a8eff2c9f4ea2/librt-0.8.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9be2f15e53ce4e83cc08adc29b26fb5978db62ef2a366fbdf716c8a6c8901040", size = 235409, upload-time = "2026-02-17T16:12:35.443Z" }, + { url = "https://files.pythonhosted.org/packages/89/1b/7bdf3e49349c134b25db816e4a3db6b94a47ac69d7d46b1e682c2c4949be/librt-0.8.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:785ae29c1f5c6e7c2cde2c7c0e148147f4503da3abc5d44d482068da5322fd9e", size = 246473, upload-time = "2026-02-17T16:12:36.656Z" }, + { url = "https://files.pythonhosted.org/packages/4e/8a/91fab8e4fd2a24930a17188c7af5380eb27b203d72101c9cc000dbdfd95a/librt-0.8.1-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1d3a7da44baf692f0c6aeb5b2a09c5e6fc7a703bca9ffa337ddd2e2da53f7732", size = 238866, upload-time = "2026-02-17T16:12:37.849Z" }, + { url = "https://files.pythonhosted.org/packages/b9/e0/c45a098843fc7c07e18a7f8a24ca8496aecbf7bdcd54980c6ca1aaa79a8e/librt-0.8.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5fc48998000cbc39ec0d5311312dda93ecf92b39aaf184c5e817d5d440b29624", size = 250248, upload-time = "2026-02-17T16:12:39.445Z" }, + { url = "https://files.pythonhosted.org/packages/82/30/07627de23036640c952cce0c1fe78972e77d7d2f8fd54fa5ef4554ff4a56/librt-0.8.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:e96baa6820280077a78244b2e06e416480ed859bbd8e5d641cf5742919d8beb4", size = 240629, upload-time = "2026-02-17T16:12:40.889Z" }, + { url = "https://files.pythonhosted.org/packages/fb/c1/55bfe1ee3542eba055616f9098eaf6eddb966efb0ca0f44eaa4aba327307/librt-0.8.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:31362dbfe297b23590530007062c32c6f6176f6099646bb2c95ab1b00a57c382", size = 239615, upload-time = "2026-02-17T16:12:42.446Z" }, + { url = "https://files.pythonhosted.org/packages/2b/39/191d3d28abc26c9099b19852e6c99f7f6d400b82fa5a4e80291bd3803e19/librt-0.8.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cc3656283d11540ab0ea01978378e73e10002145117055e03722417aeab30994", size = 263001, upload-time = "2026-02-17T16:12:43.627Z" }, + { url = "https://files.pythonhosted.org/packages/b9/eb/7697f60fbe7042ab4e88f4ee6af496b7f222fffb0a4e3593ef1f29f81652/librt-0.8.1-cp314-cp314t-win32.whl", hash = "sha256:738f08021b3142c2918c03692608baed43bc51144c29e35807682f8070ee2a3a", size = 51328, upload-time = "2026-02-17T16:12:45.148Z" }, + { url = "https://files.pythonhosted.org/packages/7c/72/34bf2eb7a15414a23e5e70ecb9440c1d3179f393d9349338a91e2781c0fb/librt-0.8.1-cp314-cp314t-win_amd64.whl", hash = "sha256:89815a22daf9c51884fb5dbe4f1ef65ee6a146e0b6a8df05f753e2e4a9359bf4", size = 58722, upload-time = "2026-02-17T16:12:46.85Z" }, + { url = "https://files.pythonhosted.org/packages/b2/c8/d148e041732d631fc76036f8b30fae4e77b027a1e95b7a84bb522481a940/librt-0.8.1-cp314-cp314t-win_arm64.whl", hash = "sha256:bf512a71a23504ed08103a13c941f763db13fb11177beb3d9244c98c29fb4a61", size = 48755, upload-time = "2026-02-17T16:12:47.943Z" }, +] + +[[package]] +name = "mypy" +version = "1.20.0+dev.f49083e5cd7124df93ea1a0a844d60adf901c250" +source = { git = "https://github.com/msullivan/mypy-typemap?rev=f49083e5cd7124df93ea1a0a844d60adf901c250#f49083e5cd7124df93ea1a0a844d60adf901c250" } dependencies = [ + { name = "librt", marker = "platform_python_implementation != 'PyPy'" }, { name = "mypy-extensions" }, { name = "pathspec" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/14/a3/931e09fc02d7ba96da65266884da4e4a8806adcdb8a57faaacc6edf1d538/mypy-1.18.1.tar.gz", hash = "sha256:9e988c64ad3ac5987f43f5154f884747faf62141b7f842e87465b45299eea5a9", size = 3448447, upload-time = "2025-09-11T23:00:47.067Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/bf/87/7b173981466219eccc64c107cf8e5ab9eb39cc304b4c07df8e7881533e4f/mypy-1.18.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:ba24603c58e34dd5b096dfad792d87b304fc6470cbb1c22fd64e7ebd17edcc61", size = 12900265, upload-time = "2025-09-11T22:59:03.4Z" }, - { url = "https://files.pythonhosted.org/packages/ae/cc/b10e65bae75b18a5ac8f81b1e8e5867677e418f0dd2c83b8e2de9ba96ebd/mypy-1.18.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ed36662fb92ae4cb3cacc682ec6656208f323bbc23d4b08d091eecfc0863d4b5", size = 11942890, upload-time = "2025-09-11T23:00:00.607Z" }, - { url = "https://files.pythonhosted.org/packages/39/d4/aeefa07c44d09f4c2102e525e2031bc066d12e5351f66b8a83719671004d/mypy-1.18.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:040ecc95e026f71a9ad7956fea2724466602b561e6a25c2e5584160d3833aaa8", size = 12472291, upload-time = "2025-09-11T22:59:43.425Z" }, - { url = "https://files.pythonhosted.org/packages/c6/07/711e78668ff8e365f8c19735594ea95938bff3639a4c46a905e3ed8ff2d6/mypy-1.18.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:937e3ed86cb731276706e46e03512547e43c391a13f363e08d0fee49a7c38a0d", size = 13318610, upload-time = "2025-09-11T23:00:17.604Z" }, - { url = "https://files.pythonhosted.org/packages/ca/85/df3b2d39339c31d360ce299b418c55e8194ef3205284739b64962f6074e7/mypy-1.18.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:1f95cc4f01c0f1701ca3b0355792bccec13ecb2ec1c469e5b85a6ef398398b1d", size = 13513697, upload-time = "2025-09-11T22:58:59.534Z" }, - { url = "https://files.pythonhosted.org/packages/b1/df/462866163c99ea73bb28f0eb4d415c087e30de5d36ee0f5429d42e28689b/mypy-1.18.1-cp314-cp314-win_amd64.whl", hash = "sha256:e4f16c0019d48941220ac60b893615be2f63afedaba6a0801bdcd041b96991ce", size = 9985739, upload-time = "2025-09-11T22:58:51.644Z" }, - { url = "https://files.pythonhosted.org/packages/e0/1d/4b97d3089b48ef3d904c9ca69fab044475bd03245d878f5f0b3ea1daf7ce/mypy-1.18.1-py3-none-any.whl", hash = "sha256:b76a4de66a0ac01da1be14ecc8ae88ddea33b8380284a9e3eae39d57ebcbe26e", size = 2352212, upload-time = "2025-09-11T22:59:26.576Z" }, -] [[package]] name = "mypy-extensions" @@ -60,11 +85,11 @@ wheels = [ [[package]] name = "pathspec" -version = "0.12.1" +version = "1.0.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043, upload-time = "2023-12-10T22:30:45Z" } +sdist = { url = "https://files.pythonhosted.org/packages/fa/36/e27608899f9b8d4dff0617b2d9ab17ca5608956ca44461ac14ac48b44015/pathspec-1.0.4.tar.gz", hash = "sha256:0210e2ae8a21a9137c0d470578cb0e595af87edaa6ebf12ff176f14a02e0e645", size = 131200, upload-time = "2026-01-27T03:59:46.938Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191, upload-time = "2023-12-10T22:30:43.14Z" }, + { url = "https://files.pythonhosted.org/packages/ef/3c/2c197d226f9ea224a9ab8d197933f9da0ae0aac5b6e0f884e2b8d9c8e9f7/pathspec-1.0.4-py3-none-any.whl", hash = "sha256:fb6ae2fd4e7c921a165808a552060e722767cfa526f99ca5156ed2ce45a5c723", size = 55206, upload-time = "2026-01-27T03:59:45.137Z" }, ] [[package]] @@ -143,7 +168,7 @@ test = [ [package.metadata.requires-dev] test = [ - { name = "mypy", specifier = "==1.18.1" }, + { name = "mypy", git = "https://github.com/msullivan/mypy-typemap?rev=f49083e5cd7124df93ea1a0a844d60adf901c250" }, { name = "pytest", specifier = ">=7.0" }, { name = "ruff" }, ]