Skip to content

Commit d162058

Browse files
feat: Add new client parameters: encoding
1 parent af09640 commit d162058

File tree

4 files changed

+80
-35
lines changed

4 files changed

+80
-35
lines changed

openapi_python_client/__init__.py

Lines changed: 45 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,19 @@ class Project:
4444
project_name_override: Optional[str] = None
4545
package_name_override: Optional[str] = None
4646
package_version_override: Optional[str] = None
47-
48-
def __init__(self, *, openapi: GeneratorData, meta: MetaType, custom_template_path: Optional[Path] = None) -> None:
47+
encoding: Optional[str] = None
48+
49+
def __init__(
50+
self,
51+
*,
52+
openapi: GeneratorData,
53+
meta: MetaType,
54+
custom_template_path: Optional[Path] = None,
55+
encoding: Optional[str] = None,
56+
) -> None:
4957
self.openapi: GeneratorData = openapi
5058
self.meta: MetaType = meta
59+
self.encoding = encoding
5160

5261
package_loader = PackageLoader(__package__)
5362
loader: BaseLoader
@@ -137,15 +146,17 @@ def _create_package(self) -> None:
137146
package_init = self.package_dir / "__init__.py"
138147

139148
package_init_template = self.env.get_template("package_init.py.jinja")
140-
package_init.write_text(package_init_template.render(description=self.package_description))
149+
package_init.write_text(
150+
package_init_template.render(description=self.package_description), encoding=self.encoding
151+
)
141152

142153
if self.meta != MetaType.NONE:
143154
pytyped = self.package_dir / "py.typed"
144-
pytyped.write_text("# Marker file for PEP 561")
155+
pytyped.write_text("# Marker file for PEP 561", encoding=self.encoding)
145156

146157
types_template = self.env.get_template("types.py.jinja")
147158
types_path = self.package_dir / "types.py"
148-
types_path.write_text(types_template.render())
159+
types_path.write_text(types_template.render(), encoding=self.encoding)
149160

150161
def _build_metadata(self) -> None:
151162
if self.meta == MetaType.NONE:
@@ -161,13 +172,14 @@ def _build_metadata(self) -> None:
161172
readme.write_text(
162173
readme_template.render(
163174
project_name=self.project_name, description=self.package_description, package_name=self.package_name
164-
)
175+
),
176+
encoding=self.encoding,
165177
)
166178

167179
# .gitignore
168180
git_ignore_path = self.project_dir / ".gitignore"
169181
git_ignore_template = self.env.get_template(".gitignore.jinja")
170-
git_ignore_path.write_text(git_ignore_template.render())
182+
git_ignore_path.write_text(git_ignore_template.render(), encoding=self.encoding)
171183

172184
def _build_pyproject_toml(self, *, use_poetry: bool) -> None:
173185
template = "pyproject.toml.jinja" if use_poetry else "pyproject_no_poetry.toml.jinja"
@@ -179,7 +191,8 @@ def _build_pyproject_toml(self, *, use_poetry: bool) -> None:
179191
package_name=self.package_name,
180192
version=self.version,
181193
description=self.package_description,
182-
)
194+
),
195+
encoding=self.encoding,
183196
)
184197

185198
def _build_setup_py(self) -> None:
@@ -191,7 +204,8 @@ def _build_setup_py(self) -> None:
191204
package_name=self.package_name,
192205
version=self.version,
193206
description=self.package_description,
194-
)
207+
),
208+
encoding=self.encoding,
195209
)
196210

197211
def _build_models(self) -> None:
@@ -204,7 +218,7 @@ def _build_models(self) -> None:
204218
model_template = self.env.get_template("model.py.jinja")
205219
for model in self.openapi.models.values():
206220
module_path = models_dir / f"{model.reference.module_name}.py"
207-
module_path.write_text(model_template.render(model=model))
221+
module_path.write_text(model_template.render(model=model), encoding=self.encoding)
208222
imports.append(import_string_from_reference(model.reference))
209223

