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

Uploaded PyPy Windows x86-64

python_datamodel-0.6.25-pp39-pypy39_pp73-win_amd64.whl (831.4 kB view details)

Uploaded PyPy Windows x86-64

python_datamodel-0.6.25-cp312-cp312-win_amd64.whl (876.1 kB view details)

Uploaded CPython 3.12 Windows x86-64

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

Uploaded CPython 3.11 Windows x86-64

python_datamodel-0.6.25-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.25-cp310-cp310-win_amd64.whl (880.4 kB view details)

Uploaded CPython 3.10 Windows x86-64

python_datamodel-0.6.25-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.25-cp39-cp39-win_amd64.whl (882.1 kB view details)

Uploaded CPython 3.9 Windows x86-64

python_datamodel-0.6.25-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.25-pp310-pypy310_pp73-win_amd64.whl.

File metadata

File hashes

Hashes for python_datamodel-0.6.25-pp310-pypy310_pp73-win_amd64.whl
Algorithm Hash digest
SHA256 d5ea1e19f554670469d493a57ec23306f71ec93d0e95d6baa4fffda1bb31e985
MD5 a5788a0a0296f6975384d656733ead34
BLAKE2b-256 76a24519e357fb2250ef6dfcfce03a8d0cfc33604d1de57b4830fd9363a52e66

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for python_datamodel-0.6.25-pp39-pypy39_pp73-win_amd64.whl
Algorithm Hash digest
SHA256 2c85c9efdcd6283992abb888e0f0c52303f69f04fa62a9f4d9941c17c02225a2
MD5 439be266d8b0d1719e318d356816c4d0
BLAKE2b-256 d58276a5a3b3dd09f77e911cc8aa4c7e27fdf1694d3ee7b04e0ac3415110e4f1

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for python_datamodel-0.6.25-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 b47ddb5be8f75e103e2382b4ea9b773432f9598f9a9fdad1200c15e3504b0fd1
MD5 7945bf2140571b8dbfc2e2b6e15929fc
BLAKE2b-256 d3a8f53ccd7bdb8d080d690b55fd3de648567cbef81ad7fd2cecaa99a50b9884

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for python_datamodel-0.6.25-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 9550c6e80e7c85a788509ef76701827a5e44507def91c999230d9628f8cfded8
MD5 8310e90195da36892898f46415a1d2c2
BLAKE2b-256 96bfa0d6661b5c7511d3512a442f44ed95af0a53e0283d9d537351f5e20f6010

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for python_datamodel-0.6.25-cp311-cp311-win_amd64.whl
Algorithm Hash digest
SHA256 0d397977a1e1b22988da355dae45c61df2d1fb3bef2a6a55eeb0a03d67b341ed
MD5 cb7b5cb00ba7d4c572cbe2f80e43a3bc
BLAKE2b-256 529077983ed150adc4bf5dcb8bae1d9d2f95a17bb233d7e8e32d678bda15cd73

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for python_datamodel-0.6.25-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 f51e71f0a9726e44dcd9785b75578d47841bf9e814e6313291f508888193af4d
MD5 027d0afe7209261b4c33379b8c12604e
BLAKE2b-256 daf60d562959b72938a945024ed3c47cd0f08f7918c1cef1d418e70606030463

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for python_datamodel-0.6.25-cp310-cp310-win_amd64.whl
Algorithm Hash digest
SHA256 4862f54533b2631209477d3f3f4e32442e40720f8373b9439a00d111046df9f4
MD5 77353dbcf2288cb7e5997e54ab6b1c6a
BLAKE2b-256 3beced1a28f51f1a9c81ffca7ddbc241a9aa008e5a9da2c6f66a15b67142d674

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for python_datamodel-0.6.25-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 5593ae8af46df9ffe51c9e13b7a9a35b33c7ce50d84d9908e6572ef424751475
MD5 71156c9bca6c9b1c3301f7f703a1af59
BLAKE2b-256 d763d79aad567adf065063ff49293dbd0de714ced4a661ef15c0431a55b9f49f

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for python_datamodel-0.6.25-cp39-cp39-win_amd64.whl
Algorithm Hash digest
SHA256 62fb4f8a56721885989b2813806567a1f19dd3aa482fc18e2929d78ca8596a26
MD5 3c03264e785165fb820ca9df86f49559
BLAKE2b-256 483548201fd3c8887fffa16a19cb5a2c0f179c20ae20623912b43a2e68ec2350

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for python_datamodel-0.6.25-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 96d0e781b33fc33f6d4a9d4386856e052c5287fbcc242880cf289063931ce5ef
MD5 731bb3813542bde0266e30a88849e97f
BLAKE2b-256 f6f98c894742efa9abbce8aff4790d9c6bd23d620e11c3ca2c7b5bbad11fcd2d

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