mirror of
https://github.com/hanzoai/python-sdk.git
synced 2026-10-26 11:49:36 +00:00
style: auto-fix ruff lint and format for Python 3.12
Run ruff check --fix and ruff format across the repo to fix ~495 auto-fixable lint errors (mostly I001 import sorting) and reformat 225 files to match the py312 target. Co-authored-by: Hanzo Dev <[email protected]>
This commit is contained in:
@@ -20,9 +20,11 @@ from hanzo_cli import __version__
|
||||
from hanzo_cli.auth import (
|
||||
browser_login,
|
||||
get_token_info,
|
||||
logout as do_logout,
|
||||
password_login,
|
||||
)
|
||||
from hanzo_cli.auth import (
|
||||
logout as do_logout,
|
||||
)
|
||||
|
||||
console = Console()
|
||||
|
||||
@@ -52,11 +54,11 @@ def login(ctx: click.Context, no_browser: bool, port: int) -> None:
|
||||
else:
|
||||
token_data = browser_login(port=port)
|
||||
|
||||
console.print(f"[green]Logged in successfully.[/green]")
|
||||
console.print("[green]Logged in successfully.[/green]")
|
||||
if token_data.get("access_token"):
|
||||
# Decode the token subject for display
|
||||
at = token_data["access_token"]
|
||||
console.print(f"Token stored at ~/.hanzo/auth/token.json")
|
||||
console.print("Token stored at ~/.hanzo/auth/token.json")
|
||||
except Exception as e:
|
||||
console.print(f"[red]Login failed:[/red] {e}")
|
||||
raise SystemExit(1)
|
||||
@@ -91,6 +93,7 @@ def whoami() -> None:
|
||||
if access_token:
|
||||
try:
|
||||
import jwt
|
||||
|
||||
# Decode without verification just to show user info
|
||||
claims = jwt.decode(access_token, options={"verify_signature": False})
|
||||
table.add_row("User", claims.get("name", claims.get("sub", "—")))
|
||||
@@ -102,6 +105,7 @@ def whoami() -> None:
|
||||
login_time = token_data.get("login_time")
|
||||
if login_time:
|
||||
from datetime import datetime, timezone
|
||||
|
||||
dt = datetime.fromtimestamp(login_time, tz=timezone.utc)
|
||||
table.add_row("Login Time", dt.isoformat())
|
||||
|
||||
|
||||
@@ -11,8 +11,6 @@ Usage:
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
|
||||
import click
|
||||
from rich.console import Console
|
||||
from rich.table import Table
|
||||
@@ -254,7 +252,7 @@ def sync_app(name: str, init_data: bool) -> None:
|
||||
else:
|
||||
console.print(f"Application: {target.owner}/{target.name}")
|
||||
console.print(f"Client ID: {target.client_id}")
|
||||
console.print(f"Redirect URIs:")
|
||||
console.print("Redirect URIs:")
|
||||
for uri in target.redirect_uris:
|
||||
console.print(f" - {uri}")
|
||||
finally:
|
||||
|
||||
@@ -133,7 +133,12 @@ def get_secret(project: str, env: str, name: str, path: str, reveal: bool) -> No
|
||||
@click.option("--path", default="/", help="Secret path prefix.")
|
||||
@click.option("--comment", default=None, help="Secret comment.")
|
||||
def set_secret(
|
||||
project: str, env: str, name: str, value: str | None, path: str, comment: str | None,
|
||||
project: str,
|
||||
env: str,
|
||||
name: str,
|
||||
value: str | None,
|
||||
path: str,
|
||||
comment: str | None,
|
||||
) -> None:
|
||||
"""Create or update a secret. Prompts for value if not given."""
|
||||
if not value:
|
||||
|
||||
@@ -176,11 +176,13 @@ class PaaSClient:
|
||||
new_rt = resp.headers.get("Refresh-Token")
|
||||
if new_at:
|
||||
self._at = new_at
|
||||
_save_session({
|
||||
"at": new_at,
|
||||
"rt": new_rt or self._rt or "",
|
||||
"login_time": int(time.time()),
|
||||
})
|
||||
_save_session(
|
||||
{
|
||||
"at": new_at,
|
||||
"rt": new_rt or self._rt or "",
|
||||
"login_time": int(time.time()),
|
||||
}
|
||||
)
|
||||
# Rebuild client with new token
|
||||
self.close()
|
||||
|
||||
@@ -244,9 +246,7 @@ class PaaSClient:
|
||||
# ========================================================================
|
||||
|
||||
def list_envs(self, org_id: str, project_id: str) -> list[dict[str, Any]]:
|
||||
return self._ok(
|
||||
self.http.get(f"/v1/org/{org_id}/project/{project_id}/env")
|
||||
)
|
||||
return self._ok(self.http.get(f"/v1/org/{org_id}/project/{project_id}/env"))
|
||||
|
||||
# ========================================================================
|
||||
# Containers (Deployments)
|
||||
@@ -256,13 +256,20 @@ class PaaSClient:
|
||||
return f"/v1/org/{org_id}/project/{project_id}/env/{env_id}/container"
|
||||
|
||||
def list_containers(
|
||||
self, org_id: str, project_id: str, env_id: str,
|
||||
self,
|
||||
org_id: str,
|
||||
project_id: str,
|
||||
env_id: str,
|
||||
) -> list[dict[str, Any]]:
|
||||
url = self._container_base(org_id, project_id, env_id)
|
||||
return self._ok(self.http.get(url))
|
||||
|
||||
def get_container(
|
||||
self, org_id: str, project_id: str, env_id: str, container_id: str,
|
||||
self,
|
||||
org_id: str,
|
||||
project_id: str,
|
||||
env_id: str,
|
||||
container_id: str,
|
||||
) -> dict[str, Any]:
|
||||
url = f"{self._container_base(org_id, project_id, env_id)}/{container_id}"
|
||||
return self._ok(self.http.get(url))
|
||||
@@ -289,13 +296,21 @@ class PaaSClient:
|
||||
return self._ok(self.http.put(url, json=payload))
|
||||
|
||||
def delete_container(
|
||||
self, org_id: str, project_id: str, env_id: str, container_id: str,
|
||||
self,
|
||||
org_id: str,
|
||||
project_id: str,
|
||||
env_id: str,
|
||||
container_id: str,
|
||||
) -> dict[str, Any]:
|
||||
url = f"{self._container_base(org_id, project_id, env_id)}/{container_id}"
|
||||
return self._ok(self.http.delete(url))
|
||||
|
||||
def redeploy_container(
|
||||
self, org_id: str, project_id: str, env_id: str, container_id: str,
|
||||
self,
|
||||
org_id: str,
|
||||
project_id: str,
|
||||
env_id: str,
|
||||
container_id: str,
|
||||
) -> dict[str, Any]:
|
||||
"""Trigger a redeploy by re-PUTting the container config.
|
||||
|
||||
@@ -308,30 +323,33 @@ class PaaSClient:
|
||||
return self._ok(self.http.put(url, json=container))
|
||||
|
||||
def get_container_pods(
|
||||
self, org_id: str, project_id: str, env_id: str, container_id: str,
|
||||
self,
|
||||
org_id: str,
|
||||
project_id: str,
|
||||
env_id: str,
|
||||
container_id: str,
|
||||
) -> list[dict[str, Any]]:
|
||||
url = (
|
||||
f"{self._container_base(org_id, project_id, env_id)}"
|
||||
f"/{container_id}/pods"
|
||||
)
|
||||
url = f"{self._container_base(org_id, project_id, env_id)}/{container_id}/pods"
|
||||
return self._ok(self.http.get(url))
|
||||
|
||||
def get_container_logs(
|
||||
self, org_id: str, project_id: str, env_id: str, container_id: str,
|
||||
self,
|
||||
org_id: str,
|
||||
project_id: str,
|
||||
env_id: str,
|
||||
container_id: str,
|
||||
) -> Any:
|
||||
url = (
|
||||
f"{self._container_base(org_id, project_id, env_id)}"
|
||||
f"/{container_id}/logs"
|
||||
)
|
||||
url = f"{self._container_base(org_id, project_id, env_id)}/{container_id}/logs"
|
||||
return self._ok(self.http.get(url))
|
||||
|
||||
def get_container_events(
|
||||
self, org_id: str, project_id: str, env_id: str, container_id: str,
|
||||
self,
|
||||
org_id: str,
|
||||
project_id: str,
|
||||
env_id: str,
|
||||
container_id: str,
|
||||
) -> list[dict[str, Any]]:
|
||||
url = (
|
||||
f"{self._container_base(org_id, project_id, env_id)}"
|
||||
f"/{container_id}/events"
|
||||
)
|
||||
url = f"{self._container_base(org_id, project_id, env_id)}/{container_id}/events"
|
||||
return self._ok(self.http.get(url))
|
||||
|
||||
# ========================================================================
|
||||
|
||||
@@ -34,23 +34,25 @@ console = Console()
|
||||
|
||||
# ── shared option decorators ────────────────────────────────────────────
|
||||
|
||||
|
||||
def _org_option(fn):
|
||||
return click.option("--org", default=None, help="Organization ID (or from context).")(fn)
|
||||
|
||||
|
||||
def _project_option(fn):
|
||||
return click.option("--project", default=None, help="Project ID (or from context).")(fn)
|
||||
|
||||
|
||||
def _env_option(fn):
|
||||
return click.option("--env", "env_id", default=None, help="Environment ID (or from context).")(fn)
|
||||
return click.option("--env", "env_id", default=None, help="Environment ID (or from context).")(
|
||||
fn
|
||||
)
|
||||
|
||||
|
||||
def _require(label: str, value: str | None) -> str:
|
||||
"""Ensure a value is set; exit with a helpful message if not."""
|
||||
if not value:
|
||||
console.print(
|
||||
f"[red]{label} is required.[/red] "
|
||||
"Pass it via flag or run 'hanzo paas use'."
|
||||
)
|
||||
console.print(f"[red]{label} is required.[/red] Pass it via flag or run 'hanzo paas use'.")
|
||||
raise SystemExit(1)
|
||||
return value
|
||||
|
||||
@@ -85,6 +87,7 @@ def paas() -> None:
|
||||
|
||||
# ── context ─────────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
@paas.command("use")
|
||||
@click.option("--org", default=None, help="Organization ID to remember.")
|
||||
@click.option("--project", default=None, help="Project ID to remember.")
|
||||
@@ -244,6 +247,7 @@ def deploy() -> None:
|
||||
|
||||
# ── deploy list ─────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
@deploy.command("list")
|
||||
@_org_option
|
||||
@_project_option
|
||||
@@ -287,16 +291,23 @@ def deploy_list(org: str | None, project: str | None, env_id: str | None) -> Non
|
||||
|
||||
# ── deploy create ───────────────────────────────────────────────────────
|
||||
|
||||
|
||||
@deploy.command("create")
|
||||
@click.argument("name")
|
||||
@click.option("--image", default=None, help="Docker image URL (e.g. nginx:latest, ghcr.io/org/app:v1).")
|
||||
@click.option(
|
||||
"--image", default=None, help="Docker image URL (e.g. nginx:latest, ghcr.io/org/app:v1)."
|
||||
)
|
||||
@click.option("--repo", default=None, help="Git repository (owner/repo).")
|
||||
@click.option("--branch", default="main", help="Branch to deploy (with --repo).")
|
||||
@click.option("--dockerfile", default="Dockerfile", help="Dockerfile path (with --repo).")
|
||||
@click.option("--port", type=int, default=3000, help="Container port.")
|
||||
@click.option("--replicas", type=int, default=1, help="Desired replica count.")
|
||||
@click.option("--type", "deploy_type", default="deployment",
|
||||
type=click.Choice(["deployment", "statefulset", "cronjob"]))
|
||||
@click.option(
|
||||
"--type",
|
||||
"deploy_type",
|
||||
default="deployment",
|
||||
type=click.Choice(["deployment", "statefulset", "cronjob"]),
|
||||
)
|
||||
@_org_option
|
||||
@_project_option
|
||||
@_env_option
|
||||
@@ -416,13 +427,17 @@ def deploy_create(
|
||||
|
||||
# ── deploy status ───────────────────────────────────────────────────────
|
||||
|
||||
|
||||
@deploy.command("status")
|
||||
@click.argument("name")
|
||||
@_org_option
|
||||
@_project_option
|
||||
@_env_option
|
||||
def deploy_status(
|
||||
name: str, org: str | None, project: str | None, env_id: str | None,
|
||||
name: str,
|
||||
org: str | None,
|
||||
project: str | None,
|
||||
env_id: str | None,
|
||||
) -> None:
|
||||
"""Show container status and pods."""
|
||||
org_id, project_id, env_id = resolve(org, project, env_id)
|
||||
@@ -474,13 +489,17 @@ def deploy_status(
|
||||
|
||||
# ── deploy logs ─────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
@deploy.command("logs")
|
||||
@click.argument("name")
|
||||
@_org_option
|
||||
@_project_option
|
||||
@_env_option
|
||||
def deploy_logs(
|
||||
name: str, org: str | None, project: str | None, env_id: str | None,
|
||||
name: str,
|
||||
org: str | None,
|
||||
project: str | None,
|
||||
env_id: str | None,
|
||||
) -> None:
|
||||
"""Show container logs."""
|
||||
org_id, project_id, env_id = resolve(org, project, env_id)
|
||||
@@ -524,13 +543,17 @@ def deploy_logs(
|
||||
|
||||
# ── deploy redeploy ─────────────────────────────────────────────────────
|
||||
|
||||
|
||||
@deploy.command("redeploy")
|
||||
@click.argument("name")
|
||||
@_org_option
|
||||
@_project_option
|
||||
@_env_option
|
||||
def deploy_redeploy(
|
||||
name: str, org: str | None, project: str | None, env_id: str | None,
|
||||
name: str,
|
||||
org: str | None,
|
||||
project: str | None,
|
||||
env_id: str | None,
|
||||
) -> None:
|
||||
"""Trigger a rebuild and redeploy of a container."""
|
||||
org_id, project_id, env_id = resolve(org, project, env_id)
|
||||
@@ -551,6 +574,7 @@ def deploy_redeploy(
|
||||
|
||||
# ── deploy env ──────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
@deploy.command("env")
|
||||
@click.argument("name")
|
||||
@click.argument("vars", nargs=-1)
|
||||
@@ -616,7 +640,11 @@ def deploy_env(
|
||||
# PaaS requires the full container payload on PUT — merge vars into it
|
||||
container["variables"] = merged
|
||||
client.update_container(
|
||||
org_id, project_id, env_id, cid, container,
|
||||
org_id,
|
||||
project_id,
|
||||
env_id,
|
||||
cid,
|
||||
container,
|
||||
)
|
||||
console.print(f"[green]Set {len(new_vars)} variable(s) on '{name}'.[/green]")
|
||||
finally:
|
||||
@@ -625,6 +653,7 @@ def deploy_env(
|
||||
|
||||
# ── deploy delete ───────────────────────────────────────────────────────
|
||||
|
||||
|
||||
@deploy.command("delete")
|
||||
@click.argument("name")
|
||||
@click.option("--yes", "-y", is_flag=True, help="Skip confirmation.")
|
||||
|
||||
@@ -11,8 +11,6 @@ Run:
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import time
|
||||
|
||||
@@ -111,20 +109,31 @@ class TestPaaSRead:
|
||||
assert "Platform" in r.stdout
|
||||
|
||||
def test_paas_envs(self):
|
||||
r = run([
|
||||
"paas", "envs",
|
||||
"--org", "698cda6739f65183b3009313",
|
||||
"--project", "698cda6739f65183b3009318",
|
||||
])
|
||||
r = run(
|
||||
[
|
||||
"paas",
|
||||
"envs",
|
||||
"--org",
|
||||
"698cda6739f65183b3009313",
|
||||
"--project",
|
||||
"698cda6739f65183b3009318",
|
||||
]
|
||||
)
|
||||
assert "production" in r.stdout
|
||||
|
||||
def test_paas_context_set_and_show(self):
|
||||
run([
|
||||
"paas", "use",
|
||||
"--org", "698cda6739f65183b3009313",
|
||||
"--project", "698cda6739f65183b3009318",
|
||||
"--env", "698cda6739f65183b300931c",
|
||||
])
|
||||
run(
|
||||
[
|
||||
"paas",
|
||||
"use",
|
||||
"--org",
|
||||
"698cda6739f65183b3009313",
|
||||
"--project",
|
||||
"698cda6739f65183b3009318",
|
||||
"--env",
|
||||
"698cda6739f65183b300931c",
|
||||
]
|
||||
)
|
||||
r = run(["paas", "context"])
|
||||
assert "698cda6739f65183b3009313" in r.stdout
|
||||
assert "698cda6739f65183b3009318" in r.stdout
|
||||
@@ -149,12 +158,18 @@ class TestPaaSDeployLifecycle:
|
||||
@classmethod
|
||||
def setup_class(cls):
|
||||
"""Ensure context is set and clean up any leftover test containers."""
|
||||
run([
|
||||
"paas", "use",
|
||||
"--org", "698cda6739f65183b3009313",
|
||||
"--project", "698cda6739f65183b3009318",
|
||||
"--env", "698cda6739f65183b300931c",
|
||||
])
|
||||
run(
|
||||
[
|
||||
"paas",
|
||||
"use",
|
||||
"--org",
|
||||
"698cda6739f65183b3009313",
|
||||
"--project",
|
||||
"698cda6739f65183b3009318",
|
||||
"--env",
|
||||
"698cda6739f65183b300931c",
|
||||
]
|
||||
)
|
||||
# Clean up leftover from previous failed runs
|
||||
r = run(["paas", "deploy", "delete", cls.CONTAINER_NAME, "-y"], check=False)
|
||||
|
||||
@@ -164,11 +179,18 @@ class TestPaaSDeployLifecycle:
|
||||
run(["paas", "deploy", "delete", cls.CONTAINER_NAME, "-y"], check=False)
|
||||
|
||||
def test_01_create(self):
|
||||
r = run([
|
||||
"paas", "deploy", "create", self.CONTAINER_NAME,
|
||||
"--image", "nginx:latest",
|
||||
"--port", "80",
|
||||
])
|
||||
r = run(
|
||||
[
|
||||
"paas",
|
||||
"deploy",
|
||||
"create",
|
||||
self.CONTAINER_NAME,
|
||||
"--image",
|
||||
"nginx:latest",
|
||||
"--port",
|
||||
"80",
|
||||
]
|
||||
)
|
||||
assert "Created container" in r.stdout
|
||||
assert self.CONTAINER_NAME in r.stdout
|
||||
|
||||
@@ -207,10 +229,15 @@ class TestPaaSDeployLifecycle:
|
||||
|
||||
def test_07_env_set(self):
|
||||
"""Set an env var on the container."""
|
||||
r = run([
|
||||
"paas", "deploy", "env", self.CONTAINER_NAME,
|
||||
"TEST_VAR=hello_e2e",
|
||||
])
|
||||
r = run(
|
||||
[
|
||||
"paas",
|
||||
"deploy",
|
||||
"env",
|
||||
self.CONTAINER_NAME,
|
||||
"TEST_VAR=hello_e2e",
|
||||
]
|
||||
)
|
||||
assert "Set 1 variable" in r.stdout
|
||||
|
||||
def test_08_env_verify(self):
|
||||
@@ -248,12 +275,18 @@ class TestPaaSErrors:
|
||||
assert "required" in r.stdout.lower() or "required" in r.stderr.lower()
|
||||
|
||||
def test_nonexistent_container(self):
|
||||
run([
|
||||
"paas", "use",
|
||||
"--org", "698cda6739f65183b3009313",
|
||||
"--project", "698cda6739f65183b3009318",
|
||||
"--env", "698cda6739f65183b300931c",
|
||||
])
|
||||
run(
|
||||
[
|
||||
"paas",
|
||||
"use",
|
||||
"--org",
|
||||
"698cda6739f65183b3009313",
|
||||
"--project",
|
||||
"698cda6739f65183b3009318",
|
||||
"--env",
|
||||
"698cda6739f65183b300931c",
|
||||
]
|
||||
)
|
||||
r = run(["paas", "deploy", "status", "nonexistent-container-xyz"], check=False)
|
||||
assert r.returncode != 0
|
||||
assert "not found" in r.stdout.lower() or "not found" in r.stderr.lower()
|
||||
|
||||
Reference in New Issue
Block a user