{"id":30250729,"url":"https://github.com/orangekame3/pydantic-openapi-sdk","last_synced_at":"2026-04-18T19:33:16.605Z","repository":{"id":309731899,"uuid":"1037322841","full_name":"orangekame3/pydantic-openapi-sdk","owner":"orangekame3","description":"Generate type-safe Python SDKs from OpenAPI 3.x specifications with Pydantic v2 models and synchronous HTTP clients","archived":false,"fork":false,"pushed_at":"2025-08-13T13:54:36.000Z","size":811,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-08-13T14:44:11.569Z","etag":null,"topics":["oas","openapi","pydantic","python"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/orangekame3.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-08-13T11:58:01.000Z","updated_at":"2025-08-13T13:55:40.000Z","dependencies_parsed_at":"2025-08-13T14:44:15.616Z","dependency_job_id":"4a7cf4f9-9712-4d86-995b-60ee6cdbc901","html_url":"https://github.com/orangekame3/pydantic-openapi-sdk","commit_stats":null,"previous_names":["orangekame3/pydantic-openapi-sdk"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/orangekame3/pydantic-openapi-sdk","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/orangekame3%2Fpydantic-openapi-sdk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/orangekame3%2Fpydantic-openapi-sdk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/orangekame3%2Fpydantic-openapi-sdk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/orangekame3%2Fpydantic-openapi-sdk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/orangekame3","download_url":"https://codeload.github.com/orangekame3/pydantic-openapi-sdk/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/orangekame3%2Fpydantic-openapi-sdk/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31982742,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-18T17:30:12.329Z","status":"ssl_error","status_checked_at":"2026-04-18T17:29:59.069Z","response_time":103,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["oas","openapi","pydantic","python"],"created_at":"2025-08-15T10:01:38.015Z","updated_at":"2026-04-18T19:33:16.575Z","avatar_url":"https://github.com/orangekame3.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"docs/img/logo.png\" alt=\"Pydantic OpenAPI SDK Generator\" width=\"350\"\u003e\n  \n  # Pydantic OpenAPI SDK Generator\n\u003c/div\u003e\n\n\u003e [!WARNING]\n\u003e **⚠️ Under Development**  \n\u003e This project is currently under development and experimental. APIs, interfaces, and generated code structure may change in future versions. Use with caution in production environments.\n\nGenerate Python SDKs from OpenAPI 3.x specifications with Pydantic v2 models and synchronous HTTP clients.\n\n## Features\n\n- **OpenAPI 3.x Support** - Parse YAML/JSON specifications and URLs\n- **Synchronous HTTP Client** - Built on httpx for production use\n- **Pydantic v2 Models** - Generated using datamodel-code-generator for accuracy\n- **Advanced Type System** - Precise return types (Pet, list[Pet], Order) instead of Any\n- **Automatic Model Serialization** - Seamless Pydantic model → JSON conversion\n- **Python Naming Conventions** - camelCase parameters converted to snake_case (petId → pet_id)\n- **Customizable Client Class** - Configure client class name (e.g., \"PetStore\", \"ApiClient\")  \n- **Multiple Authentication** - Bearer token, API key, and Basic auth\n- **YAML Configuration** - Manage generation settings in config files\n- **Code Organization** - Operations grouped by tags, clean structure\n- **Type Safety** - Full type hints throughout generated code\n- **Error Handling** - Structured exception management\n- **Make Integration** - Unified build and test workflows\n\n## Installation\n\n```bash\npip install pydantic-openapi-sdk\n```\n\nOr with uv:\n\n```bash\nuv add pydantic-openapi-sdk\n```\n\n## Quick Start\n\n### 1. Generate SDK\n\nFrom Swagger Pet Store API:\n\n```bash\npydantic-openapi-sdk generate \\\n  --spec https://petstore3.swagger.io/api/v3/openapi.json \\\n  --out ./examples/gen \\\n  --package petstore \\\n  --client-name PetStore\n```\n\nWith configuration file:\n\n```bash\npydantic-openapi-sdk generate --config configs/petstore.yaml\n```\n\n**Note**: For clean regeneration (recommended), remove the existing output directory first:\n\n```bash\nrm -rf ./examples/gen \u0026\u0026 pydantic-openapi-sdk generate --config configs/petstore.yaml\n```\n\n### 2. Use Generated SDK\n\n```python\nfrom petstore import PetStore, BearerAuth\nfrom petstore.api import pet, store\nfrom petstore.models import Pet, Category, Tag\n\n# Create client\nclient = PetStore(\n    base_url=\"https://petstore3.swagger.io/api/v3\",\n    auth=BearerAuth(\"your-token\")\n)\n\n# Find available pets\navailable_pets = pet.find_pets_by_status(client, status=\"available\")\nprint(f\"Found {len(available_pets)} available pets\")\n\n# Get store inventory\ninventory = store.get_inventory(client)\nprint(f\"Store inventory: {inventory}\")\n\n# Create and add a new pet (with type safety)\nnew_pet = Pet(\n    name=\"Buddy\",\n    category=Category(id=1, name=\"Dogs\"),\n    photoUrls=[\"https://example.com/photo.jpg\"],\n    tags=[Tag(id=1, name=\"friendly\")],\n    status=\"available\"\n)\n\n# Add pet - automatically serializes Pydantic model to JSON\nadded_pet: Pet = pet.add_pet(client, body=new_pet)\nprint(f\"Added pet: {added_pet.name} (ID: {added_pet.id})\")\n```\n\n## Configuration\n\n### YAML Configuration File\n\nCreate a configuration file to manage settings:\n\n```yaml\n# petstore.yaml\nspec: \"https://petstore3.swagger.io/api/v3/openapi.json\"\noutput_dir: \"examples/gen\"\npackage_name: \"petstore\"\nbase_url: \"https://petstore3.swagger.io/api/v3\"\nverbose: true\n\n# Code generation options\nuse_union_operator: true\n\n# Model generation options (passed to datamodel-code-generator)\nmodel_options:\n  field_constraints: true              # Generate field constraints\n  use_standard_typing: false          # Use typing_extensions\n  use_generic_container_types: true   # Use list[T] instead of List[T]\n\n# Client options\ntimeout: 30\nuser_agent: \"pydantic-openapi-sdk/1.0.0\"\nclient_class_name: \"PetStore\"  # Custom client class name (default: \"Client\")\n```\n\n### CLI Options\n\n| Option          | Description             | Example                      |\n| --------------- | ----------------------- | ---------------------------- |\n| `--config`      | Configuration file path | `--config config.yaml`       |\n| `--spec`        | OpenAPI spec file/URL   | `--spec openapi.json`        |\n| `--out`         | Output directory        | `--out ./generated`          |\n| `--package`     | Package name            | `--package my_sdk`           |\n| `--base-url`    | Default base URL        | `--base-url https://api.com` |\n| `--timeout`     | HTTP timeout (seconds)  | `--timeout 60`               |\n| `--client-name` | Client class name       | `--client-name ApiClient`    |\n| `--verbose`     | Verbose output          | `--verbose`                  |\n\nCLI options override configuration file settings.\n\n## Generated SDK Structure\n\n```text\npetstore/\n├── __init__.py          # Package exports\n├── client.py            # HTTP client and authentication\n├── exceptions.py        # Error classes\n├── api/\n│   ├── __init__.py\n│   ├── pet.py           # Pet operations\n│   ├── store.py         # Store operations\n│   └── user.py          # User operations\n└── models/\n    └── __init__.py      # Pydantic models\n```\n\n## Advanced Features\n\n### Type-Safe API Generation\n\nThe generator creates precise type annotations by analyzing OpenAPI schemas:\n\n```python\n# Generated functions with precise types and snake_case parameters:\ndef get_pet_by_id(client: PetStore, pet_id: int) -\u003e Pet:\ndef find_pets_by_status(client: PetStore, status: str) -\u003e list[Pet]:\ndef get_order_by_id(client: PetStore, order_id: int) -\u003e Order:\ndef get_inventory(client: PetStore) -\u003e dict[str, int]:\n```\n\n### Automatic Model Detection\n\nThe generator analyzes generated Pydantic models to ensure type consistency:\n\n- **Schema Reference Resolution**: `#/components/schemas/Pet` → `Pet` class\n- **Name Conflict Handling**: `Status` vs `Status1` enum conflicts resolved automatically  \n- **Validation Fallbacks**: Unknown types safely default to `Any`\n\n### Python Naming Conventions\n\nThe generator automatically converts OpenAPI parameter names to Python snake_case while preserving original names for API requests:\n\n```python\n# OpenAPI spec has: /pet/{petId}\n# Generated function uses Python conventions:\ndef get_pet_by_id(client: PetStore, pet_id: int) -\u003e Pet:  # snake_case parameter\n    path = f\"/pet/{pet_id}\"  # Uses Python variable\n    # But API request still uses: GET /pet/123 (original spec preserved)\n\n# Query parameters work the same way:\ndef update_pet_with_form(client: PetStore, pet_id: int, name: str = None) -\u003e Pet:\n    params = {}\n    if name is not None:\n        params[\"name\"] = name  # Original API parameter name preserved\n    return client.request(\"post\", f\"/pet/{pet_id}\", params=params)\n```\n\n### Smart Serialization\n\nRequest bodies are automatically serialized based on type analysis:\n\n```python\n# For Pydantic models - automatic serialization\ndef add_pet(client: PetStore, body: Pet) -\u003e Pet:\n    response = client.request(\"post\", path, params=params, \n        json=body.model_dump(mode='json') if hasattr(body, 'model_dump') else body)\n\n# For raw data - pass through unchanged  \ndef upload_data(client: PetStore, body: dict[str, Any]) -\u003e Response:\n    response = client.request(\"post\", path, params=params, json=body)\n```\n\n## Usage Examples\n\n### Basic Client Usage\n\n```python\nfrom petstore import PetStore, ApiError\nfrom petstore.api import pet\n\nclient = PetStore(base_url=\"https://petstore3.swagger.io/api/v3\")\n\ntry:\n    available_pets = pet.find_pets_by_status(client, status=\"available\")\n    print(f\"Found {len(available_pets)} available pets\")\nexcept ApiError as e:\n    print(f\"API error: {e.status_code} - {e.message}\")\n```\n\n### Authentication\n\n```python\nfrom petstore import PetStore, BearerAuth, ApiKeyAuth, BasicAuth\n\n# Bearer token\nclient = PetStore(\n    base_url=\"https://petstore3.swagger.io/api/v3\",\n    auth=BearerAuth(\"your-jwt-token\")\n)\n\n# API key\nclient = PetStore(\n    base_url=\"https://petstore3.swagger.io/api/v3\",\n    auth=ApiKeyAuth(\"your-api-key\", \"X-API-Key\")\n)\n\n# Basic auth\nclient = PetStore(\n    base_url=\"https://petstore3.swagger.io/api/v3\",\n    auth=BasicAuth(\"username\", \"password\")\n)\n```\n\n### Type System Benefits\n\n```python\nfrom petstore.api import pet, store\nfrom petstore.models import Pet, Category, Tag\n\n# Precise return types with snake_case parameters\npets: list[Pet] = pet.find_pets_by_status(client, status=\"available\")\nsingle_pet: Pet = pet.get_pet_by_id(client, pet_id=1)\norder: Order = store.get_order_by_id(client, order_id=123)\ninventory: dict[str, int] = store.get_inventory(client)\n\n# Automatic Pydantic model serialization\nnew_pet = Pet(name=\"Max\", photoUrls=[\"photo.jpg\"])\nresult: Pet = pet.add_pet(client, body=new_pet)  # Automatically converts to JSON\n\n# IDE autocompletion and type checking\nfor p in pets:\n    print(f\"Pet: {p.name}\")  # IDE knows p is Pet, not Any\n    if p.category:\n        print(f\"Category: {p.category.name}\")  # Full type safety\n```\n\n### Working with Models\n\n```python\nfrom petstore.models import Pet, Category, Tag\nfrom pydantic import ValidationError\n\n# Create model with validation\ntry:\n    new_pet = Pet(\n        name=\"Buddy\",\n        category=Category(id=1, name=\"Dogs\"),\n        photoUrls=[\"https://example.com/photo.jpg\"],\n        tags=[Tag(id=1, name=\"friendly\")],\n        status=\"available\"\n    )\n    # No manual serialization needed - handled automatically!\n    added_pet = pet.add_pet(client, body=new_pet)\nexcept ValidationError as e:\n    print(f\"Validation error: {e}\")\n```\n\n### Error Handling\n\n```python\nfrom petstore import ApiError\nfrom petstore.api import pet\n\ntry:\n    pet_data: Pet = pet.get_pet_by_id(client, pet_id=999)\nexcept ApiError as e:\n    if e.status_code == 404:\n        print(\"Pet not found\")\n    elif e.status_code == 401:\n        print(\"Authentication required\")\n    elif e.status_code \u003e= 500:\n        print(\"Server error\")\n    print(f\"Full error: {e.body}\")\n```\n\n### Context Manager\n\n```python\nfrom petstore import PetStore, BearerAuth\nfrom petstore.api import pet\n\nwith PetStore(base_url=\"https://petstore3.swagger.io/api/v3\", auth=BearerAuth(\"token\")) as client:\n    pets: list[Pet] = pet.find_pets_by_status(client, status=\"available\")\n    # Client automatically closes\n```\n\n## Development\n\n### Setup\n\n```bash\ngit clone https://github.com/orangekame3/pydantic-openapi-sdk\ncd pydantic-openapi-sdk\nmake dev\n```\n\n### Available Commands\n\n```bash\nmake help                 # Show available commands\nmake install             # Install dependencies\nmake dev                 # Set up development environment\nmake generate-sdk        # Generate SDK from config\nmake test               # Test generated SDK\nmake test-local         # Generate and test locally\nmake test-real-api      # Full test with real API\nmake lint               # Run code linting\nmake format             # Format code\nmake clean              # Clean generated files\n```\n\n### Testing with Real APIs\n\nTest the generator with the Swagger Pet Store API:\n\n```bash\n# Full test cycle\nmake test-real-api\n\n# Or step by step\nmake download-spec\nmake generate-local-spec\nmake test\n```\n\nThis downloads the official Pet Store OpenAPI spec, generates an SDK, and runs tests against the live API.\n\n## Real-World Example\n\nThe repository includes a complete example using the Swagger Pet Store API:\n\n```python\nfrom petstore_sdk import Client\nfrom petstore_sdk.api import pet\n\nclient = Client(base_url=\"https://petstore3.swagger.io/api/v3\")\navailable_pets = pet.find_pets_by_status(client, status=\"available\")\nprint(f\"Found {len(available_pets)} available pets\")\n```\n\nSee [`examples/`](examples/) for complete working examples.\n\n## Architecture\n\nThis generator uses:\n\n- **[datamodel-code-generator](https://github.com/koxudaxi/datamodel-code-generator)** - Generates accurate Pydantic v2 models from OpenAPI schemas\n- **Jinja2 templates** - Generates client code and API operations\n- **httpx** - HTTP client for generated SDKs\n- **Custom OpenAPI parser** - Handles operations, parameters, and routing\n\n## Requirements\n\n- Python ≥ 3.10\n- Dependencies: httpx, pydantic[email], pyyaml, click, jinja2, datamodel-code-generator\n\n## Current Limitations\n\n- Synchronous client only (async support planned)\n- Basic response type mapping\n- Manual pagination handling\n- Limited file upload support\n\n## Contributing\n\n1. Fork the repository\n2. Create a feature branch\n3. Make changes with tests\n4. Run `make check` to verify code quality\n5. Submit a pull request\n\n## License\n\nApache License 2.0 - see [LICENSE](LICENSE) file for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Forangekame3%2Fpydantic-openapi-sdk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Forangekame3%2Fpydantic-openapi-sdk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Forangekame3%2Fpydantic-openapi-sdk/lists"}