soap.py Client and server
soap.py contains a few basic things. There is no Web Service Description Language (Web Services Description language,wsdl) or any other add-on, only transparent support for SOAP clients and servers implemented in Python. Even one of the best features in this package is related to infrastructure: soap.py supports Secure Sockets Layer (SSL) for encrypted SOAP transmissions. To use this feature, you must install M2crypto,m2crypto is a library that contains a variety of encryption tools and formats, from RSA and DSA to HTTPs, S/MIME, and so on. In this section, we are not going to discuss soap.py SSL support.
SOAP Action Summary
So far, SOAP utilities seem to be still the more popular open source activity using Python. Here is the outline of the project and their current status. First, the participants:
- 4Suite SOAP, managed by fourthought
- Soapy, managed by Adam Elman
- A WEB service project for the Soap.py,python project
- Soaplib, managed by Secret Labs
- Orchard, managed by Ken MacLeod
- Pysoap, managed by Dave Warner
4Suite SOAP is our own implementation, which we used in the first three sections of this column (see Resources for a link to it). It is still under development.
Soapy was released in April 2001 and is currently in the preliminary phase of alpha, but it seems to have stopped developing.
The soap.py development was frozen. Soap.py the project is sponsored by Actzero, and Actzero is no longer in the industry. Voluntary development/maintenance of soap.py organizations is being invited.
The development of Soaplib seems to have slowed down, and given the amount of work that Secret Labs this time, it might be possible to understand why. The Swedish company is run by Fredrik Lundh, a famous "workaholic" in the Python circle and a member of the Python Association board. Secret Labs also developed Pythonware (a core and important add-on module for Python); Pythonworks (a leading Python IDE); Python Imaging Library and many other good things (everyday The Python-url Web log is part of it.
Orchard is a data management framework that is essentially a way of managing different data formats with a common interface. It implements a SOAP client as the basic method (called a node) to send Orchard data items to the SOAP server in a remote procedure call.
Pysoap This project is intended primarily as part of the Church Management suite of Dave Warner, but it has never released any files as if it were a lifeless project.
Installation
Start by downloading the distribution package (when writing this article, Soappy 0.9.7 is the latest distribution), unpack the file, go to the results directory, and copy the file soap.py to its preferred location. Of course, this "inclination" is where skills are needed. Since many of these SOAP lib use different combinations of "soap.py" as module names, you must be careful. Of course, UNIX users need only care about exact case matching, but for Windows users, even "soap.py" and "soap.py" conflicts can be problematic. Orchard's soap.py also has an easily conflicting name, but it is possible to avoid all problems because its modules are intelligently placed in the Orchard package.
In short, it is recommended that you ensure that all Python SOAP modules are installed with a different package name. In our case, we found a suitable directory in Pythonpath and created a webservices package that put soap.py in the package. So, in Linux:
$ mkdir ~/lib/python/webservices
$ touch ~/lib/python/webservices/__init__.py
$ cp soappy097/soap.py ~/lib/ Python/webservices
Note the important second command, which will generate a __init__.py file that will webservices directory flags as Python packages. If you need to package this code as a version of Windows, you may want to enter some comments into an empty file because some Windows tools do not create empty files.
You have gone into the topic
For publicly available SOAP servers, there are already several registry centers for activities. The most popular may be XMethods. Of course, it's also a pretty interesting guide, through which we can understand the actual situation of SOAP and not listen to its boast. Most of the public Web services here are still nothing but unimportant things that are hardly worth the hassle of our brave new model, but that's another story. In fact, we will select a public service to demonstrate and test how to use soap.py as a SOAP client.
Or, we can try. The author tries the first service, the health care provider Locator, to display a trap in the current state of SOAP interoperability when the following error message is encountered:
WebServices.SOAP.faultType: <fault soap:client:
Server did not recognize the value of
HTTP Header SOAPAction: "" .>
Oh. SOAPAction is an HTTP header that should be used to mark the service being accessed. It is a required header in a SOAP request, but even if the desired header is set (just a pair of empty double quotes), the above error persists. The author finds that this problem exists in most MS SOAP implementations. After trying out these services, we conclude that Delphi is as good as cooperating with soap.py, but in trial service-even when it is implemented with Delphi, it returns complex types, such as lists, soap.py cannot use them, returning without data WebServices.SOAP.typedArrayType instance.
Finally, the author chooses a fairly appropriate WEB service that returns the characters haddock in the comic book The Adventures of Tintin (yes, most Web services do). Listing 1 (curse.py) is the program.
Listing 1: Accessing the soap.py program for the curse generator SOAP service
#!/usr/bin/env python
#http://xmethods.net/detail.html?id=175
import sys
#Import the soap.py machinery From
webservices Import soap
remote = soap. Soapproxy (
"Http://www.tankebolaget.se/scripts/Haddock.exe/soap/IHaddock",
namespace=) urn: Haddockintf-ihaddock ",
soapaction=" Urn:haddockintf-ihaddock#curse "
)
try:
lang = sys.argv[1]
except indexerror:
lang = "us" result
= remote. Curse (Langcode=lang)
print "What Captain Haddock had to say:"%s "%result
put everything together .
After importing the library, we will set the proxy object remote. This object converts a method call to a remote SOAP message. Its initializer uses key parameters for managing remote requests: The server's URI (called the "endpoint"), the XML namespace of the request element (through which SOAP-AS-RPC makes verbal promises into an XML base) and SOAPAction header values.
Next, we will determine the method parameters, for this Web service, the method parameter is just a haddock language, Swedish ("se") or English (curiously, "us" rather than "en").
Finally, we invoke the name-correct method, the proxy object's curse to make a SOAP call, and then print out the result. The following session demonstrates the use of this program:
$ python curse.py
What Captain Haddock had to say: "Ectoplasmic byproduct!"
our own SOAP server
It is fairly easy to implement a SOAP server with soap.py. As an example, we'll built the field and implement a very common service: A program that gives the year and month, and it prints out the calendar as a string. Its program server is Listing 2 (calendar-ws.py).
Listing 2: The soap.py program that implements the calendar server
#!/usr/bin/env python
import sys, calendar
#Import the soap.py machinery from
webservices import SOAP
Cal_ns = "Http://uche.ogbuji.net/eg/ws/simple-cal"
class Calendar:
def getmonth (self, Year, month):
Return calendar.month [year, month]
def getyear (self, year): Return
Calendar.calendar (year)
server = Soap. SoapServer (("localhost", 8888))
cal = Calendar ()
Server.registerobject (Cal, Cal_ns)
print "Starting Server ... "
server.serve_forever ()
Once the necessary import has been made, we define the namespace (Cal_ns) that the SOAP request element expects for our own server. Next we define the classes that implement all the methods that will be exposed as SOAP methods. You can also register a single function as a SOAP method, but using the class method is the most flexible, especially if you want to manage the state between calls. This calendar class defines a method getmonth that uses Python's built-in calendar module to return a monthly calendar in a text form, and it also defines another way to return to a full year calendar.
It then creates an instance of the SOAP server framework with instructions to listen on port 8888. We must also create an instance of the Calendar class, which is registered to handle the SOAP message on the next line, while indicating the associated namespace. Finally, we call the Serve_forever method, which does not return until the process terminates.
To run the server, open another command shell and execute the Python calendar-ws.py. Use Ctrl-c to kill the process at the end of execution.
We could have used a client test server that was written in soap.py, but that was obvious. We still use low-level Python to write the client to build the SOAP response as an XML string and send an HTTP message. This program (testcal.py) is in Listing 3.
Listing 3: Client with access to the calendar service written in the Python core library
Import sys, httplib server_addr = "127.0.0.1" Server_port = 8888 Cal_ns = "http://uche.ogbuji.net/ws/eg/simple-cal" body _template = "" "<soap-env:envelope xmlns:soap-env=" http://schemas.xmlsoap.org/soap/envelope/"xmlns:s=" http:// Uche.ogbuji.net/eg/ws/simple-cal "xmlns:xsi=" http://www.w3.org/1999/XMLSchema-instance "xmlns:xsd=" http:// Www.w3.org/1999/XMLSchema "soap-env:encodingstyle=" http://schemas.xmlsoap.org/soap/encoding/"> <soap-env: body> <s:getMonth> <year xsi:type= "Xsd:integer" >%s</year> <month xsi:type= "Xsd:integer" ;%s</month> </s:getMonth> </SOAP-ENV:Body> </SOAP-ENV:Envelope> "" "Def GetMonth (): Year = 200 1 month = body_template% (year, month) Blen = Len (body) requestor = Httplib. HTTP (SERVER_ADDR, Server_port) requestor.putrequest ("POST", "Cal-server") Requestor.putheader ("Host", SERVER_ADDR) R Equestor.putheader ("Content-type", "Text/plain; charset= "Utf-8" ") requestor.putheAder ("Content reply_body = requestor.getfi-length", str (Blen)) Requestor.putheader ("SOAPAction", "http:// Uche.ogbuji.net/eg/ws/simple-car ") requestor.endheaders () Requestor.send (body) (Status_code, message, reply_headers = Requestor.getreply () Le (). Read () print ' status code: ', status_code print ' status message: ', message print ' HTTP
Reply Body:\n ", reply_body if __name__ = =" __main__ ": getmonth ()
The following session demonstrates the performance of this test.
$ python testcal.py
status code:200
status Message:ok
HTTP reply body:
<?xml version= "1.0" encoding = "UTF-8"?>
<soap-env:envelope soap-env:encodingstyle= "http://schemas.xmlsoap.org/soap/encoding/"
Xmlns:xsd= "Http://www.w3.org/1999/XMLSchema" xmlns:soap-
env= "http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi= "http://www.w3.org/1999/XMLSchema-instance"
xmlns:so
ap-enc= "http:// schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<getmonthresponse soap-enc:root=" 1 " >
<result xsi:type= "xsd:string" > December 2001
Mo Tu We Th Fr Sa Su
1 2
3 4 5 6 7 8 9
10 (
</getmont) (in)------- hresponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Careful review of the bytes
If you find row Self.debug = 0 and change "0" to "1" (This is line No. 210 in the soap.py version 0.9.7), one thing to note is that you can get the details of the actual SOAP message being exchanged and other critical data for debugging and tracing, which is very Use. As an example, the following provides a session that is a session of the previous curses.py program that has the debug information display switch turned on:
$ python curse.py * * * Outgoing HTTP headers ********************************************** post/scripts/haddock.exe/so Ap/ihaddock http/1.0 Host:www.tankebolaget.se user-agent:soap.py 0.9.7 actzero.com (content-type:text/xml); charset= "UTF-8" content-length:523 soapaction: "Urn:haddockintf-ihaddock#curse" **********************************
Outgoing SOAP ****************************************************** <?xml version= "1.0" encoding= "UTF-8"?> <soap-env:envelope soap-env:encodingstyle= "http://" schemas.xmlsoap.org/soap/encoding/"xmlns:xsd=" Http://www.w3.org/1999/XMLSchema "xmlns:soap-env=" http:// schemas.xmlsoap.org/soap/envelope/"xmlns:xsi=" http://www.w3.org/1999/XMLSchema-instance "Xmlns:so ap-enc=" http:/ /schemas.xmlsoap.org/soap/encoding/"> <SOAP-ENV:Body> <ns1:curse xmlns:ns1=" Urn:haddockintf-ihaddock " soap-enc:root= "1" > <langcode xsi:type= "xsd:string" >us</LangCode> </ns1:Curse> </soap-env:body> </SOAP-ENV:Envelope> *********************************************************************** * * * * * * Incoming HTTP headers ********************************************** http/1.? OK server:microsoft-iis/5.0 Date:tue, SEP 2001 16:40:19 GMT content-type:text/xml content-length:528 Content: * Incoming SOAP ************************ <?xml version= "1.0" encoding= "UTF-8"? ><soap-env:envelope xmlns:soap-env= " http://schemas.xmlsoap.org/soap/envelope/"xmlns:xsd=" Http://www.w3.org/1999/XMLSchema "xmlns:xsi=" http:// Www.w3.org/1999/XMLSchema-instance "xmlns:soap-enc=" Http://schemas.xml soap.org/soap/encoding/"><soap-env: Body><ns1:curseresponse xmlns:ns1= "Urn:haddockintf-ihaddock" soap-env:encodingstyle= "http:// schemas.xmlsoap.org/soap/encoding/"><ns1:return xsi:type=" xsd:string ">Anacoluthons!</NS1:return> </ns1:curserespon se≫</soap-env:body></soap-env:envelope> ***********************************************************
What Captain Haddock had to say: "Anacoluthons!"
For comparison, you can get the same information in an old Python script or program with the following code:
Import Calendar return
Calendar.month (2001, 10)
soap.py Summary
We have noticed that while there are some problems with the interoperability of soap.py, the available debugging tools are expected to help.