From 8b6dbfb7a1151b49b283f205f8e0a7663d04dabd Mon Sep 17 00:00:00 2001 From: Joey Krug Date: Sat, 14 Mar 2026 23:52:08 -0400 Subject: [PATCH] chore: format python scripts --- ...ck-composite-action-input-interpolation.py | 1 - skills/model-usage/scripts/model_usage.py | 52 ++++++++-------- .../nano-banana-pro/scripts/generate_image.py | 59 ++++++++----------- skills/openai-image-gen/scripts/gen.py | 37 ++++++------ skills/openai-image-gen/scripts/test_gen.py | 2 + .../skill-creator/scripts/quick_validate.py | 18 ++---- 6 files changed, 75 insertions(+), 94 deletions(-) diff --git a/scripts/check-composite-action-input-interpolation.py b/scripts/check-composite-action-input-interpolation.py index 18c52501b85..5c852a7f323 100644 --- a/scripts/check-composite-action-input-interpolation.py +++ b/scripts/check-composite-action-input-interpolation.py @@ -5,7 +5,6 @@ import pathlib import re import sys - INPUT_INTERPOLATION_RE = re.compile(r"\$\{\{\s*inputs\.") RUN_LINE_RE = re.compile(r"^(\s*)run:\s*(.*)$") USING_COMPOSITE_RE = re.compile(r"^\s*using:\s*composite\s*$", re.MULTILINE) diff --git a/skills/model-usage/scripts/model_usage.py b/skills/model-usage/scripts/model_usage.py index ea28fa0d983..7688e4e46b2 100644 --- a/skills/model-usage/scripts/model_usage.py +++ b/skills/model-usage/scripts/model_usage.py @@ -9,12 +9,12 @@ from __future__ import annotations import argparse import json -import os import subprocess import sys +from collections.abc import Iterable from dataclasses import dataclass from datetime import date, datetime, timedelta -from typing import Any, Dict, Iterable, List, Optional, Tuple +from typing import Any def positive_int(value: str) -> int: @@ -31,7 +31,7 @@ def eprint(msg: str) -> None: print(msg, file=sys.stderr) -def run_codexbar_cost(provider: str) -> List[Dict[str, Any]]: +def run_codexbar_cost(provider: str) -> list[dict[str, Any]]: cmd = ["codexbar", "cost", "--format", "json", "--provider", provider] try: output = subprocess.check_output(cmd, text=True) @@ -48,12 +48,12 @@ def run_codexbar_cost(provider: str) -> List[Dict[str, Any]]: return payload -def load_payload(input_path: Optional[str], provider: str) -> Dict[str, Any]: +def load_payload(input_path: str | None, provider: str) -> dict[str, Any]: if input_path: if input_path == "-": raw = sys.stdin.read() else: - with open(input_path, "r", encoding="utf-8") as handle: + with open(input_path, encoding="utf-8") as handle: raw = handle.read() data = json.loads(raw) else: @@ -77,7 +77,7 @@ class ModelCost: cost: float -def parse_daily_entries(payload: Dict[str, Any]) -> List[Dict[str, Any]]: +def parse_daily_entries(payload: dict[str, Any]) -> list[dict[str, Any]]: daily = payload.get("daily") if not daily: return [] @@ -86,18 +86,18 @@ def parse_daily_entries(payload: Dict[str, Any]) -> List[Dict[str, Any]]: return [entry for entry in daily if isinstance(entry, dict)] -def parse_date(value: str) -> Optional[date]: +def parse_date(value: str) -> date | None: try: return datetime.strptime(value, "%Y-%m-%d").date() except Exception: return None -def filter_by_days(entries: List[Dict[str, Any]], days: Optional[int]) -> List[Dict[str, Any]]: +def filter_by_days(entries: list[dict[str, Any]], days: int | None) -> list[dict[str, Any]]: if not days: return entries cutoff = date.today() - timedelta(days=days - 1) - filtered: List[Dict[str, Any]] = [] + filtered: list[dict[str, Any]] = [] for entry in entries: day = entry.get("date") if not isinstance(day, str): @@ -108,8 +108,8 @@ def filter_by_days(entries: List[Dict[str, Any]], days: Optional[int]) -> List[D return filtered -def aggregate_costs(entries: Iterable[Dict[str, Any]]) -> Dict[str, float]: - totals: Dict[str, float] = {} +def aggregate_costs(entries: Iterable[dict[str, Any]]) -> dict[str, float]: + totals: dict[str, float] = {} for entry in entries: breakdowns = entry.get("modelBreakdowns") if not breakdowns: @@ -129,7 +129,7 @@ def aggregate_costs(entries: Iterable[Dict[str, Any]]) -> Dict[str, float]: return totals -def pick_current_model(entries: List[Dict[str, Any]]) -> Tuple[Optional[str], Optional[str]]: +def pick_current_model(entries: list[dict[str, Any]]) -> tuple[str | None, str | None]: if not entries: return None, None sorted_entries = sorted( @@ -139,7 +139,7 @@ def pick_current_model(entries: List[Dict[str, Any]]) -> Tuple[Optional[str], Op for entry in reversed(sorted_entries): breakdowns = entry.get("modelBreakdowns") if isinstance(breakdowns, list) and breakdowns: - scored: List[ModelCost] = [] + scored: list[ModelCost] = [] for item in breakdowns: if not isinstance(item, dict): continue @@ -158,13 +158,13 @@ def pick_current_model(entries: List[Dict[str, Any]]) -> Tuple[Optional[str], Op return None, None -def usd(value: Optional[float]) -> str: +def usd(value: float | None) -> str: if value is None: return "—" return f"${value:,.2f}" -def latest_day_cost(entries: List[Dict[str, Any]], model: str) -> Tuple[Optional[str], Optional[float]]: +def latest_day_cost(entries: list[dict[str, Any]], model: str) -> tuple[str | None, float | None]: if not entries: return None, None sorted_entries = sorted( @@ -188,10 +188,10 @@ def latest_day_cost(entries: List[Dict[str, Any]], model: str) -> Tuple[Optional def render_text_current( provider: str, model: str, - latest_date: Optional[str], - total_cost: Optional[float], - latest_cost: Optional[float], - latest_cost_date: Optional[str], + latest_date: str | None, + total_cost: float | None, + latest_cost: float | None, + latest_cost_date: str | None, entry_count: int, ) -> str: lines = [f"Provider: {provider}", f"Current model: {model}"] @@ -204,7 +204,7 @@ def render_text_current( return "\n".join(lines) -def render_text_all(provider: str, totals: Dict[str, float]) -> str: +def render_text_all(provider: str, totals: dict[str, float]) -> str: lines = [f"Provider: {provider}", "Models:"] for model, cost in sorted(totals.items(), key=lambda item: item[1], reverse=True): lines.append(f"- {model}: {usd(cost)}") @@ -214,12 +214,12 @@ def render_text_all(provider: str, totals: Dict[str, float]) -> str: def build_json_current( provider: str, model: str, - latest_date: Optional[str], - total_cost: Optional[float], - latest_cost: Optional[float], - latest_cost_date: Optional[str], + latest_date: str | None, + total_cost: float | None, + latest_cost: float | None, + latest_cost_date: str | None, entry_count: int, -) -> Dict[str, Any]: +) -> dict[str, Any]: return { "provider": provider, "mode": "current", @@ -232,7 +232,7 @@ def build_json_current( } -def build_json_all(provider: str, totals: Dict[str, float]) -> Dict[str, Any]: +def build_json_all(provider: str, totals: dict[str, float]) -> dict[str, Any]: return { "provider": provider, "mode": "all", diff --git a/skills/nano-banana-pro/scripts/generate_image.py b/skills/nano-banana-pro/scripts/generate_image.py index 796022adfba..92efabc2b0f 100755 --- a/skills/nano-banana-pro/scripts/generate_image.py +++ b/skills/nano-banana-pro/scripts/generate_image.py @@ -70,42 +70,32 @@ def choose_output_resolution( def main(): - parser = argparse.ArgumentParser( - description="Generate images using Nano Banana Pro (Gemini 3 Pro Image)" - ) + parser = argparse.ArgumentParser(description="Generate images using Nano Banana Pro (Gemini 3 Pro Image)") + parser.add_argument("--prompt", "-p", required=True, help="Image description/prompt") + parser.add_argument("--filename", "-f", required=True, help="Output filename (e.g., sunset-mountains.png)") parser.add_argument( - "--prompt", "-p", - required=True, - help="Image description/prompt" - ) - parser.add_argument( - "--filename", "-f", - required=True, - help="Output filename (e.g., sunset-mountains.png)" - ) - parser.add_argument( - "--input-image", "-i", + "--input-image", + "-i", action="append", dest="input_images", metavar="IMAGE", - help="Input image path(s) for editing/composition. Can be specified multiple times (up to 14 images)." + help="Input image path(s) for editing/composition. Can be specified multiple times (up to 14 images).", ) parser.add_argument( - "--resolution", "-r", + "--resolution", + "-r", choices=["1K", "2K", "4K"], default=None, - help="Output resolution: 1K, 2K, or 4K. If omitted with input images, auto-detect from largest image dimension." + help="Output resolution: 1K, 2K, or 4K. If omitted with input images, auto-detect from largest image dimension.", ) parser.add_argument( - "--aspect-ratio", "-a", + "--aspect-ratio", + "-a", choices=SUPPORTED_ASPECT_RATIOS, default=None, - help=f"Output aspect ratio (default: model decides). Options: {', '.join(SUPPORTED_ASPECT_RATIOS)}" - ) - parser.add_argument( - "--api-key", "-k", - help="Gemini API key (overrides GEMINI_API_KEY env var)" + help=f"Output aspect ratio (default: model decides). Options: {', '.join(SUPPORTED_ASPECT_RATIOS)}", ) + parser.add_argument("--api-key", "-k", help="Gemini API key (overrides GEMINI_API_KEY env var)") args = parser.parse_args() @@ -158,10 +148,7 @@ def main(): has_input_images=bool(input_images), ) if auto_detected: - print( - f"Auto-detected resolution: {output_resolution} " - f"(from max input dimension {max_input_dim})" - ) + print(f"Auto-detected resolution: {output_resolution} (from max input dimension {max_input_dim})") # Build contents (images first if editing, prompt only if generating) if input_images: @@ -182,9 +169,8 @@ def main(): model="gemini-3-pro-image-preview", contents=contents, config=types.GenerateContentConfig( - response_modalities=["TEXT", "IMAGE"], - image_config=types.ImageConfig(**image_cfg_kwargs) - ) + response_modalities=["TEXT", "IMAGE"], image_config=types.ImageConfig(**image_cfg_kwargs) + ), ) # Process response and convert to PNG @@ -201,19 +187,20 @@ def main(): if isinstance(image_data, str): # If it's a string, it might be base64 import base64 + image_data = base64.b64decode(image_data) image = PILImage.open(BytesIO(image_data)) # Ensure RGB mode for PNG (convert RGBA to RGB with white background if needed) - if image.mode == 'RGBA': - rgb_image = PILImage.new('RGB', image.size, (255, 255, 255)) + if image.mode == "RGBA": + rgb_image = PILImage.new("RGB", image.size, (255, 255, 255)) rgb_image.paste(image, mask=image.split()[3]) - rgb_image.save(str(output_path), 'PNG') - elif image.mode == 'RGB': - image.save(str(output_path), 'PNG') + rgb_image.save(str(output_path), "PNG") + elif image.mode == "RGB": + image.save(str(output_path), "PNG") else: - image.convert('RGB').save(str(output_path), 'PNG') + image.convert("RGB").save(str(output_path), "PNG") image_saved = True if image_saved: diff --git a/skills/openai-image-gen/scripts/gen.py b/skills/openai-image-gen/scripts/gen.py index 2d8c7569016..1fd61f0f7a3 100644 --- a/skills/openai-image-gen/scripts/gen.py +++ b/skills/openai-image-gen/scripts/gen.py @@ -58,9 +58,7 @@ def pick_prompts(count: int) -> list[str]: ] prompts: list[str] = [] for _ in range(count): - prompts.append( - f"{random.choice(styles)} of {random.choice(subjects)}, {random.choice(lighting)}" - ) + prompts.append(f"{random.choice(styles)} of {random.choice(subjects)}, {random.choice(lighting)}") return prompts @@ -100,9 +98,7 @@ def normalize_optional_flag( value = aliases.get(value, value) if value not in allowed: - raise ValueError( - f"Invalid --{flag_name} '{raw_value}'. Allowed values: {allowed_text}." - ) + raise ValueError(f"Invalid --{flag_name} '{raw_value}'. Allowed values: {allowed_text}.") return value @@ -115,10 +111,7 @@ def normalize_background(model: str, background: str) -> str: supported=lambda candidate: candidate.startswith("gpt-image"), allowed={"transparent", "opaque", "auto"}, allowed_text="transparent, opaque, auto", - unsupported_message=( - "Warning: --background is only supported for gpt-image models; " - "ignoring for '{model}'." - ), + unsupported_message=("Warning: --background is only supported for gpt-image models; ignoring for '{model}'."), ) @@ -131,9 +124,7 @@ def normalize_style(model: str, style: str) -> str: supported=lambda candidate: candidate == "dall-e-3", allowed={"vivid", "natural"}, allowed_text="vivid, natural", - unsupported_message=( - "Warning: --style is only supported for dall-e-3; ignoring for '{model}'." - ), + unsupported_message=("Warning: --style is only supported for dall-e-3; ignoring for '{model}'."), ) @@ -147,8 +138,7 @@ def normalize_output_format(model: str, output_format: str) -> str: allowed={"png", "jpeg", "webp"}, allowed_text="png, jpeg, webp", unsupported_message=( - "Warning: --output-format is only supported for gpt-image models; " - "ignoring for '{model}'." + "Warning: --output-format is only supported for gpt-image models; ignoring for '{model}'." ), aliases={"jpg": "jpeg"}, ) @@ -245,9 +235,15 @@ def main() -> int: ap.add_argument("--prompt", help="Single prompt. If omitted, random prompts are generated.") ap.add_argument("--count", type=int, default=8, help="How many images to generate.") ap.add_argument("--model", default="gpt-image-1", help="Image model id.") - ap.add_argument("--size", default="", help="Image size (e.g. 1024x1024, 1536x1024). Defaults based on model if not specified.") - ap.add_argument("--quality", default="", help="Image quality (e.g. high, standard). Defaults based on model if not specified.") - ap.add_argument("--background", default="", help="Background transparency (GPT models only): transparent, opaque, or auto.") + ap.add_argument( + "--size", default="", help="Image size (e.g. 1024x1024, 1536x1024). Defaults based on model if not specified." + ) + ap.add_argument( + "--quality", default="", help="Image quality (e.g. high, standard). Defaults based on model if not specified." + ) + ap.add_argument( + "--background", default="", help="Background transparency (GPT models only): transparent, opaque, or auto." + ) ap.add_argument("--output-format", default="", help="Output format (GPT models only): png, jpeg, or webp.") ap.add_argument("--style", default="", help="Image style (dall-e-3 only): vivid or natural.") ap.add_argument("--out-dir", default="", help="Output directory (default: ./tmp/openai-image-gen-).") @@ -265,7 +261,10 @@ def main() -> int: count = args.count if args.model == "dall-e-3" and count > 1: - print(f"Warning: dall-e-3 only supports generating 1 image at a time. Reducing count from {count} to 1.", file=sys.stderr) + print( + f"Warning: dall-e-3 only supports generating 1 image at a time. Reducing count from {count} to 1.", + file=sys.stderr, + ) count = 1 out_dir = Path(args.out_dir).expanduser() if args.out_dir else default_out_dir() diff --git a/skills/openai-image-gen/scripts/test_gen.py b/skills/openai-image-gen/scripts/test_gen.py index 76445c0bb78..79d418c3e4c 100644 --- a/skills/openai-image-gen/scripts/test_gen.py +++ b/skills/openai-image-gen/scripts/test_gen.py @@ -82,6 +82,8 @@ def test_normalize_output_format_normalizes_case_for_supported_values(): def test_normalize_output_format_strips_whitespace_for_supported_values(): assert normalize_output_format("gpt-image-1", " png ") == "png" + + def test_normalize_output_format_keeps_supported_values(): assert normalize_output_format("gpt-image-1", "png") == "png" assert normalize_output_format("gpt-image-1", "jpeg") == "jpeg" diff --git a/skills/skill-creator/scripts/quick_validate.py b/skills/skill-creator/scripts/quick_validate.py index e8737b4f156..86897b373d7 100644 --- a/skills/skill-creator/scripts/quick_validate.py +++ b/skills/skill-creator/scripts/quick_validate.py @@ -6,7 +6,6 @@ Quick validation script for skills - minimal version import re import sys from pathlib import Path -from typing import Optional try: import yaml @@ -16,7 +15,7 @@ except ModuleNotFoundError: MAX_SKILL_NAME_LENGTH = 64 -def _extract_frontmatter(content: str) -> Optional[str]: +def _extract_frontmatter(content: str) -> str | None: lines = content.splitlines() if not lines or lines[0].strip() != "---": return None @@ -26,13 +25,13 @@ def _extract_frontmatter(content: str) -> Optional[str]: return None -def _parse_simple_frontmatter(frontmatter_text: str) -> Optional[dict[str, str]]: +def _parse_simple_frontmatter(frontmatter_text: str) -> dict[str, str] | None: """ Minimal fallback parser used when PyYAML is unavailable. Supports simple `key: value` mappings used by SKILL.md frontmatter. """ parsed: dict[str, str] = {} - current_key: Optional[str] = None + current_key: str | None = None for raw_line in frontmatter_text.splitlines(): stripped = raw_line.strip() if not stripped or stripped.startswith("#"): @@ -43,9 +42,7 @@ def _parse_simple_frontmatter(frontmatter_text: str) -> Optional[dict[str, str]] if current_key is None: return None current_value = parsed[current_key] - parsed[current_key] = ( - f"{current_value}\n{stripped}" if current_value else stripped - ) + parsed[current_key] = f"{current_value}\n{stripped}" if current_value else stripped continue if ":" not in stripped: @@ -55,9 +52,7 @@ def _parse_simple_frontmatter(frontmatter_text: str) -> Optional[dict[str, str]] value = value.strip() if not key: return None - if (value.startswith('"') and value.endswith('"')) or ( - value.startswith("'") and value.endswith("'") - ): + if (value.startswith('"') and value.endswith('"')) or (value.startswith("'") and value.endswith("'")): value = value[1:-1] parsed[key] = value current_key = key @@ -129,8 +124,7 @@ def validate_skill(skill_path): if len(name) > MAX_SKILL_NAME_LENGTH: return ( False, - f"Name is too long ({len(name)} characters). " - f"Maximum is {MAX_SKILL_NAME_LENGTH} characters.", + f"Name is too long ({len(name)} characters). Maximum is {MAX_SKILL_NAME_LENGTH} characters.", ) description = frontmatter.get("description", "")