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

Support for Dict types #55

Closed
dylanmcreynolds opened this issue Feb 23, 2021 · 4 comments
Closed

Support for Dict types #55

dylanmcreynolds opened this issue Feb 23, 2021 · 4 comments

Comments

@dylanmcreynolds
Copy link

dylanmcreynolds commented Feb 23, 2021

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.  
@necaris
Copy link
Collaborator

necaris commented Feb 23, 2021

Unfortunately, while Dicts are just fine in pydantic, they're not in GraphQL (and therefore graphene). As far as I know the GraphQL specification doesn't allow arbitrary key/value mappings such as dictionaries. GraphQL strongly prefers that you define exactly what keys and values will be in your data -- see https://graphql.org/learn/schema/#object-types-and-fields for more details, or https://stackoverflow.com/questions/46402182/graphene-graphql-dictionary-as-a-type for a Python-specific take on it.

Since there isn't a way to express them as a GraphQL output, I'm not sure how we'd support them?

@dylanmcreynolds
Copy link
Author

@necaris thanks! I am (obviously) a bit of a GraphQL newbie. So many of my existing pydantic models involve dicts today, that I'll have to go back an assess. In case anyone in the future sees this, using exclude_fields seems to get me running, something like:

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


class Person(PydanticObjectType):
    class Meta:
        model = PersonModel
        exclude_fields = ('foo',)

@dylanmcreynolds
Copy link
Author

I closed this, but I will add that it would super helpful if the ConversionError output the class and field that are problematic.

@polgfred
Copy link

polgfred commented Nov 8, 2022

@dylanmcreynolds I know you closed this awhile ago, but in case you're still trying to figure it out. ;)

Basically, you need to exclude the dict field (as you've done), but then explicitly define that field as a graphene.types.generic.GenericScalar:

from graphene.types.generic import GenericScalar

class Person(PydanticObjectType):
    class Meta:
        model = PersonModel
        exclude_fields = ('foo',)

    foo = GenericScalar()

It's a little more loosy than a pure dict, since from GQL's perspective it can be anything (null, boolean, int, string, list, object), but it does have the benefit of returning your dictionary in the JSON result. It's just treated in GQL as a scalar, meaning you can't use {} to resolve individual fields out of it (because your schema doesn't know what possible fields there could be).

Hope this helps!

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

No branches or pull requests

3 participants