From 7dbae20668ad8edc558b007afa9ecc82eda90aca Mon Sep 17 00:00:00 2001 From: Nicolas Geimer Date: Wed, 14 Jun 2017 17:32:16 +0200 Subject: [PATCH] [PY3] Fixing test in progress --- src/engine_swig/engtypemaps.i | 96 +- src/engine_swig/pilot.i | 78 +- src/pmml/pmml_swig/PMMLBasicsTest.py | 16 +- src/pmml/pmml_swig/PMMLBasicsTestLauncher.py | 2 +- src/runtime/PythonNode.cxx | 2 +- src/runtime/Test/xmlrun_orig.sh | 48 +- src/runtime/TypeConversions.cxx | 15 +- src/salomeloader/CMakeLists.txt | 2 - src/salomeloader/ElementPath.py | 196 --- src/salomeloader/ElementTree.py | 1254 ----------------- src/salomeloader/salomeloader.py | 4 +- src/salomeloader/testSalomeLoader.py.in | 9 +- src/yacsloader/Test/YacsLoaderTest.cxx | 4 +- src/yacsloader/Test/xmlrun_orig.sh | 48 +- src/yacsloader/samples/schemaANN2.xml | 2 +- src/yacsloader/samples/schemaANNLR2.xml | 4 +- src/yacsloader/samples/schemaLR2.xml | 2 +- .../samples/schemaPmmlDoesNotExist.xml | 2 +- 18 files changed, 258 insertions(+), 1526 deletions(-) delete mode 100644 src/salomeloader/ElementPath.py delete mode 100644 src/salomeloader/ElementTree.py diff --git a/src/engine_swig/engtypemaps.i b/src/engine_swig/engtypemaps.i index f0c708635..1ed0ee20f 100644 --- a/src/engine_swig/engtypemaps.i +++ b/src/engine_swig/engtypemaps.i @@ -274,7 +274,7 @@ static void convertFromPyObjVectorOfObj(PyObject *pyLi, swig_type_info *ty, cons $result = PyList_New($1.size()); for (i=0, iL=$1.begin(); iL!=$1.end(); i++, iL++) - PyList_SetItem($result,i,PyString_FromString((*iL).c_str())); + PyList_SetItem($result,i,PyUnicode_FromString((*iL).c_str())); } %typemap(in) std::list @@ -289,8 +289,8 @@ static void convertFromPyObjVectorOfObj(PyObject *pyLi, swig_type_info *ty, cons for (i = 0; i < size; i++) { PyObject *o = PyList_GetItem($input,i); - if (PyString_Check(o)) - $1.push_back(std::string(PyString_AsString(PyList_GetItem($input,i)))); + if (PyUnicode_Check(o)) + $1.push_back(std::string(PyUnicode_AsUTF8(PyList_GetItem($input,i)))); else { PyErr_SetString(PyExc_TypeError,"list must contain strings"); @@ -314,11 +314,13 @@ static void convertFromPyObjVectorOfObj(PyObject *pyLi, swig_type_info *ty, cons void *ptr; if (SWIG_ConvertPtr($input, (void **) &ptr, $1_descriptor, 0) == 0) $1 = 1; - else if (PyInt_Check($input)) + else if (PyLong_Check($input)) $1 = 1; else if(PyFloat_Check($input)) $1 = 1; - else if (PyString_Check($input)) + else if (PyUnicode_Check($input)) + $1 = 1; + else if (PyBytes_Check($input)) $1 = 1; else $1 = 0; @@ -331,10 +333,10 @@ static void convertFromPyObjVectorOfObj(PyObject *pyLi, swig_type_info *ty, cons // It is an Any : it is converted by SWIG_ConvertPtr $input -> $1 is_new_object=0; } - else if (PyInt_Check($input)) + else if (PyLong_Check($input)) { // It is an Int - $1=YACS::ENGINE::AtomAny::New((int)PyInt_AsLong($input)); + $1=YACS::ENGINE::AtomAny::New((int)PyLong_AsLong($input)); is_new_object=1; } else if(PyFloat_Check($input)) @@ -343,10 +345,16 @@ static void convertFromPyObjVectorOfObj(PyObject *pyLi, swig_type_info *ty, cons $1=YACS::ENGINE::AtomAny::New(PyFloat_AsDouble($input)); is_new_object=1; } - else if(PyString_Check($input)) + else if(PyUnicode_Check($input)) { - // It is a Float - $1=YACS::ENGINE::AtomAny::New(PyString_AsString($input)); + // It is a Unicode + $1=YACS::ENGINE::AtomAny::New(PyUnicode_AsUTF8($input)); + is_new_object=1; + } + else if(PyBytes_Check($input)) + { + // It is a Bytes + $1=YACS::ENGINE::AtomAny::New(PyBytes_AsString($input)); is_new_object=1; } else @@ -366,17 +374,22 @@ static void convertFromPyObjVectorOfObj(PyObject *pyLi, swig_type_info *ty, cons else if (PyInt_Check($1)) { // It is an Int - $result=YACS::ENGINE::AtomAny::New((int)PyInt_AsLong($1)); + $result=YACS::ENGINE::AtomAny::New((int)PyLong_AsLong($1)); } else if(PyFloat_Check($1)) { // It is a Float $result=YACS::ENGINE::AtomAny::New(PyFloat_AsDouble($1)); } - else if(PyString_Check($1)) + else if(PyUnicode_Check($1)) + { + // It is a Unicode + $result=YACS::ENGINE::AtomAny::New(PyUnicode_AsUTF8($1)); + } + else if(PyBytes_Check($1)) { - // It is a String - $result=YACS::ENGINE::AtomAny::New(PyString_AsString($1)); + // It is a Bytes + $result=YACS::ENGINE::AtomAny::New(PyBytes_AsString($1)); } else { @@ -828,6 +841,48 @@ static void convertFromPyObjVectorOfObj(PyObject *pyLi, swig_type_info *ty, cons Objects returned by __getitem__ are declared new (%newobject) so that when destroyed they call decrRef (see feature("unref") for RefCounter). */ +/* +%inline %{ +template class StopIterator {}; +template class Iterator { + public: + Iterator(std::map::iterator _cur, std::map::iterator _end) : cur(_cur), end(_end) {} + Iterator* __iter__() + { + return this; + } + template std::map::iterator cur; + template std::map::iterator end; + }; +%} + +%include "exception.i" +%exception Iterator::next { + try + { + $action // calls %extend function next() below + } + catch (StopIterator) + { + PyErr_SetString(PyExc_StopIteration, "End of iterator"); + return NULL; + } +} + +%extend Iterator +{ + std::map& next() + { + if ($self->cur != $self->end) + { + // dereference the iterator and return reference to the object, + // after that it increments the iterator + return *$self->cur++; + } + throw StopIterator(); + } +} +*/ template<> class std::map { @@ -872,10 +927,21 @@ public: PyObject* keyList = PyList_New(pysize); std::map::const_iterator i = self->begin(); for (int j = 0; j < pysize; ++i, ++j) { - PyList_SET_ITEM(keyList, j, PyString_FromString(i->first.c_str())); + PyList_SET_ITEM(keyList, j, PyUnicode_FromString(i->first.c_str())); } return keyList; } +/* Iterator __iter__() + { + // return a constructed Iterator object + return Iterator($self->begin(), $self->end()); + } +*/ + int __len__() + { + int pysize = self->size(); + return pysize; + } } }; diff --git a/src/engine_swig/pilot.i b/src/engine_swig/pilot.i index 34a28121a..c8568336d 100644 --- a/src/engine_swig/pilot.i +++ b/src/engine_swig/pilot.i @@ -237,13 +237,50 @@ EXCEPTION(YACS::ENGINE::ExecutorSwig::waitPause) %include %extend YACS::ENGINE::Port { - int __cmp__(Port* other) + /* __cmp__ does not exist in Python 3 */ + int __lt__(Port* other) { if(self==other) return 0; else return 1; } + int __gt__(Port* other) + { + if(self==other) + return 0; + else + return 1; + } + int __ne__(Port* other) + { + if(self==other) + return 0; + else + return 1; + } + int __eq__(Port* other) + { + if(self==other) + return 0; + else + return 1; + } + int __le__(Port* other) + { + if(self==other) + return 0; + else + return 1; + } + int __ge__(Port* other) + { + if(self==other) + return 0; + else + return 1; + } + long ptr() { return (long)self; @@ -304,13 +341,50 @@ EXCEPTION(YACS::ENGINE::ExecutorSwig::waitPause) %include %extend YACS::ENGINE::Node { - int __cmp__(Node* other) + /* __cmp__ does not exist in Python 3 */ + int __lt__(Node* other) { if(self==other) return 0; else return 1; } + int __gt__(Node* other) + { + if(self==other) + return 0; + else + return 1; + } + int __ne__(Node* other) + { + if(self==other) + return 0; + else + return 1; + } + int __eq__(Node* other) + { + if(self==other) + return 0; + else + return 1; + } + int __le__(Node* other) + { + if(self==other) + return 0; + else + return 1; + } + int __ge__(Node* other) + { + if(self==other) + return 0; + else + return 1; + } + long ptr() { return (long)self; diff --git a/src/pmml/pmml_swig/PMMLBasicsTest.py b/src/pmml/pmml_swig/PMMLBasicsTest.py index d82c3142b..b3bcc6015 100755 --- a/src/pmml/pmml_swig/PMMLBasicsTest.py +++ b/src/pmml/pmml_swig/PMMLBasicsTest.py @@ -23,8 +23,6 @@ from PMML import PMMLlib, kANN, kLR # imports python import unittest -import exceptions -from exceptions import RuntimeError import os import shutil @@ -36,7 +34,7 @@ class PMMLBasicsTest(unittest.TestCase): self.tmpDir += "PmmlUnitTest"; self.tmpDir += os.sep ; if ( not os.path.exists(self.tmpDir) ): - os.mkdir(self.tmpDir); + os.makedirs(self.tmpDir); pass pass @@ -51,13 +49,15 @@ class PMMLBasicsTest(unittest.TestCase): model = "sANNName"; exportPyScript = self.tmpDir + "swigTestExportPythonNeuralNet.py"; refPyFilename = self.resourcesDir + "unittest_ref_ann_model.py"; - refLines = file(refPyFilename).readlines(); + with open(refPyFilename,"r") as f: + refLines = f.readlines(); # p = PMMLlib( pmmlFile ); p.SetCurrentModel( model, kANN ); p.ExportPython( exportPyScript, "myTestFunc", "File used by unit test\n PMMLBasicsTest1::testExportNeuralNetworkPython" ); - myLines = file(exportPyScript).readlines(); + with open(exportPyScript,"r") as f: + myLines = f.readlines(); self.assertEqual( len(myLines), len(refLines) ); for (i,line) in enumerate(myLines): self.assertEqual( line, refLines[i] ); @@ -69,13 +69,15 @@ class PMMLBasicsTest(unittest.TestCase): model = "Modeler[LinearRegression]Tds[steamplant]Predictor[x6:x8:x6x8:x6x6x8]Target[x1]"; exportPyScript = self.tmpDir + "swigTestExportPythonRegression.py"; refPyFilename = self.resourcesDir + "unittest_ref_lr_model.py"; - refLines = file(refPyFilename).readlines(); + with open(refPyFilename,"r") as f: + refLines = f.readlines(); # p = PMMLlib( pmmlFile ); p.SetCurrentModel( model, kLR ); p.ExportPython( exportPyScript, "myTestFunc", "File used by unit test\n PMMLBasicsTest1::testExportLinearRegressionPython" ); - myLines = file(exportPyScript).readlines(); + with open(exportPyScript,"r") as f: + myLines = f.readlines(); self.assertEqual( len(myLines), len(refLines) ); for (i,line) in enumerate(myLines): self.assertEqual( line, refLines[i] ); diff --git a/src/pmml/pmml_swig/PMMLBasicsTestLauncher.py b/src/pmml/pmml_swig/PMMLBasicsTestLauncher.py index 836d6ab56..7e440e272 100755 --- a/src/pmml/pmml_swig/PMMLBasicsTestLauncher.py +++ b/src/pmml/pmml_swig/PMMLBasicsTestLauncher.py @@ -31,7 +31,7 @@ if not os.path.exists(os.path.join(dirALaCon0,dirAlaCon1)): os.chdir("..") # GO ! dn=os.path.dirname(__file__) -p=subprocess.Popen(["python","PMMLBasicsTest.py"],cwd=dn,stdout=subprocess.PIPE,stderr=subprocess.PIPE) +p=subprocess.Popen(["python3","PMMLBasicsTest.py"],cwd=dn,stdout=subprocess.PIPE,stderr=subprocess.PIPE) a,b=p.communicate() ret=p.returncode # Clean up the wonderful first part stuf diff --git a/src/runtime/PythonNode.cxx b/src/runtime/PythonNode.cxx index 02e8e302c..1fa4c4dc9 100644 --- a/src/runtime/PythonNode.cxx +++ b/src/runtime/PythonNode.cxx @@ -42,7 +42,7 @@ typedef int Py_ssize_t; #endif -//#define _DEVDEBUG_ +#define _DEVDEBUG_ #include "YacsTrace.hxx" using namespace YACS::ENGINE; diff --git a/src/runtime/Test/xmlrun_orig.sh b/src/runtime/Test/xmlrun_orig.sh index f890fb858..b1914c7cb 100755 --- a/src/runtime/Test/xmlrun_orig.sh +++ b/src/runtime/Test/xmlrun_orig.sh @@ -34,9 +34,8 @@ def echo(args): print(args) return args -f=open("input") -data=f.read() -f.close() +with open("input",'r') as f: + data=f.read() print(data) class Objref: @@ -45,10 +44,32 @@ class Objref: self.data=data def __str__(self): return self.data or "" - def __cmp__(self, other): + +# __cmp__ is not defined in Python 3 : strict ordering + def __le__(self, other): + if isinstance(other, Binary): + other = other.data + return self.data <= other + def __lt__(self, other): + if isinstance(other, Binary): + other = other.data + return self.data < other + def __ge__(self, other): + if isinstance(other, Binary): + other = other.data + return self.data >= other + def __gt__(self, other): + if isinstance(other, Binary): + other = other.data + return self.data > other + def __eq__(self, other): + if isinstance(other, Binary): + other = other.data + return self.data == other + def __ne__(self, other): if isinstance(other, Binary): other = other.data - return cmp(self.data, other) + return self.data != other def decode(self, data): self.data = data @@ -70,16 +91,15 @@ xmlrpc.client.Unmarshaller.dispatch["objref"]=end_objref params, method = xmlrpc.client.loads(data) try: - call=eval(method) - response=call(params) - response = (response,) + call=eval(method) + response=call(params) + response = (response,) except: - # report exception back to server - response = xmlrpc.client.dumps( xmlrpc.client.Fault(1, "%s:%s" % sys.exc_info()[:2])) + # report exception back to server + response = xmlrpc.client.dumps( xmlrpc.client.Fault(1, "%s:%s" % sys.exc_info()[:2])) else: - response = xmlrpc.client.dumps( response, methodresponse=1) + response = xmlrpc.client.dumps( response, methodresponse=1) print(response) -f=open("output",'w') -f.write(response) -f.close() +with open("output",'w') as f: + f.write(response) diff --git a/src/runtime/TypeConversions.cxx b/src/runtime/TypeConversions.cxx index adabc6439..895508f8f 100644 --- a/src/runtime/TypeConversions.cxx +++ b/src/runtime/TypeConversions.cxx @@ -991,11 +991,11 @@ namespace YACS //It's an objref file. Convert it specially return PyUnicode_FromString(o.c_str()); } - if(strncmp(t->id(),"python",6)==0) + if(strncmp(t->id(),"python",6)==0) //ex: "python:obj:1.0" { //It's a python pickled object, unpickled it PyObject* mod=PyImport_ImportModule("pickle"); - PyObject *ob=PyObject_CallMethod(mod,(char *)"loads",(char *)"s#",o.c_str(),o.length()); + PyObject *ob=PyObject_CallMethod(mod,(char *)"loads",(char *)"y#",o.c_str(),o.length()); DEBTRACE(PyObject_Repr(ob)); Py_DECREF(mod); if(ob==NULL) @@ -1014,7 +1014,7 @@ namespace YACS PyErr_Print(); throw YACS::ENGINE::ConversionException("Problem in convertToYacsObjreflength()); + PyObject *ob=PyObject_CallMethod(mod,(char *)"loads",(char *)"y#",s,buffer->length()); PyObject *pickled=PyObject_CallMethod(mod,(char *)"dumps",(char *)"Oi",ob,protocol); DEBTRACE(PyObject_Repr(pickled)); std::string mystr=PyBytes_AsString(pickled); @@ -2301,8 +2301,11 @@ namespace YACS { PyObject *s; PyGILState_STATE gstate = PyGILState_Ensure(); - s=PyObject_Str(ob); - std::string ss(PyBytes_AsString(s),PyBytes_Size(s)); + //s=PyObject_Repr(ob); + s=PyObject_ASCII(ob); + Py_ssize_t size; + char* characters=PyUnicode_AsUTF8AndSize(s, &size); + std::string ss( characters, size); Py_DECREF(s); PyGILState_Release(gstate); return ss; diff --git a/src/salomeloader/CMakeLists.txt b/src/salomeloader/CMakeLists.txt index 70be1f0f1..72d2d79bf 100644 --- a/src/salomeloader/CMakeLists.txt +++ b/src/salomeloader/CMakeLists.txt @@ -25,8 +25,6 @@ ENDIF() SET(salomeloader_PYTHON salomeloader.py - ElementTree.py - ElementPath.py graph.py ) diff --git a/src/salomeloader/ElementPath.py b/src/salomeloader/ElementPath.py deleted file mode 100644 index 8d8d28df3..000000000 --- a/src/salomeloader/ElementPath.py +++ /dev/null @@ -1,196 +0,0 @@ -# -# ElementTree -# $Id$ -# -# limited xpath support for element trees -# -# history: -# 2003-05-23 fl created -# 2003-05-28 fl added support for // etc -# 2003-08-27 fl fixed parsing of periods in element names -# -# Copyright (c) 2003-2004 by Fredrik Lundh. All rights reserved. -# -# fredrik@pythonware.com -# http://www.pythonware.com -# -# -------------------------------------------------------------------- -# The ElementTree toolkit is -# -# Copyright (c) 1999-2004 by Fredrik Lundh -# -# By obtaining, using, and/or copying this software and/or its -# associated documentation, you agree that you have read, understood, -# and will comply with the following terms and conditions: -# -# Permission to use, copy, modify, and distribute this software and -# its associated documentation for any purpose and without fee is -# hereby granted, provided that the above copyright notice appears in -# all copies, and that both that copyright notice and this permission -# notice appear in supporting documentation, and that the name of -# Secret Labs AB or the author not be used in advertising or publicity -# pertaining to distribution of the software without specific, written -# prior permission. -# -# SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD -# TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- -# ABILITY AND FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR -# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY -# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS -# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE -# OF THIS SOFTWARE. -# -------------------------------------------------------------------- - -## -# Implementation module for XPath support. There's usually no reason -# to import this module directly; the ElementTree does this for -# you, if needed. -## - -import re - -xpath_tokenizer = re.compile( - "(::|\.\.|\(\)|[/.*:\[\]\(\)@=])|((?:\{[^}]+\})?[^/:\[\]\(\)@=\s]+)|\s+" - ).findall - -class xpath_descendant_or_self: - pass - -## -# Wrapper for a compiled XPath. - -class Path: - - ## - # Create an Path instance from an XPath expression. - - def __init__(self, path): - tokens = xpath_tokenizer(path) - # the current version supports 'path/path'-style expressions only - self.path = [] - self.tag = None - if tokens and tokens[0][0] == "/": - raise SyntaxError("cannot use absolute path on element") - while tokens: - op, tag = tokens.pop(0) - if tag or op == "*": - self.path.append(tag or op) - elif op == ".": - pass - elif op == "/": - self.path.append(xpath_descendant_or_self()) - continue - else: - raise SyntaxError("unsupported path syntax (%s)" % op) - if tokens: - op, tag = tokens.pop(0) - if op != "/": - raise SyntaxError( - "expected path separator (%s)" % (op or tag) - ) - if self.path and isinstance(self.path[-1], xpath_descendant_or_self): - raise SyntaxError("path cannot end with //") - if len(self.path) == 1 and isinstance(self.path[0], type("")): - self.tag = self.path[0] - - ## - # Find first matching object. - - def find(self, element): - tag = self.tag - if tag is None: - nodeset = self.findall(element) - if not nodeset: - return None - return nodeset[0] - for elem in element: - if elem.tag == tag: - return elem - return None - - ## - # Find text for first matching object. - - def findtext(self, element, default=None): - tag = self.tag - if tag is None: - nodeset = self.findall(element) - if not nodeset: - return default - return nodeset[0].text or "" - for elem in element: - if elem.tag == tag: - return elem.text or "" - return default - - ## - # Find all matching objects. - - def findall(self, element): - nodeset = [element] - index = 0 - while 1: - try: - path = self.path[index] - index = index + 1 - except IndexError: - return nodeset - set = [] - if isinstance(path, xpath_descendant_or_self): - try: - tag = self.path[index] - if not isinstance(tag, type("")): - tag = None - else: - index = index + 1 - except IndexError: - tag = None # invalid path - for node in nodeset: - new = list(node.getiterator(tag)) - if new and new[0] is node: - set.extend(new[1:]) - else: - set.extend(new) - else: - for node in nodeset: - for node in node: - if path == "*" or node.tag == path: - set.append(node) - if not set: - return [] - nodeset = set - -_cache = {} - -## -# (Internal) Compile path. - -def _compile(path): - p = _cache.get(path) - if p is not None: - return p - p = Path(path) - if len(_cache) >= 100: - _cache.clear() - _cache[path] = p - return p - -## -# Find first matching object. - -def find(element, path): - return _compile(path).find(element) - -## -# Find text for first matching object. - -def findtext(element, path, default=None): - return _compile(path).findtext(element, default) - -## -# Find all matching objects. - -def findall(element, path): - return _compile(path).findall(element) - diff --git a/src/salomeloader/ElementTree.py b/src/salomeloader/ElementTree.py deleted file mode 100644 index 366e5b7ef..000000000 --- a/src/salomeloader/ElementTree.py +++ /dev/null @@ -1,1254 +0,0 @@ -# -# ElementTree -# $Id$ -# -# light-weight XML support for Python 1.5.2 and later. -# -# history: -# 2001-10-20 fl created (from various sources) -# 2001-11-01 fl return root from parse method -# 2002-02-16 fl sort attributes in lexical order -# 2002-04-06 fl TreeBuilder refactoring, added PythonDoc markup -# 2002-05-01 fl finished TreeBuilder refactoring -# 2002-07-14 fl added basic namespace support to ElementTree.write -# 2002-07-25 fl added QName attribute support -# 2002-10-20 fl fixed encoding in write -# 2002-11-24 fl changed default encoding to ascii; fixed attribute encoding -# 2002-11-27 fl accept file objects or file names for parse/write -# 2002-12-04 fl moved XMLTreeBuilder back to this module -# 2003-01-11 fl fixed entity encoding glitch for us-ascii -# 2003-02-13 fl added XML literal factory -# 2003-02-21 fl added ProcessingInstruction/PI factory -# 2003-05-11 fl added tostring/fromstring helpers -# 2003-05-26 fl added ElementPath support -# 2003-07-05 fl added makeelement factory method -# 2003-07-28 fl added more well-known namespace prefixes -# 2003-08-15 fl fixed typo in ElementTree.findtext (Thomas Dartsch) -# 2003-09-04 fl fall back on emulator if ElementPath is not installed -# 2003-10-31 fl markup updates -# 2003-11-15 fl fixed nested namespace bug -# 2004-03-28 fl added XMLID helper -# 2004-06-02 fl added default support to findtext -# 2004-06-08 fl fixed encoding of non-ascii element/attribute names -# 2004-08-23 fl take advantage of post-2.1 expat features -# 2005-02-01 fl added iterparse implementation -# 2005-03-02 fl fixed iterparse support for pre-2.2 versions -# -# Copyright (c) 1999-2005 by Fredrik Lundh. All rights reserved. -# -# fredrik@pythonware.com -# http://www.pythonware.com -# -# -------------------------------------------------------------------- -# The ElementTree toolkit is -# -# Copyright (c) 1999-2005 by Fredrik Lundh -# -# By obtaining, using, and/or copying this software and/or its -# associated documentation, you agree that you have read, understood, -# and will comply with the following terms and conditions: -# -# Permission to use, copy, modify, and distribute this software and -# its associated documentation for any purpose and without fee is -# hereby granted, provided that the above copyright notice appears in -# all copies, and that both that copyright notice and this permission -# notice appear in supporting documentation, and that the name of -# Secret Labs AB or the author not be used in advertising or publicity -# pertaining to distribution of the software without specific, written -# prior permission. -# -# SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD -# TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- -# ABILITY AND FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR -# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY -# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS -# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE -# OF THIS SOFTWARE. -# -------------------------------------------------------------------- - -__all__ = [ - # public symbols - "Comment", - "dump", - "Element", "ElementTree", - "fromstring", - "iselement", "iterparse", - "parse", - "PI", "ProcessingInstruction", - "QName", - "SubElement", - "tostring", - "TreeBuilder", - "VERSION", "XML", - "XMLTreeBuilder", - ] - -## -# The Element type is a flexible container object, designed to -# store hierarchical data structures in memory. The type can be -# described as a cross between a list and a dictionary. -#

-# Each element has a number of properties associated with it: -#

    -#
  • a tag. This is a string identifying what kind of data -# this element represents (the element type, in other words).
  • -#
  • a number of attributes, stored in a Python dictionary.
  • -#
  • a text string.
  • -#
  • an optional tail string.
  • -#
  • a number of child elements, stored in a Python sequence
  • -#
-# -# To create an element instance, use the {@link #Element} or {@link -# #SubElement} factory functions. -#

-# The {@link #ElementTree} class can be used to wrap an element -# structure, and convert it from and to XML. -## - -import string, sys, re - -class _SimpleElementPath: - # emulate pre-1.2 find/findtext/findall behaviour - def find(self, element, tag): - for elem in element: - if elem.tag == tag: - return elem - return None - def findtext(self, element, tag, default=None): - for elem in element: - if elem.tag == tag: - return elem.text or "" - return default - def findall(self, element, tag): - if tag[:3] == ".//": - return element.getiterator(tag[3:]) - result = [] - for elem in element: - if elem.tag == tag: - result.append(elem) - return result - -try: - import ElementPath -except ImportError: - # FIXME: issue warning in this case? - ElementPath = _SimpleElementPath() - -# TODO: add support for custom namespace resolvers/default namespaces -# TODO: add improved support for incremental parsing - -VERSION = "1.2.6" - -## -# Internal element class. This class defines the Element interface, -# and provides a reference implementation of this interface. -#

-# You should not create instances of this class directly. Use the -# appropriate factory functions instead, such as {@link #Element} -# and {@link #SubElement}. -# -# @see Element -# @see SubElement -# @see Comment -# @see ProcessingInstruction - -class _ElementInterface: - # text...tail - - ## - # (Attribute) Element tag. - - tag = None - - ## - # (Attribute) Element attribute dictionary. Where possible, use - # {@link #_ElementInterface.get}, - # {@link #_ElementInterface.set}, - # {@link #_ElementInterface.keys}, and - # {@link #_ElementInterface.items} to access - # element attributes. - - attrib = None - - ## - # (Attribute) Text before first subelement. This is either a - # string or the value None, if there was no text. - - text = None - - ## - # (Attribute) Text after this element's end tag, but before the - # next sibling element's start tag. This is either a string or - # the value None, if there was no text. - - tail = None # text after end tag, if any - - def __init__(self, tag, attrib): - self.tag = tag - self.attrib = attrib - self._children = [] - - def __repr__(self): - return "" % (self.tag, id(self)) - - ## - # Creates a new element object of the same type as this element. - # - # @param tag Element tag. - # @param attrib Element attributes, given as a dictionary. - # @return A new element instance. - - def makeelement(self, tag, attrib): - return Element(tag, attrib) - - ## - # Returns the number of subelements. - # - # @return The number of subelements. - - def __len__(self): - return len(self._children) - - ## - # Returns the given subelement. - # - # @param index What subelement to return. - # @return The given subelement. - # @exception IndexError If the given element does not exist. - - def __getitem__(self, index): - return self._children[index] - - ## - # Replaces the given subelement. - # - # @param index What subelement to replace. - # @param element The new element value. - # @exception IndexError If the given element does not exist. - # @exception AssertionError If element is not a valid object. - - def __setitem__(self, index, element): - assert iselement(element) - self._children[index] = element - - ## - # Deletes the given subelement. - # - # @param index What subelement to delete. - # @exception IndexError If the given element does not exist. - - def __delitem__(self, index): - del self._children[index] - - ## - # Returns a list containing subelements in the given range. - # - # @param start The first subelement to return. - # @param stop The first subelement that shouldn't be returned. - # @return A sequence object containing subelements. - - def __getslice__(self, start, stop): - return self._children[start:stop] - - ## - # Replaces a number of subelements with elements from a sequence. - # - # @param start The first subelement to replace. - # @param stop The first subelement that shouldn't be replaced. - # @param elements A sequence object with zero or more elements. - # @exception AssertionError If a sequence member is not a valid object. - - def __setslice__(self, start, stop, elements): - for element in elements: - assert iselement(element) - self._children[start:stop] = list(elements) - - ## - # Deletes a number of subelements. - # - # @param start The first subelement to delete. - # @param stop The first subelement to leave in there. - - def __delslice__(self, start, stop): - del self._children[start:stop] - - ## - # Adds a subelement to the end of this element. - # - # @param element The element to add. - # @exception AssertionError If a sequence member is not a valid object. - - def append(self, element): - assert iselement(element) - self._children.append(element) - - ## - # Inserts a subelement at the given position in this element. - # - # @param index Where to insert the new subelement. - # @exception AssertionError If the element is not a valid object. - - def insert(self, index, element): - assert iselement(element) - self._children.insert(index, element) - - ## - # Removes a matching subelement. Unlike the find methods, - # this method compares elements based on identity, not on tag - # value or contents. - # - # @param element What element to remove. - # @exception ValueError If a matching element could not be found. - # @exception AssertionError If the element is not a valid object. - - def remove(self, element): - assert iselement(element) - self._children.remove(element) - - ## - # Returns all subelements. The elements are returned in document - # order. - # - # @return A list of subelements. - # @defreturn list of Element instances - - def getchildren(self): - return self._children - - ## - # Finds the first matching subelement, by tag name or path. - # - # @param path What element to look for. - # @return The first matching element, or None if no element was found. - # @defreturn Element or None - - def find(self, path): - return ElementPath.find(self, path) - - ## - # Finds text for the first matching subelement, by tag name or path. - # - # @param path What element to look for. - # @param default What to return if the element was not found. - # @return The text content of the first matching element, or the - # default value no element was found. Note that if the element - # has is found, but has no text content, this method returns an - # empty string. - # @defreturn string - - def findtext(self, path, default=None): - return ElementPath.findtext(self, path, default) - - ## - # Finds all matching subelements, by tag name or path. - # - # @param path What element to look for. - # @return A list or iterator containing all matching elements, - # in document order. - # @defreturn list of Element instances - - def findall(self, path): - return ElementPath.findall(self, path) - - ## - # Resets an element. This function removes all subelements, clears - # all attributes, and sets the text and tail attributes to None. - - def clear(self): - self.attrib.clear() - self._children = [] - self.text = self.tail = None - - ## - # Gets an element attribute. - # - # @param key What attribute to look for. - # @param default What to return if the attribute was not found. - # @return The attribute value, or the default value, if the - # attribute was not found. - # @defreturn string or None - - def get(self, key, default=None): - return self.attrib.get(key, default) - - ## - # Sets an element attribute. - # - # @param key What attribute to set. - # @param value The attribute value. - - def set(self, key, value): - self.attrib[key] = value - - ## - # Gets a list of attribute names. The names are returned in an - # arbitrary order (just like for an ordinary Python dictionary). - # - # @return A list of element attribute names. - # @defreturn list of strings - - def keys(self): - return list(self.attrib.keys()) - - ## - # Gets element attributes, as a sequence. The attributes are - # returned in an arbitrary order. - # - # @return A list of (name, value) tuples for all attributes. - # @defreturn list of (string, string) tuples - - def items(self): - return list(self.attrib.items()) - - ## - # Creates a tree iterator. The iterator loops over this element - # and all subelements, in document order, and returns all elements - # with a matching tag. - #

- # If the tree structure is modified during iteration, the result - # is undefined. - # - # @param tag What tags to look for (default is to return all elements). - # @return A list or iterator containing all the matching elements. - # @defreturn list or iterator - - def getiterator(self, tag=None): - nodes = [] - if tag == "*": - tag = None - if tag is None or self.tag == tag: - nodes.append(self) - for node in self._children: - nodes.extend(node.getiterator(tag)) - return nodes - -# compatibility -_Element = _ElementInterface - -## -# Element factory. This function returns an object implementing the -# standard Element interface. The exact class or type of that object -# is implementation dependent, but it will always be compatible with -# the {@link #_ElementInterface} class in this module. -#

-# The element name, attribute names, and attribute values can be -# either 8-bit ASCII strings or Unicode strings. -# -# @param tag The element name. -# @param attrib An optional dictionary, containing element attributes. -# @param **extra Additional attributes, given as keyword arguments. -# @return An element instance. -# @defreturn Element - -def Element(tag, attrib={}, **extra): - attrib = attrib.copy() - attrib.update(extra) - return _ElementInterface(tag, attrib) - -## -# Subelement factory. This function creates an element instance, and -# appends it to an existing element. -#

-# The element name, attribute names, and attribute values can be -# either 8-bit ASCII strings or Unicode strings. -# -# @param parent The parent element. -# @param tag The subelement name. -# @param attrib An optional dictionary, containing element attributes. -# @param **extra Additional attributes, given as keyword arguments. -# @return An element instance. -# @defreturn Element - -def SubElement(parent, tag, attrib={}, **extra): - attrib = attrib.copy() - attrib.update(extra) - element = parent.makeelement(tag, attrib) - parent.append(element) - return element - -## -# Comment element factory. This factory function creates a special -# element that will be serialized as an XML comment. -#

-# The comment string can be either an 8-bit ASCII string or a Unicode -# string. -# -# @param text A string containing the comment string. -# @return An element instance, representing a comment. -# @defreturn Element - -def Comment(text=None): - element = Element(Comment) - element.text = text - return element - -## -# PI element factory. This factory function creates a special element -# that will be serialized as an XML processing instruction. -# -# @param target A string containing the PI target. -# @param text A string containing the PI contents, if any. -# @return An element instance, representing a PI. -# @defreturn Element - -def ProcessingInstruction(target, text=None): - element = Element(ProcessingInstruction) - element.text = target - if text: - element.text = element.text + " " + text - return element - -PI = ProcessingInstruction - -## -# QName wrapper. This can be used to wrap a QName attribute value, in -# order to get proper namespace handling on output. -# -# @param text A string containing the QName value, in the form {uri}local, -# or, if the tag argument is given, the URI part of a QName. -# @param tag Optional tag. If given, the first argument is interpreted as -# an URI, and this argument is interpreted as a local name. -# @return An opaque object, representing the QName. - -class QName: - def __init__(self, text_or_uri, tag=None): - if tag: - text_or_uri = "{%s}%s" % (text_or_uri, tag) - self.text = text_or_uri - def __str__(self): - return self.text - def __hash__(self): - return hash(self.text) - def __cmp__(self, other): - if isinstance(other, QName): - return cmp(self.text, other.text) - return cmp(self.text, other) - -## -# ElementTree wrapper class. This class represents an entire element -# hierarchy, and adds some extra support for serialization to and from -# standard XML. -# -# @param element Optional root element. -# @keyparam file Optional file handle or name. If given, the -# tree is initialized with the contents of this XML file. - -class ElementTree: - - def __init__(self, element=None, file=None): - assert element is None or iselement(element) - self._root = element # first node - if file: - self.parse(file) - - ## - # Gets the root element for this tree. - # - # @return An element instance. - # @defreturn Element - - def getroot(self): - return self._root - - ## - # Replaces the root element for this tree. This discards the - # current contents of the tree, and replaces it with the given - # element. Use with care. - # - # @param element An element instance. - - def _setroot(self, element): - assert iselement(element) - self._root = element - - ## - # Loads an external XML document into this element tree. - # - # @param source A file name or file object. - # @param parser An optional parser instance. If not given, the - # standard {@link XMLTreeBuilder} parser is used. - # @return The document root element. - # @defreturn Element - - def parse(self, source, parser=None): - if not hasattr(source, "read"): - source = open(source, "rb") - if not parser: - parser = XMLTreeBuilder() - while 1: - data = source.read(32768) - if not data: - break - parser.feed(data) - self._root = parser.close() - return self._root - - ## - # Creates a tree iterator for the root element. The iterator loops - # over all elements in this tree, in document order. - # - # @param tag What tags to look for (default is to return all elements) - # @return An iterator. - # @defreturn iterator - - def getiterator(self, tag=None): - assert self._root is not None - return self._root.getiterator(tag) - - ## - # Finds the first toplevel element with given tag. - # Same as getroot().find(path). - # - # @param path What element to look for. - # @return The first matching element, or None if no element was found. - # @defreturn Element or None - - def find(self, path): - assert self._root is not None - if path[:1] == "/": - path = "." + path - return self._root.find(path) - - ## - # Finds the element text for the first toplevel element with given - # tag. Same as getroot().findtext(path). - # - # @param path What toplevel element to look for. - # @param default What to return if the element was not found. - # @return The text content of the first matching element, or the - # default value no element was found. Note that if the element - # has is found, but has no text content, this method returns an - # empty string. - # @defreturn string - - def findtext(self, path, default=None): - assert self._root is not None - if path[:1] == "/": - path = "." + path - return self._root.findtext(path, default) - - ## - # Finds all toplevel elements with the given tag. - # Same as getroot().findall(path). - # - # @param path What element to look for. - # @return A list or iterator containing all matching elements, - # in document order. - # @defreturn list of Element instances - - def findall(self, path): - assert self._root is not None - if path[:1] == "/": - path = "." + path - return self._root.findall(path) - - ## - # Writes the element tree to a file, as XML. - # - # @param file A file name, or a file object opened for writing. - # @param encoding Optional output encoding (default is US-ASCII). - - def write(self, file, encoding="us-ascii"): - assert self._root is not None - if not hasattr(file, "write"): - file = open(file, "wb") - if not encoding: - encoding = "us-ascii" - elif encoding != "utf-8" and encoding != "us-ascii": - file.write("\n" % encoding) - self._write(file, self._root, encoding, {}) - - def _write(self, file, node, encoding, namespaces): - # write XML to file - tag = node.tag - if tag is Comment: - file.write("" % _escape_cdata(node.text, encoding)) - elif tag is ProcessingInstruction: - file.write("" % _escape_cdata(node.text, encoding)) - else: - items = list(node.items()) - xmlns_items = [] # new namespaces in this scope - try: - if isinstance(tag, QName) or tag[:1] == "{": - tag, xmlns = fixtag(tag, namespaces) - if xmlns: xmlns_items.append(xmlns) - except TypeError: - _raise_serialization_error(tag) - file.write("<" + _encode(tag, encoding)) - if items or xmlns_items: - items.sort() # lexical order - for k, v in items: - try: - if isinstance(k, QName) or k[:1] == "{": - k, xmlns = fixtag(k, namespaces) - if xmlns: xmlns_items.append(xmlns) - except TypeError: - _raise_serialization_error(k) - try: - if isinstance(v, QName): - v, xmlns = fixtag(v, namespaces) - if xmlns: xmlns_items.append(xmlns) - except TypeError: - _raise_serialization_error(v) - file.write(" %s=\"%s\"" % (_encode(k, encoding), - _escape_attrib(v, encoding))) - for k, v in xmlns_items: - file.write(" %s=\"%s\"" % (_encode(k, encoding), - _escape_attrib(v, encoding))) - if node.text or len(node): - file.write(">") - if node.text: - file.write(_escape_cdata(node.text, encoding)) - for n in node: - self._write(file, n, encoding, namespaces) - file.write("") - else: - file.write(" />") - for k, v in xmlns_items: - del namespaces[v] - if node.tail: - file.write(_escape_cdata(node.tail, encoding)) - -# -------------------------------------------------------------------- -# helpers - -## -# Checks if an object appears to be a valid element object. -# -# @param An element instance. -# @return A true value if this is an element object. -# @defreturn flag - -def iselement(element): - # FIXME: not sure about this; might be a better idea to look - # for tag/attrib/text attributes - return isinstance(element, _ElementInterface) or hasattr(element, "tag") - -## -# Writes an element tree or element structure to sys.stdout. This -# function should be used for debugging only. -#

-# The exact output format is implementation dependent. In this -# version, it's written as an ordinary XML file. -# -# @param elem An element tree or an individual element. - -def dump(elem): - # debugging - if not isinstance(elem, ElementTree): - elem = ElementTree(elem) - elem.write(sys.stdout) - tail = elem.getroot().tail - if not tail or tail[-1] != "\n": - sys.stdout.write("\n") - -def _encode(s, encoding): - try: - return s.encode(encoding) - except AttributeError: - return s # 1.5.2: assume the string uses the right encoding - -if sys.version[:3] == "1.5": - _escape = re.compile(r"[&<>\"\x80-\xff]+") # 1.5.2 -else: - _escape = re.compile(eval(r'u"[&<>\"\u0080-\uffff]+"')) - -_escape_map = { - "&": "&", - "<": "<", - ">": ">", - '"': """, -} - -_namespace_map = { - # "well-known" namespace prefixes - "http://www.w3.org/XML/1998/namespace": "xml", - "http://www.w3.org/1999/xhtml": "html", - "http://www.w3.org/1999/02/22-rdf-syntax-ns#": "rdf", - "http://schemas.xmlsoap.org/wsdl/": "wsdl", -} - -def _raise_serialization_error(text): - raise TypeError( - "cannot serialize %r (type %s)" % (text, type(text).__name__) - ) - -def _encode_entity(text, pattern=_escape): - # map reserved and non-ascii characters to numerical entities - def escape_entities(m, map=_escape_map): - out = [] - append = out.append - for char in m.group(): - text = map.get(char) - if text is None: - text = "&#%d;" % ord(char) - append(text) - return string.join(out, "") - try: - return _encode(pattern.sub(escape_entities, text), "ascii") - except TypeError: - _raise_serialization_error(text) - -# -# the following functions assume an ascii-compatible encoding -# (or "utf-16") - -def _escape_cdata(text, encoding=None, replace=string.replace): - # escape character data - try: - if encoding: - try: - text = _encode(text, encoding) - except UnicodeError: - return _encode_entity(text) - text = replace(text, "&", "&") - text = replace(text, "<", "<") - text = replace(text, ">", ">") - return text - except (TypeError, AttributeError): - _raise_serialization_error(text) - -def _escape_attrib(text, encoding=None, replace=string.replace): - # escape attribute value - try: - if encoding: - try: - text = _encode(text, encoding) - except UnicodeError: - return _encode_entity(text) - text = replace(text, "&", "&") - text = replace(text, "'", "'") # FIXME: overkill - text = replace(text, "\"", """) - text = replace(text, "<", "<") - text = replace(text, ">", ">") - return text - except (TypeError, AttributeError): - _raise_serialization_error(text) - -def fixtag(tag, namespaces): - # given a decorated tag (of the form {uri}tag), return prefixed - # tag and namespace declaration, if any - if isinstance(tag, QName): - tag = tag.text - namespace_uri, tag = string.split(tag[1:], "}", 1) - prefix = namespaces.get(namespace_uri) - if prefix is None: - prefix = _namespace_map.get(namespace_uri) - if prefix is None: - prefix = "ns%d" % len(namespaces) - namespaces[namespace_uri] = prefix - if prefix == "xml": - xmlns = None - else: - xmlns = ("xmlns:%s" % prefix, namespace_uri) - else: - xmlns = None - return "%s:%s" % (prefix, tag), xmlns - -## -# Parses an XML document into an element tree. -# -# @param source A filename or file object containing XML data. -# @param parser An optional parser instance. If not given, the -# standard {@link XMLTreeBuilder} parser is used. -# @return An ElementTree instance - -def parse(source, parser=None): - tree = ElementTree() - tree.parse(source, parser) - return tree - -## -# Parses an XML document into an element tree incrementally, and reports -# what's going on to the user. -# -# @param source A filename or file object containing XML data. -# @param events A list of events to report back. If omitted, only "end" -# events are reported. -# @return A (event, elem) iterator. - -class iterparse: - - def __init__(self, source, events=None): - if not hasattr(source, "read"): - source = open(source, "rb") - self._file = source - self._events = [] - self._index = 0 - self.root = self._root = None - self._parser = XMLTreeBuilder() - # wire up the parser for event reporting - parser = self._parser._parser - append = self._events.append - if events is None: - events = ["end"] - for event in events: - if event == "start": - try: - parser.ordered_attributes = 1 - parser.specified_attributes = 1 - def handler(tag, attrib_in, event=event, append=append, - start=self._parser._start_list): - append((event, start(tag, attrib_in))) - parser.StartElementHandler = handler - except AttributeError: - def handler(tag, attrib_in, event=event, append=append, - start=self._parser._start): - append((event, start(tag, attrib_in))) - parser.StartElementHandler = handler - elif event == "end": - def handler(tag, event=event, append=append, - end=self._parser._end): - append((event, end(tag))) - parser.EndElementHandler = handler - elif event == "start-ns": - def handler(prefix, uri, event=event, append=append): - try: - uri = _encode(uri, "ascii") - except UnicodeError: - pass - append((event, (prefix or "", uri))) - parser.StartNamespaceDeclHandler = handler - elif event == "end-ns": - def handler(prefix, event=event, append=append): - append((event, None)) - parser.EndNamespaceDeclHandler = handler - - def __next__(self): - while 1: - try: - item = self._events[self._index] - except IndexError: - if self._parser is None: - self.root = self._root - try: - raise StopIteration - except NameError: - raise IndexError - # load event buffer - del self._events[:] - self._index = 0 - data = self._file.read(16384) - if data: - self._parser.feed(data) - else: - self._root = self._parser.close() - self._parser = None - else: - self._index = self._index + 1 - return item - - try: - iter - def __iter__(self): - return self - except NameError: - def __getitem__(self, index): - return next(self) - -## -# Parses an XML document from a string constant. This function can -# be used to embed "XML literals" in Python code. -# -# @param source A string containing XML data. -# @return An Element instance. -# @defreturn Element - -def XML(text): - parser = XMLTreeBuilder() - parser.feed(text) - return parser.close() - -## -# Parses an XML document from a string constant, and also returns -# a dictionary which maps from element id:s to elements. -# -# @param source A string containing XML data. -# @return A tuple containing an Element instance and a dictionary. -# @defreturn (Element, dictionary) - -def XMLID(text): - parser = XMLTreeBuilder() - parser.feed(text) - tree = parser.close() - ids = {} - for elem in tree.getiterator(): - id = elem.get("id") - if id: - ids[id] = elem - return tree, ids - -## -# Parses an XML document from a string constant. Same as {@link #XML}. -# -# @def fromstring(text) -# @param source A string containing XML data. -# @return An Element instance. -# @defreturn Element - -fromstring = XML - -## -# Generates a string representation of an XML element, including all -# subelements. -# -# @param element An Element instance. -# @return An encoded string containing the XML data. -# @defreturn string - -def tostring(element, encoding=None): - class dummy: - pass - data = [] - file = dummy() - file.write = data.append - ElementTree(element).write(file, encoding) - return string.join(data, "") - -## -# Generic element structure builder. This builder converts a sequence -# of {@link #TreeBuilder.start}, {@link #TreeBuilder.data}, and {@link -# #TreeBuilder.end} method calls to a well-formed element structure. -#

-# You can use this class to build an element structure using a custom XML -# parser, or a parser for some other XML-like format. -# -# @param element_factory Optional element factory. This factory -# is called to create new Element instances, as necessary. - -class TreeBuilder: - - def __init__(self, element_factory=None): - self._data = [] # data collector - self._elem = [] # element stack - self._last = None # last element - self._tail = None # true if we're after an end tag - if element_factory is None: - element_factory = _ElementInterface - self._factory = element_factory - - ## - # Flushes the parser buffers, and returns the toplevel documen - # element. - # - # @return An Element instance. - # @defreturn Element - - def close(self): - assert len(self._elem) == 0, "missing end tags" - assert self._last != None, "missing toplevel element" - return self._last - - def _flush(self): - if self._data: - if self._last is not None: - text = string.join(self._data, "") - if self._tail: - assert self._last.tail is None, "internal error (tail)" - self._last.tail = text - else: - assert self._last.text is None, "internal error (text)" - self._last.text = text - self._data = [] - - ## - # Adds text to the current element. - # - # @param data A string. This should be either an 8-bit string - # containing ASCII text, or a Unicode string. - - def data(self, data): - self._data.append(data) - - ## - # Opens a new element. - # - # @param tag The element name. - # @param attrib A dictionary containing element attributes. - # @return The opened element. - # @defreturn Element - - def start(self, tag, attrs): - self._flush() - self._last = elem = self._factory(tag, attrs) - if self._elem: - self._elem[-1].append(elem) - self._elem.append(elem) - self._tail = 0 - return elem - - ## - # Closes the current element. - # - # @param tag The element name. - # @return The closed element. - # @defreturn Element - - def end(self, tag): - self._flush() - self._last = self._elem.pop() - assert self._last.tag == tag,\ - "end tag mismatch (expected %s, got %s)" % ( - self._last.tag, tag) - self._tail = 1 - return self._last - -## -# Element structure builder for XML source data, based on the -# expat parser. -# -# @keyparam target Target object. If omitted, the builder uses an -# instance of the standard {@link #TreeBuilder} class. -# @keyparam html Predefine HTML entities. This flag is not supported -# by the current implementation. -# @see #ElementTree -# @see #TreeBuilder - -class XMLTreeBuilder: - - def __init__(self, html=0, target=None): - try: - from xml.parsers import expat - except ImportError: - raise ImportError( - "No module named expat; use SimpleXMLTreeBuilder instead" - ) - self._parser = parser = expat.ParserCreate(None, "}") - if target is None: - target = TreeBuilder() - self._target = target - self._names = {} # name memo cache - # callbacks - parser.DefaultHandlerExpand = self._default - parser.StartElementHandler = self._start - parser.EndElementHandler = self._end - parser.CharacterDataHandler = self._data - # let expat do the buffering, if supported - try: - self._parser.buffer_text = 1 - except AttributeError: - pass - # use new-style attribute handling, if supported - try: - self._parser.ordered_attributes = 1 - self._parser.specified_attributes = 1 - parser.StartElementHandler = self._start_list - except AttributeError: - pass - encoding = None - if not parser.returns_unicode: - encoding = "utf-8" - # target.xml(encoding, None) - self._doctype = None - self.entity = {} - - def _fixtext(self, text): - # convert text string to ascii, if possible - try: - return _encode(text, "ascii") - except UnicodeError: - return text - - def _fixname(self, key): - # expand qname, and convert name string to ascii, if possible - try: - name = self._names[key] - except KeyError: - name = key - if "}" in name: - name = "{" + name - self._names[key] = name = self._fixtext(name) - return name - - def _start(self, tag, attrib_in): - fixname = self._fixname - tag = fixname(tag) - attrib = {} - for key, value in list(attrib_in.items()): - attrib[fixname(key)] = self._fixtext(value) - return self._target.start(tag, attrib) - - def _start_list(self, tag, attrib_in): - fixname = self._fixname - tag = fixname(tag) - attrib = {} - if attrib_in: - for i in range(0, len(attrib_in), 2): - attrib[fixname(attrib_in[i])] = self._fixtext(attrib_in[i+1]) - return self._target.start(tag, attrib) - - def _data(self, text): - return self._target.data(self._fixtext(text)) - - def _end(self, tag): - return self._target.end(self._fixname(tag)) - - def _default(self, text): - prefix = text[:1] - if prefix == "&": - # deal with undefined entities - try: - self._target.data(self.entity[text[1:-1]]) - except KeyError: - from xml.parsers import expat - raise expat.error( - "undefined entity %s: line %d, column %d" % - (text, self._parser.ErrorLineNumber, - self._parser.ErrorColumnNumber) - ) - elif prefix == "<" and text[:9] == "": - self._doctype = None - return - text = string.strip(text) - if not text: - return - self._doctype.append(text) - n = len(self._doctype) - if n > 2: - type = self._doctype[1] - if type == "PUBLIC" and n == 4: - name, type, pubid, system = self._doctype - elif type == "SYSTEM" and n == 3: - name, type, system = self._doctype - pubid = None - else: - return - if pubid: - pubid = pubid[1:-1] - self.doctype(name, pubid, system[1:-1]) - self._doctype = None - - ## - # Handles a doctype declaration. - # - # @param name Doctype name. - # @param pubid Public identifier. - # @param system System identifier. - - def doctype(self, name, pubid, system): - pass - - ## - # Feeds data to the parser. - # - # @param data Encoded data. - - def feed(self, data): - self._parser.Parse(data, 0) - - ## - # Finishes feeding data to the parser. - # - # @return An element structure. - # @defreturn Element - - def close(self): - self._parser.Parse("", 1) # end of data - tree = self._target.close() - del self._target, self._parser # get rid of circular references - return tree diff --git a/src/salomeloader/salomeloader.py b/src/salomeloader/salomeloader.py index 68be1a656..6e59de542 100644 --- a/src/salomeloader/salomeloader.py +++ b/src/salomeloader/salomeloader.py @@ -26,9 +26,9 @@ import sys,os try: - import cElementTree as ElementTree + from xml.etree import cElementTree as ElementTree except ImportError: - import ElementTree + from xml.etree import ElementTree #from sets import Set Set=set diff --git a/src/salomeloader/testSalomeLoader.py.in b/src/salomeloader/testSalomeLoader.py.in index b8633dd6d..64a41e321 100755 --- a/src/salomeloader/testSalomeLoader.py.in +++ b/src/salomeloader/testSalomeLoader.py.in @@ -72,10 +72,9 @@ class TestSalomeLoader(unittest.TestCase): p.saveSchema("tata.xml") U = os.getenv('USER') -f=open("/tmp/" + U + "/UnitTestsResult", 'a') -f.write(" --- TEST src/salomeloader: testSalomeLoader.py\n") -suite = unittest.makeSuite(TestSalomeLoader) -result=unittest.TextTestRunner(f, descriptions=1, verbosity=1).run(suite) -f.close() +with open("/tmp/" + U + "/UnitTestsResult", 'a') as f: + f.write(" --- TEST src/salomeloader: testSalomeLoader.py\n") + suite = unittest.makeSuite(TestSalomeLoader) + result=unittest.TextTestRunner(f, descriptions=1, verbosity=1).run(suite) sys.exit(not result.wasSuccessful()) diff --git a/src/yacsloader/Test/YacsLoaderTest.cxx b/src/yacsloader/Test/YacsLoaderTest.cxx index 9eae67b2f..15d995133 100644 --- a/src/yacsloader/Test/YacsLoaderTest.cxx +++ b/src/yacsloader/Test/YacsLoaderTest.cxx @@ -252,7 +252,7 @@ void YacsLoaderTest::eschema() if (p) { PyObject *data = ((OutputPyPort*)p->nodeMap["node2"]->getOutputPort("p1"))->get(); - char *text = PyBytes_AsString(data); + char *text = PyUnicode_AsUTF8(data); CPPUNIT_ASSERT_EQUAL(string("coucoucoucoucoucoucoucou"), string(text)); delete p; } @@ -268,7 +268,7 @@ void YacsLoaderTest::fschema() if (p) { PyObject *data = ((OutputPyPort*)p->nodeMap["node2"]->getOutputPort("p1"))->get(); - char *text = PyBytes_AsString(data);; + char *text = PyUnicode_AsUTF8(data); CPPUNIT_ASSERT_EQUAL(string("coucoucoucoucoucoucoucou"), string(text) ); delete p; } diff --git a/src/yacsloader/Test/xmlrun_orig.sh b/src/yacsloader/Test/xmlrun_orig.sh index 06deec926..0aa03dbad 100755 --- a/src/yacsloader/Test/xmlrun_orig.sh +++ b/src/yacsloader/Test/xmlrun_orig.sh @@ -40,9 +40,8 @@ def echo(args): else: return args -f=open("input") -data=f.read() -f.close() +with open("input",'r') as f: + data=f.read() print(data) class Objref: @@ -51,10 +50,32 @@ class Objref: self.data=data def __str__(self): return self.data or "" - def __cmp__(self, other): + +# __cmp__ is not defined in Python 3 : strict ordering + def __le__(self, other): + if isinstance(other, Binary): + other = other.data + return self.data <= other + def __lt__(self, other): + if isinstance(other, Binary): + other = other.data + return self.data < other + def __ge__(self, other): + if isinstance(other, Binary): + other = other.data + return self.data >= other + def __gt__(self, other): + if isinstance(other, Binary): + other = other.data + return self.data > other + def __eq__(self, other): + if isinstance(other, Binary): + other = other.data + return self.data == other + def __ne__(self, other): if isinstance(other, Binary): other = other.data - return cmp(self.data, other) + return self.data != other def decode(self, data): self.data = data @@ -76,16 +97,15 @@ xmlrpc.client.Unmarshaller.dispatch["objref"]=end_objref params, method = xmlrpc.client.loads(data) try: - call=eval(method) - response=call(params) - response = (response,) + call=eval(method) + response=call(params) + response = (response,) except: - # report exception back to server - response = xmlrpc.client.dumps( xmlrpc.client.Fault(1, "%s:%s" % sys.exc_info()[:2])) + # report exception back to server + response = xmlrpc.client.dumps( xmlrpc.client.Fault(1, "%s:%s" % sys.exc_info()[:2])) else: - response = xmlrpc.client.dumps( response, methodresponse=1) + response = xmlrpc.client.dumps( response, methodresponse=1) print(response) -f=open("output",'w') -f.write(response) -f.close() +with open("output",'w') as f: + f.write(response) diff --git a/src/yacsloader/samples/schemaANN2.xml b/src/yacsloader/samples/schemaANN2.xml index 9d748ef02..5c44f2aec 100644 --- a/src/yacsloader/samples/schemaANN2.xml +++ b/src/yacsloader/samples/schemaANN2.xml @@ -290,7 +290,7 @@ pmmlObj.SetCurrentModel( modelname , eval(pmmltype) ); myFunc = "pyFunc"; myHeader = "Function processed in YACCS"; myCode = pmmlObj.ExportPyStr(myFunc, myHeader); -exec myCode; +exec(myCode); ]]> diff --git a/src/yacsloader/samples/schemaANNLR2.xml b/src/yacsloader/samples/schemaANNLR2.xml index d2af5a283..e6cc4abfa 100644 --- a/src/yacsloader/samples/schemaANNLR2.xml +++ b/src/yacsloader/samples/schemaANNLR2.xml @@ -100,7 +100,7 @@ pmmlObj.SetCurrentModel( modelname , eval(pmmltype) ); myFunc = "pyFunc"; myHeader = "Function processed in YACCS"; myCode = pmmlObj.ExportPyStr(myFunc, myHeader); -exec myCode; +exec(myCode); ]]> @@ -116,7 +116,7 @@ pmmlObj.SetCurrentModel( modelname , eval(pmmltype) ); myFunc = "pyFunc"; myHeader = "Function processed in YACCS"; myCode = pmmlObj.ExportPyStr(myFunc, myHeader); -exec myCode; +exec(myCode); ]]> diff --git a/src/yacsloader/samples/schemaLR2.xml b/src/yacsloader/samples/schemaLR2.xml index 812e90f9f..d175b373b 100644 --- a/src/yacsloader/samples/schemaLR2.xml +++ b/src/yacsloader/samples/schemaLR2.xml @@ -292,7 +292,7 @@ pmmlObj.SetCurrentModel( modelname , eval(pmmltype) ); myFunc = "pyFunc"; myHeader = "Function processed in YACCS"; myCode = pmmlObj.ExportPyStr(myFunc, myHeader); -exec myCode; +exec(myCode); ]]> diff --git a/src/yacsloader/samples/schemaPmmlDoesNotExist.xml b/src/yacsloader/samples/schemaPmmlDoesNotExist.xml index d7dd2e886..6dae17859 100644 --- a/src/yacsloader/samples/schemaPmmlDoesNotExist.xml +++ b/src/yacsloader/samples/schemaPmmlDoesNotExist.xml @@ -290,7 +290,7 @@ pmmlObj.SetCurrentModel( modelname , eval(pmmltype) ); myFunc = "pyFunc"; myHeader = "Function processed in YACCS"; myCode = pmmlObj.ExportPyStr(myFunc, myHeader); -exec myCode; +exec(myCode); ]]> -- 2.39.2