Issue #13988: cElementTree is deprecated and the _elementtree accelerator is automatically used whenever available.
This commit is contained in:
parent
d1c7b1afe8
commit
a72a98f24a
|
@ -32,17 +32,18 @@ To create an element instance, use the :class:`Element` constructor or the
|
||||||
The :class:`ElementTree` class can be used to wrap an element structure, and
|
The :class:`ElementTree` class can be used to wrap an element structure, and
|
||||||
convert it from and to XML.
|
convert it from and to XML.
|
||||||
|
|
||||||
A C implementation of this API is available as :mod:`xml.etree.cElementTree`.
|
|
||||||
|
|
||||||
See http://effbot.org/zone/element-index.htm for tutorials and links to other
|
See http://effbot.org/zone/element-index.htm for tutorials and links to other
|
||||||
docs. Fredrik Lundh's page is also the location of the development version of
|
docs.
|
||||||
the xml.etree.ElementTree.
|
|
||||||
|
|
||||||
.. versionchanged:: 3.2
|
.. versionchanged:: 3.2
|
||||||
The ElementTree API is updated to 1.3. For more information, see
|
The ElementTree API is updated to 1.3. For more information, see
|
||||||
`Introducing ElementTree 1.3
|
`Introducing ElementTree 1.3
|
||||||
<http://effbot.org/zone/elementtree-13-intro.htm>`_.
|
<http://effbot.org/zone/elementtree-13-intro.htm>`_.
|
||||||
|
|
||||||
|
.. versionchanged:: 3.3
|
||||||
|
This module will use a fast implementation whenever available.
|
||||||
|
The :mod:`xml.etree.cElementTree` module is deprecated.
|
||||||
|
|
||||||
|
|
||||||
.. _elementtree-functions:
|
.. _elementtree-functions:
|
||||||
|
|
||||||
|
|
|
@ -842,6 +842,8 @@ Deprecated Python modules, functions and methods
|
||||||
* :issue:`13374`: The Windows bytes API has been deprecated in the :mod:`os`
|
* :issue:`13374`: The Windows bytes API has been deprecated in the :mod:`os`
|
||||||
module. Use Unicode filenames, instead of bytes filenames, to not depend on
|
module. Use Unicode filenames, instead of bytes filenames, to not depend on
|
||||||
the ANSI code page anymore and to support any filename.
|
the ANSI code page anymore and to support any filename.
|
||||||
|
* :issue:`13988`: The :mod:`xml.etree.cElementTree` module is deprecated. The
|
||||||
|
accelerator is used automatically whenever available.
|
||||||
|
|
||||||
|
|
||||||
Deprecated functions and types of the C API
|
Deprecated functions and types of the C API
|
||||||
|
|
|
@ -16,9 +16,9 @@ import html
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from test import support
|
from test import support
|
||||||
from test.support import findfile
|
from test.support import findfile, import_fresh_module
|
||||||
|
|
||||||
from xml.etree import ElementTree as ET
|
pyET = import_fresh_module('xml.etree.ElementTree', blocked=['_elementtree'])
|
||||||
|
|
||||||
SIMPLE_XMLFILE = findfile("simple.xml", subdir="xmltestdata")
|
SIMPLE_XMLFILE = findfile("simple.xml", subdir="xmltestdata")
|
||||||
try:
|
try:
|
||||||
|
@ -275,7 +275,7 @@ def simplefind():
|
||||||
"""
|
"""
|
||||||
Test find methods using the elementpath fallback.
|
Test find methods using the elementpath fallback.
|
||||||
|
|
||||||
>>> from xml.etree import ElementTree
|
>>> ElementTree = pyET
|
||||||
|
|
||||||
>>> CurrentElementPath = ElementTree.ElementPath
|
>>> CurrentElementPath = ElementTree.ElementPath
|
||||||
>>> ElementTree.ElementPath = ElementTree._SimpleElementPath()
|
>>> ElementTree.ElementPath = ElementTree._SimpleElementPath()
|
||||||
|
@ -460,17 +460,19 @@ def path_cache():
|
||||||
"""
|
"""
|
||||||
Check that the path cache behaves sanely.
|
Check that the path cache behaves sanely.
|
||||||
|
|
||||||
|
>>> from xml.etree import ElementPath
|
||||||
|
|
||||||
>>> elem = ET.XML(SAMPLE_XML)
|
>>> elem = ET.XML(SAMPLE_XML)
|
||||||
>>> for i in range(10): ET.ElementTree(elem).find('./'+str(i))
|
>>> for i in range(10): ET.ElementTree(elem).find('./'+str(i))
|
||||||
>>> cache_len_10 = len(ET.ElementPath._cache)
|
>>> cache_len_10 = len(ElementPath._cache)
|
||||||
>>> for i in range(10): ET.ElementTree(elem).find('./'+str(i))
|
>>> for i in range(10): ET.ElementTree(elem).find('./'+str(i))
|
||||||
>>> len(ET.ElementPath._cache) == cache_len_10
|
>>> len(ElementPath._cache) == cache_len_10
|
||||||
True
|
True
|
||||||
>>> for i in range(20): ET.ElementTree(elem).find('./'+str(i))
|
>>> for i in range(20): ET.ElementTree(elem).find('./'+str(i))
|
||||||
>>> len(ET.ElementPath._cache) > cache_len_10
|
>>> len(ElementPath._cache) > cache_len_10
|
||||||
True
|
True
|
||||||
>>> for i in range(600): ET.ElementTree(elem).find('./'+str(i))
|
>>> for i in range(600): ET.ElementTree(elem).find('./'+str(i))
|
||||||
>>> len(ET.ElementPath._cache) < 500
|
>>> len(ElementPath._cache) < 500
|
||||||
True
|
True
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -1879,37 +1881,38 @@ class CleanContext(object):
|
||||||
self.checkwarnings = support.check_warnings(*deprecations, quiet=quiet)
|
self.checkwarnings = support.check_warnings(*deprecations, quiet=quiet)
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
from xml.etree import ElementTree
|
from xml.etree import ElementPath
|
||||||
self._nsmap = ElementTree._namespace_map
|
if hasattr(ET, '_namespace_map'):
|
||||||
self._path_cache = ElementTree.ElementPath._cache
|
self._nsmap = ET._namespace_map
|
||||||
|
else:
|
||||||
|
# when testing the cElementTree alias
|
||||||
|
from xml.etree.ElementTree import _namespace_map
|
||||||
|
self._nsmap = _namespace_map
|
||||||
# Copy the default namespace mapping
|
# Copy the default namespace mapping
|
||||||
ElementTree._namespace_map = self._nsmap.copy()
|
self._nsmap_copy = self._nsmap.copy()
|
||||||
# Copy the path cache (should be empty)
|
# Copy the path cache (should be empty)
|
||||||
ElementTree.ElementPath._cache = self._path_cache.copy()
|
self._path_cache = ElementPath._cache
|
||||||
|
ElementPath._cache = self._path_cache.copy()
|
||||||
self.checkwarnings.__enter__()
|
self.checkwarnings.__enter__()
|
||||||
|
|
||||||
def __exit__(self, *args):
|
def __exit__(self, *args):
|
||||||
from xml.etree import ElementTree
|
from xml.etree import ElementPath
|
||||||
# Restore mapping and path cache
|
# Restore mapping and path cache
|
||||||
ElementTree._namespace_map = self._nsmap
|
self._nsmap.clear()
|
||||||
ElementTree.ElementPath._cache = self._path_cache
|
self._nsmap.update(self._nsmap_copy)
|
||||||
|
ElementPath._cache = self._path_cache
|
||||||
self.checkwarnings.__exit__(*args)
|
self.checkwarnings.__exit__(*args)
|
||||||
|
|
||||||
|
|
||||||
def test_main(module_name='xml.etree.ElementTree'):
|
def test_main(module=pyET):
|
||||||
from test import test_xml_etree
|
from test import test_xml_etree
|
||||||
|
|
||||||
use_py_module = (module_name == 'xml.etree.ElementTree')
|
|
||||||
|
|
||||||
# The same doctests are used for both the Python and the C implementations
|
# The same doctests are used for both the Python and the C implementations
|
||||||
assert test_xml_etree.ET.__name__ == module_name
|
test_xml_etree.ET = module
|
||||||
|
|
||||||
# XXX the C module should give the same warnings as the Python module
|
# XXX the C module should give the same warnings as the Python module
|
||||||
with CleanContext(quiet=not use_py_module):
|
with CleanContext(quiet=(module is not pyET)):
|
||||||
support.run_doctest(test_xml_etree, verbosity=True)
|
support.run_doctest(test_xml_etree, verbosity=True)
|
||||||
|
|
||||||
# The module should not be changed by the tests
|
|
||||||
assert test_xml_etree.ET.__name__ == module_name
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
test_main()
|
test_main()
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
# xml.etree test for cElementTree
|
# xml.etree test for cElementTree
|
||||||
|
|
||||||
from test import support
|
from test import support
|
||||||
from test.support import bigmemtest, _2G
|
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
cET = support.import_module('xml.etree.cElementTree')
|
from xml.etree import ElementTree as cET, cElementTree as cET_alias
|
||||||
|
|
||||||
|
|
||||||
# cElementTree specific tests
|
# cElementTree specific tests
|
||||||
|
@ -13,10 +12,9 @@ def sanity():
|
||||||
r"""
|
r"""
|
||||||
Import sanity.
|
Import sanity.
|
||||||
|
|
||||||
>>> from xml.etree import cElementTree
|
|
||||||
|
|
||||||
Issue #6697.
|
Issue #6697.
|
||||||
|
|
||||||
|
>>> cElementTree = cET
|
||||||
>>> e = cElementTree.Element('a')
|
>>> e = cElementTree.Element('a')
|
||||||
>>> getattr(e, '\uD800') # doctest: +ELLIPSIS
|
>>> getattr(e, '\uD800') # doctest: +ELLIPSIS
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
|
@ -55,19 +53,10 @@ def test_main():
|
||||||
|
|
||||||
support.run_unittest(MiscTests)
|
support.run_unittest(MiscTests)
|
||||||
|
|
||||||
# Assign the C implementation before running the doctests
|
# Run the same test suite as the Python module
|
||||||
# Patch the __name__, to prevent confusion with the pure Python test
|
test_xml_etree.test_main(module=cET)
|
||||||
pyET = test_xml_etree.ET
|
# Exercise the deprecated alias
|
||||||
py__name__ = test_xml_etree.__name__
|
test_xml_etree.test_main(module=cET_alias)
|
||||||
test_xml_etree.ET = cET
|
|
||||||
if __name__ != '__main__':
|
|
||||||
test_xml_etree.__name__ = __name__
|
|
||||||
try:
|
|
||||||
# Run the same test suite as xml.etree.ElementTree
|
|
||||||
test_xml_etree.test_main(module_name='xml.etree.cElementTree')
|
|
||||||
finally:
|
|
||||||
test_xml_etree.ET = pyET
|
|
||||||
test_xml_etree.__name__ = py__name__
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
test_main()
|
test_main()
|
||||||
|
|
|
@ -68,8 +68,9 @@ __all__ = [
|
||||||
"tostring", "tostringlist",
|
"tostring", "tostringlist",
|
||||||
"TreeBuilder",
|
"TreeBuilder",
|
||||||
"VERSION",
|
"VERSION",
|
||||||
"XML",
|
"XML", "XMLID",
|
||||||
"XMLParser", "XMLTreeBuilder",
|
"XMLParser", "XMLTreeBuilder",
|
||||||
|
"register_namespace",
|
||||||
]
|
]
|
||||||
|
|
||||||
VERSION = "1.3.0"
|
VERSION = "1.3.0"
|
||||||
|
@ -148,9 +149,9 @@ class ParseError(SyntaxError):
|
||||||
# @defreturn flag
|
# @defreturn flag
|
||||||
|
|
||||||
def iselement(element):
|
def iselement(element):
|
||||||
# FIXME: not sure about this; might be a better idea to look
|
# FIXME: not sure about this;
|
||||||
# for tag/attrib/text attributes
|
# isinstance(element, Element) or look for tag/attrib/text attributes
|
||||||
return isinstance(element, Element) or hasattr(element, "tag")
|
return hasattr(element, 'tag')
|
||||||
|
|
||||||
##
|
##
|
||||||
# Element class. This class defines the Element interface, and
|
# Element class. This class defines the Element interface, and
|
||||||
|
@ -1684,6 +1685,87 @@ class XMLParser:
|
||||||
del self.target, self._parser # get rid of circular references
|
del self.target, self._parser # get rid of circular references
|
||||||
return tree
|
return tree
|
||||||
|
|
||||||
|
|
||||||
|
# Import the C accelerators
|
||||||
|
try:
|
||||||
|
# Element, SubElement, ParseError, TreeBuilder, XMLParser
|
||||||
|
from _elementtree import *
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
# Overwrite 'ElementTree.parse' and 'iterparse' to use the C XMLParser
|
||||||
|
|
||||||
|
class ElementTree(ElementTree):
|
||||||
|
def parse(self, source, parser=None):
|
||||||
|
close_source = False
|
||||||
|
if not hasattr(source, 'read'):
|
||||||
|
source = open(source, 'rb')
|
||||||
|
close_source = True
|
||||||
|
try:
|
||||||
|
if parser is not None:
|
||||||
|
while True:
|
||||||
|
data = source.read(65536)
|
||||||
|
if not data:
|
||||||
|
break
|
||||||
|
parser.feed(data)
|
||||||
|
self._root = parser.close()
|
||||||
|
else:
|
||||||
|
parser = XMLParser()
|
||||||
|
self._root = parser._parse(source)
|
||||||
|
return self._root
|
||||||
|
finally:
|
||||||
|
if close_source:
|
||||||
|
source.close()
|
||||||
|
|
||||||
|
class iterparse:
|
||||||
|
root = None
|
||||||
|
def __init__(self, file, events=None):
|
||||||
|
self._close_file = False
|
||||||
|
if not hasattr(file, 'read'):
|
||||||
|
file = open(file, 'rb')
|
||||||
|
self._close_file = True
|
||||||
|
self._file = file
|
||||||
|
self._events = []
|
||||||
|
self._index = 0
|
||||||
|
self._error = None
|
||||||
|
self.root = self._root = None
|
||||||
|
b = TreeBuilder()
|
||||||
|
self._parser = XMLParser(b)
|
||||||
|
self._parser._setevents(self._events, events)
|
||||||
|
|
||||||
|
def __next__(self):
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
item = self._events[self._index]
|
||||||
|
self._index += 1
|
||||||
|
return item
|
||||||
|
except IndexError:
|
||||||
|
pass
|
||||||
|
if self._error:
|
||||||
|
e = self._error
|
||||||
|
self._error = None
|
||||||
|
raise e
|
||||||
|
if self._parser is None:
|
||||||
|
self.root = self._root
|
||||||
|
if self._close_file:
|
||||||
|
self._file.close()
|
||||||
|
raise StopIteration
|
||||||
|
# load event buffer
|
||||||
|
del self._events[:]
|
||||||
|
self._index = 0
|
||||||
|
data = self._file.read(16384)
|
||||||
|
if data:
|
||||||
|
try:
|
||||||
|
self._parser.feed(data)
|
||||||
|
except SyntaxError as exc:
|
||||||
|
self._error = exc
|
||||||
|
else:
|
||||||
|
self._root = self._parser.close()
|
||||||
|
self._parser = None
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
return self
|
||||||
|
|
||||||
# compatibility
|
# compatibility
|
||||||
XMLTreeBuilder = XMLParser
|
XMLTreeBuilder = XMLParser
|
||||||
|
|
||||||
|
|
|
@ -1,153 +1,3 @@
|
||||||
# Wrapper module for _elementtree
|
# Deprecated alias for xml.etree.ElementTree
|
||||||
|
|
||||||
from xml.etree.ElementTree import (ElementTree, dump, iselement, QName,
|
from xml.etree.ElementTree import *
|
||||||
fromstringlist,
|
|
||||||
tostring, tostringlist, VERSION)
|
|
||||||
# These ones are not in ElementTree.__all__
|
|
||||||
from xml.etree.ElementTree import ElementPath, register_namespace
|
|
||||||
|
|
||||||
# Import the C accelerators:
|
|
||||||
# Element, SubElement, TreeBuilder, XMLParser, ParseError
|
|
||||||
from _elementtree import *
|
|
||||||
|
|
||||||
|
|
||||||
class ElementTree(ElementTree):
|
|
||||||
|
|
||||||
def parse(self, source, parser=None):
|
|
||||||
close_source = False
|
|
||||||
if not hasattr(source, 'read'):
|
|
||||||
source = open(source, 'rb')
|
|
||||||
close_source = True
|
|
||||||
try:
|
|
||||||
if parser is not None:
|
|
||||||
while True:
|
|
||||||
data = source.read(65536)
|
|
||||||
if not data:
|
|
||||||
break
|
|
||||||
parser.feed(data)
|
|
||||||
self._root = parser.close()
|
|
||||||
else:
|
|
||||||
parser = XMLParser()
|
|
||||||
self._root = parser._parse(source)
|
|
||||||
return self._root
|
|
||||||
finally:
|
|
||||||
if close_source:
|
|
||||||
source.close()
|
|
||||||
|
|
||||||
|
|
||||||
class iterparse:
|
|
||||||
root = None
|
|
||||||
|
|
||||||
def __init__(self, file, events=None):
|
|
||||||
self._close_file = False
|
|
||||||
if not hasattr(file, 'read'):
|
|
||||||
file = open(file, 'rb')
|
|
||||||
self._close_file = True
|
|
||||||
self._file = file
|
|
||||||
self._events = []
|
|
||||||
self._index = 0
|
|
||||||
self._error = None
|
|
||||||
self.root = self._root = None
|
|
||||||
b = TreeBuilder()
|
|
||||||
self._parser = XMLParser(b)
|
|
||||||
self._parser._setevents(self._events, events)
|
|
||||||
|
|
||||||
def __next__(self):
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
item = self._events[self._index]
|
|
||||||
self._index += 1
|
|
||||||
return item
|
|
||||||
except IndexError:
|
|
||||||
pass
|
|
||||||
if self._error:
|
|
||||||
e = self._error
|
|
||||||
self._error = None
|
|
||||||
raise e
|
|
||||||
if self._parser is None:
|
|
||||||
self.root = self._root
|
|
||||||
if self._close_file:
|
|
||||||
self._file.close()
|
|
||||||
raise StopIteration
|
|
||||||
# load event buffer
|
|
||||||
del self._events[:]
|
|
||||||
self._index = 0
|
|
||||||
data = self._file.read(16384)
|
|
||||||
if data:
|
|
||||||
try:
|
|
||||||
self._parser.feed(data)
|
|
||||||
except SyntaxError as exc:
|
|
||||||
self._error = exc
|
|
||||||
else:
|
|
||||||
self._root = self._parser.close()
|
|
||||||
self._parser = None
|
|
||||||
|
|
||||||
def __iter__(self):
|
|
||||||
return self
|
|
||||||
|
|
||||||
|
|
||||||
# =============================================================================
|
|
||||||
#
|
|
||||||
# Everything below this line can be removed
|
|
||||||
# after cElementTree is folded behind ElementTree.
|
|
||||||
#
|
|
||||||
# =============================================================================
|
|
||||||
|
|
||||||
from xml.etree.ElementTree import Comment as _Comment, PI as _PI
|
|
||||||
|
|
||||||
|
|
||||||
def parse(source, parser=None):
|
|
||||||
tree = ElementTree()
|
|
||||||
tree.parse(source, parser)
|
|
||||||
return tree
|
|
||||||
|
|
||||||
|
|
||||||
def XML(text, parser=None):
|
|
||||||
if not parser:
|
|
||||||
parser = XMLParser()
|
|
||||||
parser = XMLParser()
|
|
||||||
parser.feed(text)
|
|
||||||
return parser.close()
|
|
||||||
|
|
||||||
|
|
||||||
def XMLID(text, parser=None):
|
|
||||||
tree = XML(text, parser=parser)
|
|
||||||
ids = {}
|
|
||||||
for elem in tree.iter():
|
|
||||||
id = elem.get('id')
|
|
||||||
if id:
|
|
||||||
ids[id] = elem
|
|
||||||
return tree, ids
|
|
||||||
|
|
||||||
|
|
||||||
class CommentProxy:
|
|
||||||
|
|
||||||
def __call__(self, text=None):
|
|
||||||
element = Element(_Comment)
|
|
||||||
element.text = text
|
|
||||||
return element
|
|
||||||
|
|
||||||
def __eq__(self, other):
|
|
||||||
return _Comment == other
|
|
||||||
|
|
||||||
|
|
||||||
class PIProxy:
|
|
||||||
|
|
||||||
def __call__(self, target, text=None):
|
|
||||||
element = Element(_PI)
|
|
||||||
element.text = target
|
|
||||||
if text:
|
|
||||||
element.text = element.text + ' ' + text
|
|
||||||
return element
|
|
||||||
|
|
||||||
def __eq__(self, other):
|
|
||||||
return _PI == other
|
|
||||||
|
|
||||||
|
|
||||||
Comment = CommentProxy()
|
|
||||||
PI = ProcessingInstruction = PIProxy()
|
|
||||||
del CommentProxy, PIProxy
|
|
||||||
|
|
||||||
# Aliases
|
|
||||||
fromstring = XML
|
|
||||||
XMLTreeBuilder = XMLParser
|
|
||||||
|
|
|
@ -1886,6 +1886,9 @@ Library
|
||||||
- Issue #12191: Added shutil.chown() to change user and/or group owner of a
|
- Issue #12191: Added shutil.chown() to change user and/or group owner of a
|
||||||
given path also specifying their names.
|
given path also specifying their names.
|
||||||
|
|
||||||
|
- Issue #13988: The _elementtree accelerator is used whenever available.
|
||||||
|
Now xml.etree.cElementTree becomes a deprecated alias to ElementTree.
|
||||||
|
|
||||||
Build
|
Build
|
||||||
-----
|
-----
|
||||||
|
|
||||||
|
|
|
@ -70,7 +70,7 @@
|
||||||
helps if you have lots of leaf nodes with attributes). */
|
helps if you have lots of leaf nodes with attributes). */
|
||||||
|
|
||||||
/* Also note that pymalloc always allocates blocks in multiples of
|
/* Also note that pymalloc always allocates blocks in multiples of
|
||||||
eight bytes. For the current version of cElementTree, this means
|
eight bytes. For the current C version of ElementTree, this means
|
||||||
that the number of children should be an even number, at least on
|
that the number of children should be an even number, at least on
|
||||||
32-bit platforms. */
|
32-bit platforms. */
|
||||||
|
|
||||||
|
@ -2649,7 +2649,7 @@ xmlparser_setevents(XMLParserObject* self, PyObject* args)
|
||||||
if (!TreeBuilder_CheckExact(self->target)) {
|
if (!TreeBuilder_CheckExact(self->target)) {
|
||||||
PyErr_SetString(
|
PyErr_SetString(
|
||||||
PyExc_TypeError,
|
PyExc_TypeError,
|
||||||
"event handling only supported for cElementTree.Treebuilder "
|
"event handling only supported for ElementTree.TreeBuilder "
|
||||||
"targets"
|
"targets"
|
||||||
);
|
);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -2906,7 +2906,7 @@ PyInit__elementtree(void)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
elementtree_parseerror_obj = PyErr_NewException(
|
elementtree_parseerror_obj = PyErr_NewException(
|
||||||
"cElementTree.ParseError", PyExc_SyntaxError, NULL
|
"xml.etree.ElementTree.ParseError", PyExc_SyntaxError, NULL
|
||||||
);
|
);
|
||||||
Py_INCREF(elementtree_parseerror_obj);
|
Py_INCREF(elementtree_parseerror_obj);
|
||||||
PyModule_AddObject(m, "ParseError", elementtree_parseerror_obj);
|
PyModule_AddObject(m, "ParseError", elementtree_parseerror_obj);
|
||||||
|
|
Loading…
Reference in New Issue