From 1719d9cb9021530410327751ee02385c2fc760e9 Mon Sep 17 00:00:00 2001 From: Eli Fine Date: Thu, 16 Jul 2026 15:46:32 +0000 Subject: [PATCH 1/3] ruff bump --- .config/.copier-answers.yml | 2 +- .devcontainer/devcontainer.json | 10 +++++----- .pre-commit-config.yaml | 10 +++++----- AGENTS.md | 2 +- template/.devcontainer/devcontainer.json.jinja | 8 ++++---- template/.github/workflows/release.yaml.jinja | 5 +++-- template/.pre-commit-config.yaml | 10 +++++----- template/AGENTS.md | 2 +- 8 files changed, 25 insertions(+), 24 deletions(-) diff --git a/.config/.copier-answers.yml b/.config/.copier-answers.yml index 99511a81..6f794621 100644 --- a/.config/.copier-answers.yml +++ b/.config/.copier-answers.yml @@ -1,5 +1,5 @@ # Changes here will be overwritten by Copier -_commit: v0.0.139 +_commit: v0.0.139-2-g2ecd799d _src_path: gh:LabAutomationAndScreening/copier-base-template.git copier_answers_directory: .config description: Copier template for creating Python libraries and executables diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 2d34f4ac..e5577b5e 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -16,16 +16,16 @@ "extensions": [ // basic tooling // "eamodio.gitlens@15.5.1", - "coderabbit.coderabbit-vscode@0.20.7", + "coderabbit.coderabbit-vscode@0.21.0", "ms-vscode.live-server@0.5.2025051301", "MS-vsliveshare.vsliveshare@1.0.5905", - "anthropic.claude-code@2.1.205", + "anthropic.claude-code@2.1.211", // Python "ms-python.python@2026.5.2026052901", - "meta.pyrefly@1.1.9001", + "meta.pyrefly@1.1.9002", "ms-vscode-remote.remote-containers@0.414.0", - "charliermarsh.ruff@2026.56.0", + "charliermarsh.ruff@2026.60.0", // Misc file formats "bierner.markdown-mermaid@1.29.0", @@ -60,5 +60,5 @@ "initializeCommand": "sh .devcontainer/initialize-command.sh", "onCreateCommand": "sh .devcontainer/on-create-command.sh", "postStartCommand": "sh .devcontainer/post-start-command.sh" - // Devcontainer context hash (do not manually edit this, it's managed by a pre-commit hook): 2c1bcc28 # spellchecker:disable-line + // Devcontainer context hash (do not manually edit this, it's managed by a pre-commit hook): d56eca75 # spellchecker:disable-line } diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 47306d3a..c66af060 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -49,7 +49,7 @@ repos: # Reformatting (should generally come before any file format or other checks, because reformatting can change things) - repo: https://github.com/crate-ci/typos - rev: 359573a3ff38f71c93e160f2ace96d118f6ff42e # frozen: v1 + rev: 96d9af6217dc2855210655af7e1ff19d23d4e593 # frozen: v1 hooks: - id: typos args: [--write-changes, --force-exclude, --config, .config/_typos.toml] @@ -113,7 +113,7 @@ repos: )$ - repo: https://github.com/rbubley/mirrors-prettier - rev: 515f543f5718ebfd6ce22e16708bb32c68ff96e1 # frozen: v3.8.3 + rev: 9337a74165b178ae2c766f60bee7252a0f06f3e8 # frozen: v3.9.5 hooks: - id: prettier args: [--config, .config/.prettierrc] @@ -185,7 +185,7 @@ repos: - id: check-case-conflict - repo: https://github.com/python-jsonschema/check-jsonschema - rev: 943377262562a12b57292fc98fabd7dbf81451fe # frozen: 0.37.2 + rev: 1a4bb160cab6417b3045e1b37b6b72449243e658 # frozen: 0.37.4 hooks: - id: check-github-workflows @@ -239,7 +239,7 @@ repos: description: Runs hadolint to lint Dockerfiles - repo: https://github.com/astral-sh/ruff-pre-commit - rev: 6fec9b7edb08fd9989088709d864a7826dc74e80 # frozen: v0.15.12 + rev: 2700fd5671c633760d912769c041bfcde2b9a01b # frozen: v0.15.22 hooks: - id: ruff name: ruff-src @@ -270,7 +270,7 @@ repos: )$ - repo: https://github.com/pylint-dev/pylint - rev: 88e1ab7545a4af4aea15c305a154c164a95ab842 # frozen: v4.0.5 + rev: 8a396357098337ba8be714fffdf2d00947a9778c # frozen: v4.0.6 hooks: - id: pylint name: pylint diff --git a/AGENTS.md b/AGENTS.md index d7bb4ab5..f6f733d5 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -15,6 +15,7 @@ This project is a Copier template used to generate other copier templates. It is - When disabling a linting rule with an inline directive, provide a comment at the end of the line (or on the line above for tools that don't allow extra text after an inline directive) describing the reasoning for disabling the rule. - Avoid telling the type checker what a type is rather than letting it prove it. This includes type assertions (`as SomeType` in TypeScript, `cast()` in Python) and variable annotations that override inference. Prefer approaches that let the type checker verify the type itself: `isinstance`/`instanceof` narrowing, restructuring code so the correct type flows naturally, or using discriminated unions. When there is genuinely no alternative, add a comment explaining why the workaround is necessary and why it is safe. - Avoid `||` (TypeScript) or `or` (Python) in `if`/`elif` conditions, and avoid `x in ['a', 'b']`-style membership tests in implementation code — coverage tools treat these as a single branch, silently masking untested paths and producing false 100% branch coverage. Use separate `if`/`elif` branches instead so each condition is independently covered. +- When filtering logic combines multiple `and`-joined guards (e.g. a null check alongside a value check), prefer a loop with explicit `if`/`continue` branches over a single-line comprehension. A compound boolean filter on one line hides individual branches from line coverage — each guard condition should be its own statement so missing test cases are surfaced. ## Testing @@ -24,7 +25,6 @@ This project is a Copier template used to generate other copier templates. It is - Avoid magic values in comparisons in tests in all languages (like ruff rule PLR2004 specifies). Note: `1` and `0` are not magic numbers (according to PLR2004) - Prefer using random values in tests rather than arbitrary ones (e.g. the faker library, uuids, random.randint) when possible. For enums, pick randomly rather than hardcoding one value. - Avoid loops in tests — assert each item explicitly so failures pinpoint the exact element. When verifying a condition across all items in a collection, collect the violations into a list and assert it's empty (e.g., assert [x for x in items if bad_condition(x)] == []). -- When filtering logic combines multiple `and`-joined guards (e.g. a null check alongside a value check), prefer a loop with explicit `if`/`continue` branches over a single-line comprehension. A compound boolean filter on one line hides individual branches from line coverage — each guard condition should be its own statement so missing test cases are surfaced. - When a test's final assertion is an absence (e.g., element is `null`, list is empty, modal is closed), include a prior presence assertion confirming the expected state existed before the action that removed it. A test whose only assertion is an absence check can pass vacuously if setup silently failed. - When asserting a mock or spy was called with specific arguments, always constrain as tightly as possible. In order of preference: (1) assert called exactly once with those args (`assert_called_once_with` in Python, `toHaveBeenCalledExactlyOnceWith` in Vitest/Jest); (2) if multiple calls are expected, assert the total call count and use a positional or last-call assertion (`nthCalledWith`, `lastCalledWith` / `assert_has_calls` with `call_args_list[n]`); (3) plain "called with at any point" (`toHaveBeenCalledWith`, `assert_called_with`) is a last resort only when neither the call count nor the call order can reasonably be constrained. - When asserting an exception is raised, verify the error message includes all key constructor arguments — not just one identifying field. This ensures the error message is fully populated and catches cases where arguments are swapped or missing. In Python: use the `match` parameter in `pytest.raises`. In TypeScript: use a regex or substring in `toThrow`, or catch and assert on error properties individually. diff --git a/template/.devcontainer/devcontainer.json.jinja b/template/.devcontainer/devcontainer.json.jinja index 731d2345..93091070 100644 --- a/template/.devcontainer/devcontainer.json.jinja +++ b/template/.devcontainer/devcontainer.json.jinja @@ -34,16 +34,16 @@ "-AmazonWebServices.aws-toolkit-vscode", // the AWS CLI feature installs this automatically, but it's causing problems in VS Code{% endraw %}{% endif %}{% raw %} // basic tooling // "eamodio.gitlens@15.5.1", - "coderabbit.coderabbit-vscode@0.20.7", + "coderabbit.coderabbit-vscode@0.21.0", "ms-vscode.live-server@0.5.2025051301", "MS-vsliveshare.vsliveshare@1.0.5905",{% endraw %}{% if install_claude_cli %}{% raw %} - "anthropic.claude-code@2.1.205",{% endraw %}{% endif %}{% raw %}{% endraw %}{% if (is_child_of_copier_base_template is defined and is_child_of_copier_base_template is sameas(true)) or (is_child_of_copier_base_template is not defined and template_uses_python is defined and template_uses_python is sameas(true)) %}{% raw %} + "anthropic.claude-code@2.1.211",{% endraw %}{% endif %}{% raw %}{% endraw %}{% if (is_child_of_copier_base_template is defined and is_child_of_copier_base_template is sameas(true)) or (is_child_of_copier_base_template is not defined and template_uses_python is defined and template_uses_python is sameas(true)) %}{% raw %} // Python "ms-python.python@2026.5.2026052901", - "meta.pyrefly@1.1.9001", + "meta.pyrefly@1.1.9002", "ms-vscode-remote.remote-containers@0.414.0", - "charliermarsh.ruff@2026.56.0",{% endraw %}{% endif %}{% raw %} + "charliermarsh.ruff@2026.60.0",{% endraw %}{% endif %}{% raw %} {% endraw %}{% if is_child_of_copier_base_template is not defined and template_uses_vuejs is defined and template_uses_vuejs is sameas(true) %}{% raw %} // VueJS "vue.volar@3.2.5", diff --git a/template/.github/workflows/release.yaml.jinja b/template/.github/workflows/release.yaml.jinja index 6f486f48..b5341b68 100644 --- a/template/.github/workflows/release.yaml.jinja +++ b/template/.github/workflows/release.yaml.jinja @@ -385,8 +385,9 @@ jobs: runs-on: {% endraw %}{{ gha_linux_runner }}{% raw %} timeout-minutes: {% endraw %}{{ gha_short_timeout_minutes }}{% raw %} needs: -{% endraw %}{% if not deploy_as_executable %}{% raw %} - install-from-primary -{% endraw %}{% endif %}{% raw %} - guard + - guard{% endraw %}{% if not deploy_as_executable %}{% raw %} + - create-tag + - install-from-primary{% endraw %}{% endif %}{% raw %} permissions: contents: write # needed to create GitHub releases{% endraw %}{% if deploy_as_executable %}{% raw %} actions: read # needed to download the executable artifacts from the CI run{% endraw %}{% endif %}{% raw %} diff --git a/template/.pre-commit-config.yaml b/template/.pre-commit-config.yaml index 47306d3a..c66af060 100644 --- a/template/.pre-commit-config.yaml +++ b/template/.pre-commit-config.yaml @@ -49,7 +49,7 @@ repos: # Reformatting (should generally come before any file format or other checks, because reformatting can change things) - repo: https://github.com/crate-ci/typos - rev: 359573a3ff38f71c93e160f2ace96d118f6ff42e # frozen: v1 + rev: 96d9af6217dc2855210655af7e1ff19d23d4e593 # frozen: v1 hooks: - id: typos args: [--write-changes, --force-exclude, --config, .config/_typos.toml] @@ -113,7 +113,7 @@ repos: )$ - repo: https://github.com/rbubley/mirrors-prettier - rev: 515f543f5718ebfd6ce22e16708bb32c68ff96e1 # frozen: v3.8.3 + rev: 9337a74165b178ae2c766f60bee7252a0f06f3e8 # frozen: v3.9.5 hooks: - id: prettier args: [--config, .config/.prettierrc] @@ -185,7 +185,7 @@ repos: - id: check-case-conflict - repo: https://github.com/python-jsonschema/check-jsonschema - rev: 943377262562a12b57292fc98fabd7dbf81451fe # frozen: 0.37.2 + rev: 1a4bb160cab6417b3045e1b37b6b72449243e658 # frozen: 0.37.4 hooks: - id: check-github-workflows @@ -239,7 +239,7 @@ repos: description: Runs hadolint to lint Dockerfiles - repo: https://github.com/astral-sh/ruff-pre-commit - rev: 6fec9b7edb08fd9989088709d864a7826dc74e80 # frozen: v0.15.12 + rev: 2700fd5671c633760d912769c041bfcde2b9a01b # frozen: v0.15.22 hooks: - id: ruff name: ruff-src @@ -270,7 +270,7 @@ repos: )$ - repo: https://github.com/pylint-dev/pylint - rev: 88e1ab7545a4af4aea15c305a154c164a95ab842 # frozen: v4.0.5 + rev: 8a396357098337ba8be714fffdf2d00947a9778c # frozen: v4.0.6 hooks: - id: pylint name: pylint diff --git a/template/AGENTS.md b/template/AGENTS.md index 63b14b78..490b4969 100644 --- a/template/AGENTS.md +++ b/template/AGENTS.md @@ -15,6 +15,7 @@ This project is a Python library. - When disabling a linting rule with an inline directive, provide a comment at the end of the line (or on the line above for tools that don't allow extra text after an inline directive) describing the reasoning for disabling the rule. - Avoid telling the type checker what a type is rather than letting it prove it. This includes type assertions (`as SomeType` in TypeScript, `cast()` in Python) and variable annotations that override inference. Prefer approaches that let the type checker verify the type itself: `isinstance`/`instanceof` narrowing, restructuring code so the correct type flows naturally, or using discriminated unions. When there is genuinely no alternative, add a comment explaining why the workaround is necessary and why it is safe. - Avoid `||` (TypeScript) or `or` (Python) in `if`/`elif` conditions, and avoid `x in ['a', 'b']`-style membership tests in implementation code — coverage tools treat these as a single branch, silently masking untested paths and producing false 100% branch coverage. Use separate `if`/`elif` branches instead so each condition is independently covered. +- When filtering logic combines multiple `and`-joined guards (e.g. a null check alongside a value check), prefer a loop with explicit `if`/`continue` branches over a single-line comprehension. A compound boolean filter on one line hides individual branches from line coverage — each guard condition should be its own statement so missing test cases are surfaced. ## Testing @@ -24,7 +25,6 @@ This project is a Python library. - Avoid magic values in comparisons in tests in all languages (like ruff rule PLR2004 specifies). Note: `1` and `0` are not magic numbers (according to PLR2004) - Prefer using random values in tests rather than arbitrary ones (e.g. the faker library, uuids, random.randint) when possible. For enums, pick randomly rather than hardcoding one value. - Avoid loops in tests — assert each item explicitly so failures pinpoint the exact element. When verifying a condition across all items in a collection, collect the violations into a list and assert it's empty (e.g., assert [x for x in items if bad_condition(x)] == []). -- When filtering logic combines multiple `and`-joined guards (e.g. a null check alongside a value check), prefer a loop with explicit `if`/`continue` branches over a single-line comprehension. A compound boolean filter on one line hides individual branches from line coverage — each guard condition should be its own statement so missing test cases are surfaced. - When a test's final assertion is an absence (e.g., element is `null`, list is empty, modal is closed), include a prior presence assertion confirming the expected state existed before the action that removed it. A test whose only assertion is an absence check can pass vacuously if setup silently failed. - When asserting a mock or spy was called with specific arguments, always constrain as tightly as possible. In order of preference: (1) assert called exactly once with those args (`assert_called_once_with` in Python, `toHaveBeenCalledExactlyOnceWith` in Vitest/Jest); (2) if multiple calls are expected, assert the total call count and use a positional or last-call assertion (`nthCalledWith`, `lastCalledWith` / `assert_has_calls` with `call_args_list[n]`); (3) plain "called with at any point" (`toHaveBeenCalledWith`, `assert_called_with`) is a last resort only when neither the call count nor the call order can reasonably be constrained. - When asserting an exception is raised, verify the error message includes all key constructor arguments — not just one identifying field. This ensures the error message is fully populated and catches cases where arguments are swapped or missing. In Python: use the `match` parameter in `pytest.raises`. In TypeScript: use a regex or substring in `toThrow`, or catch and assert on error properties individually. From 31351ef97db5354a5134e5b10a3ade2fabef8c8d Mon Sep 17 00:00:00 2001 From: Eli Fine Date: Thu, 16 Jul 2026 16:11:28 +0000 Subject: [PATCH 2/3] pull in --- .config/.copier-answers.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.config/.copier-answers.yml b/.config/.copier-answers.yml index 6f794621..a3074cb4 100644 --- a/.config/.copier-answers.yml +++ b/.config/.copier-answers.yml @@ -1,5 +1,5 @@ # Changes here will be overwritten by Copier -_commit: v0.0.139-2-g2ecd799d +_commit: v0.0.139-3-g456e2361 _src_path: gh:LabAutomationAndScreening/copier-base-template.git copier_answers_directory: .config description: Copier template for creating Python libraries and executables From f39c082076d9d9ddfc46b0b2d59ed1006d485fbd Mon Sep 17 00:00:00 2001 From: Eli Fine Date: Thu, 16 Jul 2026 16:50:59 +0000 Subject: [PATCH 3/3] tag --- .config/.copier-answers.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.config/.copier-answers.yml b/.config/.copier-answers.yml index a3074cb4..1e3daa07 100644 --- a/.config/.copier-answers.yml +++ b/.config/.copier-answers.yml @@ -1,5 +1,5 @@ # Changes here will be overwritten by Copier -_commit: v0.0.139-3-g456e2361 +_commit: v0.0.140 _src_path: gh:LabAutomationAndScreening/copier-base-template.git copier_answers_directory: .config description: Copier template for creating Python libraries and executables