diff --git a/LICENSE.md b/LICENSE.md index 091e634..5b3dfdd 100755 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,5 +1,6 @@ Copyright © 2019, [Encode OSS Ltd](https://www.encode.io/). Copyright © 2019, [Awesome Toolbox](https://www.awesometoolbox.com/). +Copyright © 2019, [MushroomMaula](https://github.com/MushroomMaula). All rights reserved. diff --git a/Pipfile b/Pipfile index a75d143..4f0ee95 100644 --- a/Pipfile +++ b/Pipfile @@ -4,12 +4,14 @@ verify_ssl = true name = "pypi" [packages] -ormantic = {editable = true, path = "."} +pydantic = "*" +sqlalchemy = "*" [dev-packages] aiosqlite = "*" pytest = "*" ipython = "*" +databases = {extras = ["aiosqlite"],version = "*"} [requires] python_version = "3.6" diff --git a/README.md b/README.md index a8af2e9..7734d37 100755 --- a/README.md +++ b/README.md @@ -1,3 +1,7 @@ +# Note +This repo was created as a fork of [awesometoolbox/ormantic](https://github.com/awesometoolbox/ormantic) to fix some issues. +It is not being developed anymore. Have a look at [collerek/ormar](https://github.com/collerek/ormar) for an actively maintained fork. + # Ormantic The `ormantic` package is an async ORM for Python, with support for Postgres, diff --git a/setup.py b/setup.py index 6db49b0..558355e 100755 --- a/setup.py +++ b/setup.py @@ -7,7 +7,7 @@ PACKAGE = "ormantic" -URL = "https://github.com/awesometoolbox/ormantic" +URL = "https://github.com/mushroommaula/ormantic" def get_version(package): @@ -38,11 +38,11 @@ def get_long_description(): long_description_content_type="text/markdown", author="Awesome Toolbox", author_email="info@awesometoolbox.com", - packages=find_packages("src/"), + packages=find_packages("src"), package_data={PACKAGE: ["py.typed"]}, package_dir={'': 'src'}, data_files=[("", ["LICENSE.md"])], - install_requires=["databases>=0.2.1", "pydantic==0.29"], + install_requires=["databases>=0.2.1", "pydantic"], classifiers=[ "Development Status :: 3 - Alpha", "Environment :: Web Environment", diff --git a/src/ormantic/__init__.py b/src/ormantic/__init__.py index 39788e3..1883666 100755 --- a/src/ormantic/__init__.py +++ b/src/ormantic/__init__.py @@ -3,6 +3,7 @@ Boolean, Date, DateTime, + Decimal, Enum, Float, ForeignKey, @@ -15,7 +16,7 @@ ) from ormantic.models import Model -__version__ = "0.0.29" +__version__ = "0.0.32" __all__ = [ "NoMatch", "MultipleMatches", diff --git a/src/ormantic/fields.py b/src/ormantic/fields.py index 9665f48..c3694a9 100644 --- a/src/ormantic/fields.py +++ b/src/ormantic/fields.py @@ -1,6 +1,7 @@ import json import re from datetime import datetime, date, time +from decimal import Decimal as D from typing import Type, Any import pydantic @@ -135,6 +136,37 @@ def Float( return type("Float", (pydantic.ConstrainedFloat, ColumnFactory), namespace) +def Decimal( + *, + primary_key: bool = False, + allow_null: bool = False, + index: bool = False, + unique: bool = False, + minimum: float = None, + maximum: float = None, + multiple_of: int = None, + precision: int = None, + scale: int = None, + max_digits: int = None, + decimal_places: int = None, +): + namespace = dict( + primary_key=primary_key, + allow_null=allow_null, + index=index, + unique=unique, + ge=minimum, + le=maximum, + multiple_of=multiple_of, + column_type=sqlalchemy.types.DECIMAL(precision=precision, scale=scale), + precision=precision, + scale=scale, + max_digits=max_digits, + decimal_places=decimal_places, + ) + return type("Decimal", (pydantic.ConstrainedDecimal, ColumnFactory), namespace) + + def Boolean( *, primary_key: bool = False, diff --git a/src/ormantic/models.py b/src/ormantic/models.py index c81a4fe..ab826b4 100644 --- a/src/ormantic/models.py +++ b/src/ormantic/models.py @@ -6,6 +6,11 @@ from pydantic.class_validators import Validator, make_generic_validator from .exceptions import MultipleMatches, NoMatch +if hasattr(pydantic.main, 'MetaModel'): + ModelMeta = pydantic.main.MetaModel +else: + ModelMeta = pydantic.main.ModelMetaclass + FILTER_OPERATORS = { "any": "any_", "exact": "__eq__", @@ -178,9 +183,8 @@ async def create(self, **kwargs): data = instance.table_dict() # pop id if None - pk_column = getattr(self.table.c, self.pk_name) - if data.get(pk_column, -1) is None: - data.pop(pk_column) + if data.get(self.pk_name, -1) is None: + data.pop(self.pk_name) # Build the insert expression. expr = self.table.insert() @@ -217,7 +221,7 @@ async def delete_many(self, **kwargs): await self.database.execute(expr) -class MetaModel(pydantic.main.MetaModel): +class MetaModel(ModelMeta): @typing.no_type_check def __new__(mcs: type, name, bases, namespace): new_model = super().__new__(mcs, name, bases, namespace) @@ -249,15 +253,17 @@ def __init__(self, **data): data[self.Mapping.pk_name] = data.pop("pk") if typing.TYPE_CHECKING: - self.__values__: Dict[str, Any] = {} - self.__fields_set__: "SetStr" = set() + self.__dict__: typing.Dict[str, typing.Any] = {} + self.__fields_set__: typing.Set[str] = set() pk_only = data.pop("__pk_only__", False) - values, fields_set, _ = pydantic.validate_model( - self, data, raise_exc=not pk_only + values, fields_set, error = pydantic.validate_model( + self, data ) + if not pk_only and error: + raise error - object.__setattr__(self, "__values__", values) + object.__setattr__(self, "__dict__", values) object.__setattr__(self, "__fields_set__", fields_set) @property @@ -368,9 +374,9 @@ def from_row(cls, row, select_related=None): return cls(**item) - def table_dict(self) -> "DictStrAny": + def table_dict(self) -> typing.Dict[str, typing.Any]: get_key = self._get_key_factory(False) - get_key = partial(get_key, self.fields) + get_key = partial(get_key, self.__fields__) def _get_td_value(v: typing.Any) -> typing.Any: if isinstance(v, Model): @@ -387,7 +393,7 @@ def _get_td_value(v: typing.Any) -> typing.Any: return v def _td_iter(): - for k, v in self.__values__.items(): + for k, v in self.__dict__.items(): yield k, _get_td_value(v) return {get_key(k): v for k, v in _td_iter()}