koxudaxi / datamodel-code-generator

Pydantic model and dataclasses.dataclass generator for easy conversion of JSON, OpenAPI, JSON Schema, and YAML data sources.
https://koxudaxi.github.io/datamodel-code-generator/
MIT License
2.79k stars 307 forks source link

Regex pattern in JSON schema results in PyLance error #1973

Open janeadams-ozette opened 6 months ago

janeadams-ozette commented 6 months ago

I believe the pattern matching described in #470 may no longer be compatible with PyLance. For example, creating a json schema like:

properties = {
    'session': {
        'type': 'string',
        'pattern': '^((staging)|(production)):{0-9}+',

results in a PyDantic model:

class State(BaseModel):
    session: Optional[constr(regex=r'^((staging)|(production)):{0-9}+')]

but this triggers

Call expression not allowed in type expression Pylance[reportInvalidTypeForm](https://github.com/microsoft/pyright/blob/main/docs/configuration.md#reportInvalidTypeForm).

See this issue via PyLance for more detail.

robot-ranger commented 1 month ago

this happens with integer type when min/max is applied as well.

sample schema:

{
    "$schema": "http://json-schema.org/draft-07/schema#",
    "type": "object",
    "properties": {
        "adapter_port": {
            "type": "integer",
            "description": "The adapter's SHDR port",
            "default": 7878,
            "minimum": 1,
            "maximum": 65535
        },
        "agent_port": {
            "type": "integer",
            "description": "MTConnect Agent port",
            "default": 5000,
            "minimum": 1,
            "maximum": 65535
        }
    },
    "required": [
        "adapter_port",
        "agent_port"
    ]
}

output:

# generated by datamodel-codegen:
#   filename:  schema.json
#   timestamp: 2024-10-14T22:59:46+00:00

from __future__ import annotations

from pydantic import BaseModel, Field, conint

class Model(BaseModel):
    adapter_port: conint(ge=1, le=65535) = Field(
        ..., description="The adapter's SHDR port"
    )
    agent_port: conint(ge=1, le=65535) = Field(..., description='MTConnect Agent port')

and pylance complains: image

Edit to add the docs vscode shows me:

!!! warning "Discouraged"

This function is discouraged in favor of using Annotated with [Field][pydantic.fields.Field] instead. This function will be deprecated in Pydantic 3.0. The reason is that conint returns a type, which doesn't play well with static analysis tools. === ":x: Don't do this"

py
        from pydantic import BaseModel, conint

        class Foo(BaseModel):
            bar: conint(strict=True, gt=0)

=== ":white_check_mark: Do this"
py
        from typing_extensions import Annotated

        from pydantic import BaseModel, Field

        class Foo(BaseModel):
            bar: Annotated[int, Field(strict=True, gt=0)]

A wrapper around int that allows for additional constraints.

Args strict Whether to validate the integer in strict mode. Defaults to None.

gt The value must be greater than this.

ge The value must be greater than or equal to this.

lt The value must be less than this.

le The value must be less than or equal to this.

multiple_of The value must be a multiple of this.

Returns out The wrapped integer type.

py
from pydantic import BaseModel, ValidationError, conint

class ConstrainedExample(BaseModel):
    constrained_int: conint(gt=1)

m = ConstrainedExample(constrained_int=2)
print(repr(m))
#> ConstrainedExample(constrained_int=2)

try:
    ConstrainedExample(constrained_int=0)
except ValidationError as e:
    print(e.errors())
    '''
    [
        {
            'type': 'greater_than',
            'loc': ('constrained_int',),
            'msg': 'Input should be greater than 1',
            'input': 0,
            'ctx': {'gt': 1},
            'url': 'https://errors.pydantic.dev/2/v/greater_than',
        }
    ]
    '''