unexpected attribute error in python object - python

I'm parsing objects returned by the suds client from a Web Services SOAP API
I have a list of attributeObjects, like
(defectStateAttributeValueDataObj){
attributeDefinitionId =
(attributeDefinitionIdDataObj){
name = "Comment"
}
attributeValueId =
(attributeValueIdDataObj){
name = "Owner changed because of default owner assignment specified in the component map"
}
}
and
(defectStateAttributeValueDataObj){
attributeDefinitionId =
(attributeDefinitionIdDataObj){
name = "OwnerName"
}
attributeValueId =
(attributeValueIdDataObj){
name = "Schmoe, Joe"
}
}
I use the following loop to extract key/value pairs:
for defect in myDefectsPage.mergedDefects :
print defect.cid,
for attribute in defect.defectStateAttributeValues:
print attribute
attr= attribute.attributeDefinitionId.name
val=attribute.attributeValueId.name
print attr,'=',val,
print ""
(The above objects are results of the print attribute command)
This will work as expected for EVERY attribute, except the one where attribute.attributeDefinitionId.name == "Comment"
for that one I get the
Traceback (most recent call last):
File , line 63, in
val=attribute.attributeValueId.name
AttributeError: 'Text' object has no attribute 'name'
which is strange, because if I use
val=attribute.attributeValueId #.name
it will print
Commment = (attributeValueIdDataObj){
name = "Owner changed because of default owner assignment specified in the component map"
}
So it looks like it IS an attributeValueIdDataObj and DOES have a name attribute.
I used the suds DEBUG logging and the XML return elements look exactly the same regardless of what the attribute.attributeDefinitionId.name is.
I have no idea how it changes into a 'Text' object when trying to access the name attribute
Any ideas?

On further examination (and printing out the type of the returned object when exception happened) this was a bug in the web services SOAP server.
When a Comment was empty, it returned an
<attributeValueId/>
tag,
instead of the proper
<attributeValueId>
<name/>
</attributeValueId>
object. so it resulted in sax.Text object instead of the suds.attributeValueIdDataObj object
So no python or suds mystery to solve.
Sorry for the false alarm...

Related

Amazon Neptune on submitting query: AttributeError: 'str' object has no attribute 'source_instructions'

I have the following code running on AWS lambda, but getting the following error.
Error
[ERROR] AttributeError: 'str' object has no attribute 'source_instructions'
Traceback (most recent call last):
File "/var/task/gremlin_python/driver/driver_remote_connection.py", line 56, in submit
    result_set = self._client.submit(bytecode, request_options=self._extract_request_options(bytecode))
  File "/var/task/gremlin_python/driver/driver_remote_connection.py", line 81, in _extract_request_options
    options_strategy = next((x for x in bytecode.source_instructionsEND RequestId: 4ee8073c-e941-43b3-8014-8717893b3188
Source code
from gremlin_python.driver.driver_remote_connection import DriverRemoteConnection
def test_neptune(host):
remoteConn = DriverRemoteConnection('wss://{}:8182/gremlin','g'.format(host))
query = "g.V().groupCount().by(label).unfold().project('label','count').by(keys).by(values)"
response = remoteConn.submit(query)
print("response-> {}" .format(response))
# iterate repsonse
# go thru label
for set_item in response:
for item in set_item:
print("item-> item: {}".format(item))
remoteConn.close()
test_neptune()
Your DriverRemoteConnection call is wrong. You have:
remoteConn = DriverRemoteConnection('wss://{}:8182/gremlin','g'.format(host))
So you are sending {} as the hostname, and passing 'g' as a second parameter, which is probably where the error comes from. I don't know what you intended the 'g' for, but you probably want:
remoteConn = DriverRemoteConnection('wss://{}:8182/gremlin'.format(host))
If you send the query as a text string you need to create the Client object differently or write the query as in-line Python. There are two examples at (1) and (2) that show each option. The error you are seeing is because the server is trying to find Gremlin bytecode in the packet sent but only found a string (which does not have a source_instructions method).
Using a DriverRemoteConnection you can use a Python line of code such as:
result = (g.V().groupCount().
by(label).
unfold().
project('label','count').
by(keys).
by(values).
next())
If you actually want/need to send the query as a string instead of bytecode, please see my answer to this question
https://github.com/krlawrence/graph/blob/master/sample-code/basic-client.py
https://github.com/krlawrence/graph/blob/master/sample-code/glv-client.py

getting object has no attribute 'get' or object is not subscriptable when trying to access JSON response converted to DTO

I'm trying to access a JSON response, I've trying with get() method and I'm getting the "object has no attribute 'get'" error and when I tried it with [] I'm getting the "object is not subscriptable" error.
The response is valid, as I've printed it just before the get operation and all looks ok.
Did not had such problem parsing a response before.
def get_return_params_and_identifiers(return_params):
print("******** res start **********")
print(return_params)
print("******** res end **********")
return_parameters = return_params.get('return_parameters')
Here is part of a response:
******** res start **********
{'levels': None,
'return_parameters': [{'identifier_name': 'Premium',
'level': None,
'return_parameter_name_pk': 1258407,
'return_parameters_details': [{'base_parameter_name': 'Premium '
'Parameter',
'base_parameter_pk': 1149913,
'class_value': None,
....
....
Did anybody encountered such and have any idea what is happening.
EDIT:
Tried with json.loads() but the response is a DTO and not JSON anymore and thus getting the other error:
TypeError: the JSON object must be str, bytes or bytearray, not DTO
The DTO class is below:
class ReturnParametersContainerDTO(object):
"""NOTE: This class is auto generated by the swagger code generator program.
Do not edit the class manually.
"""
"""
Attributes:
swagger_types (dict): The key is attribute name
and the value is attribute type.
attribute_map (dict): The key is attribute name
and the value is json key in definition.
"""
swagger_types = {
'return_parameters': 'list[ReturnParameterDTO]',
'levels': 'LevelsDTO'
}
attribute_map = {
'return_parameters': 'returnParameters',
'levels': 'levels'
}
It clearly says that the items in the class are dictionary, but somehow it does not recognize it.
Ok, I solved the issue.
It was something in the implementation of the OpenApi's generated DTO class, that showed it as a dictionary (in to_str() method it called to_dict() and prints it as a dictionary) but in fact those were just properties, so used the method to_dict() (in swagger's generated class) to convert it to dictionary.
Now all works.

Error trying to use pyad to update user account

I'm trying to update a user attribute in Active Directory using pyad. This is my code
from pyad import *
pyad.set_defaults(ldap_server="server.domain.local",
username="admin", password="password")
pyad.adobject.ADObject.update_attribute(self='testuser1', attribute='mail',
newvalue='my#email.com')
and this is the error i recieve.
Traceback (most recent call last):
File "c:\Users\Administrator\Desktop\scripts\AD-Edit-user.py", line 12, in
<module>
pyad.adobject.ADObject.update_attribute(self='testuser1', attribute='mail',
newvalue='my#email.com')
File "C:\Users\Administrator\AppData\Local\Programs\Python\Python36-
32\lib\site-packages\pyad-0.5.20-py3.6.egg\pyad\adobject.py", line 318, in
update_attribute
elif pyadutils.generate_list(newvalue) != self.get_attribute(attribute):
AttributeError: 'str' object has no attribute 'get_attribute'
This makes me assume that I need to change the attribute type from str to something else. I have verified that mail is the correct attribute name.
I know ldap connection is working because i can create a user using a similar script.
Your problem is how you use pyad.
Specifically in this line:
pyad.adobject.ADObject.update_attribute(self='testuser1', attribute='mail',
newvalue='my#email.com')
if we look at the source of pyad.adobject.ADObject, we can see the following:
def update_attribute(self, attribute, newvalue, no_flush=False):
"""Updates any mutable LDAP attribute for the object. If you are adding or removing
values from a multi-valued attribute, see append_to_attribute and remove_from_attribute."""
if newvalue in ((),[],None,''):
return self.clear_attribute(attribute)
elif pyadutils.generate_list(newvalue) != self.get_attribute(attribute):
self._set_attribute(attribute, 2, pyadutils.generate_list(newvalue))
if not no_flush:
self._flush()
self here is not a parameter of the function, it is a reference to the class instance. Your call includes self='testuser1' which is str.
Please lookup the documentation on how to use this function / functionality / module, here. You will notice that there is no "self"... other than looking into the source code I am not sure how you got to the conclusion you needed self.
I have no way of testing the following, but this is roughly how it should work:
# first you create an instance of the object, based on
# the distinguished name of the user object which you
# want to change
my_ad_object = pyad.adobject.ADObject.from_dn('the_distinguished_name')
# then you call the update_attribute() method on the instance
my_ad_object.update_attribute(attribute='mail', newvalue='my#email.com')

Python intermittently throws "AttributeError: 'NoneType' object has no attribute 'get'" on the same dictionary

I have a nested dictionary like so:
mail = {
'data': { 'from': {'text': '123#example.com'}}
# some other entries...
}
I'm trying to copy from value using following code:
data = mail.get('data')
new_dict['parse']['from'] = data.get('from').get('text')
The second line throws the exception:
AttributeError: 'NoneType' object has no attribute 'get'
The strange thing is, this only happens sometimes. If I add a print statement just before the second line like:
data = mail.get('data')
print(type(data.get('from')))
new_dict['parse']['from'] = data.get('from').get('text')
The error disappears and I get <class 'dict'> as expected. If I remove the print statement, it works sometimes and other times it throws the error. Nothing else changes in the code or data. The reason I'm using get() is to retrieve value safely in case the key is missing.
In the call data.get('from').get('text'), if data does not contain the key 'from', it will return None. None.get('text') raises then the exception you see, because a None object has no get method (of course).
The way around this is to pass in a better default-object than None (the default default-object), which has the get method. That would be an empty dictionary, {}:
data = mail.get('data')
new_dict['parse']['from'] = data.get('from', {}).get('text')

boto instance.__dict__['tags']['Name'] output issue

UPDATE:
I did what was suggested below, however, I was still getting an KeyError:'Name' in the output, even though the output was correct.
This was the output:
us-west-1 EC2Connection:
ec2.us-west-1.amazonaws.com
Showing all of your current instances
Proxy-44-1000-Enrollments
Proxy-45-1000-Enrollments
Proxy-48-1000-Enrollments
Proxy-49-1000-Enrollments
Proxy-59-1000-Enrollments
Proxy-67-1000-Enrollments
Traceback (most recent call last): File "/Users/xxxxx/xxxx/boto/instanceid.py",
line 43, in <module> print "\t%s" % (instance.tags['Name']) if instance.state ==
'running' else instance.state KeyError: 'Name'
Initial Question:
I'm trying to dump out a list of Instance ID's along with their "Name" tag from AWS using boto. I found online a method that one can attach to the instance object, called __dict__, which seemed to work well, however, I wanted to pull out the "name" tag only when using this method, but I keep getting an error "Key Error:'Name'"
Basically, this code works:
# Creating connection object to EC2
conn = boto.connect_ec2()
regions = boto.ec2.regions()
# the 5 element in the array is "us-west-1" and setting the object to connect
us = regions[5]
print us.name
conn_us = us.connect()
print conn_us
filters = {'key-name' : 'misc-key'}
all_inst = conn_us.get_all_instances(filters=filters)
print "Showing all of your current instances"
for res in all_inst:
# each reservation have a instance:
for instance in res.instances:
print "\t%s: \t%s" % (instance.id, instance.__dict__['tags'])
The output is hoky tho:
us-west-1
EC2Connection:ec2.us-west-1.amazonaws.com
Showing all of your current instances
i-xxxxxxxx: {u'Name': u'Proxy-xx-1000-Enrollments'}
i-xxxxxxxx: {u'Name': u'Proxy-xx-1000-Enrollments'}
i-xxxxxxxx: {u'Name': u'Proxy-xx-1000-Enrollments'}
i-xxxxxxxx: {u'Name': u'Proxy-xx-1000-Enrollments'}
i-xxxxxxxx: {u'Name': u'Proxy-xx-1000-Enrollments'}
When I make a change to the __dict__ method to "pull" out "name" only, it works (or seems to work, but throws an error:
Here is the code change:
print "\t%s: \t%s" % (instance.id, instance.__dict__['tags']['Name'])
Here is the output:
us-west-1
EC2Connection:ec2.us-west-1.amazonaws.com
Showing all of your current instances
i-xxxxxxxx: Proxy-xx-1000-Enrollments
i-xxxxxxxx: Proxy-xx-1000-Enrollments
i-xxxxxxxx: Proxy-xx-1000-Enrollments
i-xxxxxxxx: Proxy-xx-1000-Enrollments
i-xxxxxxxx: Proxy-xx-1000-Enrollments
i-xxxxxxxx: Proxy-xx-1000-Enrollments
Traceback (most recent call last):
File "/Users/xxxxxx/xxx.xxx/boto/instanceid.py", line 43, in <module>
print "\t%s: \t%s" % (instance.id, instance.__dict__['tags']["Name"])
KeyError: 'Name'
I prefer this output, WITHOUT the error - can anyone tell me what I'm doing wrong here?
Thanks
Why not just access the tags attribute directly? Getting to it via __dict__ is not very pythonic:
instance.tags['Name']
You also might want to look at the state of the instance since some of the instances in the Reservation objects that you get back from get_all_instances() may be recently terminated instances. You could report the name on only the running instances and the state otherwise (NOTE - this .state check is just an idea to show the A if cond else B syntax. You will still have to play with it on your own):
instance.tags['Name'] if instance.state == 'running' else instance.state
You can use dict.get() if all you want to do is avoid the KeyError and return a default value.
instance.tags.get('Name')
# or with a default
instance.tags.get('Name', '--')
Here is a blurb pulled from the boto ec2 tutorial that mentions Reservation objects and instance state.
If you just want to get a list of all of your running instances, use
the get_all_instances method of the connection object. Note that the
list returned is actually a list of Reservation objects (which contain
the Instances) and that the list may include recently terminated
instances for a small period of time subsequent to their termination.

Categories

Resources