From 700c99a918a7e63d0b5b46b01c7b4edd70f4e216 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dean=20Qui=C3=B1anola?= Date: Tue, 28 Apr 2026 11:31:56 -0700 Subject: [PATCH 1/5] feat(constants): add Python 3.13 to SUPPORTED_PYTHON_VERSIONS Collapse GPU_PYTHON_VERSIONS and CPU_PYTHON_VERSIONS into a single SUPPORTED_PYTHON_VERSIONS tuple now that flash-worker publishes native per-version images for all four image types uniformly. The two old names remain as aliases for any downstream callers. DEFAULT_PYTHON_VERSION stays at 3.12 -- it drives the :latest tag aliases, not SDK behavior. Drops the unused WORKER_PYTHON_VERSION and GPU_BASE_IMAGE_PYTHON_VERSION constants. Updates test_live_serverless.py to use SUPPORTED_PYTHON_VERSIONS parametrization, and updates two tests that used "3.13" as the example unsupported version (now use "3.14"). Refs AE-2827. --- src/runpod_flash/core/resources/constants.py | 26 +++++++++---------- .../runtime/resource_provisioner.py | 5 ++-- tests/unit/core/resources/test_constants.py | 23 ++++++++++------ tests/unit/resources/test_live_serverless.py | 15 ++++++----- tests/unit/resources/test_serverless.py | 2 +- 5 files changed, 40 insertions(+), 31 deletions(-) diff --git a/src/runpod_flash/core/resources/constants.py b/src/runpod_flash/core/resources/constants.py index 188a2567..9b46390d 100644 --- a/src/runpod_flash/core/resources/constants.py +++ b/src/runpod_flash/core/resources/constants.py @@ -1,20 +1,20 @@ import os -# Worker runtime Python versions. One tarball serves every resource in an app, -# so all resources must share a single Python version. GPU images ship 3.12 -# with torch pre-installed; 3.10 and 3.11 are available via side-by-side -# install (~7 GB alt-Python overhead) in the same base image. -WORKER_PYTHON_VERSION: str = "3.12" -GPU_PYTHON_VERSIONS: tuple[str, ...] = ("3.10", "3.11", "3.12") -CPU_PYTHON_VERSIONS: tuple[str, ...] = ("3.10", "3.11", "3.12") - -# Base image ships 3.12 with torch pre-installed; non-3.12 targets reinstall -# torch side-by-side for the selected interpreter. -GPU_BASE_IMAGE_PYTHON_VERSION: str = "3.12" +# Single source of truth for Python versions Flash supports end-to-end. +# Phase 1 of AE-2827 publishes native per-version worker images for each. +SUPPORTED_PYTHON_VERSIONS: tuple[str, ...] = ("3.10", "3.11", "3.12", "3.13") + +# DEFAULT_PYTHON_VERSION drives the :latest tag aliases on Docker Hub +# (runpod/flash:latest -> runpod/flash:py3.12-latest). It is NOT a fallback +# the SDK reaches for — _reconcile_python_version uses sys.version_info +# when no override or per-resource declaration is set. DEFAULT_PYTHON_VERSION: str = "3.12" -# Python versions that can run the flash SDK locally (for flash build, etc.) -SUPPORTED_PYTHON_VERSIONS: tuple[str, ...] = ("3.10", "3.11", "3.12") +# Per-image-type Python sets are now uniform — native per-version images +# cover GPU and CPU equally. Aliased to SUPPORTED_PYTHON_VERSIONS for any +# downstream callers that still reference the old names. +GPU_PYTHON_VERSIONS: tuple[str, ...] = SUPPORTED_PYTHON_VERSIONS +CPU_PYTHON_VERSIONS: tuple[str, ...] = SUPPORTED_PYTHON_VERSIONS def local_python_version() -> str: diff --git a/src/runpod_flash/runtime/resource_provisioner.py b/src/runpod_flash/runtime/resource_provisioner.py index 981a234b..e10935f6 100644 --- a/src/runpod_flash/runtime/resource_provisioner.py +++ b/src/runpod_flash/runtime/resource_provisioner.py @@ -124,8 +124,9 @@ def create_resource_from_manifest( deployment_kwargs = {"name": prefixed_name, "env": env} # Use per-resource target_python_version (set by manifest builder based on - # resource type: GPU uses GPU_BASE_IMAGE_PYTHON_VERSION, CPU uses DEFAULT). - # Falls back to the caller-provided python_version for backward compatibility. + # the resource's declared python_version, or DEFAULT_PYTHON_VERSION when + # not specified). Falls back to the caller-provided python_version for + # backward compatibility. effective_python_version = ( resource_data.get("target_python_version") or python_version ) diff --git a/tests/unit/core/resources/test_constants.py b/tests/unit/core/resources/test_constants.py index 6384c6a4..a23b24ef 100644 --- a/tests/unit/core/resources/test_constants.py +++ b/tests/unit/core/resources/test_constants.py @@ -8,7 +8,6 @@ from runpod_flash.core.resources.constants import ( CPU_PYTHON_VERSIONS, DEFAULT_PYTHON_VERSION, - GPU_BASE_IMAGE_PYTHON_VERSION, GPU_PYTHON_VERSIONS, SUPPORTED_PYTHON_VERSIONS, get_image_name, @@ -19,19 +18,27 @@ class TestSupportedPythonVersions: def test_supported_versions(self): - assert SUPPORTED_PYTHON_VERSIONS == ("3.10", "3.11", "3.12") + assert SUPPORTED_PYTHON_VERSIONS == ("3.10", "3.11", "3.12", "3.13") def test_gpu_python_versions(self): - assert GPU_PYTHON_VERSIONS == ("3.10", "3.11", "3.12") + assert GPU_PYTHON_VERSIONS == ("3.10", "3.11", "3.12", "3.13") def test_cpu_python_versions(self): - assert CPU_PYTHON_VERSIONS == ("3.10", "3.11", "3.12") + assert CPU_PYTHON_VERSIONS == ("3.10", "3.11", "3.12", "3.13") def test_default_python_version_is_3_12(self): assert DEFAULT_PYTHON_VERSION == "3.12" - def test_gpu_base_image_python_version(self): - assert GPU_BASE_IMAGE_PYTHON_VERSION == "3.12" + def test_supported_python_versions_contains_310_through_313(self): + from runpod_flash.core.resources.constants import SUPPORTED_PYTHON_VERSIONS + + assert SUPPORTED_PYTHON_VERSIONS == ("3.10", "3.11", "3.12", "3.13") + + def test_default_python_version_unchanged_for_latest_alias(self): + """DEFAULT_PYTHON_VERSION drives the :latest tag alias, not SDK fallback.""" + from runpod_flash.core.resources.constants import DEFAULT_PYTHON_VERSION + + assert DEFAULT_PYTHON_VERSION == "3.12" class TestGetImageName: @@ -82,7 +89,7 @@ def test_invalid_image_type_raises(self): def test_invalid_python_version_raises(self): with pytest.raises(ValueError, match="not supported"): - get_image_name("gpu", "3.13") + get_image_name("gpu", "3.14") def test_custom_tag(self): assert get_image_name("gpu", "3.12", tag="v2.0") == "runpod/flash:py3.12-v2.0" @@ -128,7 +135,7 @@ def test_valid_versions(self): def test_invalid_version_raises(self): with pytest.raises(ValueError, match="not supported"): - validate_python_version("3.13") + validate_python_version("3.14") def test_old_version_raises(self): with pytest.raises(ValueError, match="not supported"): diff --git a/tests/unit/resources/test_live_serverless.py b/tests/unit/resources/test_live_serverless.py index 4dfeb929..87b00e5d 100644 --- a/tests/unit/resources/test_live_serverless.py +++ b/tests/unit/resources/test_live_serverless.py @@ -4,7 +4,8 @@ import pytest from runpod_flash.core.resources.constants import ( - GPU_BASE_IMAGE_PYTHON_VERSION, + DEFAULT_PYTHON_VERSION, + SUPPORTED_PYTHON_VERSIONS, ) from runpod_flash.core.resources.cpu import CpuInstanceType from runpod_flash.core.resources.live_serverless import ( @@ -223,14 +224,14 @@ class TestLiveServerlessPythonVersion: def test_gpu_default_image_uses_gpu_base_python(self): ls = LiveServerless(name="test") - assert f"py{GPU_BASE_IMAGE_PYTHON_VERSION}" in ls.imageName + assert f"py{DEFAULT_PYTHON_VERSION}" in ls.imageName - @pytest.mark.parametrize("version", ["3.10", "3.11", "3.12"]) + @pytest.mark.parametrize("version", list(SUPPORTED_PYTHON_VERSIONS)) def test_gpu_explicit_supported_versions(self, version): ls = LiveServerless(name="test", python_version=version) assert f"py{version}" in ls.imageName - @pytest.mark.parametrize("version", ["3.10", "3.11", "3.12"]) + @pytest.mark.parametrize("version", list(SUPPORTED_PYTHON_VERSIONS)) def test_cpu_explicit_supported_versions(self, version): ls = CpuLiveServerless(name="test", python_version=version) assert f"py{version}" in ls.imageName @@ -250,16 +251,16 @@ class TestLiveLoadBalancerPythonVersion: def test_lb_default_image_uses_gpu_base_python(self): lb = LiveLoadBalancer(name="test") - assert f"py{GPU_BASE_IMAGE_PYTHON_VERSION}" in lb.imageName + assert f"py{DEFAULT_PYTHON_VERSION}" in lb.imageName assert "runpod/flash-lb:" in lb.imageName - @pytest.mark.parametrize("version", ["3.10", "3.11", "3.12"]) + @pytest.mark.parametrize("version", list(SUPPORTED_PYTHON_VERSIONS)) def test_lb_explicit_supported_versions(self, version): lb = LiveLoadBalancer(name="test", python_version=version) assert f"py{version}" in lb.imageName assert "runpod/flash-lb:" in lb.imageName - @pytest.mark.parametrize("version", ["3.10", "3.11", "3.12"]) + @pytest.mark.parametrize("version", list(SUPPORTED_PYTHON_VERSIONS)) def test_cpu_lb_explicit_supported_versions(self, version): lb = CpuLiveLoadBalancer(name="test", python_version=version) assert f"py{version}" in lb.imageName diff --git a/tests/unit/resources/test_serverless.py b/tests/unit/resources/test_serverless.py index 366d29f3..5341261e 100644 --- a/tests/unit/resources/test_serverless.py +++ b/tests/unit/resources/test_serverless.py @@ -2429,7 +2429,7 @@ def test_python_version_accepts_valid_values(self): def test_python_version_rejects_invalid(self): with pytest.raises(ValueError, match="not supported"): ServerlessEndpoint( - name="test", imageName="test:latest", python_version="3.13" + name="test", imageName="test:latest", python_version="3.14" ) def test_python_version_rejects_3_9(self): From 2af8b239fddeee7fb9af0c9d746b362db451eb30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dean=20Qui=C3=B1anola?= Date: Tue, 28 Apr 2026 11:46:47 -0700 Subject: [PATCH 2/5] feat(build): match local Python version by default Change _reconcile_python_version to use sys.version_info as the resolution default when no --python-version override and no per-resource python_version declaration is set. Eliminates forced cloudpickle drift between the user's local interpreter and the deployed worker. Resolution order: 1. CLI --python-version override (validated) 2. Single distinct python_version declared across resources (validated) 3. Local sys.version_info (validated against SUPPORTED_PYTHON_VERSIONS) A local interpreter outside the supported set raises a clear error pointing at the override flag and per-resource declaration paths -- no silent downgrade to 3.12. Refs AE-2827. BREAKING CHANGE: Projects that previously deployed to Python 3.12 by default (via the SDK's hardcoded fallback) now deploy to whichever Python the user is running flash from. The first deploy after upgrading will trigger a rolling release because the manifest fingerprint changes when target_python_version flips. Teams that want lockstep behavior across team members and CI should declare python_version explicitly on each resource config. --- .../cli/commands/build_utils/manifest.py | 33 +++++--- .../cli/commands/build_utils/test_manifest.py | 81 +++++++++++++++++-- 2 files changed, 98 insertions(+), 16 deletions(-) diff --git a/src/runpod_flash/cli/commands/build_utils/manifest.py b/src/runpod_flash/cli/commands/build_utils/manifest.py index 87cd0975..32f19e0a 100644 --- a/src/runpod_flash/cli/commands/build_utils/manifest.py +++ b/src/runpod_flash/cli/commands/build_utils/manifest.py @@ -10,7 +10,7 @@ from typing import Any, Dict, List, Optional from runpod_flash.core.resources.constants import ( - DEFAULT_PYTHON_VERSION, + SUPPORTED_PYTHON_VERSIONS, validate_python_version, ) @@ -321,18 +321,23 @@ def _extract_config_properties(config: Dict[str, Any], resource_config) -> None: def _reconcile_python_version( self, resources_dict: Dict[str, Dict[str, Any]] ) -> str: - """Pick one Python version for the app from per-resource declarations. + """Pick one Python version for the app. Flash apps ship as a single tarball, so every resource must target the same Python ABI. Resolution order: 1. Explicit override passed to ManifestBuilder (validated) 2. Exactly one distinct ``python_version`` declared across resources - 3. ``DEFAULT_PYTHON_VERSION`` when no resource declares one + 3. The local interpreter (``sys.version_info``) — the user's + environment is the source of truth when nothing else is declared. + + There is no fallback to a hardcoded default. A local interpreter + outside ``SUPPORTED_PYTHON_VERSIONS`` raises an actionable error. Raises: - ValueError: When resources declare conflicting ``python_version`` - values, or when the override conflicts with a resource's - explicit declaration. + ValueError: when resources declare conflicting ``python_version`` + values; when the override conflicts with a resource's explicit + declaration; or when the local interpreter is unsupported and + no override or declaration was provided. """ per_resource: Dict[str, str] = { name: r["python_version"] @@ -366,14 +371,24 @@ def _reconcile_python_version( raise ValueError( "Flash apps require one python_version across all resources " f"(found {sorted(distinct)}): {details}. Set python_version to the " - "same value on every resource, or omit it to use the default " - f"({DEFAULT_PYTHON_VERSION})." + "same value on every resource, pass --python-version, or run " + "flash from a single-version interpreter." ) if distinct: return validate_python_version(next(iter(distinct))) - return DEFAULT_PYTHON_VERSION + # Match the user's local interpreter — parity, not policy. + local = f"{sys.version_info.major}.{sys.version_info.minor}" + if local not in SUPPORTED_PYTHON_VERSIONS: + supported = ", ".join(SUPPORTED_PYTHON_VERSIONS) + raise ValueError( + f"Local Python {local} is not supported by Flash workers " + f"(supported: {supported}). Pass --python-version, declare " + f"python_version on a resource config, or run flash from a " + f"supported interpreter." + ) + return local def build(self) -> Dict[str, Any]: """Build the manifest dictionary. diff --git a/tests/unit/cli/commands/build_utils/test_manifest.py b/tests/unit/cli/commands/build_utils/test_manifest.py index 3a86c121..c1572caa 100644 --- a/tests/unit/cli/commands/build_utils/test_manifest.py +++ b/tests/unit/cli/commands/build_utils/test_manifest.py @@ -944,13 +944,13 @@ def test_manifest_includes_python_version(): ) ] - builder = ManifestBuilder("test_app", functions) + # Explicit override avoids depending on the runner's local interpreter, + # which is the new resolution default after AE-2827. + builder = ManifestBuilder("test_app", functions, python_version="3.12") manifest = builder.build() assert "python_version" in manifest - from runpod_flash.core.resources.constants import DEFAULT_PYTHON_VERSION - - assert manifest["python_version"] == DEFAULT_PYTHON_VERSION + assert manifest["python_version"] == "3.12" def test_manifest_uses_explicit_python_version(): @@ -1000,13 +1000,21 @@ class TestReconcilePythonVersion: def _builder(self, python_version: Optional[str] = None) -> ManifestBuilder: return ManifestBuilder("test_app", [], python_version=python_version) - def test_no_resources_declare_version_uses_default(self): - from runpod_flash.core.resources.constants import DEFAULT_PYTHON_VERSION + def test_no_resources_no_override_uses_local_interpreter(self, monkeypatch): + """With no override and no declaration, reconcile reads sys.version_info.""" + + class _StubVersionInfo: + pass + + info = _StubVersionInfo() + info.major = 3 + info.minor = 11 + monkeypatch.setattr(sys, "version_info", info) resolved = self._builder()._reconcile_python_version( _make_resources_dict(gpu=None, cpu=None) ) - assert resolved == DEFAULT_PYTHON_VERSION + assert resolved == "3.11" def test_single_declared_version_wins(self): resolved = self._builder()._reconcile_python_version( @@ -1053,3 +1061,62 @@ def test_unsupported_override_raises(self): def test_unsupported_resource_version_raises(self): with pytest.raises(ValueError, match="not supported"): self._builder()._reconcile_python_version(_make_resources_dict(gpu="3.8")) + + +class TestReconcileLocalInterpreter: + """Tests for AE-2827 match-local default in _reconcile_python_version.""" + + def _builder(self, python_version: Optional[str] = None) -> ManifestBuilder: + return ManifestBuilder("test_app", [], python_version=python_version) + + def _stub_version_info(self, monkeypatch, major: int, minor: int): + class _StubVersionInfo: + pass + + info = _StubVersionInfo() + info.major = major + info.minor = minor + monkeypatch.setattr(sys, "version_info", info) + + @pytest.mark.parametrize( + "major,minor,expected", + [ + (3, 10, "3.10"), + (3, 11, "3.11"), + (3, 12, "3.12"), + (3, 13, "3.13"), + ], + ) + def test_resolves_to_local_when_no_override_or_declaration( + self, monkeypatch, major, minor, expected + ): + self._stub_version_info(monkeypatch, major, minor) + resolved = self._builder()._reconcile_python_version( + _make_resources_dict(gpu=None, cpu=None) + ) + assert resolved == expected + + @pytest.mark.parametrize("major,minor", [(3, 9), (3, 14)]) + def test_raises_when_local_is_unsupported(self, monkeypatch, major, minor): + self._stub_version_info(monkeypatch, major, minor) + with pytest.raises(ValueError, match="Local Python") as excinfo: + self._builder()._reconcile_python_version( + _make_resources_dict(gpu=None, cpu=None) + ) + message = str(excinfo.value) + assert f"{major}.{minor}" in message + assert "--python-version" in message + + def test_local_does_not_shadow_override(self, monkeypatch): + self._stub_version_info(monkeypatch, 3, 10) + resolved = self._builder("3.12")._reconcile_python_version( + _make_resources_dict(gpu=None, cpu=None) + ) + assert resolved == "3.12" + + def test_local_does_not_shadow_declaration(self, monkeypatch): + self._stub_version_info(monkeypatch, 3, 13) + resolved = self._builder()._reconcile_python_version( + _make_resources_dict(gpu="3.11", cpu=None) + ) + assert resolved == "3.11" From 345fc852ccfe80438dad2d61d69888c5e2235581 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dean=20Qui=C3=B1anola?= Date: Tue, 28 Apr 2026 11:54:04 -0700 Subject: [PATCH 3/5] feat(build): print resolved Python version at build time Surface the chosen Python version and its source on a single line during flash build, so users see the parity decision without inspecting the manifest. Source is one of: - "--python-version override" - "declared on resource " - "matched local interpreter" Refs AE-2827. --- src/runpod_flash/cli/commands/build.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/runpod_flash/cli/commands/build.py b/src/runpod_flash/cli/commands/build.py index 2146ad31..a183428d 100644 --- a/src/runpod_flash/cli/commands/build.py +++ b/src/runpod_flash/cli/commands/build.py @@ -263,6 +263,28 @@ def _resolve_pip_python_version(manifest: dict) -> str | None: return max(versions) +def _python_version_source(override: str | None, resources_dict: dict) -> str: + """Return a human-readable source string for the resolved Python version. + + Used at build time to surface where the resolved version came from: + explicit override, per-resource declaration, or local interpreter match. + """ + if override: + return "--python-version override" + declared = { + name: r["python_version"] + for name, r in resources_dict.items() + if r.get("python_version") + } + if declared: + # All declared values are identical at this point — reconcile would + # have raised otherwise — so report the lexicographically-first + # resource name for stability. + name = next(iter(sorted(declared))) + return f"declared on resource {name}" + return "matched local interpreter" + + def run_build( project_dir: Path, app_name: str, @@ -339,6 +361,10 @@ def run_build( python_version=manifest_python_version_override, ) manifest = manifest_builder.build() + console.print( + f"[dim]targeting Python {manifest_builder.python_version} " + f"({_python_version_source(manifest_python_version_override, manifest.get('resources', {}))})[/dim]" + ) manifest["source_fingerprint"] = compute_source_fingerprint( project_dir, files ) From 3e26e0635a5be5a6d25d9e00b4bd4bf1c1dea2c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dean=20Qui=C3=B1anola?= Date: Tue, 28 Apr 2026 11:57:45 -0700 Subject: [PATCH 4/5] docs(deploy-guide): rewrite Python version section for parity-by-default MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Lead with the parity contract (local Python = deploy target), document the bounded {3.10..3.13} support set, document the override and per-resource declaration paths, and call out the team-consistency recommendation. Drop the side-by-side / 7 GB cold-start callouts — no longer accurate after the worker image rearchitecture. Refs AE-2827. --- docs/Flash_Deploy_Guide.md | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/docs/Flash_Deploy_Guide.md b/docs/Flash_Deploy_Guide.md index c2dc3162..20d84d9c 100644 --- a/docs/Flash_Deploy_Guide.md +++ b/docs/Flash_Deploy_Guide.md @@ -6,22 +6,26 @@ This guide walks through deploying a Flash application from local development to ## Prerequisites -- Python 3.10, 3.11, or 3.12 +- Python 3.10, 3.11, 3.12, or 3.13 - `pip install runpod-flash` - A Runpod account with API key ([get one here](https://docs.runpod.io/get-started/api-keys)) ### Python version selection -Flash apps ship as a single tarball, so every resource in an app shares one Python version. The worker runtime defaults to 3.12 (the version torch is pre-installed for in the GPU base image). Select a different version in two ways: +Flash workers support Python 3.10, 3.11, 3.12, and 3.13. Native per-version images mean each interpreter has torch, numpy, and the worker runtime built directly for it — no side-by-side overhead, no cold-start tax for non-default versions. -- **Per-resource declaration**: set `python_version="3.11"` on any resource config — all resources in the same app must agree or leave it unset. -- **App-level override**: pass `--python-version 3.11` to `flash build` or `flash deploy`. The override wins over per-resource values that are unset and must match any that are set. +By default, `flash build` and `flash deploy` target the Python version you're running flash from. If you're on 3.11 locally, your deploy runs on 3.11; on 3.13, it runs on 3.13. The build prints the resolved version and its source on the first line of output. -| Version | Status | GPU cold-start | Notes | -|---------|--------|----------------|-------| -| 3.10 | Supported (EOL 2026-10-31) | +~7 GB alt-Python install | Consider migrating to 3.11 before EOL | -| 3.11 | Supported | +~7 GB alt-Python install | | -| 3.12 | Supported (default) | No overhead | Torch pre-installed in base image | +You can override the choice in two ways: + +- **CLI flag:** `flash build --python-version 3.12` or `flash deploy --python-version 3.12`. Validated against the supported set. +- **Per-resource declaration:** set `python_version="3.12"` on any `LiveServerless`, `CpuLiveServerless`, `LiveLoadBalancer`, or `CpuLiveLoadBalancer` config. The build reconciles to the declared value (or raises if resources disagree). + +For projects shared across a team, declare `python_version` explicitly on each resource config. That makes the deploy result identical regardless of who runs `flash build` and what Python they happen to have installed locally — useful when team members and CI run different interpreters. + +Flash will refuse to build if your local Python is outside the supported set (e.g. 3.9 or 3.14). The error message tells you to pass `--python-version`, declare on a resource, or upgrade your interpreter. + +The `runpod/flash:latest`, `runpod/flash-lb:latest`, `runpod/flash-cpu:latest`, and `runpod/flash-lb-cpu:latest` aliases all point at the 3.12 image variant — Dockerfiles or compose files that pin `:latest` will keep getting 3.12. Use the `:py3.X-{tag}` form for explicit version pinning. ## Quick Start From 3b6e212f6a2c526c80eb5d2a0118644101de80a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dean=20Qui=C3=B1anola?= Date: Tue, 28 Apr 2026 12:01:44 -0700 Subject: [PATCH 5/5] docs(cli): document parity-by-default and 3.13 in --python-version help Phase 3 of AE-2827. Updates the Options bullet for --python-version on both flash build and flash deploy docs to reflect the new behavior: local interpreter is the default; 3.13 is now in the supported set. Refs AE-2827. --- src/runpod_flash/cli/docs/flash-build.md | 8 ++++---- src/runpod_flash/cli/docs/flash-deploy.md | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/runpod_flash/cli/docs/flash-build.md b/src/runpod_flash/cli/docs/flash-build.md index 0798e0de..baaddc64 100644 --- a/src/runpod_flash/cli/docs/flash-build.md +++ b/src/runpod_flash/cli/docs/flash-build.md @@ -28,7 +28,7 @@ flash build [OPTIONS] - `--no-deps`: Skip transitive dependencies during pip install (default: false) - `--output, -o`: Custom archive name (default: artifact.tar.gz) - `--exclude`: Comma-separated packages to exclude (e.g., 'torch,torchvision') -- `--python-version`: Target Python version for worker images (`3.10`, `3.11`, or `3.12`). Overrides per-resource `python_version`. Default: value declared on resource configs, or 3.12 if none set. +- `--python-version`: Target Python version for worker images (`3.10`, `3.11`, `3.12`, or `3.13`). Overrides per-resource `python_version` declarations and the local-interpreter default. By default, `flash build` targets the Python version you're running flash from. To launch a local preview environment, use `flash deploy --preview` instead. @@ -68,7 +68,7 @@ After `flash build` completes: Flash automatically handles cross-platform builds, ensuring compatibility with Runpod's Linux x86_64 serverless infrastructure: - **Automatic Platform Targeting**: Dependencies are always installed for Linux x86_64, regardless of your build platform (macOS, Windows, or Linux) -- **Python Version**: Targets Python 3.12 for wheel ABI selection regardless of local interpreter +- **Python Version**: Targets the resolved Python version (your local interpreter by default, or whatever `--python-version` / per-resource `python_version` selects) for wheel ABI selection - **Binary Wheel Enforcement**: Only pre-built binary wheels are used, preventing platform-specific compilation issues This means you can safely build on macOS ARM64, Windows, or any platform, and the deployment will work correctly on Runpod. @@ -181,8 +181,8 @@ ls .flash/.build/my-project/ If a package doesn't have pre-built Linux x86_64 wheels: 1. **Install standard pip**: `python -m ensurepip --upgrade` -- standard pip has better manylinux compatibility than uv pip -2. **Check package availability**: Visit PyPI and verify the package has Linux wheels for Python 3.12 -3. **Python 3.12**: All flash workers run Python 3.12. Ensure packages are available for this version. +2. **Check package availability**: Visit PyPI and verify the package has Linux wheels for your target Python version (`3.10`, `3.11`, `3.12`, or `3.13`) +3. **Match interpreter**: Flash builds default to your local Python version. If a wheel is missing for that version, either pick a different `--python-version` or upgrade/downgrade the package. 4. **Pure-Python packages**: These work regardless, as they don't require platform-specific builds ## Managing Deployment Size diff --git a/src/runpod_flash/cli/docs/flash-deploy.md b/src/runpod_flash/cli/docs/flash-deploy.md index ef2c288a..24bcafde 100644 --- a/src/runpod_flash/cli/docs/flash-deploy.md +++ b/src/runpod_flash/cli/docs/flash-deploy.md @@ -88,7 +88,7 @@ flash deploy [OPTIONS] - `--exclude`: Comma-separated packages to exclude (e.g., 'torch,torchvision') - `--output, -o`: Custom archive name (default: artifact.tar.gz) - `--preview`: Build and launch local preview environment instead of deploying -- `--python-version`: Target Python version for worker images (`3.10`, `3.11`, or `3.12`). Overrides per-resource `python_version`. +- `--python-version`: Target Python version for worker images (`3.10`, `3.11`, `3.12`, or `3.13`). Overrides per-resource `python_version` declarations and the local-interpreter default. By default, `flash deploy` targets the Python version you're running flash from. ## Examples