Skip to content
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

[Python] support multi namespace #5271

Closed
wants to merge 56 commits into from
Closed
Changes from 1 commit
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
feb80b5
update dependency tcgc 0.48.1
msyyc Nov 11, 2024
60e4c15
add clientNamespace property
msyyc Nov 11, 2024
ac2b225
init
msyyc Nov 25, 2024
0a391bd
init2
msyyc Nov 26, 2024
80ea470
init3
msyyc Nov 27, 2024
d7f6e87
init4
msyyc Dec 2, 2024
4146dc4
init5
msyyc Dec 2, 2024
f0d01be
format
msyyc Dec 3, 2024
3613073
format
msyyc Dec 3, 2024
db6402e
merge
msyyc Dec 3, 2024
5ea817c
review
msyyc Dec 3, 2024
ed61e31
review
msyyc Dec 3, 2024
682b381
review
msyyc Dec 4, 2024
32399e8
review
msyyc Dec 4, 2024
ab818e2
review
msyyc Dec 4, 2024
f3f0140
review
msyyc Dec 4, 2024
ea246a9
review
msyyc Dec 4, 2024
08a68ff
review
msyyc Dec 5, 2024
a8dc1d4
review
msyyc Dec 5, 2024
089ebcc
review
msyyc Dec 5, 2024
59d97c2
review
msyyc Dec 6, 2024
bbb5884
Merge branch 'main' of https://github.com/microsoft/typespec into pyt…
msyyc Dec 6, 2024
9c5f209
review
msyyc Dec 6, 2024
d8881d1
review
msyyc Dec 6, 2024
5aeb9cf
review
msyyc Dec 6, 2024
c8cac2c
review
msyyc Dec 6, 2024
b0b1b43
review
msyyc Dec 6, 2024
a21d7ad
review
msyyc Dec 6, 2024
6c37c0c
review
msyyc Dec 6, 2024
d0dcc68
review
msyyc Dec 6, 2024
6121243
merge
msyyc Dec 6, 2024
05309a8
for sample and test
msyyc Dec 6, 2024
f3d25ff
for sample and test
msyyc Dec 6, 2024
42f29c9
review
msyyc Dec 6, 2024
bf9806d
merge
msyyc Dec 9, 2024
ab88321
debug
msyyc Dec 9, 2024
7f88e3e
review
msyyc Dec 9, 2024
adf95fe
fix
msyyc Dec 10, 2024
7c5532c
fix
msyyc Dec 10, 2024
2781b09
new test
msyyc Dec 10, 2024
657176d
review
msyyc Dec 10, 2024
29c30fd
review
msyyc Dec 10, 2024
af457ca
review
msyyc Dec 10, 2024
b58ef98
review
msyyc Dec 10, 2024
5458bb5
merge
msyyc Dec 11, 2024
d5b473a
fix
msyyc Dec 11, 2024
689a06b
fix
msyyc Dec 11, 2024
4128461
fix
msyyc Dec 11, 2024
08ca7c7
Merge branch 'main' of https://github.com/microsoft/typespec into pyt…
msyyc Dec 13, 2024
6aa4203
fix typing
msyyc Dec 13, 2024
5700597
fix typing
msyyc Dec 13, 2024
49cc526
review
msyyc Dec 13, 2024
5b7fe1a
review
msyyc Dec 13, 2024
7290a71
Merge branch 'main' of https://github.com/microsoft/typespec into pyt…
msyyc Dec 16, 2024
c592198
review
msyyc Dec 16, 2024
21d8448
review
msyyc Dec 16, 2024
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
Prev Previous commit
Next Next commit
review
msyyc committed Dec 4, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
commit ab818e241e5aadc3fee7e29d99a50575b6880d82
Original file line number Diff line number Diff line change
@@ -390,7 +390,7 @@ def _imports_shared(self, async_mode: bool, **kwargs: Any) -> FileImport:
if self.code_model.options["package_version"]:
serialize_namespace = kwargs.get("serialize_namespace", self.code_model.namespace)
file_import.add_submodule_import(
f"{self.code_model.get_relative_import_path(serialize_namespace, module_name="_version")}", "VERSION", ImportType.LOCAL
self.code_model.get_relative_import_path(serialize_namespace, module_name="_version"), "VERSION", ImportType.LOCAL
)
if self.code_model.options["azure_arm"]:
policy = "AsyncARMChallengeAuthenticationPolicy" if async_mode else "ARMChallengeAuthenticationPolicy"
Original file line number Diff line number Diff line change
@@ -4,6 +4,7 @@
# license information.
# --------------------------------------------------------------------------
import logging
from collections import namedtuple
from typing import List, Optional, Any, Union
from pathlib import Path
from jinja2 import PackageLoader, Environment, FileSystemLoader, StrictUndefined
@@ -54,7 +55,7 @@
]

_REGENERATE_FILES = {"setup.py", "MANIFEST.in"}

AsyncInfo = namedtuple("AsyncInfo", ["async_mode", "async_path"])

# extract sub folders. For example, source_file_path is like:
# "xxx/resource-manager/Microsoft.XX/stable/2023-04-01/examples/Compute/createOrUpdate/AKSCompute.json",
@@ -86,6 +87,12 @@ def has_aio_folder(self) -> bool:
def has_operations_folder(self) -> bool:
return self.code_model.options["show_operations"] and bool(self.code_model.has_operations)

@property
def serialize_loop(self) -> List[AsyncInfo]:
sync_loop = AsyncInfo(async_mode=False, async_path="")
async_loop = AsyncInfo(async_mode=True, async_path="aio/")
return [sync_loop, async_loop] if self.has_aio_folder else [sync_loop]

def serialize(self) -> None:
env = Environment(
loader=PackageLoader("pygen.codegen", "templates"),
@@ -97,7 +104,6 @@ def serialize(self) -> None:
)

general_serializer = GeneralSerializer(code_model=self.code_model, env=env, async_mode=False)

for client_namespace, client_namespace_type in self.code_model.client_namespace_types.items():
if client_namespace == "":
# Write the setup file
@@ -118,7 +124,7 @@ def serialize(self) -> None:
elif client_namespace_type.clients:
# add clients folder if there are clients in this namespace
self._serialize_client_and_config_files(
client_namespace, general_serializer, client_namespace_type.clients, env
client_namespace, client_namespace_type.clients, env
)
else:
# add pkgutil init file if no clients in this namespace
@@ -261,76 +267,44 @@ def _serialize_and_write_single_rest_layer(
).serialize_init(),
)

def _serialize_and_write_operations_file(
self,
env: Environment,
operation_groups: List[OperationGroup],
namespace: str,
operation_group: Optional[OperationGroup] = None,
) -> None:
filename = operation_group.filename if operation_group else "_operations"
# write first sync file
operation_group_serializer = OperationGroupsSerializer(
code_model=self.code_model,
operation_groups=operation_groups if operation_groups else [operation_group],
env=env,
async_mode=False,
)
operations_folder_name = self.code_model.operations_folder_name(namespace)
self.write_file(
self.exec_path(namespace) / Path(operations_folder_name) / Path(f"{filename}.py"),
operation_group_serializer.serialize(),
)

if self.has_aio_folder:
# write async operation group and operation files
operation_group_serializer.async_mode = True
self.write_file(
(self.exec_path(namespace) / Path("aio") / Path(operations_folder_name) / Path(f"{filename}.py")),
operation_group_serializer.serialize(),
)

def _serialize_and_write_operations_folder(
self, operation_groups: List[OperationGroup], env: Environment, namespace: str
) -> None:
operations_folder_name = self.code_model.operations_folder_name(namespace)

# if there was a patch file before, we keep it
self._keep_patch_file(self.exec_path(namespace) / operations_folder_name / Path("_patch.py"), env)
if self.has_aio_folder:
self._keep_patch_file(self.exec_path(namespace) / Path("aio") / operations_folder_name / Path("_patch.py"), env)

# write sync operations init file
operations_init_serializer = OperationsInitSerializer(
code_model=self.code_model, operation_groups=operation_groups, env=env, async_mode=False
)
self.write_file(
self.exec_path(namespace) / operations_folder_name / Path("__init__.py"),
operations_init_serializer.serialize(),
)

# write async operations init file
if self.has_aio_folder:
operations_init_serializer.async_mode = True
exec_path = self.exec_path(namespace)
for async_mode, async_path in self.serialize_loop:
prefix_path = f"{async_path}{operations_folder_name}"
# write init file
operations_init_serializer = OperationsInitSerializer(
code_model=self.code_model, operation_groups=operation_groups, env=env, async_mode=async_mode
)
self.write_file(
self.exec_path(namespace) / "aio" / operations_folder_name / Path("__init__.py"),
exec_path / Path(f"{prefix_path}/__init__.py"),
operations_init_serializer.serialize(),
)

if self.code_model.options["combine_operation_files"]:
self._serialize_and_write_operations_file(
env=env,
namespace=namespace,
operation_groups=operation_groups,
)
else:
for operation_group in operation_groups:
self._serialize_and_write_operations_file(
# write operations file
OgLoop = namedtuple("OgLoop", ["operation_groups", "filename"])
if self.code_model.options["combine_operation_files"]:
loops = [OgLoop(operation_groups, "_operations")]
else:
loops = [OgLoop([og], og.filename) for og in operation_groups]
for ogs, filename in loops:
operation_group_serializer = OperationGroupsSerializer(
code_model=self.code_model,
operation_groups=ogs,
env=env,
namespace=namespace,
operation_group=operation_group,
async_mode=async_mode,
)
self.write_file(
exec_path / Path(f"{prefix_path}/{filename}.py"),
operation_group_serializer.serialize(),
)

# if there was a patch file before, we keep it
self._keep_patch_file(exec_path / Path(f"{prefix_path}/_patch.py"), env)


def _serialize_and_write_version_file(
self,
namespace: str,
@@ -359,36 +333,35 @@ def _write_version_file(original_version_file_name: str) -> None:
def _serialize_client_and_config_files(
self,
namespace: str,
general_serializer: GeneralSerializer,
clients: List[Client],
env: Environment,
) -> None:
general_serializer.async_mode = False
general_serializer.client_namespace = namespace
self.write_file(
self.exec_path(namespace) / Path(f"{self.code_model.client_filename}.py"),
general_serializer.serialize_service_client_file(clients),
)
self.write_file(
self.exec_path(namespace) / Path("_configuration.py"),
general_serializer.serialize_config_file(clients),
)
exec_path = self.exec_path(namespace)
for async_mode, async_path in self.serialize_loop:
general_serializer = GeneralSerializer(code_model=self.code_model, env=env, async_mode=async_mode)
# when there is client.py, there must be __init__.py
self.write_file(
exec_path / Path(f"{async_path}__init__.py"),
general_serializer.serialize_init_file(clients),
)

# write client file
self.write_file(
exec_path / Path(f"{async_path}{self.code_model.client_filename}.py"),
general_serializer.serialize_service_client_file(clients),
)

#write config file
self.write_file(
exec_path / Path(f"{async_path}_configuration.py"),
general_serializer.serialize_config_file(clients),
)

# if there was a patch file before, we keep it
self._keep_patch_file(exec_path / Path(f"{async_path}_patch.py"), env)

# if there was a patch file before, we keep it
self._keep_patch_file(self.exec_path(namespace) / Path("_patch.py"), env)

general_serializer.async_mode = True
self.write_file(
self.exec_path(namespace) / Path(f"aio/{self.code_model.client_filename}.py"),
general_serializer.serialize_service_client_file(clients),
)
self.write_file(
self.exec_path(namespace) / Path("aio/_configuration.py"),
general_serializer.serialize_config_file(clients),
)

if self.has_aio_folder:
self._keep_patch_file(self.exec_path(namespace) / Path("aio/_patch.py"), env)

def _serialize_and_write_top_level_folder(self, env: Environment, namespace: str) -> None:
general_serializer = GeneralSerializer(code_model=self.code_model, env=env, async_mode=False)