Skip to content

Commit

Permalink
model - using regex_engine python-re instead of the default rust-regex
Browse files Browse the repository at this point in the history
rust re is not posix compatible
rust-lang/regex#592
  • Loading branch information
commonism committed Aug 28, 2024
1 parent 7870ce0 commit ff73e2d
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 3 deletions.
13 changes: 10 additions & 3 deletions aiopenapi3/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ def class_from_schema(s, _type):
import pydantic_core


class ConfiguredRootModel(RootModel):
model_config = dict(regex_engine="python-re")


@dataclasses.dataclass
class _ClassInfo:
@dataclasses.dataclass
Expand Down Expand Up @@ -226,18 +230,20 @@ def model(self) -> Union[Type[BaseModel], Type[None]]:
return m

@classmethod
def collapse(cls, type_name, items) -> Type[BaseModel]:
def collapse(cls, type_name, items: List["_ClassInfo"]) -> Type[BaseModel]:
r: List[Union[Type[BaseModel], Type[None]]]

r = [i.model() for i in items]

if len(r) > 1:
ru: object = Union[tuple(r)]
m: Type[RootModel] = pydantic.create_model(type_name, __base__=(RootModel[ru],), __module__=me.__name__)
m: Type[RootModel] = pydantic.create_model(
type_name, __base__=(ConfiguredRootModel[ru],), __module__=me.__name__
)
elif len(r) == 1:
m: Type[BaseModel] = cast(Type[BaseModel], r[0])
if not (inspect.isclass(m) and issubclass(m, pydantic.BaseModel)):
m = pydantic.create_model(type_name, __base__=(RootModel[m],), __module__=me.__name__)
m = pydantic.create_model(type_name, __base__=(ConfiguredRootModel[m],), __module__=me.__name__)
else: # == 0
assert len(r), r
return m
Expand Down Expand Up @@ -476,6 +482,7 @@ def createConfigDict(schema: "SchemaType"):
return ConfigDict(
extra=extra_,
arbitrary_types_allowed=arbitrary_types_allowed_,
regex_engine="python-re",
# defer_build=True,
# validate_assignment=True
)
Expand Down
5 changes: 5 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,11 @@ def with_schema_string_pattern(openapi_version):
yield _get_parsed_yaml("schema-string-pattern.yaml", openapi_version)


@pytest.fixture
def with_schema_regex_engine(openapi_version):
yield _get_parsed_yaml("schema-regex-engine.yaml", openapi_version)


@pytest.fixture
def with_schema_type_list():
yield _get_parsed_yaml("schema-type-list.yaml")
Expand Down
20 changes: 20 additions & 0 deletions tests/fixtures/schema-regex-engine.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
openapi: "3.1.0"
info:
version: 1.0.0
title: |
string pattern test with pattern invalid with pydantic-core/rust regex
https://github.com/pydantic/pydantic-core/issues/1374
components:
schemas:
Root:
type: string
pattern: ^Passphrase:[ ^[ !#-~]+$

Object:
type: object
additionalProperties: False
properties:
v:
type: string
pattern: ^Passphrase:[ ^[ !#-~]+$
26 changes: 26 additions & 0 deletions tests/schema_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,32 @@ def test_schema_string_pattern(with_schema_string_pattern):
GUID.model_validate(str(uuid.uuid4()).replace("-", "@"))


def test_schema_regex_engine(with_schema_regex_engine):
api = OpenAPI("/", with_schema_regex_engine)
Root = api.components.schemas["Root"].get_type()

Root.model_validate("Passphrase: test!")

with pytest.raises(ValidationError):
Root.model_validate("P_ssphrase:")

Object = api.components.schemas["Object"].get_type()
Object.model_validate({"v": "Passphrase: test!"})

with pytest.raises(ValidationError):
Object.model_validate({"v": "P_ssphrase:"})

import pydantic_core._pydantic_core

with pytest.raises(pydantic_core._pydantic_core.SchemaError, match="error: unclosed character class$"):
pattern = typing.get_args(Root.model_fields["root"].annotation)[1].metadata[0].pattern

from typing import Annotated

C = Annotated[str, pydantic.Field(pattern=pattern)]
pydantic.create_model("C", __base__=(pydantic.RootModel[C],))


def test_schema_type_list(with_schema_type_list):
api = OpenAPI("/", with_schema_type_list)
_Any = api.components.schemas["Any"]
Expand Down

0 comments on commit ff73e2d

Please sign in to comment.