Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,13 @@ Options:
generating models.
--include-request-argument Auto-inject a FastAPI Request parameter into
operations when not present.
--allow-remote-refs / --no-allow-remote-refs
Allow or block fetching remote $ref targets
over HTTP/HTTPS. The default follows
datamodel-code-generator compatibility
behavior.
--allow-private-network Allow trusted remote $ref targets on local
or private network addresses.
-d, --output-model-type [pydantic_v2.BaseModel|pydantic_v2.dataclass|dataclasses.dataclass|typing.TypedDict|msgspec.Struct]
[default: pydantic_v2.BaseModel]
-p, --python-version [3.10|3.11|3.12|3.13|3.14]
Expand Down
27 changes: 27 additions & 0 deletions docs/cli-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@ Options:
generating models.
--include-request-argument Auto-inject a FastAPI Request parameter into
operations when not present.
--allow-remote-refs / --no-allow-remote-refs
Allow or block fetching remote $ref targets
over HTTP/HTTPS. The default follows
datamodel-code-generator compatibility
behavior.
--allow-private-network Allow trusted remote $ref targets on local
or private network addresses.
-d, --output-model-type [pydantic_v2.BaseModel|pydantic_v2.dataclass|dataclasses.dataclass|typing.TypedDict|msgspec.Struct]
[default: pydantic_v2.BaseModel]
-p, --python-version [3.10|3.11|3.12|3.13|3.14]
Expand Down Expand Up @@ -81,6 +88,26 @@ Render generated files with a custom template directory.

Input schema: `openapi/custom_template_security/custom_security.yaml`

### --allow-private-network

Allow trusted remote `$ref` targets on local or private network addresses.

`fastapi-codegen --input openapi/remote_ref/body_and_parameters.yaml --output app --allow-private-network`

Input schema: `openapi/remote_ref/body_and_parameters.yaml`

Related options: `--allow-remote-refs`

### --allow-remote-refs, --no-allow-remote-refs

Allow or block fetching remote `$ref` targets over HTTP/HTTPS.

`fastapi-codegen --input openapi/remote_ref/body_and_parameters.yaml --output app --allow-remote-refs`

Input schema: `openapi/remote_ref/body_and_parameters.yaml`

Related options: `--allow-private-network`

### --include-request-argument

Auto-inject a FastAPI Request argument in generated operation signatures when not present.
Expand Down
7 changes: 7 additions & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,13 @@ Options:
generating models.
--include-request-argument Auto-inject a FastAPI Request parameter into
operations when not present.
--allow-remote-refs / --no-allow-remote-refs
Allow or block fetching remote $ref targets
over HTTP/HTTPS. The default follows
datamodel-code-generator compatibility
behavior.
--allow-private-network Allow trusted remote $ref targets on local
or private network addresses.
-d, --output-model-type [pydantic_v2.BaseModel|pydantic_v2.dataclass|dataclasses.dataclass|typing.TypedDict|msgspec.Struct]
[default: pydantic_v2.BaseModel]
-p, --python-version [3.10|3.11|3.12|3.13|3.14]
Expand Down
34 changes: 34 additions & 0 deletions docs/llms-full.txt
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,13 @@ Options:
generating models.
--include-request-argument Auto-inject a FastAPI Request parameter into
operations when not present.
--allow-remote-refs / --no-allow-remote-refs
Allow or block fetching remote $ref targets
over HTTP/HTTPS. The default follows
datamodel-code-generator compatibility
behavior.
--allow-private-network Allow trusted remote $ref targets on local
or private network addresses.
-d, --output-model-type [pydantic_v2.BaseModel|pydantic_v2.dataclass|dataclasses.dataclass|typing.TypedDict|msgspec.Struct]
[default: pydantic_v2.BaseModel]
-p, --python-version [3.10|3.11|3.12|3.13|3.14]
Expand Down Expand Up @@ -352,6 +359,13 @@ Options:
generating models.
--include-request-argument Auto-inject a FastAPI Request parameter into
operations when not present.
--allow-remote-refs / --no-allow-remote-refs
Allow or block fetching remote $ref targets
over HTTP/HTTPS. The default follows
datamodel-code-generator compatibility
behavior.
--allow-private-network Allow trusted remote $ref targets on local
or private network addresses.
-d, --output-model-type [pydantic_v2.BaseModel|pydantic_v2.dataclass|dataclasses.dataclass|typing.TypedDict|msgspec.Struct]
[default: pydantic_v2.BaseModel]
-p, --python-version [3.10|3.11|3.12|3.13|3.14]
Expand Down Expand Up @@ -411,6 +425,26 @@ Render generated files with a custom template directory.

Input schema: `openapi/custom_template_security/custom_security.yaml`

### --allow-private-network

Allow trusted remote `$ref` targets on local or private network addresses.

`fastapi-codegen --input openapi/remote_ref/body_and_parameters.yaml --output app --allow-private-network`

Input schema: `openapi/remote_ref/body_and_parameters.yaml`

Related options: `--allow-remote-refs`

### --allow-remote-refs, --no-allow-remote-refs

Allow or block fetching remote `$ref` targets over HTTP/HTTPS.

`fastapi-codegen --input openapi/remote_ref/body_and_parameters.yaml --output app --allow-remote-refs`

Input schema: `openapi/remote_ref/body_and_parameters.yaml`

Related options: `--allow-private-network`

### --include-request-argument

Auto-inject a FastAPI Request argument in generated operation signatures when not present.
Expand Down
2 changes: 2 additions & 0 deletions fastapi_code_generator/_types/generate_config_dict.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@


class GenerateConfigDict(TypedDict):
allow_private_network: NotRequired[bool]
allow_remote_refs: NotRequired[bool | None]
custom_visitors: NotRequired[list[str] | None]
disable_timestamp: NotRequired[bool]
enable_faux_immutability: NotRequired[bool]
Expand Down
48 changes: 45 additions & 3 deletions fastapi_code_generator/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,25 @@ def _show_version(value: bool) -> None:
raise typer.Exit()


def _resolve_remote_reference_options(
allow_remote_refs: Optional[bool], allow_private_network: bool
) -> tuple[Optional[bool], bool]:
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
match allow_remote_refs, allow_private_network:
case False, True:
return False, False
case None, True:
return True, True
case _:
pass
return allow_remote_refs, allow_private_network


def _parse_specified_tags(specify_tags: Optional[str]) -> set[str]:
if not specify_tags:
return set()
return {tag for raw_tag in specify_tags.split(",") if (tag := raw_tag.strip())}


