From dc3e6f6a41b4b1133be663afad21e7a27de9e69f Mon Sep 17 00:00:00 2001 From: Eli Fine Date: Thu, 11 Dec 2025 13:22:16 +0000 Subject: [PATCH 01/28] bump uv --- .devcontainer/devcontainer.json | 4 +-- .devcontainer/install-ci-tooling.py | 2 +- extensions/context.py | 25 ++++++++++--------- pyproject.toml | 2 +- .../devcontainer.json.jinja-base | 2 +- template/extensions/context.py.jinja-base | 1 + uv.lock | 8 +++--- 7 files changed, 23 insertions(+), 21 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 3d70bd49..0fe831b6 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -22,7 +22,7 @@ "-AmazonWebServices.aws-toolkit-vscode", // the AWS CLI feature installs this automatically, but it's causing problems in VS Code // basic tooling // "eamodio.gitlens@15.5.1", - "coderabbit.coderabbit-vscode@0.16.0", + "coderabbit.coderabbit-vscode@0.16.1", "ms-vscode.live-server@0.5.2025051301", "MS-vsliveshare.vsliveshare@1.0.5905", "github.copilot@1.388.0", @@ -62,5 +62,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): 99d2d16a # spellchecker:disable-line + // Devcontainer context hash (do not manually edit this, it's managed by a pre-commit hook): 71b2d03b # spellchecker:disable-line } diff --git a/.devcontainer/install-ci-tooling.py b/.devcontainer/install-ci-tooling.py index 880938cb..e28b2b16 100644 --- a/.devcontainer/install-ci-tooling.py +++ b/.devcontainer/install-ci-tooling.py @@ -5,7 +5,7 @@ import subprocess import sys -UV_VERSION = "0.9.11" +UV_VERSION = "0.9.17" COPIER_VERSION = "9.11.0" COPIER_TEMPLATE_EXTENSIONS_VERSION = "0.3.3" PRE_COMMIT_VERSION = "4.5.0" diff --git a/extensions/context.py b/extensions/context.py index 7b6b895c..cda14760 100644 --- a/extensions/context.py +++ b/extensions/context.py @@ -11,16 +11,16 @@ class ContextUpdater(ContextHook): @override def hook(self, context: dict[Any, Any]) -> dict[Any, Any]: # These are duplicated in the install-ci-tooling.py script in this repository - context["uv_version"] = "0.9.11" + context["uv_version"] = "0.9.17" context["pre_commit_version"] = "4.5.0" # These also in pyproject.toml context["copier_version"] = "9.11.0" context["copier_template_extensions_version"] = "0.3.3" ####### - context["pnpm_version"] = "10.24.0" + context["pnpm_version"] = "10.25.0" # These are duplicated in the pyproject.toml of this repository context["pyright_version"] = "1.1.407" - context["pytest_version"] = "9.0.1" + context["pytest_version"] = "9.0.2" context["pytest_randomly_version"] = "4.0.1" context["pytest_cov_version"] = "7.0.0" ####### @@ -33,29 +33,30 @@ def hook(self, context: dict[Any, Any]) -> dict[Any, Any]: context["pulumi_okta_version"] = "6.1.0" context["boto3_version"] = "1.41.2" context["ephemeral_pulumi_deploy_version"] = "0.0.5" - context["pydantic_version"] = "2.12.4" - context["pyinstaller_version"] = "6.16.0" + context["pydantic_version"] = "2.12.5" + context["pyinstaller_version"] = "6.17.0" context["setuptools_version"] = "80.7.1" context["strawberry_graphql_version"] = "0.287.0" - context["fastapi_version"] = "0.121.0" + context["fastapi_version"] = "0.124.2" context["fastapi_offline_version"] = "1.7.4" context["uvicorn_version"] = "0.38.0" context["lab_auto_pulumi_version"] = "0.1.17" context["ariadne_codegen_version"] = "0.15.2" context["pytest_mock_version"] = "3.15.1" - context["uuid_utils_version"] = "0.11.0" + context["uuid_utils_version"] = "0.12.0" context["syrupy_version"] = "5.0.0" context["structlog_version"] = "25.5.0" context["httpx_version"] = "0.28.1" context["python_kiota_bundle_version"] = "1.9.7" + context["vcrpy_version"] = "8.1.0" ####### context["node_version"] = "24.7.0" context["nuxt_ui_version"] = "^4.2.1" - context["nuxt_version"] = "^4.2.0" + context["nuxt_version"] = "^4.2.2" context["nuxt_icon_version"] = "^2.1.0" context["typescript_version"] = "^5.9.3" - context["playwright_version"] = "^1.56.0" - context["vue_version"] = "^3.5.22" + context["playwright_version"] = "^1.57.0" + context["vue_version"] = "^3.5.25" context["vue_tsc_version"] = "^3.1.2" context["vue_devtools_api_version"] = "^8.0.0" context["vue_router_version"] = "^4.6.0" @@ -66,7 +67,7 @@ def hook(self, context: dict[Any, Any]) -> dict[Any, Any]: context["nuxt_eslint_version"] = "^1.10.0" context["zod_version"] = "^4.1.12" context["zod_from_json_schema_version"] = "^0.5.1" - context["types_node_version"] = "^24.10.1" + context["types_node_version"] = "^25.0.0" context["nuxt_apollo_version"] = "5.0.0-alpha.15" context["graphql_codegen_cli_version"] = "^6.0.0" context["graphql_codegen_typescript_version"] = "^5.0.0" @@ -83,7 +84,7 @@ def hook(self, context: dict[Any, Any]) -> dict[Any, Any]: context["node_kiota_bundle_version"] = "1.0.0-preview.99" ####### # These are duplicated in the CI files for this repository - context["gha_checkout"] = "v5.0.0" + context["gha_checkout"] = "v6.0.1" context["gha_setup_python"] = "v6.0.0" context["gha_cache"] = "v4.2.4" context["gha_linux_runner"] = "ubuntu-24.04" diff --git a/pyproject.toml b/pyproject.toml index e4f2cb66..55d0c0fc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ description = "Add your description here" readme = "README.md" requires-python = ">=3.12.7" dependencies = [ - "pytest>=9.0.1", + "pytest>=9.0.2", "pytest-cov>=7.0.0", "pytest-randomly>=4.0.1", "pyright[nodejs]>=1.1.407", diff --git a/template/.devcontainer/devcontainer.json.jinja-base b/template/.devcontainer/devcontainer.json.jinja-base index 4a118dd6..33cf5f35 100644 --- a/template/.devcontainer/devcontainer.json.jinja-base +++ b/template/.devcontainer/devcontainer.json.jinja-base @@ -28,7 +28,7 @@ "-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.16.0", + "coderabbit.coderabbit-vscode@0.16.1", "ms-vscode.live-server@0.5.2025051301", "MS-vsliveshare.vsliveshare@1.0.5905", "github.copilot@1.388.0", diff --git a/template/extensions/context.py.jinja-base b/template/extensions/context.py.jinja-base index f4085b16..1b5a701c 100644 --- a/template/extensions/context.py.jinja-base +++ b/template/extensions/context.py.jinja-base @@ -43,6 +43,7 @@ class ContextUpdater(ContextHook): context["structlog_version"] = "{{ structlog_version }}" context["httpx_version"] = "{{ httpx_version }}" context["python_kiota_bundle_version"] = "{{ python_kiota_bundle_version }}" + context["vcrpy_version"] = "{{ vcrpy_version }}" context["node_version"] = "{{ node_version }}" context["nuxt_ui_version"] = "{{ nuxt_ui_version }}" diff --git a/uv.lock b/uv.lock index ba3f48a1..52c915b8 100644 --- a/uv.lock +++ b/uv.lock @@ -62,7 +62,7 @@ requires-dist = [ { name = "copier", specifier = ">=9.11.0" }, { name = "copier-template-extensions", specifier = ">=0.3.3" }, { name = "pyright", extras = ["nodejs"], specifier = ">=1.1.407" }, - { name = "pytest", specifier = ">=9.0.1" }, + { name = "pytest", specifier = ">=9.0.2" }, { name = "pytest-cov", specifier = ">=7.0.0" }, { name = "pytest-randomly", specifier = ">=4.0.1" }, ] @@ -402,7 +402,7 @@ nodejs = [ [[package]] name = "pytest" -version = "9.0.1" +version = "9.0.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, @@ -411,9 +411,9 @@ dependencies = [ { name = "pluggy" }, { name = "pygments" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/07/56/f013048ac4bc4c1d9be45afd4ab209ea62822fb1598f40687e6bf45dcea4/pytest-9.0.1.tar.gz", hash = "sha256:3e9c069ea73583e255c3b21cf46b8d3c56f6e3a1a8f6da94ccb0fcf57b9d73c8", size = 1564125, upload-time = "2025-11-12T13:05:09.333Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d1/db/7ef3487e0fb0049ddb5ce41d3a49c235bf9ad299b6a25d5780a89f19230f/pytest-9.0.2.tar.gz", hash = "sha256:75186651a92bd89611d1d9fc20f0b4345fd827c41ccd5c299a868a05d70edf11", size = 1568901, upload-time = "2025-12-06T21:30:51.014Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/0b/8b/6300fb80f858cda1c51ffa17075df5d846757081d11ab4aa35cef9e6258b/pytest-9.0.1-py3-none-any.whl", hash = "sha256:67be0030d194df2dfa7b556f2e56fb3c3315bd5c8822c6951162b92b32ce7dad", size = 373668, upload-time = "2025-11-12T13:05:07.379Z" }, + { url = "https://files.pythonhosted.org/packages/3b/ab/b3226f0bd7cdcf710fbede2b3548584366da3b19b5021e74f5bde2a8fa3f/pytest-9.0.2-py3-none-any.whl", hash = "sha256:711ffd45bf766d5264d487b917733b453d917afd2b0ad65223959f59089f875b", size = 374801, upload-time = "2025-12-06T21:30:49.154Z" }, ] [[package]] From ae1c48a6902c0489679ffe8a0ea124c48948f9e5 Mon Sep 17 00:00:00 2001 From: Eli Fine Date: Thu, 11 Dec 2025 13:24:11 +0000 Subject: [PATCH 02/28] gha --- .github/workflows/ci.yaml | 12 ++++++------ .github/workflows/tag-on-merge.yaml | 2 +- extensions/context.py | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index c44da0e2..75063b00 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -25,12 +25,12 @@ jobs: timeout-minutes: 8 runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v5.0.0 + - uses: actions/checkout@v6.0.1 with: persist-credentials: false - name: Setup Python - uses: actions/setup-python@v6.0.0 + uses: actions/setup-python@v6.1.0 with: python-version: ${{ matrix.python-version }} @@ -50,7 +50,7 @@ jobs: timeout-minutes: 30 # this is the amount of time this action will wait to attempt to acquire the mutex lock before failing, e.g. if other jobs are queued up in front of it - name: Cache Pre-commit hooks - uses: actions/cache@v4.2.4 + uses: actions/cache@v4.3.0 env: cache-name: cache-pre-commit-hooks with: @@ -83,12 +83,12 @@ jobs: contents: write # needed for mutex steps: - - uses: actions/checkout@v5.0.0 + - uses: actions/checkout@v6.0.1 with: persist-credentials: false - name: Setup Python - uses: actions/setup-python@v6.0.0 + uses: actions/setup-python@v6.1.0 with: python-version: ${{ matrix.python-version }} @@ -134,7 +134,7 @@ jobs: timeout-minutes: 30 # this is the amount of time this action will wait to attempt to acquire the mutex lock before failing, e.g. if other jobs are queued up in front of it - name: Cache Pre-commit hooks - uses: actions/cache@v4.2.4 + uses: actions/cache@v4.3.0 env: cache-name: cache-pre-commit-hooks with: diff --git a/.github/workflows/tag-on-merge.yaml b/.github/workflows/tag-on-merge.yaml index 3c208ca7..2e9b2277 100644 --- a/.github/workflows/tag-on-merge.yaml +++ b/.github/workflows/tag-on-merge.yaml @@ -14,7 +14,7 @@ jobs: permissions: contents: write steps: - - uses: actions/checkout@v5.0.0 + - uses: actions/checkout@v6.0.1 with: ref: ${{ github.event.pull_request.merge_commit_sha }} fetch-depth: '0' diff --git a/extensions/context.py b/extensions/context.py index cda14760..58c34128 100644 --- a/extensions/context.py +++ b/extensions/context.py @@ -85,8 +85,8 @@ def hook(self, context: dict[Any, Any]) -> dict[Any, Any]: ####### # These are duplicated in the CI files for this repository context["gha_checkout"] = "v6.0.1" - context["gha_setup_python"] = "v6.0.0" - context["gha_cache"] = "v4.2.4" + context["gha_setup_python"] = "v6.1.0" + context["gha_cache"] = "v4.3.0" context["gha_linux_runner"] = "ubuntu-24.04" ####### context["gha_upload_artifact"] = "v5.0.0" From 5184f186a29916c9676b81736df986ba9b10fd58 Mon Sep 17 00:00:00 2001 From: Eli Fine Date: Thu, 11 Dec 2025 13:26:22 +0000 Subject: [PATCH 03/28] More actions --- extensions/context.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/extensions/context.py b/extensions/context.py index 58c34128..8b977cf0 100644 --- a/extensions/context.py +++ b/extensions/context.py @@ -95,9 +95,9 @@ def hook(self, context: dict[Any, Any]) -> dict[Any, Any]: context["gha_setup_buildx"] = "v3.11.1" context["buildx_version"] = "v0.27.0" context["gha_docker_build_push"] = "v6.18.0" - context["gha_configure_aws_credentials"] = "v5.1.0" + context["gha_configure_aws_credentials"] = "v5.1.1" context["gha_amazon_ecr_login"] = "v2.0.1" - context["gha_setup_node"] = "v6.0.0" + context["gha_setup_node"] = "v6.1.0" context["gha_action_gh_release"] = "v2.2.1" context["gha_mutex"] = "1ebad517141198e08d47cf72f3c0975316620a65 # v1.0.0-alpha.10" context["gha_pypi_publish"] = "v1.13.0" @@ -109,8 +109,8 @@ def hook(self, context: dict[Any, Any]) -> dict[Any, Any]: context["gha_xlong_timeout_minutes"] = "45" ####### context["debian_release_name"] = "bookworm" - context["alpine_image_version"] = "3.22" - context["nginx_image_version"] = "1.29.1" + context["alpine_image_version"] = "3.23" + context["nginx_image_version"] = "1.29.4" ####### context["kiota_cli_version"] = "1.29.0" # These also in the tests/data.yml files in this repository and in copier.yaml From 082ee1155917577c9f6987e62a029fcacc4332a8 Mon Sep 17 00:00:00 2001 From: Eli Fine Date: Thu, 11 Dec 2025 13:29:45 +0000 Subject: [PATCH 04/28] more context --- extensions/context.py | 2 ++ template/extensions/context.py.jinja-base | 2 ++ 2 files changed, 4 insertions(+) diff --git a/extensions/context.py b/extensions/context.py index 8b977cf0..8eb28722 100644 --- a/extensions/context.py +++ b/extensions/context.py @@ -49,6 +49,8 @@ def hook(self, context: dict[Any, Any]) -> dict[Any, Any]: context["httpx_version"] = "0.28.1" context["python_kiota_bundle_version"] = "1.9.7" context["vcrpy_version"] = "8.1.0" + context["pytest_recording_version"] = "0.13.4" + context["pytest_asyncio_version"] = "1.3.0" ####### context["node_version"] = "24.7.0" context["nuxt_ui_version"] = "^4.2.1" diff --git a/template/extensions/context.py.jinja-base b/template/extensions/context.py.jinja-base index 1b5a701c..e91e40d8 100644 --- a/template/extensions/context.py.jinja-base +++ b/template/extensions/context.py.jinja-base @@ -44,6 +44,8 @@ class ContextUpdater(ContextHook): context["httpx_version"] = "{{ httpx_version }}" context["python_kiota_bundle_version"] = "{{ python_kiota_bundle_version }}" context["vcrpy_version"] = "{{ vcrpy_version }}" + context["pytest_recording_version"] = "{{ pytest_recording_version }}" + context["pytest_asyncio_version"] = "{{ pytest_asyncio_version }}" context["node_version"] = "{{ node_version }}" context["nuxt_ui_version"] = "{{ nuxt_ui_version }}" From b08479b46312ed8b085f6089848fa7844ab61ea1 Mon Sep 17 00:00:00 2001 From: Eli Fine Date: Thu, 11 Dec 2025 13:31:03 +0000 Subject: [PATCH 05/28] aridane --- extensions/context.py | 1 + template/extensions/context.py.jinja-base | 1 + 2 files changed, 2 insertions(+) diff --git a/extensions/context.py b/extensions/context.py index 8eb28722..c743787c 100644 --- a/extensions/context.py +++ b/extensions/context.py @@ -51,6 +51,7 @@ def hook(self, context: dict[Any, Any]) -> dict[Any, Any]: context["vcrpy_version"] = "8.1.0" context["pytest_recording_version"] = "0.13.4" context["pytest_asyncio_version"] = "1.3.0" + context["ariadne_codegen_version"] = "0.17.0" ####### context["node_version"] = "24.7.0" context["nuxt_ui_version"] = "^4.2.1" diff --git a/template/extensions/context.py.jinja-base b/template/extensions/context.py.jinja-base index e91e40d8..c3a2693a 100644 --- a/template/extensions/context.py.jinja-base +++ b/template/extensions/context.py.jinja-base @@ -46,6 +46,7 @@ class ContextUpdater(ContextHook): context["vcrpy_version"] = "{{ vcrpy_version }}" context["pytest_recording_version"] = "{{ pytest_recording_version }}" context["pytest_asyncio_version"] = "{{ pytest_asyncio_version }}" + context["ariadne_codegen_version"] = "{{ ariadne_codegen_version }}" context["node_version"] = "{{ node_version }}" context["nuxt_ui_version"] = "{{ nuxt_ui_version }}" From 752d837eb2fa718dd256bffc37afb877e71bba28 Mon Sep 17 00:00:00 2001 From: Eli Fine Date: Thu, 11 Dec 2025 13:33:13 +0000 Subject: [PATCH 06/28] fix --- extensions/context.py | 3 +-- template/extensions/context.py.jinja-base | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/extensions/context.py b/extensions/context.py index c743787c..b95fdb0d 100644 --- a/extensions/context.py +++ b/extensions/context.py @@ -41,7 +41,7 @@ def hook(self, context: dict[Any, Any]) -> dict[Any, Any]: context["fastapi_offline_version"] = "1.7.4" context["uvicorn_version"] = "0.38.0" context["lab_auto_pulumi_version"] = "0.1.17" - context["ariadne_codegen_version"] = "0.15.2" + context["ariadne_codegen_version"] = "0.17.0" context["pytest_mock_version"] = "3.15.1" context["uuid_utils_version"] = "0.12.0" context["syrupy_version"] = "5.0.0" @@ -51,7 +51,6 @@ def hook(self, context: dict[Any, Any]) -> dict[Any, Any]: context["vcrpy_version"] = "8.1.0" context["pytest_recording_version"] = "0.13.4" context["pytest_asyncio_version"] = "1.3.0" - context["ariadne_codegen_version"] = "0.17.0" ####### context["node_version"] = "24.7.0" context["nuxt_ui_version"] = "^4.2.1" diff --git a/template/extensions/context.py.jinja-base b/template/extensions/context.py.jinja-base index c3a2693a..e91e40d8 100644 --- a/template/extensions/context.py.jinja-base +++ b/template/extensions/context.py.jinja-base @@ -46,7 +46,6 @@ class ContextUpdater(ContextHook): context["vcrpy_version"] = "{{ vcrpy_version }}" context["pytest_recording_version"] = "{{ pytest_recording_version }}" context["pytest_asyncio_version"] = "{{ pytest_asyncio_version }}" - context["ariadne_codegen_version"] = "{{ ariadne_codegen_version }}" context["node_version"] = "{{ node_version }}" context["nuxt_ui_version"] = "{{ nuxt_ui_version }}" From 497af1213cd92fe68d6d39dc26367ba2ffed5e2f Mon Sep 17 00:00:00 2001 From: Eli Fine Date: Thu, 11 Dec 2025 13:41:17 +0000 Subject: [PATCH 07/28] pulumi --- ...ulumi %}pulumi-aws.yml{% endif %}.jinja-base | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/template/template/.github/workflows/{% if template_uses_pulumi %}pulumi-aws.yml{% endif %}.jinja-base b/template/template/.github/workflows/{% if template_uses_pulumi %}pulumi-aws.yml{% endif %}.jinja-base index 480ebf59..9356f7be 100644 --- a/template/template/.github/workflows/{% if template_uses_pulumi %}pulumi-aws.yml{% endif %}.jinja-base +++ b/template/template/.github/workflows/{% if template_uses_pulumi %}pulumi-aws.yml{% endif %}.jinja-base @@ -76,6 +76,16 @@ on: required: false default: '' type: string + DOWNLOAD_ARTIFACT_NAME: + description: 'Name of the artifact to download from the build job' + required: false + default: '' + type: string + DOWNLOAD_ARTIFACT_PATH: + description: 'Path to extract the downloaded artifact to' + required: false + default: '' + type: string secrets: iac-github-api-tokens: description: 'API tokens to use for Github IaC deployment when not using AWS Secrets Manager' @@ -107,6 +117,13 @@ jobs: with: python-version: ${{ inputs.PYTHON_VERSION }} + - name: Download Artifact + uses: actions/download-artifact@{% endraw %}{{ gha_download_artifact }}{% raw %} + if: ${{ inputs.DOWNLOAD_ARTIFACT_NAME != '' }} + with: + name: ${{ inputs.DOWNLOAD_ARTIFACT_NAME }} + path: ${{ inputs.DOWNLOAD_ARTIFACT_PATH }} + - name: Set up mutex # Github concurrency management is horrible, things get arbitrarily cancelled if queued up. So using mutex until github fixes itself. When multiple jobs are modifying cache at once, weird things can happen. possible issue is https://github.com/actions/toolkit/issues/658 uses: ben-z/gh-action-mutex@{% endraw %}{{ gha_mutex }}{% raw %} with: From e1e27183576321f1ef1da887c2f2f3159133d69a Mon Sep 17 00:00:00 2001 From: Eli Fine Date: Thu, 11 Dec 2025 13:46:55 +0000 Subject: [PATCH 08/28] more context --- extensions/context.py | 1 + template/extensions/context.py.jinja-base | 1 + 2 files changed, 2 insertions(+) diff --git a/extensions/context.py b/extensions/context.py index b95fdb0d..945df641 100644 --- a/extensions/context.py +++ b/extensions/context.py @@ -74,6 +74,7 @@ def hook(self, context: dict[Any, Any]) -> dict[Any, Any]: context["graphql_codegen_cli_version"] = "^6.0.0" context["graphql_codegen_typescript_version"] = "^5.0.0" context["graphql_codegen_typescript_operations_version"] = "^5.0.0" + context["graphql_tools_mock_version"] = "^9.1.0" context["tailwindcss_version"] = "^4.1.11" context["iconify_vue_version"] = "^5.0.0" context["iconify_json_lucide_version"] = "^1.2.71" diff --git a/template/extensions/context.py.jinja-base b/template/extensions/context.py.jinja-base index e91e40d8..65a5af4c 100644 --- a/template/extensions/context.py.jinja-base +++ b/template/extensions/context.py.jinja-base @@ -69,6 +69,7 @@ class ContextUpdater(ContextHook): context["graphql_codegen_cli_version"] = "{{ graphql_codegen_cli_version }}" context["graphql_codegen_typescript_version"] = "{{ graphql_codegen_typescript_version }}" context["graphql_codegen_typescript_operations_version"] = "{{ graphql_codegen_typescript_operations_version }}" + context["graphql_tools_mock_version"] = "{{ graphql_tools_mock_version }}" context["tailwindcss_version"] = "{{ tailwindcss_version }}" context["iconify_vue_version"] = "{{ iconify_vue_version }}" context["iconify_json_lucide_version"] = "{{ iconify_json_lucide_version }}" From c7a1bea7e9af8050386de6c0e15f0f7acf2d5a33 Mon Sep 17 00:00:00 2001 From: Eli Fine Date: Thu, 11 Dec 2025 13:47:26 +0000 Subject: [PATCH 09/28] more context --- extensions/context.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/extensions/context.py b/extensions/context.py index 945df641..a9046814 100644 --- a/extensions/context.py +++ b/extensions/context.py @@ -41,16 +41,16 @@ def hook(self, context: dict[Any, Any]) -> dict[Any, Any]: context["fastapi_offline_version"] = "1.7.4" context["uvicorn_version"] = "0.38.0" context["lab_auto_pulumi_version"] = "0.1.17" - context["ariadne_codegen_version"] = "0.17.0" + context["ariadne_codegen_version"] = ">=0.17.0" context["pytest_mock_version"] = "3.15.1" - context["uuid_utils_version"] = "0.12.0" + context["uuid_utils_version"] = ">=0.12.0" context["syrupy_version"] = "5.0.0" context["structlog_version"] = "25.5.0" context["httpx_version"] = "0.28.1" - context["python_kiota_bundle_version"] = "1.9.7" - context["vcrpy_version"] = "8.1.0" - context["pytest_recording_version"] = "0.13.4" - context["pytest_asyncio_version"] = "1.3.0" + context["python_kiota_bundle_version"] = ">=1.9.7" + context["vcrpy_version"] = ">=8.1.0" + context["pytest_recording_version"] = ">=0.13.4" + context["pytest_asyncio_version"] = ">=1.3.0" ####### context["node_version"] = "24.7.0" context["nuxt_ui_version"] = "^4.2.1" From 756a2e43db2a112a042c754ff36a3c89915955e3 Mon Sep 17 00:00:00 2001 From: Eli Fine Date: Thu, 11 Dec 2025 13:52:33 +0000 Subject: [PATCH 10/28] More fixues --- extensions/context.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/extensions/context.py b/extensions/context.py index a9046814..8f3977d5 100644 --- a/extensions/context.py +++ b/extensions/context.py @@ -36,16 +36,16 @@ def hook(self, context: dict[Any, Any]) -> dict[Any, Any]: context["pydantic_version"] = "2.12.5" context["pyinstaller_version"] = "6.17.0" context["setuptools_version"] = "80.7.1" - context["strawberry_graphql_version"] = "0.287.0" - context["fastapi_version"] = "0.124.2" - context["fastapi_offline_version"] = "1.7.4" - context["uvicorn_version"] = "0.38.0" + context["strawberry_graphql_version"] = ">=0.287.0" + context["fastapi_version"] = ">=0.124.2" + context["fastapi_offline_version"] = ">=1.7.4" + context["uvicorn_version"] = ">=0.38.0" context["lab_auto_pulumi_version"] = "0.1.17" context["ariadne_codegen_version"] = ">=0.17.0" context["pytest_mock_version"] = "3.15.1" context["uuid_utils_version"] = ">=0.12.0" - context["syrupy_version"] = "5.0.0" - context["structlog_version"] = "25.5.0" + context["syrupy_version"] = ">=5.0.0" + context["structlog_version"] = ">=25.5.0" context["httpx_version"] = "0.28.1" context["python_kiota_bundle_version"] = ">=1.9.7" context["vcrpy_version"] = ">=8.1.0" From 2c010244f2a53e81315e50244013889ad1606454 Mon Sep 17 00:00:00 2001 From: Eli Fine Date: Thu, 11 Dec 2025 14:03:55 +0000 Subject: [PATCH 11/28] codegen path --- .devcontainer/devcontainer.json | 2 +- .pre-commit-config.yaml | 10 +++++----- pyrightconfig.json | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 0fe831b6..6869992e 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -62,5 +62,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): 71b2d03b # spellchecker:disable-line + // Devcontainer context hash (do not manually edit this, it's managed by a pre-commit hook): db11d38d # spellchecker:disable-line } diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 86348a0b..67bf40d8 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -257,7 +257,7 @@ repos: files: src/.+\.py$ exclude: | (?x)^( - .*/graphql_codegen/.*| + .*/generated/graphql/.*| .*/generated/open[-_]api/.*| template/.*| )$ @@ -267,14 +267,14 @@ repos: files: tests?/.+\.py$ exclude: | (?x)^( - .*/graphql_codegen/.*| + .*/generated/graphql/.*| .*/generated/open[-_]api/.*| template/.*| )$ - id: ruff-format exclude: | (?x)^( - .*/graphql_codegen/.*| + .*/generated/graphql/.*| .*/generated/open[-_]api/.*| )$ @@ -286,7 +286,7 @@ repos: # exclude the template files---duplication within them will be discovered during CI of that template instantiation exclude: | (?x)^( - .*/graphql_codegen/.*| + .*/generated/graphql/.*| .*/generated/open[-_]api/.*| template/.*| )$ @@ -302,7 +302,7 @@ repos: files: '.+\.py$' exclude: | (?x)^( - .*/graphql_codegen/.*| + .*/generated/graphql/.*| .*/generated/open[-_]api/.*| )$ # don't pass filenames else the command line sees them twice diff --git a/pyrightconfig.json b/pyrightconfig.json index 1e26d9d5..8ce005ea 100644 --- a/pyrightconfig.json +++ b/pyrightconfig.json @@ -10,7 +10,7 @@ "**/.pipx_cache", "**/__pycache__", "**/vendor_files", - "**/graphql_codegen", + "**/generated/graphql", "**/generated/open_api", "**/.venv", "**/venv" From 76e6fb1d6ffe6d78f6dc269198521692dfd7f47f Mon Sep 17 00:00:00 2001 From: Eli Fine Date: Thu, 11 Dec 2025 14:12:16 +0000 Subject: [PATCH 12/28] node --- extensions/context.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/context.py b/extensions/context.py index 8f3977d5..b48037c6 100644 --- a/extensions/context.py +++ b/extensions/context.py @@ -52,7 +52,7 @@ def hook(self, context: dict[Any, Any]) -> dict[Any, Any]: context["pytest_recording_version"] = ">=0.13.4" context["pytest_asyncio_version"] = ">=1.3.0" ####### - context["node_version"] = "24.7.0" + context["node_version"] = "24.11.1" context["nuxt_ui_version"] = "^4.2.1" context["nuxt_version"] = "^4.2.2" context["nuxt_icon_version"] = "^2.1.0" From 30927204ae4586d16a6e43e460b1834acb87aa3a Mon Sep 17 00:00:00 2001 From: Eli Fine Date: Thu, 11 Dec 2025 15:15:38 +0000 Subject: [PATCH 13/28] question --- tests/copier_data/data1.yaml | 1 + tests/copier_data/data2.yaml | 1 + 2 files changed, 2 insertions(+) diff --git a/tests/copier_data/data1.yaml b/tests/copier_data/data1.yaml index bc5cd650..7e695e71 100644 --- a/tests/copier_data/data1.yaml +++ b/tests/copier_data/data1.yaml @@ -11,3 +11,4 @@ repo_org_name_for_copyright: The Greatest Org template_uses_javascript: false template_uses_vuejs: false template_might_want_to_install_aws_ssm_port_forwarding_plugin: true +template_might_want_to_use_vcrpy: false diff --git a/tests/copier_data/data2.yaml b/tests/copier_data/data2.yaml index 90f125a9..4e92e5f7 100644 --- a/tests/copier_data/data2.yaml +++ b/tests/copier_data/data2.yaml @@ -13,3 +13,4 @@ repo_org_name_for_copyright: Initech Corporation template_uses_javascript: true template_uses_vuejs: true template_might_want_to_install_aws_ssm_port_forwarding_plugin: false +template_might_want_to_use_vcrpy: true From 2388dd3af3278acaba5e0b567bb7460a425bb052 Mon Sep 17 00:00:00 2001 From: Eli Fine Date: Thu, 11 Dec 2025 15:17:44 +0000 Subject: [PATCH 14/28] downstream --- template/copier.yml.jinja-base | 7 ++++++- template/tests/copier_data/data1.yaml.jinja-base | 1 + template/tests/copier_data/data2.yaml.jinja-base | 1 + 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/template/copier.yml.jinja-base b/template/copier.yml.jinja-base index 963d9949..40d3abb3 100644 --- a/template/copier.yml.jinja-base +++ b/template/copier.yml.jinja-base @@ -42,7 +42,12 @@ install_aws_ssm_port_forwarding_plugin: type: bool help: Should the AWS SSM Port Forwarding Plugin be installed? default: no{% endraw %}{% endif %}{% raw %} -{% endraw %}{% if template_uses_python %} +{% endraw %}{% if template_uses_python %}{% endraw %}{% endif %}{% raw %}{% endraw %}{% if template_might_want_to_use_vcrpy %}{% raw %} +configure_vcrpy: + type: bool + help: Should VCRpy be configured for use during unit testing in Python? + default: no{% endraw %}{% endif %}{% raw %} +{% endraw %} python_version: type: str help: What version of Python is used for development? diff --git a/template/tests/copier_data/data1.yaml.jinja-base b/template/tests/copier_data/data1.yaml.jinja-base index e363d330..0f58e4f0 100644 --- a/template/tests/copier_data/data1.yaml.jinja-base +++ b/template/tests/copier_data/data1.yaml.jinja-base @@ -7,6 +7,7 @@ install_claude_cli: false ssh_port_number: 12345 use_windows_in_ci: false {% endraw %}{% if template_might_want_to_install_aws_ssm_port_forwarding_plugin %}{% raw %}install_aws_ssm_port_forwarding_plugin: true{% endraw %}{% endif %}{% raw %} +{% endraw %}{% if template_might_want_to_use_vcrpy %}{% raw %}configure_vcrpy: true{% endraw %}{% endif %}{% raw %} {% endraw %}{% if template_uses_javascript %}{% raw %} node_version: 22.13.0{% endraw %}{% endif %}{% raw %} {% endraw %}{% if template_uses_python %}{% raw %} diff --git a/template/tests/copier_data/data2.yaml.jinja-base b/template/tests/copier_data/data2.yaml.jinja-base index aa7f10e0..51712214 100644 --- a/template/tests/copier_data/data2.yaml.jinja-base +++ b/template/tests/copier_data/data2.yaml.jinja-base @@ -7,6 +7,7 @@ install_claude_cli: true ssh_port_number: 54321 use_windows_in_ci: true {% endraw %}{% if template_might_want_to_install_aws_ssm_port_forwarding_plugin %}{% raw %}install_aws_ssm_port_forwarding_plugin: false{% endraw %}{% endif %}{% raw %} +{% endraw %}{% if template_might_want_to_use_vcrpy %}{% raw %}configure_vcrpy: false{% endraw %}{% endif %}{% raw %} {% endraw %}{% if template_uses_javascript %}{% raw %} node_version: 22.14.0{% endraw %}{% endif %}{% raw %} {% endraw %}{% if template_uses_python %}{% raw %} From 460728251c0a14b70fae7a753aa9c5f1abe7e154 Mon Sep 17 00:00:00 2001 From: Eli Fine Date: Thu, 11 Dec 2025 15:20:35 +0000 Subject: [PATCH 15/28] endif --- template/copier.yml.jinja-base | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/template/copier.yml.jinja-base b/template/copier.yml.jinja-base index 40d3abb3..525cf469 100644 --- a/template/copier.yml.jinja-base +++ b/template/copier.yml.jinja-base @@ -42,7 +42,7 @@ install_aws_ssm_port_forwarding_plugin: type: bool help: Should the AWS SSM Port Forwarding Plugin be installed? default: no{% endraw %}{% endif %}{% raw %} -{% endraw %}{% if template_uses_python %}{% endraw %}{% endif %}{% raw %}{% endraw %}{% if template_might_want_to_use_vcrpy %}{% raw %} +{% endraw %}{% if template_uses_python %}{% if template_might_want_to_use_vcrpy %}{% raw %} configure_vcrpy: type: bool help: Should VCRpy be configured for use during unit testing in Python? From 63f113e278097566d48f99b8234b83c6d67a4d28 Mon Sep 17 00:00:00 2001 From: Eli Fine Date: Thu, 11 Dec 2025 15:22:21 +0000 Subject: [PATCH 16/28] fix --- copier.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/copier.yaml b/copier.yaml index 9798ee3d..19af399e 100644 --- a/copier.yaml +++ b/copier.yaml @@ -66,6 +66,12 @@ template_might_want_to_install_aws_ssm_port_forwarding_plugin: help: Is this template for something that might want the AWS SSM Port Forwarding plugin be installed? default: no +template_might_want_to_use_vcrpy: + type: bool + help: Is this template for something that might want to use VCRpy during unit testing? + default: no + when: "{{ template_uses_python }}" + _min_copier_version: "9.4" From a329aaffec30ee9295ed882bb6bbd32dcb801640 Mon Sep 17 00:00:00 2001 From: Eli Fine Date: Thu, 11 Dec 2025 15:30:58 +0000 Subject: [PATCH 17/28] fixture --- ...emplate_might_want_to_use_vcrpy %}vcrpy_fixtures.py{% endif %} | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 template/resources/{% template_might_want_to_use_vcrpy %}vcrpy_fixtures.py{% endif %} diff --git a/template/resources/{% template_might_want_to_use_vcrpy %}vcrpy_fixtures.py{% endif %} b/template/resources/{% template_might_want_to_use_vcrpy %}vcrpy_fixtures.py{% endif %} new file mode 100644 index 00000000..e69de29b From 471ef29a41a2d6bce9290552f3c68d41ba946f37 Mon Sep 17 00:00:00 2001 From: Eli Fine Date: Thu, 11 Dec 2025 15:32:08 +0000 Subject: [PATCH 18/28] contents --- ...o_use_vcrpy %}vcrpy_fixtures.py{% endif %} | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/template/resources/{% template_might_want_to_use_vcrpy %}vcrpy_fixtures.py{% endif %} b/template/resources/{% template_might_want_to_use_vcrpy %}vcrpy_fixtures.py{% endif %} index e69de29b..a6b9d621 100644 --- a/template/resources/{% template_might_want_to_use_vcrpy %}vcrpy_fixtures.py{% endif %} +++ b/template/resources/{% template_might_want_to_use_vcrpy %}vcrpy_fixtures.py{% endif %} @@ -0,0 +1,44 @@ +from typing import cast + +import pytest +from pydantic import JsonValue +from vcr import VCR +from vcr.request import Request + + +def pytest_recording_configure( + vcr: VCR, + config: pytest.Config, # noqa: ARG001 # the config argument MUST be present (even when unused) or pytest-recording throws an error +): + vcr.match_on = cast("tuple[str]", vcr.match_on) # type: ignore[reportUnknownMemberType] # I know vcr.match_on is unknown, that's why I'm casting and isinstance-ing it...not sure if there's a different approach pyright prefers + assert isinstance(vcr.match_on, tuple), ( + f"vcr.match_on is not a tuple, it is a {type(vcr.match_on)} with value {vcr.match_on}" + ) + vcr.match_on += ("body",) # body is not included by default, but it seems relevant + + def before_record_request(request: Request) -> Request | None: + request_headers_to_filter = ("User-Agent",) + for header in request_headers_to_filter: + if header in request.headers: + del request.headers[header] + + return request + + vcr.before_record_request = before_record_request + + def before_record_response(response: dict[str, JsonValue]) -> dict[str, JsonValue]: + headers_to_filter = [ + "Transfer-Encoding", + "Date", + "Server", + ] # none of these headers in the response matter for unit testing, so might as well make the cassette files smaller + headers = response["headers"] + assert isinstance(headers, dict), ( + f"Expected response['headers'] to be a dict, got {type(headers)} with value {headers}" + ) + for header in headers_to_filter: + if header in headers: + del headers[header] + return response + + vcr.before_record_response = before_record_response From b0f51b5c4b787dc1cae20eb613c7cd2d4f2ed989 Mon Sep 17 00:00:00 2001 From: Eli Fine Date: Thu, 11 Dec 2025 15:33:48 +0000 Subject: [PATCH 19/28] if --- ...mplate_might_want_to_use_vcrpy %}vcrpy_fixtures.py{% endif %}} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename template/resources/{{% template_might_want_to_use_vcrpy %}vcrpy_fixtures.py{% endif %} => {% if template_might_want_to_use_vcrpy %}vcrpy_fixtures.py{% endif %}} (100%) diff --git a/template/resources/{% template_might_want_to_use_vcrpy %}vcrpy_fixtures.py{% endif %} b/template/resources/{% if template_might_want_to_use_vcrpy %}vcrpy_fixtures.py{% endif %} similarity index 100% rename from template/resources/{% template_might_want_to_use_vcrpy %}vcrpy_fixtures.py{% endif %} rename to template/resources/{% if template_might_want_to_use_vcrpy %}vcrpy_fixtures.py{% endif %} From bc82a2b7ad1cece500135fa08b3dc42b1d1796f9 Mon Sep 17 00:00:00 2001 From: Eli Fine Date: Thu, 11 Dec 2025 15:46:52 +0000 Subject: [PATCH 20/28] tidy --- ...ht_want_to_use_vcrpy %}vcrpy_fixtures.py{% endif %} | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/template/resources/{% if template_might_want_to_use_vcrpy %}vcrpy_fixtures.py{% endif %} b/template/resources/{% if template_might_want_to_use_vcrpy %}vcrpy_fixtures.py{% endif %} index a6b9d621..ecb84a41 100644 --- a/template/resources/{% if template_might_want_to_use_vcrpy %}vcrpy_fixtures.py{% endif %} +++ b/template/resources/{% if template_might_want_to_use_vcrpy %}vcrpy_fixtures.py{% endif %} @@ -10,13 +10,17 @@ def pytest_recording_configure( vcr: VCR, config: pytest.Config, # noqa: ARG001 # the config argument MUST be present (even when unused) or pytest-recording throws an error ): - vcr.match_on = cast("tuple[str]", vcr.match_on) # type: ignore[reportUnknownMemberType] # I know vcr.match_on is unknown, that's why I'm casting and isinstance-ing it...not sure if there's a different approach pyright prefers + vcr.match_on = cast(tuple[str, ...], vcr.match_on) # pyright: ignore[reportUnknownMemberType] # I know vcr.match_on is unknown, that's why I'm casting and isinstance-ing it...not sure if there's a different approach pyright prefers assert isinstance(vcr.match_on, tuple), ( f"vcr.match_on is not a tuple, it is a {type(vcr.match_on)} with value {vcr.match_on}" ) vcr.match_on += ("body",) # body is not included by default, but it seems relevant def before_record_request(request: Request) -> Request | None: + # Skip recording any requests to our own server - let them run live + if request.host == "testserver": # pyright: ignore[reportUnknownMemberType] # new version of VCRpy has worse typing + return None + request_headers_to_filter = ("User-Agent",) for header in request_headers_to_filter: if header in request.headers: @@ -27,11 +31,11 @@ def pytest_recording_configure( vcr.before_record_request = before_record_request def before_record_response(response: dict[str, JsonValue]) -> dict[str, JsonValue]: - headers_to_filter = [ + headers_to_filter = ( "Transfer-Encoding", "Date", "Server", - ] # none of these headers in the response matter for unit testing, so might as well make the cassette files smaller + ) # none of these headers in the response matter for unit testing, so might as well make the cassette files smaller headers = response["headers"] assert isinstance(headers, dict), ( f"Expected response['headers'] to be a dict, got {type(headers)} with value {headers}" From 6a28776f41e8f40113b1b87ed774b4bde07acef0 Mon Sep 17 00:00:00 2001 From: Eli Fine Date: Thu, 11 Dec 2025 15:49:23 +0000 Subject: [PATCH 21/28] More fixture --- ...t_want_to_use_vcrpy %}vcrpy_fixtures.py{% endif %} | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/template/resources/{% if template_might_want_to_use_vcrpy %}vcrpy_fixtures.py{% endif %} b/template/resources/{% if template_might_want_to_use_vcrpy %}vcrpy_fixtures.py{% endif %} index ecb84a41..c6c49075 100644 --- a/template/resources/{% if template_might_want_to_use_vcrpy %}vcrpy_fixtures.py{% endif %} +++ b/template/resources/{% if template_might_want_to_use_vcrpy %}vcrpy_fixtures.py{% endif %} @@ -1,3 +1,4 @@ +import os from typing import cast import pytest @@ -6,6 +7,16 @@ from vcr import VCR from vcr.request import Request +@pytest.fixture(autouse=True) +def vcr_config() -> dict[str, list[str]]: + allowed_hosts: list[str] = [] + if ( + os.name == "nt" + ): # on Windows (in CI), the network calls happen at a lower level socket connection even to our FastAPI test client, and can get automatically blocked. This disables that automatic network guard, which isn't great...but since it's still in place on Linux, any actual problems would hopefully get caught before pushing to CI. + allowed_hosts = ["127.0.0.1", "localhost", "::1"] + return {"allowed_hosts": allowed_hosts} + + def pytest_recording_configure( vcr: VCR, config: pytest.Config, # noqa: ARG001 # the config argument MUST be present (even when unused) or pytest-recording throws an error From a67f70fa33a41e68d8fbce9999ca303ed51ff6d1 Mon Sep 17 00:00:00 2001 From: Eli Fine Date: Thu, 11 Dec 2025 15:59:57 +0000 Subject: [PATCH 22/28] template --- pyrightconfig.json | 3 ++- ...late_might_want_to_use_vcrpy %}vcrpy_fixtures.py{% endif %} | 0 2 files changed, 2 insertions(+), 1 deletion(-) rename template/{resources => copier_template_resources}/{% if template_might_want_to_use_vcrpy %}vcrpy_fixtures.py{% endif %} (100%) diff --git a/pyrightconfig.json b/pyrightconfig.json index 8ce005ea..10ed1516 100644 --- a/pyrightconfig.json +++ b/pyrightconfig.json @@ -13,7 +13,8 @@ "**/generated/graphql", "**/generated/open_api", "**/.venv", - "**/venv" + "**/venv", + "**/copier_template_resources" ], "strictListInference": true, "strictDictionaryInference": true, diff --git a/template/resources/{% if template_might_want_to_use_vcrpy %}vcrpy_fixtures.py{% endif %} b/template/copier_template_resources/{% if template_might_want_to_use_vcrpy %}vcrpy_fixtures.py{% endif %} similarity index 100% rename from template/resources/{% if template_might_want_to_use_vcrpy %}vcrpy_fixtures.py{% endif %} rename to template/copier_template_resources/{% if template_might_want_to_use_vcrpy %}vcrpy_fixtures.py{% endif %} From ebb35e14eaca079ec3681fb5a5837a62409acc2e Mon Sep 17 00:00:00 2001 From: Eli Fine Date: Thu, 11 Dec 2025 16:06:13 +0000 Subject: [PATCH 23/28] precommit --- .devcontainer/devcontainer.json | 2 +- .pre-commit-config.yaml | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 6869992e..36a0f529 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -62,5 +62,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): db11d38d # spellchecker:disable-line + // Devcontainer context hash (do not manually edit this, it's managed by a pre-commit hook): ce8ed462 # spellchecker:disable-line } diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 67bf40d8..a9e1bbd5 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -42,7 +42,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: 6573587991823ef75e4d6ca97fe895f45e9f14e4 # frozen: v1 + rev: 802d5794ff9cf7b15610c47eca99cd1ab757d8d4 # frozen: v1 hooks: - id: typos exclude: | @@ -108,7 +108,7 @@ repos: )$ - repo: https://github.com/rbubley/mirrors-prettier - rev: 5ba47274f9b181bce26a5150a725577f3c336011 # frozen: v3.6.2 + rev: 14abee445aea04b39069c19b4bd54efff6775819 # frozen: v3.7.4 hooks: - id: prettier # TODO: get template YAML and MD files more in line with prettier expectations so we can start using prettier on those too @@ -195,7 +195,7 @@ repos: - id: check-case-conflict - repo: https://github.com/python-jsonschema/check-jsonschema - rev: 83b816d020105076daac266dbf6bfed199a2da93 # frozen: 0.34.1 + rev: 16a6ad2fead09286ee6eb6b0a3fab55655a6c22a # frozen: 0.35.0 hooks: - id: check-github-workflows @@ -249,7 +249,7 @@ repos: description: Runs hadolint to lint Dockerfiles - repo: https://github.com/astral-sh/ruff-pre-commit - rev: 3db93a2be6f214ed722bf7bce095ec1b1715422a # frozen: v0.14.2 + rev: 1a1f58ba4c35362efe8fed2279715a905baee93d # frozen: v0.14.8 hooks: - id: ruff name: ruff-src @@ -279,7 +279,7 @@ repos: )$ - repo: https://github.com/pylint-dev/pylint - rev: 0eb92d25fd38ba5bad2f8d2ea7df63ad23e18ae3 # frozen: v4.0.2 + rev: e16f942166511d6fb4427e503a734152fae0c4fe # frozen: v4.0.4 hooks: - id: pylint name: pylint From e986f1f5647fe66d3ff9a9be9df1303ce89bbcd4 Mon Sep 17 00:00:00 2001 From: Eli Fine Date: Thu, 11 Dec 2025 16:14:28 +0000 Subject: [PATCH 24/28] extend --- ...plate_might_want_to_use_vcrpy %}vcrpy_fixtures.py{% endif %} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/template/copier_template_resources/{% if template_might_want_to_use_vcrpy %}vcrpy_fixtures.py{% endif %} b/template/copier_template_resources/{% if template_might_want_to_use_vcrpy %}vcrpy_fixtures.py{% endif %} index c6c49075..f839aa31 100644 --- a/template/copier_template_resources/{% if template_might_want_to_use_vcrpy %}vcrpy_fixtures.py{% endif %} +++ b/template/copier_template_resources/{% if template_might_want_to_use_vcrpy %}vcrpy_fixtures.py{% endif %} @@ -13,7 +13,7 @@ def vcr_config() -> dict[str, list[str]]: if ( os.name == "nt" ): # on Windows (in CI), the network calls happen at a lower level socket connection even to our FastAPI test client, and can get automatically blocked. This disables that automatic network guard, which isn't great...but since it's still in place on Linux, any actual problems would hopefully get caught before pushing to CI. - allowed_hosts = ["127.0.0.1", "localhost", "::1"] + allowed_hosts.extend(["127.0.0.1", "localhost", "::1"]) return {"allowed_hosts": allowed_hosts} From 37b2e8b813ff4612d4c6ebb3c488422bd356a6bc Mon Sep 17 00:00:00 2001 From: Eli Fine Date: Thu, 11 Dec 2025 16:17:28 +0000 Subject: [PATCH 25/28] more vcrpy --- ...ate_might_want_to_use_vcrpy %}vcrpy_fixtures.py{% endif %} | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/template/copier_template_resources/{% if template_might_want_to_use_vcrpy %}vcrpy_fixtures.py{% endif %} b/template/copier_template_resources/{% if template_might_want_to_use_vcrpy %}vcrpy_fixtures.py{% endif %} index f839aa31..183e2fd3 100644 --- a/template/copier_template_resources/{% if template_might_want_to_use_vcrpy %}vcrpy_fixtures.py{% endif %} +++ b/template/copier_template_resources/{% if template_might_want_to_use_vcrpy %}vcrpy_fixtures.py{% endif %} @@ -54,6 +54,10 @@ def pytest_recording_configure( for header in headers_to_filter: if header in headers: del headers[header] + if ( + header.lower() in headers + ): # some headers are lowercased by the server in the response (e.g. Date, Server) + del headers[header.lower()] return response vcr.before_record_response = before_record_response From 5a5d0bd1968174d035e3c1cfe11eb009f071dacc Mon Sep 17 00:00:00 2001 From: Eli Fine Date: Thu, 11 Dec 2025 16:25:57 +0000 Subject: [PATCH 26/28] better hosts --- ...o_use_vcrpy %}vcrpy_fixtures.py{% endif %} | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/template/copier_template_resources/{% if template_might_want_to_use_vcrpy %}vcrpy_fixtures.py{% endif %} b/template/copier_template_resources/{% if template_might_want_to_use_vcrpy %}vcrpy_fixtures.py{% endif %} index 183e2fd3..8b97df90 100644 --- a/template/copier_template_resources/{% if template_might_want_to_use_vcrpy %}vcrpy_fixtures.py{% endif %} +++ b/template/copier_template_resources/{% if template_might_want_to_use_vcrpy %}vcrpy_fixtures.py{% endif %} @@ -6,15 +6,20 @@ from pydantic import JsonValue from vcr import VCR from vcr.request import Request +ALLOWED_HOSTS = ["testserver"] # Skip recording any requests to our own server - let them run live + +CUSTOM_ALLOWED_HOSTS: tuple[str, ...] = () + +ALLOWED_HOSTS.extend(CUSTOM_ALLOWED_HOSTS) +if ( + os.name == "nt" +): # on Windows (in CI), the network calls happen at a lower level socket connection even to our FastAPI test client, and can get automatically blocked. This disables that automatic network guard, which isn't great...but since it's still in place on Linux, any actual problems would hopefully get caught before pushing to CI. + ALLOWED_HOSTS.extend(["127.0.0.1", "localhost", "::1"]) + @pytest.fixture(autouse=True) def vcr_config() -> dict[str, list[str]]: - allowed_hosts: list[str] = [] - if ( - os.name == "nt" - ): # on Windows (in CI), the network calls happen at a lower level socket connection even to our FastAPI test client, and can get automatically blocked. This disables that automatic network guard, which isn't great...but since it's still in place on Linux, any actual problems would hopefully get caught before pushing to CI. - allowed_hosts.extend(["127.0.0.1", "localhost", "::1"]) - return {"allowed_hosts": allowed_hosts} + return {"allowed_hosts": ALLOWED_HOSTS} def pytest_recording_configure( @@ -28,10 +33,6 @@ def pytest_recording_configure( vcr.match_on += ("body",) # body is not included by default, but it seems relevant def before_record_request(request: Request) -> Request | None: - # Skip recording any requests to our own server - let them run live - if request.host == "testserver": # pyright: ignore[reportUnknownMemberType] # new version of VCRpy has worse typing - return None - request_headers_to_filter = ("User-Agent",) for header in request_headers_to_filter: if header in request.headers: From 90f9ebde4df216049c65260285eaeee054f2d81c Mon Sep 17 00:00:00 2001 From: Eli Fine Date: Thu, 11 Dec 2025 16:36:27 +0000 Subject: [PATCH 27/28] more error --- .devcontainer/devcontainer.json | 2 +- .devcontainer/windows-host-helper.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 36a0f529..3f826879 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -62,5 +62,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): ce8ed462 # spellchecker:disable-line + // Devcontainer context hash (do not manually edit this, it's managed by a pre-commit hook): 5b56d8b0 # spellchecker:disable-line } diff --git a/.devcontainer/windows-host-helper.sh b/.devcontainer/windows-host-helper.sh index 8624e443..a071d4f7 100644 --- a/.devcontainer/windows-host-helper.sh +++ b/.devcontainer/windows-host-helper.sh @@ -7,7 +7,7 @@ # If you're still having issues, make sure in Windows Developer Settings that you enabled Developer Mode, and also that you set your git config to have `core.autocrlf=false` and `core.symlinks=true` globally -set -e # Exit immediately on error +set -euo pipefail # Exit immediately on error if [ -z "$BASH_VERSION" ]; then echo "Error: This script must be run with bash (e.g., 'bash windows-host-helper.sh')." >&2 From 085bdbaf19b5800fba6d3adb226021434d9b114f Mon Sep 17 00:00:00 2001 From: Eli Fine Date: Thu, 11 Dec 2025 16:40:48 +0000 Subject: [PATCH 28/28] filter --- ...want_to_use_vcrpy %}vcrpy_fixtures.py{% endif %} | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/template/copier_template_resources/{% if template_might_want_to_use_vcrpy %}vcrpy_fixtures.py{% endif %} b/template/copier_template_resources/{% if template_might_want_to_use_vcrpy %}vcrpy_fixtures.py{% endif %} index 8b97df90..065f9bdc 100644 --- a/template/copier_template_resources/{% if template_might_want_to_use_vcrpy %}vcrpy_fixtures.py{% endif %} +++ b/template/copier_template_resources/{% if template_might_want_to_use_vcrpy %}vcrpy_fixtures.py{% endif %} @@ -4,7 +4,6 @@ from typing import cast import pytest from pydantic import JsonValue from vcr import VCR -from vcr.request import Request ALLOWED_HOSTS = ["testserver"] # Skip recording any requests to our own server - let them run live @@ -19,7 +18,7 @@ if ( @pytest.fixture(autouse=True) def vcr_config() -> dict[str, list[str]]: - return {"allowed_hosts": ALLOWED_HOSTS} + return {"allowed_hosts": ALLOWED_HOSTS, "filter_headers": ["User-Agent"]} def pytest_recording_configure( @@ -32,16 +31,6 @@ def pytest_recording_configure( ) vcr.match_on += ("body",) # body is not included by default, but it seems relevant - def before_record_request(request: Request) -> Request | None: - request_headers_to_filter = ("User-Agent",) - for header in request_headers_to_filter: - if header in request.headers: - del request.headers[header] - - return request - - vcr.before_record_request = before_record_request - def before_record_response(response: dict[str, JsonValue]) -> dict[str, JsonValue]: headers_to_filter = ( "Transfer-Encoding",