diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index bd6854b..4a10747 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -52,4 +52,30 @@ jobs: with: files: ./coverage.xml fail_ci_if_error: false - verbose: true \ No newline at end of file + verbose: true + + deploy-pages: + runs-on: ubuntu-latest + needs: [tests] + if: github.ref == 'refs/heads/main' && github.event_name == 'push' + permissions: + contents: read + pages: write + id-token: write + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - uses: actions/checkout@v4 + + - name: Setup Pages + uses: actions/configure-pages@v4 + + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + path: './docs' + + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..0620bf3 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,290 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [1.0.0] - 2025-01-18 + +### Breaking Changes + +- Dropped support for Python 3.7 and 3.8 +- Minimum required Python version is now 3.9 + +### Added + +**Pydantic v2 Support** +- New `pydantic_v2` models type with native Pydantic v2 syntax +- Uses `X | None` instead of `Optional[X]` +- Uses `dict | list` for JSON/JSONB types instead of `Json` +- Adds `from __future__ import annotations` for Python 3.9 compatibility +- Nullable fields automatically get `= None` default + +**OpenAPI 3 (Swagger) Support** +- Generate OpenAPI 3 schemas from DDL: `create_models(ddl, models_type="openapi3")` +- Convert OpenAPI 3 schemas to Python models: `create_models_from_openapi3(schema)` +- Supports JSON and YAML input (with pyyaml) + +**Plugin System for Custom Generators** +- `register_generator()` - register custom generator +- `unregister_generator()` - remove custom generator +- `list_generators()` - list all available generators +- Base classes: `BaseGenerator`, `ORMGenerator`, `DataModelGenerator` +- `TypeConverter` class for type mappings +- Entry points support for auto-discovery +- See examples: `example/custom_generator.py`, `example/extend_builtin_generator.py` + +**Pydantic Improvements** +- Field alias support for invalid Python identifiers +- Handle Pydantic reserved names (copy, parse_obj, schema, etc.) +- Support for generated columns (`GENERATED ALWAYS AS`) with `exclude=True` +- `table_prefix` and `table_suffix` parameters for class name customization +- Boolean defaults 0/1 converted to False/True +- Expanded `datetime_now_check` with more SQL datetime keywords + +**SQLModel Improvements** +- Fixed array type generation (issue #66) +- Arrays now properly generate `List[T]` with correct SQLAlchemy ARRAY type +- Added `typing_imports` support for List import +- Added `pydantic_to_sa_fallback` mapping for array element types + +**MySQL Support** +- Added blob types support: `tinyblob`, `blob`, `mediumblob`, `longblob` map to `bytes` (issue #62) + +**Other** +- Added support for Python 3.12 and 3.13 +- Added tox configuration for local multi-version testing (py39-py313) +- Added pytest-cov for code coverage reporting + +### Changed + +- Simplified datetime imports (`from datetime import datetime` instead of `import datetime`) +- Use `Any` type instead of `Json` for json/jsonb columns in Pydantic +- Enum generation now uses functional syntax: `Enum(value='Name', names=[...])` +- Updated GitHub Actions workflow with latest action versions (checkout@v4, setup-python@v5) +- Updated py-models-parser to version 1.0.0 +- Reorganized types module with TypeConverter class + +### Fixed + +- Fixed `iterate_over_the_list()` modifying list during iteration +- Fixed meaningless condition in dataclass generator +- Fixed incorrect column type crash (PR #63) +- Fixed enums including whitespace in values (issue #69) +- Fixed boolean values capitalization - now generates `True`/`False` instead of `true`/`false` (PR #67) +- Fixed SQLModel array type generation TypeError (issue #66) +- Fixed MySQL blob types not mapping to `bytes` (issue #62) + +### Documentation + +- Added ARCHITECTURE.md with project documentation +- Updated documentation with Pydantic v2 examples + +## [0.17.0] + +### Fixed + +- Fix character varying type (issue #59) + +### Changed + +- SQLAlchemy import removed from generation in SQLModels if it is not used +- `= Field()` is not placed in SQLModel if there is no defaults or other settings + +## [0.16.0] + +### Added + +- Initial SQLModel Support + +## [0.15.1] + +### Changed + +- Foreign Key processing updates (PR #55) +- Move to simple-ddl-parser version 1.X + +## [0.14.0] + +### Added + +- Python 3.11 support + +## [0.13.0] + +### Added + +- Added argument `schema_global=` to support SQLAlchemy & Gino different table schemas (issue #41) + +## [0.12.1] + +### Fixed + +- `current_timestamp` function processed now same way as `now()` function from DDL + +## [0.12.0] + +### Fixed + +- Named arguments always go after positional (issue #35) + +### Added + +- Availability to disable auto-name conversion (issue #36) +- `no_auto_snake_case=True` keeps names 1-to-1 as in DDL file + +## [0.11.1] + +### Added + +- Added bytes type to pydantic (PR #31) + +### Changed + +- Parser version updated to the latest + +## [0.11.0] + +### Fixed + +- MSSQL column & table names in `[]` now parsed validly (issue #28) +- Names like `users_WorkSchedule` now converted correctly to PascalCase + +## [0.10.1] + +### Changed + +- Update simple-ddl-parser version to 0.21.2 + +## [0.10.0] + +### Changed + +- Meta models moved to separate package (table-meta) +- `common` module renamed to `from_ddl` + +### Fixed + +- Fixed bugs in converter (still in beta) +- Can generate Enum models if DDL has only CREATE TYPE statements +- String enums now inherit from `(str, Enum)` in all model types + +### Added + +- Converter feature to convert one model type to another (excluding SQLAlchemy Core Tables) + +## [0.9.0] + +### Added + +- Beta models converter from one type of models to another +- If O!MyModels does not know how to convert type - leaves it as is + +### Fixed + +- In Dataclass & Pydantic generators Decimals & Floats converted to float (previously was int) + +## [0.8.4] + +### Changed + +- If tables not found in DDL - raises NoTable error +- Added `exit_silent` flag for silent exit if no tables + +## [0.8.3] + +### Added + +- TableMetaModel class for unified metadata parsing + +### Fixed + +- `NOW()` recognized as `now()` (issue #18) +- Default value of `now()` uses field for dataclass (issue #19) + +## [0.8.1] + +### Fixed + +- Parser version updated (fixed several issues) +- Fixed Unique Constraint after schema in SQLAlchemy Core + +## [0.8.0] + +### Fixed + +- `--defaults-off` flag in CLI + +### Added + +- Support for SQLAlchemy Core Tables generating +- Added examples folder + +### Fixed + +- ForeignKey in SQLAlchemy + +## [0.7.0] + +### Added + +- SQLAlchemy models generation (defaults as 'server_default') +- Defaults for Pydantic models +- `defaults_off=True` flag and `--defaults-off` CLI flag + +### Fixed + +- Enum types with lower case names in DDLs +- Dataclass generation issues (default with datetime & Enums) +- Quotes not removed from defaults + +## [0.6.0] + +### Added + +- Python Dataclass generation from DDL +- ForeignKey generation to GinoORM Models with ondelete/onupdate support + +## [0.5.0] + +### Added + +- Enums/IntEnums types for Gino & Pydantic +- UUID type +- `schema_global` key (default True) +- `--no-global-schema` CLI flag + +### Changed + +- Primary key columns don't show nullable argument + +## [0.4.1] + +### Fixed + +- Table names containing multiple '-' + +## [0.4.0] + +### Added + +- Pydantic models generation from DDL + +### Changed + +- `create_gino_models` renamed to `create_models` + +## [0.3.0] + +### Fixed + +- Generated Index for 'index' statement (not unique constraint) +- Column size as tuple (4,2) + +## [0.2.0] + +### Added + +- Valid generating columns: autoincrement, default, type, arrays, unique, primary key +- Creating `__table_args__` for indexes diff --git a/README.md b/README.md index b474179..e5900bc 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,8 @@ ## O! My Models -   +    +**[Interactive Demo](https://xnuinside.github.io/omymodels/)** | **[Documentation](https://github.com/xnuinside/omymodels#how-to-use)** | **[PyPI](https://pypi.org/project/omymodels/)** ## 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) @@ -498,222 +499,25 @@ If you see any bugs or have any suggestions - feel free to open the issue. Any h One more time, big 'thank you!' goes to https://github.com/archongum for Web-version: https://archon-omymodels-online.hf.space/ ## Changelog -**v1.0.0** -### Breaking Changes -1. Dropped support for Python 3.7 and 3.8 -2. Minimum required Python version is now 3.9 +See [CHANGELOG.md](CHANGELOG.md) for full version history. -### New Features -1. Added support for Python 3.12 and 3.13 -2. Added `pydantic_v2` models type with native Pydantic v2 syntax: - - Uses `X | None` instead of `Optional[X]` - - Uses `dict | list` for JSON/JSONB types instead of `Json` - - Adds `from __future__ import annotations` for Python 3.9 compatibility - - Nullable fields automatically get `= None` default -3. Added plugin system for custom generators - add your own model types without forking: - - `register_generator()` - register custom generator - - `unregister_generator()` - remove custom generator - - `list_generators()` - list all available generators - - Base classes: `BaseGenerator`, `ORMGenerator`, `DataModelGenerator` - - `TypeConverter` class for type mappings - - Entry points support for auto-discovery - - See examples: `example/custom_generator.py`, `example/extend_builtin_generator.py` -4. Added OpenAPI 3 (Swagger) schema support: - - Generate OpenAPI 3 schemas from DDL: `create_models(ddl, models_type="openapi3")` - - Convert OpenAPI 3 schemas to Python models: `create_models_from_openapi3(schema, models_type="pydantic_v2")` - - Supports JSON and YAML input (with pyyaml) -5. Added tox configuration for local multi-version testing (py39-py313) -6. Added pytest-cov for code coverage reporting +### v1.0.0 Highlights -### Improvements -1. Updated GitHub Actions workflow with latest action versions (checkout@v4, setup-python@v5) -2. Added ARCHITECTURE.md with project documentation -3. Updated documentation with Pydantic v2 examples -4. Reorganized types module with TypeConverter class -5. Updated py-models-parser to version 1.0.0 +**Breaking Changes:** +- Dropped support for Python 3.7 and 3.8 +- Minimum required Python version is now 3.9 -### Bug Fixes -1. Fixed `iterate_over_the_list()` modifying list during iteration -2. Fixed meaningless condition in dataclass generator +**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 -**v0.17.0** +**Improvements:** +- Simplified datetime imports +- Better Pydantic field handling (aliases, reserved names, generated columns) +- Enum functional syntax generation -### Updates -1. fix character varying type - https://github.com/xnuinside/omymodels/issues/59 -2. sqlalchemy import removed from generation in sqlmodels if it is not used -3. = Field() - is not placed in SQLModel if there is no defaults or other settings to the field - -**v0.16.0** - -### Updates -1. Initial SQLModel Support - - -**v0.15.1** -## Updates -1. Foreign Key processing updates - https://github.com/xnuinside/omymodels/pull/55 -2. Move to simple-ddl-parser version 1.X - -**v0.14.0** -## Updates - -1. Python 3.11 support. - - -**v0.13.0** -## New feature - -1. Added argument 'schema_global=' to support SQLAlchemy & Gino different table schemas https://github.com/xnuinside/omymodels/issues/41 - -**v0.12.1** -### Improvements - -1. current_timestamp function processed now same was as "now()" function from ddl - - -**v0.12.0** -### Fixes -1. Now named arguments always went after positional. Fix for https://github.com/xnuinside/omymodels/issues/35 - -### New feature: -1. Availability to disable auto-name convertion - https://github.com/xnuinside/omymodels/issues/36. -Now, if you want to keep names 1-to-1 as in your DDL file, you can set argument `no_auto_snake_case=True` and O!MyModels will do nothing with the table or column names. - - - -**v0.11.1** - -### Improvements: -1. added bytes type to pydantic - https://github.com/xnuinside/omymodels/pull/31 -2. parser version updated to the latest - - -**v0.11.0** - -### Fixes: - -1. MSSQL column & tables names in [] now is parsed validly - https://github.com/xnuinside/omymodels/issues/28 -2. names like 'users_WorkSchedule' now converted correctly to PascalCase like UsersWorkSchedule - - -**v0.10.1** -1. Update simple-ddl-parser version to 0.21.2 - - -**v0.10.0** -### Improvements: -1. Meta models moved to separate package - https://github.com/xnuinside/table-meta -2. `common` module renamed to `from_ddl`, but anyway please use public API as imports from main module: - -`from omymodels import create_models` or `from omymodels import convert_models` - -### Fixes: - -1. Fixed bunch of bugs in converter, but it stil in 'beta'. -2. Previously you can generate models if was any tables in ddl. Now you can also generate Enum models if in ddl you have only CREATE TYPE statements. -3. String enums now in any models types will be inherit from (str, Enum) - - -### Features: - -1. Added converter feature to convert one model type to another (excluding SQLAlchemy Core (Tables)). -Now with more tests for supported models, but still in Beta with bucnh of issues. - -**v0.9.0** -Features: -1. Added beta models converter from one type of models to another. -To use models convertor: - -```python -from omymodels import convert_models - - -models_from = """ - -class MaterialType(str, Enum): - - article = "article" - video = "video" - - -@dataclass -class Material: - - id: int - title: str - description: str - link: str - type: MaterialType - additional_properties: Union[dict, list] - created_at: datetime.datetime - updated_at: datetime.datetime - -""" - -result = convert_models(models_from, models_type="gino") -print(result) -``` - -where `models_type` - type of models that you want to get as a result - -2. Now if O!MyModels does not know how to convert type - he just leave it as is. - -Fixes: -1. In Dataclass & Pydantic generators now Decimals & Floats converted to float (previously was int). - -**v0.8.4** -1. Now if tables was not found in input DDL - models generator raise NoTable error. if you want to have still silent exit if no tables, please use flag: exit_silent - -**v0.8.3** -1. Added fundamental concept of TableMetaModel - class that unifies metadata parsed from different classes/ORM models types/DDLs to one standard to allow easy way convert one models to another -in next releases it will be used for converter from one type of models to another. -2. Fixed issue: https://github.com/xnuinside/omymodels/issues/18 "NOW() not recognized as now()" -3. Fixed issue: https://github.com/xnuinside/omymodels/issues/19 "Default value of now() always returns same time, use field for dataclass" - -**v0.8.1** -1. Parser version is updated (fixed several issues with generation) -2. Fixed issue with Unique Constraint after schema in SQLAlchemy Core - -**v0.8.0** -1. Fix --defaults-off flag in cli -2. Added support for SQLAlchemy Core Tables generating -3. Added examples folder in github `omymodels/example` -4. Fix issue with ForeignKey in SQLAlchemy - -**v0.7.0** -1. Added generation for SQLAlchemy models (defaults from DDLs are setting up as 'server_default') -2. Added defaults for Pydantic models -3. Added flag to generate Pydantic & Dataclass models WITHOUT defaults `defaults_off=True` (by default it is False). And cli flag --defaults-off -4. Fixed issue with Enum types with lower case names in DDLs -5. Fixed several issues with Dataclass generation (default with datetime & Enums) -6. '"' do not remove from defaults now - -**v0.6.0** -1. O!MyModels now also can generate python Dataclass from DDL. Use argument models_type='dataclass' or if you use the cli flag --models_type dataclass or -m dataclass -2. Added ForeignKey generation to GinoORM Models, added support for ondelete and onupdate - -**v0.5.0** -1. Added Enums/IntEnums types for Gino & Pydantic -2. Added UUID type -3. Added key `schema_global` in create_models method (by default schema_global = True). -If you set schema_global=False schema if it exists in ddl will be defined for each table (model) in table args. -This way you can have differen schemas per model (table). By default schema_global=True - this mean for all -table only one schema and it is defined in `db = Gino(schema="prefix--schema-name")`. -4. If column is a primary key (primary_key=True) nullable argument not showed, because primary keys always are not null. -5. To cli was added flag '--no-global-schema' to set schema in table_args. - -**v0.4.1** -1. Added correct work with table names contains multiple '-' - -**v0.4.0** -1. Added generation for Pydantic models from ddl -2. Main method create_gino_models renamed to create_models - -**v0.3.0** -1. Generated Index for 'index' statement in __table_args__ (not unique constrait as previously) -2. Fix issue with column size as tuple (4,2) - -**v0.2.0** -1. Valid generating columns in models: autoincrement, default, type, arrays, unique, primary key and etc. -2. Added creating __table_args__ for indexes +See [CHANGELOG.md](CHANGELOG.md) for complete details and previous versions. diff --git a/build.sh b/build.sh index b2503ea..6241e72 100755 --- a/build.sh +++ b/build.sh @@ -1,11 +1,4 @@ #!/bin/bash -# Build script for omymodels package - -# Merge changelog into README (keep full changelog in README.md for PyPI) -sed '/## Changelog/q' README.md > new_README.md -cat CHANGELOG.txt >> new_README.md -rm README.md -mv new_README.md README.md # Build package (PyPI supports Markdown directly via pyproject.toml readme field) rm -rf dist diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 0000000..9d98723 --- /dev/null +++ b/docs/index.html @@ -0,0 +1,763 @@ + + +
+ + +Generate Pydantic, SQLAlchemy, SQLModel, Dataclasses and more from your database schema in seconds
+ ++ * Web UI version may differ from the latest release +
+Paste your SQL, get Python models instantly
+ +CREATE TABLE "users" ( + "id" SERIAL PRIMARY KEY, + "email" VARCHAR(255) NOT NULL, + "name" VARCHAR(100), + "is_active" BOOLEAN DEFAULT TRUE, + "created_at" TIMESTAMP DEFAULT NOW() +);+
from datetime import datetime +from typing import Optional +from pydantic import BaseModel + + +class Users(BaseModel): + id: int + email: str + name: Optional[str] + is_active: Optional[bool] = True + created_at: Optional[datetime] = datetime.now()+
from __future__ import annotations +import datetime +from pydantic import BaseModel + + +class Users(BaseModel): + id: int + email: str + name: str | None = None + is_active: bool | None = True + created_at: datetime.datetime | None = datetime.datetime.now()+
import sqlalchemy as sa +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.sql import func + +Base = declarative_base() + + +class Users(Base): + __tablename__ = 'users' + + id = sa.Column(sa.Integer(), primary_key=True) + email = sa.Column(sa.String(255), nullable=False) + name = sa.Column(sa.String(100)) + is_active = sa.Column(sa.Boolean(), server_default='true') + created_at = sa.Column(sa.TIMESTAMP(), server_default=func.now())+
import datetime +from typing import Optional +from sqlmodel import Field, SQLModel +from sqlalchemy.sql import func + + +class Users(SQLModel, table=True): + __tablename__ = 'users' + + id: Optional[int] = Field(default=None, primary_key=True) + email: str + name: Optional[str] + is_active: Optional[bool] = Field(server_default='true') + created_at: Optional[datetime.datetime] = Field(server_default=func.now())+
import datetime +from dataclasses import dataclass, field + + +@dataclass +class Users: + id: int + email: str + name: str = None + is_active: bool = True + created_at: datetime.datetime = field( + default_factory=datetime.datetime.now + )+
One DDL, many possibilities
+ +pydantic
+ pydantic_v2
+ sqlalchemy
+ sqlmodel
+ dataclass
+ gino
+ openapi3
+ sqlalchemy_core
+ Get started in 3 simple steps
+ +Install via pip in seconds
+pip install omymodels
+ Import and generate models
+from omymodels import create_models + +result = create_models( + ddl, + models_type="pydantic_v2" +) +print(result["code"])+
Generate directly from terminal
+# Generate Pydantic v2 models +omm schema.sql -m pydantic_v2 -t models.py + +# Generate SQLModel +omm schema.sql -m sqlmodel -t models.py+
Everything you need for model generation
+ +Convert between different model types. Turn Pydantic into SQLAlchemy or vice versa.
+Automatically generates Python Enums from SQL ENUM and TYPE definitions.
+Preserves relationships with proper foreign key references and constraints.
+Handles default values, nullable fields, and other column constraints.
+Create custom generators for your own frameworks without forking.
+Generate OpenAPI 3 schemas or convert them to Python models.
+