Skip to content

Commit

Permalink
fix: external references to parent folder (#1999)
Browse files Browse the repository at this point in the history
* Add support for external referenced discriminators

* Fix discriminator reference in parent folder

* Extend test case

* post-fork-sync fixes

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* fix formatting

* add test case for whole folder

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* ruff format

---------

Co-authored-by: Koudai Aono <koxudaxi@gmail.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
  • Loading branch information
3 people authored Jun 11, 2024
1 parent b1c0f22 commit 5727116
Show file tree
Hide file tree
Showing 17 changed files with 180 additions and 14 deletions.
18 changes: 14 additions & 4 deletions datamodel_code_generator/parser/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -700,6 +700,7 @@ def __change_from_import(
from_, import_ = full_path = relative(
model.module_name, data_type.full_name
)
import_ = import_.replace('-', '_')

alias = scoped_model_resolver.add(full_path, import_).name

Expand Down Expand Up @@ -778,10 +779,18 @@ def __apply_discriminator_type(
discriminator_model.path.split('#/')[-1]
!= path.split('#/')[-1]
):
if '#' in path or discriminator_model.path[
:-1
] != path.lstrip('./'):
continue
if (
path.startswith('#/')
or discriminator_model.path[:-1]
!= path.split('/')[-1]
):
t_path = path[str(path).find('/') + 1 :]
t_disc = discriminator_model.path[
: str(discriminator_model.path).find('#')
].lstrip('../')
t_disc_2 = '/'.join(t_disc.split('/')[1:])
if t_path != t_disc and t_path != t_disc_2:
continue
type_names.append(name)
else:
type_names = [discriminator_model.path.split('/')[-1]]
Expand Down Expand Up @@ -1252,6 +1261,7 @@ class Processed(NamedTuple):
init = True
else:
module = (*module[:-1], f'{module[-1]}.py')
module = tuple(part.replace('-', '_') for part in module)
else:
module = ('__init__.py',)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from __future__ import annotations

from typing import Union
from typing import Optional, Union

from pydantic import BaseModel, Field
from typing_extensions import Literal
Expand All @@ -16,11 +16,22 @@ class Type1(BaseModel):

class Type2(BaseModel):
type_: Literal['b'] = Field('b', title='Type ')
ref_type: Optional[Type1] = Field(None, description='A referenced type.')


class Type4(BaseModel):
type_: Literal['d'] = Field('d', title='Type ')


class Type5(BaseModel):
type_: Literal['e'] = Field('e', title='Type ')


class Type3(BaseModel):
type_: Literal['c'] = Field('c', title='Type ')


class Response(BaseModel):
inner: Union[Type1, Type2, Type3] = Field(..., discriminator='type_', title='Inner')
inner: Union[Type1, Type2, Type3, Type4, Type5] = Field(
..., discriminator='type_', title='Inner'
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# generated by datamodel-codegen:
# filename: discriminator_with_external_reference
# timestamp: 2019-07-26T00:00:00+00:00
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# generated by datamodel-codegen:
# filename: discriminator_with_external_reference
# timestamp: 2019-07-26T00:00:00+00:00
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# generated by datamodel-codegen:
# filename: discriminator_with_external_reference
# timestamp: 2019-07-26T00:00:00+00:00
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# generated by datamodel-codegen:
# filename: inner_folder/artificial_folder/type-1.json
# timestamp: 2019-07-26T00:00:00+00:00

from __future__ import annotations

from pydantic import BaseModel, Field
from typing_extensions import Literal


class Type1(BaseModel):
type_: Literal['a'] = Field(..., const=True, title='Type ')
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# generated by datamodel-codegen:
# filename: inner_folder/schema.json
# timestamp: 2019-07-26T00:00:00+00:00

from __future__ import annotations

from typing import Union

from pydantic import BaseModel, Field
from typing_extensions import Literal

from .. import type_4
from ..subfolder import type_5
from . import type_2
from .artificial_folder import type_1


class Type3(BaseModel):
type_: Literal['c'] = Field(..., const=True, title='Type ')


class Response(BaseModel):
inner: Union[type_1.Type1, type_2.Type2, Type3, type_4.Type4, type_5.Type5] = Field(
..., discriminator='type_', title='Inner'
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# generated by datamodel-codegen:
# filename: inner_folder/type-2.json
# timestamp: 2019-07-26T00:00:00+00:00

from __future__ import annotations

from typing import Optional

from pydantic import BaseModel, Field

from .artificial_folder import type_1


class Type2(BaseModel):
type_: Literal['b'] = Field(..., const=True, title='Type ')
ref_type: Optional[type_1.Type1] = Field(None, description='A referenced type.')
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# generated by datamodel-codegen:
# filename: discriminator_with_external_reference
# timestamp: 2019-07-26T00:00:00+00:00
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# generated by datamodel-codegen:
# filename: subfolder/type-5.json
# timestamp: 2019-07-26T00:00:00+00:00

from __future__ import annotations

from pydantic import BaseModel, Field


class Type5(BaseModel):
type_: Literal['e'] = Field(..., const=True, title='Type ')
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# generated by datamodel-codegen:
# filename: type-4.json
# timestamp: 2019-07-26T00:00:00+00:00

from __future__ import annotations

from pydantic import BaseModel, Field


class Type4(BaseModel):
type_: Literal['d'] = Field(..., const=True, title='Type ')
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,29 @@
"inner": {
"discriminator": {
"mapping": {
"a": "./artificial_folder/type1.json",
"b": "./type2.json",
"c": "#/$def/Type3"
"a": "./artificial_folder/type-1.json",
"b": "./type-2.json",
"c": "#/$def/Type3",
"d": "../type-4.json",
"e": "../subfolder/type-5.json"
},
"propertyName": "type_"
},
"oneOf": [
{
"$ref": "./artificial_folder/type1.json"
"$ref": "./artificial_folder/type-1.json"
},
{
"$ref": "./type2.json"
"$ref": "./type-2.json"
},
{
"$ref": "#/$def/Type3"
},
{
"$ref": "../type-4.json"
},
{
"$ref": "../subfolder/type-5.json"
}
],
"title": "Inner"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"properties": {
"type_": {
"const": "b",
"default": "b",
"title": "Type "
},
"ref_type": {
"$ref": "./artificial_folder/type-1.json",
"description": "A referenced type."
}
},
"title": "Type2",
"type": "object"
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
{
"properties": {
"type_": {
"const": "b",
"default": "b",
"const": "e",
"default": "e",
"title": "Type "
}
},
"title": "Type2",
"title": "Type5",
"type": "object"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"properties": {
"type_": {
"const": "d",
"default": "d",
"title": "Type "
}
},
"title": "Type4",
"type": "object"
}
24 changes: 24 additions & 0 deletions tests/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -6133,6 +6133,7 @@ def test_main_jsonschema_external_discriminator():
str(
JSON_SCHEMA_DATA_PATH
/ 'discriminator_with_external_reference'
/ 'inner_folder'
/ 'schema.json'
),
'--output',
Expand All @@ -6152,6 +6153,29 @@ def test_main_jsonschema_external_discriminator():
)


@freeze_time('2019-07-26')
def test_main_jsonschema_external_discriminator_folder():
with TemporaryDirectory() as output_dir:
output_path: Path = Path(output_dir)
return_code: Exit = main(
[
'--input',
str(JSON_SCHEMA_DATA_PATH / 'discriminator_with_external_reference'),
'--output',
str(output_path),
]
)
assert return_code == Exit.OK
main_modular_dir = (
EXPECTED_MAIN_PATH / 'discriminator_with_external_references_folder'
)
for path in main_modular_dir.rglob('*.py'):
result = output_path.joinpath(
path.relative_to(main_modular_dir)
).read_text()
assert result == path.read_text()


@freeze_time('2019-07-26')
@pytest.mark.skipif(
black.__version__.split('.')[0] == '19',
Expand Down

0 comments on commit 5727116

Please sign in to comment.