codecov-io: # [Codecov](https://codecov.io/gh/Azure/msrest-for-python/pull/198?src=pr&el=h1) Report
> Merging [#198](https://codecov.io/gh/Azure/msrest-for-python/pull/198?src=pr&el=desc) into [master](https://codecov.io/gh/Azure/msrest-for-python/commit/df4cea0e45976951700e21d5c192da372754443c&el=desc) will **decrease** coverage by `0.29%`.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/Azure/msrest-for-python/pull/198/graphs/tree.svg?width=650&height=150&src=pr&token=Lny6ZO1MUF)](https://codecov.io/gh/Azure/msrest-for-python/pull/198?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master     #198      +/-   ##
==========================================
- Coverage   87.64%   87.34%   -0.30%     
==========================================
  Files          25       25              
  Lines        2638     2640       +2     
==========================================
- Hits         2312     2306       -6     
- Misses        326      334       +8     
```


| [Impacted Files](https://codecov.io/gh/Azure/msrest-for-python/pull/198?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [msrest/serialization.py](https://codecov.io/gh/Azure/msrest-for-python/pull/198/diff?src=pr&el=tree#diff-bXNyZXN0L3NlcmlhbGl6YXRpb24ucHk=) | `91.06% <100.00%> (-0.19%)` | :arrow_down: |
| [msrest/async\_client.py](https://codecov.io/gh/Azure/msrest-for-python/pull/198/diff?src=pr&el=tree#diff-bXNyZXN0L2FzeW5jX2NsaWVudC5weQ==) | `77.27% <0.00%> (-6.82%)` | :arrow_down: |
| [msrest/exceptions.py](https://codecov.io/gh/Azure/msrest-for-python/pull/198/diff?src=pr&el=tree#diff-bXNyZXN0L2V4Y2VwdGlvbnMucHk=) | `97.46% <0.00%> (-1.27%)` | :arrow_down: |
| [msrest/pipeline/universal.py](https://codecov.io/gh/Azure/msrest-for-python/pull/198/diff?src=pr&el=tree#diff-bXNyZXN0L3BpcGVsaW5lL3VuaXZlcnNhbC5weQ==) | `94.11% <0.00%> (-0.99%)` | :arrow_down: |
| [msrest/universal\_http/requests.py](https://codecov.io/gh/Azure/msrest-for-python/pull/198/diff?src=pr&el=tree#diff-bXNyZXN0L3VuaXZlcnNhbF9odHRwL3JlcXVlc3RzLnB5) | `84.65% <0.00%> (-0.53%)` | :arrow_down: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/Azure/msrest-for-python/pull/198?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/Azure/msrest-for-python/pull/198?src=pr&el=footer). Last update [df4cea0...fe9b944](https://codecov.io/gh/Azure/msrest-for-python/pull/198?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

diff --git a/msrest/serialization.py b/msrest/serialization.py
index 27fb7e9..59187e1 100644
--- a/msrest/serialization.py
+++ b/msrest/serialization.py
@@ -1108,6 +1108,11 @@ def rest_key_extractor(attr, attr_desc, data):
             break
         working_key = _decode_attribute_map_key(dict_keys[0])
         working_data = working_data.get(working_key, data)
+        if working_data is None:
+            # If at any point while following flatten JSON path see None, it means
+            # that all properties under are None as well
+            # https://github.com/Azure/msrest-for-python/issues/197
+            return None
         key = '.'.join(dict_keys[1:])
 
     return working_data.get(key)
@@ -1123,6 +1128,11 @@ def rest_key_case_insensitive_extractor(attr, attr_desc, data):
             break
         working_key = _decode_attribute_map_key(dict_keys[0])
         working_data = attribute_key_case_insensitive_extractor(working_key, None, working_data)
+        if working_data is None:
+            # If at any point while following flatten JSON path see None, it means
+            # that all properties under are None as well
+            # https://github.com/Azure/msrest-for-python/issues/197
+            return None
         key = '.'.join(dict_keys[1:])
 
     if working_data:

Error when serializing flattened properties with null value as the container object
i found the msrest will report error when serializing flattened properties with null value as the container object, could you help to check? I tried to look at the msrest code, and seems the situation when 'data' is null is not handled in the last screenshot below. thanks.
![image](https://user-images.githubusercontent.com/6038235/78621314-e6cf1980-78b4-11ea-9316-58bee4dbbb38.png)
![image](https://user-images.githubusercontent.com/6038235/78621324-ef275480-78b4-11ea-94b3-29b6350b7218.png)
![image](https://user-images.githubusercontent.com/6038235/78621335-f64e6280-78b4-11ea-972b-b062f01efeab.png)

diff --git a/tests/test_serialization.py b/tests/test_serialization.py
index 4b3f537..12a0042 100644
--- a/tests/test_serialization.py
+++ b/tests/test_serialization.py
@@ -1527,6 +1527,46 @@ class TestRuntimeDeserialized(unittest.TestCase):
         obj = TestObj.from_dict({'name': 'ab'})
         self.assertEqual('ab', obj.name)
 
+    def test_deserialize_flattening(self):
+        # https://github.com/Azure/msrest-for-python/issues/197
+
+        json_body = {
+            "properties" : {
+                "properties": None
+            }
+        }
+
+        class ComputeResource(Model):
+
+            _attribute_map = {
+                'properties': {'key': 'properties', 'type': 'VirtualMachine'},
+            }
+
+            def __init__(self, properties=None, **kwargs):
+                self.properties = properties
+
+        class VirtualMachine(Model):
+
+            _attribute_map = {
+                'virtual_machine_size': {'key': 'properties.virtualMachineSize', 'type': 'str'},
+                'ssh_port': {'key': 'properties.sshPort', 'type': 'int'},
+                'address': {'key': 'properties.address', 'type': 'str'},
+                'administrator_account': {'key': 'properties.administratorAccount', 'type': 'VirtualMachineSshCredentials'},
+            }
+
+            def __init__(self, **kwargs):
+                super(VirtualMachine, self).__init__(**kwargs)
+                self.virtual_machine_size = kwargs.get('virtual_machine_size', None)
+                self.ssh_port = kwargs.get('ssh_port', None)
+                self.address = kwargs.get('address', None)
+                self.administrator_account = kwargs.get('administrator_account', None)
+
+        d = Deserializer({
+            'ComputeResource': ComputeResource,
+            'VirtualMachine': VirtualMachine,
+        })
+        response = d(ComputeResource, json.dumps(json_body), 'application/json')
+
     def test_deserialize_storage(self):
         StorageAccount = storage_models.StorageAccount
 

pip install -e .[dev]
parse_log_pytest
requirements.txt
pytest pytest-cov pytest-asyncio
apt-get update apt-get install -y libunwind8-dev
3.9
requirements.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
certifi==2025.1.31
charset-normalizer==3.4.1
coverage==7.8.0
exceptiongroup==1.2.2
idna==3.10
iniconfig==2.1.0
isodate==0.7.2
-e git+https://github.com/Azure/msrest-for-python.git@df4cea0e45976951700e21d5c192da372754443c#egg=msrest
oauthlib==3.2.2
packaging==24.2
pluggy==1.5.0
pytest==8.3.5
pytest-asyncio==0.26.0
pytest-cov==6.0.0
requests==2.32.3
requests-oauthlib==2.0.0
tomli==2.2.1
typing_extensions==4.13.0
urllib3==2.3.0

name: msrest-for-python
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - pip=25.0=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tzdata=2025a=h04d1e81_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - certifi==2025.1.31
      - charset-normalizer==3.4.1
      - coverage==7.8.0
      - exceptiongroup==1.2.2
      - idna==3.10
      - iniconfig==2.1.0
      - isodate==0.7.2
      - oauthlib==3.2.2
      - packaging==24.2
      - pluggy==1.5.0
      - pytest==8.3.5
      - pytest-asyncio==0.26.0
      - pytest-cov==6.0.0
      - requests==2.32.3
      - requests-oauthlib==2.0.0
      - tomli==2.2.1
      - typing-extensions==4.13.0
      - urllib3==2.3.0
prefix: /opt/conda/envs/msrest-for-python

tests/test_serialization.py::TestRuntimeDeserialized::test_deserialize_flattening
tests/test_serialization.py::TestModelDeserialization::test_empty_enum_logs tests/test_serialization.py::TestModelDeserialization::test_model_kwargs tests/test_serialization.py::TestModelDeserialization::test_model_kwargs_logs tests/test_serialization.py::TestModelDeserialization::test_response tests/test_serialization.py::TestRuntimeSerialized::test_additional_properties tests/test_serialization.py::TestRuntimeSerialized::test_additional_properties_declared tests/test_serialization.py::TestRuntimeSerialized::test_additional_properties_manual tests/test_serialization.py::TestRuntimeSerialized::test_additional_properties_no_send tests/test_serialization.py::TestRuntimeSerialized::test_additional_properties_with_auto_model tests/test_serialization.py::TestRuntimeSerialized::test_attr_bool tests/test_serialization.py::TestRuntimeSerialized::test_attr_dict_simple tests/test_serialization.py::TestRuntimeSerialized::test_attr_duration tests/test_serialization.py::TestRuntimeSerialized::test_attr_enum tests/test_serialization.py::TestRuntimeSerialized::test_attr_int tests/test_serialization.py::TestRuntimeSerialized::test_attr_list_complex tests/test_serialization.py::TestRuntimeSerialized::test_attr_list_simple tests/test_serialization.py::TestRuntimeSerialized::test_attr_none tests/test_serialization.py::TestRuntimeSerialized::test_attr_sequence tests/test_serialization.py::TestRuntimeSerialized::test_attr_str tests/test_serialization.py::TestRuntimeSerialized::test_empty_list tests/test_serialization.py::TestRuntimeSerialized::test_json_with_xml_map tests/test_serialization.py::TestRuntimeSerialized::test_key_type tests/test_serialization.py::TestRuntimeSerialized::test_long_as_type_object tests/test_serialization.py::TestRuntimeSerialized::test_model_validate tests/test_serialization.py::TestRuntimeSerialized::test_obj_serialize_none tests/test_serialization.py::TestRuntimeSerialized::test_obj_with_malformed_map tests/test_serialization.py::TestRuntimeSerialized::test_obj_with_mismatched_map tests/test_serialization.py::TestRuntimeSerialized::test_polymorphic_serialization tests/test_serialization.py::TestRuntimeSerialized::test_serialize_datetime tests/test_serialization.py::TestRuntimeSerialized::test_serialize_direct_model tests/test_serialization.py::TestRuntimeSerialized::test_serialize_empty_iter tests/test_serialization.py::TestRuntimeSerialized::test_serialize_from_dict_datetime tests/test_serialization.py::TestRuntimeSerialized::test_serialize_int_as_iter_with_div tests/test_serialization.py::TestRuntimeSerialized::test_serialize_json_obj tests/test_serialization.py::TestRuntimeSerialized::test_serialize_object tests/test_serialization.py::TestRuntimeSerialized::test_serialize_primitive_types tests/test_serialization.py::TestRuntimeSerialized::test_serialize_query tests/test_serialization.py::TestRuntimeSerialized::test_serialize_str_as_iter tests/test_serialization.py::TestRuntimeSerialized::test_serialize_time tests/test_serialization.py::TestRuntimeSerialized::test_validate tests/test_serialization.py::TestRuntimeSerialized::test_validation_flag tests/test_serialization.py::TestRuntimeSerialized::test_validation_type tests/test_serialization.py::TestRuntimeDeserialized::test_additional_properties tests/test_serialization.py::TestRuntimeDeserialized::test_additional_properties_declared tests/test_serialization.py::TestRuntimeDeserialized::test_additional_properties_flattening tests/test_serialization.py::TestRuntimeDeserialized::test_additional_properties_not_configured tests/test_serialization.py::TestRuntimeDeserialized::test_array_deserialize tests/test_serialization.py::TestRuntimeDeserialized::test_attr_bool tests/test_serialization.py::TestRuntimeDeserialized::test_attr_enum tests/test_serialization.py::TestRuntimeDeserialized::test_attr_int tests/test_serialization.py::TestRuntimeDeserialized::test_attr_list_complex tests/test_serialization.py::TestRuntimeDeserialized::test_attr_list_in_list tests/test_serialization.py::TestRuntimeDeserialized::test_attr_list_simple tests/test_serialization.py::TestRuntimeDeserialized::test_attr_none tests/test_serialization.py::TestRuntimeDeserialized::test_attr_str tests/test_serialization.py::TestRuntimeDeserialized::test_basic_deserialization tests/test_serialization.py::TestRuntimeDeserialized::test_cls_method_deserialization tests/test_serialization.py::TestRuntimeDeserialized::test_deserialize_date tests/test_serialization.py::TestRuntimeDeserialized::test_deserialize_datetime tests/test_serialization.py::TestRuntimeDeserialized::test_deserialize_object tests/test_serialization.py::TestRuntimeDeserialized::test_deserialize_storage tests/test_serialization.py::TestRuntimeDeserialized::test_deserialize_time tests/test_serialization.py::TestRuntimeDeserialized::test_invalid_json tests/test_serialization.py::TestRuntimeDeserialized::test_long_as_type_object tests/test_serialization.py::TestRuntimeDeserialized::test_non_obj_deserialization tests/test_serialization.py::TestRuntimeDeserialized::test_obj_with_malformed_map tests/test_serialization.py::TestRuntimeDeserialized::test_obj_with_no_attr tests/test_serialization.py::TestRuntimeDeserialized::test_personalize_deserialization tests/test_serialization.py::TestRuntimeDeserialized::test_polymorphic_deserialization tests/test_serialization.py::TestRuntimeDeserialized::test_polymorphic_deserialization_with_escape tests/test_serialization.py::TestRuntimeDeserialized::test_polymorphic_missing_info tests/test_serialization.py::TestRuntimeDeserialized::test_robust_deserialization tests/test_serialization.py::TestModelInstanceEquality::test_model_instance_equality
msrest/serialization.py
msrest/serialization.py