Closed ismettaslann closed 6 years ago
I believe you have this error because the "datetime" is not in the isoformat ISO 8601. And maybe since it is not in this format, it returns None ?
Do you know how is the expected data ? It should be in the ISO 8601 format: like this:
2018-01-29T13:00:00 Notice the "T" between the date and time.
Maybe take a look here: https://docs.python.org/3/library/datetime.html?highlight=datetime%20isoformat#datetime.datetime.isoformat
Yes, My return data isn't datetime iso format. But, actually i can't intefere in casting to iso8601. I mean, is respone has to return iso8601 format? My actual question is, what can i do when response return like '27-01-2017' ? Because zeep does not let me accept like string or etc.
@ismettaslann I faced a similar problem in one of my projects. We came up with two solutions: 1) Convert the date to ISO before zeep parses it: This can be done by modifying the function (file : zeep\xsd\types\builtins.py class : Date method : pythonvalue() ) to -
def pythonvalue(self, value):
try:
_date = datetime.strptime(value, "%d-%m-%Y").date()
value = str(_date)
except:
pass
return isodate.parse_date(value)
2) Write a plugin to parse the response yourself and change the dates to ISO format (Not implemented yet)
The first one is a quick and nasty solution whereas second option seems to be more legit. Hope this helps.
I had this same issue @asutkarpeeyush 's fix didnt work for my date issue. I did a really lazy 'fix' which doesn't fix any typing issues but works for my specific application
def pythonvalue(self, value):
if 'T' not in value:
value = value + 'T00:00:00'
return isodate.parse_datetime(value)
That is really good solution. But I fix my problem with different way. Thank you for your response :)
@shausman yea coz your date format is different from what @ismettaslann had asked for! @ismettaslann I would love to know how you have fixed it :)
I forgot to write my solution, sorry :) Actually my solution isn't the perfect way, But it works :) I imported to xmltodict library and it converted all data succesfully.
response_from_xml = xmltodict.parse(response.text)
data=dict(response_from_xml.get("env:Envelope").get("env:Body").get("AddCustomerAutopayResponse"))
return jsonify(data)
I used this like that as above.
@ismettaslann @shausman I ended up coding the second solution I had proposed. Posting it for anyone who might need it someday.
class _XMLParsingPlugin(Plugin):
def ingress(self, envelope, http_headers, operation):
# define the namespace
namespace = {'soap': 'http://schemas.xmlsoap.org/soap/envelope/'}
# start iterating over the xml from body tag
xml_elements = Queue()
body = envelope.find("soap:Body", namespace)
xml_elements.put(body)
while not xml_elements.empty():
element = xml_elements.get()
# if element's text is a date ("%d-%m-%Y"), change the format
# can have multiple operations here!!
try:
element_text = element.text
_date = datetime.strptime(element_text, "%d-%b-%Y").date()
element.text = str(_date)
except:
pass
# push all child elements to the queue
element_children = list(element)
for child in element_children:
try:
xml_elements.put(child, block=False)
except Full:
raise Full("Queue is full")
return envelope, http_headers
Fixed in master, with a bit of a hack :-)
In my case the error was: isodate.isoerror.ISO8601Error: Unable to parse duration string '55'
, issued by return isodate.parse_duration(value)
(source code in Zeep)
Checked source code of isodate
. In description all examples start with P
-> In wiki found what is P
:
P is the duration designator (for period) placed at the start of the duration representation.
and an example:
"P3Y6M4DT12H30M5S" represents a duration of "three years, six months, four days, twelve hours, thirty minutes, and five seconds".
Full code:
import zeep
class HandleDurationTime(zeep.Plugin):
"""
Fix the error: "isodate.isoerror.ISO8601Error: Unable to parse duration string '55'"
"Duration" must have the next format 'P3Y6M4DT12H30M5S', which represents
a duration of "three years, six months, four days, twelve hours, thirty minutes, and five seconds"
"""
def ingress(self, envelope, http_headers, operation):
tree = envelope
# "Flight" is a tag name
for i in tree.xpath("//*[name()='Flight']"):
# "Duration" is an attribute of "Flight" tag, ie:
# <Flight DepartureDateTime="2019-12-31T09:15:00" TravelCode="100109" Duration="55">...</Flight>
duration = i.get('Duration')
if duration and duration.isdigit():
minutes = int(duration)
hours, minutes = minutes // 60, minutes % 60
if minutes > 59:
raise NotImplementedError('Please convert minutes to hours')
# "P3Y6M4DT12H30M5S" .
date_time_str = f'P0Y0M0DT{hours}H{minutes}M0S'
i.set('Duration', date_time_str)
return envelope, http_headers
def run():
settings = zeep.Settings(strict=True)
client = zeep.Client(wsdl='path_to_wsdl_file', settings=settings, plugins=[HandleDurationTime()])
some_data_to_send = {}
r = client.service.SERVICE_NAME(**some_data_to_send)
Hi, plugin is great solution. I have same error and my response with data string is:
Zeep cant parse it, because T is missing in datetime.
And my short solution for this
class _DateToISOPlugin(Plugin):
def ingress(self, envelope, http_headers, operation):
tree = envelope
for i in tree.xpath("//*[name()='date']"):
i.text = i.text.replace(' ', 'T')
return envelope, http_headers
Hi, I'm trying to send soap request with wsdl, I'am getting response but somehow all datetime parameters return 'None'. I'am using zeep version 2.5.0.
Part of wsdl, actually xsd is below, this is the type that return 'None';
This is my response data;
And this is my script;
And this is error;
Thank you!