Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion release-please-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@
{"type": "ci", "section": "Continuous Integration", "hidden": true},
{"type": "chore", "section": "Miscellaneous", "hidden": true}
],
"pull-request-title-pattern": "chore: release ${version}"
"pull-request-title-pattern": "chore: release ${version}",
"extra-files": [
"src/runpod_flash/__init__.py"
]
}
}
}
2 changes: 2 additions & 0 deletions src/runpod_flash/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
__version__ = "1.4.1" # x-release-please-version

# Load .env vars from file before everything else
from dotenv import load_dotenv

Expand Down
98 changes: 51 additions & 47 deletions src/runpod_flash/cli/commands/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,50 +56,56 @@
PIP_MODULE = "pip"


def _find_local_runpod_flash() -> Optional[Path]:
"""Find local runpod_flash source directory if available.
def _find_runpod_flash(project_dir: Optional[Path] = None) -> Optional[Path]:
"""Find installed runpod_flash package directory.

Tries two strategies:
1. importlib.util.find_spec -- works for any installed runpod_flash
(dev-installed or site-packages)
2. Relative path search -- walks upward from project_dir looking for a sibling
flash repo (worktree or standard layout)

Args:
project_dir: Flash project directory, used for relative path search fallback

Returns:
Path to runpod_flash package directory, or None if not found or installed from PyPI
Path to runpod_flash package directory, or None if not found
"""
# Strategy 1: importlib (any installed runpod_flash -- dev or site-packages)
try:
spec = importlib.util.find_spec("runpod_flash")
if spec and spec.origin:
return Path(spec.origin).parent
except Exception:
pass

if not spec or not spec.origin:
return None

# Get package directory (spec.origin is __init__.py path)
pkg_dir = Path(spec.origin).parent

# Skip if installed in site-packages (PyPI install)
if "site-packages" in str(pkg_dir):
return None
# Strategy 2: search upward from project_dir for flash repo
if project_dir is None:
return None

# Must be development install
return pkg_dir
current = project_dir.resolve()
for _ in range(6):
# Worktree layout: flash-project/flash/main/src/runpod_flash/
# Standard layout: flash-project/flash/src/runpod_flash/
for sub in ("flash/main/src/runpod_flash", "flash/src/runpod_flash"):
candidate = current / sub
if (candidate / "__init__.py").is_file():
return candidate
parent = current.parent
if parent == current:
break
current = parent

except Exception:
return None
return None


def _bundle_local_runpod_flash(build_dir: Path) -> bool:
"""Copy local runpod_flash source into build directory.
def _bundle_runpod_flash(build_dir: Path, flash_pkg: Path) -> None:
"""Copy runpod_flash source into build directory.

Args:
build_dir: Target build directory

Returns:
True if bundled successfully, False otherwise
flash_pkg: Path to the runpod_flash package directory to bundle
"""
flash_pkg = _find_local_runpod_flash()

if not flash_pkg:
console.print(
"[yellow]⚠ Local runpod_flash not found or using PyPI install[/yellow]"
)
return False

# Copy runpod_flash to build
dest = build_dir / "runpod_flash"
if dest.exists():
shutil.rmtree(dest)
Expand All @@ -110,8 +116,7 @@ def _bundle_local_runpod_flash(build_dir: Path) -> bool:
ignore=shutil.ignore_patterns("__pycache__", "*.pyc", ".pytest_cache"),
)

console.print(f"[cyan]✓ Bundled local runpod_flash from {flash_pkg}[/cyan]")
return True
console.print(f"[cyan]Bundled runpod_flash from {flash_pkg}[/cyan]")


def _extract_runpod_flash_dependencies(flash_pkg_dir: Path) -> list[str]:
Expand Down Expand Up @@ -171,8 +176,8 @@ def _remove_runpod_flash_from_requirements(build_dir: Path) -> None:
filtered = [
line
for line in lines
if not line.strip().startswith("runpod_flash")
and not line.strip().startswith("runpod-flash")
if not line.strip().lower().startswith("runpod_flash")
and not line.strip().lower().startswith("runpod-flash")
]

