@typespec/http-client-python 0.34.0 → 0.34.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.
Files changed (36) hide show
  1. package/README.md +25 -3
  2. package/dist/emitter/emitter.d.ts.map +1 -1
  3. package/dist/emitter/emitter.js +2 -11
  4. package/dist/emitter/emitter.js.map +1 -1
  5. package/dist/emitter/external-process.d.ts +14 -0
  6. package/dist/emitter/external-process.d.ts.map +1 -1
  7. package/dist/emitter/external-process.js +17 -1
  8. package/dist/emitter/external-process.js.map +1 -1
  9. package/dist/emitter/lib.js +1 -1
  10. package/dist/emitter/lib.js.map +1 -1
  11. package/dist/emitter/node-runner.d.ts.map +1 -1
  12. package/dist/emitter/node-runner.js +2 -1
  13. package/dist/emitter/node-runner.js.map +1 -1
  14. package/dist/emitter/utils.d.ts +10 -0
  15. package/dist/emitter/utils.d.ts.map +1 -1
  16. package/dist/emitter/utils.js +12 -0
  17. package/dist/emitter/utils.js.map +1 -1
  18. package/emitter/src/emitter.ts +2 -14
  19. package/emitter/src/external-process.ts +18 -1
  20. package/emitter/src/lib.ts +1 -1
  21. package/emitter/src/node-runner.ts +2 -1
  22. package/emitter/src/utils.ts +13 -0
  23. package/emitter/temp/tsconfig.tsbuildinfo +1 -1
  24. package/emitter/test/external-process.test.ts +28 -0
  25. package/emitter/test/utils.test.ts +12 -1
  26. package/eng/scripts/setup/__pycache__/package_manager.cpython-311.pyc +0 -0
  27. package/eng/scripts/setup/__pycache__/venvtools.cpython-311.pyc +0 -0
  28. package/generator/build/lib/pygen/codegen/models/model_type.py +4 -0
  29. package/generator/build/lib/pygen/codegen/serializers/types_serializer.py +105 -12
  30. package/generator/build/lib/pygen/preprocess/__init__.py +55 -17
  31. package/generator/component-detection-pip-report.json +9 -9
  32. package/generator/dist/pygen-0.1.0-py3-none-any.whl +0 -0
  33. package/generator/pygen/codegen/models/model_type.py +4 -0
  34. package/generator/pygen/codegen/serializers/types_serializer.py +105 -12
  35. package/generator/pygen/preprocess/__init__.py +55 -17
  36. package/package.json +1 -1
@@ -307,8 +307,18 @@ class PreProcessPlugin(YamlUpdatePlugin):
307
307
  return self.options.get("tsp_file", False)
308
308
 
309
309
  @staticmethod
310
- def _find_existing_typeddict(code_model: dict[str, Any], cross_lang_id: Optional[str]) -> Optional[dict[str, Any]]:
311
- """Find an existing typeddict copy with the given crossLanguageDefinitionId."""
310
+ def _find_existing_typeddict(
311
+ code_model: dict[str, Any],
312
+ cross_lang_id: Optional[str],
313
+ name: Optional[str] = None,
314
+ ) -> Optional[dict[str, Any]]:
315
+ """Find an existing typeddict copy for the given model.
316
+
317
+ Matches on both ``crossLanguageDefinitionId`` and ``name``. The name is required because
318
+ template-instantiated models (e.g. ``ResourceUpdateModel<Foo, FooProperties>``) all share
319
+ the template's cross-language id, so matching on the id alone would reuse one model's copy
320
+ (e.g. ``CacheUpdate``) for a different model (e.g. ``VolumeUpdate``).
321
+ """
312
322
  if not cross_lang_id:
313
323
  return None
314
324
  return next(
@@ -318,10 +328,50 @@ class PreProcessPlugin(YamlUpdatePlugin):
318
328
  if t.get("type") == "model"
319
329
  and t.get("base") == "typeddict"
320
330
  and t.get("crossLanguageDefinitionId") == cross_lang_id
331
+ and (name is None or t.get("name") == name)
321
332
  ),
322
333
  None,
323
334
  )
324
335
 
336
+ @staticmethod
337
+ def _find_spread_original(code_model: dict[str, Any], json_model: dict[str, Any]) -> Optional[dict[str, Any]]:
338
+ """Recover the dpg model that a spread (json) body was cloned from.
339
+
340
+ When a spread body type is also used elsewhere, the emitter clones it, renames the clone to
341
+ ``<Method>Request`` and sets ``base = "json"`` while keeping the original
342
+ ``crossLanguageDefinitionId``. To reference the real model's TypedDict we look the clone up
343
+ by that id.
344
+
345
+ Distinct template-instantiated models share a single ``crossLanguageDefinitionId``, so an id
346
+ match alone is ambiguous. We only reuse an original when the choice is unambiguous:
347
+
348
+ * a dpg candidate whose ``name`` equals the json model's name (the body was not renamed), or
349
+ * exactly one dpg candidate carries the id.
350
+
351
+ Otherwise we return ``None`` so the caller falls back to the json model itself, avoiding a
352
+ reference to the wrong model's TypedDict.
353
+ """
354
+ cross_lang_id = json_model.get("crossLanguageDefinitionId")
355
+ if not cross_lang_id:
356
+ return None
357
+ candidates = [
358
+ t
359
+ for t in code_model["types"]
360
+ if t.get("type") == "model"
361
+ and t.get("base") == "dpg"
362
+ and t.get("crossLanguageDefinitionId") == cross_lang_id
363
+ and t is not json_model
364
+ ]
365
+ if not candidates:
366
+ return None
367
+ name = json_model.get("name")
368
+ for candidate in candidates:
369
+ if candidate.get("name") == name:
370
+ return candidate
371
+ if len(candidates) == 1:
372
+ return candidates[0]
373
+ return None
374
+
325
375
  @staticmethod
326
376
  def _insert_typeddict_overload(
327
377
  code_model: dict[str, Any],
@@ -376,25 +426,14 @@ class PreProcessPlugin(YamlUpdatePlugin):
376
426
  # Add typeddict overload for non-spread dpg models
377
427
  if self.options["models-mode"] == "dpg" and is_dpg_model:
378
428
  cross_lang_id = model_type.get("crossLanguageDefinitionId")
379
- existing_td = self._find_existing_typeddict(code_model, cross_lang_id)
429
+ existing_td = self._find_existing_typeddict(code_model, cross_lang_id, model_type.get("name"))
380
430
  self._insert_typeddict_overload(code_model, body_parameter, model_type, origin_type, existing_td)
381
431
 
382
432
  # For spread bodies (json base), add a typeddict overload that references
383
433
  # the original model. This replaces the JSON single-body overload.
384
434
  if is_json_model:
385
435
  cross_lang_id = model_type.get("crossLanguageDefinitionId")
386
- original = None
387
- if cross_lang_id:
388
- original = next(
389
- (
390
- t
391
- for t in code_model["types"]
392
- if t.get("type") == "model"
393
- and t.get("crossLanguageDefinitionId") == cross_lang_id
394
- and t is not model_type
395
- ),
396
- None,
397
- )
436
+ original = self._find_spread_original(code_model, model_type)
398
437
 
399
438
  if is_typeddict_only and original:
400
439
  # In typeddict-only mode, the original dpg model already renders
@@ -407,7 +446,7 @@ class PreProcessPlugin(YamlUpdatePlugin):
407
446
  body_parameter["type"]["types"].insert(1, td_list_or_dict)
408
447
  else:
409
448
  source = original or model_type
410
- existing_td = self._find_existing_typeddict(code_model, cross_lang_id)
449
+ existing_td = self._find_existing_typeddict(code_model, cross_lang_id, source.get("name"))
411
450
  self._insert_typeddict_overload(code_model, body_parameter, source, origin_type, existing_td)
412
451
 
413
452
  if len(body_parameter["type"]["types"]) == 1:
@@ -420,7 +459,6 @@ class PreProcessPlugin(YamlUpdatePlugin):
420
459
 
421
460
  code_model["types"].append(body_parameter["type"])
422
461
 
423
-
424
462
  def pad_reserved_words(self, name: str, pad_type: PadType, yaml_type: dict[str, Any]) -> str:
425
463
  # we want to pad hidden variables as well
426
464
  if not name:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@typespec/http-client-python",
3
- "version": "0.34.0",
3
+ "version": "0.34.1",
4
4
  "author": "Microsoft Corporation",
5
5
  "description": "TypeSpec emitter for Python SDKs",
6
6
  "homepage": "https://typespec.io",