Skip to content

Commit c5cf087

Browse files
authored
[python] Add logic to clear output folder (#8716)
fix Azure/azure-sdk-tools#11791 - For common scenario without `generation-subdir` configured, added test case in this PR - For scenario with `generation-subdir` configured, since there is no `generated` folder, I have to add test case in autorest.python repo Azure/autorest.python#3239
1 parent c9fe3a8 commit c5cf087

File tree

5 files changed

+79
-2
lines changed

5 files changed

+79
-2
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
changeKind: feature
3+
packages:
4+
- "@typespec/http-client-python"
5+
---
6+
7+
Add logic to clear output folder

packages/http-client-python/eng/scripts/ci/regenerate.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -447,11 +447,35 @@ async function runTaskPool(tasks: Array<() => Promise<void>>, poolLimit: number)
447447
await Promise.all(workers);
448448
}
449449

450+
// create some files before regeneration. After regeneration, these files should be deleted and we will test it
451+
// in test case
452+
async function preprocess(flags: RegenerateFlagsInput): Promise<void> {
453+
if (flags.flavor === "azure") {
454+
// create folder if not exists
455+
const folderParts = [
456+
"test",
457+
"azure",
458+
"generated",
459+
"authentication-api-key",
460+
"authentication",
461+
"apikey",
462+
"_operations",
463+
];
464+
await promises.mkdir(join(GENERATED_FOLDER, ...folderParts), { recursive: true });
465+
await promises.writeFile(
466+
join(GENERATED_FOLDER, ...folderParts, "to_be_deleted.py"),
467+
"# This file is to be deleted after regeneration",
468+
);
469+
}
470+
}
471+
450472
async function regenerate(flags: RegenerateFlagsInput): Promise<void> {
451473
if (flags.flavor === undefined) {
452474
await regenerate({ flavor: "azure", ...flags });
453475
await regenerate({ flavor: "unbranded", ...flags });
454476
} else {
477+
await preprocess(flags);
478+
455479
const flagsResolved = { debug: false, flavor: flags.flavor, ...flags };
456480
const subdirectoriesForAzure = await getSubdirectories(AZURE_HTTP_SPECS, flagsResolved);
457481
const subdirectoriesForNonAzure = await getSubdirectories(HTTP_SPECS, flagsResolved);

packages/http-client-python/generator/pygen/__init__.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
# Licensed under the MIT License. See License.txt in the project root for
44
# license information.
55
# --------------------------------------------------------------------------
6+
import shutil
67
from collections.abc import ItemsView, KeysView, MutableMapping, ValuesView
78
import logging
89
from pathlib import Path
@@ -248,9 +249,23 @@ def remove_file(self, filename: Union[str, Path]) -> None:
248249
except FileNotFoundError:
249250
pass
250251

252+
def remove_folder(self, foldername: Union[str, Path]) -> None:
253+
try:
254+
folder_path = self.output_folder / Path(foldername)
255+
if folder_path.exists() and folder_path.is_dir():
256+
shutil.rmtree(folder_path)
257+
except FileNotFoundError:
258+
pass
259+
251260
def list_file(self) -> list[str]:
252261
return [str(f.relative_to(self.output_folder)) for f in self.output_folder.glob("**/*") if f.is_file()]
253262

263+
def list_file_of_folder(self, foldername: Union[str, Path]) -> list[str]:
264+
folder_path = self.output_folder / Path(foldername)
265+
if folder_path.exists() and folder_path.is_dir():
266+
return [str(f.relative_to(self.output_folder)) for f in folder_path.glob("**/*") if f.is_file()]
267+
return []
268+
254269

255270
class Plugin(ReaderAndWriter, ABC):
256271
"""A base class for autorest plugin.

packages/http-client-python/generator/pygen/codegen/serializers/__init__.py

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,21 @@ def keep_version_file(self) -> bool:
122122
# If parsing the version fails, we assume the version file is not valid and overwrite.
123123
return False
124124

125+
# pylint: disable=too-many-branches
125126
def serialize(self) -> None:
127+
# remove existing folders when generate from tsp
128+
if self.code_model.is_tsp and self.code_model.is_azure_flavor:
129+
# remove generated_samples and generated_tests folder
130+
self.remove_folder(self._generated_tests_samples_folder("generated_samples"))
131+
self.remove_folder(self._generated_tests_samples_folder("generated_tests"))
132+
133+
# remove generated sdk files
134+
generation_path = self.code_model.get_generation_dir(self.code_model.namespace)
135+
for file in self.list_file_of_folder(generation_path):
136+
if file.endswith(".py") and "_patch.py" not in file:
137+
self.remove_file(file)
138+
139+
# serialize logic
126140
env = Environment(
127141
loader=PackageLoader("pygen.codegen", "templates"),
128142
keep_trailing_newline=True,
@@ -519,8 +533,11 @@ def sample_additional_folder(self) -> Path:
519533
return Path("/".join(namespace_config.split(".")[num_of_package_namespace:]))
520534
return Path("")
521535

536+
def _generated_tests_samples_folder(self, folder_name: str) -> Path:
537+
return self._root_of_sdk / folder_name
538+
522539
def _serialize_and_write_sample(self, env: Environment):
523-
out_path = self._root_of_sdk / "generated_samples"
540+
out_path = self._generated_tests_samples_folder("generated_samples")
524541
for client in self.code_model.clients:
525542
for op_group in client.operation_groups:
526543
for operation in op_group.operations:
@@ -549,7 +566,7 @@ def _serialize_and_write_sample(self, env: Environment):
549566

550567
def _serialize_and_write_test(self, env: Environment):
551568
self.code_model.for_test = True
552-
out_path = self._root_of_sdk / "generated_tests"
569+
out_path = self._generated_tests_samples_folder("generated_tests")
553570
general_serializer = TestGeneralSerializer(code_model=self.code_model, env=env)
554571
self.write_file(out_path / "conftest.py", general_serializer.serialize_conftest())
555572
if not self.code_model.options["azure-arm"]:
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# -------------------------------------------------------------------------
2+
# Copyright (c) Microsoft Corporation. All rights reserved.
3+
# Licensed under the MIT License. See License.txt in the project root for
4+
# license information.
5+
# --------------------------------------------------------------------------
6+
from pathlib import Path
7+
8+
GENERATED_PATH = Path(__file__).parent.parent.resolve() / "generated"
9+
10+
11+
def test_clear_output_folder():
12+
folder = GENERATED_PATH / "authentication-api-key/authentication/apikey/_operations"
13+
assert folder.exists(), "Operations folder should exist"
14+
assert not (folder / "to_be_deleted.py").exists(), "File to_be_deleted.py should be deleted after regeneration"

0 commit comments

Comments
 (0)