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

Uploaded PyPy Windows x86-64

python_datamodel-0.7.0-pp39-pypy39_pp73-win_amd64.whl (834.5 kB view details)

Uploaded PyPy Windows x86-64

python_datamodel-0.7.0-cp313-cp313-win_amd64.whl (876.4 kB view details)

Uploaded CPython 3.13 Windows x86-64

python_datamodel-0.7.0-cp312-cp312-win_amd64.whl (878.7 kB view details)

Uploaded CPython 3.12 Windows x86-64

python_datamodel-0.7.0-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.7.0-cp311-cp311-win_amd64.whl (883.8 kB view details)

Uploaded CPython 3.11 Windows x86-64

python_datamodel-0.7.0-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.7.0-cp310-cp310-win_amd64.whl (882.0 kB view details)

Uploaded CPython 3.10 Windows x86-64

python_datamodel-0.7.0-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.7.0-cp39-cp39-win_amd64.whl (883.6 kB view details)

Uploaded CPython 3.9 Windows x86-64

python_datamodel-0.7.0-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.7.0-pp310-pypy310_pp73-win_amd64.whl.

File metadata

File hashes

Hashes for python_datamodel-0.7.0-pp310-pypy310_pp73-win_amd64.whl
Algorithm Hash digest
SHA256 ecab7983c82baa60561226a97e0be65a4928ec06a98e14ee2aaa5ac159d9ff4d
MD5 ebb16d40a500d346744e3c7a040a71b1
BLAKE2b-256 2d4131c079e473a1eaf180e4dae42663897f8005798e9932a4889819360342b8

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for python_datamodel-0.7.0-pp39-pypy39_pp73-win_amd64.whl
Algorithm Hash digest
SHA256 f19798746da54b03884ca2c584fab1e803d675e33449ceceb0c136f2515cfb56
MD5 d281454a00fddb5f2c54096bc936d23f
BLAKE2b-256 4da7d71b1d6897770f1a327d98fb085386db73d27f5e454fc1c207f675f6ec24

See more details on using hashes here.

File details

Details for the file python_datamodel-0.7.0-cp313-cp313-win_amd64.whl.

File metadata

File hashes

Hashes for python_datamodel-0.7.0-cp313-cp313-win_amd64.whl
Algorithm Hash digest
SHA256 a1907375fe4a776781656d9780aaa208c3a73bf5cc7cd8d5357f3d7a34daf662
MD5 bca60f0afc623b774047930a27609b4a
BLAKE2b-256 605ed69df4e7d210c983d0af84255e528c46d9f60fed34ddf2107245fab71de2

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for python_datamodel-0.7.0-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 b5082bd0658ff5ba53b863eb73533baa05e61c981c52e2ec0e10d244f9137c3b
MD5 0ff1bb3e93ccfb54e9598dafacf6dfaa
BLAKE2b-256 222d362e4c05742d599a5c0442f18358e930281db7ad43fa48f99bbfe5e6cefc

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for python_datamodel-0.7.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 ee0ddb6805800580c540e47108eb862d7a129ed7e844a4867095ac18f50ca8c7
MD5 2d38ca0e7f274ebbfeef6a95c3b86bfb
BLAKE2b-256 bb03e7c5f379d30fe786e6e47879b2ae7a28a952cb034953a07c59fae3c9929a

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for python_datamodel-0.7.0-cp311-cp311-win_amd64.whl
Algorithm Hash digest
SHA256 b392edde6d4252960d26a5f3d2d681ddafa497a94ba1dcca42707139c3899646
MD5 d44a7509064274bfca5731f40f4f70e4
BLAKE2b-256 3ce9d51e6390b7fc2daa1b3b1c344428ffd1bd40fa38bc899aad26d407edad46

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for python_datamodel-0.7.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 daf31b4f9b550343583796ead6ec7a3016d289964b31b743c035e923a0d5d04c
MD5 42e555e9a0c0d8d71d68c04890f30ec6
BLAKE2b-256 eeef8d25e23516e8688bc5026c82afaed310e3879f8c4018b7f4d021e9b55ee6

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for python_datamodel-0.7.0-cp310-cp310-win_amd64.whl
Algorithm Hash digest
SHA256 f7a2e9f0066c363ae2e5f331e1afadf7700aef526758e9e4de73c5a07d4887b2
MD5 76271f971394247762b7d28a35ce4df6
BLAKE2b-256 21d65a214ed9a826d5fe613b90074cf3059407d7750a07191a246fa911488d14

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for python_datamodel-0.7.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 4cf028ed319df23e4caa08013102ec984be6538e96cf063f9ddae0f84dd5abb0
MD5 cbb55ec967cfdc095572e3c2218f39e1
BLAKE2b-256 c3d8ff0d5fd21b05fdf41d1b5d5c958171c525622b76989bf771b200408a65f1

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for python_datamodel-0.7.0-cp39-cp39-win_amd64.whl
Algorithm Hash digest
SHA256 08cba003d19932f4807ff73fadf15dce2278fe09689d521176b41869674f0217
MD5 6242e014213bab361a076d70502218e3
BLAKE2b-256 f15944a63c99dda1cdcec22e52408b8d5e4ae0358de9896258ead4bb57564dd3

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for python_datamodel-0.7.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 abe8bf6211f9d7d917c86183f36853e8987767c04670252758befac5cbd64f2b
MD5 74b826e079101dc10c0e44fb2adb9bb0
BLAKE2b-256 4c21eebbd982eafac6ce53cfb42ca52c8bd3a71eaa01d04d88d8166afb045b1f

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