Skip to content
Merged
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
45 changes: 45 additions & 0 deletions doc/dev/mgmt/hybrid_model_migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ When migrating to the hybrid model design, expect these breaking changes:
| [Additional Properties](#additional-properties-handling) | `additional_properties` parameter removed | Use direct dictionary syntax: `model["key"] = value` |
| [String Representation](#string-representation-matches-rest-api) | Model key output changed from `snake_case` to `camelCase` | Update any code parsing model strings to expect `camelCase` |
| [Serialization/Deserialization](#serialization-and-deserialization-methods-removed) | `serialize` and `deserialize` methods removed | Use dictionary access for serialization, constructor for deserialization |
| [Reserved Property Names](#reserved-property-name-conflicts) | Conflicting names suffixed with `_property` | Update code to use `_property` suffix: `model.keys``model.keys_property` |

## Detailed Breaking Changes

Expand Down Expand Up @@ -273,6 +274,50 @@ serialized_dict = as_attribute_dict(model, exclude_readonly=False)
serialized_dict = as_attribute_dict(model, exclude_readonly=True)
```

### Reserved Property Name Conflicts

**What changed**: Hybrid models now inherit from Python's built-in `dict`. If a REST API property name collides with a `dict` method name (e.g. `keys`, `values`, `items`, `clear`, `update`, `get`, `pop`, `popitem`, `setdefault`, `copy`), the Python emitter appends `_property` to the generated attribute to avoid masking the dictionary method.

**What will break**:

- Constructor calls that pass reserved names as keyword arguments: `Model(keys=...)` will now pass the argument to the underlying `dict` constructor, which means the property value will not be set as expected and may result in a `TypeError` or unexpected behavior.
- Attribute access expecting the property value: `model.keys` now refers to the method; calling it without parentheses will not return the property data.

**Before**:

```python
from azure.mgmt.test.models import Model

model = Model(keys={"a": 1}, values=[1, 2, 3])
print(model.keys) # Property value (old behavior)
print(model.values) # Property value (old behavior)
print(model.as_dict()["keys"]) # REST layer value
```

**After**:

```python
from azure.mgmt.test.models import Model

# Reserved property names receive a `_property` suffix
model = Model(keys_property={"a": 1}, values_property=[1, 2, 3])

print(model.keys_property) # ✅ Property value
print(model.values_property) # ✅ Property value
print(model["keys"]) # REST layer value

# names without suffix are now dict methods
print(list(model.keys())) # ✅ Dict method listing all keys in the model
print(list(model.values())) # ✅ Dict method listing all values
```

**Migration steps:**

1. Search for any usage of reserved names as constructor keywords or attribute accesses.
2. Append `_property` to both initialization and attribute access: `Model(keys=...)``Model(keys_property=...)`; `model.keys``model.keys_property`.
3. Update tests and documentation references accordingly.
4. If you had dynamic code relying on `getattr(model, name)`, ensure you add a rule to transform reserved names to `name + "_property"` first.

---

## Additional Helper Methods
Expand Down
Loading