Giter Site home page Giter Site logo

graphene-pydantic's People

Contributors

abhinand-c avatar arun-sureshkumar avatar arunsureshkumar avatar boyanghuang avatar conao3 avatar dantheman39 avatar davidkell avatar doctorjohn avatar excessdenied avatar gary-liguoliang avatar jaygorrell avatar jmhammel avatar kierandarcy avatar kodyliszek avatar mak626 avatar mnieber avatar necaris avatar process0 avatar trollboy avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

graphene-pydantic's Issues

Model inheritance does not convert correctly

Use Case Scenario

I've two pydantic models. Each in his own module (file). One Model, the TUser depends on the TAddress.

address_model.py

class TAddress(BaseModel):
    id: Optional[int]
    address: Optional[constr(max_length=100, strip_whitespace=True)]
    city: Optional[constr(max_length=80, strip_whitespace=True)]
    postal_code: Optional[constr(max_length=15, strip_whitespace=True)]
    country: Optional[constr(max_length=3)]

user_model.py

class TUser(BaseModel):
    id: UUID = None
    email: Optional[EmailStr]

    address: Optional[TAddress]

    is_active: Optional[bool]
    is_email_verified: Optional[bool]
    created_at: Optional[datetime.datetime]

If I use the TUser model know for my PydanticObjectType

class UserType(PydanticObjectType):
    class Meta:
        model = TUser

I get the following error message:

graphene_pydantic.converters.ConversionError: Don't know how to convert the Pydantic field ModelField(name='address', type=Optional[TAddress], required=False, default=None) (<class 'app.address.serializers.TAddress'>)

It seems like that there is a problem when using pydantic models from different modules that depends on each other.
What is the solution for this use case?

Any idea?

Pydantic Version Error

When installing graphene-pydantic with pip, I get this error message

ERROR: After October 2020 you may experience errors when installing or updating packages. This is because pip will change the way that it resolves dependency conflicts.

We recommend you use --use-feature=2020-resolver to test your packages with the new resolver before it becomes the default.

graphene-pydantic 0.1.0 requires pydantic<=1.6,>=1.0, but you'll have pydantic 1.6.1 which is incompatible.

This does not affect installation in any way but it would help updating the library to use the latest pydantic version

Document PydanticObjectType.resolve_foo member functions

I was delighted that the following works (I copied something from django_graphene code), but AFAICT it's not a documented feature

class Resolution(PydanticObjectType):
    class Meta:
        model = ResolutionModel
        exclude_fields = ("status",)

    status = graphene.String()

    def resolve_status(self, info, **kwargs):
        return str(self.status)

I suppose you can add any additional field to a PydanticObjectType by declaring it and adding a resolve function for it? It would be nice to add this to the docs.

Support for pydantic 1.8

Currently, library is built for pydantic:

pydantic = ">=1.0,<1.7"

But newer version 1.8.2 of pydantic is currently available making it impossible to use graphene-pydantic with this version.

Required/NonNull behaviour for Pydantic fields with defaults

We think the following code produces an incorrect schema:

from pydantic import BaseModel
from graphene_pydantic import PydanticObjectType
import graphene

class ExampleModel(BaseModel):
	attr: int = 0

class ExampleType(PydanticObjectType):
	class Meta:
		model = ExampleModel

class Query(graphene.ObjectType):
    example = graphene.Field(ExampleType)

    @staticmethod
    def resolve_example(parent, info):
        # fetch actual PersonModels here
        return [ExampleType()]

schema = graphene.Schema(query=Query)

print(schema)

Result:

schema {
  query: Query
}

type ExampleType {
  attr: Int
}

type Query {
  example: ExampleType
}

AFAICT, the Int field on ExampleType should not be nullable, since there will always be a default value and this value cannot be null. Instead it should be:

type ExampleType {
  attr: Int!
}

I think it's a one line fix here, you need to change:

field_kwargs.setdefault("required", field.required)

to

field_kwargs.setdefault("required", not field.allow_none)

For reference, the Pydantic docs on distinguishing nullability (optional) and required fields.

If you agree with this, I'm happy to submit a PR - we are already doing this on our fork.

How do we indicate that a List is made of non-null elements?

Right now, when my pydantic model looks like the following:

class MyClassModel(BaseModel):
    myList: List[str]

and my graphene model looks like this:

class MyClassType(PydanticObjectType):
    class Meta:
        model = MyClassModel
        fields = ("myList")

the GraphQL schema output for this field looks like this:

myList: [String]!

This means that introspection in TypeScript interprets each element in the List as a Maybe<String> instead of a String. What can I do here to ensure that the type is myList: [String!]!?

Thanks!

Enum name conflict for models used in both ObjectType and InputObjectType

If you try to build an ObjectType and InputObjectType for pydantic models with the same enum, it tries to create the same enum twice. (This is not an issue with re-using the same enum in multiple ObjectTypes though.)

Here's a reproducible example:

import enum
import pydantic
import graphene
from graphene_pydantic import PydanticObjectType, PydanticInputObjectType

class Color(enum.Enum):
  red = 1
  green = 2
  blue = 3

class ColorModel(pydantic.BaseModel):
  color: Color

class ColorType(PydanticObjectType):
  class Meta:
    model = ColorModel

class ColorInputType(PydanticInputObjectType
):
  class Meta:
    model = ColorModel

class CreateColor(graphene.Mutation):
  class Arguments:
    data = graphene.Argument(ColorInputType)

  ok = graphene.String()

  def mutate(self, info, data):
    return ColorModel(**data)

class Query(graphene.ObjectType):
  color = graphene.Field(ColorType)

class Mutation(graphene.ObjectType):
  createColor = CreateColor.Field()

schema = graphene.Schema(query=Query, mutation=Mutation)

And the error:

     95             _type = map[type._meta.name]
     96             if isinstance(_type, GrapheneGraphQLType):
---> 97                 assert _type.graphene_type == type, (
     98                     "Found different types with the same name in the schema: {}, {}."
     99                 ).format(_type.graphene_type, type)

AssertionError: Found different types with the same name in the schema: Color, Color.

The workaround is just to manually define the enum type, but thought it would be helpful to know.

For others who got this error:

ColorEnumType = graphene.Enum.from_enum(Color)

class ColorType(PydanticObjectType):
  class Meta:
    model = ColorModel

  color = graphene.Field(ColorEnumType)

class ColorInputType(PydanticInputObjectType
):
  class Meta:
    model = ColorModel

  color = graphene.Argument(ColorEnumType)

Great work on the package

Hi team!

I think this package could be a great addition to the GraphQL-Python organization.
Let me know if you would be interested in adding this repo to the org! ❤️

support for V3?

looks like v3 is not supported yet, because it's throwing errors during installation

Nested PydanticInputObjectType

Hello,

I wanted to use nested pydantic.BaseModel with PydanticInputObjectType, but I struggle to make it work

Something like this:

from pydantic import BaseModel
from graphene_pydantic import PydanticInputObjectType
import graphene

class A(BaseModel):
    x: str

class B(BaseModel):
    a: A

class BInput(PydanticInputObjectType):
    class Meta:
        model = B

class createB(graphene.Mutation):
    class Arguments:
        b = BInput()

    output = graphene.String()

    def mutate(self, info, b):
        return "42"

class Mutation(graphene.ObjectType):
    createB = createB.Field()

schema = graphene.Schema(mutation=Mutation)

Gives me:

Traceback (most recent call last):
  File "[PATH]/lib/python3.9/site-packages/graphene/types/schema.py", line 122, in add_type
    name = graphene_type._meta.name
AttributeError: 'Placeholder' object has no attribute '_meta'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "[PATH]/lib/python3.9/site-packages/graphql/type/definition.py", line 1456, in fields
    fields = resolve_thunk(self._fields)
  File "[PATH]/lib/python3.9/site-packages/graphql/type/definition.py", line 300, in resolve_thunk
    return thunk() if callable(thunk) else thunk
  File "[PATH]/lib/python3.9/site-packages/graphene/types/schema.py", line 312, in create_fields_for_type
    field_type = create_graphql_type(field.type)
  File "[PATH]/lib/python3.9/site-packages/graphene/types/schema.py", line 120, in add_type
    return GraphQLNonNull(self.add_type(graphene_type.of_type))
  File "[PATH]/lib/python3.9/site-packages/graphene/types/schema.py", line 124, in add_type
    raise TypeError(f"Expected Graphene type, but received: {graphene_type}.")
TypeError: Expected Graphene type, but received: Placeholder(<class '__main__.A'>).

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "[PATH]/lib/python3.9/site-packages/graphene/types/schema.py", line 440, in __init__
    self.graphql_schema = GraphQLSchema(
  File "[PATH]/lib/python3.9/site-packages/graphql/type/schema.py", line 226, in __init__
    collect_referenced_types(mutation)
  File "[PATH]/lib/python3.9/site-packages/graphql/type/schema.py", line 435, in collect_referenced_types
    collect_referenced_types(arg.type)
  File "[PATH]/lib/python3.9/site-packages/graphql/type/schema.py", line 438, in collect_referenced_types
    for field in named_type.fields.values():
  File "[PATH]/lib/python3.9/functools.py", line 993, in __get__
    val = self.func(instance)
  File "[PATH]/lib/python3.9/site-packages/graphql/type/definition.py", line 1459, in fields
    raise cls(f"{self.name} fields cannot be resolved. {error}") from error
TypeError: BInput fields cannot be resolved. Expected Graphene type, but received: Placeholder(<class '__main__.A'>).

I tried using resolve_placeholders, but then I get an error:

from pydantic import BaseModel
from graphene_pydantic import PydanticInputObjectType
import graphene

class A(BaseModel):
    x: str

class B(BaseModel):
    a: A

class BInput(PydanticInputObjectType):
    class Meta:
        model = B

BInput.resolve_placeholders()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "[PATH]/lib/python3.9/site-packages/graphene_pydantic/inputobjecttype.py", line 152, in resolve_placeholders
    meta.registry.register_object_field(
TypeError: register_object_field() got an unexpected keyword argument 'model'

My versions are:

graphene==3.3
pydantic==2.7.1
graphene_pdantic==0.6.1

Is there any way to use PydanticInputObjectType in nested case?

Support for Pydantic Dataclass

Dataclasses are really useful in some instances. Pydantic has a drop-in replacement for dataclasses - but does not seem to supported by this library. Not sure how difficult it would be to include it? I know the classes have a __pydantic_model__ variable.

Correct handling of python reserved keywords

Hey.

Is there a way to handle reserved keywords in schema?

Pydantic model that works fine:

class Model(BaseModel):
    class_: str

    class Config:
        fields = {
            'class_': 'class'
        }

But with this model, graphene don't see field named class. Only class_.

Union of Scalar Types

Hi,

I am running into an issue in which my pydantic model defines a union of scalar types, as follows:

class ImageModel(BaseModel):
    url: str
    filename: str
    modified: Union[str, int]
    key: str
    size: int

My graphene object type:

class Image(PydanticObjectType):
    class Meta:
        model = ImageModel

Attempting to generate a graphql schema from this results in the error:
AttributeError: 'GraphQLScalarType' object has no attribute 'graphene_type'
at
graphene/types/typemap.py(251)

The caveats for unions seem to be for custom object types only. Are scalars supported?

Thanks.

EDIT

This may be a graphene specific issue?

Using Optional or Union['Model', None] with self referencing fails

Hey.

Can't make this code work. Fails with error

graphene_pydantic.converters.ConversionError: Don't know how to convert the Pydantic field ModelField(name='nodes', type=Optional[NodeModel], required=False, default=None) (<class 'app.graphql.schemas.blablabla.NodeModel'>)

Code example

from typing import Optional, Union

from pydantic import BaseModel
from graphene_pydantic import PydanticObjectType


class NodeModel(BaseModel):
    id: int
    name: str
    # nodes: Union['NodeModel', None]
    nodes: Optional['NodeModel']


NodeModel.update_forward_refs()


class NodeModelSchema(PydanticObjectType):
    class Meta:  # noqa: too-few-public-methods
        model = NodeModel

    @classmethod
    def is_type_of(cls, root, info):
        return isinstance(root, (cls, NodeModel))


NodeModelSchema.resolve_placeholders()

Am I doing something wrong?

Don't know how to convert the Pydantic field AnyUrl

I am trying to use pydantic's AnyUrl type:

class SomePydanticModel(pydantic.BaseModel):
    url: pydantic.AnyUrl = pydantic.Field()

class SomeGrapheneObject(graphene_pydantic.PydanticObjectType):
    class Meta:
        model = SomePydanticModel

But I receive the following error:

graphene_pydantic.converters.ConversionError: Don't know how to convert the Pydantic field FieldInfo(annotation=Url, required=True) (<class 'pydantic_core._pydantic_core.Url'>)

Is there a way to support this field?

graphene==3.3
graphene-pydantic==0.6.1

Support for Dict types

In the following example, add the foo: Dict[str, str] member to Person model causes an error. Is there another way that I can use a Dict, which works great in pydantic?

import uuid
from typing import Dict

import pydantic
import graphene
from graphene_pydantic import PydanticObjectType


class PersonModel(pydantic.BaseModel):
    id: uuid.UUID
    first_name: str
    last_name: str
    foo: Dict[str, str]



class Person(PydanticObjectType):
    class Meta:
        model = PersonModel

class Query(graphene.ObjectType):
    people = graphene.List(Person)

    @staticmethod
    def resolve_people(parent, info):
        # fetch actual PersonModels here
        return [PersonModel(id=uuid.uuid4(), first_name="Beth", last_name="Smith")]

Produces:

Traceback (most recent call last):
  File "/usr/lib/python3.8/runpy.py", line 194, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "/usr/lib/python3.8/runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "/home/dylan/.vscode/extensions/ms-python.python-2021.2.582707922/pythonFiles/lib/python/debugpy/__main__.py", line 45, in <module>
    cli.main()
  File "/home/dylan/.vscode/extensions/ms-python.python-2021.2.582707922/pythonFiles/lib/python/debugpy/../debugpy/server/cli.py", line 444, in main
    run()
  File "/home/dylan/.vscode/extensions/ms-python.python-2021.2.582707922/pythonFiles/lib/python/debugpy/../debugpy/server/cli.py", line 285, in run_file
    runpy.run_path(target_as_str, run_name=compat.force_str("__main__"))
  File "/usr/lib/python3.8/runpy.py", line 265, in run_path
    return _run_module_code(code, init_globals, run_name,
  File "/usr/lib/python3.8/runpy.py", line 97, in _run_module_code
    _run_code(code, mod_globals, init_globals,
  File "/usr/lib/python3.8/runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "/home/dylan/work/als-computing/splash-ml/examples/test_graphql.py", line 17, in <module>
    class Person(PydanticObjectType):
  File "/home/dylan/work/als-computing/splash-ml/env/lib/python3.8/site-packages/graphene/types/objecttype.py", line 30, in __new__
    base_cls = super().__new__(
  File "/home/dylan/work/als-computing/splash-ml/env/lib/python3.8/site-packages/graphene/utils/subclass_with_meta.py", line 46, in __init_subclass__
    super_class.__init_subclass_with_meta__(**options)
  File "/home/dylan/work/als-computing/splash-ml/env/lib/python3.8/site-packages/graphene_pydantic/objecttype.py", line 90, in __init_subclass_with_meta__
    construct_fields(
  File "/home/dylan/work/als-computing/splash-ml/env/lib/python3.8/site-packages/graphene_pydantic/objecttype.py", line 46, in construct_fields
    converted = convert_pydantic_field(
  File "/home/dylan/work/als-computing/splash-ml/env/lib/python3.8/site-packages/graphene_pydantic/converters.py", line 130, in convert_pydantic_field
    convert_pydantic_type(
  File "/home/dylan/work/als-computing/splash-ml/env/lib/python3.8/site-packages/graphene_pydantic/converters.py", line 166, in convert_pydantic_type
    raise ConversionError("Don't know how to handle mappings in Graphene.")
graphene_pydantic.converters.ConversionError: Don't know how to handle mappings in Graphene.  

Pydantic - Graphene throws error for discriminator input objects.

I am using graphene-pydantic to generate a GraphQL schema for my mutation. I have gone through the documentation and it's working fine for all the types but the problem is when I use discriminators in the modules. Below is the sample code with discriminators and that's throwing an error.

from graphene_pydantic import PydanticInputObjectType, PydanticObjectType
import graphene
from typing import Literal, Union
from pydantic import BaseModel, Field


class Cat(BaseModel):
    pet_type: Literal['cat']
    meows: int


class Dog(BaseModel):
    pet_type: Literal['dog']
    barks: float


class Lizard(BaseModel):
    pet_type: Literal['reptile', 'lizard']
    scales: bool


class Model(BaseModel):
    pet: Union[Cat, Dog, Lizard] = Field(..., discriminator='pet_type')
    n: int


# print(Model(pet={'pet_type': 'dog', 'barks': 3.14, 'eats': 'biscuit'}, n=1))


class Input(PydanticInputObjectType):
    class Meta:
        model = Model
        # exclude specified fields
        exclude_fields = ("id",)


class Output(PydanticObjectType):
    class Meta:
        model = Model
        # exclude specified fields
        exclude_fields = ("id",)


class CreateAnimal(graphene.Mutation):
    class Arguments:
        input = Input()

    output = Output

    @staticmethod
    def mutate(parent, info, input):
        print(input)
        # save model here
        return input


class Mutation(graphene.ObjectType):
    createPerson = CreateAnimal.Field()


schema = graphene.Schema(mutation=Mutation)
print(schema)

The error getting from graphene is like below and it is like a generalized error.

File "\AppData\Local\Programs\Python\Python310\lib\site-packages\graphql\type\definition.py", line 1338, in fields    raise TypeError(f"{self.name} fields cannot be resolved. {error}")
TypeError: Input fields cannot be resolved. The input field type must be a GraphQL input type.

Can someone help on this?

Support for interfaces

I see the following comment in PydanticObjectType.__init_subclass_with_meta__:

# TODO: We don't currently do anything with interfaces, and it would
# be great to handle them as well. Some options include:
# - throwing an error if they're present, because we _can't_ handle them
# - finding a model class with that name and generating an interface
#   from it
# - using the nearest common ancestor of multiple types in a Union

Are there any concrete plans to add support for interfaces in the near future? For my particular use case, I'd be happy with manually defining interfaces rather than deducing them. For example, I'd like to be able to do this:

# this model will be used to define an interface
class HasIdentityModel(pydantic.BaseModel):
    name: str
    id: str

class IdentityListModel(pydantic.BaseModel):
    things_with_ids: list[HasIdentityModel]

class PersonModel(HasIdentityModel):
    age: int

class BusinessModel(HasIdentityModel):
    owner: PersonModel

# would have to define PydanticInterfaceType similarly to PydanticObjectType
class HasIdentity(PydanticInterfaceType):
    class Meta:
        model = HasIdentityModel

class IdentityList(PydanticObjectType):
    class Meta:
        model = IdentityListModel

class Person(PydanticObjectType):
    class Meta:
        model = PersonModel
        interfaces = (HasIdentity,)  # or (HasIdentityModel, ) if that's more appropriate

class Business(PydanticObjectType):
    class Meta:
        model = BusinessModel
        interfaces = (HasIdentity,)  # as above

and then query the thingsWithIds field as

thingsWithId: {
    name
    id
    ...on Person {
        age
    }
    ...on Business {
        owner {
            name
        }
    }
}

without having to put the name and id fields on the Person or Business fragments.

Passing field descriptions to graphiql documentation

I'm trying to pass a description from one of the pydantic fields to the graphiQL documentation. I can't seem to get it to be recognized. It seems to be supported in graphene directly on the fields like this:

class Person(ObjectType):
    first_name = graphene.String(required=True)
    last_name = graphene.Field(String, description='Surname')

In pydantic it's supported like this:

class MainModel(BaseModel):
    """
    This is the description of the main model
    """
    snap: int = Field(
        42,
        title='The Snap',
        description='this is the value of snap',
        gt=30,
        lt=50,
    )

I've implemented the pydantic style description and don't see any change to the GraphiQL documentation on that field. Any ideas how to pass it over, or is this simply not supported with this library? I'm following the excellent tutorial here: https://testdriven.io/blog/fastapi-graphql/ but they don't spend any time on the self-documenting nature of graphql which is something really enjoy.

Thanks!

Several features to improve compatibility with pidantic

@necaris I have some requirements on a project that graphene-pydantic==0.3.0 doesn't support.

  1. In mutations - those fields that were not passed - still come as None. As a result, when parsing a dictionary into a Type[BaseModel], these fields are also passed through and an entry is added to the database with these values. exclude_default, exclude_unset - don't work. It is not correct.
  2. If null comes from the client to the Int field - I get an error. The field must be nullable.
  3. Pass empty strings as null in Output.

I corrected them - #75

problem with examples

Hi,

I was playing around with this library and tried running the departments.py script and got an error:

$ python departments.py
[GraphQLError('Unknown type "Manager".',)]
null

I removed the Manager part of the query:

$ git diff
diff --git a/examples/departments.py b/examples/departments.py
index c77e131..2637cb9 100644
--- a/examples/departments.py
+++ b/examples/departments.py
@@ -115,14 +115,6 @@ if __name__ == "__main__":
               hiredOn
               salary { rating }
             }
-            ...on Manager {
-              name
-              salary {
-                rating
-                amount
-              }
-              teamSize
-            }
           }
         }
       }

and got:

$ python departments.py
None
{
  "listDepartments": [
    {
      "id": "48809bd6-0ff7-4942-94b6-b2c6a77e3621",
      "name": "Administration",
      "employees": [
        {
          "id": "467ae7ca-6398-41d4-b780-ab5f39ed24d3",
          "name": "Jason",
          "hiredOn": null,
          "salary": {
            "rating": "GS-11"
          }
        },
        {
          "id": "4eace3f7-190b-4b49-a9f3-faab3fba8ce7",
          "name": "Carmen",
          "hiredOn": "2019-01-01T15:26:00",
          "salary": {
            "rating": "GS-9"
          }
        },
        {
          "id": "08a791cf-0b36-4f0b-9c87-a1a1f17a5113",
          "name": "Derek",
          "hiredOn": null,
          "salary": null
        }
      ]
    }
  ]
}

Is the union functionality not working?

how to pass in a json data struct?

I have the following challenge:

I am getting data from a database in json format / as dict.
This works great when I am directly grabbing the data in the query and "upgrading" it to the defined and in meta class registered pedantic data model.

Example:

class GrapheneModel(PydanticObjectType):
    class Meta:
        model = PydanticModel

...
class Queries(ObjectType):
    examples = List(
        GrapheneModel
    )

    @staticmethod
    def resolve_examples(root, info, **kwargs):
        result = fetch_from_db() # return a list of dicts
        return [PydanticModel.model_validate(q) for q in result]

But I also have other cases where I come through an interface.
I can overlay the is_type_of method to get to the right GrapheneModel, but the data that comes in is then a dict, which does not work... Do you guys have an idea how the data can be upgraded within the Graphene Model?
I cannot do it in the interface as I do not know the type there...
Thanks for any advise.

Published artifact for 0.0.6 specifies Pydantic <= 1.3

I'm a little confused how this happened, but 0.0.6 on PyPI specifies Pydantic <= 1.3, even though master specifies <= 1.4 and there don't appear to be any intervening commits.

Also, FYI, there is no tag that GitHub can see for 0.0.6.

Support Constrained types

Currently attempting to convert a constrained type will result in:

graphene_pydantic.converters.ConversionError: Don't know how to convert the Pydantic field ModelField(name='id', type=ConstrainedIntValue, required=True) (<class 'pydantic.types.ConstrainedIntValue'>)

Incompatible versions in the resolved dependencies

Tried to install this package to a newly created FastAPI app. Got an "Incompatible versions in the resolved dependencies" error. Pipenv logs below:

Installing graphene-pydantic...
Adding graphene-pydantic to Pipfile's [packages]...
Installation Succeeded
Pipfile.lock (c505a8) out of date, updating to (9f8497)...
Locking [dev-packages] dependencies...
Locking [packages] dependencies...
 Locking...Building requirements...
Resolving dependencies...
Locking Failed!
[ResolutionFailure]:   File "c:/users/akuani/appdata/local/programs/python/python38/lib/site-packages/pipenv/resolver.py", line 741, in _main
[ResolutionFailure]:       resolve_packages(pre, clear, verbose, system, write, requirements_dir, packages, dev)
[ResolutionFailure]:   File "c:/users/akuani/appdata/local/programs/python/python38/lib/site-packages/pipenv/resolver.py", line 702, in resolve_packages
[ResolutionFailure]:       results, resolver = resolve(
[ResolutionFailure]:   File "c:/users/akuani/appdata/local/programs/python/python38/lib/site-packages/pipenv/resolver.py", line 684, in resolve
[ResolutionFailure]:       return resolve_deps(
[ResolutionFailure]:   File "c:\users\akuani\appdata\local\programs\python\python38\lib\site-packages\pipenv\utils.py", line 1395, in resolve_deps
[ResolutionFailure]:       results, hashes, markers_lookup, resolver, skipped = actually_resolve_deps(
[ResolutionFailure]:   File "c:\users\akuani\appdata\local\programs\python\python38\lib\site-packages\pipenv\utils.py", line 1108, in actually_resolve_deps
[ResolutionFailure]:       resolver.resolve()
[ResolutionFailure]:   File "c:\users\akuani\appdata\local\programs\python\python38\lib\site-packages\pipenv\utils.py", line 833, in resolve
[ResolutionFailure]:       raise ResolutionFailure(message=str(e))
[pipenv.exceptions.ResolutionFailure]: Warning: Your dependencies could not be resolved. You likely have a mismatch in your sub-dependencies.
  First try clearing your dependency cache with $ pipenv lock --clear, then try the original command again.
 Alternatively, you can use $ pipenv install --skip-lock to bypass this mechanism, then run $ pipenv graph to inspect the situation.
  Hint: try $ pipenv lock --pre if it is a pre-release dependency.
ERROR: Could not find a version that matches graphene>=3.0b5 (from -r C:\Users\akuani\AppData\Local\Temp\pipenvnka3svhprequirements\pipenv-frhatc4t-constraints.txt (line 10))
Tried: 0.1.0, 0.1.1, 0.1.2, 0.1.3, 0.1.4, 0.1.5, 0.1.5.1, 0.1.5.2, 0.1.5.3, 0.1.6.0, 0.1.6.1, 0.3.0, 0.4.0, 0.4.0.1, 0.4.1, 0.4.1.1, 0.4.2, 0.4.3, 0.5.0, 0.6.0, 0.6.1, 0.7.0, 0.7.1, 0.7.2, 0.7.3, 0.8.0, 0.8.1, 0.9, 0.9.1, 0.10.0, 0.10.1, 0.10.2, 1.0, 1.0.1, 1.0.2,
1.1, 1.1.1, 1.1.2, 1.1.3, 1.2, 1.3, 1.4, 1.4.1, 1.4.2, 2.0, 2.0, 2.0.1, 2.0.1, 2.1, 2.1, 2.1.1, 2.1.1, 2.1.2, 2.1.2, 2.1.3, 2.1.3, 2.1.5, 2.1.5, 2.1.6, 2.1.6, 2.1.7, 2.1.7, 2.1.8, 2.1.8
Skipped pre-versions: 0.1.6a1, 0.9b1, 1.0.dev20160815004752, 1.0.dev20160816073455, 1.0.dev20160822080320, 1.0.dev20160823061102, 1.0.dev20160909040318, 1.0.dev20160909055438, 1.0.dev20160911044410, 1.0.dev20160911051803, 1.0.dev20160917190505, 1.0.dev2016091804123
9, 1.0.dev20160920015515, 1.0.dev20160920070441, 1.0.dev20160921153356, 1.0.dev20160922020647, 2.0.dev20170724064308, 2.0.dev20170725043308, 2.0.dev20170725061556, 2.0.dev20170727024417, 2.0.dev20170727061432, 2.0.dev20170801053013, 2.0.dev20170801053013, 2.0.dev20
170802065539, 2.0.dev20170802065539, 3.0.dev20190817210753, 3.0.dev20190817210753, 3.0a1, 3.0a1, 3.0b0, 3.0b0, 3.0b1, 3.0b1, 3.0b2, 3.0b2, 3.0b3, 3.0b3, 3.0b4, 3.0b4, 3.0b5, 3.0b5, 3.0b6, 3.0b6, 3.0b7, 3.0b7
There are incompatible versions in the resolved dependencies:
  graphene (from -r C:\Users\akuani\AppData\Local\Temp\pipenvnka3svhprequirements\pipenv-frhatc4t-constraints.txt (line 10))
  graphene>=3.0b5 (from graphene-pydantic==0.2.0->-r C:\Users\akuani\AppData\Local\Temp\pipenvnka3svhprequirements\pipenv-frhatc4t-constraints.txt (line 14))

graphql.error.located_error.GraphQLLocatedError: name 'get_hackers' is not defined

I'm sorry for the title being vague but I didn't know how to present to you the problem.

Basically I was trying to hack up an API using FastAPI, Pydantic and GraphQL. I found this repo from an Issue there.
Following the readme, I couldn't query the data using GraphiQl(I hacked starlette and currently running on graphql playground).
for this query

query {
  hackers {
    id
  }
}

I'm getting an error like this

{
  "error": {
    "data": {
      "hackers": null
    },
    "errors": [
      {
        "message": "name 'get_hackers' is not defined",
        "locations": [
          {
            "line": 2,
            "column": 3
          }
        ],
        "path": [
          "hackers"
        ]
      }
    ]
  }
}

My Pydantic Basemodel and ObjectType as

class HackerModel(BaseModel):
    id: int
    name: str
    college: str
    email: str
    dob: date

class Hacker(PydanticObjectType):
    class Meta:
        model = HackerModel
        only_fields=("name","college","id","email","dob")
    class Config:
        arbitrary_types_allowed = True

And my Query Class Looks like this

class Query(graphene.ObjectType):
    hackers = graphene.List(Hacker)
    def resolve_hackers(self, info):
        return get_hackers()

I only followed your Readme Example . Any idea on How to resolve this?

Support for `Literal` typed fields

I'm using some Literal['some-str'] field types in my pydantic models as a part of a discriminated union. I'd love to be able to use this with graphene-pydantic!

Unfortunately currently using Literal field types seems to produce exceptions like the following:

server_1  |   File "./main.py", line 11, in <module>
server_1  |     import graphql_api
server_1  |   File "./graphql_api.py", line 48, in <module>
server_1  |     class BlockPlateSchema(PydanticObjectType):
server_1  |   File "/opt/conda/lib/python3.7/site-packages/graphene/utils/subclass_with_meta.py", line 52, in __init_subclass__
server_1  |     super_class.__init_subclass_with_meta__(**options)
server_1  |   File "/opt/conda/lib/python3.7/site-packages/graphene_pydantic/objecttype.py", line 95, in __init_subclass_with_meta__
server_1  |     exclude_fields=exclude_fields,
server_1  |   File "/opt/conda/lib/python3.7/site-packages/graphene_pydantic/objecttype.py", line 47, in construct_fields
server_1  |     field, registry, parent_type=obj_type, model=model
server_1  |   File "/opt/conda/lib/python3.7/site-packages/graphene_pydantic/converters.py", line 130, in convert_pydantic_field
server_1  |     declared_type, field, registry, parent_type=parent_type, model=model
server_1  |   File "/opt/conda/lib/python3.7/site-packages/graphene_pydantic/converters.py", line 157, in convert_pydantic_type
server_1  |     type_, field, registry, parent_type=parent_type, model=model
server_1  |   File "/opt/conda/lib/python3.7/site-packages/graphene_pydantic/converters.py", line 211, in find_graphene_type
server_1  |     type_, field, registry, parent_type=parent_type, model=model
server_1  |   File "/opt/conda/lib/python3.7/site-packages/graphene_pydantic/converters.py", line 273, in convert_generic_python_type
server_1  |     ) or issubclass(origin, collections.abc.Sequence):
server_1  |   File "/opt/conda/lib/python3.7/abc.py", line 143, in __subclasscheck__
server_1  |     return _abc_subclasscheck(cls, subclass)
server_1  | TypeError: issubclass() arg 1 must be a class

From what I could tell, there is currently no support for Literal fields. Is that correct?

Support type hinting for InputObjectTypes

Take the following example, adapted from the README:

import uuid

import graphene
import pydantic
from graphene_pydantic import PydanticInputObjectType, PydanticObjectType


class PersonModel(pydantic.BaseModel):
    id: uuid.UUID
    first_name: str
    last_name: str


class PersonInput(PydanticInputObjectType):
    class Meta:
        model = PersonModel
        exclude_fields = ("id",)


class CreatePerson(graphene.Mutation):
    class Arguments:
        person = PersonInput()

    @staticmethod
    def mutate(parent, info, person: PersonInput):  # I'd like to type hint this argument
        personModel = PersonModel(
            id=uuid.uuid4(),
            first_name=person.first_name,
            last_name=person.last_name
        )
        return person

It would be nice to be able to type hint the model properties that are defined on the InputObjectType through introspection. Currently, the mutate method generates type warnings:

Screen Shot 2020-12-02 at 10 09 38 AM

Pydantic -> Graphene type conversion breaks when using freezegun

this schema

class TestSchema(BaseModel):
    date_field: datetime.date

breaks in tests that use freezegun to freeze time:

E   graphene_pydantic.converters.ConversionError: Don't know how to convert the Pydantic field ModelField(name='date_field', type=date, required=True) (<class 'datetime.date'>)

I believe the issue is because freezegun overwrites the type of datetime.date and datetime.datetime, so these lines in the graphene_pydantic converter (find_graphene_type()) don't evaluate to true:

elif type_ == datetime.date:
    return Date

pydantic code: https://github.com/graphql-python/graphene-pydantic/blob/master/graphene_pydantic/converters.py#L186
freezegun code: https://github.com/spulec/freezegun/blob/master/freezegun/api.py#L637
related freezegun issue: spulec/freezegun#170

I'm not sure if this is a weird fix or not, but changing the if condition to:

elif type_.__name__ == "date"

or

elif issubclass(type_, datetime.date):

fixes this use case.

A better suggestion (though I don't know the best way to implement) is to allow a custom type mappings so we don't have to rely on this switch statement.

Support for Mutations / InputObjectTypes

Hi there!

Are there any plans to extend the graphene-pydantic magic to Graphene Mutations, in particular InputObjectTypes? It would be excellent to be able to validate Mutation arguments against Pydantic Models.

Pydantic 1.3+ support

Hi there, thanks for creating the graphene-pydantic project :-) graphene-pydantic is currently locked into Pydantic version <=1.1,>=0.26

Do you have plans to keep up with the pydantic releases, or will you only update from time to time?

Not working list[str] field

I found graphene-pydantic fails converting list[str] field.

import graphene
import pydantic

import graphene_pydantic


class Model(pydantic.BaseModel):
    field: list[str] = []


class GrapheneModel(graphene_pydantic.PydanticObjectType):
    class Meta:
        model = Model


class Query(graphene.ObjectType):
    model = graphene.Field(GrapheneModel)
    hello = graphene.String()

    @staticmethod
    def resolve_model(parent, info):
        return Model()


schema = graphene.Schema(query=Query)
print(schema)
print(schema.execute('{model {field}}'))

saved as tmp.conao3/04_list.sample.py and run like this

$ poetry run python tmp.conao3/04_list.sample.py

then, you see error.

Traceback (most recent call last):
  File "/home/conao/dev/forks/graphene-pydantic/tmp.conao3/04_list.sample.py", line 11, in <module>
    class GrapheneModel(graphene_pydantic.PydanticObjectType):
  File "/home/conao/dev/forks/graphene-pydantic/.venv/lib/python3.10/site-packages/graphene/types/objecttype.py", line 45, in __new__
    dataclass = make_dataclass(name_, fields, bases=())
  File "/usr/lib/python3.10/dataclasses.py", line 1401, in make_dataclass
    return dataclass(cls, init=init, repr=repr, eq=eq, order=order,
  File "/usr/lib/python3.10/dataclasses.py", line 1185, in dataclass
    return wrap(cls)
  File "/usr/lib/python3.10/dataclasses.py", line 1176, in wrap
    return _process_class(cls, init, repr, eq, order, unsafe_hash,
  File "/usr/lib/python3.10/dataclasses.py", line 956, in _process_class
    cls_fields.append(_get_field(cls, name, type, kw_only))
  File "/usr/lib/python3.10/dataclasses.py", line 813, in _get_field
    raise ValueError(f'mutable default {type(f.default)} for field '
ValueError: mutable default <class 'list'> for field field is not allowed: use default_factory

I use now main(2fd67a8) and I use Python3.10

Support pydantic >1.3

Currently pydantic is pinned to <=1.3.

Is this intentional or is it just because the version pinning is old?

TypeError: __init__() missing 1 required positional argument: 'type'

To reproduce create example models:
python 3.7
graphene==2.1.8
pydantic==1.7.1
graphene-pydantic==0.2.0

`class NodeModel(BaseModel):
    id: int
    name: str
    labels: 'LabelsModel'
    
class LabelsModel(BaseModel):
    node: NodeModel
    labels: typing.List[str]
    
class Node(PydanticObjectType):
    class Meta:
        model = NodeModel
        
class Labels(PydanticObjectType):
    class Meta:
        model = LabelsModel`

then when I try to run my app I receive:

`  File "\site-packages\graphene\utils\subclass_with_meta.py", line 52, in __init_subclass__
    super_class.__init_subclass_with_meta__(**options)
  File "b\site-packages\graphene_pydantic\objecttype.py", line 95, in __init_subclass_with_meta__
    exclude_fields=exclude_fields,
  File "\site-packages\graphene_pydantic\objecttype.py", line 47, in construct_fields
    field, registry, parent_type=obj_type, model=model
  File "\site-packages\graphene_pydantic\converters.py", line 141, in convert_pydantic_field
    return Field(resolver=get_attr_resolver(field.name), **field_kwargs)
TypeError: __init__() missing 1 required positional argument: 'type'
`

I believe the error is because constructor is expecting type but it receives type
When I have changed locally line 129 in converters is working fine.
Here is my PR: #63

Restore Graphene 2 support?

I added a comment to an already-merged PR, so creating an issue to keep track of this question.

b043031#r127675726

Is dropping support for Graphene 2 intentional? It looked like there was a decision to specifically support Graphene 2 in 2022: #77

It looks like version 0.4.0 on PyPi supports Graphene 2, but version 0.4.1 does not, and I think it may be due to this change.

Sorry if I'm missing a deliberate choice to drop Graphene 2 support. Thanks!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.