Skip to main content

simple library based on python +3.8 to use Dataclass-syntaxfor interacting with Data

Project description

DataModel

DataModel is a simple library based on python +3.8 to use Dataclass-syntax for interacting with Data, using the same syntax of Dataclass, users can write Python Objects and work with Data in the same way (like ORM's), is a reimplementation of python Dataclasses supporting true inheritance (without decorators), true composition and other good features.

The key features are:

  • Easy to use: No more using decorators, concerns abour re-ordering attributes or common problems with using dataclasses with inheritance.
  • Extensibility: Can use other dataclasses, Data objects or primitives as data-types.
  • Fast: DataModel is a replacement 100% full compatible with dataclasses, without any overhead.

Requirements

Python 3.8+

Installation

$ pip install python-datamodel
---> 100%
Successfully installed datamodel

Quickstart

from datamodel import Field, BaseModel
from dataclasses import dataclass, fields, is_dataclass


# This pure Dataclass:
@dataclass
class Point:
    x: int = Field(default=0, min=0, max=10)
    y: int = Field(default=0, min=0, max=10)

point = Point(x=10, y=10)
print(point)
print(fields(point))
print('IS a Dataclass?: ', is_dataclass(point))

# Can be represented by BaseModel
class newPoint(BaseModel):
    x: int = Field(default=0, min=0, max=10)
    y: int = Field(default=0, min=0, max=10)

    def get_coordinate(self):
        return (self.x, self.y)

point = newPoint(x=10, y=10)
print(point)
print(fields(point))
print('IS a Dataclass?: ', is_dataclass(point))
print(point.get_coordinate())

Supported types

DataModel support recursive transformation of fields, so you can easily work with nested dataclasses or complex types.

DataModel supports automatic conversion of:

  • datetime objects. datetime objects are encoded to str exactly like orjson conversion, any str typed as datetime is decoded to datetime. The same behavior is used to decoding time, date and timedelta objects.

  • UUID objects. They are encoded as str (JSON string) and decoded back to uuid.UUID objects.

  • Decimal objects. They are also encoded as float and decoded back to Decimal.

Also, "custom" encoders are supported.

import uuid
from typing import (
    List,
    Optional,
    Union
)
from dataclasses import dataclass, field
from datamodel import BaseModel, Field

@dataclass
class Point:
    x: int = Field(default=0, min=0, max=10)
    y: int = Field(default=0, min=0, max=10)

class coordinate(BaseModel, intSum):
    latitude: float
    longitude: float

    def get_location(self) -> tuple:
        return (self.latitude, self.longitude)

def auto_uid():
    return uuid.uuid4()

def default_rect():
    return [0,0,0,0]

def valid_zipcode(field, value):
    return value > 1000

class Address(BaseModel):
    id: uuid.UUID = field(default_factory=auto_uid)
    street: str = Field(required=True)
    zipcode: int = Field(required=False, default=1010, validator=valid_zipcode)
    location: Optional[coordinate]
    box: List[Optional[Point]]
    rect: List[int] = Field(factory=default_rect)


addr = Address(street="Calle Mayor", location=(18.1, 22.1), zipcode=3021, box=[(2, 10), (4, 8)], rect=[1, 2, 3, 4])
print('IS a Dataclass?: ', is_dataclass(addr))

print(addr.location.get_location())
# returns
Address(id=UUID('24b34dd5-8d35-4cfd-8916-7876b28cdae3'), street='Calle Mayor', zipcode=3021, location=coordinate(latitude=18.1, longitude=22.1), box=[Point(x=2, y=10), Point(x=4, y=8)], rect=[1, 2, 3, 4])
  • Fast and convenience conversion from-to JSON (using orjson):
import orjson

b = addr.json()
print(b)
{"id":"24b34dd5-8d35-4cfd-8916-7876b28cdae3","street":"Calle Mayor","zipcode":3021,"location":{"latitude":18.1,"longitude":22.1}, "box":[{"x":2,"y":10},{"x":4,"y":8}],"rect":[1,2,3,4]}
# and re-imported from json
new_addr = Address.from_json(b) # load directly from json string
# or using a dictionary decoded by orjson
data = orjson.loads(b)
new_addr = Address(**data)

Inheritance

python-datamodel supports inheritance of classes.

import uuid
from typing import Union, List
from dataclasses import dataclass, field
from datamodel import BaseModel, Column, Field


def auto_uid():
    return uuid.uuid4()

class User(BaseModel):
    id: uuid.UUID = field(default_factory=auto_uid)
    name: str
    first_name: str
    last_name: str


@dataclass
class Address:
    street: str
    city: str
    state: str
    zipcode: str
    country: Optional[str] = 'US'

    def __str__(self) -> str:
        """Provides pretty response of address"""
        lines = [self.street]
        lines.append(f"{self.city}, {self.zipcode} {self.state}")
        lines.append(f"{self.country}")
        return "\n".join(lines)

class Employee(User):
    """
    Base Employee.
    """
    role: str
    address: Address # composition of a dataclass inside of DataModel is possible.

# Supporting multiple inheritance and composition
# Wage Policies
class MonthlySalary(BaseModel):
    salary: Union[float, int]

    def calculate_payroll(self) -> Union[float, int]:
        return self.salary

class HourlySalary(BaseModel):
    salary: Union[float, int] = Field(default=0)
    hours_worked: Union[float, int] = Field(default=0)

    def calculate_payroll(self) -> Union[float, int]:
        return (self.hours_worked * self.salary)

# employee types
class Secretary(Employee, MonthlySalary):
    """Secretary.

    Person with montly salary policy and no commissions.
    """
    role: str = 'Secretary'

class FactoryWorker(Employee, HourlySalary):
    """
    FactoryWorker is an employee with hourly salary policy and no commissions.
    """
    role: str = 'Factory Worker'

class PayrollSystem:
    def calculate_payroll(self, employees: List[dataclass]) -> None:
        print('=== Calculating Payroll === ')
        for employee in employees:
            print(f"Payroll for employee {employee.id} - {employee.name}")
            print(f"- {employee.role} Amount: {employee.calculate_payroll()}")
            if employee.address:
                print('- Sent to:')
                print(employee.address)
            print("")

jane = Secretary(name='Jane Doe', first_name='Jane', last_name='Doe', salary=1500)
bob = FactoryWorker(name='Bob Doyle', first_name='Bob', last_name='Doyle', salary=15, hours_worked=40)
mitch = FactoryWorker(name='Mitch Brian', first_name='Mitch', last_name='Brian', salary=20, hours_worked=35)

payroll = PayrollSystem()
payroll.calculate_payroll([jane, bob, mitch])

A sample of output:

```console
=== Calculating Payroll ===
Payroll for employee 745a2623-d4d2-4da6-bf0a-1fa691bafd33 - Jane Doe
- Secretary Amount: 1500
- Sent to:
Rodeo Drive, Rd
Los Angeles, 31050 CA
US

Contributing

First of all, thank you for being interested in contributing to this library. I really appreciate you taking the time to work on this project.

  • If you're just interested in getting into the code, a good place to start are issues tagged as bugs.
  • If introducing a new feature, especially one that modifies the public API, consider submitting an issue for discussion before a PR. Please also take a look at existing issues / PRs to see what you're proposing has already been covered before / exists.
  • I like to follow the commit conventions documented here

License

This project is licensed under the terms of the BSD v3. license.

Project details


Release history Release notifications | RSS feed

Download files

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

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

python_datamodel-0.6.19-pp310-pypy310_pp73-win_amd64.whl (824.4 kB view details)

Uploaded PyPy Windows x86-64

python_datamodel-0.6.19-pp39-pypy39_pp73-win_amd64.whl (823.9 kB view details)

Uploaded PyPy Windows x86-64

python_datamodel-0.6.19-cp312-cp312-win_amd64.whl (869.4 kB view details)

Uploaded CPython 3.12 Windows x86-64

python_datamodel-0.6.19-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.4 MB view details)

Uploaded CPython 3.12 manylinux: glibc 2.17+ x86-64

python_datamodel-0.6.19-cp311-cp311-win_amd64.whl (874.0 kB view details)

Uploaded CPython 3.11 Windows x86-64

python_datamodel-0.6.19-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.2 MB view details)

Uploaded CPython 3.11 manylinux: glibc 2.17+ x86-64

python_datamodel-0.6.19-cp310-cp310-win_amd64.whl (872.7 kB view details)

Uploaded CPython 3.10 Windows x86-64

python_datamodel-0.6.19-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.1 MB view details)

Uploaded CPython 3.10 manylinux: glibc 2.17+ x86-64

python_datamodel-0.6.19-cp39-cp39-win_amd64.whl (874.3 kB view details)

Uploaded CPython 3.9 Windows x86-64

python_datamodel-0.6.19-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.1 MB view details)

Uploaded CPython 3.9 manylinux: glibc 2.17+ x86-64

File details

Details for the file python_datamodel-0.6.19-pp310-pypy310_pp73-win_amd64.whl.

File metadata

File hashes

Hashes for python_datamodel-0.6.19-pp310-pypy310_pp73-win_amd64.whl
Algorithm Hash digest
SHA256 a4c01d10f2fb56bc735fa90eedf0f7a880a98d790e7cc7e4015d12542e262307
MD5 41501f477a644d9e35cbfd3184f1149e
BLAKE2b-256 8955c7702047aae5b9dca267a8ee9ee10d60f35d7c82aa54202a30f434aaa377

See more details on using hashes here.

File details

Details for the file python_datamodel-0.6.19-pp39-pypy39_pp73-win_amd64.whl.

File metadata

File hashes

Hashes for python_datamodel-0.6.19-pp39-pypy39_pp73-win_amd64.whl
Algorithm Hash digest
SHA256 b9ff3dc93baa9a6934e7e50c867d185a185506d5a7cc8c35da0622c21e943eab
MD5 ae35cd6233ba76c6643610bb3d81909d
BLAKE2b-256 3f65562eafe1aa05b49b669236a1330017c7cb7e0f02aa097be192df090cc245

See more details on using hashes here.

File details

Details for the file python_datamodel-0.6.19-cp312-cp312-win_amd64.whl.

File metadata

File hashes

Hashes for python_datamodel-0.6.19-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 95dc8c8086be1eee01a999e6d4ab414469e3525b8842f5a7ba20bcb0b4a341ab
MD5 e1508baaa327cfc22ab5cc5b8fc286fd
BLAKE2b-256 d642db5bb996c8ad1ee6dc3093145474f0fdca7fd78ca5764d1c6832c9359711

See more details on using hashes here.

File details

Details for the file python_datamodel-0.6.19-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for python_datamodel-0.6.19-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 ba376f5c9e366aa61cc821a39fc8db77e0727c7186eac78dd0ff6ff7daaabf74
MD5 52a8bec61b17282494de0adf3fee6dd5
BLAKE2b-256 36098c30369277f6e8ce1f5c35385f1db5136606e2330885301e77980923cd58

See more details on using hashes here.

File details

Details for the file python_datamodel-0.6.19-cp311-cp311-win_amd64.whl.

File metadata

File hashes

Hashes for python_datamodel-0.6.19-cp311-cp311-win_amd64.whl
Algorithm Hash digest
SHA256 b62d4d132a7e86ac56555082f3e2887d43418baf4da8cef1cb096c39d5e9e939
MD5 d2e9f25ccdb50605b6b7faffa6899009
BLAKE2b-256 d7c757ff4ece4c61c31a668614a5ec2a1779e5eb12ede5dfc00c47d39cba5caa

See more details on using hashes here.

File details

Details for the file python_datamodel-0.6.19-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for python_datamodel-0.6.19-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 c0f6d91b31bfc0a7f7714666275486ede3ff84fdadbc22d92e4efbee98faed78
MD5 0e2281c32c8e8183656da25b0453037e
BLAKE2b-256 3ca52f8d5c2a3cc937c4413bd39cda7287fa30078ee7ad73a37a22d048c605de

See more details on using hashes here.

File details

Details for the file python_datamodel-0.6.19-cp310-cp310-win_amd64.whl.

File metadata

File hashes

Hashes for python_datamodel-0.6.19-cp310-cp310-win_amd64.whl
Algorithm Hash digest
SHA256 12a8eaf0422b8e8232001ee4a1cbdaf6717b81302e9222767fd689afa8188397
MD5 3e4019c203851576e20786c7c814b6f2
BLAKE2b-256 b2ee3ce4d6a820bb096ee9a436e06c00d0f90bcac2d6a34e630fb0ae0445d8b3

See more details on using hashes here.

File details

Details for the file python_datamodel-0.6.19-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for python_datamodel-0.6.19-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 cd918f1b1fdbf3fbae501eeef47396c13ec3b2b59d46dc7e08580285bab811cb
MD5 d6b267166e2fe2a6748c76ef504c6420
BLAKE2b-256 9ff2010719fded5a362744e89133e673018b1357e9becb8399701f9f9d969d42

See more details on using hashes here.

File details

Details for the file python_datamodel-0.6.19-cp39-cp39-win_amd64.whl.

File metadata

File hashes

Hashes for python_datamodel-0.6.19-cp39-cp39-win_amd64.whl
Algorithm Hash digest
SHA256 d5004e157ac64144046da4bde6788edf74bbdfc4911333cdb738456f78fc01d3
MD5 5a75d4f1dcb00d538dba5be8c654689d
BLAKE2b-256 a7c8fee0126e43e162db5d49b6d72f7ca5ee320a147fcd3f1efebc6fb77fe32d

See more details on using hashes here.

File details

Details for the file python_datamodel-0.6.19-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for python_datamodel-0.6.19-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 cf7ee8c52f968bbee0a437697ab8a7ec636b15e66ebd40414e127d001ec4964b
MD5 900d9f3a1f24d40127335d888a6da06c
BLAKE2b-256 e73f272a60845690e18f7079c57f7ae42d40578576cbde5083fd47b60f4ae0d8

See more details on using hashes here.

Supported by

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