Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
262414e
switch to vendor folder
Mar 18, 2025
fdd2e5a
Merge branch 'main' of https://github.com/microsoft/typespec into pyt…
Mar 24, 2025
26dcd60
fix serialization import
Mar 24, 2025
833162b
passing with serialization folder
Mar 24, 2025
544580d
Merge branch 'main' of https://github.com/microsoft/typespec into pyt…
Mar 25, 2025
cb6394a
move vendor folder to single folder at root of namespaces
Mar 25, 2025
2108e11
trying to get vendor as a single folder at the root of the namespace …
Mar 25, 2025
4367006
Merge branch 'main' of https://github.com/microsoft/typespec into pyt…
Apr 17, 2025
6a88e2c
authenticaiton-apikey passing
Apr 17, 2025
e2c9f99
fix lint
Apr 17, 2025
1c1850d
add changeset
Apr 17, 2025
d7c0ae6
Merge branch 'main' of https://github.com/microsoft/typespec into pyt…
Apr 17, 2025
8769d8d
revert package lock change
Apr 17, 2025
64d9442
move model_base into vendor folder
Apr 17, 2025
85c4508
give serialization file name
Apr 17, 2025
13ab58e
Merge branch 'main' of https://github.com/microsoft/typespec into pyt…
Apr 17, 2025
92de95a
format and lint
Apr 17, 2025
7c00235
update model base
Apr 17, 2025
d03d9da
rename to utils folder
Apr 17, 2025
f3fec24
Merge branch 'main' of https://github.com/microsoft/typespec into pyt…
Apr 17, 2025
908f4c6
Merge branch 'main' of https://github.com/microsoft/typespec into pyt…
Apr 17, 2025
5d9ebc6
remove import for formdata
Apr 17, 2025
787b9fe
fix formdata generation
Apr 17, 2025
72d2b53
Merge branch 'main' of https://github.com/microsoft/typespec into pyt…
Apr 18, 2025
874ce16
add alias to formdata import
Apr 18, 2025
7dc50db
update serialization in base model
Apr 18, 2025
941e21c
fix serialization import
Apr 18, 2025
2b85df5
update import namespace for multiapi
Apr 18, 2025
dd4afff
fix imports for multiapi
Apr 18, 2025
e3fddd8
Merge branch 'main' into python/moveToVendorFolder
msyyc Apr 21, 2025
88795ae
fix raise_if_not_implemented import
Apr 21, 2025
6b6bdbc
Merge branch 'python/moveToVendorFolder' of https://github.com/iscai-…
Apr 21, 2025
c54d3df
Merge branch 'main' of https://github.com/microsoft/typespec into pyt…
Apr 21, 2025
d3d98f5
generate init file for multiapi utils folders
Apr 21, 2025
2bf385c
Merge branch 'main' of https://github.com/microsoft/typespec into pyt…
Apr 21, 2025
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
changeKind: fix
packages:
- "@typespec/http-client-python"
---

