Skip to main content

A utility to generate Clio API models from OpenAPI specifications for use with our Clio API Python Client.

Project description

Usage

Installation

pip install clio-api-model-generator

Generating Models

To execute the generator and produce dataclass models, run:

from clio_api_model_generator import clio_manage as manage_model_generator

manage_model_generator.generate_models(output_dir=models_dir, overwrite=False)

This script will initialize the models directory, download the OpenAPI spec, and generate all necessary dataclasses.


Model Generator Generation Flow

This document explains the setup process for handling the models directory, running generator scripts, and ensuring the correct paths are set dynamically.

Overview

The project handles the models directory in the following way:

  1. Checks for the existence of the models folder in the parent directory first (preferred).
  2. If not found in the parent, it checks the project root directory.
  3. If the folder exists and is not empty, it is backed up with a unique name (e.g., models.backup, models.backup1, etc.).
  4. If no models folder is found, a new one is created in the preferred location (parent or project root).
  5. Static files from the static/ directory are copied into the models folder.
  6. Environment variables are set to ensure the generator scripts use the correct folder paths.
  7. Generator scripts are imported after paths are set.

Setup Process

Execution Flow Summary

  1. Check parent directory for models folder first.
  2. Backup existing folder if not empty and create a new one.
  3. Copy static files into the models folder.
  4. Set environment variables with the correct paths.
  5. Import generator scripts that rely on the updated paths.

Expected Outputs

Case 1: Models folder found in the parent directory and backed up

Existing non-empty models directory found at: /home/user/models
Renamed "/home/user/models" to "/home/user/models.backup"
Created new "/home/user/models" directory.
Copied all files from "static/" to "/home/user/models".
Set environment variables for model paths: /home/user/models

Case 2: No models folder found, creating a new one

No existing "models" directory found in parent or current directory.
Created new "/home/user/project/models" directory.
Copied all files from "static/" to "/home/user/project/models".
Set environment variables for model paths: /home/user/project/models

Notes

  • Ensure the static/ directory exists and contains the required files before running the script.
  • The parent directory is prioritized when determining the location of the models folder.
  • Environment variables are crucial to dynamically set paths without modifying scripts manually.

Dataclass Generator Scripts

This document provides an overview of the dataclass generator scripts, explaining their order of execution, flow, and parsing/extraction logic for each generator.

Overview

The scripts process an OpenAPI specification to generate Python dataclasses for:

  1. Schemas – Representing API response objects.
  2. Fields – Handling OpenAPI field mappings.
  3. Query Parameters – Handling API query parameters.
  4. Request Bodies – Handling request payloads.
  5. Endpoints – Registering API endpoints with generated models.

Order of Execution

The generation process is orchestrated by generate_models.py, which follows this sequence:

  1. Initialization (folder setup and OpenAPI spec download)

    • Ensures the models directory is ready.
    • Downloads the OpenAPI spec if not present.
  2. Schema Generation (components.py)

    • Generates dataclasses from OpenAPI schemas.
  3. Field Extraction (fields.py)

    • Extracts field definitions for models based on schema dependencies.
  4. Query Parameter Handling (query.py)

    • Creates query dataclasses based on API query parameters.
  5. Request Body Handling (request_body.py)

    • Processes and generates dataclasses for API request bodies.
  6. Endpoint Registry Creation (endpoints.py)

    • Registers generated models to the API endpoint paths.

Parsing and Extraction Logic

1. Schema Generator (components.py)

Purpose:
Processes OpenAPI components.schemas to generate Python dataclasses.

Key Logic:

  • Reads the OpenAPI spec from SPEC_FILE_PATH.
  • Iterates over schemas containing _base in the name.
  • Recursively processes properties:
    • Required fields are listed first.
    • Optional fields are annotated with Optional.
  • Handles nested objects by generating sub-dataclasses.

Example Output:

@dataclass
class UserBase:
    id: int
    name: str
    email: Optional[str] = None

Fields Generation (fields.py)

Purpose

The fields.py script generates dataclasses that represent OpenAPI schema field definitions, including handling dependencies and nested resources.

Key Steps in Fields Generation

  1. Reading OpenAPI Spec:

    • Reads schema definitions from SPEC_FILE_PATH.
    • Focuses on schemas without underscores (filters _base schemas).
  2. Processing Base Fields:

    • Base schema references are extracted from allOf definitions.
    • Fields are copied from the base schema into the generated dataclass.
    • Field names are sanitized to be valid Python identifiers.
  3. Handling Nested Resources:

    • Nested resources are identified within the schema.
    • If a nested reference is found, the corresponding nested resource dataclass is created and included in the parent class.
    • Nested fields are marked as Optional and are postponed if dependencies exist.
  4. Topological Sorting:

    • Ensures that dataclasses are generated in the correct dependency order.
    • Handles cyclic dependencies by raising errors.
  5. Mapping to Endpoints:

    • Generates a mapping of fields to API responses using list and show schemas.
    • Outputs a endpoint_field_mapping.json file for later use in endpoint definitions.

Example Workflow in fields.py

Input OpenAPI Schema Example

"Account": {
    "allOf": [
        { "$ref": "#/components/schemas/BaseEntity" },
        {
            "properties": {
                "name": { "type": "string" },
                "contacts": {
                    "$ref": "#/components/schemas/Contact"
                }
            }
        }
    ]
},
"Contact": {
    "properties": {
        "email": { "type": "string" },
        "phone": { "type": "string" }
    }
}

Output Generated Dataclass

from dataclasses import dataclass
from typing import Optional
from models.schemas import *

@dataclass
class Account_Fields:
    id: Optional[int] = None
    created_at: Optional[str] = None
    name: Optional[str] = None
    contacts: Optional[Contact_Fields] = None

Handling Base Fields

  1. Base Schema Reference Processing:

    • Extracted from the first allOf item.
    • Fields from the referenced schema (e.g., BaseEntity) are added.
  2. Base Fields Example:

    @dataclass
    class BaseEntity:
        id: Optional[int] = None
        created_at: Optional[str] = None
    

Handling Nested Resources

  1. Detecting Nested Fields:

    • Any field containing a reference ($ref) to another schema is treated as a nested resource.
    • These are appended with _Fields and added to the parent dataclass.
  2. Nested Field Example:

    @dataclass
    class Contact_Fields:
        email: Optional[str] = None
        phone: Optional[str] = None
    
  3. Embedding in Parent:

    @dataclass
    class Account_Fields:
        name: Optional[str] = None
        contacts: Optional[Contact_Fields] = None
    

Mapping to Endpoints

The generator script processes schemas with _list and _show suffixes to establish relationships between fields and endpoint responses.

Example Mapping in endpoint_field_mapping.json:

{
    "Account_list": "Account_Fields",
    "User_show": "User_Fields"
}

Logic:

  • The mapping associates the API response schemas to the generated field dataclasses.
  • Helps the endpoint generator (endpoints.py) link responses to correct models.

3. Query Generator (query.py)

Purpose:
Generates dataclasses for API query parameters.

Key Logic:

  • Reads query parameters from API operations.
  • Transforms query parameter names to valid Python identifiers.
  • Maps OpenAPI types to Python types.
  • Writes required and optional fields separately.

Example Output:

@dataclass
class AccountQuery:
    account_id: int
    status: Optional[str] = None

4. Request Body Generator (request_body.py)

Purpose:
Processes request body parameters for API operations.

Key Logic:

  • Extracts the request body schema from application/json content.
  • Handles nested object properties.
  • Generates dataclasses with required and optional fields.

Example Output:

@dataclass
class CreateAccountRequestBody:
    name: str
    email: str
    age: Optional[int] = None

5. Endpoints Generator (endpoints.py)

Purpose:
Creates an Endpoints registry to store endpoint mappings.

Key Logic:

  • Iterates through API paths and methods.
  • Stores metadata such as path, method, query, and request body models.
  • Handles special download cases based on HTTP 303 responses.

Example Output:

class Endpoints:
    registry = {
        'get_user': {
            'path': '/users/{user_id}',
            'method': 'GET',
            'query_model': UserQuery,
            'request_body_model': None
        }
    }

Directory Structure

project-root/
│-- models/
│   ├── query.py
│   ├── request_body.py
│   ├── endpoints.py
│   ├── fields.py
│   ├── schemas.py
│-- static/
│   ├── __init__.py
│   ├── models_registry.py
│-- generate_models.py
│-- openapi.json

Static files get copied to models directory automatically before generating the model dataclasses

Conclusion

This setup automates the creation of Python dataclasses from an OpenAPI spec, providing a structured way to handle API interactions and ensuring maintainability through a clear generation flow.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

clio_api_model_generator-0.2.4.tar.gz (21.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

clio_api_model_generator-0.2.4-py3-none-any.whl (23.8 kB view details)

Uploaded Python 3

File details

Details for the file clio_api_model_generator-0.2.4.tar.gz.

File metadata

  • Download URL: clio_api_model_generator-0.2.4.tar.gz
  • Upload date:
  • Size: 21.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.12

File hashes

Hashes for clio_api_model_generator-0.2.4.tar.gz
Algorithm Hash digest
SHA256 8328621eed7f293f576f05960b01449edc080755f65627164d17358dc3cb0bfe
MD5 d379cb2f0fb286cfd32ea0d0cc57b893
BLAKE2b-256 6a7773bd3b47670922afb1880bb4303a967d514ebf94c5ff4d7178f23b0e8bd8

See more details on using hashes here.

File details

Details for the file clio_api_model_generator-0.2.4-py3-none-any.whl.

File metadata

File hashes

Hashes for clio_api_model_generator-0.2.4-py3-none-any.whl
Algorithm Hash digest
SHA256 94754257bf49944ea8693d75556c5134ec0db36d90997561fc676736fae38d63
MD5 f064ed72413c1f930ef6d619ae8504f2
BLAKE2b-256 623ad0ce5d00e934cfd4a0bfb876a0a6adbd61c805dc5def7b0c1ee99f7873a9

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page