Kernel.run()inKernel.pyis the runtime entrypoint: it finds the first matching route, buildsRequest/Response, calls controller action, then returnsresponse.getContent().- Route matching is strict on method + regex path (
Route.match()inRoute.py), with trailing slash normalization (/foo/->/foo). - Controllers are loaded dynamically from route strings like
Controllers.X.YController(Route.__buildMethod()), instantiated withconfigfromconfig.py. - If no route matches, framework returns plain-text 404 in
Kernel.run(). - Exceptions deriving from
Exceptions.Baseare translated to HTTP code/message inKernel.run(); other exceptions become 500 (with traceback only whendebug=Truein config).
Kernelimports project-root modules by name (config,routesby default), so these modules must be importable inPYTHONPATH.- In
routes.py, export a list named exactly like the module name (routes), becauseKernel.__loadRoutes()callsgetattr(module, self.__nameRoutes). - Route path parameters must be declared in
paramsDefand support only'int'or'str'(Route.__buildPathRegEx()). - Use
nameRouteonly if you need a stable custom route name; default is built from controller + method + HTTP method.
Requestmerges params from three sources (path params, query string, multipart/form body) inRequest.__getParameters().- For repeated keys, values are accumulated as lists;
Request.get()returns the first value,Request.getAsList()returns all. - File uploads are parsed via vendored
multipart.py(parse_form_data) and exposed byRequest.getFile()/hasFile(). Response.getContent()always calls WSGIstart_responseand returnslist[bytes]; controller actions should mutateresponseinstead of returning body strings.Response.__buildHeader()always setsContent-typeand defaultAccess-Control-Allow-Origin: *;Kernelmay add another origin header if configured.
- Controller action signature is
action(self, request: Request, response: Response); mutateresponse.stringContentorresponse.byteContent. - Base class is
BaseControllerand receives injected config asself._config. - For BasicAuth-gated actions, use
decoratorLoginRequiredfromBaseController.py(expectsAUTH_TYPE=BasicandREMOTE_USER). BaseTplControllerexpectspathBaseandpathTemplatesin config and reads template files directly.
- Core external dependency:
SQLObject~=3.11.0(requirements.txt), used inKernel.__connectToDatabase()whenuriDbexists in config. - Multipart handling is intentionally not
cgi.FieldStorage; project uses localmultipart.py(from defnull/multipart). - Deployment assumptions are Apache +
mod_wsgi(README.md); static assets are expected to be served by Apache aliases, not by this framework.
- No automated test suite is present in this repository; validate changes with focused local smoke tests.
- Package build flow is script-driven:
makePyPiPackage.shcreatespypiPackage/and runspython3 -m build. - Generated docs exist under
docs/; treat them as generated artifacts unless you intentionally regenerate documentation.
- In
Exceptions.py, subclasses currently set private fields without callingBase.__init__; if you add/modify exceptions, ensure.returnCode/.returnMsgstill work withKernelerror mapping. Requestreadswsgi.inputduring initialization; middleware/controllers should not expect unread request body streams afterward.- Keep route/controller wiring explicit; dynamic import strings are fragile to module renames.