@lru_cache(maxsize=1)
def _get_command() -> Command:
return get_command(app)
Expand Down Expand Up @@ -108,6 +127,22 @@ def main(
"present."
),
),
allow_remote_refs: Optional[bool] = typer.Option(
None,
"--allow-remote-refs/--no-allow-remote-refs",
help=(
"Allow or block fetching remote $ref targets over HTTP/HTTPS. "
"The default follows datamodel-code-generator compatibility behavior."
),
),
allow_private_network: bool = typer.Option(
False,
"--allow-private-network",
help=(
"Allow trusted remote $ref targets on local or private network "
"addresses."
),
),
output_model_type: DataModelType = typer.Option(
DataModelType.PydanticV2BaseModel.value, "--output-model-type", "-d"
),
Expand Down Expand Up @@ -162,6 +197,8 @@ def main(
disable_timestamp=disable_timestamp,
strict_nullable=strict_nullable,
include_request_argument=include_request_argument,
allow_remote_refs=allow_remote_refs,
allow_private_network=allow_private_network,
generate_routers=generate_routers,
specify_tags=specify_tags,
output_model_type=output_model_type,
Expand Down Expand Up @@ -203,6 +240,8 @@ def generate_code(
disable_timestamp: bool = False,
strict_nullable: bool = False,
include_request_argument: bool = False,
allow_remote_refs: Optional[bool] = None,
allow_private_network: bool = False,
generate_routers: Optional[bool] = None,
specify_tags: Optional[str] = None,
output_model_type: DataModelType = DataModelType.PydanticV2BaseModel,
Expand All @@ -226,6 +265,9 @@ def generate_code(
custom_visitors = []
data_model_types = get_data_model_types(output_model_type, python_version)
code_formatter = _get_code_formatter(python_version, Path().resolve())
allow_remote_refs, allow_private_network = _resolve_remote_reference_options(
allow_remote_refs, allow_private_network
)

parser = OpenAPIParser(
input_text,
Expand All @@ -239,6 +281,8 @@ def generate_code(
target_python_version=python_version,
strict_nullable=strict_nullable,
include_request_argument=include_request_argument,
allow_remote_refs=allow_remote_refs,
allow_private_network=allow_private_network,
use_annotated=use_annotated,
reuse_model=reuse_model,
enable_faux_immutability=enable_faux_immutability,
Expand Down Expand Up @@ -304,9 +348,7 @@ def generate_code(
specified_tags = set()
existing_main_has_router_includes = False
if generate_routers and specify_tags:
specified_tags = {
tag.strip() for tag in str(specify_tags).split(",") if tag.strip()
}
specified_tags = _parse_specified_tags(specify_tags)
main_path = output_dir / "main.py"
if main_path.exists():
existing_main_has_router_includes = (
Expand Down
20 changes: 18 additions & 2 deletions fastapi_code_generator/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,21 @@ class GenerateConfig(BaseModel):
),
json_schema_extra=cast(Any, _cli_metadata("--include-request-argument")),
)
allow_remote_refs: bool | None = Field(
default=None,
description="Allow or block fetching remote `$ref` targets over HTTP/HTTPS.",
json_schema_extra=cast(
Any, _cli_metadata("--allow-remote-refs", "--no-allow-remote-refs")
),
)
allow_private_network: bool = Field(
default=False,
description=(
"Allow trusted remote `$ref` targets on local or private network "
"addresses."
),
json_schema_extra=cast(Any, _cli_metadata("--allow-private-network")),
)
output_model_type: OutputModelTypeName = Field(
default="pydantic_v2.BaseModel",
description="Model backend passed through to datamodel-code-generator.",
Expand Down Expand Up @@ -296,9 +311,10 @@ def validate_generate_config_model() -> None:
cli = _get_cli_metadata(field)
param = params[name]
expected_flags = tuple(cli["flags"])
if tuple(param.opts) != expected_flags:
actual_flags = tuple(param.opts) + tuple(getattr(param, "secondary_opts", ()))
if actual_flags != expected_flags:
raise ValueError(
f"{name} flags drifted: expected {expected_flags!r}, got {tuple(param.opts)!r}"
f"{name} flags drifted: expected {expected_flags!r}, got {actual_flags!r}"
)
if cli["multiple"] != bool(getattr(param, "multiple", False)):
raise ValueError(f"{name} multiple setting drifted from the CLI")
Expand Down
21 changes: 15 additions & 6 deletions fastapi_code_generator/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,8 @@ def __init__(
field_extra_keys: Optional[Set[str]] = None,
field_include_all_keys: bool = False,
include_request_argument: bool = False,
allow_remote_refs: Optional[bool] = None,
allow_private_network: bool = False,
use_annotated: bool = False,
):
super().__init__(
Expand Down Expand Up @@ -389,6 +391,8 @@ def __init__(
field_extra_keys=field_extra_keys,
field_include_all_keys=field_include_all_keys,
openapi_scopes=[OpenAPIScope.Schemas, OpenAPIScope.Paths],
allow_remote_refs=allow_remote_refs,
allow_private_network=allow_private_network,
use_annotated=use_annotated,
)
self.operations: Dict[str, Operation] = {}
Expand Down Expand Up @@ -438,12 +442,17 @@ def get_parameter_type(
schema: Optional[JsonSchemaObject] = None
data_type: Optional[DataType] = None
for content in parameters.content.values():
if isinstance(content.schema_, ReferenceObject):
data_type = self.get_ref_data_type(content.schema_.ref)
ref_model = self.get_ref_model(content.schema_.ref)
schema = JsonSchemaObject.model_validate(ref_model) # pragma: no cover
else:
schema = content.schema_
match content.schema_:
case ReferenceObject() as schema_ref:
data_type = self.get_ref_data_type(schema_ref.ref)
ref_model = self.get_ref_model(schema_ref.ref)
schema = JsonSchemaObject.model_validate(
ref_model
) # pragma: no cover
case JsonSchemaObject() as schema_obj:
schema = schema_obj
case _:
continue
break
if not data_type:
if not schema:
Expand Down
48 changes: 48 additions & 0 deletions fastapi_code_generator/prompt_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,28 @@
'type': 'boolean',
'choices': [],
},
{
'name': 'allow_remote_refs',
'cli_flags': ['--allow-remote-refs', '--no-allow-remote-refs'],
'description': 'Allow or block fetching remote `$ref` targets '
'over HTTP/HTTPS.',
'required': False,
'default': None,
'multiple': False,
'type': 'boolean | null',
'choices': [],
},
{
'name': 'allow_private_network',
'cli_flags': ['--allow-private-network'],
'description': 'Allow trusted remote `$ref` targets on local or '
'private network addresses.',
'required': False,
'default': False,
'multiple': False,
'type': 'boolean',
'choices': [],
},
{
'name': 'output_model_type',
'cli_flags': ['--output-model-type', '-d'],
Expand Down Expand Up @@ -255,6 +277,32 @@
],
'input_schema': 'openapi/custom_template_security/custom_security.yaml',
},
{
'options': ['--allow-private-network'],
'description': 'Allow trusted remote `$ref` targets on local or '
'private network addresses.',
'cli_args': [
'--input',
'openapi/remote_ref/body_and_parameters.yaml',
'--output',
'app',
'--allow-private-network',
],
'input_schema': 'openapi/remote_ref/body_and_parameters.yaml',
},
{
'options': ['--allow-remote-refs', '--no-allow-remote-refs'],
'description': 'Allow or block fetching remote `$ref` targets over '
'HTTP/HTTPS.',
'cli_args': [
'--input',
'openapi/remote_ref/body_and_parameters.yaml',
'--output',
'app',
'--allow-remote-refs',
],
'input_schema': 'openapi/remote_ref/body_and_parameters.yaml',
},
{
'options': ['--include-request-argument'],
'description': 'Auto-inject a FastAPI Request argument in generated '
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ classifiers = [
dynamic = ["version"]
dependencies = [
"click>=8.1.8,<8.2",
"datamodel-code-generator[http]>=0.59,<0.60",
"datamodel-code-generator[http]>=0.61,<0.66",
"jinja2>=2.11.2,<4",
"pydantic>=2.12,<3",
"pysnooper>=0.4.1,<2",
Expand Down
Loading
Loading