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
4 changes: 1 addition & 3 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,9 @@ jobs:
test:
strategy:
matrix:
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
pydantic-version: ["v2"]
include:
- python-version: "3.8"
pydantic-version: "v1"
- python-version: "3.9"
pydantic-version: "v1"
- python-version: "3.10"
Expand Down
2 changes: 1 addition & 1 deletion .python-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.8
3.9
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.8"
requires-python = ">=3.9"
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.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
Expand Down
25 changes: 14 additions & 11 deletions src/fastapi_cloud_cli/commands/deploy.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from itertools import cycle
from pathlib import Path
from textwrap import dedent
from typing import Any, Dict, List, Optional, Union
from typing import Annotated, Any, Optional, Union

import fastar
import rignore
Expand All @@ -17,7 +17,6 @@
from rich.text import Text
from rich_toolkit import RichToolkit
from rich_toolkit.menu import Option
from typing_extensions import Annotated

from fastapi_cloud_cli.commands.login import login
from fastapi_cloud_cli.utils.api import APIClient, BuildLogError, TooManyRetriesError
Expand Down Expand Up @@ -102,7 +101,7 @@ class Team(BaseModel):
name: str


def _get_teams() -> List[Team]:
def _get_teams() -> list[Team]:
with APIClient() as client:
response = client.get("/teams/")
response.raise_for_status()
Expand Down Expand Up @@ -184,7 +183,7 @@ def _create_deployment(app_id: str) -> CreateDeploymentResponse:

class RequestUploadResponse(BaseModel):
url: str
fields: Dict[str, str]
fields: dict[str, str]


def _upload_deployment(deployment_id: str, archive_path: Path) -> None:
Expand Down Expand Up @@ -242,7 +241,7 @@ def _get_app(app_slug: str) -> Optional[AppResponse]:
return model_validate(AppResponse, data)


def _get_apps(team_id: str) -> List[AppResponse]:
def _get_apps(team_id: str) -> list[AppResponse]:
with APIClient() as client:
response = client.get("/apps/", params={"team_id": team_id})
response.raise_for_status()
Expand Down Expand Up @@ -363,9 +362,12 @@ def _wait_for_deployment(

last_message_changed_at = time.monotonic()

with toolkit.progress(
next(messages), inline_logs=True, lines_to_show=20
) as progress, APIClient() as client:
with (
toolkit.progress(
next(messages), inline_logs=True, lines_to_show=20
) as progress,
APIClient() as client,
):
try:
for log in client.stream_build_logs(deployment.id):
time_elapsed = time.monotonic() - started_at
Expand Down Expand Up @@ -609,9 +611,10 @@ def deploy(
archive_path = Path(temp_dir) / "archive.tar"
archive(path or Path.cwd(), archive_path)

with toolkit.progress(
title="Creating deployment"
) as progress, handle_http_errors(progress):
with (
toolkit.progress(title="Creating deployment") as progress,
handle_http_errors(progress),
):
logger.debug("Creating deployment for app: %s", app.id)
deployment = _create_deployment(app.id)

Expand Down
5 changes: 2 additions & 3 deletions src/fastapi_cloud_cli/commands/env.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import logging
from pathlib import Path
from typing import Any, List, Union
from typing import Annotated, Any, Union

import typer
from pydantic import BaseModel
from typing_extensions import Annotated

from fastapi_cloud_cli.utils.api import APIClient
from fastapi_cloud_cli.utils.apps import get_app_config
Expand All @@ -22,7 +21,7 @@ class EnvironmentVariable(BaseModel):


class EnvironmentVariableResponse(BaseModel):
data: List[EnvironmentVariable]
data: list[EnvironmentVariable]


def _get_environment_variables(app_id: str) -> EnvironmentVariableResponse:
Expand Down
5 changes: 3 additions & 2 deletions src/fastapi_cloud_cli/utils/api.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import json
import logging
import time
from collections.abc import Generator
from contextlib import contextmanager
from datetime import timedelta
from functools import wraps
from typing import (
Annotated,
Callable,
Generator,
Literal,
Optional,
TypeVar,
Expand All @@ -15,7 +16,7 @@

import httpx
from pydantic import BaseModel, Field, ValidationError
from typing_extensions import Annotated, ParamSpec
from typing_extensions import ParamSpec

from fastapi_cloud_cli import __version__
from fastapi_cloud_cli.config import Settings
Expand Down
7 changes: 4 additions & 3 deletions src/fastapi_cloud_cli/utils/cli.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import contextlib
import logging
from typing import Any, Dict, Generator, List, Optional, Tuple
from collections.abc import Generator
from typing import Any, Optional

import typer
from httpx import HTTPError, HTTPStatusError, ReadTimeout
Expand All @@ -18,10 +19,10 @@ def __init__(self, tag_width: int = 11):

def _get_tag_segments(
self,
metadata: Dict[str, Any],
metadata: dict[str, Any],
is_animated: bool = False,
done: bool = False,
) -> Tuple[List[Segment], int]:
) -> tuple[list[Segment], int]:
if not is_animated:
return super()._get_tag_segments(metadata, is_animated, done)

Expand Down
10 changes: 5 additions & 5 deletions src/fastapi_cloud_cli/utils/pydantic_compat.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Any, Dict, Generic, Type, TypeVar
from typing import Any, Generic, TypeVar

from pydantic import BaseModel
from pydantic.version import VERSION as PYDANTIC_VERSION
Expand All @@ -11,21 +11,21 @@
Model = TypeVar("Model", bound=BaseModel)


def model_validate(model_class: Type[Model], data: Dict[Any, Any]) -> Model:
def model_validate(model_class: type[Model], data: dict[Any, Any]) -> Model:
if PYDANTIC_V2:
return model_class.model_validate(data) # type: ignore[no-any-return, unused-ignore, attr-defined]
else:
return model_class.parse_obj(data) # type: ignore[no-any-return, unused-ignore, attr-defined]


def model_validate_json(model_class: Type[Model], data: str) -> Model:
def model_validate_json(model_class: type[Model], data: str) -> Model:
if PYDANTIC_V2:
return model_class.model_validate_json(data) # type: ignore[no-any-return, unused-ignore, attr-defined]
else:
return model_class.parse_raw(data) # type: ignore[no-any-return, unused-ignore, attr-defined]


def model_dump(obj: BaseModel, **kwargs: Any) -> Dict[Any, Any]:
def model_dump(obj: BaseModel, **kwargs: Any) -> dict[Any, Any]:
if PYDANTIC_V2:
return obj.model_dump(**kwargs) # type: ignore[no-any-return, unused-ignore, attr-defined]
else:
Expand All @@ -41,7 +41,7 @@ def model_dump_json(obj: BaseModel) -> str:


class TypeAdapter(Generic[T]):
def __init__(self, type_: Type[T]) -> None:
def __init__(self, type_: type[T]) -> None:
self.type_ = type_

if PYDANTIC_V2:
Expand Down
2 changes: 1 addition & 1 deletion tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import sys
from collections.abc import Generator
from dataclasses import dataclass
from pathlib import Path
from typing import Generator
from unittest.mock import patch

import pytest
Expand Down
Loading