ZeroIntensity / view.py

The Batteries-Detachable Web Framework
https://view.zintensity.dev
MIT License
206 stars 15 forks source link

Custom Loaders #107

Closed ZeroIntensity closed 1 month ago

ZeroIntensity commented 7 months ago

Feature description

For "batteries-detachable" purposes, there should be an API for creating custom loaders. Perhaps some plugin API could be introduced with this? (If so, that will be a separate issue).

Feature example API

[app]
loader = "custom"
from view import new_app, App, Route
from pathlib import Path

@app.loader
async def load(app: App, path: Path) -> list[Route]:
    return [...]

Anything else?

No response

tallhypnosis commented 1 month ago

could you please elaborate more on this required feature ?

ZeroIntensity commented 1 month ago

Well, to start, do you know how loaders work?

ZeroIntensity commented 1 month ago

Ok, ignore my previous message. I'm going to assume you don't know what loaders do - loaders in view.py are responsible for collection of routes. Each loader has some sort of logic to extract Route objects from a given path (see the loaders section of the docs).

For example, the filesystem loader takes a Path specified in the config, extracts routes from the directory via runpy, and assigns each route a path accordingly. The source code for the filesystem loader can be found here, if you're interested on how that works.

This issue involves letting the user decide how to load routes from a given path. In my example API, I proposed some sort of app.loader decorator that specifies a custom loader. In this issue, you'll likely want to add a custom option to the config (see here), and then a way to call the custom loader (see here). You'll probably want to have some _user_loader attribute to store the loader function, and then just call that when the loader is custom.

I'm thinking it would look something like:

if self.config.app.loader == "custom":
    if not self._user_loader:
        raise SomeErrorYouCanDecide("no custom loader is set")
    self._user_loader(self, self.config.app.loader_path)

I'll leave writing the decorator up to you. If you have any questions, feel free to ask here on on our discord.