diff --git a/pynetbox/core/response.py b/pynetbox/core/response.py index 45b026c9..56b84cae 100644 --- a/pynetbox/core/response.py +++ b/pynetbox/core/response.py @@ -16,11 +16,6 @@ from pynetbox.core.query import Request from pynetbox.core.util import Hashabledict -# List of fields that contain a dict but are not to be converted into -# Record objects. -JSON_FIELDS = ( - "custom_fields", "data", "config_context", "object_data" -) # List of fields that are lists but should be treated as sets. LIST_AS_SET = ("tags", "tagged_vlans") @@ -61,6 +56,12 @@ def flatten_custom(custom_dict): } +class JsonField(object): + """Explicit field type for values that are not to be converted + to a Record object""" + _json_field = True + + class Record(object): """Create python objects from netbox API responses. @@ -235,25 +236,25 @@ def list_parser(list_item): return list_item for k, v in values.items(): + if isinstance(v, dict): + lookup = getattr(self.__class__, k, None) + if k == "custom_fields" or hasattr(lookup, "_json_field"): + self._add_cache((k, v.copy())) + setattr(self, k, v) + continue + if lookup: + v = lookup(v, self.api, self.endpoint) + else: + v = self.default_ret(v, self.api, self.endpoint) + self._add_cache((k, v)) - if k not in JSON_FIELDS: - if isinstance(v, dict): - lookup = getattr(self.__class__, k, None) - if lookup: - v = lookup(v, self.api, self.endpoint) - else: - v = self.default_ret(v, self.api, self.endpoint) - self._add_cache((k, v)) - - elif isinstance(v, list): - v = [list_parser(i) for i in v] - to_cache = list(v) - self._add_cache((k, to_cache)) + elif isinstance(v, list): + v = [list_parser(i) for i in v] + to_cache = list(v) + self._add_cache((k, to_cache)) - else: - self._add_cache((k, v)) else: - self._add_cache((k, v.copy())) + self._add_cache((k, v)) setattr(self, k, v) def _compare(self): diff --git a/pynetbox/models/dcim.py b/pynetbox/models/dcim.py index e151ce5e..9ceade2c 100644 --- a/pynetbox/models/dcim.py +++ b/pynetbox/models/dcim.py @@ -13,7 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. """ -from pynetbox.core.response import Record +from pynetbox.core.response import Record, JsonField from pynetbox.core.endpoint import RODetailEndpoint from pynetbox.models.ipam import IpAddresses from pynetbox.models.circuits import Circuits @@ -44,6 +44,8 @@ class Devices(Record): primary_ip = IpAddresses primary_ip4 = IpAddresses primary_ip6 = IpAddresses + local_context_data = JsonField + config_context = JsonField @property def napalm(self): diff --git a/pynetbox/models/extras.py b/pynetbox/models/extras.py index 6bf7f075..0848a704 100644 --- a/pynetbox/models/extras.py +++ b/pynetbox/models/extras.py @@ -13,9 +13,15 @@ See the License for the specific language governing permissions and limitations under the License. """ -from pynetbox.core.response import Record +from pynetbox.core.response import Record, JsonField + + +class ConfigContexts(Record): + data = JsonField class ObjectChanges(Record): + object_data = JsonField + def __str__(self): return self.request_id diff --git a/tests/fixtures/dcim/device.json b/tests/fixtures/dcim/device.json index 4320349c..b29fe44d 100644 --- a/tests/fixtures/dcim/device.json +++ b/tests/fixtures/dcim/device.json @@ -65,8 +65,11 @@ }, "primary_ip6": null, "comments": "", + "local_context_data": { + "testing": "test" + }, "custom_fields": {}, "config_context": { "test_key": "test_val" } -} \ No newline at end of file +} diff --git a/tests/test_dcim.py b/tests/test_dcim.py index c00e1d81..7aed9893 100644 --- a/tests/test_dcim.py +++ b/tests/test_dcim.py @@ -170,6 +170,7 @@ def test_get(self, mock): self.assertTrue(isinstance(ret.primary_ip4, pynetbox.models.ipam.IpAddresses)) self.assertTrue(isinstance(ret.config_context, dict)) self.assertTrue(isinstance(ret.custom_fields, dict)) + self.assertTrue(isinstance(ret.local_context_data, dict)) mock.assert_called_with( 'http://localhost:8000/api/{}/{}/1/'.format( self.app,