From 2a5615a785167b5a06b1246dda57a399a32447d3 Mon Sep 17 00:00:00 2001 From: Nick Pope Date: Wed, 31 Mar 2021 09:29:36 +0100 Subject: [PATCH] docs: overhaul and add readthedocs support. Resolves #32, resolves #33. --- .readthedocs.yml | 10 +++ CONTRIBUTING.md | 32 ---------- INFORMATION.md | 28 --------- LIMITATIONS.md | 99 ----------------------------- TODO.md | 61 ------------------ docs/conf.py | 35 +---------- docs/contributing.rst | 30 +++++++++ docs/index.rst | 4 ++ docs/limitations.rst | 100 ++++++++++++++++++++++++++++++ docs/middlewares.rst | 43 ++++++++----- docs/requirements.txt | 2 + docs/specifications.rst | 27 ++++++++ docs/todo.rst | 51 +++++++++++++++ docs/tutorial.rst | 134 +++++++++++++++++----------------------- setup.cfg | 5 +- soapfish/xsd_types.py | 3 +- 16 files changed, 318 insertions(+), 346 deletions(-) create mode 100644 .readthedocs.yml delete mode 100644 CONTRIBUTING.md delete mode 100644 INFORMATION.md delete mode 100644 LIMITATIONS.md delete mode 100644 TODO.md create mode 100644 docs/contributing.rst create mode 100644 docs/limitations.rst create mode 100644 docs/requirements.txt create mode 100644 docs/specifications.rst create mode 100644 docs/todo.rst diff --git a/.readthedocs.yml b/.readthedocs.yml new file mode 100644 index 00000000..770dc798 --- /dev/null +++ b/.readthedocs.yml @@ -0,0 +1,10 @@ +version: 2 +formats: all +python: + version: 3.8 + install: + - requirements: docs/requirements.txt +sphinx: + builder: html + configuration: docs/conf.py + fail_on_warning: true diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index bcd745e2..00000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,32 +0,0 @@ -How to Contribute -=================== - -Contributions to the project can take many forms: - -** Document missing features ** -I won't even pretend to understand the XML/XSD semantics completely so there is -a good chance I missed something. -You can help by submitting examples of XML (with the according schema) which -soapfish currently can not handle. Ideally you'd write a unit test which clearly -demonstrates the failure. - -Please try to minimize the sample as much as possible. I know this can be -time-consuming but otherwise another developer has to do it, taking away -precious development time. - - -** Implement missing features ** -Well, of course that's most helpful. - -Some advice about the order in which new features should be implemented: -1. Ensure that you can express the XSD schema using the classes from - soapfish.xsdspec. This is the actual schema representation without any - semantic sugar. -2. Build your schema in soapfish.xsd elements which is the high-level API. Try - to build the object graph as you need. -3. Ensure that the assigned values in the object graph can be parsed and - serialized to XML. -4. Implement XSD generation using your object graph. -5. Implement code-generation based on a pre-built XSD representing your - use-case. - diff --git a/INFORMATION.md b/INFORMATION.md deleted file mode 100644 index 6cdb806a..00000000 --- a/INFORMATION.md +++ /dev/null @@ -1,28 +0,0 @@ -Specifications -============== - -Links to various specifications relevant to the project: - -- [Extensible Markup Language (XML) 1.0 (Fifth Edition)](https://www.w3.org/tr/xml/) -- [Extensible Markup Language (XML) 1.1 (Second Edition)](https://www.w3.org/tr/xml11/) -- [Namespaces in XML 1.0 (Third Edition)](https://www.w3.org/tr/xml-names/) -- [XML Schema Part 0: Primer (Second Edition)](https://www.w3.org/tr/xmlschema-0/) -- [XML Schema Part 1: Structures (Second Edition)](https://www.w3.org/tr/xmlschema-1/) -- [XML Schema Part 2: Datatypes (Second Edition)](https://www.w3.org/tr/xmlschema-2/) -- [Simple Object Access Protocol (SOAP) 1.1](https://www.w3.org/tr/soap11/) -- [Simple Object Access Protocol (SOAP) 1.2 Part 1: Messaging Framework (Second Edition)](https://www.w3.org/tr/soap12-part1/) -- [Simple Object Access Protocol (SOAP) 1.2 Part 2: Adjuncts (Second Edition)](https://www.w3.org/tr/soap12-part2/) -- [Simple Object Access Protocol (SOAP) 1.2 Specific Assertions and Test Collection (Second Edition)](https://www.w3.org/tr/soap12-testcollection/) -- [Web Services Description Language (WSDL) 1.1](https://www.w3.org/tr/wsdl) -- [Web Services Description Language (WSDL) 2.0 Part 0: Primer](https://www.w3.org/tr/wsdl20-primer) -- [Web Services Description Language (WSDL) 2.0 Part 1: Core Language](https://www.w3.org/tr/wsdl20) -- [Web Services Description Language (WSDL) 2.0 Part 2: Adjuncts](https://www.w3.org/tr/wsdl20-adjuncts) -- [Web Services Description Language (WSDL) 2.0 Additional MEPs](https://www.w3.org/tr/wsdl20-additional-meps/) -- [Web Services Addressing 1.0 - Core](https://www.w3.org/tr/ws-addr-core/) -- [Web Services Addressing 1.0 - SOAP Binding](https://www.w3.org/tr/ws-addr-soap/) -- [Web Services Addressing 1.0 - WSDL Binding](https://www.w3.org/tr/ws-addr-wsdl/) -- [Web Services Architecture](https://www.w3.org/tr/ws-arch/) -- [Web Services Security 1.0](https://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0.pdf) -- [Web Services Security 1.1](https://www.oasis-open.org/committees/download.php/16790/wss-v1.1-spec-os-SOAPMessageSecurity.pdf) - -- [WSDL 1.1 Binding Extension for SOAP 1.2](https://www.w3.org/submission/wsdl11soap12/) diff --git a/LIMITATIONS.md b/LIMITATIONS.md deleted file mode 100644 index 12389d7d..00000000 --- a/LIMITATIONS.md +++ /dev/null @@ -1,99 +0,0 @@ -Limitations -=========== - -xsd.Ref() is not serialized ---------------------------- - -XML schema references are not serialized. Below is an example of code that does not generate a valid schema: - -```python -from lxml import etree -from soapfish import py2xsd, xsd - -class Person(xsd.Group): - name = xsd.Element(xsd.String) - surname = xsd.Element(xsd.String) - -class Job(xsd.ComplexType): - title = xsd.Element(xsd.String) - person = xsd.Ref(Person) - -schema = xsd.Schema( - imports=[], - targetNamespace='http://example.com/ws/spec', - elementFormDefault='qualified', - simpleTypes=[], - attributeGroups=[], - groups=[], - complexTypes=[], - elements={'job': xsd.Element(Job())}, -) - -print(etree.tostring(py2xsd.generate_xsd(schema), pretty_print=True)) -``` - -Incorrect XML Schema: - -```xml - - - - - - - - - -``` - -Expected XML Schema: - -```xml - - - - - - - - - - - - - - - - - - -``` - -Valid XML for Expected Schema: - -```xml - - - Software Developer - - Joe - Bloggs - - -``` - -XSDDate does not support full date range ----------------------------------------- - -The XML schema specification does not limit the range of dates representable by -`xs:date`. For example, the values `-2000-03-10` and `20000-04-20` are valid -as far `xs:date` is concerned. Currently `soapfish.xsd_types.XSDDate` is -subclassing Python's standard library `datetime.date` which has a much more -narrow definition. - -Very likely the best solution is to back our implementation with an alternative -date implementation such as [`mxDateTime`](https://pypi.org/project/egenix-mx-base/) -which seems to represent all possible values from `xs:date`. As `mxDateTime` -currently (2014-11-13) uses compiled components (making it harder to install in -some environments) and does not support Python 3 this should likely be an -optional dependency (if at all). diff --git a/TODO.md b/TODO.md deleted file mode 100644 index 99cd22c5..00000000 --- a/TODO.md +++ /dev/null @@ -1,61 +0,0 @@ -To Do -===== - -This project is very, very promising: - -- It is focused on XML and SOAP/WSDL without any compromise. In an ideal world - soapfish works with each and every syntax allowed by these technologies. -- It allows you to have a representation of arbitrary XML including support - for XSD. Parse any XML described by a schema into a nice class-based tree - (and the other way round: serialization is possible as well). -- Because soapfish supports only SOAP and no other remoting protocol (e.g. - ReST-style APIs with JSON) the API is not tied to the lowest common - denominator. You should be able implement any given WSDL. - -Unfortunately we're not there yet. - -This is a typical open source software and XML/SOAP is usually not perceived -as a fun project. So various users added some smaller features which they -needed but typically there are many incomplete implementations above the very -basic layer (the object model to represent XML/XSD programmatically). -On the upside that means there are a lot of ways to improve the code and your -contribution and make a big difference. - -Here some bigger areas which need work: - -- A much more comprehensive set of unit tests -- Implement support for additional web frameworks -- XSD schema generation (object graph to XSD file) has most of its logic in a - very complex Jinja2 template which shows it limits. For example features like - named xs:Elements with embedded anonymous ComplexTypes can not be serialized - to XSD currently. - However the code internally assumes that the class tree and the XSD - representation contain the same information so this can lead to bugs. -- The XSD mapping is currently incomplete: Some types in schemas are not - implemented at all (e.g. xs:date, xs:gYearMonth). Other types might not be - parsed/serialized correctly. Also references to xs:elements are pretty - incomplete right now. -- Generated code (e.g. WSDL handling or XSD mapping) usually has some syntax - errors. Some of them are fixable on their own but often this is because of - other missing features (see above). The output should be usable as - scaffolding though. - -Don't worry if the items on the list above seem to big for you. Just start out -with something small, write tests and contribute them. Even a small (failing) -unit test which demonstrates a current shortcoming is great. - -You might also check out current skipped unit tests which usually represent -missing functionality (though these might not be ideal beginner projects - if -they were trivial to implement I would have done that already). - -All these shortcomings and limitations exist only because of the lack of -time and/or awareness about certain XSD features. The goal of this library is -to fully implement XSD schemas and potentially SOAP/WSDL so patches (with tests) -are always welcome. - -Specific Items --------------- - -- Fix circular dependency of generated schema classes. - -See the **TODO** markers in `soapfish/*.py` for a complete list. diff --git a/docs/conf.py b/docs/conf.py index 01c9eeef..ee993773 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,30 +1,5 @@ -# Soapfish documentation build configuration file, created by -# sphinx-quickstart on Thu Mar 6 16:06:14 2014. -# -# This file is execfile()d with the current directory set to its -# containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -# sys.path.insert(0, os.path.abspath('.')) - -# -- General configuration ------------------------------------------------ - -# If your documentation needs a minimal Sphinx version, state it here. -# needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. extensions = [ - 'sphinx.ext.todo', + 'sphinx.ext.intersphinx', 'sphinx.ext.viewcode', ] @@ -97,15 +72,11 @@ # If true, keep warnings as "system message" paragraphs in the built documents. # keep_warnings = False -# If true, `todo` and `todoList` produce output, else they produce nothing. -todo_include_todos = False - - # -- Options for HTML output ---------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -html_theme = 'alabaster' +html_theme = 'sphinx_rtd_theme' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the @@ -134,7 +105,7 @@ # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] +html_static_path = [] # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied diff --git a/docs/contributing.rst b/docs/contributing.rst new file mode 100644 index 00000000..950f253e --- /dev/null +++ b/docs/contributing.rst @@ -0,0 +1,30 @@ +Contributing +============ + +Contributions to the project can take many forms. + +Document missing features +------------------------- + +I won't even pretend to understand the XML/XSD semantics completely so there is a good chance I missed something. + +You can help by submitting examples of XML (with the according schema) which soapfish currently can not handle. Ideally +you'd write a unit test which clearly demonstrates the failure. + +Please try to minimize the sample as much as possible. We know this can be time-consuming but otherwise another +developer has to do it, taking away precious development time. + +Implement missing features +-------------------------- + +Well, of course that's most helpful. + +Some advice about the order in which new features should be implemented: + +#. Ensure that you can express the XSD schema using the classes from ``soapfish.xsdspec``. This is the actual schema + representation without any semantic sugar. +#. Build your schema in soapfish.xsd elements which is the high-level API. Try to build the object graph as you need. +#. Ensure that the assigned values in the object graph can be parsed and serialized to XML. +#. Implement XSD generation using your object graph. +#. Implement code-generation based on a pre-built XSD representing your use-case. + diff --git a/docs/index.rst b/docs/index.rst index 32e1e667..053100b7 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -8,6 +8,10 @@ Contents: tutorial middlewares + limitations + specifications + contributing + todo Indices and tables ================== diff --git a/docs/limitations.rst b/docs/limitations.rst new file mode 100644 index 00000000..6db0a6c2 --- /dev/null +++ b/docs/limitations.rst @@ -0,0 +1,100 @@ +Limitations +=========== + +``xsd.Ref()`` is not serialized +------------------------------- + +XML schema references are not serialized. Below is an example of code that does not generate a valid schema: + +.. code-block:: python + + from lxml import etree + from soapfish import py2xsd, xsd + + class Person(xsd.Group): + name = xsd.Element(xsd.String) + surname = xsd.Element(xsd.String) + + class Job(xsd.ComplexType): + title = xsd.Element(xsd.String) + person = xsd.Ref(Person) + + schema = xsd.Schema( + imports=[], + targetNamespace='http://example.com/ws/spec', + elementFormDefault='qualified', + simpleTypes=[], + attributeGroups=[], + groups=[], + complexTypes=[], + elements={'job': xsd.Element(Job())}, + ) + + print(etree.tostring(py2xsd.generate_xsd(schema), pretty_print=True)) + +Incorrect XML Schema: + +.. code-block:: xml + + + + + + + + + + + +Expected XML Schema: + +.. code-block:: xml + + + + + + + + + + + + + + + + + + + + +Valid XML for Expected Schema: + +.. code-block:: xml + + + + Software Developer + + Joe + Bloggs + + + +``XSDDate`` does not support full date range +-------------------------------------------- + +The XML schema specification does not limit the range of dates representable by ``xs:date``. For example, the values +``-2000-03-10`` and ``20000-04-20`` are valid as far ``xs:date`` is concerned. Currently ``soapfish.xsd_types.XSDDate`` +is subclassing Python's standard library :py:class:`datetime.date` which has a much more narrow definition. + +Very likely the best solution will be to back our implementation with an alternative ``date`` implementation. diff --git a/docs/middlewares.rst b/docs/middlewares.rst index a616265f..079072bc 100644 --- a/docs/middlewares.rst +++ b/docs/middlewares.rst @@ -1,23 +1,30 @@ Middlewares =========== - Middlewares Overview -------------------- -The soapfish library implements a version of the Rack protocol. As a result, a soapfish dispatcher can have middlewares that may inspect, analyze, or modify the application environment, request, and response before and/or after the method call. - +The soapfish library implements a version of the Rack protocol. As a result, a soapfish dispatcher can have middlewares +that may inspect, analyze, or modify the application environment, request, and response before and/or after the +method call. Middlewares Architecture '''''''''''''''''''''''' -Think of a soapfish dispatcher as an onion. Each layer of the onion is a middleware. When you invoke the dispatcher dispatch() method, the outer-most middleware layer is invoked first. When ready, that middleware layer is responsible for optionally invoking the next middleware layer that it surrounds. This process steps deeper into the onion - through each middleware layer - until the service method is invoked. This stepped process is possible because each middleware layer are callable. When you add new middleware to the dispatcher, the added middleware will become a new outer layer and surround the previous outer middleware layer (if available) or the service method call itself. - +Think of a soapfish dispatcher as an onion. Each layer of the onion is a middleware. When you invoke the dispatcher +``dispatch()`` method, the outer-most middleware layer is invoked first. When ready, that middleware layer is +responsible for optionally invoking the next middleware layer that it surrounds. This process steps deeper into the +onion --- through each middleware layer --- until the service method is invoked. This stepped process is possible +because each middleware layer are callable. When you add new middleware to the dispatcher, the added middleware will +become a new outer layer and surround the previous outer middleware layer (if available) or the service method call +itself. Dispatcher Reference '''''''''''''''''''' -The purpose of a middleware is to inspect, analyze, or modify the application environment, request, and response before and/or after the service method is invoked. It is easy for each middleware to obtain references to the primary dispatcher, its environment, its request, and its response: +The purpose of a middleware is to inspect, analyze, or modify the application environment, request, and response before +and/or after the service method is invoked. It is easy for each middleware to obtain references to the primary +dispatcher, its environment, its request, and its response: .. code-block:: python @@ -29,26 +36,29 @@ The purpose of a middleware is to inspect, analyze, or modify the application en request.soap_body # the parsed soap body request.soap_header # the parsed soap header -Changes made to the environment, request, and response objects will propagate immediately throughout the application and its other middleware layers. - +Changes made to the environment, request, and response objects will propagate immediately throughout the application +and its other middleware layers. Next Middleware Reference ''''''''''''''''''''''''' -Each middleware layer also has a reference to the next inner middleware layer to call with next_call. It is each middleware’s responsibility to optionally call the next middleware. Doing so will allow the request to complete its full life-cycle. If a middleware layer chooses not to call the next inner middleware layer, further inner middleware and the service method itself will not be run. +Each middleware layer also has a reference to the next inner middleware layer to call with next_call. It is each +middleware’s responsibility to optionally call the next middleware. Doing so will allow the request to complete its +full life-cycle. If a middleware layer chooses not to call the next inner middleware layer, further inner middleware +and the service method itself will not be run. .. code-block:: python def my_middleware(request, next_call): return next_call(request) # optionally call the next middleware - How to Use Middleware --------------------- -On the dispatcher instantiation, use the `middlewares` parameter to give a list of middleware, the first middleware in the list will be called first, it is the outer onion. -This is also possible to add middlewares by modifying the list `dispatcher.middlewares`. +On the dispatcher instantiation, use the ``middlewares`` parameter to give a list of middleware, the first middleware +in the list will be called first, it is the outer onion. +This is also possible to add middlewares by modifying the list ``dispatcher.middlewares``. Example Middleware '''''''''''''''''' @@ -69,7 +79,6 @@ This example middleware will log the client IP address. # call next middleware return next_call(request) - Add Middleware '''''''''''''' @@ -83,14 +92,16 @@ Add Middleware # add an inside middleware dispatcher.middlewate.append(get_client_address) - When the example dispatcher above is invoked, the client IP address will be logged. How to Write Middleware ----------------------- -Middleware must be a callable accepting 2 parameters `request` and `next_call` with these exact names. The callable must return a soapfish response object. -You are encouraged to look at soapfish built-in middleware for working examples, e.g. `soapfish.middlewares.ExceptionToSoapFault` or `soapfish.middlewares.ExceptionLogger`. +Middleware must be a callable accepting 2 parameters ``request`` and ``next_call`` with these exact names. The callable +must return a soapfish response object. + +You are encouraged to look at soapfish built-in middleware for working examples, e.g. +``soapfish.middlewares.ExceptionToSoapFault`` or ``soapfish.middlewares.ExceptionLogger``. This example is the most simple implementation of middleware. diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 00000000..cbf1e365 --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,2 @@ +sphinx +sphinx-rtd-theme diff --git a/docs/specifications.rst b/docs/specifications.rst new file mode 100644 index 00000000..615972c6 --- /dev/null +++ b/docs/specifications.rst @@ -0,0 +1,27 @@ +Specifications +============== + +Links to various specifications relevant to the project: + +* `Extensible Markup Language (XML) 1.0 (Fifth Edition) `_ +* `Extensible Markup Language (XML) 1.1 (Second Edition) `_ +* `Namespaces in XML 1.0 (Third Edition) `_ +* `XML Schema Part 0: Primer (Second Edition) `_ +* `XML Schema Part 1: Structures (Second Edition) `_ +* `XML Schema Part 2: Datatypes (Second Edition) `_ +* `Simple Object Access Protocol (SOAP) 1.1 `_ +* `Simple Object Access Protocol (SOAP) 1.2 Part 1: Messaging Framework (Second Edition) `_ +* `Simple Object Access Protocol (SOAP) 1.2 Part 2: Adjuncts (Second Edition) `_ +* `Simple Object Access Protocol (SOAP) 1.2 Specific Assertions and Test Collection (Second Edition) `_ +* `Web Services Description Language (WSDL) 1.1 `_ +* `Web Services Description Language (WSDL) 2.0 Part 0: Primer `_ +* `Web Services Description Language (WSDL) 2.0 Part 1: Core Language `_ +* `Web Services Description Language (WSDL) 2.0 Part 2: Adjuncts `_ +* `Web Services Description Language (WSDL) 2.0 Additional MEPs `_ +* `Web Services Addressing 1.0 - Core `_ +* `Web Services Addressing 1.0 - SOAP Binding `_ +* `Web Services Addressing 1.0 - WSDL Binding `_ +* `Web Services Architecture `_ +* `Web Services Security 1.0 `_ +* `Web Services Security 1.1 `_ +* `WSDL 1.1 Binding Extension for SOAP 1.2 `_ diff --git a/docs/todo.rst b/docs/todo.rst new file mode 100644 index 00000000..1c8d3eab --- /dev/null +++ b/docs/todo.rst @@ -0,0 +1,51 @@ +To Do +===== + +This project is very, very promising: + +- It is focused on XML and SOAP/WSDL without any compromise. In an ideal world soapfish works with each and every + syntax allowed by these technologies. +- It allows you to have a representation of arbitrary XML including support for XSD. Parse any XML described by a + schema into a nice class-based tree (and the other way round: serialization is possible as well). +- Because soapfish supports only SOAP and no other remoting protocol (e.g. ReST-style APIs with JSON) the API is not + tied to the lowest common denominator. You should be able implement any given WSDL. + +Unfortunately we're not there yet. + +This is a typical open source software and XML/SOAP is usually not perceived as a fun project. So various users added +some smaller features which they needed but typically there are many incomplete implementations above the very basic +layer (the object model to represent XML/XSD programmatically). On the upside that means there are a lot of ways to +improve the code and your contribution and make a big difference. + +Here some bigger areas which need work: + +- A much more comprehensive set of unit tests +- Implement support for additional web frameworks +- XSD schema generation (object graph to XSD file) has most of its logic in a very complex Jinja2 template which shows + it limits. For example features like named ``xs:Elements`` with embedded anonymous ``ComplexType``\s can not be + serialized to XSD currently. + However the code internally assumes that the class tree and the XSD representation contain the same information so + this can lead to bugs. +- The XSD mapping is currently incomplete: Some types in schemas are not implemented at all (e.g. ``xs:date``, + ``xs:gYearMonth``). Other types might not be parsed/serialized correctly. Also references to ``xs:elements`` are + pretty incomplete right now. +- Generated code (e.g. WSDL handling or XSD mapping) usually has some syntax errors. Some of them are fixable on their + own but often this is because of other missing features (see above). The output should be usable as scaffolding + though. + +Don't worry if the items on the list above seem to big for you. Just start out with something small, write tests and +contribute them. Even a small (failing) unit test which demonstrates a current shortcoming is great. + +You might also check out current skipped unit tests which usually represent missing functionality (though these might +not be ideal beginner projects --- if they were trivial to implement I would have done that already). + +All these shortcomings and limitations exist only because of the lack of time and/or awareness about certain XSD +features. The goal of this library is to fully implement XSD schemas and potentially SOAP/WSDL so patches (with tests) +are always welcome. + +Specific Items +-------------- + +- Fix circular dependency of generated schema classes. + +See the **TODO** markers in ``soapfish/*.py`` for a complete list. diff --git a/docs/tutorial.rst b/docs/tutorial.rst index 921c420a..08713372 100644 --- a/docs/tutorial.rst +++ b/docs/tutorial.rst @@ -6,12 +6,10 @@ This tutorial assumes some understanding of XML, XSD, WSDL and SOAP. Introduction ------------ -The main purpose of this library is a neat implementation of the SOAP protocol, -but the `soapfish.xsd` module can used for any XML as it gives a means of -mapping XML to an object. The object description generally is similar to fields -in the Django ORM - the static fields that define instance fields. The main -difference would be that type is passed as first parameter, rather than being a -field e.g. +The main purpose of this library is a neat implementation of the SOAP protocol, but the ``soapfish.xsd`` module can +used for any XML as it gives a means of mapping XML to an object. The object description generally is similar to fields +in the Django ORM --- the static fields that define instance fields. The main difference would be that type is passed +as first parameter, rather than being a field, e.g. .. code-block:: python @@ -21,30 +19,25 @@ field e.g. # Soapfish: tail_number = xsd.Element(xsd.String) -`xsd.Element` reflects the nature of the field, elements are fields that will -be wrapped with tags. Other options are `xsd.Attribute`, `xsd.Ref` and -`xsd.ListElement`. For more detail see the documentation string for -`xsd.Element`. As SOAP, WSDL and XSD files are also XML documents the -`soapfish.xsd` module was also used to describe them. The descriptions are -located in `soapfish.xsdspec`, `soapfish.soap` and `soapfish.wsdl`. The -`soapfish.soap` module also provides dispatcher and client Stub. +``xsd.Element`` reflects the nature of the field, elements are fields that will be wrapped with tags. Other options are +``xsd.Attribute``, ``xsd.Ref`` and ``xsd.ListElement``. For more detail see the documentation string for +``xsd.Element``. As SOAP, WSDL and XSD files are also XML documents the ``soapfish.xsd`` module was also used to +describe them. The descriptions are located in ``soapfish.xsdspec``, ``soapfish.soap`` and ``soapfish.wsdl``. The +``soapfish.soap`` module 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. Relevant modules -include `soapfish.py2xsd`, `soapfish.xsd2py`, `soapfish.wsdl2py` and -`soapfish.py2wsdl`. +Other elements included in this tool are translators, that can generate python code from formal description or formal +description from code. Relevant modules include ``soapfish.py2xsd``, ``soapfish.xsd2py``, ``soapfish.wsdl2py`` and +``soapfish.py2wsdl``. -`soapfish.utils` mostly contains helper functions for Jinja2. Jinja2 is -templating engine used for code generation. +``soapfish.utils`` mostly contains helper functions for Jinja2. Jinja2 is a templating engine being used for code +generation. 1. Working with XML ------------------- -The main building blocks are `xsd.ComplexType`, `xsd.Element`, `xsd.Attribute` -and the simple types defined in the `soapfish.xsd` module. `xsd.ComplexType` is -a class that can be extended to define custom types. The main methods defined -for types are `xml()` - translates object into XML - and `parsexml()` - builds -object from XML. +The main building blocks are ``xsd.ComplexType``, ``xsd.Element``, ``xsd.Attribute`` and the simple types defined in +the ``soapfish.xsd`` module. ``xsd.ComplexType`` is a class that can be extended to define custom types. The main +methods defined for types are ``xml()`` - translates object into XML --- and ``parsexml()`` --- builds object from XML. **Example 1: Rendering an object to XML** @@ -69,7 +62,7 @@ object from XML. WAW -Note that `xml()` method takes one parameter - the name of the root tag. +Note that ``xml()`` method takes one parameter --- the name of the root tag. **Example 2: Parsing XML to an object** @@ -135,19 +128,17 @@ Note that `xml()` method takes one parameter - the name of the root tag. 2. Schema --------- -`xsd.Schema` is an object that aggregates all information stored in XSD file. -There two main use cases for this object. It can be used to generate an XSD -file or it can be generated from such file. For detail field description see -the documentation string for `xsd.Schema`. A schema instance is required for -validation and because SOAP webservice performs validation is required for -service configuration too. +``xsd.Schema`` is an object that aggregates all information stored in XSD file. There two main use cases for this +object. It can be used to generate an XSD file or it can be generated from such file. For detail field description see +the documentation string for ``xsd.Schema``. A schema instance is required for validation and because SOAP webservice +performs validation is required for service configuration too. 2.1. Generating code from XSD file '''''''''''''''''''''''''''''''''' -`soapfish.py2xsd` generates a Python representation of an XML from an XSD file. +``soapfish.py2xsd`` generates a Python representation of an XML from an XSD file. -**Example:** `python -m soapfish.xsd2py examples/ops.xsd` +**Example:** ``python -m soapfish.xsd2py examples/ops.xsd`` .. code-block:: python @@ -211,33 +202,33 @@ service configuration too. ) -Redirect the output to a python file: `python -m soapfish.xsd2py examples/ops.xsd > /tmp/ops.py`. +Redirect the output to a python file: ``python -m soapfish.xsd2py examples/ops.xsd > /tmp/ops.py``. -Now calling `python -m soapfish.py2xsd /tmp/ops.py` will generate the -equivalent XSD from the Python code. The `soapfish.xsd2py` script expects a -schema instance to be defined in global scope called "Schema", in a way similar -to one in generated code. +Now calling ``python -m soapfish.py2xsd /tmp/ops.py`` will generate the equivalent XSD from the Python code. The +``soapfish.xsd2py`` script expects a schema instance to be defined in global scope called "Schema", in a way similar to +one in generated code. 3. Web Service -------------- -When a WSDL file is provided server or client code can be generated using the -`soapfish.wsdl2py` script. If not, it is advised to write code first a then use -a browser to request the specification. Accessing your service with the query -string `?wsdl` appended will give the current WSDL with XSD embedded. +When a WSDL file is provided server or client code can be generated using the ``soapfish.wsdl2py`` script. If not, it +is advised to write code first a then use a browser to request the specification. Accessing your service with the query +string ``?wsdl`` appended will give the current WSDL with XSD embedded. 3.1. Generating code from WSDL file ''''''''''''''''''''''''''''''''''' -`soapfish.wsdl2py` can generate either client or server code: +``soapfish.wsdl2py`` can generate either client or server code: - `python -m soapfish.wsdl2py -c examples/ops.wsdl` - `python -m soapfish.wsdl2py -s examples/ops.wsdl` +.. code-block:: sh + + python -m soapfish.wsdl2py -c examples/ops.wsdl + python -m soapfish.wsdl2py -s examples/ops.wsdl 3.1.1. Server ^^^^^^^^^^^^^ -**Example:** `python -m soapfish.wsdl2py -s examples/ops.wsdl` +**Example:** ``python -m soapfish.wsdl2py -s examples/ops.wsdl`` .. code-block:: python @@ -259,29 +250,24 @@ string `?wsdl` appended will give the current WSDL with XSD embedded. ) -Generated code includes methods descriptions, service description, dispatcher -and Django `urls.py` binding. +Generated code includes methods descriptions, service description, dispatcher and Django ``urls.py`` binding. -`xsd.Method` describes one method for service (that can consist from more than -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 the documentation string -for `xsd.Method`. +``xsd.Method`` describes one method for service (that can consist from more than 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 the documentation string for ``xsd.Method``. -`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 a `Status` instance. +``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 a ``Status`` instance. -URLs binding it is commented out, paste this code into your `urls.py` and -change to point file where to code was generated. +URLs binding it is commented out, paste this code into your ``urls.py`` and change ```` to point +file where to code was generated. 3.1.2. Client ^^^^^^^^^^^^^ -**Example:** `python -m soapfish.wsdl2py -c examples/ops.wsdl` +**Example:** ``python -m soapfish.wsdl2py -c examples/ops.wsdl`` .. code-block:: python @@ -308,13 +294,11 @@ change to point file where to code was generated. return self.call('PutOps', ops) -`ServiceStub` is a proxy object that defines methods available on the remote -webservice. Calling one of those methods - 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 encountering any problems. +``ServiceStub`` is a proxy object that defines methods available on the remote webservice. Calling one of those methods +--- 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 encountering any problems. -For more examples see `examples/client.py` +For more examples see ``examples/client.py``. 3.2. Building Webservice '''''''''''''''''''''''' @@ -322,13 +306,12 @@ For more examples see `examples/client.py` The build a webservice we need to define few things: * Classes that would be send via SOAP - * Schema instance that aggregates all classes with name space etc. + * Schema instance that aggregates all classes with name space, etc. * Web service functions and all related informations * Service instance to put everything together * Binding to a URL -Lets build the stock web service that will give a stock price for provided -company code and datetime. +Lets build the stock web service that will give a stock price for provided company code and datetime. 3.2.1. Stack classes ^^^^^^^^^^^^^^^^^^^^ @@ -351,9 +334,8 @@ company code and datetime. }, ) -Note the elements in schema - for this version it is required to create an -element of a specific type and use its string element name as input/output in -Service definitions. WSDL specifications allows also direct use of the type, +Note the elements in schema --- for this version it is required to create an element of a specific type and use its +string element name as input/output in Service definitions. WSDL specifications allows also direct use of the type, which is not covered yet. 3.2.2. Method definition @@ -399,7 +381,7 @@ which is not covered yet. httpd = make_server('', 8000, app) httpd.serve_forever() -Now requesting `http://127.0.0.1:8000/stock?wsdl` will give service specification and SOAP messages like: +Now requesting ``http://127.0.0.1:8000/stock?wsdl`` will give service specification and SOAP messages like: .. code-block:: xml @@ -413,6 +395,6 @@ Now requesting `http://127.0.0.1:8000/stock?wsdl` will give service specificatio -can be sent to http://127.0.0.1:8000/stock. +can be sent to ``http://127.0.0.1:8000/stock``. *The full working example can be found in examples/stock.* diff --git a/setup.cfg b/setup.cfg index 9b949ab0..e6ccb4a9 100644 --- a/setup.cfg +++ b/setup.cfg @@ -8,7 +8,7 @@ author_email = dpowazka@gmail.com maintainer = Felix Schwarz maintainer_email = felix.schwarz@oss.schwarz.eu description = A SOAP library for Python -long_description = file: README.md, AUTHORS.md, CHANGES.md, TODO.md +long_description = file: README.md, AUTHORS.md, CHANGES.md long_description_content_type = text/markdown keywords = soap, wsdl, xsd, xml, schema, web service obsoletes = soapbox @@ -34,6 +34,9 @@ classifiers = Programming Language :: Python :: Implementation :: CPython Topic :: Internet :: WWW/HTTP Topic :: Software Development :: Libraries :: Python Modules +project_urls = + Documentation = https://soapfish.readthedocs.io/ + Source = https://github.com/soapteam/soapfish [options] zip_safe = false diff --git a/soapfish/xsd_types.py b/soapfish/xsd_types.py index 02b5958a..034f0c99 100644 --- a/soapfish/xsd_types.py +++ b/soapfish/xsd_types.py @@ -17,7 +17,8 @@ class XSDDate: Also the schema spec supports "negative" dates (B.C.) and dates with years > 10000. Currently this class only supports dates representable by Python's datetime.date (with an optional time zone - attached) but you should not assume that this will be true forever (see LIMITATIONS.md for further information). + attached) but you should not assume that this will be true forever (see the limitations section in the + documentation for further information). """ def __init__(self, year, month, day, tzinfo=None):