Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 7 additions & 0 deletions .chronus/changes/python-discriminator-vartype-2026-10-7.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
changeKind: fix
packages:
- "@typespec/http-client-python"
---

Fix the `:vartype` docstring of constant enum values (such as discriminator properties on polymorphic subclasses) to reference the enum class instead of a non-existent module-level symbol named after the enum member.
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,9 @@ def docstring_type(self, **kwargs: Any) -> str:
client_namespace = self.enum_type.client_namespace
if self.code_model.options.get("generation-subdir"):
client_namespace += f".{self.code_model.options['generation-subdir']}"
enum_type_annotation = f"{client_namespace}.models.{self.name}"
# Reference the enum class, which is what the models module actually exports.
# The member name (e.g. ``MODEL_WEB_SUMMARIZATION``) is not a module-level symbol.
enum_type_annotation = f"{client_namespace}.models.{self.enum_type.name}"
return f"{type_annotation} or ~{enum_type_annotation}"

def get_json_template_representation(
Expand Down
40 changes: 40 additions & 0 deletions packages/http-client-python/tests/unit/test_typeddict.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
_qualify_shadowed_builtins,
)
from pygen.codegen.serializers.import_serializer import FileImportSerializer
from pygen.codegen.serializers.model_serializer import DpgModelSerializer
from pygen.codegen.serializers.unions_serializer import UnionsSerializer


Expand Down Expand Up @@ -756,6 +757,45 @@ def test_enum_value_dpg_imports_enums_module():
assert any("_enums" in module for module in modules)


def test_enum_value_docstring_type_references_enum_class():
"""The ``:vartype`` of a constant enum value (e.g. a discriminator) must reference the enum class.

The enum member name (``RED``) is not a symbol of the models module, so ``~<ns>.models.RED``
is an unresolvable Sphinx cross-reference; ``~<ns>.models.Color`` is the exported enum type.
"""
code_model = _make_code_model(models_mode="dpg")
enum_value = _make_enum_value(code_model)
namespace = enum_value.enum_type.client_namespace
assert enum_value.docstring_type() == f"str or ~{namespace}.models.Color"
assert enum_value.docstring_type() == enum_value.enum_type.docstring_type()


def test_enum_value_docstring_type_with_generation_subdir():
"""``generation-subdir`` is still honored when referencing the enum class."""
code_model = _make_code_model(models_mode="dpg")
code_model.options["generation-subdir"] = "_generated"
enum_value = _make_enum_value(code_model)
namespace = enum_value.enum_type.client_namespace
assert enum_value.docstring_type() == f"str or ~{namespace}._generated.models.Color"


def test_discriminator_vartype_references_enum_class():
"""A discriminator subclass's ``:vartype`` points at the discriminator enum, not the member name."""
code_model = _make_code_model(models_mode="dpg")
enum_value = _make_enum_value(
code_model, enum_name="ActivityRecordType", member_name="MODEL_WEB_SUMMARIZATION", value="modelWebSummarization"
)
prop = Property(
yaml_data={"wireName": "type", "clientName": "type", "optional": False, "isDiscriminator": True},
code_model=code_model,
type=enum_value,
)
namespace = enum_value.enum_type.client_namespace
vartype = DpgModelSerializer.variable_documentation_string(prop)[-1]
assert vartype == f":vartype type: str or ~{namespace}.models.ActivityRecordType"
assert "MODEL_WEB_SUMMARIZATION" not in vartype


# ---------- builtin-shadowing qualification (Literal-value false positives) ----------


Expand Down
Loading