Skip to main content

O! My Models

badge1 badge2 badge3 workflow

Interactive Demo | Documentation | PyPI

Try in Web-UI

Try the online O!MyModels converter or simply use it online: https://archon-omymodels-online.hf.space/ (A big thanks for that goes to https://github.com/archongum)

Examples

You can find usage examples in the example/ folder on GitHub: https://github.com/xnuinside/omymodels/tree/main/example

About library

O! My Models (omymodels) is a library that allow you to generate different ORM & pure Python models from SQL DDL or convert one models type to another (exclude SQLAlchemy Table, it does not supported yet by py-models-parser).

Supported Models:

How to install

    pip install omymodels

How to use

From Python code

Create Models from DDL

By default method create_models generates GinoORM models. Use the argument models_type to specify output format:

  • 'pydantic' - Pydantic v1 models (uses Optional[X])
  • 'pydantic_v2' - Pydantic v2 models (uses X | None syntax, dict | list for JSON)
  • 'sqlalchemy' - SQLAlchemy ORM models
  • 'sqlalchemy_core' - SQLAlchemy Core Tables
  • 'dataclass' - Python Dataclasses
  • 'sqlmodel' - SQLModel models
  • 'openapi3' - OpenAPI 3 (Swagger) schema definitions

A lot of examples in tests/ - https://github.com/xnuinside/omymodels/tree/main/tests.

Pydantic v1 example

from omymodels import create_models


ddl = """
CREATE table user_history (
     runid                 decimal(21) null
    ,job_id                decimal(21)  null
    ,id                    varchar(100) not null
    ,user              varchar(100) not null
    ,status                varchar(10) not null
    ,event_time            timestamp not null default now()
    ,comment           varchar(1000) not null default 'none'
    ) ;
"""
result = create_models(ddl, models_type='pydantic')['code']

# output:
import datetime
from typing import Optional
from pydantic import BaseModel


class UserHistory(BaseModel):

    runid: Optional[int]
    job_id: Optional[int]
    id: str
    user: str
    status: str
    event_time: datetime.datetime
    comment: str

Pydantic v2 example

from omymodels import create_models


ddl = """
CREATE table user_history (
     runid                 decimal(21) null
    ,job_id                decimal(21)  null
    ,id                    varchar(100) not null
    ,user              varchar(100) not null
    ,status                varchar(10) not null
    ,event_time            timestamp not null default now()
    ,comment           varchar(1000) not null default 'none'
    ) ;
"""
result = create_models(ddl, models_type='pydantic_v2')['code']

# output:
from __future__ import annotations

import datetime
from pydantic import BaseModel


class UserHistory(BaseModel):

    runid: float | None = None
    job_id: float | None = None
    id: str
    user: str
    status: str
    event_time: datetime.datetime = datetime.datetime.now()
    comment: str = 'none'

Key differences in Pydantic v2 output:

  • Uses X | None instead of Optional[X]
  • Uses dict | list for JSON/JSONB types instead of Json
  • Includes from __future__ import annotations for Python 3.9 compatibility
  • Nullable fields automatically get = None default

To generate Dataclasses from DDL use argument models_type='dataclass'

for example:

    #  (same DDL as in Pydantic sample)
    result = create_models(ddl, schema_global=False, models_type='dataclass')['code']

    # and result will be: 
    import datetime
    from dataclasses import dataclass


    @dataclass
    class UserHistory:

        id: str
        user: str
        status: str
        runid: int = None
        job_id: int = None
        event_time: datetime.datetime = datetime.datetime.now()
        comment: str = 'none'

GinoORM example. If you provide an input like:

CREATE TABLE "users" (
  "id" SERIAL PRIMARY KEY,
  "name" varchar,
  "created_at" timestamp,
  "updated_at" timestamp,
  "country_code" int,
  "default_language" int
);

CREATE TABLE "languages" (
  "id" int PRIMARY KEY,
  "code" varchar(2) NOT NULL,
  "name" varchar NOT NULL
);

and you will get output:

    from gino import Gino


    db = Gino()


    class Users(db.Model):

        __tablename__ = 'users'

        id = db.Column(db.Integer(), autoincrement=True, primary_key=True)
        name = db.Column(db.String())
        created_at = db.Column(db.TIMESTAMP())
        updated_at = db.Column(db.TIMESTAMP())
        country_code = db.Column(db.Integer())
        default_language = db.Column(db.Integer())


    class Languages(db.Model):

        __tablename__ = 'languages'

        id = db.Column(db.Integer(), primary_key=True)
        code = db.Column(db.String(2))
        name = db.Column(db.String())

