mirror of https://github.com/python/cpython
Issue #19176: Fixed doctype() related bugs in C implementation of ElementTree.
A deprecation warning no longer issued by XMLParser subclass with default doctype() method. Direct call of doctype() now issues a warning. Parser's doctype() now is not called if target's doctype() is called. Based on patch by Martin Panter.
This commit is contained in:
commit
c28e985f3c
|
@ -12,6 +12,7 @@ import pickle
|
||||||
import sys
|
import sys
|
||||||
import types
|
import types
|
||||||
import unittest
|
import unittest
|
||||||
|
import warnings
|
||||||
import weakref
|
import weakref
|
||||||
|
|
||||||
from itertools import product
|
from itertools import product
|
||||||
|
@ -2237,6 +2238,20 @@ class XMLParserTest(unittest.TestCase):
|
||||||
parser.feed(self.sample1)
|
parser.feed(self.sample1)
|
||||||
self._check_sample_element(parser.close())
|
self._check_sample_element(parser.close())
|
||||||
|
|
||||||
|
def test_doctype_warning(self):
|
||||||
|
parser = ET.XMLParser()
|
||||||
|
with self.assertWarns(DeprecationWarning):
|
||||||
|
parser.doctype('html', '-//W3C//DTD XHTML 1.0 Transitional//EN',
|
||||||
|
'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd')
|
||||||
|
parser.feed('<html/>')
|
||||||
|
parser.close()
|
||||||
|
|
||||||
|
with warnings.catch_warnings():
|
||||||
|
warnings.simplefilter('error', DeprecationWarning)
|
||||||
|
parser = ET.XMLParser()
|
||||||
|
parser.feed(self.sample2)
|
||||||
|
parser.close()
|
||||||
|
|
||||||
def test_subclass_doctype(self):
|
def test_subclass_doctype(self):
|
||||||
_doctype = None
|
_doctype = None
|
||||||
class MyParserWithDoctype(ET.XMLParser):
|
class MyParserWithDoctype(ET.XMLParser):
|
||||||
|
@ -2252,6 +2267,32 @@ class XMLParserTest(unittest.TestCase):
|
||||||
('html', '-//W3C//DTD XHTML 1.0 Transitional//EN',
|
('html', '-//W3C//DTD XHTML 1.0 Transitional//EN',
|
||||||
'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'))
|
'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'))
|
||||||
|
|
||||||
|
_doctype = _doctype2 = None
|
||||||
|
with warnings.catch_warnings():
|
||||||
|
warnings.simplefilter('error', DeprecationWarning)
|
||||||
|
class DoctypeParser:
|
||||||
|
def doctype(self, name, pubid, system):
|
||||||
|
nonlocal _doctype2
|
||||||
|
_doctype2 = (name, pubid, system)
|
||||||
|
|
||||||
|
parser = MyParserWithDoctype(target=DoctypeParser())
|
||||||
|
parser.feed(self.sample2)
|
||||||
|
parser.close()
|
||||||
|
self.assertIsNone(_doctype)
|
||||||
|
self.assertEqual(_doctype2,
|
||||||
|
('html', '-//W3C//DTD XHTML 1.0 Transitional//EN',
|
||||||
|
'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'))
|
||||||
|
|
||||||
|
def test_inherited_doctype(self):
|
||||||
|
'''Ensure that ordinary usage is not deprecated (Issue 19176)'''
|
||||||
|
with warnings.catch_warnings():
|
||||||
|
warnings.simplefilter('error', DeprecationWarning)
|
||||||
|
class MyParserWithoutDoctype(ET.XMLParser):
|
||||||
|
pass
|
||||||
|
parser = MyParserWithoutDoctype()
|
||||||
|
parser.feed(self.sample2)
|
||||||
|
parser.close()
|
||||||
|
|
||||||
def test_parse_string(self):
|
def test_parse_string(self):
|
||||||
parser = ET.XMLParser(target=ET.TreeBuilder())
|
parser = ET.XMLParser(target=ET.TreeBuilder())
|
||||||
parser.feed(self.sample3)
|
parser.feed(self.sample3)
|
||||||
|
|
|
@ -51,6 +51,12 @@ Core and Builtins
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issue #19176: Fixed doctype() related bugs in C implementation of ElementTree.
|
||||||
|
A deprecation warning no longer issued by XMLParser subclass with default
|
||||||
|
doctype() method. Direct call of doctype() now issues a warning. Parser's
|
||||||
|
doctype() now is not called if target's doctype() is called. Based on patch
|
||||||
|
by Martin Panter.
|
||||||
|
|
||||||
- Issue #20387: Restore semantic round-trip correctness in tokenize/untokenize
|
- Issue #20387: Restore semantic round-trip correctness in tokenize/untokenize
|
||||||
for tab-indented blocks.
|
for tab-indented blocks.
|
||||||
|
|
||||||
|
|
|
@ -2782,7 +2782,11 @@ typedef struct {
|
||||||
|
|
||||||
} XMLParserObject;
|
} XMLParserObject;
|
||||||
|
|
||||||
#define XMLParser_CheckExact(op) (Py_TYPE(op) == &XMLParser_Type)
|
static PyObject*
|
||||||
|
_elementtree_XMLParser_doctype(XMLParserObject* self, PyObject* args);
|
||||||
|
static PyObject *
|
||||||
|
_elementtree_XMLParser_doctype_impl(XMLParserObject *self, PyObject *name,
|
||||||
|
PyObject *pubid, PyObject *system);
|
||||||
|
|
||||||
/* helpers */
|
/* helpers */
|
||||||
|
|
||||||
|
@ -3182,20 +3186,22 @@ expat_start_doctype_handler(XMLParserObject *self,
|
||||||
doctype_name_obj, pubid_obj, sysid_obj);
|
doctype_name_obj, pubid_obj, sysid_obj);
|
||||||
Py_CLEAR(res);
|
Py_CLEAR(res);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
/* Now see if the parser itself has a doctype method. If yes and it's
|
/* Now see if the parser itself has a doctype method. If yes and it's
|
||||||
* a subclass, call it but warn about deprecation. If it's not a subclass
|
* a custom method, call it but warn about deprecation. If it's only
|
||||||
* (i.e. vanilla XMLParser), do nothing.
|
* the vanilla XMLParser method, do nothing.
|
||||||
*/
|
*/
|
||||||
parser_doctype = PyObject_GetAttrString(self_pyobj, "doctype");
|
parser_doctype = PyObject_GetAttrString(self_pyobj, "doctype");
|
||||||
if (parser_doctype) {
|
if (parser_doctype &&
|
||||||
if (!XMLParser_CheckExact(self_pyobj)) {
|
!(PyCFunction_Check(parser_doctype) &&
|
||||||
if (PyErr_WarnEx(PyExc_DeprecationWarning,
|
PyCFunction_GET_SELF(parser_doctype) == self_pyobj &&
|
||||||
"This method of XMLParser is deprecated. Define"
|
PyCFunction_GET_FUNCTION(parser_doctype) ==
|
||||||
" doctype() method on the TreeBuilder target.",
|
(PyCFunction) _elementtree_XMLParser_doctype)) {
|
||||||
1) < 0) {
|
res = _elementtree_XMLParser_doctype_impl(self, doctype_name_obj,
|
||||||
|
pubid_obj, sysid_obj);
|
||||||
|
if (!res)
|
||||||
goto clear;
|
goto clear;
|
||||||
}
|
Py_DECREF(res);
|
||||||
res = PyObject_CallFunction(parser_doctype, "OOO",
|
res = PyObject_CallFunction(parser_doctype, "OOO",
|
||||||
doctype_name_obj, pubid_obj, sysid_obj);
|
doctype_name_obj, pubid_obj, sysid_obj);
|
||||||
Py_CLEAR(res);
|
Py_CLEAR(res);
|
||||||
|
@ -3572,12 +3578,24 @@ _elementtree_XMLParser__parse_whole(XMLParserObject *self, PyObject *file)
|
||||||
/*[clinic input]
|
/*[clinic input]
|
||||||
_elementtree.XMLParser.doctype
|
_elementtree.XMLParser.doctype
|
||||||
|
|
||||||
|
name: object
|
||||||
|
pubid: object
|
||||||
|
system: object
|
||||||
|
/
|
||||||
|
|
||||||
[clinic start generated code]*/
|
[clinic start generated code]*/
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
_elementtree_XMLParser_doctype_impl(XMLParserObject *self)
|
_elementtree_XMLParser_doctype_impl(XMLParserObject *self, PyObject *name,
|
||||||
/*[clinic end generated code: output=d09fdb9c45f3a602 input=20d5e0febf902a2f]*/
|
PyObject *pubid, PyObject *system)
|
||||||
|
/*[clinic end generated code: output=10fb50c2afded88d input=84050276cca045e1]*/
|
||||||
{
|
{
|
||||||
|
if (PyErr_WarnEx(PyExc_DeprecationWarning,
|
||||||
|
"This method of XMLParser is deprecated. Define"
|
||||||
|
" doctype() method on the TreeBuilder target.",
|
||||||
|
1) < 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -619,20 +619,33 @@ PyDoc_STRVAR(_elementtree_XMLParser__parse_whole__doc__,
|
||||||
{"_parse_whole", (PyCFunction)_elementtree_XMLParser__parse_whole, METH_O, _elementtree_XMLParser__parse_whole__doc__},
|
{"_parse_whole", (PyCFunction)_elementtree_XMLParser__parse_whole, METH_O, _elementtree_XMLParser__parse_whole__doc__},
|
||||||
|
|
||||||
PyDoc_STRVAR(_elementtree_XMLParser_doctype__doc__,
|
PyDoc_STRVAR(_elementtree_XMLParser_doctype__doc__,
|
||||||
"doctype($self, /)\n"
|
"doctype($self, name, pubid, system, /)\n"
|
||||||
"--\n"
|
"--\n"
|
||||||
"\n");
|
"\n");
|
||||||
|
|
||||||
#define _ELEMENTTREE_XMLPARSER_DOCTYPE_METHODDEF \
|
#define _ELEMENTTREE_XMLPARSER_DOCTYPE_METHODDEF \
|
||||||
{"doctype", (PyCFunction)_elementtree_XMLParser_doctype, METH_NOARGS, _elementtree_XMLParser_doctype__doc__},
|
{"doctype", (PyCFunction)_elementtree_XMLParser_doctype, METH_VARARGS, _elementtree_XMLParser_doctype__doc__},
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
_elementtree_XMLParser_doctype_impl(XMLParserObject *self);
|
_elementtree_XMLParser_doctype_impl(XMLParserObject *self, PyObject *name,
|
||||||
|
PyObject *pubid, PyObject *system);
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
_elementtree_XMLParser_doctype(XMLParserObject *self, PyObject *Py_UNUSED(ignored))
|
_elementtree_XMLParser_doctype(XMLParserObject *self, PyObject *args)
|
||||||
{
|
{
|
||||||
return _elementtree_XMLParser_doctype_impl(self);
|
PyObject *return_value = NULL;
|
||||||
|
PyObject *name;
|
||||||
|
PyObject *pubid;
|
||||||
|
PyObject *system;
|
||||||
|
|
||||||
|
if (!PyArg_UnpackTuple(args, "doctype",
|
||||||
|
3, 3,
|
||||||
|
&name, &pubid, &system))
|
||||||
|
goto exit;
|
||||||
|
return_value = _elementtree_XMLParser_doctype_impl(self, name, pubid, system);
|
||||||
|
|
||||||
|
exit:
|
||||||
|
return return_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyDoc_STRVAR(_elementtree_XMLParser__setevents__doc__,
|
PyDoc_STRVAR(_elementtree_XMLParser__setevents__doc__,
|
||||||
|
@ -663,4 +676,4 @@ _elementtree_XMLParser__setevents(XMLParserObject *self, PyObject *args)
|
||||||
exit:
|
exit:
|
||||||
return return_value;
|
return return_value;
|
||||||
}
|
}
|
||||||
/*[clinic end generated code: output=119aed84c1545187 input=a9049054013a1b77]*/
|
/*[clinic end generated code: output=25b8bf7e7f2151ca input=a9049054013a1b77]*/
|
||||||
|
|
Loading…
Reference in New Issue