Skip to content

Conversation

deckar01
Copy link
Member

Add an experimental decorator for declaring meta attributes that inherits by default.

Resolves #1879

Screenshot 2025-02-13 at 4 05 28 PM

@deckar01 deckar01 force-pushed the 1879-meta-decorator branch 2 times, most recently from 98a871c to 73cbe0f Compare February 14, 2025 00:42
@deckar01 deckar01 force-pushed the 1879-meta-decorator branch from 73cbe0f to a07a40a Compare February 14, 2025 00:46
def meta(*bases, **kwargs): ...


def meta(*bases, **kwargs):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the @overload usage seems a bit odd...does the approach with TypedDict and total=False not work? like what we do here?

class _BaseFieldKwargs(typing.TypedDict, total=False):
load_default: typing.Any
dump_default: typing.Any
data_key: str | None
attribute: str | None
validate: types.Validator | typing.Iterable[types.Validator] | None
required: bool
allow_none: bool | None
load_only: bool
dump_only: bool
error_messages: dict[str, str] | None
metadata: typing.Mapping[str, typing.Any] | None

or perhaps

def meta(
    *bases: SchemaMeta,
    fields: tuple[str, ...] | list[str] | None,
    additional: tuple[str, ...] | list[str] | None,
    # ...
    **kwargs,
):
    def wrapper(schema):
        mro = bases if bases else (schema.Meta,)
        meta = type(schema.Meta.__name__, mro, {
            "fields": fields,
            "additional": additional,
             # ...
             **kwargs
        })
        return type(schema.__name__, (schema,), {"Meta": meta})

    return wrapper

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unpack[TypedDict] does not allow accepting extra kwargs, but we allow custom Meta attributes.

Explicitly copying the args into a dictionary defines missing attributes as None, which breaks inheritance.

One @overloadis all that is needed (and is valid), but mypy requires a sacrificial overload.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I see. In that case, maybe just add comments about why this approach is necessary. Could even include a link to that gh comment


@typing.overload
def meta(
*bases: SchemaMeta,
Copy link
Member

@sloria sloria Feb 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be

Suggested change
*bases: SchemaMeta,
*bases: Schema.Meta,

? Surprised mypy doesn't raise an error in the tests tho 🤔

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Meta Decorator

2 participants