Skip to content
This repository was archived by the owner on Mar 6, 2021. It is now read-only.

Merge my fork #12

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
1 change: 1 addition & 0 deletions LICENSE.md
Original file line number Diff line number Diff line change
@@ -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.

Expand Down
4 changes: 3 additions & 1 deletion Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -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"
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -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,
Expand Down
6 changes: 3 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@


PACKAGE = "ormantic"
URL = "https://github.com/awesometoolbox/ormantic"
URL = "https://github.com/mushroommaula/ormantic"


def get_version(package):
Expand Down Expand Up @@ -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",
Expand Down
3 changes: 2 additions & 1 deletion src/ormantic/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
Boolean,
Date,
DateTime,
Decimal,
Enum,
Float,
ForeignKey,
Expand All @@ -15,7 +16,7 @@
)
from ormantic.models import Model

__version__ = "0.0.29"
__version__ = "0.0.32"
__all__ = [
"NoMatch",
"MultipleMatches",
Expand Down
32 changes: 32 additions & 0 deletions src/ormantic/fields.py
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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,
Expand Down
30 changes: 18 additions & 12 deletions src/ormantic/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -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__",
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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):
Expand All @@ -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()}