Skip to content

typespec-python emitter generates empty class for Record<string> inside MergePatchUpdate<T> #3358

@yungshinlintw

Description

@yungshinlintw

Bug Description

When a TypeSpec model containing a Record<string> property is wrapped with MergePatchUpdate<T>, the Python emitter generates an empty, unusable class RecordMergePatchUpdate instead of emitting Dict[str, str].

TypeSpec Source

The ContentUnderstandingDefaults model has a Record<string> property:

model ContentUnderstandingDefaults {
  modelDeployments: Record<string>;
}

This model is used in an operation via MergePatchUpdate<T>:

updateDefaults is Foundations.Operation<
  MergePatchUpdate<ContentUnderstandingDefaults>,
  ContentUnderstandingDefaults,
  ServiceTraits
>;

Generated Code (Broken)

The emitter generates an empty class with no properties, constructor, or dict-like behavior:

class RecordMergePatchUpdate(_Model):
    """RecordMergePatchUpdate."""

This type is then used in the generated update_defaults operation signature:

def update_defaults(
    self,
    model_deployments: Optional[RecordMergePatchUpdate] = None,
    ...
)

User Impact

Users cannot pass a dictionary to model_deployments. The empty class has no way to set key-value pairs, making the update_defaults API effectively broken without a workaround.

Contrast: Same Record<string> Works Correctly Elsewhere

The same Record<string> type on ContentUnderstandingDefaults (the response model, not the merge-patch input) generates correctly as dict[str, str]:

class ContentUnderstandingDefaults(_Model):
    model_deployments: dict[str, str] = rest_field(name="modelDeployments", ...)

Other Record<string> properties (e.g., tags on ContentAnalyzer) also generate correctly as dict[str, str]. The issue is specifically triggered when MergePatchUpdate<T> wraps a model containing Record<string>.

Our Workaround

We patched it in _patch.py by aliasing the empty class to Dict[str, str] and monkey-patching it onto the models module at runtime:

# _patch.py
RecordMergePatchUpdate = Dict[str, str]

def patch_sdk():
    from . import _models
    _models.RecordMergePatchUpdate = RecordMergePatchUpdate

Expected Behavior

The emitter should either:

  1. Generate RecordMergePatchUpdate as a type alias for Dict[str, str], or
  2. Inline the Record<string> property on the merge-patch model as dict[str, str] (same as it does for the non-patch model)

Metadata

Metadata

Assignees

Labels

needs-author-feedbackWorkflow: More information is needed from author to address the issue.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions