I'm trying to get results from a SOAP service called Chrome ADS (for vehicle data). They provided php and Java samples, but I need python (our site is in Django). My question is:
What should I be passing as a request to the SOAP service when using wsdl2py-generated classes?
Following the examples I'm using a DataVersionsRequest object as the request parameter, but the code generated by wsdl2py seems to want a getDataVersions object, and there's something like that defined at the bottom of the generated _client.py file. But that too seems to throw an error. So I'm not sure what I should be passing as the request obj. Any suggestions?
$sudo apt-get install python-zsi
$wsdl2py http://platform.chrome.com/***********
$python
>>> url = "http://platform.chrome.com/***********"
>>> from AutomotiveDescriptionService6_client import *
>>> from AutomotiveDescriptionService6_types import *
>>> locator = AutomotiveDescriptionService6Locator()
>>> service = locator.getAutomotiveDescriptionService6Port()
>>> locale = ns0.Locale_Def('locale')
>>> locale._country="US"
>>> locale._language="English"
>>> acctInfo = ns0.AccountInfo_Def('accountInfo')
>>> acctInfo._accountNumber=*****
>>> acctInfo._accountSecret="*****"
>>> acctInfo._locale = locale
>>> dataVersionsRequest = ns0.DataVersionsRequest_Dec()
>>> dataVersionsRequest._accountInfo = acctInfo
>>> service.getDataVersions(dataVersionsRequest)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "AutomotiveDescriptionService6_client.py", line 36, in getDataVersions
raise TypeError, "%s incorrect request type" % (request.__class__)
TypeError: <class 'AutomotiveDescriptionService6_types.DataVersionsRequest_Dec'> incorrect request type
>>> dataVersionsRequest = getDataVersions
>>> dataVersionsRequest._accountInfo = acctInfo
>>> service.getDataVersions(dataVersionsRequest)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "AutomotiveDescriptionService6_client.py", line 36, in getDataVersions
raise TypeError, "%s incorrect request type" % (request.__class__)
AttributeError: class DataVersionsRequest_Holder has no attribute '__class__'
>>> quit()
$cat AutomotiveDescriptionService6_client.py
.....
# Locator
class AutomotiveDescriptionService6Locator:
AutomotiveDescriptionService6Port_address = "http://platform.chrome.com:80/AutomotiveDescriptionService/AutomotiveDescriptionService6"
def getAutomotiveDescriptionService6PortAddress(self):
return AutomotiveDescriptionService6Locator.AutomotiveDescriptionService6Port_address
def getAutomotiveDescriptionService6Port(self, url=None, **kw):
return AutomotiveDescriptionService6BindingSOAP(url or AutomotiveDescriptionService6Locator.AutomotiveDescriptionService6Port_address, **kw)
# Methods
class AutomotiveDescriptionService6BindingSOAP:
def __init__(self, url, **kw):
kw.setdefault("readerclass", None)
kw.setdefault("writerclass", None)
# no resource properties
self.binding = client.Binding(url=url, **kw)
# no ws-addressing
# op: getDataVersions
def getDataVersions(self, request, **kw):
if isinstance(request, getDataVersions) is False:
raise TypeError, "%s incorrect request type" % (request.__class__)
# no input wsaction
self.binding.Send(None, None, request, soapaction="", **kw)
# no output wsaction
response = self.binding.Receive(getDataVersionsResponse.typecode)
return response
.....
getDataVersions = GED("urn:description6.kp.chrome.com", "DataVersionsRequest").pyclass
Also, as an aside, I'm not sure that the strings I'm passing to the pname parameter are correct, I assume that those are the ones I see inside the XML when I explore the service with SOAP UI, right?
It looks like you might be passing a class to service.getDataVersions() the second time instead of an instance (it can't be an instance if it doesn't have __class__).
What's happening is isinstance() returns false, and in the process of trying to raise a type error, an attribute error gets raised instead because it's trying to access __class__ which apparently doesn't exist.
What happens if you try:
>>> dataVersionsRequest = getDataVersions**()**
>>> dataVersionsRequest._accountInfo = acctInfo
>>> service.getDataVersions(dataVersionsRequest)
?
Based on the line:
if isinstance(request, getDataVersions) is False:
raise TypeError, "%s incorrect request type" % (request.__class__)
it definitely looks like you should be passing an instance of getDataVersions, so you're probably on the right track.
You probably need to be instantiating your definition objects and then populating them. Look for type == pyclass_type objects associated with the request you're wanting to make and instantiate them.
e.g. (just guessing)
>>> versionrequest = getDataVersions()
>>> versionrequest.AccountInfo = versionrequest.new_AccountInfo()
>>> versionrequest.AccountInfo.accountNumber = "123"
>>> versionrequest.AccountInfo.accountSecret = "shhhh!"
>>> service.getDataVersions(versionrequest)
I found that the code generated by wsdl2py was too slow for my purposes. Good luck.
Related
when I test this view
#action(methods=['GET'], detail=True)
def nearby(self, request, pk=None):
"""get nearby energy resources to
the current energy resource in detail"""
energy_resource = self.get_object()
energy_resources = EnergyResource.objects.annotate(
distance=Distance('location', energy_resource.location)
).order_by('distance')[0:3]
serializer = self.get_serializer(energy_resources, many=True)
return Response(serializer.data)
with this test
def test_retrieve_nearby_energy_resources(self):
"""Test getting a list of three nearby energy resources"""
test_user2 = get_user_model().objects.create_user(
username='test2', password='test2password')
r = sample_resource(self.user, 5, 5)
sample_resource(test_user2, 4, 5)
sample_resource(test_user2, 5, 4)
sample_resource(test_user2, 5, 3)
r4 = sample_resource(test_user2, 25, 63)
url = reverse('energy-resource-nearby',
args=[r.id])
response = self.client.get(url)
resources_nearby = EnergyResource.objects.exclude(id=r4.id).order_by()
resource_not_nearby = EnergyResource.objects.get(id=r4.id)
serializer_nearby = EnergyResourceSerializer(
resources_nearby, many=True)
serializer_not_nearby = EnergyResourceSerializer(resource_not_nearby)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertContains(response.data, serializer_nearby.data)
self.assertNotContains(response.data, serializer_not_nearby)
it returns
ERROR: test_retrieve_nearby_energy_resources (energy_resources.tests.test_views.EnergyResourcePrivateAPITests)
Test getting a list of three nearby energy resources
----------------------------------------------------------------------
Traceback (most recent call last):
File "/workspace/energy_resources/tests/test_views.py", line 210, in test_retrieve_nearby_energy_resources
self.assertContains(response.data, serializer_nearby.data)
File "/root/.local/share/virtualenvs/workspace-dqq3IVyd/lib/python3.8/site-packages/django/test/testcases.py", line 445, in assertContains
text_repr, real_count, msg_prefix = self._assert_contains(
File "/root/.local/share/virtualenvs/workspace-dqq3IVyd/lib/python3.8/site-packages/django/test/testcases.py", line 416, in _assert_contains
response.status_code, status_code,
AttributeError: 'ReturnList' object has no attribute 'status_code'
----------------------------------------------------------------------
Ran 12 tests in 2.250s
it works in broswer and if I commented out assertContain and assertNotContain the test passes so it meants the response has status code attribute, right? what is different about assertContain and assertNotContain?
The error message misleading, but the stacktrace clearly shows the problem happens on the next line (so deleting it makes the test pass)
# this is not the function you are looking for
self.assertContains(response.data, serializer_nearby.data)
The problem is assertContains. It doesn't do what it sounds like at all, it actually checks some things releated to a django response:
def assertContains(self, response, text, count=None, status_code=200, msg_prefix='', html=False):
"""
Assert that a response indicates that some content was retrieved
successfully, (i.e., the HTTP status code was as expected) and that
``text`` occurs ``count`` times in the content of the response.
If ``count`` is None, the count doesn't matter - the assertion is true
if the text occurs at least once in the response.
"""
This method is so bad that my custom test base throwns an exception if anyone calls it, but I still accidentally do sometimes. In those cases I really wanted to call assertIn.
In your case it looks like you want to compare to dict instances for equality. TestCase has some methods like that, but be aware that they aren't perfect.
self.assertDictEqual({"a":1}, {"a":2})
# passes, all items in subset are in dictionary
self.assertDictContainsSubset(
subset={"a": 1},
dictionary={"z": 2, "a": 2}
)
I'm a beginner in python. I'm not able to understand what the problem is?
the runtime process for the instance running on port 43421 has unexpectedly quit
ERROR 2019-12-24 17:29:10,258 base.py:209] Internal Server Error: /input/
Traceback (most recent call last):
File "/var/www/html/sym_math/google_appengine/lib/django-1.3/django/core/handlers/base.py", line 178, in get_response
response = middleware_method(request, response)
File "/var/www/html/sym_math/google_appengine/lib/django-1.3/django/middleware/common.py", line 94, in process_response
if response.status_code == 404:
AttributeError: 'tuple' object has no attribute 'status_code'
Whatever middleware_method returns is a tuple, so in the form ('a', 1, []) or something.
The error is telling you that you can't access members of the tuple by name, because they don't have names.
Maybe you created a tuple like this:
status_code = 404
name = 'Not found'
response = (name, status_code)
Once you declare the tuple, the names that went into it are lost. You have a couple of options for getting things out.
Direct access
You can get the objects by index, like you would with a list:
assert response[1] == 404
If you don't know what the tuple looks like, just print it, and calculate the index.
Named tuple
If you're determined to use names, you can create a namedtuple, provided that the tuple is going to be in the same format every time.
from collections import namedtuple
Response = namedtuple('Response', ('name', 'status_code')
response = Response('Not found', 404)
assert response.status_code == 404
Alternatively there may be a mistake in your code, where you are inadvertently returning a tuple, but one part of it is a requests.Response object. In that case, you can just extract the object as in "Direct access", and then use as you are already.
Would have to see the code to be of more help, but it might be something like:
response[2].status_code
I will try to explain how this error comes with a simple example
def example_error():
a1 = "I am here"
b1 = "you are there"
c1 = "This is error"
return a1, b1, c1
def call_function():
strings = example_error()
s1 = strings.a1
s2 = strings.b1
s3 = strings.c1
print(s1, s2, s3)
call_function()
This will return the error
AttributeError: 'tuple' object has no attribute 'a1'
Because I have returned three variables a1, b1, c1 in example_error function and trying to get them by using single variable strings.
I can get rid of this by using the following modified call_function
def call_function():
strings = example_error()
s1 = strings[0]
s2 = strings[1]
s3 = strings[2]
print(s1, s2, s3)
call_function()
As you did not show your code, I assume you have done something similar as here in the first case.
I'm trying to prevent to use eval based on an example how-to-avoid-eval-in-python-for-string-conversion using ast. The challange is that there are a dozen of these self.ch%s_label's to be made but the variable for it changes based on user input in the GUI.
My code:
import ast ...etc.
....
channel_no += 1
ch_width = eval('self.ch%s_label.frameGeometry().width()' % (channel_no))
When I change it into:
ch_width = ast.literal_eval('self.ch%s_label.frameGeometry().width()' % (channel_no))
I'll get the error:
File "c:\python\anac2\lib\ast.py", line 80, in literal_eval
return _convert(node_or_string)
File "c:\python\anac2\lib\ast.py", line 79, in _convert
raise ValueError('malformed string')
ValueError: malformed string
Changing the code (using closing " ") retains the error:
ch_width = ast.literal_eval("'self.ch%s_label.frameGeometry().width()' % (channel_no)")
What other options are there... Any suggestions?
You could use getattr to get the attribute from the instance using the dynamically constructed attribute name:
ch_width = getattr(self, 'ch%s_label' % channel_no).frameGeometry().width()
Or step by step:
channel_no = 5
attr_name = 'ch%s_label' % channel_no
attr = getattr(self, attr_name)
ch_width = attr.frameGeometry().width()
Using getattr in this way also means you get an AttributeError if an object doesn't have the attribute, as you'd expect.
I want to return the queryset in json format, and I use the JsonResponse as the following:
def all_alert_history(request):
''' get all all alert history data '''
all_data_json = serializers.serialize('json', LatestAlert.objects.all())
return JsonResponse(all_data_json,safe=False)
but the browser shows like this:
"[{\"fields\": {\"alert_name\": \"memory usage\", \"alert_value\": 83.7, \"alert_time\": \"2016-11-08T06:21:20.717Z\", \"alert_level\": \"warning\", \"alert_rule\": \"warning: > 80%\"}, \"model\": \"alert_handler.latestalert\", \"pk\": \"xyz.test-java.ip-10-0-10-138.memory.percent\"}]"
I replace the JsonResponse with HttpResponse :
def all_alert_history(request):
''' get all all alert history data '''
all_data_json = serializers.serialize('json', LatestAlert.objects.all())
return HttpResponse(all_data_json, content_type='application/json')
and the browser shows like this:
[{"fields": {"alert_name": "memory usage", "alert_value": 83.7, "alert_time": "2016-11-08T06:21:20.717Z", "alert_level": "warning", "alert_rule": "warning: > 80%"}, "model": "alert_handler.latestalert", "pk": "xyz.test-java.ip-10-0-10-138.memory.percent"}]
so, why does the \ appears when I use the JsonResponse but disappear when use the HttpResponse?
django version:1.8
JsonResponse takes a python dictionary and returns it as a json formatted string for the browser.
Since you're providing the JsonResponse with an already json formatted string it will try to escape all necessary characters with \.
Example:
>>> from django.http import JsonResponse
>>> response = JsonResponse({'foo': 'bar'})
>>> response.content
b'{"foo": "bar"}'
In your case JsonResponse even warns you about what you are doing when passing a string, hence making the safe = False parameter necessary:
>>> mydata = {"asd":"bdf"}
>>> import json
>>> myjson = json.dumps(mydata)
>>> JsonResponse(myjson)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/swozny/work2/local/lib/python2.7/site-packages/django/http/response.py", line 500, in __init__
raise TypeError('In order to allow non-dict objects to be '
TypeError: In order to allow non-dict objects to be serialized set the safe parameter to False
With the parameter set to False your observed behavior is reproducible:
>>> JsonResponse(myjson,safe=False).content
'"{\\"asd\\": \\"bdf\\"}"'
Bottom line is that if your model is a little more complex than basic data types ( IntegerField,CharField,...) then you probably will want to do the serialization yourself and stick to HttpResponse or just use djangorestframework which offers tools to do it for you.
I have the following MongonEngine models:
from app import db
from datetime import datetime
from mongoengine import signals
class PathEmbedded(db.EmbeddedDocument):
"""
To be embedded.
"""
_id = db.ObjectIdField(required=False)
distance = db.IntField(required=False, min_value=0, default=0)
meta = {
"allow_inheritance": True,
}
def __unicode__(self):
return "Path '%s': %d m" % (self.id, self.distance)
class Path2(PathEmbedded, db.Document):
"""
Same as above, but standalone version to be stored in its own collection.
"""
_id = db.ObjectIdField()
orig = db.ObjectIdField(required=True)
dest = db.ObjectIdField(required=True)
updateStamp = db.DateTimeField(required=True)
ok_to_use = db.BooleanField(required=True, default=False)
meta = {
'indexes': [
{
'fields': ['ok_to_use', 'orig', 'dest'],
'cls': False, # does this affect performance?!
},
],
}
#classmethod
def pre_save(cls, sender, document, **kwargs):
document.updateStamp = datetime.utcnow()
def to_embedded(self):
"""
Converts the standalone Path instance into an embeddadle PathEmbedded instance.
"""
import json
temp = json.loads(self.to_json())
#remove the {"_cls": "Location"} key.
#If we don't do this, the output will be a 'Location' instance, not a 'LocationEmbedded' instace
temp.pop('_cls')
return PathEmbedded().from_json(json.dumps(temp))
def get_from_gmaps(self):
"""
Get distance from Google maps using the directions API and append to the 'paths' list.
Return False on error or True on success.
"""
try:
self.distance = 10,
self.save()
except Exception, e:
print str(e)
return False
else:
return True
# connect event hooks:
signals.pre_save.connect(Path2.pre_save, sender=Path2)
So, at some point I'm updating a path instance by calling get_from_gmaps():
from app.models.Path2 import Path2 as P
from bson import ObjectId
p=P(orig=ObjectId(), dest=ObjectId())
p.save()
p.get_from_gmaps()
which raises:
>>> p.get_from_gmaps()
ValidationError (Path2:54d34b97362499300a6ec3be) (10 could not be converted to int: ['distance'])
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "[...]app/models/Path2/get_from_gmaps.py", line 18, in get_from_gmaps
self.save()
File "[...]venv/local/lib/python2.7/site-packages/mongoengine/document.py", line 224, in save
self.validate(clean=clean)
File "[...]venv/local/lib/python2.7/site-packages/mongoengine/base/document.py", line 323, in validate
raise ValidationError(message, errors=errors)
ValidationError: ValidationError (Path2:54d34b97362499300a6ec3be) (10 could not be converted to int: ['distance'])
Originally I was storing an integer parsed from some json and converted to int, and thought somthing was wrong there, but i replaced it with an int value for debugging and now get this. I really don't know where to start o.O
EDIT: expanded code to provide complete [non]working example.
There's an extra comma after the 10:
self.distance = 10,
^
You are setting distance to a tuple containing an int, instead of an int.
HINT: The reason why your are seeing such an unhelpful message is that MongoEngine is using %s format string improperly. In fact, the result of "%s" % something depends on the type of something, as tuples are special cased. Compare:
>>> '%s' % 10
'10'
>>> '%s' % (10,)
'10'
>>> '%s' % (10, 11)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: not all arguments converted during string formatting
>>> '%s' % ((10,),) # This is the correct way of formatting strings
'(10,)' # when the type of the argument is unknown.
This is a MongoEngine's problem of course, but if you want to avoid the same kind of mistake in your code, remember to always use tuples at the right of the % operator, or even better use the .format() method.
Are you sure the self model you send is the right one?
This ValidationError is thrown when you have declare a ReferenceField in a document, and you try to save this document before saving the referenced document (Mongoengine represents a reference field in MongoDB as an dictionnay containing the class and the ObjectId of the reference).