210224
# Generate enums
@@ -213,25 +227,25 @@ def _build_models(self) -> None:
213227
for enum in self.openapi.enums.values():
214228
module_path = models_dir / f"{enum.reference.module_name}.py"
215229
if enum.value_type is int:
216-
module_path.write_text(int_enum_template.render(enum=enum))
230+
module_path.write_text(int_enum_template.render(enum=enum), encoding=self.encoding)
217231
else:
218-
module_path.write_text(str_enum_template.render(enum=enum))
232+
module_path.write_text(str_enum_template.render(enum=enum), encoding=self.encoding)
219233
imports.append(import_string_from_reference(enum.reference))
220234

221235
models_init_template = self.env.get_template("models_init.py.jinja")
222-
models_init.write_text(models_init_template.render(imports=imports))
236+
models_init.write_text(models_init_template.render(imports=imports), encoding=self.encoding)
223237

224238
def _build_api(self) -> None:
225239
# Generate Client
226240
client_path = self.package_dir / "client.py"
227241
client_template = self.env.get_template("client.py.jinja")
228-
client_path.write_text(client_template.render())
242+
client_path.write_text(client_template.render(), encoding=self.encoding)
229243

230244
# Generate endpoints
231245
api_dir = self.package_dir / "api"
232246
api_dir.mkdir()
233247
api_init = api_dir / "__init__.py"
234-
api_init.write_text('""" Contains methods for accessing the API """')
248+
api_init.write_text('""" Contains methods for accessing the API """', encoding=self.encoding)
235249

236250
endpoint_template = self.env.get_template("endpoint_module.py.jinja")
237251
for tag, collection in self.openapi.endpoint_collections_by_tag.items():
@@ -242,31 +256,42 @@ def _build_api(self) -> None:
242256

243257
for endpoint in collection.endpoints:
244258
module_path = tag_dir / f"{snake_case(endpoint.name)}.py"
245-
module_path.write_text(endpoint_template.render(endpoint=endpoint))
259+
module_path.write_text(endpoint_template.render(endpoint=endpoint), encoding=self.encoding)
246260

247261

248262
def _get_project_for_url_or_path(
249-
url: Optional[str], path: Optional[Path], meta: MetaType, custom_template_path: Optional[Path] = None
263+
url: Optional[str],
264+
path: Optional[Path],
265+
meta: MetaType,
266+
custom_template_path: Optional[Path] = None,
267+
encoding: Optional[str] = None,
250268
) -> Union[Project, GeneratorError]:
251269
data_dict = _get_document(url=url, path=path)
252270
if isinstance(data_dict, GeneratorError):
253271
return data_dict
254272
openapi = GeneratorData.from_dict(data_dict)
255273
if isinstance(openapi, GeneratorError):
256274
return openapi
257-
return Project(openapi=openapi, custom_template_path=custom_template_path, meta=meta)
275+
return Project(openapi=openapi, custom_template_path=custom_template_path, meta=meta, encoding=encoding)
258276

259277

260278
def create_new_client(
261-
*, url: Optional[str], path: Optional[Path], meta: MetaType, custom_template_path: Optional[Path] = None
279+
*,
280+
url: Optional[str],
281+
path: Optional[Path],
282+
meta: MetaType,
283+
custom_template_path: Optional[Path] = None,
284+
encoding: Optional[str] = None,
262285
) -> Sequence[GeneratorError]:
263286
"""
264287
Generate the client library
265288
266289
Returns:
267290
A list containing any errors encountered when generating.
268291
"""
269-
project = _get_project_for_url_or_path(url=url, path=path, custom_template_path=custom_template_path, meta=meta)
292+
project = _get_project_for_url_or_path(
293+
url=url, path=path, custom_template_path=custom_template_path, meta=meta, encoding=encoding
294+
)
270295
if isinstance(project, GeneratorError):
271296
return [project]
272297
return project.build()

openapi_python_client/cli.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ def generate(
116116
url: Optional[str] = typer.Option(None, help="A URL to read the JSON from"),
117117
path: Optional[pathlib.Path] = typer.Option(None, help="A path to the JSON file"),
118118
custom_template_path: Optional[pathlib.Path] = typer.Option(None, **custom_template_path_options), # type: ignore
119+
encoding: Optional[str] = typer.Option(None, help="Set file encoding for client files"), # type: ignore
119120
meta: MetaType = _meta_option,
120121
) -> None:
121122
""" Generate a new OpenAPI Client library """
@@ -127,7 +128,9 @@ def generate(
127128
if url and path:
128129
typer.secho("Provide either --url or --path, not both", fg=typer.colors.RED)
129130
raise typer.Exit(code=1)
130-
errors = create_new_client(url=url, path=path, meta=meta, custom_template_path=custom_template_path)
131+
errors = create_new_client(
132+
url=url, path=path, meta=meta, custom_template_path=custom_template_path, encoding=encoding
133+
)
131134
handle_errors(errors)
132135

133136

tests/test___init__.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def test__get_project_for_url_or_path(mocker):
2323

2424
_get_document.assert_called_once_with(url=url, path=path)
2525
from_dict.assert_called_once_with(data_dict)
26-
_Project.assert_called_once_with(openapi=openapi, custom_template_path=None, meta=MetaType.POETRY)
26+
_Project.assert_called_once_with(openapi=openapi, custom_template_path=None, meta=MetaType.POETRY, encoding=None)
2727
assert project == _Project.return_value
2828

2929

@@ -76,7 +76,7 @@ def test_create_new_client(mocker):
7676
result = create_new_client(url=url, path=path, meta=MetaType.POETRY)
7777

7878
_get_project_for_url_or_path.assert_called_once_with(
79-
url=url, path=path, custom_template_path=None, meta=MetaType.POETRY
79+
url=url, path=path, custom_template_path=None, meta=MetaType.POETRY, encoding=None
8080
)
8181
project.build.assert_called_once()
8282
assert result == project.build.return_value
@@ -95,7 +95,7 @@ def test_create_new_client_project_error(mocker):
9595
result = create_new_client(url=url, path=path, meta=MetaType.POETRY)
9696

9797
_get_project_for_url_or_path.assert_called_once_with(
98-
url=url, path=path, custom_template_path=None, meta=MetaType.POETRY
98+
url=url, path=path, custom_template_path=None, meta=MetaType.POETRY, encoding=None
9999
)
100100
assert result == [error]
101101

@@ -392,9 +392,9 @@ def test__build_metadata_poetry(self, mocker):
392392
project_name=project.project_name,
393393
package_name=project.package_name,
394394
)
395-
readme_path.write_text.assert_called_once_with(readme_template.render())
395+
readme_path.write_text.assert_called_once_with(readme_template.render(), encoding=None)
396396
git_ignore_template.render.assert_called_once()
397-
git_ignore_path.write_text.assert_called_once_with(git_ignore_template.render())
397+
git_ignore_path.write_text.assert_called_once_with(git_ignore_template.render(), encoding=None)
398398
project._build_pyproject_toml.assert_called_once_with(use_poetry=True)
399399

400400
def test__build_metadata_setup(self, mocker):
@@ -429,9 +429,9 @@ def test__build_metadata_setup(self, mocker):
429429
project_name=project.project_name,
430430
package_name=project.package_name,
431431
)
432-
readme_path.write_text.assert_called_once_with(readme_template.render())
432+
readme_path.write_text.assert_called_once_with(readme_template.render(), encoding=None)
433433
git_ignore_template.render.assert_called_once()
434-
git_ignore_path.write_text.assert_called_once_with(git_ignore_template.render())
434+
git_ignore_path.write_text.assert_called_once_with(git_ignore_template.render(), encoding=None)
435435
project._build_pyproject_toml.assert_called_once_with(use_poetry=False)
436436
project._build_setup_py.assert_called_once()
437437

@@ -475,7 +475,7 @@ def test__build_pyproject_toml(self, mocker, use_poetry):
475475
version=project.version,
476476
description=project.package_description,
477477
)
478-
pyproject_path.write_text.assert_called_once_with(pyproject_template.render())
478+
pyproject_path.write_text.assert_called_once_with(pyproject_template.render(), encoding=None)
479479

480480
def test__build_setup_py(self, mocker):
481481
from openapi_python_client import MetaType, Project
@@ -505,7 +505,7 @@ def test__build_setup_py(self, mocker):
505505
version=project.version,
506506
description=project.package_description,
507507
)
508-
setup_path.write_text.assert_called_once_with(setup_template.render())
508+
setup_path.write_text.assert_called_once_with(setup_template.render(), encoding=None)
509509

510510

511511
def test__reformat(mocker):

tests/test_cli.py

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,16 @@ def test_config_arg(mocker, _create_new_client):
3131

3232
config_path = "config/path"
3333
path = "cool/path"
34+
encoding = "utf-8"
3435

35-
result = runner.invoke(app, [f"--config={config_path}", "generate", f"--path={path}"], catch_exceptions=False)
36+
result = runner.invoke(
37+
app, [f"--config={config_path}", "generate", f"--path={path}", f"--encoding={encoding}"], catch_exceptions=False
38+
)
3639

3740
assert result.exit_code == 0
3841
load_config.assert_called_once_with(path=Path(config_path))
3942
_create_new_client.assert_called_once_with(
40-
url=None, path=Path(path), custom_template_path=None, meta=MetaType.POETRY
43+
url=None, path=Path(path), custom_template_path=None, meta=MetaType.POETRY, encoding="utf-8"
4144
)
4245

4346

@@ -82,7 +85,9 @@ def test_generate_url(self, _create_new_client):
8285
result = runner.invoke(app, ["generate", f"--url={url}"])
8386

8487
assert result.exit_code == 0
85-
_create_new_client.assert_called_once_with(url=url, path=None, custom_template_path=None, meta=MetaType.POETRY)
88+
_create_new_client.assert_called_once_with(
89+
url=url, path=None, custom_template_path=None, meta=MetaType.POETRY, encoding=None
90+
)
8691

8792
def test_generate_path(self, _create_new_client):
8893
path = "cool/path"
@@ -92,7 +97,7 @@ def test_generate_path(self, _create_new_client):
9297

9398
assert result.exit_code == 0
9499
_create_new_client.assert_called_once_with(
95-
url=None, path=Path(path), custom_template_path=None, meta=MetaType.POETRY
100+
url=None, path=Path(path), custom_template_path=None, meta=MetaType.POETRY, encoding=None
96101
)
97102

98103
def test_generate_meta(self, _create_new_client):
@@ -103,7 +108,19 @@ def test_generate_meta(self, _create_new_client):
103108

104109
assert result.exit_code == 0
105110
_create_new_client.assert_called_once_with(
106-
url=None, path=Path(path), custom_template_path=None, meta=MetaType.NONE
111+
url=None, path=Path(path), custom_template_path=None, meta=MetaType.NONE, encoding=None
112+
)
113+
114+
def test_generate_encoding(self, _create_new_client):
115+
path = "cool/path"
116+
encoding = "utf-8"
117+
from openapi_python_client.cli import MetaType, app
118+
119+
result = runner.invoke(app, ["generate", f"--path={path}", f"--encoding={encoding}"])
120+
121+
assert result.exit_code == 0
122+
_create_new_client.assert_called_once_with(
123+
url=None, path=Path(path), custom_template_path=None, meta=MetaType.POETRY, encoding="utf-8"
107124
)
108125

109126
def test_generate_handle_errors(self, _create_new_client):

0 commit comments

Comments
 (0)