{"id":15740420,"url":"https://github.com/phenobarbital/python-datamodel","last_synced_at":"2025-04-26T18:58:14.788Z","repository":{"id":59239523,"uuid":"535609131","full_name":"phenobarbital/python-datamodel","owner":"phenobarbital","description":"DataModel is a reimplementation of python Dataclasses supporting true inheritance (without decorators), true composition and other good features.","archived":false,"fork":false,"pushed_at":"2025-04-08T11:54:26.000Z","size":1986,"stargazers_count":4,"open_issues_count":5,"forks_count":3,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-04-08T12:16:23.686Z","etag":null,"topics":["dataclass","dataclasses","dataclasses-json"],"latest_commit_sha":null,"homepage":"","language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/phenobarbital.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-09-12T10:09:34.000Z","updated_at":"2025-04-08T11:53:46.000Z","dependencies_parsed_at":"2024-02-05T09:53:02.779Z","dependency_job_id":"71ad10ca-ff0e-4303-9ce4-99dd74414876","html_url":"https://github.com/phenobarbital/python-datamodel","commit_stats":{"total_commits":250,"total_committers":4,"mean_commits":62.5,"dds":"0.30800000000000005","last_synced_commit":"90a90f58f27dab02f1cbff5ed1c401eaac63d792"},"previous_names":[],"tags_count":133,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phenobarbital%2Fpython-datamodel","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phenobarbital%2Fpython-datamodel/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phenobarbital%2Fpython-datamodel/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phenobarbital%2Fpython-datamodel/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/phenobarbital","download_url":"https://codeload.github.com/phenobarbital/python-datamodel/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250868871,"owners_count":21500346,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dataclass","dataclasses","dataclasses-json"],"created_at":"2024-10-04T02:21:23.087Z","updated_at":"2025-04-25T17:57:21.865Z","avatar_url":"https://github.com/phenobarbital.png","language":"HTML","funding_links":[],"categories":[],"sub_categories":[],"readme":"# DataModel\nDataModel is a simple library based on python +3.8 to use Dataclass-syntax for interacting with\nData, using the same syntax of Dataclass, users can write Python Objects\nand 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.\n\nThe key features are:\n* **Easy to use**: No more using decorators, concerns abour re-ordering attributes or common problems with using dataclasses with inheritance.\n* **Extensibility**: Can use other dataclasses, Data objects or primitives as data-types.\n* **Fast**: DataModel is a replacement 100% full compatible with dataclasses, without any overhead.\n\n\n\n## Requirements\n\nPython 3.8+\n\n## Installation\n\n\u003cdiv class=\"termy\"\u003e\n\n```console\n$ pip install python-datamodel\n---\u003e 100%\nSuccessfully installed datamodel\n```\n\n\n\u003c/div\u003e\n\n## Quickstart\n\n\n```python\n\nfrom datamodel import Field, BaseModel\nfrom dataclasses import dataclass, fields, is_dataclass\n\n\n# This pure Dataclass:\n@dataclass\nclass Point:\n    x: int = Field(default=0, min=0, max=10)\n    y: int = Field(default=0, min=0, max=10)\n\npoint = Point(x=10, y=10)\nprint(point)\nprint(fields(point))\nprint('IS a Dataclass?: ', is_dataclass(point))\n\n# Can be represented by BaseModel\nclass newPoint(BaseModel):\n    x: int = Field(default=0, min=0, max=10)\n    y: int = Field(default=0, min=0, max=10)\n\n    def get_coordinate(self):\n        return (self.x, self.y)\n\npoint = newPoint(x=10, y=10)\nprint(point)\nprint(fields(point))\nprint('IS a Dataclass?: ', is_dataclass(point))\nprint(point.get_coordinate())\n```\n## Supported types\n\nDataModel support recursive transformation of fields, so you can easily work with nested dataclasses or complex types.\n\nDataModel supports automatic conversion of:\n\n- [datetime](https://docs.python.org/3/library/datetime.html#available-types)\nobjects. `datetime` objects are encoded to str exactly like orjson conversion, any str typed as datetime is decoded to datetime.\nThe same behavior is used to decoding time, date and timedelta objects.\n\n- [UUID](https://docs.python.org/3/library/uuid.html#uuid.UUID) objects. They\nare encoded as `str` (JSON string) and decoded back to uuid.UUID objects.\n\n- [Decimal](https://docs.python.org/3/library/decimal.html) objects. They are\nalso encoded as `float` and decoded back to Decimal.\n\nAlso, \"custom\" encoders are supported.\n\n```python\n\nimport uuid\nfrom typing import (\n    List,\n    Optional,\n    Union\n)\nfrom dataclasses import dataclass, field\nfrom datamodel import BaseModel, Field\n\n@dataclass\nclass Point:\n    x: int = Field(default=0, min=0, max=10)\n    y: int = Field(default=0, min=0, max=10)\n\nclass coordinate(BaseModel, intSum):\n    latitude: float\n    longitude: float\n\n    def get_location(self) -\u003e tuple:\n        return (self.latitude, self.longitude)\n\ndef auto_uid():\n    return uuid.uuid4()\n\ndef default_rect():\n    return [0,0,0,0]\n\ndef valid_zipcode(field, value):\n    return value \u003e 1000\n\nclass Address(BaseModel):\n    id: uuid.UUID = field(default_factory=auto_uid)\n    street: str = Field(required=True)\n    zipcode: int = Field(required=False, default=1010, validator=valid_zipcode)\n    location: Optional[coordinate]\n    box: List[Optional[Point]]\n    rect: List[int] = Field(factory=default_rect)\n\n\naddr = Address(street=\"Calle Mayor\", location=(18.1, 22.1), zipcode=3021, box=[(2, 10), (4, 8)], rect=[1, 2, 3, 4])\nprint('IS a Dataclass?: ', is_dataclass(addr))\n\nprint(addr.location.get_location())\n```\n```console\n# returns\nAddress(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])\n```\n\n* Fast and convenience conversion from-to JSON (using orjson):\n\n```python\nimport orjson\n\nb = addr.json()\nprint(b)\n```\n```console\n{\"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]}\n```\n\n```python\n# and re-imported from json\nnew_addr = Address.from_json(b) # load directly from json string\n# or using a dictionary decoded by orjson\ndata = orjson.loads(b)\nnew_addr = Address(**data)\n\n```\n\n## Inheritance\n\npython-datamodel supports inheritance of classes.\n\n```python\nimport uuid\nfrom typing import Union, List\nfrom dataclasses import dataclass, field\nfrom datamodel import BaseModel, Column, Field\n\n\ndef auto_uid():\n    return uuid.uuid4()\n\nclass User(BaseModel):\n    id: uuid.UUID = field(default_factory=auto_uid)\n    name: str\n    first_name: str\n    last_name: str\n\n\n@dataclass\nclass Address:\n    street: str\n    city: str\n    state: str\n    zipcode: str\n    country: Optional[str] = 'US'\n\n    def __str__(self) -\u003e str:\n        \"\"\"Provides pretty response of address\"\"\"\n        lines = [self.street]\n        lines.append(f\"{self.city}, {self.zipcode} {self.state}\")\n        lines.append(f\"{self.country}\")\n        return \"\\n\".join(lines)\n\nclass Employee(User):\n    \"\"\"\n    Base Employee.\n    \"\"\"\n    role: str\n    address: Address # composition of a dataclass inside of DataModel is possible.\n\n# Supporting multiple inheritance and composition\n# Wage Policies\nclass MonthlySalary(BaseModel):\n    salary: Union[float, int]\n\n    def calculate_payroll(self) -\u003e Union[float, int]:\n        return self.salary\n\nclass HourlySalary(BaseModel):\n    salary: Union[float, int] = Field(default=0)\n    hours_worked: Union[float, int] = Field(default=0)\n\n    def calculate_payroll(self) -\u003e Union[float, int]:\n        return (self.hours_worked * self.salary)\n\n# employee types\nclass Secretary(Employee, MonthlySalary):\n    \"\"\"Secretary.\n\n    Person with montly salary policy and no commissions.\n    \"\"\"\n    role: str = 'Secretary'\n\nclass FactoryWorker(Employee, HourlySalary):\n    \"\"\"\n    FactoryWorker is an employee with hourly salary policy and no commissions.\n    \"\"\"\n    role: str = 'Factory Worker'\n\nclass PayrollSystem:\n    def calculate_payroll(self, employees: List[dataclass]) -\u003e None:\n        print('=== Calculating Payroll === ')\n        for employee in employees:\n            print(f\"Payroll for employee {employee.id} - {employee.name}\")\n            print(f\"- {employee.role} Amount: {employee.calculate_payroll()}\")\n            if employee.address:\n                print('- Sent to:')\n                print(employee.address)\n            print(\"\")\n\njane = Secretary(name='Jane Doe', first_name='Jane', last_name='Doe', salary=1500)\nbob = FactoryWorker(name='Bob Doyle', first_name='Bob', last_name='Doyle', salary=15, hours_worked=40)\nmitch = FactoryWorker(name='Mitch Brian', first_name='Mitch', last_name='Brian', salary=20, hours_worked=35)\n\npayroll = PayrollSystem()\npayroll.calculate_payroll([jane, bob, mitch])\n```\nA sample of output:\n```\n```console\n=== Calculating Payroll ===\nPayroll for employee 745a2623-d4d2-4da6-bf0a-1fa691bafd33 - Jane Doe\n- Secretary Amount: 1500\n- Sent to:\nRodeo Drive, Rd\nLos Angeles, 31050 CA\nUS\n```\n## Contributing\n\nFirst of all, thank you for being interested in contributing to this library.\nI really appreciate you taking the time to work on this project.\n\n- If you're just interested in getting into the code, a good place to start are\nissues tagged as bugs.\n- If introducing a new feature, especially one that modifies the public API,\nconsider submitting an issue for discussion before a PR. Please also take a look\nat existing issues / PRs to see what you're proposing has  already been covered\nbefore / exists.\n- I like to follow the commit conventions documented [here](https://www.conventionalcommits.org/en/v1.0.0/#summary)\n\n## License\n\nThis project is licensed under the terms of the BSD v3. license.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphenobarbital%2Fpython-datamodel","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fphenobarbital%2Fpython-datamodel","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphenobarbital%2Fpython-datamodel/lists"}