diff --git a/app/community_prs.py b/app/community_prs.py index a38c5dd..1db1f68 100644 --- a/app/community_prs.py +++ b/app/community_prs.py @@ -11,6 +11,7 @@ fetch_pr_info, get_all_github_prs, ) +from app.utils.streamlit_date_input import normalize_date_range st.set_page_config( page_title="Community PRs", @@ -205,10 +206,8 @@ def get_change_types(labels: list) -> list[str]: max_value=max_date, ) - # Filter data based on selected date range - # date_input can return () or (start,) or (start, end) depending on user input - start_date = date_range[0] if len(date_range) > 0 else None - end_date = date_range[1] if len(date_range) > 1 else None + # Streamlit can temporarily return partial tuples while a range is being edited. + start_date, end_date = normalize_date_range(date_range) if start_date and end_date: df_filtered = all_prs_df[ (all_prs_df["created_at"].dt.date >= start_date) & (all_prs_df["created_at"].dt.date <= end_date) diff --git a/app/flaky_tests.py b/app/flaky_tests.py index be4961a..61f1f34 100644 --- a/app/flaky_tests.py +++ b/app/flaky_tests.py @@ -1,5 +1,6 @@ from __future__ import annotations +import math from collections import Counter from datetime import date, datetime from typing import Any @@ -144,7 +145,10 @@ def extract_browser(test_name: str) -> str | None: else: flaky_tests_df["Workflow Failure Probability"] = float("nan") -overall_failure_prob: float = 1 - (1 - flaky_tests_df["Workflow Failure Probability"].fillna(0).astype(float)).prod() # type: ignore[operator,assignment] +workflow_failure_probabilities = [ + float(probability) for probability in flaky_tests_df["Workflow Failure Probability"].fillna(0).tolist() +] +overall_failure_prob = 1.0 - math.prod(1.0 - probability for probability in workflow_failure_probabilities) total_flaky_failures = int(flaky_tests_df["Failures"].sum()) diff --git a/app/github_issue_download.py b/app/github_issue_download.py index 11e3885..21f4256 100644 --- a/app/github_issue_download.py +++ b/app/github_issue_download.py @@ -85,11 +85,15 @@ def _format_issue_record( if "issues_state" not in st.session_state: st.session_state["issues_state"] = "all" +issue_state_options: tuple[IssueState, IssueState, IssueState] = ("open", "closed", "all") +saved_issue_state = st.session_state["issues_state"] +default_issue_state: IssueState = saved_issue_state if saved_issue_state in issue_state_options else "all" + with st.form("issue_download_form"): - issue_state = st.selectbox( + issue_state: IssueState = st.selectbox( "Issue state", - options=["open", "closed", "all"], - index=["open", "closed", "all"].index(st.session_state["issues_state"]), + options=issue_state_options, + index=issue_state_options.index(default_issue_state), help="GitHub issues state to fetch.", ) include_prs = st.checkbox( @@ -101,8 +105,7 @@ def _format_issue_record( if submit: with st.spinner("Fetching issues from GitHub…"): - # Cast is safe because selectbox options are limited to these values - raw_issues = _fetch_issue_data(issue_state) # type: ignore[arg-type] + raw_issues = _fetch_issue_data(issue_state) records: list[dict[str, object]] = [] for issue in raw_issues: diff --git a/app/issue_reactions.py b/app/issue_reactions.py index 6fa541c..c184b50 100644 --- a/app/issue_reactions.py +++ b/app/issue_reactions.py @@ -9,6 +9,7 @@ from app.utils.github_utils import get_all_github_issues from app.utils.issue_formatting import get_issue_type, reactions_to_str +from app.utils.streamlit_date_input import normalize_date_range DEFAULT_ISSUES_FOLDER = "issues" PATH_OF_SCRIPT = pathlib.Path(__file__).parent.resolve() @@ -56,10 +57,8 @@ # Filter who closed the issue: closed_by_filter = st.text_input("Closed by", value=st.query_params.get("closed_by", "")) - # Filter data based on selected date range - # date_input can return () or (start,) or (start, end) depending on user input - start_date = date_range[0] if len(date_range) > 0 else None - end_date = date_range[1] if len(date_range) > 1 else None + # Streamlit can temporarily return partial tuples while a range is being edited. + start_date, end_date = normalize_date_range(date_range) if start_date and end_date: df_filtered = all_issues_df[ (all_issues_df["closed_at"].dt.date >= start_date) & (all_issues_df["closed_at"].dt.date <= end_date) diff --git a/app/perf/utils/test_diff_analyzer.py b/app/perf/utils/test_diff_analyzer.py index 04aace6..26194a1 100644 --- a/app/perf/utils/test_diff_analyzer.py +++ b/app/perf/utils/test_diff_analyzer.py @@ -61,13 +61,14 @@ def _extract_react_profile_metrics( stable_test_name (str): Stable test name. """ phase_data = all_phases[index][react_profile_key][phase] - metrics = phase_data.keys() - for metric in metrics: - key = f"{react_profile_key}__{phase}__{metric}" + phase_metrics = ( + ("duration_ms", phase_data["duration_ms"]), + ("count", phase_data["count"]), + ) + for metric_name, metric_value in phase_metrics: + key = f"{react_profile_key}__{phase}__{metric_name}" if key not in results_per_test[stable_test_name]: results_per_test[stable_test_name][key] = [] - # Access by variable key - cast to handle TypedDict limitations - metric_value: float | int = phase_data[metric] # type: ignore[literal-required] results_per_test[stable_test_name][key].append(metric_value) diff --git a/app/utils/github_graphql_utils.py b/app/utils/github_graphql_utils.py index f59ea4a..5a0eb25 100644 --- a/app/utils/github_graphql_utils.py +++ b/app/utils/github_graphql_utils.py @@ -255,8 +255,8 @@ def _extract_pr_metrics( for review in all_reviews: author_info = review.get("author") or {} login = author_info.get("login") - if _is_human_reviewer(author_info.get("__typename", ""), login, ignore_bots): - reviewer_logins.add(login) # type: ignore[arg-type] + if login and _is_human_reviewer(author_info.get("__typename", ""), login, ignore_bots): + reviewer_logins.add(login) reviewers = sorted(reviewer_logins) diff --git a/app/utils/github_utils.py b/app/utils/github_utils.py index 5c845b3..c1cd73e 100644 --- a/app/utils/github_utils.py +++ b/app/utils/github_utils.py @@ -5,14 +5,14 @@ import json import urllib.parse from io import BytesIO -from typing import TYPE_CHECKING, Any, Final, Literal, cast +from typing import TYPE_CHECKING, Any, Final, Literal, Protocol, cast from zipfile import ZipFile import requests import streamlit as st if TYPE_CHECKING: - from collections.abc import Iterator + from collections.abc import Callable, Iterator from datetime import date # Streamlit team members: @@ -165,6 +165,12 @@ def __init__(self, message: str, partial_data: Any) -> None: self.partial_data = partial_data +class _PullRequestFilesPayloadFetcher(Protocol): + def __call__(self, repo: str, pr_number: int) -> tuple[list[dict[str, Any]], str | None]: ... + + clear: Callable[..., None] + + @st.cache_data(ttl=60 * 10, max_entries=256, show_spinner=False) def fetch_issue_payload(repo: str, issue_number: int | str) -> tuple[dict[str, Any] | None, str | None]: """Fetch issue payload and return (data, error_message).""" @@ -351,7 +357,7 @@ def _fetch_pull_request_files_payload_cached(repo: str, pr_number: int) -> list[ return files -def fetch_pull_request_files_payload(repo: str, pr_number: int) -> tuple[list[dict[str, Any]], str | None]: +def _fetch_pull_request_files_payload(repo: str, pr_number: int) -> tuple[list[dict[str, Any]], str | None]: """Fetch all changed files for a pull request.""" try: return _fetch_pull_request_files_payload_cached(repo, pr_number), None @@ -359,7 +365,8 @@ def fetch_pull_request_files_payload(repo: str, pr_number: int) -> tuple[list[di return cast("list[dict[str, Any]]", exc.partial_data), str(exc) -fetch_pull_request_files_payload.clear = _fetch_pull_request_files_payload_cached.clear # type: ignore[attr-defined] +fetch_pull_request_files_payload = cast("_PullRequestFilesPayloadFetcher", _fetch_pull_request_files_payload) +fetch_pull_request_files_payload.clear = _fetch_pull_request_files_payload_cached.clear @st.cache_data(ttl=300, max_entries=256, show_spinner=False) diff --git a/app/utils/streamlit_date_input.py b/app/utils/streamlit_date_input.py new file mode 100644 index 0000000..725b1eb --- /dev/null +++ b/app/utils/streamlit_date_input.py @@ -0,0 +1,18 @@ +from __future__ import annotations + +from datetime import date + +type DateInputValue = date | tuple[()] | tuple[date] | tuple[date, date] + + +def normalize_date_range(date_input_value: DateInputValue) -> tuple[date | None, date | None]: + """Normalize a Streamlit date_input value into a start/end tuple.""" + match date_input_value: + case (start_date, end_date): + return start_date, end_date + case (start_date,): + return start_date, None + case _ if isinstance(date_input_value, date): + return date_input_value, date_input_value + case _: + return None, None diff --git a/pyproject.toml b/pyproject.toml index e2a99bc..48d04c0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,7 +48,7 @@ default-groups = ["dev"] dev = [ "pytest>=9.0.2", "ruff==0.15.12", - "ty==0.0.12", + "ty==0.0.34", "mypy==1.20.2", "watchdog", "pandas-stubs", diff --git a/uv.lock b/uv.lock index 0ba4671..acd4ae3 100644 --- a/uv.lock +++ b/uv.lock @@ -1624,7 +1624,7 @@ dev = [ { name = "pre-commit", specifier = ">=4.5.1" }, { name = "pytest", specifier = ">=9.0.2" }, { name = "ruff", specifier = "==0.15.12" }, - { name = "ty", specifier = "==0.0.12" }, + { name = "ty", specifier = "==0.0.34" }, { name = "watchdog" }, ] @@ -1773,27 +1773,26 @@ wheels = [ [[package]] name = "ty" -version = "0.0.12" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b5/78/ba1a4ad403c748fbba8be63b7e774a90e80b67192f6443d624c64fe4aaab/ty-0.0.12.tar.gz", hash = "sha256:cd01810e106c3b652a01b8f784dd21741de9fdc47bd595d02c122a7d5cefeee7", size = 4981303, upload-time = "2026-01-14T22:30:48.537Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7d/8f/c21314d074dda5fb13d3300fa6733fd0d8ff23ea83a721818740665b6314/ty-0.0.12-py3-none-linux_armv6l.whl", hash = "sha256:eb9da1e2c68bd754e090eab39ed65edf95168d36cbeb43ff2bd9f86b4edd56d1", size = 9614164, upload-time = "2026-01-14T22:30:44.016Z" }, - { url = "https://files.pythonhosted.org/packages/09/28/f8a4d944d13519d70c486e8f96d6fa95647ac2aa94432e97d5cfec1f42f6/ty-0.0.12-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:c181f42aa19b0ed7f1b0c2d559980b1f1d77cc09419f51c8321c7ddf67758853", size = 9542337, upload-time = "2026-01-14T22:30:05.687Z" }, - { url = "https://files.pythonhosted.org/packages/e1/9c/f576e360441de7a8201daa6dc4ebc362853bc5305e059cceeb02ebdd9a48/ty-0.0.12-py3-none-macosx_11_0_arm64.whl", hash = "sha256:1f829e1eecd39c3e1b032149db7ae6a3284f72fc36b42436e65243a9ed1173db", size = 8909582, upload-time = "2026-01-14T22:30:46.089Z" }, - { url = "https://files.pythonhosted.org/packages/d6/13/0898e494032a5d8af3060733d12929e3e7716db6c75eac63fa125730a3e7/ty-0.0.12-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f45162e7826e1789cf3374627883cdeb0d56b82473a0771923e4572928e90be3", size = 9384932, upload-time = "2026-01-14T22:30:13.769Z" }, - { url = "https://files.pythonhosted.org/packages/e4/1a/b35b6c697008a11d4cedfd34d9672db2f0a0621ec80ece109e13fca4dfef/ty-0.0.12-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d11fec40b269bec01e751b2337d1c7ffa959a2c2090a950d7e21c2792442cccd", size = 9453140, upload-time = "2026-01-14T22:30:11.131Z" }, - { url = "https://files.pythonhosted.org/packages/dd/1e/71c9edbc79a3c88a0711324458f29c7dbf6c23452c6e760dc25725483064/ty-0.0.12-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09d99e37e761a4d2651ad9d5a610d11235fbcbf35dc6d4bc04abf54e7cf894f1", size = 9960680, upload-time = "2026-01-14T22:30:33.621Z" }, - { url = "https://files.pythonhosted.org/packages/0e/75/39375129f62dd22f6ad5a99cd2a42fd27d8b91b235ce2db86875cdad397d/ty-0.0.12-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:d9ca0cdb17bd37397da7b16a7cd23423fc65c3f9691e453ad46c723d121225a1", size = 10904518, upload-time = "2026-01-14T22:30:08.464Z" }, - { url = "https://files.pythonhosted.org/packages/32/5e/26c6d88fafa11a9d31ca9f4d12989f57782ec61e7291d4802d685b5be118/ty-0.0.12-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcf2757b905e7eddb7e456140066335b18eb68b634a9f72d6f54a427ab042c64", size = 10525001, upload-time = "2026-01-14T22:30:16.454Z" }, - { url = "https://files.pythonhosted.org/packages/c2/a5/2f0b91894af13187110f9ad7ee926d86e4e6efa755c9c88a820ed7f84c85/ty-0.0.12-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:00cf34c1ebe1147efeda3021a1064baa222c18cdac114b7b050bbe42deb4ca80", size = 10307103, upload-time = "2026-01-14T22:30:41.221Z" }, - { url = "https://files.pythonhosted.org/packages/4b/77/13d0410827e4bc713ebb7fdaf6b3590b37dcb1b82e0a81717b65548f2442/ty-0.0.12-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb3a655bd869352e9a22938d707631ac9fbca1016242b1f6d132d78f347c851", size = 10072737, upload-time = "2026-01-14T22:30:51.783Z" }, - { url = "https://files.pythonhosted.org/packages/e1/dd/fc36d8bac806c74cf04b4ca735bca14d19967ca84d88f31e121767880df1/ty-0.0.12-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:4658e282c7cb82be304052f8f64f9925f23c3c4f90eeeb32663c74c4b095d7ba", size = 9368726, upload-time = "2026-01-14T22:30:18.683Z" }, - { url = "https://files.pythonhosted.org/packages/54/70/9e8e461647550f83e2fe54bc632ccbdc17a4909644783cdbdd17f7296059/ty-0.0.12-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:c167d838eaaa06e03bb66a517f75296b643d950fbd93c1d1686a187e5a8dbd1f", size = 9454704, upload-time = "2026-01-14T22:30:22.759Z" }, - { url = "https://files.pythonhosted.org/packages/04/9b/6292cf7c14a0efeca0539cf7d78f453beff0475cb039fbea0eb5d07d343d/ty-0.0.12-py3-none-musllinux_1_2_i686.whl", hash = "sha256:2956e0c9ab7023533b461d8a0e6b2ea7b78e01a8dde0688e8234d0fce10c4c1c", size = 9649829, upload-time = "2026-01-14T22:30:31.234Z" }, - { url = "https://files.pythonhosted.org/packages/49/bd/472a5d2013371e4870886cff791c94abdf0b92d43d305dd0f8e06b6ff719/ty-0.0.12-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:5c6a3fd7479580009f21002f3828320621d8a82d53b7ba36993234e3ccad58c8", size = 10162814, upload-time = "2026-01-14T22:30:36.174Z" }, - { url = "https://files.pythonhosted.org/packages/31/e9/2ecbe56826759845a7c21d80aa28187865ea62bc9757b056f6cbc06f78ed/ty-0.0.12-py3-none-win32.whl", hash = "sha256:a91c24fd75c0f1796d8ede9083e2c0ec96f106dbda73a09fe3135e075d31f742", size = 9140115, upload-time = "2026-01-14T22:30:38.903Z" }, - { url = "https://files.pythonhosted.org/packages/5d/6d/d9531eff35a5c0ec9dbc10231fac21f9dd6504814048e81d6ce1c84dc566/ty-0.0.12-py3-none-win_amd64.whl", hash = "sha256:df151894be55c22d47068b0f3b484aff9e638761e2267e115d515fcc9c5b4a4b", size = 9884532, upload-time = "2026-01-14T22:30:25.112Z" }, - { url = "https://files.pythonhosted.org/packages/e9/f3/20b49e75967023b123a221134548ad7000f9429f13fdcdda115b4c26305f/ty-0.0.12-py3-none-win_arm64.whl", hash = "sha256:cea99d334b05629de937ce52f43278acf155d3a316ad6a35356635f886be20ea", size = 9313974, upload-time = "2026-01-14T22:30:27.44Z" }, +version = "0.0.34" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c4/69/e24eefe2c35c0fdbdec9b60e162727af669bb76d64d993d982eb67b24c38/ty-0.0.34.tar.gz", hash = "sha256:a6efe66b0f13c03a65e6c72ec9abfe2792e2fd063c74fa67e2c4930e29d661be", size = 5585933, upload-time = "2026-05-01T23:06:46.388Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/83/7b/8b85003d6639ef17a97dcbb31f4511cfe78f1c81a964470db100c8c883e7/ty-0.0.34-py3-none-linux_armv6l.whl", hash = "sha256:9ecc3d14f07a95a6ceb88e07f8e62358dbd37325d3d5bd56da7217ff1fef7fb8", size = 11067094, upload-time = "2026-05-01T23:06:21.133Z" }, + { url = "https://files.pythonhosted.org/packages/d7/25/b0098f65b020b015c40567c763fc66fffbec88b2ba6f584bca1e92f05ebb/ty-0.0.34-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:0dccffd8a9d02321cd2dee3249df205e26d62694e741f4eeca36b157fd8b419f", size = 10840909, upload-time = "2026-05-01T23:06:18.409Z" }, + { url = "https://files.pythonhosted.org/packages/e4/55/5e4adcf7d2a1006b844903b27cb81244a9b748d850433a46a6c21776c401/ty-0.0.34-py3-none-macosx_11_0_arm64.whl", hash = "sha256:b0ea47a2998e167ab3b21d2f4b5309a9cf33c297809f6d7e3e753252223174d0", size = 10279378, upload-time = "2026-05-01T23:06:37.962Z" }, + { url = "https://files.pythonhosted.org/packages/4d/91/f537dca0db8fe2558e8ab04d8941d687b384fcc1df5eb9023b2db75ac26c/ty-0.0.34-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b37da00b41a118a459ae56d8947e70651073fb33ebfbceb820e4a10b22d5023", size = 10817423, upload-time = "2026-05-01T23:06:26.247Z" }, + { url = "https://files.pythonhosted.org/packages/2c/c4/55a3ad1da2815af1009bdc1b8c90dc11a364cd314e4b48c5128ba9d38859/ty-0.0.34-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:81cbbb93c2342fe3de43e625d3a9eb149633e9f485e816ebf6395d08685355d8", size = 10851826, upload-time = "2026-05-01T23:06:24.198Z" }, + { url = "https://files.pythonhosted.org/packages/ce/8c/9c7606af22d73fb43ea4369472d9c66ece11231be73b0efe8e3c61655559/ty-0.0.34-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c5b4dea1594a021289e172582df9cde7089dce14b276fc650e7b212b1772e12", size = 11356318, upload-time = "2026-05-01T23:06:51.139Z" }, + { url = "https://files.pythonhosted.org/packages/20/54/bb423f663721ab4138b216425c6b55eaefd3a068243b24d6d8fe988f4e13/ty-0.0.34-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:030fb00aa2d2a5b5ae9d9183d574e0c82dae80566700a7490c43669d8ece40cd", size = 11902968, upload-time = "2026-05-01T23:06:35.82Z" }, + { url = "https://files.pythonhosted.org/packages/b6/22/01122b21ab6b534a2f618c6bbe5f1f7f49fd56f4b2ec8887cd6d40d08fb3/ty-0.0.34-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ae9555e24e36c63a8218e037a5a63f15579eb6aa94f41017e57cd41d335cfb5", size = 11548860, upload-time = "2026-05-01T23:06:42.155Z" }, + { url = "https://files.pythonhosted.org/packages/d1/50/86008b1392ec64bed1957bbcc7aaa43b466b50dfc91bb131841c21d7c5c3/ty-0.0.34-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:99eb23df9ed129fc26d1ab00d6f0b8dfe5253b09c2ac6abdb11523fa70d67f10", size = 11457097, upload-time = "2026-05-01T23:06:53.477Z" }, + { url = "https://files.pythonhosted.org/packages/92/3e/4558b2296963ba99c58d8409c57d7db4f3061b656c3613cb21c02c1ef4c2/ty-0.0.34-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:85de45382016eceae69e104815eb2cfa200787df104002e262a86cbd43ed2c02", size = 10798192, upload-time = "2026-05-01T23:06:40.004Z" }, + { url = "https://files.pythonhosted.org/packages/76/bf/650d24402be2ef678528d60caac1d9477a40fc37e3792ecef07834fd7a4a/ty-0.0.34-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:14cb575fb8fa5131f5129d100cfe23c1575d23faf5dfc5158432749a3e38c9b5", size = 10890390, upload-time = "2026-05-01T23:06:33.076Z" }, + { url = "https://files.pythonhosted.org/packages/5c/ef/ccd2ca13906079f7935fd7e067661b24233017f57d987d51d6a121d85bb5/ty-0.0.34-py3-none-musllinux_1_2_i686.whl", hash = "sha256:c6fc0b69d8450e6910ba9db34572b959b81329a97ae273c391f70e9fb6c1aade", size = 11031564, upload-time = "2026-05-01T23:06:55.812Z" }, + { url = "https://files.pythonhosted.org/packages/ba/2d/d27b72005b6f43599e3bcabab0d7135ac0c230b7a307bb99f9eea02c1cda/ty-0.0.34-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:30dfcec2f0fde3993f4f912ed0e057dcbebc8615299f610a4c2ddb7b5a3e1e06", size = 11553430, upload-time = "2026-05-01T23:06:31.096Z" }, + { url = "https://files.pythonhosted.org/packages/a7/12/20812e1ad930b8d4af70eebf19ad23cff6e31efcfa613ef884531fcdbaa1/ty-0.0.34-py3-none-win32.whl", hash = "sha256:97b77ddf007271b812a313a8f0a14929bc5590958433e1fb83ef585676f53342", size = 10436048, upload-time = "2026-05-01T23:06:49.108Z" }, + { url = "https://files.pythonhosted.org/packages/b0/6a/afa095c5987868fbda27c0f731146ac8e3d07b357adfa83daccaee5b1a16/ty-0.0.34-py3-none-win_amd64.whl", hash = "sha256:1f543968accb952705134028d1fda8656882787dbbc667ad4d6c3ba23791d604", size = 11462526, upload-time = "2026-05-01T23:06:28.514Z" }, + { url = "https://files.pythonhosted.org/packages/63/8f/bf041a06260d77662c0605e56dacfe90b786bf824cbe1aed238d15fe5e84/ty-0.0.34-py3-none-win_arm64.whl", hash = "sha256:ea09108cbcb16b6b06d7596312b433bf49681e78d30e4dc7fb3c1b248a95e09a", size = 10846945, upload-time = "2026-05-01T23:06:44.428Z" }, ] [[package]]