From c835f2da067b33ae093962a9cc3965b6dc6debce Mon Sep 17 00:00:00 2001 From: Ludy87 Date: Wed, 19 Aug 2026 00:26:55 +0200 Subject: [PATCH] Update Ruff and lint cleanup Bump Python tooling to Ruff 0.16.2 and datamodel-code-generator 0.72.3, add the py313 target in pre-commit, and refresh the engine lockfile. This also narrows broad exception handling and applies small Python cleanups across the engine and helper scripts to satisfy newer lint rules without changing runtime behavior. --- .taskfiles/pre-commit.yml | 6 ++- .../resources/static/python/png_to_webp.py | 2 +- engine/pyproject.toml | 6 +-- engine/src/stirling/api/routes/config.py | 2 +- engine/src/stirling/documents/README.md | 1 + engine/src/stirling/documents/service.py | 2 +- engine/uv.lock | 50 +++++++++---------- scripts/convert_cff_to_ttf.py | 16 +++--- scripts/counter_translation_v3.py | 22 ++++---- scripts/coverage-matrix.py | 6 +-- scripts/coverage-summary.py | 2 +- scripts/download_pdf_samples.py | 2 +- scripts/harvest_type3_fonts.py | 12 ++--- scripts/index_type3_catalogue.py | 4 +- scripts/playwright-coverage-summary.py | 6 +-- scripts/pre-commit/install_gitleaks.py | 2 +- scripts/translations/ai_translation_helper.py | 15 +++--- scripts/translations/auto_translate.py | 8 +-- scripts/translations/batch_translator.py | 8 +-- scripts/translations/bulk_auto_translate.py | 7 +-- scripts/translations/compact_translator.py | 4 +- scripts/translations/toml_beautifier.py | 8 +-- scripts/translations/toml_validator.py | 6 +-- scripts/translations/translation_analyzer.py | 9 ++-- scripts/translations/translation_merger.py | 12 ++--- .../translations/validate_json_structure.py | 9 ++-- scripts/translations/validate_placeholders.py | 11 ++-- scripts/type3_to_cff.py | 6 +-- scripts/update_type3_library.py | 2 +- 29 files changed, 119 insertions(+), 127 deletions(-) diff --git a/.taskfiles/pre-commit.yml b/.taskfiles/pre-commit.yml index 444115010f..5d0bf5faff 100644 --- a/.taskfiles/pre-commit.yml +++ b/.taskfiles/pre-commit.yml @@ -65,6 +65,8 @@ tasks: cmds: # Auto-fixers first, then the report-only tools (codespell, gitleaks) so a # finding there does not stop the fixers from running. + - task: ruff-format + vars: { FIX: '1' } - task: ruff vars: { FIX: '1' } - task: ruff-format @@ -101,12 +103,12 @@ tasks: ruff: deps: [install] cmds: - - uv run --project engine --locked --group pre-commit ruff check --isolated --line-length=120 {{if .FIX}}--fix {{end}}$(git ls-files {{.PY_FILES}}) + - uv run --project engine --locked --group pre-commit ruff check --isolated --target-version=py313 --line-length=120 {{if .FIX}}--fix {{end}}$(git ls-files {{.PY_FILES}}) ruff-format: deps: [install] cmds: - - uv run --project engine --locked --group pre-commit ruff format --isolated --line-length=120 {{if .FIX}}{{else}}--check {{end}}$(git ls-files {{.PY_FILES}}) + - uv run --project engine --locked --group pre-commit ruff format --isolated --target-version=py313 --line-length=120 {{if .FIX}}{{else}}--check {{end}}$(git ls-files {{.PY_FILES}}) codespell: deps: [install] diff --git a/app/core/src/main/resources/static/python/png_to_webp.py b/app/core/src/main/resources/static/python/png_to_webp.py index 094b1b5033..dcb18185f7 100644 --- a/app/core/src/main/resources/static/python/png_to_webp.py +++ b/app/core/src/main/resources/static/python/png_to_webp.py @@ -61,7 +61,7 @@ def resize_image(input_image_path, output_image_path, max_size=(16383, 16383)): # If dimensions are within the allowed limits, save the image directly image.save(output_image_path, format="WEBP", quality=100) print(f"The image was successfully saved as WebP: {output_image_path}") - except Exception as e: + except (OSError, ValueError) as e: print(f"An error occurred: {e}") diff --git a/engine/pyproject.toml b/engine/pyproject.toml index 87e7cc99c0..95d384110c 100644 --- a/engine/pyproject.toml +++ b/engine/pyproject.toml @@ -26,11 +26,11 @@ engine = [ # Type checking, testing, model generation, and formatting tools for the engine. engine-dev = [ "anyio>=4.14.2", - "datamodel-code-generator[ruff]==0.64.0", + "datamodel-code-generator[ruff]==0.72.3", "pyright>=1.1.411", "pytest>=9.1.1", "referencing>=0.37.0", - "ruff==0.15.5", + "ruff==0.16.2", ] # Dependencies for the Cucumber/Python integration test suite. cucumber = [ @@ -65,7 +65,7 @@ updater-signatures = [ # Pinned repository-wide pre-commit tooling. pre-commit = [ "codespell==2.4.3", - "ruff==0.15.5", + "ruff==0.16.2", "tomli-w==1.2.0", ] diff --git a/engine/src/stirling/api/routes/config.py b/engine/src/stirling/api/routes/config.py index cc06a8d87e..d1bdf222df 100644 --- a/engine/src/stirling/api/routes/config.py +++ b/engine/src/stirling/api/routes/config.py @@ -218,7 +218,7 @@ async def apply_config(request: ConfigPushRequest, http_request: Request) -> Con save_config(request) # Claim the stamp we just wrote so this worker's watcher does not rebuild for it. app.state.config_cache_stamp = cache_stamp() - except Exception: # noqa: BLE001 - best-effort persist, never fail the applied push + except Exception: # best-effort persist, never fail the applied push logger.warning("Applied AI config but failed to persist the encrypted cache", exc_info=True) notes.append( "Config applied on this worker but could not be persisted; it will not survive an" diff --git a/engine/src/stirling/documents/README.md b/engine/src/stirling/documents/README.md index 6848d8a101..e32d6e80b0 100644 --- a/engine/src/stirling/documents/README.md +++ b/engine/src/stirling/documents/README.md @@ -17,6 +17,7 @@ from pydantic_ai import Agent from stirling.services import AppRuntime + class MyAgent: def __init__(self, runtime: AppRuntime) -> None: rag = runtime.rag_capability diff --git a/engine/src/stirling/documents/service.py b/engine/src/stirling/documents/service.py index 0415e9d140..b3f4722791 100644 --- a/engine/src/stirling/documents/service.py +++ b/engine/src/stirling/documents/service.py @@ -139,7 +139,7 @@ class DocumentService: try: results = await self._store.search(col_name, query_embedding, k, principals) all_results.extend(results) - except Exception: # noqa: BLE001 - any backend error on one collection should not stop the others + except Exception: # any backend error on one collection should not stop the others logger.warning( "Skipping collection %s during cross-collection search", col_name, diff --git a/engine/uv.lock b/engine/uv.lock index fbfa665bc6..a788a239db 100644 --- a/engine/uv.lock +++ b/engine/uv.lock @@ -534,7 +534,7 @@ wheels = [ [[package]] name = "datamodel-code-generator" -version = "0.64.0" +version = "0.72.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "argcomplete" }, @@ -546,9 +546,9 @@ dependencies = [ { name = "pydantic" }, { name = "pyyaml" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9c/d2/86c94a2836ed42231653a7ddaefa0a5bc23418167a876bba7376c96b3a35/datamodel_code_generator-0.64.0.tar.gz", hash = "sha256:9c592900a00b20e416494273c22435f5a9aef6ea8c7b9190747522a60497a1cb", size = 1316440, upload-time = "2026-06-14T17:24:50.528Z" } +sdist = { url = "https://files.pythonhosted.org/packages/14/4b/4652f0bb085a564982c3e515a0b02bcee21765ddac967bcf152a70d2af14/datamodel_code_generator-0.72.3.tar.gz", hash = "sha256:a20160de09b76d4a293ccba5a9ee5c341b5365890237ac1ff812f420e4c09f3b", size = 1965678, upload-time = "2026-08-10T18:58:41.636Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/23/94/71338e2f0146ac10747a5537b3a1e45256e66b7c229869eb0ee787111b41/datamodel_code_generator-0.64.0-py3-none-any.whl", hash = "sha256:b7cd8bd41a312aa997aec6150670bad781847c5b674f17e4d70e78208a0fb990", size = 374698, upload-time = "2026-06-14T17:24:48.809Z" }, + { url = "https://files.pythonhosted.org/packages/84/fd/9d8a0594aedcc6ee8133b21dd3543d6021842e013058803a69918720d0aa/datamodel_code_generator-0.72.3-py3-none-any.whl", hash = "sha256:4536f6dd12dd86c9c7a78b16ef83ae9aa7a9cbdb8bef8a3b63baa4ad9d3d3829", size = 554226, upload-time = "2026-08-10T18:58:40.087Z" }, ] [package.optional-dependencies] @@ -711,15 +711,15 @@ engine = [ ] engine-dev = [ { name = "anyio", specifier = ">=4.14.2" }, - { name = "datamodel-code-generator", extras = ["ruff"], specifier = "==0.64.0" }, + { name = "datamodel-code-generator", extras = ["ruff"], specifier = "==0.72.3" }, { name = "pyright", specifier = ">=1.1.411" }, { name = "pytest", specifier = ">=9.1.1" }, { name = "referencing", specifier = ">=0.37.0" }, - { name = "ruff", specifier = "==0.15.5" }, + { name = "ruff", specifier = "==0.16.2" }, ] pre-commit = [ { name = "codespell", specifier = "==2.4.3" }, - { name = "ruff", specifier = "==0.15.5" }, + { name = "ruff", specifier = "==0.16.2" }, { name = "tomli-w", specifier = "==1.2.0" }, ] tools = [ @@ -2791,27 +2791,27 @@ wheels = [ [[package]] name = "ruff" -version = "0.15.5" +version = "0.16.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/77/9b/840e0039e65fcf12758adf684d2289024d6140cde9268cc59887dc55189c/ruff-0.15.5.tar.gz", hash = "sha256:7c3601d3b6d76dce18c5c824fc8d06f4eef33d6df0c21ec7799510cde0f159a2", size = 4574214, upload-time = "2026-03-05T20:06:34.946Z" } +sdist = { url = "https://files.pythonhosted.org/packages/73/e1/4508a569211b35599016e84ba65c1a992b7a4004b4b6c4bea02a851cba1b/ruff-0.16.2.tar.gz", hash = "sha256:c3d7828d12e8927a6fc65fe38e2c2541b9e762d360a1786d752cb1b8883b3c9c", size = 4885811, upload-time = "2026-08-07T13:31:01.432Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/47/20/5369c3ce21588c708bcbe517a8fbe1a8dfdb5dfd5137e14790b1da71612c/ruff-0.15.5-py3-none-linux_armv6l.whl", hash = "sha256:4ae44c42281f42e3b06b988e442d344a5b9b72450ff3c892e30d11b29a96a57c", size = 10478185, upload-time = "2026-03-05T20:06:29.093Z" }, - { url = "https://files.pythonhosted.org/packages/44/ed/e81dd668547da281e5dce710cf0bc60193f8d3d43833e8241d006720e42b/ruff-0.15.5-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:6edd3792d408ebcf61adabc01822da687579a1a023f297618ac27a5b51ef0080", size = 10859201, upload-time = "2026-03-05T20:06:32.632Z" }, - { url = "https://files.pythonhosted.org/packages/c4/8f/533075f00aaf19b07c5cd6aa6e5d89424b06b3b3f4583bfa9c640a079059/ruff-0.15.5-py3-none-macosx_11_0_arm64.whl", hash = "sha256:89f463f7c8205a9f8dea9d658d59eff49db05f88f89cc3047fb1a02d9f344010", size = 10184752, upload-time = "2026-03-05T20:06:40.312Z" }, - { url = "https://files.pythonhosted.org/packages/66/0e/ba49e2c3fa0395b3152bad634c7432f7edfc509c133b8f4529053ff024fb/ruff-0.15.5-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba786a8295c6574c1116704cf0b9e6563de3432ac888d8f83685654fe528fd65", size = 10534857, upload-time = "2026-03-05T20:06:19.581Z" }, - { url = "https://files.pythonhosted.org/packages/59/71/39234440f27a226475a0659561adb0d784b4d247dfe7f43ffc12dd02e288/ruff-0.15.5-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fd4b801e57955fe9f02b31d20375ab3a5c4415f2e5105b79fb94cf2642c91440", size = 10309120, upload-time = "2026-03-05T20:06:00.435Z" }, - { url = "https://files.pythonhosted.org/packages/f5/87/4140aa86a93df032156982b726f4952aaec4a883bb98cb6ef73c347da253/ruff-0.15.5-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:391f7c73388f3d8c11b794dbbc2959a5b5afe66642c142a6effa90b45f6f5204", size = 11047428, upload-time = "2026-03-05T20:05:51.867Z" }, - { url = "https://files.pythonhosted.org/packages/5a/f7/4953e7e3287676f78fbe85e3a0ca414c5ca81237b7575bdadc00229ac240/ruff-0.15.5-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8dc18f30302e379fe1e998548b0f5e9f4dff907f52f73ad6da419ea9c19d66c8", size = 11914251, upload-time = "2026-03-05T20:06:22.887Z" }, - { url = "https://files.pythonhosted.org/packages/77/46/0f7c865c10cf896ccf5a939c3e84e1cfaeed608ff5249584799a74d33835/ruff-0.15.5-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1cc6e7f90087e2d27f98dc34ed1b3ab7c8f0d273cc5431415454e22c0bd2a681", size = 11333801, upload-time = "2026-03-05T20:05:57.168Z" }, - { url = "https://files.pythonhosted.org/packages/d3/01/a10fe54b653061585e655f5286c2662ebddb68831ed3eaebfb0eb08c0a16/ruff-0.15.5-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c1cb7169f53c1ddb06e71a9aebd7e98fc0fea936b39afb36d8e86d36ecc2636a", size = 11206821, upload-time = "2026-03-05T20:06:03.441Z" }, - { url = "https://files.pythonhosted.org/packages/7a/0d/2132ceaf20c5e8699aa83da2706ecb5c5dcdf78b453f77edca7fb70f8a93/ruff-0.15.5-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:9b037924500a31ee17389b5c8c4d88874cc6ea8e42f12e9c61a3d754ff72f1ca", size = 11133326, upload-time = "2026-03-05T20:06:25.655Z" }, - { url = "https://files.pythonhosted.org/packages/72/cb/2e5259a7eb2a0f87c08c0fe5bf5825a1e4b90883a52685524596bfc93072/ruff-0.15.5-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:65bb414e5b4eadd95a8c1e4804f6772bbe8995889f203a01f77ddf2d790929dd", size = 10510820, upload-time = "2026-03-05T20:06:37.79Z" }, - { url = "https://files.pythonhosted.org/packages/ff/20/b67ce78f9e6c59ffbdb5b4503d0090e749b5f2d31b599b554698a80d861c/ruff-0.15.5-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:d20aa469ae3b57033519c559e9bc9cd9e782842e39be05b50e852c7c981fa01d", size = 10302395, upload-time = "2026-03-05T20:05:54.504Z" }, - { url = "https://files.pythonhosted.org/packages/5f/e5/719f1acccd31b720d477751558ed74e9c88134adcc377e5e886af89d3072/ruff-0.15.5-py3-none-musllinux_1_2_i686.whl", hash = "sha256:15388dd28c9161cdb8eda68993533acc870aa4e646a0a277aa166de9ad5a8752", size = 10754069, upload-time = "2026-03-05T20:06:06.422Z" }, - { url = "https://files.pythonhosted.org/packages/c3/9c/d1db14469e32d98f3ca27079dbd30b7b44dbb5317d06ab36718dee3baf03/ruff-0.15.5-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:b30da330cbd03bed0c21420b6b953158f60c74c54c5f4c1dabbdf3a57bf355d2", size = 11304315, upload-time = "2026-03-05T20:06:10.867Z" }, - { url = "https://files.pythonhosted.org/packages/28/3a/950367aee7c69027f4f422059227b290ed780366b6aecee5de5039d50fa8/ruff-0.15.5-py3-none-win32.whl", hash = "sha256:732e5ee1f98ba5b3679029989a06ca39a950cced52143a0ea82a2102cb592b74", size = 10551676, upload-time = "2026-03-05T20:06:13.705Z" }, - { url = "https://files.pythonhosted.org/packages/b8/00/bf077a505b4e649bdd3c47ff8ec967735ce2544c8e4a43aba42ee9bf935d/ruff-0.15.5-py3-none-win_amd64.whl", hash = "sha256:821d41c5fa9e19117616c35eaa3f4b75046ec76c65e7ae20a333e9a8696bc7fe", size = 11678972, upload-time = "2026-03-05T20:06:45.379Z" }, - { url = "https://files.pythonhosted.org/packages/fe/4e/cd76eca6db6115604b7626668e891c9dd03330384082e33662fb0f113614/ruff-0.15.5-py3-none-win_arm64.whl", hash = "sha256:b498d1c60d2fe5c10c45ec3f698901065772730b411f164ae270bb6bfcc4740b", size = 10965572, upload-time = "2026-03-05T20:06:16.984Z" }, + { url = "https://files.pythonhosted.org/packages/14/57/db19951540f98859c956b50bdb4d31089b4d91e9f15e2968e7d5193806d5/ruff-0.16.2-py3-none-linux_armv6l.whl", hash = "sha256:3c8de4cf2181f01d57946d87d777aa52916976fc09942aed89938fab5e013318", size = 10847925, upload-time = "2026-08-07T13:30:14.468Z" }, + { url = "https://files.pythonhosted.org/packages/13/5a/995fe85a8470d3e391ac0f7fa8054bb454eaf33ee138196d6172ed1079c0/ruff-0.16.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:9a48cc05c6fbc811ca81b5d7ba95375affea6582d1b8024e455e41afbbf55344", size = 11072662, upload-time = "2026-08-07T13:30:18.143Z" }, + { url = "https://files.pythonhosted.org/packages/32/53/370d767c61c71a971a4ace36703a7ecd8c393956349a7325d7fab2b56827/ruff-0.16.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:a2c0d14fcbb26c91f0f867a6dc9bd71bbc30b1b6151829c884f23faeab2e5700", size = 10566771, upload-time = "2026-08-07T13:30:20.899Z" }, + { url = "https://files.pythonhosted.org/packages/85/d6/9d96948caf5a632be62d62202d5ec914d6856f204fd79eb036e5915e79ea/ruff-0.16.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:335c621622c4650330be50842561c6586ac6971bb8ab5407fe34dcc9efb16bbe", size = 10975825, upload-time = "2026-08-07T13:30:23.517Z" }, + { url = "https://files.pythonhosted.org/packages/3b/92/ea87129b3414acb0b5770563779c51804d37ac67675c7ba35447ddb14773/ruff-0.16.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:20e66910f2c37cc753f9ef6580c914a621b80c4fa3549d3e3521e29d0f5bfc3f", size = 10649437, upload-time = "2026-08-07T13:30:26.097Z" }, + { url = "https://files.pythonhosted.org/packages/ac/43/f8f291dcd4af5bb7872b74fdfa41a7cd7c856ca1d4069670971cf1b9f5cb/ruff-0.16.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7e36fbfba65510548156902bcf1350a979a958ce0347ce0f90d73894036b39f", size = 11446761, upload-time = "2026-08-07T13:30:28.752Z" }, + { url = "https://files.pythonhosted.org/packages/71/4a/ef991fb2fcf516ab71f0808adcdd8da5e18c8cde447f4ceaf5f47a5132a5/ruff-0.16.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f0eab35f80df8f134aae5d1630e751901321d317cc8e50dc39e36fa3ed34cd12", size = 12336364, upload-time = "2026-08-07T13:30:31.468Z" }, + { url = "https://files.pythonhosted.org/packages/f3/24/f615e74f307e6ca0e56a482872477b856c70d530aa356abfb6dfe5ca8a80/ruff-0.16.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:40ea8c0594feb894e89c8c61ab9c103d38b0ea72dfde6c594107147ca31b1140", size = 11630720, upload-time = "2026-08-07T13:30:34.426Z" }, + { url = "https://files.pythonhosted.org/packages/c5/d3/8ef50149e8412a77f7ab409efdef0e2b23803707a3863da4fc64cb23d459/ruff-0.16.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab3d62dde0b19facdd632008cc4827fc28ada7736c6bd35ab6f1050f0bfed53f", size = 11466130, upload-time = "2026-08-07T13:30:36.958Z" }, + { url = "https://files.pythonhosted.org/packages/dd/a7/a19334985c4dea8c381981fa252cd854c7ee52dc4b1686dc16f4a911c702/ruff-0.16.2-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:e43e1f5b8388da9eca1b9e88328d47a5cec794633ccf6f7484ac2dd15eee92c0", size = 11523634, upload-time = "2026-08-07T13:30:39.822Z" }, + { url = "https://files.pythonhosted.org/packages/6e/6c/96d192b0e742412ceda08c0a50f9669b253dde9fd6a60ea1a10c9fa79a63/ruff-0.16.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:c24788a980581e1d7ea3a0cbe4344c4fbeb0a6a9b1f4713aa46bb104f8294690", size = 10949807, upload-time = "2026-08-07T13:30:42.745Z" }, + { url = "https://files.pythonhosted.org/packages/fa/51/e26599ceca11e79ee255c7df515995561edf87e9ca1893284e44d98f5a86/ruff-0.16.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:81806b08329130005dd4a8a8394a0c9da8c6f4cafb16ba438d2a2ee6a18bedf1", size = 10646891, upload-time = "2026-08-07T13:30:45.522Z" }, + { url = "https://files.pythonhosted.org/packages/68/01/800c4b1f97bc8d7c6029e06b1f20473a3cf1e13c4933d8f3342add83fc55/ruff-0.16.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:4ce4e02bad779bef557f541a1b31f20d6abeae1cc05ed1b1ac019d4ffd1044c8", size = 11162063, upload-time = "2026-08-07T13:30:48.131Z" }, + { url = "https://files.pythonhosted.org/packages/e4/d0/1477ea50fc5a0d4b0b71d1d63d50770bdd794d90b43e37a7618e63ec9894/ruff-0.16.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:e0422abdf70070255fc4073ce9dfc814cc03db577013761ddd09bc1e4a9a4fbd", size = 11556038, upload-time = "2026-08-07T13:30:50.686Z" }, + { url = "https://files.pythonhosted.org/packages/b8/76/a7776f32048d991e16d4fa8ff91790b877342d3596cc3ed04acdbf1aaedc/ruff-0.16.2-py3-none-win32.whl", hash = "sha256:bf3a63d78fb39f4bf5ac8ae52051c5520505301abe19ba4e204c453b3f09bb0b", size = 10872850, upload-time = "2026-08-07T13:30:53.471Z" }, + { url = "https://files.pythonhosted.org/packages/00/0d/929c800d920e61397d82a01b60bffc68da3052c17d31de59efaad2e4ed75/ruff-0.16.2-py3-none-win_amd64.whl", hash = "sha256:bcabe2f6d0fc7819f1431793005af4e4de7371927d037345bf941252b195b9fa", size = 12023338, upload-time = "2026-08-07T13:30:56.193Z" }, + { url = "https://files.pythonhosted.org/packages/5b/6c/93e26c22c5f78ff87363e07da49c84955affbeb1098bd1936bf3b3f293bf/ruff-0.16.2-py3-none-win_arm64.whl", hash = "sha256:d614e95cedf38a2053fd351c55b103ba30d017d61688fdbfd40ee0412852a99f", size = 11374065, upload-time = "2026-08-07T13:30:58.775Z" }, ] [[package]] diff --git a/scripts/convert_cff_to_ttf.py b/scripts/convert_cff_to_ttf.py index 0ae480da7a..6629ba6c9c 100644 --- a/scripts/convert_cff_to_ttf.py +++ b/scripts/convert_cff_to_ttf.py @@ -75,7 +75,7 @@ def parse_unicode_mapping(mapping_path): print(f"Parsed ToUnicode CMap: {len(gid_to_unicode)} mappings", file=sys.stderr) return gid_to_unicode - except Exception as e: + except (OSError, UnicodeError, ValueError, TypeError, KeyError) as e: print(f"Warning: Failed to parse Unicode mapping: {e}", file=sys.stderr) return {} @@ -122,7 +122,7 @@ def wrap_cff_as_otf(input_path, output_path, tounicode_path=None): else: # Fallback to CharStrings keys charstrings = cff_font.CharStrings - glyph_order = [".notdef"] + [name for name in charstrings.keys() if name != ".notdef"] + glyph_order = [".notdef"] + [name for name in charstrings if name != ".notdef"] otf.setGlyphOrder(glyph_order) @@ -186,10 +186,10 @@ def wrap_cff_as_otf(input_path, output_path, tounicode_path=None): min_lsb = min(min_lsb, lsb) min_rsb = min(min_rsb, rsb) max_extent = max(max_extent, extent) - except Exception: + except (AttributeError, TypeError, ValueError): pass # Some glyphs may not have outlines - except Exception: + except (AttributeError, KeyError, TypeError, ValueError): pass # Use defaults widths[glyph_name] = width @@ -308,14 +308,14 @@ def wrap_cff_as_otf(input_path, output_path, tounicode_path=None): unicode_val = int(glyph_name[3:], 16) if unicode_val not in unicode_to_glyph: unicode_to_glyph[unicode_val] = glyph_name - except Exception: + except ValueError: pass elif glyph_name.startswith("u") and len(glyph_name) >= 5: try: unicode_val = int(glyph_name[1:], 16) if unicode_val not in unicode_to_glyph: unicode_to_glyph[unicode_val] = glyph_name - except Exception: + except ValueError: pass # === Create cmap table === @@ -476,8 +476,8 @@ def wrap_cff_as_otf(input_path, output_path, tounicode_path=None): return True - except Exception as e: - print(f"ERROR: Conversion failed: {str(e)}", file=sys.stderr) + except (OSError, ValueError, TypeError, KeyError, RuntimeError) as e: + print(f"ERROR: Conversion failed: {e!s}", file=sys.stderr) import traceback traceback.print_exc(file=sys.stderr) diff --git a/scripts/counter_translation_v3.py b/scripts/counter_translation_v3.py index 17f62e2758..241ec2111d 100644 --- a/scripts/counter_translation_v3.py +++ b/scripts/counter_translation_v3.py @@ -116,12 +116,11 @@ def write_readme(progress_list: list[tuple[str, int]]) -> None: for i, line in enumerate(content[2:], start=2): for progress in progress_list: language, value = progress - if language in line: - if match := re.search(r"\!\[(\d+(\.\d+)?)%\]\(.*\)", line): - content[i] = line.replace( - match.group(0), - f"![{value}%](https://geps.dev/progress/{value})", - ) + if language in line and (match := re.search(r"\!\[(\d+(\.\d+)?)%\]\(.*\)", line)): + content[i] = line.replace( + match.group(0), + f"![{value}%](https://geps.dev/progress/{value})", + ) with open( os.path.join(os.getcwd(), "devGuide", "HowToAddNewLanguage.md"), @@ -261,12 +260,11 @@ def compare_files( # Missing translation (same as default and not ignored) fails += 1 missing_str_keys.append(default_key) - if default_value != file_value: - if default_key in sort_ignore_translation[language]["ignore"]: - if default_key == "language.direction": - continue - # Remove from ignore if actually translated - sort_ignore_translation[language]["ignore"].remove(default_key) + if default_value != file_value and default_key in sort_ignore_translation[language]["ignore"]: + if default_key == "language.direction": + continue + # Remove from ignore if actually translated + sort_ignore_translation[language]["ignore"].remove(default_key) if show_missing_keys: if len(missing_str_keys) > 0: diff --git a/scripts/coverage-matrix.py b/scripts/coverage-matrix.py index 1cd4e6ad33..d30499ee2c 100644 --- a/scripts/coverage-matrix.py +++ b/scripts/coverage-matrix.py @@ -116,11 +116,7 @@ def _classify_backend(package_name: str) -> str | None: return "saas" if p.startswith("stirling.software.proprietary"): return "proprietary" - if ( - p.startswith("stirling.software.SPDF") - or p.startswith("stirling.software.common") - or p.startswith("org.apache.pdfbox") - ): + if p.startswith(("stirling.software.SPDF", "stirling.software.common", "org.apache.pdfbox")): return "core" return None diff --git a/scripts/coverage-summary.py b/scripts/coverage-summary.py index 11ea7099c1..728bf5ae9f 100644 --- a/scripts/coverage-summary.py +++ b/scripts/coverage-summary.py @@ -80,7 +80,7 @@ def _parse_jacoco_xml(path: Path) -> dict[str, CounterTotals]: def _bar(pct: float, width: int = 20) -> str: """Render a fixed-width ASCII progress bar. Markdown-safe on all consoles.""" - filled = int(round(pct / 100.0 * width)) + filled = round(pct / 100.0 * width) return "[" + "#" * filled + "-" * (width - filled) + "]" diff --git a/scripts/download_pdf_samples.py b/scripts/download_pdf_samples.py index c2ab27a1f9..3825abefbf 100644 --- a/scripts/download_pdf_samples.py +++ b/scripts/download_pdf_samples.py @@ -150,7 +150,7 @@ def download_pdf( output_dir.mkdir(parents=True, exist_ok=True) dest.write_bytes(content) return url, dest, None - except Exception as exc: # pylint: disable=broad-except + except (OSError, ValueError, requests.RequestException) as exc: return url, None, str(exc) diff --git a/scripts/harvest_type3_fonts.py b/scripts/harvest_type3_fonts.py index 380d332d96..be3efd5ddd 100644 --- a/scripts/harvest_type3_fonts.py +++ b/scripts/harvest_type3_fonts.py @@ -118,7 +118,7 @@ def collect_known_signatures(signatures_dir: Path) -> dict[str, dict]: for json_file in signatures_dir.rglob("*.json"): try: payload = load_signature_file(json_file) - except Exception: + except (OSError, ValueError, TypeError, json.JSONDecodeError): continue pdf = payload.get("pdf") for font in payload.get("fonts", []): @@ -148,9 +148,9 @@ def run_signature_tool(gradle_cmd: str, pdf: Path, output_path: Path, pretty: bo cmd, shell=True, cwd=cwd, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, + capture_output=True, text=True, + check=False, ) if completed.returncode != 0: raise RuntimeError(f"Gradle Type3SignatureTool failed for {pdf}:\n{completed.stderr.strip()}") @@ -179,7 +179,7 @@ def extract_fonts_from_payload(payload: dict) -> list[dict]: def write_report(report_path: Path, fonts_by_signature: dict[str, dict]) -> None: ordered = sorted(fonts_by_signature.values(), key=lambda entry: entry["signature"]) report = { - "generatedAt": dt.datetime.utcnow().isoformat(timespec="seconds") + "Z", + "generatedAt": dt.datetime.now(dt.UTC).isoformat(timespec="seconds").replace("+00:00", "Z"), "totalSignatures": len(ordered), "fonts": ordered, } @@ -202,13 +202,13 @@ def main() -> None: if signature_path.exists() and not args.force: try: payload = load_signature_file(signature_path) - except Exception as exc: + except (OSError, ValueError, TypeError, json.JSONDecodeError) as exc: print(f"[WARN] Failed to parse cached signature {signature_path}: {exc}") payload = None else: try: run_signature_tool(args.gradle_cmd, pdf, signature_path, args.pretty, REPO_ROOT) - except Exception as exc: + except (OSError, RuntimeError, subprocess.SubprocessError) as exc: print(f"[ERROR] Harvest failed for {pdf}: {exc}", file=sys.stderr) continue payload = load_signature_file(signature_path) diff --git a/scripts/index_type3_catalogue.py b/scripts/index_type3_catalogue.py index 69e7c33e47..31ef27efa4 100644 --- a/scripts/index_type3_catalogue.py +++ b/scripts/index_type3_catalogue.py @@ -8,7 +8,7 @@ from pathlib import Path def run(cmd, cwd=None): - result = subprocess.run(cmd, cwd=cwd, capture_output=True, text=True) + result = subprocess.run(cmd, cwd=cwd, capture_output=True, text=True, check=False) if result.returncode != 0: raise RuntimeError(f"Command {' '.join(cmd)} failed: {result.stderr}") return result.stdout @@ -55,7 +55,7 @@ def main(): for pdf in sorted(samples_dir.glob("*.pdf")): try: output = run(["pdffonts", str(pdf)]) - except Exception as exc: + except (OSError, RuntimeError) as exc: print(f"Skipping {pdf.name}: {exc}") continue for font_name, encoding in parse_pdffonts(output): diff --git a/scripts/playwright-coverage-summary.py b/scripts/playwright-coverage-summary.py index 0759156d3f..8379461497 100644 --- a/scripts/playwright-coverage-summary.py +++ b/scripts/playwright-coverage-summary.py @@ -48,11 +48,9 @@ SKIP_URL_FRAGMENTS = ( def _is_app_url(url: str) -> bool: if not url: return False - if not (url.startswith("http://") or url.startswith("https://")): + if not (url.startswith(("http://", "https://"))): return False - if any(frag in url for frag in SKIP_URL_FRAGMENTS): - return False - return True + return not any(frag in url for frag in SKIP_URL_FRAGMENTS) def aggregate(dump_dir: Path) -> dict: diff --git a/scripts/pre-commit/install_gitleaks.py b/scripts/pre-commit/install_gitleaks.py index c331b10b65..372a1d289b 100644 --- a/scripts/pre-commit/install_gitleaks.py +++ b/scripts/pre-commit/install_gitleaks.py @@ -61,7 +61,7 @@ def cached_version() -> str | None: if not BIN.exists(): return None try: - return subprocess.run([str(BIN), "version"], capture_output=True, text=True).stdout.strip() + return subprocess.run([str(BIN), "version"], capture_output=True, text=True, check=False).stdout.strip() except OSError: return None diff --git a/scripts/translations/ai_translation_helper.py b/scripts/translations/ai_translation_helper.py index 03b606f1d9..48fff9db3b 100644 --- a/scripts/translations/ai_translation_helper.py +++ b/scripts/translations/ai_translation_helper.py @@ -11,7 +11,7 @@ import csv import json import re import tomllib -from datetime import datetime +from datetime import UTC, datetime from pathlib import Path from typing import Any @@ -28,7 +28,7 @@ class AITranslationHelper: try: with open(file_path, "rb") as f: return tomllib.load(f) - except (FileNotFoundError, Exception) as e: + except (OSError, tomllib.TOMLDecodeError) as e: print(f"Error loading {file_path}: {e}") return {} @@ -47,7 +47,7 @@ class AITranslationHelper: golden_truth = self._load_translation_file(self.golden_truth_file) batch_data = { "metadata": { - "created_at": datetime.now().isoformat(), + "created_at": datetime.now(UTC).isoformat(), "source_language": "en-US", "target_languages": languages, "max_entries_per_language": max_entries_per_language, @@ -105,9 +105,8 @@ class AITranslationHelper: key not in lang_flat or lang_flat[key] == value or (isinstance(lang_flat[key], str) and lang_flat[key].startswith("[UNTRANSLATED]")) - ): - if not self._is_expected_identical(key, value): - untranslated[key] = value + ) and not self._is_expected_identical(key, value): + untranslated[key] = value return untranslated @@ -286,7 +285,7 @@ class AITranslationHelper: golden_flat = self._flatten_dict(golden_truth) if output_format == "csv": - output_file = Path(f"translations_export_{datetime.now().strftime('%Y%m%d')}.csv") + output_file = Path(f"translations_export_{datetime.now(UTC).strftime('%Y%m%d')}.csv") with open(output_file, "w", newline="", encoding="utf-8") as csvfile: fieldnames = ["key", "context", "en_US"] + languages @@ -322,7 +321,7 @@ class AITranslationHelper: print(f"Exported to {output_file}") elif output_format == "json": - output_file = Path(f"translations_export_{datetime.now().strftime('%Y%m%d')}.json") + output_file = Path(f"translations_export_{datetime.now(UTC).strftime('%Y%m%d')}.json") export_data = {"languages": languages, "translations": {}} for key, en_value in golden_flat.items(): diff --git a/scripts/translations/auto_translate.py b/scripts/translations/auto_translate.py index cabfb9269e..b72a3b1344 100644 --- a/scripts/translations/auto_translate.py +++ b/scripts/translations/auto_translate.py @@ -10,9 +10,9 @@ import json import os import subprocess import sys -from concurrent.futures import ThreadPoolExecutor import time import tomllib +from concurrent.futures import ThreadPoolExecutor from pathlib import Path @@ -23,7 +23,7 @@ def run_command(cmd, description=""): print(f"Step: {description}") print(f"{'=' * 60}") - result = subprocess.run(cmd, shell=True, capture_output=True, text=True) + result = subprocess.run(cmd, shell=True, capture_output=True, text=True, check=False) if result.stdout: print(result.stdout) @@ -155,7 +155,7 @@ def translate_batches(batch_files, language_code, api_key, timeout=600, model="g cmd = f'python3 scripts/translations/batch_translator.py "{batch_file}" --language {language_code} --api-key "{api_key}" --model {model}' try: - result = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=timeout) + result = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=timeout, check=False) except subprocess.TimeoutExpired: print(f"✗ Timed out after {timeout}s: {batch_file}", file=sys.stderr) return None @@ -388,7 +388,7 @@ Examples: except KeyboardInterrupt: print("\n\n⚠ Translation interrupted by user") sys.exit(1) - except Exception as e: + except (OSError, ValueError, RuntimeError, subprocess.SubprocessError) as e: print(f"\n\n✗ Error: {e}") import traceback diff --git a/scripts/translations/batch_translator.py b/scripts/translations/batch_translator.py index 864e580fe0..f518796b34 100644 --- a/scripts/translations/batch_translator.py +++ b/scripts/translations/batch_translator.py @@ -160,7 +160,7 @@ Return ONLY the translated JSON. No markdown, no explanations, just the JSON obj print(f"Error: AI returned invalid JSON: {e}") print(f"Response: {translated_text[:500]}...") raise - except Exception as e: + except (OSError, ValueError, KeyError, RuntimeError) as e: print(f"Error during translation: {e}") raise @@ -182,11 +182,11 @@ Return ONLY the translated JSON. No markdown, no explanations, just the JSON obj placeholder_pattern = r"\{[^}]+\}|\{\{[^}]+\}\}" - for key in original.keys(): + for key, original_value in original.items(): if key not in translated: continue - orig_value = str(original[key]) + orig_value = str(original_value) trans_value = str(translated[key]) # Find all placeholders in original @@ -366,7 +366,7 @@ Examples: if i < len(input_files): time.sleep(args.delay) - except Exception as e: + except (OSError, ValueError, KeyError, RuntimeError) as e: print(f"✗ Failed: {e}") failed += 1 continue diff --git a/scripts/translations/bulk_auto_translate.py b/scripts/translations/bulk_auto_translate.py index 827c44d3dc..2205d4421b 100644 --- a/scripts/translations/bulk_auto_translate.py +++ b/scripts/translations/bulk_auto_translate.py @@ -79,7 +79,7 @@ def get_language_completion(locales_dir: Path, language: str) -> float | None: return (translated / total * 100) if total > 0 else 0.0 - except Exception as e: + except (OSError, TypeError, KeyError, ValueError, tomllib.TOMLDecodeError) as e: print(f"Warning: Could not calculate completion for {language}: {e}") return None @@ -124,6 +124,7 @@ def translate_language( cmd, capture_output=True, text=True, + check=False, timeout=timeout * 5, # Overall timeout = 5x per-batch timeout ) @@ -144,8 +145,8 @@ def translate_language( except subprocess.TimeoutExpired: safe_print(f"[{language}] ✗ Timeout exceeded") return (language, False, "Timeout exceeded") - except Exception as e: - safe_print(f"[{language}] ✗ Error: {str(e)}") + except (OSError, TypeError, KeyError, ValueError, tomllib.TOMLDecodeError) as e: + safe_print(f"[{language}] ✗ Error: {e!s}") return (language, False, str(e)) diff --git a/scripts/translations/compact_translator.py b/scripts/translations/compact_translator.py index 527eca8a12..926af223fb 100644 --- a/scripts/translations/compact_translator.py +++ b/scripts/translations/compact_translator.py @@ -38,7 +38,7 @@ class CompactTranslationExtractor: except FileNotFoundError: print(f"Error: File not found: {file_path}", file=sys.stderr) sys.exit(1) - except Exception as e: + except (OSError, tomllib.TOMLDecodeError) as e: print(f"Error: Invalid TOML file {file_path}: {e}", file=sys.stderr) sys.exit(1) @@ -51,7 +51,7 @@ class CompactTranslationExtractor: with open(self.ignore_file, "rb") as f: ignore_data = tomllib.load(f) return {lang: set(data.get("ignore", [])) for lang, data in ignore_data.items()} - except Exception as e: + except (OSError, tomllib.TOMLDecodeError, TypeError, AttributeError) as e: print( f"Warning: Could not load ignore file {self.ignore_file}: {e}", file=sys.stderr, diff --git a/scripts/translations/toml_beautifier.py b/scripts/translations/toml_beautifier.py index 5d529b8a02..39801ee918 100644 --- a/scripts/translations/toml_beautifier.py +++ b/scripts/translations/toml_beautifier.py @@ -28,7 +28,7 @@ class TOMLBeautifier: except FileNotFoundError: print(f"Error: File not found: {file_path}") sys.exit(1) - except Exception as e: + except (OSError, tomllib.TOMLDecodeError) as e: print(f"Error: Invalid TOML in {file_path}: {e}") sys.exit(1) @@ -172,11 +172,11 @@ class TOMLBeautifier: def get_key_order(obj: dict, path: str = "") -> list[str]: keys = [] - for key in obj.keys(): + for key, value in obj.items(): new_path = f"{path}.{key}" if path else key keys.append(new_path) - if isinstance(obj[key], dict): - keys.extend(get_key_order(obj[key], new_path)) + if isinstance(value, dict): + keys.extend(get_key_order(value, new_path)) return keys golden_order = get_key_order(self.golden_structure) diff --git a/scripts/translations/toml_validator.py b/scripts/translations/toml_validator.py index f260871cb1..26b23a145f 100644 --- a/scripts/translations/toml_validator.py +++ b/scripts/translations/toml_validator.py @@ -33,7 +33,7 @@ def get_line_context(file_path, line_num, context_lines=3): context.append(f"{marker}{i + 1:4d}: {lines[i].rstrip()}") return "\n".join(context) - except Exception as e: + except (OSError, UnicodeError, IndexError) as e: return f"Could not read context: {e}" @@ -56,7 +56,7 @@ def get_character_context(file_path, char_pos, context_chars=100): "after": after, "display": f"{before}[{error_char}]{after}", } - except Exception: + except (IndexError, ValueError): return None @@ -90,7 +90,7 @@ def validate_toml_file(file_path): result["valid"] = True result["entry_count"] = count_keys(data) - except Exception as e: + except (OSError, tomllib.TOMLDecodeError, TypeError, ValueError) as e: error_msg = str(e) result["error"] = error_msg diff --git a/scripts/translations/translation_analyzer.py b/scripts/translations/translation_analyzer.py index 9e38c2ad1f..af18e3629e 100644 --- a/scripts/translations/translation_analyzer.py +++ b/scripts/translations/translation_analyzer.py @@ -31,7 +31,7 @@ class TranslationAnalyzer: except FileNotFoundError: print(f"Error: File not found: {file_path}") sys.exit(1) - except Exception as e: + except (OSError, tomllib.TOMLDecodeError) as e: print(f"Error: Invalid file {file_path}: {e}") sys.exit(1) @@ -51,7 +51,7 @@ class TranslationAnalyzer: for patterns in [data.get("ignore", [])] if patterns } - except Exception as e: + except (OSError, tomllib.TOMLDecodeError, TypeError, AttributeError) as e: print(f"Warning: Could not load ignore file {self.ignore_file}: {e}") return {} @@ -165,9 +165,8 @@ class TranslationAnalyzer: for key in relevant_keys: if key in target_flat: value = target_flat[key] - if not (isinstance(value, str) and value.startswith("[UNTRANSLATED]")): - if key not in untranslated: # Not identical to en-US (unless expected) - properly_translated += 1 + if not (isinstance(value, str) and value.startswith("[UNTRANSLATED]")) and key not in untranslated: + properly_translated += 1 completion_rate = (properly_translated / total_keys) * 100 if total_keys > 0 else 0 diff --git a/scripts/translations/translation_merger.py b/scripts/translations/translation_merger.py index 10b4a99d14..2e9a39b7c1 100644 --- a/scripts/translations/translation_merger.py +++ b/scripts/translations/translation_merger.py @@ -12,7 +12,7 @@ import os import shutil import sys import tomllib -from datetime import datetime +from datetime import UTC, datetime from pathlib import Path from typing import Any @@ -39,14 +39,14 @@ class TranslationMerger: except FileNotFoundError: print(f"Error: File not found: {file_path}") sys.exit(1) - except Exception as e: + except (OSError, tomllib.TOMLDecodeError) as e: print(f"Error: Invalid file {file_path}: {e}") sys.exit(1) def _save_translation_file(self, data: dict[str, Any], file_path: Path, backup: bool = False) -> None: """Save TOML translation file with backup option.""" if backup and file_path.exists(): - backup_path = file_path.with_suffix(f".backup.{datetime.now().strftime('%Y%m%d_%H%M%S')}.toml") + backup_path = file_path.with_suffix(f".backup.{datetime.now(UTC).strftime('%Y%m%d_%H%M%S')}.toml") shutil.copy2(file_path, backup_path) print(f"Backup created: {backup_path}") @@ -64,7 +64,7 @@ class TranslationMerger: # Convert to sets for faster lookup return {lang: set(data.get("ignore", [])) for lang, data in ignore_data.items()} - except Exception as e: + except (OSError, tomllib.TOMLDecodeError, TypeError, AttributeError) as e: print(f"Warning: Could not load ignore file {self.ignore_file}: {e}") return {} @@ -264,7 +264,7 @@ class TranslationMerger: self._set_nested_value(target_data, key, translation) applied_count += 1 - except Exception as e: + except (KeyError, TypeError, ValueError) as e: errors.append(f"Error setting {key}: {e}") if applied_count > 0: @@ -316,7 +316,7 @@ class TranslationMerger: "source_language": "en-US", "target_language": target_file.parent.name, "total_entries": len(untranslated), - "created_at": datetime.now().isoformat(), + "created_at": datetime.now(UTC).isoformat(), "instructions": 'Translate the "original" values to the target language. Keep the same keys.', }, "translations": {}, diff --git a/scripts/translations/validate_json_structure.py b/scripts/translations/validate_json_structure.py index 5f083632e1..d9c7ff9ebb 100644 --- a/scripts/translations/validate_json_structure.py +++ b/scripts/translations/validate_json_structure.py @@ -37,8 +37,8 @@ def validate_translation_file(file_path: Path) -> tuple[bool, str]: with open(file_path, "rb") as f: tomllib.load(f) return True, "Valid TOML" - except Exception as e: - return False, f"Error reading file: {str(e)}" + except (OSError, tomllib.TOMLDecodeError) as e: + return False, f"Error reading file: {e!s}" def validate_structure(en_us_keys: set[str], lang_keys: set[str], lang_code: str) -> dict: @@ -139,9 +139,8 @@ def main(): # Validate all languages except en-US languages = [] for d in locales_dir.iterdir(): - if d.is_dir() and d.name != "en-US": - if (d / "translation.toml").exists(): - languages.append(d.name) + if d.is_dir() and d.name != "en-US" and (d / "translation.toml").exists(): + languages.append(d.name) results = [] json_errors = [] diff --git a/scripts/translations/validate_placeholders.py b/scripts/translations/validate_placeholders.py index 440439ea7a..61d5c1fca0 100644 --- a/scripts/translations/validate_placeholders.py +++ b/scripts/translations/validate_placeholders.py @@ -40,11 +40,11 @@ def validate_language(en_us_flat: dict[str, str], lang_flat: dict[str, str], lan """Validate placeholders for a language against en-US.""" issues = [] - for key in en_us_flat: + for key, en_text in en_us_flat.items(): if key not in lang_flat: continue - en_placeholders = find_placeholders(en_us_flat[key]) + en_placeholders = find_placeholders(en_text) lang_placeholders = find_placeholders(lang_flat[key]) if en_placeholders != lang_placeholders: @@ -56,7 +56,7 @@ def validate_language(en_us_flat: dict[str, str], lang_flat: dict[str, str], lan "key": key, "missing": missing, "extra": extra, - "en_text": en_us_flat[key], + "en_text": en_text, "lang_text": lang_flat[key], } issues.append(issue) @@ -127,9 +127,8 @@ def main(): # Validate all languages except en-US languages = [] for d in locales_dir.iterdir(): - if d.is_dir() and d.name != "en-US": - if (d / "translation.toml").exists(): - languages.append(d.name) + if d.is_dir() and d.name != "en-US" and (d / "translation.toml").exists(): + languages.append(d.name) all_issues = [] diff --git a/scripts/type3_to_cff.py b/scripts/type3_to_cff.py index 48fe89c70c..dc96694c37 100644 --- a/scripts/type3_to_cff.py +++ b/scripts/type3_to_cff.py @@ -74,7 +74,7 @@ def load_json(path: Path) -> dict[str, object]: try: with path.open("r", encoding="utf-8") as handle: return json.load(handle) - except Exception as exc: # pragma: no cover - fatal configuration error + except (OSError, UnicodeError, json.JSONDecodeError) as exc: # pragma: no cover - fatal configuration error print(f"ERROR: Failed to load glyph JSON '{path}': {exc}", file=sys.stderr) sys.exit(2) @@ -298,7 +298,7 @@ def build_ttf_glyph(glyph: GlyphSource, max_error: float) -> object | None: try: glyph_obj = pen.glyph() - except Exception: + except (AttributeError, TypeError, ValueError): return None return glyph_obj @@ -472,7 +472,7 @@ def main() -> None: units_per_em=args.units_per_em, cu2qu_error=args.cu2qu_error, ) - except Exception as exc: + except (OSError, ValueError, TypeError, RuntimeError) as exc: print(f"ERROR: Failed to generate fonts: {exc}", file=sys.stderr) if otf_output.exists(): otf_output.unlink() diff --git a/scripts/update_type3_library.py b/scripts/update_type3_library.py index a0d5515573..fd2de895cb 100644 --- a/scripts/update_type3_library.py +++ b/scripts/update_type3_library.py @@ -100,7 +100,7 @@ def normalize_source_path(pdf_path: str | None) -> str | None: try: source = Path(pdf_path) rel = source.relative_to(REPO_ROOT) - except Exception: + except ValueError: rel = Path(pdf_path) return str(rel).replace("\\", "/")