diff --git a/MANIFEST.in b/MANIFEST.in index 99fe7ea79096fc51b2b423827da2ce0d5072df90..6203fff0824bd1dfd72bd9e9bd96dfe6e0acd3e9 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -132,6 +132,20 @@ include tests/rem_dup_elems1_sub.py include tests/reference_simpletype.xsd include tests/reference_simpletype1_sup.py include tests/reference_simpletype1_sub.py +include tests/defaults_cases_always.xsd +include tests/defaults_cases_always1_out.xml +include tests/defaults_cases_always1_sub.py +include tests/defaults_cases_always1_sup.py +include tests/defaults_cases_always.xml +include tests/no_namespace_defs.xsd +include tests/no_namespace_defs1_sub.py +include tests/no_namespace_defs1_sup.py +include tests/mixedcontent.xsd +include tests/mixedcontent.xml +include tests/mixedcontent1_out.xml +include tests/mixedcontent1_sub.py +include tests/mixedcontent1_sup.py +include tests/check_results.rb include gui/generateds_gui.py include gui/generateds_gui.glade diff --git a/README.rst b/README.rst index 1e04616f4b93c1a575732438bd24454b12cb9749..61b2ca8a50653d75a546e6f75ffd88ff014f7ead 100644 --- a/README.rst +++ b/README.rst @@ -141,6 +141,13 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Change history -------------- +Version 2.29.11 (03/16/2018) + +- Fix for the --no-namespace-defs command line option. The work on + namespaces in v. 2.29.6 appears to have conflicted with and + deactivated this. Thanks to Olof Kindgren for reporting this. +- Added unit test for --no-namespace-defs. + Version 2.29.10 (03/14/2018) - Fix to resolution of child types -- Formerly, we were adding some diff --git a/generateDS.html b/generateDS.html index da8d74c19d730410a418e88bf59b4fd58e3ace43..f03cee636ad791948e1c76e5369439633ae2701b 100644 --- a/generateDS.html +++ b/generateDS.html @@ -220,7 +220,7 @@ They are used by updateversion.py. --> <col class="field-name" /> <col class="field-body" /> <tbody valign="top"> -<tr class="field"><th class="field-name">revision:</th><td class="field-body">2.29.10</td> +<tr class="field"><th class="field-name">revision:</th><td class="field-body">2.29.11</td> </tr> </tbody> </table> @@ -229,7 +229,7 @@ They are used by updateversion.py. --> <col class="field-name" /> <col class="field-body" /> <tbody valign="top"> -<tr class="field"><th class="field-name">date:</th><td class="field-body">March 14, 2018</td> +<tr class="field"><th class="field-name">date:</th><td class="field-body">March 16, 2018</td> </tr> </tbody> </table> @@ -3386,7 +3386,7 @@ following among others:</p> <div class="footer"> <hr class="footer" /> <a class="reference external" href="generateDS.txt">View document source</a>. -Generated on: 2018-03-14 18:27 UTC. +Generated on: 2018-03-16 20:52 UTC. Generated by <a class="reference external" href="http://docutils.sourceforge.net/">Docutils</a> from <a class="reference external" href="http://docutils.sourceforge.net/rst.html">reStructuredText</a> source. </div> diff --git a/generateDS.py b/generateDS.py index 0d183a9dfb0230ed96a08fa421504379f2b1874f..539392abebe16569e37ad9785da942bff9f2fe95 100755 --- a/generateDS.py +++ b/generateDS.py @@ -232,7 +232,7 @@ logging.disable(logging.INFO) # Do not modify the following VERSION comments. # Used by updateversion.py. ##VERSION## -VERSION = '2.29.10' +VERSION = '2.29.11' ##VERSION## BaseStrTypes = six.string_types @@ -2836,9 +2836,13 @@ def generateExportFn(wrt, prefix, element, namespace, nameSpacesDef): ns_prefix = SchemaNamespaceDict.get(name) if ns_prefix is not None and ns_prefix[0] is not None: namespace = ns_prefix[0] + ':' - ns_def = 'xmlns:{}'.format(ns_prefix[0]) - if ns_def not in nameSpacesDef: - nameSpacesDef += ' {}="{}"'.format(ns_def, ns_prefix[1]) + # Was the --no-namespace-defs command line option used? + if nameSpacesDef: + if ns_prefix is not None and ns_prefix[0] is not None: + namespace = ns_prefix[0] + ':' + ns_def = 'xmlns:{}'.format(ns_prefix[0]) + if ns_def not in nameSpacesDef: + nameSpacesDef += ' {}="{}"'.format(ns_def, ns_prefix[1]) wrt(" def export(self, outfile, level, namespace_='%s', " "name_='%s', namespacedef_='%s', pretty_print=True):\n" % (namespace, encodedname, nameSpacesDef)) diff --git a/generateDS.txt b/generateDS.txt index 7f7d31111850e42f97d77b0d38ebcd0ac9407fc3..e9c12dd4f1c0a20f56b780739a590be4719120b0 100644 --- a/generateDS.txt +++ b/generateDS.txt @@ -12,7 +12,7 @@ generateDS -- Generate Data Structures from XML Schema .. version -:revision: 2.29.10 +:revision: 2.29.11 .. version diff --git a/generateds_gui_notes.html b/generateds_gui_notes.html index 7432d82f614b1535d014f7b481a858d12470ae69..f566ce5d792d39fbea6e915188cfa875c2868d9c 100644 --- a/generateds_gui_notes.html +++ b/generateds_gui_notes.html @@ -220,7 +220,7 @@ They are used by updateversion.py. --> <col class="field-name" /> <col class="field-body" /> <tbody valign="top"> -<tr class="field"><th class="field-name">revision:</th><td class="field-body">2.29.10</td> +<tr class="field"><th class="field-name">revision:</th><td class="field-body">2.29.11</td> </tr> </tbody> </table> @@ -229,7 +229,7 @@ They are used by updateversion.py. --> <col class="field-name" /> <col class="field-body" /> <tbody valign="top"> -<tr class="field"><th class="field-name">date:</th><td class="field-body">March 14, 2018</td> +<tr class="field"><th class="field-name">date:</th><td class="field-body">March 16, 2018</td> </tr> </tbody> </table> @@ -401,7 +401,7 @@ $ mv generateds_gui.mo locale/ru/LC_MESSAGES/ <div class="footer"> <hr class="footer" /> <a class="reference external" href="generateds_gui_notes.txt">View document source</a>. -Generated on: 2018-03-14 18:27 UTC. +Generated on: 2018-03-16 20:52 UTC. Generated by <a class="reference external" href="http://docutils.sourceforge.net/">Docutils</a> from <a class="reference external" href="http://docutils.sourceforge.net/rst.html">reStructuredText</a> source. </div> diff --git a/generateds_gui_notes.txt b/generateds_gui_notes.txt index f8efa786c4c3f1840ed6b38c812f069068353fd6..0cd90f10e6f081d444164b1fb78d1a50c330942a 100644 --- a/generateds_gui_notes.txt +++ b/generateds_gui_notes.txt @@ -12,7 +12,7 @@ GenerateDS GUI Notes .. version -:revision: 2.29.10 +:revision: 2.29.11 .. version diff --git a/gui/generateds_gui.py b/gui/generateds_gui.py index 1a34eb2a12c5a981c31ce333267d83ffd9aea54c..9193a249496707d992db0c4a77d7ff6bd8b2dcf6 100644 --- a/gui/generateds_gui.py +++ b/gui/generateds_gui.py @@ -41,7 +41,7 @@ from libgenerateDS.gui import generateds_gui_session # Do not modify the following VERSION comments. # Used by updateversion.py. ##VERSION## -VERSION = '2.29.10' +VERSION = '2.29.11' ##VERSION## diff --git a/librarytemplate_howto.html b/librarytemplate_howto.html index a5724e3f4920b55203bf0bc492e21317f1096df9..bf62a12a37c20b53e9ad1f382c1f458724549b6a 100644 --- a/librarytemplate_howto.html +++ b/librarytemplate_howto.html @@ -217,7 +217,7 @@ dkuhlman (at) davekuhlman (dot) org <col class="field-name" /> <col class="field-body" /> <tbody valign="top"> -<tr class="field"><th class="field-name">revision:</th><td class="field-body">2.29.10</td> +<tr class="field"><th class="field-name">revision:</th><td class="field-body">2.29.11</td> </tr> </tbody> </table> @@ -226,7 +226,7 @@ dkuhlman (at) davekuhlman (dot) org <col class="field-name" /> <col class="field-body" /> <tbody valign="top"> -<tr class="field"><th class="field-name">date:</th><td class="field-body">March 14, 2018</td> +<tr class="field"><th class="field-name">date:</th><td class="field-body">March 16, 2018</td> </tr> </tbody> </table> @@ -380,7 +380,7 @@ this command for your needs. For example, you may need to use <div class="footer"> <hr class="footer" /> <a class="reference external" href="librarytemplate_howto.txt">View document source</a>. -Generated on: 2018-03-14 18:27 UTC. +Generated on: 2018-03-16 20:52 UTC. Generated by <a class="reference external" href="http://docutils.sourceforge.net/">Docutils</a> from <a class="reference external" href="http://docutils.sourceforge.net/rst.html">reStructuredText</a> source. </div> diff --git a/librarytemplate_howto.txt b/librarytemplate_howto.txt index 72b3f8bd825a85d705605086605d30d38bc50aae..a726e0e7cd246abf553684ab0d55570d32030850 100644 --- a/librarytemplate_howto.txt +++ b/librarytemplate_howto.txt @@ -8,7 +8,7 @@ How to package a generateDS.py generated library .. version -:revision: 2.29.10 +:revision: 2.29.11 .. version diff --git a/process_includes.py b/process_includes.py index abbc7daccdc695df74da28806345a90ae9829af6..f7ffb58199b0ff1028fb183b81068d8955e96ecd 100755 --- a/process_includes.py +++ b/process_includes.py @@ -40,7 +40,7 @@ except ImportError: # Do not modify the following VERSION comments. # Used by updateversion.py. ##VERSION## -VERSION = '2.29.10' +VERSION = '2.29.11' ##VERSION## CatalogDict = {} diff --git a/setup.py b/setup.py index ef25b06fdfd9b3e06b1aecd429704d69f08ba6da..4e915666f05d091a76d3ad1d03477a36466394cf 100644 --- a/setup.py +++ b/setup.py @@ -7,7 +7,7 @@ setup(name="generateDS", # Do not modify the following VERSION comments. # Used by updateversion.py. ##VERSION## - version="2.29.10", + version="2.29.11", ##VERSION## author="Dave Kuhlman", author_email="dkuhlman@davekuhlman.org", diff --git a/tests/no_namespace_defs.xsd b/tests/no_namespace_defs.xsd new file mode 100644 index 0000000000000000000000000000000000000000..6d84a4d949092a769de1be19710283cc75235d0c --- /dev/null +++ b/tests/no_namespace_defs.xsd @@ -0,0 +1,36 @@ +<?xml version="1.0"?> +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> + + <xs:element name="people" type="peopleType"> + <xs:annotation><xs:documentation> + A list of people. + </xs:documentation></xs:annotation> + </xs:element> + <xs:complexType name="peopleType"> + <xs:sequence> + <xs:element name="person" maxOccurs="unbounded" type="personType"/> + <xs:element name="specialperson" maxOccurs="unbounded" type="specialperson"/> + </xs:sequence> + </xs:complexType> + + <xs:element name="person" type="personType"> + <xs:annotation><xs:documentation> + A generic person. This is the base for a number of different + kinds of people. They are each an extension of this base + type of person. + </xs:documentation></xs:annotation> + </xs:element> + + <xs:complexType name="personType" mixed="0"> + <xs:sequence> + <xs:element name="name" type="xs:string"/> + <xs:element name="interest" type="xs:string" maxOccurs="unbounded" /> + <xs:element name="category" type="xs:integer" minOccurs="0" /> + <xs:element name="description" type="xs:string"/> + </xs:sequence> + <xs:attribute name="value" type="xs:ID" /> + <xs:attribute name="id" type="xs:integer" /> + <xs:attribute name="ratio" type="xs:float" /> + </xs:complexType> + +</xs:schema> diff --git a/tests/no_namespace_defs1_sub.py b/tests/no_namespace_defs1_sub.py new file mode 100644 index 0000000000000000000000000000000000000000..b54fcb2437d89727415e192418f763daf63868ce --- /dev/null +++ b/tests/no_namespace_defs1_sub.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python + +# +# Generated by generateDS.py. +# Python 2.7.14 (default, Sep 23 2017, 22:06:14) [GCC 7.2.0] +# +# Command line options: +# ('--no-dates', '') +# ('--no-versions', '') +# ('--disable-xml', '') +# ('--disable-generatedssuper-lookup', '') +# ('--member-specs', 'list') +# ('-f', '') +# ('-a', 'xsd:') +# ('-o', 'tests/no_namespace_defs2_sup.py') +# ('-s', 'tests/no_namespace_defs2_sub.py') +# ('--super', 'no_namespace_defs2_sup') +# ('--no-warnings', '') +# +# Command line arguments: +# tests/no_namespace_defs.xsd +# +# Command line: +# generateDS.py --no-dates --no-versions --disable-xml --disable-generatedssuper-lookup --member-specs="list" -f -a "xsd:" -o "tests/no_namespace_defs2_sup.py" -s "tests/no_namespace_defs2_sub.py" --super="no_namespace_defs2_sup" --no-warnings tests/no_namespace_defs.xsd +# +# Current working directory (os.getcwd()): +# generateds +# + +import sys +## from lxml import etree as etree_ + +import no_namespace_defs2_sup as supermod + +## def parsexml_(infile, parser=None, **kwargs): +## if parser is None: +## # Use the lxml ElementTree compatible parser so that, e.g., +## # we ignore comments. +## parser = etree_.ETCompatXMLParser() +## doc = etree_.parse(infile, parser=parser, **kwargs) +## return doc + +# +# Globals +# + +ExternalEncoding = 'ascii' + +# +# Data representation classes +# + + +class peopleTypeSub(supermod.peopleType): + def __init__(self, person=None, specialperson=None): + super(peopleTypeSub, self).__init__(person, specialperson, ) +supermod.peopleType.subclass = peopleTypeSub +# end class peopleTypeSub + + +class personTypeSub(supermod.personType): + def __init__(self, value=None, id=None, ratio=None, name=None, interest=None, category=None, description=None): + super(personTypeSub, self).__init__(value, id, ratio, name, interest, category, description, ) +supermod.personType.subclass = personTypeSub +# end class personTypeSub + + diff --git a/tests/no_namespace_defs1_sup.py b/tests/no_namespace_defs1_sup.py new file mode 100644 index 0000000000000000000000000000000000000000..ca8cbc78a3702ab448dc4b6757c97e206f27b98a --- /dev/null +++ b/tests/no_namespace_defs1_sup.py @@ -0,0 +1,849 @@ +## #!/usr/bin/env python +# -*- coding: utf-8 -*- + +# +# Generated by generateDS.py. +# Python 2.7.14 (default, Sep 23 2017, 22:06:14) [GCC 7.2.0] +# +# Command line options: +# ('--no-dates', '') +# ('--no-versions', '') +# ('--disable-xml', '') +# ('--disable-generatedssuper-lookup', '') +# ('--member-specs', 'list') +# ('-f', '') +# ('-a', 'xsd:') +# ('-o', 'tests/no_namespace_defs2_sup.py') +# ('-s', 'tests/no_namespace_defs2_sub.py') +# ('--super', 'no_namespace_defs2_sup') +# ('--no-warnings', '') +# +# Command line arguments: +# tests/no_namespace_defs.xsd +# +# Command line: +# generateDS.py --no-dates --no-versions --disable-xml --disable-generatedssuper-lookup --member-specs="list" -f -a "xsd:" -o "tests/no_namespace_defs2_sup.py" -s "tests/no_namespace_defs2_sub.py" --super="no_namespace_defs2_sup" --no-warnings tests/no_namespace_defs.xsd +# +# Current working directory (os.getcwd()): +# generateds +# + +import sys +import re as re_ +import base64 +import datetime as datetime_ +import warnings as warnings_ +## try: +## from lxml import etree as etree_ +## except ImportError: +## from xml.etree import ElementTree as etree_ + + +Validate_simpletypes_ = True +if sys.version_info.major == 2: + BaseStrType_ = basestring +else: + BaseStrType_ = str + + +## def parsexml_(infile, parser=None, **kwargs): +## if parser is None: +## # Use the lxml ElementTree compatible parser so that, e.g., +## # we ignore comments. +## try: +## parser = etree_.ETCompatXMLParser() +## except AttributeError: +## # fallback to xml.etree +## parser = etree_.XMLParser() +## doc = etree_.parse(infile, parser=parser, **kwargs) +## return doc + +## def parsexmlstring_(instring, parser=None, **kwargs): +## if parser is None: +## # Use the lxml ElementTree compatible parser so that, e.g., +## # we ignore comments. +## try: +## parser = etree_.ETCompatXMLParser() +## except AttributeError: +## # fallback to xml.etree +## parser = etree_.XMLParser() +## element = etree_.fromstring(instring, parser=parser, **kwargs) +## return element + +# +# Namespace prefix definition table (and other attributes, too) +# +# The module generatedsnamespaces, if it is importable, must contain +# a dictionary named GeneratedsNamespaceDefs. This Python dictionary +# should map element type names (strings) to XML schema namespace prefix +# definitions. The export method for any class for which there is +# a namespace prefix definition, will export that definition in the +# XML representation of that element. See the export method of +# any generated element type class for a example of the use of this +# table. +# A sample table is: +# +# # File: generatedsnamespaces.py +# +# GenerateDSNamespaceDefs = { +# "ElementtypeA": "http://www.xxx.com/namespaceA", +# "ElementtypeB": "http://www.xxx.com/namespaceB", +# } +# + +try: + from generatedsnamespaces import GenerateDSNamespaceDefs as GenerateDSNamespaceDefs_ +except ImportError: + GenerateDSNamespaceDefs_ = {} + +# +# The root super-class for element type classes +# +# Calls to the methods in these classes are generated by generateDS.py. +# You can replace these methods by re-implementing the following class +# in a module named generatedssuper.py. + + +class GeneratedsSuper(object): + tzoff_pattern = re_.compile(r'(\+|-)((0\d|1[0-3]):[0-5]\d|14:00)$') + class _FixedOffsetTZ(datetime_.tzinfo): + def __init__(self, offset, name): + self.__offset = datetime_.timedelta(minutes=offset) + self.__name = name + def utcoffset(self, dt): + return self.__offset + def tzname(self, dt): + return self.__name + def dst(self, dt): + return None + def gds_format_string(self, input_data, input_name=''): + return input_data + def gds_validate_string(self, input_data, node=None, input_name=''): + if not input_data: + return '' + else: + return input_data + def gds_format_base64(self, input_data, input_name=''): + return base64.b64encode(input_data) + def gds_validate_base64(self, input_data, node=None, input_name=''): + return input_data + def gds_format_integer(self, input_data, input_name=''): + return '%d' % input_data + def gds_validate_integer(self, input_data, node=None, input_name=''): + return input_data + def gds_format_integer_list(self, input_data, input_name=''): + return '%s' % ' '.join(input_data) + def gds_validate_integer_list( + self, input_data, node=None, input_name=''): + values = input_data.split() + for value in values: + try: + int(value) + except (TypeError, ValueError): + raise_parse_error(node, 'Requires sequence of integers') + return values + def gds_format_float(self, input_data, input_name=''): + return ('%.15f' % input_data).rstrip('0') + def gds_validate_float(self, input_data, node=None, input_name=''): + return input_data + def gds_format_float_list(self, input_data, input_name=''): + return '%s' % ' '.join(input_data) + def gds_validate_float_list( + self, input_data, node=None, input_name=''): + values = input_data.split() + for value in values: + try: + float(value) + except (TypeError, ValueError): + raise_parse_error(node, 'Requires sequence of floats') + return values + def gds_format_double(self, input_data, input_name=''): + return '%e' % input_data + def gds_validate_double(self, input_data, node=None, input_name=''): + return input_data + def gds_format_double_list(self, input_data, input_name=''): + return '%s' % ' '.join(input_data) + def gds_validate_double_list( + self, input_data, node=None, input_name=''): + values = input_data.split() + for value in values: + try: + float(value) + except (TypeError, ValueError): + raise_parse_error(node, 'Requires sequence of doubles') + return values + def gds_format_boolean(self, input_data, input_name=''): + return ('%s' % input_data).lower() + def gds_validate_boolean(self, input_data, node=None, input_name=''): + return input_data + def gds_format_boolean_list(self, input_data, input_name=''): + return '%s' % ' '.join(input_data) + def gds_validate_boolean_list( + self, input_data, node=None, input_name=''): + values = input_data.split() + for value in values: + if value not in ('true', '1', 'false', '0', ): + raise_parse_error( + node, + 'Requires sequence of booleans ' + '("true", "1", "false", "0")') + return values + def gds_validate_datetime(self, input_data, node=None, input_name=''): + return input_data + def gds_format_datetime(self, input_data, input_name=''): + if input_data.microsecond == 0: + _svalue = '%04d-%02d-%02dT%02d:%02d:%02d' % ( + input_data.year, + input_data.month, + input_data.day, + input_data.hour, + input_data.minute, + input_data.second, + ) + else: + _svalue = '%04d-%02d-%02dT%02d:%02d:%02d.%s' % ( + input_data.year, + input_data.month, + input_data.day, + input_data.hour, + input_data.minute, + input_data.second, + ('%f' % (float(input_data.microsecond) / 1000000))[2:], + ) + if input_data.tzinfo is not None: + tzoff = input_data.tzinfo.utcoffset(input_data) + if tzoff is not None: + total_seconds = tzoff.seconds + (86400 * tzoff.days) + if total_seconds == 0: + _svalue += 'Z' + else: + if total_seconds < 0: + _svalue += '-' + total_seconds *= -1 + else: + _svalue += '+' + hours = total_seconds // 3600 + minutes = (total_seconds - (hours * 3600)) // 60 + _svalue += '{0:02d}:{1:02d}'.format(hours, minutes) + return _svalue + @classmethod + def gds_parse_datetime(cls, input_data): + tz = None + if input_data[-1] == 'Z': + tz = GeneratedsSuper._FixedOffsetTZ(0, 'UTC') + input_data = input_data[:-1] + else: + results = GeneratedsSuper.tzoff_pattern.search(input_data) + if results is not None: + tzoff_parts = results.group(2).split(':') + tzoff = int(tzoff_parts[0]) * 60 + int(tzoff_parts[1]) + if results.group(1) == '-': + tzoff *= -1 + tz = GeneratedsSuper._FixedOffsetTZ( + tzoff, results.group(0)) + input_data = input_data[:-6] + time_parts = input_data.split('.') + if len(time_parts) > 1: + micro_seconds = int(float('0.' + time_parts[1]) * 1000000) + input_data = '%s.%s' % (time_parts[0], micro_seconds, ) + dt = datetime_.datetime.strptime( + input_data, '%Y-%m-%dT%H:%M:%S.%f') + else: + dt = datetime_.datetime.strptime( + input_data, '%Y-%m-%dT%H:%M:%S') + dt = dt.replace(tzinfo=tz) + return dt + def gds_validate_date(self, input_data, node=None, input_name=''): + return input_data + def gds_format_date(self, input_data, input_name=''): + _svalue = '%04d-%02d-%02d' % ( + input_data.year, + input_data.month, + input_data.day, + ) + try: + if input_data.tzinfo is not None: + tzoff = input_data.tzinfo.utcoffset(input_data) + if tzoff is not None: + total_seconds = tzoff.seconds + (86400 * tzoff.days) + if total_seconds == 0: + _svalue += 'Z' + else: + if total_seconds < 0: + _svalue += '-' + total_seconds *= -1 + else: + _svalue += '+' + hours = total_seconds // 3600 + minutes = (total_seconds - (hours * 3600)) // 60 + _svalue += '{0:02d}:{1:02d}'.format( + hours, minutes) + except AttributeError: + pass + return _svalue + @classmethod + def gds_parse_date(cls, input_data): + tz = None + if input_data[-1] == 'Z': + tz = GeneratedsSuper._FixedOffsetTZ(0, 'UTC') + input_data = input_data[:-1] + else: + results = GeneratedsSuper.tzoff_pattern.search(input_data) + if results is not None: + tzoff_parts = results.group(2).split(':') + tzoff = int(tzoff_parts[0]) * 60 + int(tzoff_parts[1]) + if results.group(1) == '-': + tzoff *= -1 + tz = GeneratedsSuper._FixedOffsetTZ( + tzoff, results.group(0)) + input_data = input_data[:-6] + dt = datetime_.datetime.strptime(input_data, '%Y-%m-%d') + dt = dt.replace(tzinfo=tz) + return dt.date() + def gds_validate_time(self, input_data, node=None, input_name=''): + return input_data + def gds_format_time(self, input_data, input_name=''): + if input_data.microsecond == 0: + _svalue = '%02d:%02d:%02d' % ( + input_data.hour, + input_data.minute, + input_data.second, + ) + else: + _svalue = '%02d:%02d:%02d.%s' % ( + input_data.hour, + input_data.minute, + input_data.second, + ('%f' % (float(input_data.microsecond) / 1000000))[2:], + ) + if input_data.tzinfo is not None: + tzoff = input_data.tzinfo.utcoffset(input_data) + if tzoff is not None: + total_seconds = tzoff.seconds + (86400 * tzoff.days) + if total_seconds == 0: + _svalue += 'Z' + else: + if total_seconds < 0: + _svalue += '-' + total_seconds *= -1 + else: + _svalue += '+' + hours = total_seconds // 3600 + minutes = (total_seconds - (hours * 3600)) // 60 + _svalue += '{0:02d}:{1:02d}'.format(hours, minutes) + return _svalue + def gds_validate_simple_patterns(self, patterns, target): + # pat is a list of lists of strings/patterns. We should: + # - AND the outer elements + # - OR the inner elements + found1 = True + for patterns1 in patterns: + found2 = False + for patterns2 in patterns1: + if re_.search(patterns2, target) is not None: + found2 = True + break + if not found2: + found1 = False + break + return found1 + @classmethod + def gds_parse_time(cls, input_data): + tz = None + if input_data[-1] == 'Z': + tz = GeneratedsSuper._FixedOffsetTZ(0, 'UTC') + input_data = input_data[:-1] + else: + results = GeneratedsSuper.tzoff_pattern.search(input_data) + if results is not None: + tzoff_parts = results.group(2).split(':') + tzoff = int(tzoff_parts[0]) * 60 + int(tzoff_parts[1]) + if results.group(1) == '-': + tzoff *= -1 + tz = GeneratedsSuper._FixedOffsetTZ( + tzoff, results.group(0)) + input_data = input_data[:-6] + if len(input_data.split('.')) > 1: + dt = datetime_.datetime.strptime(input_data, '%H:%M:%S.%f') + else: + dt = datetime_.datetime.strptime(input_data, '%H:%M:%S') + dt = dt.replace(tzinfo=tz) + return dt.time() + def gds_str_lower(self, instring): + return instring.lower() + def get_path_(self, node): + path_list = [] + self.get_path_list_(node, path_list) + path_list.reverse() + path = '/'.join(path_list) + return path + Tag_strip_pattern_ = re_.compile(r'\{.*\}') + def get_path_list_(self, node, path_list): + if node is None: + return + tag = GeneratedsSuper.Tag_strip_pattern_.sub('', node.tag) + if tag: + path_list.append(tag) + self.get_path_list_(node.getparent(), path_list) + def get_class_obj_(self, node, default_class=None): + class_obj1 = default_class + if 'xsi' in node.nsmap: + classname = node.get('{%s}type' % node.nsmap['xsi']) + if classname is not None: + names = classname.split(':') + if len(names) == 2: + classname = names[1] + class_obj2 = globals().get(classname) + if class_obj2 is not None: + class_obj1 = class_obj2 + return class_obj1 + def gds_build_any(self, node, type_name=None): + return None + @classmethod + def gds_reverse_node_mapping(cls, mapping): + return dict(((v, k) for k, v in mapping.iteritems())) + @staticmethod + def gds_encode(instring): + if sys.version_info.major == 2: + return instring.encode(ExternalEncoding) + else: + return instring + @staticmethod + def convert_unicode(instring): + if isinstance(instring, str): + result = quote_xml(instring) + elif sys.version_info.major == 2 and isinstance(instring, unicode): + result = quote_xml(instring).encode('utf8') + else: + result = GeneratedsSuper.gds_encode(str(instring)) + return result + def __eq__(self, other): + if type(self) != type(other): + return False + return self.__dict__ == other.__dict__ + def __ne__(self, other): + return not self.__eq__(other) + +def getSubclassFromModule_(module, class_): + '''Get the subclass of a class from a specific module.''' + name = class_.__name__ + 'Sub' + if hasattr(module, name): + return getattr(module, name) + else: + return None + + +# +# If you have installed IPython you can uncomment and use the following. +# IPython is available from http://ipython.scipy.org/. +# + +## from IPython.Shell import IPShellEmbed +## args = '' +## ipshell = IPShellEmbed(args, +## banner = 'Dropping into IPython', +## exit_msg = 'Leaving Interpreter, back to program.') + +# Then use the following line where and when you want to drop into the +# IPython shell: +# ipshell('<some message> -- Entering ipshell.\nHit Ctrl-D to exit') + +# +# Globals +# + +ExternalEncoding = 'ascii' +Tag_pattern_ = re_.compile(r'({.*})?(.*)') +String_cleanup_pat_ = re_.compile(r"[\n\r\s]+") +Namespace_extract_pat_ = re_.compile(r'{(.*)}(.*)') +CDATA_pattern_ = re_.compile(r"<!\[CDATA\[.*?\]\]>", re_.DOTALL) + +# Change this to redirect the generated superclass module to use a +# specific subclass module. +CurrentSubclassModule_ = None + +# +# Support/utility functions. +# + + +def showIndent(outfile, level, pretty_print=True): + if pretty_print: + for idx in range(level): + outfile.write(' ') + + +def quote_xml(inStr): + "Escape markup chars, but do not modify CDATA sections." + if not inStr: + return '' + s1 = (isinstance(inStr, BaseStrType_) and inStr or '%s' % inStr) + s2 = '' + pos = 0 + matchobjects = CDATA_pattern_.finditer(s1) + for mo in matchobjects: + s3 = s1[pos:mo.start()] + s2 += quote_xml_aux(s3) + s2 += s1[mo.start():mo.end()] + pos = mo.end() + s3 = s1[pos:] + s2 += quote_xml_aux(s3) + return s2 + + +def quote_xml_aux(inStr): + s1 = inStr.replace('&', '&') + s1 = s1.replace('<', '<') + s1 = s1.replace('>', '>') + return s1 + + +def quote_attrib(inStr): + s1 = (isinstance(inStr, BaseStrType_) and inStr or '%s' % inStr) + s1 = s1.replace('&', '&') + s1 = s1.replace('<', '<') + s1 = s1.replace('>', '>') + if '"' in s1: + if "'" in s1: + s1 = '"%s"' % s1.replace('"', """) + else: + s1 = "'%s'" % s1 + else: + s1 = '"%s"' % s1 + return s1 + + +def quote_python(inStr): + s1 = inStr + if s1.find("'") == -1: + if s1.find('\n') == -1: + return "'%s'" % s1 + else: + return "'''%s'''" % s1 + else: + if s1.find('"') != -1: + s1 = s1.replace('"', '\\"') + if s1.find('\n') == -1: + return '"%s"' % s1 + else: + return '"""%s"""' % s1 + + +def get_all_text_(node): + if node.text is not None: + text = node.text + else: + text = '' + for child in node: + if child.tail is not None: + text += child.tail + return text + + +def find_attr_value_(attr_name, node): + attrs = node.attrib + attr_parts = attr_name.split(':') + value = None + if len(attr_parts) == 1: + value = attrs.get(attr_name) + elif len(attr_parts) == 2: + prefix, name = attr_parts + namespace = node.nsmap.get(prefix) + if namespace is not None: + value = attrs.get('{%s}%s' % (namespace, name, )) + return value + + +class GDSParseError(Exception): + pass + + +def raise_parse_error(node, msg): + msg = '%s (element %s/line %d)' % (msg, node.tag, node.sourceline, ) + raise GDSParseError(msg) + + +class MixedContainer: + # Constants for category: + CategoryNone = 0 + CategoryText = 1 + CategorySimple = 2 + CategoryComplex = 3 + # Constants for content_type: + TypeNone = 0 + TypeText = 1 + TypeString = 2 + TypeInteger = 3 + TypeFloat = 4 + TypeDecimal = 5 + TypeDouble = 6 + TypeBoolean = 7 + TypeBase64 = 8 + def __init__(self, category, content_type, name, value): + self.category = category + self.content_type = content_type + self.name = name + self.value = value + def getCategory(self): + return self.category + def getContenttype(self, content_type): + return self.content_type + def getValue(self): + return self.value + def getName(self): + return self.name +## def export(self, outfile, level, name, namespace, +## pretty_print=True): +## if self.category == MixedContainer.CategoryText: +## # Prevent exporting empty content as empty lines. +## if self.value.strip(): +## outfile.write(self.value) +## elif self.category == MixedContainer.CategorySimple: +## self.exportSimple(outfile, level, name) +## else: # category == MixedContainer.CategoryComplex +## self.value.export( +## outfile, level, namespace, name, +## pretty_print=pretty_print) +## def exportSimple(self, outfile, level, name): +## if self.content_type == MixedContainer.TypeString: +## outfile.write('<%s>%s</%s>' % ( +## self.name, self.value, self.name)) +## elif self.content_type == MixedContainer.TypeInteger or \ +## self.content_type == MixedContainer.TypeBoolean: +## outfile.write('<%s>%d</%s>' % ( +## self.name, self.value, self.name)) +## elif self.content_type == MixedContainer.TypeFloat or \ +## self.content_type == MixedContainer.TypeDecimal: +## outfile.write('<%s>%f</%s>' % ( +## self.name, self.value, self.name)) +## elif self.content_type == MixedContainer.TypeDouble: +## outfile.write('<%s>%g</%s>' % ( +## self.name, self.value, self.name)) +## elif self.content_type == MixedContainer.TypeBase64: +## outfile.write('<%s>%s</%s>' % ( +## self.name, +## base64.b64encode(self.value), +## self.name)) +## def to_etree(self, element): +## if self.category == MixedContainer.CategoryText: +## # Prevent exporting empty content as empty lines. +## if self.value.strip(): +## if len(element) > 0: +## if element[-1].tail is None: +## element[-1].tail = self.value +## else: +## element[-1].tail += self.value +## else: +## if element.text is None: +## element.text = self.value +## else: +## element.text += self.value +## elif self.category == MixedContainer.CategorySimple: +## subelement = etree_.SubElement( +## element, '%s' % self.name) +## subelement.text = self.to_etree_simple() +## else: # category == MixedContainer.CategoryComplex +## self.value.to_etree(element) +## def to_etree_simple(self): +## if self.content_type == MixedContainer.TypeString: +## text = self.value +## elif (self.content_type == MixedContainer.TypeInteger or +## self.content_type == MixedContainer.TypeBoolean): +## text = '%d' % self.value +## elif (self.content_type == MixedContainer.TypeFloat or +## self.content_type == MixedContainer.TypeDecimal): +## text = '%f' % self.value +## elif self.content_type == MixedContainer.TypeDouble: +## text = '%g' % self.value +## elif self.content_type == MixedContainer.TypeBase64: +## text = '%s' % base64.b64encode(self.value) +## return text +## def exportLiteral(self, outfile, level, name): +## if self.category == MixedContainer.CategoryText: +## showIndent(outfile, level) +## outfile.write( +## 'model_.MixedContainer(%d, %d, "%s", "%s"),\n' % ( +## self.category, self.content_type, +## self.name, self.value)) +## elif self.category == MixedContainer.CategorySimple: +## showIndent(outfile, level) +## outfile.write( +## 'model_.MixedContainer(%d, %d, "%s", "%s"),\n' % ( +## self.category, self.content_type, +## self.name, self.value)) +## else: # category == MixedContainer.CategoryComplex +## showIndent(outfile, level) +## outfile.write( +## 'model_.MixedContainer(%d, %d, "%s",\n' % ( +## self.category, self.content_type, self.name,)) +## self.value.exportLiteral(outfile, level + 1) +## showIndent(outfile, level) +## outfile.write(')\n') + + +class MemberSpec_(object): + def __init__(self, name='', data_type='', container=0, + optional=0, child_attrs=None, choice=None): + self.name = name + self.data_type = data_type + self.container = container + self.child_attrs = child_attrs + self.choice = choice + self.optional = optional + def set_name(self, name): self.name = name + def get_name(self): return self.name + def set_data_type(self, data_type): self.data_type = data_type + def get_data_type_chain(self): return self.data_type + def get_data_type(self): + if isinstance(self.data_type, list): + if len(self.data_type) > 0: + return self.data_type[-1] + else: + return 'xs:string' + else: + return self.data_type + def set_container(self, container): self.container = container + def get_container(self): return self.container + def set_child_attrs(self, child_attrs): self.child_attrs = child_attrs + def get_child_attrs(self): return self.child_attrs + def set_choice(self, choice): self.choice = choice + def get_choice(self): return self.choice + def set_optional(self, optional): self.optional = optional + def get_optional(self): return self.optional + + +def _cast(typ, value): + if typ is None or value is None: + return value + return typ(value) + +# +# Data representation classes. +# + + +class peopleType(GeneratedsSuper): + member_data_items_ = [ + MemberSpec_('person', 'personType', 1, 0, {u'maxOccurs': u'unbounded', u'type': u'personType', u'name': u'person'}, None), + MemberSpec_('specialperson', 'xs:string', 1, 0, {u'maxOccurs': u'unbounded', u'type': u'xs:string', u'name': u'specialperson'}, None), + ] + subclass = None + superclass = None + def __init__(self, person=None, specialperson=None): + self.original_tagname_ = None + if person is None: + self.person = [] + else: + self.person = person + if specialperson is None: + self.specialperson = [] + else: + self.specialperson = specialperson + def factory(*args_, **kwargs_): + if CurrentSubclassModule_ is not None: + subclass = getSubclassFromModule_( + CurrentSubclassModule_, peopleType) + if subclass is not None: + return subclass(*args_, **kwargs_) + if peopleType.subclass: + return peopleType.subclass(*args_, **kwargs_) + else: + return peopleType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_person(self): return self.person + def set_person(self, person): self.person = person + def add_person(self, value): self.person.append(value) + def insert_person_at(self, index, value): self.person.insert(index, value) + def replace_person_at(self, index, value): self.person[index] = value + def get_specialperson(self): return self.specialperson + def set_specialperson(self, specialperson): self.specialperson = specialperson + def add_specialperson(self, value): self.specialperson.append(value) + def insert_specialperson_at(self, index, value): self.specialperson.insert(index, value) + def replace_specialperson_at(self, index, value): self.specialperson[index] = value + def hasContent_(self): + if ( + self.person or + self.specialperson + ): + return True + else: + return False +# end class peopleType + + +class personType(GeneratedsSuper): + member_data_items_ = [ + MemberSpec_('value', 'xs:string', 0, 1, {'use': 'optional'}), + MemberSpec_('id', 'xs:integer', 0, 1, {'use': 'optional'}), + MemberSpec_('ratio', 'xs:float', 0, 1, {'use': 'optional'}), + MemberSpec_('name', 'xs:string', 0, 0, {u'type': u'xs:string', u'name': u'name'}, None), + MemberSpec_('interest', 'xs:string', 1, 0, {u'maxOccurs': u'unbounded', u'type': u'xs:string', u'name': u'interest'}, None), + MemberSpec_('category', 'xs:integer', 0, 1, {u'type': u'xs:integer', u'name': u'category', u'minOccurs': u'0'}, None), + MemberSpec_('description', 'xs:string', 0, 0, {u'type': u'xs:string', u'name': u'description'}, None), + ] + subclass = None + superclass = None + def __init__(self, value=None, id=None, ratio=None, name=None, interest=None, category=None, description=None): + self.original_tagname_ = None + self.value = _cast(None, value) + self.id = _cast(int, id) + self.ratio = _cast(float, ratio) + self.name = name + if interest is None: + self.interest = [] + else: + self.interest = interest + self.category = category + self.description = description + def factory(*args_, **kwargs_): + if CurrentSubclassModule_ is not None: + subclass = getSubclassFromModule_( + CurrentSubclassModule_, personType) + if subclass is not None: + return subclass(*args_, **kwargs_) + if personType.subclass: + return personType.subclass(*args_, **kwargs_) + else: + return personType(*args_, **kwargs_) + factory = staticmethod(factory) + def get_name(self): return self.name + def set_name(self, name): self.name = name + def get_interest(self): return self.interest + def set_interest(self, interest): self.interest = interest + def add_interest(self, value): self.interest.append(value) + def insert_interest_at(self, index, value): self.interest.insert(index, value) + def replace_interest_at(self, index, value): self.interest[index] = value + def get_category(self): return self.category + def set_category(self, category): self.category = category + def get_description(self): return self.description + def set_description(self, description): self.description = description + def get_value(self): return self.value + def set_value(self, value): self.value = value + def get_id(self): return self.id + def set_id(self, id): self.id = id + def get_ratio(self): return self.ratio + def set_ratio(self, ratio): self.ratio = ratio + def hasContent_(self): + if ( + self.name is not None or + self.interest or + self.category is not None or + self.description is not None + ): + return True + else: + return False +# end class personType + + +GDSClassesMapping = { + 'people': peopleType, + 'person': personType, +} + + + +__all__ = [ + "peopleType", + "personType" +] diff --git a/tests/test.py b/tests/test.py index 56a70b9ab52c53ccc680a1508dcf7bedbe575a92..ffa9bf7ed869f6ff0a68093e6ec33f8a5d2f10f7 100755 --- a/tests/test.py +++ b/tests/test.py @@ -899,6 +899,31 @@ class GenTest(unittest.TestCase): self.remove('{}2_sub.py'.format(t_)) self.remove('{}2_out.xml'.format(t_)) + # + # Test for command line option --no-namespace-defs. + def test_036_no_namespace_defs(self): + cmdTempl = ( + 'python generateDS.py --no-dates --no-versions ' + '--disable-xml --disable-generatedssuper-lookup ' + '--member-specs=list -f -a "xsd:" ' + '-o tests/%s2_sup.py -s tests/%s2_sub.py ' + '--super=%s2_sup --no-warnings ' + 'tests/%s.xsd' + ) + t_ = 'no_namespace_defs' + cmd = cmdTempl % (t_, t_, t_, t_, ) + self.executeClean(cmd, cwd='..') + self.compareFiles( + '{}1_sup.py'.format(t_), + '{}2_sup.py'.format(t_), + ('sys.stdout.write',)) + self.compareFiles('{}1_sub.py'.format(t_), '{}2_sub.py'.format(t_)) + # Need to preserve generated files for next command, cleanup at end + # cleanup generated files + #self.remove('{}2_sup.py'.format(t_)) + #self.remove('{}2_sub.py'.format(t_)) + #self.remove('{}2_out.xml'.format(t_)) + def compareFiles(self, left, right, ignore=None): with open(left) as left_file: with open(right) as right_file: diff --git a/tutorial/generateds_tutorial.html b/tutorial/generateds_tutorial.html index 4b83f308a40e6ebea72592190e992cca031a3051..c8c30d80d0cee692db91693cbf54ee828cbf9930 100644 --- a/tutorial/generateds_tutorial.html +++ b/tutorial/generateds_tutorial.html @@ -219,7 +219,7 @@ They are used by updateversion.py. --> <col class="field-name" /> <col class="field-body" /> <tbody valign="top"> -<tr class="field"><th class="field-name">revision:</th><td class="field-body">2.29.10</td> +<tr class="field"><th class="field-name">revision:</th><td class="field-body">2.29.11</td> </tr> </tbody> </table> @@ -228,7 +228,7 @@ They are used by updateversion.py. --> <col class="field-name" /> <col class="field-body" /> <tbody valign="top"> -<tr class="field"><th class="field-name">date:</th><td class="field-body">March 14, 2018</td> +<tr class="field"><th class="field-name">date:</th><td class="field-body">March 16, 2018</td> </tr> </tbody> </table> @@ -1210,7 +1210,7 @@ named <tt class="docutils literal">garden_api.py</tt>, you can create an instanc <div class="footer"> <hr class="footer" /> <a class="reference external" href="generateds_tutorial.txt">View document source</a>. -Generated on: 2018-03-14 18:27 UTC. +Generated on: 2018-03-16 20:52 UTC. Generated by <a class="reference external" href="http://docutils.sourceforge.net/">Docutils</a> from <a class="reference external" href="http://docutils.sourceforge.net/rst.html">reStructuredText</a> source. </div> diff --git a/tutorial/generateds_tutorial.txt b/tutorial/generateds_tutorial.txt index e89fa7e49ccc08eb347308acbcaa1e0bf5136329..421804363af912a48854fe99d3c4828e42a67eaf 100644 --- a/tutorial/generateds_tutorial.txt +++ b/tutorial/generateds_tutorial.txt @@ -11,7 +11,7 @@ generateDS -- Introduction and Tutorial .. version -:revision: 2.29.10 +:revision: 2.29.11 .. version diff --git a/tutorial/generateds_tutorial.zip b/tutorial/generateds_tutorial.zip index febd5dad5775f685cfc1d863691555447c06084d..e7990575fca2070f20ed4e6f7e2ac5703cd65229 100644 Binary files a/tutorial/generateds_tutorial.zip and b/tutorial/generateds_tutorial.zip differ