pydantic model generator for atproto lexicons

fix cache dir to use XDG on all unix, add --show-cache flag (#3)

- use ~/.cache/pmgfal (XDG standard) on all unix-like systems including macOS
- add --show-cache flag to print cache directory and exit
- update README: change suggested output dir from src/models to src/atproto
to avoid confusion with ORM schemas

๐Ÿค– Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>

authored by zzstoatzz.io

Claude and committed by
GitHub
46a9285d 9a7f5fac

+19 -12
+8 -9
README.md
··· 17 uvx pmgfal 18 19 # explicit paths 20 - uvx pmgfal ./lexicons -o ./src/models 21 22 # filter by namespace 23 uvx pmgfal -p fm.plyr ··· 31 pmgfal 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 33 cache location: 34 - - macos: `~/Library/Caches/pmgfal/` 35 - - linux: `~/.cache/pmgfal/` 36 - windows: `%LOCALAPPDATA%/pmgfal/` 37 38 the cache key includes: ··· 72 โ”‚ โ”œโ”€โ”€ like.json 73 โ”‚ โ””โ”€โ”€ comment.json 74 โ”œโ”€โ”€ src/ 75 - โ”‚ โ””โ”€โ”€ models/ 76 โ”‚ โ””โ”€โ”€ .gitkeep 77 โ””โ”€โ”€ pyproject.toml 78 ``` ··· 80 ### 2. generate models 81 82 ```bash 83 - uvx pmgfal ./lexicons -o ./src/models -p fm.plyr 84 ``` 85 86 ### 3. use in your code 87 88 ```python 89 - from your_project.models import FmPlyrTrack, FmPlyrLike 90 91 track = FmPlyrTrack( 92 uri="at://did:plc:xyz/fm.plyr.track/123", ··· 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 ··· 117 ```just 118 # justfile 119 generate: 120 - uvx pmgfal ./lexicons -o ./src/models -p fm.plyr 121 ``` 122 123 **option c: github actions** ··· 125 ```yaml 126 # .github/workflows/ci.yml 127 - name: generate models 128 - run: uvx pmgfal ./lexicons -o ./src/models -p fm.plyr 129 ``` 130 131 caching ensures regeneration is fast (~0.3s for 300 lexicons) when files haven't changed.
··· 17 uvx pmgfal 18 19 # explicit paths 20 + uvx pmgfal ./lexicons -o ./src/atproto 21 22 # filter by namespace 23 uvx pmgfal -p fm.plyr ··· 31 pmgfal 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 33 cache location: 34 + - unix (linux/macos/bsd): `~/.cache/pmgfal/` (or `$XDG_CACHE_HOME/pmgfal/`) 35 - windows: `%LOCALAPPDATA%/pmgfal/` 36 37 the cache key includes: ··· 71 โ”‚ โ”œโ”€โ”€ like.json 72 โ”‚ โ””โ”€โ”€ comment.json 73 โ”œโ”€โ”€ src/ 74 + โ”‚ โ””โ”€โ”€ atproto/ 75 โ”‚ โ””โ”€โ”€ .gitkeep 76 โ””โ”€โ”€ pyproject.toml 77 ``` ··· 79 ### 2. generate models 80 81 ```bash 82 + uvx pmgfal ./lexicons -o ./src/atproto -p fm.plyr 83 ``` 84 85 ### 3. use in your code 86 87 ```python 88 + from your_project.atproto import FmPlyrTrack, FmPlyrLike 89 90 track = FmPlyrTrack( 91 uri="at://did:plc:xyz/fm.plyr.track/123", ··· 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 ··· 116 ```just 117 # justfile 118 generate: 119 + uvx pmgfal ./lexicons -o ./src/atproto -p fm.plyr 120 ``` 121 122 **option c: github actions** ··· 124 ```yaml 125 # .github/workflows/ci.yml 126 - name: generate models 127 + run: uvx pmgfal ./lexicons -o ./src/atproto -p fm.plyr 128 ``` 129 130 caching ensures regeneration is fast (~0.3s for 300 lexicons) when files haven't changed.
+11 -3
python/pmgfal/__init__.py
··· 70 71 def get_cache_dir() -> Path: 72 """get the user cache directory for pmgfal.""" 73 - if sys.platform == "darwin": 74 - base = Path.home() / "Library" / "Caches" 75 - elif sys.platform == "win32": 76 base = Path(os.environ.get("LOCALAPPDATA", Path.home() / "AppData" / "Local")) 77 else: 78 base = Path(os.environ.get("XDG_CACHE_HOME", Path.home() / ".cache")) 79 return base / "pmgfal" 80 ··· 162 action="version", 163 version=f"%(prog)s {__version__}", 164 ) 165 166 parsed = parser.parse_args(args) 167 168 temp_dir = None 169 try:
··· 70 71 def get_cache_dir() -> Path: 72 """get the user cache directory for pmgfal.""" 73 + if sys.platform == "win32": 74 base = Path(os.environ.get("LOCALAPPDATA", Path.home() / "AppData" / "Local")) 75 else: 76 + # XDG standard for all unix-like systems (linux, macos, bsd) 77 base = Path(os.environ.get("XDG_CACHE_HOME", Path.home() / ".cache")) 78 return base / "pmgfal" 79 ··· 161 action="version", 162 version=f"%(prog)s {__version__}", 163 ) 164 + parser.add_argument( 165 + "--show-cache", 166 + action="store_true", 167 + help="print cache directory path and exit", 168 + ) 169 170 parsed = parser.parse_args(args) 171 + 172 + if parsed.show_cache: 173 + print(get_cache_dir()) 174 + return 0 175 176 temp_dir = None 177 try: