I'm trying to enumerate some EC2 instance details in an AWS account using the boto3 Python module, but I keep getting an unexpected error. Specifically, I'm trying to get the tags associated with each instance. Here is a rough copy of my code:
#!/usr/bin/python3
import boto3
import botocore
boto3_session = create_boto3_session(profile_name='some_profile')
ec2_resource = boto3_session.resource("ec2", region_name='some_region')
ec2_instances = ec2_resource.instances.all()
for ec2_instance in ec2_instances:
tags = getattr(ec2_instance, 'tags', [])
for tag in tags:
print(tag)
When the code runs, it prints the tags of the instances as expected - until it finds an instance without tags, and then I get the error:
for tag in tags:
TypeError: 'NoneType' object is not iterable
What I don't understand is why the getattr() function returns a 'NoneType', instead of an empty list like I've asked it to. Am I missing something?
CodePudding user response:
I think I've found the answer. It's not specific to boto3.
When you call getattr() on an object, it only seems to return a supplied, default value if the class doesn't have a __getattr__() method implemented. If it does have that method, then it will return the value specified in __getattr__(), regardless.
This also seems to be the case for calling hasattr() on an object. It will return the value specified in __getattr__() if the method is implemented. This is somewhat counter-intuitive, because if the __getattr__() method is set to return False, then
calling hasattr() for a non-existent attribute will return True.
CodePudding user response:
Would something like this work? All my instances have tags, but I think if no tags exist, you get an empty list, so you may have to check on length if an error pops up.
for ec2_instance in ec2_instances:
for tag in ec2_instance.tags:
print(tag)
