-54
languages/python/language/patterns.md
-54
languages/python/language/patterns.md
···
168
168
# callers can catch AppError for all, or specific types
169
169
```
170
170
171
-
## decorators that modify signatures
172
-
173
-
add parameters dynamically:
174
-
175
-
```python
176
-
import inspect
177
-
from functools import wraps
178
-
179
-
def filterable(fn):
180
-
"""add _filter parameter for jmespath filtering."""
181
-
@wraps(fn)
182
-
async def wrapper(*args, _filter: str | None = None, **kwargs):
183
-
result = await fn(*args, **kwargs)
184
-
if _filter:
185
-
import jmespath
186
-
return jmespath.search(_filter, result)
187
-
return result
188
-
189
-
# modify signature to include new param
190
-
sig = inspect.signature(fn)
191
-
params = list(sig.parameters.values())
192
-
params.append(inspect.Parameter(
193
-
"_filter",
194
-
inspect.Parameter.KEYWORD_ONLY,
195
-
default=None,
196
-
))
197
-
wrapper.__signature__ = sig.replace(parameters=params)
198
-
return wrapper
199
-
```
200
-
201
-
the wrapper's signature now includes `_filter`. IDEs and schema generators see it.
202
-
203
-
from [pdsx/mcp/filterable.py](https://github.com/zzstoatzz/pdsx/blob/main/src/pdsx/mcp/filterable.py)
204
-
205
171
## argparse for CLIs
206
172
207
173
argparse is stdlib. subparsers with aliases give you unix-style commands:
···
265
231
266
232
console = Console()
267
233
```
268
-
269
-
## lowercase aesthetic
270
-
271
-
docstrings, comments, and output in lowercase:
272
-
273
-
```python
274
-
"""list records in a collection."""
275
-
276
-
def list_records(collection: str) -> list[dict]:
277
-
"""list records from the specified collection.
278
-
279
-
args:
280
-
collection: the collection to list from
281
-
282
-
returns:
283
-
list of record dictionaries
284
-
"""
285
-
```
286
-
287
-
consistent voice throughout.
288
234
289
235
sources:
290
236
- [pdsx](https://github.com/zzstoatzz/pdsx)