@typespec/http-client-python 0.30.0-alpha.20260529.2 → 0.30.0-alpha.20260601.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/eng/scripts/setup/__pycache__/package_manager.cpython-311.pyc +0 -0
- package/eng/scripts/setup/__pycache__/venvtools.cpython-311.pyc +0 -0
- package/generator/build/lib/pygen/codegen/serializers/general_serializer.py +1 -0
- package/generator/build/lib/pygen/codegen/templates/utils.py.jinja2 +45 -8
- package/generator/component-detection-pip-report.json +1 -1
- package/generator/dist/pygen-0.1.0-py3-none-any.whl +0 -0
- package/generator/pygen/codegen/serializers/general_serializer.py +1 -0
- package/generator/pygen/codegen/templates/utils.py.jinja2 +45 -8
- package/package.json +1 -1
|
Binary file
|
|
Binary file
|
|
@@ -76,23 +76,60 @@ def serialize_multipart_data_entry(data_entry: Any) -> Any:
|
|
|
76
76
|
return json.dumps(data_entry, cls=SdkJSONEncoder, exclude_readonly=True)
|
|
77
77
|
return data_entry
|
|
78
78
|
|
|
79
|
+
def _normalize_multipart_file_entry(field_name: str, entry: Any, index: int) -> Any:
|
|
80
|
+
"""Ensure a multipart file entry carries a filename for Content-Disposition.
|
|
81
|
+
|
|
82
|
+
Servers distinguish file parts from plain form fields by the presence of
|
|
83
|
+
``filename=`` in the ``Content-Disposition`` header. When callers pass
|
|
84
|
+
bare bytes/str/IO the HTTP client omits the filename and the server may
|
|
85
|
+
reject the upload. This helper wraps bare values into a (filename, content)
|
|
86
|
+
tuple, deriving the name from IO.name when available.
|
|
87
|
+
|
|
88
|
+
:param str field_name: The multipart field name used as a filename fallback.
|
|
89
|
+
:param entry: The user-provided file entry (tuple, bytes, str, or IO).
|
|
90
|
+
:type entry: any
|
|
91
|
+
:param int index: The positional index of the entry within the field, used
|
|
92
|
+
to disambiguate fallback filenames when multiple entries are provided.
|
|
93
|
+
:return: Either the original tuple entry, or a ``(filename, content)`` tuple
|
|
94
|
+
wrapping the bare value.
|
|
95
|
+
:rtype: any
|
|
96
|
+
"""
|
|
97
|
+
if isinstance(entry, tuple):
|
|
98
|
+
return entry
|
|
99
|
+
filename: Optional[str] = None
|
|
100
|
+
name_attr = getattr(entry, "name", None)
|
|
101
|
+
if isinstance(name_attr, str) and name_attr:
|
|
102
|
+
filename = os.path.basename(name_attr)
|
|
103
|
+
if not filename:
|
|
104
|
+
filename = f"{field_name}_{index}" if index else field_name
|
|
105
|
+
|
|
106
|
+
# Return a 3-tuple with an explicit "application/octet-stream" content type.
|
|
107
|
+
# A 2-tuple (filename, content) would leave the part's Content-Type unset, and
|
|
108
|
+
# the sdk core library only defaults to "application/octet-stream" for bare
|
|
109
|
+
# (non-tuple) values - a tuple bypasses that default and falls back to the
|
|
110
|
+
# HTTP "text/plain" default instead. Setting it explicitly preserves the
|
|
111
|
+
# pre-existing behavior for bare bytes/IO across all transports.
|
|
112
|
+
return (filename, entry, "application/octet-stream")
|
|
113
|
+
|
|
79
114
|
def prepare_multipart_form_data(
|
|
80
115
|
body: Mapping[str, Any], multipart_fields: list[str], data_fields: list[str]
|
|
81
116
|
) -> list[FileType]:
|
|
82
117
|
files: list[FileType] = []
|
|
83
|
-
for multipart_field in multipart_fields:
|
|
84
|
-
multipart_entry = body.get(multipart_field)
|
|
85
|
-
if isinstance(multipart_entry, list):
|
|
86
|
-
files.extend([(multipart_field, e) for e in multipart_entry ])
|
|
87
|
-
elif multipart_entry:
|
|
88
|
-
files.append((multipart_field, multipart_entry))
|
|
89
118
|
|
|
90
|
-
#
|
|
91
|
-
#
|
|
119
|
+
# Data fields first so streaming server-side parsers see metadata before
|
|
120
|
+
# binary file parts.
|
|
92
121
|
for data_field in data_fields:
|
|
93
122
|
data_entry = body.get(data_field)
|
|
94
123
|
if data_entry:
|
|
95
124
|
files.append((data_field, str(serialize_multipart_data_entry(data_entry))))
|
|
96
125
|
|
|
126
|
+
for multipart_field in multipart_fields:
|
|
127
|
+
multipart_entry = body.get(multipart_field)
|
|
128
|
+
if isinstance(multipart_entry, list):
|
|
129
|
+
for idx, e in enumerate(multipart_entry):
|
|
130
|
+
files.append((multipart_field, _normalize_multipart_file_entry(multipart_field, e, idx)))
|
|
131
|
+
elif multipart_entry is not None:
|
|
132
|
+
files.append((multipart_field, _normalize_multipart_file_entry(multipart_field, multipart_entry, 0)))
|
|
133
|
+
|
|
97
134
|
return files
|
|
98
135
|
{% endif %}
|
|
Binary file
|
|
@@ -76,23 +76,60 @@ def serialize_multipart_data_entry(data_entry: Any) -> Any:
|
|
|
76
76
|
return json.dumps(data_entry, cls=SdkJSONEncoder, exclude_readonly=True)
|
|
77
77
|
return data_entry
|
|
78
78
|
|
|
79
|
+
def _normalize_multipart_file_entry(field_name: str, entry: Any, index: int) -> Any:
|
|
80
|
+
"""Ensure a multipart file entry carries a filename for Content-Disposition.
|
|
81
|
+
|
|
82
|
+
Servers distinguish file parts from plain form fields by the presence of
|
|
83
|
+
``filename=`` in the ``Content-Disposition`` header. When callers pass
|
|
84
|
+
bare bytes/str/IO the HTTP client omits the filename and the server may
|
|
85
|
+
reject the upload. This helper wraps bare values into a (filename, content)
|
|
86
|
+
tuple, deriving the name from IO.name when available.
|
|
87
|
+
|
|
88
|
+
:param str field_name: The multipart field name used as a filename fallback.
|
|
89
|
+
:param entry: The user-provided file entry (tuple, bytes, str, or IO).
|
|
90
|
+
:type entry: any
|
|
91
|
+
:param int index: The positional index of the entry within the field, used
|
|
92
|
+
to disambiguate fallback filenames when multiple entries are provided.
|
|
93
|
+
:return: Either the original tuple entry, or a ``(filename, content)`` tuple
|
|
94
|
+
wrapping the bare value.
|
|
95
|
+
:rtype: any
|
|
96
|
+
"""
|
|
97
|
+
if isinstance(entry, tuple):
|
|
98
|
+
return entry
|
|
99
|
+
filename: Optional[str] = None
|
|
100
|
+
name_attr = getattr(entry, "name", None)
|
|
101
|
+
if isinstance(name_attr, str) and name_attr:
|
|
102
|
+
filename = os.path.basename(name_attr)
|
|
103
|
+
if not filename:
|
|
104
|
+
filename = f"{field_name}_{index}" if index else field_name
|
|
105
|
+
|
|
106
|
+
# Return a 3-tuple with an explicit "application/octet-stream" content type.
|
|
107
|
+
# A 2-tuple (filename, content) would leave the part's Content-Type unset, and
|
|
108
|
+
# the sdk core library only defaults to "application/octet-stream" for bare
|
|
109
|
+
# (non-tuple) values - a tuple bypasses that default and falls back to the
|
|
110
|
+
# HTTP "text/plain" default instead. Setting it explicitly preserves the
|
|
111
|
+
# pre-existing behavior for bare bytes/IO across all transports.
|
|
112
|
+
return (filename, entry, "application/octet-stream")
|
|
113
|
+
|
|
79
114
|
def prepare_multipart_form_data(
|
|
80
115
|
body: Mapping[str, Any], multipart_fields: list[str], data_fields: list[str]
|
|
81
116
|
) -> list[FileType]:
|
|
82
117
|
files: list[FileType] = []
|
|
83
|
-
for multipart_field in multipart_fields:
|
|
84
|
-
multipart_entry = body.get(multipart_field)
|
|
85
|
-
if isinstance(multipart_entry, list):
|
|
86
|
-
files.extend([(multipart_field, e) for e in multipart_entry ])
|
|
87
|
-
elif multipart_entry:
|
|
88
|
-
files.append((multipart_field, multipart_entry))
|
|
89
118
|
|
|
90
|
-
#
|
|
91
|
-
#
|
|
119
|
+
# Data fields first so streaming server-side parsers see metadata before
|
|
120
|
+
# binary file parts.
|
|
92
121
|
for data_field in data_fields:
|
|
93
122
|
data_entry = body.get(data_field)
|
|
94
123
|
if data_entry:
|
|
95
124
|
files.append((data_field, str(serialize_multipart_data_entry(data_entry))))
|
|
96
125
|
|
|
126
|
+
for multipart_field in multipart_fields:
|
|
127
|
+
multipart_entry = body.get(multipart_field)
|
|
128
|
+
if isinstance(multipart_entry, list):
|
|
129
|
+
for idx, e in enumerate(multipart_entry):
|
|
130
|
+
files.append((multipart_field, _normalize_multipart_file_entry(multipart_field, e, idx)))
|
|
131
|
+
elif multipart_entry is not None:
|
|
132
|
+
files.append((multipart_field, _normalize_multipart_file_entry(multipart_field, multipart_entry, 0)))
|
|
133
|
+
|
|
97
134
|
return files
|
|
98
135
|
{% endif %}
|
package/package.json
CHANGED