Skip to content

feat: add option to not prepend path to Model Classes with title names #560

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

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
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,5 +157,13 @@ post_hooks:
- "black ."
```

### use_path_prefixes_for_title_model_names

By default, `openapi-python-client` generates class names which include the full path to the schema, including any parent-types. This can result in very long class names like `MyRouteSomeClassAnotherClassResponse`—which is very unique and unlikely to cause conflicts with future API additions, but also super verbose.

If you are carefully curating your `title` properties already to ensure no duplicate class names, you can turn off this prefixing feature by setting `use_path_prefixes_for_title_model_names` to `false` in your config file. This will use the `title` property of any object that has it set _without_ prefixing.

If this option results in conflicts, you will need to manually override class names instead via the `class_overrides` option.

[changelog.md]: CHANGELOG.md
[poetry]: https://python-poetry.org/
1 change: 1 addition & 0 deletions openapi_python_client/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class Config(BaseModel):
project_name_override: Optional[str]
package_name_override: Optional[str]
package_version_override: Optional[str]
use_path_prefixes_for_title_model_names: bool = True
post_hooks: List[str] = [
"autoflake -i -r --remove-all-unused-imports --remove-unused-variables --ignore-init-module-imports .",
"isort .",
Expand Down
11 changes: 8 additions & 3 deletions openapi_python_client/parser/properties/model_property.py
Original file line number Diff line number Diff line change
Expand Up @@ -391,9 +391,14 @@ def build_model_property(
roots: Set of strings that identify schema objects on which the new ModelProperty will depend
process_properties: Determines whether the new ModelProperty will be initialized with property data
"""
class_string = data.title or name
if parent_name:
class_string = f"{utils.pascal_case(parent_name)}{utils.pascal_case(class_string)}"
if not config.use_path_prefixes_for_title_model_names and data.title:
class_string = data.title
else:
title = data.title or name
if parent_name:
class_string = f"{utils.pascal_case(parent_name)}{utils.pascal_case(title)}"
else:
class_string = title
class_info = Class.from_string(string=class_string, config=config)
model_roots = {*roots, class_info.name}
required_properties: Optional[List[Property]] = None
Expand Down
41 changes: 41 additions & 0 deletions tests/test_parser/test_properties/test_model_property.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from typing import Optional
from unittest.mock import MagicMock

import pytest
Expand Down Expand Up @@ -201,6 +202,46 @@ def test_model_name_conflict(self):
assert new_schemas == schemas
assert err == PropertyError(detail='Attempted to generate duplicate models with name "OtherModel"', data=data)

@pytest.mark.parametrize(
"name, title, parent_name, use_title_prefixing, expected",
ids=(
"basic name only",
"title override",
"name with parent",
"name with parent and title prefixing disabled",
"title with parent",
"title with parent and title prefixing disabled",
),
argvalues=(
("prop", None, None, True, "Prop"),
("prop", "MyModel", None, True, "MyModel"),
("prop", None, "parent", True, "ParentProp"),
("prop", None, "parent", False, "ParentProp"),
("prop", "MyModel", "parent", True, "ParentMyModel"),
("prop", "MyModel", "parent", False, "MyModel"),
),
)
def test_model_naming(
self, name: str, title: Optional[str], parent_name: Optional[str], use_title_prefixing: bool, expected: str
):
from openapi_python_client.parser.properties import Schemas, build_model_property

data = oai.Schema(
title=title,
properties={},
)
result = build_model_property(
data=data,
name=name,
schemas=Schemas(),
required=True,
parent_name=parent_name,
config=Config(use_path_prefixes_for_title_model_names=use_title_prefixing),
roots={"root"},
process_properties=True,
)[0]
assert result.class_info.name == expected

def test_model_bad_properties(self):
from openapi_python_client.parser.properties import Schemas, build_model_property

Expand Down