diff --git a/AutoDuck/document_object.py b/AutoDuck/document_object.py index 9d9139699d..82be3a8a21 100644 --- a/AutoDuck/document_object.py +++ b/AutoDuck/document_object.py @@ -73,6 +73,8 @@ def GetDocument(fname="pywin32-document.xml"): handler = categoryHandler() parser.setContentHandler(handler) parser.parse(fname) + if handler.document is None: + raise RuntimeError("document was not set by parser") return handler.document diff --git a/adodbapi/adodbapi.py b/adodbapi/adodbapi.py index cbc0c0f0e1..38426b4613 100644 --- a/adodbapi/adodbapi.py +++ b/adodbapi/adodbapi.py @@ -27,6 +27,8 @@ or CPython 3.4 or later. """ +from __future__ import annotations + __version__ = "2.6.2.0" version = "adodbapi v" + __version__ @@ -35,6 +37,8 @@ import os import sys import weakref +from collections.abc import Callable, Mapping +from typing import NoReturn from . import ado_consts as adc, apibase as api, process_connect_string @@ -59,9 +63,6 @@ def getIndexedValue(obj, index): return obj(index) -from collections.abc import Mapping - - # ----------------- The .connect method ----------------- def make_COM_connecter(): try: @@ -238,7 +239,9 @@ def __init__(self): # now define the instance attributes self.cursors = weakref.WeakValueDictionary[int, Cursor]() self.dbms_name = "" self.dbms_version = "" - self.errorhandler = None # use the standard error handler for this instance + self.errorhandler: ( + Callable[[Connection, Cursor, type[api.Error], object], NoReturn] | None + ) = None # use the standard error handler for this instance self.transaction_level = 0 # 0 == Not in a transaction, at the top level self._autocommit = False @@ -401,6 +404,9 @@ def _rollback(self): except Exception as e: self._raiseConnectionError(api.ProgrammingError, e) + # TODO: Use a property+setter instead + variantConversions: api.MultiMap + def __setattr__(self, name, value): if name == "autocommit": # extension: allow user to turn autocommit on or off if self.supportsTransactions: @@ -542,17 +548,21 @@ class Cursor: ## errorhandler... ## allows the programmer to override the connection's default error handler - def __init__(self, connection): + def __init__(self, connection: Connection): self.command = None self._ado_prepared = False - self.messages = [] + self.messages: list[tuple[type[api.Error], object]] = [] self.connection = connection - self.paramstyle = connection.paramstyle # used for overriding the paramstyle - self._parameter_names = [] + self.paramstyle = connection.paramstyle + """Used for overriding the paramstyle""" + self._parameter_names: list[str] = [] self.recordset_is_remote = False - self.rs = None # the ADO recordset for this cursor - self.converters = [] # conversion function for each column - self.columnNames = {} # names of columns {lowercase name : number,...} + self.rs = None + """The ADO recordset for this cursor""" + self.converters: list[Callable[[object], object]] = [] + """Conversion function for each column""" + self.columnNames: dict[str, int] = {} + """Names of columns {lowercase name : number,...}""" self.numberOfColumns = 0 self._description = None self.rowcount = -1 @@ -587,7 +597,9 @@ def __exit__(self, exc_type, exc_val, exc_tb): "Allow database cursors to be used with context managers." self.close() - def _raiseCursorError(self, errorclass, errorvalue): + def _raiseCursorError( + self, errorclass: type[api.Error], errorvalue: object + ) -> NoReturn: eh = self.errorhandler if eh is None: eh = api.standardErrorHandler @@ -613,9 +625,8 @@ def build_column_info(self, recordset): for i in range(self.numberOfColumns): f = getIndexedValue(self.rs.Fields, i) try: - self.converters.append( - varCon[f.Type] - ) # conversion function for this column + # conversion function for this column + self.converters.append(varCon[f.Type]) except KeyError: self._raiseCursorError( api.InternalError, "Data column of Unknown ADO type=%s" % f.Type @@ -716,7 +727,7 @@ def _new_command(self, command_type=adc.adCmdText): if self.connection is None: self._raiseCursorError(api.InterfaceError, None) - return + return # Still return in case a custom errorHandler doesn't raise try: self.cmd = Dispatch("ADODB.Command") self.cmd.ActiveConnection = self.connection.connector @@ -1036,7 +1047,7 @@ def _fetch(self, limit=None): self._raiseCursorError( api.FetchFailedError, "fetch() on closed connection or empty query set" ) - return + return # Still return in case a custom errorHandler doesn't raise if self.rs.State == adc.adStateClosed or self.rs.BOF or self.rs.EOF: return list() diff --git a/adodbapi/apibase.py b/adodbapi/apibase.py index 87a5317eb8..f1fb298489 100644 --- a/adodbapi/apibase.py +++ b/adodbapi/apibase.py @@ -13,15 +13,20 @@ import sys import time from collections.abc import Callable, Iterable, Mapping +from typing import TYPE_CHECKING, NoReturn -# noinspection PyUnresolvedReferences from . import ado_consts as adc +if TYPE_CHECKING: + from adodbapi.adodbapi import Connection, Cursor + verbose = False # debugging flag # ------- Error handlers ------ -def standardErrorHandler(connection, cursor, errorclass, errorvalue): +def standardErrorHandler( + connection: Connection, cursor: Cursor, errorclass: type[Error], errorvalue: object +) -> NoReturn: err = (errorclass, errorvalue) try: connection.messages.append(err) diff --git a/adodbapi/examples/db_print.py b/adodbapi/examples/db_print.py index 33a6511388..52a6a5bc75 100644 --- a/adodbapi/examples/db_print.py +++ b/adodbapi/examples/db_print.py @@ -50,7 +50,7 @@ print("") print("result data description is:") print(" NAME Type DispSize IntrnlSz Prec Scale Null?") - for d in c.description: + for d in c.description or (): print( ("%16s %-12s %8s %8d %4d %5d %s") % (d[0], adc.adTypeNames[d[1]], d[2], d[3], d[4], d[5], bool(d[6])) @@ -59,10 +59,10 @@ print("str() of first five records are...") # get the results - db = c.fetchmany(5) + db_result = c.fetchmany(5) # print them - for rec in db: + for rec in db_result: print(rec) print("") diff --git a/com/win32com/client/__init__.py b/com/win32com/client/__init__.py index b4aae20a8c..3217a97aa0 100644 --- a/com/win32com/client/__init__.py +++ b/com/win32com/client/__init__.py @@ -521,6 +521,8 @@ def register_record_class(cls): # The base of all makepy generated classes ############################################ class DispatchBaseClass: + Properties_: DispatchBaseClass + def __init__(self, oobj=None): if oobj is None: oobj = pythoncom.new(self.CLSID) diff --git a/com/win32com/client/combrowse.py b/com/win32com/client/combrowse.py index 46d0fef2af..585e1166b1 100644 --- a/com/win32com/client/combrowse.py +++ b/com/win32com/client/combrowse.py @@ -24,6 +24,7 @@ """ import sys +from typing import Any, TypeVar import pythoncom import pywintypes @@ -33,8 +34,14 @@ from pywin.tools import browser from win32com.client import util +# Representing the full set of HLICOM subclasses generics +# would also require statically exposing many types from pythoncom. +# So make the type parameter optional and using `__init__` inference for now, +# and consider relying on typeshed's `pywin32-stubs` later. +_HLICOMT = TypeVar("_HLICOMT", default=Any) # incomplete -class HLIRoot(browser.HLIPythonObject): + +class HLIRoot(browser.HLIPythonObject[None]): def __init__(self, title): super().__init__(name=title) @@ -51,7 +58,7 @@ def __lt__(self, other): return self.name < other.name -class HLICOM(browser.HLIPythonObject): +class HLICOM(browser.HLIPythonObject[_HLICOMT]): def GetText(self): return self.name diff --git a/com/win32com/client/dynamic.py b/com/win32com/client/dynamic.py index 3738da9031..5306cd6dc3 100644 --- a/com/win32com/client/dynamic.py +++ b/com/win32com/client/dynamic.py @@ -16,6 +16,8 @@ """ +from __future__ import annotations + import traceback from itertools import chain from types import MethodType @@ -185,6 +187,8 @@ def DumbDispatch( class CDispatch: + Properties_: CDispatch + def __init__(self, IDispatch, olerepr, userName=None, lazydata=None): if userName is None: userName = "" diff --git a/pyrightconfig.json b/pyrightconfig.json index 6bf7f9184f..b2824c83a1 100644 --- a/pyrightconfig.json +++ b/pyrightconfig.json @@ -37,7 +37,6 @@ "reportCallIssue": "warning", "reportOperatorIssue": "warning", "reportOptionalCall": "warning", - "reportOptionalIterable": "warning", "reportOptionalMemberAccess": "warning", "reportOptionalSubscript": "warning", // Too many dynamically generated modules. This will require type stubs to properly fix. diff --git a/pythonwin/pywin/debugger/debugger.py b/pythonwin/pywin/debugger/debugger.py index 72b9cf2dc4..803e1a3a0a 100644 --- a/pythonwin/pywin/debugger/debugger.py +++ b/pythonwin/pywin/debugger/debugger.py @@ -1,12 +1,13 @@ -# debugger.py +"""A debugger for Pythonwin. Built from pdb. -# A debugger for Pythonwin. Built from pdb. +Mark Hammond (MHammond@skippinet.com.au) - Dec 94. -# Mark Hammond (MHammond@skippinet.com.au) - Dec 94. +usage: +>>> import pywin.debugger +>>> pywin.debugger.GetDebugger().run("command") +""" -# usage: -# >>> import pywin.debugger -# >>> pywin.debugger.GetDebugger().run("command") +from __future__ import annotations import bdb import os @@ -15,6 +16,7 @@ import sys import traceback import types +from typing import TypeVar import commctrl import pywin.docking.DockingBar @@ -28,6 +30,8 @@ from .dbgcon import * +_T = TypeVar("_T") + LVN_ENDLABELEDIT = commctrl.LVN_ENDLABELEDITW @@ -44,11 +48,11 @@ def _LineStateToMarker(ls): return MARKER_BREAKPOINT -class HierListItem(browser.HLIPythonObject): +class HierListItem(browser.HLIPythonObject[_T]): pass -class HierFrameItem(HierListItem): +class HierFrameItem(HierListItem[types.FrameType]): def __init__(self, frame, debugger): HierListItem.__init__(self, frame, repr(frame)) self.debugger = debugger @@ -89,16 +93,16 @@ def TakeDefaultAction(self): return 1 -class HierFrameDict(browser.HLIDict): - def __init__(self, dict, name, bitmapColumn): +class HierFrameDict(browser.HLIDict[str, _T]): + def __init__(self, dict: dict[str, _T], name, bitmapColumn): self.bitmapColumn = bitmapColumn - browser.HLIDict.__init__(self, dict, name) + super().__init__(dict, name) def GetBitmapColumn(self): return self.bitmapColumn -class NoStackAvailableItem(HierListItem): +class NoStackAvailableItem(HierListItem[None]): def __init__(self, why): HierListItem.__init__(self, None, why) @@ -112,7 +116,7 @@ def GetBitmapColumn(self): return 8 -class HierStackRoot(HierListItem): +class HierStackRoot(HierListItem["Debugger"]): def __init__(self, debugger): HierListItem.__init__(self, debugger, None) self.last_stack = [] diff --git a/pythonwin/pywin/tools/browser.py b/pythonwin/pywin/tools/browser.py index b5629dc065..608cfb8938 100644 --- a/pythonwin/pywin/tools/browser.py +++ b/pythonwin/pywin/tools/browser.py @@ -1,12 +1,18 @@ -# basic module browser. +""" +basic module browser. + +usage: +>>> import browser +>>> browser.Browse() +or +>>> browser.Browse(your_module) +""" + +from __future__ import annotations -# usage: -# >>> import browser -# >>> browser.Browse() -# or -# >>> browser.Browse(your_module) import sys import types +from typing import TYPE_CHECKING, Any, Generic, TypeVar import __main__ import win32ui @@ -14,13 +20,25 @@ from . import hierlist +if TYPE_CHECKING: + from _typeshed import SupportsLenAndGetItem + +_T = TypeVar("_T") +_KT = TypeVar("_KT") +_VT = TypeVar("_VT") +_SequenceT = TypeVar("_SequenceT", bound="SupportsLenAndGetItem[Any]") + special_names = ["__doc__", "__name__", "__self__"] # # HierList items -class HLIPythonObject(hierlist.HierListItem): - def __init__(self, myobject=None, name=None): +class HLIPythonObject(hierlist.HierListItem, Generic[_T]): + def __init__( + self, + myobject: _T = None, # type: ignore[assignment] # False-positive, None is part of the bound type + name=None, + ): hierlist.HierListItem.__init__(self) self.myobject = myobject self.knownExpandable = None @@ -129,7 +147,7 @@ def TakeDefaultAction(self): ShowObject(self.myobject, self.name) -class HLIDocString(HLIPythonObject): +class HLIDocString(HLIPythonObject[str]): def GetHLIType(self): return "DocString" @@ -143,22 +161,22 @@ def GetBitmapColumn(self): return 6 -class HLIModule(HLIPythonObject): +class HLIModule(HLIPythonObject[types.ModuleType]): def GetHLIType(self): return "Module" -class HLIFrame(HLIPythonObject): +class HLIFrame(HLIPythonObject[types.FrameType]): def GetHLIType(self): return "Stack Frame" -class HLITraceback(HLIPythonObject): +class HLITraceback(HLIPythonObject[types.TracebackType]): def GetHLIType(self): return "Traceback" -class HLIClass(HLIPythonObject): +class HLIClass(HLIPythonObject[type]): def GetHLIType(self): return "Class" @@ -170,7 +188,7 @@ def GetSubList(self): return ret -class HLIMethod(HLIPythonObject): +class HLIMethod(HLIPythonObject[str]): # myobject is just a string for methods. def GetHLIType(self): return "Method" @@ -179,7 +197,7 @@ def GetText(self): return "Method: " + self.myobject + "()" -class HLICode(HLIPythonObject): +class HLICode(HLIPythonObject[types.CodeType]): def GetHLIType(self): return "Code" @@ -197,7 +215,7 @@ def GetSubList(self): return ret -class HLIInstance(HLIPythonObject): +class HLIInstance(HLIPythonObject[_T]): def GetHLIType(self): return "Instance" @@ -219,12 +237,12 @@ def GetSubList(self): return ret -class HLIBuiltinFunction(HLIPythonObject): +class HLIBuiltinFunction(HLIPythonObject[types.BuiltinFunctionType]): def GetHLIType(self): return "Builtin Function" -class HLIFunction(HLIPythonObject): +class HLIFunction(HLIPythonObject[types.FunctionType]): def GetHLIType(self): return "Function" @@ -240,7 +258,7 @@ def GetSubList(self): return ret -class HLISeq(HLIPythonObject): +class HLISeq(HLIPythonObject[_SequenceT]): def GetHLIType(self): return "Sequence (abstract!)" @@ -257,17 +275,17 @@ def GetSubList(self): return ret -class HLIList(HLISeq): +class HLIList(HLISeq[list[_T]]): def GetHLIType(self): return "List" -class HLITuple(HLISeq): +class HLITuple(HLISeq[tuple[_T]]): def GetHLIType(self): return "Tuple" -class HLIDict(HLIPythonObject): +class HLIDict(HLIPythonObject[dict[_KT, _VT]]): def GetHLIType(self): return "Dict" @@ -285,7 +303,7 @@ def GetSubList(self): # strings and Unicode have builtin methods, but we don't really want to see these -class HLIString(HLIPythonObject): +class HLIString(HLIPythonObject[str]): def IsExpandable(self): return 0 diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000000..a1ce2cec70 --- /dev/null +++ b/uv.lock @@ -0,0 +1,270 @@ +version = 1 +revision = 3 +requires-python = ">=3.14" + +[manifest] + +[manifest.dependency-groups] +checkers = [ + { name = "clang-format", specifier = "==18.1.8" }, + { name = "ruff", specifier = "==0.14.14" }, +] +dev = [ + { name = "clang-format", specifier = "==18.1.8" }, + { name = "mypy", marker = "python_full_version >= '3.9'", specifier = "==1.16.*" }, + { name = "pre-commit" }, + { name = "pyopengl" }, + { name = "pyright", specifier = "==1.1.401" }, + { name = "ruff", specifier = "==0.14.14" }, + { name = "types-setuptools" }, +] +type-checkers = [ + { name = "mypy", marker = "python_full_version >= '3.9'", specifier = "==1.16.*" }, + { name = "pyopengl" }, + { name = "pyright", specifier = "==1.1.401" }, + { name = "types-setuptools" }, +] + +[[package]] +name = "cfgv" +version = "3.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4e/b5/721b8799b04bf9afe054a3899c6cf4e880fcf8563cc71c15610242490a0c/cfgv-3.5.0.tar.gz", hash = "sha256:d5b1034354820651caa73ede66a6294d6e95c1b00acc5e9b098e917404669132", size = 7334, upload-time = "2025-11-19T20:55:51.612Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/db/3c/33bac158f8ab7f89b2e59426d5fe2e4f63f7ed25df84c036890172b412b5/cfgv-3.5.0-py2.py3-none-any.whl", hash = "sha256:a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0", size = 7445, upload-time = "2025-11-19T20:55:50.744Z" }, +] + +[[package]] +name = "clang-format" +version = "18.1.8" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/ef/e8d7160175753f11c939a842fa2b4fcd1221136b7232b0570e890ff1d96d/clang_format-18.1.8.tar.gz", hash = "sha256:065ddb7fdd0cb329976115fa03500dd560d9753dd50c25a269776648e6e6bf35", size = 11078, upload-time = "2024-06-28T10:18:22.183Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/15/36/974be8a5b9776d39a2f96746db80c3d963b232ab9660fd0891765b5b6a17/clang_format-18.1.8-py2.py3-none-macosx_10_9_x86_64.whl", hash = "sha256:7c41e2521b7e6ba706cc5d1c3e95eed9a41c1522244e23624e1518991f02a604", size = 1375281, upload-time = "2024-06-28T10:17:51.843Z" }, + { url = "https://files.pythonhosted.org/packages/18/4c/5f82861a89cbdd99b1525c353a35a034d2eb3ee392348b4ba713dc697a3e/clang_format-18.1.8-py2.py3-none-macosx_11_0_arm64.whl", hash = "sha256:4be2b5d983a0cc1ef90a224b599f5928d82ce31154ba69accfdcb670aea62f40", size = 1332812, upload-time = "2024-06-28T10:17:54.67Z" }, + { url = "https://files.pythonhosted.org/packages/37/00/bd44b4d3e5d80560297d49ee7be0ed87260453a5115c6f613527f122a2e2/clang_format-18.1.8-py2.py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d2db077523bd4517b41fa6adb2e5ee63fc91bc7b641dc6e28b959fa8050cf41b", size = 1669509, upload-time = "2024-06-28T10:17:56.89Z" }, + { url = "https://files.pythonhosted.org/packages/df/64/ce934b3d1002fdb87994fd15e7fd2eb7eb4e6770ccf9dac46f03d74edbe6/clang_format-18.1.8-py2.py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:310206c21fa8177c019a3871de8c5400e51867376cae630ee3d1610aa6c93816", size = 1853376, upload-time = "2024-06-28T10:17:58.541Z" }, + { url = "https://files.pythonhosted.org/packages/4f/22/937978c6ef5604a6441c214d7350d347d6796f69acd127631e0aa24f1933/clang_format-18.1.8-py2.py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c11ecdae9cd9068ed010b7cc5fa9d3d2ae08de8bbfa493df865774ad63fd7d76", size = 2597740, upload-time = "2024-06-28T10:18:00.256Z" }, + { url = "https://files.pythonhosted.org/packages/08/20/5b2928c74c3d8ceab9d60348d26e177e7c2dc39c43a5e6a8b9865aa66c84/clang_format-18.1.8-py2.py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2a73a50e17c94325712631c15e5b210e374841bbeefb915f12934b902310df7b", size = 1670549, upload-time = "2024-06-28T10:18:04.565Z" }, + { url = "https://files.pythonhosted.org/packages/05/a8/d94adc8025c6a313bed5da994c421fff7dc4288d20028b309b1d45e15032/clang_format-18.1.8-py2.py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2de122b8aa78ba49e326f974131caab2c79f4ae877c227cd4e3e5d82a98d21e5", size = 1677341, upload-time = "2024-06-28T10:18:06.795Z" }, + { url = "https://files.pythonhosted.org/packages/a7/93/48c0fd19ac5d6221059049facf0e1a91572e7f811e57f94d4882e37ee8a7/clang_format-18.1.8-py2.py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:7d71869103d0f27be3c4930bea59dc6325177a259ba321a04663a231432ec343", size = 2755836, upload-time = "2024-06-28T10:18:08.425Z" }, + { url = "https://files.pythonhosted.org/packages/b2/10/d691db9818417687627ae388417ef97f6ca8b8e489a2ca071a8f32ea438e/clang_format-18.1.8-py2.py3-none-musllinux_1_2_i686.whl", hash = "sha256:ea103b3ae5b0941152cd29c67eab086aafc98675370ac13581005807680132aa", size = 3047804, upload-time = "2024-06-28T10:18:10.149Z" }, + { url = "https://files.pythonhosted.org/packages/c0/99/5d15eacc59a447afb0a2a3ffd1a5aace3a8eae4ff20be06530cc043fe9b1/clang_format-18.1.8-py2.py3-none-musllinux_1_2_ppc64le.whl", hash = "sha256:82c5dd546efa80a838bb9fd4cf6f6e37d85301c0bca13cd79ab5749422ca35a1", size = 3235427, upload-time = "2024-06-28T10:18:11.902Z" }, + { url = "https://files.pythonhosted.org/packages/d8/9a/1b390ff1eb080a96f113e813bb9f0104c8b998e3ebe78ad6222d1b563d3a/clang_format-18.1.8-py2.py3-none-musllinux_1_2_s390x.whl", hash = "sha256:d3a41b7c7c3e65fa56763f5712f919111b35d7a8e857f8bef4ad5a4cdc1be131", size = 3172694, upload-time = "2024-06-28T10:18:14.035Z" }, + { url = "https://files.pythonhosted.org/packages/c8/b1/7bdec805dfa84eb4d2f3cbe65a419eaeb4cb0d67634c68d0915f54a32b88/clang_format-18.1.8-py2.py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:4762e95ea887d522bf664c1411d93d4d41fc9eb059835dd88b9ad54bc3cb08e0", size = 2835733, upload-time = "2024-06-28T10:18:16.051Z" }, + { url = "https://files.pythonhosted.org/packages/c3/b5/72fad56b06caef8dd41bcc40618ebf90e0ff881fef80b61c826a7bba9bef/clang_format-18.1.8-py2.py3-none-win32.whl", hash = "sha256:03e0a762b4b504750ce4999174fa50a3c4d6b83d7999481e1b6a1b3bc2915121", size = 1184681, upload-time = "2024-06-28T10:18:18.315Z" }, + { url = "https://files.pythonhosted.org/packages/e8/80/9b7ac1db31369307a74178ece94af2d7f800bb948af3b6d68fe2266f32b0/clang_format-18.1.8-py2.py3-none-win_amd64.whl", hash = "sha256:6ca6768270e291495174faa6d8c082aa0181722b29ef8e36558b397069fa4a2d", size = 1370844, upload-time = "2024-06-28T10:18:20.422Z" }, +] + +[[package]] +name = "distlib" +version = "0.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/96/8e/709914eb2b5749865801041647dc7f4e6d00b549cfe88b65ca192995f07c/distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d", size = 614605, upload-time = "2025-07-17T16:52:00.465Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16", size = 469047, upload-time = "2025-07-17T16:51:58.613Z" }, +] + +[[package]] +name = "filelock" +version = "3.25.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/b8/00651a0f559862f3bb7d6f7477b192afe3f583cc5e26403b44e59a55ab34/filelock-3.25.2.tar.gz", hash = "sha256:b64ece2b38f4ca29dd3e810287aa8c48182bbecd1ae6e9ae126c9b35f1382694", size = 40480, upload-time = "2026-03-11T20:45:38.487Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a4/a5/842ae8f0c08b61d6484b52f99a03510a3a72d23141942d216ebe81fefbce/filelock-3.25.2-py3-none-any.whl", hash = "sha256:ca8afb0da15f229774c9ad1b455ed96e85a81373065fb10446672f64444ddf70", size = 26759, upload-time = "2026-03-11T20:45:37.437Z" }, +] + +[[package]] +name = "identify" +version = "2.6.18" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/46/c4/7fb4db12296cdb11893d61c92048fe617ee853f8523b9b296ac03b43757e/identify-2.6.18.tar.gz", hash = "sha256:873ac56a5e3fd63e7438a7ecbc4d91aca692eb3fefa4534db2b7913f3fc352fd", size = 99580, upload-time = "2026-03-15T18:39:50.319Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/46/33/92ef41c6fad0233e41d3d84ba8e8ad18d1780f1e5d99b3c683e6d7f98b63/identify-2.6.18-py2.py3-none-any.whl", hash = "sha256:8db9d3c8ea9079db92cafb0ebf97abdc09d52e97f4dcf773a2e694048b7cd737", size = 99394, upload-time = "2026-03-15T18:39:48.915Z" }, +] + +[[package]] +name = "mypy" +version = "1.16.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mypy-extensions" }, + { name = "pathspec" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/81/69/92c7fa98112e4d9eb075a239caa4ef4649ad7d441545ccffbd5e34607cbb/mypy-1.16.1.tar.gz", hash = "sha256:6bd00a0a2094841c5e47e7374bb42b83d64c527a502e3334e1173a0c24437bab", size = 3324747, upload-time = "2025-06-16T16:51:35.145Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cf/d3/53e684e78e07c1a2bf7105715e5edd09ce951fc3f47cf9ed095ec1b7a037/mypy-1.16.1-py3-none-any.whl", hash = "sha256:5fc2ac4027d0ef28d6ba69a0343737a23c4d1b83672bf38d1fe237bdc0643b37", size = 2265923, upload-time = "2025-06-16T16:48:02.366Z" }, +] + +[[package]] +name = "mypy-extensions" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343, upload-time = "2025-04-22T14:54:24.164Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" }, +] + +[[package]] +name = "nodeenv" +version = "1.10.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/24/bf/d1bda4f6168e0b2e9e5958945e01910052158313224ada5ce1fb2e1113b8/nodeenv-1.10.0.tar.gz", hash = "sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb", size = 55611, upload-time = "2025-12-20T14:08:54.006Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827", size = 23438, upload-time = "2025-12-20T14:08:52.782Z" }, +] + +[[package]] +name = "pathspec" +version = "1.0.4" +source = { registry = "https://pypi.org/simple" } +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/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]] +name = "platformdirs" +version = "4.9.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/19/56/8d4c30c8a1d07013911a8fdbd8f89440ef9f08d07a1b50ab8ca8be5a20f9/platformdirs-4.9.4.tar.gz", hash = "sha256:1ec356301b7dc906d83f371c8f487070e99d3ccf9e501686456394622a01a934", size = 28737, upload-time = "2026-03-05T18:34:13.271Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/63/d7/97f7e3a6abb67d8080dd406fd4df842c2be0efaf712d1c899c32a075027c/platformdirs-4.9.4-py3-none-any.whl", hash = "sha256:68a9a4619a666ea6439f2ff250c12a853cd1cbd5158d258bd824a7df6be2f868", size = 21216, upload-time = "2026-03-05T18:34:12.172Z" }, +] + +[[package]] +name = "pre-commit" +version = "4.5.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cfgv" }, + { name = "identify" }, + { name = "nodeenv" }, + { name = "pyyaml" }, + { name = "virtualenv" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/40/f1/6d86a29246dfd2e9b6237f0b5823717f60cad94d47ddc26afa916d21f525/pre_commit-4.5.1.tar.gz", hash = "sha256:eb545fcff725875197837263e977ea257a402056661f09dae08e4b149b030a61", size = 198232, upload-time = "2025-12-16T21:14:33.552Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5d/19/fd3ef348460c80af7bb4669ea7926651d1f95c23ff2df18b9d24bab4f3fa/pre_commit-4.5.1-py2.py3-none-any.whl", hash = "sha256:3b3afd891e97337708c1674210f8eba659b52a38ea5f822ff142d10786221f77", size = 226437, upload-time = "2025-12-16T21:14:32.409Z" }, +] + +[[package]] +name = "pyopengl" +version = "3.1.10" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6f/16/912b7225d56284859cd9a672827f18be43f8012f8b7b932bc4bd959a298e/pyopengl-3.1.10.tar.gz", hash = "sha256:c4a02d6866b54eb119c8e9b3fb04fa835a95ab802dd96607ab4cdb0012df8335", size = 1915580, upload-time = "2025-08-18T02:33:01.76Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/de/e4/1ba6f44e491c4eece978685230dde56b14d51a0365bc1b774ddaa94d14cd/pyopengl-3.1.10-py3-none-any.whl", hash = "sha256:794a943daced39300879e4e47bd94525280685f42dbb5a998d336cfff151d74f", size = 3194996, upload-time = "2025-08-18T02:32:59.902Z" }, +] + +[[package]] +name = "pyright" +version = "1.1.401" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nodeenv" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/79/9a/7ab2b333b921b2d6bfcffe05a0e0a0bbeff884bd6fb5ed50cd68e2898e53/pyright-1.1.401.tar.gz", hash = "sha256:788a82b6611fa5e34a326a921d86d898768cddf59edde8e93e56087d277cc6f1", size = 3894193, upload-time = "2025-05-21T10:44:52.03Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0d/e6/1f908fce68b0401d41580e0f9acc4c3d1b248adcff00dfaad75cd21a1370/pyright-1.1.401-py3-none-any.whl", hash = "sha256:6fde30492ba5b0d7667c16ecaf6c699fab8d7a1263f6a18549e0b00bf7724c06", size = 5629193, upload-time = "2025-05-21T10:44:50.129Z" }, +] + +[[package]] +name = "python-discovery" +version = "1.2.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "filelock" }, + { name = "platformdirs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b9/88/815e53084c5079a59df912825a279f41dd2e0df82281770eadc732f5352c/python_discovery-1.2.1.tar.gz", hash = "sha256:180c4d114bff1c32462537eac5d6a332b768242b76b69c0259c7d14b1b680c9e", size = 58457, upload-time = "2026-03-26T22:30:44.496Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/67/0f/019d3949a40280f6193b62bc010177d4ce702d0fce424322286488569cd3/python_discovery-1.2.1-py3-none-any.whl", hash = "sha256:b6a957b24c1cd79252484d3566d1b49527581d46e789aaf43181005e56201502", size = 31674, upload-time = "2026-03-26T22:30:43.396Z" }, +] + +[[package]] +name = "pyyaml" +version = "6.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814, upload-time = "2025-09-25T21:32:35.712Z" }, + { url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809, upload-time = "2025-09-25T21:32:36.789Z" }, + { url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454, upload-time = "2025-09-25T21:32:37.966Z" }, + { url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355, upload-time = "2025-09-25T21:32:39.178Z" }, + { url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175, upload-time = "2025-09-25T21:32:40.865Z" }, + { url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228, upload-time = "2025-09-25T21:32:42.084Z" }, + { url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194, upload-time = "2025-09-25T21:32:43.362Z" }, + { url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429, upload-time = "2025-09-25T21:32:57.844Z" }, + { url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912, upload-time = "2025-09-25T21:32:59.247Z" }, + { url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108, upload-time = "2025-09-25T21:32:44.377Z" }, + { url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641, upload-time = "2025-09-25T21:32:45.407Z" }, + { url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901, upload-time = "2025-09-25T21:32:48.83Z" }, + { url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132, upload-time = "2025-09-25T21:32:50.149Z" }, + { url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261, upload-time = "2025-09-25T21:32:51.808Z" }, + { url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272, upload-time = "2025-09-25T21:32:52.941Z" }, + { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" }, + { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" }, + { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" }, +] + +[[package]] +name = "ruff" +version = "0.14.14" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2e/06/f71e3a86b2df0dfa2d2f72195941cd09b44f87711cb7fa5193732cb9a5fc/ruff-0.14.14.tar.gz", hash = "sha256:2d0f819c9a90205f3a867dbbd0be083bee9912e170fd7d9704cc8ae45824896b", size = 4515732, upload-time = "2026-01-22T22:30:17.527Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d2/89/20a12e97bc6b9f9f68343952da08a8099c57237aef953a56b82711d55edd/ruff-0.14.14-py3-none-linux_armv6l.whl", hash = "sha256:7cfe36b56e8489dee8fbc777c61959f60ec0f1f11817e8f2415f429552846aed", size = 10467650, upload-time = "2026-01-22T22:30:08.578Z" }, + { url = "https://files.pythonhosted.org/packages/a3/b1/c5de3fd2d5a831fcae21beda5e3589c0ba67eec8202e992388e4b17a6040/ruff-0.14.14-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:6006a0082336e7920b9573ef8a7f52eec837add1265cc74e04ea8a4368cd704c", size = 10883245, upload-time = "2026-01-22T22:30:04.155Z" }, + { url = "https://files.pythonhosted.org/packages/b8/7c/3c1db59a10e7490f8f6f8559d1db8636cbb13dccebf18686f4e3c9d7c772/ruff-0.14.14-py3-none-macosx_11_0_arm64.whl", hash = "sha256:026c1d25996818f0bf498636686199d9bd0d9d6341c9c2c3b62e2a0198b758de", size = 10231273, upload-time = "2026-01-22T22:30:34.642Z" }, + { url = "https://files.pythonhosted.org/packages/a1/6e/5e0e0d9674be0f8581d1f5e0f0a04761203affce3232c1a1189d0e3b4dad/ruff-0.14.14-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f666445819d31210b71e0a6d1c01e24447a20b85458eea25a25fe8142210ae0e", size = 10585753, upload-time = "2026-01-22T22:30:31.781Z" }, + { url = "https://files.pythonhosted.org/packages/23/09/754ab09f46ff1884d422dc26d59ba18b4e5d355be147721bb2518aa2a014/ruff-0.14.14-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3c0f18b922c6d2ff9a5e6c3ee16259adc513ca775bcf82c67ebab7cbd9da5bc8", size = 10286052, upload-time = "2026-01-22T22:30:24.827Z" }, + { url = "https://files.pythonhosted.org/packages/c8/cc/e71f88dd2a12afb5f50733851729d6b571a7c3a35bfdb16c3035132675a0/ruff-0.14.14-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1629e67489c2dea43e8658c3dba659edbfd87361624b4040d1df04c9740ae906", size = 11043637, upload-time = "2026-01-22T22:30:13.239Z" }, + { url = "https://files.pythonhosted.org/packages/67/b2/397245026352494497dac935d7f00f1468c03a23a0c5db6ad8fc49ca3fb2/ruff-0.14.14-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:27493a2131ea0f899057d49d303e4292b2cae2bb57253c1ed1f256fbcd1da480", size = 12194761, upload-time = "2026-01-22T22:30:22.542Z" }, + { url = "https://files.pythonhosted.org/packages/5b/06/06ef271459f778323112c51b7587ce85230785cd64e91772034ddb88f200/ruff-0.14.14-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:01ff589aab3f5b539e35db38425da31a57521efd1e4ad1ae08fc34dbe30bd7df", size = 12005701, upload-time = "2026-01-22T22:30:20.499Z" }, + { url = "https://files.pythonhosted.org/packages/41/d6/99364514541cf811ccc5ac44362f88df66373e9fec1b9d1c4cc830593fe7/ruff-0.14.14-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1cc12d74eef0f29f51775f5b755913eb523546b88e2d733e1d701fe65144e89b", size = 11282455, upload-time = "2026-01-22T22:29:59.679Z" }, + { url = "https://files.pythonhosted.org/packages/ca/71/37daa46f89475f8582b7762ecd2722492df26421714a33e72ccc9a84d7a5/ruff-0.14.14-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb8481604b7a9e75eff53772496201690ce2687067e038b3cc31aaf16aa0b974", size = 11215882, upload-time = "2026-01-22T22:29:57.032Z" }, + { url = "https://files.pythonhosted.org/packages/2c/10/a31f86169ec91c0705e618443ee74ede0bdd94da0a57b28e72db68b2dbac/ruff-0.14.14-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:14649acb1cf7b5d2d283ebd2f58d56b75836ed8c6f329664fa91cdea19e76e66", size = 11180549, upload-time = "2026-01-22T22:30:27.175Z" }, + { url = "https://files.pythonhosted.org/packages/fd/1e/c723f20536b5163adf79bdd10c5f093414293cdf567eed9bdb7b83940f3f/ruff-0.14.14-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e8058d2145566510790eab4e2fad186002e288dec5e0d343a92fe7b0bc1b3e13", size = 10543416, upload-time = "2026-01-22T22:30:01.964Z" }, + { url = "https://files.pythonhosted.org/packages/3e/34/8a84cea7e42c2d94ba5bde1d7a4fae164d6318f13f933d92da6d7c2041ff/ruff-0.14.14-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:e651e977a79e4c758eb807f0481d673a67ffe53cfa92209781dfa3a996cf8412", size = 10285491, upload-time = "2026-01-22T22:30:29.51Z" }, + { url = "https://files.pythonhosted.org/packages/55/ef/b7c5ea0be82518906c978e365e56a77f8de7678c8bb6651ccfbdc178c29f/ruff-0.14.14-py3-none-musllinux_1_2_i686.whl", hash = "sha256:cc8b22da8d9d6fdd844a68ae937e2a0adf9b16514e9a97cc60355e2d4b219fc3", size = 10733525, upload-time = "2026-01-22T22:30:06.499Z" }, + { url = "https://files.pythonhosted.org/packages/6a/5b/aaf1dfbcc53a2811f6cc0a1759de24e4b03e02ba8762daabd9b6bd8c59e3/ruff-0.14.14-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:16bc890fb4cc9781bb05beb5ab4cd51be9e7cb376bf1dd3580512b24eb3fda2b", size = 11315626, upload-time = "2026-01-22T22:30:36.848Z" }, + { url = "https://files.pythonhosted.org/packages/2c/aa/9f89c719c467dfaf8ad799b9bae0df494513fb21d31a6059cb5870e57e74/ruff-0.14.14-py3-none-win32.whl", hash = "sha256:b530c191970b143375b6a68e6f743800b2b786bbcf03a7965b06c4bf04568167", size = 10502442, upload-time = "2026-01-22T22:30:38.93Z" }, + { url = "https://files.pythonhosted.org/packages/87/44/90fa543014c45560cae1fffc63ea059fb3575ee6e1cb654562197e5d16fb/ruff-0.14.14-py3-none-win_amd64.whl", hash = "sha256:3dde1435e6b6fe5b66506c1dff67a421d0b7f6488d466f651c07f4cab3bf20fd", size = 11630486, upload-time = "2026-01-22T22:30:10.852Z" }, + { url = "https://files.pythonhosted.org/packages/9e/6a/40fee331a52339926a92e17ae748827270b288a35ef4a15c9c8f2ec54715/ruff-0.14.14-py3-none-win_arm64.whl", hash = "sha256:56e6981a98b13a32236a72a8da421d7839221fa308b223b9283312312e5ac76c", size = 10920448, upload-time = "2026-01-22T22:30:15.417Z" }, +] + +[[package]] +name = "types-setuptools" +version = "82.0.0.20260210" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4b/90/796ac8c774a7f535084aacbaa6b7053d16fff5c630eff87c3ecff7896c37/types_setuptools-82.0.0.20260210.tar.gz", hash = "sha256:d9719fbbeb185254480ade1f25327c4654f8c00efda3fec36823379cebcdee58", size = 44768, upload-time = "2026-02-10T04:22:02.107Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3e/54/3489432b1d9bc713c9d8aa810296b8f5b0088403662959fb63a8acdbd4fc/types_setuptools-82.0.0.20260210-py3-none-any.whl", hash = "sha256:5124a7daf67f195c6054e0f00f1d97c69caad12fdcf9113eba33eff0bce8cd2b", size = 68433, upload-time = "2026-02-10T04:22:00.876Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.15.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, +] + +[[package]] +name = "virtualenv" +version = "21.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "distlib" }, + { name = "filelock" }, + { name = "platformdirs" }, + { name = "python-discovery" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/aa/92/58199fe10049f9703c2666e809c4f686c54ef0a68b0f6afccf518c0b1eb9/virtualenv-21.2.0.tar.gz", hash = "sha256:1720dc3a62ef5b443092e3f499228599045d7fea4c79199770499df8becf9098", size = 5840618, upload-time = "2026-03-09T17:24:38.013Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c6/59/7d02447a55b2e55755011a647479041bc92a82e143f96a8195cb33bd0a1c/virtualenv-21.2.0-py3-none-any.whl", hash = "sha256:1bd755b504931164a5a496d217c014d098426cddc79363ad66ac78125f9d908f", size = 5825084, upload-time = "2026-03-09T17:24:35.378Z" }, +]