pydantic model generator for atproto lexicons
at main 151 lines 3.2 kB view raw view rendered
1# pmgfal 2 3pydantic model generator for atproto lexicons 4 5rust-powered lexicon parsing and python code generation. 6 7## install 8 9```bash 10uv add pmgfal 11``` 12 13## usage 14 15```bash 16# auto-detect ./lexicons or current dir 17uvx pmgfal 18 19# explicit paths 20uvx pmgfal ./lexicons -o ./src/atproto 21 22# filter by namespace 23uvx pmgfal -p fm.plyr 24 25# force regeneration (skip cache) 26uvx pmgfal --no-cache 27``` 28 29## caching 30 31pmgfal caches generated models based on a hash of your lexicon files. on subsequent runs with unchanged lexicons, it copies from cache instead of regenerating. 32 33cache location: 34- unix (linux/macos/bsd): `~/.cache/pmgfal/` (or `$XDG_CACHE_HOME/pmgfal/`) 35- windows: `%LOCALAPPDATA%/pmgfal/` 36 37the cache key includes: 38- pmgfal version (cache invalidates on upgrade) 39- namespace prefix filter 40- content of all lexicon json files 41 42## output 43 44```python 45# auto-generated by pmgfal - do not edit 46 47from __future__ import annotations 48 49from pydantic import BaseModel, Field 50 51 52class FmPlyrTrack(BaseModel): 53 """fm.plyr.track record""" 54 55 uri: str 56 title: str 57 artist: str 58 duration_ms: int | None = Field(default=None, alias="durationMs") 59``` 60 61## adoption guide 62 63### 1. add lexicons to your project 64 65``` 66your-project/ 67├── lexicons/ 68│ └── fm/ 69│ └── plyr/ 70│ ├── track.json 71│ ├── like.json 72│ └── comment.json 73├── src/ 74│ └── atproto/ 75│ └── .gitkeep 76└── pyproject.toml 77``` 78 79### 2. generate models 80 81```bash 82uvx pmgfal ./lexicons -o ./src/atproto -p fm.plyr 83``` 84 85### 3. use in your code 86 87```python 88from your_project.atproto import FmPlyrTrack, FmPlyrLike 89 90track = FmPlyrTrack( 91 uri="at://did:plc:xyz/fm.plyr.track/123", 92 title="my song", 93 artist="me", 94) 95``` 96 97### 4. regenerate when lexicons change 98 99**option a: pre-commit hook** 100 101```yaml 102# .pre-commit-config.yaml 103repos: 104 - repo: local 105 hooks: 106 - id: pmgfal 107 name: generate atproto models 108 entry: uvx pmgfal ./lexicons -o ./src/atproto -p fm.plyr 109 language: system 110 files: ^lexicons/.*\.json$ 111 pass_filenames: false 112``` 113 114**option b: justfile** 115 116```just 117# justfile 118generate: 119 uvx pmgfal ./lexicons -o ./src/atproto -p fm.plyr 120``` 121 122**option c: github actions** 123 124```yaml 125# .github/workflows/ci.yml 126- name: generate models 127 run: uvx pmgfal ./lexicons -o ./src/atproto -p fm.plyr 128``` 129 130caching ensures regeneration is fast (~0.3s for 300 lexicons) when files haven't changed. 131 132## external refs 133 134pmgfal bundles all `com.atproto.*` lexicons and automatically resolves external refs. for example, if your lexicon references `com.atproto.repo.strongRef`, pmgfal generates: 135 136```python 137class ComAtprotoRepoStrongRef(BaseModel): 138 uri: str 139 cid: str 140 141class FmPlyrLike(BaseModel): 142 subject: ComAtprotoRepoStrongRef # properly typed! 143 created_at: str = Field(alias="createdAt") 144``` 145 146## how it works 147 1481. parses lexicon json using [atrium-lex](https://github.com/atrium-rs/atrium) (rust) 1492. resolves internal (`#localDef`) and external (`com.atproto.*`) refs 1503. generates pydantic v2 models with field aliases 1514. outputs standalone python - no atproto sdk dependency