Commit 10e324fe authored by Jérome Perrin's avatar Jérome Perrin

Modernize and add python3 support

This had a dependency on PyXML, which does not support python3 (actually
does not even support python2.7 byt we have been using a patched version).
To drop this dependency, we use lxml sax interface directly.

Modernize several things:
 - enable the doctest
 - use lxml xml comparison to compare XML
 - use python3 compatible syntax
parent 7587ba0a
History History
======= =======
0.5 (unreleased) 0.5 (2022-09-14)
---------------- ----------------
- Support python3 and python2.7 by dropping dependency on PyXML
0.4 (2010-01-21) 0.4 (2010-01-21)
---------------- ----------------
......
include *.py
include *.rst
include MANIFEST.in
...@@ -4,16 +4,18 @@ Introduction ...@@ -4,16 +4,18 @@ Introduction
Apply xupdate diff on XML documents. Apply xupdate diff on XML documents.
Installation Testing
============ =======
python setup.py install To run tests::
python -m unittest discover src
Testing or, using ``zc.buildout`` and ``zope.testrunner``::
=======
buildout
./bin/test
python setup.py test
Usage Usage
===== =====
......
...@@ -5,4 +5,3 @@ parts = test ...@@ -5,4 +5,3 @@ parts = test
[test] [test]
recipe = zc.recipe.testrunner recipe = zc.recipe.testrunner
eggs = xupdate_processor eggs = xupdate_processor
initialization = from shutil import copy2; from glob import glob; [copy2(f, '../../parts/test/%s' % f.split('/')[-1]) for f in glob('../../*.xml')]
\ No newline at end of file
...@@ -3,15 +3,16 @@ ...@@ -3,15 +3,16 @@
from setuptools import setup, find_packages from setuptools import setup, find_packages
version = '0.4' version = '0.5'
def read(name): def read(name):
return open(name).read() with open(name) as f:
return f.read()
long_description=( long_description=(
read('README.txt') read('README.rst')
+ '\n' + + '\n' +
read('CHANGES.txt') read('CHANGES.rst')
) )
setup(name="xupdate-processor", setup(name="xupdate-processor",
...@@ -20,17 +21,16 @@ setup(name="xupdate-processor", ...@@ -20,17 +21,16 @@ setup(name="xupdate-processor",
long_description=long_description, long_description=long_description,
author="Nicolas DELABY", author="Nicolas DELABY",
author_email="nicolas@nexedi.com", author_email="nicolas@nexedi.com",
url="http://nexedi.com", url="https://lab.nexedi.com/nexedi/xupdate_processor",
license="GPL", license="GPL",
packages=find_packages('src'), packages=find_packages('src'),
package_dir={'': 'src'}, package_dir={'': 'src'},
scripts=["xuproc"], scripts=["xuproc"],
install_requires=['PyXML', 'lxml', 'erp5diff >= 0.7'], install_requires=['six', 'lxml', 'erp5diff >= 0.7'],
classifiers=['License :: OSI Approved :: GNU General Public License (GPL)', classifiers=['License :: OSI Approved :: GNU General Public License (GPL)',
'Operating System :: OS Independent', 'Operating System :: OS Independent',
'Topic :: Text Processing :: Markup :: XML', 'Topic :: Text Processing :: Markup :: XML',
'Topic :: Utilities'], 'Topic :: Utilities'],
include_package_data=True, include_package_data=True,
zip_safe=False, zip_safe=False,
test_suite='xupdate_processor',
) )
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from xuproc import applyXUpdate from __future__ import absolute_import
from __future__ import print_function
from .xuproc import applyXUpdate
from lxml import etree from lxml import etree
import sys
def main(): def main():
from optparse import OptionParser from optparse import OptionParser
...@@ -10,12 +13,13 @@ def main(): ...@@ -10,12 +13,13 @@ def main():
options, args = parser.parse_args() options, args = parser.parse_args()
if len(args) != 2: if len(args) != 2:
print parser.print_help() parser.print_help()
parser.error('incorrect number of arguments') parser.error('incorrect number of arguments')
sys.exit(2)
xu_xml_name = args[0] xu_xml_name = args[0]
doc_xml_name = args[1] doc_xml_name = args[1]
print etree.tostring(applyXUpdate(xml_xu_filename=xu_xml_name, print(etree.tostring(applyXUpdate(xml_xu_filename=xu_xml_name,
xml_doc_filename=doc_xml_name), xml_doc_filename=doc_xml_name),
pretty_print=True) pretty_print=True))
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import absolute_import
from lxml import etree from lxml import etree
from lxml.etree import Element, _ElementTree, ProcessingInstruction, Comment from lxml.etree import Element, _ElementTree, ProcessingInstruction, Comment
from xml.sax.handler import ContentHandler from xml.sax.handler import ContentHandler
......
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import absolute_import
import unittest import unittest
import pkg_resources import pkg_resources
from io import BytesIO
import doctest
from ERP5Diff import ERP5Diff from ERP5Diff import ERP5Diff
import xupdate_processor import xupdate_processor
from xupdate_processor import applyXUpdate from xupdate_processor import applyXUpdate
import lxml.doctestcompare
from lxml import etree from lxml import etree
from cStringIO import StringIO
class TestXUpdateProcessor(unittest.TestCase): class TestXUpdateProcessor(unittest.TestCase):
""" """
...@@ -17,9 +20,14 @@ class TestXUpdateProcessor(unittest.TestCase): ...@@ -17,9 +20,14 @@ class TestXUpdateProcessor(unittest.TestCase):
""" """
result_tree = applyXUpdate(xml_xu_string=xml_xu_string, result_tree = applyXUpdate(xml_xu_string=xml_xu_string,
xml_doc_string=xml_doc_string) xml_doc_string=xml_doc_string)
result_string = etree.tostring(result_tree, pretty_print=True) result_string = etree.tostring(result_tree, pretty_print=True, encoding="unicode")
self.assertEquals(result_string, expected_result_string, checker = lxml.doctestcompare.LXMLOutputChecker()
'\n%s\n\n%s' % (result_string, expected_result_string)) if not checker.check_output(expected_result_string, result_string, 0):
self.fail(
checker.output_difference(
doctest.Example("", expected_result_string),
result_string,
0))
def test_textNodes(self): def test_textNodes(self):
...@@ -683,13 +691,15 @@ class TestXUpdateProcessor(unittest.TestCase): ...@@ -683,13 +691,15 @@ class TestXUpdateProcessor(unittest.TestCase):
result_tree = applyXUpdate(xml_xu_filename=xu_filename, result_tree = applyXUpdate(xml_xu_filename=xu_filename,
xml_doc_filename=orig_filename) xml_doc_filename=orig_filename)
destination_tree = etree.parse(destination_filename) destination_tree = etree.parse(destination_filename)
destination_buffer = StringIO() destination_buffer = BytesIO()
result_buffer = StringIO() result_buffer = BytesIO()
destination_tree.write_c14n(destination_buffer) destination_tree.write_c14n(destination_buffer)
destination_buffer.seek(0)
result_tree.write_c14n(result_buffer) result_tree.write_c14n(result_buffer)
result_buffer.seek(0)
erp5diff = ERP5Diff() erp5diff = ERP5Diff()
erp5diff.compare(result_buffer.getvalue(), destination_buffer.getvalue()) erp5diff.compare(result_buffer, destination_buffer)
self.assertEquals(etree.tostring(erp5diff._result), self.assertEqual(etree.tostring(erp5diff._result, encoding='unicode'),
'<xupdate:modifications xmlns:xupdate="http://www.xmldb.org/xupdate" version="1.0"/>') '<xupdate:modifications xmlns:xupdate="http://www.xmldb.org/xupdate" version="1.0"/>')
def test_OOofiles2(self): def test_OOofiles2(self):
...@@ -706,16 +716,23 @@ class TestXUpdateProcessor(unittest.TestCase): ...@@ -706,16 +716,23 @@ class TestXUpdateProcessor(unittest.TestCase):
'tests/dest_ooo_2.xml') 'tests/dest_ooo_2.xml')
result_tree = applyXUpdate(xml_xu_filename=xu_filename, xml_doc_filename=orig_filename) result_tree = applyXUpdate(xml_xu_filename=xu_filename, xml_doc_filename=orig_filename)
destination_tree = etree.parse(destination_filename) destination_tree = etree.parse(destination_filename)
destination_buffer = StringIO() destination_buffer = BytesIO()
result_buffer = StringIO() result_buffer = BytesIO()
destination_tree.write_c14n(destination_buffer) destination_tree.write_c14n(destination_buffer)
destination_buffer.seek(0)
result_tree.write_c14n(result_buffer) result_tree.write_c14n(result_buffer)
result_buffer.seek(0)
erp5diff = ERP5Diff() erp5diff = ERP5Diff()
erp5diff.compare(result_buffer.getvalue(), destination_buffer.getvalue()) erp5diff.compare(result_buffer, destination_buffer)
self.assertEquals(etree.tostring(erp5diff._result), self.assertEqual(etree.tostring(erp5diff._result, encoding='unicode'),
'<xupdate:modifications xmlns:xupdate="http://www.xmldb.org/xupdate" version="1.0"/>') '<xupdate:modifications xmlns:xupdate="http://www.xmldb.org/xupdate" version="1.0"/>')
def load_tests(loader, tests, ignore):
tests.addTests(doctest.DocFileSuite("test_doctest.txt"))
return tests
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()
\ No newline at end of file
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import xml.sax from __future__ import absolute_import
from __future__ import print_function
import lxml.sax
from lxml import etree from lxml import etree
from cStringIO import StringIO from six import StringIO
from content_handler import XUpdateHandler from .content_handler import XUpdateHandler
def applyXUpdate(xml_xu_file=None, def applyXUpdate(xml_xu_file=None,
xml_doc_file=None, xml_doc_file=None,
...@@ -26,16 +28,12 @@ def applyXUpdate(xml_xu_file=None, ...@@ -26,16 +28,12 @@ def applyXUpdate(xml_xu_file=None,
if xml_doc_filename: if xml_doc_filename:
xml_doc = xml_doc_filename xml_doc = xml_doc_filename
original_tree = etree.parse(xml_doc, etree_parser) original_tree = etree.parse(xml_doc, etree_parser)
parser = xml.sax.make_parser() content_handler = XUpdateHandler(original_tree=original_tree)
parser.setFeature(xml.sax.handler.feature_namespaces, True) lxml.sax.saxify(etree.parse(xml_xu, etree_parser), content_handler)
parser.setFeature(xml.sax.handler.feature_namespace_prefixes, True)
parser.setContentHandler(XUpdateHandler(original_tree=original_tree))
parser.parse(xml_xu)
content_handler = parser.getContentHandler()
return content_handler.result_tree return content_handler.result_tree
if __name__ == '__main__': if __name__ == '__main__':
import sys import sys
doc_xml_name = sys.argv[1] doc_xml_name = sys.argv[1]
xu_xml_name = sys.argv[2] xu_xml_name = sys.argv[2]
print etree.tostring(applyXUpdate(xml_xu_filename=xu_xml_name, xml_doc_filename=doc_xml_name), pretty_print=True) print(etree.tostring(applyXUpdate(xml_xu_filename=xu_xml_name, xml_doc_filename=doc_xml_name), pretty_print=True))
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment