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

139 graphql strawberry #141

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft

139 graphql strawberry #141

wants to merge 3 commits into from

Conversation

paula-mg
Copy link

@paula-mg paula-mg commented Sep 6, 2024

No description provided.

Comment on lines +40 to +43
# We make a strawberry input classs using the scanspec pydantic models
# This isn't possible because scanspec models are actually pydantic
# dataclasses. We should have a word with Tom about it and probably
# raise an issue on strawberry.
Copy link
Contributor

Choose a reason for hiding this comment

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

@callumforrester I am not tied to dataclass, but I have a requirement for positional args. I have a choice of directions for you:

  1. Continue using dataclasses, add support to strawberry, probably using something like what I needed to do to autodoc_pydantic
  2. Ditch dataclasses and make a BaseModel subclass with positional arg support. I think we could make this work both at runtime using something like this and at static analysis by overriding the dataclass_transform. The closed issue would suggest that pydantic would never accept such an approach upstream.

Copy link
Contributor

Choose a reason for hiding this comment

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

To elaborate on 2, this works for both static analysis and at runtime:

from __future__ import annotations

from abc import ABCMeta
from typing import Any

from pydantic import BaseModel, Field
from typing_extensions import dataclass_transform

# TODO: not sure about the others like NoInitField and PrivateAttr
@dataclass_transform(field_specifiers=(Field,))
class PosargsMeta(type(BaseModel), ABCMeta):
    def __new__(
        mcs,
        cls_name: str,
        bases: tuple[type[Any], ...],
        namespace: dict[str, Any],
        **kwargs: Any,
    ) -> type:
        cls = super().__new__(mcs, cls_name, bases, namespace, **kwargs)
        original_init = cls.__init__

        def patched_init(self, *args, **kwargs):
            for k, v in zip(cls.model_fields, args, strict=False):
                kwargs[k] = v
            original_init(self, **kwargs)

        cls.__init__ = patched_init
        return cls

class Spec(BaseModel, metaclass=PosargsMeta):
    pass

class Line(Spec):
    start: float = Field(description="Midpoint of the first point of the line")
    stop: float = Field(description="Midpoint of the last point of the line")
    num: int = Field(min=1, description="Number of frames to produce")

# pyright and pydantic are happy with this...
obj = Line(3, 4, 5)

Copy link
Contributor

Choose a reason for hiding this comment

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

I have no particular preference, we should discuss with @paula-mg since she'll be doing the work.

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.

3 participants