From cli

    omm path/to/your.ddl

    # for example
    omm tests/test_two_tables.sql

You can define target path where to save models with -t, --target flag:

    # for example
    omm tests/test_two_tables.sql -t test_path/test_models.py

If you want generate the Pydantic or Dataclasses models - just use flag -m or --models_type='pydantic' / --models_type='dataclass'

    omm /path/to/your.ddl -m dataclass

    # or 
    omm /path/to/your.ddl --models_type pydantic

Small library is used for parse DDL- https://github.com/xnuinside/simple-ddl-parser.

What to do if types not supported in O!MyModels and you cannot wait until PR will be approved

First of all, to parse types correct from DDL to models - they must be in types mypping, for Gino it exitst in this file:

omymodels/gino/types.py types_mapping

If you need to use fast type that not exist in mapping - just do a path before call code with types_mapping.update()

for example:

    from omymodels.models.gino import types
    from omymodels import create_models

    types.types_mapping.update({'your_type_from_ddl': 'db.TypeInGino'})

    ddl = "YOUR DDL with your custom your_type_from_ddl"

    models = create_models(ddl)

    #### And similar for Pydantic types

    from omymodels.models.pydantic import types  types_mapping
    from omymodels import create_models

    types.types_mapping.update({'your_type_from_ddl': 'db.TypeInGino'})

    ddl = "YOUR DDL with your custom your_type_from_ddl"

    models = create_models(ddl, models_type='pydantic')

Schema defenition

There is 2 ways how to define schema in Models:

  1. Globally in Gino() class and it will be like this:
    from gino import Gino
    db = Gino(schema="schema_name")

And this is a default way for put schema during generation - it takes first schema in tables and use it.

  1. But if you work with tables in different schemas, you need to define schema in each model in table_args. O!MyModels can do this also. Just use flag --no-global-schema if you use cli or put argument 'schema_global=False' to create_models() function if you use library from code. Like this:
    ddl = """
    CREATE TABLE "prefix--schema-name"."table" (
    _id uuid PRIMARY KEY,
    one_more_id int
    );
        create unique index table_pk on "prefix--schema-name"."table" (one_more_id) ;
        create index table_ix2 on "prefix--schema-name"."table" (_id) ;
    """
    result = create_models(ddl, schema_global=False)

And result will be this:

    from sqlalchemy.dialects.postgresql import UUID
    from sqlalchemy.schema import UniqueConstraint
    from sqlalchemy import Index
    from gino import Gino

    db = Gino()


    class Table(db.Model):

        __tablename__ = 'table'

        _id = db.Column(UUID, primary_key=True)
        one_more_id = db.Column(db.Integer())

        __table_args__ = (
                    
        UniqueConstraint(one_more_id, name='table_pk'),
        Index('table_ix2', _id),
        dict(schema="prefix--schema-name")
                )

OpenAPI 3 (Swagger) Support

O!MyModels supports bidirectional conversion with OpenAPI 3 schemas.

Generate OpenAPI 3 schema from DDL

from omymodels import create_models

ddl = """
CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    username VARCHAR(100) NOT NULL,
    email VARCHAR(255),
    is_active BOOLEAN DEFAULT TRUE,
    created_at TIMESTAMP
);
"""

result = create_models(ddl, models_type="openapi3")
print(result["code"])

# Output:
# {
#   "components": {
#     "schemas": {
#       "Users": {
#         "type": "object",
#         "properties": {
#           "id": {"type": "integer"},
#           "username": {"type": "string", "maxLength": 100},
#           "email": {"type": "string", "maxLength": 255},
#           "is_active": {"type": "boolean", "default": true},
#           "created_at": {"type": "string", "format": "date-time"}
#         },
#         "required": ["id", "username"]
#       }
#     }
#   }
# }

Convert OpenAPI 3 schema to Python models

from omymodels import create_models_from_openapi3

schema = """
{
    "components": {
        "schemas": {
            "User": {
                "type": "object",
                "properties": {
                    "id": {"type": "integer"},
                    "name": {"type": "string"},
                    "email": {"type": "string"},
                    "created_at": {"type": "string", "format": "date-time"}
                },
                "required": ["id", "name"]
            }
        }
    }
}
"""

# Convert to Pydantic v2
result = create_models_from_openapi3(schema, models_type="pydantic_v2")
print(result)

# Output:
# from __future__ import annotations
#
# import datetime
# from pydantic import BaseModel
#
#
# class User(BaseModel):
#
#     id: int
#     name: str
#     email: str | None = None
#     created_at: datetime.datetime | None = None

YAML schemas are also supported (requires pyyaml):

pip install pyyaml

Custom Generators (Plugin System)

You can add support for your own model types without forking the repository.

Creating a Custom Generator

from omymodels import BaseGenerator, TypeConverter, register_generator, create_models

# Define type mapping
MY_TYPES = {
    "varchar": "String",
    "integer": "Integer",
    "boolean": "Boolean",
    "timestamp": "DateTime",
}

class MyGenerator(BaseGenerator):
    def __init__(self):
        super().__init__()
        self.type_converter = TypeConverter(MY_TYPES)

    def generate_model(self, table, singular=True, **kwargs):
        class_name = table.name.title().replace("_", "")
        lines = [f"class {class_name}(MyBaseModel):"]
        for column in table.columns:
            col_type = self.type_converter.convert(column.type)
            lines.append(f"    {column.name}: {col_type}")
        return "\n".join(lines)

    def create_header(self, tables, **kwargs):
        return "from my_framework import MyBaseModel\n"

# Register and use
register_generator("my_framework", MyGenerator)
result = create_models(ddl, models_type="my_framework")

Extending Built-in Generators

from omymodels import register_generator
from omymodels.models.pydantic_v2.core import ModelGenerator as PydanticV2Generator

class CustomPydanticGenerator(PydanticV2Generator):
    def create_header(self, *args, **kwargs):
        header = super().create_header(*args, **kwargs)
        return "from my_types import CustomType\n" + header

register_generator("my_pydantic", CustomPydanticGenerator)

See full examples in example/custom_generator.py and example/extend_builtin_generator.py.

TODO in next releases

  1. Add Sequence generation in Models (Gino, SQLAlchemy)
  2. Add support for Tortoise ORM (https://tortoise-orm.readthedocs.io/en/latest/)
  3. Add support for DjangoORM Models
  4. Add support for PyDAL Models (https://py4web.com/_documentation/static/en/chapter-07.html)

How to contribute

Please describe issue that you want to solve and open the PR, I will review it as soon as possible.

Any questions? Ping me in Telegram: https://t.me/xnuinside or mail xnuinside@gmail.com

If you see any bugs or have any suggestions - feel free to open the issue. Any help will be appritiated.

Appretiation & thanks

One more time, big 'thank you!' goes to https://github.com/archongum for Web-version: https://archon-omymodels-online.hf.space/

Changelog

See CHANGELOG.md for full version history.

v1.0.0 Highlights

Breaking Changes:

  • Dropped support for Python 3.7 and 3.8
  • Minimum required Python version is now 3.9

New Features:

  • Pydantic v2 support with native syntax (X | None, dict | list)
  • OpenAPI 3 (Swagger) schema generation and conversion
  • Plugin system for custom generators
  • SQLModel array type support
  • MySQL blob types support

Improvements:

  • Simplified datetime imports
  • Better Pydantic field handling (aliases, reserved names, generated columns)
  • Enum functional syntax generation

See CHANGELOG.md for complete details and previous versions.

Metadata

Release files for omymodels 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for omymodels 1.0.0
File Size Uploaded
omymodels-1.0.0.tar.gz 43.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for omymodels 1.0.0
File Interpreter ABI Platform
omymodels-1.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 107.9 kB

Release files / omymodels-1.0.0.tar.gz

Download URL omymodels-1.0.0.tar.gz
Size 43.6 kB
Tags Source
SHA-256 checksum
How to use checksums
62ed5b4a44e555a51d6bcf6881072613dc7be8042bce1823217347d46bfed06d
BLAKE2b-256 checksum
How to use checksums
524e2f9d72a45e86c4d36cd1c9c630e418ace2606adcad7135ea4dfde19b2cd1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.11.12

Release files / omymodels-1.0.0-py3-none-any.whl

Download URL omymodels-1.0.0-py3-none-any.whl
Size 64.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
fed44e1bf4cc688ba82b23bb1a6e7fe48ee0746b5b149733a6bfc99ea603a816
BLAKE2b-256 checksum
How to use checksums
4637925fa04ad23b9a0f307e050635010c4158b77a148ffb155dfe20ba0ebd5c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.11.12
Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page