Merging upstream version 0.24.0.

This commit is contained in:
Mathias Behrle 2017-01-31 12:26:10 +01:00
parent 90d4bf5939
commit 5323e146dc
72 changed files with 9058 additions and 1145 deletions

View File

@ -1,19 +0,0 @@
root = true
[*.py]
line_length = 79
multi_line_output = 4
balanced_wrapping = true
known_first_party = zeep,tests
use_parentheses = true
indent_style = space
indent_size = 4
tab_width = 4
[*.yml]
indent_size = 2
shift_width = 2
[Makefile]
indent_style = tab
indent_size = 4

20
.gitignore vendored
View File

@ -1,20 +0,0 @@
*.egg-info
*.pyc
.tox
.coverage
.eggs
.cache
.python-version
.venv
.idea/
/build/
/dist/
/test_clients/
/docs/_build/
/frutsels/
/server/
/htmlcov/
# Editors
.idea/

View File

@ -1,40 +0,0 @@
---
sudo: false
language: python
python:
- '2.7'
- '3.3'
- '3.4'
- '3.5'
- 'pypy'
install:
- |
if [ "$TRAVIS_PYTHON_VERSION" = "pypy" ]; then
export PYENV_ROOT="$HOME/.pyenv"
if [ -f "$PYENV_ROOT/bin/pyenv" ]; then
pushd "$PYENV_ROOT" && git pull && popd
else
rm -rf "$PYENV_ROOT" && git clone --depth 1 https://github.com/yyuu/pyenv.git "$PYENV_ROOT"
fi
export PYPY_VERSION="5.4"
"$PYENV_ROOT/bin/pyenv" install --skip-existing "pypy-$PYPY_VERSION"
virtualenv --python="$PYENV_ROOT/versions/pypy-$PYPY_VERSION/bin/python" "$HOME/virtualenvs/pypy-$PYPY_VERSION"
source "$HOME/virtualenvs/pypy-$PYPY_VERSION/bin/activate"
fi
- pip install codecov
- pip install -e .[test]
script:
- py.test --cov=zeep --cov-report=term-missing
after_success:
- codecov
before_cache:
- rm -rf $HOME/.cache/pip/log
cache:
directories:
- $HOME/.cache/pip

17
CHANGES
View File

@ -1,3 +1,20 @@
0.24.0 (2016-12-16)
-------------------
- Don't fail the parsing of responses if an xsi:type references an non-existing
type. Instead log a message (#273)
- Fix serializing etree.Element instances in the helpers.serialize function
(#255)
- Fix infinite loop during parsing of xsd.Sequence where max_occurs is
unbounded (#256)
- Make the xsd.Element name kwarg required
- Improve handling of the xsd:anyType element when passed instances of
complexType's (#252)
- Silently ignore unsupported binding transports instead of an hard error
(#277)
- Support microseconds for xsd.dateTime and xsd.Time (#280)
- Don't mutate passed values to the zeep operations (#280)
0.23.0 (2016-11-24)
-------------------
- Add Client.set_default_soapheaders() to set soapheaders which are to be used

View File

@ -1,30 +0,0 @@
.PHONY: install clean test retest coverage docs
install:
pip install -e .[docs,test]
pip install bumpversion twine wheel
lint:
flake8 src/ tests/
isort --recursive --check-only --diff src tests
clean:
find . -name '*.pyc' -delete
test:
py.test -vvv
retest:
py.test -vvv --lf
coverage:
py.test --cov=zeep --cov-report=term-missing --cov-report=html
docs:
$(MAKE) -C docs html
release:
pip install twine wheel
rm -rf dist/*
python setup.py sdist bdist_wheel
twine upload -s dist/*

View File

@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: zeep
Version: 0.23.0
Version: 0.24.0
Summary: A modern/fast Python SOAP client based on lxml / requests
Home-page: http://docs.python-zeep.org
Author: Michael van Tellingen
@ -69,8 +69,10 @@ Description: ========================
If you encounter bugs then please `let me know`_ . A copy of the WSDL file if
possible would be most helpful.
I'm also able to offer commercial support. Please contact me at
info@mvantellingen.nl for more information.
I'm also able to offer commercial support. As in contracting work. Please
contact me at info@mvantellingen.nl for more information. If you just have a
random question and don't intent to actually pay me for my support then please
DO NOT email me at that e-mail address but just use stackoverflow or something..
.. _let me know: https://github.com/mvantellingen/python-zeep/issues

View File

@ -84,7 +84,9 @@ Support
If you encounter bugs then please `let me know`_ . A copy of the WSDL file if
possible would be most helpful.
I'm also able to offer commercial support. Please contact me at
info@mvantellingen.nl for more information.
I'm also able to offer commercial support. As in contracting work. Please
contact me at info@mvantellingen.nl for more information. If you just have a
random question and don't intent to actually pay me for my support then please
DO NOT email me at that e-mail address but just use stackoverflow or something..
.. _let me know: https://github.com/mvantellingen/python-zeep/issues

View File

@ -1,216 +0,0 @@
# Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = _build
# User-friendly check for sphinx-build
ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
endif
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
.PHONY: help
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " applehelp to make an Apple Help Book"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " texinfo to make Texinfo files"
@echo " info to make Texinfo files and run them through makeinfo"
@echo " gettext to make PO message catalogs"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " xml to make Docutils-native XML files"
@echo " pseudoxml to make pseudoxml-XML files for display purposes"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
@echo " coverage to run coverage check of the documentation (if enabled)"
.PHONY: clean
clean:
rm -rf $(BUILDDIR)/*
.PHONY: html
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
.PHONY: dirhtml
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
.PHONY: singlehtml
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
.PHONY: pickle
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
.PHONY: json
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
.PHONY: htmlhelp
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
.PHONY: qthelp
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Zeep.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Zeep.qhc"
.PHONY: applehelp
applehelp:
$(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp
@echo
@echo "Build finished. The help book is in $(BUILDDIR)/applehelp."
@echo "N.B. You won't be able to view it unless you put it in" \
"~/Library/Documentation/Help or install it in your application" \
"bundle."
.PHONY: devhelp
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/Zeep"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Zeep"
@echo "# devhelp"
.PHONY: epub
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
.PHONY: latex
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
.PHONY: latexpdf
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
.PHONY: latexpdfja
latexpdfja:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through platex and dvipdfmx..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
.PHONY: text
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
.PHONY: man
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
.PHONY: texinfo
texinfo:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
@echo "Run \`make' in that directory to run these through makeinfo" \
"(use \`make info' here to do that automatically)."
.PHONY: info
info:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo "Running Texinfo files through makeinfo..."
make -C $(BUILDDIR)/texinfo info
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
.PHONY: gettext
gettext:
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
@echo
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
.PHONY: changes
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
.PHONY: linkcheck
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
.PHONY: doctest
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."
.PHONY: coverage
coverage:
$(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage
@echo "Testing of coverage in the sources finished, look at the " \
"results in $(BUILDDIR)/coverage/python.txt."
.PHONY: xml
xml:
$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
@echo
@echo "Build finished. The XML files are in $(BUILDDIR)/xml."
.PHONY: pseudoxml
pseudoxml:
$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
@echo
@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."

View File

@ -1,18 +0,0 @@
<a href="{{ pathto(master_doc) }}">
<img class="logo" src="{{ pathto('_static/zeep-logo.png', 1) }}">
</a>
<p>Zeep is a modern SOAP client for Python</p>
<p>
<iframe src="http://ghbtns.com/github-btn.html?user=mvantellingen&repo=python-zeep&type=watch&count=true&size=large"
allowtransparency="true" frameborder="0" scrolling="0" width="200px" height="35px"></iframe>
</p>
<h3>Links</h3>
<ul>
<li><a href="http://github.com/mvantellingen/python-zeep">Zeep @ GitHub</a></li>
<li><a href="http://pypi.python.org/pypi/zeep">Zeep @ PyPI</a></li>
<li><a href="http://github.com/mvantellingen/python-zeep/issues">Issue Tracker</a></li>
</ul>

View File

@ -1,299 +0,0 @@
# -*- coding: utf-8 -*-
#
# Zeep documentation build configuration file, created by
# sphinx-quickstart on Fri Mar 4 16:51:06 2016.
#
# 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.
import sys
import os
import pkg_resources
# 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.autodoc']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
# source_suffix = ['.rst', '.md']
source_suffix = '.rst'
# The encoding of source files.
#source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'Zeep'
copyright = u'2016, <a href="https://www.mvantellingen.nl/">Michael van Tellingen</a>'
author = u'Michael van Tellingen'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '0.23.0'
release = version
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_build']
# The reST default role (used for this markup: `text`) to use for all
# documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
# 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
autodoc_default_flags = [':members:']
# -- 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'
# 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
# documentation.
html_theme_options = {
'github_user': 'mvantellingen',
'github_banner': True,
'github_repo': 'python-zeep',
'travis_button': True,
'codecov_button': True,
'analytics_id': 'UA-75907833-1',
}
# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
# The name of an image file (relative to this directory) to use as a favicon of
# the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
# 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']
# Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied
# directly to the root of the documentation.
#html_extra_path = []
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
html_sidebars = {
'*': [
'sidebar-intro.html', 'globaltoc.html', 'sourcelink.html',
'searchbox.html'
]
}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
#html_domain_indices = True
# If false, no index is generated.
#html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None
# Language to be used for generating the HTML full-text search index.
# Sphinx supports the following languages:
# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja'
# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr'
#html_search_language = 'en'
# A dictionary with options for the search language support, empty by default.
# Now only 'ja' uses this config value
#html_search_options = {'type': 'default'}
# The name of a javascript file (relative to the configuration directory) that
# implements a search results scorer. If empty, the default will be used.
#html_search_scorer = 'scorer.js'
# Output file base name for HTML help builder.
htmlhelp_basename = 'Zeepdoc'
# -- Options for LaTeX output ---------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
# Latex figure (float) alignment
#'figure_align': 'htbp',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(master_doc, 'Zeep.tex', u'Zeep Documentation',
u'Michael van Tellingen', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# If true, show page references after internal links.
#latex_show_pagerefs = False
# If true, show URL addresses after external links.
#latex_show_urls = False
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_domain_indices = True
# -- Options for manual page output ---------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
(master_doc, 'zeep', u'Zeep Documentation',
[author], 1)
]
# If true, show URL addresses after external links.
#man_show_urls = False
# -- Options for Texinfo output -------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(master_doc, 'Zeep', u'Zeep Documentation',
author, 'Zeep', 'One line description of project.',
'Miscellaneous'),
]
# Documents to append as an appendix to all manuals.
#texinfo_appendices = []
# If false, no module index is generated.
#texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote'
# If true, do not generate a @detailmenu in the "Top" node's menu.
#texinfo_no_detailmenu = False

View File

@ -1,131 +0,0 @@
========================
Zeep: Python SOAP client
========================
A fast and modern Python SOAP client
Highlights:
* Modern codebase compatible with Python 2.7, 3.3, 3.4, 3.5 and PyPy
* Build on top of lxml and requests
* Supports recursive WSDL and XSD documents.
* Supports the xsd:choice and xsd:any elements.
* Uses the defusedxml module for handling potential XML security issues
* Support for WSSE (UsernameToken only for now)
* Experimental support for HTTP bindings
* Experimental support for WS-Addressing headers
* Experimental support for asyncio via aiohttp (Python 3.5+)
Features still in development include:
* WSSE x.509 support (BinarySecurityToken)
* WS Policy support
A simple example:
.. code-block:: python
from zeep import Client
client = Client('http://www.webservicex.net/ConvertSpeed.asmx?WSDL')
result = client.service.ConvertSpeed(
100, 'kilometersPerhour', 'milesPerhour')
assert result == 62.137
Quick Introduction
==================
Zeep inspects the wsdl document and generates the corresponding bindings. This
provides an easy to use programmatic interface to a soap server.
The emphasis is on Soap 1.1 and Soap 1.2, however Zeep also offers experimental
support for HTTP Get and Post bindings.
Parsing the XML documents is done by using the lxml library. This is the most
performant and compliant Python XML library currently available. This results
in major speed benefits when retrieving large soap responses.
The SOAP specifications are unfortunately really vague and leave a lot of
things open for interpretation. Due to this there are a lot of WSDL documents
available which are invalid or SOAP servers which contain bugs. Zeep tries to
be as compatible as possible but there might be cases where you run into
problems. Don't hesitate to submit an issue in this case (please see
:ref:`reporting_bugs`).
Getting started
===============
You can install the latest version of zeep using pip::
pip install zeep
The first thing you generally want to do is inspect the wsdl file you need to
implement. This can be done with::
python -mzeep <wsdl>
See ``python -mzeep --help`` for more information about this command.
.. note:: Since this module hasn't reached 1.0.0 yet their might be minor
releases which introduce backwards compatible changes. While I try
to keep this to a minimum it can still happen. So as always pin the
version of zeep you used (e.g. ``zeep==0.14.0``').
A simple use-case
-----------------
To give you an idea how zeep works a basic example.
.. code-block:: python
import zeep
wsdl = 'http://www.soapclient.com/xml/soapresponder.wsdl'
client = zeep.Client(wsdl=wsdl)
print(client.service.Method1('Zeep', 'is cool'))
The WSDL used above only defines one simple function (``Method1``) which is
made available by zeep via ``client.service.Method1``. It takes two arguments
and returns a string. To get an overview of the services available on the
endpoint you can run the following command in your terminal.
.. code-block:: bash
python -mzeep http://www.soapclient.com/xml/soapresponder.wsdl
More information
================
.. toctree::
:maxdepth: 2
:name: mastertoc
in_depth
datastructures
transport
wsa
wsse
plugins
helpers
reporting_bugs
changes
Support
=======
If you encounter bugs then please `let me know`_ . Please see :doc:`reporting_bugs`
for information how to best report them.
I'm also able to offer commercial support. Please contact me at
info@mvantellingen.nl for more information.
.. _let me know: https://github.com/mvantellingen/python-zeep/issues

View File

@ -1,263 +0,0 @@
@ECHO OFF
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set BUILDDIR=_build
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
set I18NSPHINXOPTS=%SPHINXOPTS% .
if NOT "%PAPER%" == "" (
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
)
if "%1" == "" goto help
if "%1" == "help" (
:help
echo.Please use `make ^<target^>` where ^<target^> is one of
echo. html to make standalone HTML files
echo. dirhtml to make HTML files named index.html in directories
echo. singlehtml to make a single large HTML file
echo. pickle to make pickle files
echo. json to make JSON files
echo. htmlhelp to make HTML files and a HTML help project
echo. qthelp to make HTML files and a qthelp project
echo. devhelp to make HTML files and a Devhelp project
echo. epub to make an epub
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
echo. text to make text files
echo. man to make manual pages
echo. texinfo to make Texinfo files
echo. gettext to make PO message catalogs
echo. changes to make an overview over all changed/added/deprecated items
echo. xml to make Docutils-native XML files
echo. pseudoxml to make pseudoxml-XML files for display purposes
echo. linkcheck to check all external links for integrity
echo. doctest to run all doctests embedded in the documentation if enabled
echo. coverage to run coverage check of the documentation if enabled
goto end
)
if "%1" == "clean" (
for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
del /q /s %BUILDDIR%\*
goto end
)
REM Check if sphinx-build is available and fallback to Python version if any
%SPHINXBUILD% 1>NUL 2>NUL
if errorlevel 9009 goto sphinx_python
goto sphinx_ok
:sphinx_python
set SPHINXBUILD=python -m sphinx.__init__
%SPHINXBUILD% 2> nul
if errorlevel 9009 (
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.http://sphinx-doc.org/
exit /b 1
)
:sphinx_ok
if "%1" == "html" (
%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/html.
goto end
)
if "%1" == "dirhtml" (
%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
goto end
)
if "%1" == "singlehtml" (
%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
goto end
)
if "%1" == "pickle" (
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the pickle files.
goto end
)
if "%1" == "json" (
%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the JSON files.
goto end
)
if "%1" == "htmlhelp" (
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run HTML Help Workshop with the ^
.hhp project file in %BUILDDIR%/htmlhelp.
goto end
)
if "%1" == "qthelp" (
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run "qcollectiongenerator" with the ^
.qhcp project file in %BUILDDIR%/qthelp, like this:
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\Zeep.qhcp
echo.To view the help file:
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\Zeep.ghc
goto end
)
if "%1" == "devhelp" (
%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished.
goto end
)
if "%1" == "epub" (
%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The epub file is in %BUILDDIR%/epub.
goto end
)
if "%1" == "latex" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
if errorlevel 1 exit /b 1
echo.
echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "latexpdf" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
cd %BUILDDIR%/latex
make all-pdf
cd %~dp0
echo.
echo.Build finished; the PDF files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "latexpdfja" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
cd %BUILDDIR%/latex
make all-pdf-ja
cd %~dp0
echo.
echo.Build finished; the PDF files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "text" (
%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The text files are in %BUILDDIR%/text.
goto end
)
if "%1" == "man" (
%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The manual pages are in %BUILDDIR%/man.
goto end
)
if "%1" == "texinfo" (
%SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
goto end
)
if "%1" == "gettext" (
%SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
goto end
)
if "%1" == "changes" (
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
if errorlevel 1 exit /b 1
echo.
echo.The overview file is in %BUILDDIR%/changes.
goto end
)
if "%1" == "linkcheck" (
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
if errorlevel 1 exit /b 1
echo.
echo.Link check complete; look for any errors in the above output ^
or in %BUILDDIR%/linkcheck/output.txt.
goto end
)
if "%1" == "doctest" (
%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
if errorlevel 1 exit /b 1
echo.
echo.Testing of doctests in the sources finished, look at the ^
results in %BUILDDIR%/doctest/output.txt.
goto end
)
if "%1" == "coverage" (
%SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage
if errorlevel 1 exit /b 1
echo.
echo.Testing of coverage in the sources finished, look at the ^
results in %BUILDDIR%/coverage/python.txt.
goto end
)
if "%1" == "xml" (
%SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The XML files are in %BUILDDIR%/xml.
goto end
)
if "%1" == "pseudoxml" (
%SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml.
goto end
)
:end

View File

@ -1,8 +0,0 @@
from __future__ import print_function
import zeep
client = zeep.Client(
wsdl='http://www.webservicex.net/barcode.asmx?WSDL')
response = client.service.Code39('1234', 20, ShowCodeString=True, Title='ZEEP')
print(repr(response))

View File

@ -1,5 +0,0 @@
from zeep.client import Client
# RPC style soap service
client = Client('http://www.soapclient.com/xml/soapresponder.wsdl')
print(client.service.Method1('zeep', 'soap'))

View File

@ -1,7 +0,0 @@
from __future__ import print_function
import zeep
client = zeep.Client(
wsdl='http://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl')
print(client.service.checkVat('NL', '170944128B01'))

View File

@ -1,16 +0,0 @@
from __future__ import print_function
import zeep
client = zeep.Client(
wsdl='http://www.webservicex.net/ConvertSpeed.asmx?WSDL')
client.wsdl.dump()
print (client.service.ConvertSpeed(100, 'kilometersPerhour', 'milesPerhour'))
http_get = client.bind('ConvertSpeeds', 'ConvertSpeedsHttpGet')
http_post = client.bind('ConvertSpeeds', 'ConvertSpeedsHttpPost')
print(http_get.ConvertSpeed(100, 'kilometersPerhour', 'milesPerhour'))
print(http_post.ConvertSpeed(100, 'kilometersPerhour', 'milesPerhour'))

View File

@ -37,7 +37,7 @@ with open('README.rst') as fh:
setup(
name='zeep',
version='0.23.0',
version='0.24.0',
description='A modern/fast Python SOAP client based on lxml / requests',
long_description=long_description,
author="Michael van Tellingen",

View File

@ -0,0 +1,89 @@
Metadata-Version: 1.1
Name: zeep
Version: 0.24.0
Summary: A modern/fast Python SOAP client based on lxml / requests
Home-page: http://docs.python-zeep.org
Author: Michael van Tellingen
Author-email: michaelvantellingen@gmail.com
License: MIT
Description: ========================
Zeep: Python SOAP client
========================
A fast and modern Python SOAP client
| Website: http://docs.python-zeep.org/
| IRC: #python-zeep on Freenode
Highlights:
* Modern codebase compatible with Python 2.7, 3.3, 3.4, 3.5 and PyPy
* Build on top of lxml and requests
* Supports recursive WSDL and XSD documents.
* Supports the xsd:choice and xsd:any elements.
* Uses the defusedxml module for handling potential XML security issues
* Support for WSSE (UsernameToken only for now)
* Experimental support for HTTP bindings
* Experimental support for WS-Addressing headers
* Experimental support for asyncio via aiohttp (Python 3.5+)
Features still in development include:
* WSSE x.509 support (BinarySecurityToken)
* WS Policy support
Please see for more information the documentation at
http://docs.python-zeep.org/
Installation
------------
.. code-block:: bash
pip install zeep
Usage
-----
.. code-block:: python
from zeep import Client
client = Client('tests/wsdl_files/example.rst')
client.service.ping()
To quickly inspect a WSDL file use::
python -mzeep <url-to-wsdl>
Please see the documentation at http://docs.python-zeep.org for more
information.
Support
=======
If you encounter bugs then please `let me know`_ . A copy of the WSDL file if
possible would be most helpful.
I'm also able to offer commercial support. As in contracting work. Please
contact me at info@mvantellingen.nl for more information. If you just have a
random question and don't intent to actually pay me for my support then please
DO NOT email me at that e-mail address but just use stackoverflow or something..
.. _let me know: https://github.com/mvantellingen/python-zeep/issues
Platform: UNKNOWN
Classifier: Development Status :: 4 - Beta
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.3
Classifier: Programming Language :: Python :: 3.4
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy

View File

@ -0,0 +1,110 @@
CHANGES
LICENSE
README.rst
setup.cfg
setup.py
src/zeep/__init__.py
src/zeep/__main__.py
src/zeep/cache.py
src/zeep/client.py
src/zeep/exceptions.py
src/zeep/helpers.py
src/zeep/parser.py
src/zeep/plugins.py
src/zeep/transports.py
src/zeep/utils.py
src/zeep/wsa.py
src/zeep.egg-info/PKG-INFO
src/zeep.egg-info/SOURCES.txt
src/zeep.egg-info/dependency_links.txt
src/zeep.egg-info/not-zip-safe
src/zeep.egg-info/pbr.json
src/zeep.egg-info/requires.txt
src/zeep.egg-info/top_level.txt
src/zeep/asyncio/__init__.py
src/zeep/asyncio/bindings.py
src/zeep/asyncio/transport.py
src/zeep/wsdl/__init__.py
src/zeep/wsdl/definitions.py
src/zeep/wsdl/parse.py
src/zeep/wsdl/utils.py
src/zeep/wsdl/wsdl.py
src/zeep/wsdl/bindings/__init__.py
src/zeep/wsdl/bindings/http.py
src/zeep/wsdl/bindings/soap.py
src/zeep/wsdl/messages/__init__.py
src/zeep/wsdl/messages/base.py
src/zeep/wsdl/messages/http.py
src/zeep/wsdl/messages/mime.py
src/zeep/wsdl/messages/soap.py
src/zeep/wsse/__init__.py
src/zeep/wsse/username.py
src/zeep/wsse/utils.py
src/zeep/xsd/__init__.py
src/zeep/xsd/builtins.py
src/zeep/xsd/const.py
src/zeep/xsd/context.py
src/zeep/xsd/elements.py
src/zeep/xsd/indicators.py
src/zeep/xsd/parser.py
src/zeep/xsd/printer.py
src/zeep/xsd/schema.py
src/zeep/xsd/types.py
src/zeep/xsd/utils.py
src/zeep/xsd/valueobjects.py
src/zeep/xsd/visitor.py
tests/__init__.py
tests/conftest.py
tests/test_cache.py
tests/test_client.py
tests/test_client_factory.py
tests/test_helpers.py
tests/test_main.py
tests/test_pprint.py
tests/test_response.py
tests/test_transports.py
tests/test_wsa.py
tests/test_wsdl.py
tests/test_wsdl_arrays.py
tests/test_wsdl_messages_document.py
tests/test_wsdl_messages_http.py
tests/test_wsdl_messages_rpc.py
tests/test_wsdl_soap.py
tests/test_wsse_username.py
tests/test_wsse_utils.py
tests/test_xsd.py
tests/test_xsd_any.py
tests/test_xsd_attributes.py
tests/test_xsd_builtins.py
tests/test_xsd_choice.py
tests/test_xsd_complex_types.py
tests/test_xsd_extension.py
tests/test_xsd_integration.py
tests/test_xsd_parse.py
tests/test_xsd_schemas.py
tests/test_xsd_signatures.py
tests/test_xsd_simple_types.py
tests/test_xsd_types.py
tests/test_xsd_union.py
tests/test_xsd_valueobjects.py
tests/test_xsd_visitor.py
tests/utils.py
tests/integration/hello_world_recursive.wsdl
tests/integration/hello_world_recursive_import.wsdl
tests/integration/recursive_schema_a.xsd
tests/integration/recursive_schema_b.xsd
tests/integration/recursive_schema_c.xsd
tests/integration/recursive_schema_main.wsdl
tests/integration/test_hello_world_recursive.py
tests/integration/test_http_post.py
tests/integration/test_http_post.wsdl
tests/integration/test_recursive_schema.py
tests/wsdl_files/http.wsdl
tests/wsdl_files/soap-enc.xsd
tests/wsdl_files/soap.wsdl
tests/wsdl_files/soap_header.wsdl
tests/wsdl_files/soap_import_2.wsdl
tests/wsdl_files/soap_import_main.wsdl
tests/wsdl_files/soap_transport_err.wsdl
tests/wsdl_files/test_import_2.xsd
tests/wsdl_files/xmldsig-core-schema.xsd

View File

@ -0,0 +1 @@

View File

@ -0,0 +1 @@

View File

@ -0,0 +1 @@
{"is_release": false, "git_version": "70e9199"}

View File

@ -0,0 +1,23 @@
appdirs>=1.4.0
cached-property>=1.0.0
defusedxml>=0.4.1
isodate>=0.5.4
lxml>=3.0.0
requests>=2.7.0
six>=1.9.0
pytz
[docs]
sphinx>=1.4.0
[test]
freezegun==0.3.7
mock==2.0.0
pretend==1.0.8
pytest-cov==2.3.1
pytest==3.0.2
requests_mock>=0.7.0
isort==4.2.5
flake8==3.0.3
flake8-blind-except==0.1.1
flake8-debugger==1.4.0

View File

@ -0,0 +1 @@
zeep

View File

@ -2,4 +2,4 @@ from zeep.client import Client # noqa
from zeep.transports import Transport # noqa
from zeep.plugins import Plugin # noqa
__version__ = '0.23.0'
__version__ = '0.24.0'

View File

@ -1,5 +1,7 @@
from collections import OrderedDict
from lxml import etree
from zeep.xsd.valueobjects import CompoundValue
@ -8,6 +10,9 @@ def serialize_object(obj):
if obj is None:
return obj
if isinstance(obj, etree._Element):
return obj
if isinstance(obj, list):
return [serialize_object(sub) for sub in obj]

View File

@ -193,7 +193,9 @@ class SoapBinding(Binding):
soap_node = xmlelement.find('soap:binding', namespaces=cls.nsmap)
transport = soap_node.get('transport')
if transport != 'http://schemas.xmlsoap.org/soap/http':
raise NotImplementedError("Only soap/http is supported for now")
raise NotImplementedError(
"The binding transport %s is not supported (only soap/http)" % (
transport))
default_style = soap_node.get('style', 'document')
obj = cls(definitions.wsdl, name, port_name, transport, default_style)

View File

@ -288,6 +288,8 @@ class SoapMessage(ConcreteMessage):
for header_value in headers_value:
if hasattr(header_value, '_xsd_elm'):
header_value._xsd_elm.render(header, header_value)
elif hasattr(header_value, '_xsd_type'):
header_value._xsd_type.render(header, header_value)
elif isinstance(header_value, etree._Element):
header.append(header_value)
else:
@ -298,7 +300,7 @@ class SoapMessage(ConcreteMessage):
"_soapheaders only accepts a dictionary if the wsdl "
"defines the headers.")
headers_value = self.header(**headers_value)
self.header.render(header, headers_value)
self.header.type.render(header, headers_value)
else:
raise ValueError("Invalid value given to _soapheaders")
@ -315,9 +317,11 @@ class SoapMessage(ConcreteMessage):
return {}
def _resolve_header(self, info, definitions, parts):
name = etree.QName(self.nsmap['soap-env'], 'Header')
sequence = xsd.Sequence()
if not info:
return xsd.Element(None, xsd.ComplexType(sequence))
return xsd.Element(name, xsd.ComplexType(sequence))
for item in info:
message_name = item['message'].text
@ -334,7 +338,7 @@ class SoapMessage(ConcreteMessage):
else:
element = xsd.Element(part_name, part.type)
sequence.append(element)
return xsd.Element(None, xsd.ComplexType(sequence))
return xsd.Element(name, xsd.ComplexType(sequence))
class DocumentMessage(SoapMessage):
@ -360,8 +364,10 @@ class DocumentMessage(SoapMessage):
return {'body': result}
def _resolve_body(self, info, definitions, parts):
name = etree.QName(self.nsmap['soap-env'], 'Body')
if not info or not parts:
return xsd.Element(None, xsd.ComplexType([]))
return xsd.Element(name, xsd.ComplexType([]))
# If the part name is omitted then all parts are available under
# the soap:body tag. Otherwise only the part with the given name.
@ -377,8 +383,7 @@ class DocumentMessage(SoapMessage):
if len(sub_elements) > 1:
self._is_body_wrapped = True
return xsd.Element(
None, xsd.ComplexType(xsd.All(sub_elements)))
return xsd.Element(name, xsd.ComplexType(xsd.All(sub_elements)))
else:
self._is_body_wrapped = False
return sub_elements[0]
@ -404,8 +409,9 @@ class RpcMessage(SoapMessage):
name and its namespace is the value of the namespace attribute.
"""
name = etree.QName(self.nsmap['soap-env'], 'Body')
if not info:
return xsd.Element(None, xsd.ComplexType([]))
return xsd.Element(name, xsd.ComplexType([]))
namespace = info['namespace']
if self.type == 'input':

View File

@ -358,7 +358,12 @@ class Definition(object):
binding = None
for binding_class in binding_classes:
if binding_class.match(binding_node):
binding = binding_class.parse(self, binding_node)
try:
binding = binding_class.parse(self, binding_node)
except NotImplementedError as exc:
logger.debug("Ignoring binding: %s", exc)
continue
logger.debug("Adding binding: %s", binding.name.text)
result[binding.name.text] = binding

View File

@ -179,6 +179,8 @@ class DateTime(_BuiltinType):
@check_no_collection
def xmlvalue(self, value):
if value.microsecond:
return isodate.isostrf.strftime(value, '%Y-%m-%dT%H:%M:%S.%f%Z')
return isodate.isostrf.strftime(value, '%Y-%m-%dT%H:%M:%S%Z')
def pythonvalue(self, value):
@ -191,6 +193,8 @@ class Time(_BuiltinType):
@check_no_collection
def xmlvalue(self, value):
if value.microsecond:
return isodate.isostrf.strftime(value, '%H:%M:%S.%f%Z')
return isodate.isostrf.strftime(value, '%H:%M:%S%Z')
def pythonvalue(self, value):
@ -512,6 +516,9 @@ class AnyType(_BuiltinType):
if isinstance(value, AnyObject):
value.xsd_type.render(parent, value.value)
parent.set(xsi_ns('type'), value.xsd_type.qname)
elif hasattr(value, '_xsd_elm'):
value._xsd_elm.render(parent, value)
parent.set(xsi_ns('type'), value._xsd_elm.qname)
else:
parent.text = self.xmlvalue(value)
@ -525,7 +532,12 @@ class AnyType(_BuiltinType):
return None
if xsi_type and schema:
xsd_type = schema.get_type(xsi_type)
xsd_type = schema.get_type(xsi_type, fail_silently=True)
# If we were unable to resolve a type for the xsi:type (due to
# buggy soap servers) then we just return the lxml element.
if not xsd_type:
return xmlelement.getchildren()
# If the xsd_type is xsd:anyType then we will recurs so ignore
# that.

View File

@ -28,13 +28,14 @@ class Base(object):
def is_optional(self):
return self.min_occurs == 0
def parse_args(self, args):
def parse_args(self, args, index=0):
result = {}
if not args:
return result, args
return result, args, index
value = args.pop(0)
return {self.attr_name: value}, args
value = args[index]
index += 1
return {self.attr_name: value}, args, index
def parse_kwargs(self, kwargs, name, available_kwargs):
raise NotImplementedError()
@ -146,7 +147,7 @@ class Any(Base):
self._render_value_item(parent, value)
def _render_value_item(self, parent, value):
if not value:
if value is None: # can be an lxml element
return
# Check if we received a proper value object. If we receive the wrong
@ -202,7 +203,9 @@ class Any(Base):
class Element(Base):
def __init__(self, name, type_=None, min_occurs=1, max_occurs=1,
nillable=False, default=None, is_global=False, attr_name=None):
if name and not isinstance(name, etree.QName):
if name is None:
raise ValueError("name cannot be None", self.__class__)
if not isinstance(name, etree.QName):
name = etree.QName(name)
self.name = name.localname if name else None
@ -264,10 +267,10 @@ class Element(Base):
"""
context = context or XmlParserContext()
instance_type = qname_attr(xmlelement, xsi_ns('type'))
xsd_type = None
if instance_type:
xsd_type = schema.get_type(instance_type)
else:
xsd_type = self.type
xsd_type = schema.get_type(instance_type, fail_silently=True)
xsd_type = xsd_type or self.type
return xsd_type.parse_xmlelement(
xmlelement, schema, allow_none=allow_none, context=context)
@ -343,9 +346,6 @@ class Element(Base):
elm.set(xsi_ns('nil'), 'true')
return
if self.name is None:
return self.type.render(parent, value)
node = etree.SubElement(parent, self.qname)
xsd_type = getattr(value, '_xsd_type', self.type)

View File

@ -97,15 +97,15 @@ class OrderIndicator(Indicator, list):
num += element.accept(values)
return num
def parse_args(self, args):
def parse_args(self, args, index=0):
result = {}
for name, element in self.elements:
if not args:
if index >= len(args):
break
arg = args.pop(0)
result[name] = arg
result[name] = args[index]
index += 1
return result, args
return result, args, index
def parse_kwargs(self, kwargs, name, available_kwargs):
"""Apply the given kwarg to the element.
@ -164,12 +164,7 @@ class OrderIndicator(Indicator, list):
return self
def render(self, parent, value):
"""Create subelements in the given parent object.
To make sure we render values only once the value items are copied
and the rendered attribute is removed from it once it is rendered.
"""
"""Create subelements in the given parent object."""
if not isinstance(value, list):
values = [value]
else:
@ -180,7 +175,6 @@ class OrderIndicator(Indicator, list):
if name:
if name in value:
element_value = value[name]
del value[name]
else:
element_value = None
else:
@ -256,8 +250,9 @@ class Choice(OrderIndicator):
result = []
for i in max_occurs_iter(self.max_occurs):
if len(xmlelements) < 1:
if not xmlelements:
break
for node in list(xmlelements):
# Choose out of multiple
@ -409,7 +404,7 @@ class Choice(OrderIndicator):
else:
num = element.accept(values)
nums.add(num)
return max(nums)
return max(nums) if nums else 0
def _find_element_to_render(self, value):
"""Return a tuple (element, value) for the best matching choice"""
@ -460,6 +455,9 @@ class Sequence(OrderIndicator):
def parse_xmlelements(self, xmlelements, schema, name=None, context=None):
result = []
for item in max_occurs_iter(self.max_occurs):
if not xmlelements:
break
item_result = OrderedDict()
for elm_name, element in self.elements:
item_subresult = element.parse_xmlelements(
@ -516,8 +514,8 @@ class Group(Indicator):
return [('_value_1', self.child)]
return self.child.elements
def parse_args(self, args):
return self.child.parse_args(args)
def parse_args(self, args, index=0):
return self.child.parse_args(args, index)
def parse_kwargs(self, kwargs, name, available_kwargs):
if self.accepts_multiple:

View File

@ -106,7 +106,7 @@ class Schema(object):
"No schema available for the namespace %r."
) % (qname.text, qname.namespace))
def get_type(self, qname):
def get_type(self, qname, fail_silently=False):
"""Return a global xsd.Type object with the given qname"""
qname = self._create_qname(qname)
@ -121,10 +121,15 @@ class Schema(object):
schema = self._get_schema_document(qname.namespace)
return schema.get_type(qname)
except exceptions.NamespaceError:
raise exceptions.NamespaceError((
message = (
"Unable to resolve type %s. " +
"No schema available for the namespace %r."
) % (qname.text, qname.namespace))
) % (qname.text, qname.namespace)
if fail_silently:
logger.info(message)
else:
raise exceptions.NamespaceError(message)
def get_group(self, qname):
"""Return a global xsd.Group object with the given qname"""

View File

@ -355,8 +355,11 @@ class ComplexType(Type):
else:
element.render(parent, element_value)
if xsd_type and xsd_type._xsd_name:
parent.set(xsi_ns('type'), xsd_type._xsd_name)
if xsd_type:
if xsd_type._xsd_name:
parent.set(xsi_ns('type'), xsd_type._xsd_name)
if xsd_type.qname:
parent.set(xsi_ns('type'), xsd_type.qname)
def parse_kwargs(self, kwargs, name, available_kwargs):
value = None

View File

@ -55,6 +55,13 @@ class CompoundValue(object):
def __contains__(self, key):
return self.__values__.__contains__(key)
def __eq__(self, other):
if self.__class__ != other.__class__:
return False
other_values = {key: other[key] for key in other}
return other_values == self.__values__
def __len__(self):
return self.__values__.__len__()
@ -118,21 +125,24 @@ def _process_signature(xsd_type, args, kwargs):
if args:
args = list(args)
num_args = len(args)
index = 0
for element_name, element in xsd_type.elements_nested:
values, args = element.parse_args(args)
values, args, index = element.parse_args(args, index)
if not values:
break
result.update(values)
if args:
for attribute_name, attribute in xsd_type.attributes:
result[attribute_name] = args.pop(0)
if num_args <= index:
break
result[attribute_name] = args[index]
index += 1
if args:
raise TypeError(
"__init__() takes at most %s positional arguments (%s given)" % (
len(result), num_args))
if num_args > index:
raise TypeError(
"__init__() takes at most %s positional arguments (%s given)" % (
len(result), num_args))
# Process the named arguments (sequence/group/all/choice). The
# available_kwargs set is modified in-place.

View File

@ -0,0 +1,34 @@
import os
import pytest
import requests_mock
import zeep
WSDL = os.path.join(os.path.dirname(__file__), 'test_http_post.wsdl')
@pytest.mark.requests
def test_get_urlreplacement():
client = zeep.Client(WSDL)
with requests_mock.mock() as m:
m.get('http://example.com/companyinfo/o1/EUR/', text='<root>Hoi</root>')
result = client.service.o1('EUR')
assert result == 'Hoi'
history = m.request_history[0]
assert history._request.path_url == '/companyinfo/o1/EUR/'
@pytest.mark.requests
def test_post_mime_content():
client = zeep.Client(WSDL, service_name='CompanyInfoService', port_name='Port3')
with requests_mock.mock() as m:
m.post('http://example.com/companyinfo/o1', text='<root>Hoi</root>')
result = client.service.o1('EUR')
assert result == 'Hoi'
history = m.request_history[0]
assert history._request.path_url == '/companyinfo/o1'

View File

@ -0,0 +1,74 @@
<?xml version="1.0"?>
<definitions
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
xmlns:tns="http://test.python-zeep.org/tns/"
targetNamespace="http://test.python-zeep.org/tns/">
<types>
<xsd:schema></xsd:schema>
</types>
<message name="m1">
<part name="tickerSymbol" type="xsd:string"/>
</message>
<message name="m2">
<part name="image" type="xsd:hexBinary"/>
</message>
<portType name="pt1">
<operation name="o1">
<input message="tns:m1"/>
<output message="tns:m2"/>
</operation>
</portType>
<binding name="b1" type="pt1">
<http:binding verb="GET"/>
<operation name="o1">
<http:operation location="/o1/(tickerSymbol)/"/>
<input>
<http:urlReplacement/>
</input>
<output>
<mime:content type="image/gif"/>
<mime:content type="image/jpeg"/>
</output>
</operation>
</binding>
<binding name="b2" type="pt1">
<http:binding verb="GET"/>
<operation name="o1">
<http:operation location="/o1"/>
<input>
<http:urlEncoded/>
</input>
<output>
<mime:content type="image/gif"/>
<mime:content type="image/jpeg"/>
</output>
</operation>
</binding>
<binding name="b3" type="pt1">
<http:binding verb="POST"/>
<operation name="o1">
<http:operation location="/o1"/>
<input>
<mime:content type="application/x-www-form-urlencoded"/>
</input>
<output>
<mime:content type="image/gif"/>
<mime:content type="image/jpeg"/>
</output>
</operation>
</binding>
<service name="CompanyInfoService">
<port name="Port1" binding="tns:b1">
<http:address location="http://example.com/companyinfo"/>
</port>
<port name="Port2" binding="tns:b2">
<http:address location="http://example.com/companyinfo"/>
</port>
<port name="Port3" binding="tns:b3">
<http:address location="http://example.com/companyinfo"/>
</port>
</service>
</definitions>

View File

@ -16,6 +16,12 @@ def test_bind():
assert service
def test_unknown_transport():
client_obj = client.Client('tests/wsdl_files/soap_transport_err.wsdl')
service = client_obj.bind()
assert service
def test_bind_service():
client_obj = client.Client('tests/wsdl_files/soap.wsdl')
service = client_obj.bind('StockQuoteService')
@ -174,13 +180,13 @@ def test_set_context_options_timeout():
@pytest.mark.requests
def test_default_soap_headers():
header = xsd.Element(None, xsd.ComplexType(
header = xsd.ComplexType(
xsd.Sequence([
xsd.Element('{http://tests.python-zeep.org}name', xsd.String()),
xsd.Element('{http://tests.python-zeep.org}password', xsd.String()),
])
))
header_value = header(name='ik', password='geheim')
)
header_value = header(name='ik', password='foo')
client_obj = client.Client('tests/wsdl_files/soap.wsdl')
client_obj.set_default_soapheaders([header_value])
@ -211,20 +217,20 @@ def test_default_soap_headers():
@pytest.mark.requests
def test_default_soap_headers_extra():
header = xsd.Element(None, xsd.ComplexType(
header = xsd.ComplexType(
xsd.Sequence([
xsd.Element('{http://tests.python-zeep.org}name', xsd.String()),
xsd.Element('{http://tests.python-zeep.org}password', xsd.String()),
])
))
)
header_value = header(name='ik', password='geheim')
extra_header = xsd.Element(None, xsd.ComplexType(
extra_header = xsd.ComplexType(
xsd.Sequence([
xsd.Element('{http://tests.python-zeep.org}name', xsd.String()),
xsd.Element('{http://tests.python-zeep.org}password', xsd.String()),
])
))
)
extra_header_value = extra_header(name='ik', password='geheim')
client_obj = client.Client('tests/wsdl_files/soap.wsdl')

View File

@ -0,0 +1,35 @@
import pytest
from zeep import Client
def test_factory_namespace():
client = Client('tests/wsdl_files/soap.wsdl')
factory = client.type_factory('http://example.com/stockquote.xsd')
obj = factory.Address(NameFirst='Michael', NameLast='van Tellingen')
assert obj.NameFirst == 'Michael'
assert obj.NameLast == 'van Tellingen'
def test_factory_ns_auto_prefix():
client = Client('tests/wsdl_files/soap.wsdl')
factory = client.type_factory('ns0')
obj = factory.Address(NameFirst='Michael', NameLast='van Tellingen')
assert obj.NameFirst == 'Michael'
assert obj.NameLast == 'van Tellingen'
def test_factory_ns_custom_prefix():
client = Client('tests/wsdl_files/soap.wsdl')
client.set_ns_prefix('sq', 'http://example.com/stockquote.xsd')
factory = client.type_factory('sq')
obj = factory.Address(NameFirst='Michael', NameLast='van Tellingen')
assert obj.NameFirst == 'Michael'
assert obj.NameLast == 'van Tellingen'
def test_factory_ns_unknown_prefix():
client = Client('tests/wsdl_files/soap.wsdl')
with pytest.raises(ValueError):
client.type_factory('bla')

View File

@ -1,6 +1,6 @@
from lxml import etree
from tests.utils import load_xml
from tests.utils import assert_nodes_equal, load_xml
from zeep import xsd
from zeep.helpers import serialize_object
@ -111,3 +111,39 @@ def test_nested_complex_types():
assert isinstance(result, dict), type(result)
assert isinstance(result['item'], dict), type(result['item'])
assert result['item']['item_1'] == 'foo'
def test_serialize_any_array():
custom_type = xsd.Element(
etree.QName('http://tests.python-zeep.org/', 'authentication'),
xsd.ComplexType(
xsd.Sequence([
xsd.Any(max_occurs=2),
])
))
any_obj = etree.Element('{http://tests.python-zeep.org}lxml')
etree.SubElement(any_obj, 'node').text = 'foo'
obj = custom_type(any_obj)
expected = """
<document>
<ns0:authentication xmlns:ns0="http://tests.python-zeep.org/">
<ns0:lxml xmlns:ns0="http://tests.python-zeep.org">
<node>foo</node>
</ns0:lxml>
</ns0:authentication>
</document>
"""
node = etree.Element('document')
custom_type.render(node, obj)
assert_nodes_equal(expected, node)
schema = xsd.Schema()
obj = custom_type.parse(node.getchildren()[0], schema=schema)
result = serialize_object(obj)
assert result == {
'_value_1': [any_obj],
}

31
tests/test_main.py Normal file
View File

@ -0,0 +1,31 @@
from mock import patch
from pretend import stub
from zeep import __main__, client
def test_main_no_args(monkeypatch):
def mock_init(self, *args, **kwargs):
self.wsdl = stub(dump=lambda: None)
monkeypatch.setattr(client.Client, '__init__', mock_init)
args = __main__.parse_arguments(['foo.wsdl'])
__main__.main(args)
def test_main_extract_auth(monkeypatch):
def mock_init(self, *args, **kwargs):
self.wsdl = stub(dump=lambda: None)
monkeypatch.setattr(client.Client, '__init__', mock_init)
with patch.object(__main__, 'Transport', autospec=True) as mock_transport:
args = __main__.parse_arguments(
['http://user:secret@tests.python-zeep.org/foo.wsdl'])
__main__.main(args)
assert mock_transport.call_count == 1
args, kwargs = mock_transport.call_args
assert kwargs['http_auth'] == ('user', 'secret')

34
tests/test_pprint.py Normal file
View File

@ -0,0 +1,34 @@
from zeep.xsd import printer
def test_dict():
pprint = printer.PrettyPrinter()
data = {
'foo': 'bar',
'foo_2': 'bar',
'foo_3': 'bar',
'foo_4': {
'bar': '1',
'bar': {
'bala': 'qwe',
},
'x': [1, 2, 3, 4],
'y': [],
}
}
pprint.pformat(data)
def test_list():
pprint = printer.PrettyPrinter()
data = [
{
'foo': 'bar',
'foo_2': 'bar',
},
{
'foo': 'bar',
'foo_2': 'bar',
},
]
pprint.pformat(data)

29
tests/test_transports.py Normal file
View File

@ -0,0 +1,29 @@
import pytest
import requests_mock
from pretend import stub
from zeep import cache, transports
@pytest.mark.requests
def test_default_cache():
transport = transports.Transport()
assert isinstance(transport.cache, cache.SqliteCache)
@pytest.mark.requests
def test_no_cache():
transport = transports.Transport(cache=None)
assert transport.cache is None
@pytest.mark.requests
def test_load():
cache = stub(get=lambda url: None, add=lambda url, content: None)
transport = transports.Transport(cache=cache)
with requests_mock.mock() as m:
m.get('http://tests.python-zeep.org/test.xml', text='x')
result = transport.load('http://tests.python-zeep.org/test.xml')
assert result == b'x'

268
tests/test_wsa.py Normal file
View File

@ -0,0 +1,268 @@
import uuid
from pretend import stub
from six import StringIO
from tests.utils import DummyTransport, assert_nodes_equal
from zeep import wsa, wsdl, Client
def test_require_wsa(recwarn, monkeypatch):
monkeypatch.setattr(
uuid, 'uuid4', lambda: uuid.UUID('ada686f9-5995-4088-bea4-239f694b2eaf'))
wsdl_main = StringIO("""
<?xml version="1.0"?>
<wsdl:definitions
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/xsd-main"
xmlns:sec="http://tests.python-zeep.org/wsdl-secondary"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl"
xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/"
targetNamespace="http://tests.python-zeep.org/xsd-main">
<wsdl:types>
<xsd:schema
targetNamespace="http://tests.python-zeep.org/xsd-main"
xmlns:tns="http://tests.python-zeep.org/xsd-main">
<xsd:element name="input" type="xsd:string"/>
<xsd:element name="input2" type="xsd:string"/>
</xsd:schema>
</wsdl:types>
<wsdl:message name="dummyRequest">
<wsdl:part name="response" element="tns:input"/>
</wsdl:message>
<wsdl:message name="dummyResponse">
<wsdl:part name="response" element="tns:input2"/>
</wsdl:message>
<wsdl:portType name="TestPortType">
<wsdl:operation name="TestOperation1">
<wsdl:input message="dummyRequest" wsaw:Action="urn:dummyRequest"/>
<wsdl:output message="dummyResponse" wsaw:Action="urn:dummyResponse"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="TestBinding" type="tns:TestPortType">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="TestOperation1">
<soap:operation soapAction=""/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="TestService">
<wsdl:documentation>Test service</wsdl:documentation>
<wsdl:port name="TestPortType" binding="tns:TestBinding">
<soap:address location="http://tests.python-zeep.org/test"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
""".strip())
client = stub(plugins=[], wsse=None)
transport = DummyTransport()
client = Client(wsdl_main, transport=transport)
binding = client.wsdl.services.get('TestService').ports.get('TestPortType').binding
envelope, headers = binding._create(
'TestOperation1',
args=['foo'],
kwargs={},
client=client,
options={'address': 'http://tests.python-zeep.org/test'})
expected = """
<soap-env:Envelope
xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">
<soap-env:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
<wsa:Action>urn:dummyRequest</wsa:Action>
<wsa:MessageID>urn:uuid:ada686f9-5995-4088-bea4-239f694b2eaf</wsa:MessageID>
<wsa:To>http://tests.python-zeep.org/test</wsa:To>
</soap-env:Header>
<soap-env:Body>
<ns0:input xmlns:ns0="http://tests.python-zeep.org/xsd-main">foo</ns0:input>
</soap-env:Body>
</soap-env:Envelope>
"""
assert_nodes_equal(expected, envelope)
def test_force_wsa(recwarn, monkeypatch):
monkeypatch.setattr(
uuid, 'uuid4', lambda: uuid.UUID('ada686f9-5995-4088-bea4-239f694b2eaf'))
wsdl_main = StringIO("""
<?xml version="1.0"?>
<wsdl:definitions
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/xsd-main"
xmlns:sec="http://tests.python-zeep.org/wsdl-secondary"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/"
targetNamespace="http://tests.python-zeep.org/xsd-main">
<wsdl:types>
<xsd:schema
targetNamespace="http://tests.python-zeep.org/xsd-main"
xmlns:tns="http://tests.python-zeep.org/xsd-main">
<xsd:element name="input" type="xsd:string"/>
<xsd:element name="input2" type="xsd:string"/>
</xsd:schema>
</wsdl:types>
<wsdl:message name="dummyRequest">
<wsdl:part name="response" element="tns:input"/>
</wsdl:message>
<wsdl:message name="dummyResponse">
<wsdl:part name="response" element="tns:input2"/>
</wsdl:message>
<wsdl:portType name="TestPortType">
<wsdl:operation name="TestOperation1">
<wsdl:input message="dummyRequest"/>
<wsdl:output message="dummyResponse"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="TestBinding" type="tns:TestPortType">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="TestOperation1">
<soap:operation soapAction="urn:dummyRequest"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="TestService">
<wsdl:documentation>Test service</wsdl:documentation>
<wsdl:port name="TestPortType" binding="tns:TestBinding">
<soap:address location="http://tests.python-zeep.org/test"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
""".strip())
transport = DummyTransport()
client = Client(wsdl_main, transport=transport, plugins=[wsa.WsAddressingPlugin()])
binding = client.wsdl.services.get('TestService').ports.get('TestPortType').binding
envelope, headers = binding._create(
'TestOperation1',
args=['foo'],
kwargs={},
client=client,
options={'address': 'http://tests.python-zeep.org/test'})
expected = """
<soap-env:Envelope
xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">
<soap-env:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
<wsa:Action>urn:dummyRequest</wsa:Action>
<wsa:MessageID>urn:uuid:ada686f9-5995-4088-bea4-239f694b2eaf</wsa:MessageID>
<wsa:To>http://tests.python-zeep.org/test</wsa:To>
</soap-env:Header>
<soap-env:Body>
<ns0:input xmlns:ns0="http://tests.python-zeep.org/xsd-main">foo</ns0:input>
</soap-env:Body>
</soap-env:Envelope>
"""
assert_nodes_equal(expected, envelope)
def test_force_wsa_soap12(recwarn, monkeypatch):
monkeypatch.setattr(
uuid, 'uuid4', lambda: uuid.UUID('ada686f9-5995-4088-bea4-239f694b2eaf'))
wsdl_main = StringIO("""
<?xml version="1.0"?>
<wsdl:definitions
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/xsd-main"
xmlns:sec="http://tests.python-zeep.org/wsdl-secondary"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap12/"
xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap12/"
targetNamespace="http://tests.python-zeep.org/xsd-main">
<wsdl:types>
<xsd:schema
targetNamespace="http://tests.python-zeep.org/xsd-main"
xmlns:tns="http://tests.python-zeep.org/xsd-main">
<xsd:element name="input" type="xsd:string"/>
<xsd:element name="input2" type="xsd:string"/>
</xsd:schema>
</wsdl:types>
<wsdl:message name="dummyRequest">
<wsdl:part name="response" element="tns:input"/>
</wsdl:message>
<wsdl:message name="dummyResponse">
<wsdl:part name="response" element="tns:input2"/>
</wsdl:message>
<wsdl:portType name="TestPortType">
<wsdl:operation name="TestOperation1">
<wsdl:input message="dummyRequest"/>
<wsdl:output message="dummyResponse"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="TestBinding" type="tns:TestPortType">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="TestOperation1">
<soap:operation soapAction="urn:dummyRequest"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="TestService">
<wsdl:documentation>Test service</wsdl:documentation>
<wsdl:port name="TestPortType" binding="tns:TestBinding">
<soap:address location="http://tests.python-zeep.org/test"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
""".strip())
client = stub(plugins=[wsa.WsAddressingPlugin()], wsse=None)
transport = DummyTransport()
doc = wsdl.Document(wsdl_main, transport)
binding = doc.services.get('TestService').ports.get('TestPortType').binding
envelope, headers = binding._create(
'TestOperation1',
args=['foo'],
kwargs={},
client=client,
options={'address': 'http://tests.python-zeep.org/test'})
expected = """
<soap-env:Envelope
xmlns:soap-env="http://www.w3.org/2003/05/soap-envelope">
<soap-env:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
<wsa:Action>urn:dummyRequest</wsa:Action>
<wsa:MessageID>urn:uuid:ada686f9-5995-4088-bea4-239f694b2eaf</wsa:MessageID>
<wsa:To>http://tests.python-zeep.org/test</wsa:To>
</soap-env:Header>
<soap-env:Body>
<ns0:input xmlns:ns0="http://tests.python-zeep.org/xsd-main">foo</ns0:input>
</soap-env:Body>
</soap-env:Envelope>
"""
assert_nodes_equal(expected, envelope)
assert headers['Content-Type'] == (
'application/soap+xml; charset=utf-8; action="urn:dummyRequest"')

360
tests/test_wsdl_arrays.py Normal file
View File

@ -0,0 +1,360 @@
import io
from lxml import etree
from tests.utils import DummyTransport, assert_nodes_equal, load_xml
from zeep import xsd
def get_transport():
transport = DummyTransport()
transport.bind(
'http://schemas.xmlsoap.org/soap/encoding/',
load_xml(io.open('tests/wsdl_files/soap-enc.xsd', 'r').read().encode('utf-8')))
return transport
def test_simple_type():
schema = xsd.Schema(load_xml("""
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
targetNamespace="http://tests.python-zeep.org/tns">
<xsd:import namespace="http://schemas.xmlsoap.org/soap/encoding/"/>
<xsd:complexType name="ArrayOfString">
<xsd:complexContent>
<xsd:restriction base="SOAP-ENC:Array">
<xsd:attribute ref="SOAP-ENC:arrayType" wsdl:arrayType="xsd:string[]"/>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
</xsd:schema>
"""), transport=get_transport())
ArrayOfString = schema.get_type('ns0:ArrayOfString')
print(ArrayOfString.__dict__)
value = ArrayOfString(['item', 'and', 'even', 'more', 'items'])
node = etree.Element('document')
ArrayOfString.render(node, value)
expected = """
<document>
<item xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">item</item>
<item xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">and</item>
<item xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">even</item>
<item xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">more</item>
<item xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">items</item>
</document>
""" # noqa
assert_nodes_equal(expected, node)
def test_complex_type():
schema = xsd.Schema(load_xml("""
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:tns="http://tests.python-zeep.org/tns"
targetNamespace="http://tests.python-zeep.org/tns">
<xsd:import namespace="http://schemas.xmlsoap.org/soap/encoding/"/>
<xsd:complexType name="ArrayObject">
<xsd:sequence>
<xsd:element name="attr_1" type="xsd:string"/>
<xsd:element name="attr_2" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ArrayOfObject">
<xsd:complexContent>
<xsd:restriction base="SOAP-ENC:Array">
<xsd:sequence>
<xsd:element name="obj" type="tns:ArrayObject" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute ref="SOAP-ENC:arrayType" wsdl:arrayType="tns:ArrayObject[]"/>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
</xsd:schema>
"""), transport=get_transport())
ArrayOfObject = schema.get_type('ns0:ArrayOfObject')
ArrayObject = schema.get_type('ns0:ArrayObject')
value = ArrayOfObject([
ArrayObject(attr_1='attr-1', attr_2='attr-2'),
ArrayObject(attr_1='attr-3', attr_2='attr-4'),
ArrayObject(attr_1='attr-5', attr_2='attr-6'),
])
node = etree.Element('document')
ArrayOfObject.render(node, value)
expected = """
<document>
<obj>
<attr_1>attr-1</attr_1>
<attr_2>attr-2</attr_2>
</obj>
<obj>
<attr_1>attr-3</attr_1>
<attr_2>attr-4</attr_2>
</obj>
<obj>
<attr_1>attr-5</attr_1>
<attr_2>attr-6</attr_2>
</obj>
</document>
"""
assert_nodes_equal(expected, node)
def test_complex_type_without_name():
schema = xsd.Schema(load_xml("""
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:tns="http://tests.python-zeep.org/tns"
targetNamespace="http://tests.python-zeep.org/tns">
<xsd:import namespace="http://schemas.xmlsoap.org/soap/encoding/"/>
<xsd:complexType name="ArrayObject">
<xsd:sequence>
<xsd:element name="attr_1" type="xsd:string"/>
<xsd:element name="attr_2" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ArrayOfObject">
<xsd:complexContent>
<xsd:restriction base="SOAP-ENC:Array">
<xsd:attribute ref="SOAP-ENC:arrayType" wsdl:arrayType="tns:ArrayObject[]"/>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
</xsd:schema>
"""), transport=get_transport())
ArrayOfObject = schema.get_type('ns0:ArrayOfObject')
ArrayObject = schema.get_type('ns0:ArrayObject')
value = ArrayOfObject([
ArrayObject(attr_1='attr-1', attr_2='attr-2'),
ArrayObject(attr_1='attr-3', attr_2='attr-4'),
ArrayObject(attr_1='attr-5', attr_2='attr-6'),
])
node = etree.Element('document')
ArrayOfObject.render(node, value)
expected = """
<document>
<ArrayObject>
<attr_1>attr-1</attr_1>
<attr_2>attr-2</attr_2>
</ArrayObject>
<ArrayObject>
<attr_1>attr-3</attr_1>
<attr_2>attr-4</attr_2>
</ArrayObject>
<ArrayObject>
<attr_1>attr-5</attr_1>
<attr_2>attr-6</attr_2>
</ArrayObject>
</document>
"""
assert_nodes_equal(expected, node)
def test_soap_array_parse_remote_ns():
transport = DummyTransport()
transport.bind(
'http://schemas.xmlsoap.org/soap/encoding/',
load_xml(io.open('tests/wsdl_files/soap-enc.xsd', 'r').read().encode('utf-8')))
schema = xsd.Schema(load_xml("""
<?xml version="1.0"?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
targetNamespace="http://tests.python-zeep.org/"
elementFormDefault="qualified">
<xsd:import namespace="http://schemas.xmlsoap.org/soap/encoding/"/>
<xsd:simpleType name="CountryCodeType">
<xsd:restriction base="xsd:string">
<xsd:length value="2"/>
<xsd:pattern value="[a-zA-Z]{2}"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:complexType name="CountryItemType">
<xsd:sequence>
<xsd:element name="code" type="tns:CountryCodeType"/>
<xsd:element name="name" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CountriesArrayType">
<xsd:complexContent>
<xsd:restriction base="soapenc:Array">
<xsd:attribute ref="soapenc:arrayType" wsdl:arrayType="tns:CountryItemType[]"/>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
<xsd:element name="countries" type="tns:CountriesArrayType"/>
</xsd:schema>
"""), transport)
doc = load_xml("""
<countries
SOAP-ENC:arrayType="ns1:CountryItemType[1]"
xsi:type="ns1:CountriesArrayType"
xmlns:ns1="http://tests.python-zeep.org/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<item xsi:type="ns1:CountryItemType">
<code xsi:type="ns1:CountryCodeType">NL</code>
<name xsi:type="xsd:string">The Netherlands</name>
</item>
</countries>
""")
elm = schema.get_element('ns0:countries')
data = elm.parse(doc, schema)
assert data._value_1[0].code == 'NL'
assert data._value_1[0].name == 'The Netherlands'
def test_wsdl_array_type():
transport = DummyTransport()
transport.bind(
'http://schemas.xmlsoap.org/soap/encoding/',
load_xml(io.open('tests/wsdl_files/soap-enc.xsd', 'r').read().encode('utf-8')))
schema = xsd.Schema(load_xml("""
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
targetNamespace="http://tests.python-zeep.org/"
elementFormDefault="qualified">
<xsd:import namespace="http://schemas.xmlsoap.org/soap/encoding/"/>
<xsd:complexType name="array">
<xsd:complexContent>
<xsd:restriction base="SOAP-ENC:Array">
<xsd:attribute ref="SOAP-ENC:arrayType" wsdl:arrayType="tns:base[]"/>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="base">
<xsd:sequence>
<xsd:element minOccurs="0" name="item_1" type="xsd:string"/>
<xsd:element minOccurs="0" name="item_2" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:element name="array" type="tns:array"/>
</xsd:schema>
"""), transport)
array_elm = schema.get_element('{http://tests.python-zeep.org/}array')
item_type = schema.get_type('{http://tests.python-zeep.org/}base')
item_1 = item_type(item_1='foo_1', item_2='bar_1')
item_2 = item_type(item_1='foo_2', item_2='bar_2')
# array = array_elm([
# xsd.AnyObject(item_type, item_1),
# xsd.AnyObject(item_type, item_2),
# ])
array = array_elm([item_1, item_2])
node = etree.Element('document')
assert array_elm.signature() == (
'_value_1: base[], arrayType: xsd:string, offset: arrayCoordinate, ' +
'id: xsd:ID, href: xsd:anyURI, _attr_1: {}')
array_elm.render(node, array)
expected = """
<document>
<ns0:array xmlns:ns0="http://tests.python-zeep.org/">
<base>
<ns0:item_1>foo_1</ns0:item_1>
<ns0:item_2>bar_1</ns0:item_2>
</base>
<base>
<ns0:item_1>foo_2</ns0:item_1>
<ns0:item_2>bar_2</ns0:item_2>
</base>
</ns0:array>
</document>
"""
assert_nodes_equal(expected, node)
def test_soap_array_parse():
transport = DummyTransport()
transport.bind(
'http://schemas.xmlsoap.org/soap/encoding/',
load_xml(io.open('tests/wsdl_files/soap-enc.xsd', 'r').read().encode('utf-8')))
schema = xsd.Schema(load_xml("""
<?xml version="1.0"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
targetNamespace="http://tests.python-zeep.org/"
elementFormDefault="qualified">
<import namespace="http://schemas.xmlsoap.org/soap/encoding/"/>
<complexType name="FlagDetailsStruct">
<sequence>
<element name="Name">
<simpleType>
<restriction base="string">
<maxLength value="512"/>
</restriction>
</simpleType>
</element>
<element name="Value" type="string"/>
</sequence>
</complexType>
<complexType name="FlagDetailsList">
<complexContent>
<restriction base="soapenc:Array">
<sequence>
<element
name="FlagDetailsStruct" type="tns:FlagDetailsStruct"
minOccurs="0" maxOccurs="unbounded"/>
</sequence>
<attribute ref="soapenc:arrayType" use="required"/>
</restriction>
</complexContent>
</complexType>
<element name="FlagDetailsList" type="tns:FlagDetailsList"/>
</schema>
"""), transport)
doc = load_xml("""
<FlagDetailsList xmlns="http://tests.python-zeep.org/">
<FlagDetailsStruct>
<Name>flag1</Name>
<Value>value1</Value>
</FlagDetailsStruct>
<FlagDetailsStruct>
<Name>flag2</Name>
<Value>value2</Value>
</FlagDetailsStruct>
</FlagDetailsList>
""")
elm = schema.get_element('ns0:FlagDetailsList')
data = elm.parse(doc, schema)
assert data.FlagDetailsStruct[0].Name == 'flag1'
assert data.FlagDetailsStruct[0].Value == 'value1'
assert data.FlagDetailsStruct[1].Name == 'flag2'
assert data.FlagDetailsStruct[1].Value == 'value2'

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,390 @@
from six import StringIO
from tests.utils import assert_nodes_equal, load_xml
from zeep.wsdl import wsdl
##
# URLEncoded Message
#
def test_urlencoded_serialize():
wsdl_content = StringIO("""
<definitions xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:tns="http://tests.python-zeep.org/tns"
xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://tests.python-zeep.org/tns">
<message name="Input">
<part name="arg1" type="xsd:string"/>
<part name="arg2" type="xsd:string"/>
</message>
<message name="Output">
<part name="Body" type="xsd:string"/>
</message>
<portType name="TestPortType">
<operation name="TestOperation">
<input message="Input"/>
<output message="Output"/>
</operation>
</portType>
<binding name="TestBinding" type="tns:TestPortType">
<http:binding verb="POST"/>
<operation name="TestOperation">
<http:operation location="test-operation"/>
<input>
<http:urlEncoded/>
</input>
<output>
<mime:mimeXml part="Body"/>
</output>
</operation>
</binding>
</definitions>
""".strip())
root = wsdl.Document(wsdl_content, None)
binding = root.bindings['{http://tests.python-zeep.org/tns}TestBinding']
operation = binding.get('TestOperation')
assert operation.input.body.signature() == 'arg1: xsd:string, arg2: xsd:string'
assert operation.input.signature(as_output=False) == 'arg1: xsd:string, arg2: xsd:string'
assert operation.output.body.signature() == 'Body: xsd:string'
assert operation.output.signature(as_output=True) == 'xsd:string'
serialized = operation.input.serialize(arg1='ah1', arg2='ah2')
assert serialized.headers == {'Content-Type': 'text/xml; charset=utf-8'}
assert serialized.path == 'test-operation'
assert serialized.content == {'arg1': 'ah1', 'arg2': 'ah2'}
##
# URLReplacement Message
#
def test_urlreplacement_serialize():
wsdl_content = StringIO("""
<definitions xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:tns="http://tests.python-zeep.org/tns"
xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://tests.python-zeep.org/tns">
<message name="Input">
<part name="arg1" type="xsd:string"/>
<part name="arg2" type="xsd:string"/>
</message>
<message name="Output">
<part name="Body" type="xsd:string"/>
</message>
<portType name="TestPortType">
<operation name="TestOperation">
<input message="Input"/>
<output message="Output"/>
</operation>
</portType>
<binding name="TestBinding" type="tns:TestPortType">
<http:binding verb="POST"/>
<operation name="TestOperation">
<http:operation location="test-operation/(arg1)/(arg2)/"/>
<input>
<http:urlReplacement/>
</input>
<output>
<mime:mimeXml part="Body"/>
</output>
</operation>
</binding>
</definitions>
""".strip())
root = wsdl.Document(wsdl_content, None)
binding = root.bindings['{http://tests.python-zeep.org/tns}TestBinding']
operation = binding.get('TestOperation')
assert operation.input.body.signature() == 'arg1: xsd:string, arg2: xsd:string'
assert operation.input.signature(as_output=False) == 'arg1: xsd:string, arg2: xsd:string'
assert operation.output.body.signature() == 'Body: xsd:string'
assert operation.output.signature(as_output=True) == 'xsd:string'
serialized = operation.input.serialize(arg1='ah1', arg2='ah2')
assert serialized.headers == {'Content-Type': 'text/xml; charset=utf-8'}
assert serialized.path == 'test-operation/ah1/ah2/'
assert serialized.content == ''
##
# MimeContent Message
#
def test_mime_content_serialize_form_urlencoded():
wsdl_content = StringIO("""
<definitions xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:tns="http://tests.python-zeep.org/tns"
xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://tests.python-zeep.org/tns">
<message name="Input">
<part name="arg1" type="xsd:string"/>
<part name="arg2" type="xsd:string"/>
</message>
<message name="Output">
<part name="Body" type="xsd:string"/>
</message>
<portType name="TestPortType">
<operation name="TestOperation">
<input message="Input"/>
<output message="Output"/>
</operation>
</portType>
<binding name="TestBinding" type="tns:TestPortType">
<http:binding verb="POST"/>
<operation name="TestOperation">
<http:operation location="test-operation"/>
<input>
<mime:content type="application/x-www-form-urlencoded"/>
</input>
<output>
<mime:mimeXml part="Body"/>
</output>
</operation>
</binding>
</definitions>
""".strip())
root = wsdl.Document(wsdl_content, None)
binding = root.bindings['{http://tests.python-zeep.org/tns}TestBinding']
operation = binding.get('TestOperation')
assert operation.input.body.signature() == 'arg1: xsd:string, arg2: xsd:string'
assert operation.input.signature(as_output=False) == 'arg1: xsd:string, arg2: xsd:string'
assert operation.output.body.signature() == 'Body: xsd:string'
assert operation.output.signature(as_output=True) == 'xsd:string'
serialized = operation.input.serialize(arg1='ah1', arg2='ah2')
assert serialized.headers == {'Content-Type': 'application/x-www-form-urlencoded'}
assert serialized.path == 'test-operation'
assert serialized.content == 'arg1=ah1&arg2=ah2'
def test_mime_content_serialize_text_xml():
wsdl_content = StringIO("""
<definitions xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:tns="http://tests.python-zeep.org/tns"
xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://tests.python-zeep.org/tns">
<message name="Input">
<part name="arg1" type="xsd:string"/>
<part name="arg2" type="xsd:string"/>
</message>
<message name="Output">
<part name="Body" type="xsd:string"/>
</message>
<portType name="TestPortType">
<operation name="TestOperation">
<input message="Input"/>
<output message="Output"/>
</operation>
</portType>
<binding name="TestBinding" type="tns:TestPortType">
<http:binding verb="POST"/>
<operation name="TestOperation">
<http:operation location="test-operation"/>
<input>
<mime:content type="text/xml"/>
</input>
<output>
<mime:mimeXml part="Body"/>
</output>
</operation>
</binding>
</definitions>
""".strip())
root = wsdl.Document(wsdl_content, None)
binding = root.bindings['{http://tests.python-zeep.org/tns}TestBinding']
operation = binding.get('TestOperation')
assert operation.input.body.signature() == 'arg1: xsd:string, arg2: xsd:string'
assert operation.input.signature(as_output=False) == 'arg1: xsd:string, arg2: xsd:string'
assert operation.output.body.signature() == 'Body: xsd:string'
assert operation.output.signature(as_output=True) == 'xsd:string'
serialized = operation.input.serialize(arg1='ah1', arg2='ah2')
assert serialized.headers == {'Content-Type': 'text/xml'}
assert serialized.path == 'test-operation'
assert_nodes_equal(
load_xml(serialized.content),
load_xml("<TestOperation><arg1>ah1</arg1><arg2>ah2</arg2></TestOperation>"))
def test_mime_content_no_parts():
wsdl_content = StringIO("""
<definitions xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:tns="http://tests.python-zeep.org/tns"
xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://tests.python-zeep.org/tns">
<message name="Input"/>
<message name="Output">
<part name="Body" type="xsd:string"/>
</message>
<portType name="TestPortType">
<operation name="TestOperation">
<input message="Input"/>
<output message="Output"/>
</operation>
</portType>
<binding name="TestBinding" type="tns:TestPortType">
<http:binding verb="POST"/>
<operation name="TestOperation">
<http:operation location="/test-operation"/>
<input>
<mime:content type="application/x-www-form-urlencoded"/>
</input>
<output>
<mime:mimeXml part="Body"/>
</output>
</operation>
</binding>
</definitions>
""".strip())
root = wsdl.Document(wsdl_content, None)
binding = root.bindings['{http://tests.python-zeep.org/tns}TestBinding']
operation = binding.get('TestOperation')
assert operation.input.signature() == ''
serialized = operation.input.serialize()
assert serialized.content == ''
def test_mime_xml_deserialize():
wsdl_content = StringIO("""
<definitions xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:tns="http://tests.python-zeep.org/tns"
xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://tests.python-zeep.org/tns">
<types>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/tns"
targetNamespace="http://tests.python-zeep.org/tns"
elementFormDefault="qualified">
<xsd:element name="response">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="item_1" type="xsd:string"/>
<xsd:element name="item_2" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
</types>
<message name="Input">
<part name="arg1" type="xsd:string"/>
<part name="arg2" type="xsd:string"/>
</message>
<message name="Output">
<part name="Body" element="tns:response"/>
</message>
<portType name="TestPortType">
<operation name="TestOperation">
<input message="Input"/>
<output message="Output"/>
</operation>
</portType>
<binding name="TestBinding" type="tns:TestPortType">
<http:binding verb="POST"/>
<operation name="TestOperation">
<http:operation location="/test-operation"/>
<input>
<mime:content type="application/x-www-form-urlencoded"/>
</input>
<output>
<mime:mimeXml part="Body"/>
</output>
</operation>
</binding>
</definitions>
""".strip())
root = wsdl.Document(wsdl_content, None)
binding = root.bindings['{http://tests.python-zeep.org/tns}TestBinding']
operation = binding.get('TestOperation')
assert operation.input.signature() == 'arg1: xsd:string, arg2: xsd:string'
assert operation.output.signature(as_output=True) == (
'item_1: xsd:string, item_2: xsd:string')
node = """
<response xmlns="http://tests.python-zeep.org/tns">
<item_1>foo</item_1>
<item_2>bar</item_2>
</response>
""".strip()
serialized = operation.output.deserialize(node)
assert serialized.item_1 == 'foo'
assert serialized.item_2 == 'bar'
def test_mime_multipart_parse():
load_xml("""
<output
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/">
<mime:multipartRelated>
<mime:part>
<soap:body parts="body" use="literal"/>
</mime:part>
<mime:part>
<mime:content part="test" type="text/html"/>
</mime:part>
<mime:part>
<mime:content part="logo" type="image/gif"/>
<mime:content part="logo" type="image/jpeg"/>
</mime:part>
</mime:multipartRelated>
</output>
""")

View File

@ -0,0 +1,434 @@
import io
from six import StringIO
from tests.utils import DummyTransport, assert_nodes_equal, load_xml
from zeep.wsdl import wsdl
def test_serialize():
wsdl_content = StringIO("""
<definitions xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:tns="http://tests.python-zeep.org/tns"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://tests.python-zeep.org/tns">
<message name="Input">
<part name="arg1" type="xsd:string"/>
<part name="arg2" type="xsd:string"/>
</message>
<portType name="TestPortType">
<operation name="TestOperation">
<input message="Input"/>
</operation>
</portType>
<binding name="TestBinding" type="tns:TestPortType">
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="TestOperation">
<soap:operation soapAction=""/>
<input>
<soap:body use="encoded"
namespace="http://test.python-zeep.org/tests/rpc"/>
</input>
</operation>
</binding>
</definitions>
""".strip())
root = wsdl.Document(wsdl_content, None)
binding = root.bindings['{http://tests.python-zeep.org/tns}TestBinding']
operation = binding.get('TestOperation')
assert operation.input.signature() == 'arg1: xsd:string, arg2: xsd:string'
serialized = operation.input.serialize(arg1='ah1', arg2='ah2')
expected = """
<?xml version="1.0"?>
<soap-env:Envelope
xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">
<soap-env:Body>
<ns0:TestOperation xmlns:ns0="http://test.python-zeep.org/tests/rpc">
<arg1>ah1</arg1>
<arg2>ah2</arg2>
</ns0:TestOperation>
</soap-env:Body>
</soap-env:Envelope>
"""
assert_nodes_equal(expected, serialized.content)
def test_serialize_empty_input():
wsdl_content = StringIO("""
<definitions xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:tns="http://tests.python-zeep.org/tns"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://tests.python-zeep.org/tns">
<portType name="TestPortType">
<operation name="TestOperation">
<input message="tns:TestOperationRequests"/>
</operation>
</portType>
<message name="TestOperationRequests"/>
<binding name="TestBinding" type="tns:TestPortType">
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="TestOperation">
<soap:operation soapAction=""/>
<input>
<soap:body use="encoded"
namespace="http://test.python-zeep.org/tests/rpc"/>
</input>
</operation>
</binding>
</definitions>
""".strip())
root = wsdl.Document(wsdl_content, None)
binding = root.bindings['{http://tests.python-zeep.org/tns}TestBinding']
operation = binding.get('TestOperation')
serialized = operation.input.serialize()
expected = """
<?xml version="1.0"?>
<soap-env:Envelope
xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">
<soap-env:Body>
<ns0:TestOperation xmlns:ns0="http://test.python-zeep.org/tests/rpc"/>
</soap-env:Body>
</soap-env:Envelope>
"""
assert_nodes_equal(expected, serialized.content)
def test_deserialize():
wsdl_content = StringIO("""
<definitions xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:tns="http://tests.python-zeep.org/tns"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://tests.python-zeep.org/tns">
<message name="Output">
<part name="result" type="xsd:string"/>
</message>
<portType name="TestPortType">
<operation name="TestOperation">
<output message="Output"/>
</operation>
</portType>
<binding name="TestBinding" type="tns:TestPortType">
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="TestOperation">
<soap:operation soapAction=""/>
<output>
<soap:body use="encoded"
namespace="http://test.python-zeep.org/tests/rpc"/>
</output>
</operation>
</binding>
</definitions>
""".strip())
root = wsdl.Document(wsdl_content, None)
binding = root.bindings['{http://tests.python-zeep.org/tns}TestBinding']
operation = binding.get('TestOperation')
document = load_xml("""
<soap-env:Envelope
xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">
<soap-env:Body>
<ns0:Output xmlns:ns0="http://test.python-zeep.org/tests/rpc">
<result>ah1</result>
</ns0:Output>
</soap-env:Body>
</soap-env:Envelope>
""")
assert operation.output.signature(True) == 'body: {result: xsd:string}, header: {}'
result = operation.output.deserialize(document)
assert result == 'ah1'
def test_wsdl_array_of_simple_types():
wsdl_content = StringIO("""
<definitions xmlns="http://schemas.xmlsoap.org/wsdl/"
targetNamespace="http://tests.python-zeep.org/tns"
xmlns:tns="http://tests.python-zeep.org/tns"
xmlns:impl="http://tests.python-zeep.org/tns"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">
<types>
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://tests.python-zeep.org/tns">
<complexType name="ArrayOfString">
<complexContent>
<restriction base="soapenc:Array">
<attribute ref="soapenc:arrayType" wsdl:arrayType="xsd:string[]"/>
</restriction>
</complexContent>
</complexType>
</schema>
</types>
<portType name="SimpleTypeArrayPortType">
<operation name="getSimpleArray">
<input message="tns:getSimpleArrayRequest"/>
<output message="tns:getSimpleArrayResponse"/>
</operation>
</portType>
<binding name="SimpleTypeArrayBinding" type="tns:SimpleTypeArrayPortType">
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="getSimpleArray">
<soap:operation soapAction=""/>
<input>
<soap:body use="encoded" namespace="http://tests.python-zeep.org/tns" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
</input>
<output>
<soap:body parts="return" use="encoded" namespace="http://tests.python-zeep.org/tns" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
</output>
</operation>
</binding>
<message name="getSimpleArrayRequest"/>
<message name="getSimpleArrayResponse">
<part name="return" type="tns:ArrayOfString"/>
</message>
</definitions>
""".strip()) # noqa
transport = DummyTransport()
transport.bind(
'http://schemas.xmlsoap.org/soap/encoding/',
load_xml(io.open('tests/wsdl_files/soap-enc.xsd', 'r').read().encode('utf-8')))
root = wsdl.Document(wsdl_content, transport)
binding = root.bindings['{http://tests.python-zeep.org/tns}SimpleTypeArrayBinding']
operation = binding.get('getSimpleArray')
document = load_xml("""
<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ns1="http://tests.python-zeep.org/tns"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Body>
<ns1:getSimpleArrayResponse>
<return SOAP-ENC:arrayType="xsd:string[16]" xsi:type="ns1:ArrayOfString">
<item xsi:type="xsd:string">item</item>
<item xsi:type="xsd:string">and</item>
<item xsi:type="xsd:string">even</item>
<item xsi:type="xsd:string">more</item>
<item xsi:type="xsd:string">items</item>
</return>
</ns1:getSimpleArrayResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
""")
deserialized = operation.output.deserialize(document)
assert deserialized == ['item', 'and', 'even', 'more', 'items']
def test_handle_incorrectly_qualified():
# Based on #176
wsdl_content = StringIO("""
<?xml version="1.0"?>
<wsdl:definitions
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:tns="http://tests.python-zeep.org/tns"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://tests.python-zeep.org/tns">
<wsdl:message name="getResponse">
<wsdl:part name="getItemReturn" type="xsd:string"/>
</wsdl:message>
<wsdl:message name="getRequest"></wsdl:message>
<wsdl:portType name="Test">
<wsdl:operation name="getItem">
<wsdl:input message="tns:getRequest" name="getRequest"/>
<wsdl:output message="tns:getResponse" name="getResponse"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="TestSoapBinding" type="tns:Test">
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="getItem">
<soap:operation soapAction=""/>
<wsdl:input name="getRequest">
<soap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="http://tests.python-zeep.org/tns" use="encoded"/>
</wsdl:input>
<wsdl:output name="getResponse">
<soap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="http://tests.python-zeep.org/tns" use="encoded"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="TestService">
<wsdl:port binding="tns:TestSoapBinding" name="Test">
<soap:address location="http://test.python-zeeo.org/rpc"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
""".strip())
transport = DummyTransport()
root = wsdl.Document(wsdl_content, transport)
binding = root.bindings['{http://tests.python-zeep.org/tns}TestSoapBinding']
operation = binding.get('getItem')
document = load_xml("""
<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<ns1:getResponse
soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:ns1="http://tests.python-zeep.org/tns">
<ns1:getItemReturn xsi:type="xsd:string">foobar</ns1:getItemReturn>
</ns1:getResponse>
</soapenv:Body>
</soapenv:Envelope>
""")
deserialized = operation.output.deserialize(document)
assert deserialized == 'foobar'
def test_deserialize_rpc_literal():
# Based on #219
wsdl_content = StringIO("""
<?xml version="1.0"?>
<wsdl:definitions
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:tns="http://tests.python-zeep.org/tns"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://tests.python-zeep.org/tns">
<wsdl:message name="getItemSoapIn"></wsdl:message>
<wsdl:message name="getItemSoapOut">
<wsdl:part name="getItemReturn" type="xsd:string"/>
</wsdl:message>
<wsdl:portType name="Test">
<wsdl:operation name="getItem">
<wsdl:input message="tns:getItemSoapIn"/>
<wsdl:output message="tns:getItemSoapOut"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="TestSoapBinding" type="tns:Test">
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="getItem">
<soap:operation soapAction=""/>
<wsdl:input>
<soap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="http://tests.python-zeep.org/tns" use="encoded"/>
</wsdl:input>
<wsdl:output>
<soap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="http://tests.python-zeep.org/tns" use="encoded"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="TestService">
<wsdl:port binding="tns:TestSoapBinding" name="Test">
<soap:address location="http://test.python-zeeo.org/rpc"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
""".strip())
transport = DummyTransport()
root = wsdl.Document(wsdl_content, transport)
binding = root.bindings['{http://tests.python-zeep.org/tns}TestSoapBinding']
operation = binding.get('getItem')
document = load_xml("""
<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<ns1:getItemResponse
soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:ns1="http://tests.python-zeep.org/tns">
<ns1:getItemReturn xsi:type="xsd:string">foobar</ns1:getItemReturn>
</ns1:getItemResponse>
</soapenv:Body>
</soapenv:Envelope>
""")
deserialized = operation.output.deserialize(document)
assert deserialized == 'foobar'
def test_deserialize():
wsdl_content = StringIO("""
<definitions xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:tns="http://tests.python-zeep.org/tns"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata"
targetNamespace="http://tests.python-zeep.org/tns">
<message name="clearFoo">
<part name="code" type="xsd:string"/>
</message>
<message name="clearFooResponse"/>
<portType name="TestPortType">
<operation name="clearFoo">
<input wsam:Action="http://foo.services.example.com/Util/clearFooRequest" message="tns:clearFoo"/>
<output wsam:Action="http://foo.services.example.com/Util/clearFooResponse" message="tns:clearFooResponse"/>
</operation>
</portType>
<binding name="TestBinding" type="tns:TestPortType">
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="clearFoo">
<soap:operation soapAction=""/>
<input>
<soap:body use="literal" namespace="http://foo.services.example.com/"/>
</input>
<output>
<soap:body use="literal" namespace="http://foo.services.example.com/"/>
</output>
</operation>
</binding>
</definitions>
""".strip())
root = wsdl.Document(wsdl_content, None)
binding = root.bindings['{http://tests.python-zeep.org/tns}TestBinding']
operation = binding.get('clearFoo')
document = load_xml("""
<?xml version="1.0" ?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<ns2:clearFooResponse xmlns:ns2="http://foo.services.example.com/"/>
</S:Body>
</S:Envelope>
""")
result = operation.output.deserialize(document)
assert result is None

110
tests/test_wsdl_soap.py Normal file
View File

@ -0,0 +1,110 @@
from lxml import etree
from tests.utils import load_xml
from zeep.exceptions import Fault
from zeep.wsdl import bindings
def test_soap11_process_error():
response = load_xml("""
<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:stoc="http://example.com/stockquote.xsd">
<soapenv:Body>
<soapenv:Fault>
<faultcode>fault-code</faultcode>
<faultstring>fault-string</faultstring>
<detail>
<e:myFaultDetails xmlns:e="http://myexample.org/faults">
<e:message>detail-message</e:message>
<e:errorcode>detail-code</e:errorcode>
</e:myFaultDetails>
</detail>
</soapenv:Fault>
</soapenv:Body>
</soapenv:Envelope>
""")
binding = bindings.Soap11Binding(
wsdl=None, name=None, port_name=None, transport=None,
default_style=None)
try:
binding.process_error(response, None)
assert False
except Fault as exc:
assert exc.message == 'fault-string'
assert exc.code == 'fault-code'
assert exc.actor is None
assert exc.subcodes is None
assert 'detail-message' in etree.tostring(exc.detail).decode('utf-8')
def test_soap12_process_error():
response = """
<soapenv:Envelope
xmlns="http://example.com/example1"
xmlns:ex="http://example.com/example2"
xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
<soapenv:Body>
<soapenv:Fault>
<soapenv:Code>
<soapenv:Value>fault-code</soapenv:Value>
%s
</soapenv:Code>
<soapenv:Reason>
<soapenv:Text xml:lang="en-US">us-error</soapenv:Text>
<soapenv:Text xml:lang="nl-NL">nl-error</soapenv:Text>
</soapenv:Reason>
<soapenv:Detail>
<e:myFaultDetails
xmlns:e="http://myexample.org/faults" >
<e:message>Invalid credit card details</e:message>
<e:errorcode>999</e:errorcode>
</e:myFaultDetails>
</soapenv:Detail>
</soapenv:Fault>
</soapenv:Body>
</soapenv:Envelope>
"""
subcode = """
<soapenv:Subcode>
<soapenv:Value>%s</soapenv:Value>
%s
</soapenv:Subcode>
"""
binding = bindings.Soap12Binding(
wsdl=None, name=None, port_name=None, transport=None,
default_style=None)
try:
binding.process_error(load_xml(response % ""), None)
assert False
except Fault as exc:
assert exc.message == 'us-error'
assert exc.code == 'fault-code'
assert exc.subcodes == []
try:
binding.process_error(
load_xml(response % subcode % ("fault-subcode1", "")), None)
assert False
except Fault as exc:
assert exc.message == 'us-error'
assert exc.code == 'fault-code'
assert len(exc.subcodes) == 1
assert exc.subcodes[0].namespace == 'http://example.com/example1'
assert exc.subcodes[0].localname == 'fault-subcode1'
try:
binding.process_error(
load_xml(response % subcode % ("fault-subcode1", subcode % ("ex:fault-subcode2", ""))),
None)
assert False
except Fault as exc:
assert exc.message == 'us-error'
assert exc.code == 'fault-code'
assert len(exc.subcodes) == 2
assert exc.subcodes[0].namespace == 'http://example.com/example1'
assert exc.subcodes[0].localname == 'fault-subcode1'
assert exc.subcodes[1].namespace == 'http://example.com/example2'
assert exc.subcodes[1].localname == 'fault-subcode2'

238
tests/test_wsse_username.py Normal file
View File

@ -0,0 +1,238 @@
import datetime
import os
import pytest
import requests_mock
from freezegun import freeze_time
from tests.utils import assert_nodes_equal, load_xml
from zeep import client
from zeep.wsse.username import UsernameToken
@pytest.mark.requests
def test_integration():
client_obj = client.Client(
'tests/wsdl_files/soap.wsdl',
wsse=UsernameToken('username', 'password'))
response = """
<?xml version="1.0"?>
<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:stoc="http://example.com/stockquote.xsd">
<soapenv:Header/>
<soapenv:Body>
<stoc:TradePrice>
<price>120.123</price>
</stoc:TradePrice>
</soapenv:Body>
</soapenv:Envelope>
""".strip()
with requests_mock.mock() as m:
m.post('http://example.com/stockquote', text=response)
result = client_obj.service.GetLastTradePrice('foobar')
assert result == 120.123
def test_password_text():
envelope = load_xml("""
<soap-env:Envelope
xmlns:ns0="http://example.com/stockquote.xsd"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
>
<soap-env:Body>
<ns0:TradePriceRequest>
<tickerSymbol>foobar</tickerSymbol>
<ns0:country/>
</ns0:TradePriceRequest>
</soap-env:Body>
</soap-env:Envelope>
""")
token = UsernameToken('michael', 'geheim')
envelope, headers = token.sign(envelope, {})
expected = """
<soap-env:Envelope
xmlns:ns0="http://example.com/stockquote.xsd"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap-env:Header>
<ns0:Security xmlns:ns0="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<ns0:UsernameToken>
<ns0:Username>michael</ns0:Username>
<ns0:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">geheim</ns0:Password>
</ns0:UsernameToken>
</ns0:Security>
</soap-env:Header>
<soap-env:Body>
<ns0:TradePriceRequest>
<tickerSymbol>foobar</tickerSymbol>
<ns0:country/>
</ns0:TradePriceRequest>
</soap-env:Body>
</soap-env:Envelope>
""" # noqa
assert_nodes_equal(envelope, expected)
@freeze_time('2016-05-08 12:00:00')
def test_password_digest(monkeypatch):
monkeypatch.setattr(os, 'urandom', lambda x: b'mocked-random')
envelope = load_xml("""
<soap-env:Envelope
xmlns:ns0="http://example.com/stockquote.xsd"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
>
<soap-env:Body>
<ns0:TradePriceRequest>
<tickerSymbol>foobar</tickerSymbol>
<ns0:country/>
</ns0:TradePriceRequest>
</soap-env:Body>
</soap-env:Envelope>
""")
token = UsernameToken('michael', 'geheim', use_digest=True)
envelope, headers = token.sign(envelope, {})
expected = """
<soap-env:Envelope
xmlns:ns0="http://example.com/stockquote.xsd"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap-env:Header>
<ns0:Security xmlns:ns0="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<ns0:UsernameToken>
<ns0:Username>michael</ns0:Username>
<ns0:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">hVicspAQSg70JNhe67OHqD9gexc=</ns0:Password>
<ns0:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">bW9ja2VkLXJhbmRvbQ==</ns0:Nonce>
<ns0:Created xmlns:ns0="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">2016-05-08T12:00:00+00:00</ns0:Created>
</ns0:UsernameToken>
</ns0:Security>
</soap-env:Header>
<soap-env:Body>
<ns0:TradePriceRequest>
<tickerSymbol>foobar</tickerSymbol>
<ns0:country/>
</ns0:TradePriceRequest>
</soap-env:Body>
</soap-env:Envelope>
""" # noqa
assert_nodes_equal(envelope, expected)
@freeze_time('2016-05-08 12:00:00')
def test_password_digest_custom(monkeypatch):
monkeypatch.setattr(os, 'urandom', lambda x: b'mocked-random')
envelope = load_xml("""
<soap-env:Envelope
xmlns:ns0="http://example.com/stockquote.xsd"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
>
<soap-env:Body>
<ns0:TradePriceRequest>
<tickerSymbol>foobar</tickerSymbol>
<ns0:country/>
</ns0:TradePriceRequest>
</soap-env:Body>
</soap-env:Envelope>
""")
created = datetime.datetime(2016, 6, 4, 20, 10)
token = UsernameToken(
'michael', password_digest='12345', use_digest=True,
nonce='iets', created=created)
envelope, headers = token.sign(envelope, {})
expected = """
<soap-env:Envelope
xmlns:ns0="http://example.com/stockquote.xsd"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap-env:Header>
<ns0:Security xmlns:ns0="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<ns0:UsernameToken>
<ns0:Username>michael</ns0:Username>
<ns0:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">12345</ns0:Password>
<ns0:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">aWV0cw==</ns0:Nonce>
<ns0:Created xmlns:ns0="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">2016-06-04T20:10:00+00:00</ns0:Created>
</ns0:UsernameToken>
</ns0:Security>
</soap-env:Header>
<soap-env:Body>
<ns0:TradePriceRequest>
<tickerSymbol>foobar</tickerSymbol>
<ns0:country/>
</ns0:TradePriceRequest>
</soap-env:Body>
</soap-env:Envelope>
""" # noqa
assert_nodes_equal(envelope, expected)
def test_password_prepared():
envelope = load_xml("""
<soap-env:Envelope
xmlns:ns0="http://example.com/stockquote.xsd"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
>
<soap-env:Header xmlns:ns0="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<ns0:Security>
<ns0:UsernameToken/>
</ns0:Security>
</soap-env:Header>
<soap-env:Body>
<ns0:TradePriceRequest>
<tickerSymbol>foobar</tickerSymbol>
<ns0:country/>
</ns0:TradePriceRequest>
</soap-env:Body>
</soap-env:Envelope>
""") # noqa
token = UsernameToken('michael', 'geheim')
envelope, headers = token.sign(envelope, {})
expected = """
<soap-env:Envelope
xmlns:ns0="http://example.com/stockquote.xsd"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap-env:Header xmlns:ns0="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<ns0:Security>
<ns0:UsernameToken>
<ns0:Username>michael</ns0:Username>
<ns0:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">geheim</ns0:Password>
</ns0:UsernameToken>
</ns0:Security>
</soap-env:Header>
<soap-env:Body>
<ns0:TradePriceRequest>
<tickerSymbol>foobar</tickerSymbol>
<ns0:country/>
</ns0:TradePriceRequest>
</soap-env:Body>
</soap-env:Envelope>
""" # noqa
assert_nodes_equal(envelope, expected)

25
tests/test_wsse_utils.py Normal file
View File

@ -0,0 +1,25 @@
from lxml import etree
from zeep.wsse import utils
def test_get_security_header():
doc = etree.fromstring("""
<soap-env:Envelope
xmlns:ns0="http://example.com/stockquote.xsd"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
>
<soap-env:Body>
<ns0:TradePriceRequest>
<tickerSymbol>foobar</tickerSymbol>
<ns0:country/>
</ns0:TradePriceRequest>
</soap-env:Body>
</soap-env:Envelope>
""".strip())
element = utils.get_security_header(doc)
assert element.tag == '{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd}Security' # noqa

280
tests/test_xsd_any.py Normal file
View File

@ -0,0 +1,280 @@
import datetime
import pytest
from lxml import etree
from tests.utils import assert_nodes_equal, load_xml
from zeep import xsd
def get_any_schema():
return xsd.Schema(load_xml("""
<?xml version="1.0"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
targetNamespace="http://tests.python-zeep.org/"
elementFormDefault="qualified">
<element name="item" type="string"/>
<element name="container">
<complexType>
<sequence>
<any/>
</sequence>
</complexType>
</element>
</schema>
"""))
def test_any_simple():
schema = get_any_schema()
item_elm = schema.get_element('{http://tests.python-zeep.org/}item')
assert isinstance(item_elm.type, xsd.String)
container_elm = schema.get_element('{http://tests.python-zeep.org/}container')
# Create via arg
obj = container_elm(xsd.AnyObject(item_elm, item_elm('argh')))
node = etree.Element('document')
container_elm.render(node, obj)
expected = """
<document>
<ns0:container xmlns:ns0="http://tests.python-zeep.org/">
<ns0:item>argh</ns0:item>
</ns0:container>
</document>
"""
assert_nodes_equal(expected, node)
item = container_elm.parse(node.getchildren()[0], schema)
assert item._value_1 == 'argh'
# Create via kwarg _value_1
obj = container_elm(_value_1=xsd.AnyObject(item_elm, item_elm('argh')))
node = etree.Element('document')
container_elm.render(node, obj)
expected = """
<document>
<ns0:container xmlns:ns0="http://tests.python-zeep.org/">
<ns0:item>argh</ns0:item>
</ns0:container>
</document>
"""
assert_nodes_equal(expected, node)
item = container_elm.parse(node.getchildren()[0], schema)
assert item._value_1 == 'argh'
def test_any_value_element_tree():
schema = get_any_schema()
item = etree.Element('{http://tests.python-zeep.org}lxml')
etree.SubElement(item, 'node').text = 'foo'
container_elm = schema.get_element('{http://tests.python-zeep.org/}container')
# Create via arg
obj = container_elm(item)
node = etree.Element('document')
container_elm.render(node, obj)
expected = """
<document>
<ns0:container xmlns:ns0="http://tests.python-zeep.org/">
<ns0:lxml xmlns:ns0="http://tests.python-zeep.org">
<node>foo</node>
</ns0:lxml>
</ns0:container>
</document>
"""
assert_nodes_equal(expected, node)
item = container_elm.parse(node.getchildren()[0], schema)
assert isinstance(item._value_1, etree._Element)
assert item._value_1.tag == '{http://tests.python-zeep.org}lxml'
def test_any_value_invalid():
schema = get_any_schema()
class SomeThing(object):
pass
container_elm = schema.get_element('{http://tests.python-zeep.org/}container')
# Create via arg
item = SomeThing()
obj = container_elm(item)
node = etree.Element('document')
with pytest.raises(TypeError):
container_elm.render(node, obj)
def test_any_with_ref():
schema = xsd.Schema(load_xml("""
<?xml version="1.0"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
targetNamespace="http://tests.python-zeep.org/"
elementFormDefault="qualified">
<element name="item" type="string"/>
<element name="container">
<complexType>
<sequence>
<element ref="tns:item"/>
<any/>
<any maxOccurs="unbounded"/>
</sequence>
</complexType>
</element>
</schema>
"""))
item_elm = schema.get_element('{http://tests.python-zeep.org/}item')
assert isinstance(item_elm.type, xsd.String)
container_elm = schema.get_element('{http://tests.python-zeep.org/}container')
obj = container_elm(
item='bar',
_value_1=xsd.AnyObject(item_elm, item_elm('argh')))
node = etree.Element('document')
container_elm.render(node, obj)
expected = """
<document>
<ns0:container xmlns:ns0="http://tests.python-zeep.org/">
<ns0:item>bar</ns0:item>
<ns0:item>argh</ns0:item>
</ns0:container>
</document>
"""
assert_nodes_equal(expected, node)
item = container_elm.parse(node.getchildren()[0], schema)
assert item.item == 'bar'
assert item._value_1 == 'argh'
def test_element_any_parse():
node = load_xml("""
<xsd:schema
elementFormDefault="qualified"
targetNamespace="https://tests.python-zeep.org"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="container">
<xsd:complexType>
<xsd:sequence>
<xsd:any/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
""")
schema = xsd.Schema(node)
node = load_xml("""
<container xmlns="https://tests.python-zeep.org">
<something>
<contains>text</contains>
</something>
</container>
""")
elm = schema.get_element('ns0:container')
elm.parse(node, schema)
def test_element_any_type():
node = etree.fromstring("""
<?xml version="1.0"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
targetNamespace="http://tests.python-zeep.org/"
elementFormDefault="qualified">
<element name="container">
<complexType>
<sequence>
<element name="something" type="anyType"/>
</sequence>
</complexType>
</element>
</schema>
""".strip())
schema = xsd.Schema(node)
container_elm = schema.get_element('{http://tests.python-zeep.org/}container')
obj = container_elm(something='bar')
node = etree.Element('document')
container_elm.render(node, obj)
expected = """
<document>
<ns0:container xmlns:ns0="http://tests.python-zeep.org/">
<ns0:something>bar</ns0:something>
</ns0:container>
</document>
"""
assert_nodes_equal(expected, node)
item = container_elm.parse(node.getchildren()[0], schema)
assert item.something == 'bar'
def test_any_in_nested_sequence():
schema = xsd.Schema(load_xml("""
<?xml version="1.0"?>
<xsd:schema
xmlns:tns="http://tests.python-zeep.org/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified"
targetNamespace="http://tests.python-zeep.org/"
>
<xsd:element name="something" type="xsd:date"/>
<xsd:element name="foobar" type="xsd:boolean"/>
<xsd:element name="container">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="items" minOccurs="0">
<xsd:complexType>
<xsd:sequence>
<xsd:any namespace="##any" processContents="lax"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="version" type="xsd:string"/>
<xsd:any namespace="##any" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
""")) # noqa
container_elm = schema.get_element('{http://tests.python-zeep.org/}container')
assert container_elm.signature() == (
'items: {_value_1: ANY}, version: xsd:string, _value_1: ANY[]')
something = schema.get_element('{http://tests.python-zeep.org/}something')
foobar = schema.get_element('{http://tests.python-zeep.org/}foobar')
any_1 = xsd.AnyObject(something, datetime.date(2016, 7, 4))
any_2 = xsd.AnyObject(foobar, True)
obj = container_elm(
items={'_value_1': any_1}, version='str1234', _value_1=[any_1, any_2])
node = etree.Element('document')
container_elm.render(node, obj)
expected = """
<document>
<ns0:container xmlns:ns0="http://tests.python-zeep.org/">
<ns0:items>
<ns0:something>2016-07-04</ns0:something>
</ns0:items>
<ns0:version>str1234</ns0:version>
<ns0:something>2016-07-04</ns0:something>
<ns0:foobar>true</ns0:foobar>
</ns0:container>
</document>
"""
assert_nodes_equal(expected, node)
item = container_elm.parse(node.getchildren()[0], schema)
assert item.items._value_1 == datetime.date(2016, 7, 4)
assert item.version == 'str1234'
assert item._value_1 == [datetime.date(2016, 7, 4), True]

View File

@ -0,0 +1,420 @@
from collections import OrderedDict
from lxml import etree
from tests.utils import assert_nodes_equal, load_xml
from zeep import xsd
def test_anyattribute():
schema = xsd.Schema(load_xml("""
<?xml version="1.0"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
elementFormDefault="qualified"
targetNamespace="http://tests.python-zeep.org/">
<element name="container">
<complexType>
<sequence>
<element name="foo" type="xsd:string" />
</sequence>
<xsd:anyAttribute processContents="lax"/>
</complexType>
</element>
</schema>
"""))
container_elm = schema.get_element('{http://tests.python-zeep.org/}container')
assert container_elm.signature() == (
'foo: xsd:string, _attr_1: {}')
obj = container_elm(foo='bar', _attr_1=OrderedDict([
('hiep', 'hoi'), ('hoi', 'hiep')
]))
expected = """
<document>
<ns0:container xmlns:ns0="http://tests.python-zeep.org/" hiep="hoi" hoi="hiep">
<ns0:foo>bar</ns0:foo>
</ns0:container>
</document>
"""
node = etree.Element('document')
container_elm.render(node, obj)
assert_nodes_equal(expected, node)
item = container_elm.parse(node.getchildren()[0], schema)
assert item._attr_1 == {'hiep': 'hoi', 'hoi': 'hiep'}
assert item.foo == 'bar'
def test_attribute_list_type():
schema = xsd.Schema(load_xml("""
<?xml version="1.0"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
elementFormDefault="qualified"
targetNamespace="http://tests.python-zeep.org/">
<simpleType name="list">
<list itemType="int"/>
</simpleType>
<element name="container">
<complexType>
<sequence>
<element name="foo" type="xsd:string" />
</sequence>
<xsd:attribute name="lijst" type="tns:list"/>
</complexType>
</element>
</schema>
"""))
container_elm = schema.get_element('{http://tests.python-zeep.org/}container')
assert container_elm.signature() == ('foo: xsd:string, lijst: xsd:int[]')
obj = container_elm(foo='bar', lijst=[1, 2, 3])
expected = """
<document>
<ns0:container xmlns:ns0="http://tests.python-zeep.org/" lijst="1 2 3">
<ns0:foo>bar</ns0:foo>
</ns0:container>
</document>
"""
node = etree.Element('document')
container_elm.render(node, obj)
assert_nodes_equal(expected, node)
item = container_elm.parse(node.getchildren()[0], schema)
assert item.lijst == [1, 2, 3]
assert item.foo == 'bar'
def test_ref_attribute_qualified():
schema = xsd.Schema(load_xml("""
<?xml version="1.0"?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
attributeFormDefault="qualified"
targetNamespace="http://tests.python-zeep.org/">
<xsd:element name="container">
<xsd:complexType>
<xsd:attribute ref="tns:attr" use="required" />
</xsd:complexType>
</xsd:element>
<xsd:attribute name="attr" type="xsd:string" />
</xsd:schema>
"""))
elm_cls = schema.get_element('{http://tests.python-zeep.org/}container')
instance = elm_cls(attr="hoi")
expected = """
<document>
<ns0:container xmlns:ns0="http://tests.python-zeep.org/" ns0:attr="hoi"/>
</document>
"""
node = etree.Element('document')
elm_cls.render(node, instance)
assert_nodes_equal(expected, node)
def test_ref_attribute_unqualified():
schema = xsd.Schema(load_xml("""
<?xml version="1.0"?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
attributeFormDefault="unqualified"
targetNamespace="http://tests.python-zeep.org/">
<xsd:element name="container">
<xsd:complexType>
<xsd:attribute ref="tns:attr" use="required" />
</xsd:complexType>
</xsd:element>
<xsd:attribute name="attr" type="xsd:string" />
</xsd:schema>
"""))
elm_cls = schema.get_element('{http://tests.python-zeep.org/}container')
instance = elm_cls(attr="hoi")
expected = """
<document>
<ns0:container xmlns:ns0="http://tests.python-zeep.org/" ns0:attr="hoi"/>
</document>
"""
node = etree.Element('document')
elm_cls.render(node, instance)
assert_nodes_equal(expected, node)
def test_complex_type_with_attributes():
schema = xsd.Schema(load_xml("""
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="Address">
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="1" name="NameFirst" type="xs:string"/>
<xs:element minOccurs="0" maxOccurs="1" name="NameLast" type="xs:string"/>
<xs:element minOccurs="0" maxOccurs="1" name="Email" type="xs:string"/>
</xs:sequence>
<xs:attribute name="id" type="xs:string" use="required"/>
</xs:complexType>
<xs:element name="Address" type="Address"/>
</xs:schema>
"""))
address_type = schema.get_element('Address')
obj = address_type(
NameFirst='John', NameLast='Doe', Email='j.doe@example.com', id='123')
node = etree.Element('document')
address_type.render(node, obj)
expected = """
<document>
<Address id="123">
<NameFirst>John</NameFirst>
<NameLast>Doe</NameLast>
<Email>j.doe@example.com</Email>
</Address>
</document>
"""
assert_nodes_equal(expected, node)
def test_qualified_attribute():
schema = xsd.Schema(load_xml("""
<?xml version="1.0"?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
attributeFormDefault="qualified"
elementFormDefault="qualified"
targetNamespace="http://tests.python-zeep.org/">
<xsd:element name="Address">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="foo" type="xsd:string" form="unqualified" />
</xsd:sequence>
<xsd:attribute name="id" type="xsd:string" use="required" form="unqualified" />
<xsd:attribute name="pos" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:schema>
"""))
address_type = schema.get_element('{http://tests.python-zeep.org/}Address')
obj = address_type(foo='bar', id="20", pos="30")
expected = """
<document>
<ns0:Address xmlns:ns0="http://tests.python-zeep.org/" id="20" ns0:pos="30">
<foo>bar</foo>
</ns0:Address>
</document>
"""
node = etree.Element('document')
address_type.render(node, obj)
assert_nodes_equal(expected, node)
def test_group():
schema = xsd.Schema(load_xml("""
<?xml version="1.0"?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
attributeFormDefault="qualified"
elementFormDefault="qualified"
targetNamespace="http://tests.python-zeep.org/">
<xsd:attributeGroup name="groepje">
<xsd:attribute name="id" type="xsd:string" use="required" form="unqualified" />
<xsd:attribute name="pos" type="xsd:string" use="required" />
</xsd:attributeGroup>
<xsd:element name="Address">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="foo" type="xsd:string" form="unqualified" />
</xsd:sequence>
<xsd:attributeGroup ref="tns:groepje"/>
</xsd:complexType>
</xsd:element>
</xsd:schema>
"""))
address_type = schema.get_element('{http://tests.python-zeep.org/}Address')
obj = address_type(foo='bar', id="20", pos="30")
expected = """
<document>
<ns0:Address xmlns:ns0="http://tests.python-zeep.org/" id="20" ns0:pos="30">
<foo>bar</foo>
</ns0:Address>
</document>
"""
node = etree.Element('document')
address_type.render(node, obj)
assert_nodes_equal(expected, node)
def test_group_nested():
schema = xsd.Schema(load_xml("""
<?xml version="1.0"?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
attributeFormDefault="qualified"
elementFormDefault="qualified"
targetNamespace="http://tests.python-zeep.org/">
<xsd:attributeGroup name="groepje">
<xsd:attribute name="id" type="xsd:string" use="required" form="unqualified" />
<xsd:attribute name="pos" type="xsd:string" use="required" />
<xsd:attributeGroup ref="tns:nestje"/>
</xsd:attributeGroup>
<xsd:attributeGroup name="nestje">
<xsd:attribute name="size" type="xsd:string" use="required" />
</xsd:attributeGroup>
<xsd:element name="Address">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="foo" type="xsd:string" form="unqualified" />
</xsd:sequence>
<xsd:attributeGroup ref="tns:groepje"/>
</xsd:complexType>
</xsd:element>
</xsd:schema>
"""))
address_type = schema.get_element('{http://tests.python-zeep.org/}Address')
obj = address_type(foo='bar', id="20", pos="30", size="maat")
expected = """
<document>
<ns0:Address
xmlns:ns0="http://tests.python-zeep.org/" id="20" ns0:pos="30" ns0:size="maat">
<foo>bar</foo>
</ns0:Address>
</document>
"""
node = etree.Element('document')
address_type.render(node, obj)
assert_nodes_equal(expected, node)
def test_nested_attribute():
schema = xsd.Schema(load_xml("""
<?xml version="1.0"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
elementFormDefault="qualified"
targetNamespace="http://tests.python-zeep.org/">
<element name="container">
<complexType>
<sequence>
<element name="item">
<complexType>
<sequence>
<element name="x" type="xsd:string"/>
</sequence>
<attribute name="y" type="xsd:string"/>
</complexType>
</element>
</sequence>
</complexType>
</element>
</schema>
"""))
container_elm = schema.get_element('{http://tests.python-zeep.org/}container')
assert container_elm.signature() == 'item: {x: xsd:string, y: xsd:string}'
obj = container_elm(item={'x': 'foo', 'y': 'bar'})
expected = """
<document>
<ns0:container xmlns:ns0="http://tests.python-zeep.org/">
<ns0:item y="bar">
<ns0:x>foo</ns0:x>
</ns0:item>
</ns0:container>
</document>
"""
node = etree.Element('document')
container_elm.render(node, obj)
assert_nodes_equal(expected, node)
def test_attribute_union_type():
schema = xsd.Schema(load_xml("""
<?xml version="1.0"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
elementFormDefault="qualified"
targetNamespace="http://tests.python-zeep.org/">
<simpleType name="one">
<restriction base="xsd:string"/>
</simpleType>
<simpleType name="parent">
<union memberTypes="one two"/>
</simpleType>
<simpleType name="two">
<restriction base="xsd:string"/>
</simpleType>
<attribute name="something" type="tns:something"/>
<simpleType name="something">
<restriction base="tns:parent">
<enumeration value="preserve"/>
</restriction>
</simpleType>
</schema>
"""))
attr = schema.get_attribute('{http://tests.python-zeep.org/}something')
assert attr('foo') == 'foo'
def test_attribute_union_type_inline():
schema = xsd.Schema(load_xml("""
<?xml version="1.0"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
elementFormDefault="qualified"
targetNamespace="http://tests.python-zeep.org/">
<simpleType name="parent">
<union>
<simpleType name="one">
<restriction base="xsd:string"/>
</simpleType>
<simpleType name="two">
<restriction base="xsd:string"/>
</simpleType>
</union>
</simpleType>
<attribute name="something" type="tns:something"/>
<simpleType name="something">
<restriction base="tns:parent">
<enumeration value="preserve"/>
</restriction>
</simpleType>
</schema>
"""))
attr = schema.get_attribute('{http://tests.python-zeep.org/}something')
assert attr('foo') == 'foo'

View File

@ -122,6 +122,10 @@ class TestDateTime:
value = datetime.datetime(2016, 3, 4, 21, 14, 42, tzinfo=pytz.utc)
assert instance.xmlvalue(value) == '2016-03-04T21:14:42Z'
value = datetime.datetime(2016, 3, 4, 21, 14, 42, 123456, tzinfo=pytz.utc)
assert instance.xmlvalue(value) == '2016-03-04T21:14:42.123456Z'
value = datetime.datetime(2016, 3, 4, 21, 14, 42, tzinfo=pytz.utc)
value = value.astimezone(pytz.timezone('Europe/Amsterdam'))
assert instance.xmlvalue(value) == '2016-03-04T22:14:42+01:00'
@ -130,6 +134,9 @@ class TestDateTime:
value = datetime.datetime(2016, 3, 4, 21, 14, 42)
assert instance.pythonvalue('2016-03-04T21:14:42') == value
value = datetime.datetime(2016, 3, 4, 21, 14, 42, 123456)
assert instance.pythonvalue('2016-03-04T21:14:42.123456') == value
def test_pythonvalue_invalid(self):
instance = builtins.DateTime()
with pytest.raises(ValueError):

979
tests/test_xsd_choice.py Normal file
View File

@ -0,0 +1,979 @@
import pytest
from lxml import etree
from tests.utils import assert_nodes_equal, load_xml, render_node
from zeep import xsd
from zeep.exceptions import XMLParseError
from zeep.helpers import serialize_object
def test_choice_element():
node = etree.fromstring("""
<?xml version="1.0"?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
elementFormDefault="qualified"
targetNamespace="http://tests.python-zeep.org/">
<xsd:element name="container">
<xsd:complexType>
<xsd:choice>
<xsd:element name="item_1" type="xsd:string" />
<xsd:element name="item_2" type="xsd:string" />
<xsd:element name="item_3" type="xsd:string" />
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
""".strip())
schema = xsd.Schema(node)
element = schema.get_element('ns0:container')
value = element(item_1="foo")
assert value.item_1 == 'foo'
assert value.item_2 is None
assert value.item_3 is None
expected = """
<document>
<ns0:container xmlns:ns0="http://tests.python-zeep.org/">
<ns0:item_1>foo</ns0:item_1>
</ns0:container>
</document>
"""
node = etree.Element('document')
element.render(node, value)
assert_nodes_equal(expected, node)
value = element.parse(node.getchildren()[0], schema)
assert value.item_1 == 'foo'
assert value.item_2 is None
assert value.item_3 is None
def test_choice_element_second_elm():
node = etree.fromstring("""
<?xml version="1.0"?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
elementFormDefault="qualified"
targetNamespace="http://tests.python-zeep.org/">
<xsd:element name="container">
<xsd:complexType>
<xsd:choice>
<xsd:element name="item_1" type="xsd:string" />
<xsd:element name="item_2" type="xsd:string" />
<xsd:element name="item_3" type="xsd:string" />
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
""".strip())
schema = xsd.Schema(node)
element = schema.get_element('ns0:container')
value = element(item_2="foo")
assert value.item_1 is None
assert value.item_2 == 'foo'
assert value.item_3 is None
expected = """
<document>
<ns0:container xmlns:ns0="http://tests.python-zeep.org/">
<ns0:item_2>foo</ns0:item_2>
</ns0:container>
</document>
"""
node = etree.Element('document')
element.render(node, value)
assert_nodes_equal(expected, node)
value = element.parse(node.getchildren()[0], schema)
assert value.item_1 is None
assert value.item_2 == 'foo'
assert value.item_3 is None
def test_choice_element_multiple():
node = etree.fromstring("""
<?xml version="1.0"?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
elementFormDefault="qualified"
targetNamespace="http://tests.python-zeep.org/">
<xsd:element name="container">
<xsd:complexType>
<xsd:choice maxOccurs="3">
<xsd:element name="item_1" type="xsd:string" />
<xsd:element name="item_2" type="xsd:string" />
<xsd:element name="item_3" type="xsd:string" />
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
""".strip())
schema = xsd.Schema(node)
element = schema.get_element('ns0:container')
value = element(_value_1=[
{'item_1': 'foo'}, {'item_2': 'bar'}, {'item_1': 'three'},
])
assert value._value_1 == [
{'item_1': 'foo'}, {'item_2': 'bar'}, {'item_1': 'three'},
]
expected = """
<document>
<ns0:container xmlns:ns0="http://tests.python-zeep.org/">
<ns0:item_1>foo</ns0:item_1>
<ns0:item_2>bar</ns0:item_2>
<ns0:item_1>three</ns0:item_1>
</ns0:container>
</document>
"""
node = etree.Element('document')
element.render(node, value)
assert_nodes_equal(expected, node)
value = element.parse(node.getchildren()[0], schema)
assert value._value_1 == [
{'item_1': 'foo'}, {'item_2': 'bar'}, {'item_1': 'three'},
]
def test_choice_element_optional():
node = etree.fromstring("""
<?xml version="1.0"?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
elementFormDefault="qualified"
targetNamespace="http://tests.python-zeep.org/">
<xsd:element name="container">
<xsd:complexType>
<xsd:sequence>
<xsd:choice minOccurs="0">
<xsd:element name="item_1" type="xsd:string" />
<xsd:element name="item_2" type="xsd:string" />
<xsd:element name="item_3" type="xsd:string" />
</xsd:choice>
<xsd:element name="item_4" type="xsd:string" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
""".strip())
schema = xsd.Schema(node)
element = schema.get_element('ns0:container')
value = element(item_4="foo")
expected = """
<document>
<ns0:container xmlns:ns0="http://tests.python-zeep.org/">
<ns0:item_4>foo</ns0:item_4>
</ns0:container>
</document>
"""
node = etree.Element('document')
element.render(node, value)
assert_nodes_equal(expected, node)
def test_choice_element_with_any():
node = etree.fromstring("""
<?xml version="1.0"?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
elementFormDefault="qualified"
targetNamespace="http://tests.python-zeep.org/">
<xsd:element name="container">
<xsd:complexType>
<xsd:choice minOccurs="0">
<xsd:element name="item_1" type="xsd:string" />
<xsd:element name="item_2" type="xsd:string" />
<xsd:element name="item_3" type="xsd:string" />
<xsd:any namespace="##other" minOccurs="0" maxOccurs="unbounded"/>
</xsd:choice>
<xsd:attribute name="name" type="xsd:QName" use="required" />
<xsd:attribute name="something" type="xsd:boolean" use="required" />
<xsd:anyAttribute namespace="##other" processContents="lax"/>
</xsd:complexType>
</xsd:element>
</xsd:schema>
""".strip())
schema = xsd.Schema(node)
element = schema.get_element('ns0:container')
value = element(item_1="foo", name="foo", something="bar")
expected = """
<document>
<ns0:container xmlns:ns0="http://tests.python-zeep.org/" name="foo" something="true">
<ns0:item_1>foo</ns0:item_1>
</ns0:container>
</document>
"""
node = etree.Element('document')
element.render(node, value)
assert_nodes_equal(expected, node)
result = element.parse(node.getchildren()[0], schema)
assert result.name == 'foo'
assert result.something is True
assert result.item_1 == 'foo'
def test_choice_element_with_any_max_occurs():
schema = xsd.Schema(load_xml("""
<schema targetNamespace="http://tests.python-zeep.org/"
xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
elementFormDefault="qualified">
<element name="item_any" type="string"/>
<element name="container">
<complexType>
<sequence>
<choice minOccurs="0">
<element maxOccurs="999" minOccurs="0" name="item_1" type="string"/>
<sequence>
<element minOccurs="0" name="item_2"/>
<any maxOccurs="unbounded" minOccurs="0"/>
</sequence>
</choice>
</sequence>
</complexType>
</element>
</schema>
"""))
element = schema.get_element('ns0:container')
value = element(
item_2="item-2",
_value_1=[
xsd.AnyObject(schema.get_element('ns0:item_any'), 'any-content')
])
expected = """
<document>
<ns0:container xmlns:ns0="http://tests.python-zeep.org/">
<ns0:item_2>item-2</ns0:item_2>
<ns0:item_any>any-content</ns0:item_any>
</ns0:container>
</document>
"""
node = render_node(element, value)
assert_nodes_equal(node, expected)
result = element.parse(node.getchildren()[0], schema)
assert result.item_2 == 'item-2'
assert result._value_1 == ['any-content']
def test_choice_optional_values():
schema = load_xml("""
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
targetNamespace="http://tests.python-zeep.org/"
elementFormDefault="qualified">
<xsd:complexType name="Transport">
<xsd:sequence>
<xsd:choice minOccurs="0" maxOccurs="1">
<xsd:element name="item" type="xsd:string"/>
</xsd:choice>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
""")
schema = xsd.Schema(schema)
node = load_xml("<Transport></Transport>")
elm = schema.get_type('ns0:Transport')
elm.parse_xmlelement(node, schema)
def test_choice_in_sequence():
node = etree.fromstring("""
<?xml version="1.0"?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
elementFormDefault="qualified"
targetNamespace="http://tests.python-zeep.org/">
<xsd:element name="container">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="something" type="xsd:string" />
<xsd:choice>
<xsd:element name="item_1" type="xsd:string" />
<xsd:element name="item_2" type="xsd:string" />
<xsd:element name="item_3" type="xsd:string" />
</xsd:choice>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
""".strip())
schema = xsd.Schema(node)
container_elm = schema.get_element('ns0:container')
assert container_elm.type.signature() == (
'something: xsd:string, ({item_1: xsd:string} | {item_2: xsd:string} | {item_3: xsd:string})') # noqa
value = container_elm(item_1='item-1')
expected = """
<document>
<ns0:container xmlns:ns0="http://tests.python-zeep.org/">
<ns0:something/>
<ns0:item_1>item-1</ns0:item_1>
</ns0:container>
</document>
"""
node = etree.Element('document')
container_elm.render(node, value)
assert_nodes_equal(expected, node)
def test_choice_with_sequence():
node = load_xml("""
<?xml version="1.0"?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
elementFormDefault="qualified"
targetNamespace="http://tests.python-zeep.org/">
<xsd:element name="container">
<xsd:complexType xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:choice>
<xsd:sequence>
<xsd:element name="item_1" type="xsd:string"/>
<xsd:element name="item_2" type="xsd:string"/>
</xsd:sequence>
<xsd:sequence>
<xsd:element name="item_3" type="xsd:string"/>
<xsd:element name="item_4" type="xsd:string"/>
</xsd:sequence>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
""")
schema = xsd.Schema(node)
element = schema.get_element('ns0:container')
assert element.type.signature() == (
'({item_1: xsd:string, item_2: xsd:string} | {item_3: xsd:string, item_4: xsd:string})')
value = element(item_1='foo', item_2='bar')
expected = """
<document>
<ns0:container xmlns:ns0="http://tests.python-zeep.org/">
<ns0:item_1>foo</ns0:item_1>
<ns0:item_2>bar</ns0:item_2>
</ns0:container>
</document>
"""
node = etree.Element('document')
element.render(node, value)
assert_nodes_equal(expected, node)
def test_choice_with_sequence_once():
node = load_xml("""
<?xml version="1.0"?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
elementFormDefault="qualified"
targetNamespace="http://tests.python-zeep.org/">
<xsd:element name="container">
<xsd:complexType xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:sequence>
<xsd:element name="item_0" type="xsd:string"/>
<xsd:choice>
<xsd:sequence>
<xsd:element name="item_1" type="xsd:string"/>
<xsd:element name="item_2" type="xsd:string"/>
</xsd:sequence>
</xsd:choice>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
""")
schema = xsd.Schema(node)
element = schema.get_element('ns0:container')
assert element.type.signature() == (
'item_0: xsd:string, ({item_1: xsd:string, item_2: xsd:string})')
value = element(item_0='nul', item_1='foo', item_2='bar')
expected = """
<document>
<ns0:container xmlns:ns0="http://tests.python-zeep.org/">
<ns0:item_0>nul</ns0:item_0>
<ns0:item_1>foo</ns0:item_1>
<ns0:item_2>bar</ns0:item_2>
</ns0:container>
</document>
"""
node = etree.Element('document')
element.render(node, value)
assert_nodes_equal(expected, node)
def test_choice_with_sequence_once_extra_data():
node = load_xml("""
<?xml version="1.0"?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
elementFormDefault="qualified"
targetNamespace="http://tests.python-zeep.org/">
<xsd:element name="container">
<xsd:complexType xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:sequence>
<xsd:element name="item_0" type="xsd:string"/>
<xsd:choice>
<xsd:sequence>
<xsd:element name="item_1" type="xsd:string"/>
<xsd:element name="item_2" type="xsd:string"/>
</xsd:sequence>
</xsd:choice>
<xsd:element name="item_3" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
""")
schema = xsd.Schema(node)
element = schema.get_element('ns0:container')
assert element.type.signature() == (
'item_0: xsd:string, ({item_1: xsd:string, item_2: xsd:string}), item_3: xsd:string')
value = element(item_0='nul', item_1='foo', item_2='bar', item_3='item-3')
expected = """
<document>
<ns0:container xmlns:ns0="http://tests.python-zeep.org/">
<ns0:item_0>nul</ns0:item_0>
<ns0:item_1>foo</ns0:item_1>
<ns0:item_2>bar</ns0:item_2>
<ns0:item_3>item-3</ns0:item_3>
</ns0:container>
</document>
"""
node = etree.Element('document')
element.render(node, value)
assert_nodes_equal(expected, node)
def test_choice_with_sequence_second():
node = load_xml("""
<?xml version="1.0"?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
elementFormDefault="qualified"
targetNamespace="http://tests.python-zeep.org/">
<xsd:element name="container">
<xsd:complexType xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:choice>
<xsd:sequence>
<xsd:element name="item_1" type="xsd:string"/>
<xsd:element name="item_2" type="xsd:string"/>
</xsd:sequence>
<xsd:sequence>
<xsd:element name="item_3" type="xsd:string"/>
<xsd:element name="item_4" type="xsd:string"/>
</xsd:sequence>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
""")
schema = xsd.Schema(node)
element = schema.get_element('ns0:container')
assert element.type.signature() == (
'({item_1: xsd:string, item_2: xsd:string} | {item_3: xsd:string, item_4: xsd:string})')
value = element(item_3='foo', item_4='bar')
expected = """
<document>
<ns0:container xmlns:ns0="http://tests.python-zeep.org/">
<ns0:item_3>foo</ns0:item_3>
<ns0:item_4>bar</ns0:item_4>
</ns0:container>
</document>
"""
node = etree.Element('document')
element.render(node, value)
assert_nodes_equal(expected, node)
def test_choice_with_sequence_invalid():
node = load_xml("""
<?xml version="1.0"?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
elementFormDefault="qualified"
targetNamespace="http://tests.python-zeep.org/">
<xsd:element name="container">
<xsd:complexType xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:choice>
<xsd:sequence>
<xsd:element name="item_1" type="xsd:string"/>
<xsd:element name="item_2" type="xsd:string"/>
</xsd:sequence>
<xsd:sequence>
<xsd:element name="item_3" type="xsd:string"/>
<xsd:element name="item_4" type="xsd:string"/>
</xsd:sequence>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
""")
schema = xsd.Schema(node)
element = schema.get_element('ns0:container')
assert element.type.signature() == (
'({item_1: xsd:string, item_2: xsd:string} | {item_3: xsd:string, item_4: xsd:string})')
with pytest.raises(TypeError):
element(item_1='foo', item_4='bar')
def test_choice_with_sequence_change():
node = load_xml("""
<?xml version="1.0"?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
elementFormDefault="qualified"
targetNamespace="http://tests.python-zeep.org/">
<xsd:element name='ElementName'>
<xsd:complexType xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:choice>
<xsd:sequence>
<xsd:element name="item_1" type="xsd:string"/>
<xsd:element name="item_2" type="xsd:string"/>
</xsd:sequence>
<xsd:sequence>
<xsd:element name="item_3" type="xsd:string"/>
<xsd:element name="item_4" type="xsd:string"/>
</xsd:sequence>
<xsd:element name="nee" type="xsd:string"/>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
""")
schema = xsd.Schema(node)
element = schema.get_element('ns0:ElementName')
elm = element(item_1='foo', item_2='bar')
assert serialize_object(elm) == {
'item_3': None,
'item_2': 'bar',
'item_1': 'foo',
'item_4': None,
'nee': None
}
elm.item_1 = 'bla-1'
elm.item_2 = 'bla-2'
expected = """
<document>
<ns0:ElementName xmlns:ns0="http://tests.python-zeep.org/">
<ns0:item_1>bla-1</ns0:item_1>
<ns0:item_2>bla-2</ns0:item_2>
</ns0:ElementName>
</document>
"""
node = etree.Element('document')
element.render(node, elm)
assert_nodes_equal(expected, node)
def test_choice_with_sequence_change_named():
node = load_xml("""
<?xml version="1.0"?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
elementFormDefault="qualified"
targetNamespace="http://tests.python-zeep.org/">
<xsd:element name='ElementName'>
<xsd:complexType xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:choice>
<xsd:sequence>
<xsd:element name="item_1" type="xsd:string"/>
<xsd:element name="item_2" type="xsd:string"/>
</xsd:sequence>
<xsd:element name="item_3" type="xsd:string"/>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
""")
schema = xsd.Schema(node)
element = schema.get_element('ns0:ElementName')
elm = element(item_3='foo')
elm = element(item_1='foo', item_2='bar')
assert elm['item_1'] == 'foo'
assert elm['item_2'] == 'bar'
elm['item_1'] = 'bla-1'
elm['item_2'] = 'bla-2'
expected = """
<document>
<ns0:ElementName xmlns:ns0="http://tests.python-zeep.org/">
<ns0:item_1>bla-1</ns0:item_1>
<ns0:item_2>bla-2</ns0:item_2>
</ns0:ElementName>
</document>
"""
node = etree.Element('document')
element.render(node, elm)
assert_nodes_equal(expected, node)
def test_choice_with_sequence_multiple():
node = load_xml("""
<?xml version="1.0"?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
elementFormDefault="qualified"
targetNamespace="http://tests.python-zeep.org/">
<xsd:element name="container">
<xsd:complexType xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:choice maxOccurs="2">
<xsd:sequence>
<xsd:element name="item_1" type="xsd:string"/>
<xsd:element name="item_2" type="xsd:string"/>
</xsd:sequence>
<xsd:sequence>
<xsd:element name="item_3" type="xsd:string"/>
<xsd:element name="item_4" type="xsd:string"/>
</xsd:sequence>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
""")
schema = xsd.Schema(node)
element = schema.get_element('ns0:container')
assert element.type.signature() == (
'({item_1: xsd:string, item_2: xsd:string} | {item_3: xsd:string, item_4: xsd:string})[]')
value = element(_value_1=[
dict(item_1='foo', item_2='bar'),
dict(item_3='foo', item_4='bar'),
])
expected = """
<document>
<ns0:container xmlns:ns0="http://tests.python-zeep.org/">
<ns0:item_1>foo</ns0:item_1>
<ns0:item_2>bar</ns0:item_2>
<ns0:item_3>foo</ns0:item_3>
<ns0:item_4>bar</ns0:item_4>
</ns0:container>
</document>
"""
node = etree.Element('document')
element.render(node, value)
assert_nodes_equal(expected, node)
def test_choice_with_sequence_and_element():
node = load_xml("""
<?xml version="1.0"?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
elementFormDefault="qualified"
targetNamespace="http://tests.python-zeep.org/">
<xsd:element name="container">
<xsd:complexType xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:choice>
<xsd:element name="item_1" type="xsd:string"/>
<xsd:sequence>
<xsd:choice>
<xsd:element name="item_2" type="xsd:string"/>
<xsd:element name="item_3" type="xsd:string"/>
</xsd:choice>
</xsd:sequence>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
""")
schema = xsd.Schema(node)
element = schema.get_element('ns0:container')
assert element.type.signature() == (
'({item_1: xsd:string} | {({item_2: xsd:string} | {item_3: xsd:string})})')
value = element(item_2='foo')
expected = """
<document>
<ns0:container xmlns:ns0="http://tests.python-zeep.org/">
<ns0:item_2>foo</ns0:item_2>
</ns0:container>
</document>
"""
node = etree.Element('document')
element.render(node, value)
assert_nodes_equal(expected, node)
def test_element_ref_in_choice():
node = etree.fromstring("""
<?xml version="1.0"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
targetNamespace="http://tests.python-zeep.org/"
elementFormDefault="qualified">
<element name="foo" type="string"/>
<element name="bar" type="string"/>
<element name="container">
<complexType>
<sequence>
<choice>
<element ref="tns:foo"/>
<element ref="tns:bar"/>
</choice>
</sequence>
</complexType>
</element>
</schema>
""".strip())
schema = xsd.Schema(node)
foo_type = schema.get_element('{http://tests.python-zeep.org/}foo')
assert isinstance(foo_type.type, xsd.String)
custom_type = schema.get_element('{http://tests.python-zeep.org/}container')
value = custom_type(foo='bar')
assert value.foo == 'bar'
assert value.bar is None
node = etree.Element('document')
custom_type.render(node, value)
expected = """
<document>
<ns0:container xmlns:ns0="http://tests.python-zeep.org/">
<ns0:foo>bar</ns0:foo>
</ns0:container>
</document>
"""
assert_nodes_equal(expected, node)
def test_parse_dont_loop():
schema = xsd.Schema(load_xml("""
<?xml version="1.0"?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
elementFormDefault="qualified"
targetNamespace="http://tests.python-zeep.org/">
<xsd:element name="container">
<xsd:complexType xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:choice maxOccurs="unbounded">
<xsd:element name="item_1" type="xsd:string"/>
<xsd:element name="item_2" type="xsd:string"/>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
"""))
element = schema.get_element('ns0:container')
expected = load_xml("""
<ns0:container xmlns:ns0="http://tests.python-zeep.org/">
<ns0:item_1>foo</ns0:item_1>
<ns0:item_2>bar</ns0:item_2>
<ns0:item_3>foo</ns0:item_3>
<ns0:item_4>bar</ns0:item_4>
</ns0:container>
""")
with pytest.raises(XMLParseError):
element.parse(expected, schema)
def test_parse_check_unexpected():
schema = xsd.Schema(load_xml("""
<?xml version="1.0"?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
elementFormDefault="qualified"
targetNamespace="http://tests.python-zeep.org/">
<xsd:element name="container">
<xsd:complexType xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:choice maxOccurs="unbounded">
<xsd:element name="item_1" type="xsd:string"/>
<xsd:element name="item_2" type="xsd:string"/>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
"""))
element = schema.get_element('ns0:container')
expected = load_xml("""
<ns0:container xmlns:ns0="http://tests.python-zeep.org/">
<ns0:item_1>foo</ns0:item_1>
<ns0:item_2>bar</ns0:item_2>
<ns0:item_3>foo</ns0:item_3>
</ns0:container>
""")
with pytest.raises(XMLParseError):
element.parse(expected, schema)
def test_parse_check_mixed():
schema = xsd.Schema(load_xml("""
<?xml version="1.0"?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
elementFormDefault="qualified"
targetNamespace="http://tests.python-zeep.org/">
<xsd:element name="container">
<xsd:complexType xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:sequence>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="item_1" type="xsd:string"/>
<xsd:element name="item_2" type="xsd:string"/>
</xsd:choice>
<xsd:element name="item_3" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
"""))
element = schema.get_element('ns0:container')
expected = load_xml("""
<ns0:container xmlns:ns0="http://tests.python-zeep.org/">
<ns0:item_1>foo</ns0:item_1>
<ns0:item_2>bar</ns0:item_2>
<ns0:item_3>foo</ns0:item_3>
</ns0:container>
""")
element.parse(expected, schema)
def test_parse_check_mixed_choices():
schema = xsd.Schema(load_xml("""
<?xml version="1.0"?>
<schema
xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
elementFormDefault="qualified"
targetNamespace="http://tests.python-zeep.org/">
<element name="container">
<complexType>
<sequence>
<choice>
<choice>
<element name="item_1_1" type="string"/>
<sequence>
<element name="item_1_2a" type="string"/>
<element name="item_1_2b" type="string" minOccurs="0"/>
</sequence>
</choice>
<element name="item_2" type="string"/>
<element name="item_3" type="string"/>
</choice>
<element name="isRegistered" type="boolean" fixed="true" minOccurs="0"/>
</sequence>
</complexType>
</element>
</schema>
"""))
element = schema.get_element('ns0:container')
# item_1_1
value = element(item_1_1="foo")
assert value.item_1_1 == 'foo'
node = etree.Element('document')
element.render(node, value)
expected = """
<document>
<ns0:container xmlns:ns0="http://tests.python-zeep.org/">
<ns0:item_1_1>foo</ns0:item_1_1>
</ns0:container>
</document>
"""
assert_nodes_equal(expected, node)
# item_1_2a
value = element(item_1_2a="foo")
node = etree.Element('document')
element.render(node, value)
expected = """
<document>
<ns0:container xmlns:ns0="http://tests.python-zeep.org/">
<ns0:item_1_2a>foo</ns0:item_1_2a>
</ns0:container>
</document>
"""
assert_nodes_equal(expected, node)
# item_1_2a & item_1_2b
value = element(item_1_2a="foo", item_1_2b="bar")
node = etree.Element('document')
element.render(node, value)
expected = """
<document>
<ns0:container xmlns:ns0="http://tests.python-zeep.org/">
<ns0:item_1_2a>foo</ns0:item_1_2a>
<ns0:item_1_2b>bar</ns0:item_1_2b>
</ns0:container>
</document>
"""
assert_nodes_equal(expected, node)
# item_2
value = element(item_2="foo")
assert value.item_2 == 'foo'
node = etree.Element('document')
element.render(node, value)
expected = """
<document>
<ns0:container xmlns:ns0="http://tests.python-zeep.org/">
<ns0:item_2>foo</ns0:item_2>
</ns0:container>
</document>
"""
assert_nodes_equal(expected, node)
# item_3
value = element(item_3="foo")
assert value.item_3 == 'foo'
node = etree.Element('document')
element.render(node, value)
expected = """
<document>
<ns0:container xmlns:ns0="http://tests.python-zeep.org/">
<ns0:item_3>foo</ns0:item_3>
</ns0:container>
</document>
"""
assert_nodes_equal(expected, node)

View File

@ -0,0 +1,233 @@
import pytest
from lxml import etree
from tests.utils import assert_nodes_equal, load_xml, render_node
from zeep import xsd
def test_single_node():
schema = xsd.Schema(load_xml("""
<?xml version="1.0"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
targetNamespace="http://tests.python-zeep.org/"
elementFormDefault="qualified">
<element name="container">
<complexType>
<sequence>
<element minOccurs="0" maxOccurs="1" name="item" type="string" />
</sequence>
</complexType>
</element>
</schema>
"""))
schema.set_ns_prefix('tns', 'http://tests.python-zeep.org/')
container_elm = schema.get_element('tns:container')
obj = container_elm(item='bar')
expected = """
<document>
<ns0:container xmlns:ns0="http://tests.python-zeep.org/">
<ns0:item>bar</ns0:item>
</ns0:container>
</document>
"""
result = render_node(container_elm, obj)
assert_nodes_equal(result, expected)
obj = container_elm.parse(result[0], schema)
assert obj.item == 'bar'
def test_nested_sequence():
schema = xsd.Schema(load_xml("""
<?xml version="1.0"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
targetNamespace="http://tests.python-zeep.org/"
elementFormDefault="qualified">
<element name="container">
<complexType>
<sequence>
<element minOccurs="0" maxOccurs="1" name="item">
<complexType>
<sequence>
<element name="x" type="integer"/>
<element name="y" type="integer"/>
</sequence>
</complexType>
</element>
</sequence>
</complexType>
</element>
</schema>
"""))
schema.set_ns_prefix('tns', 'http://tests.python-zeep.org/')
container_elm = schema.get_element('tns:container')
obj = container_elm(item={'x': 1, 'y': 2})
expected = """
<document>
<ns0:container xmlns:ns0="http://tests.python-zeep.org/">
<ns0:item>
<ns0:x>1</ns0:x>
<ns0:y>2</ns0:y>
</ns0:item>
</ns0:container>
</document>
"""
result = render_node(container_elm, obj)
assert_nodes_equal(result, expected)
obj = container_elm.parse(result[0], schema)
assert obj.item.x == 1
assert obj.item.y == 2
def test_single_node_array():
schema = xsd.Schema(load_xml("""
<?xml version="1.0"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
targetNamespace="http://tests.python-zeep.org/"
elementFormDefault="qualified">
<element name="container">
<complexType>
<sequence>
<element minOccurs="0" maxOccurs="unbounded" name="item" type="string" />
</sequence>
</complexType>
</element>
</schema>
"""))
schema.set_ns_prefix('tns', 'http://tests.python-zeep.org/')
container_elm = schema.get_element('tns:container')
obj = container_elm(item=['item-1', 'item-2', 'item-3'])
assert obj.item == ['item-1', 'item-2', 'item-3']
expected = """
<document>
<ns0:container xmlns:ns0="http://tests.python-zeep.org/">
<ns0:item>item-1</ns0:item>
<ns0:item>item-2</ns0:item>
<ns0:item>item-3</ns0:item>
</ns0:container>
</document>
"""
result = render_node(container_elm, obj)
assert_nodes_equal(result, expected)
obj = container_elm.parse(result[0], schema)
assert obj.item == ['item-1', 'item-2', 'item-3']
def test_single_node_no_iterable():
schema = xsd.Schema(load_xml("""
<?xml version="1.0"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
targetNamespace="http://tests.python-zeep.org/"
elementFormDefault="qualified">
<element name="container">
<complexType>
<sequence>
<element minOccurs="0" maxOccurs="1" name="item" type="string" />
</sequence>
</complexType>
</element>
</schema>
"""))
schema.set_ns_prefix('tns', 'http://tests.python-zeep.org/')
container_elm = schema.get_element('tns:container')
obj = container_elm(item=['item-1', 'item-2', 'item-3'])
assert obj.item == ['item-1', 'item-2', 'item-3']
with pytest.raises(ValueError):
render_node(container_elm, obj)
def test_complex_any_types():
# see https://github.com/mvantellingen/python-zeep/issues/252
schema = xsd.Schema(load_xml("""
<?xml version="1.0"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
targetNamespace="http://tests.python-zeep.org/"
elementFormDefault="qualified">
<element name="container">
<complexType>
<sequence>
<element minOccurs="0" maxOccurs="1" name="auth" type="anyType" />
<element minOccurs="0" maxOccurs="1" name="params" type="anyType" />
</sequence>
</complexType>
</element>
</schema>
"""))
schema.set_ns_prefix('tns', 'http://tests.python-zeep.org/')
KeyValueData = xsd.Element(
'{http://xml.apache.org/xml-soap}KeyValueData',
xsd.ComplexType(
xsd.Sequence([
xsd.Element(
'key',
xsd.AnyType(),
),
xsd.Element(
'value',
xsd.AnyType(),
),
]),
),
)
Map = xsd.ComplexType(
xsd.Sequence([
xsd.Element(
'item',
xsd.AnyType(),
min_occurs=1,
max_occurs="unbounded"),
]),
qname=etree.QName('{http://xml.apache.org/xml-soap}Map'))
header_Username = KeyValueData(xsd.AnyObject(xsd.String(), 'Username'), value=xsd.AnyObject(xsd.String(), 'abc'))
header_ShopId = KeyValueData(xsd.AnyObject(xsd.String(), 'ShopId'), value=xsd.AnyObject(xsd.Int(), 123))
auth = Map(item=[header_Username, header_ShopId])
header_LimitNum = KeyValueData(xsd.AnyObject(xsd.String(), 'LimitNum'), value=xsd.AnyObject(xsd.Int(), 2))
params = Map(item=[header_LimitNum])
container = schema.get_element('ns0:container')
obj = container(auth=auth, params=params)
result = render_node(container, obj)
expected = load_xml("""
<document>
<ns0:container xmlns:ns0="http://tests.python-zeep.org/">
<ns0:auth xmlns:ns1="http://xml.apache.org/xml-soap" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ns1:Map">
<item>
<key xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Username</key>
<value xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">abc</value>
</item>
<item>
<key xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">ShopId</key>
<value xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:int">123</value>
</item>
</ns0:auth>
<ns0:params xmlns:ns2="http://xml.apache.org/xml-soap" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ns2:Map">
<item>
<key xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">LimitNum</key>
<value xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:int">2</value>
</item>
</ns0:params>
</ns0:container>
</document>
""") # noqa
assert_nodes_equal(result, expected)

597
tests/test_xsd_extension.py Normal file
View File

@ -0,0 +1,597 @@
import datetime
import io
from lxml import etree
from tests.utils import DummyTransport, assert_nodes_equal, load_xml, render_node
from zeep import xsd
def test_simple_content_extension():
schema = xsd.Schema(load_xml("""
<?xml version="1.0"?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
targetNamespace="http://tests.python-zeep.org/"
elementFormDefault="qualified">
<xsd:element name="ShoeSize">
<xsd:complexType>
<xsd:simpleContent>
<xsd:extension base="xsd:integer">
<xsd:attribute name="sizing" type="xsd:string" />
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
</xsd:element>
</xsd:schema>
""".strip()))
shoe_type = schema.get_element('{http://tests.python-zeep.org/}ShoeSize')
obj = shoe_type(20, sizing='EUR')
node = render_node(shoe_type, obj)
expected = """
<document>
<ns0:ShoeSize
xmlns:ns0="http://tests.python-zeep.org/"
sizing="EUR">20</ns0:ShoeSize>
</document>
"""
assert_nodes_equal(expected, node)
obj = shoe_type.parse(node[0], schema)
assert obj._value_1 == 20
assert obj.sizing == 'EUR'
def test_complex_content_sequence_extension():
schema = xsd.Schema(load_xml("""
<?xml version="1.0"?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
targetNamespace="http://tests.python-zeep.org/"
elementFormDefault="qualified">
<xsd:complexType name="Address">
<xsd:complexContent>
<xsd:extension base="tns:Name">
<xsd:sequence>
<xsd:element name="country" type="xsd:string"/>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:element name="Address" type="tns:Address"/>
<xsd:complexType name="Name">
<xsd:sequence>
<xsd:element name="first_name" type="xsd:string"/>
<xsd:element name="last_name" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
"""))
address_type = schema.get_element('{http://tests.python-zeep.org/}Address')
obj = address_type(
first_name='foo', last_name='bar', country='The Netherlands')
node = etree.Element('document')
address_type.render(node, obj)
expected = """
<document>
<ns0:Address xmlns:ns0="http://tests.python-zeep.org/">
<ns0:first_name>foo</ns0:first_name>
<ns0:last_name>bar</ns0:last_name>
<ns0:country>The Netherlands</ns0:country>
</ns0:Address>
</document>
"""
assert_nodes_equal(expected, node)
def test_complex_content_with_recursive_elements():
schema = xsd.Schema(load_xml("""
<?xml version="1.0"?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
targetNamespace="http://tests.python-zeep.org/"
elementFormDefault="qualified">
<xsd:complexType name="Pet">
<xsd:complexContent>
<xsd:extension base="tns:Name">
<xsd:sequence>
<xsd:element name="children" type="tns:Pet"/>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:element name="Pet" type="tns:Pet"/>
<xsd:complexType name="Name">
<xsd:sequence>
<xsd:element name="name" type="xsd:string"/>
<xsd:element name="common_name" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
"""))
pet_type = schema.get_element('{http://tests.python-zeep.org/}Pet')
assert(pet_type.signature() == 'name: xsd:string, common_name: xsd:string, children: Pet')
obj = pet_type(
name='foo', common_name='bar')
node = etree.Element('document')
pet_type.render(node, obj)
expected = """
<document>
<ns0:Pet xmlns:ns0="http://tests.python-zeep.org/">
<ns0:name>foo</ns0:name>
<ns0:common_name>bar</ns0:common_name>
<ns0:children/>
</ns0:Pet>
</document>
"""
assert_nodes_equal(expected, node)
def test_complex_content_sequence_extension_2():
schema = xsd.Schema(load_xml("""
<?xml version="1.0"?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
targetNamespace="http://tests.python-zeep.org/"
elementFormDefault="qualified">
<xsd:element name="container" type="tns:baseResponse"/>
<xsd:complexType name="baseResponse">
<xsd:sequence>
<xsd:element name="item-1" type="xsd:string"/>
<xsd:element name="item-2" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="response">
<xsd:complexContent>
<xsd:extension base="tns:baseResponse">
<xsd:sequence>
<xsd:element name="item-3" type="xsd:string"/>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:schema>
"""))
elm_cls = schema.get_element('{http://tests.python-zeep.org/}container')
node = load_xml("""
<ns0:container xmlns:ns0="http://tests.python-zeep.org/"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
i:type="ns0:response">
<ns0:item-1>item-1</ns0:item-1>
<ns0:item-2>item-2</ns0:item-2>
<ns0:item-3>item-3</ns0:item-3>
</ns0:container>
""")
data = elm_cls.parse(node, schema)
assert data['item-1'] == 'item-1'
assert data['item-2'] == 'item-2'
assert data['item-3'] == 'item-3'
def test_complex_type_with_extension_optional():
schema = xsd.Schema(load_xml("""
<?xml version="1.0"?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
targetNamespace="http://tests.python-zeep.org/"
elementFormDefault="qualified">
<xsd:complexType name="containerType">
<xsd:complexContent>
<xsd:extension base="tns:base">
<xsd:sequence>
<xsd:element name="main_1" type="xsd:string"/>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:element name="container" type="tns:containerType"/>
<xsd:complexType name="base">
<xsd:sequence>
<xsd:element minOccurs="0" name="base_1" type="tns:baseType"/>
<xsd:element minOccurs="0" name="base_2" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="baseType">
<xsd:sequence>
<xsd:element minOccurs="0" name="base_1_1" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
"""))
container_elm = schema.get_element('{http://tests.python-zeep.org/}container')
obj = container_elm(main_1='foo')
node = etree.Element('document')
container_elm.render(node, obj)
expected = """
<document>
<ns0:container xmlns:ns0="http://tests.python-zeep.org/">
<ns0:main_1>foo</ns0:main_1>
</ns0:container>
</document>
"""
assert_nodes_equal(expected, node)
assert_nodes_equal(expected, node)
item = container_elm.parse(node.getchildren()[0], schema)
assert item.main_1 == 'foo'
def test_complex_with_simple():
schema = xsd.Schema(load_xml("""
<?xml version="1.0"?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
elementFormDefault="qualified"
targetNamespace="http://tests.python-zeep.org/">
<xsd:element name="Address">
<xsd:complexType>
<xsd:simpleContent>
<xsd:extension base="tns:DateTimeType">
<xsd:attribute name="name" type="xsd:token"/>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
</xsd:element>
<xsd:simpleType name="DateTimeType">
<xsd:restriction base="xsd:dateTime"/>
</xsd:simpleType>
</xsd:schema>
"""))
address_type = schema.get_element('ns0:Address')
assert address_type.type.signature()
val = datetime.datetime(2016, 5, 29, 11, 13, 45)
obj = address_type(val, name='foobie')
expected = """
<document>
<ns0:Address xmlns:ns0="http://tests.python-zeep.org/"
name="foobie">2016-05-29T11:13:45</ns0:Address>
</document>
"""
node = etree.Element('document')
address_type.render(node, obj)
assert_nodes_equal(expected, node)
def test_sequence_with_type():
schema = xsd.Schema(load_xml("""
<?xml version="1.0"?>
<schema
xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
elementFormDefault="qualified"
targetNamespace="http://tests.python-zeep.org/">
<complexType name="base" abstract="true">
<sequence>
<element name="name" type="xsd:string" minOccurs="0"/>
</sequence>
</complexType>
<complexType name="subtype">
<complexContent>
<extension base="tns:base">
<attribute name="attr_1" type="xsd:string"/>
</extension>
</complexContent>
</complexType>
<complexType name="polytype">
<sequence>
<element name="item" type="tns:base" maxOccurs="unbounded" minOccurs="0"/>
</sequence>
</complexType>
<element name="Seq" type="tns:polytype"/>
</schema>
"""))
seq = schema.get_type('ns0:polytype')
sub_type = schema.get_type('ns0:subtype')
value = seq(item=[sub_type(attr_1='test', name='name')])
node = etree.Element('document')
seq.render(node, value)
expected = """
<document>
<ns0:item
xmlns:ns0="http://tests.python-zeep.org/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
attr_1="test" xsi:type="ns0:subtype">
<ns0:name>name</ns0:name>
</ns0:item>
</document>
"""
assert_nodes_equal(expected, node)
def test_complex_simple_content():
schema = xsd.Schema(load_xml("""
<?xml version="1.0"?>
<xsd:schema
xmlns:tns="http://tests.python-zeep.org/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://tests.python-zeep.org/"
elementFormDefault="qualified">
<xsd:element name="value" type="tns:UUID"/>
<xsd:complexType name="UUID">
<xsd:simpleContent>
<xsd:extension base="tns:UUID.Content">
<xsd:attribute name="schemeID">
<xsd:simpleType>
<xsd:restriction base="xsd:token">
<xsd:maxLength value="60"/>
<xsd:minLength value="1"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:attribute>
<xsd:attribute name="schemeAgencyID">
<xsd:simpleType>
<xsd:restriction base="xsd:token">
<xsd:maxLength value="60"/>
<xsd:minLength value="1"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:attribute>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
<xsd:simpleType name="UUID.Content">
<xsd:restriction base="xsd:token">
<xsd:maxLength value="36"/>
<xsd:minLength value="36"/>
<xsd:pattern value="[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>
""")) # noqa
value_elm = schema.get_element('ns0:value')
value = value_elm('00163e0c-0ea1-1ed6-93af-e818529bc1f1')
node = etree.Element('document')
value_elm.render(node, value)
expected = """
<document>
<ns0:value xmlns:ns0="http://tests.python-zeep.org/">00163e0c-0ea1-1ed6-93af-e818529bc1f1</ns0:value>
</document>
""" # noqa
assert_nodes_equal(expected, node)
item = value_elm.parse(node.getchildren()[0], schema)
assert item._value_1 == '00163e0c-0ea1-1ed6-93af-e818529bc1f1'
def test_issue_221():
transport = DummyTransport()
transport.bind(
'https://www.w3.org/TR/xmldsig-core/xmldsig-core-schema.xsd',
load_xml(io.open('tests/wsdl_files/xmldsig-core-schema.xsd', 'r').read().encode('utf-8')))
schema = xsd.Schema(load_xml("""
<?xml version="1.0"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
targetNamespace="http://tests.python-zeep.org/"
elementFormDefault="qualified">
<import namespace="http://www.w3.org/2000/09/xmldsig#"
schemaLocation="https://www.w3.org/TR/xmldsig-core/xmldsig-core-schema.xsd"/>
<complexType name="BaseType">
<sequence>
<element ref="ds:Signature" minOccurs="0"/>
</sequence>
<attribute name="Id"/>
</complexType>
<element name="exportOrgRegistryRequest">
<complexType>
<complexContent>
<extension base="tns:BaseType">
<sequence>
<element name="SearchCriteria" maxOccurs="100">
<complexType>
<sequence>
<choice>
<choice>
<element ref="tns:OGRNIP"/>
<sequence>
<element name="OGRN" type="string"/>
<element name="KPP" type="string" minOccurs="0"/>
</sequence>
</choice>
<element ref="tns:orgVersionGUID"/>
<element ref="tns:orgRootEntityGUID"/>
</choice>
<element name="isRegistered" type="boolean" fixed="true" minOccurs="0">
</element>
</sequence>
</complexType>
</element>
<element name="lastEditingDateFrom" type="date" minOccurs="0"/>
</sequence>
</extension>
</complexContent>
</complexType>
</element>
<simpleType name="OGRNIPType">
<restriction base="string">
<length value="13"/>
</restriction>
</simpleType>
<element name="OGRNIP" type="tns:OGRNIPType"/>
<element name="orgVersionGUID" type="tns:GUIDType"/>
<element name="orgRootEntityGUID" type="tns:GUIDType"/>
<simpleType name="GUIDType">
<restriction base="string">
<pattern value="([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}"/>
</restriction>
</simpleType>x
</schema>
"""), transport=transport)
schema.set_ns_prefix('tns', 'http://tests.python-zeep.org/')
elm = schema.get_element('tns:exportOrgRegistryRequest')
# Args
obj = elm(None, {'OGRN': '123123123123', 'isRegistered': True})
node = etree.Element('document')
elm.render(node, obj)
expected = """
<document>
<ns0:exportOrgRegistryRequest xmlns:ns0="http://tests.python-zeep.org/">
<ns0:SearchCriteria>
<ns0:OGRN>123123123123</ns0:OGRN>
<ns0:isRegistered>true</ns0:isRegistered>
</ns0:SearchCriteria>
</ns0:exportOrgRegistryRequest>
</document>
"""
assert_nodes_equal(expected, node)
obj = elm(SearchCriteria={'orgVersionGUID': '1234', 'isRegistered': False})
node = etree.Element('document')
elm.render(node, obj)
expected = """
<document>
<ns0:exportOrgRegistryRequest xmlns:ns0="http://tests.python-zeep.org/">
<ns0:SearchCriteria>
<ns0:orgVersionGUID>1234</ns0:orgVersionGUID>
<ns0:isRegistered>false</ns0:isRegistered>
</ns0:SearchCriteria>
</ns0:exportOrgRegistryRequest>
</document>
"""
assert_nodes_equal(expected, node)
obj = elm(SearchCriteria={'OGRNIP': '123123123123', 'isRegistered': True})
node = etree.Element('document')
elm.render(node, obj)
expected = """
<document>
<ns0:exportOrgRegistryRequest xmlns:ns0="http://tests.python-zeep.org/">
<ns0:SearchCriteria>
<ns0:OGRNIP>123123123123</ns0:OGRNIP>
<ns0:isRegistered>true</ns0:isRegistered>
</ns0:SearchCriteria>
</ns0:exportOrgRegistryRequest>
</document>
"""
assert_nodes_equal(expected, node)
def test_complex_content_extension_with_sequence():
schema = xsd.Schema(load_xml("""
<?xml version="1.0"?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
targetNamespace="http://tests.python-zeep.org/"
elementFormDefault="qualified">
<xsd:complexType name="Package">
<xsd:complexContent>
<xsd:extension base="tns:AbstractPackage">
<xsd:attribute name="id" type="xsd:string"/>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="SpecialPackage">
<xsd:complexContent>
<xsd:extension base="tns:Package">
<xsd:sequence>
<xsd:element name="otherElement" type="xsd:string"/>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="AbstractPackage">
<xsd:attribute name="pkg_id" type="xsd:string"/>
</xsd:complexType>
<xsd:element name="SpecialPackage" type="tns:SpecialPackage"/>
</xsd:schema>
"""))
address_type = schema.get_element('{http://tests.python-zeep.org/}SpecialPackage')
obj = address_type(
id='testString', pkg_id='nameId')
node = etree.Element('document')
address_type.render(node, obj)
expected = """
<document>
<ns0:SpecialPackage xmlns:ns0="http://tests.python-zeep.org/" pkg_id="nameId" id="testString">
<ns0:otherElement/>
</ns0:SpecialPackage>
</document>
"""
assert_nodes_equal(expected, node)
def test_extension_abstract_complex_type():
schema = xsd.Schema(load_xml("""
<?xml version="1.0"?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
targetNamespace="http://tests.python-zeep.org/"
elementFormDefault="qualified">
<xsd:complexType name="Package" abstract="true"/>
<xsd:complexType name="SpecialPackage">
<xsd:complexContent>
<xsd:extension base="tns:Package">
<xsd:sequence>
<xsd:element name="item" type="xsd:string"/>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:element name="SpecialPackage" type="tns:SpecialPackage"/>
</xsd:schema>
"""))
package_cls = schema.get_element('{http://tests.python-zeep.org/}SpecialPackage')
obj = package_cls(item='foo')
node = etree.Element('document')
package_cls.render(node, obj)
expected = """
<document>
<ns0:SpecialPackage xmlns:ns0="http://tests.python-zeep.org/">
<ns0:item>foo</ns0:item>
</ns0:SpecialPackage>
</document>
"""
assert_nodes_equal(expected, node)

View File

@ -1,3 +1,5 @@
import copy
import pytest
from lxml import etree
@ -125,7 +127,6 @@ def test_array():
"""
node = etree.Element('document', nsmap=schema._prefix_map_custom)
address_type.render(node, obj)
print(etree.tostring(node))
assert_nodes_equal(expected, node)
@ -902,3 +903,51 @@ def test_empty_xmlns():
""")
item = container_elm.parse(node, schema)
assert item._value_1 == 'foo'
def test_keep_objects_intact():
node = etree.fromstring("""
<?xml version="1.0"?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
attributeFormDefault="qualified"
elementFormDefault="qualified"
targetNamespace="http://tests.python-zeep.org/">
<xsd:element name="Address">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="name" type="xsd:string"/>
<xsd:element minOccurs="0" name="optional" type="xsd:string"/>
<xsd:element name="container" nillable="true" type="tns:Container"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:complexType name="Container">
<xsd:sequence>
<xsd:element maxOccurs="unbounded" minOccurs="0" name="service"
nillable="true" type="tns:ServiceRequestType"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ServiceRequestType">
<xsd:sequence>
<xsd:element name="name" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
""".strip())
schema = xsd.Schema(node)
address_type = schema.get_element('{http://tests.python-zeep.org/}Address')
obj = address_type(name='foo', container={'service': [{'name': 'foo'}]})
org_obj = copy.deepcopy(obj)
node = etree.Element('document')
address_type.render(node, obj)
print(org_obj)
print(obj)
assert org_obj['container']['service'] == obj['container']['service']

View File

@ -30,6 +30,33 @@ def test_sequence_parse_basic():
assert obj.item_2 == 'bar'
def test_sequence_parse_max_occurs_infinite_loop():
custom_type = xsd.Element(
etree.QName('http://tests.python-zeep.org/', 'authentication'),
xsd.ComplexType(
xsd.Sequence([
xsd.Element(
etree.QName('http://tests.python-zeep.org/', 'item_1'),
xsd.String()),
xsd.Element(
etree.QName('http://tests.python-zeep.org/', 'item_2'),
xsd.String()),
], max_occurs='unbounded')
))
expected = etree.fromstring("""
<ns0:container xmlns:ns0="http://tests.python-zeep.org/">
<ns0:item_1>foo</ns0:item_1>
<ns0:item_2>bar</ns0:item_2>
</ns0:container>
""")
obj = custom_type.parse(expected, None)
assert obj._value_1 == [
{
'item_1': 'foo',
'item_2': 'bar',
}
]
def test_sequence_parse_basic_with_attrs():
custom_element = xsd.Element(
etree.QName('http://tests.python-zeep.org/', 'authentication'),

656
tests/test_xsd_schemas.py Normal file
View File

@ -0,0 +1,656 @@
import pytest
from lxml import etree
from tests.utils import DummyTransport, load_xml
from zeep import exceptions, xsd
from zeep.xsd.builtins import Schema as Schema
from zeep.exceptions import ZeepWarning
def test_default_types():
schema = xsd.Schema()
xsd_string = schema.get_type('{http://www.w3.org/2001/XMLSchema}string')
assert xsd_string == xsd.String()
def test_default_types_not_found():
schema = xsd.Schema()
with pytest.raises(exceptions.LookupError):
schema.get_type('{http://www.w3.org/2001/XMLSchema}bar')
def test_default_elements():
schema = xsd.Schema()
xsd_schema = schema.get_element('{http://www.w3.org/2001/XMLSchema}schema')
isinstance(xsd_schema, Schema)
def test_default_elements_not_found():
schema = xsd.Schema()
with pytest.raises(exceptions.LookupError):
schema.get_element('{http://www.w3.org/2001/XMLSchema}bar')
def test_invalid_namespace_handling():
schema = xsd.Schema()
qname = '{http://tests.python-zeep.org/404}foo'
with pytest.raises(exceptions.NamespaceError) as exc:
schema.get_element(qname)
assert qname in str(exc.value.message)
with pytest.raises(exceptions.NamespaceError) as exc:
schema.get_type(qname)
assert qname in str(exc.value.message)
with pytest.raises(exceptions.NamespaceError) as exc:
schema.get_group(qname)
assert qname in str(exc.value.message)
with pytest.raises(exceptions.NamespaceError) as exc:
schema.get_attribute(qname)
assert qname in str(exc.value.message)
with pytest.raises(exceptions.NamespaceError) as exc:
schema.get_attribute_group(qname)
assert qname in str(exc.value.message)
def test_invalid_localname_handling():
schema = xsd.Schema(load_xml("""
<?xml version="1.0"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
targetNamespace="http://tests.python-zeep.org/"
elementFormDefault="qualified">
</xs:schema>
"""))
qname = '{http://tests.python-zeep.org/}foo'
namespace = 'http://tests.python-zeep.org/'
localname = 'foo'
with pytest.raises(exceptions.LookupError) as exc:
schema.get_element(qname)
assert namespace in str(exc.value.message)
assert localname in str(exc.value.message)
with pytest.raises(exceptions.LookupError) as exc:
schema.get_type(qname)
assert namespace in str(exc.value.message)
assert localname in str(exc.value.message)
with pytest.raises(exceptions.LookupError) as exc:
schema.get_group(qname)
assert namespace in str(exc.value.message)
assert localname in str(exc.value.message)
with pytest.raises(exceptions.LookupError) as exc:
schema.get_attribute(qname)
assert namespace in str(exc.value.message)
assert localname in str(exc.value.message)
with pytest.raises(exceptions.LookupError) as exc:
schema.get_attribute_group(qname)
assert namespace in str(exc.value.message)
assert localname in str(exc.value.message)
def test_schema_repr_none():
schema = xsd.Schema()
assert repr(schema) == "<Schema(location='<none>')>"
def test_schema_repr_val():
schema = xsd.Schema(load_xml("""
<?xml version="1.0"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
targetNamespace="http://tests.python-zeep.org/"
elementFormDefault="qualified">
</xs:schema>
"""))
assert repr(schema) == "<Schema(location=None)>"
def test_schema_doc_repr_val():
schema = xsd.Schema(load_xml("""
<?xml version="1.0"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
targetNamespace="http://tests.python-zeep.org/"
elementFormDefault="qualified">
</xs:schema>
"""))
doc = schema._get_schema_document('http://tests.python-zeep.org/')
assert repr(doc) == "<SchemaDocument(location=None, tns='http://tests.python-zeep.org/', is_empty=True)>"
def test_multiple_extension():
node_a = etree.fromstring("""
<?xml version="1.0"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/a"
targetNamespace="http://tests.python-zeep.org/a"
xmlns:b="http://tests.python-zeep.org/b"
elementFormDefault="qualified">
<xs:import
schemaLocation="http://tests.python-zeep.org/b.xsd"
namespace="http://tests.python-zeep.org/b"/>
<xs:complexType name="type_a">
<xs:complexContent>
<xs:extension base="b:type_b"/>
</xs:complexContent>
</xs:complexType>
<xs:element name="typetje" type="tns:type_a"/>
</xs:schema>
""".strip())
node_b = etree.fromstring("""
<?xml version="1.0"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/b"
targetNamespace="http://tests.python-zeep.org/b"
xmlns:c="http://tests.python-zeep.org/c"
elementFormDefault="qualified">
<xs:import
schemaLocation="http://tests.python-zeep.org/c.xsd"
namespace="http://tests.python-zeep.org/c"/>
<xs:complexType name="type_b">
<xs:complexContent>
<xs:extension base="c:type_c"/>
</xs:complexContent>
</xs:complexType>
</xs:schema>
""".strip())
node_c = etree.fromstring("""
<?xml version="1.0"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/c"
targetNamespace="http://tests.python-zeep.org/c"
elementFormDefault="qualified">
<xs:complexType name="type_c">
<xs:complexContent>
<xs:extension base="tns:type_d"/>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="type_d">
<xs:attribute name="wat" type="xs:string" />
</xs:complexType>
</xs:schema>
""".strip())
etree.XMLSchema(node_c)
transport = DummyTransport()
transport.bind('http://tests.python-zeep.org/b.xsd', node_b)
transport.bind('http://tests.python-zeep.org/c.xsd', node_c)
schema = xsd.Schema(node_a, transport=transport)
type_a = schema.get_type('ns0:type_a')
type_a(wat='x')
def test_global_element_and_type():
node_a = etree.fromstring("""
<?xml version="1.0"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/a"
targetNamespace="http://tests.python-zeep.org/a"
xmlns:b="http://tests.python-zeep.org/b"
elementFormDefault="qualified">
<xs:import
schemaLocation="http://tests.python-zeep.org/b.xsd"
namespace="http://tests.python-zeep.org/b"/>
<xs:complexType name="refs">
<xs:sequence>
<xs:element ref="b:ref_elm"/>
</xs:sequence>
<xs:attribute ref="b:ref_attr"/>
</xs:complexType>
</xs:schema>
""".strip())
node_b = etree.fromstring("""
<?xml version="1.0"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/b"
targetNamespace="http://tests.python-zeep.org/b"
xmlns:c="http://tests.python-zeep.org/c"
elementFormDefault="qualified">
<xs:import
schemaLocation="http://tests.python-zeep.org/c.xsd"
namespace="http://tests.python-zeep.org/c"/>
<xs:element name="ref_elm" type="xs:string"/>
<xs:attribute name="ref_attr" type="xs:string"/>
</xs:schema>
""".strip())
node_c = etree.fromstring("""
<?xml version="1.0"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/c"
targetNamespace="http://tests.python-zeep.org/c"
elementFormDefault="qualified">
<xs:complexType name="type_a">
<xs:sequence>
<xs:element name="item_a" type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:element name="item" type="xs:string"/>
</xs:schema>
""".strip())
etree.XMLSchema(node_c)
transport = DummyTransport()
transport.bind('http://tests.python-zeep.org/b.xsd', node_b)
transport.bind('http://tests.python-zeep.org/c.xsd', node_c)
schema = xsd.Schema(node_a, transport=transport)
type_a = schema.get_type('{http://tests.python-zeep.org/c}type_a')
type_a = schema.get_type('{http://tests.python-zeep.org/c}type_a')
type_a(item_a='x')
elm = schema.get_element('{http://tests.python-zeep.org/c}item')
elm('x')
elm = schema.get_type('{http://tests.python-zeep.org/a}refs')
elm(ref_elm='foo', ref_attr='bar')
def test_cyclic_imports():
schema_a = etree.fromstring("""
<?xml version="1.0"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/a"
targetNamespace="http://tests.python-zeep.org/a"
xmlns:b="http://tests.python-zeep.org/b"
elementFormDefault="qualified">
<xs:import
schemaLocation="http://tests.python-zeep.org/b.xsd"
namespace="http://tests.python-zeep.org/b"/>
</xs:schema>
""".strip())
schema_b = etree.fromstring("""
<?xml version="1.0"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/b"
targetNamespace="http://tests.python-zeep.org/b"
xmlns:c="http://tests.python-zeep.org/c"
elementFormDefault="qualified">
<xs:import
schemaLocation="http://tests.python-zeep.org/c.xsd"
namespace="http://tests.python-zeep.org/c"/>
</xs:schema>
""".strip())
schema_c = etree.fromstring("""
<?xml version="1.0"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/c"
targetNamespace="http://tests.python-zeep.org/c"
elementFormDefault="qualified">
<xs:import
schemaLocation="http://tests.python-zeep.org/a.xsd"
namespace="http://tests.python-zeep.org/a"/>
</xs:schema>
""".strip())
transport = DummyTransport()
transport.bind('http://tests.python-zeep.org/a.xsd', schema_a)
transport.bind('http://tests.python-zeep.org/b.xsd', schema_b)
transport.bind('http://tests.python-zeep.org/c.xsd', schema_c)
xsd.Schema(schema_a, transport=transport, location='http://tests.python-zeep.org/a.xsd')
def test_get_type_through_import():
schema_a = etree.fromstring("""
<?xml version="1.0"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/a"
targetNamespace="http://tests.python-zeep.org/a"
xmlns:b="http://tests.python-zeep.org/b"
elementFormDefault="qualified">
<xs:import
schemaLocation="http://tests.python-zeep.org/b.xsd"
namespace="http://tests.python-zeep.org/b"/>
<xs:element name="foo" type="b:bar"/>
</xs:schema>
""".strip())
schema_b = etree.fromstring("""
<?xml version="1.0"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/b"
targetNamespace="http://tests.python-zeep.org/b"
xmlns:c="http://tests.python-zeep.org/c"
elementFormDefault="qualified">
<xs:complexType name="bar"/>
</xs:schema>
""".strip())
transport = DummyTransport()
transport.bind('http://tests.python-zeep.org/a.xsd', schema_a)
transport.bind('http://tests.python-zeep.org/b.xsd', schema_b)
xsd.Schema(schema_a, transport=transport)
def test_duplicate_target_namespace():
schema_a = etree.fromstring("""
<?xml version="1.0"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/a"
targetNamespace="http://tests.python-zeep.org/a"
elementFormDefault="qualified">
<xs:import
schemaLocation="http://tests.python-zeep.org/b.xsd"
namespace="http://tests.python-zeep.org/duplicate"/>
<xs:import
schemaLocation="http://tests.python-zeep.org/c.xsd"
namespace="http://tests.python-zeep.org/duplicate"/>
</xs:schema>
""".strip())
schema_b = etree.fromstring("""
<?xml version="1.0"?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://tests.python-zeep.org/duplicate"
elementFormDefault="qualified">
</xsd:schema>
""".strip())
schema_c = etree.fromstring("""
<?xml version="1.0"?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://tests.python-zeep.org/duplicate"
elementFormDefault="qualified">
</xsd:schema>
""".strip())
transport = DummyTransport()
transport.bind('http://tests.python-zeep.org/a.xsd', schema_a)
transport.bind('http://tests.python-zeep.org/b.xsd', schema_b)
transport.bind('http://tests.python-zeep.org/c.xsd', schema_c)
with pytest.warns(ZeepWarning):
xsd.Schema(schema_a, transport=transport)
def test_multiple_no_namespace():
node_a = etree.fromstring("""
<?xml version="1.0"?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/a"
targetNamespace="http://tests.python-zeep.org/a"
elementFormDefault="qualified">
<xsd:import schemaLocation="http://tests.python-zeep.org/b.xsd"/>
<xsd:import schemaLocation="http://tests.python-zeep.org/c.xsd"/>
</xsd:schema>
""".strip())
node_b = etree.fromstring("""
<?xml version="1.0"?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified">
</xsd:schema>
""".strip())
transport = DummyTransport()
transport.bind('http://tests.python-zeep.org/b.xsd', node_b)
transport.bind('http://tests.python-zeep.org/c.xsd', node_b)
with pytest.warns(ZeepWarning):
xsd.Schema(node_a, transport=transport)
def test_multiple_only_target_ns():
node_a = etree.fromstring("""
<?xml version="1.0"?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/a"
targetNamespace="http://tests.python-zeep.org/a"
elementFormDefault="qualified">
<xsd:import schemaLocation="http://tests.python-zeep.org/b.xsd"/>
<xsd:import schemaLocation="http://tests.python-zeep.org/c.xsd"/>
</xsd:schema>
""".strip())
node_b = etree.fromstring("""
<?xml version="1.0"?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified"
targetNamespace="http://tests.python-zeep.org/duplicate-ns">
</xsd:schema>
""".strip())
transport = DummyTransport()
transport.bind('http://tests.python-zeep.org/b.xsd', node_b)
transport.bind('http://tests.python-zeep.org/c.xsd', node_b)
with pytest.warns(ZeepWarning):
xsd.Schema(node_a, transport=transport)
def test_schema_error_handling():
node_a = etree.fromstring("""
<?xml version="1.0"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/a"
targetNamespace="http://tests.python-zeep.org/a"
xmlns:b="http://tests.python-zeep.org/b"
elementFormDefault="qualified">
</xs:schema>
""".strip())
transport = DummyTransport()
schema = xsd.Schema(node_a, transport=transport)
with pytest.raises(ValueError):
schema.get_element('nonexisting:something')
with pytest.raises(ValueError):
schema.get_type('nonexisting:something')
with pytest.raises(exceptions.NamespaceError):
schema.get_element('{nonexisting}something')
with pytest.raises(exceptions.NamespaceError):
schema.get_type('{nonexisting}something')
with pytest.raises(exceptions.LookupError):
schema.get_element('ns0:something')
with pytest.raises(exceptions.LookupError):
schema.get_type('ns0:something')
def test_schema_import_xmlsoap():
node_a = etree.fromstring("""
<?xml version="1.0"?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/a"
targetNamespace="http://tests.python-zeep.org/a"
xmlns:b="http://tests.python-zeep.org/b"
elementFormDefault="qualified">
<xsd:import namespace="http://schemas.xmlsoap.org/soap/encoding/"/>
</xsd:schema>
""".strip())
transport = DummyTransport()
xsd.Schema(node_a, transport=transport)
def test_schema_import_unresolved():
node_a = etree.fromstring("""
<?xml version="1.0"?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/a"
targetNamespace="http://tests.python-zeep.org/a"
xmlns:b="http://tests.python-zeep.org/b"
elementFormDefault="qualified">
<xsd:import namespace="http://schemas.xmlsoap.org/soap/encoding/"/>
</xsd:schema>
""".strip())
transport = DummyTransport()
xsd.Schema(node_a, transport=transport)
def test_no_target_namespace():
node_a = etree.fromstring("""
<?xml version="1.0"?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/a"
targetNamespace="http://tests.python-zeep.org/a"
elementFormDefault="qualified">
<xsd:import schemaLocation="http://tests.python-zeep.org/b.xsd"/>
<xsd:element name="container">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="bla"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
""".strip())
node_b = etree.fromstring("""
<?xml version="1.0"?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified">
<xsd:element name="bla" type="xsd:string"/>
</xsd:schema>
""".strip())
transport = DummyTransport()
transport.bind('http://tests.python-zeep.org/b.xsd', node_b)
xsd.Schema(node_a, transport=transport)
def test_include_recursion():
node_a = etree.fromstring("""
<?xml version="1.0"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/a"
targetNamespace="http://tests.python-zeep.org/a"
xmlns:b="http://tests.python-zeep.org/b"
elementFormDefault="qualified">
<xs:import
schemaLocation="http://tests.python-zeep.org/b.xsd"
namespace="http://tests.python-zeep.org/b"/>
</xs:schema>
""".strip())
node_b = etree.fromstring("""
<?xml version="1.0"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/b"
targetNamespace="http://tests.python-zeep.org/b"
elementFormDefault="qualified">
<xs:include schemaLocation="http://tests.python-zeep.org/c.xsd"/>
<xs:element name="bar" type="xs:string"/>
</xs:schema>
""".strip())
node_c = etree.fromstring("""
<?xml version="1.0"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/b"
targetNamespace="http://tests.python-zeep.org/b"
elementFormDefault="qualified">
<xs:include schemaLocation="http://tests.python-zeep.org/b.xsd"/>
<xs:element name="foo" type="xs:string"/>
</xs:schema>
""".strip())
transport = DummyTransport()
transport.bind('http://tests.python-zeep.org/b.xsd', node_b)
transport.bind('http://tests.python-zeep.org/c.xsd', node_c)
schema = xsd.Schema(node_a, transport=transport)
schema.get_element('{http://tests.python-zeep.org/b}foo')
schema.get_element('{http://tests.python-zeep.org/b}bar')
def test_merge():
node_a = etree.fromstring("""
<?xml version="1.0"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/a"
targetNamespace="http://tests.python-zeep.org/a"
xmlns:b="http://tests.python-zeep.org/b"
elementFormDefault="qualified">
<xs:element name="foo" type="xs:string"/>
</xs:schema>
""".strip())
node_b = etree.fromstring("""
<?xml version="1.0"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/b"
targetNamespace="http://tests.python-zeep.org/b"
elementFormDefault="qualified">
<xs:element name="foo" type="xs:int"/>
</xs:schema>
""".strip())
schema_a = xsd.Schema(node_a)
schema_b = xsd.Schema(node_b)
schema_a.merge(schema_b)
schema_a.get_element('{http://tests.python-zeep.org/a}foo')
schema_a.get_element('{http://tests.python-zeep.org/b}foo')

View File

@ -0,0 +1,187 @@
from lxml import etree
from zeep import xsd
def test_signature_complex_type_choice():
custom_type = xsd.Element(
etree.QName('http://tests.python-zeep.org/', 'authentication'),
xsd.ComplexType(
xsd.Choice([
xsd.Element(
etree.QName('http://tests.python-zeep.org/', 'item_1'),
xsd.String()),
xsd.Element(
etree.QName('http://tests.python-zeep.org/', 'item_2'),
xsd.String()),
])
))
assert custom_type.signature() == '({item_1: xsd:string} | {item_2: xsd:string})'
def test_signature_complex_type_choice_sequence():
custom_type = xsd.Element(
etree.QName('http://tests.python-zeep.org/', 'authentication'),
xsd.ComplexType(
xsd.Choice([
xsd.Element(
etree.QName('http://tests.python-zeep.org/', 'item_1'),
xsd.String()),
xsd.Sequence([
xsd.Element(
etree.QName('http://tests.python-zeep.org/', 'item_2_1'),
xsd.String()),
xsd.Element(
etree.QName('http://tests.python-zeep.org/', 'item_2_2'),
xsd.String()),
])
])
))
assert custom_type.signature() == (
'({item_1: xsd:string} | {item_2_1: xsd:string, item_2_2: xsd:string})')
def test_signature_nested_sequences():
custom_type = xsd.Element(
etree.QName('http://tests.python-zeep.org/', 'authentication'),
xsd.ComplexType(
xsd.Sequence([
xsd.Element(
etree.QName('http://tests.python-zeep.org/', 'item_1'),
xsd.String()),
xsd.Element(
etree.QName('http://tests.python-zeep.org/', 'item_2'),
xsd.String()),
xsd.Sequence([
xsd.Element(
etree.QName('http://tests.python-zeep.org/', 'item_3'),
xsd.String()),
xsd.Element(
etree.QName('http://tests.python-zeep.org/', 'item_4'),
xsd.String()),
]),
xsd.Choice([
xsd.Element(
etree.QName('http://tests.python-zeep.org/', 'item_5'),
xsd.String()),
xsd.Element(
etree.QName('http://tests.python-zeep.org/', 'item_6'),
xsd.String()),
xsd.Sequence([
xsd.Element(
etree.QName('http://tests.python-zeep.org/', 'item_5'),
xsd.String()),
xsd.Element(
etree.QName('http://tests.python-zeep.org/', 'item_6'),
xsd.String()),
])
])
])
))
assert custom_type.signature() == (
'item_1: xsd:string, item_2: xsd:string, item_3: xsd:string, item_4: xsd:string, ({item_5: xsd:string} | {item_6: xsd:string} | {item_5: xsd:string, item_6: xsd:string})' # noqa
)
def test_signature_nested_sequences_multiple():
custom_type = xsd.Element(
etree.QName('http://tests.python-zeep.org/', 'authentication'),
xsd.ComplexType(
xsd.Sequence([
xsd.Element(
etree.QName('http://tests.python-zeep.org/', 'item_1'),
xsd.String()),
xsd.Element(
etree.QName('http://tests.python-zeep.org/', 'item_2'),
xsd.String()),
xsd.Sequence([
xsd.Element(
etree.QName('http://tests.python-zeep.org/', 'item_3'),
xsd.String()),
xsd.Element(
etree.QName('http://tests.python-zeep.org/', 'item_4'),
xsd.String()),
]),
xsd.Choice([
xsd.Element(
etree.QName('http://tests.python-zeep.org/', 'item_5'),
xsd.String()),
xsd.Element(
etree.QName('http://tests.python-zeep.org/', 'item_6'),
xsd.String()),
xsd.Sequence([
xsd.Element(
etree.QName('http://tests.python-zeep.org/', 'item_5'),
xsd.String()),
xsd.Element(
etree.QName('http://tests.python-zeep.org/', 'item_6'),
xsd.String()),
])
], min_occurs=2, max_occurs=3)
])
))
assert custom_type.signature() == (
'item_1: xsd:string, item_2: xsd:string, item_3: xsd:string, item_4: xsd:string, _value_1: ({item_5: xsd:string} | {item_6: xsd:string} | {item_5: xsd:string, item_6: xsd:string})[]' # noqa
)
def test_signature_complex_type_any():
custom_type = xsd.Element(
etree.QName('http://tests.python-zeep.org/', 'authentication'),
xsd.ComplexType(
xsd.Choice([
xsd.Element(
etree.QName('http://tests.python-zeep.org/', 'item_1'),
xsd.String()),
xsd.Any()
])
))
assert custom_type.signature() == '({item_1: xsd:string} | {_value_1: ANY})'
custom_type(item_1='foo')
def test_signature_complex_type_sequence_with_any():
custom_type = xsd.Element(
etree.QName('http://tests.python-zeep.org/', 'authentication'),
xsd.ComplexType(
xsd.Choice([
xsd.Element(
etree.QName('http://tests.python-zeep.org/', 'item_1'),
xsd.String()),
xsd.Element(
etree.QName('http://tests.python-zeep.org/', 'item_2'),
xsd.ComplexType(
xsd.Sequence([
xsd.Any()
])
)
)
])
))
assert custom_type.signature() == (
'({item_1: xsd:string} | {item_2: {_value_1: ANY}})')
def test_signature_complex_type_sequence_with_anys():
custom_type = xsd.Element(
etree.QName('http://tests.python-zeep.org/', 'authentication'),
xsd.ComplexType(
xsd.Choice([
xsd.Element(
etree.QName('http://tests.python-zeep.org/', 'item_1'),
xsd.String()),
xsd.Element(
etree.QName('http://tests.python-zeep.org/', 'item_2'),
xsd.ComplexType(
xsd.Sequence([
xsd.Any(),
xsd.Any(),
])
)
)
])
))
assert custom_type.signature() == (
'({item_1: xsd:string} | {item_2: {_value_1: ANY, _value_2: ANY}})')

View File

@ -0,0 +1,193 @@
from lxml import etree
from tests.utils import assert_nodes_equal, load_xml
from zeep import xsd
def test_simple_type():
schema = xsd.Schema(load_xml("""
<?xml version="1.0"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
targetNamespace="http://tests.python-zeep.org/"
elementFormDefault="qualified">
<element name="item">
<complexType>
<sequence>
<element name="something" type="long"/>
</sequence>
</complexType>
</element>
</schema>
"""))
item_cls = schema.get_element('{http://tests.python-zeep.org/}item')
item = item_cls(something=12345678901234567890)
node = etree.Element('document')
item_cls.render(node, item)
expected = """
<document>
<ns0:item xmlns:ns0="http://tests.python-zeep.org/">
<ns0:something>12345678901234567890</ns0:something>
</ns0:item>
</document>
"""
assert_nodes_equal(expected, node)
item = item_cls.parse(node.getchildren()[0], schema)
assert item.something == 12345678901234567890
def test_simple_type_optional():
schema = xsd.Schema(load_xml("""
<?xml version="1.0"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
targetNamespace="http://tests.python-zeep.org/"
elementFormDefault="qualified">
<element name="item">
<complexType>
<sequence>
<element name="something" type="long" minOccurs="0"/>
</sequence>
</complexType>
</element>
</schema>
"""))
item_cls = schema.get_element('{http://tests.python-zeep.org/}item')
item = item_cls()
assert item.something is None
node = etree.Element('document')
item_cls.render(node, item)
expected = """
<document>
<ns0:item xmlns:ns0="http://tests.python-zeep.org/"/>
</document>
"""
assert_nodes_equal(expected, node)
item = item_cls.parse(node.getchildren()[0], schema)
assert item.something is None
def test_restriction_global():
schema = xsd.Schema(load_xml("""
<?xml version="1.0"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
targetNamespace="http://tests.python-zeep.org/"
elementFormDefault="qualified">
<simpleType name="foo">
<restriction base="integer">
<minInclusive value="0"/>
<maxInclusive value="100"/>
</restriction>
</simpleType>
</schema>
"""))
type_cls = schema.get_type('{http://tests.python-zeep.org/}foo')
assert type_cls.qname.text == '{http://tests.python-zeep.org/}foo'
def test_restriction_anon():
schema = xsd.Schema(load_xml("""
<?xml version="1.0"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
targetNamespace="http://tests.python-zeep.org/"
elementFormDefault="qualified">
<element name="something">
<simpleType>
<restriction base="integer">
<minInclusive value="0"/>
<maxInclusive value="100"/>
</restriction>
</simpleType>
</element>
</schema>
"""))
element_cls = schema.get_element('{http://tests.python-zeep.org/}something')
assert element_cls.type.qname == etree.QName(
'{http://tests.python-zeep.org/}something')
obj = element_cls(75)
node = etree.Element('document')
element_cls.render(node, obj)
expected = """
<document>
<ns0:something xmlns:ns0="http://tests.python-zeep.org/">75</ns0:something>
</document>
"""
assert_nodes_equal(expected, node)
def test_simple_type_list():
schema = xsd.Schema(load_xml("""
<?xml version="1.0"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
targetNamespace="http://tests.python-zeep.org/"
elementFormDefault="qualified">
<simpleType name="values">
<list itemType="integer"/>
</simpleType>
<element name="something" type="tns:values"/>
</schema>
"""))
element_cls = schema.get_element('{http://tests.python-zeep.org/}something')
obj = element_cls([1, 2, 3])
assert obj == [1, 2, 3]
node = etree.Element('document')
element_cls.render(node, obj)
expected = """
<document>
<ns0:something xmlns:ns0="http://tests.python-zeep.org/">1 2 3</ns0:something>
</document>
"""
assert_nodes_equal(expected, node)
def test_simple_type_list_custom_type():
schema = xsd.Schema(load_xml("""
<?xml version="1.0"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
targetNamespace="http://tests.python-zeep.org/"
elementFormDefault="qualified">
<simpleType name="CountryNameType">
<list>
<simpleType>
<restriction base="string">
<enumeration value="None"/>
<enumeration value="AlternateName"/>
<enumeration value="City"/>
<enumeration value="Code"/>
<enumeration value="Country"/>
</restriction>
</simpleType>
</list>
</simpleType>
<element name="something" type="tns:CountryNameType"/>
</schema>
"""))
element_cls = schema.get_element('{http://tests.python-zeep.org/}something')
obj = element_cls(['Code', 'City'])
assert obj == ['Code', 'City']
node = etree.Element('document')
element_cls.render(node, obj)
expected = """
<document>
<ns0:something xmlns:ns0="http://tests.python-zeep.org/">Code City</ns0:something>
</document>
"""
assert_nodes_equal(expected, node)

80
tests/test_xsd_types.py Normal file
View File

@ -0,0 +1,80 @@
import pytest
import six
from lxml import etree
from zeep.xsd import types
def test_base_type():
# Basically just for coverage... ;-)
base = types.Type()
with pytest.raises(NotImplementedError):
base.accept('x')
with pytest.raises(NotImplementedError):
base.parse_xmlelement(None)
with pytest.raises(NotImplementedError):
base.parsexml(None)
with pytest.raises(NotImplementedError):
base.render(None, None)
with pytest.raises(NotImplementedError):
base.resolve()
base.signature() == ''
def test_simpletype_eq():
type_1 = types.SimpleType()
type_2 = types.SimpleType()
assert type_1 == type_2
def test_simpletype_parse():
node = etree.Element('foobar')
item = types.SimpleType()
assert item.parse_xmlelement(node) is None
def test_simpletype_xmlvalue():
item = types.SimpleType()
with pytest.raises(NotImplementedError):
item.xmlvalue(None)
def test_simpletype_pythonvalue():
item = types.SimpleType()
with pytest.raises(NotImplementedError):
item.pythonvalue(None)
def test_simpletype_call_wrong_arg_count():
item = types.SimpleType()
with pytest.raises(TypeError):
item('foo', 'bar')
def test_simpletype_call_wrong_kwarg():
item = types.SimpleType()
with pytest.raises(TypeError):
item(uhhh='x')
def test_simpletype_str():
item = types.SimpleType()
item.name = u'foobar'
assert six.text_type(item) == 'SimpleType(value)'
def test_complextype_parse_xmlelement_no_childs():
xmlelement = etree.Element('foobar')
item = types.ComplexType()
assert item.parse_xmlelement(xmlelement, None) is None

91
tests/test_xsd_union.py Normal file
View File

@ -0,0 +1,91 @@
import datetime
import io
from lxml import etree
from tests.utils import DummyTransport, assert_nodes_equal, load_xml, render_node
from zeep import xsd
def test_union_same_types():
schema = xsd.Schema(load_xml("""
<?xml version="1.0"?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
targetNamespace="http://tests.python-zeep.org/"
elementFormDefault="qualified">
<xsd:simpleType name="MMYY">
<xsd:restriction base="xsd:int"/>
</xsd:simpleType>
<xsd:simpleType name="MMYYYY">
<xsd:restriction base="xsd:int"/>
</xsd:simpleType>
<xsd:simpleType name="Date">
<xsd:union memberTypes="MMYY MMYYYY"/>
</xsd:simpleType>
<xsd:element name="item" type="tns:Date"/>
</xsd:schema>
"""))
elm = schema.get_element('ns0:item')
node = render_node(elm, '102018')
expected = """
<document>
<ns0:item xmlns:ns0="http://tests.python-zeep.org/">102018</ns0:item>
</document>
"""
assert_nodes_equal(expected, node)
value = elm.parse(node.getchildren()[0], schema)
assert value == 102018
def test_union_mixed():
schema = xsd.Schema(load_xml("""
<?xml version="1.0"?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://tests.python-zeep.org/"
targetNamespace="http://tests.python-zeep.org/"
elementFormDefault="qualified">
<xsd:element name="item" type="tns:Date"/>
<xsd:simpleType name="Date">
<xsd:union memberTypes="xsd:date xsd:gYear xsd:gYearMonth MMYY MMYYYY"/>
</xsd:simpleType>
<xsd:simpleType name="MMYY">
<xsd:restriction base="xsd:string">
<xsd:pattern value="(0[123456789]|1[012]){1}\d{2}"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="MMYYYY">
<xsd:restriction base="xsd:string">
<xsd:pattern value="(0[123456789]|1[012]){1}\d{4}"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>
"""))
elm = schema.get_element('ns0:item')
node = render_node(elm, '102018')
expected = """
<document>
<ns0:item xmlns:ns0="http://tests.python-zeep.org/">102018</ns0:item>
</document>
"""
assert_nodes_equal(expected, node)
value = elm.parse(node.getchildren()[0], schema)
assert value == '102018'
node = render_node(elm, '2018')
expected = """
<document>
<ns0:item xmlns:ns0="http://tests.python-zeep.org/">2018</ns0:item>
</document>
"""
assert_nodes_equal(expected, node)
value = elm.parse(node.getchildren()[0], schema)
assert value == '2018'

View File

@ -0,0 +1,403 @@
import pytest
import six
from zeep import xsd
from zeep.xsd import valueobjects
def test_simple_args():
xsd_type = xsd.ComplexType(
xsd.Sequence([
xsd.Element('item_1', xsd.String()),
xsd.Element('item_2', xsd.String())
]))
args = tuple(['value-1', 'value-2'])
kwargs = {}
result = valueobjects._process_signature(xsd_type, args, kwargs)
assert result == {
'item_1': 'value-1',
'item_2': 'value-2',
}
def test_simple_args_attributes():
xsd_type = xsd.ComplexType(
xsd.Sequence([
xsd.Element('item_1', xsd.String()),
xsd.Element('item_2', xsd.String())
]),
[
xsd.Attribute('attr_1', xsd.String())
]
)
args = tuple(['value-1', 'value-2', 'bla'])
kwargs = {}
result = valueobjects._process_signature(xsd_type, args, kwargs)
assert result == {
'item_1': 'value-1',
'item_2': 'value-2',
'attr_1': 'bla',
}
def test_simple_args_attributes_as_kwargs():
xsd_type = xsd.ComplexType(
xsd.Sequence([
xsd.Element('item_1', xsd.String()),
xsd.Element('item_2', xsd.String())
]),
[
xsd.Attribute('attr_1', xsd.String())
]
)
args = tuple(['value-1', 'value-2'])
kwargs = {'attr_1': 'bla'}
result = valueobjects._process_signature(xsd_type, args, kwargs)
assert result == {
'item_1': 'value-1',
'item_2': 'value-2',
'attr_1': 'bla',
}
def test_simple_args_too_many():
xsd_type = xsd.ComplexType(
xsd.Sequence([
xsd.Element('item_1', xsd.String()),
xsd.Element('item_2', xsd.String())
]))
args = tuple(['value-1', 'value-2', 'value-3'])
kwargs = {}
try:
valueobjects._process_signature(xsd_type, args, kwargs)
except TypeError as exc:
assert six.text_type(exc) == (
'__init__() takes at most 2 positional arguments (3 given)')
else:
assert False, "TypeError not raised"
def test_simple_args_too_few():
xsd_type = xsd.ComplexType(
xsd.Sequence([
xsd.Element('item_1', xsd.String()),
xsd.Element('item_2', xsd.String())
]))
args = tuple(['value-1'])
kwargs = {}
valueobjects._process_signature(xsd_type, args, kwargs)
def test_simple_kwargs():
xsd_type = xsd.ComplexType(
xsd.Sequence([
xsd.Element('item_1', xsd.String()),
xsd.Element('item_2', xsd.String())
]))
args = tuple([])
kwargs = {'item_1': 'value-1', 'item_2': 'value-2'}
result = valueobjects._process_signature(xsd_type, args, kwargs)
assert result == {
'item_1': 'value-1',
'item_2': 'value-2',
}
def test_simple_mixed():
xsd_type = xsd.ComplexType(
xsd.Sequence([
xsd.Element('item_1', xsd.String()),
xsd.Element('item_2', xsd.String())
]))
args = tuple(['value-1'])
kwargs = {'item_2': 'value-2'}
result = valueobjects._process_signature(xsd_type, args, kwargs)
assert result == {
'item_1': 'value-1',
'item_2': 'value-2',
}
def test_choice():
xsd_type = xsd.ComplexType(
xsd.Sequence([
xsd.Choice([
xsd.Element('item_1', xsd.String()),
xsd.Element('item_2', xsd.String())
])
])
)
args = tuple([])
kwargs = {'item_2': 'value-2'}
result = valueobjects._process_signature(xsd_type, args, kwargs)
assert result == {'item_1': None, 'item_2': 'value-2'}
def test_choice_max_occurs_simple_interface():
fields = xsd.ComplexType(
xsd.Sequence([
xsd.Choice([
xsd.Element('item_1', xsd.String()),
xsd.Element('item_2', xsd.String())
], max_occurs=2)
])
)
args = tuple([])
kwargs = {
'_value_1': [{'item_1': 'foo'}, {'item_2': 'bar'}]
}
result = valueobjects._process_signature(fields, args, kwargs)
assert result == {
'_value_1': [
{'item_1': 'foo'},
{'item_2': 'bar'},
]
}
def test_choice_max_occurs():
fields = xsd.ComplexType(
xsd.Sequence([
xsd.Choice([
xsd.Element('item_1', xsd.String()),
xsd.Element('item_2', xsd.String())
], max_occurs=3)
])
)
args = tuple([])
kwargs = {
'_value_1': [
{'item_1': 'foo'}, {'item_2': 'bar'}, {'item_1': 'bla'}
]
}
result = valueobjects._process_signature(fields, args, kwargs)
assert result == {
'_value_1': [
{'item_1': 'foo'},
{'item_2': 'bar'},
{'item_1': 'bla'},
]
}
def test_choice_max_occurs_on_choice():
xsd_type = xsd.ComplexType(
xsd.Sequence([
xsd.Choice([
xsd.Element('item_1', xsd.String(), max_occurs=2),
xsd.Element('item_2', xsd.String())
], max_occurs=2)
])
)
args = tuple([])
kwargs = {
'_value_1': [
{'item_1': ['foo', 'bar']},
{'item_2': 'bla'},
]
}
result = valueobjects._process_signature(xsd_type, args, kwargs)
assert result == {
'_value_1': [
{'item_1': ['foo', 'bar']},
{'item_2': 'bla'}
]
}
def test_choice_mixed():
xsd_type = xsd.ComplexType(
xsd.Sequence([
xsd.Choice([
xsd.Element('item_1', xsd.String()),
xsd.Element('item_2', xsd.String()),
]),
xsd.Element('item_2', xsd.String())
])
)
expected = '({item_1: xsd:string} | {item_2: xsd:string}), item_2__1: xsd:string'
assert xsd_type.signature() == expected
args = tuple([])
kwargs = {'item_1': 'value-1', 'item_2__1': 'value-2'}
result = valueobjects._process_signature(xsd_type, args, kwargs)
assert result == {
'item_1': 'value-1',
'item_2': None,
'item_2__1': 'value-2',
}
def test_choice_sequences_simple():
xsd_type = xsd.ComplexType(
xsd.Sequence([
xsd.Choice([
xsd.Sequence([
xsd.Element('item_1', xsd.String()),
xsd.Element('item_2', xsd.String())
]),
xsd.Sequence([
xsd.Element('item_3', xsd.String()),
xsd.Element('item_4', xsd.String())
]),
])
])
)
args = tuple([])
kwargs = {'item_1': 'value-1', 'item_2': 'value-2'}
result = valueobjects._process_signature(xsd_type, args, kwargs)
assert result == {
'item_1': 'value-1',
'item_2': 'value-2',
'item_3': None,
'item_4': None,
}
def test_choice_sequences_no_match():
xsd_type = xsd.ComplexType(
xsd.Sequence([
xsd.Choice([
xsd.Sequence([
xsd.Element('item_1', xsd.String()),
xsd.Element('item_2', xsd.String())
]),
xsd.Sequence([
xsd.Element('item_3', xsd.String()),
xsd.Element('item_4', xsd.String())
]),
])
])
)
args = tuple([])
with pytest.raises(TypeError):
kwargs = {'item_1': 'value-1', 'item_3': 'value-3'}
valueobjects._process_signature(xsd_type, args, kwargs)
def test_choice_sequences_no_match_last():
xsd_type = xsd.ComplexType(
xsd.Sequence([
xsd.Choice([
xsd.Sequence([
xsd.Element('item_1', xsd.String()),
xsd.Element('item_2', xsd.String())
]),
xsd.Sequence([
xsd.Element('item_3', xsd.String()),
xsd.Element('item_4', xsd.String())
]),
])
])
)
args = tuple([])
with pytest.raises(TypeError):
kwargs = {'item_2': 'value-2', 'item_4': 'value-4'}
valueobjects._process_signature(xsd_type, args, kwargs)
def test_choice_sequences_no_match_nested():
xsd_type = xsd.ComplexType(
xsd.Sequence([
xsd.Choice([
xsd.Sequence([
xsd.Element('item_1', xsd.String()),
xsd.Element('item_2', xsd.String())
]),
])
])
)
args = tuple([])
kwargs = {'item_1': 'value-1'}
value = valueobjects._process_signature(xsd_type, args, kwargs)
assert value == {
'item_1': 'value-1',
'item_2': None,
}
def test_choice_sequences_optional_elms():
xsd_type = xsd.ComplexType(
xsd.Sequence([
xsd.Choice([
xsd.Sequence([
xsd.Element('item_1', xsd.String()),
xsd.Element('item_2', xsd.String(), min_occurs=0)
]),
xsd.Sequence([
xsd.Element('item_1', xsd.String()),
xsd.Element('item_2', xsd.String()),
xsd.Element('item_3', xsd.String())
]),
])
])
)
args = tuple([])
kwargs = {'item_1': 'value-1'}
result = valueobjects._process_signature(xsd_type, args, kwargs)
assert result == {
'item_1': 'value-1',
'item_2': None,
'item_3': None,
}
def test_choice_sequences_max_occur():
xsd_type = xsd.ComplexType(
xsd.Sequence([
xsd.Choice([
xsd.Sequence([
xsd.Element('item_1', xsd.String()),
xsd.Element('item_2', xsd.String())
]),
xsd.Sequence([
xsd.Element('item_2', xsd.String()),
xsd.Element('item_3', xsd.String()),
]),
], max_occurs=2)
]),
)
args = tuple([])
kwargs = {
'_value_1': [
{'item_1': 'value-1', 'item_2': 'value-2'},
{'item_2': 'value-2', 'item_3': 'value-3'},
]
}
result = valueobjects._process_signature(xsd_type, args, kwargs)
assert result == {
'_value_1': [
{'item_1': 'value-1', 'item_2': 'value-2'},
{'item_2': 'value-2', 'item_3': 'value-3'},
]
}
def test_choice_sequences_init_dict():
xsd_type = xsd.ComplexType(
xsd.Sequence([
xsd.Choice([
xsd.Sequence([
xsd.Element('item_1', xsd.String()),
xsd.Element('item_2', xsd.String())
]),
xsd.Sequence([
xsd.Element('item_2', xsd.String()),
xsd.Element('item_3', xsd.String()),
]),
], max_occurs=2)
]),
)
args = tuple([])
kwargs = {
'_value_1': {'item_1': 'value-1', 'item_2': 'value-2'},
}
result = valueobjects._process_signature(xsd_type, args, kwargs)
assert result == {
'_value_1': [
{'item_1': 'value-1', 'item_2': 'value-2'}
]
}

View File

@ -0,0 +1,535 @@
<?xml version='1.0' encoding='UTF-8' ?>
<!-- Schema for the SOAP/1.1 encoding
Portions © 2001 DevelopMentor.
© 2001 W3C (Massachusetts Institute of Technology, Institut National de Recherche en Informatique et en Automatique, Keio University). All Rights Reserved.
This document is governed by the W3C Software License [1] as described in the FAQ [2].
[1] http://www.w3.org/Consortium/Legal/copyright-software-19980720
[2] http://www.w3.org/Consortium/Legal/IPR-FAQ-20000620.html#DTD
By obtaining, using and/or copying this work, you (the licensee) agree that you have read, understood, and will comply with the following terms and conditions:
Permission to use, copy, modify, and distribute this software and its documentation, with or without modification, for any purpose and without fee or royalty is hereby granted, provided that you include the following on ALL copies of the software and documentation or portions thereof, including modifications, that you make:
1. The full text of this NOTICE in a location viewable to users of the redistributed or derivative work.
2. Any pre-existing intellectual property disclaimers, notices, or terms and conditions. If none exist, a short notice of the following form (hypertext is preferred, text is permitted) should be used within the body of any redistributed or derivative code: "Copyright © 2001 World Wide Web Consortium, (Massachusetts Institute of Technology, Institut National de Recherche en Informatique et en Automatique, Keio University). All Rights Reserved. http://www.w3.org/Consortium/Legal/"
3. Notice of any changes or modifications to the W3C files, including the date changes were made. (We recommend you provide URIs to the location from which the code is derived.)
Original W3C files; http://www.w3.org/2001/06/soap-encoding
Changes made:
- reverted namespace to http://schemas.xmlsoap.org/soap/encoding/
- reverted root to only allow 0 and 1 as lexical values
- removed default value from root attribute declaration
THIS SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.
COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR DOCUMENTATION.
The name and trademarks of copyright holders may NOT be used in advertising or publicity pertaining to the software without specific, written prior permission. Title to copyright in this software and any associated documentation will at all times remain with copyright holders.
-->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://schemas.xmlsoap.org/soap/encoding/"
targetNamespace="http://schemas.xmlsoap.org/soap/encoding/" >
<xs:attribute name="root" >
<xs:annotation>
<xs:documentation>
'root' can be used to distinguish serialization roots from other
elements that are present in a serialization but are not roots of
a serialized value graph
</xs:documentation>
</xs:annotation>
<xs:simpleType>
<xs:restriction base='xs:boolean'>
<xs:pattern value='0|1' />
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<xs:attributeGroup name="commonAttributes" >
<xs:annotation>
<xs:documentation>
Attributes common to all elements that function as accessors or
represent independent (multi-ref) values. The href attribute is
intended to be used in a manner like CONREF. That is, the element
content should be empty iff the href attribute appears
</xs:documentation>
</xs:annotation>
<xs:attribute name="id" type="xs:ID" />
<xs:attribute name="href" type="xs:anyURI" />
<xs:anyAttribute namespace="##other" processContents="lax" />
</xs:attributeGroup>
<!-- Global Attributes. The following attributes are intended to be usable via qualified attribute names on any complex type referencing them. -->
<!-- Array attributes. Needed to give the type and dimensions of an array's contents, and the offset for partially-transmitted arrays. -->
<xs:simpleType name="arrayCoordinate" >
<xs:restriction base="xs:string" />
</xs:simpleType>
<xs:attribute name="arrayType" type="xs:string" />
<xs:attribute name="offset" type="tns:arrayCoordinate" />
<xs:attributeGroup name="arrayAttributes" >
<xs:attribute ref="tns:arrayType" />
<xs:attribute ref="tns:offset" />
</xs:attributeGroup>
<xs:attribute name="position" type="tns:arrayCoordinate" />
<xs:attributeGroup name="arrayMemberAttributes" >
<xs:attribute ref="tns:position" />
</xs:attributeGroup>
<xs:group name="Array" >
<xs:sequence>
<xs:any namespace="##any" minOccurs="0" maxOccurs="unbounded" processContents="lax" />
</xs:sequence>
</xs:group>
<xs:element name="Array" type="tns:Array" />
<xs:complexType name="Array" >
<xs:annotation>
<xs:documentation>
'Array' is a complex type for accessors identified by position
</xs:documentation>
</xs:annotation>
<xs:group ref="tns:Array" minOccurs="0" />
<xs:attributeGroup ref="tns:arrayAttributes" />
<xs:attributeGroup ref="tns:commonAttributes" />
</xs:complexType>
<!-- 'Struct' is a complex type for accessors identified by name.
Constraint: No element may be have the same name as any other,
nor may any element have a maxOccurs > 1. -->
<xs:element name="Struct" type="tns:Struct" />
<xs:group name="Struct" >
<xs:sequence>
<xs:any namespace="##any" minOccurs="0" maxOccurs="unbounded" processContents="lax" />
</xs:sequence>
</xs:group>
<xs:complexType name="Struct" >
<xs:group ref="tns:Struct" minOccurs="0" />
<xs:attributeGroup ref="tns:commonAttributes"/>
</xs:complexType>
<!-- 'Base64' can be used to serialize binary data using base64 encoding
as defined in RFC2045 but without the MIME line length limitation. -->
<xs:simpleType name="base64" >
<xs:restriction base="xs:base64Binary" />
</xs:simpleType>
<!-- Element declarations corresponding to each of the simple types in the
XML Schemas Specification. -->
<xs:element name="duration" type="tns:duration" />
<xs:complexType name="duration" >
<xs:simpleContent>
<xs:extension base="xs:duration" >
<xs:attributeGroup ref="tns:commonAttributes" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:element name="dateTime" type="tns:dateTime" />
<xs:complexType name="dateTime" >
<xs:simpleContent>
<xs:extension base="xs:dateTime" >
<xs:attributeGroup ref="tns:commonAttributes" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:element name="NOTATION" type="tns:NOTATION" />
<xs:complexType name="NOTATION" >
<xs:simpleContent>
<xs:extension base="xs:QName" >
<xs:attributeGroup ref="tns:commonAttributes" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:element name="time" type="tns:time" />
<xs:complexType name="time" >
<xs:simpleContent>
<xs:extension base="xs:time" >
<xs:attributeGroup ref="tns:commonAttributes" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:element name="date" type="tns:date" />
<xs:complexType name="date" >
<xs:simpleContent>
<xs:extension base="xs:date" >
<xs:attributeGroup ref="tns:commonAttributes" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:element name="gYearMonth" type="tns:gYearMonth" />
<xs:complexType name="gYearMonth" >
<xs:simpleContent>
<xs:extension base="xs:gYearMonth" >
<xs:attributeGroup ref="tns:commonAttributes" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:element name="gYear" type="tns:gYear" />
<xs:complexType name="gYear" >
<xs:simpleContent>
<xs:extension base="xs:gYear" >
<xs:attributeGroup ref="tns:commonAttributes" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:element name="gMonthDay" type="tns:gMonthDay" />
<xs:complexType name="gMonthDay" >
<xs:simpleContent>
<xs:extension base="xs:gMonthDay" >
<xs:attributeGroup ref="tns:commonAttributes" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:element name="gDay" type="tns:gDay" />
<xs:complexType name="gDay" >
<xs:simpleContent>
<xs:extension base="xs:gDay" >
<xs:attributeGroup ref="tns:commonAttributes" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:element name="gMonth" type="tns:gMonth" />
<xs:complexType name="gMonth" >
<xs:simpleContent>
<xs:extension base="xs:gMonth" >
<xs:attributeGroup ref="tns:commonAttributes" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:element name="boolean" type="tns:boolean" />
<xs:complexType name="boolean" >
<xs:simpleContent>
<xs:extension base="xs:boolean" >
<xs:attributeGroup ref="tns:commonAttributes" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:element name="base64Binary" type="tns:base64Binary" />
<xs:complexType name="base64Binary" >
<xs:simpleContent>
<xs:extension base="xs:base64Binary" >
<xs:attributeGroup ref="tns:commonAttributes" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:element name="hexBinary" type="tns:hexBinary" />
<xs:complexType name="hexBinary" >
<xs:simpleContent>
<xs:extension base="xs:hexBinary" >
<xs:attributeGroup ref="tns:commonAttributes" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:element name="float" type="tns:float" />
<xs:complexType name="float" >
<xs:simpleContent>
<xs:extension base="xs:float" >
<xs:attributeGroup ref="tns:commonAttributes" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:element name="double" type="tns:double" />
<xs:complexType name="double" >
<xs:simpleContent>
<xs:extension base="xs:double" >
<xs:attributeGroup ref="tns:commonAttributes" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:element name="anyURI" type="tns:anyURI" />
<xs:complexType name="anyURI" >
<xs:simpleContent>
<xs:extension base="xs:anyURI" >
<xs:attributeGroup ref="tns:commonAttributes" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:element name="QName" type="tns:QName" />
<xs:complexType name="QName" >
<xs:simpleContent>
<xs:extension base="xs:QName" >
<xs:attributeGroup ref="tns:commonAttributes" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:element name="string" type="tns:string" />
<xs:complexType name="string" >
<xs:simpleContent>
<xs:extension base="xs:string" >
<xs:attributeGroup ref="tns:commonAttributes" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:element name="normalizedString" type="tns:normalizedString" />
<xs:complexType name="normalizedString" >
<xs:simpleContent>
<xs:extension base="xs:normalizedString" >
<xs:attributeGroup ref="tns:commonAttributes" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:element name="token" type="tns:token" />
<xs:complexType name="token" >
<xs:simpleContent>
<xs:extension base="xs:token" >
<xs:attributeGroup ref="tns:commonAttributes" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:element name="language" type="tns:language" />
<xs:complexType name="language" >
<xs:simpleContent>
<xs:extension base="xs:language" >
<xs:attributeGroup ref="tns:commonAttributes" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:element name="Name" type="tns:Name" />
<xs:complexType name="Name" >
<xs:simpleContent>
<xs:extension base="xs:Name" >
<xs:attributeGroup ref="tns:commonAttributes" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:element name="NMTOKEN" type="tns:NMTOKEN" />
<xs:complexType name="NMTOKEN" >
<xs:simpleContent>
<xs:extension base="xs:NMTOKEN" >
<xs:attributeGroup ref="tns:commonAttributes" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:element name="NCName" type="tns:NCName" />
<xs:complexType name="NCName" >
<xs:simpleContent>
<xs:extension base="xs:NCName" >
<xs:attributeGroup ref="tns:commonAttributes" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:element name="NMTOKENS" type="tns:NMTOKENS" />
<xs:complexType name="NMTOKENS" >
<xs:simpleContent>
<xs:extension base="xs:NMTOKENS" >
<xs:attributeGroup ref="tns:commonAttributes" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:element name="ID" type="tns:ID" />
<xs:complexType name="ID" >
<xs:simpleContent>
<xs:extension base="xs:ID" >
<xs:attributeGroup ref="tns:commonAttributes" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:element name="IDREF" type="tns:IDREF" />
<xs:complexType name="IDREF" >
<xs:simpleContent>
<xs:extension base="xs:IDREF" >
<xs:attributeGroup ref="tns:commonAttributes" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:element name="ENTITY" type="tns:ENTITY" />
<xs:complexType name="ENTITY" >
<xs:simpleContent>
<xs:extension base="xs:ENTITY" >
<xs:attributeGroup ref="tns:commonAttributes" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:element name="IDREFS" type="tns:IDREFS" />
<xs:complexType name="IDREFS" >
<xs:simpleContent>
<xs:extension base="xs:IDREFS" >
<xs:attributeGroup ref="tns:commonAttributes" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:element name="ENTITIES" type="tns:ENTITIES" />
<xs:complexType name="ENTITIES" >
<xs:simpleContent>
<xs:extension base="xs:ENTITIES" >
<xs:attributeGroup ref="tns:commonAttributes" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:element name="decimal" type="tns:decimal" />
<xs:complexType name="decimal" >
<xs:simpleContent>
<xs:extension base="xs:decimal" >
<xs:attributeGroup ref="tns:commonAttributes" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:element name="integer" type="tns:integer" />
<xs:complexType name="integer" >
<xs:simpleContent>
<xs:extension base="xs:integer" >
<xs:attributeGroup ref="tns:commonAttributes" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:element name="nonPositiveInteger" type="tns:nonPositiveInteger" />
<xs:complexType name="nonPositiveInteger" >
<xs:simpleContent>
<xs:extension base="xs:nonPositiveInteger" >
<xs:attributeGroup ref="tns:commonAttributes" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:element name="negativeInteger" type="tns:negativeInteger" />
<xs:complexType name="negativeInteger" >
<xs:simpleContent>
<xs:extension base="xs:negativeInteger" >
<xs:attributeGroup ref="tns:commonAttributes" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:element name="long" type="tns:long" />
<xs:complexType name="long" >
<xs:simpleContent>
<xs:extension base="xs:long" >
<xs:attributeGroup ref="tns:commonAttributes" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:element name="int" type="tns:int" />
<xs:complexType name="int" >
<xs:simpleContent>
<xs:extension base="xs:int" >
<xs:attributeGroup ref="tns:commonAttributes" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:element name="short" type="tns:short" />
<xs:complexType name="short" >
<xs:simpleContent>
<xs:extension base="xs:short" >
<xs:attributeGroup ref="tns:commonAttributes" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:element name="byte" type="tns:byte" />
<xs:complexType name="byte" >
<xs:simpleContent>
<xs:extension base="xs:byte" >
<xs:attributeGroup ref="tns:commonAttributes" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:element name="nonNegativeInteger" type="tns:nonNegativeInteger" />
<xs:complexType name="nonNegativeInteger" >
<xs:simpleContent>
<xs:extension base="xs:nonNegativeInteger" >
<xs:attributeGroup ref="tns:commonAttributes" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:element name="unsignedLong" type="tns:unsignedLong" />
<xs:complexType name="unsignedLong" >
<xs:simpleContent>
<xs:extension base="xs:unsignedLong" >
<xs:attributeGroup ref="tns:commonAttributes" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:element name="unsignedInt" type="tns:unsignedInt" />
<xs:complexType name="unsignedInt" >
<xs:simpleContent>
<xs:extension base="xs:unsignedInt" >
<xs:attributeGroup ref="tns:commonAttributes" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:element name="unsignedShort" type="tns:unsignedShort" />
<xs:complexType name="unsignedShort" >
<xs:simpleContent>
<xs:extension base="xs:unsignedShort" >
<xs:attributeGroup ref="tns:commonAttributes" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:element name="unsignedByte" type="tns:unsignedByte" />
<xs:complexType name="unsignedByte" >
<xs:simpleContent>
<xs:extension base="xs:unsignedByte" >
<xs:attributeGroup ref="tns:commonAttributes" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:element name="positiveInteger" type="tns:positiveInteger" />
<xs:complexType name="positiveInteger" >
<xs:simpleContent>
<xs:extension base="xs:positiveInteger" >
<xs:attributeGroup ref="tns:commonAttributes" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:element name="anyType" />
</xs:schema>

View File

@ -0,0 +1,42 @@
<?xml version="1.0"?>
<definitions
xmlns:tns="http://example.com/stockquote.wsdl"
xmlns:xsd1="http://example.com/stockquote.xsd"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns="http://schemas.xmlsoap.org/wsdl/"
name="StockQuote"
targetNamespace="http://example.com/stockquote.wsdl">
<types>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://test.python-zeep.org/imports"
xmlns:tns="http://test.python-zeep.org/imports">
<import schemaLocation="test_import_2.xsd" namespace="http://example.com/stockquote.xsd"/>
</schema>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://test.python-zeep.org/something"
xmlns:tns="http://test.python-zeep.org/something">
<import namespace="http://schemas.xmlsoap.org/soap/encoding/"
schemaLocation="http://schemas.xmlsoap.org/soap/encoding/"/>
</schema>
</types>
<message name="GetLastTradePriceInput">
<part name="body" element="xsd1:TradePriceRequest"/>
</message>
<message name="GetLastTradePriceOutput">
<part name="body" element="xsd1:TradePrice"/>
</message>
<message name="FaultMessageMsg1">
<part name="fault1" element="xsd1:Fault1"/>
</message>
<message name="FaultMessageMsg2">
<part name="fault2" element="xsd1:Fault2"/>
</message>
<portType name="StockQuotePortType">
<operation name="GetLastTradePrice">
<input message="tns:GetLastTradePriceInput"/>
<output message="tns:GetLastTradePriceOutput"/>
<fault message="tns:FaultMessageMsg1" name="fault1"/>
<fault message="tns:FaultMessageMsg2" name="fault2"/>
</operation>
</portType>
</definitions>

View File

@ -0,0 +1,38 @@
<?xml version="1.0"?>
<definitions
xmlns:tns="http://example.com/stockquote.wsdl"
xmlns:xsd1="http://example.com/stockquote.xsd"
xmlns:sub="http://test.python-zeep.org/sub"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns="http://schemas.xmlsoap.org/wsdl/"
name="StockQuote"
targetNamespace="http://example.com/stockquote.wsdl">
<import namespace="http://test.python-zeep.org/sub" location="soap_import_2.wsdl"/>
<types/>
<binding name="StockQuoteBinding" type="tns:StockQuotePortType">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="GetLastTradePrice">
<soap:operation soapAction="http://example.com/GetLastTradePrice"/>
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
<fault name="fault1">
<soap:fault name="fault1" use="literal"/>
</fault>
<fault name="fault2">
<soap:fault name="fault2" use="literal"/>
</fault>
</operation>
</binding>
<service name="StockQuoteService">
<documentation>My first service</documentation>
<port name="StockQuotePort" binding="tns:StockQuoteBinding">
<soap:address location="http://example.com/stockquote"/>
</port>
</service>
</definitions>

View File

@ -0,0 +1,138 @@
<?xml version="1.0"?>
<definitions
xmlns:tns="http://example.com/stockquote.wsdl"
xmlns:xsd1="http://example.com/stockquote.xsd"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns="http://schemas.xmlsoap.org/wsdl/"
name="StockQuote"
targetNamespace="http://example.com/stockquote.wsdl">
<types>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://example.com/stockquote.xsd"
xmlns:tns="http://example.com/stockquote.xsd" >
<complexType name="Address">
<sequence>
<element minOccurs="0" maxOccurs="1" name="NameFirst" type="string"/>
<element minOccurs="0" maxOccurs="1" name="NameLast" type="string"/>
<element minOccurs="0" maxOccurs="1" name="Email" type="string"/>
</sequence>
</complexType>
<element name="Fault1">
<complexType>
<sequence>
<element name="message" type="string"/>
</sequence>
</complexType>
</element>
<element name="Fault2">
<complexType>
<sequence>
<element name="message" type="string"/>
</sequence>
</complexType>
</element>
<element name="TradePriceRequest">
<complexType>
<all>
<element name="tickerSymbol" type="string"/>
<element name="account" type="tns:account" minOccurs="0" />
<element ref="tns:country"/>
</all>
</complexType>
</element>
<element name="TradePrice">
<complexType>
<all>
<element name="price" type="float"/>
</all>
</complexType>
</element>
<complexType name="account">
<sequence>
<element name="id" type="int"/>
<element name="user" type="string"/>
</sequence>
</complexType>
<complexType name="country">
<sequence>
<element name="code" type="string"/>
</sequence>
</complexType>
<element name="country">
<complexType>
<sequence>
<element name="name" type="string"/>
<element name="code" type="string"/>
</sequence>
</complexType>
</element>
</schema>
</types>
<message name="GetLastTradePriceInput">
<part name="body" element="xsd1:TradePriceRequest"/>
</message>
<message name="GetLastTradePriceOutput">
<part name="body" element="xsd1:TradePrice"/>
</message>
<message name="FaultMessageMsg1">
<part name="fault1" element="xsd1:Fault1"/>
</message>
<message name="FaultMessageMsg2">
<part name="fault2" element="xsd1:Fault2"/>
</message>
<portType name="StockQuotePortType">
<operation name="GetLastTradePrice">
<input message="tns:GetLastTradePriceInput"/>
<output message="tns:GetLastTradePriceOutput"/>
<fault message="tns:FaultMessageMsg1" name="fault1"/>
<fault message="tns:FaultMessageMsg2" name="fault2"/>
</operation>
</portType>
<binding name="StockQuoteBinding" type="tns:StockQuotePortType">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="GetLastTradePrice">
<soap:operation soapAction="http://example.com/GetLastTradePrice"/>
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
<fault name="fault1">
<soap:fault name="fault1" use="literal"/>
</fault>
<fault name="fault2">
<soap:fault name="fault2" use="literal"/>
</fault>
</operation>
</binding>
<binding name="StockQuoteBinding" type="tns:StockQuotePortType">
<soap:binding style="document" transport="http://schemas.microsoft.com/soap/tcp"/>
<operation name="GetLastTradePrice">
<soap:operation soapAction="http://example.com/GetLastTradePrice"/>
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
<fault name="fault1">
<soap:fault name="fault1" use="literal"/>
</fault>
<fault name="fault2">
<soap:fault name="fault2" use="literal"/>
</fault>
</operation>
</binding>
<service name="StockQuoteService">
<documentation>My first service</documentation>
<port name="StockQuotePort" binding="tns:StockQuoteBinding">
<soap:address location="http://example.com/stockquote"/>
</port>
</service>
</definitions>

View File

@ -0,0 +1,60 @@
<schema xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://example.com/stockquote.xsd"
xmlns:tns="http://example.com/stockquote.xsd" >
<complexType name="Address">
<sequence>
<element minOccurs="0" maxOccurs="1" name="NameFirst" type="string"/>
<element minOccurs="0" maxOccurs="1" name="NameLast" type="string"/>
<element minOccurs="0" maxOccurs="1" name="Email" type="string"/>
</sequence>
</complexType>
<element name="Fault1">
<complexType>
<sequence>
<element name="message" type="string"/>
</sequence>
</complexType>
</element>
<element name="Fault2">
<complexType>
<sequence>
<element name="message" type="string"/>
</sequence>
</complexType>
</element>
<element name="TradePriceRequest">
<complexType>
<all>
<element name="tickerSymbol" type="string"/>
<element name="account" type="tns:account" minOccurs="0" />
<element ref="tns:country"/>
</all>
</complexType>
</element>
<element name="TradePrice">
<complexType>
<all>
<element name="price" type="float"/>
</all>
</complexType>
</element>
<complexType name="account">
<sequence>
<element name="id" type="int"/>
<element name="user" type="string"/>
</sequence>
</complexType>
<complexType name="country">
<sequence>
<element name="code" type="string"/>
</sequence>
</complexType>
<element name="country">
<complexType>
<sequence>
<element name="name" type="string"/>
<element name="code" type="string"/>
</sequence>
</complexType>
</element>
</schema>

View File

@ -0,0 +1,309 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Schema for XML Signatures
http://www.w3.org/2000/09/xmldsig#
$Revision: 1.1 $ on $Date: 2002/02/08 20:32:26 $ by $Author: reagle $
Copyright 2001 The Internet Society and W3C (Massachusetts Institute
of Technology, Institut National de Recherche en Informatique et en
Automatique, Keio University). All Rights Reserved.
http://www.w3.org/Consortium/Legal/
This document is governed by the W3C Software License [1] as described
in the FAQ [2].
[1] http://www.w3.org/Consortium/Legal/copyright-software-19980720
[2] http://www.w3.org/Consortium/Legal/IPR-FAQ-20000620.html#DTD
-->
<schema xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
targetNamespace="http://www.w3.org/2000/09/xmldsig#"
version="0.1" elementFormDefault="qualified">
<!-- Basic Types Defined for Signatures -->
<simpleType name="CryptoBinary">
<restriction base="base64Binary">
</restriction>
</simpleType>
<!-- Start Signature -->
<element name="Signature" type="ds:SignatureType"/>
<complexType name="SignatureType">
<sequence>
<element ref="ds:SignedInfo"/>
<element ref="ds:SignatureValue"/>
<element ref="ds:KeyInfo" minOccurs="0"/>
<element ref="ds:Object" minOccurs="0" maxOccurs="unbounded"/>
</sequence>
<attribute name="Id" type="ID" use="optional"/>
</complexType>
<element name="SignatureValue" type="ds:SignatureValueType"/>
<complexType name="SignatureValueType">
<simpleContent>
<extension base="base64Binary">
<attribute name="Id" type="ID" use="optional"/>
</extension>
</simpleContent>
</complexType>
<!-- Start SignedInfo -->
<element name="SignedInfo" type="ds:SignedInfoType"/>
<complexType name="SignedInfoType">
<sequence>
<element ref="ds:CanonicalizationMethod"/>
<element ref="ds:SignatureMethod"/>
<element ref="ds:Reference" maxOccurs="unbounded"/>
</sequence>
<attribute name="Id" type="ID" use="optional"/>
</complexType>
<element name="CanonicalizationMethod" type="ds:CanonicalizationMethodType"/>
<complexType name="CanonicalizationMethodType" mixed="true">
<sequence>
<any namespace="##any" minOccurs="0" maxOccurs="unbounded"/>
<!-- (0,unbounded) elements from (1,1) namespace -->
</sequence>
<attribute name="Algorithm" type="anyURI" use="required"/>
</complexType>
<element name="SignatureMethod" type="ds:SignatureMethodType"/>
<complexType name="SignatureMethodType" mixed="true">
<sequence>
<element name="HMACOutputLength" minOccurs="0" type="ds:HMACOutputLengthType"/>
<any namespace="##other" minOccurs="0" maxOccurs="unbounded"/>
<!-- (0,unbounded) elements from (1,1) external namespace -->
</sequence>
<attribute name="Algorithm" type="anyURI" use="required"/>
</complexType>
<!-- Start Reference -->
<element name="Reference" type="ds:ReferenceType"/>
<complexType name="ReferenceType">
<sequence>
<element ref="ds:Transforms" minOccurs="0"/>
<element ref="ds:DigestMethod"/>
<element ref="ds:DigestValue"/>
</sequence>
<attribute name="Id" type="ID" use="optional"/>
<attribute name="URI" type="anyURI" use="optional"/>
<attribute name="Type" type="anyURI" use="optional"/>
</complexType>
<element name="Transforms" type="ds:TransformsType"/>
<complexType name="TransformsType">
<sequence>
<element ref="ds:Transform" maxOccurs="unbounded"/>
</sequence>
</complexType>
<element name="Transform" type="ds:TransformType"/>
<complexType name="TransformType" mixed="true">
<choice minOccurs="0" maxOccurs="unbounded">
<any namespace="##other" processContents="lax"/>
<!-- (1,1) elements from (0,unbounded) namespaces -->
<element name="XPath" type="string"/>
</choice>
<attribute name="Algorithm" type="anyURI" use="required"/>
</complexType>
<!-- End Reference -->
<element name="DigestMethod" type="ds:DigestMethodType"/>
<complexType name="DigestMethodType" mixed="true">
<sequence>
<any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
</sequence>
<attribute name="Algorithm" type="anyURI" use="required"/>
</complexType>
<element name="DigestValue" type="ds:DigestValueType"/>
<simpleType name="DigestValueType">
<restriction base="base64Binary"/>
</simpleType>
<!-- End SignedInfo -->
<!-- Start KeyInfo -->
<element name="KeyInfo" type="ds:KeyInfoType"/>
<complexType name="KeyInfoType" mixed="true">
<choice maxOccurs="unbounded">
<element ref="ds:KeyName"/>
<element ref="ds:KeyValue"/>
<element ref="ds:RetrievalMethod"/>
<element ref="ds:X509Data"/>
<element ref="ds:PGPData"/>
<element ref="ds:SPKIData"/>
<element ref="ds:MgmtData"/>
<any processContents="lax" namespace="##other"/>
<!-- (1,1) elements from (0,unbounded) namespaces -->
</choice>
<attribute name="Id" type="ID" use="optional"/>
</complexType>
<element name="KeyName" type="string"/>
<element name="MgmtData" type="string"/>
<element name="KeyValue" type="ds:KeyValueType"/>
<complexType name="KeyValueType" mixed="true">
<choice>
<element ref="ds:DSAKeyValue"/>
<element ref="ds:RSAKeyValue"/>
<any namespace="##other" processContents="lax"/>
</choice>
</complexType>
<element name="RetrievalMethod" type="ds:RetrievalMethodType"/>
<complexType name="RetrievalMethodType">
<sequence>
<element ref="ds:Transforms" minOccurs="0"/>
</sequence>
<attribute name="URI" type="anyURI"/>
<attribute name="Type" type="anyURI" use="optional"/>
</complexType>
<!-- Start X509Data -->
<element name="X509Data" type="ds:X509DataType"/>
<complexType name="X509DataType">
<sequence maxOccurs="unbounded">
<choice>
<element name="X509IssuerSerial" type="ds:X509IssuerSerialType"/>
<element name="X509SKI" type="base64Binary"/>
<element name="X509SubjectName" type="string"/>
<element name="X509Certificate" type="base64Binary"/>
<element name="X509CRL" type="base64Binary"/>
<any namespace="##other" processContents="lax"/>
</choice>
</sequence>
</complexType>
<complexType name="X509IssuerSerialType">
<sequence>
<element name="X509IssuerName" type="string"/>
<element name="X509SerialNumber" type="integer"/>
</sequence>
</complexType>
<!-- End X509Data -->
<!-- Begin PGPData -->
<element name="PGPData" type="ds:PGPDataType"/>
<complexType name="PGPDataType">
<choice>
<sequence>
<element name="PGPKeyID" type="base64Binary"/>
<element name="PGPKeyPacket" type="base64Binary" minOccurs="0"/>
<any namespace="##other" processContents="lax" minOccurs="0"
maxOccurs="unbounded"/>
</sequence>
<sequence>
<element name="PGPKeyPacket" type="base64Binary"/>
<any namespace="##other" processContents="lax" minOccurs="0"
maxOccurs="unbounded"/>
</sequence>
</choice>
</complexType>
<!-- End PGPData -->
<!-- Begin SPKIData -->
<element name="SPKIData" type="ds:SPKIDataType"/>
<complexType name="SPKIDataType">
<sequence maxOccurs="unbounded">
<element name="SPKISexp" type="base64Binary"/>
<any namespace="##other" processContents="lax" minOccurs="0"/>
</sequence>
</complexType>
<!-- End SPKIData -->
<!-- End KeyInfo -->
<!-- Start Object (Manifest, SignatureProperty) -->
<element name="Object" type="ds:ObjectType"/>
<complexType name="ObjectType" mixed="true">
<sequence minOccurs="0" maxOccurs="unbounded">
<any namespace="##any" processContents="lax"/>
</sequence>
<attribute name="Id" type="ID" use="optional"/>
<attribute name="MimeType" type="string" use="optional"/> <!-- add a grep facet -->
<attribute name="Encoding" type="anyURI" use="optional"/>
</complexType>
<element name="Manifest" type="ds:ManifestType"/>
<complexType name="ManifestType">
<sequence>
<element ref="ds:Reference" maxOccurs="unbounded"/>
</sequence>
<attribute name="Id" type="ID" use="optional"/>
</complexType>
<element name="SignatureProperties" type="ds:SignaturePropertiesType"/>
<complexType name="SignaturePropertiesType">
<sequence>
<element ref="ds:SignatureProperty" maxOccurs="unbounded"/>
</sequence>
<attribute name="Id" type="ID" use="optional"/>
</complexType>
<element name="SignatureProperty" type="ds:SignaturePropertyType"/>
<complexType name="SignaturePropertyType" mixed="true">
<choice maxOccurs="unbounded">
<any namespace="##other" processContents="lax"/>
<!-- (1,1) elements from (1,unbounded) namespaces -->
</choice>
<attribute name="Target" type="anyURI" use="required"/>
<attribute name="Id" type="ID" use="optional"/>
</complexType>
<!-- End Object (Manifest, SignatureProperty) -->
<!-- Start Algorithm Parameters -->
<simpleType name="HMACOutputLengthType">
<restriction base="integer"/>
</simpleType>
<!-- Start KeyValue Element-types -->
<element name="DSAKeyValue" type="ds:DSAKeyValueType"/>
<complexType name="DSAKeyValueType">
<sequence>
<sequence minOccurs="0">
<element name="P" type="ds:CryptoBinary"/>
<element name="Q" type="ds:CryptoBinary"/>
</sequence>
<element name="G" type="ds:CryptoBinary" minOccurs="0"/>
<element name="Y" type="ds:CryptoBinary"/>
<element name="J" type="ds:CryptoBinary" minOccurs="0"/>
<sequence minOccurs="0">
<element name="Seed" type="ds:CryptoBinary"/>
<element name="PgenCounter" type="ds:CryptoBinary"/>
</sequence>
</sequence>
</complexType>
<element name="RSAKeyValue" type="ds:RSAKeyValueType"/>
<complexType name="RSAKeyValueType">
<sequence>
<element name="Modulus" type="ds:CryptoBinary"/>
<element name="Exponent" type="ds:CryptoBinary"/>
</sequence>
</complexType>
<!-- End KeyValue Element-types -->
<!-- End Signature -->
</schema>

View File

@ -1,7 +0,0 @@
[tox]
envlist = py27,py33,py34,py35,pypy
[testenv]
commands =
pip install .[test]
py.test -vvv