Open
Description
pynetbox version
v.7.4.1
NetBox version
v4.2.6
Python version
3.11
Steps to Reproduce
When doing isinstance-checks on a Record, there's a chance of re-hydration happening, with two unwanted effects:
- An unnecessary network call is made
- Any updates done on the Record is reset
For instance, the internal instance check of BaseModel of Pydantic, will perform a hasattr(instance, '__pydantic_decorators__')
on the Record, triggering Record.__getattr__
and thus a re-hydration.
Example:
import pynetbox
from pydantic import BaseModel
nb = pynetbox.api(...)
device = nb.dcim.devices.get(1) # Any object works
device.name = "New Name"
isinstance(device, BaseModel) # Will trigger network call and re-hydration/resetting of values
assert device.name != "New Name" # Local name update will have been reset
Expected Behavior
Local updates on the Record should persist after __getattr__ is called by overloaded instance checks. Furthermore, not doing a network call in this case would be preferable.
Specifically, I'm suggesting the following change to Record.__getattr__
.
def __getattr__(self, k):
if self.url:
if self.has_details is False and k != "keys" and not k.startswith("__"): # <---- Fix 1: No need for network calls for dunder attrs
if self.full_details():
ret = getattr(self, k, None)
if ret or hasattr(self, k):
return ret
raise AttributeError('object has no attribute "{}"'.format(k))
along with the following change to Record.full_details
def full_details(self):
if self.url:
req = Request(
base=self.url,
token=self.api.token,
http_session=self.api.http_session,
)
curr_updates = self.updates() # <---- Fix 2: Save current updates
self._parse_values(next(req.get()))
for k, v in curr_updates.items(): # <---- Fix 2: Restore
setattr(self, k, v) # <---- current updates
self.has_details = True
return True
return False
Observed Behavior
See code comments in "Steps to Reproduce"