req_file.write_text("\n".join(filtered) + "\n")
Expand All @@ -190,12 +195,12 @@ def run_build(
no_deps: bool = False,
output_name: str | None = None,
exclude: str | None = None,
use_local_flash: bool = False,
verbose: bool = False,
) -> Path:
"""Run the build process and return the artifact path.

Contains all build steps: validate, collect files, manifest, deps, tarball.
Always bundles the runpod_flash installed in the current environment.
Always keeps the build directory — caller decides cleanup.

Args:
Expand All @@ -204,7 +209,6 @@ def run_build(
no_deps: Skip transitive dependencies during pip install
output_name: Custom archive name (default: artifact.tar.gz)
exclude: Comma-separated packages to exclude
use_local_flash: Bundle local runpod_flash source
verbose: Show archive and build directory paths in summary

Returns:
Expand Down Expand Up @@ -309,13 +313,19 @@ def run_build(
console.print("[red]Error:[/red] Failed to install dependencies")
raise typer.Exit(1)

# bundle local runpod_flash if requested
if use_local_flash:
if _bundle_local_runpod_flash(build_dir):
_remove_runpod_flash_from_requirements(build_dir)
# Always bundle the installed runpod_flash
flash_pkg = _find_runpod_flash(project_dir)
if not flash_pkg:
console.print(
"[red]Error:[/red] Could not find runpod_flash.\n"
" Ensure runpod-flash is installed: pip install runpod-flash"
)
raise typer.Exit(1)
_bundle_runpod_flash(build_dir, flash_pkg)
_remove_runpod_flash_from_requirements(build_dir)

# Generate _flash_resource_config.py for @remote local-vs-stub dispatch.
# Must happen AFTER _bundle_local_runpod_flash which replaces build_dir/runpod_flash/.
# Must happen AFTER _bundle_runpod_flash which replaces build_dir/runpod_flash/.
manifest_json_path = build_dir / "flash_manifest.json"
if manifest_json_path.exists():
manifest_data = json.loads(manifest_json_path.read_text())
Expand Down Expand Up @@ -371,11 +381,6 @@ def build_command(
"--exclude",
help="Comma-separated packages to exclude (e.g., 'torch,torchvision')",
),
use_local_flash: bool = typer.Option(
False,
"--use-local-flash",
help="Bundle local runpod_flash source instead of PyPI version (for development/testing)",
),
):
"""
Build Flash application for debugging (build only, no deploy).
Expand All @@ -398,7 +403,6 @@ def build_command(
no_deps=no_deps,
output_name=output_name,
exclude=exclude,
use_local_flash=use_local_flash,
verbose=True,
)

Expand Down
6 changes: 0 additions & 6 deletions src/runpod_flash/cli/commands/deploy.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,6 @@ def deploy_command(
"--exclude",
help="Comma-separated packages to exclude (e.g., 'torch,torchvision')",
),
use_local_flash: bool = typer.Option(
False,
"--use-local-flash",
help="Bundle local runpod_flash source instead of PyPI version (for development/testing)",
),
output_name: str | None = typer.Option(
None, "--output", "-o", help="Custom archive name (default: artifact.tar.gz)"
),
Expand Down Expand Up @@ -71,7 +66,6 @@ def deploy_command(
no_deps=no_deps,
output_name=output_name,
exclude=exclude,
use_local_flash=use_local_flash,
)

if preview:
Expand Down
1 change: 0 additions & 1 deletion src/runpod_flash/cli/docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,6 @@ flash deploy [OPTIONS]
- `--app, -a`: Flash app name
- `--no-deps`: Skip transitive dependencies during pip install
- `--exclude`: Comma-separated packages to exclude (e.g., 'torch,torchvision')
- `--use-local-flash`: Bundle local runpod_flash source (for development)
- `--output, -o`: Custom archive name (default: artifact.tar.gz)
- `--preview`: Build and launch local preview instead of deploying

Expand Down
9 changes: 0 additions & 9 deletions src/runpod_flash/cli/docs/flash-deploy.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@ flash deploy [OPTIONS]
- `--app, -a`: Flash app name (auto-detected from current directory)
- `--no-deps`: Skip transitive dependencies during pip install (default: false)
- `--exclude`: Comma-separated packages to exclude (e.g., 'torch,torchvision')
- `--use-local-flash`: Bundle local runpod_flash source instead of PyPI version (for development/testing)
- `--output, -o`: Custom archive name (default: artifact.tar.gz)
- `--preview`: Build and launch local preview environment instead of deploying

Expand Down Expand Up @@ -162,14 +161,6 @@ flash deploy --exclude torch,torchvision,torchaudio

Skips specified packages during dependency installation. Critical for staying under Runpod's 500MB deployment limit. See [flash build](./flash-build.md#managing-deployment-size) for base image package reference.

### Local Flash Development

```bash
flash deploy --use-local-flash
```

Bundles your local `runpod_flash` source instead of the PyPI version. Only use this for development and testing.

## Preview Mode

```bash
Expand Down
10 changes: 3 additions & 7 deletions src/runpod_flash/core/utils/user_agent.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
"""User-Agent header generation for HTTP requests."""

import platform
from importlib.metadata import version


def get_user_agent() -> str:
Expand All @@ -12,16 +11,13 @@ def get_user_agent() -> str:

Example:
>>> get_user_agent()
'Runpod Flash/1.1.1 (Python 3.11.12; Darwin 25.2.0; arm64)'
'Runpod Flash/1.4.1 (Python 3.11.12; Darwin 25.2.0; arm64)'
"""
try:
pkg_version = version("runpod-flash")
except Exception:
pkg_version = "unknown"
from runpod_flash import __version__

python_version = platform.python_version()
os_name = platform.system()
os_version = platform.release()
arch = platform.machine()

return f"Runpod Flash/{pkg_version} (Python {python_version}; {os_name} {os_version}; {arch})"
return f"Runpod Flash/{__version__} (Python {python_version}; {os_name} {os_version}; {arch})"
Loading
Loading