mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 18:59:04 +08:00
Forward pyexpat lexical events (#8264)
* Restore pyexpat lexical callback compatibility Forward processing instructions, comments, and CDATA boundaries already emitted by xml-rs so registered Python handlers observe CPython-compatible events. Constraint: Reuse existing xml-rs events without changing the dependency Confidence: high Scope-risk: narrow Tested: prek; test_pyexpat; test_sax; 402 extra tests; workspace tests; clippy Assisted-by: Codex:gpt-5.6-sol * Recognize XML compatibility restored by lexical events Remove stale expected-failure markers for CPython XML tests now satisfied by pyexpat lexical-event forwarding, and simplify parser event error propagation. Constraint: CPython test edits are limited to removing stale expectedFailure markers Confidence: high Scope-risk: narrow Directive: Keep parser event dispatch aligned with pyexpat handler behavior Tested: user-verified full suite; prek run --all-files; cargo run --release -- -m test test_pyexpat test_xml_etree test_xml_etree_c test_minidom test_sax Assisted-by: Codex:gpt-5.6-sol
This commit is contained in:
1 parent
8e2872538b
commit
fe7993572c
5 files changed
+43
-15
No files matched your search
Vendored
-5
@@ -659,7 +659,6 @@ class MinidomTest(unittest.TestCase):
|
||||
self.assertIsNone(pi.localName)
|
||||
self.assertEqual(pi.namespaceURI, xml.dom.EMPTY_NAMESPACE)
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON
|
||||
def testProcessingInstructionRepr(self):
|
||||
dom = parseString('<e><?mypi \t\n data \t\n ?></e>')
|
||||
pi = dom.documentElement.firstChild
|
||||
@@ -957,11 +956,9 @@ class MinidomTest(unittest.TestCase):
|
||||
self.confirm(clone.target == pi.target
|
||||
and clone.data == pi.data)
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON
|
||||
def testClonePIShallow(self):
|
||||
self.check_clone_pi(0, "testClonePIShallow")
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON
|
||||
def testClonePIDeep(self):
|
||||
self.check_clone_pi(1, "testClonePIDeep")
|
||||
|
||||
@@ -1219,7 +1216,6 @@ class MinidomTest(unittest.TestCase):
|
||||
self.assertIsNone(node.childNodes[-1].nextSibling,
|
||||
"Final child's .nextSibling should be None")
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON
|
||||
def testSiblings(self):
|
||||
doc = parseString("<doc><?pi?>text?<elm/></doc>")
|
||||
root = doc.documentElement
|
||||
@@ -1792,7 +1788,6 @@ class MinidomTest(unittest.TestCase):
|
||||
'<?xml version="1.0" ?>\n'
|
||||
'<curriculum status="public" company="example"/>\n')
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON
|
||||
def test_toprettyxml_with_cdata(self):
|
||||
xml_str = '<?xml version="1.0" ?><root><node><![CDATA[</data>]]></node></root>'
|
||||
doc = parseString(xml_str)
|
||||
|
||||
Vendored
-1
@@ -560,7 +560,6 @@ class BufferTextTest(unittest.TestCase):
|
||||
["<a>", "1", "<b>", "</b>", "2", "<c>", "</c>", "345", "</a>"],
|
||||
"buffered text not properly split")
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON
|
||||
def test7(self):
|
||||
self.setHandlers(["CommentHandler", "EndElementHandler",
|
||||
"StartElementHandler"])
|
||||
|
||||
Vendored
-2
@@ -1800,7 +1800,6 @@ class XMLPullParserTest(unittest.TestCase):
|
||||
self._feed(parser, "<!-- text here -->\n")
|
||||
self.assert_events(parser, [('comment', (ET.Comment, ' text here '))])
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON
|
||||
def test_events_pi(self):
|
||||
parser = ET.XMLPullParser(events=('start', 'pi', 'end'))
|
||||
self._feed(parser, "<?pitarget?>\n")
|
||||
@@ -3821,7 +3820,6 @@ class TreeBuilderTest(unittest.TestCase):
|
||||
a = parser.close()
|
||||
self.assertEqual(a.text, "texttail")
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON
|
||||
def test_late_tail_mix_pi_comments(self):
|
||||
# Issue #37399: The tail of an ignored comment could overwrite the text before it.
|
||||
# Test appending tails to comments/pis.
|
||||
|
||||
@@ -305,8 +305,9 @@ mod _pyexpat {
|
||||
|
||||
fn create_config(&self) -> xml::ParserConfig {
|
||||
xml::ParserConfig::new()
|
||||
.cdata_to_characters(true)
|
||||
.cdata_to_characters(false)
|
||||
.coalesce_characters(false)
|
||||
.ignore_comments(false)
|
||||
.whitespace_to_characters(true)
|
||||
}
|
||||
|
||||
@@ -350,10 +351,10 @@ mod _pyexpat {
|
||||
T: std::io::Read,
|
||||
{
|
||||
for e in parser {
|
||||
match e {
|
||||
Ok(XmlEvent::StartElement {
|
||||
match e? {
|
||||
XmlEvent::StartElement {
|
||||
name, attributes, ..
|
||||
}) => {
|
||||
} => {
|
||||
let dict = vm.ctx.new_dict();
|
||||
for attribute in attributes {
|
||||
let attr_name = self.make_name(&attribute.name);
|
||||
@@ -368,15 +369,29 @@ mod _pyexpat {
|
||||
let name_str = PyStr::from(self.make_name(&name)).into_ref(&vm.ctx);
|
||||
invoke_handler(vm, &self.start_element, (name_str, dict));
|
||||
}
|
||||
Ok(XmlEvent::EndElement { name, .. }) => {
|
||||
XmlEvent::EndElement { name, .. } => {
|
||||
let name_str = PyStr::from(self.make_name(&name)).into_ref(&vm.ctx);
|
||||
invoke_handler(vm, &self.end_element, (name_str,));
|
||||
}
|
||||
Ok(XmlEvent::Characters(chars)) => {
|
||||
XmlEvent::Characters(chars) => {
|
||||
let str = PyStr::from(chars).into_ref(&vm.ctx);
|
||||
invoke_handler(vm, &self.character_data, (str,));
|
||||
}
|
||||
Err(e) => return Err(e),
|
||||
XmlEvent::ProcessingInstruction { name, data } => {
|
||||
let name = PyStr::from(name).into_ref(&vm.ctx);
|
||||
let data = PyStr::from(data.unwrap_or_default()).into_ref(&vm.ctx);
|
||||
invoke_handler(vm, &self.processing_instruction, (name, data));
|
||||
}
|
||||
XmlEvent::Comment(comment) => {
|
||||
let comment = PyStr::from(comment).into_ref(&vm.ctx);
|
||||
invoke_handler(vm, &self.comment, (comment,));
|
||||
}
|
||||
XmlEvent::CData(chars) => {
|
||||
invoke_handler(vm, &self.start_cdata_section, ());
|
||||
let str = PyStr::from(chars).into_ref(&vm.ctx);
|
||||
invoke_handler(vm, &self.character_data, (str,));
|
||||
invoke_handler(vm, &self.end_cdata_section, ());
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,3 +45,24 @@ assert handler.events == [
|
||||
("end", "child"),
|
||||
("end", "main"),
|
||||
]
|
||||
|
||||
events = []
|
||||
parser = expat.ParserCreate()
|
||||
parser.ProcessingInstructionHandler = lambda target, data: events.append(
|
||||
("processing-instruction", target, data)
|
||||
)
|
||||
parser.CommentHandler = lambda data: events.append(("comment", data))
|
||||
parser.StartCdataSectionHandler = lambda: events.append(("start-cdata",))
|
||||
parser.CharacterDataHandler = lambda data: events.append(("characters", data))
|
||||
parser.EndCdataSectionHandler = lambda: events.append(("end-cdata",))
|
||||
parser.Parse(
|
||||
"<?target data?><?empty?><root><!--comment--><![CDATA[text]]></root>", True
|
||||
)
|
||||
assert events == [
|
||||
("processing-instruction", "target", "data"),
|
||||
("processing-instruction", "empty", ""),
|
||||
("comment", "comment"),
|
||||
("start-cdata",),
|
||||
("characters", "text"),
|
||||
("end-cdata",),
|
||||
]
|
||||
Reference in new issue
Block a user