/ duper-python / README.md
README.md
  1  <p align="center">
  2      <img src="https://duper.dev.br/logos/duper-400.png" alt="The Duper logo, with a confident spectacled mole wearing a flailing blue cape." /> <br>
  3  </p>
  4  <h1 align="center">duper-python</h1>
  5  
  6  <p align="center">
  7      <a href="https://pypi.org/project/duper-python"><img alt="PyPI version" src="https://img.shields.io/pypi/v/duper-python?style=flat&logo=python&logoColor=white&label=duper-python"></a>
  8      <a href="https://github.com/EpicEric/duper"><img alt="GitHub license" src="https://img.shields.io/github/license/EpicEric/duper"></a>
  9  </p>
 10  
 11  Duper support for Python.
 12  
 13  [Check out the official website for Duper.](https://duper.dev.br)
 14  
 15  ## Installation
 16  
 17  ```bash
 18  uv add duper-python
 19  # -- or --
 20  pip install duper-python
 21  ```
 22  
 23  ## Examples
 24  
 25  The basic `json`/`pickle`-like interface:
 26  
 27  ```python
 28  import duper
 29  
 30  DUPER_DATA = """
 31  APIResponse({
 32    status: 200,
 33    headers: {
 34      content_type: "application/duper",
 35      cache_control: "max-age=3600",
 36    },
 37    body: {
 38      users: [
 39        User({
 40          id: Uuid("7039311b-02d2-4849-a6de-900d4dbe9acb"),
 41          name: "Alice",
 42          email: Email("alice@example.com"),
 43          roles: ["admin", "user"],
 44          metadata: {
 45            last_login: DateTime("2024-01-15T10:30:00Z"),
 46            ip: IPV4("173.255.230.79"),
 47          },
 48        }),
 49      ],
 50    },
 51  })
 52  """
 53  
 54  python_dict = duper.loads(DUPER_DATA)  # Actually a Pydantic BaseModel!
 55  
 56  with open("out.duper", "w") as f:
 57      duper.dump(DUPER_DATA)
 58  ```
 59  
 60  ---
 61  
 62  Using [Pydantic](https://pypi.org/project/pydantic/):
 63  
 64  ```python
 65  from datetime import datetime
 66  import re
 67  import uuid
 68  
 69  from duper import BaseModel
 70  
 71  
 72  class RegisteredRegex(BaseModel):
 73      regex_id: uuid.UUID
 74      created_at: datetime
 75      pattern: re.Pattern
 76      matches: list[str] | None = None
 77  
 78  data = RegisteredRegex(
 79      regex_id=uuid.uuid4(),
 80      created_at=datetime.now(),
 81      pattern=re.compile(r"^Hello w.rld!$"),
 82  )
 83  
 84  data_str = data.model_dump(mode="duper")
 85  print(data_str)
 86  
 87  reconstituted_data = RegisteredRegex.model_validate_duper(data_str)
 88  assert data == reconstituted_data
 89  ```
 90  
 91  ---
 92  
 93  Using [FastAPI](https://pypi.org/project/fastapi/):
 94  
 95  ```python
 96  from typing import Annotated
 97  from duper.fastapi import DuperBody, DuperResponse
 98  from duper import BaseModel
 99  from fastapi import FastAPI
100  
101  class DuplicatableData(BaseModel):
102      tup: tuple[str, bytes]
103      value: int
104  
105  app = FastAPI()
106  
107  @app.post("/double", response_class=DuperResponse)
108  async def double_the_data(
109      body: Annotated[DuplicatableData, DuperBody(DuplicatableData)],
110  ) -> DuperResponse:
111      return DuperResponse(
112          DuplicatableData(
113              tup=(body.tup[0] + body.tup[0], body.tup[1] + body.tup[1]),
114              value=2 * body.value,
115          )
116      )
117  ```