ZeroIntensity / view.py

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

Casting Protocol #187

Open ZeroIntensity opened 3 months ago

ZeroIntensity commented 3 months ago

Proposal:

view.py should support casting any arbitrary type through a __view_cast__ protocol. This will make file upload types in #174 possible. Adding asynchronous support will be a royal pain in the ass, but I can't really get around that.

Example API

from view import new_app
from typing import Self

app = new_app()
ViewNativeType = str | int | bytes | ...  # Rest of the native types, this will go in the view.typing module

class MyCustomType:
    def __init__(self, whatever: str) -> None:
        self.whatever = whatever

    @classmethod
    async def __view_cast__(cls, obj: ViewNativeType) -> Self:
        if not isinstance(obj, str):
            raise TypeError("")  # This could possibly be something like a TypeCastError?
        return cls(obj)

@app.get("/")
@app.body("something", MyCustomType)
async def index(something: MyCustomType):
    return something.whatever

app.run()

It might be a good idea to remove __view_body__ and __view_construct__, or at least add some sort of base class to implement the behavior using __view_cast__:

class SupportsViewBody:
    __view_body__: ClassVar[dict[str, type[Any]]]

    async def __view_cast__(cls, obj: ViewNativeType) -> Self:
        if not isinstance(obj, dict):
            raise TypeError(...)

        # We can use our own TypeCode API!
        tp = compile_type(cls.__view_body__)
        return tp.cast(obj)