Skip to content
Closed
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
3 changes: 1 addition & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name = "fastapi-cloud-cli"
dynamic = ["version"]
description = "Deploy and manage FastAPI Cloud apps from the command line 🚀"
authors = [{ name = "Patrick Arminio", email = "patrick@fastapilabs.com" }]
requires-python = ">=3.10"
requires-python = ">=3.11"
readme = "README.md"
license = { text = "MIT" }
classifiers = [
Expand All @@ -22,7 +22,6 @@ classifiers = [
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
Expand Down
27 changes: 26 additions & 1 deletion src/fastapi_cloud_cli/commands/deploy/archive.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import rignore
from pydantic import AfterValidator

import tomllib

logger = logging.getLogger(__name__)


Expand Down Expand Up @@ -42,9 +44,32 @@ def validate_app_directory(v: str | None) -> str | None:

AppDirectory = Annotated[str | None, AfterValidator(validate_app_directory)]

def _project_name_from_pyproject(path: Path) -> str:
if not path.exists():
return ""

try:
with path.open("rb") as f:
data = tomllib.load(f)

project_name = data.get("project", {}).get("name")
if project_name:
return str(project_name)

poetry_name = data.get("tool", {}).get("poetry", {}).get("name")
if poetry_name:
return str(poetry_name)

except Exception:
return ""

return ""

def _get_app_name(path: Path) -> str:
# TODO: use pyproject.toml to get the app name
pyproject_path = path / "pyproject.toml"
name = _project_name_from_pyproject(pyproject_path)
if name:
return name
return path.name


Expand Down
69 changes: 69 additions & 0 deletions tests/test_cli_deploy.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
from fastapi_cloud_cli.utils.api import StreamLogError, TooManyRetriesError
from tests.conftest import ConfiguredApp
from tests.utils import Keys, build_logs_response, changing_dir, create_jwt_token
from fastapi_cloud_cli.commands.deploy.archive import _project_name_from_pyproject


runner = CliRunner()

Expand Down Expand Up @@ -2494,3 +2496,70 @@ def test_invalid_large_file_threshold(

assert result.exit_code == 2
assert "Invalid value for '--large-file-threshold'" in result.output

def test_project_name_from_pyproject_project_section(tmp_path: Path) -> None:
pyproject = tmp_path / "pyproject.toml"
pyproject.write_text(
"""
[project]
name = "my-app"
""",
encoding="utf-8",
)

result = _project_name_from_pyproject(pyproject)

assert result == "my-app"


def test_project_name_from_pyproject_poetry_section(tmp_path: Path) -> None:
pyproject = tmp_path / "pyproject.toml"
pyproject.write_text(
"""
[tool.poetry]
name = "my-poetry-app"
""",
encoding="utf-8",
)

result = _project_name_from_pyproject(pyproject)

assert result == "my-poetry-app"


def test_project_name_from_pyproject_missing_file(tmp_path: Path) -> None:
pyproject = tmp_path / "missing.toml"

result = _project_name_from_pyproject(pyproject)

assert result == ""


def test_project_name_from_pyproject_missing_name(tmp_path: Path) -> None:
pyproject = tmp_path / "pyproject.toml"
pyproject.write_text(
"""
[project]
version = "0.1.0"
""",
encoding="utf-8",
)

result = _project_name_from_pyproject(pyproject)

assert result == ""


def test_project_name_from_pyproject_invalid_toml(tmp_path: Path) -> None:
pyproject = tmp_path / "pyproject.toml"
pyproject.write_text(
"""
[project
name = "invalid"
""",
encoding="utf-8",
)

result = _project_name_from_pyproject(pyproject)

assert result == ""
Loading