Skip to main content

It just provide a pair of pre & post methods around pydantic fields, the rest is up to your imagination

Project description

pypi Downloads Python Versions CI

Pydantic-resolve is a schema based solution for data composition, it can provide you with 3 ~ 5 times the increase in development efficiency and reduce the amount of code by more than 50%.

  1. It manages the deep data inside each schema, instead of visiting from outside by manual traversal.
  2. It runs a Level Order Traversal (BFS) inside and execute resolve and post during this process.
  3. It describes the relationship between data in a form close to ERD (entity relationship diagram)

Install

User of pydantic v2, please use pydantic2-resolve instead.

This lib now supports both pydantic v1 and v2 starts from v1.11.0

pip install pydantic-resolve

Hello world

manage your data inside the schema.

class Tree(BaseModel):
    name: str
    number: int
    description: str = ''
    def resolve_description(self):
        return f"I'm {self.name}, my number is {self.number}"
    children: list['Tree'] = []


tree = dict(
    name='root',
    number=1,
    children=[
        dict(
            name='child1',
            number=2,
            children=[
                dict(
                    name='child1-1',
                    number=3,
                ),
                dict(
                    name='child1-2',
                    number=4,
                ),
            ]
        )
    ]
)

async def main():
    t = Tree.parse_obj(tree)
    t = await Resolver().resolve(t)
    print(t.json(indent=4))

import asyncio
asyncio.run(main())

output

{
  "name": "root",
  "number": 1,
  "description": "I'm root, my number is 1",
  "children": [
    {
      "name": "child1",
      "number": 2,
      "description": "I'm child1, my number is 2",
      "children": [
        {
          "name": "child1-1",
          "number": 3,
          "description": "I'm child1-1, my number is 3",
          "children": []
        },
        {
          "name": "child1-2",
          "number": 4,
          "description": "I'm child1-2, my number is 4",
          "children": []
        }
      ]
    }
  ]
}

Composing a subset from ERD definitions

define elements of ERD, schema (entity), dataloader (relationship).

then pick and compose them together according to your requirement and get the result.

import asyncio
import json
from typing import Optional
from pydantic import BaseModel
from pydantic_resolve import Resolver, build_object, build_list, LoaderDepend
from aiodataloader import DataLoader

# Schema/ Entity
class Comment(BaseModel):
    id: int
    content: str
    user_id: int

class Blog(BaseModel):
    id: int
    title: str
    content: str

class User(BaseModel):
    id: int
    name: str


# Loaders/ relationships
class CommentLoader(DataLoader):
    async def batch_load_fn(self, comment_ids):
        comments = [
            dict(id=1, content="world is beautiful", blog_id=1, user_id=1),
            dict(id=2, content="Mars is beautiful", blog_id=2, user_id=2),
            dict(id=3, content="I love Mars", blog_id=2, user_id=3),
        ]
        return build_list(comments, comment_ids, lambda c: c['blog_id'])

class UserLoader(DataLoader):
    async def batch_load_fn(self, user_ids):
        users = [ dict(id=1, name="Alice"), dict(id=2, name="Bob"), ]
        return build_object(users, user_ids, lambda u: u['id'])


# Compose schemas and dataloaders together
class CommentWithUser(Comment):
    user: Optional[User] = None
    def resolve_user(self, loader=LoaderDepend(UserLoader)):
        return loader.load(self.user_id)

class BlogWithComments(Blog):
    comments: list[CommentWithUser] = []
    def resolve_comments(self, loader=LoaderDepend(CommentLoader)):
        return loader.load(self.id)


# Run
async def main():
    raw_blogs =[
        dict(id=1, title="hello world", content="hello world detail"),
        dict(id=2, title="hello Mars", content="hello Mars detail"),
    ]
    blogs = await Resolver().resolve([BlogWithComments.parse_obj(b) for b in raw_blogs])
    print(json.dumps(blogs, indent=2, default=lambda o: o.dict()))

asyncio.run(main())

output

[
  {
    "id": 1,
    "title": "hello world",
    "content": "hello world detail",
    "comments": [
      {
        "id": 1,
        "content": "world is beautiful",
        "user_id": 1,
        "user": {
          "id": 1,
          "name": "Alice"
        }
      }
    ]
  },
  {
    "id": 2,
    "title": "hello Mars",
    "content": "hello Mars detail",
    "comments": [
      {
        "id": 2,
        "content": "Mars is beautiful",
        "user_id": 2,
        "user": {
          "id": 2,
          "name": "Bob"
        }
      },
      {
        "id": 3,
        "content": "I love Mars",
        "user_id": 3,
        "user": null
      }
    ]
  }
]

Documents

Test and coverage

tox
tox -e coverage
python -m http.server

latest coverage: 98%

Sponsor

If this code helps and you wish to support me

Paypal: https://www.paypal.me/tangkikodo

Discussion

Discord

Project details


Download files

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

Source Distribution

pydantic_resolve-1.11.2.tar.gz (18.0 kB view details)

Uploaded Source

Built Distribution

pydantic_resolve-1.11.2-py3-none-any.whl (20.7 kB view details)

Uploaded Python 3

File details

Details for the file pydantic_resolve-1.11.2.tar.gz.

File metadata

  • Download URL: pydantic_resolve-1.11.2.tar.gz
  • Upload date:
  • Size: 18.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.5.1 CPython/3.10.4 Darwin/23.6.0

File hashes

Hashes for pydantic_resolve-1.11.2.tar.gz
Algorithm Hash digest
SHA256 2fb2f7fc01260739781885073674dce4138e81ac42af3ffc1cad51e1e5646978
MD5 0701a4de245077e54b6f6bae69d89dbc
BLAKE2b-256 87b2ee3e019c13f4bcf4cc849e4319d99dd09f76d586fcf584051e2048c48113

See more details on using hashes here.

File details

Details for the file pydantic_resolve-1.11.2-py3-none-any.whl.

File metadata

File hashes

Hashes for pydantic_resolve-1.11.2-py3-none-any.whl
Algorithm Hash digest
SHA256 ef6cc921bf904ace0687623bd668e9a6889996f7522260c80dad24efa8fa2521
MD5 e26602c8fc30e557f8a0552291dc2625
BLAKE2b-256 a9bd7c2894691ceafd018cd17256c112ddeff6005cf25d664fb2df28a9f43d97

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