From 11b90f2a8817b87e35a75677d3ca912b85b24683 Mon Sep 17 00:00:00 2001 From: Sajal-Kulshreshtha Date: Sat, 20 Sep 2025 19:04:44 +0530 Subject: [PATCH 1/6] added mypy and fixed one file types issues Signed-off-by: Sajal-Kulshreshtha --- augur/application/db/lib.py | 3 +- augur/application/db/util.py | 79 ++++++++++++++++++++---------------- augur/mypy.ini | 6 +++ 3 files changed, 51 insertions(+), 37 deletions(-) create mode 100644 augur/mypy.ini diff --git a/augur/application/db/lib.py b/augur/application/db/lib.py index a82c97dd66..5d83715bdc 100644 --- a/augur/application/db/lib.py +++ b/augur/application/db/lib.py @@ -603,5 +603,4 @@ def get_repo_group_by_name(name): with get_session() as session: - return session.query(RepoGroup).filter(RepoGroup.rg_name == name).first() - \ No newline at end of file + return session.query(RepoGroup).filter(RepoGroup.rg_name == name).first() \ No newline at end of file diff --git a/augur/application/db/util.py b/augur/application/db/util.py index 81f24ea6dd..73cac331ad 100644 --- a/augur/application/db/util.py +++ b/augur/application/db/util.py @@ -1,20 +1,20 @@ -from sqlalchemy.exc import OperationalError import time +from typing import Callable, Any, List, Dict, Optional, Union +from sqlalchemy.exc import OperationalError - -def catch_operational_error(func): - +def catch_operational_error(func: Callable[[], Any]) -> Any: + """ + Executes a function and retries up to 4 times if OperationalError occurs. + Implements exponential backoff starting with 240 seconds. + """ attempts = 0 - error = None + error: Optional[str] = None timeout = 240 while attempts < 4: - - # do the sleep here instead of instead of in the exception - # so it doesn't sleep after the last failed time if attempts > 0: - #Do a 30% exponential backoff + # Do a 30% exponential backoff time.sleep(timeout) timeout = int(timeout * 1.3) try: @@ -28,9 +28,19 @@ def catch_operational_error(func): raise Exception(error) -def execute_session_query(query, query_type="all"): +def execute_session_query(query: Any, query_type: str = "all") -> Any: + """ + Executes an SQLAlchemy ORM query with retries on OperationalError. + + Args: + query: SQLAlchemy ORM query object. + query_type: One of 'all', 'one', 'first'. + + Returns: + Query result according to query_type. + """ + func: Optional[Callable[[], Any]] = None - func = None if query_type == "all": func = query.all elif query_type == "one": @@ -43,48 +53,47 @@ def execute_session_query(query, query_type="all"): return catch_operational_error(func) - -def convert_orm_list_to_dict_list(result): - new_list = [] +def convert_orm_list_to_dict_list(result: List[Any]) -> List[Dict[str, Any]]: + """ + Converts a list of ORM model instances to a list of dictionaries. + """ + new_list: List[Dict[str, Any]] = [] for row in result: - row_dict = row.__dict__ - try: - del row_dict['_sa_instance_state'] - except: - pass - + row_dict = dict(row.__dict__) # Copy to avoid mutating the ORM instance + row_dict.pop("_sa_instance_state", None) # Remove SQLAlchemy internal state new_list.append(row_dict) - - return new_list + return new_list -def convert_type_of_value(config_dict, logger=None): - - data_type = config_dict["type"] +def convert_type_of_value( + config_dict: Dict[str, Any], logger: Optional[Any] = None +) -> Dict[str, Any]: + """ + Converts the 'value' field in config_dict to the type specified in 'type'. + Supported types: str, int, bool, float. + """ + data_type: Optional[str] = config_dict.get("type") - if data_type == "str" or data_type is None: + if data_type is None or data_type == "str": return config_dict elif data_type == "int": config_dict["value"] = int(config_dict["value"]) elif data_type == "bool": - value = config_dict["value"] - - if value.lower() == "false": - config_dict["value"] = False - else: - config_dict["value"] = True + value = str(config_dict["value"]).lower() + config_dict["value"] = value != "false" elif data_type == "float": config_dict["value"] = float(config_dict["value"]) else: + msg = f"Need to add support for {data_type} types to config" if logger: - logger.error(f"Need to add support for {data_type} types to config") + logger.error(msg) else: - print(f"Need to add support for {data_type} types to config") + print(msg) - return config_dict \ No newline at end of file + return config_dict diff --git a/augur/mypy.ini b/augur/mypy.ini new file mode 100644 index 0000000000..22f91473c1 --- /dev/null +++ b/augur/mypy.ini @@ -0,0 +1,6 @@ +[mypy] +files = augur/application/db/util.py + +ignore_missing_imports = True +follow_imports = skip +disallow_untyped_defs = True From 1b46aaa814725a0ce65f4e2d248e6769e25da49e Mon Sep 17 00:00:00 2001 From: Sajal-Kulshreshtha Date: Sat, 20 Sep 2025 19:18:30 +0530 Subject: [PATCH 2/6] fixed one unnecessary change Signed-off-by: Sajal-Kulshreshtha --- augur/application/db/lib.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/augur/application/db/lib.py b/augur/application/db/lib.py index 5d83715bdc..cfb48fda86 100644 --- a/augur/application/db/lib.py +++ b/augur/application/db/lib.py @@ -603,4 +603,5 @@ def get_repo_group_by_name(name): with get_session() as session: - return session.query(RepoGroup).filter(RepoGroup.rg_name == name).first() \ No newline at end of file + return session.query(RepoGroup).filter(RepoGroup.rg_name == name).first() + \ No newline at end of file From 355e5ddafbd0c7a0906bb52fcde15cdc2d2547a2 Mon Sep 17 00:00:00 2001 From: Sajal-Kulshreshtha Date: Tue, 23 Sep 2025 16:30:40 +0530 Subject: [PATCH 3/6] reduced use of any and fixed some logical errors Signed-off-by: Sajal-Kulshreshtha --- augur/application/db/util.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/augur/application/db/util.py b/augur/application/db/util.py index 73cac331ad..4accae7544 100644 --- a/augur/application/db/util.py +++ b/augur/application/db/util.py @@ -1,6 +1,8 @@ import time -from typing import Callable, Any, List, Dict, Optional, Union +import logging +from typing import Callable, TypedDict, Any, List, Dict, Optional, Union from sqlalchemy.exc import OperationalError +from augur.application.db.models.base import Base def catch_operational_error(func: Callable[[], Any]) -> Any: @@ -14,7 +16,7 @@ def catch_operational_error(func: Callable[[], Any]) -> Any: while attempts < 4: if attempts > 0: - # Do a 30% exponential backoff + #Do a 30% exponential backoff time.sleep(timeout) timeout = int(timeout * 1.3) try: @@ -52,8 +54,7 @@ def execute_session_query(query: Any, query_type: str = "all") -> Any: return catch_operational_error(func) - -def convert_orm_list_to_dict_list(result: List[Any]) -> List[Dict[str, Any]]: +def convert_orm_list_to_dict_list(result: List["Base"]) -> List[Dict[str, Any]]: """ Converts a list of ORM model instances to a list of dictionaries. """ @@ -66,17 +67,20 @@ def convert_orm_list_to_dict_list(result: List[Any]) -> List[Dict[str, Any]]: return new_list +class ConfigDict(TypedDict, total=False): + type: Optional[str] + value: Union[str, int, float, bool] def convert_type_of_value( - config_dict: Dict[str, Any], logger: Optional[Any] = None -) -> Dict[str, Any]: + config_dict: ConfigDict, logger: Optional[logging.Logger] = None +) -> ConfigDict: """ Converts the 'value' field in config_dict to the type specified in 'type'. Supported types: str, int, bool, float. """ data_type: Optional[str] = config_dict.get("type") - if data_type is None or data_type == "str": + if data_type == "str" or data_type is None: return config_dict elif data_type == "int": @@ -96,4 +100,4 @@ def convert_type_of_value( else: print(msg) - return config_dict + return config_dict \ No newline at end of file From 7691979e9b4a1731edd8fc3f4899b5b03f899626 Mon Sep 17 00:00:00 2001 From: Sajal-Kulshreshtha Date: Sun, 28 Sep 2025 04:37:59 +0530 Subject: [PATCH 4/6] added CI Job for type checking Signed-off-by: Sajal-Kulshreshtha --- .github/workflows/mypy.yaml | 28 ++++++++++++++++++++++++++++ pyproject.toml | 1 + 2 files changed, 29 insertions(+) create mode 100644 .github/workflows/mypy.yaml diff --git a/.github/workflows/mypy.yaml b/.github/workflows/mypy.yaml new file mode 100644 index 0000000000..cd4417cf3c --- /dev/null +++ b/.github/workflows/mypy.yaml @@ -0,0 +1,28 @@ +name: Type Check + +on: + pull_request: + push: + branches: + - main + +jobs: + mypy: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: "3.11" + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install .[dev] + + - name: Run mypy + run: | + mypy --config-file augur/mypy.ini diff --git a/pyproject.toml b/pyproject.toml index 6e78b2118f..284e4fd36f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -99,6 +99,7 @@ dev = [ "pytest==6.2.5", "toml>=0.10.2", "ipdb==0.13.9", + "mypy>=1.8.0", {include-group = "docs"}, ] docs = [ From 5f480f4241b23ae23a53037e2d4dfc0585b4302a Mon Sep 17 00:00:00 2001 From: Sajal-Kulshreshtha Date: Mon, 29 Sep 2025 20:01:55 +0530 Subject: [PATCH 5/6] Update dependencies and sync lockfile Signed-off-by: Sajal-Kulshreshtha --- uv.lock | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-) diff --git a/uv.lock b/uv.lock index 66352a8f2e..34e7fbca73 100644 --- a/uv.lock +++ b/uv.lock @@ -1,5 +1,5 @@ version = 1 -revision = 2 +revision = 3 requires-python = ">=3.10" resolution-markers = [ "python_full_version >= '3.12'", @@ -218,6 +218,7 @@ dependencies = [ dev = [ { name = "docutils" }, { name = "ipdb" }, + { name = "mypy" }, { name = "pytest" }, { name = "setuptools" }, { name = "sphinx" }, @@ -316,6 +317,7 @@ requires-dist = [ dev = [ { name = "docutils", specifier = "==0.20.1" }, { name = "ipdb", specifier = "==0.13.9" }, + { name = "mypy", specifier = ">=1.8.0" }, { name = "pytest", specifier = "==6.2.5" }, { name = "setuptools" }, { name = "sphinx", specifier = "==7.2.6" }, @@ -2016,6 +2018,60 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ca/91/7dc28d5e2a11a5ad804cf2b7f7a5fcb1eb5a4966d66a5d2b41aee6376543/msgpack-1.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:6d489fba546295983abd142812bda76b57e33d0b9f5d5b71c09a583285506f69", size = 72341, upload-time = "2025-06-13T06:52:27.835Z" }, ] +[[package]] +name = "mypy" +version = "1.18.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mypy-extensions" }, + { name = "pathspec" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c0/77/8f0d0001ffad290cef2f7f216f96c814866248a0b92a722365ed54648e7e/mypy-1.18.2.tar.gz", hash = "sha256:06a398102a5f203d7477b2923dda3634c36727fa5c237d8f859ef90c42a9924b", size = 3448846, upload-time = "2025-09-19T00:11:10.519Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/03/6f/657961a0743cff32e6c0611b63ff1c1970a0b482ace35b069203bf705187/mypy-1.18.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c1eab0cf6294dafe397c261a75f96dc2c31bffe3b944faa24db5def4e2b0f77c", size = 12807973, upload-time = "2025-09-19T00:10:35.282Z" }, + { url = "https://files.pythonhosted.org/packages/10/e9/420822d4f661f13ca8900f5fa239b40ee3be8b62b32f3357df9a3045a08b/mypy-1.18.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7a780ca61fc239e4865968ebc5240bb3bf610ef59ac398de9a7421b54e4a207e", size = 11896527, upload-time = "2025-09-19T00:10:55.791Z" }, + { url = "https://files.pythonhosted.org/packages/aa/73/a05b2bbaa7005f4642fcfe40fb73f2b4fb6bb44229bd585b5878e9a87ef8/mypy-1.18.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:448acd386266989ef11662ce3c8011fd2a7b632e0ec7d61a98edd8e27472225b", size = 12507004, upload-time = "2025-09-19T00:11:05.411Z" }, + { url = "https://files.pythonhosted.org/packages/4f/01/f6e4b9f0d031c11ccbd6f17da26564f3a0f3c4155af344006434b0a05a9d/mypy-1.18.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f9e171c465ad3901dc652643ee4bffa8e9fef4d7d0eece23b428908c77a76a66", size = 13245947, upload-time = "2025-09-19T00:10:46.923Z" }, + { url = "https://files.pythonhosted.org/packages/d7/97/19727e7499bfa1ae0773d06afd30ac66a58ed7437d940c70548634b24185/mypy-1.18.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:592ec214750bc00741af1f80cbf96b5013d81486b7bb24cb052382c19e40b428", size = 13499217, upload-time = "2025-09-19T00:09:39.472Z" }, + { url = "https://files.pythonhosted.org/packages/9f/4f/90dc8c15c1441bf31cf0f9918bb077e452618708199e530f4cbd5cede6ff/mypy-1.18.2-cp310-cp310-win_amd64.whl", hash = "sha256:7fb95f97199ea11769ebe3638c29b550b5221e997c63b14ef93d2e971606ebed", size = 9766753, upload-time = "2025-09-19T00:10:49.161Z" }, + { url = "https://files.pythonhosted.org/packages/88/87/cafd3ae563f88f94eec33f35ff722d043e09832ea8530ef149ec1efbaf08/mypy-1.18.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:807d9315ab9d464125aa9fcf6d84fde6e1dc67da0b6f80e7405506b8ac72bc7f", size = 12731198, upload-time = "2025-09-19T00:09:44.857Z" }, + { url = "https://files.pythonhosted.org/packages/0f/e0/1e96c3d4266a06d4b0197ace5356d67d937d8358e2ee3ffac71faa843724/mypy-1.18.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:776bb00de1778caf4db739c6e83919c1d85a448f71979b6a0edd774ea8399341", size = 11817879, upload-time = "2025-09-19T00:09:47.131Z" }, + { url = "https://files.pythonhosted.org/packages/72/ef/0c9ba89eb03453e76bdac5a78b08260a848c7bfc5d6603634774d9cd9525/mypy-1.18.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1379451880512ffce14505493bd9fe469e0697543717298242574882cf8cdb8d", size = 12427292, upload-time = "2025-09-19T00:10:22.472Z" }, + { url = "https://files.pythonhosted.org/packages/1a/52/ec4a061dd599eb8179d5411d99775bec2a20542505988f40fc2fee781068/mypy-1.18.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1331eb7fd110d60c24999893320967594ff84c38ac6d19e0a76c5fd809a84c86", size = 13163750, upload-time = "2025-09-19T00:09:51.472Z" }, + { url = "https://files.pythonhosted.org/packages/c4/5f/2cf2ceb3b36372d51568f2208c021870fe7834cf3186b653ac6446511839/mypy-1.18.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3ca30b50a51e7ba93b00422e486cbb124f1c56a535e20eff7b2d6ab72b3b2e37", size = 13351827, upload-time = "2025-09-19T00:09:58.311Z" }, + { url = "https://files.pythonhosted.org/packages/c8/7d/2697b930179e7277529eaaec1513f8de622818696857f689e4a5432e5e27/mypy-1.18.2-cp311-cp311-win_amd64.whl", hash = "sha256:664dc726e67fa54e14536f6e1224bcfce1d9e5ac02426d2326e2bb4e081d1ce8", size = 9757983, upload-time = "2025-09-19T00:10:09.071Z" }, + { url = "https://files.pythonhosted.org/packages/07/06/dfdd2bc60c66611dd8335f463818514733bc763e4760dee289dcc33df709/mypy-1.18.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:33eca32dd124b29400c31d7cf784e795b050ace0e1f91b8dc035672725617e34", size = 12908273, upload-time = "2025-09-19T00:10:58.321Z" }, + { url = "https://files.pythonhosted.org/packages/81/14/6a9de6d13a122d5608e1a04130724caf9170333ac5a924e10f670687d3eb/mypy-1.18.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a3c47adf30d65e89b2dcd2fa32f3aeb5e94ca970d2c15fcb25e297871c8e4764", size = 11920910, upload-time = "2025-09-19T00:10:20.043Z" }, + { url = "https://files.pythonhosted.org/packages/5f/a9/b29de53e42f18e8cc547e38daa9dfa132ffdc64f7250e353f5c8cdd44bee/mypy-1.18.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d6c838e831a062f5f29d11c9057c6009f60cb294fea33a98422688181fe2893", size = 12465585, upload-time = "2025-09-19T00:10:33.005Z" }, + { url = "https://files.pythonhosted.org/packages/77/ae/6c3d2c7c61ff21f2bee938c917616c92ebf852f015fb55917fd6e2811db2/mypy-1.18.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01199871b6110a2ce984bde85acd481232d17413868c9807e95c1b0739a58914", size = 13348562, upload-time = "2025-09-19T00:10:11.51Z" }, + { url = "https://files.pythonhosted.org/packages/4d/31/aec68ab3b4aebdf8f36d191b0685d99faa899ab990753ca0fee60fb99511/mypy-1.18.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a2afc0fa0b0e91b4599ddfe0f91e2c26c2b5a5ab263737e998d6817874c5f7c8", size = 13533296, upload-time = "2025-09-19T00:10:06.568Z" }, + { url = "https://files.pythonhosted.org/packages/9f/83/abcb3ad9478fca3ebeb6a5358bb0b22c95ea42b43b7789c7fb1297ca44f4/mypy-1.18.2-cp312-cp312-win_amd64.whl", hash = "sha256:d8068d0afe682c7c4897c0f7ce84ea77f6de953262b12d07038f4d296d547074", size = 9828828, upload-time = "2025-09-19T00:10:28.203Z" }, + { url = "https://files.pythonhosted.org/packages/5f/04/7f462e6fbba87a72bc8097b93f6842499c428a6ff0c81dd46948d175afe8/mypy-1.18.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:07b8b0f580ca6d289e69209ec9d3911b4a26e5abfde32228a288eb79df129fcc", size = 12898728, upload-time = "2025-09-19T00:10:01.33Z" }, + { url = "https://files.pythonhosted.org/packages/99/5b/61ed4efb64f1871b41fd0b82d29a64640f3516078f6c7905b68ab1ad8b13/mypy-1.18.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ed4482847168439651d3feee5833ccedbf6657e964572706a2adb1f7fa4dfe2e", size = 11910758, upload-time = "2025-09-19T00:10:42.607Z" }, + { url = "https://files.pythonhosted.org/packages/3c/46/d297d4b683cc89a6e4108c4250a6a6b717f5fa96e1a30a7944a6da44da35/mypy-1.18.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c3ad2afadd1e9fea5cf99a45a822346971ede8685cc581ed9cd4d42eaf940986", size = 12475342, upload-time = "2025-09-19T00:11:00.371Z" }, + { url = "https://files.pythonhosted.org/packages/83/45/4798f4d00df13eae3bfdf726c9244bcb495ab5bd588c0eed93a2f2dd67f3/mypy-1.18.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a431a6f1ef14cf8c144c6b14793a23ec4eae3db28277c358136e79d7d062f62d", size = 13338709, upload-time = "2025-09-19T00:11:03.358Z" }, + { url = "https://files.pythonhosted.org/packages/d7/09/479f7358d9625172521a87a9271ddd2441e1dab16a09708f056e97007207/mypy-1.18.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7ab28cc197f1dd77a67e1c6f35cd1f8e8b73ed2217e4fc005f9e6a504e46e7ba", size = 13529806, upload-time = "2025-09-19T00:10:26.073Z" }, + { url = "https://files.pythonhosted.org/packages/71/cf/ac0f2c7e9d0ea3c75cd99dff7aec1c9df4a1376537cb90e4c882267ee7e9/mypy-1.18.2-cp313-cp313-win_amd64.whl", hash = "sha256:0e2785a84b34a72ba55fb5daf079a1003a34c05b22238da94fcae2bbe46f3544", size = 9833262, upload-time = "2025-09-19T00:10:40.035Z" }, + { url = "https://files.pythonhosted.org/packages/5a/0c/7d5300883da16f0063ae53996358758b2a2df2a09c72a5061fa79a1f5006/mypy-1.18.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:62f0e1e988ad41c2a110edde6c398383a889d95b36b3e60bcf155f5164c4fdce", size = 12893775, upload-time = "2025-09-19T00:10:03.814Z" }, + { url = "https://files.pythonhosted.org/packages/50/df/2cffbf25737bdb236f60c973edf62e3e7b4ee1c25b6878629e88e2cde967/mypy-1.18.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:8795a039bab805ff0c1dfdb8cd3344642c2b99b8e439d057aba30850b8d3423d", size = 11936852, upload-time = "2025-09-19T00:10:51.631Z" }, + { url = "https://files.pythonhosted.org/packages/be/50/34059de13dd269227fb4a03be1faee6e2a4b04a2051c82ac0a0b5a773c9a/mypy-1.18.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6ca1e64b24a700ab5ce10133f7ccd956a04715463d30498e64ea8715236f9c9c", size = 12480242, upload-time = "2025-09-19T00:11:07.955Z" }, + { url = "https://files.pythonhosted.org/packages/5b/11/040983fad5132d85914c874a2836252bbc57832065548885b5bb5b0d4359/mypy-1.18.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d924eef3795cc89fecf6bedc6ed32b33ac13e8321344f6ddbf8ee89f706c05cb", size = 13326683, upload-time = "2025-09-19T00:09:55.572Z" }, + { url = "https://files.pythonhosted.org/packages/e9/ba/89b2901dd77414dd7a8c8729985832a5735053be15b744c18e4586e506ef/mypy-1.18.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:20c02215a080e3a2be3aa50506c67242df1c151eaba0dcbc1e4e557922a26075", size = 13514749, upload-time = "2025-09-19T00:10:44.827Z" }, + { url = "https://files.pythonhosted.org/packages/25/bc/cc98767cffd6b2928ba680f3e5bc969c4152bf7c2d83f92f5a504b92b0eb/mypy-1.18.2-cp314-cp314-win_amd64.whl", hash = "sha256:749b5f83198f1ca64345603118a6f01a4e99ad4bf9d103ddc5a3200cc4614adf", size = 9982959, upload-time = "2025-09-19T00:10:37.344Z" }, + { url = "https://files.pythonhosted.org/packages/87/e3/be76d87158ebafa0309946c4a73831974d4d6ab4f4ef40c3b53a385a66fd/mypy-1.18.2-py3-none-any.whl", hash = "sha256:22a1748707dd62b58d2ae53562ffc4d7f8bcc727e8ac7cbc69c053ddc874d47e", size = 2352367, upload-time = "2025-09-19T00:10:15.489Z" }, +] + +[[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 = "networkx" version = "3.4.2" @@ -2168,6 +2224,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/71/e7/40fb618334dcdf7c5a316c0e7343c5cd82d3d866edc100d98e29bc945ecd/partd-1.4.2-py3-none-any.whl", hash = "sha256:978e4ac767ec4ba5b86c6eaa52e5a2a3bc748a2ca839e8cc798f1cc6ce6efb0f", size = 18905, upload-time = "2024-05-06T19:51:39.271Z" }, ] +[[package]] +name = "pathspec" +version = "0.12.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043, upload-time = "2023-12-10T22:30:45Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191, upload-time = "2023-12-10T22:30:43.14Z" }, +] + [[package]] name = "pexpect" version = "4.9.0" From e6126e5338a3c542fa127475e9a83a5e72d5fc61 Mon Sep 17 00:00:00 2001 From: Sajal-Kulshreshtha Date: Fri, 3 Oct 2025 13:53:15 +0530 Subject: [PATCH 6/6] fixing circular dependency and mypy errors Signed-off-by: Sajal-Kulshreshtha --- .github/workflows/mypy.yaml | 3 ++- augur/application/config.py | 2 +- augur/application/db/helpers.py | 26 +++++++++++++++++++ augur/application/db/lib.py | 2 +- augur/application/db/models/augur_data.py | 2 +- augur/application/db/util.py | 25 ------------------ augur/application/logs.py | 2 +- .../data_analysis/discourse_analysis/tasks.py | 2 +- .../facade_worker/facade_worker/repofetch.py | 2 +- .../facade_worker/utilitymethods.py | 2 +- augur/tasks/github/contributors.py | 2 +- augur/tasks/github/detect_move/core.py | 2 +- .../pull_requests/commits_model/core.py | 2 +- .../github/pull_requests/files_model/core.py | 2 +- .../github/pull_requests/files_model/tasks.py | 2 +- augur/tasks/github/pull_requests/tasks.py | 2 +- augur/tasks/github/releases/core.py | 2 +- augur/tasks/util/collection_util.py | 2 +- augur/util/repo_load_controller.py | 2 +- .../test_repo_load_controller/helper.py | 2 +- 20 files changed, 45 insertions(+), 43 deletions(-) create mode 100644 augur/application/db/helpers.py diff --git a/.github/workflows/mypy.yaml b/.github/workflows/mypy.yaml index cd4417cf3c..b5fd7f7b04 100644 --- a/.github/workflows/mypy.yaml +++ b/.github/workflows/mypy.yaml @@ -21,7 +21,8 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install .[dev] + pip install .[dev] + pip install mypy - name: Run mypy run: | diff --git a/augur/application/config.py b/augur/application/config.py index 7ace2befd3..f7139fb927 100644 --- a/augur/application/config.py +++ b/augur/application/config.py @@ -4,7 +4,7 @@ from typing import List, Any, Optional import os from augur.application.db.models import Config -from augur.application.db.util import execute_session_query, convert_type_of_value +from augur.application.db.helpers import execute_session_query, convert_type_of_value def get_development_flag_from_config(): diff --git a/augur/application/db/helpers.py b/augur/application/db/helpers.py new file mode 100644 index 0000000000..ddd1a210de --- /dev/null +++ b/augur/application/db/helpers.py @@ -0,0 +1,26 @@ +from typing import Any, Callable, Optional +from augur.application.db.util import catch_operational_error + +def execute_session_query(query: Any, query_type: str = "all") -> Any: + """ + Executes an SQLAlchemy ORM query with retries on OperationalError. + + Args: + query: SQLAlchemy ORM query object. + query_type: One of 'all', 'one', 'first'. + + Returns: + Query result according to query_type. + """ + func: Optional[Callable[[], Any]] = None + + if query_type == "all": + func = query.all + elif query_type == "one": + func = query.one + elif query_type == "first": + func = query.first + else: + raise Exception(f"ERROR: Unsupported query type '{query_type}'") + + return catch_operational_error(func) diff --git a/augur/application/db/lib.py b/augur/application/db/lib.py index cfb48fda86..425e4e52eb 100644 --- a/augur/application/db/lib.py +++ b/augur/application/db/lib.py @@ -13,7 +13,7 @@ from augur.application.db.models import Config, Repo, Commit, WorkerOauth, Issue, PullRequest, PullRequestReview, ContributorsAlias,UnresolvedCommitEmail, Contributor, CollectionStatus, UserGroup, RepoGroup from augur.tasks.util.collection_state import CollectionState from augur.application.db import get_session, get_engine -from augur.application.db.util import execute_session_query, convert_type_of_value +from augur.application.db.helpers import execute_session_query, convert_type_of_value from augur.application.db.session import remove_duplicates_by_uniques, remove_null_characters_from_list_of_dicts logger = logging.getLogger("db_lib") diff --git a/augur/application/db/models/augur_data.py b/augur/application/db/models/augur_data.py index 9212bcc5e9..2f712fca4b 100644 --- a/augur/application/db/models/augur_data.py +++ b/augur/application/db/models/augur_data.py @@ -30,7 +30,7 @@ from augur.application.db.models.base import Base -from augur.application.db.util import execute_session_query +from augur.application.db.helpers import execute_session_query from augur.application.db import get_session DEFAULT_REPO_GROUP_ID = 1 diff --git a/augur/application/db/util.py b/augur/application/db/util.py index 4accae7544..d892b7ad54 100644 --- a/augur/application/db/util.py +++ b/augur/application/db/util.py @@ -29,31 +29,6 @@ def catch_operational_error(func: Callable[[], Any]) -> Any: raise Exception(error) - -def execute_session_query(query: Any, query_type: str = "all") -> Any: - """ - Executes an SQLAlchemy ORM query with retries on OperationalError. - - Args: - query: SQLAlchemy ORM query object. - query_type: One of 'all', 'one', 'first'. - - Returns: - Query result according to query_type. - """ - func: Optional[Callable[[], Any]] = None - - if query_type == "all": - func = query.all - elif query_type == "one": - func = query.one - elif query_type == "first": - func = query.first - else: - raise Exception(f"ERROR: Unsupported query type '{query_type}'") - - return catch_operational_error(func) - def convert_orm_list_to_dict_list(result: List["Base"]) -> List[Dict[str, Any]]: """ Converts a list of ORM model instances to a list of dictionaries. diff --git a/augur/application/logs.py b/augur/application/logs.py index 1fb8709b82..2a176190bb 100644 --- a/augur/application/logs.py +++ b/augur/application/logs.py @@ -12,7 +12,7 @@ from augur.application.db.models import Config from augur.application.config import convert_type_of_value -from augur.application.db.util import execute_session_query +from augur.application.db.helpers import execute_session_query ROOT_AUGUR_DIRECTORY = os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))) diff --git a/augur/tasks/data_analysis/discourse_analysis/tasks.py b/augur/tasks/data_analysis/discourse_analysis/tasks.py index e78e030e66..a28d52e74d 100644 --- a/augur/tasks/data_analysis/discourse_analysis/tasks.py +++ b/augur/tasks/data_analysis/discourse_analysis/tasks.py @@ -10,7 +10,7 @@ from augur.tasks.init.celery_app import celery_app as celery from augur.application.db.lib import get_session, get_repo_by_repo_git from augur.application.db.models import Repo, DiscourseInsight -from augur.application.db.util import execute_session_query +from augur.application.db.helpers import execute_session_query from augur.tasks.init.celery_app import AugurMlRepoCollectionTask #import os, sys, time, requests, json diff --git a/augur/tasks/git/util/facade_worker/facade_worker/repofetch.py b/augur/tasks/git/util/facade_worker/facade_worker/repofetch.py index 874f338902..16b1e3676f 100644 --- a/augur/tasks/git/util/facade_worker/facade_worker/repofetch.py +++ b/augur/tasks/git/util/facade_worker/facade_worker/repofetch.py @@ -34,7 +34,7 @@ from sqlalchemy.orm.exc import NoResultFound from augur.application.db.models.augur_data import * from augur.application.db.models.augur_operations import CollectionStatus -from augur.application.db.util import execute_session_query, convert_orm_list_to_dict_list +from augur.application.db.helpers import execute_session_query from augur.application.db.lib import execute_sql, get_repo_by_repo_git class GitCloneError(Exception): diff --git a/augur/tasks/git/util/facade_worker/facade_worker/utilitymethods.py b/augur/tasks/git/util/facade_worker/facade_worker/utilitymethods.py index caae6c02ba..8aafe6ee0e 100644 --- a/augur/tasks/git/util/facade_worker/facade_worker/utilitymethods.py +++ b/augur/tasks/git/util/facade_worker/facade_worker/utilitymethods.py @@ -33,7 +33,7 @@ from .config import FacadeHelper as FacadeHelper from augur.tasks.util.worker_util import calculate_date_weight_from_timestamps from augur.application.db.lib import execute_sql, fetchall_data_from_sql_text, remove_working_commits_by_repo_id_and_hashes, remove_commits_by_repo_id_and_hashes, get_repo_by_repo_git, get_session -from augur.application.db.util import execute_session_query +from augur.application.db.helpers import execute_session_query #from augur.tasks.git.util.facade_worker.facade def update_repo_log(logger, facade_helper, repos_id,status): diff --git a/augur/tasks/github/contributors.py b/augur/tasks/github/contributors.py index 20f796647e..010e7809ba 100644 --- a/augur/tasks/github/contributors.py +++ b/augur/tasks/github/contributors.py @@ -7,7 +7,7 @@ from augur.tasks.github.util.github_paginator import hit_api from augur.tasks.github.facade_github.tasks import * from augur.application.db.models import Contributor -from augur.application.db.util import execute_session_query +from augur.application.db.helpers import execute_session_query from augur.application.db.lib import bulk_insert_dicts, get_session, batch_insert_contributors from augur.tasks.github.util.github_random_key_auth import GithubRandomKeyAuth diff --git a/augur/tasks/github/detect_move/core.py b/augur/tasks/github/detect_move/core.py index b302a70a06..97428a1756 100644 --- a/augur/tasks/github/detect_move/core.py +++ b/augur/tasks/github/detect_move/core.py @@ -5,7 +5,7 @@ from augur.tasks.github.util.util import parse_json_response from datetime import datetime from augur.tasks.util.collection_state import CollectionState -from augur.application.db.util import execute_session_query +from augur.application.db.helpers import execute_session_query from augur.application.db.lib import bulk_insert_dicts diff --git a/augur/tasks/github/pull_requests/commits_model/core.py b/augur/tasks/github/pull_requests/commits_model/core.py index 2df6d66f5d..94de06837c 100644 --- a/augur/tasks/github/pull_requests/commits_model/core.py +++ b/augur/tasks/github/pull_requests/commits_model/core.py @@ -2,7 +2,7 @@ from augur.tasks.github.util.github_data_access import GithubDataAccess, UrlNotFoundException ## URLNotFoundException added to deal with percolation of 404 errors when the commits are not anywhere for a PR already captured. from augur.application.db.models import * from augur.tasks.github.util.util import get_owner_repo -from augur.application.db.util import execute_session_query +from augur.application.db.helpers import execute_session_query from augur.application.db.lib import get_secondary_data_last_collected, get_updated_prs diff --git a/augur/tasks/github/pull_requests/files_model/core.py b/augur/tasks/github/pull_requests/files_model/core.py index cbecb44d6d..6195fac672 100644 --- a/augur/tasks/github/pull_requests/files_model/core.py +++ b/augur/tasks/github/pull_requests/files_model/core.py @@ -2,7 +2,7 @@ from augur.tasks.github.util.github_graphql_data_access import GithubGraphQlDataAccess, NotFoundException, InvalidDataException from augur.application.db.models import * from augur.tasks.github.util.util import get_owner_repo -from augur.application.db.util import execute_session_query +from augur.application.db.helpers import execute_session_query from augur.application.db.lib import get_secondary_data_last_collected, get_updated_prs diff --git a/augur/tasks/github/pull_requests/files_model/tasks.py b/augur/tasks/github/pull_requests/files_model/tasks.py index be75c88a9d..0ed62fe225 100644 --- a/augur/tasks/github/pull_requests/files_model/tasks.py +++ b/augur/tasks/github/pull_requests/files_model/tasks.py @@ -3,7 +3,7 @@ from augur.tasks.github.util.github_task_session import GithubTaskManifest from augur.tasks.init.celery_app import celery_app as celery from augur.tasks.init.celery_app import AugurSecondaryRepoCollectionTask -from augur.application.db.util import execute_session_query +from augur.application.db.helpers import execute_session_query @celery.task(base=AugurSecondaryRepoCollectionTask) def process_pull_request_files(repo_git: str, full_collection: bool) -> None: diff --git a/augur/tasks/github/pull_requests/tasks.py b/augur/tasks/github/pull_requests/tasks.py index 812a4eef25..e79a152666 100644 --- a/augur/tasks/github/pull_requests/tasks.py +++ b/augur/tasks/github/pull_requests/tasks.py @@ -12,7 +12,7 @@ from augur.tasks.github.util.github_task_session import GithubTaskManifest from augur.tasks.github.util.github_random_key_auth import GithubRandomKeyAuth from augur.application.db.lib import get_session, get_repo_by_repo_git, bulk_insert_dicts, get_pull_request_reviews_by_repo_id, batch_insert_contributors -from augur.application.db.util import execute_session_query +from augur.application.db.helpers import execute_session_query from ..messages import process_github_comment_contributors from augur.application.db.lib import get_secondary_data_last_collected, get_updated_prs, get_core_data_last_collected diff --git a/augur/tasks/github/releases/core.py b/augur/tasks/github/releases/core.py index 239b83dce9..07d661799f 100644 --- a/augur/tasks/github/releases/core.py +++ b/augur/tasks/github/releases/core.py @@ -3,7 +3,7 @@ from augur.application.db.models import * from augur.tasks.github.util.util import get_owner_repo from augur.tasks.github.util.gh_graphql_entities import request_graphql_dict -from augur.application.db.util import execute_session_query +from augur.application.db.helpers import execute_session_query from augur.application.db.lib import bulk_insert_dicts diff --git a/augur/tasks/util/collection_util.py b/augur/tasks/util/collection_util.py index 44effbbf78..6c7ea57af9 100644 --- a/augur/tasks/util/collection_util.py +++ b/augur/tasks/util/collection_util.py @@ -9,7 +9,7 @@ from augur.application.logs import AugurLogger from augur.tasks.init.celery_app import celery_app as celery from augur.application.db.models import CollectionStatus, Repo -from augur.application.db.util import execute_session_query +from augur.application.db.helpers import execute_session_query from augur.application.db.lib import get_section from augur.tasks.github.util.util import get_repo_weight_core, get_repo_weight_by_issue from augur.application.db import get_engine diff --git a/augur/util/repo_load_controller.py b/augur/util/repo_load_controller.py index af46ce3260..cbb0e87248 100644 --- a/augur/util/repo_load_controller.py +++ b/augur/util/repo_load_controller.py @@ -7,7 +7,7 @@ from augur.application.db.engine import DatabaseEngine from augur.application.db.models import Repo, UserRepo, RepoGroup, UserGroup, User, CollectionStatus from augur.application.db.models.augur_operations import retrieve_owner_repos -from augur.application.db.util import execute_session_query +from augur.application.db.helpers import execute_session_query from sqlalchemy import Column, Table, MetaData, or_ from sqlalchemy.sql.operators import ilike_op diff --git a/tests/test_applicaton/test_repo_load_controller/helper.py b/tests/test_applicaton/test_repo_load_controller/helper.py index 29aa0dc9c7..2effc3a79f 100644 --- a/tests/test_applicaton/test_repo_load_controller/helper.py +++ b/tests/test_applicaton/test_repo_load_controller/helper.py @@ -6,7 +6,7 @@ from augur.application.db.session import DatabaseSession from augur.application.db.models import Config, User from augur.tasks.github.util.github_paginator import hit_api -from augur.application.db.util import execute_session_query +from augur.application.db.helpers import execute_session_query logger = logging.getLogger(__name__)