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.26-pp310-pypy310_pp73-win_amd64.whl (831.5 kB view details)

Uploaded PyPy Windows x86-64

python_datamodel-0.6.26-pp39-pypy39_pp73-win_amd64.whl (831.2 kB view details)

Uploaded PyPy Windows x86-64

python_datamodel-0.6.26-cp312-cp312-win_amd64.whl (876.2 kB view details)

Uploaded CPython 3.12 Windows x86-64

python_datamodel-0.6.26-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.26-cp311-cp311-win_amd64.whl (882.0 kB view details)

Uploaded CPython 3.11 Windows x86-64

python_datamodel-0.6.26-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.3 MB view details)

Uploaded CPython 3.11 manylinux: glibc 2.17+ x86-64

python_datamodel-0.6.26-cp310-cp310-win_amd64.whl (880.4 kB view details)

Uploaded CPython 3.10 Windows x86-64

python_datamodel-0.6.26-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.2 MB view details)

Uploaded CPython 3.10 manylinux: glibc 2.17+ x86-64

python_datamodel-0.6.26-cp39-cp39-win_amd64.whl (882.0 kB view details)

Uploaded CPython 3.9 Windows x86-64

python_datamodel-0.6.26-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.2 MB view details)

Uploaded CPython 3.9 manylinux: glibc 2.17+ x86-64

File details

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

File metadata

File hashes

Hashes for python_datamodel-0.6.26-pp310-pypy310_pp73-win_amd64.whl
Algorithm Hash digest
SHA256 f5b84c610e6aa225721fb26f8e9692a021618b4c7bb9e9b4f26efa1705e3ede2
MD5 8e6afaf7741ad73c70fb45e0817fcaa2
BLAKE2b-256 95144a06da960c47d12214d07b51bd5a47bf5576f0fdff68c2ced4d959f0dc0a

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for python_datamodel-0.6.26-pp39-pypy39_pp73-win_amd64.whl
Algorithm Hash digest
SHA256 17b22ae781dbc24e5a83dc0195ed341b8071a377dd41f56b0000dea4f1c43085
MD5 2cf95fb706ab3977eeabb50bfc73bdab
BLAKE2b-256 001596ca493a33e4f70054bbd61489b7fb0a9efbd9bc991bfa3689f06092ddc7

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for python_datamodel-0.6.26-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 8b701717f17422c07902f6b32ba486bc2392cc1ce22cbea66cf5c0bc0f2ed903
MD5 a0a944b9c26b667abac196918c79e1ff
BLAKE2b-256 abe800fec3de62af3b2c07835162f2fb7c476de8fa2cb00c1a709c8df148ac20

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for python_datamodel-0.6.26-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 83ac42cd50104d1528db5dcac56a6e5ff061173cbf8446c5ab27de08e8d1e4b3
MD5 ea7bb79a65b0499618291826af77063e
BLAKE2b-256 292a9ce6a584c82b04717824d5175fe76fc16a6c67f1eb212219f74ff69dfee8

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for python_datamodel-0.6.26-cp311-cp311-win_amd64.whl
Algorithm Hash digest
SHA256 ae6dc489ea81f6d38824bcd0c68eea94d31c83f7a0202a1bb29b98591e153ea8
MD5 279e83111e0bc0a29ae7918b746dc0bc
BLAKE2b-256 bb14ba6d41e7a47c84a139f8bd9d272786f1b69dd18f6e1348e8bf3d1b20715c

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for python_datamodel-0.6.26-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 537e980de843caeacebe3270dc9c5a91b76dcff60c829426b9e33af5fd3950cb
MD5 78737554cbe8b72addb0c5ab3ff91b67
BLAKE2b-256 396c7f41a40b0674a23858da5f8ff5affa6b2d3932773f81489099241c8c0cc6

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for python_datamodel-0.6.26-cp310-cp310-win_amd64.whl
Algorithm Hash digest
SHA256 e802b209363734295cd9dba22e2065bacc7f6744aead47ce616a5a58ef0354c8
MD5 95d0a6b5d819e0456b45c0bda3332463
BLAKE2b-256 229871918fdf6f1212cf2557073b8225b3e75eedcb690f8f679fdd8cfa32384b

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for python_datamodel-0.6.26-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 8f3dc277b57bada82e87f4d2a0acfeaaed87995cf3e1fe5612bd08ad4d90bc28
MD5 52b03434b6e407d1b03ea48b319573a1
BLAKE2b-256 59e556510d82432b8d7a61241cc92d107e73a91b4817a177f7a7363c074d5063

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for python_datamodel-0.6.26-cp39-cp39-win_amd64.whl
Algorithm Hash digest
SHA256 07a49a145d2094abccc0080daa1055bb6fe0235a639e6b0cb9934e04ed96ae2b
MD5 0d133a4b942495ef8abea61626976e28
BLAKE2b-256 3fa08b358c7616097da5445631592cda625572a887dd598920d5694dc625162b

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for python_datamodel-0.6.26-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 14557108c2c15e12a20ed9e31637abf08f8e1a04356085c5c94c7e5e3fd494dd
MD5 3001ad482e562d183ab6801b773db5de
BLAKE2b-256 4e385055736ebba9b5902bfa600219f286af98b45030b4b456bc5873851102b1

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