From 9bbf1dba621771f1b7f8f274f19e9967b9cbc9a8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 May 2026 17:12:50 +0000 Subject: [PATCH 1/2] Bump ty from 0.0.12 to 0.0.34 Bumps [ty](https://github.com/astral-sh/ty) from 0.0.12 to 0.0.34. - [Release notes](https://github.com/astral-sh/ty/releases) - [Changelog](https://github.com/astral-sh/ty/blob/main/CHANGELOG.md) - [Commits](https://github.com/astral-sh/ty/compare/0.0.12...0.0.34) --- updated-dependencies: - dependency-name: ty dependency-version: 0.0.34 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pyproject.toml | 2 +- uv.lock | 43 +++++++++++++++++++++---------------------- 2 files changed, 22 insertions(+), 23 deletions(-) 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]] From add1d6a98fa719d9486623353ed131f8a57acc1a Mon Sep 17 00:00:00 2001 From: Bob Nisco Date: Mon, 11 May 2026 10:20:41 -0700 Subject: [PATCH 2/2] fix(ci): satisfy ty 0.0.34 type checks Adapt the app's stricter typing paths to the newer ty release so the dependency bump can land without breaking CI. This preserves the existing behavior while tightening date-range handling, cached helper typing, and a few optional-value code paths. Co-authored-by: Cursor --- app/community_prs.py | 7 +++---- app/flaky_tests.py | 6 +++++- app/github_issue_download.py | 13 ++++++++----- app/issue_reactions.py | 7 +++---- app/perf/utils/test_diff_analyzer.py | 11 ++++++----- app/utils/github_graphql_utils.py | 4 ++-- app/utils/github_utils.py | 15 +++++++++++---- app/utils/streamlit_date_input.py | 18 ++++++++++++++++++ 8 files changed, 56 insertions(+), 25 deletions(-) create mode 100644 app/utils/streamlit_date_input.py 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