pyRPC has no registration list. No plugin discovery, no directory scan, no decorators collected into a manifest. There is exactly one mechanism: importing a module executes its @rpc decorators, which insert procedures into the router singleton. Every codegen feature rests on this sentence, and v0.13.0 makes you name that module explicitly.
The failure mode that forced the contract
Consider the standard Django layout: procedures declared in views.py, wired in urls.py. If your configured module was the entrypoint, the watcher would import urls.py... or think it did. Here is the trap the old flow contained:
reload_modulerestores the edited module’s bytecode but does not re-execute its importers.urls.pystays cached insys.modules; its top-levelfrom . import viewsdoes not run again.- The decorators never re-fire. The router keeps whatever was registered before your edit.
- Regenerated types are stale, silently, with a green checkmark.
For FastAPI single-file apps the entrypoint is the registration module, so the bug hid. Split-module layouts exposed it. The fix is not cleverer reloading machinery, it is naming the module whose import registers everything, and importing exactly that:
// pyrpc.json, django layout
{ "backend": {
"framework": "django",
"entrypoint": "manage.py",
"types_module": "myproject.views" // <- the file with @rpc
} }Defaults that fail loudly
For fastapi/flask/asgi, types_module defaults to the module part of entrypoint, usually right, because those files typically call mount_*(app) themselves. For Django there is no honest default ( settings.py registers nothing; guessing views paths is how silent emptiness happens), so the contract requires it: omit it and resolution fails with a message telling you what to name. The wizard auto-detects the shallowest */views.py under the project and offers it preselected.
The general shape of the lesson
Import-side-effect systems are compact and delightful until someone asks “which import?” At that moment the honest answers are only ever: a named module or a real registry. We picked naming, one string in one JSON file, because it composes with reload semantics instead of fighting them, and because the failure mode of naming wrong (empty schema, loud) beats the failure mode of scanning wrong (partial schema, quiet).
If you remember one line from this post: codegen reflects what imported, not what exists. Point the name at the file where your procedures live.

pyRPC