-
Notifications
You must be signed in to change notification settings - Fork 184
Open
Labels
severity: lowDoes not significantly disrupt application functionality, or a workaround is availableDoes not significantly disrupt application functionality, or a workaround is availablestatus: needs ownerThis issue is tentatively accepted pending a volunteer committed to its implementationThis issue is tentatively accepted pending a volunteer committed to its implementationtype: bugA confirmed report of unexpected behavior in the applicationA confirmed report of unexpected behavior in the application
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"
Metadata
Metadata
Assignees
Labels
severity: lowDoes not significantly disrupt application functionality, or a workaround is availableDoes not significantly disrupt application functionality, or a workaround is availablestatus: needs ownerThis issue is tentatively accepted pending a volunteer committed to its implementationThis issue is tentatively accepted pending a volunteer committed to its implementationtype: bugA confirmed report of unexpected behavior in the applicationA confirmed report of unexpected behavior in the application