diff --git a/sdk/core/azure-core/CHANGELOG.md b/sdk/core/azure-core/CHANGELOG.md index b8f7e4dbe1ff..063fa490ef4b 100644 --- a/sdk/core/azure-core/CHANGELOG.md +++ b/sdk/core/azure-core/CHANGELOG.md @@ -5,6 +5,7 @@ ### Features Added - Added a `start_time` keyword argument to the `start_span` and `start_as_current_span` methods in the `OpenTelemetryTracer` class. This allows users to specify a custom start time for created spans. #41106 +- Added `is_generated_model` method to `azure.core.serialization`. Returns whether a given input is a model from one of our generated sdks. #41445 ### Breaking Changes diff --git a/sdk/core/azure-core/azure/core/serialization.py b/sdk/core/azure-core/azure/core/serialization.py index 7991aca913be..59c0fb00f5c0 100644 --- a/sdk/core/azure-core/azure/core/serialization.py +++ b/sdk/core/azure-core/azure/core/serialization.py @@ -129,3 +129,14 @@ def default(self, o: Any) -> Any: except AttributeError: pass return super(AzureJSONEncoder, self).default(o) + + +def is_generated_model(obj: Any) -> bool: + """Check if the object is a generated SDK model. + + :param obj: The object to check. + :type obj: any + :return: True if the object is a generated SDK model, False otherwise. + :rtype: bool + """ + return bool(getattr(obj, "_is_model", False) or hasattr(obj, "_attribute_map")) diff --git a/sdk/core/azure-core/tests/test_serialization.py b/sdk/core/azure-core/tests/test_serialization.py index 30276c6a1d91..4cb81eba6620 100644 --- a/sdk/core/azure-core/tests/test_serialization.py +++ b/sdk/core/azure-core/tests/test_serialization.py @@ -8,7 +8,7 @@ import json import sys -from azure.core.serialization import AzureJSONEncoder, NULL +from azure.core.serialization import AzureJSONEncoder, NULL, is_generated_model import pytest from modeltest._utils.model_base import Model as HybridModel, rest_field from modeltest import models @@ -512,3 +512,45 @@ def test_readonly(): assert model.id == 1 assert model.as_dict() == {"id": 1} assert model.as_dict(exclude_readonly=True) == {} + + +def test_is_generated_model_with_hybrid_model(): + assert is_generated_model(HybridModel()) + assert is_generated_model(models.FlattenModel({"name": "wall-e", "properties": {"description": "a dog", "age": 2}})) + assert is_generated_model(models.ClientNamedPropertyModel(prop_client_name="wall-e")) + assert is_generated_model(models.ReadonlyModel()) + + +def test_is_generated_model_with_msrest_model(): + # Instead of importing msrest, we're just going to do a basic rendering of the msrest models + class MsrestModel(object): + _subtype_map = {} + _attribute_map = {} + _validation = {} + + def __init__(self, *args, **kwargs): + self.additional_properties = {} + + assert is_generated_model(MsrestModel()) + + class InstantiatedMsrestModel(MsrestModel): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.attr = "value" + + assert is_generated_model(InstantiatedMsrestModel()) + + +def test_is_generated_model_with_non_models(): + assert not is_generated_model({}) + assert not is_generated_model([]) + assert not is_generated_model("string") + assert not is_generated_model(42) + assert not is_generated_model(None) + assert not is_generated_model(object) + + class Model: + def __init__(self): + self.attr = "value" + + assert not is_generated_model(Model())