Zeep got an unexpected keyword argument in operation - python

I'm trying to send a request to a WSDL WebServices. According to documentation, the requests must be formatted in XML.
I'm using Python and Zeep module. The operation a want to use is called 'Consulta' and parameters are called 'Comercio' and 'NumPedido' (first one is numeric type and second is alphanumeric).
The code I've tried is the following:
from zeep import Client, Settings
settings = Settings(strict=False, xml_huge_tree=True)
client = Client('https://testws.punto-web.com/wcfadproc/srvproceso.svc?wsdl', settings=settings)
request_data = { 'Comercio': '8004749', 'NumPedido': '7030510'}
client.service.Consulta_Marca(**request_data)
But this gives me error TypeError: {http://tempuri.org/}Consulta_Marca() got an unexpected keyword argument 'NumPedido'. Signature: `xml: xsd:string`
Can anyone give me some advice about fixing this? Because seems that the operation is correct, but do not why the parameters are bad.
EDIT:
I've tried this little new code
from zeep import Client, xsd, Settings
settings = Settings(strict=False, xml_huge_tree=True)
client = Client('https://testws.punto-web.com/wcfadproc/srvproceso.svc?wsdl', settings = settings)
parameters = xsd.Element(
'Consulta',
xsd.ComplexType([
xsd.Element(
'Comercio', xsd.Integer()
),
xsd.Element(
'NumPedido', xsd.String()
)
])
)
parameters_values = parameters( Comercio=8004749, NumPedido='7030510')
operation = client.service.Consulta_Marca(parameters_values)
operation
This gives me another error
The formatter threw an exception while trying to deserialize the message: Error in deserializing body of request message for operation 'Consulta_Marca'. End element 'xml' from namespace 'http://tempuri.org/' expected. Found element 'Comercio' from namespace ''. Line 2, position 465
But think I'm closer because if I execute
client.service.Consulta_Marca(parameters), I get a valid response, but with null values because no parameters values were passed.
Please some help!

Related

TDAmeritrade API get user positions

I am building software to track my portfolio and trade from. I am currently trying to get my account positions from the TD API.
acct_endpt = 'https://api.tdameritrade.com/v1/accounts/{accountId}'
full_url_acct = acct_endpt.format(accountId='accountId')
account = requests.get(url=full_url_acct,
params={'fields' : 'positions', 'apikey' : 'apikey'})
acct_content = json.loads(account.content)
My code above is returning me the following error:
json.decoder.JSONDecodeError: Expecting value: line 2 column 11 (char 11)
Update:
I removed the line containing json.loads() as it was returning a 401 error [An error message indicating the caller must pass a valid AuthToken in the HTTP authorization request header]. I must be passing the fields and apikey parameters incorrectly. How would the syntax look to properly pass these parameters?
Your parameters look correct, but I think the url formatting isn't doing what you want. Instead, you can format your url using f-string as follows:
accountId = "ACCOUNT_ID"
acct_endpt = f"https://api.tdameritrade.com/v1/accounts/{accountId}"

set parameters in EventInput in Dialogflow V2 API

I desperatly try to set parameters in a
dialogflow.types.EventInput
in python.
This doc says the parameters need to be of type Struct.
I read here that the parameters needs to be a google.protobuf.Struct.
But it does not work for me.
Is there another Struct type equivalent in python?
If i send the EventInput without parameters, the intent is detected correctly.
I tried this so far:
import dialogflow_v2 as dialogflow
session_client = dialogflow.SessionsClient()
session = session_client.session_path(project_id, session_id)
parameters = struct_pb2.Struct()
parameters['given-name'] = 'Jeff'
parameters['last-name'] = 'Bridges'
event_input = dialogflow.types.EventInput(
name='greetPerson',
language_code='de',
parameters=parameters)
query_input = dialogflow.types.QueryInput(event=event_input)
response = session_client.detect_intent(
session=session, query_input=query_input)
Anybody having experience with this usecase?
Things i also tried:
Pass a class named p yields:
Parameter to MergeFrom() must be instance of same class: expected
Struct got p. for field EventInput.parameters
Pass a dict:
parameters = {
'given-name': 'Jeff',
'last-name': 'Bridges'}
yields:
Protocol message Struct has no "given-name" field.
Generate Struct with constructor:
from google.protobuf.struct_pb2 import Struct, Value
parameters = Struct(fields={
'given-name':Value(string_value='Jeff'),
'last-name':Value(string_value='Bidges')
})
yields sometimes:
Exception in thread ptvsd.stopping (most likely raised during
interpreter shutdown):
/EventInput
This is how I did this:
import dialogflow
from google.protobuf import struct_pb2
session_client = dialogflow.SessionsClient()
session = session_client.session_path(project_id, session_id)
parameters = struct_pb2.Struct()
parameters["given-name"] = 'Jeff'
parameters["last-name"] = 'Bridges'
query_input = {
'event': {
"name": "greetPerson",
"parameters": parameters,
"language_code": "de"
}
}
response = session_client.detect_intent(
session=session,
query_input=query_input)
Note:
In dialogflow console, you must give default values of parameters as #even_name.parameter_name.
In this case for parameter given-name it would be #greetPerson.given-name and for last-name it would be #greetPerson.last-name.
Docs Reference:
We are using DetectIntent, in which we are using QueryInput, in which finally we are using EvenInput
Hope it helps.
Information in accepted answer is incorrect.
You don't have to provide default values.
You can reference event parameters directly in Value column of Parameters table.
To reference an event parameter in the parameter table or a response,
use the following format: #event-name.parameter-name.
dialogflow docs
Therefore, putting #greetPerson.given-name in Value would be enough.

Python zeep - XML tag missing type declaration for string type

When using zeep, the following code:
string_type = client.get_type("xsd:string")
string_expression = string_type("my string value")
Results in this:
<ns1:Value>my string value</ns1:Value>
What the serializer on the SOAP server expects is actually this:
<ns1:Value xsi:type="b:string" xmlns:b="http://www.w3.org/2001/XMLSchema">my string value</ns1:Value>
This discrepancy results in an Exception being thrown by the SOAP server:
zeep.exceptions.Fault: The formatter threw an exception while trying
to deserialize the message: There was an error while trying to
deserialize parameter http://Services.IPWS/. The
InnerException message was 'Element Value from namespace
http://schemas.datacontract.org/
cannot have child contents to be deserialized as an object. Please use
XmlNode[] to deserialize this pattern of XML.'. Please see
InnerException for more details.
What could be done to get zeep to retain the type declaration in the XML tag?
I have found a way to get zeep to generate the following tag, which is what the SOAP server expects:
value = zeep.xsd.AnyObject(zeep.xsd.String(), "my string value")
This results in:
<ns1:Value xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:string">my string value</ns1:Value>

Python requests call not handling authentication as expected

I have a list in which I am putting the url and authentication parameters for a requests get call. If I try the call this way I get authentication error (401) but if I break out the auth by itself explicitly on the call things work. Why can't I include auth in this manner and expect it to properly "explode" in the call?
parms = []
parms.append(url)
parms.append('auth=(''UID'', ''PWD'')')
response = requests.get(*parms)
This results in 404 because it is not recognizing the authentication. BUT, if I do this it works. To me these seem the same. The single quotes are only different to get the string to append in the list properly. I thought the first way would result in 2 parameters - url and auth
parms = []
parms.append(url)
response = requests.get(*parms, auth=('UID', 'PWD'))
The first one is equivalent to the following:
requests.get(url, "auth=('UID', 'PWD')")
When you really want:
requests.get(url, auth=('UID', 'PWD'))
You must use this instead:
args = []
kwargs = {}
args.append(url)
kwargs['auth'] = ('UID', 'PWD')
requests.get(*args, **kwargs)
The rule is:
when you have function(foo, bar) you are using positional parameters, they go into *args.
when you have function(foo=1, bar=2) you are using named parameters, they go into **kwargs.
you can mix both, in Python 2 positional parameters must be placed before named parameters.

geopy openmapquest for Python throws GeocoderInsufficientPrivileges error

I am running the following:
import geopy
geolocator = geopy.geocoders.OpenMapQuest(api_key='my_key_here')
location1 = geolocator.geocode('Madrid')
where my_key_here is my consumer key for mapquest, and I get the following error:
GeocoderInsufficientPrivileges: HTTP Error 403: Forbidden
Not sure what I am doing wrong.
Thanks!
I've also tried the same with the same result. After checking the Library, I found out, that the error is referring to the line, where the request ist build and it seems, that the API Key is not transmitted. If you add no key in the init statement, the api_key='' so I tried to change the line 66 in my own Library of the file: https://github.com/geopy/geopy/blob/master/geopy/geocoders/openmapquest.py to my key.
Still no success! The key itself works, I've tested it with calling the URL that is also called in the Library:
http://open.mapquestapi.com/nominatim/v1/search.php?key="MY_KEY"&format=json&json_callback=renderBasicSearchNarrative&q=westminster+abbey
no idea why this isn't working…
Cheers.kg
I made slight progress with fixing this one. I was able to get the query written correctly, but its the json parsing that kind of have me stumped. Maybe someone knows. I know the url is being sent correctly (I checked it in the browser and it returned a json object). Maybe someone knows how to parse the returned json object to get it to finally work.
Anyways, I had to go in the openmapquest.py source code, and starting from line 66, I made the following modifications:
self.api_key = api_key
self.api = "http://www.mapquestapi.com/geocoding/v1/address?"
def geocode(self, query, exactly_one=True, timeout=None): # pylint: disable=W0221
"""
Geocode a location query.
:param string query: The address or query you wish to geocode.
:param bool exactly_one: Return one result or a list of results, if
available.
:param int timeout: Time, in seconds, to wait for the geocoding service
to respond before raising a :class:`geopy.exc.GeocoderTimedOut`
exception. Set this only if you wish to override, on this call
only, the value set during the geocoder's initialization.
.. versionadded:: 0.97
"""
params = {
'key': self.api_key,
'location': self.format_string % query
}
if exactly_one:
params['maxResults'] = 1
url = "&".join((self.api, urlencode(params)))
print url # Print the URL just to make sure it's produced correctly
Now the task remains to get the _parse_json function working.

Categories

Resources