Reorder generated `_vendor` file into a `_utils_` folder
Original file line number Diff line number Diff line change
Expand Up @@ -242,31 +242,42 @@ def is_top_namespace(self, client_namespace: str) -> bool:
"""
return client_namespace == self.namespace

def need_vendored_code(self, async_mode: bool, client_namespace: str) -> bool:
"""Whether we need to vendor code in the _vendor.py in specific namespace"""
def need_utils_folder(self, async_mode: bool, client_namespace: str) -> bool:
return (
self.need_vendored_form_data(async_mode, client_namespace)
or self.need_vendored_etag(client_namespace)
or self.need_vendored_abstract(client_namespace)
or self.need_vendored_mixin(client_namespace)
self.need_utils_utils(async_mode, client_namespace)
or self.need_utils_serialization
or self.options["models_mode"] == "dpg"
)

def need_vendored_form_data(self, async_mode: bool, client_namespace: str) -> bool:
@property
def need_utils_serialization(self) -> bool:
return not self.options["client_side_validation"]

def need_utils_utils(self, async_mode: bool, client_namespace: str) -> bool:
return (
self.need_utils_form_data(async_mode, client_namespace)
or self.need_utils_etag(client_namespace)
or self.need_utils_abstract(client_namespace)
or self.need_utils_mixin
)

def need_utils_form_data(self, async_mode: bool, client_namespace: str) -> bool:
return (
(not async_mode)
and self.is_top_namespace(client_namespace)
and self.has_form_data
and self.options["models_mode"] == "dpg"
)

def need_vendored_etag(self, client_namespace: str) -> bool:
def need_utils_etag(self, client_namespace: str) -> bool:
return self.is_top_namespace(client_namespace) and self.has_etag

def need_vendored_abstract(self, client_namespace: str) -> bool:
def need_utils_abstract(self, client_namespace: str) -> bool:
return self.is_top_namespace(client_namespace) and self.has_abstract_operations

def need_vendored_mixin(self, client_namespace: str) -> bool:
return self.has_mixin(client_namespace)
@property
def need_utils_mixin(self) -> bool:
return any(c_n for c_n in self.client_namespace_types if self.has_mixin(c_n))

def has_mixin(self, client_namespace: str) -> bool:
return any(c for c in self.get_clients(client_namespace) if c.has_mixin)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,11 @@ class TypingSection(str, Enum):


class MsrestImportType(Enum):
Module = auto() # import _serialization.py or msrest.serialization as Module
Serializer = auto() # from _serialization.py or msrest.serialization import Serializer
SerializerDeserializer = auto() # from _serialization.py or msrest.serialization import Serializer and Deserializer
Module = auto() # import _utils/serialization.py or msrest.serialization as Module
Serializer = auto() # from _utils/serialization.py or msrest.serialization import Serializer
SerializerDeserializer = (
auto()
) # from _utils/serialization.py or msrest.serialization import Serializer and Deserializer


class ImportModel:
Expand Down Expand Up @@ -261,21 +263,23 @@ def add_msrest_import(
if msrest_import_type == MsrestImportType.SerializerDeserializer:
self.add_submodule_import("msrest", "Deserializer", ImportType.THIRDPARTY, typing_section)
else:
# _serialization.py is always in root namespace
imported_namespace = self.code_model.namespace
# _utils/serialization.py is always in root namespace
imported_namespace = f"{self.code_model.namespace}._utils"
if self.code_model.options["multiapi"]:
# for multiapi, the namespace is azure.mgmt.xxx.v20XX_XX_XX while _serialization.py is in azure.mgmt.xxx
imported_namespace = get_parent_namespace(imported_namespace)
# for multiapi, the namespace is azure.mgmt.xxx.v20XX_XX_XX
# while _utils/serialization.py is in azure.mgmt.xxx
imported_namespace = f"{get_parent_namespace(imported_namespace)}._utils"
if msrest_import_type == MsrestImportType.Module:
self.add_submodule_import(
self.code_model.get_relative_import_path(serialize_namespace, imported_namespace),
"_serialization",
"serialization",
ImportType.LOCAL,
typing_section,
alias="_serialization",
)
else:
relative_path = self.code_model.get_relative_import_path(
serialize_namespace, imported_namespace, module_name="_serialization"
serialize_namespace, f"{self.code_model.namespace}._utils.serialization"
)
self.add_submodule_import(relative_path, "Serializer", ImportType.LOCAL, typing_section)
if msrest_import_type == MsrestImportType.SerializerDeserializer:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ def imports(self, async_mode: bool, **kwargs: Any) -> FileImport:
# but final call returns a model
serialize_namespace = kwargs.get("serialize_namespace", self.code_model.namespace)
file_import.add_submodule_import(
self.code_model.get_relative_import_path(serialize_namespace, module_name="_model_base"),
self.code_model.get_relative_import_path(serialize_namespace, module_name="_utils.model_base"),
"_deserialize",
ImportType.LOCAL,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -318,9 +318,10 @@ def imports(self, **kwargs: Any) -> FileImport:
)
if self.is_form_data:
file_import.add_submodule_import(
self.code_model.get_relative_import_path(serialize_namespace),
"_model_base",
self.code_model.get_relative_import_path(serialize_namespace, module_name="_utils.model_base"),
"Model",
ImportType.LOCAL,
alias="_Model",
)
elif serialize_namespace_type == NamespaceType.TYPES_FILE or (
serialize_namespace_type == NamespaceType.MODEL and called_by_property
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,9 @@ def imports( # pylint: disable=too-many-branches, disable=too-many-statements
ImportType.SDKCORE,
)
if not async_mode:
relative_path = self.code_model.get_relative_import_path(serialize_namespace, module_name="_vendor")
relative_path = self.code_model.get_relative_import_path(
serialize_namespace, module_name="_utils.utils"
)
file_import.add_submodule_import(
relative_path,
"prep_if_match",
Expand Down Expand Up @@ -436,12 +438,17 @@ def imports( # pylint: disable=too-many-branches, disable=too-many-statements
if self.overloads:
file_import.add_submodule_import("typing", "overload", ImportType.STDLIB)
if self.code_model.options["models_mode"] == "dpg":
relative_path = self.code_model.get_relative_import_path(serialize_namespace, module_name="_model_base")
relative_path = self.code_model.get_relative_import_path(
serialize_namespace, module_name="_utils.model_base"
)
body_param = self.parameters.body_parameter if self.parameters.has_body else None
if body_param and not isinstance(body_param.type, BinaryType):
if self.has_form_data_body:
file_import.add_submodule_import(
self.code_model.get_relative_import_path(serialize_namespace), "_model_base", ImportType.LOCAL
relative_path,
"Model",
ImportType.LOCAL,
alias="_Model",
)
elif xml_serializable(self.parameters.body_parameter.default_content_type):
file_import.add_submodule_import(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,11 @@ def has_non_abstract_operations(self) -> bool:
operation_group.has_non_abstract_operations for operation_group in self.operation_groups
)

@property
def base_class(self) -> str:
def base_class(self, async_mode: bool) -> str:
pipeline_client = f"{'Async' if async_mode else ''}PipelineClient"
base_classes: List[str] = []
if self.is_mixin:
base_classes.append(f"{self.client.name}MixinABC")
base_classes.append(f"ClientMixinABC[{pipeline_client}, {self.client.name}Configuration]")
return ", ".join(base_classes)

def imports_for_multiapi(self, async_mode: bool, **kwargs) -> FileImport:
Expand Down Expand Up @@ -100,8 +100,12 @@ def need_validation(self) -> bool:

def imports(self, async_mode: bool, **kwargs: Any) -> FileImport:
file_import = FileImport(self.code_model)

serialize_namespace = kwargs.get("serialize_namespace", self.code_model.namespace)
utils_path = self.code_model.get_relative_import_path(
serialize_namespace,
f"{self.code_model.namespace}._utils.utils",
)

for operation in self.operations:
file_import.merge(operation.imports(async_mode, **kwargs))
if not self.code_model.options["combine_operation_files"]:
Expand Down Expand Up @@ -141,32 +145,28 @@ def imports(self, async_mode: bool, **kwargs: Any) -> FileImport:
ImportType.LOCAL,
alias="_models",
)
file_import.add_submodule_import(
self.code_model.get_relative_import_path(
serialize_namespace,
self.code_model.get_imported_namespace_for_client(self.client.client_namespace, async_mode),
module_name="_configuration",
),
f"{self.client.name}Configuration",
ImportType.LOCAL,
)
file_import.add_submodule_import(
"" if self.code_model.is_azure_flavor else "runtime",
f"{'Async' if async_mode else ''}PipelineClient",
ImportType.SDKCORE,
)
if self.is_mixin:
file_import.add_submodule_import(
# XxxMixinABC is always defined in _vendor of client namespace
self.code_model.get_relative_import_path(
serialize_namespace,
self.code_model.get_imported_namespace_for_client(self.client.client_namespace, async_mode),
module_name="_vendor",
),
f"{self.client.name}MixinABC",
# XxxMixinABC is always defined in _utils of client namespace
utils_path,
"ClientMixinABC",
ImportType.LOCAL,
)
else:
file_import.add_submodule_import(
"" if self.code_model.is_azure_flavor else "runtime",
f"{'Async' if async_mode else ''}PipelineClient",
ImportType.SDKCORE,
)
file_import.add_submodule_import(
self.code_model.get_relative_import_path(
serialize_namespace,
self.code_model.get_imported_namespace_for_client(self.client.client_namespace, async_mode),
module_name="_configuration",
),
f"{self.client.name}Configuration",
ImportType.LOCAL,
)
file_import.add_msrest_import(
serialize_namespace=kwargs.get("serialize_namespace", self.code_model.namespace),
msrest_import_type=MsrestImportType.Serializer,
Expand All @@ -179,12 +179,8 @@ def imports(self, async_mode: bool, **kwargs: Any) -> FileImport:
)
if self.has_abstract_operations:
file_import.add_submodule_import(
# raise_if_not_implemented is always defined in _vendor of top namespace
self.code_model.get_relative_import_path(
serialize_namespace,
self.code_model.get_imported_namespace_for_client(self.code_model.namespace, async_mode),
module_name="_vendor",
),
# raise_if_not_implemented is always defined in _utils of top namespace
utils_path,
"raise_if_not_implemented",
ImportType.LOCAL,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,9 @@ def imports(self, async_mode: bool, **kwargs: Any) -> FileImport:
ImportType.SDKCORE,
)
if self.code_model.options["models_mode"] == "dpg":
relative_path = self.code_model.get_relative_import_path(serialize_namespace, module_name="_model_base")
relative_path = self.code_model.get_relative_import_path(
serialize_namespace, module_name="_utils.model_base"
)
file_import.merge(self.item_type.imports(**kwargs))
if self.default_error_deserialization or self.need_deserialize:
file_import.add_submodule_import(relative_path, "_deserialize", ImportType.LOCAL)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ def imports(self, async_mode: bool, **kwargs: Any) -> FileImport:
if self.is_form_data:
serialize_namespace = kwargs.get("serialize_namespace", self.code_model.namespace)
file_import.add_submodule_import(
self.code_model.get_relative_import_path(serialize_namespace, module_name="_vendor"),
self.code_model.get_relative_import_path(serialize_namespace, module_name="_utils.utils"),
"prepare_multipart_form_data",
ImportType.LOCAL,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -618,13 +618,13 @@ def type_annotation(self, **kwargs: Any) -> str:
return self.name

def docstring_type(self, **kwargs: Any) -> str:
return f"~{self.code_model.namespace}._vendor.{self.name}"
return f"~{self.code_model.namespace}._utils.utils.{self.name}"

def imports(self, **kwargs: Any) -> FileImport:
file_import = super().imports(**kwargs)
serialize_namespace = kwargs.get("serialize_namespace", self.code_model.namespace)
file_import.add_submodule_import(
self.code_model.get_relative_import_path(serialize_namespace, module_name="_vendor"),
self.code_model.get_relative_import_path(serialize_namespace, module_name="_utils.utils"),
self.name,
ImportType.LOCAL,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ def imports(self, **kwargs) -> FileImport:
if self.code_model.options["models_mode"] == "dpg":
serialize_namespace = kwargs.get("serialize_namespace", self.code_model.namespace)
file_import.add_submodule_import(
self.code_model.get_relative_import_path(serialize_namespace, module_name="_model_base"),
self.code_model.get_relative_import_path(serialize_namespace, module_name="_utils.model_base"),
"rest_discriminator" if self.is_discriminator else "rest_field",
ImportType.LOCAL,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ def serialize(self) -> None:
general_serializer.serialize_pkgutil_init_file(),
)

# _model_base.py/_serialization.py/_vendor.py/py.typed/_types.py/_validation.py
# _utils/py.typed/_types.py/_validation.py
# is always put in top level namespace
if self.code_model.is_top_namespace(client_namespace):
self._serialize_and_write_top_level_folder(env=env, namespace=client_namespace)
Expand Down Expand Up @@ -404,25 +404,41 @@ def _serialize_client_and_config_files(
general_serializer.serialize_config_file(clients),
)

# sometimes we need define additional Mixin class for client in _vendor.py
self._serialize_and_write_vendor_file(env, namespace)
# sometimes we need define additional Mixin class for client in _utils.py
self._serialize_and_write_utils_folder(env, namespace)

def _serialize_and_write_vendor_file(self, env: Environment, namespace: str) -> None:
def _serialize_and_write_utils_folder(self, env: Environment, namespace: str) -> None:
exec_path = self.exec_path(namespace)
# write _vendor.py
for async_mode, async_path in self.serialize_loop:
if self.code_model.need_vendored_code(async_mode=async_mode, client_namespace=namespace):
self.write_file(
exec_path / Path(f"{async_path}_vendor.py"),
GeneralSerializer(
code_model=self.code_model, env=env, async_mode=async_mode, client_namespace=namespace
).serialize_vendor_file(),
)
general_serializer = GeneralSerializer(code_model=self.code_model, env=env, async_mode=False)
utils_folder_path = exec_path / Path("_utils")
if self.code_model.need_utils_folder(async_mode=False, client_namespace=namespace):
self.write_file(
utils_folder_path / Path("__init__.py"),
self.code_model.license_header,
)
if self.code_model.need_utils_utils(async_mode=False, client_namespace=namespace):
self.write_file(
utils_folder_path / Path("utils.py"),
general_serializer.need_utils_utils_file(),
)
# write _utils/serialization.py
if self.code_model.need_utils_serialization:
self.write_file(
utils_folder_path / Path("serialization.py"),
general_serializer.serialize_serialization_file(),
)

# write _model_base.py
if self.code_model.options["models_mode"] == "dpg":
self.write_file(
utils_folder_path / Path("model_base.py"),
general_serializer.serialize_model_base_file(),
)

def _serialize_and_write_top_level_folder(self, env: Environment, namespace: str) -> None:
exec_path = self.exec_path(namespace)
# write _vendor.py
self._serialize_and_write_vendor_file(env, namespace)
# write _utils folder
self._serialize_and_write_utils_folder(env, namespace)

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

Expand All @@ -432,20 +448,6 @@ def _serialize_and_write_top_level_folder(self, env: Environment, namespace: str
# write the empty py.typed file
self.write_file(exec_path / Path("py.typed"), "# Marker file for PEP 561.")

# write _serialization.py
if not self.code_model.options["client_side_validation"] and not self.code_model.options["multiapi"]:
self.write_file(
exec_path / Path("_serialization.py"),
general_serializer.serialize_serialization_file(),
)

# write _model_base.py
if self.code_model.options["models_mode"] == "dpg":
self.write_file(
exec_path / Path("_model_base.py"),
general_serializer.serialize_model_base_file(),
)

# write _validation.py
if any(og for client in self.code_model.clients for og in client.operation_groups if og.need_validation):
self.write_file(
Expand Down
Loading
Loading