Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Positional init-only arguments? #33

Closed
nolar opened this issue Apr 3, 2021 · 2 comments
Closed

Positional init-only arguments? #33

nolar opened this issue Apr 3, 2021 · 2 comments
Labels
question Further information is requested

Comments

@nolar
Copy link

nolar commented Apr 3, 2021

First of all, thanks for this great library. I like how it makes data classes easier than the built-in dataclasses, and especially the support for __slots__.

While switching my framework to dataclassy, I've hit one problem that I cannot express in code properly:

How can I declare pseudo-positional InitVars?

Here is the equivalent code for dataclasses:

import dataclasses

@dataclasses.dataclass()
class Selector:
    arg1: dataclasses.InitVar[Union[None, str, Marker]] = None
    arg2: dataclasses.InitVar[Union[None, str, Marker]] = None
    arg3: dataclasses.InitVar[Union[None, str, Marker]] = None
    argN: dataclasses.InitVar[None] = None  # a runtime guard against too many positional arguments

    group: Optional[str] = None
    version: Optional[str] = None
    plural: Optional[str] = None
    # ... more things here

    def __post_init__(
            self,
            arg1: Union[None, str, Marker],
            arg2: Union[None, str, Marker],
            arg3: Union[None, str, Marker],
            argN: None,  # a runtime guard against too many positional arguments
    ) -> None:
        ...

The supposed use-case is:

# All notations are equivalent and must create exactly the same objects:
CRDS = Selector('apiextensions.k8s.io', 'customresourcedefinitions')
CRDS = Selector('apiextensions.k8s.io', plural='customresourcedefinitions')
CRDS = Selector('apiextensions.k8s.io', None, plural='customresourcedefinitions')
CRDS = Selector('apiextensions.k8s.io', version=None, plural='customresourcedefinitions')
CRDS = Selector(group='apiextensions.k8s.io', version=None, plural='customresourcedefinitions')

I.e., it is either explicitly specifying the kwargs to be stored on the data class, or passing them as positional (pseudo-positional) init-vars. The positional init-vars "arg1..arg3" are then interpreted in the post-init method to be stored as one of the group/version/plural/etc fields as it seems appropriate. In some cases, it might even parse and split positional init-args into several fields: e.g. Selector('apiextensions.k8s.io/v1') would be split to Selector(group='apiextensions.k8s.io', version='v1').

The details are not essential, the only essential part here is the post-init contains "some logic" for converting these pseudo-positional arg1..argN into the actual useful storeable fields.

For the full example:


When I try to do this the dataclassy-way, and remove the InitVar[] declarations, the positional arguments go to the first fields: e.g., group & version for the first example line, while the intention is to interpret them as group & plural (as it would be implemented in the post-init function) — which expectedly gives wrong results.

If I keep the arg1..argN fields in the top of the list of fields, they are accepted as needed but are stored on the object as the same-named fields. I can make them internal and hide them from reprs, but I would prefer to not store them at all and keep them as init-only.

What would be the best way to implement the positional init-only variables with dataclassy?

Thank you in advance.

@biqqles
Copy link
Owner

biqqles commented Apr 3, 2021

Since you are doing so much in __post_init__ anyway, it might be simplest to just use init=False and write a custom __init__ instead of using the generated method.

@biqqles biqqles added the question Further information is requested label Apr 3, 2021
@nolar
Copy link
Author

nolar commented Apr 3, 2021

Thanks! Indeed, I somehow managed to miss this option :-)

@nolar nolar closed this as completed Apr 3, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants