From 166165c51fb3facebe60e6476f6bb788c8f7cb6d Mon Sep 17 00:00:00 2001 From: "Peter A. Bigot" Date: Sun, 18 Sep 2016 18:07:14 -0500 Subject: [PATCH 01/41] Update for development version 1.2.6-DEV --- README.txt | 2 +- doc/conf.py | 2 +- pyxb/__init__.py | 2 +- setup.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.txt b/README.txt index 8a80b791..d22d3628 100644 --- a/README.txt +++ b/README.txt @@ -1,5 +1,5 @@ PyXB -- Python W3C XML Schema Bindings -Version 1.2.5 +Version 1.2.6-DEV The source releases includes pre-built bundles for common XML namespaces, assorted web service namespaces, and SAML. A bundle with over 75 namespaces diff --git a/doc/conf.py b/doc/conf.py index 6e097924..e7c4bba2 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -47,7 +47,7 @@ # The short X.Y version. version = '1.2' # The full version, including alpha/beta/rc tags. -release = '1.2.5' +release = '1.2.6-DEV' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/pyxb/__init__.py b/pyxb/__init__.py index 198caafe..ca097de2 100644 --- a/pyxb/__init__.py +++ b/pyxb/__init__.py @@ -61,7 +61,7 @@ def __init__ (self, *args, **kw): if issubclass(self.__class__.mro()[-2], ( list, dict )): super(cscRoot, self).__init__(*args) -__version__ = '1.2.5' +__version__ = '1.2.6-DEV' """The version of PyXB""" __url__ = 'http://pyxb.sourceforge.net' diff --git a/setup.py b/setup.py index 4b94027f..04b6f882 100755 --- a/setup.py +++ b/setup.py @@ -4,7 +4,7 @@ import sys # The current version of the system. Format is #.#.#[-DEV]. -version = '1.2.5' +version = '1.2.6-DEV' # Require Python 2.6 or higher or Python 3.1 or higher if (sys.version_info[:2] < (2, 6)) or ((sys.version_info[0] == 3) and sys.version_info[:2] < (3, 1)): From de8cfd490a868e3ec7014c8e815470b4b8621ec7 Mon Sep 17 00:00:00 2001 From: "Peter A. Bigot" Date: Wed, 21 Sep 2016 07:28:15 -0500 Subject: [PATCH 02/41] fix #59: decimal values not supported by PyXB.BIND This example is not part of the test suite, so the fact that decimal.Decimal(99.95) does not compare equal to 99.95 was not detected. Work around this by checking for preservation of string value. --- pyxb/binding/basis.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pyxb/binding/basis.py b/pyxb/binding/basis.py index 79db86fb..273586d0 100644 --- a/pyxb/binding/basis.py +++ b/pyxb/binding/basis.py @@ -23,6 +23,7 @@ from pyxb.utils import domutils, utility, six import pyxb.namespace from pyxb.namespace.builtin import XMLSchema_instance as XSI +import decimal _log = logging.getLogger(__name__) @@ -428,6 +429,10 @@ def _CompatibleValue (cls, value, **kw): rv = cls.Factory(value) if isinstance(rv, simpleTypeDefinition) and (rv == value): return rv + # Python decimal instances do not compare equal to float values; + # test whether the string representation is equal instead. + if isinstance(rv, decimal.Decimal) and (str(rv) == str(value)): + return rv if isinstance(rv, complexTypeDefinition) and (rv.value() == value): return rv From e6f002655c4b4f94e4eb5c95a683692b3345dfc3 Mon Sep 17 00:00:00 2001 From: "Peter A. Bigot" Date: Wed, 14 Dec 2016 06:32:43 -0600 Subject: [PATCH 03/41] fix #69: Python regex alternation binds too tightly XML regex like 'foo|bar' where naively converted to Python '^foo|bar$' which matches either '^foo' or 'bar$' rather than the intended '^(foo|bar)$'. As we don't actually care about group results enclosing the entire expression in a group produces the expected result. --- pyxb/utils/xmlre.py | 4 +-- tests/trac/test-issue-0069.py | 52 +++++++++++++++++++++++++++++++++++ tests/utils/test-xmlre.py | 10 +++++-- 3 files changed, 62 insertions(+), 4 deletions(-) create mode 100644 tests/trac/test-issue-0069.py diff --git a/pyxb/utils/xmlre.py b/pyxb/utils/xmlre.py index 913ed0a5..6e9e50e0 100644 --- a/pyxb/utils/xmlre.py +++ b/pyxb/utils/xmlre.py @@ -288,7 +288,7 @@ def XMLToPython (pattern): that matches the same language as C{pattern}.""" assert isinstance(pattern, six.text_type) new_pattern_elts = [] - new_pattern_elts.append('^') + new_pattern_elts.append('^(') position = 0 while position < len(pattern): cg = MaybeMatchCharacterClass(pattern, position) @@ -305,5 +305,5 @@ def XMLToPython (pattern): else: (cps, position) = cg new_pattern_elts.append(cps.asPattern()) - new_pattern_elts.append('$') + new_pattern_elts.append(')$') return ''.join(new_pattern_elts) diff --git a/tests/trac/test-issue-0069.py b/tests/trac/test-issue-0069.py new file mode 100644 index 00000000..af167a62 --- /dev/null +++ b/tests/trac/test-issue-0069.py @@ -0,0 +1,52 @@ +# -*- coding: utf-8 -*- +import logging +if __name__ == '__main__': + logging.basicConfig() +_log = logging.getLogger(__name__) +import pyxb.binding.generate +import pyxb.utils.domutils +from xml.dom import Node + +import os.path +xsd=''' + + + + + + + + + + + + + + + + +''' + +code = pyxb.binding.generate.GeneratePython(schema_text=xsd) +#open('code.py', 'w').write(code) +#print code + +rv = compile(code, 'test', 'exec') +eval(rv) + +from pyxb.exceptions_ import * + +import unittest + +class TestIssue0069 (unittest.TestCase): + def testCountry (self): + address = Address() + address.City = 'New-York' + with self.assertRaises(SimpleFacetValueError) as cm: + address.Country = 'USA' + address.Country = 'US' + xmls = address.toxml('utf8', root_only=True); + self.assertEqual(xmls, '
New-YorkUS
') + +if __name__ == '__main__': + unittest.main() diff --git a/tests/utils/test-xmlre.py b/tests/utils/test-xmlre.py index 150e4f16..88af01cb 100644 --- a/tests/utils/test-xmlre.py +++ b/tests/utils/test-xmlre.py @@ -178,10 +178,10 @@ def testMatchCharClassExpr (self): self.assertEqual(charset, expected) def testXMLToPython (self): - self.assertEqual(r'^123$', xmlre.XMLToPython('123')) + self.assertEqual(r'^(123)$', xmlre.XMLToPython('123')) # Note that single-char escapes in the expression are # converted to character classes. - self.assertEqual(r'^Why[ ]not[?]$', xmlre.XMLToPython(r'Why[ ]not\?')) + self.assertEqual(r'^(Why[ ]not[?])$', xmlre.XMLToPython(r'Why[ ]not\?')) def testRegularExpressions (self): text = '[\i-[:]][\c-[:]]*' @@ -467,5 +467,11 @@ def testSingleCharRange(self): def testQuotedSingleChar(self): self.assertMatches("foo\\\\bar", "foo\\bar") + def testAlternation(self): + self.assertMatches("[0-9]{3}|", "123"); + self.assertMatches("[0-9]{3}|", ""); + self.assertNoMatch("[0-9]{3}|", "12"); + self.assertNoMatch("[0-9]{3}|", "1234"); + if __name__ == '__main__': unittest.main() From c66d65e7eb00b2ec7b3c184b4f803f6f286c0e3c Mon Sep 17 00:00:00 2001 From: "Peter A. Bigot" Date: Fri, 12 May 2017 07:56:36 -0500 Subject: [PATCH 04/41] README: add link to github-hosted documentation --- README.txt.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.txt.in b/README.txt.in index 7447e05d..d3516c56 100644 --- a/README.txt.in +++ b/README.txt.in @@ -8,7 +8,7 @@ those, read pyxb/bundles/opengis/README.txt before installing PyXB. Installation: python setup.py install -Documentation: doc/html +Documentation: doc/html or https://pabigot.github.io/pyxb/ Help Forum: http://sourceforge.net/forum/forum.php?forum_id=956708 From 11017b0866f2bfb6856e3633a74a74d8900bcc73 Mon Sep 17 00:00:00 2001 From: "Peter A. Bigot" Date: Fri, 12 May 2017 09:12:46 -0500 Subject: [PATCH 05/41] test/support.sh: add file Infrastructure to simplify additional validation in the shell scripts used to test PyXB. --- tests/support.sh | 59 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 tests/support.sh diff --git a/tests/support.sh b/tests/support.sh new file mode 100644 index 00000000..34fc8868 --- /dev/null +++ b/tests/support.sh @@ -0,0 +1,59 @@ +# POSIX shell infrastructure included by various test scripts to +# remove redundancy and simplify the scripts. +# +# REMOVE_ON_EXIT: A list of files that will be removed when the +# including script exits. +# + +# Untested failures are test failures +set -e + +# Improve comparability by using the same encoding as the developer's +# console environment when redirecting to a file. +export PYTHONIOENCODING='utf-8' + +# Capture the directory from which the test script was run. +TEST_DIR=$(cd $(dirname ${0}); pwd) +echo "TEST: ${TEST_DIR}" + +# Don't throw away temp file names if somebody includes this multiple +# times. +${REMOVE_ON_EXIT:=} + +# Create a temporary file into which output can be directed for +# comparison with expected results. The file name is placed in +# variable tmpout and is also cached for removal when the script +# exits. If you need multiple temporary outputs you may invoke this +# multiple times. +# +# Usage: name=$(make_tmpout [base]) +make_tmpout () { + tmpout=$(mktemp -t ${1:-test}_XXXXXXXXXX) + REMOVE_ON_EXIT="${REMOVE_ON_EXIT} ${tmpout}" + echo ${tmpout} +} + +# Remove remaining temporary files +cleanup () { + rm -f ${REMOVE_ON_EXIT} +} +trap cleanup EXIT + +# Indicate a test failure, with arguments displayed as a message, +# and exit with an error. If tmpout specifies a non-empty file +# its contents will be copied +fail () { + echo 1>&2 "TEST: FAIL: ${TEST_DIR}${@:+: $@}" + exit 1 +} + +# Indicate the test passed, with arguments displayed as a message, +# and continue to execute. +passed () { + echo 1>&2 "TEST: PASS: ${TEST_DIR}${@:+: $@}" +} + +# Local Variables: +# mode:sh +# indent-tabs-mode:nil +# End: From dc037fb08449ee0a41bafde6da61b5e95ea5045d Mon Sep 17 00:00:00 2001 From: "Peter A. Bigot" Date: Fri, 12 May 2017 08:02:30 -0500 Subject: [PATCH 06/41] examples/weather: disable test This service has been spotty for the last couple years, and at this point is no longer available. --- doc/index.txt | 13 +++++++++---- examples/weather/README.txt | 4 ++++ examples/weather/{test.sh => disabled-test.sh} | 0 3 files changed, 13 insertions(+), 4 deletions(-) rename examples/weather/{test.sh => disabled-test.sh} (100%) diff --git a/doc/index.txt b/doc/index.txt index 4b0e3978..cfa50008 100644 --- a/doc/index.txt +++ b/doc/index.txt @@ -68,7 +68,7 @@ Thirty Second Example ********************* An example of a program using PyXB to interact with a `web service -`_ using an +`_ [*]_ using an automatically-generated module. First, retrieve the WSDL and generate the bindings:: @@ -100,9 +100,14 @@ And run it:: Monday, August 18 2014: Partly Cloudy, from 67 to 83 Tuesday, August 19 2014: Partly Cloudy, from 65 to 84 -That's it. (Note: Although the `CDYNE Weather Service -`_ is -still available, the data underlying it is no longer updated.) +That's it. + +.. [*] **Note**: Sometime between 2014 and 2017 the CDYNE Weather Service + disappeared, although as of 2017-05-13 the link to its description + above was still present. If you care about weather, there is a more + complex example interfacing with the `National Digital Forecast + Database `_ in the ``examples/ndfd`` + directory. ****************** Indices and tables diff --git a/examples/weather/README.txt b/examples/weather/README.txt index a3f430e3..896254c7 100644 --- a/examples/weather/README.txt +++ b/examples/weather/README.txt @@ -1,3 +1,7 @@ +Updated 2017-05-12: This service is no longer available. Similar +services are still hosted by this company but require a developer key to +access. + A free weather service at http://ws.cdyne.com/WeatherWS/Weather.asmx Use genbindings.sh to retrieve the wsdl and generate the bindings for the diff --git a/examples/weather/test.sh b/examples/weather/disabled-test.sh similarity index 100% rename from examples/weather/test.sh rename to examples/weather/disabled-test.sh From 2f2d18ccb4c270c4750c3aa7dfb0de2efb94d113 Mon Sep 17 00:00:00 2001 From: "Peter A. Bigot" Date: Fri, 12 May 2017 09:50:29 -0500 Subject: [PATCH 07/41] examples passim: update test infrastructure Use the support routines, validate expected output, use consistent approach for disabled tests where servers no longer functional. Note that expected test results may have trailing whitespace. --- examples/cablelabs/disabled-test.sh | 3 + examples/cablelabs/test.sh | 3 - examples/content/test.expected | 4 + examples/content/test.sh | 12 +- examples/customization/test.sh | 9 +- examples/dictionary/showdict.expected | 11 + examples/dictionary/showdict.py | 14 +- examples/dictionary/test.sh | 10 +- .../geocoder/{xtest.sh => disabled-test.sh} | 0 examples/ndfd/showreq.expected | 24 + examples/ndfd/showreq.py | 4 +- examples/ndfd/test.sh | 20 +- .../tmsxtvd/{xtest.sh => disabled-test.sh} | 0 examples/ucum/test.expected | 511 ++++++++++++++++++ examples/ucum/test.sh | 16 +- examples/unicode_jp/test.sh | 17 +- examples/xhtml/test.sh | 22 +- examples/xsdprimer/demo.expected | 4 + examples/xsdprimer/demo.py | 12 +- examples/xsdprimer/ipo.py | 2 +- examples/xsdprimer/saxdemo.py | 6 +- examples/xsdprimer/test.sh | 9 + 22 files changed, 650 insertions(+), 63 deletions(-) create mode 100755 examples/cablelabs/disabled-test.sh delete mode 100755 examples/cablelabs/test.sh create mode 100644 examples/content/test.expected create mode 100644 examples/dictionary/showdict.expected rename examples/geocoder/{xtest.sh => disabled-test.sh} (100%) create mode 100644 examples/ndfd/showreq.expected rename examples/tmsxtvd/{xtest.sh => disabled-test.sh} (100%) create mode 100644 examples/ucum/test.expected create mode 100644 examples/xsdprimer/demo.expected create mode 100755 examples/xsdprimer/test.sh diff --git a/examples/cablelabs/disabled-test.sh b/examples/cablelabs/disabled-test.sh new file mode 100755 index 00000000..5e84c356 --- /dev/null +++ b/examples/cablelabs/disabled-test.sh @@ -0,0 +1,3 @@ +rm -f cablelabs.wxs +sh genbindings.sh \ + && python demo.py diff --git a/examples/cablelabs/test.sh b/examples/cablelabs/test.sh deleted file mode 100755 index 82e4edab..00000000 --- a/examples/cablelabs/test.sh +++ /dev/null @@ -1,3 +0,0 @@ -#rm -f cablelabs.wxs -#sh genbindings.sh \ -# && python demo.py diff --git a/examples/content/test.expected b/examples/content/test.expected new file mode 100644 index 00000000..37ec9815 --- /dev/null +++ b/examples/content/test.expected @@ -0,0 +1,4 @@ +12 +3 +8 +15 diff --git a/examples/content/test.sh b/examples/content/test.sh index b92fab93..506ebf19 100755 --- a/examples/content/test.sh +++ b/examples/content/test.sh @@ -1,5 +1,11 @@ +#!/bin/sh + +. ${PYXB_ROOT}/tests/support.sh + rm -f content.py pyxbgen \ - -u content.xsd -m content \ - && python showcontent.py > showcontent.out \ - && cat showcontent.out + -u content.xsd -m content \ + || failed generating bindings +python showcontent.py > test.out || fail running +cmp test.out test.expected || fail output comparison +passed diff --git a/examples/customization/test.sh b/examples/customization/test.sh index fc192f09..c36b0679 100755 --- a/examples/customization/test.sh +++ b/examples/customization/test.sh @@ -1,9 +1,6 @@ #!/bin/sh -fail () { - echo 1>&2 "${test_name} FAILED: ${@}" - exit 1 -} +. ${PYXB_ROOT}/tests/support.sh xmllint --schema custom.xsd test.xml || fail Test document is not valid @@ -11,6 +8,8 @@ rm -rf raw *.pyc pyxbgen \ -m custom \ -u custom.xsd \ - --write-for-customization + --write-for-customization \ + || fail generating bindings python tst-normal.py || fail Normal customization failed python tst-introspect.py || fail Introspection customization failed +passed diff --git a/examples/dictionary/showdict.expected b/examples/dictionary/showdict.expected new file mode 100644 index 00000000..bacedf15 --- /dev/null +++ b/examples/dictionary/showdict.expected @@ -0,0 +1,11 @@ +THE DEVIL'S DICTIONARY ((C)1911 Released April 15 1993) (devils) : 3235 chars +Easton's 1897 Bible Dictionary (easton) : 2182 chars +Elements database 20001107 (elements) : 1285 chars +The Free On-line Dictionary of Computing (27 SEP 03) (foldoc) : 3952 chars +U.S. Gazetteer (1990) (gazetteer) : 604 chars +The Collaborative International Dictionary of English v.0.44 (gcide) : 3168 chars +Hitchcock's Bible Names Dictionary (late 1800's) (hitchcock) : 1021 chars +Jargon File (4.3.1, 29 Jun 2001) (jargon) : 2992 chars +Virtual Entity of Relevant Acronyms (Version 1.9, June 2002) (vera) : 1355 chars +WordNet (r) 2.0 (wn) : 2562 chars +CIA World Factbook 2002 (world02) : 2544 chars diff --git a/examples/dictionary/showdict.py b/examples/dictionary/showdict.py index 6b856e1b..cefbe914 100644 --- a/examples/dictionary/showdict.py +++ b/examples/dictionary/showdict.py @@ -1,4 +1,7 @@ +# -*- coding: utf-8 -*- + from __future__ import print_function +import sys import dict from pyxb.utils.six.moves.urllib.request import urlopen import pyxb.utils.domutils as domutils @@ -16,9 +19,12 @@ # Create a REST-style query to retrieve the information about this dictionary. uri = '%s%s?dictId=%s' % (port_uri, op_path, d.Id) resp = urlopen(uri).read() + print("%s (%s) : %d chars" % (d.Name.encode('utf-8'), d.Id.encode('utf-8'), len(resp))); + # The response is a simple type derived from string, so we can - # just extract and print it. + # just extract and print it. Excluded by default since it has + # leading and trailing whitespace that causes problems with using + # git to store the expected output. di_resp = dict.CreateFromDOM(domutils.StringToDOM(resp)) - # Do the "encode" garbage because one of these dictionaries has a - # non-ASCII character - print("%s (%s)\n%s\n" % (d.Name.encode('utf-8'), d.Id.encode('utf-8'), di_resp.encode('utf-8'))) + if sys.stdout.isatty(): + print("%s\n" % di_resp.encode('utf-8')); diff --git a/examples/dictionary/test.sh b/examples/dictionary/test.sh index 60a19eff..aa9fdd40 100755 --- a/examples/dictionary/test.sh +++ b/examples/dictionary/test.sh @@ -1,2 +1,8 @@ -sh genbindings.sh -python showdict.py +#!/bin/sh + +. ${PYXB_ROOT}/tests/support.sh + +sh genbindings.sh || failed generating bindings +python showdict.py > showdict.out || failed running +cmp showdict.out showdict.expected || failed output comparison +passed diff --git a/examples/geocoder/xtest.sh b/examples/geocoder/disabled-test.sh similarity index 100% rename from examples/geocoder/xtest.sh rename to examples/geocoder/disabled-test.sh diff --git a/examples/ndfd/showreq.expected b/examples/ndfd/showreq.expected new file mode 100644 index 00000000..e024ca33 --- /dev/null +++ b/examples/ndfd/showreq.expected @@ -0,0 +1,24 @@ +PS None +ndfdXMLBinding +ndfdXMLPortType + +Returns National Weather Service digital weather forecast data + + +{http://graphical.weather.gov/xml/DWMLgen/wsdl/ndfdXML.wsdl}NDFDgenRequest +{http://graphical.weather.gov/xml/DWMLgen/wsdl/ndfdXML.wsdl}NDFDgenRequest + + + + + + + +uri:DWMLgen None +latitude latitude +longitude longitude +product product +startTime startTime +endTime endTime +Unit Unit +weatherParameters weatherParameters diff --git a/examples/ndfd/showreq.py b/examples/ndfd/showreq.py index e3ed499e..88167195 100644 --- a/examples/ndfd/showreq.py +++ b/examples/ndfd/showreq.py @@ -13,7 +13,7 @@ dom = xml.dom.minidom.parse(open('NDFDgen.xml', 'rb')) body_dom = dom.documentElement.firstChild.nextSibling.firstChild.nextSibling -print(body_dom) +#print(body_dom) # contains varying text in object description # Service interface types import ndfd @@ -40,7 +40,7 @@ im_en = input.message print(im_en) msg = im_en.message() -print(msg) +#print(msg) # contains varying text in object description for p in msg.part: print(p.toxml("utf-8")) msg_ns = pyxb.namespace.NamespaceForURI(body_dom.namespaceURI) diff --git a/examples/ndfd/test.sh b/examples/ndfd/test.sh index 899ffba4..3d1878cd 100755 --- a/examples/ndfd/test.sh +++ b/examples/ndfd/test.sh @@ -1,5 +1,19 @@ +#!/bin/sh + +. ${PYXB_ROOT}/tests/support.sh + PYXB_ARCHIVE_PATH="&pyxb/bundles/wssplat//" export PYXB_ARCHIVE_PATH -sh genbindings.sh \ - && python showreq.py \ - && python forecast.py + +sh genbindings.sh || fail generating bindings + +python showreq.py > showreq.out || fail showreq +cmp showreq.out showreq.expected || fail request comparison +# The NWS servers may throttle this; expect it to take no more than 30 +# s +echo "Wait for forecast to be retrieved..." +date +python forecast.py > forecast.out || fail forecast +date +cat forecast.out +passed diff --git a/examples/tmsxtvd/xtest.sh b/examples/tmsxtvd/disabled-test.sh similarity index 100% rename from examples/tmsxtvd/xtest.sh rename to examples/tmsxtvd/disabled-test.sh diff --git a/examples/ucum/test.expected b/examples/ucum/test.expected new file mode 100644 index 00000000..3f68111a --- /dev/null +++ b/examples/ucum/test.expected @@ -0,0 +1,511 @@ +m + prints as: m +s + prints as: s +g + prints as: g +rad + prints as: rad +K + prints as: K +C + prints as: C +cd + prints as: cd +10* as 10 times 1 + prints as: 10 +10^ as 10 times 1 + prints as: 10 +[pi] as 3.1415926535897932384626433832795028841971693993751058209749445923 times 1 + prints as: π +% alias 10*-2 + prints as: % +[ppth] alias 10*-3 + prints as: ppth +[ppm] alias 10*-6 + prints as: ppm +[ppb] alias 10*-9 + prints as: ppb +[pptr] alias 10*-12 + prints as: pptr +mol as 6.0221367 times 10*23 + prints as: mol +sr alias rad2 + prints as: sr +Hz alias s-1 + prints as: Hz +N alias kg.m/s2 + prints as: N +Pa alias N/m2 + prints as: Pa +J alias N.m + prints as: J +W alias J/s + prints as: W +A alias C/s + prints as: A +V alias J/C + prints as: V +F alias C/V + prints as: F +Ohm alias V/A + prints as: Ω +S alias Ohm-1 + prints as: S +Wb alias V.s + prints as: Wb +Cel as value cel(1 K) + prints as: °C +T alias Wb/m2 + prints as: T +H alias Wb/A + prints as: H +lm alias cd.sr + prints as: lm +lx alias lm/m2 + prints as: lx +Bq alias s-1 + prints as: Bq +Gy alias J/kg + prints as: Gy +Sv alias J/kg + prints as: Sv +gon as 0.9 times deg + prints as: □g +deg as 2 times [pi].rad/360 + prints as: ° +' alias deg/60 + prints as: ' +'' alias '/60 + prints as: '' +l alias dm3 + prints as: l +L alias l + prints as: L +ar as 100 times m2 + prints as: a +min as 60 times s + prints as: min +h as 60 times min + prints as: h +d as 24 times h + prints as: d +a_t as 365.24219 times d + prints as: at +a_j as 365.25 times d + prints as: aj +a_g as 365.2425 times d + prints as: ag +a alias a_j + prints as: a +wk as 7 times d + prints as: wk +mo_s as 29.53059 times d + prints as: mos +mo_j alias a_j/12 + prints as: moj +mo_g alias a_g/12 + prints as: mog +mo alias mo_j + prints as: mo +t as 1E+3 times kg + prints as: t +bar as 1E+5 times Pa + prints as: bar +u as 1.6605402E-24 times g + prints as: u +eV alias [e].V + prints as: eV +AU as 149597.870691 times Mm + prints as: AU +pc as 3.085678E+16 times m + prints as: pc +[c] as 299792458 times m/s + prints as: c +[h] as 6.6260755E-34 times J.s + prints as: h +[k] as 1.380658E-23 times J/K + prints as: k +[eps_0] as 8.854187817E-12 times F/m + prints as: ε0 +[mu_0] alias 4.[pi].10*-7.N/A2 + prints as: μ0 +[e] as 1.60217733E-19 times C + prints as: e +[m_e] as 9.1093897E-28 times g + prints as: me +[m_p] as 1.6726231E-24 times g + prints as: mp +[G] as 6.67259E-11 times m3.kg-1.s-2 + prints as: G +[g] as 9.80665 times m/s2 + prints as: gn +atm as 101325 times Pa + prints as: atm +[ly] alias [c].a_j + prints as: l.y. +gf alias g.[g] + prints as: gf +[lbf_av] alias [lb_av].[g] + prints as: lbf +Ky alias cm-1 + prints as: K +Gal alias cm/s2 + prints as: Gal +dyn alias g.cm/s2 + prints as: dyn +erg alias dyn.cm + prints as: erg +P alias dyn.s/cm2 + prints as: P +Bi as 10 times A + prints as: Bi +St alias cm2/s + prints as: St +Mx as 1E-8 times Wb + prints as: Mx +G as 0.0001 times T + prints as: Gs +Oe as 250 times /[pi].A/m + prints as: Oe +Gb alias Oe.cm + prints as: Gb +sb alias cd/cm2 + prints as: sb +Lmb alias cd/cm2/[pi] + prints as: L +ph as 0.0001 times lx + prints as: ph +Ci as 3.7E+10 times Bq + prints as: Ci +R as 0.000258 times C/kg + prints as: R +RAD as 100 times erg/g + prints as: RAD +REM alias RAD + prints as: REM +[in_i] as 2.54 times cm + prints as: in +[ft_i] as 12 times [in_i] + prints as: ft +[yd_i] as 3 times [ft_i] + prints as: yd +[mi_i] as 5280 times [ft_i] + prints as: mi +[fth_i] as 6 times [ft_i] + prints as: fth +[nmi_i] as 1852 times m + prints as: n.mi +[kn_i] alias [nmi_i]/h + prints as: knot +[sin_i] alias [in_i]2 +[sft_i] alias [ft_i]2 +[syd_i] alias [yd_i]2 +[cin_i] alias [in_i]3 +[cft_i] alias [ft_i]3 +[cyd_i] alias [yd_i]3 + prints as: cu.yd +[bf_i] as 144 times [in_i]3 +[cr_i] as 128 times [ft_i]3 +[mil_i] as 0.001 times [in_i] + prints as: mil +[cml_i] alias [pi]/4.[mil_i]2 + prints as: circ.mil +[hd_i] as 4 times [in_i] + prints as: hd +[ft_us] as 1200 times m/3937 + prints as: ftus +[yd_us] as 3 times [ft_us] +[in_us] alias [ft_us]/12 +[rd_us] as 16.5 times [ft_us] +[ch_us] as 4 times [rd_us] +[lk_us] alias [ch_us]/100 +[rch_us] as 100 times [ft_us] +[rlk_us] alias [rch_us]/100 +[fth_us] as 6 times [ft_us] +[fur_us] as 40 times [rd_us] +[mi_us] as 8 times [fur_us] +[acr_us] as 160 times [rd_us]2 +[srd_us] alias [rd_us]2 +[smi_us] alias [mi_us]2 +[sct] alias [mi_us]2 +[twp] as 36 times [sct] +[mil_us] as 0.001 times [in_us] +[in_br] as 2.539998 times cm +[ft_br] as 12 times [in_br] +[rd_br] as 16.5 times [ft_br] +[ch_br] as 4 times [rd_br] +[lk_br] alias [ch_br]/100 +[fth_br] as 6 times [ft_br] +[pc_br] as 2.5 times [ft_br] +[yd_br] as 3 times [ft_br] +[mi_br] as 5280 times [ft_br] +[nmi_br] as 6080 times [ft_br] +[kn_br] alias [nmi_br]/h +[acr_br] as 4840 times [yd_br]2 +[gal_us] as 231 times [in_i]3 +[bbl_us] as 42 times [gal_us] +[qt_us] alias [gal_us]/4 +[pt_us] alias [qt_us]/2 +[gil_us] alias [pt_us]/4 +[foz_us] alias [gil_us]/4 + prints as: oz fl +[fdr_us] alias [foz_us]/8 +[min_us] alias [fdr_us]/60 +[crd_us] as 128 times [ft_i]3 +[bu_us] as 2150.42 times [in_i]3 +[gal_wi] alias [bu_us]/8 +[pk_us] alias [bu_us]/4 +[dqt_us] alias [pk_us]/8 +[dpt_us] alias [dqt_us]/2 +[tbs_us] alias [foz_us]/2 +[tsp_us] alias [tbs_us]/3 +[cup_us] as 16 times [tbs_us] +[foz_m] as 30 times mL + prints as: oz fl +[cup_m] as 240 times mL +[tsp_m] as 5 times mL +[tbs_m] as 15 times mL +[gal_br] as 4.54609 times l +[pk_br] as 2 times [gal_br] +[bu_br] as 4 times [pk_br] +[qt_br] alias [gal_br]/4 +[pt_br] alias [qt_br]/2 +[gil_br] alias [pt_br]/4 +[foz_br] alias [gil_br]/5 +[fdr_br] alias [foz_br]/8 +[min_br] alias [fdr_br]/60 +[gr] as 64.79891 times mg +[lb_av] as 7000 times [gr] + prints as: lb +[oz_av] alias [lb_av]/16 + prints as: oz +[dr_av] alias [oz_av]/16 +[scwt_av] as 100 times [lb_av] +[lcwt_av] as 112 times [lb_av] +[ston_av] as 20 times [scwt_av] +[lton_av] as 20 times [lcwt_av] +[stone_av] as 14 times [lb_av] +[pwt_tr] as 24 times [gr] +[oz_tr] as 20 times [pwt_tr] +[lb_tr] as 12 times [oz_tr] +[sc_ap] as 20 times [gr] +[dr_ap] as 3 times [sc_ap] +[oz_ap] as 8 times [dr_ap] +[lb_ap] as 12 times [oz_ap] +[oz_m] as 28 times g +[lne] alias [in_i]/12 +[pnt] alias [lne]/6 +[pca] as 12 times [pnt] +[pnt_pr] as 0.013837 times [in_i] +[pca_pr] as 12 times [pnt_pr] +[pied] as 32.48 times cm +[pouce] alias [pied]/12 +[ligne] alias [pouce]/12 +[didot] alias [ligne]/6 +[cicero] as 12 times [didot] +[degF] as value degf(5 K/9) + prints as: °F +[degR] as 5 times K/9 + prints as: °R +[degRe] as value degre(5 K/4) + prints as: °Ré +cal_[15] as 4.18580 times J + prints as: cal15°C +cal_[20] as 4.18190 times J + prints as: cal20°C +cal_m as 4.19002 times J + prints as: calm +cal_IT as 4.1868 times J + prints as: calIT +cal_th as 4.184 times J + prints as: calth +cal alias cal_th + prints as: cal +[Cal] alias kcal_th + prints as: Cal +[Btu_39] as 1.05967 times kJ + prints as: Btu39°F +[Btu_59] as 1.05480 times kJ + prints as: Btu59°F +[Btu_60] as 1.05468 times kJ + prints as: Btu60°F +[Btu_m] as 1.05587 times kJ + prints as: Btum +[Btu_IT] as 1.05505585262 times kJ + prints as: BtuIT +[Btu_th] as 1.054350 times kJ + prints as: Btuth +[Btu] alias [Btu_th] + prints as: btu +[HP] as 550 times [ft_i].[lbf_av]/s +tex alias g/km + prints as: tex +[den] alias g/9/km + prints as: den +m[H2O] as 9.80665 times kPa + prints as: m H2O +m[Hg] as 133.3220 times kPa + prints as: m Hg +[in_i'H2O] alias m[H2O].[in_i]/m + prints as: in H2O +[in_i'Hg] alias m[Hg].[in_i]/m + prints as: in Hg +[PRU] alias mm[Hg].s/ml + prints as: P.R.U. +[wood'U] alias mm[Hg].min/L + prints as: Wood U. +[diop] alias /m + prints as: dpt +[p'diop] as value 100tan(1 rad) + prints as: PD +%[slope] as value 100tan(1 rad) + prints as: % +[mesh_i] alias /[in_i] +[Ch] alias mm/3 + prints as: Ch +[drp] alias ml/20 + prints as: drp +[hnsf'U] alias 1 + prints as: HF +[MET] as 3.5 times mL/min/kg + prints as: MET +[hp'_X] as value hpX(1 1) + prints as: X +[hp'_C] as value hpC(1 1) + prints as: C +[hp'_M] as value hpM(1 1) + prints as: M +[hp'_Q] as value hpQ(1 1) + prints as: Q +[hp_X] alias 1 + prints as: X +[hp_C] alias 1 + prints as: C +[hp_M] alias 1 + prints as: M +[hp_Q] alias 1 + prints as: Q +[kp_X] alias 1 + prints as: X +[kp_C] alias 1 + prints as: C +[kp_M] alias 1 + prints as: M +[kp_Q] alias 1 + prints as: Q +eq alias mol + prints as: eq +osm alias mol + prints as: osm +[pH] as value pH(1 mol/l) + prints as: pH +g% alias g/dl + prints as: g% +[S] alias 10*-13.s + prints as: S +[HPF] alias 1 + prints as: HPF +[LPF] as 100 times 1 + prints as: LPF +kat alias mol/s + prints as: kat +U alias umol/min + prints as: U +[iU] alias 1 + prints as: IU +[IU] alias [iU] + prints as: i.U. +[arb'U] alias 1 + prints as: arb. U +[USP'U] alias 1 + prints as: U.S.P. +[GPL'U] alias 1 +[MPL'U] alias 1 +[APL'U] alias 1 +[beth'U] alias 1 +[anti'Xa'U] alias 1 +[todd'U] alias 1 +[dye'U] alias 1 +[smgy'U] alias 1 +[bdsk'U] alias 1 +[ka'U] alias 1 +[knk'U] alias 1 +[mclg'U] alias 1 +[tb'U] alias 1 +[CCID_50] alias 1 + prints as: CCID50 +[TCID_50] alias 1 + prints as: TCID50 +[EID_50] alias 1 + prints as: EID50 +[PFU] alias 1 + prints as: PFU +[FFU] alias 1 + prints as: FFU +[CFU] alias 1 + prints as: CFU +[IR] alias 1 + prints as: IR +[BAU] alias 1 + prints as: BAU +[AU] alias 1 + prints as: AU +[Amb'a'1'U] alias 1 + prints as: Amb a 1 U +[PNU] alias 1 + prints as: PNU +[Lf] alias 1 + prints as: Lf +[D'ag'U] alias 1 +[FEU] alias 1 +[ELU] alias 1 +[EU] alias 1 +Np as value ln(1 1) + prints as: Np +B as value lg(1 1) + prints as: B +B[SPL] as value 2lg(2 10*-5.Pa) + prints as: B(SPL) +B[V] as value 2lg(1 V) + prints as: B(V) +B[mV] as value 2lg(1 mV) + prints as: B(mV) +B[uV] as value 2lg(1 uV) + prints as: B(μV) +B[10.nV] as value 2lg(10 nV) + prints as: B(10 nV) +B[W] as value lg(1 W) + prints as: B(W) +B[kW] as value lg(1 kW) + prints as: B(kW) +st alias m3 + prints as: st +Ao as 0.1 times nm + prints as: Å +b as 100 times fm2 + prints as: b +att alias kgf/cm2 + prints as: at +mho alias S + prints as: mho +[psi] alias [lbf_av]/[in_i]2 + prints as: psi +circ as 2 times [pi].rad + prints as: circ +sph as 4 times [pi].sr + prints as: sph +[car_m] as 0.2 times g + prints as: ctm +[car_Au] alias /24 + prints as: ctAu +[smoot] as 67 times [in_i] +[m/s2/Hz^(1/2)] as value sqrt(1 m2/s4/Hz) +bit_s as value ld(1 1) + prints as: bits +bit alias 1 + prints as: bit +By as 8 times bit + prints as: B +Bd alias /s + prints as: Bd diff --git a/examples/ucum/test.sh b/examples/ucum/test.sh index 7a00cb1e..b36d30f7 100755 --- a/examples/ucum/test.sh +++ b/examples/ucum/test.sh @@ -1,12 +1,16 @@ +#!/bin/sh + +. ${PYXB_ROOT}/tests/support.sh + pyxbgen \ -u ucum-essence.xsd \ - -m ucum + -m ucum \ + || fail generating bindings + if [ ! -f ucum-essence.xml ] ; then wget http://unitsofmeasure.org/ucum-essence.xml fi -# This allows this script to run under the autotest environment, where -# output is sent to a file. -export PYTHONIOENCODING='utf-8' - -python showunits.py +python showunits.py > test.out || fail running +cmp test.out test.expected || fail output mismatch +passed diff --git a/examples/unicode_jp/test.sh b/examples/unicode_jp/test.sh index 691c4b74..90f658c4 100755 --- a/examples/unicode_jp/test.sh +++ b/examples/unicode_jp/test.sh @@ -1,9 +1,6 @@ #!/bin/sh -fail () { - echo 1>&2 "${test_name} FAILED: ${@}" - exit 1 -} +. ${PYXB_ROOT}/tests/support.sh # Because this is an OpenGIS application, the OpenGIS bundle must be # made available during binding generation. OpenGIS also depends @@ -27,14 +24,12 @@ opengis bundle directory. EOText fi -# This allows this script to run under the autotest environment, where -# output is sent to a file. -export PYTHONIOENCODING='utf-8' - -rm fgd_gml.* +rm -f fgd_gml.* # A customized pyxbgen is required to do the translation ./pyxbgen_jp \ - --schema-location=data/shift_jis/FGD_GMLSchema.xsd --module=fgd_gml + --schema-location=data/shift_jis/FGD_GMLSchema.xsd --module=fgd_gml \ + || fail generating bindings # Make sure it worked -python check.py +python check.py || fail check +passed diff --git a/examples/xhtml/test.sh b/examples/xhtml/test.sh index 59507151..d666903b 100755 --- a/examples/xhtml/test.sh +++ b/examples/xhtml/test.sh @@ -1,20 +1,17 @@ -TEST_URI=http://www.w3.org/People/mimasa/test/xhtml/media-types/test.xhtml +#!/bin/sh -aout="${0}" +. ${PYXB_ROOT}/tests/support.sh -fail () { - echo 1>&2 "${aout} FAILED: ${@}" - exit 1 -} +TEST_URI=http://www.w3.org/People/mimasa/test/xhtml/media-types/test.xhtml if [ ! -f in.xhtml ] ; then - wget -O in.xhtml ${TEST_URI} || fail Unable to retrieve test document + wget -O in.xhtml ${TEST_URI} || fail retrieving document fi -python rewrite.py || fail Unable to rewrite test document +python rewrite.py || fail rewriting document xmllint --format in.xhtml > inf.xhtml xmllint --format out.xhtml > outf.xhtml -diff -uw inf.xhtml outf.xhtml > deltas +diff -uw inf.xhtml outf.xhtml > deltas || true # Need to manually validate that outf.xhtml and in.xhtml are about the # same. The rewrite does not preserve the order of attributes in the @@ -23,8 +20,5 @@ echo "See deltas for differences" # Test most primitive generation of documents rm -f genout.xhtml -python generate.py \ - && diff expout.xhtml genout.xhtml \ - || fail generate did not match expected - -echo "Passed XHTML tests" +python generate.py > genout.xhtml || fail running +passed diff --git a/examples/xsdprimer/demo.expected b/examples/xsdprimer/demo.expected new file mode 100644 index 00000000..ad21113e --- /dev/null +++ b/examples/xsdprimer/demo.expected @@ -0,0 +1,4 @@ +Robert Smith is sending Mary Jones 1 thing(s): + Quantity 1 of Lapis necklace at $99.95 +Too many: Type maxExclusive constraint violated by value 100 +Increased quantity to 10 diff --git a/examples/xsdprimer/demo.py b/examples/xsdprimer/demo.py index 34e5f519..6c018156 100644 --- a/examples/xsdprimer/demo.py +++ b/examples/xsdprimer/demo.py @@ -9,14 +9,14 @@ order = ipo.CreateFromDOM(xml.dom.minidom.parse(io.BytesIO(xmld)).documentElement) -print('%s is sending %s %d thing(s):' % (order.billTo().name(), order.shipTo().name(), len(order.items().item()))) -for item in order.items().item(): - print(' Quantity %d of%s at $%s' % (item.quantity(), item.productName(), item.USPrice())) +print('%s is sending %s %d thing(s):' % (order.billTo.name, order.shipTo.name, len(order.items.item))) +for item in order.items.item: + print(' Quantity %d of %s at $%s' % (item.quantity, item.productName, item.USPrice)) # Give Mary more try: - item.setQuantity(100) + item.quantity = 100; except pyxb.SimpleTypeValueError as e: print('Too many: %s' % (e,)) - item.setQuantity(10) -print('Increased quantity to %d' % (item.quantity(),)) + item.quantity = 10; +print('Increased quantity to %d' % (item.quantity,)) diff --git a/examples/xsdprimer/ipo.py b/examples/xsdprimer/ipo.py index bfb82a21..0b5fe5ea 100644 --- a/examples/xsdprimer/ipo.py +++ b/examples/xsdprimer/ipo.py @@ -10,6 +10,6 @@ class USAddress (raw_ipo.USAddress): def __str__ (self): return six.u('''%s %s -%s %s, %s''') % (self.name(), self.street(), self.city(), self.state(), self.zip()) +%s %s, %s''') % (self.name, self.street, self.city, self.state, self.zip) pass raw_ipo.USAddress._SetSupersedingClass(USAddress) diff --git a/examples/xsdprimer/saxdemo.py b/examples/xsdprimer/saxdemo.py index dfe4e8c2..e5b156ae 100644 --- a/examples/xsdprimer/saxdemo.py +++ b/examples/xsdprimer/saxdemo.py @@ -5,9 +5,9 @@ import ipo def ShowOrder (order): - print('%s is sending %s %d thing(s):' % (order.billTo().name(), order.shipTo().name(), len(order.items().item()))) - for item in order.items().item(): - print(' Quantity %d of %s at $%s' % (item.quantity(), item.productName(), item.USPrice())) + print('%s is sending %s %d thing(s):' % (order.billTo.name, order.shipTo.name, len(order.items.item))) + for item in order.items.item: + print(' Quantity %d of %s at $%s' % (item.quantity, item.productName, item.USPrice)) if False: import pyxb.utils.domutils diff --git a/examples/xsdprimer/test.sh b/examples/xsdprimer/test.sh new file mode 100755 index 00000000..4392cb9e --- /dev/null +++ b/examples/xsdprimer/test.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +. ${PYXB_ROOT}/tests/support.sh + +sh genbindings.sh || fail generating bindings +python demo.py > demo.out || fail running demo +cmp demo.out demo.expected || fail demo output mismatch + +passed From e728a6e362cccf3b6f5b0757cb93b4d88253fe03 Mon Sep 17 00:00:00 2001 From: "Peter A. Bigot" Date: Sat, 13 May 2017 03:59:52 -0500 Subject: [PATCH 08/41] examples/manual: integrate into test suite Closes #61 --- doc/userref_pyxbgen.txt | 4 +- examples/manual/badcontent.expected | 6 +++ examples/manual/demo.expected | 3 ++ examples/manual/{demo3c.sh => demo3c1.sh} | 0 examples/manual/{demo3d.sh => demo3c2.sh} | 0 examples/manual/demo4.expected | 1 + examples/manual/demo4a1.expected | 18 +++++++ examples/manual/demo4a1.out | 18 ------- examples/manual/demo4c.expected | 17 ++++++ examples/manual/demo4c1.expected | 29 ++++++++++ examples/manual/demo4c2.expected | 32 +++++++++++ examples/manual/demo4c3.expected | 32 +++++++++++ examples/manual/test.sh | 65 +++++++++++++++++++++++ 13 files changed, 205 insertions(+), 20 deletions(-) create mode 100644 examples/manual/badcontent.expected create mode 100644 examples/manual/demo.expected rename examples/manual/{demo3c.sh => demo3c1.sh} (100%) rename examples/manual/{demo3d.sh => demo3c2.sh} (100%) create mode 100644 examples/manual/demo4.expected create mode 100644 examples/manual/demo4a1.expected create mode 100644 examples/manual/demo4c.expected create mode 100644 examples/manual/demo4c1.expected create mode 100644 examples/manual/demo4c2.expected create mode 100644 examples/manual/demo4c3.expected create mode 100755 examples/manual/test.sh diff --git a/doc/userref_pyxbgen.txt b/doc/userref_pyxbgen.txt index d688b0cf..f33f632f 100644 --- a/doc/userref_pyxbgen.txt +++ b/doc/userref_pyxbgen.txt @@ -150,7 +150,7 @@ namespace, so they can be referenced in independent generation activities. To generate the archive, you add the :ref:`pyxbgen--archive-to-file` flag to the binding generation command: -.. literalinclude:: ../examples/manual/demo3c.sh +.. literalinclude:: ../examples/manual/demo3c1.sh In addition to generating the ``address`` Python module, this causes a :ref:`archive ` of the schema contents to be saved in the @@ -161,7 +161,7 @@ in this archive, so that cross-namespace extension works correctly. You can then generate bindings for importing namespaces by providing PyXB with the information necessary to locate this archive: -.. literalinclude:: ../examples/manual/demo3d.sh +.. literalinclude:: ../examples/manual/demo3c2.sh The :ref:`pyxbgen--archive-path` directive indicates that the current directory (``.``) should be searched for files that end in ``.wxs``, and any diff --git a/examples/manual/badcontent.expected b/examples/manual/badcontent.expected new file mode 100644 index 00000000..4ad65c6d --- /dev/null +++ b/examples/manual/badcontent.expected @@ -0,0 +1,6 @@ +The containing element shipTo is defined at po1.xsd[6:6]. +The containing element type USAddress is defined at po1.xsd[13:2] +The unrecognized content streeet begins at badcontent.xml[5:4] +The USAddress automaton is not in an accepting state. +The following element and wildcard content would be accepted: + An element street per po1.xsd[16:6] diff --git a/examples/manual/demo.expected b/examples/manual/demo.expected new file mode 100644 index 00000000..2aa8a409 --- /dev/null +++ b/examples/manual/demo.expected @@ -0,0 +1,3 @@ +Robert Smith is sending Alice Smith 2 thing(s): + Quantity 1 of Lapis necklace at $99.95 + Quantity 4 of Plastic necklace at $3.95 diff --git a/examples/manual/demo3c.sh b/examples/manual/demo3c1.sh similarity index 100% rename from examples/manual/demo3c.sh rename to examples/manual/demo3c1.sh diff --git a/examples/manual/demo3d.sh b/examples/manual/demo3c2.sh similarity index 100% rename from examples/manual/demo3d.sh rename to examples/manual/demo3c2.sh diff --git a/examples/manual/demo4.expected b/examples/manual/demo4.expected new file mode 100644 index 00000000..6eb0d259 --- /dev/null +++ b/examples/manual/demo4.expected @@ -0,0 +1 @@ +Robert Smith8 Oak AvenueAnytownAK12341 diff --git a/examples/manual/demo4a1.expected b/examples/manual/demo4a1.expected new file mode 100644 index 00000000..eff929dc --- /dev/null +++ b/examples/manual/demo4a1.expected @@ -0,0 +1,18 @@ +Traceback (most recent call last): + File "demo4a1.py", line #, in + addr.state = 'NY' + File "/mnt/devel/pyxb/pyxb/binding/basis.py", line #, in __setattr__ + return super(_TypeBinding_mixin, self).__setattr__(name, value) + File "/mnt/devel/pyxb/pyxb/binding/content.py", line #, in set + value = self.__elementBinding.compatibleValue(value, is_plural=self.isPlural()) + File "/mnt/devel/pyxb/pyxb/binding/basis.py", line #, in compatibleValue + return self.typeDefinition()._CompatibleValue(value, **kw) + File "/mnt/devel/pyxb/pyxb/binding/basis.py", line #, in _CompatibleValue + return cls(value) + File "/mnt/devel/pyxb/pyxb/binding/basis.py", line #, in __init__ + self.xsdConstraintsOK(location) + File "/mnt/devel/pyxb/pyxb/binding/basis.py", line #, in xsdConstraintsOK + return self.XsdConstraintsOK(self, location) + File "/mnt/devel/pyxb/pyxb/binding/basis.py", line #, in XsdConstraintsOK + raise pyxb.SimpleFacetValueError(cls, value, f, location) +pyxb.exceptions_.SimpleFacetValueError: Type {URN:address}USState enumeration constraint violated by value NY diff --git a/examples/manual/demo4a1.out b/examples/manual/demo4a1.out index a68f10ab..e69de29b 100644 --- a/examples/manual/demo4a1.out +++ b/examples/manual/demo4a1.out @@ -1,18 +0,0 @@ -Traceback (most recent call last): - File "demo4a1.py", line 8, in - addr.state = 'NY' - File "/opt/pyxb/pyxb/binding/basis.py", line 100, in __setattr__ - return super(_TypeBinding_mixin, self).__setattr__(name, value) - File "/opt/pyxb/pyxb/binding/content.py", line 1037, in set - value = self.__elementBinding.compatibleValue(value, is_plural=self.isPlural()) - File "/opt/pyxb/pyxb/binding/basis.py", line 1623, in compatibleValue - return self.typeDefinition()._CompatibleValue(value, **kw) - File "/opt/pyxb/pyxb/binding/basis.py", line 373, in _CompatibleValue - return cls(value) - File "/opt/pyxb/pyxb/binding/basis.py", line 924, in __init__ - self.xsdConstraintsOK(location) - File "/opt/pyxb/pyxb/binding/basis.py", line 1050, in xsdConstraintsOK - return self.XsdConstraintsOK(self, location) - File "/opt/pyxb/pyxb/binding/basis.py", line 1045, in XsdConstraintsOK - raise pyxb.SimpleFacetValueError(cls, value, f, location) -pyxb.exceptions_.SimpleFacetValueError: Type {URN:address}USState enumeration constraint violated by value NY diff --git a/examples/manual/demo4c.expected b/examples/manual/demo4c.expected new file mode 100644 index 00000000..cf270b5d --- /dev/null +++ b/examples/manual/demo4c.expected @@ -0,0 +1,17 @@ + + + + Anytown + AK + 8 Oak Avenue + Robert Smith + 12341 + + + Anytown + AK + 123 Maple Street + Alice Smith + 12341 + + diff --git a/examples/manual/demo4c1.expected b/examples/manual/demo4c1.expected new file mode 100644 index 00000000..0938dad7 --- /dev/null +++ b/examples/manual/demo4c1.expected @@ -0,0 +1,29 @@ + + + + Alice Smith + 123 Maple Street + Anytown + AK + 12341 + + + Robert Smith + 8 Oak Avenue + Anytown + AK + 12341 + + + + Lapis necklace + 1 + 99.95 + + + Plastic necklace + 4 + 3.95 + + + diff --git a/examples/manual/demo4c2.expected b/examples/manual/demo4c2.expected new file mode 100644 index 00000000..2f918053 --- /dev/null +++ b/examples/manual/demo4c2.expected @@ -0,0 +1,32 @@ + + + + Alice Smith + 123 Maple Street + Anytown + AK + 12341 + + + Robert Smith + 8 Oak Avenue + Anytown + AK + 12341 + + + + Lapis necklace + 1 + 99.95 + Want this for the holidays! + 1999-12-05 + + + Plastic necklace + 4 + 3.95 + 1999-12-24 + + + diff --git a/examples/manual/demo4c3.expected b/examples/manual/demo4c3.expected new file mode 100644 index 00000000..23af5d71 --- /dev/null +++ b/examples/manual/demo4c3.expected @@ -0,0 +1,32 @@ + + + + Alice Smith + 123 Maple Street + Anytown + AK + 12341 + + + Robert Smith + 8 Oak Avenue + Anytown + AK + 12341 + + + + Lapis necklace + 1 + 99.95 + Want this for the holidays! + 1999-12-05 + + + Plastic necklace + 4 + 3.95 + 1999-12-24 + + + diff --git a/examples/manual/test.sh b/examples/manual/test.sh new file mode 100755 index 00000000..1c81c93e --- /dev/null +++ b/examples/manual/test.sh @@ -0,0 +1,65 @@ +#!/bin/sh + +. ${PYXB_ROOT}/tests/support.sh + +rm -f *.wxs po?.py *.pyc + +sh demo1.sh || fail building demo1 +python demo1.py > demo1.out || fail running demo1 +cat demo1.out +cmp demo1.out demo.expected || fail demo1 output check + +sh demo2.sh || fail building demo2 +python demo2.py > demo2.out || fail running demo2 +cat demo2.out +cmp demo2.out demo.expected || fail demo2 output check + +sh demo3a.sh || fail building demo3a +python demo3.py > demo3a.out || fail running demo3a +cat demo3a.out +cmp demo3a.out demo.expected || fail demo3a output check + +sh demo3b.sh || fail building demo3b +python demo3.py > demo3b.out || fail running demo3 variant b +cat demo3b.out +cmp demo3b.out demo.expected || fail demo3b output check + +sh demo3c1.sh || fail building demo3c1 +sh demo3c2.sh || fail building demo3c2 +python demo3.py > demo3c.out || fail running demo3c +cat demo3c.out +cmp demo3c.out demo.expected || fail demo3c output check + +sh demo4.sh || fail building demo4 + +python demo4a.py > demo4a.out || fail running demo4a +cat demo4a.out +cmp demo4a.out demo4.expected || fail demo4a output check + +# This one displays an error which we capture and verify +python demo4a1.py 2>demo4a1.err 1>demo4a1.out || true +test -s demo4a1.out && fail demo4a1 stdout check +# Do output comparison without checking line numbers in trace +cat demo4a1.err \ + | sed -r -e 's@line [0-9]+@line #@' \ + > demo4a1.errc +cmp demo4a1.errc demo4a1.expected || fail demo4a1 error check + +python demo4a2.py > demo4a2.out || fail running demo4a2 +cat demo4a2.out +cmp demo4a2.out demo4.expected || fail demo4a2 output check + +sh demo4b.sh || fail building demo4b +python demo4b.py > demo4b.out || fail running demo4b +cat demo4b.out +cmp demo4b.out demo4.expected || fail demo4b output check + +for dc in 4c 4c1 4c2 4c3 ; do + python demo${dc}.py | xmllint --format - > demo${dc}.out + cmp demo${dc}.out demo${dc}.expected || fail demo${dc} output check +done +python badcontent.py > badcontent.out || fail running badcontent +cat badcontent.out +cmp badcontent.out badcontent.expected || fail badcontent output check + +passed From a8f5097e069923669ec0c65ffe59dfdb9a3965cf Mon Sep 17 00:00:00 2001 From: "Peter A. Bigot" Date: Sat, 13 May 2017 04:26:48 -0500 Subject: [PATCH 09/41] binding/generate: update documentation for --schema-stripped-prefix When issue #39 was closed the generated help content was updated without changing the original description. --- pyxb/binding/generate.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/pyxb/binding/generate.py b/pyxb/binding/generate.py index cb44b822..c8e9f69d 100644 --- a/pyxb/binding/generate.py +++ b/pyxb/binding/generate.py @@ -1932,13 +1932,9 @@ def setSchemaRoot (self, schema_root): def schemaStrippedPrefix (self): """Optional string that is stripped from the beginning of - schemaLocation values before loading from them. - - This applies only to the values of schemaLocation attributes - in C{import} and C{include} elements. Its purpose is to - convert absolute schema locations into relative ones to allow - offline processing when all schema are available in a local - directory. See C{schemaRoot}. + schemaLocation values before loading from them. This now + applies only to URIs specified on the command line so is + unlikely to be useful. """ return self.__schemaStrippedPrefix def setSchemaStrippedPrefix (self, schema_stripped_prefix): @@ -1977,7 +1973,15 @@ def argAddLocationPrefixRewrite (self, prefix_rewrite): Parameter values are strings of the form C{pfx=sub}. The effect is that a schema location that begins with C{pfx} is - rewritten so that it instead begins with C{sub}.""" + rewritten so that it instead begins with C{sub}. + + This applies to schemaLocation attributes in C{import} and + C{include} elements. It may be used to convert absolute + schema locations into relative ones to allow offline + processing when all schema are available in a local + directory. See C{schemaRoot}. + """ + try: (prefix, substituent) = prefix_rewrite.split('=', 1) except: From 6e3151dda15e1cf63414e5a08298c2c66436a7af Mon Sep 17 00:00:00 2001 From: "Peter A. Bigot" Date: Sat, 13 May 2017 06:40:52 -0500 Subject: [PATCH 10/41] docs: remove unreferenced file --- doc/hierarchy.rst | 49 ----------------------------------------------- 1 file changed, 49 deletions(-) delete mode 100644 doc/hierarchy.rst diff --git a/doc/hierarchy.rst b/doc/hierarchy.rst deleted file mode 100644 index 06e21b0f..00000000 --- a/doc/hierarchy.rst +++ /dev/null @@ -1,49 +0,0 @@ -##### -Parts -##### - -******** -Chapters -******** - -Sections -======== - -Subsections ------------ - -SubSubsections -^^^^^^^^^^^^^^ - -Paragraphs -"""""""""" - -================================================== - -Overview - What it is - How to use it - Capabilities and Limitations - References - Original vision -Examples - Dictionary (Aonaware) - Simple Weather (CDyne) - Professional Weather (National Digital Forecast Data) - Television Schedules (Tribune Media Services) -Architecture - Conceptual Models - Component Model - Binding Model - Content Model - Binding Generation -User Reference - Creating bindings with genbind - Self-contained schema - Multi-document schema - Saving pre-processed namespaces - Standard bindings - WSDL -Maintainer Reference - API - Coding practices From 3202497aa64d311069a361452e8cca230d223086 Mon Sep 17 00:00:00 2001 From: "Peter A. Bigot" Date: Sat, 13 May 2017 07:08:06 -0500 Subject: [PATCH 11/41] doc/Makefile: strip gratuitous trailing newline from generated file --- doc/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/Makefile b/doc/Makefile index 2b1b3fd3..43fe8abf 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -36,7 +36,7 @@ apihtml: pyxbgen_cli.txt: ../pyxb/binding/generate.py ../maintainer/gendoc PYTHONPATH=.. ../maintainer/gendoc \ - | sed -e 's@ *$$@@' \ + | sed -e 's@ *$$@@' -e '$${/^$$/d;}' \ > $@ GENERATED_TXT += pyxbgen_cli.txt From 69be38abacdb3494cd8bde08f0f0f4ecb295ec67 Mon Sep 17 00:00:00 2001 From: "Peter A. Bigot" Date: Sat, 13 May 2017 07:35:10 -0500 Subject: [PATCH 12/41] doc/extapi: remove GPL material http://git.savannah.gnu.org/cgit/kenozooid.git/tree/doc/extapi.py was originally adopted to link from sphinx to to epydoc-generated documentation. epydoc was last updated over nine years ago, so it's dead. A downstream packager noticed that the imported material was GPL, being the only part of PyXB so licensed and conflicting with the intended Apache 2.0 license. Remove the material that came from the original file, leaving only the ticket-related roles that were subsequently added for PyXB support. Mark that material as Apache 2.0. Closes #77. --- doc/extapi.py | 120 +++++--------------------------------------------- 1 file changed, 11 insertions(+), 109 deletions(-) diff --git a/doc/extapi.py b/doc/extapi.py index 09d46763..f26db9c0 100644 --- a/doc/extapi.py +++ b/doc/extapi.py @@ -1,22 +1,17 @@ -# Kenozooid - software stack to support different capabilities of dive -# computers. +# -*- coding: utf-8 -*- +# Copyright 2009-2017, Peter A. Bigot # -# Copyright (C) 2009 by Artur Wroblewski <wrobell@pld-linux.org> +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain a +# copy of the License at: # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +# http://www.apache.org/licenses/LICENSE-2.0 # -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. -# -# Modifications by PAB to override reference text +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. from __future__ import print_function import os.path @@ -26,74 +21,6 @@ __Reference_re = re.compile('\s*(.*)\s+<(.*)>\s*$', re.MULTILINE + re.DOTALL) -def api_role(role, rawtext, text, lineno, inliner, options={}, content=[]): - """ - Role `:api:` bridges generated API documentation by tool like EpyDoc - with Sphinx Python Documentation Generator. - - Other tools, other than EpyDoc, can be easily supported as well. - - First generate the documentation to be referenced, i.e. with EpyDoc:: - - $ mkdir -p doc/html/api - $ epydoc -o doc/html/api ... - - Next step is to generate documentation with Sphinx:: - - $ sphinx-build doc doc/html - - """ - basedir = 'api' - prefix = 'html/' # fixme: fetch it from configuration - exists = lambda f: os.path.exists(prefix + f) - - # assume module is references - - #print 'Text "%s"' % (text,) - mo = __Reference_re.match(text) - label = None - if mo is not None: - ( label, text ) = mo.group(1, 2) - name = text.strip() - - uri = file = '%s/%s-module.html' % (basedir, text) - chunks = text.split('.') - - #print 'Trying module file %s' % (file,) - - # if not module, then a class - if not exists(file): - name = text.split('.')[-1] - uri = file = '%s/%s-class.html' % (basedir, text) - #print 'Trying class file %s' % (file,) - - # if not a class, then function or class method - if not exists(file): - method = chunks[-1] - fprefix = '.'.join(chunks[:-1]) - # assume function is referenced - file = '%s/%s-module.html' % (basedir, fprefix) - #print 'Trying method file %s' % (file,) - if exists(file): - uri = '%s#%s' % (file, method) - else: - # class method is references - file = '%s/%s-class.html' % (basedir, fprefix) - if exists(file): - name = '.'.join(chunks[-2:]) # name should be Class.method - uri = '%s/%s-class.html#%s' % (basedir, fprefix, method) - - if label is None: - label = name - if exists(file): - node = nodes.reference(rawtext, label, refuri=uri, **options) - else: - # cannot find reference, then just inline the text - print('WARNING: Unable to find %s in API' % (text,)) - node = nodes.literal(rawtext, text) - - return [node], [] - def ticket_role(role, rawtext, text, lineno, inliner, options={}, content=[]): """ Role `:ticket:` generates references to SourceForge tickets. @@ -137,31 +64,6 @@ def issue_role(role, rawtext, text, lineno, inliner, options={}, content=[]): return [node], [] - -def pyex_role(role, rawtext, text, lineno, inliner, options={}, content=[]): - """ - Role `:pyex:` generates reference to Python exception classes. - """ - - pyex_fmt = 'http://docs.python.org/library/exceptions.html#exceptions.%s' - mo = __Reference_re.match(text) - label = None - if mo is not None: - ( label, text ) = mo.group(1, 2) - exc = text.strip() - print('Python exception %s as %s' % (text, label)) - - uri = pyex_fmt % (exc,) - if label is None: - label = '%s' % (exc,) - node = nodes.reference(rawtext, label, refuri=uri, **options) - - return [node], [] - def setup(app): - app.add_role('api', api_role) - app.add_config_value('epydoc_basedir', 'api', False) - app.add_config_value('epydoc_prefix', 'doc/html/', False) app.add_role('ticket', ticket_role) app.add_role('issue', issue_role) - app.add_role('pyex', pyex_role) From e314377f82f4bd68208a58a84529d05914782992 Mon Sep 17 00:00:00 2001 From: "Peter A. Bigot" Date: Sat, 13 May 2017 07:47:33 -0500 Subject: [PATCH 13/41] doc: replace epydoc with sphinx plus sphinx-epytext Start with: sphinx-apidoc -o . ../pyxb Remove all the references to pyxb.bundles and rename the remaining .rst files to .txt. Run: sed -i -e 's@:api:@:py:obj:@g' *.txt to eliminate the old api role usage. Strip epydoc references out of the Makefile. sphinx-epytext fails to convert B{} directives and mis-handles L{} and U{} directives that span lines. It also doesn't support @group. Still, it's good enough for now. --- doc/Makefile | 10 +--- doc/arch_binding.txt | 83 +++++++++++++++--------------- doc/arch_component.txt | 20 ++++---- doc/arch_content.txt | 76 +++++++++++++-------------- doc/arch_namespaces.txt | 44 ++++++++-------- doc/conf.py | 10 +++- doc/conf.py.in | 10 +++- doc/index.txt | 1 + doc/limitations.txt | 4 +- doc/maintref.txt | 29 +++++------ doc/pyxb.binding.txt | 70 +++++++++++++++++++++++++ doc/pyxb.namespace.txt | 46 +++++++++++++++++ doc/pyxb.txt | 34 +++++++++++++ doc/pyxb.utils.txt | 102 +++++++++++++++++++++++++++++++++++++ doc/pyxb.xmlschema.txt | 22 ++++++++ doc/releases.txt | 12 ++--- doc/userref_pyxbgen.txt | 6 +-- doc/userref_usebind.txt | 48 ++++++++--------- doc/userref_validating.txt | 6 +-- 19 files changed, 455 insertions(+), 178 deletions(-) create mode 100644 doc/pyxb.binding.txt create mode 100644 doc/pyxb.namespace.txt create mode 100644 doc/pyxb.txt create mode 100644 doc/pyxb.utils.txt create mode 100644 doc/pyxb.xmlschema.txt diff --git a/doc/Makefile b/doc/Makefile index 43fe8abf..da686f7e 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -6,16 +6,12 @@ SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = -EPYDOC = epydoc -EPYDOCOPTS = --config documentation.cfg - # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d _build/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest -.PHONY: apihtml help: @echo "Please use \`make ' where is one of" @@ -30,10 +26,6 @@ help: @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" -apihtml: - mkdir -p html/api - PYTHONPATH=.. $(EPYDOC) $(EPYDOCOPTS) - pyxbgen_cli.txt: ../pyxb/binding/generate.py ../maintainer/gendoc PYTHONPATH=.. ../maintainer/gendoc \ | sed -e 's@ *$$@@' -e '$${/^$$/d;}' \ @@ -42,7 +34,7 @@ pyxbgen_cli.txt: ../pyxb/binding/generate.py ../maintainer/gendoc GENERATED_TXT += pyxbgen_cli.txt html: $(GENERATED_TXT) - PYTHONPATH=. $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) html + PYTHONPATH=.:.. $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) html @echo @echo "Build finished. The HTML pages are in _build/html." diff --git a/doc/arch_binding.txt b/doc/arch_binding.txt index 7eeff030..77bd404c 100644 --- a/doc/arch_binding.txt +++ b/doc/arch_binding.txt @@ -19,27 +19,27 @@ Supporting Capabilities Common Binding Instance Features ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -:api:`pyxb.binding.basis._TypeBinding_mixin` is a marker class to indicate +:py:obj:`pyxb.binding.basis._TypeBinding_mixin` is a marker class to indicate that the incorporating class represents a binding associated with a type definition (whether simple or complex). The key features of this mixin are: - - The :api:`_ExpandedName + - The :py:obj:`_ExpandedName ` class variable is overridden in each class to identify the type definition corresponding to the class. - - The :api:`_XSDLocation + - The :py:obj:`_XSDLocation ` class variable is overridden in each class to provide the line, column, and schema at which the data type definition was found. This is used in diagnostics. - - The :api:`namespace context + - The :py:obj:`namespace context ` of the type definition is recorded to allow users to perform QName resolution of values within instance documents (see, for example, the customized bindings in ``pyxb.bundles.wssplat.wsdl11``). - - Each instance records the :api:`pyxb.binding.basis.element` instance that + - Each instance records the :py:obj:`pyxb.binding.basis.element` instance that determines where the type came from. The element is required in order to provide the correct name when converting the binding instance to a DOM instance on its way to expression as a text XML document. @@ -48,7 +48,7 @@ definition (whether simple or complex). The key features of this mixin are: `_ information for the instance is stored. - - A :api:`Factory ` infrastructure is + - A :py:obj:`Factory ` infrastructure is provided to allow creation of new instances of the binding while permitting developers to customize the generated binding classes; see :ref:`binding_customization`. @@ -70,38 +70,38 @@ their XML name, the chances of conflict are high. PyXB resolves this by ensuring every identifiable object has a unique identifier within its context. The steps involved are: -#. Make object name into an :api:`identifier +#. Make object name into an :py:obj:`identifier ` by stripping out non-printable characters, replacing characters that cannot appear in identifiers with underscores, stripping leading underscores, and prefixing an initial digit with the character ``n``. -#. :api:`Deconflict ` the resulting - identifier from Python :api:`reserved identifiers +#. :py:obj:`Deconflict ` the resulting + identifier from Python :py:obj:`reserved identifiers ` and other context-specific keywords. #. Prepend the standard prefix that denotes the identifier's :ref:`visibility ` (public, protected, private) -#. Make the resulting identifier :api:`unique ` +#. Make the resulting identifier :py:obj:`unique ` within its context (containing class or module). These steps are encapsulated into a single function -:api:`pyxb.utils.utility.PrepareIdentifier` which takes parameters that +:py:obj:`pyxb.utils.utility.PrepareIdentifier` which takes parameters that customize the context for the identifier. In addition to name conflicts with namespace-global identifiers appearing directly in the module, conflicts may also appear within a binding class as a result of collision with names from Python keywords, public class names, and public field or method names in the class. The -:api:`pyxb.utils.utility._DeconflictSymbols_mixin` is used to refine the set +:py:obj:`pyxb.utils.utility._DeconflictSymbols_mixin` is used to refine the set of type-specific public names. If you customize a generated binding class by extending from it, you must specify your own class variable ``_ReservedSymbols`` with a value that is the union of your symbols and those -of the superclass(es) (see :api:`pyxb.utils.utility._DeconflictSymbols_mixin` +of the superclass(es) (see :py:obj:`pyxb.utils.utility._DeconflictSymbols_mixin` for details). -Deconfliction of module-level names occurs prior to :api:`code generation +Deconfliction of module-level names occurs prior to :py:obj:`code generation `. Identifiers are deconflicted in favor of higher items on this list: @@ -122,9 +122,9 @@ the generated bindings by adding both functionality and derived content. Maintenance issues require that these extensions exist separately from the automatically-generated binding modules; usability requires that they inherit from the automatically-generated modules. This is supported by the -:api:`pyxb.binding.basis._DynamicCreate_mixin` class. +:py:obj:`pyxb.binding.basis._DynamicCreate_mixin` class. -This class provides a :api:`method +This class provides a :py:obj:`method ` which is used by the generated bindings to create new instances of themselves. The raw bindings are generated into a sub-module with the prefix ``raw``, and the @@ -159,10 +159,10 @@ Simple Type Definitions `Simple type definitions `_ derive from -:api:`pyxb.binding.basis.simpleTypeDefinition` and a standard Python type. +:py:obj:`pyxb.binding.basis.simpleTypeDefinition` and a standard Python type. For simple types that are not derived by list or union, you can construct -instances using the :api:`Factory ` +instances using the :py:obj:`Factory ` method or directly, providing the value as an argument. New instance creation is validated against the `facets `_ recorded in the binding class. @@ -175,7 +175,7 @@ Each class corresponding to a simple type definition has class variables for the `constraining facets `_ that are valid for that class. These variables are named by prefixing the facet name with ``_CF_``, and have a value that is an instance of the -corresponding :api:`facet class `. Where possible, the +corresponding :py:obj:`facet class `. Where possible, the variables are inherited from the parent class; when a simple type is derived by restriction, the restricted class overrides its parent with a new value for the corresponding facet. @@ -199,11 +199,11 @@ Enumeration and pattern constraints maintain a list of the respective acceptable enumeration and pattern values. Facets implement the -:api:`pyxb.binding.facets.ConstrainingFacet.validateConstraint` method, which +:py:obj:`pyxb.binding.facets.ConstrainingFacet.validateConstraint` method, which in turn is invoked by the -:api:`pyxb.binding.basis.simpleTypeDefinition.XsdConstraintsOK` class method +:py:obj:`pyxb.binding.basis.simpleTypeDefinition.XsdConstraintsOK` class method when given a value that may or may not satisfy the constraints. The -:api:`Factory ` will normally +:py:obj:`Factory ` will normally validate the constraints before allowing a new instance to be returned. List Types @@ -211,9 +211,9 @@ List Types Simple types that derive by `list `_ extend from -:api:`pyxb.binding.basis.STD_list` which in turn descends from the Python +:py:obj:`pyxb.binding.basis.STD_list` which in turn descends from the Python ``list`` type. These derived classes must override the base class -:api:`pyxb.binding.basis.STD_list._ItemType` value with the appropriate +:py:obj:`pyxb.binding.basis.STD_list._ItemType` value with the appropriate class to use when creating or validating list members. When constructing an instance of a simple list type, you can provide a list as @@ -224,9 +224,9 @@ Union Types ^^^^^^^^^^^ Union types are classes that are never instantiated. Instead, the binding -classes define a :api:`pyxb.binding.basis.STD_union._MemberTypes` variable +classes define a :py:obj:`pyxb.binding.basis.STD_union._MemberTypes` variable which contains a list of binding classes that are permitted as members of the -union. The :api:`pyxb.binding.basis.STD_union.Factory` method attempts, in +union. The :py:obj:`pyxb.binding.basis.STD_union.Factory` method attempts, in turn, to create an instance of each potential member type using the arguments passed into it. The returned value is the first instance that was successfully created. @@ -236,7 +236,7 @@ member of a union is not recorded in the attribute value. See :ref:`attributeUse`. It is not possible to construct an instance of a union type directly. You -must use the :api:`Factory ` method, +must use the :py:obj:`Factory ` method, with an argument that is acceptable as an initializer for one of the member types. @@ -246,24 +246,24 @@ Complex Type Definitions `Complex type definitions `_ derive from -:api:`pyxb.binding.basis.complexTypeDefinition`. Classes representing complex -type definitions record maps that specify :api:`attribute -` and :api:`element +:py:obj:`pyxb.binding.basis.complexTypeDefinition`. Classes representing complex +type definitions record maps that specify :py:obj:`attribute +` and :py:obj:`element ` use structures to record the attributes and elements that comprise the type. Each such structure is stored as a private class field and is used by Python properties to provide access to element and attribute values in a binding instance. -The base :api:`pyxb.binding.basis.complexTypeDefinition` class provides the +The base :py:obj:`pyxb.binding.basis.complexTypeDefinition` class provides the infrastructure to identify the appropriate attribute or element given an XML tag name. For classes corresponding to types that enable `wildcards `_, it also provides a mechanism -to access unrecognized elements and attributes. :api:`Wildcard elements +to access unrecognized elements and attributes. :py:obj:`Wildcard elements ` are converted to binding instances if their namespace and name are recognized, and otherwise -are left as DOM nodes. :api:`Wildcard attributes +are left as DOM nodes. :py:obj:`Wildcard attributes ` are stored in -a map from their :api:`expanded name ` to the +a map from their :py:obj:`expanded name ` to the unicode value of the attribute. When creating a complex type definition, you can provide the values for its @@ -301,8 +301,8 @@ Simple Content Complex types with simple content (i.e., those in which the body of the element is an octet sequence in the lexical space of a specified simple type) are distinguished by providing a value for the class-level -:api:`pyxb.binding.basis.complexTypeDefinition._TypeDefinition` variable. -For these types, the :api:`pyxb.binding.basis.complexTypeDefinition.content` +:py:obj:`pyxb.binding.basis.complexTypeDefinition._TypeDefinition` variable. +For these types, the :py:obj:`pyxb.binding.basis.complexTypeDefinition.content` method returns the instance of that type that corresponds to the content of the object. @@ -335,17 +335,16 @@ was not necessary for ``v.simple`` or ``v.attribute``. Mixed and Element-Only Content ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -`Mixed and element-only content -`_ nodes use the :api:` -` method +`Mixed and element-only content `_ nodes +use the :py:obj:`pyxb.binding.basis.complexTypeDefinition._ElementBindingDeclForName` method to manage the mapping from XML schema element names to class members. The element and attribute names are distinct. Instances of complex types also -reference a :api:`content automaton +reference a :py:obj:`content automaton ` to ensure the constraints of the schema are satisfied. These structures are described in :ref:`contentModel`. -For these types, the :api:`pyxb.binding.basis.complexTypeDefinition.content` +For these types, the :py:obj:`pyxb.binding.basis.complexTypeDefinition.content` method returns a list, in parsed order, of the Python objects and (if mixed) non-element content that belong to the instance. Be aware that this order currently does not influence the order of elements when converting bindings @@ -356,7 +355,7 @@ Elements Unlike the bindings for schema type definitions, which are represented as Python classes, bindings corresponding to XML Schema element declarations are -represented as instances of the :api:`pyxb.binding.basis.element` class. The +represented as instances of the :py:obj:`pyxb.binding.basis.element` class. The instances can be used to create new binding instances that are associated with the element. Elements are used in the content model to identify transitions through a finite automaton. diff --git a/doc/arch_component.txt b/doc/arch_component.txt index cee19eb2..ea87bae5 100644 --- a/doc/arch_component.txt +++ b/doc/arch_component.txt @@ -8,7 +8,7 @@ complex relation of data objects. Each object class corresponds to one of the thirteen `XML Schema Components `_, and names of components and their properties follow those definitions. All classes specific to the -component model are found in the :api:`pyxb.xmlschema.structures` module. +component model are found in the :py:obj:`pyxb.xmlschema.structures` module. The relationships amongst components is depicted in the following diagram. Composite aggregation generally denotes ownership and shared aggregation @@ -22,36 +22,36 @@ Component Model Mix-ins A variety of :ref:`mixins` are used to allow common code to be abstracted or to mark objects as having certain capabilities. These mixins are: -- :api:`pyxb.xmlschema.structures._SchemaComponent_mixin` marks the object +- :py:obj:`pyxb.xmlschema.structures._SchemaComponent_mixin` marks the object as being a schema component and holds its - :api:`pyxb.namespace.NamespaceContext`. It also records relations between + :py:obj:`pyxb.namespace.NamespaceContext`. It also records relations between components in a global definition and their clones where those definitions are expanded. -- :api:`pyxb.xmlschema.structures._Singleton_mixin` is used to ensure there is only one instance each +- :py:obj:`pyxb.xmlschema.structures._Singleton_mixin` is used to ensure there is only one instance each of the `simple ur-type `_ and `ur-type `_. It overloads ``__new__`` to ensure that only one instance of the class is ever constructed. -- :api:`pyxb.xmlschema.structures._Annotated_mixin` provides the support for all components that +- :py:obj:`pyxb.xmlschema.structures._Annotated_mixin` provides the support for all components that contain an `annotation `_ as a child element. -- :api:`pyxb.xmlschema.structures._NamedComponent_mixin` supports components +- :py:obj:`pyxb.xmlschema.structures._NamedComponent_mixin` supports components that can be identified by name. This includes the target namespace (which may be anonymous) if the component is global, and the `complex type definition `_ that serves as the component's `scope `_ when it is local. -- :api:`pyxb.xmlschema.structures._ValueConstraint_mixin` provides support +- :py:obj:`pyxb.xmlschema.structures._ValueConstraint_mixin` provides support for components that have `value constraints `_ : that is, provide a default value and optionally require a fixed value. -- :api:`pyxb.xmlschema.structures._ScopedDeclaration_mixin` is used by +- :py:obj:`pyxb.xmlschema.structures._ScopedDeclaration_mixin` is used by `element declarations `_ and `complex type definitions @@ -59,7 +59,7 @@ to mark objects as having certain capabilities. These mixins are: named but only referenceable within a specific `scope `_. -- :api:`pyxb.xmlschema.structures._AttributeWildcard_mixin` provides support +- :py:obj:`pyxb.xmlschema.structures._AttributeWildcard_mixin` provides support for `attribute group definitions `_ and `complex type definitions @@ -72,7 +72,7 @@ Other Information Most of the important information about the component model is best obtained from the `specification `_ or -from the :api:`PyXB component model API `. +from the :py:obj:`PyXB component model API `. Tidbits of other relevant information: - An understanding of :ref:`resolution` is important. diff --git a/doc/arch_content.txt b/doc/arch_content.txt index 16098ee7..328046d9 100644 --- a/doc/arch_content.txt +++ b/doc/arch_content.txt @@ -19,7 +19,7 @@ Associating XML and Python Objects ---------------------------------- Most of the classes involved in the content model are in the -:api:`pyxb.binding.content` module. The relations among these classes are +:py:obj:`pyxb.binding.content` module. The relations among these classes are displayed in the following diagram. .. _cd_contentModel: @@ -34,12 +34,12 @@ distinct names in the Python class corresponding to that type. Use information for each of these is maintained in the type class. This use information comprises: -- the original :api:`name ` of the element/attribute in the XML -- its :api:`deconflicted name ` in Python +- the original :py:obj:`name ` of the element/attribute in the XML +- its :py:obj:`deconflicted name ` in Python - the private name by which the value is stored in the Python instance dictionary Other information is specific to the type of use. The -:api:`pyxb.binding.basis.complexTypeDefinition` retains maps from the +:py:obj:`pyxb.binding.basis.complexTypeDefinition` retains maps from the component's name the attribute use or element use instance corresponding to the component's use. @@ -50,30 +50,30 @@ Attribute Uses The information associated with an `attribute use `_ is recorded in an -:api:`pyxb.binding.content.AttributeUse` instance. This class provides: +:py:obj:`pyxb.binding.content.AttributeUse` instance. This class provides: -- The :api:`name ` of the +- The :py:obj:`name ` of the attribute -- The :api:`default value ` of +- The :py:obj:`default value ` of the attribute -- Whether the attribute value is :api:`fixed ` +- Whether the attribute value is :py:obj:`fixed ` - Whether the `attribute use `_ is - :api:`required ` - or :api:`prohibited ` + :py:obj:`required ` + or :py:obj:`prohibited ` -- The :api:`type ` of the - attribute, as a subclass of :api:`pyxb.binding.basis.simpleTypeDefinition` +- The :py:obj:`type ` of the + attribute, as a subclass of :py:obj:`pyxb.binding.basis.simpleTypeDefinition` -- Methods to :api:`read `, :api:`set - `, and :api:`reset +- Methods to :py:obj:`read `, :py:obj:`set + `, and :py:obj:`reset ` the value of the attribute in a given binding instance. -A :api:`map ` is used +A :py:obj:`map ` is used to map from expanded names to AttributeUse instances. This map is defined within the class definition itself. @@ -85,34 +85,34 @@ Element Uses The element analog to an attribute use is an `element declaration `_, and the corresponding information is stored in a -:api:`pyxb.binding.content.ElementDeclaration` instance. This class provides: +:py:obj:`pyxb.binding.content.ElementDeclaration` instance. This class provides: -- The :api:`element binding ` +- The :py:obj:`element binding ` that defines the properties of the referenced element, including its type -- Whether the use allows :api:`multiple occurrences +- Whether the use allows :py:obj:`multiple occurrences ` -- The :api:`default value ` of +- The :py:obj:`default value ` of the element. Currently this is either C{None} or an empty list, depending - on :api:`pyxb.binding.content.ElementDeclaration.isPlural` + on :py:obj:`pyxb.binding.content.ElementDeclaration.isPlural` -- Methods to :api:`read `, :api:`set - `, :api:`append to +- Methods to :py:obj:`read `, :py:obj:`set + `, :py:obj:`append to ` (only for plural elements), and - :api:`reset ` the value of the + :py:obj:`reset ` the value of the element in a given binding instance -- The :api:`setOrAppend ` method, +- The :py:obj:`setOrAppend ` method, which is most commonly used to provide new content to a value -A :api:`map ` is used to +A :py:obj:`map ` is used to map from expanded names to ElementDeclaration instances. This map is defined within the class definition itself. As mentioned before, when the same element name appears at multiple places within the element content the uses are collapsed into a single attribute on the complex type; thus the map is to -the :api:`ElementDeclaration `, not -the :api:`ElementUse `. +the :py:obj:`ElementDeclaration `, not +the :py:obj:`ElementUse `. .. _validating-content: @@ -132,8 +132,8 @@ without the complexity of the original back-tracking validation solution from :ticket:`incorrect rejection of valid documents <112>` that (rarely) occurred with the greedy algorithm introduced in :ref:`PyXB 1.1.2 `. Conversion to this data structure also enabled the distinction between -:api:`element declaration ` and -:api:`element use ` nodes, allowing +:py:obj:`element declaration ` and +:py:obj:`element use ` nodes, allowing diagnostics to trace back to the element references in context. The data structures for the automaton and the configuration structure @@ -150,7 +150,7 @@ that maintains a distinct sub-automaton for each alternative, requiring a layered approach where executon of an automaton is suspended until the subordinate automaton has accepted and a transition out of it is encountered. -For more information on the implementation, please see the :api:`FAC module +For more information on the implementation, please see the :py:obj:`FAC module `. This module has been written to be independent of PyXB infrastructure, and may be re-used in other code in accordance with the :ref:`PyXB license `. @@ -159,21 +159,21 @@ FAC and the PyXB Content Model ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ As depicted in the :ref:`Content Model class diagram ` each -complex type binding class has a :api:`_Automaton ` +complex type binding class has a :py:obj:`_Automaton ` which encodes the content model of the type as a Finite Automaton with Counters. This representation models the occurrence constraints and sub-element orders, referencing the specific element and wildcard uses as they appear in the schema. Each instance of a complex binding supports an -:api:`AutomatonConfiguration ` +:py:obj:`AutomatonConfiguration ` that is used to validate the binding content against the model. -An :api:`ElementUse ` instance is provided as +An :py:obj:`ElementUse ` instance is provided as the metadata for automaton states that correspond an element declaration in the -schema. Similarly, a :api:`WildcardUse ` +schema. Similarly, a :py:obj:`WildcardUse ` instance is used as the metadata for automaton states that correspond to an instance of the `xs:any `_ wildcard schema component. Validation in the automaton delegates through the -:api:`SymbolMatch_mixin ` interface to see +:py:obj:`SymbolMatch_mixin ` interface to see whether content in the form of a complex type binding instance is conformant to the restrictions on symbols associated with a particular state. @@ -181,13 +181,13 @@ When parsing, a transition taken results in the storage of the consumed symbol into the appropriate element attribute or wildcard list in the binding instance. In many cases, the transition from one state to a next is uniquely determined by the content; as long as this condition holds, the -:api:`AutomatonConfiguration ` -instance retains a single underlying :api:`FAC Configuration +:py:obj:`AutomatonConfiguration ` +instance retains a single underlying :py:obj:`FAC Configuration ` representing the current state. To generate the XML corresponding to a binding instance, the element and wildcard content of the instance are loaded into a Python dictionary, keyed by -the :api:`ElementDeclaration `. +the :py:obj:`ElementDeclaration `. These subordinate elements are appended to a list of child nodes as transitions that recognize them are encountered. As of :ref:`PyXB 1.2.0 ` the first legal transition in the order imposed by the schema is diff --git a/doc/arch_namespaces.txt b/doc/arch_namespaces.txt index 8d807854..e2d4fa81 100644 --- a/doc/arch_namespaces.txt +++ b/doc/arch_namespaces.txt @@ -24,12 +24,12 @@ the same namespace in different instance documents, as in the `dangling type `_ pattern. This diagram shows the class structure of the PyXB namespace infrastructure. -The central object is the :api:`pyxb.namespace.Namespace`. Four mix-in +The central object is the :py:obj:`pyxb.namespace.Namespace`. Four mix-in classes provide implementations of separate namespace functions. -:api:`pyxb.namespace.ExpandedName` is used ubiquitously to pair local names -with their namespaces. :api:`pyxb.namespace.NamedObjectMap` maps names to the objects +:py:obj:`pyxb.namespace.ExpandedName` is used ubiquitously to pair local names +with their namespaces. :py:obj:`pyxb.namespace.NamedObjectMap` maps names to the objects (generally, schema components) for a particular category of object. The -:api:`pyxb.namespace.NamespaceContext` class provides information related to +:py:obj:`pyxb.namespace.NamespaceContext` class provides information related to the use of namespaces in XML documents, including mappings from prefixes to namespaces. @@ -38,7 +38,7 @@ namespaces. Namespace Category Maps ----------------------- -The :api:`pyxb.namespace._NamespaceCategory_mixin` provides support for +The :py:obj:`pyxb.namespace._NamespaceCategory_mixin` provides support for discrete categories of named objects. It allows arbitrary, runtime-identified, groups of objects to be registered in individual dictionaries within the namespace. For example, XML Schema require that type @@ -56,7 +56,7 @@ and portTypes as named objects that can be identified. Namespace Component Associations -------------------------------- -The :api:`pyxb.namespace._NamespaceComponentAssociation_mixin` provides +The :py:obj:`pyxb.namespace._NamespaceComponentAssociation_mixin` provides support for associating schema components with a namespace. Of particular interest is that a namespace can be comprised of components defined from multiple sources (generally, distinct schema documents). In addition, there @@ -81,7 +81,7 @@ within XML elements, usually as values of specific attributes. The ``type`` portion of the attribute declaration above also identifies an object by name, and it must be possible to resolve the named object. The work involved in associating names with schema components is encapsulated in the -:api:`pyxb.namespace.resolution._NamespaceResolution_mixin` class. +:py:obj:`pyxb.namespace.resolution._NamespaceResolution_mixin` class. The following `concepts `_ are important to understand: @@ -100,7 +100,7 @@ important to understand: - The combination of a namespace URI and the local name comprise an `expanded namespace name `_, which is - represented by :api:`pyxb.namespace.ExpandedName`. + represented by :py:obj:`pyxb.namespace.ExpandedName`. - The category within which the local name must be resolved in the namespace is determined through external information, in the above case the fact of @@ -111,12 +111,12 @@ important to understand: pair: resolution; name pair: resolution; object (component) -:api:`pyxb.namespace._NamespaceCategory_mixin` is used to define the set of +:py:obj:`pyxb.namespace._NamespaceCategory_mixin` is used to define the set of categories supported by a namespace and to add named objects to those categories. A name is **resolved** when the object with which it is associated has been identified. Objects are **resolved** when any names on which they depend have been resolved. -:api:`pyxb.namespace.resolution._NamespaceResolution_mixin` provides a mechanism to +:py:obj:`pyxb.namespace.resolution._NamespaceResolution_mixin` provides a mechanism to hold on to names that have been encountered but whose associated objects have not yet been resolved (perhaps because the named object on which they depend has not been defined). @@ -124,16 +124,16 @@ depend has not been defined). Because one named object (e.g., a model group definition) might require resolution of another (e.g., an element reference), resolution is an iterative process, implemented by -:api:`pyxb.namespace.resolution._NamespaceResolution_mixin.resolveDefinitions`, +:py:obj:`pyxb.namespace.resolution._NamespaceResolution_mixin.resolveDefinitions`, and executed when all named objects have been added to the namespace. It -depends on :api:`pyxb.namespace.resolution.NamespaceContext` to identify named +depends on :py:obj:`pyxb.namespace.resolution.NamespaceContext` to identify named objects using the -:api:`pyxb.namespace.resolution.NamespaceContext.interpretQName` method. +:py:obj:`pyxb.namespace.resolution.NamespaceContext.interpretQName` method. Expanded Names -------------- -An :api:`pyxb.namespace.ExpandedName` instance couples a local name with +An :py:obj:`pyxb.namespace.ExpandedName` instance couples a local name with (optionally) a namespace, resulting in a QName. This class also integrates with namespace categories, permitting lookup of the object with its name in a specific category by using the category name as a method. For example, the @@ -153,7 +153,7 @@ Methods are also present to test whether the name matches a DOM node, and to retrieve the named attribute (if present) from a DOM node. In this version of PyXB, the hash codes and comparison methods for -:api:`ExpandedName ` have been overridden so that +:py:obj:`ExpandedName ` have been overridden so that an expanded name with no namespace is treated equivalently to the string value of the local name. This simplified management of default namespace lookups in earlier versions of PyXB, but may no longer be necessary; reliance on this @@ -164,7 +164,7 @@ Namespace Context `Namespaces in XML `_ specifies how the ``xmlns`` attributes are used to associate prefix strings with namespaces. -The :api:`pyxb.namespace.NamespaceContext` class supports this by associating +The :py:obj:`pyxb.namespace.NamespaceContext` class supports this by associating with each node in a DOM document the contextual information extracted from ``xmlns`` and other namespace-relevant attributes. @@ -204,7 +204,7 @@ namespace". If the target namespace for a schema is absent, we still need to be able to store things somewhere, so we represent the target namespace as a normal -:api:`pyxb.namespace.Namespace` instance, except that the associated URI is +:py:obj:`pyxb.namespace.Namespace` instance, except that the associated URI is ``None``. If in the same schema there is no default namespace, the default namespace is assigned to be this absent (but valid) target namespace, so that QName resolution works. Absence of a target namespace is the only situation @@ -223,7 +223,7 @@ Storage of Namespaces In PyXB, when the :ref:`componentModel` is used to define various elements, attributes, and types by representing them in Python instances, those instance -objects are stored in a :api:`pyxb.namespace.Namespace` instance. In addition +objects are stored in a :py:obj:`pyxb.namespace.Namespace` instance. In addition to generating code corresponding to those objects, it is possible to save the pre-computed objects into a file so that they can be referenced in other namespaces. @@ -302,7 +302,7 @@ another. The component model for a namespace is read from a namespace archive only when it is necessary to generate new bindings for a namespace that refers to it, through import or namespace declarations. The component model is defined by -invoking the :api:`pyxb.namespace.Namespace.validateComponentModel` method. +invoking the :py:obj:`pyxb.namespace.Namespace.validateComponentModel` method. Within an archive, each namespace can be marked as `private` or `public`. When the component model for a namespace is validated, all archives in which @@ -316,11 +316,11 @@ in which the namespace is marked `public`. The contents of the namespace archive are: -- A set of :api:`pyxb.namespace.archive._ModuleRecord` instances which +- A set of :py:obj:`pyxb.namespace.archive._ModuleRecord` instances which identify namespaces and mark whether they are public or private in the archive. Each instance in turn contains (for namespace ``A``): - - the set of :api:`pyxb.namespace.archive._ObjectOrigin` instances which + - the set of :py:obj:`pyxb.namespace.archive._ObjectOrigin` instances which identify the origins for components that are defined in the archive. In turn, each of these origins identifies by category and name the objects that were defined by this origin and consequently are stored in the @@ -328,7 +328,7 @@ The contents of the namespace archive are: `_ directive, multiple origins may be associated with a single module record - - the set of :api:`pyxb.namespace.Namespace` instances that were referenced + - the set of :py:obj:`pyxb.namespace.Namespace` instances that were referenced by ``A``. This includes namespaces that were imported into one of the origin objects, as well as those that were incorporated simply through reference to an object in a declared namespace diff --git a/doc/conf.py b/doc/conf.py index e7c4bba2..9dfde94e 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -22,7 +22,12 @@ # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['sphinx.ext.todo', 'extapi' ] +extensions = [ + 'sphinx.ext.todo', + 'sphinx.ext.autodoc', + 'sphinx_epytext', + 'extapi', +] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -86,6 +91,9 @@ # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] +# Show everything useful in the API +autodoc_default_flags = ['members', 'private-members', 'undoc-members', 'show-inheritance']; + # -- Options for HTML output --------------------------------------------------- diff --git a/doc/conf.py.in b/doc/conf.py.in index 344b6920..a4fc9a31 100644 --- a/doc/conf.py.in +++ b/doc/conf.py.in @@ -22,7 +22,12 @@ import sys, os # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['sphinx.ext.todo', 'extapi' ] +extensions = [ + 'sphinx.ext.todo', + 'sphinx.ext.autodoc', + 'sphinx_epytext', + 'extapi', +] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -86,6 +91,9 @@ pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] +# Show everything useful in the API +autodoc_default_flags = ['members', 'private-members', 'undoc-members', 'show-inheritance']; + # -- Options for HTML output --------------------------------------------------- diff --git a/doc/index.txt b/doc/index.txt index cfa50008..7b6cfee8 100644 --- a/doc/index.txt +++ b/doc/index.txt @@ -59,6 +59,7 @@ Contents releases architecture userref_index + pyxb maintref .. _thirty_sec_example: diff --git a/doc/limitations.txt b/doc/limitations.txt index 488f2cbe..ab7648a1 100644 --- a/doc/limitations.txt +++ b/doc/limitations.txt @@ -42,7 +42,7 @@ Things That Don't Work * `Wildcard elements `_ are supported in the sense that classes that enable them in the content model provide access to unrecognized values through the - :api:`pyxb.binding.basis.complexTypeDefinition.wildcardElements` method. + :py:obj:`pyxb.binding.basis.complexTypeDefinition.wildcardElements` method. Where the type of the node is recognized, it is converted to a Python binding instance; otherwise, the xml DOM instance is stored. Although namespace constraints are applied when checking for wildcard matches, the @@ -52,7 +52,7 @@ Things That Don't Work `_ are supported in much the same sense as wildcard elements: no constraints are checked, and all are aggregated into the - :api:`pyxb.binding.basis.complexTypeDefinition.wildcardAttributeMap`. + :py:obj:`pyxb.binding.basis.complexTypeDefinition.wildcardAttributeMap`. Values are uninterpreted Unicode strings. ...and probably never will diff --git a/doc/maintref.txt b/doc/maintref.txt index 1addc74f..1260d116 100644 --- a/doc/maintref.txt +++ b/doc/maintref.txt @@ -2,13 +2,6 @@ Maintainer Reference ******************** -The `API `_ -*************************** - -The `API `_ for PyXB was generated using `Epydoc -`_. Most of the public API is commented, -though not all docstrings have been updated to use Epydoc syntax. - .. _git_repository: Git Repository @@ -96,14 +89,14 @@ PyXB provides a `standard exception hierarchy Where an execution branch has been identified that requires behavior that has not yet been implemented, raise an -:api:`pyxb.exceptions_.IncompleteImplementationError`. At the current stage +:py:obj:`pyxb.exceptions_.IncompleteImplementationError`. At the current stage of development, these should be extremely rare. Where the system detects that a precondition is not satisfied, processing must stop. If the precondition failure is due to improper use of the PyXB -internal or public API, a :api:`pyxb.exceptions_.LogicError` should be +internal or public API, a :py:obj:`pyxb.exceptions_.LogicError` should be raised. If the precondition failure is due to invalid input from the -schema, a :api:`pyxb.exceptions_.SchemaValidationError` should be raised. +schema, a :py:obj:`pyxb.exceptions_.SchemaValidationError` should be raised. If the precondition is inexplicably false, Python's ``assert`` functionality may be used. Use of ``assert`` should be rare, and only in places that are @@ -121,11 +114,13 @@ us to Python 2.4 or later. Sigh with disappointment and move on. Documentation ============= -Use the `Epytext Markup Language -`_ for all public and -implementation-shared methods and classes. (Formerly, this was "Use -docstrings :PEP:`257`". Documentation in only a few modules has been -converted.) +Use Sphinx-compatible documentation for all public and +implementation-shared methods and classes. (Formerly, this was "Use the +`Epytext Markup Language +`_" but epydoc hasn't +been updated since before PyXB was born. Few if any modules have been +converted. ) (Formerly, this was "Use docstrings :PEP:`257`". +Documentation in only a few modules has been converted.) Comments ======== @@ -216,8 +211,8 @@ Class Variables At Multiple Levels There are several cases where we want to store information in a class, but allow subclasses (not instances) to override it. An example is in the -:api:`pyxb.binding.basis.simpleTypeDefinition` hierarchy where each class -maintains a set of :api:`pyxb.binding.facets.ConstrainingFacet` instances +:py:obj:`pyxb.binding.basis.simpleTypeDefinition` hierarchy where each class +maintains a set of :py:obj:`pyxb.binding.facets.ConstrainingFacet` instances that are available for constraining values of the class. In many cases, a subclass will not change the set of facets that affect instances, so we want to be able to inherit the parent class map; but in other cases we may need diff --git a/doc/pyxb.binding.txt b/doc/pyxb.binding.txt new file mode 100644 index 00000000..716a237e --- /dev/null +++ b/doc/pyxb.binding.txt @@ -0,0 +1,70 @@ +pyxb\.binding package +===================== + +Submodules +---------- + +pyxb\.binding\.basis module +--------------------------- + +.. automodule:: pyxb.binding.basis + :members: + :undoc-members: + :show-inheritance: + +pyxb\.binding\.content module +----------------------------- + +.. automodule:: pyxb.binding.content + :members: + :undoc-members: + :show-inheritance: + +pyxb\.binding\.datatypes module +------------------------------- + +.. automodule:: pyxb.binding.datatypes + :members: + :undoc-members: + :show-inheritance: + +pyxb\.binding\.facets module +---------------------------- + +.. automodule:: pyxb.binding.facets + :members: + :undoc-members: + :show-inheritance: + +pyxb\.binding\.generate module +------------------------------ + +.. automodule:: pyxb.binding.generate + :members: + :undoc-members: + :show-inheritance: + +pyxb\.binding\.saxer module +--------------------------- + +.. automodule:: pyxb.binding.saxer + :members: + :undoc-members: + :show-inheritance: + +pyxb\.binding\.xml\_ module +--------------------------- + +.. automodule:: pyxb.binding.xml_ + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: pyxb.binding + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/pyxb.namespace.txt b/doc/pyxb.namespace.txt new file mode 100644 index 00000000..f72ad843 --- /dev/null +++ b/doc/pyxb.namespace.txt @@ -0,0 +1,46 @@ +pyxb\.namespace package +======================= + +Submodules +---------- + +pyxb\.namespace\.archive module +------------------------------- + +.. automodule:: pyxb.namespace.archive + :members: + :undoc-members: + :show-inheritance: + +pyxb\.namespace\.builtin module +------------------------------- + +.. automodule:: pyxb.namespace.builtin + :members: + :undoc-members: + :show-inheritance: + +pyxb\.namespace\.resolution module +---------------------------------- + +.. automodule:: pyxb.namespace.resolution + :members: + :undoc-members: + :show-inheritance: + +pyxb\.namespace\.utility module +------------------------------- + +.. automodule:: pyxb.namespace.utility + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: pyxb.namespace + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/pyxb.txt b/doc/pyxb.txt new file mode 100644 index 00000000..6808e7e9 --- /dev/null +++ b/doc/pyxb.txt @@ -0,0 +1,34 @@ +pyxb package +============ + +.. automodule:: pyxb + +subpackages +----------- + +.. toctree:: + + pyxb.binding + pyxb.namespace + pyxb.utils + pyxb.xmlschema + +Submodules +---------- + +pyxb\.exceptions\_ module +------------------------- + +.. automodule:: pyxb.exceptions_ + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: pyxb + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/pyxb.utils.txt b/doc/pyxb.utils.txt new file mode 100644 index 00000000..2681d070 --- /dev/null +++ b/doc/pyxb.utils.txt @@ -0,0 +1,102 @@ +pyxb\.utils package +=================== + +Submodules +---------- + +pyxb\.utils\.activestate module +------------------------------- + +.. automodule:: pyxb.utils.activestate + :members: + :undoc-members: + :show-inheritance: + +pyxb\.utils\.domutils module +---------------------------- + +.. automodule:: pyxb.utils.domutils + :members: + :undoc-members: + :show-inheritance: + +pyxb\.utils\.fac module +----------------------- + +.. automodule:: pyxb.utils.fac + :members: + :undoc-members: + :show-inheritance: + +pyxb\.utils\.saxdom module +-------------------------- + +.. automodule:: pyxb.utils.saxdom + :members: + :undoc-members: + :show-inheritance: + +pyxb\.utils\.saxutils module +---------------------------- + +.. automodule:: pyxb.utils.saxutils + :members: + :undoc-members: + :show-inheritance: + +pyxb\.utils\.six module +----------------------- + +.. automodule:: pyxb.utils.six + :members: + :undoc-members: + :show-inheritance: + +pyxb\.utils\.templates module +----------------------------- + +.. automodule:: pyxb.utils.templates + :members: + :undoc-members: + :show-inheritance: + +pyxb\.utils\.unicode module +--------------------------- + +.. automodule:: pyxb.utils.unicode + :members: + :undoc-members: + :show-inheritance: + +pyxb\.utils\.unicode\_data module +--------------------------------- + +.. automodule:: pyxb.utils.unicode_data + :members: + :undoc-members: + :show-inheritance: + +pyxb\.utils\.utility module +--------------------------- + +.. automodule:: pyxb.utils.utility + :members: + :undoc-members: + :show-inheritance: + +pyxb\.utils\.xmlre module +------------------------- + +.. automodule:: pyxb.utils.xmlre + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: pyxb.utils + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/pyxb.xmlschema.txt b/doc/pyxb.xmlschema.txt new file mode 100644 index 00000000..29704681 --- /dev/null +++ b/doc/pyxb.xmlschema.txt @@ -0,0 +1,22 @@ +pyxb\.xmlschema package +======================= + +Submodules +---------- + +pyxb\.xmlschema\.structures module +---------------------------------- + +.. automodule:: pyxb.xmlschema.structures + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: pyxb.xmlschema + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/releases.txt b/doc/releases.txt index c6c534c7..ff5423bd 100644 --- a/doc/releases.txt +++ b/doc/releases.txt @@ -188,7 +188,7 @@ The following reported `defects/enhancements :ref:`pyxbgen--wsdl-location`. :ticket:`210` - Refine diagnostics when an element with simple type appears in a context that expects non-element content. :ticket:`211` -- Add :api:`pyxb.NonElementContent` to simplify access to non-element content +- Add :py:obj:`pyxb.NonElementContent` to simplify access to non-element content in a mixed-content instance. :ticket:`212` - Convert assert failures to diagnostic exceptions when generating DOM expressions of complex types with simple content where the content is @@ -239,9 +239,9 @@ Documentation: http://pyxb.sourceforge.net/PyXB-1.2.1 .. warning:: - This release has an interface change: the :api:`content + This release has an interface change: the :py:obj:`content ` method on complex types - is now deprecated in favor of the :api:`orderedContent + is now deprecated in favor of the :py:obj:`orderedContent ` method. The members in the new list have wrapper classes to correctly associate instance bindings with the element declaration and to distinguish instances @@ -252,7 +252,7 @@ Documentation: http://pyxb.sourceforge.net/PyXB-1.2.1 Key features of the release: - Full support for mixed content schema through a new method - :api:`orderedContent ` on complex + :py:obj:`orderedContent ` on complex binding instances and flags that control when that list affects document generation. See :ref:`mixed_content`. This is particularly relevant to XHTML. @@ -260,7 +260,7 @@ Key features of the release: - Immediate validation of values assigned to plural elements. - A first step to providing finer control of validation, using - :api:`pyxb.ValidationConfig` + :py:obj:`pyxb.ValidationConfig` The following reported `defects/enhancements `_ have been addressed: @@ -513,7 +513,7 @@ not acceptable to the validating parser, and where it can be found in the document. See :ref:`invalid-content`. Also, using keyword parameters in binding instance constructors will now raise -an :api:`pyxb.exceptions_.ExtraContentError` in the case where the keyword does not +an :py:obj:`pyxb.exceptions_.ExtraContentError` in the case where the keyword does not correspond to the PyXB-generated identifier associated with an attribute or element of the class being instantiated. diff --git a/doc/userref_pyxbgen.txt b/doc/userref_pyxbgen.txt index f33f632f..b05a6c34 100644 --- a/doc/userref_pyxbgen.txt +++ b/doc/userref_pyxbgen.txt @@ -244,11 +244,11 @@ create instances of the customized class when automatically generating ``tParam`` instances from XML documents. To customize bindings, you will need to be familiar with the -:api:`pyxb.binding.basis._DynamicCreate_mixin` class. +:py:obj:`pyxb.binding.basis._DynamicCreate_mixin` class. -Be aware that :api:`_SetSupersedingClass +Be aware that :py:obj:`_SetSupersedingClass ` only affects the behavior of -:api:`Factory `, and does not change +:py:obj:`Factory `, and does not change the Python inheritance tree. This means that the superseding class is only invoked when the content model requires an instance of the original type. When an instance of a subclass of a superseded class (that is not itself diff --git a/doc/userref_usebind.txt b/doc/userref_usebind.txt index 5c196d16..f0a700db 100644 --- a/doc/userref_usebind.txt +++ b/doc/userref_usebind.txt @@ -27,7 +27,7 @@ Locating Invalid Content ^^^^^^^^^^^^^^^^^^^^^^^^ If a document does not validate, PyXB will generally through an -:api:`pyxb.UnrecognizedContentError` exception. You can determine where the +:py:obj:`pyxb.UnrecognizedContentError` exception. You can determine where the problem lies, and what was not recognized, by examining attributes present on the exception as shown in this example: @@ -44,7 +44,7 @@ Some web services and binding tools mis-use `xsi:type `_, providing attribute values that either are not types, or do not specify a type that is derived from an abstract type. The -:api:`pyxb.namespace.builtin.XMLSchema_instance.ProcessTypeAttribute +:py:obj:`pyxb.namespace.builtin.XMLSchema_instance.ProcessTypeAttribute ` method can be used to relax how PyXB processes those attributes. @@ -98,7 +98,7 @@ schema does not include New York as a state, so the following assignment:: addr.state = 'NY' -will cause a :api:`pyxb.exceptions_.BadTypeValueError` exception to be raised: +will cause a :py:obj:`pyxb.exceptions_.BadTypeValueError` exception to be raised: .. literalinclude:: ../examples/manual/demo4a1.out @@ -130,10 +130,10 @@ This example produces (after reformatting): Note that, because we're in the middle of the example and have not provided the ``items`` element that the content model requires, the code -:api:`explicitly disables the requirement for +:py:obj:`explicitly disables the requirement for validation ` when generating XML from a binding instance. A consequence of this is that the generated XML is not -valid, and validation must be :api:`disabled for parsing +valid, and validation must be :py:obj:`disabled for parsing ` as well if the resulting document is to be re-converted into a binding with ``CreateFromDocument``. @@ -152,11 +152,11 @@ the deeper elements of the purchase order: In particular, there is no global ``item`` element that can be used to create the individual items. For situations like this, we use -:api:`pyxb.BIND`: +:py:obj:`pyxb.BIND`: .. literalinclude:: ../examples/manual/demo4c1.py -The :api:`pyxb.BIND` reference wraps the content of the inner elements, and +The :py:obj:`pyxb.BIND` reference wraps the content of the inner elements, and is a cue to PyXB to attempt to build an instance of whatever type of object would satisfy the content model at that point. The resulting document (after reformatting) is: @@ -186,7 +186,7 @@ The ``toxml`` method is short-hand for a sequence that converts the binding to a DOM instance using ``xml.dom.minidom``, then uses the DOM interface to generate the XML document. -The :api:`pyxb.utils.domutils.BindingDOMSupport` class provides ways to +The :py:obj:`pyxb.utils.domutils.BindingDOMSupport` class provides ways to control this generation. In particular, you may want to use something more informative than ``ns#`` to denote namespaces in the generated documents. This can be done using the following code: @@ -229,32 +229,32 @@ elements appear in the original schema. As of release 1.2.1 [#content]_, PyXB appends both element and non-element content to a list in each complex binding instance. The list may be obtained using the -:api:`orderedContent +:py:obj:`orderedContent ` method. The list -comprises instances of :api:`pyxb.binding.basis.ElementContent` and -:api:`pyxb.binding.basis.NonElementContent` added in the order in which they were +comprises instances of :py:obj:`pyxb.binding.basis.ElementContent` and +:py:obj:`pyxb.binding.basis.NonElementContent` added in the order in which they were added to the binding instance: when creating the instance from a document or through a constructor, or by invoking the -:api:`append ` or -:api:`extend ` methods to add +:py:obj:`append ` or +:py:obj:`extend ` methods to add content consistent with the content model. -The :api:`contentInfluencesGeneration +The :py:obj:`contentInfluencesGeneration ` flag of -:api:`pyxb.ValidationConfig` controls how the ``orderedContent`` list affects +:py:obj:`pyxb.ValidationConfig` controls how the ``orderedContent`` list affects generation of documents (both DOM directly and XML indirectly). With the -default value of :api:`MIXED_ONLY ` the +default value of :py:obj:`MIXED_ONLY ` the ``orderedContent`` list is only consulted when a complex type allows both element and non-element content. The bundle for XHTML has been modified to use: -- :api:`ALWAYS ` for :api:`contentInfluencesGeneration +- :py:obj:`ALWAYS ` for :py:obj:`contentInfluencesGeneration ` -- :api:`RAISE_EXCEPTION ` for - :api:`orphanElementInContent ` -- :api:`RAISE_EXCEPTION ` for - :api:`invalidElementInContent ` +- :py:obj:`RAISE_EXCEPTION ` for + :py:obj:`orphanElementInContent ` +- :py:obj:`RAISE_EXCEPTION ` for + :py:obj:`invalidElementInContent ` for all binding classes in that module. (See ``pyxb/bundles/common/xhtml1.py`` for the technique used.) This ensures @@ -279,7 +279,7 @@ incorrect in at least two cases: the newly added elements do not appear in the ``orderedContent`` list. -The value returned by :api:`orderedContent +The value returned by :py:obj:`orderedContent ` is a mutable list so that you can manipulate it to reflect the content you wish to have generated. @@ -287,9 +287,9 @@ generated. Where the ``orderedContent`` list is not consistent with the content model (e.g., references elements that are no longer part of the binding instance, or proposes an order that is not valid) various exceptions may arise. To some -extent this can be controlled through the :api:`orphanElementInContent +extent this can be controlled through the :py:obj:`orphanElementInContent ` and -:api:`invalidElementInContent ` +:py:obj:`invalidElementInContent ` flags. .. [#content] Though previous versions also provided this information through diff --git a/doc/userref_validating.txt b/doc/userref_validating.txt index f5c8b5e8..b9fbb7cd 100644 --- a/doc/userref_validating.txt +++ b/doc/userref_validating.txt @@ -53,7 +53,7 @@ instance: r = DWML.CreateFromDocument(rxml) When invoking the program, the following diagnostic output is provided -through the :api:`details ` +through the :py:obj:`details ` method: .. code-block:: none @@ -98,7 +98,7 @@ This tells the user that: A much shorter but still useful synopsis of the invalidity would be available through the ``str`` operation on the exception. Full details are -available through attributes on the :api:`UnrecognizedContentError +available through attributes on the :py:obj:`UnrecognizedContentError ` and other exceptions. In cases where the service generating the documents is under your control, @@ -112,7 +112,7 @@ Runtime Exception Hierarchy --------------------------- Details on the interfaces presented by these exceptions can be found through -the :api:`API Documentation `. +the :py:obj:`API Documentation `. .. image:: Images/RuntimeExceptions.jpg From 1d26a048192811b43c07c3039de05ebf25324455 Mon Sep 17 00:00:00 2001 From: "Peter A. Bigot" Date: Sat, 13 May 2017 07:49:47 -0500 Subject: [PATCH 14/41] doc/maintref: update repository reference to github --- doc/maintref.txt | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/doc/maintref.txt b/doc/maintref.txt index 1260d116..326d5142 100644 --- a/doc/maintref.txt +++ b/doc/maintref.txt @@ -7,20 +7,17 @@ Maintainer Reference Git Repository ************** -PyXB is developed using `git `_. You can check out the -development branch with:: - - git clone git://pyxb.git.sourceforge.net/gitroot/pyxb/pyxb - +PyXB is developed using `git `_ with active +development hosted on `Github `_. Public development is mostly done on the ``next`` branch, which is the -default for checkouts from SourceForge. The ``master`` branch contains -material integrated into the release, and follows ``next``. Tags for each +default for cloned checkouts. The ``master`` branch contains material +integrated into the release, and follows ``next``. Tags for each release are in the format ``PyXB-X.Y.Z``. -Bug fixes with unit tests are pushed to the ``next`` branch as soon as they -are fixed. Users whose reported issues have been fixed are encouraged to -use the development branch until the fix has been made available in a tagged -and packaged release. +Bug fixes with unit tests are pushed to the ``next`` branch as soon as +they are fixed. Users whose reported issues have been fixed are +encouraged to use the development branch until the fix has been made +available in a tagged and packaged release. Coding Practices **************** From 0dfd102e2dfbc997f27c3f54966899ce3f1b1e49 Mon Sep 17 00:00:00 2001 From: "Peter A. Bigot" Date: Sat, 13 May 2017 11:03:51 -0500 Subject: [PATCH 15/41] binding/datatypes: detect empty xml construction of scalar values The Python default value was inappropriately used for simple data types when constructed from an empty XML element (i.e. an empty string value). Detect this situation and reject unless the value is explicitly nil. Closes #71 --- pyxb/binding/basis.py | 21 ++++- pyxb/binding/datatypes.py | 148 +++++++++++++++++-------------- tests/datatypes/test-duration.py | 6 +- tests/datatypes/test-time.py | 1 + tests/drivers/test-facets.py | 5 ++ tests/trac/test-issue-0071.py | 61 +++++++++++++ 6 files changed, 171 insertions(+), 71 deletions(-) create mode 100644 tests/trac/test-issue-0071.py diff --git a/pyxb/binding/basis.py b/pyxb/binding/basis.py index 273586d0..16e81022 100644 --- a/pyxb/binding/basis.py +++ b/pyxb/binding/basis.py @@ -705,6 +705,14 @@ class _RepresentAsXsdLiteral_mixin (pyxb.cscRoot): e.g. duration, decimal, and any of the date/time types.""" pass +class _NoNullaryNonNillableNew_mixin (pyxb.cscRoot): + """Marker class indicating that a simple data type cannot construct + a value from XML through an empty string. + + This class should appear immediately L{simpleTypeDefinition} (or whatever + inherits from L{simpleTypeDefinition} in cases where it applies.""" + pass + class simpleTypeDefinition (_TypeBinding_mixin, utility._DeconflictSymbols_mixin, _DynamicCreate_mixin): """L{simpleTypeDefinition} is a base class that is part of the hierarchy of any class that represents the Python datatype for a @@ -886,11 +894,16 @@ def __new__ (cls, *args, **kw): kw.pop('_element', None) kw.pop('_fallback_namespace', None) kw.pop('_apply_attributes', None) - kw.pop('_nil', None) - # ConvertArguments will remove _element and _apply_whitespace_facet - dom_node = kw.get('_dom_node') + is_nil = kw.pop('_nil', None) + # ConvertArguments will remove _dom_node, _element, and + # _apply_whitespace_facet, and it will set _from_xml. args = cls._ConvertArguments(args, kw) - kw.pop('_from_xml', dom_node is not None) + from_xml = kw.pop('_from_xml', False) + if ((0 == len(args)) + and from_xml + and not is_nil + and issubclass(cls, _NoNullaryNonNillableNew_mixin)): + raise pyxb.SimpleTypeValueError(cls, args); kw.pop('_location', None) assert issubclass(cls, _TypeBinding_mixin) try: diff --git a/pyxb/binding/datatypes.py b/pyxb/binding/datatypes.py index 05c1fb72..90b721fc 100644 --- a/pyxb/binding/datatypes.py +++ b/pyxb/binding/datatypes.py @@ -94,7 +94,7 @@ def XsdValueLength (cls, value): # It is illegal to subclass the bool type in Python, so we subclass # int instead. @six.python_2_unicode_compatible -class boolean (basis.simpleTypeDefinition, six.int_type): +class boolean (basis.simpleTypeDefinition, six.int_type, basis._NoNullaryNonNillableNew_mixin): """XMLSchema datatype U{boolean}.""" _XsdBaseType = anySimpleType _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('boolean') @@ -126,7 +126,7 @@ def __new__ (cls, *args, **kw): _PrimitiveDatatypes.append(boolean) -class decimal (basis.simpleTypeDefinition, python_decimal.Decimal, basis._RepresentAsXsdLiteral_mixin): +class decimal (basis.simpleTypeDefinition, python_decimal.Decimal, basis._RepresentAsXsdLiteral_mixin, basis._NoNullaryNonNillableNew_mixin): """XMLSchema datatype U{decimal}. This class uses Python's L{decimal.Decimal} class to support (by @@ -184,7 +184,7 @@ def XsdLiteral (cls, value): _PrimitiveDatatypes.append(decimal) -class _fp (basis.simpleTypeDefinition, six.float_type): +class _fp (basis.simpleTypeDefinition, six.float_type, basis._NoNullaryNonNillableNew_mixin): _XsdBaseType = anySimpleType @classmethod @@ -246,70 +246,79 @@ def durationData (self): def __new__ (cls, *args, **kw): args = cls._ConvertArguments(args, kw) have_kw_update = False - if not kw.get('_nil'): - if 0 == len(args): - raise SimpleTypeValueError(cls, args) - text = args[0] + negative_duration = False if kw.get('_nil'): data = dict(zip(cls.__PythonFields, len(cls.__PythonFields) * [0,])) - negative_duration = False - elif isinstance(text, six.string_types): - match = cls.__Lexical_re.match(text) - if match is None: - raise SimpleTypeValueError(cls, text) - match_map = match.groupdict() - if 'T' == match_map.get('Time'): - # Can't have T without additional time information - raise SimpleTypeValueError(cls, text) - - negative_duration = ('-' == match_map.get('neg')) - - fractional_seconds = 0.0 - if match_map.get('fracsec') is not None: - fractional_seconds = six.float_type('0%s' % (match_map['fracsec'],)) - usec = six.int_type(1000000 * fractional_seconds) - if negative_duration: - kw['microseconds'] = - usec - else: - kw['microseconds'] = usec - else: - # Discard any bogosity passed in by the caller - kw.pop('microsecond', None) - - data = { } - for fn in cls.__XSDFields: - v = match_map.get(fn, 0) - if v is None: - v = 0 - data[fn] = six.int_type(v) - if fn in cls.__PythonFields: - if negative_duration: - kw[fn] = - data[fn] - else: - kw[fn] = data[fn] - data['seconds'] += fractional_seconds - have_kw_update = True - elif isinstance(text, cls): - data = text.durationData().copy() - negative_duration = text.negativeDuration() - elif isinstance(text, datetime.timedelta): - data = { 'days' : text.days, - 'seconds' : text.seconds + (text.microseconds / 1000000.0) } - negative_duration = (0 > data['days']) - if negative_duration: - if 0.0 == data['seconds']: - data['days'] = - data['days'] - else: - data['days'] = 1 - data['days'] - data['seconds'] = 24 * 60 * 60.0 - data['seconds'] - data['minutes'] = 0 - data['hours'] = 0 - elif isinstance(text, six.integer_types) and (1 < len(args)): + elif 0 == len(args): + if kw.get('_from_xml'): + raise SimpleTypeValueError(cls, args) + data = dict(zip(cls.__PythonFields, len(cls.__PythonFields) * [0,])) + elif 1 < len(args): + if kw.get('_from_xml'): + raise SimpleTypeValueError(cls, args) # Apply the arguments as in the underlying Python constructor data = dict(zip(cls.__PythonFields[:len(args)], args)) - negative_duration = False else: - raise SimpleTypeValueError(cls, text) + text = args[0]; + if isinstance(text, six.string_types): + match = cls.__Lexical_re.match(text) + if match is None: + raise SimpleTypeValueError(cls, text) + match_map = match.groupdict() + if 'T' == match_map.get('Time'): + # Can't have T without additional time information + raise SimpleTypeValueError(cls, text) + + negative_duration = ('-' == match_map.get('neg')) + + fractional_seconds = 0.0 + if match_map.get('fracsec') is not None: + fractional_seconds = six.float_type('0%s' % (match_map['fracsec'],)) + usec = six.int_type(1000000 * fractional_seconds) + if negative_duration: + kw['microseconds'] = - usec + else: + kw['microseconds'] = usec + else: + # Discard any bogosity passed in by the caller + kw.pop('microsecond', None) + + data = { } + for fn in cls.__XSDFields: + v = match_map.get(fn, 0) + if v is None: + v = 0 + data[fn] = six.int_type(v) + if fn in cls.__PythonFields: + if negative_duration: + kw[fn] = - data[fn] + else: + kw[fn] = data[fn] + data['seconds'] += fractional_seconds + have_kw_update = True + elif kw.get('_from_xml'): + raise SimpleTypeValueError(cls, args) + elif isinstance(text, cls): + data = text.durationData().copy() + negative_duration = text.negativeDuration() + elif isinstance(text, datetime.timedelta): + data = { 'days' : text.days, + 'seconds' : text.seconds + (text.microseconds / 1000000.0) } + negative_duration = (0 > data['days']) + if negative_duration: + if 0.0 == data['seconds']: + data['days'] = - data['days'] + else: + data['days'] = 1 - data['days'] + data['seconds'] = 24 * 60 * 60.0 - data['seconds'] + data['minutes'] = 0 + data['hours'] = 0 + elif isinstance(text, six.integer_types): + # Apply the arguments as in the underlying Python constructor + data = dict(zip(cls.__PythonFields[:len(args)], args)) + negative_duration = False + else: + raise SimpleTypeValueError(cls, text) if not have_kw_update: rem_time = data.pop('seconds', 0) if (0 != (rem_time % 1)): @@ -516,6 +525,10 @@ def __new__ (cls, *args, **kw): ctor_kw = { } if kw.get('_nil'): ctor_kw = { 'year': 1900, 'month': 1, 'day': 1 } + elif 0 == len(args): + if kw.get('_from_xml'): + raise SimpleTypeValueError(cls, args) + ctor_kw = { 'year': 1900, 'month': 1, 'day': 1 } elif 1 == len(args): value = args[0] if isinstance(value, six.string_types): @@ -590,7 +603,12 @@ class time (_PyXBDateTime_base, datetime.time): def __new__ (cls, *args, **kw): args = cls._ConvertArguments(args, kw) ctor_kw = { } - if 1 <= len(args): + if kw.get('_nil'): + pass + elif 0 == len(args): + if kw.get('_from_xml'): + raise SimpleTypeValueError(cls, args) + else: value = args[0] if isinstance(value, six.string_types): ctor_kw.update(cls._LexicalToKeywords(value)) @@ -1162,7 +1180,7 @@ class ENTITIES (basis.STD_list): _ItemType = ENTITY _ListDatatypes.append(ENTITIES) -class integer (basis.simpleTypeDefinition, six.long_type): +class integer (basis.simpleTypeDefinition, six.long_type, basis._NoNullaryNonNillableNew_mixin): """XMLSchema datatype U{integer}.""" _XsdBaseType = decimal _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('integer') @@ -1188,7 +1206,7 @@ class long (integer): _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('long') _DerivedDatatypes.append(long) -class int (basis.simpleTypeDefinition, six.int_type): +class int (basis.simpleTypeDefinition, six.int_type, basis._NoNullaryNonNillableNew_mixin): """XMLSchema datatype U{int}.""" _XsdBaseType = long _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('int') diff --git a/tests/datatypes/test-duration.py b/tests/datatypes/test-duration.py index ff29a248..0773cca0 100644 --- a/tests/datatypes/test-duration.py +++ b/tests/datatypes/test-duration.py @@ -108,8 +108,10 @@ def testCreation (self): self.assertEqual(3, v.days) self.assertEqual(14842, v.seconds) self.assertEqual('P3DT4H7M22.5S', v.xsdLiteral()) - self.assertRaises(pyxb.SimpleTypeValueError, xsd.duration) - self.assertRaises(pyxb.SimpleTypeValueError, xsd.duration, 4) + self.assertEqual(datetime.timedelta(), xsd.duration()) + self.assertRaises(pyxb.SimpleTypeValueError, xsd.duration, _from_xml=True) + self.assertEqual(datetime.timedelta(4), xsd.duration(4)) + self.assertRaises(pyxb.SimpleTypeValueError, xsd.duration, 4, _from_xml=True) if __name__ == '__main__': unittest.main() diff --git a/tests/datatypes/test-time.py b/tests/datatypes/test-time.py index 2b21a047..013b0d27 100644 --- a/tests/datatypes/test-time.py +++ b/tests/datatypes/test-time.py @@ -24,6 +24,7 @@ def testBad (self): self.assertRaises(pyxb.SimpleTypeValueError, xsd.time, '12:14:32.Z') self.assertRaises(pyxb.SimpleTypeValueError, xsd.time, '12:14:32.123405:00') self.assertRaises(pyxb.SimpleTypeValueError, xsd.time, '12:14:32.1234+05') + self.assertRaises(pyxb.SimpleTypeValueError, xsd.time, _from_xml=True) def testFromText (self): self.verifyTime(xsd.time('12:14:32'), with_usec=False, with_tzinfo=False) diff --git a/tests/drivers/test-facets.py b/tests/drivers/test-facets.py index 5316dd9c..cda57825 100644 --- a/tests/drivers/test-facets.py +++ b/tests/drivers/test-facets.py @@ -27,5 +27,10 @@ def testQuantity (self): self.assertRaises(Exception, quantity, -52) self.assertRaises(Exception, quantity, 100) + def testEmptyQuantity(self): + xml = '' + dom = pyxb.utils.domutils.StringToDOM(xml).documentElement; + self.assertRaises(SimpleTypeValueError, CreateFromDOM, dom) + if __name__ == '__main__': unittest.main() diff --git a/tests/trac/test-issue-0071.py b/tests/trac/test-issue-0071.py new file mode 100644 index 00000000..658aae88 --- /dev/null +++ b/tests/trac/test-issue-0071.py @@ -0,0 +1,61 @@ +# -*- coding: utf-8 -*- +import logging +if __name__ == '__main__': + logging.basicConfig() +_log = logging.getLogger(__name__) +import pyxb.binding.generate +import pyxb.utils.domutils +import pyxb.binding.datatypes as xs +import datetime; +from xml.dom import Node + +import os.path +xsd=''' + + + + + + + +''' + +code = pyxb.binding.generate.GeneratePython(schema_text=xsd) +#open('code.py', 'w').write(code) +#print code + +rv = compile(code, 'test', 'exec') +eval(rv) + +from pyxb.exceptions_ import * + +import unittest + +class TestIssue0071 (unittest.TestCase): + def testNonNegativeInteger (self): + self.assertEqual(0, xs.nonNegativeInteger()); + self.assertEqual(0, CreateFromDocument(six.u('0'))); + self.assertRaises(SimpleTypeValueError, CreateFromDocument, six.u('')); + + def testBoolean (self): + self.assertEqual(0, xs.boolean()); + self.assertEqual(0, CreateFromDocument(six.u('0'))); + self.assertRaises(SimpleTypeValueError, CreateFromDocument, six.u('')); + + def testInt (self): + self.assertEqual(0, xs.int()); + self.assertEqual(0, CreateFromDocument(six.u('0'))); + self.assertRaises(SimpleTypeValueError, CreateFromDocument, six.u('')); + + def testTime (self): + self.assertEqual(datetime.time(), xs.time()); + self.assertEqual(datetime.time(), CreateFromDocument(six.u(''))); + self.assertRaises(SimpleTypeValueError, CreateFromDocument, six.u('