mirror of
				https://github.com/python/cpython.git
				synced 2025-11-04 03:44:55 +00:00 
			
		
		
		
	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
					
				
					 4 changed files with 100 additions and 22 deletions
				
			
		| 
						 | 
				
			
			@ -12,6 +12,7 @@ import pickle
 | 
			
		|||
import sys
 | 
			
		||||
import types
 | 
			
		||||
import unittest
 | 
			
		||||
import warnings
 | 
			
		||||
import weakref
 | 
			
		||||
 | 
			
		||||
from itertools import product
 | 
			
		||||
| 
						 | 
				
			
			@ -2237,6 +2238,20 @@ class XMLParserTest(unittest.TestCase):
 | 
			
		|||
        parser.feed(self.sample1)
 | 
			
		||||
        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):
 | 
			
		||||
        _doctype = None
 | 
			
		||||
        class MyParserWithDoctype(ET.XMLParser):
 | 
			
		||||
| 
						 | 
				
			
			@ -2252,6 +2267,32 @@ class XMLParserTest(unittest.TestCase):
 | 
			
		|||
            ('html', '-//W3C//DTD XHTML 1.0 Transitional//EN',
 | 
			
		||||
             '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):
 | 
			
		||||
        parser = ET.XMLParser(target=ET.TreeBuilder())
 | 
			
		||||
        parser.feed(self.sample3)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -51,6 +51,12 @@ Core and Builtins
 | 
			
		|||
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
 | 
			
		||||
  for tab-indented blocks.
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2782,7 +2782,11 @@ typedef struct {
 | 
			
		|||
 | 
			
		||||
} 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 */
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3182,20 +3186,22 @@ expat_start_doctype_handler(XMLParserObject *self,
 | 
			
		|||
                                    doctype_name_obj, pubid_obj, sysid_obj);
 | 
			
		||||
        Py_CLEAR(res);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    else {
 | 
			
		||||
        /* 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
 | 
			
		||||
     * (i.e. vanilla XMLParser), do nothing.
 | 
			
		||||
         * a custom method, call it but warn about deprecation. If it's only
 | 
			
		||||
         * the vanilla XMLParser method, do nothing.
 | 
			
		||||
         */
 | 
			
		||||
        parser_doctype = PyObject_GetAttrString(self_pyobj, "doctype");
 | 
			
		||||
    if (parser_doctype) {
 | 
			
		||||
        if (!XMLParser_CheckExact(self_pyobj)) {
 | 
			
		||||
            if (PyErr_WarnEx(PyExc_DeprecationWarning,
 | 
			
		||||
                            "This method of XMLParser is deprecated.  Define"
 | 
			
		||||
                            " doctype() method on the TreeBuilder target.",
 | 
			
		||||
                            1) < 0) {
 | 
			
		||||
        if (parser_doctype &&
 | 
			
		||||
            !(PyCFunction_Check(parser_doctype) &&
 | 
			
		||||
              PyCFunction_GET_SELF(parser_doctype) == self_pyobj &&
 | 
			
		||||
              PyCFunction_GET_FUNCTION(parser_doctype) ==
 | 
			
		||||
                    (PyCFunction) _elementtree_XMLParser_doctype)) {
 | 
			
		||||
            res = _elementtree_XMLParser_doctype_impl(self, doctype_name_obj,
 | 
			
		||||
                                                      pubid_obj, sysid_obj);
 | 
			
		||||
            if (!res)
 | 
			
		||||
                goto clear;
 | 
			
		||||
            }
 | 
			
		||||
            Py_DECREF(res);
 | 
			
		||||
            res = PyObject_CallFunction(parser_doctype, "OOO",
 | 
			
		||||
                                        doctype_name_obj, pubid_obj, sysid_obj);
 | 
			
		||||
            Py_CLEAR(res);
 | 
			
		||||
| 
						 | 
				
			
			@ -3572,12 +3578,24 @@ _elementtree_XMLParser__parse_whole(XMLParserObject *self, PyObject *file)
 | 
			
		|||
/*[clinic input]
 | 
			
		||||
_elementtree.XMLParser.doctype
 | 
			
		||||
 | 
			
		||||
    name: object
 | 
			
		||||
    pubid: object
 | 
			
		||||
    system: object
 | 
			
		||||
    /
 | 
			
		||||
 | 
			
		||||
[clinic start generated code]*/
 | 
			
		||||
 | 
			
		||||
static PyObject *
 | 
			
		||||
_elementtree_XMLParser_doctype_impl(XMLParserObject *self)
 | 
			
		||||
/*[clinic end generated code: output=d09fdb9c45f3a602 input=20d5e0febf902a2f]*/
 | 
			
		||||
_elementtree_XMLParser_doctype_impl(XMLParserObject *self, PyObject *name,
 | 
			
		||||
                                    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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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__},
 | 
			
		||||
 | 
			
		||||
PyDoc_STRVAR(_elementtree_XMLParser_doctype__doc__,
 | 
			
		||||
"doctype($self, /)\n"
 | 
			
		||||
"doctype($self, name, pubid, system, /)\n"
 | 
			
		||||
"--\n"
 | 
			
		||||
"\n");
 | 
			
		||||
 | 
			
		||||
#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 *
 | 
			
		||||
_elementtree_XMLParser_doctype_impl(XMLParserObject *self);
 | 
			
		||||
_elementtree_XMLParser_doctype_impl(XMLParserObject *self, PyObject *name,
 | 
			
		||||
                                    PyObject *pubid, PyObject *system);
 | 
			
		||||
 | 
			
		||||
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__,
 | 
			
		||||
| 
						 | 
				
			
			@ -663,4 +676,4 @@ _elementtree_XMLParser__setevents(XMLParserObject *self, PyObject *args)
 | 
			
		|||
exit:
 | 
			
		||||
    return return_value;
 | 
			
		||||
}
 | 
			
		||||
/*[clinic end generated code: output=119aed84c1545187 input=a9049054013a1b77]*/
 | 
			
		||||
/*[clinic end generated code: output=25b8bf7e7f2151ca input=a9049054013a1b77]*/
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue