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

Failed to generate schema with typing.Any #237

Closed
Gr1N opened this Issue Jul 31, 2018 · 6 comments

Comments

3 participants
@Gr1N
Collaborator

Gr1N commented Jul 31, 2018

Hi,

Found issue with schema generation. Please look at example below:

Python 3.6.5 (default, Mar 30 2018, 06:41:53)
Type 'copyright', 'credits' or 'license' for more information
IPython 6.4.0 -- An enhanced Interactive Python. Type '?' for help.

In [1]: from pydantic import BaseModel

In [2]: from typing import Dict, Any

In [3]: class Model(BaseModel):
   ...:     foo: Dict[str, Any]
   ...:

In [4]: Model.schema()
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-4-c6adfc7bfbde> in <module>()
----> 1 Model.schema()

~/Projects/Python/pydantic/pydantic/main.py in schema(cls, by_alias)
    297             s['description'] = clean_docstring(cls.__doc__)
    298
--> 299         s.update(cls.type_schema(by_alias))
    300         cls._schema_cache[by_alias] = s
    301         return s

~/Projects/Python/pydantic/pydantic/main.py in type_schema(cls, by_alias)
    283             'properties': (
    284                 {f.alias: f.schema(by_alias) for f in cls.__fields__.values()}
--> 285                 if by_alias else
    286                 {k: f.schema(by_alias) for k, f in cls.__fields__.items()}
    287             )

~/Projects/Python/pydantic/pydantic/main.py in <dictcomp>(.0)
    282             'type': 'object',
    283             'properties': (
--> 284                 {f.alias: f.schema(by_alias) for f in cls.__fields__.values()}
    285                 if by_alias else
    286                 {k: f.schema(by_alias) for k, f in cls.__fields__.items()}

~/Projects/Python/pydantic/pydantic/fields.py in schema(self, by_alias)
    146         s.update(self._schema.extra)
    147
--> 148         ts = self.type_schema(by_alias)
    149         s.update(ts if isinstance(ts, dict) else {'type': ts})
    150         return s

~/Projects/Python/pydantic/pydantic/fields.py in type_schema(self, by_alias)
    164             return {
    165                 'type': 'mapping',
--> 166                 'item_type': self._singleton_schema(by_alias),
    167                 'key_type': self.key_field.type_schema(by_alias)
    168             }

~/Projects/Python/pydantic/pydantic/fields.py in _singleton_schema(self, by_alias)
    185                     'types': [sf.type_schema(by_alias) for sf in self.sub_fields]
    186                 }
--> 187         elif issubclass(self.type_, Enum):
    188             choice_names = self._schema.choice_names or {}
    189             return {

TypeError: issubclass() arg 1 must be a class

In [5]:
@samuelcolvin

This comment has been minimized.

Owner

samuelcolvin commented Jul 31, 2018

sorry about that, would you be able to submit a fix?

Otherwise I'll try to fix tomorrow.

Gr1N added a commit to Gr1N/pydantic that referenced this issue Jul 31, 2018

@Gr1N

This comment has been minimized.

Collaborator

Gr1N commented Jul 31, 2018

Review please #238

samuelcolvin added a commit that referenced this issue Jul 31, 2018

fix schema generation for fields defined using ``typing.Any`` #237 (#238
)

* fix schema generation for fields defined using ``typing.Any`` #237

* review fixes
@vbrinnel

This comment has been minimized.

vbrinnel commented Aug 21, 2018

Although d293773 fixed schema generation for a model like this one:

class TestCase(BaseModel):
    var: str
    arguments: Dict[str, Any]

the Exception is still thrown with:

class TestCase(BaseModel):
    var: ConstrainedStr('abc')
    arguments: Dict[str, Any]
In []: TestCase.schema()
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-18-656f846a985c> in <module>()
----> 1 TestCase.schema()

/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/pydantic/main.py in schema(cls, by_alias)
    297             s['description'] = clean_docstring(cls.__doc__)
    298 
--> 299         s.update(cls.type_schema(by_alias))
    300         cls._schema_cache[by_alias] = s
    301         return s

/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/pydantic/main.py in type_schema(cls, by_alias)
    283             'properties': (
    284                 {f.alias: f.schema(by_alias) for f in cls.__fields__.values()}
--> 285                 if by_alias else
    286                 {k: f.schema(by_alias) for k, f in cls.__fields__.items()}
    287             )

/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/pydantic/main.py in <dictcomp>(.0)
    282             'type': 'object',
    283             'properties': (
--> 284                 {f.alias: f.schema(by_alias) for f in cls.__fields__.values()}
    285                 if by_alias else
    286                 {k: f.schema(by_alias) for k, f in cls.__fields__.items()}

/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/pydantic/fields.py in schema(self, by_alias)
    146         s.update(self._schema.extra)
    147 
--> 148         ts = self.type_schema(by_alias)
    149         s.update(ts if isinstance(ts, dict) else {'type': ts})
    150         return s

/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/pydantic/fields.py in type_schema(self, by_alias)
    174         else:
    175             assert self.shape is Shape.SINGLETON, self.shape
--> 176             return self._singleton_schema(by_alias)
    177 
    178     def _singleton_schema(self, by_alias):

/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/pydantic/fields.py in _singleton_schema(self, by_alias)
    187         elif self.type_ is Any:
    188             return 'any'
--> 189         elif issubclass(self.type_, Enum):
    190             choice_names = self._schema.choice_names or {}
    191             return {

TypeError: issubclass() arg 1 must be a class

@samuelcolvin

This comment has been minimized.

Owner

samuelcolvin commented Aug 21, 2018

ConstrainedStr('abc') is not a valid type definition. What are you trying to achieve?

The following works fine.

class TestCase(BaseModel):
    var: constr(min_length=5)
    arguments: Dict[str, Any]

debug(TestCase.schema())
    TestCase.schema(): {
        'title': 'TestCase',
        'type': 'object',
        'properties': {
            'var': {
                'title': 'Var',
                'required': True,
                'type': 'ConstrainedStrValue',
            },
            'arguments': {
                'title': 'Arguments',
                'required': True,
                'type': 'mapping',
                'item_type': 'any',
                'key_type': 'str',
            },
        },
    } (dict)

min_length etc. should proably be added to the schema, but that's a different issue.

@vbrinnel

This comment has been minimized.

vbrinnel commented Aug 21, 2018

Thanks for your response.
I think I misunderstood what ConstrainedStr is, thanks for pointing that out.
Thought that var: ConstrainedStr('abc') was equivalent to var: constr(regex='^abc$')

I am trying to implement validation for a JSON struct that could either look like:

{
    'after': {
        'use': 'timeDelta',
        'arguments': {'days': -10}
    }
}

or:

{
    'after': {
        'use': 'lastRun',
        'jobName': 'myJob'
    }
}

using:

class TCDelta(BaseModel):
    use: constr(regex='^timeDelta$')
    arguments: Dict[str, Any]
    
class TCLastRun(BaseModel):
    use: constr(regex='^lastRun$')
    jobName: str

class TimeConstraint(BaseModel):
    before: Union[TCDelta, TCLastRun] = None
    after: Union[TCDelta, TCLastRun] = None
@samuelcolvin

This comment has been minimized.

Owner

samuelcolvin commented Aug 21, 2018

ok, that seems to be working fine and generating a schema.

I'm not sure what problem you're having. Could you create another issue with an explanation of the problem if you still have one.

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