-
Notifications
You must be signed in to change notification settings - Fork 43
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit ec1e096
Showing
21 changed files
with
2,940 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
# use glob syntax. | ||
syntax: glob | ||
|
||
*.pyc | ||
.project | ||
.pydevproject |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,274 @@ | ||
About | ||
===== | ||
|
||
The main purpose of this library is neat implementation of SOAP protocol, | ||
but xsd package can used for any XML as it gives means of mapping XML | ||
to object. | ||
The object description generally is similar to Django database models - the static | ||
fields that define instance fields. The main difference would be that type is | ||
passed as first parameter, rather then being a field e.g | ||
Django: tail_number = models.CharField() | ||
ws: tail_number = xsd.Element(xsd.String) | ||
xsd.Element reflects the nature of the field, elements are fields that | ||
will be wrapped with tag, other options are xsd.Attribute, xsd.Ref and | ||
xsd.ListElement. For more detail see xsd.Element pydoc. | ||
As SOAP, WSDL and XSD files are also XMLs the xsd package was also | ||
used to describe them. The descriptions are located in xsdspec.py, soap.py | ||
and wsdl.py. soap package also provides dispatcher and client Stub. | ||
Other elements included in this tool are translators, that can generate python | ||
code from formal description, or formal description from code. Related files: | ||
py2xsd.py, xsd2py.py, wsdl2py.py, py2wsdl.py. | ||
utils.py is mostly jinja2 helper functions. jinja2 is templating engine used | ||
for code generation. | ||
|
||
1. Working with XML | ||
================ | ||
The main building block are xsd.ComplexType, xsd.Element, xsd.Attribute and | ||
simple types defined in xsd package. xsd.ComplexType is a parent to extend to define | ||
own type. Main methods for types are xml - translates object into XML, and parsexml | ||
builds object from XML. | ||
|
||
#Example 1. Rendering object to XML. | ||
from ws import xsd | ||
|
||
class Airport(xsd.ComplexType): | ||
type = xsd.Element(xsd.String) | ||
code = xsd.Element(xsd.String) | ||
|
||
airport = Airport() | ||
airport.type = "IATA" | ||
airport.code = "WAW" | ||
print airport.xml("takeoff_airport") | ||
|
||
Note that xml method takes one parameter - root tag name. | ||
|
||
#Example 2. Parsing XML to object. | ||
from ws import xsd | ||
class Airport(xsd.ComplexType): | ||
type = xsd.Element(xsd.String) | ||
code = xsd.Element(xsd.String) | ||
XML = """<takeoff_airport> | ||
<type>IATA</type> | ||
<code>WAW</code> | ||
</takeoff_airport>""" | ||
airpport = Airport.parsexml(XML) | ||
print "Type:", airport.type#prints Type: IATA | ||
print "Code:", airport.code#Code: WAW | ||
|
||
#Example 3. Nested ComplexTypes with attributes. | ||
from datetime import datetime | ||
from ws import xsd | ||
class Airport(xsd.ComplexType): | ||
type = xsd.Element(xsd.String) | ||
code = xsd.Element(xsd.String) | ||
|
||
class Flight(xsd.ComplexType): | ||
tail_number = xsd.Attribute(xsd.String) | ||
type = xsd.Attribute(xsd.Integer, use=xsd.Use.OPTIONAL) | ||
takeoff_airport = xsd.Element(Airport) | ||
takeoff_datetime = xsd.Element(xsd.DateTime, minOccurs=0) | ||
landing_airport = xsd.Element(Airport) | ||
landing_datetime = xsd.Element(xsd.DateTime, minOccurs=0) | ||
|
||
flight = Flight(tail_number="LN-KKA")#Constructor handles field inititailization. | ||
flight.takeoff_airport = Airport(type="IATA", code="WAW") | ||
flight.landing_airport = Airport(type="ICAO", code="EGLL") | ||
|
||
print flight.xml("flight") | ||
#datetime field types will accept, datetime object or string, | ||
#that parses correctly to such object. | ||
flight.takeoff_datetime = datetime.now() | ||
print flight.xml("flight") | ||
|
||
will produce: | ||
<flight tail_number="LN-KKA"> | ||
<takeoff_airport> | ||
<type>IATA</type> | ||
<code>WAW</code> | ||
</takeoff_airport> | ||
<takeoff_datetime>2011-05-06T11:11:23</takeoff_datetime> | ||
<landing_airport> | ||
<type>ICAO</type> | ||
<code>EGLL</code> | ||
</landing_airport> | ||
</flight> | ||
|
||
2. Schema | ||
================= | ||
xsd.Schema is an object that aggregates all informations stored in XSD file. | ||
There two main use cases for this object. It can be used to generate XSD file or | ||
it can be generated from such file. For detail field description see: xsd.Schema | ||
pydoc. Schema instance is required for validation and because SOAP webservice | ||
performs validation is required for service configuration too: See documentation | ||
Defining webservice. | ||
|
||
2.1 Generating code from XSD file. | ||
================================= | ||
py2xsd.py generates Python representation of XML from XSD file. | ||
Example: xsd2py.py Specifications\ops.xsd will generate: | ||
|
||
from ws import xsd | ||
|
||
class Pilot(xsd.String): | ||
enumeration = [ "CAPTAIN", "FIRST_OFFICER", ] | ||
|
||
class Airport(xsd.ComplexType): | ||
INHERITANCE = None | ||
INDICATOR = xsd.Sequence | ||
code_type = xsd.Element(xsd.String( enumeration = | ||
[ "ICAO", "IATA", "FAA",]) ) | ||
code = xsd.Element(xsd.String) | ||
|
||
|
||
class Weight(xsd.ComplexType): | ||
INHERITANCE = None | ||
INDICATOR = xsd.Sequence | ||
value = xsd.Element(xsd.Integer) | ||
unit = xsd.Element(xsd.String( enumeration = | ||
[ "kg", "lb",]) ) | ||
|
||
|
||
class Ops(xsd.ComplexType): | ||
INHERITANCE = None | ||
INDICATOR = xsd.Sequence | ||
aircraft = xsd.Element(xsd.String) | ||
flight_number = xsd.Element(xsd.String) | ||
type = xsd.Element(xsd.String( enumeration = | ||
[ "COMMERCIAL", "INCOMPLETE", "ENGINE_RUN_UP", "TEST", "TRAINING", "FERRY", | ||
"POSITIONING", "LINE_TRAINING",]) ) | ||
takeoff_airport = xsd.Element(Airport) | ||
takeoff_gate_datetime = xsd.Element(xsd.DateTime, minOccurs=0) | ||
takeoff_datetime = xsd.Element(xsd.DateTime) | ||
takeoff_fuel = xsd.Element(Weight, minOccurs=0) | ||
takeoff_gross_weight = xsd.Element(Weight, minOccurs=0) | ||
takeoff_pilot = xsd.Element(Pilot, minOccurs=0) | ||
landing_airport = xsd.Element(Airport) | ||
landing_gate_datetime = xsd.Element(xsd.DateTime, minOccurs=0) | ||
landing_datetime = xsd.Element(xsd.DateTime) | ||
landing_fuel = xsd.Element(Weight, minOccurs=0) | ||
landing_pilot = xsd.Element(Pilot, minOccurs=0) | ||
destination_airport = xsd.Element(Airport, minOccurs=0) | ||
captain_code = xsd.Element(xsd.String, minOccurs=0) | ||
first_officer_code = xsd.Element(xsd.String, minOccurs=0) | ||
V2 = xsd.Element(xsd.Integer, minOccurs=0) | ||
Vref = xsd.Element(xsd.Integer, minOccurs=0) | ||
Vapp = xsd.Element(xsd.Integer, minOccurs=0) | ||
|
||
|
||
class Status(xsd.ComplexType): | ||
INHERITANCE = None | ||
INDICATOR = xsd.Sequence | ||
action = xsd.Element(xsd.String( enumeration = | ||
[ "INSERTED", "UPDATED", "EXISTS",]) ) | ||
id = xsd.Element(xsd.Long) | ||
|
||
Schema = xsd.Schema( | ||
targetNamespace = "http://flightdataservices.com/ops.xsd", | ||
elementFormDefault = "unqualified", | ||
simpleTypes = [ Pilot,], | ||
attributeGroups = [], | ||
groups = [], | ||
complexTypes = [ Airport, Weight, Ops, Status,], | ||
elements = { "status":xsd.Element(Status), "ops":xsd.Element(Ops),}) | ||
|
||
|
||
Let redirect output to the python file. | ||
{{xsd2py.py Specifications\ops.xsd > tmp\ops.py}} | ||
Now calling {{py2xsd.py tmp\ops.py}} will generate equivalent XSD from Python | ||
code. xsd2py script expects schema instance to be defined in global scope | ||
called "Schema", in way similar to one in generated code. | ||
|
||
2. Web service. | ||
======================== | ||
|
||
When WSDL file is provided code can be generated from it. If not, advised | ||
would be to write to code first a then use browser to request it. Accessing | ||
<your webservice context>?wsdl with browser will give current WSDL with XSD | ||
embaded. | ||
|
||
2.1 Generating code from WSDL file | ||
================================== | ||
wsdl2py can generate either client or server code. For server use -s, client -c | ||
flag. | ||
Server example: wsdl2py.py -s Specifications\ops.wsdl | ||
|
||
{{{ | ||
...XSD part truncated... | ||
PutOps_method = xsd.Method(function = PutOps, | ||
soapAction = "http://polaris.flightdataservices.com/ws/ops/PutOps", | ||
input = "ops",#Pointer to Schema.elements | ||
output = "status",#Pointer to Schema.elements | ||
operationName = "PutOps") | ||
|
||
SERVICE = soap.Service( | ||
targetNamespace = "http://flightdataservices.com/ops.wsdl", | ||
location = "http://polaris.flightdataservices.com/ws/ops", | ||
schema = Schema, | ||
methods = [PutOps_method, ]) | ||
|
||
|
||
#Comment this lines for py2xsd generation to avoid error message about | ||
#DJANGO_SETTINGS_MODULE not being set. If authorization is required | ||
#dispatch can be wrapped with login required in way similar to csrf_exempt. | ||
from django.views.decorators.csrf import csrf_exempt | ||
dispatch = csrf_exempt(soap.get_django_dispatch(SERVICE)) | ||
|
||
#Put this lines in your urls.py: | ||
#urlpatterns += patterns('', | ||
# (r"^ws/ops$", "<fill the module path>.dispatch") | ||
#) | ||
}}} | ||
|
||
Generated code has four main items: methods descriptions, Service description, | ||
dispatcher and Django ulrs.py binding. | ||
Method description describes one method for service(that can consist from | ||
more then one method). Methods give dispatcher informations required for method | ||
distinction - soapAction and operationName, and function to call on incoming SOAP message. | ||
For detail field meaning see xsd.Method pydoc. | ||
SERVICE aggregates all informations required for WSDL generation and correct | ||
dispatching. | ||
get_django_dispatch returns a function binded to SERVICE that pointed from | ||
urls.py will call appropriate function on incoming SOAP message. The called function, | ||
in this example PutOps, is expected to return object from XSD that could be translated | ||
to correct and valid response - for this example this would be Status instance. | ||
URLs binding it is commented out, paste this code into your urls.py and change | ||
<fill the module path> to point file where to code was generated. | ||
|
||
2.1 Client | ||
========== | ||
Client can be generated with flag -c: wsdl2py.py -c Specifications\ops.wsdl | ||
|
||
Generated code: | ||
{{{ | ||
...XSD Part truncated ... | ||
PutOps_method = xsd.Method( | ||
soapAction = "http://polaris.flightdataservices.com/ws/ops/PutOps", | ||
input = "ops",#Pointer to Schema.elements | ||
output = "status",#Pointer to Schema.elements | ||
operationName = "PutOps") | ||
|
||
SERVICE = soap.Service( | ||
targetNamespace = "http://flightdataservices.com/ops.wsdl", | ||
location = "http://polaris.flightdataservices.com/ws/ops", | ||
schema = Schema, | ||
methods = [PutOps_method, ]) | ||
|
||
|
||
class ServiceStub(soap.Stub): | ||
SERVICE = SERVICE | ||
|
||
def PutOps(self, ops): | ||
return self.call("PutOps", ops) | ||
}}} | ||
|
||
ServiceStub is a proxy object that defines methods available on remote webservice. | ||
Calling one of those method, in the example there is only one PutOps, will produce SOAP | ||
call to remote server defined in SERVICE. The methods will return appropriate object | ||
from XSD description or raise an exception on any problems. | ||
|
||
For more real example: See docs/example_client.py | ||
|
||
|
||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
#This was was generated by wsdl2py, try to not edit. | ||
from soapbox import soap, xsd | ||
|
||
class Pilot(xsd.String): | ||
enumeration = [ "CAPTAIN", "FIRST_OFFICER", ] | ||
|
||
|
||
class Airport(xsd.ComplexType): | ||
INHERITANCE = None | ||
INDICATOR = xsd.Sequence | ||
code_type = xsd.Element(xsd.String( enumeration = | ||
[ "ICAO", "IATA", "FAA",]) ) | ||
code = xsd.Element(xsd.String) | ||
|
||
|
||
class Weight(xsd.ComplexType): | ||
INHERITANCE = None | ||
INDICATOR = xsd.Sequence | ||
value = xsd.Element(xsd.Integer) | ||
unit = xsd.Element(xsd.String( enumeration = | ||
[ "kg", "lb",]) ) | ||
|
||
|
||
class Ops(xsd.ComplexType): | ||
INHERITANCE = None | ||
INDICATOR = xsd.Sequence | ||
aircraft = xsd.Element(xsd.String) | ||
flight_number = xsd.Element(xsd.String) | ||
type = xsd.Element(xsd.String( enumeration = | ||
[ "COMMERCIAL", "INCOMPLETE", "ENGINE_RUN_UP", "TEST", "TRAINING", "FERRY", "POSITIONING", "LINE_TRAINING",]) ) | ||
takeoff_airport = xsd.Element(Airport) | ||
takeoff_gate_datetime = xsd.Element(xsd.DateTime, minOccurs=0) | ||
takeoff_datetime = xsd.Element(xsd.DateTime) | ||
takeoff_fuel = xsd.Element(Weight, minOccurs=0) | ||
takeoff_gross_weight = xsd.Element(Weight, minOccurs=0) | ||
takeoff_pilot = xsd.Element(Pilot, minOccurs=0) | ||
landing_airport = xsd.Element(Airport) | ||
landing_gate_datetime = xsd.Element(xsd.DateTime, minOccurs=0) | ||
landing_datetime = xsd.Element(xsd.DateTime) | ||
landing_fuel = xsd.Element(Weight, minOccurs=0) | ||
landing_pilot = xsd.Element(Pilot, minOccurs=0) | ||
destination_airport = xsd.Element(Airport, minOccurs=0) | ||
captain_code = xsd.Element(xsd.String, minOccurs=0) | ||
first_officer_code = xsd.Element(xsd.String, minOccurs=0) | ||
V2 = xsd.Element(xsd.Integer, minOccurs=0) | ||
Vref = xsd.Element(xsd.Integer, minOccurs=0) | ||
Vapp = xsd.Element(xsd.Integer, minOccurs=0) | ||
|
||
|
||
class Status(xsd.ComplexType): | ||
INHERITANCE = None | ||
INDICATOR = xsd.Sequence | ||
action = xsd.Element(xsd.String( enumeration = | ||
[ "INSERTED", "UPDATED", "EXISTS",]) ) | ||
id = xsd.Element(xsd.Long) | ||
|
||
Schema = xsd.Schema( | ||
targetNamespace = "http://flightdataservices.com/ops.xsd", | ||
elementFormDefault = "unqualified", | ||
simpleTypes = [ Pilot,], | ||
attributeGroups = [], | ||
groups = [], | ||
complexTypes = [ Airport, Weight, Ops, Status,], | ||
elements = { "ops":xsd.Element(Ops), "status":xsd.Element(Status),}) | ||
|
||
|
||
|
||
PutOps_method = xsd.Method( | ||
soapAction = "http://polaris.flightdataservices.com/ws/ops/PutOps", | ||
input = "ops",#Pointer to Schema.elements | ||
output = "status",#Pointer to Schema.elements | ||
operationName = "PutOps") | ||
|
||
SERVICE = soap.Service( | ||
targetNamespace = "http://flightdataservices.com/ops.wsdl", | ||
location = "http://127.0.0.1:8000/ws/ops", | ||
schema = Schema, | ||
methods = [PutOps_method, ]) | ||
|
||
|
||
class ServiceStub(soap.Stub): | ||
SERVICE = SERVICE | ||
|
||
def PutOps(self, ops): | ||
return self.call("PutOps", ops) | ||
|
||
if __name__ == "__main__": | ||
from datetime import datetime | ||
stub = ServiceStub() | ||
ops = Ops() | ||
ops.aircraft = "LN-KKU" | ||
ops.flight_number = "1234" | ||
ops.type = "COMMERCIAL" | ||
ops.takeoff_airport = Airport(code_type="IATA",code="WAW") | ||
ops.takeoff_datetime = datetime.now() | ||
ops.landing_airport = Airport(code_type="ICAO", code="EGLL") | ||
ops.landing_datetime = datetime.now() | ||
status = stub.PutOps(ops) | ||
print status.action, status.id | ||
|
Oops, something went wrong.