+30
-5
README.md
+30
-5
README.md
···
86
86
### 3. use in your code
87
87
88
88
```python
89
-
from src.models.models import FmPlyrTrack, FmPlyrLike
89
+
from your_project.models import FmPlyrTrack, FmPlyrLike
90
90
91
91
track = FmPlyrTrack(
92
92
uri="at://did:plc:xyz/fm.plyr.track/123",
···
97
97
98
98
### 4. regenerate when lexicons change
99
99
100
-
add to your build/ci:
100
+
**option a: pre-commit hook**
101
+
102
+
```yaml
103
+
# .pre-commit-config.yaml
104
+
repos:
105
+
- repo: local
106
+
hooks:
107
+
- id: pmgfal
108
+
name: generate atproto models
109
+
entry: uvx pmgfal ./lexicons -o ./src/models -p fm.plyr
110
+
language: system
111
+
files: ^lexicons/.*\.json$
112
+
pass_filenames: false
113
+
```
114
+
115
+
**option b: justfile**
116
+
117
+
```just
118
+
# justfile
119
+
generate:
120
+
uvx pmgfal ./lexicons -o ./src/models -p fm.plyr
121
+
```
122
+
123
+
**option c: github actions**
101
124
102
-
```bash
103
-
uvx pmgfal ./lexicons -o ./src/models -p fm.plyr
125
+
```yaml
126
+
# .github/workflows/ci.yml
127
+
- name: generate models
128
+
run: uvx pmgfal ./lexicons -o ./src/models -p fm.plyr
104
129
```
105
130
106
-
caching ensures this is fast when lexicons haven't changed.
131
+
caching ensures regeneration is fast (~0.3s for 300 lexicons) when files haven't changed.
107
132
108
133
## external refs
109
134
+55
bench.py
+55
bench.py
···
1
+
#!/usr/bin/env python3
2
+
"""benchmark pmgfal on real lexicons."""
3
+
4
+
import subprocess
5
+
import tempfile
6
+
import time
7
+
from pathlib import Path
8
+
9
+
10
+
def bench_atproto():
11
+
"""benchmark against full atproto lexicons."""
12
+
with tempfile.TemporaryDirectory() as tmp:
13
+
# clone atproto
14
+
print("cloning atproto lexicons...")
15
+
subprocess.run(
16
+
["git", "clone", "--depth=1", "https://github.com/bluesky-social/atproto.git", tmp],
17
+
capture_output=True,
18
+
check=True,
19
+
)
20
+
21
+
lexicon_dir = Path(tmp) / "lexicons"
22
+
output_dir = Path(tmp) / "output"
23
+
json_files = list(lexicon_dir.rglob("*.json"))
24
+
25
+
print(f"found {len(json_files)} lexicon files")
26
+
27
+
# benchmark generation (cold)
28
+
start = time.perf_counter()
29
+
subprocess.run(
30
+
["uv", "run", "pmgfal", str(lexicon_dir), "-o", str(output_dir), "--no-cache"],
31
+
check=True,
32
+
)
33
+
cold_time = time.perf_counter() - start
34
+
35
+
# count output
36
+
models_file = output_dir / "models.py"
37
+
lines = len(models_file.read_text().splitlines()) if models_file.exists() else 0
38
+
39
+
# benchmark cache hit
40
+
start = time.perf_counter()
41
+
subprocess.run(
42
+
["uv", "run", "pmgfal", str(lexicon_dir), "-o", str(output_dir)],
43
+
check=True,
44
+
)
45
+
cache_time = time.perf_counter() - start
46
+
47
+
print(f"\nresults:")
48
+
print(f" lexicons: {len(json_files)}")
49
+
print(f" output: {lines} lines")
50
+
print(f" cold generation: {cold_time:.3f}s")
51
+
print(f" cache hit: {cache_time:.3f}s")
52
+
53
+
54
+
if __name__ == "__main__":
55
+
bench_atproto()