Browse Source

v0.4.4 which finally brings nothing more than Python 3 compatibility

main
Sorin Sbarnea 9 years ago
parent
commit
f74298a5b0
17 changed files with 704 additions and 338 deletions
  1. +2
    -2
      MANIFEST.in
  2. +0
    -30
      README.mdown
  3. +73
    -0
      README.rst
  4. +45
    -0
      setup.cfg
  5. +158
    -21
      setup.py
  6. +3
    -3
      tests/config.txt
  7. +23
    -11
      tests/test_wsdl.py
  8. +1
    -1
      tox.ini
  9. +0
    -1
      wstools/.cvsignore
  10. +3
    -0
      wstools/Namespaces.py
  11. +2
    -2
      wstools/TimeoutSocket.py
  12. +74
    -62
      wstools/Utility.py
  13. +64
    -31
      wstools/WSDLTools.py
  14. +245
    -164
      wstools/XMLSchema.py
  15. +3
    -3
      wstools/XMLname.py
  16. +7
    -6
      wstools/c14n.py
  17. +1
    -1
      wstools/version.py

+ 2
- 2
MANIFEST.in View File

@@ -1,5 +1,5 @@
include README.txt
include README.rst
include CHANGES.txt
recursive-include docs *.*
recursive-include src *.txt *.py *.tar.gz README
recursive-include wstools *.py


+ 0
- 30
README.mdown View File

@@ -1,30 +0,0 @@
[![Build Status](https://travis-ci.org/kartoch/wstools.svg?branch=master)](https://travis-ci.org/kartoch/wstools)[![Coverage Status](https://img.shields.io/coveralls/kartoch/wstools.svg)](https://coveralls.io/r/kartoch/wstools?branch=master)

General
========
- Homepage: https://github.com/pycontribs/wstools
- Mailing List: https://groups.google.com/forum/#!forum/pycontribs
- Package: http://pypi.python.org/pypi/wstools/
- Docs (TBD): http://packages.python.org/wstools

Credits
========
Companies
---------
|makinacom|_

* `Planet Makina Corpus <http://www.makina-corpus.org>`_
* `Contact us <mailto:python@makina-corpus.org>`_

.. |makinacom| image:: http://depot.makina-corpus.org/public/logo.gif
.. _makinacom: http://www.makina-corpus.com

Authors
------------

- Makina Corpus <python@makina-corpus.com>

Contributors
-----------------
- Sorin Sbarnea <sorin.sbarnea+os@gmail.com>


+ 73
- 0
README.rst View File

@@ -0,0 +1,73 @@
=========================================================
WSDL parsing services package for Web Services for Python
=========================================================

. image:: https://pypip.in/py_versions/wstools/badge.svg?style=flat
:target: https://pypi.python.org/pypi/wstools/

.. image:: https://pypip.in/license/wstools/badge.svg?style=flat
:target: https://pypi.python.org/pypi/wstools/

.. image:: https://pypip.in/download/wstools/badge.svg?style=flat
:target: https://pypi.python.org/pypi/wstools/

.. image:: https://pypip.in/version/wstools/badge.svg?style=flat
:target: https://pypi.python.org/pypi/wstools/

.. image:: https://pypip.in/egg/wstools/badge.svg?style=flat
:target: https://pypi.python.org/pypi/wstools/

.. image:: https://pypip.in/wheel/wstools/badge.svg?style=flat
:target: https://pypi.python.org/pypi/wstools/

------------

.. image:: https://api.travis-ci.org/pycontribs/wstools.svg?branch=master
:target: https://travis-ci.org/pycontribs/wstools

.. image:: https://pypip.in/status/wstools/badge.svg?style=flat
:target: https://pypi.python.org/pypi/wstools/

.. image:: https://img.shields.io/coveralls/pycontribs/wstools.svg
:target: https://coveralls.io/r/pycontribs/wstools

.. image:: http://api.flattr.com/button/flattr-badge-large.png
:target: https://flattr.com/submit/auto?user_id=sbarnea&url=https://github.com/pycontribs/wstools&title=Python wstools&language=&tags=github&category=software


General
=======

- Homepage: https://github.com/pycontribs/wstools
- Mailing List: https://groups.google.com/forum/#!forum/pycontribs
- Package: http://pypi.python.org/pypi/wstools/
- Docs (TBD): http://packages.python.org/wstools

Credits
=======

Companies
---------

\|makinacom\|\_

- ``Planet Makina Corpus <http://www.makina-corpus.org>``\ \_
- ``Contact us <mailto:python@makina-corpus.org>``\ \_

.. \|makinacom\| image:: http://depot.makina-corpus.org/public/logo.gif
.. \_makinacom: http://www.makina-corpus.com

Authors
-------

- Makina Corpus python@makina-corpus.com

Contributors
------------

- Sorin Sbarnea sorin.sbarnea@gmail.com

.. |Build Status| image:: https://travis-ci.org/kartoch/wstools.svg?branch=master
:target: https://travis-ci.org/kartoch/wstools
.. |Coverage Status| image:: https://img.shields.io/coveralls/kartoch/wstools.svg
:target: https://coveralls.io/r/kartoch/wstools?branch=master

+ 45
- 0
setup.cfg View File

@@ -0,0 +1,45 @@
[metadata]
description-file = README

[bdist_wheel]
universal = 1

[build_sphinx]
source-dir = docs
build-dir = docs/build
all_files = 1

[upload_sphinx]
upload-dir = docs/build/html

[pytest]
norecursedirs = . .svn jira _build tmp* lib/third lib *.egg bin distutils build docs demo
python_files = *.py
addopts = -p no:xdist --ignore=setup.py --tb=long -rsxX -v --maxfail=10 --pep8 tests
# --maxfail=2 -n4
# -n4 runs up to 4 parallel procs
# --maxfail=2 fail fast, dude
# --durations=3 report the top 3 longest tests

# these are important for distributed testing, to speedup their execution we minimize what we sync
rsyncdirs = . jira demo docs
rsyncignore = .hg .git
pep8ignore = E501 E265 E127 E901 E128 E402

[pep8]
exclude=build,lib,.tox,third,*.egg,docs,packages
;filename=
;select
ignore=E501,E265,E402
max-line-length=1024
count=1
;format
;quiet
;show-pep8
;show-source
statistics=1
;verbose=1

;PEP8_OPTS="--filename=*.py --exclude=lib --ignore=E501 scripts"
;pep8 $PEP8_OPTS --show-source --repeat
;pep8 --statistics -qq $PEP8_OPTS

+ 158
- 21
setup.py View File

@@ -1,34 +1,171 @@
#!/usr/bin/env python
import logging
import os
from setuptools import setup
import re
import sys
import subprocess
import warnings
import codecs

from setuptools import setup, find_packages, Command
from setuptools.command.test import test as TestCommand

NAME = "wstools"
url = "https://github.com/pycontribs/wstools.git"

# Get the version - do not use normal import because it does break coverage
base_path = os.path.dirname(__file__)
fp = open(os.path.join(base_path, NAME, 'version.py'))
__version__ = re.compile(r".*__version__\s*=\s*['\"](.*?)['\"]",
re.S).match(fp.read()).group(1)
fp.close()

# this should help getting annoying warnings from inside distutils
warnings.simplefilter('ignore', UserWarning)


class PyTest(TestCommand):
user_options = [('pytest-args=', 'a', "Arguments to pass to py.test")]

def initialize_options(self):
TestCommand.initialize_options(self)
self.pytest_args = []

FORMAT = '%(levelname)-10s %(message)s'
logging.basicConfig(format=FORMAT)
logging.getLogger().setLevel(logging.INFO)

# if we have pytest-cache module we enable the test failures first mode
try:
import pytest_cache
self.pytest_args.append("--ff")
except ImportError:
pass
self.pytest_args.append("-s")

if sys.stdout.isatty():
# when run manually we enable fail fast
self.pytest_args.append("--maxfail=1")
try:
import coveralls
self.pytest_args.append("--cov=%s" % NAME)
self.pytest_args.extend(["--cov-report", "term"])
self.pytest_args.extend(["--cov-report", "xml"])

except ImportError:
pass

def read(*rnames):
return "\n" + open(
os.path.join('.', *rnames)
).read()
def finalize_options(self):
TestCommand.finalize_options(self)
self.test_args = []
self.test_suite = True

long_description = \
"WSDL parsing services package for Web Services for Python. see" + url
def run_tests(self):
# before running tests we need to run autopep8
try:
r = subprocess.check_call(
"python -m autopep8 -r --in-place wstools/ tests/",
shell=True)
except subprocess.CalledProcessError:
logging.getLogger().warn('autopep8 is not installed so '
'it will not be run')
# import here, cause outside the eggs aren't loaded
import pytest
errno = pytest.main(self.pytest_args)
sys.exit(errno)

from wstools.version import __version__

install_requires = [
'docutils'
]
class Release(Command):
user_options = []

def initialize_options(self):
# Command.initialize_options(self)
pass

def finalize_options(self):
# Command.finalize_options(self)
pass

def run(self):
import json
try:
from urllib.request import urlopen
except ImportError:
from urllib2 import urlopen
response = urlopen(
"http://pypi.python.org/pypi/%s/json" % NAME)
data = json.load(codecs.getreader("utf-8")(response))
released_version = data['info']['version']
if released_version == __version__:
raise RuntimeError(
"This version was already released, remove it from PyPi if you want to release it again or increase the version number. http://pypi.python.org/pypi/%s/" % NAME)
elif released_version > __version__:
raise RuntimeError("Cannot release a version (%s) smaller than the PyPI current release (%s)." % (
__version__, released_version))


class PreRelease(Command):
user_options = []

def initialize_options(self):
# Command.initialize_options(self)
pass

def finalize_options(self):
# Command.finalize_options(self)
pass

def run(self):
import json
try:
from urllib.request import urlopen
except ImportError:
from urllib2 import urlopen
response = urlopen(
"http://pypi.python.org/pypi/%s/json" % NAME)
data = json.load(codecs.getreader("utf-8")(response))
released_version = data['info']['version']
if released_version >= __version__:
raise RuntimeError(
"Current version of the package is equal or lower than the already published ones (PyPi). Increse version to be able to pass prerelease stage.")


setup(
name="wstools",
name=NAME,
version=__version__,
description="wstools",
maintainer="Gregory Warnes, kiorky, sorin",
maintainer_email="Gregory.R.Warnes@Pfizer.com, "
+ " kiorky@cryptelium.net, " + "sorin.sbarnea+os@gmail.com",
url=url,
long_description=long_description,
packages=['wstools'],
install_requires=install_requires,
cmdclass={'test': PyTest, 'release': Release, 'prerelease': PreRelease},
packages=find_packages(exclude=['tests']),
include_package_data=True,
install_requires=['docutils','six'],

license='BSD',
description="WSDL parsing services package for Web Services for Python. see" + url,
long_description=open("README.rst").read(),
maintainer="Sorin Sbarnea",
maintainer_email="sorin.sbarnea@gmail.com",
author='Makina Corpus',
author_email='python@makina-corpus.com',
provides=[NAME],
url='https://github.com/pycontribs/wstools',
bugtrack_url='https://github.com/pycontribs/wstools/issues',
home_page='https://github.com/pycontribs/wstools',
keywords='api wstools wdsl web',
classifiers=[
'Programming Language :: Python',
'Programming Language :: Python :: 2.5',
'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Development Status :: 4 - Beta',
'Environment :: Other Environment',
'Intended Audience :: Developers',
'License :: OSI Approved :: BSD License',
'Operating System :: OS Independent',
'Topic :: Software Development :: Libraries :: Python Modules',
'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3.3',
'Programming Language :: Python :: 3.4',
'Topic :: Internet :: WWW/HTTP',
],
)

+ 3
- 3
tests/config.txt View File

@@ -10,7 +10,7 @@
[services_by_file]
ip2geo = data/ip2geo.wsdl
zip2geo = data/zip2geo.wsdl
soapi-dlw = data/soapi-1.63.0-dlw.wsdl
soapi-dlw = data/soapi-1.63.0-dlw.wsdl
soapi-re = data/soapi-1.63.0-re.wsdl

##########################################################################
@@ -209,7 +209,7 @@ FOPService = http://live.capescience.com/wsdl/FOPService.wsdl
FedRoutingDirectoryService = http://demo.soapam.com/services/FedEpayDirectory/FedEpayDirectoryService.wsdl
GMChart = http://service.graphmagic.com/GMService/GraphMagic.asmx?wsdl
GeoPlaces = http://www.codebump.com/services/placelookup.asmx?wsdl
GlobalWeather = http://live.capescience.com/wsdl/GlobalWeather.wsdl
GlobalWeatherComplex = http://live.capescience.com/wsdl/GlobalWeather.wsdl
GoogleSearch = http://api.google.com/GoogleSearch.wsdl
HPcatalogService = http://www.lixusnet.com/lixusnet/HPcatalog.jws?wsdl
HTMLeMail = http://www.framewerks.com/WebServices/HTMLeMail/HTMLeMail.asmx?WSDL
@@ -245,7 +245,7 @@ SendSMS = http://www.webservicex.net/SendSMS.asmx?WSDL
Server = http://addison.ra.cwru.edu/orc/calendar_copy/server.php?wsdl
Service = http://www.ejse.com/WeatherService/Service.asmx?WSDL
SpamKillerService = http://wavendon.dsdata.co.uk/axis/services/SpamKiller?wsdl
StockQuotes = http://www.swanandmokashi.com/HomePage/WebServices/StockQuotes.asmx?WSDL
StockQuotesComplex = http://www.swanandmokashi.com/HomePage/WebServices/StockQuotes.asmx?WSDL
TWSFissionDotNet = http://www.sidespace.com/ws/fission/fissiondotnet.php?wsdl
TerraService = http://terraservice.net/TerraService.asmx?WSDL
Transform = http://transform.dataconcert.com/transform.wsdl


+ 23
- 11
tests/test_wsdl.py View File

@@ -7,11 +7,19 @@

import sys
import unittest
import ConfigParser
import os
import inspect
cmd_folder = os.path.abspath(os.path.join(os.path.split(inspect.getfile(
inspect.currentframe()))[0], ".."))
if cmd_folder not in sys.path:
sys.path.insert(0, cmd_folder)
from wstools.Utility import DOM
from wstools.WSDLTools import WSDLReader
from wstools.TimeoutSocket import TimeoutError
try:
import configparser
except:
from six.moves import configparser

cwd = 'tests'

@@ -37,8 +45,11 @@ class WSDLToolsTestCase(unittest.TestCase):

def setUp(self):
makeTestSuite()
self.path = nameGenerator.next()
print self.path
if hasattr(nameGenerator, '__next__'):
self.path = nameGenerator.__next__()
else:
self.path = nameGenerator.next()
#print(self.path)
sys.stdout.flush()

def __str__(self):
@@ -72,7 +83,7 @@ class WSDLToolsTestCase(unittest.TestCase):
self.wsdl = WSDLReader().loadFromFile('tests/' + self.path)

except TimeoutError:
print "connection timed out"
print("connection timed out")
sys.stdout.flush()
return
except:
@@ -104,8 +115,8 @@ class WSDLToolsTestCase(unittest.TestCase):
raise

try:
self.checkWSDLCollection('import', self.wsdl.imports, \
key='namespace')
self.checkWSDLCollection('import', self.wsdl.imports,
key='namespace')
except:
self.path = self.path + ": wsdl.imports"
raise
@@ -131,9 +142,9 @@ class WSDLToolsTestCase(unittest.TestCase):
raise

if self.wsdl.extensions:
print 'No check for WSDLTools(%s) Extensions:' % (self.wsdl.name)
print('No check for WSDLTools(%s) Extensions:' % (self.wsdl.name))
for ext in self.wsdl.extensions:
print '\t', ext
print('\t', ext)

def schemaAttributesDeclarations(self, schema, node):
self.checkXSDCollection('attribute', schema.attr_decl, node)
@@ -150,13 +161,14 @@ class WSDLToolsTestCase(unittest.TestCase):


def setUpOptions(section):
cp = ConfigParser.ConfigParser()
cp = configparser.ConfigParser()
cp.optionxform = str
cp.read(cwd + '/config.txt')
if not cp.sections():
print 'fatal error: configuration file config.txt not present'
print('fatal error: configuration file config.txt not present')
sys.exit(0)
if not cp.has_section(section):
print '%s section not present in configuration file, exiting' % section
print('%s section not present in configuration file, exiting' % section)
sys.exit(0)
return cp, len(cp.options(section))



+ 1
- 1
tox.ini View File

@@ -1,6 +1,6 @@
[tox]
minversion = 1.3
envlist = py26,py27,py33,py34,flake8
envlist = py26,py27,py34,flake8

[testenv]
deps=


+ 0
- 1
wstools/.cvsignore View File

@@ -1 +0,0 @@
*.pyc

+ 3
- 0
wstools/Namespaces.py View File

@@ -136,6 +136,7 @@ WSRFLIST = (WSRF_V1_2,)


class OASIS:

'''URLs for Oasis specifications
'''
WSSE = "http://docs.oasis-open.org/wss/2004/01/"
@@ -164,6 +165,7 @@ class OASIS:


class APACHE:

'''
This name space is defined by AXIS and it is used for the TC in
TCapache.py, Map and file attachment (DataHandler)
@@ -222,6 +224,7 @@ WSA_LIST = (WSA200508, WSA200408, WSA200403, WSA200303)


class _WSAW(str):

"""
Define ADDRESS attribute to be compatible with WSA* layout
"""


+ 2
- 2
wstools/TimeoutSocket.py View File

@@ -51,7 +51,7 @@ class TimeoutSocket:
apply(sock.connect, addr)
sock.setblocking(timeout != 0)
return 1
except socket.error, why:
except socket.error as why:
if not timeout:
raise
sock.setblocking(1)
@@ -67,7 +67,7 @@ class TimeoutSocket:
try:
apply(sock.connect, addr)
return 1
except socket.error, why:
except socket.error as why:
if len(why.args) == 1:
code = 0
else:


+ 74
- 62
wstools/Utility.py View File

@@ -15,15 +15,27 @@

ident = "$Id$"

import copy
import sys
import types
import string
import six

import socket
import weakref
from os.path import isfile
from string import join, strip, split
from UserDict import UserDict
import urllib
try:
from urlparse import urljoin as basejoin
except:
from urllib.parse import urljoin as basejoin

try:
from UserDict import UserDict
from UserDict import DictMixin
except ImportError:
from collections import UserDict
from collections import MutableMapping as DictMixin

from .TimeoutSocket import TimeoutSocket, TimeoutError

@@ -42,9 +54,10 @@ try:
except ImportError:
from http.client import HTTPConnection, HTTPSConnection



from exceptions import Exception
try:
from exceptions import Exception
except:
pass
try:
from ZSI import _get_idstr
except:
@@ -61,9 +74,10 @@ import xml.dom.minidom
from xml.dom import Node

import logging
from c14n import Canonicalize
from Namespaces import SCHEMA, SOAP, XMLNS, ZSI_SCHEMA_URI
from .c14n import Canonicalize
from .Namespaces import SCHEMA, SOAP, XMLNS, ZSI_SCHEMA_URI

DEFAULT = "".join

try:
from xml.dom.ext import SplitQName
@@ -91,20 +105,6 @@ except:
return
return tuple(l)

#
# python2.3 urllib.basejoin does not remove current directory ./
# from path and this causes problems on subsequent basejoins.
#
basejoin = urllib.basejoin
if sys.version_info[0:2] < (2, 4, 0, 'final', 0)[0:2]:
#basejoin = lambda base,url: urllib.basejoin(base,url.lstrip('./'))
token = './'

def basejoin(base, url):
if url.startswith(token) is True:
return urllib.basejoin(base, url[2:])
return urllib.basejoin(base, url)


class NamespaceError(Exception):

@@ -235,7 +235,7 @@ def urlopen(url, timeout=20, redirects=None):
if redirects is not None and location in redirects:
raise RecursionError(
'Circular HTTP redirection detected.'
)
)
if redirects is None:
redirects = {}
redirects[location] = 1
@@ -289,40 +289,40 @@ class DOM:
return value
raise ValueError(
'Unsupported SOAP envelope uri: %s' % uri
)
)

def GetSOAPEnvUri(self, version):
"""Return the appropriate SOAP envelope uri for a given
human-friendly SOAP version string (e.g. '1.1')."""
attrname = 'NS_SOAP_ENV_%s' % join(split(version, '.'), '_')
attrname = 'NS_SOAP_ENV_%s' % '_'.join(version.split('.'))
value = getattr(self, attrname, None)
if value is not None:
return value
raise ValueError(
'Unsupported SOAP version: %s' % version
)
)

def GetSOAPEncUri(self, version):
"""Return the appropriate SOAP encoding uri for a given
human-friendly SOAP version string (e.g. '1.1')."""
attrname = 'NS_SOAP_ENC_%s' % join(split(version, '.'), '_')
attrname = 'NS_SOAP_ENC_%s' % '_'.join(version.split('.'))
value = getattr(self, attrname, None)
if value is not None:
return value
raise ValueError(
'Unsupported SOAP version: %s' % version
)
)

def GetSOAPActorNextUri(self, version):
"""Return the right special next-actor uri for a given
human-friendly SOAP version string (e.g. '1.1')."""
attrname = 'SOAP_ACTOR_NEXT_%s' % join(split(version, '.'), '_')
attrname = 'SOAP_ACTOR_NEXT_%s' % '_'.join(version.split('.'))
value = getattr(self, attrname, None)
if value is not None:
return value
raise ValueError(
'Unsupported SOAP version: %s' % version
)
)

# Namespace stuff related to XML Schema.
NS_XSD_99 = 'http://www.w3.org/1999/XMLSchema'
@@ -346,7 +346,7 @@ class DOM:
NS_XSD_01: NS_XSI_01,
}

for key, value in _xsd_uri_mapping.items():
for key, value in copy.deepcopy(_xsd_uri_mapping).items():
_xsd_uri_mapping[value] = key

def InstanceUriForSchemaUri(self, uri):
@@ -391,52 +391,52 @@ class DOM:
return value
raise ValueError(
'Unsupported SOAP envelope uri: %s' % uri
)
)

def GetWSDLUri(self, version):
attr = 'NS_WSDL_%s' % join(split(version, '.'), '_')
attr = 'NS_WSDL_%s' % '_'.join(version.split('.'))
value = getattr(self, attr, None)
if value is not None:
return value
raise ValueError(
'Unsupported WSDL version: %s' % version
)
)

def GetWSDLSoapBindingUri(self, version):
attr = 'NS_SOAP_BINDING_%s' % join(split(version, '.'), '_')
attr = 'NS_SOAP_BINDING_%s' % '_'.join(version.split('.'))
value = getattr(self, attr, None)
if value is not None:
return value
raise ValueError(
'Unsupported WSDL version: %s' % version
)
)

def GetWSDLHttpBindingUri(self, version):
attr = 'NS_HTTP_BINDING_%s' % join(split(version, '.'), '_')
attr = 'NS_HTTP_BINDING_%s' % '_'.join(version.split('.'))
value = getattr(self, attr, None)
if value is not None:
return value
raise ValueError(
'Unsupported WSDL version: %s' % version
)
)

def GetWSDLMimeBindingUri(self, version):
attr = 'NS_MIME_BINDING_%s' % join(split(version, '.'), '_')
attr = 'NS_MIME_BINDING_%s' % '_'.join(version.split('.'))
value = getattr(self, attr, None)
if value is not None:
return value
raise ValueError(
'Unsupported WSDL version: %s' % version
)
)

def GetWSDLHttpTransportUri(self, version):
attr = 'NS_SOAP_HTTP_%s' % join(split(version, '.'), '_')
attr = 'NS_SOAP_HTTP_%s' % '_'.join(version.split('.'))
value = getattr(self, attr, None)
if value is not None:
return value
raise ValueError(
'Unsupported WSDL version: %s' % version
)
)

# Other xml namespace constants.
NS_XMLNS = 'http://www.w3.org/2000/xmlns/'
@@ -449,7 +449,7 @@ class DOM:
return node.localName == name and \
(nsuri is None or self.nsUriMatch(node.namespaceURI, nsuri))

def getElement(self, node, name, nsuri=None, default=join):
def getElement(self, node, name, nsuri=None, default=DEFAULT):
"""Return the first child of node with a matching name and
namespace uri, or the default if one is provided."""
nsmatch = self.nsUriMatch
@@ -457,13 +457,13 @@ class DOM:
for child in node.childNodes:
if child.nodeType == ELEMENT_NODE:
if ((child.localName == name or name is None) and
(nsuri is None or nsmatch(child.namespaceURI, nsuri))):
(nsuri is None or nsmatch(child.namespaceURI, nsuri))):
return child
if default is not join:
if default != DEFAULT:
return default
raise KeyError(name)

def getElementById(self, node, id, default=join):
def getElementById(self, node, id, default=DEFAULT):
"""Return the first child of node matching an id reference."""
attrget = self.getAttr
ELEMENT_NODE = node.ELEMENT_NODE
@@ -471,7 +471,7 @@ class DOM:
if child.nodeType == ELEMENT_NODE:
if attrget(child, 'id') == id:
return child
if default is not join:
if default != DEFAULT:
return default
raise KeyError(name)

@@ -503,7 +503,7 @@ class DOM:
for child in node.childNodes:
if child.nodeType == ELEMENT_NODE:
if ((child.localName == name or name is None) and (
(nsuri is None) or nsmatch(child.namespaceURI, nsuri))):
(nsuri is None) or nsmatch(child.namespaceURI, nsuri))):
result.append(child)
return result

@@ -517,23 +517,35 @@ class DOM:
return False
return node.hasAttributeNS(nsuri, name)

def getAttr(self, node, name, nsuri=None, default=join):
def getAttr(self, node, name, nsuri=None, default=DEFAULT):
"""Return the value of the attribute named 'name' with the
optional nsuri, or the default if one is specified. If
nsuri is not specified, an attribute that matches the
given name will be returned regardless of namespace."""
if nsuri is None:
result = node._attrs.get(name, None)
if node._attrs is None:
result = None
else:
result = node._attrs.get(name, None)
if result is None:
for item in node._attrsNS.keys():
if item[1] == name:
result = node._attrsNS[item]
break
if node._attrsNS is None:
result = None
else:
for item in node._attrsNS.keys():
if item[1] == name:
result = node._attrsNS[item]
break
else:
result = node._attrsNS.get((nsuri, name), None)
if node._attrsNS is None:
result = None
else:
if node._attrsNS is None:
result = None
else:
result = node._attrsNS.get((nsuri, name), None)
if result is not None:
return result.value
if default is not join:
if default != DEFAULT:
return default
return ''

@@ -555,9 +567,9 @@ class DOM:
if nodetype == child.TEXT_NODE or \
nodetype == child.CDATA_SECTION_NODE:
result.append(child.nodeValue)
value = join(result, '')
value = ''.join(result)
if preserve_ws is None:
value = strip(value)
value = value.strip()
return value

def findNamespaceURI(self, prefix, node):
@@ -901,7 +913,7 @@ class ElementProxy(Base, MessageInterface):
for attr in node.attributes.values():
if attr.namespaceURI == XMLNS.BASE \
and nsuri == attr.value:
return attr.localName
return attr.localName
else:
if node.parentNode:
return self._getPrefix(node.parentNode, nsuri)
@@ -1190,8 +1202,8 @@ class Collection(UserDict):
self._func = key or self.default

def __getitem__(self, key):
NumberTypes = (types.IntType, types.LongType, types.FloatType,
types.ComplexType)
NumberTypes = six.integer_types
NumberTypes = NumberTypes + (type(float), type(complex))
if isinstance(key, NumberTypes):
return self.list[key]
return self.data[key]
@@ -1226,7 +1238,7 @@ class CollectionNS(UserDict):

def __getitem__(self, key):
self.targetNamespace = self.parent().targetNamespace
if isinstance(key, types.IntType):
if isinstance(key, six.integer_types):
return self.list[key]
elif self.__isSequence(key):
nsuri, name = key
@@ -1243,7 +1255,7 @@ class CollectionNS(UserDict):
self.data[targetNamespace][key] = item

def __isSequence(self, key):
return (type(key) in (types.TupleType, types.ListType)
return (isinstance(key, (tuple, list))
and len(key) == 2)

def keys(self):


+ 64
- 31
wstools/WSDLTools.py View File

@@ -21,6 +21,7 @@ from .XMLSchema import XMLSchema, SchemaReader, WSDLToolsAdapter


class WSDLReader:

"""A WSDLReader creates WSDL instances from urls and xml data."""

# Custom subclasses of WSDLReader may wish to implement a caching
@@ -61,6 +62,7 @@ class WSDLReader:


class WSDL:

"""A WSDL object models a WSDL service description. WSDL objects
may be created manually or loaded from an xml representation
using a WSDLReader instance."""
@@ -90,7 +92,7 @@ class WSDL:
if name in self.services:
raise WSDLError(
'Duplicate service element: %s' % name
)
)
item = Service(name, documentation)
if targetNamespace:
item.targetNamespace = targetNamespace
@@ -101,7 +103,7 @@ class WSDL:
if name in self.messages:
raise WSDLError(
'Duplicate message element: %s.' % name
)
)
item = Message(name, documentation)
if targetNamespace:
item.targetNamespace = targetNamespace
@@ -112,7 +114,7 @@ class WSDL:
if name in self.portTypes:
raise WSDLError(
'Duplicate portType element: name'
)
)
item = PortType(name, documentation)
if targetNamespace:
item.targetNamespace = targetNamespace
@@ -123,7 +125,7 @@ class WSDL:
if name in self.bindings:
raise WSDLError(
'Duplicate binding element: %s' % name
)
)
item = Binding(name, type, documentation)
if targetNamespace:
item.targetNamespace = targetNamespace
@@ -182,7 +184,7 @@ class WSDL:
if definitions is None:
raise WSDLError(
'Missing <definitions> element.'
)
)
self.version = DOM.WSDLUriToVersion(definitions.namespaceURI)
NS_WSDL = DOM.GetWSDLUri(self.version)

@@ -261,7 +263,7 @@ class WSDL:
if type is None:
raise WSDLError(
'Missing type attribute for binding %s.' % name
)
)
type = ParseQName(type, element)
docs = GetDocumentation(element)
binding = self.addBinding(name, type, docs, targetNamespace)
@@ -318,7 +320,7 @@ class WSDL:
if namespace is None or location is None:
raise WSDLError(
'Invalid import element (missing namespace or location).'
)
)
if base_location:
location = basejoin(base_location, location)
element.setAttributeNS(None, 'location', location)
@@ -336,7 +338,7 @@ class WSDL:
if imported is None:
raise WSDLError(
'Import target element not found for: %s' % location
)
)

imported_tns = DOM.findTargetNS(imported)
if imported_tns != namespace:
@@ -376,7 +378,9 @@ class WSDL:


class Element:

"""A class that provides common functions for WSDL element classes."""

def __init__(self, name=None, documentation=''):
self.name = name
self.documentation = documentation
@@ -402,6 +406,7 @@ class Element:


class ImportElement(Element):

def __init__(self, namespace, location):
self.namespace = namespace
self.location = location
@@ -438,6 +443,7 @@ class Types(Collection):


class Message(Element):

def __init__(self, name, documentation=''):
Element.__init__(self, name, documentation)
self.parts = Collection(self)
@@ -446,11 +452,11 @@ class Message(Element):
if name in self.parts:
raise WSDLError(
'Duplicate message part element: %s' % name
)
)
if type is None and element is None:
raise WSDLError(
'Missing type or element attribute for part: %s' % name
)
)
item = MessagePart(name)
item.element = element
item.type = type
@@ -467,7 +473,7 @@ class Message(Element):
if typeref is None and elemref is None:
raise WSDLError(
'No type or element attribute for part: %s' % name
)
)
if typeref is not None:
part.type = ParseTypeRef(typeref, element)
if elemref is not None:
@@ -508,6 +514,7 @@ class Message(Element):


class MessagePart(Element):

def __init__(self, name):
Element.__init__(self, name, '')
self.element = None
@@ -547,6 +554,7 @@ class MessagePart(Element):


class PortType(Element):

'''PortType has a anyAttribute, thus must provide for an extensible
mechanism for supporting such attributes. ResourceProperties is
specified in WS-ResourceProperties. wsa:Action is specified in
@@ -644,13 +652,14 @@ class PortType(Element):
ns, name = self.resourceProperties
prefix = epc.getPrefix(ns)
epc.setAttributeNS(WSRF.PROPERTIES.LATEST, 'ResourceProperties',
'%s:%s' % (prefix, name))
'%s:%s' % (prefix, name))

for op in self.operations:
op.toDom(epc._getNode())


class Operation(Element):

def __init__(self, name, documentation='', parameterOrder=None):
Element.__init__(self, name, documentation)
self.parameterOrder = parameterOrder
@@ -697,7 +706,7 @@ class Operation(Element):
if name in self.faults:
raise WSDLError(
'Duplicate fault element: %s' % name
)
)
item = MessageRole('fault', message, name, documentation, action)
self.faults[name] = item
return item
@@ -728,6 +737,7 @@ class Operation(Element):


class MessageRole(Element):

def __init__(self, type, message, name='', documentation='', action=None):
Element.__init__(self, name, documentation)
self.message = message
@@ -775,6 +785,7 @@ class MessageRole(Element):


class Binding(Element):

def __init__(self, name, type, documentation=''):
Element.__init__(self, name, documentation)
self.operations = Collection(self)
@@ -869,6 +880,7 @@ class Binding(Element):


class OperationBinding(Element):

def __init__(self, name, documentation=''):
Element.__init__(self, name, documentation)
self.input = None
@@ -952,6 +964,7 @@ class OperationBinding(Element):


class MessageRoleBinding(Element):

def __init__(self, type, name='', documentation=''):
Element.__init__(self, name, documentation)
self.type = type
@@ -976,7 +989,7 @@ class MessageRoleBinding(Element):
if use is None:
raise WSDLError(
'Invalid soap:body binding element.'
)
)
ob = SoapBodyBinding(use, namespace, encstyle, parts)
self.addExtension(ob)
continue
@@ -989,14 +1002,14 @@ class MessageRoleBinding(Element):
if use is None or name is None:
raise WSDLError(
'Invalid soap:fault binding element.'
)
)
ob = SoapFaultBinding(name, use, namespace, encstyle)
self.addExtension(ob)
continue

elif ns in DOM.NS_SOAP_BINDING_ALL and name in (
'header', 'headerfault'
):
):
encstyle = DOM.getAttr(e, 'encodingStyle', default=None)
namespace = DOM.getAttr(e, 'namespace', default=None)
message = DOM.getAttr(e, 'message')
@@ -1055,6 +1068,7 @@ class MessageRoleBinding(Element):


class Service(Element):

def __init__(self, name, documentation=''):
Element.__init__(self, name, documentation)
self.ports = Collection(self)
@@ -1075,7 +1089,7 @@ class Service(Element):
if name is None or binding is None:
raise WSDLError(
'Invalid port element.'
)
)
binding = ParseQName(binding, element)
port = self.addPort(name, binding, docs)
port.load_ex(GetExtensions(element))
@@ -1096,6 +1110,7 @@ class Service(Element):


class Port(Element):

def __init__(self, name, binding, documentation=''):
Element.__init__(self, name, documentation)
self.binding = binding
@@ -1127,7 +1142,7 @@ class Port(Element):
return item
raise WSDLError(
'No address binding found in port.'
)
)

def load_ex(self, elements):
for e in elements:
@@ -1161,6 +1176,7 @@ class Port(Element):


class SoapBinding:

def __init__(self, transport, style='rpc'):
self.transport = transport
self.style = style
@@ -1179,6 +1195,7 @@ class SoapBinding:


class SoapAddressBinding:

def __init__(self, location):
self.location = location

@@ -1193,6 +1210,7 @@ class SoapAddressBinding:


class SoapOperationBinding:

def __init__(self, soapAction=None, style=None):
self.soapAction = soapAction
self.style = style
@@ -1211,11 +1229,12 @@ class SoapOperationBinding:


class SoapBodyBinding:

def __init__(self, use, namespace=None, encodingStyle=None, parts=None):
if not use in ('literal', 'encoded'):
raise WSDLError(
'Invalid use attribute value: %s' % use
)
)
self.encodingStyle = encodingStyle
self.namespace = namespace
if type(parts) in (type(''), type(u'')):
@@ -1235,11 +1254,12 @@ class SoapBodyBinding:


class SoapFaultBinding:

def __init__(self, name, use, namespace=None, encodingStyle=None):
if not use in ('literal', 'encoded'):
raise WSDLError(
'Invalid use attribute value: %s' % use
)
)
self.encodingStyle = encodingStyle
self.namespace = namespace
self.name = name
@@ -1261,11 +1281,12 @@ class SoapFaultBinding:


class SoapHeaderBinding:

def __init__(self, message, part, use, namespace=None, encodingStyle=None):
if not use in ('literal', 'encoded'):
raise WSDLError(
'Invalid use attribute value: %s' % use
)
)
self.encodingStyle = encodingStyle
self.namespace = namespace
self.message = message
@@ -1280,16 +1301,19 @@ class SoapHeaderFaultBinding(SoapHeaderBinding):


class HttpBinding:

def __init__(self, verb):
self.verb = verb


class HttpAddressBinding:

def __init__(self, location):
self.location = location


class HttpOperationBinding:

def __init__(self, location):
self.location = location

@@ -1303,17 +1327,20 @@ class HttpUrlEncodedBinding:


class MimeContentBinding:

def __init__(self, part=None, type=None):
self.part = part
self.type = type


class MimeXmlBinding:

def __init__(self, part=None):
self.part = part


class MimeMultipartRelatedBinding:

def __init__(self):
self.parts = []

@@ -1326,6 +1353,7 @@ class MimeMultipartRelatedBinding:


class MimePartBinding:

def __init__(self):
self.items = []

@@ -1353,7 +1381,7 @@ class MimePartBinding:
if use is None:
raise WSDLError(
'Invalid soap:body binding element.'
)
)
ob = SoapBodyBinding(use, namespace, encstyle, parts)
self.items.append(ob)
continue
@@ -1397,7 +1425,7 @@ def GetDocumentation(element):

def GetExtensions(element):
return [item for item in DOM.getElements(element, None, None)
if item.namespaceURI != DOM.NS_WSDL]
if item.namespaceURI != DOM.NS_WSDL]


def GetWSAActionFault(operation, name):
@@ -1446,8 +1474,8 @@ def FindExtensions(object, kind, t_type=type(())):
result = []
namespaceURI, name = kind
return [item for item in object.extensions
if hasattr(item, 'nodeType') \
and DOM.nsUriMatch(namespaceURI, item.namespaceURI) \
if hasattr(item, 'nodeType')
and DOM.nsUriMatch(namespaceURI, item.namespaceURI)
and item.name == name]
return [item for item in object.extensions if isinstance(item, kind)]

@@ -1457,8 +1485,8 @@ def FindExtension(object, kind, t_type=type(())):
namespaceURI, name = kind
for item in object.extensions:
if hasattr(item, 'nodeType') \
and DOM.nsUriMatch(namespaceURI, item.namespaceURI) \
and item.name == name:
and DOM.nsUriMatch(namespaceURI, item.namespaceURI) \
and item.name == name:
return item
else:
for item in object.extensions:
@@ -1468,6 +1496,7 @@ def FindExtension(object, kind, t_type=type(())):


class SOAPCallInfo:

"""SOAPCallInfo captures the important binding information about a
SOAP operation, in a structure that is easier to work with than
raw WSDL structures."""
@@ -1547,7 +1576,9 @@ class SOAPCallInfo:


class ParameterInfo:

"""A ParameterInfo object captures parameter binding information."""

def __init__(self, name, type, namespace=None, element_type=0):
if element_type:
self.element_type = 1
@@ -1562,7 +1593,9 @@ class ParameterInfo:


class HeaderInfo(ParameterInfo):

"""A HeaderInfo object captures SOAP header binding information."""

def __init__(self, name, type, namespace, element_type=None):
ParameterInfo.__init__(self, name, type, namespace, element_type)

@@ -1614,7 +1647,7 @@ def callInfoFromWSDL(port, name):
part.element or part.type,
item.namespace,
element_type=part.element and 1 or 0
)
)
header.encodingStyle = item.encodingStyle

body = msgrole.findBinding(SoapBodyBinding)
@@ -1636,7 +1669,7 @@ def callInfoFromWSDL(port, name):
part.name,
part.element or part.type,
element_type=part.element and 1 or 0
)
)

if operation.output is not None:
try:
@@ -1665,7 +1698,7 @@ def callInfoFromWSDL(port, name):
part.element or part.type,
item.namespace,
element_type=part.element and 1 or 0
)
)
header.encodingStyle = item.encodingStyle

body = msgrole.findBinding(SoapBodyBinding)
@@ -1688,6 +1721,6 @@ def callInfoFromWSDL(port, name):
part.name,
part.element or part.type,
element_type=part.element and 1 or 0
)
)

return callinfo

+ 245
- 164
wstools/XMLSchema.py
File diff suppressed because it is too large
View File


+ 3
- 3
wstools/XMLname.py View File

@@ -72,9 +72,9 @@ def toXMLname(string):
if i < N - 1 and T[i] == u'_' and T[i + 1] == u'x':
X.append(u'_x005F_')
elif i == 0 and N >= 3 and \
(T[0] == u'x' or T[0] == u'X') and \
(T[1] == u'm' or T[1] == u'M') and \
(T[2] == u'l' or T[2] == u'L'):
(T[0] == u'x' or T[0] == u'X') and \
(T[1] == u'm' or T[1] == u'M') and \
(T[2] == u'l' or T[2] == u'L'):
X.append(u'_xFFFF_' + T[0])
elif (not _NCNameChar(T[i])) or (i == 0 and not _NCNameStartChar(T[i])):
X.append(_toUnicodeHex(T[i]))


+ 7
- 6
wstools/c14n.py View File

@@ -101,8 +101,8 @@ def _utilized(n, node, other_attrs, unsuppressedPrefixes):
elif n.startswith('xmlns'):
n = n[5:]
if (n == "" and node.prefix in ["#default", None]) or \
n == node.prefix or n in unsuppressedPrefixes:
return 1
n == node.prefix or n in unsuppressedPrefixes:
return 1
for attr in other_attrs:
if n == attr.prefix:
return 1
@@ -151,6 +151,7 @@ _in_subset = lambda subset, node: subset is None or node in subset # rich's twe


class _implementation:

'''Implementation class for C14N. This accompanies a node during it's
processing and includes the parameters and processing state.'''

@@ -174,7 +175,7 @@ class _implementation:
self.documentOrder = _Element # At document element
if not _inclusive(self):
inherited, unused = _inclusiveNamespacePrefixes(node, self._inherit_context(node),
self.unsuppressedPrefixes)
self.unsuppressedPrefixes)
self._do_element(node, inherited, unused=unused)
else:
inherited = self._inherit_context(node)
@@ -311,7 +312,7 @@ class _implementation:
# xml_attrs_local -- Local attributes in XML namespace.
# ns_unused_inherited -- not rendered namespaces, used for exclusive
ns_parent, ns_rendered, xml_attrs = \
self.state[0], self.state[1].copy(), self.state[2].copy() # 0422
self.state[0], self.state[1].copy(), self.state[2].copy() # 0422

ns_unused_inherited = unused
if unused is None:
@@ -372,14 +373,14 @@ class _implementation:
# If default namespace is XMLNS.BASE or empty,
# and if an ancestor was the same
if n == "xmlns" and v in [XMLNS.BASE, ''] \
and ns_rendered.get('xmlns') in [XMLNS.BASE, '', None]:
and ns_rendered.get('xmlns') in [XMLNS.BASE, '', None]:
continue

# "omit namespace node with local name xml, which defines
# the xml prefix, if its string value is
# http://www.w3.org/XML/1998/namespace."
if n in ["xmlns:xml", "xml"] \
and v in ['http://www.w3.org/XML/1998/namespace']:
and v in ['http://www.w3.org/XML/1998/namespace']:
continue

# If not previously rendered


+ 1
- 1
wstools/version.py View File

@@ -1 +1 @@
__version__ = "0.4.3"
__version__ = "0.4.4"

Loading…
Cancel
Save