Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Termination sub-attribute not found #223

Open
TitouanS31 opened this issue Jul 25, 2024 · 8 comments
Open

Termination sub-attribute not found #223

TitouanS31 opened this issue Jul 25, 2024 · 8 comments

Comments

@TitouanS31
Copy link

I found a bug by trying to get the name of a device at the end of a cable. Here is the cable trace from the Nautobot demo.

image

I wanted to get the device name lhr01-edge-01 from the cable 73a65bf1-333e-4a09-9023-e77e05487151 using the termination_a attribute. Here is the code I wrote to achieve this.

import pynautobot

nautobot = pynautobot.api(
    url="https://demo.nautobot.com",
    token="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
)

cable = nautobot.dcim.cables.get("73a65bf1-333e-4a09-9023-e77e05487151")

# print(cable.termination_a)
# cable.termination_a.full_details()
print(cable.termination_a.device.name)

I expected to get lhr01-edge-01 as output. I instead got the following exception.

Traceback (most recent call last):
  File "c:\Users\foo\Documents\misc\termination_bug.py", line 16, in <module>
    print(cable.termination_a.device.name)
AttributeError: type object 'Devices' has no attribute 'name'

The most surprising thing is that if I print the termination first, it works. I guess there is a full_details call missing since calling this method seems to be a workaround ; but I don't think that behaviour is intended.

Nautobot version: 2.2.8
Pynautobot version: 2.2.0

@tsm1th
Copy link
Contributor

tsm1th commented Jul 25, 2024

This and #222 will work if I remove lines 221 & 222 from the below code. I just need to do some further testing on why it's not doing the full_details call otherwise.

class Termination(Record):
def __str__(self):
# hacky check to see if we're a circuit termination to
# avoid another call to Nautobot because of a non-existent attr
# in self.name
if "circuit" in str(self.url):
return self.circuit.cid
return self.name
device = Devices
circuit = Circuits

@tsm1th
Copy link
Contributor

tsm1th commented Jul 25, 2024

Can you try the following to see if it solves your issue?

import pynautobot

nautobot = pynautobot.api(
    url="https://demo.nautobot.com",
    token="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
)

cable = nautobot.dcim.cables.get("73a65bf1-333e-4a09-9023-e77e05487151")

cable.termination_a #Incrementally accessing the endpoints (causes pynautobot to fetch the attributes)
print(cable.termination_a.device.name)

> 'lhr01-edge-01'

@TitouanS31
Copy link
Author

I have tested the 3 following options and None of them worked. It always raises the same error.

cable = nautobot.dcim.cables.get("73a65bf1-333e-4a09-9023-e77e05487151")

cable.termination_a
print(cable.termination_a.device.name)
cable = nautobot.dcim.cables.get("73a65bf1-333e-4a09-9023-e77e05487151")

termination_a = cable.termination_a
device = cable.termination_a.device
print(device.name)
cable = nautobot.dcim.cables.get("73a65bf1-333e-4a09-9023-e77e05487151")

termination_a = cable.termination_a
device = termination_a.device
print(device.name)

@tsm1th
Copy link
Contributor

tsm1th commented Jul 26, 2024

I am not able to recreate the same behavior on my side. Incrementally accessing the endpoint works on pynautobot==2.2.0 using the demo site. I only get the attribute error when attempting to access the full endpoint like shown in your original example.

image

@TitouanS31
Copy link
Author

I confirm it does not work on my side. I am not using the same Python version, mine is 3.10.11. Maybe that is the point.

@tsm1th
Copy link
Contributor

tsm1th commented Jul 26, 2024

Had a python 3.10.12 environment too, confirmed it worked there as well.

image

@TitouanS31
Copy link
Author

I have tried again to execute the following code and I found something interseting.

import pynautobot

nautobot = pynautobot.api(
    url="https://demo.nautobot.com",
    token="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
)

cable = nautobot.dcim.cables.get("73a65bf1-333e-4a09-9023-e77e05487151")

cable.termination_a
print(cable.termination_a.device.name)

The behaviour is not the same if I execute it as a script or if I use the interactive shell. Using a script the workaround does not work while it does in interactive mode. In the latter case, the termination is printed so I think the line cable.termination_a does the same as print(cable.termination_a), which works.

@tsm1th
Copy link
Contributor

tsm1th commented Aug 6, 2024

If I understand correctly, I think I was able to reproduce what you are seeing. It appears something needs to invoke the __str__ method of the cable_termination before pynautobot will fetch it's related objects.

The behavior I observed while running python in script mode instead of interactive:

# Behavior in script mode #

# Example1
print(cable.termination_a)
print(cable.termination_a.device.name)  # This works because I printed cable.termination_a first

# Example2
cable.termination_a
print(cable.termination_a.device.name)  # This does not not work

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants