diff --git a/bookshop/schema.graphqls b/bookshop/schema.graphqls index f5e6985..e85fa51 100644 --- a/bookshop/schema.graphqls +++ b/bookshop/schema.graphqls @@ -23,6 +23,9 @@ type Query { "The publication with this identifier." publication(id: ID!): Publication + "The printed publication with this identifier." + printed(id: ID!): Printed + "Everything whose title or name contains the text." search(text: String!): [SearchResult!]! diff --git a/pyproject.toml b/pyproject.toml index a7ff148..a078db1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -35,7 +35,7 @@ license-files = ["LICENSE"] name = "graphql-codegen" readme = "README.md" requires-python = ">=3.12" -version = "1.0.1" +version = "1.0.2" [project.optional-dependencies] # Only reading a YAML graphql-config file needs it. diff --git a/src/graphql_codegen/_generator/_data_type.py b/src/graphql_codegen/_generator/_data_type.py index 6067631..360119e 100644 --- a/src/graphql_codegen/_generator/_data_type.py +++ b/src/graphql_codegen/_generator/_data_type.py @@ -199,7 +199,7 @@ def _emit_normalized( if field.name == "__typename": keys.append( Key( - name="__typename", + name=field.response_name, annotation=_typename_annotation( self._possible_types(normalized.type) ), diff --git a/src/graphql_codegen/_generator/package.py b/src/graphql_codegen/_generator/package.py index f19c5a7..53bdfcb 100644 --- a/src/graphql_codegen/_generator/package.py +++ b/src/graphql_codegen/_generator/package.py @@ -322,7 +322,7 @@ def _annotations(self) -> AnnotationBuilder: def _module_source( self, - body: list[ast.stmt], + body: Sequence[ast.stmt], /, *, generated_module: GeneratedModule, diff --git a/tests/test_bookshop.py b/tests/test_bookshop.py index 3f11cf3..3c52a6c 100644 --- a/tests/test_bookshop.py +++ b/tests/test_bookshop.py @@ -1,7 +1,7 @@ import json import runpy from asyncio import run as run_async -from collections.abc import Callable, Mapping +from collections.abc import Callable, Collection, Mapping from decimal import Decimal from http.server import BaseHTTPRequestHandler from pathlib import Path @@ -171,7 +171,7 @@ def test_a_request_error_is_read_whatever_its_status( ], ) def test_watching_an_order_asynchronously_follows_its_statuses( - events: list[str], statuses: list[str], mocked_http: Callable[[_Handle], None] + events: Collection[str], statuses: list[str], mocked_http: Callable[[_Handle], None] ) -> None: mocked_http(lambda _request: _events(*events)) diff --git a/tests/test_cli.py b/tests/test_cli.py index 997beff..fc0d94b 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -1,6 +1,7 @@ import shutil import subprocess import sys +from collections.abc import Sequence from pathlib import Path import pytest @@ -20,7 +21,7 @@ ], ) def test_the_cli_generates_the_committed_bookshop_package( - command: list[str], tmp_path: Path + command: Sequence[str], tmp_path: Path ) -> None: generated = (BOOKSHOP_GENERATED_PACKAGE_DIRECTORY.name, "*_graphql.py") diff --git a/tests/test_emit.py b/tests/test_emit.py index 6007483..5490467 100644 --- a/tests/test_emit.py +++ b/tests/test_emit.py @@ -4,7 +4,7 @@ import shutil import subprocess import sys -from collections.abc import Mapping +from collections.abc import Collection, Mapping from importlib.util import find_spec from pathlib import Path, PurePosixPath @@ -66,7 +66,7 @@ pytest.param( "schema.py", "_BookFilter_and = _compat.TypedDict('_BookFilter_and', {'and': _abc.Sequence[BookFilter]}, closed=True)", - id="so that a keyword key, declared functionally, names it directly", + id="a keyword key is declared functionally, so that the union member names it directly", ), pytest.param( "../app_graphql.py", @@ -81,12 +81,12 @@ pytest.param( "../app_graphql.py", "class _GetPublicationData_publication_Magazine(_GetPublicationData_publication_Magazine_Base, closed=True):\n title: _builtins.str\n pages: _builtins.int\n\n", - id="and only those", + id="a member gathers no field of a condition it does not meet", ), pytest.param( "../app_graphql.py", "class _GetPublicationData_publication_Audiobook(_GetPublicationData_publication_Audiobook_Base, closed=True):\n title: _builtins.str\n duration: _builtins.int\n", - id="each with the fields of its own condition", + id="a member of a concrete type with its own condition gathers that condition's fields", ), pytest.param( "../app_graphql.py", @@ -193,7 +193,7 @@ def test_a_document_goes_on_the_wire_triple_quoted_without_its_client_directive( @pytest.mark.parametrize( - ("document", "present", "absent"), + ("document", "present"), [ pytest.param( 'query Q { publication(id: "1") { __typename ... on Book { ...PageCount } } } fragment PageCount on Printed { pageCount }', @@ -201,83 +201,96 @@ def test_a_document_goes_on_the_wire_triple_quoted_without_its_client_directive( "class _QData_publication_Book(_QData_publication_Book_Base, PageCount, closed=True):", "class _QData_publication_Magazine(_QData_publication_Magazine_Base, closed=True):\n ...", ], - [], id="a spread on an interface inside a branch is a base of that branch", ), pytest.param( - 'query Q { search(text: "Austen") { ...Result } } fragment Result on SearchResult { __typename ... on Author { name } }', + 'query Q { search(text: "Austen") { ...Result ... on Book { title } } } fragment Result on SearchResult { __typename ... on Author { name } }', [ - "class _QData_search_Author(_QData_search_Author_Base, closed=True):\n name: _builtins.str" + "class _QData_search_Author(_QData_search_Author_Base, closed=True):\n name: _builtins.str", + " search: _builtins.list[_QData_search]\n", ], - ["(Result)", "(Result,", ", Result)", ", Result,"], id="a fragment on a union is expanded into its members", ), pytest.param( 'query Q { search(text: "Austen") { ...Result } } fragment Result on SearchResult { __typename ... on Author { name } }', ["class _Result_Author(_Result_Author_Base):\n name: _builtins.str"], - ["class _Result_Author(_Result_Author_Base, closed=True)"], id="a fragment on a union has open members, so that a spread's member is assignable to it", ), pytest.param( 'query Q { publication(id: "1") { title ...Length } } fragment Length on Printed { pageCount ... on Book { isbn } }', [ "class _QData_publication_Book(_QData_publication_Book_Base, closed=True):\n title: _builtins.str\n pageCount: _builtins.int\n isbn: _builtins.object", + "type _QData_publication = _QData_publication_Book | _QData_publication_Magazine | _QData_publication_Audiobook\n", ], - ["_Book_Book"], id="a condition an expanded fragment brings folds into the concrete member meeting it", ), pytest.param( 'query Q { book(lookup: {id: "1"}) { ...Title ...Title } } fragment Title on Book { title }', [" book: Title | None\n"], - ["class _QData_book("], id="a field selecting one fragment and nothing else is typed by it, however often it spreads it", ), pytest.param( - 'query Q { book(lookup: {id: "1"}) { ...Title id } } fragment Title on Book { title }', - ["class _QData_book(Title, closed=True):\n id: _builtins.str"], - [], - id="a field selecting more than one fragment gets a class inheriting it", + 'query Q { book(lookup: {id: "1"}) { __typename tn: __typename ...Title } } fragment Title on Book { title }', + [ + "class _QData_book(_QData_book_Base, Title, closed=True):\n tn: _compat.ReadOnly[_typing.Literal['Book']]", + " book: _QData_book | None\n", + ], + id="a field selecting `__typename`, aliased or not, next to one fragment gets a class holding those keys", + ), + pytest.param( + 'query Q { printed(id: "1") { ...Info } } fragment Info on Publication { title }', + [ + "_QData_printed_Base = _compat.TypedDict('_QData_printed_Base', {'__typename': _compat.ReadOnly[_typing.Literal['Book', 'Magazine']]})", + "class _QData_printed(_QData_printed_Base, Info, closed=True):", + ], + id="a fragment on a supertype of its field's type is a base, whose `__typename` the field's own class narrows", + ), + pytest.param( + 'query Q { publication(id: "1") { ...Info } } fragment Info on Publication { title ... on Audiobook { duration } }', + [ + "class _QData_publication_Audiobook(_QData_publication_Audiobook_Base, closed=True):\n title: _builtins.str\n duration: _builtins.int", + " publication: _QData_publication | None\n", + ], + id="a field on an abstract type selecting one fragment alone gets a closed union of its own, since a key check narrows open members unsoundly", + ), + pytest.param( + 'query Q { book(lookup: {id: "1"}) { ...Info } } fragment Info on Publication { ...Inner } fragment Inner on Publication { title ... on Audiobook { duration } }', + [ + "class _QData_book(_QData_book_Base, closed=True):\n title: _builtins.str\n", + " book: _QData_book | None\n", + ], + id="a fragment on a supertype of its field's type is expanded, since the field cannot hold the fragment's other possible types, wherever its conditions come from", ), pytest.param( 'query Q { book(lookup: {id: "1"}) { ...Title ...Pages } } fragment Title on Book { title } fragment Pages on Book { pageCount }', ["class _QData_book(Title, Pages, closed=True):"], - [], id="two fragments are two bases", ), pytest.param( 'query Q { book(lookup: {id: "1"}) { ...Card ...Title } } fragment Card on Book { ...Title isbn } fragment Title on Book { title }', ["class _QData_book(Card, Title, closed=True):"], - [], id="a fragment and its own base are both bases", ), pytest.param( - 'query Q { book(lookup: {id: "1"}) { ...Title title } } fragment Title on Book { title }', - ["class _QData_book(Title, closed=True):"], - [], - id="a key the selection declares alike is no conflict", + 'query Q { book(lookup: {id: "1"}) { ...Title title id } } fragment Title on Book { title }', + [ + "class _QData_book(Title, closed=True):\n title: _builtins.str\n id: _builtins.str" + ], + id="a field selecting keys next to one fragment, declared alike or not, gets a class inheriting it", ), pytest.param( 'query Q { book(lookup: {id: "1"}) { ...AuthorName author { id } } } fragment AuthorName on Book { author { name } }', [ - "class _QData_book_author(_compat.TypedDict, closed=True):\n id: _builtins.str\n name: _builtins.str" + "class _QData_book_author(_compat.TypedDict, closed=True):\n id: _builtins.str\n name: _builtins.str", + "class _QData_book(_compat.TypedDict, closed=True):\n author: _QData_book_author | None\n", ], - ["(AuthorName)", "(AuthorName,", ", AuthorName)", ", AuthorName,"], id="a fragment declaring a key otherwise than the selection is expanded", ), pytest.param( 'query Q { book(lookup: {id: "1"}) { ...AuthorName ...AuthorId } } fragment AuthorName on Book { author { name } } fragment AuthorId on Book { author { id } }', [ - "class _QData_book_author(_compat.TypedDict, closed=True):\n name: _builtins.str\n id: _builtins.str" - ], - [ - "(AuthorName)", - "(AuthorName,", - ", AuthorName)", - ", AuthorName,", - "(AuthorId)", - "(AuthorId,", - ", AuthorId)", - ", AuthorId,", + "class _QData_book_author(_compat.TypedDict, closed=True):\n name: _builtins.str\n id: _builtins.str", + "class _QData_book(_compat.TypedDict, closed=True):\n author: _QData_book_author | None\n", ], id="two fragments declaring a key differently are expanded", ), @@ -287,23 +300,20 @@ def test_a_document_goes_on_the_wire_triple_quoted_without_its_client_directive( "class _QData_book(Title, closed=True):", "class _QData_book_author(_compat.TypedDict, closed=True):\n id: _builtins.str\n name: _builtins.str", ], - ["(Card)", "(Card,", ", Card)", ", Card,"], id="expanding a fragment keeps the base it spreads", ), pytest.param( 'query Q($withGenre: Boolean!) { book(lookup: {id: "1"}) { title genre @include(if: $withGenre) never: genre @include(if: false) always: genre @skip(if: false) } }', [ - " title: _builtins.str\n genre: _typing.NotRequired[_schema.Genre]\n always: _schema.Genre\n" + "class _QData_book(_compat.TypedDict, closed=True):\n title: _builtins.str\n genre: _typing.NotRequired[_schema.Genre]\n always: _schema.Genre\n\nclass QData(" ], - ["never: _"], id="a field skip or include may leave out is not required", ), pytest.param( 'query Q($withTitle: Boolean!) { book(lookup: {id: "1"}) { genre ...Title @include(if: $withTitle) } } fragment Title on Book { title }', [ - " genre: _schema.Genre\n title: _typing.NotRequired[_builtins.str]\n" + "class _QData_book(_compat.TypedDict, closed=True):\n genre: _schema.Genre\n title: _typing.NotRequired[_builtins.str]\n\nclass QData(" ], - ["(Title)", "(Title,", ", Title)", ", Title,"], id="a conditional spread is expanded, its keys not required", ), pytest.param( @@ -311,19 +321,19 @@ def test_a_document_goes_on_the_wire_triple_quoted_without_its_client_directive( [ " title: _builtins.str\n genre: _typing.NotRequired[_schema.Genre]\n" ], - [], id="a field selected unconditionally somewhere is required", ), pytest.param( 'query Q { __type(name: "Book") { kind } }', - ["kind: _typing.Literal['SCALAR', 'OBJECT',"], - ["_schema."], + [ + "kind: _typing.Literal['SCALAR', 'OBJECT',", + "from .. import runtime as _runtime\n\nclass QVariables(", + ], id="an introspection enum is spelled where it is selected", ), pytest.param( 'query Q { search(text: """Austen""") { __typename ... on Author { name } } }', ['search(text: "Austen")'], - [], id="a block string goes on the wire as an ordinary one", ), pytest.param( @@ -332,27 +342,23 @@ def test_a_document_goes_on_the_wire_triple_quoted_without_its_client_directive( "'__typename': _compat.ReadOnly[_typing.Literal['Book', 'Magazine', 'Audiobook']]", 'publication(id: "1") {\n __typename\n title', ], - [], id="a selection on an abstract type gets `__typename`, even without branches", ), pytest.param( 'query Q { search(text: "Austen") { ... on Publication { title ... on Book { isbn } } } }', [ - 'search(text: "Austen") {\n __typename\n ... on Publication {\n title' + 'search(text: "Austen") {\n __typename\n ... on Publication {\n title\n ... on Book {\n isbn\n }\n }\n }\n}"""' ], - ["... on Publication {\n __typename"], id="an inline fragment's selections get none, gathered into the branches the enclosing `__typename` tells apart", ), pytest.param( 'query Q { search(text: "Austen") { __typename ... on Author { name } } }', - [], - ["__typename\n __typename"], + ['search(text: "Austen") {\n __typename\n ... on Author {'], id="a selection already holding `__typename` gets no other", ), pytest.param( 'query Q($x: Boolean!) { search(text: "Austen") { __typename @include(if: $x) ... on Author { name } } }', ["__typename\n __typename @include(if: $x§)"], - [], id="a conditional `__typename` gets an unconditional one, since the key must be present", ), pytest.param( @@ -360,7 +366,6 @@ def test_a_document_goes_on_the_wire_triple_quoted_without_its_client_directive( [ "class _QData_publication_Book(_QData_publication_Book_Base, Pages, closed=True):" ], - [], id="a fragment selecting `__typename` is still a base, whose key a branch narrows", ), pytest.param( @@ -368,21 +373,20 @@ def test_a_document_goes_on_the_wire_triple_quoted_without_its_client_directive( [ "class _QData_publication_Book(_QData_publication_Book_Base, closed=True):\n pageCount: _builtins.int\n isbn: _builtins.object" ], - [], id="a condition nested in another gathers into the members of its type", ), pytest.param( 'query Q { order(id: "1") { id } }', [ - "class _QData_order(_compat.TypedDict, closed=True):\n id: _builtins.str" + "class _QData_order(_compat.TypedDict, closed=True):\n id: _builtins.str", + "from .. import runtime as _runtime\n\nclass QVariables(", ], - ["_schema"], id="an operation reaching no enum and no input imports neither", ), ], ) def test_a_document_generates( - document: str, present: list[str], absent: list[str], bookshop_schema: GraphQLSchema + document: str, present: Collection[str], bookshop_schema: GraphQLSchema ) -> None: source = generate( document=parse(document), schema=bookshop_schema, config=Config() @@ -391,9 +395,6 @@ def test_a_document_generates( for snippet in present: assert snippet in source - for snippet in absent: - assert snippet not in source - @pytest.mark.parametrize( "description", diff --git a/tests/test_generate.py b/tests/test_generate.py index 47773d0..e3bdd45 100644 --- a/tests/test_generate.py +++ b/tests/test_generate.py @@ -1,5 +1,5 @@ import re -from collections.abc import Callable +from collections.abc import Callable, Collection, Mapping from pathlib import PurePosixPath from typing import Final @@ -40,7 +40,7 @@ @pytest.mark.parametrize( - ("document", "config", "path", "present", "absent"), + ("document", "config", "path", "present"), [ pytest.param( _PRICE, @@ -51,7 +51,6 @@ "from my_app.money import decode as _decode", "type Money = _typing.Annotated[_Decimal, _reflection.Codec(decode=_decode, encode=_encode)]", ], - [], id="a codec scalar imports its paths absolutely, and never while generating: they need not exist yet", ), pytest.param( @@ -59,7 +58,6 @@ Config(scalars={"ISBN": Scalar(type="str")}), "schema.py", ["type ISBN = _builtins.str"], - [], id="an identity scalar named by a bare name is a builtin", ), pytest.param( @@ -78,7 +76,6 @@ "from .. import decode_money as _decode_money", "from ...money import encode as _encode", ], - [], id="a path starting with two dots or more is relative to the generated package's directory", ), pytest.param( @@ -86,7 +83,6 @@ Config(), "document/GraphQL_request.py", ["price: _builtins.object"], - [], id="a custom scalar left out of the config is typed `object`", ), pytest.param( @@ -94,7 +90,6 @@ Config(struct_interface_name="Struct"), "document/GraphQL_request.py", ["value: _schema.BookFilter | None"], - [], id="a struct payload is typed with its input type", ), pytest.param( @@ -102,7 +97,6 @@ Config(struct_interface_name="Struct"), "schema.py", ["type BookFilter = "], - ["PlaceOrderInput"], id="which it reaches even when no variable does", ), pytest.param( @@ -110,7 +104,6 @@ Config(), "document/GraphQL_request.py", ["value: _builtins.object | None"], - [], id="but only when the struct interface is named", ), pytest.param( @@ -118,23 +111,25 @@ Config(non_null_directive_name="nonNull", struct_interface_name="Struct"), "document/GraphQL_request.py", ["value: _typing.Annotated[_schema.BookFilter, _reflection.NON_NULL]"], - [], id="and not optional when asserted non-null", ), pytest.param( 'query Q { book(lookup: {id: "1"}) @nonNull { title } }', Config(non_null_directive_name="nonNull"), "document/GraphQL_request.py", - ["book: _typing.Annotated[_QData_book, _reflection.NON_NULL]"], - ["@nonNull"], + [ + "book: _typing.Annotated[_QData_book, _reflection.NON_NULL]", + 'document="""query Q {\n book§: book(lookup: { id: "1" }) {\n title\n }\n}"""', + ], id="a field asserted non-null is not optional, and its directive stays off the wire", ), pytest.param( _PLACE_ORDER, Config(injector_names={"idempotencyKey"}), "schema.py", - ["class PlaceOrderInput("], - ["idempotencyKey"], + [ + 'class PlaceOrderInput(_compat.TypedDict, closed=True):\n customer: _typing.NotRequired[_builtins.str | None]\n """The customer to act for, the authenticated account itself when omitted."""\n lines: _abc.Sequence[OrderLineInput]\n' + ], id="an injected field is left out of its input type", ), pytest.param( @@ -144,7 +139,6 @@ [ "injections={'city': _builtins.frozenset({('input', 'shippingAddress')})}" ], - [], id="and received wherever an input holds it, at any depth", ), pytest.param( @@ -155,7 +149,6 @@ "note: _abc.Callable[[], _builtins.str | None | _OMITTED]", "def injectors(functions: InjectorFunctions, /) -> _injection._Injectors:", ], - [], id="an injector is required, typed by what it injects, and may return `OMITTED` where it is nullable", ), pytest.param( @@ -163,7 +156,6 @@ Config(injector_names={"note"}), "injection.py", ["note: _abc.Callable[[], _builtins.str]"], - [], id="an injector takes the strictest nullability of its positions, since it cannot tell which one it is called for", ), pytest.param( @@ -173,7 +165,6 @@ [ "InjectorFunctions = _compat.TypedDict('InjectorFunctions', {'in': _abc.Callable[[], _builtins.str]}, closed=True)" ], - [], id="an injector named like a keyword is declared functionally", ), ], @@ -182,8 +173,7 @@ def test_a_config_field_shapes_the_package( document: str, config: Config, path: str, - present: list[str], - absent: list[str], + present: Collection[str], bookshop_schema: GraphQLSchema, ) -> None: source = generate(document=parse(document), schema=bookshop_schema, config=config)[ @@ -193,9 +183,6 @@ def test_a_config_field_shapes_the_package( for snippet in present: assert snippet in source - for snippet in absent: - assert snippet not in source - def _message(error: Exception, /) -> str: return error.message if isinstance(error, GraphQLError) else str(error) @@ -358,7 +345,7 @@ def _message(error: Exception, /) -> str: ], ) def test_an_input_is_rejected( - schema: str, document: str, config: Config, errors: list[Exception] + schema: str, document: str, config: Config, errors: Collection[Exception] ) -> None: with pytest.raises((ExceptionGroup, GraphQLError, ValueError)) as error_info: generate(document=parse(document), schema=build_schema(schema), config=config) @@ -399,7 +386,7 @@ def test_a_config_field_cannot_be_constructed_invalid( construct() -def _documents(sources: dict[str, str], /) -> DocumentNode: +def _documents(sources: Mapping[str, str], /) -> DocumentNode: return DocumentNode( definitions=tuple( definition @@ -410,7 +397,7 @@ def _documents(sources: dict[str, str], /) -> DocumentNode: def _generated( - sources: dict[str, str], + sources: Mapping[str, str], /, *, sibling_module_name: str | None, @@ -523,7 +510,7 @@ def test_a_fragment_goes_next_to_the_operations_of_its_document_and_is_imported_ ], ) def test_a_document_s_module_depends_on_its_document_alone( - sources: dict[str, str], + sources: Mapping[str, str], sibling_module_name: str | None, message: str, bookshop_schema: GraphQLSchema, diff --git a/tests/test_merge.py b/tests/test_merge.py index 9947edb..a535ec1 100644 --- a/tests/test_merge.py +++ b/tests/test_merge.py @@ -1,4 +1,5 @@ import json +from collections.abc import Collection from itertools import product from typing import Any @@ -172,7 +173,9 @@ def test_a_lone_operation_is_sent_without_its_sigils( ), ], ) -def test_an_operation_merged_with_itself(source: str, snippets: list[str]) -> None: +def test_an_operation_merged_with_itself( + source: str, snippets: Collection[str] +) -> None: operation = _operation(source) query = _sent(merge(operation({}), operation({})))["query"] diff --git a/tests/test_runtime.py b/tests/test_runtime.py index 90d9d74..bd21b8c 100644 --- a/tests/test_runtime.py +++ b/tests/test_runtime.py @@ -1,5 +1,5 @@ import json -from collections.abc import Callable +from collections.abc import Callable, Mapping from typing import Annotated, Any, Final, Literal, assert_type import pytest @@ -171,7 +171,7 @@ def _sent( def _mutation( - document: str, /, *, injections: dict[str, frozenset[tuple[str, ...]]] + document: str, /, *, injections: Mapping[str, frozenset[tuple[str, ...]]] ) -> Operation[Literal["mutation"], dict[str, object], dict[str, object]]: return Operation( operation_type="mutation", diff --git a/uv.lock b/uv.lock index a0600a7..1d80fc8 100644 --- a/uv.lock +++ b/uv.lock @@ -205,7 +205,7 @@ wheels = [ [[package]] name = "graphql-codegen" -version = "1.0.1" +version = "1.0.2" source = { editable = "." } dependencies = [ { name = "graphql-core" }, @@ -611,7 +611,7 @@ nodejs = [ [[package]] name = "pytest" -version = "9.1.1" +version = "9.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, @@ -620,9 +620,9 @@ dependencies = [ { name = "pluggy" }, { name = "pygments" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e4/47/b9efed96c114afcfa3c9d3fe98a76a1d14c74a9e266d397cf6eb64be5e01/pytest-9.1.1.tar.gz", hash = "sha256:1088fbde8f2b49d95a549a195707afa7a76a3ce9bcadc26b6d71f0ffda5fe313", size = 1636369, upload-time = "2026-06-19T10:58:32.857Z" } +sdist = { url = "https://files.pythonhosted.org/packages/79/42/bb4641652e58dedeac2ec51abc1f8cae4fee4ec63899a0999016229a0f2a/pytest-9.2.0.tar.gz", hash = "sha256:97c4f3b1f3c7414aa36465e09b8220f1d03627993bd51b1282e193753c80557b", size = 1797555, upload-time = "2026-10-27T21:30:20.728Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl", hash = "sha256:37a86b45efb9a47a61a36449063e8e18d0cab3161329fc099eb21783169c4f0c", size = 386536, upload-time = "2026-06-19T10:58:31.347Z" }, + { url = "https://files.pythonhosted.org/packages/51/39/1f5d8c8877a0fa327db959c19341d4be61660de1ab6b7391f9eb805bcd67/pytest-9.2.0-py3-none-any.whl", hash = "sha256:07acdcf88ec174f907dc01af70bf52d49b014bbab03faeeade31c96b18c2e588", size = 411776, upload-time = "2026-10-27T21:30:19.131Z" }, ] [[package]] @@ -673,27 +673,27 @@ wheels = [ [[package]] name = "ruff" -version = "0.17.2" +version = "0.17.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ae/58/690cf56da80c8f2c8bf12042b6017beac2c34fe961f65420bcb3fb7fac38/ruff-0.17.2.tar.gz", hash = "sha256:84d632402d14c23b488f941db23712d6736a013225162062d34558c3f3c780eb", size = 5333400, upload-time = "2026-10-22T18:38:00.181Z" } +sdist = { url = "https://files.pythonhosted.org/packages/59/73/81f140c4edd9cc323de5478e6bbd3bbcfae9a82692df1a258de8cec6a6d2/ruff-0.17.3.tar.gz", hash = "sha256:a57049c8addb3662073859bb55a7ad35aa54f8a7c9ed268911d1333c5aadaaa9", size = 5339444, upload-time = "2026-10-27T00:34:05.914Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/98/b8/8b6d69c57e8fe1cc6af1aa7493b72a1a5b5a8afe34694e302025441729d4/ruff-0.17.2-py3-none-linux_armv6l.whl", hash = "sha256:96a65e755d8dba094707fb23ab602111d9a31ec2835b3a6992a1914a8fcb211e", size = 10183857, upload-time = "2026-10-22T18:37:14.956Z" }, - { url = "https://files.pythonhosted.org/packages/e8/61/12cc2ff7b2fa90a268ce1e2162c23aaf76e601d22623f6a31b0eeaa764b0/ruff-0.17.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:39c5b55c960515cdb32be16e69efb5734c589c06a0eb38a22694524a336b889d", size = 10210904, upload-time = "2026-10-22T18:37:17.985Z" }, - { url = "https://files.pythonhosted.org/packages/e8/7c/b8850a8e4ad29f64a827dd6c6902db4a9aa538fb2b9eef4e26084001a3bb/ruff-0.17.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:92a80d2f44584dabb0189b3a6c393e37e525e04942838482010575cb81945be7", size = 9408439, upload-time = "2026-10-22T18:37:20.964Z" }, - { url = "https://files.pythonhosted.org/packages/b7/b6/6a64fae86ca5e5e29d5adc311e5481de726cedf9aee607435a16c31c442a/ruff-0.17.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b7d0906677d89bbf3cf73cde64b5bbe2ab35df3ae43e49ee2627301e91265bac", size = 10047078, upload-time = "2026-10-22T18:37:23.717Z" }, - { url = "https://files.pythonhosted.org/packages/10/19/23d376547715175aa1bd46df48df6aacc7c6439d9daf19cac15975180aa5/ruff-0.17.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7cfd783590edf2b77317882631900f6a13ea2e8eacefe6ebf2370d2715299160", size = 9990478, upload-time = "2026-10-22T18:37:26.584Z" }, - { url = "https://files.pythonhosted.org/packages/93/6c/34cda32cbe13adac5c6b291a307a5570d8ebd37c0c86339f0fe628e55632/ruff-0.17.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122258f6ecde0e0dd1bb60b24263c3edde4338caf723fca711cc729f9bfd414a", size = 10673624, upload-time = "2026-10-22T18:37:29.767Z" }, - { url = "https://files.pythonhosted.org/packages/bf/10/5d762a4dbc851d8bb47863cf3a28a61bf31c804d393b70d891fac899f5d1/ruff-0.17.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7f8fba429d6ac4128ab29cfb8fa6240d2fa671d04adf7f84d3b22fc7b6b6bea4", size = 11351797, upload-time = "2026-10-22T18:37:32.535Z" }, - { url = "https://files.pythonhosted.org/packages/3f/04/a0e92a81faf5c81c1c98d4374c8401734ccf2b8cca7d0170cb0fec08c6e2/ruff-0.17.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:583bd67bb9e7061dd09bc46a0a884bae2bbd214dbcd48e509813612619683869", size = 10949414, upload-time = "2026-10-22T18:37:35.501Z" }, - { url = "https://files.pythonhosted.org/packages/c3/d8/59894cf630d2d86882457a2a6a0a1533410c5c805bfbac6f6eb4b5aef69d/ruff-0.17.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c60f93fec7142dba5b8f487f94bf2f6231dae24dc11e4c48648347c8b0720004", size = 10528000, upload-time = "2026-10-22T18:37:37.88Z" }, - { url = "https://files.pythonhosted.org/packages/ab/95/d6e30c51e851d37e10762ad91fa1e76ddaad998589b5667962a3cfbc9edd/ruff-0.17.2-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:c555a877f8f41447e318101cfefea9bf12dfa9f82eedf90c376e57e069f917d0", size = 10571779, upload-time = "2026-10-22T18:37:40.444Z" }, - { url = "https://files.pythonhosted.org/packages/f4/5a/a7e1d74fb464250137d3d4eca645d323536533b672004d04ee0e46e0caf3/ruff-0.17.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:ba405cbd5ec7bda1f555d5e52be1fd68d02608d4d95d24591bdac92cfacb579f", size = 10051707, upload-time = "2026-10-22T18:37:42.812Z" }, - { url = "https://files.pythonhosted.org/packages/6e/f2/02fca29ca7999380f0350a7212fe755c11ab9c22d61327356cce8decdbc6/ruff-0.17.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:8c21b4ab24485358f17291a4f8dc5399b834e963b8efedd920fe4fdb02081bb4", size = 9998227, upload-time = "2026-10-22T18:37:45.224Z" }, - { url = "https://files.pythonhosted.org/packages/d1/00/55aa604a093dfdc1526e570fae0bb7d37a2221c7b4728d5f080b2add16ba/ruff-0.17.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:5875a16b0de70b43cb81eabea5ae5e8f5d1b2fd1b5e6ed07f80cfe5019d0bd5a", size = 10377692, upload-time = "2026-10-22T18:37:47.704Z" }, - { url = "https://files.pythonhosted.org/packages/e4/5a/a7a640f47bb906ec8fa233ea84319d503e6dee02b59e3901bd312ebd1f9b/ruff-0.17.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:2d086be452eed686aa51271ecf2cbe5037956517cc6ee39a17b4489ac12f8bbe", size = 10790587, upload-time = "2026-10-22T18:37:50.191Z" }, - { url = "https://files.pythonhosted.org/packages/2c/d4/c3b74e1b4808438ea7f14bb914478025e2d51261f60774a54a0fa222ec46/ruff-0.17.2-py3-none-win32.whl", hash = "sha256:6bce7d1f5165701ae18f5df85c65afe78cddfa6c5fb4b9bdb0014d60388f3edd", size = 9870537, upload-time = "2026-10-22T18:37:52.486Z" }, - { url = "https://files.pythonhosted.org/packages/1c/9a/c7da96c2c96d20704cf9027f7a5121da272a8c05f1d1531ba949e3b3df04/ruff-0.17.2-py3-none-win_amd64.whl", hash = "sha256:1b59d447f197bef9ef48a22ba1a6016137753c6099e9bac9c36eb566e422424c", size = 10282826, upload-time = "2026-10-22T18:37:55.2Z" }, - { url = "https://files.pythonhosted.org/packages/81/60/a3604c79cb02777b6cb84da894104021986f06c4bc41375102cc95049a32/ruff-0.17.2-py3-none-win_arm64.whl", hash = "sha256:195ad918027f817c119310ca89a42d347887dfc28934aaa869325e9c5dc9d962", size = 9827036, upload-time = "2026-10-22T18:37:58.031Z" }, + { url = "https://files.pythonhosted.org/packages/9e/8c/083365310c4e79c842f25bf5a842facbd9b0c0ec336f96dffa5074fe723d/ruff-0.17.3-py3-none-linux_armv6l.whl", hash = "sha256:ab86b84cd9d05e56d329742c0cabdcbe2d1d56c98f4a04aab9b5b66196febfb4", size = 10216522, upload-time = "2026-10-27T00:33:29.822Z" }, + { url = "https://files.pythonhosted.org/packages/72/26/4b2edf31cfebe9605d8f6ed8f1d6f376d3a53d4c9a123e62661c64c440f0/ruff-0.17.3-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:e407b4a6852853a9a2cdce96963e94ad9775578bb44e7561a0f2829f3cc04b11", size = 10217786, upload-time = "2026-10-27T00:33:33.949Z" }, + { url = "https://files.pythonhosted.org/packages/a2/7e/537aba4b7f54397a374d2f6a6fc93e9c8015e18553f31a4a7b7dbced48b5/ruff-0.17.3-py3-none-macosx_11_0_arm64.whl", hash = "sha256:b75cc113b3aca388933d8296b667b1ac401a80317ea3074c9b0a66541199da29", size = 9440362, upload-time = "2026-10-27T00:33:35.784Z" }, + { url = "https://files.pythonhosted.org/packages/3d/66/283e39734f66c8a5ebaa93c22eb7b7515779a0b1d5a5c0ad20e05c0edb41/ruff-0.17.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ab5fa7ed5ce18554ea69d850ad162cbaa0c85fc47c08d83a569f806681c9a6ad", size = 10094281, upload-time = "2026-10-27T00:33:38.216Z" }, + { url = "https://files.pythonhosted.org/packages/21/4c/1ffc768497bd025a32c72152771e40c0b99bddc5cc6e4f50c7949a395346/ruff-0.17.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c673c170e27834d1262e3a9c1e97bdc9b9c3b180c63d89173ce69747232474c1", size = 10022543, upload-time = "2026-10-27T00:33:40.181Z" }, + { url = "https://files.pythonhosted.org/packages/73/c3/f90db547301080fcb82c92abf914c8bd57b89911d9b65a6c4cc6b52d0635/ruff-0.17.3-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6a754c0341bc9ca151b7b335988b3263921c08859f84ca219b70cee825571b6f", size = 10683921, upload-time = "2026-10-27T00:33:42.182Z" }, + { url = "https://files.pythonhosted.org/packages/e5/98/92d4a8a26c6c96cf1a5b34dd59036d8a71e52d650aab065c58867e964e63/ruff-0.17.3-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4590b9d86c0b1543ebb09094254e191cd43fe8edaf330baa035aab03da251532", size = 11373408, upload-time = "2026-10-27T00:33:44.19Z" }, + { url = "https://files.pythonhosted.org/packages/43/02/1f24d2e3064c9753926deeb901afa57777b37ee46799b09ddd7aee6e5145/ruff-0.17.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bbde18beccd98c29a227c63c99022e3443b99258e08326df6425dfe0443705ef", size = 10977469, upload-time = "2026-10-27T00:33:46.179Z" }, + { url = "https://files.pythonhosted.org/packages/f0/20/fecedea2209f574ab92033b344e01a7f0c2dc76c6d6d19a14c9f8141173f/ruff-0.17.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7fa4b0f931cdbcb8a52044f370a3eb429fb42eb88807b0e800fcaa98dd42b24e", size = 10577491, upload-time = "2026-10-27T00:33:48.233Z" }, + { url = "https://files.pythonhosted.org/packages/33/36/b93fdf0bc6f84f0cd487aadfb0354deb40013669ea35ac3d26855de1e959/ruff-0.17.3-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:39405f341deec934b4289634324ad695f72df2970f9121582872eaf5b722f0f5", size = 10608748, upload-time = "2026-10-27T00:33:50.284Z" }, + { url = "https://files.pythonhosted.org/packages/5d/b7/7d3f5f14145daead1efb0b9a8289ed1daa100f419d60774375951723ce00/ruff-0.17.3-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:68074094f55ca3d29ab19491f640282f7a84061c4c7977aa5094b968ca457e9a", size = 10075057, upload-time = "2026-10-27T00:33:52.074Z" }, + { url = "https://files.pythonhosted.org/packages/b0/ed/93ff7a5909ee56e2bd4b982deae9e0efb2724417874a90c9e41ad66c6dd7/ruff-0.17.3-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:27bb571ac78fef178fe5118d2827df95c2aae74a48fff2b15f6acd03af5ff5bb", size = 10022431, upload-time = "2026-10-27T00:33:54.061Z" }, + { url = "https://files.pythonhosted.org/packages/9b/07/a83b9eeec8c1c3c0e4eda15f06c3a91001bfd2687ea2f07b750719bf9712/ruff-0.17.3-py3-none-musllinux_1_2_i686.whl", hash = "sha256:029c37cbd3de48ca37aa12117bead2d065f15da17d66bf84e0d4274013705db2", size = 10394903, upload-time = "2026-10-27T00:33:56.158Z" }, + { url = "https://files.pythonhosted.org/packages/af/b2/05c39857c2526fcbebe46ad93a8dc97424656dfef14d3ef933abe1ffd331/ruff-0.17.3-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:692fdb46d0fd9c71e380947dc5fc72f2c3f881073bc1f739e4579376231affbe", size = 10799780, upload-time = "2026-10-27T00:33:58.204Z" }, + { url = "https://files.pythonhosted.org/packages/ec/d9/47171a16739eb7a353936b31c20cf54340531e68c9af7d72fd7a784e235d/ruff-0.17.3-py3-none-win32.whl", hash = "sha256:46539cb031b01fd29ae0a02142483c46640b233ee12bb1c1b690bffa1555d5ca", size = 9908481, upload-time = "2026-10-27T00:34:00.087Z" }, + { url = "https://files.pythonhosted.org/packages/d0/a0/f08c1631bfd81faa6a90eaf70c37c786c11bed2046302b56bb506c25e1a0/ruff-0.17.3-py3-none-win_amd64.whl", hash = "sha256:56b8ffb3f3b3cbccb8b76b71b38261b7ed982ef5d20f5b447b1b61a7f4949b24", size = 10341333, upload-time = "2026-10-27T00:34:02.099Z" }, + { url = "https://files.pythonhosted.org/packages/99/d5/4ad4ed31413c301430918e70d3d38ae6f097af0766cb9ab8c9d502b2a4d6/ruff-0.17.3-py3-none-win_arm64.whl", hash = "sha256:81fce74bcd6be0e9da7c67c7553fd0f1f12964a2052cd728ef917b937a5ca1d9", size = 9854332, upload-time = "2026-10-27T00:34:03.847Z" }, ] [[package]] @@ -707,27 +707,27 @@ wheels = [ [[package]] name = "ty" -version = "0.0.92" +version = "0.0.93" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/45/f8/2629d3533019eec56b0008d93198b2cb1575795e017c52759d6ddbdad353/ty-0.0.92.tar.gz", hash = "sha256:d08ff5d89bb63780e30837446ea08ddae3db73ae0b872a441a5b514d37726459", size = 8071788, upload-time = "2026-10-26T03:13:58.999Z" } +sdist = { url = "https://files.pythonhosted.org/packages/78/35/e1cbce56e80f6d911b6b6821d211b4150d0e061d426df038cad78d2800f4/ty-0.0.93.tar.gz", hash = "sha256:18b99060d7f1d601fd4ce1acdcc336d1b3345fea8561307948827e8809c31c25", size = 8105272, upload-time = "2026-10-28T00:52:42.089Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c4/cb/47bdaffb41500ebbd222952fdf5262b4efffca8c8df237b91915fd4f2849/ty-0.0.92-py3-none-linux_armv6l.whl", hash = "sha256:924af587c0d450e3589f4773de416d284483b68bb5cf5580159ad78c272e3298", size = 14365057, upload-time = "2026-10-26T03:13:07.962Z" }, - { url = "https://files.pythonhosted.org/packages/2e/68/1a18a4511b3cf12af9193f6466884f2cbe0ce2aed962ab9db6a1ddf586da/ty-0.0.92-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:ce0232a3beee089de8ee120fdde4ea3b8ca02758e07128b83138970a4ded8db6", size = 13922188, upload-time = "2026-10-26T03:13:11.422Z" }, - { url = "https://files.pythonhosted.org/packages/18/6c/01c6680ea6d02e3b0a6a444dafbf549419fe4971cf7e139ea9c3f087a3c1/ty-0.0.92-py3-none-macosx_11_0_arm64.whl", hash = "sha256:b1753fdfa241af570c1dbd3fbfae9ff600d2c479ba60efe528bbb47ca15860b0", size = 13064190, upload-time = "2026-10-26T03:13:14.029Z" }, - { url = "https://files.pythonhosted.org/packages/4e/f2/79faf9b5ee7defd6df4fc97ff693502d21d34762e16b9031e1cbb4b3f51c/ty-0.0.92-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cfaa6f4825144d0e873654d7223c72dda2ec8f9db6b1049e6897efbfb0a78680", size = 13852740, upload-time = "2026-10-26T03:13:17.019Z" }, - { url = "https://files.pythonhosted.org/packages/5c/aa/7e05fde03b145bac15164df206a844a806442570718fe4f478160607a2e3/ty-0.0.92-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e0041d6786f0d33768afd4f2d21650140534a2600a27576a0292812af49408ec", size = 14093792, upload-time = "2026-10-26T03:13:19.936Z" }, - { url = "https://files.pythonhosted.org/packages/49/21/cae3d9687922c4ce0e8c112634c3b43756cccad24733dca380ba1339fd71/ty-0.0.92-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2c9d8060d840a291ae746ccfedd0e963786e09a7288599d370cde73168b208da", size = 14994799, upload-time = "2026-10-26T03:13:22.963Z" }, - { url = "https://files.pythonhosted.org/packages/34/77/bcf546f2fe4dd8eea9ff35b5eb6b9e0603dcc47b5c8a8f15d41f4a82030f/ty-0.0.92-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2088a253b98f04851e261e8e597b384988b790075451ff47b011e6018bf8bc80", size = 15473722, upload-time = "2026-10-26T03:13:26.062Z" }, - { url = "https://files.pythonhosted.org/packages/74/5e/c5c405a08d91874479887d8a8539ab4194a2322a47987785a3cf2c6a009b/ty-0.0.92-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a0a63965d320c569265ba65788fcfd4cd17f0b0d20c6e88bcfa21dc5fb509a4c", size = 15443218, upload-time = "2026-10-26T03:13:29.115Z" }, - { url = "https://files.pythonhosted.org/packages/26/77/6fd2ec1fd78eb783e93b89f1e1aee7fce9095b32dc5f6cc0fc831bd903f4/ty-0.0.92-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9b6b40225ddd0c049b299e0a655ce04d4de594c6cac3fb9c1e020b113494924", size = 14700747, upload-time = "2026-10-26T03:13:31.851Z" }, - { url = "https://files.pythonhosted.org/packages/fc/d3/b994c68a51f32029a60d56180ee33e9c708bb60997ea5f50b91b3027bd31/ty-0.0.92-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:020ccc79656c0d0f8f353e5e0760988775cdaa253fa4427e265ed96b4994e7fe", size = 14936345, upload-time = "2026-10-26T03:13:34.908Z" }, - { url = "https://files.pythonhosted.org/packages/d4/68/5e5732af9d38c1e00a31b7478f0a81b9e5557cca88f8848dc2573e00f665/ty-0.0.92-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:be5c1fc769335ab03d96f08ecc9878b598a57fd983c36cf5a04137d754828b63", size = 13781405, upload-time = "2026-10-26T03:13:37.684Z" }, - { url = "https://files.pythonhosted.org/packages/2f/6a/e833260c7bf85a5fdc3e08515d1351c6ce8e1186ee8f82cfeb93175f53df/ty-0.0.92-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:a9f389840ec585075531ec1dfd62d25c73aeda0fb409a676ed996e426fb0a7bf", size = 14104200, upload-time = "2026-10-26T03:13:40.476Z" }, - { url = "https://files.pythonhosted.org/packages/66/94/79ea7b18132bcf33fb18cfe7ff5cd31f64ff34a13da56e2afe5ef4e81370/ty-0.0.92-py3-none-musllinux_1_2_i686.whl", hash = "sha256:6a59f712c41b37f964b5b53f0c4207fcf25f4a0ae6cdd4db216f7c19d48c0673", size = 14410183, upload-time = "2026-10-26T03:13:43.707Z" }, - { url = "https://files.pythonhosted.org/packages/e6/da/a68a8dd13cee1df46270d68b2649eba40ae700d737c271bd44c03e9c3c90/ty-0.0.92-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:ca63bad30a6efb95a705de80db2b3d9fc8f120a03e0c7fe765a0413cd8e290e3", size = 14809277, upload-time = "2026-10-26T03:13:46.629Z" }, - { url = "https://files.pythonhosted.org/packages/03/3c/08d37a4c00675c3bd36a03ce3a18c3da284bbca02860df0f788617ceb7ee/ty-0.0.92-py3-none-win32.whl", hash = "sha256:7425c361755fb811e0067c9b29c4b8be65015f694fb2fcca63f99453f8966c30", size = 13311040, upload-time = "2026-10-26T03:13:50.558Z" }, - { url = "https://files.pythonhosted.org/packages/77/b1/f455ba90564e00fbef1e58ea8b29bfebaad6c67ea050a3386fba32db55ef/ty-0.0.92-py3-none-win_amd64.whl", hash = "sha256:646bed75c51c7ca3ae4cba015c699f384241bc873d6ad775e0c0d66629532312", size = 13942099, upload-time = "2026-10-26T03:13:53.17Z" }, - { url = "https://files.pythonhosted.org/packages/6e/70/8369564e77a7e896d37819570c27f52573fa356d1c225312bf16ee402524/ty-0.0.92-py3-none-win_arm64.whl", hash = "sha256:37eaf557f9a9723515bece5c4e8228eb0e2286184de6115c0071ce08d8a21267", size = 13411491, upload-time = "2026-10-26T03:13:56.15Z" }, + { url = "https://files.pythonhosted.org/packages/4e/16/5b0766d3de2b531f47d6f24986f21607546b6ee1861d294ccec69a750b45/ty-0.0.93-py3-none-linux_armv6l.whl", hash = "sha256:74fad0e17d96076364be426b15ed3f052f068ec6e37b9d8dbf9c9c424fcb6f0d", size = 14510907, upload-time = "2026-10-28T00:52:04.298Z" }, + { url = "https://files.pythonhosted.org/packages/14/4a/ba4e9586f22b42f86e95c5f06798d30b288e1d6557b29c137384031c561c/ty-0.0.93-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:83beb545d52c38deb910d977679dcac1c274f5cf8ee0a1868b10d390042c40df", size = 14074052, upload-time = "2026-10-28T00:52:07.324Z" }, + { url = "https://files.pythonhosted.org/packages/ce/3c/00e4195634b61a6ec1f53a2c70777df644a3ee79f6579b48c4e2f6e884d0/ty-0.0.93-py3-none-macosx_11_0_arm64.whl", hash = "sha256:47d6be14343a997c6f828d812513f940929c906f6cf83ca4cdd74db6e16ef261", size = 13132684, upload-time = "2026-10-28T00:52:09.528Z" }, + { url = "https://files.pythonhosted.org/packages/3e/f4/36fb44a79e2d7c8b2d5f2c42cab6d2c1d4d0e8b9fb7e51acb82648fc4d3e/ty-0.0.93-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d696b82ade77500826d84874d46658020486daa9d39eabc71b94a641247ce484", size = 13955788, upload-time = "2026-10-28T00:52:11.478Z" }, + { url = "https://files.pythonhosted.org/packages/49/21/ae904789846d93e4b01faa33ef9a73f28657dd88b8b99619dbae05f30f1d/ty-0.0.93-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9882e7b55ee025feceaf8f1210acda368f931c3f597771385f97a460292a9c8b", size = 14252702, upload-time = "2026-10-28T00:52:13.466Z" }, + { url = "https://files.pythonhosted.org/packages/13/8e/fecf0492b20f1e28fafac944f5a6c7a404d8408f2e6fb0fb5666550f994f/ty-0.0.93-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:318871545c28f22564b445cadd022650e0fa892c913c0c1eb4cf6345d72037a2", size = 15192511, upload-time = "2026-10-28T00:52:15.923Z" }, + { url = "https://files.pythonhosted.org/packages/97/1f/67d3284747800456e96892d51df3fefc9f98b844653a86cfc6312902a490/ty-0.0.93-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1f9c494291a7c83706b380e31606f88b6dcf801499623645861c3099c17edc01", size = 15594668, upload-time = "2026-10-28T00:52:18.133Z" }, + { url = "https://files.pythonhosted.org/packages/ed/1f/2a903b2309c8ea265a0cef1edc00fa9223be42d004171f7f87aded4b1bed/ty-0.0.93-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:43ff1ee239c94260cf2146e23537fb069b7267423723096603051bb7d36ce165", size = 15533756, upload-time = "2026-10-28T00:52:20.271Z" }, + { url = "https://files.pythonhosted.org/packages/dc/75/99bdbbd00220703c51af60160fb1c080f653b45ddb585baf8468588f70ef/ty-0.0.93-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c278c86adeb82374e0f5142b44bb628e9dcb663d98e8f274707300d926e0997", size = 16236455, upload-time = "2026-10-28T00:52:22.244Z" }, + { url = "https://files.pythonhosted.org/packages/ca/7d/edbcce5e504275b3574272629c2c7d657c666312fd5a74a5a3202f256e0a/ty-0.0.93-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:02c7cc6f1d9d2fe49eff5b230d243c696ac798ecce034998e3d67872ab2a5236", size = 15065832, upload-time = "2026-10-28T00:52:24.23Z" }, + { url = "https://files.pythonhosted.org/packages/e6/ce/201c42e84b49a8bb6473edfd3e16e311b942178cefd9678f98dda36f25a4/ty-0.0.93-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:50c580e31da3e4dd3f1b7ab1969497996ab55e61ee06d90132ab46a2964249ef", size = 13919356, upload-time = "2026-10-28T00:52:26.893Z" }, + { url = "https://files.pythonhosted.org/packages/68/5c/f323a70974bd57274d4315d1894586498557e21d4d78cd35b550deaf7878/ty-0.0.93-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:7f037c1761a6874cc0072c39950a987cd6d1563d6df3c94bb131b3e727e921c9", size = 14258573, upload-time = "2026-10-28T00:52:29.049Z" }, + { url = "https://files.pythonhosted.org/packages/c8/ba/0d2a2f0892d19c91cef7785ac1bac5de555059f1bad2a0009d83f2df1d0d/ty-0.0.93-py3-none-musllinux_1_2_i686.whl", hash = "sha256:a8bfbcc8a715a5497210cc89eb134476f511b2de3004697c96b5f6eaa0f1602b", size = 14613304, upload-time = "2026-10-28T00:52:31.474Z" }, + { url = "https://files.pythonhosted.org/packages/b8/02/b0f7b83ef79c85b8813e54ed73189995e3d4ec2f1dda791a8d0acd051386/ty-0.0.93-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:19ae7e56c9021d7eafbc305926ca174183b431c63c27e9d2b7db342d45142446", size = 14937750, upload-time = "2026-10-28T00:52:33.528Z" }, + { url = "https://files.pythonhosted.org/packages/06/ad/d2ece9e2ec588394d0ea0c12b683ff68540f5534988b4e4412664bb87a56/ty-0.0.93-py3-none-win32.whl", hash = "sha256:1c677be05fb0ef0864a305fa4a5258190fc0fc9d79f53c1ce93a0342256f21f1", size = 13464721, upload-time = "2026-10-28T00:52:35.916Z" }, + { url = "https://files.pythonhosted.org/packages/a9/17/ef0c1180498564f08331f4be35aea9de09b37c6ca12fa50ad1959d9d1e38/ty-0.0.93-py3-none-win_amd64.whl", hash = "sha256:65072e0a71f9af81a31a4656521c96eaf539452c37287b9e14a81504b22e0864", size = 14091561, upload-time = "2026-10-28T00:52:38.008Z" }, + { url = "https://files.pythonhosted.org/packages/ef/f8/13fb149c7c5a33be119ecea9c56033b32cc1f87c5ac84d577f2236b7c964/ty-0.0.93-py3-none-win_arm64.whl", hash = "sha256:47991915f6a2101cc63da1dd07b2f3bbd226ab4a14ff3c858b20764c38376166", size = 13552165, upload-time = "2026-10-28T00:52:40.111Z" }, ] [[package]]