@suss/adapter-python 0.22.4 → 0.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -414,10 +414,40 @@ Where it stops, and what the gap says:
414
414
 
415
415
  One callee spelling that lands on two definitions in one body, `load()` under a class body that imports its own `load` say, is placed on neither.
416
416
 
417
- Not followed yet: a method inherited from a base class, a callable stored in a dict or a list, a decorator's own body, a call written in a parameter default such as `Depends(get_db)`, and an attribute set on `self` in `__init__` and called elsewhere.
417
+ Not followed yet: a method inherited from a base class, a callable stored in a dict or a list, a decorator's own body, and an attribute set on `self` in `__init__` and called elsewhere. A function written in a parameter default such as `Depends(get_db)` is not a call the route makes; it runs around the route, and the next section says how it is read.
418
418
 
419
419
  A summary's `identity.id` is the file relative to the project root plus the export path (`app/store.py::read_orders`, `app/models.py::Orders.total`), and `summary` on an effect is that id. Two summaries that would share an id are told apart by their boundary, then by their line.
420
420
 
421
+ ## What runs around a route
422
+
423
+ A route's wire behavior is not only what its own body does. A FastAPI dependency that raises 401, a middleware that returns 429 and an exception handler that turns a `ValueError` into a 500 all respond for the route without appearing in it. Each of those gets a summary of its own, the route lists them under `metadata.wrappers.applied` in the order they run, and the extractor composes their transitions into the route's, with `wrappers.from` on each transition a wrapper contributed. How that composition works is in the extractor's README; this section says which registrations the adapter reads.
424
+
425
+ A pack declares each way its library attaches something around a route, in `wrappers` on a discovery pattern. There are two forms:
426
+
427
+ | Form | Reads | Example |
428
+ | --- | --- | --- |
429
+ | `dependency` | a function passed to one of `callees` inside a `keyword` list, on the app or router construction, on the route decorator, or in a parameter default | `Depends(require_caller)` |
430
+ | `decoratedWrapper` | a function decorated with `attribute` on the app or router object | `@app.middleware("http")`, `@app.exception_handler(ValueError)`, `@app.before_request` |
431
+
432
+ Each form says which constructions register it, and how far the registration reaches. A registrar with `covers: "everyRoute"` (the app) reaches every route the pack discovers; one with `covers: "ownRoutes"` (a router or namespace) reaches the routes decorated on that same object, told apart by where it was constructed. A registration is read only where the object is recognized the way a route decorator's object is, so `app = FastAPI(...)` in one module and `@app.middleware` in another are joined through the import the same way a route on an imported router is.
433
+
434
+ How a wrapper's body is read depends on the form:
435
+
436
+ - A `dependency` runs to completion before the handler, so each `raise` of a response status is a response of its own and every `return` hands on to the route.
437
+ - A `decoratedWrapper` with `continuationParam` (FastAPI middleware) hands on at the statement that calls that parameter, and anything after the call is not read. A `return` that does not call it responds on its own.
438
+ - A `decoratedWrapper` with `returnedValueResponds` (Flask's `before_request`) responds with whatever it returns and hands on only where it returns nothing.
439
+ - A `decoratedWrapper` with `throwParam` (an exception handler) runs only for a request that raised, so its responses replace each of the route's paths that end in a `raise` the pack does not read as a response. A raised `HTTPException` or `abort` already has a status, so no handler applies to it.
440
+
441
+ Wrappers run in the order the library runs them: middleware first, then dependencies from the app, the router and the route in that order, then exception handlers over what raised. Two registrations of the same function are one wrapper.
442
+
443
+ Not read yet:
444
+
445
+ - `include_router(router, dependencies=[...])` and `add_middleware(SomeClass)`. A dependency at the mount and a middleware given as a class are missed.
446
+ - Which exception type a handler is for. Every handler applies to every unread raise, so a route with two handlers reports both statuses on the paths that raise.
447
+ - A dependency's own dependencies. `Depends(f)` where `f` takes `g: str = Depends(g)` reads `f` only.
448
+ - A parameter default that refers to something other than a function at module scope, such as a method or a variable bound inside a function.
449
+ - Flask's `before_request` on a blueprint. A flask-restx route is decorated on a namespace, and the blueprint is where it is mounted, so only the app's hook is read.
450
+
421
451
  ## What a file imports from the project
422
452
 
423
453
  Every summary has `metadata.moduleImports`, the project files its own file's imports resolved to, relative to the workspace root and sorted. A file whose imports all resolve outside the project gets an empty list rather than no field, so a Lambda handler that imports only the standard library still tells the checker that its closure is the handler module alone. A checker rebuilds the import graph from that field to work out which modules a template's handler entry loads; the entry `app.handler` under `CodeUri: src/` matches `src/app.py`, and a dotted module such as `shop.app.handler` matches `src/shop/app.py`.