Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 05744ac

Browse files
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.
1 parent 7b6e3b9 commit 05744ac

3 files changed

Lines changed: 68 additions & 14 deletions

File tree

Lib/test/test_xml_etree.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import sys
1313
import types
1414
import unittest
15+
import warnings
1516
import weakref
1617

1718
from itertools import product
@@ -2237,6 +2238,20 @@ class MyParser(ET.XMLParser):
22372238
parser.feed(self.sample1)
22382239
self._check_sample_element(parser.close())
22392240

2241+
def test_doctype_warning(self):
2242+
parser = ET.XMLParser()
2243+
with self.assertWarns(DeprecationWarning):
2244+
parser.doctype('html', '-//W3C//DTD XHTML 1.0 Transitional//EN',
2245+
'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd')
2246+
parser.feed('<html/>')
2247+
parser.close()
2248+
2249+
with warnings.catch_warnings():
2250+
warnings.simplefilter('error', DeprecationWarning)
2251+
parser = ET.XMLParser()
2252+
parser.feed(self.sample2)
2253+
parser.close()
2254+
22402255
def test_subclass_doctype(self):
22412256
_doctype = None
22422257
class MyParserWithDoctype(ET.XMLParser):
@@ -2252,6 +2267,32 @@ def doctype(self, name, pubid, system):
22522267
('html', '-//W3C//DTD XHTML 1.0 Transitional//EN',
22532268
'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'))
22542269

2270+
_doctype = _doctype2 = None
2271+
with warnings.catch_warnings():
2272+
warnings.simplefilter('error', DeprecationWarning)
2273+
class DoctypeParser:
2274+
def doctype(self, name, pubid, system):
2275+
nonlocal _doctype2
2276+
_doctype2 = (name, pubid, system)
2277+
2278+
parser = MyParserWithDoctype(target=DoctypeParser())
2279+
parser.feed(self.sample2)
2280+
parser.close()
2281+
self.assertIsNone(_doctype)
2282+
self.assertEqual(_doctype2,
2283+
('html', '-//W3C//DTD XHTML 1.0 Transitional//EN',
2284+
'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'))
2285+
2286+
def test_inherited_doctype(self):
2287+
'''Ensure that ordinary usage is not deprecated (Issue 19176)'''
2288+
with warnings.catch_warnings():
2289+
warnings.simplefilter('error', DeprecationWarning)
2290+
class MyParserWithoutDoctype(ET.XMLParser):
2291+
pass
2292+
parser = MyParserWithoutDoctype()
2293+
parser.feed(self.sample2)
2294+
parser.close()
2295+
22552296
def test_parse_string(self):
22562297
parser = ET.XMLParser(target=ET.TreeBuilder())
22572298
parser.feed(self.sample3)

Misc/NEWS

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,12 @@ Core and Builtins
6464
Library
6565
-------
6666

67+
- Issue #19176: Fixed doctype() related bugs in C implementation of ElementTree.
68+
A deprecation warning no longer issued by XMLParser subclass with default
69+
doctype() method. Direct call of doctype() now issues a warning. Parser's
70+
doctype() now is not called if target's doctype() is called. Based on patch
71+
by Martin Panter.
72+
6773
- Issue #20387: Restore semantic round-trip correctness in tokenize/untokenize
6874
for tab-indented blocks.
6975

Modules/_elementtree.c

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2791,7 +2791,7 @@ typedef struct {
27912791

27922792
} XMLParserObject;
27932793

2794-
#define XMLParser_CheckExact(op) (Py_TYPE(op) == &XMLParser_Type)
2794+
static PyObject* xmlparser_doctype(XMLParserObject* self, PyObject* args);
27952795

27962796
/* helpers */
27972797

@@ -3190,20 +3190,21 @@ expat_start_doctype_handler(XMLParserObject *self,
31903190
doctype_name_obj, pubid_obj, sysid_obj);
31913191
Py_CLEAR(res);
31923192
}
3193-
3194-
/* Now see if the parser itself has a doctype method. If yes and it's
3195-
* a subclass, call it but warn about deprecation. If it's not a subclass
3196-
* (i.e. vanilla XMLParser), do nothing.
3197-
*/
3198-
parser_doctype = PyObject_GetAttrString(self_pyobj, "doctype");
3199-
if (parser_doctype) {
3200-
if (!XMLParser_CheckExact(self_pyobj)) {
3201-
if (PyErr_WarnEx(PyExc_DeprecationWarning,
3202-
"This method of XMLParser is deprecated. Define"
3203-
" doctype() method on the TreeBuilder target.",
3204-
1) < 0) {
3193+
else {
3194+
/* Now see if the parser itself has a doctype method. If yes and it's
3195+
* a custom method, call it but warn about deprecation. If it's only
3196+
* the vanilla XMLParser method, do nothing.
3197+
*/
3198+
parser_doctype = PyObject_GetAttrString(self_pyobj, "doctype");
3199+
if (parser_doctype &&
3200+
!(PyCFunction_Check(parser_doctype) &&
3201+
PyCFunction_GET_SELF(parser_doctype) == self_pyobj &&
3202+
PyCFunction_GET_FUNCTION(parser_doctype) ==
3203+
(PyCFunction) xmlparser_doctype)) {
3204+
res = xmlparser_doctype(self, NULL);
3205+
if (!res)
32053206
goto clear;
3206-
}
3207+
Py_DECREF(res);
32073208
res = PyObject_CallFunction(parser_doctype, "OOO",
32083209
doctype_name_obj, pubid_obj, sysid_obj);
32093210
Py_CLEAR(res);
@@ -3556,6 +3557,12 @@ xmlparser_parse_whole(XMLParserObject* self, PyObject* args)
35563557
static PyObject*
35573558
xmlparser_doctype(XMLParserObject *self, PyObject *args)
35583559
{
3560+
if (PyErr_WarnEx(PyExc_DeprecationWarning,
3561+
"This method of XMLParser is deprecated. Define"
3562+
" doctype() method on the TreeBuilder target.",
3563+
1) < 0) {
3564+
return NULL;
3565+
}
35593566
Py_RETURN_NONE;
35603567
}
35613568

0 commit comments

Comments
 (0)