1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
|
# -*- coding: utf-8 -*-
"""
Test cases related to direct loading of external libxml2 documents
"""
from __future__ import absolute_import
import sys
import unittest
from .common_imports import HelperTestCase, etree
DOC_NAME = b'libxml2:xmlDoc'
DESTRUCTOR_NAME = b'destructor:xmlFreeDoc'
class ExternalDocumentTestCase(HelperTestCase):
def setUp(self):
try:
import ctypes
from ctypes import pythonapi
from ctypes.util import find_library
except ImportError:
raise unittest.SkipTest("ctypes support missing")
def wrap(func, restype, *argtypes):
func.restype = restype
func.argtypes = list(argtypes)
return func
self.get_capsule_name = wrap(pythonapi.PyCapsule_GetName,
ctypes.c_char_p, ctypes.py_object)
self.capsule_is_valid = wrap(pythonapi.PyCapsule_IsValid, ctypes.c_int,
ctypes.py_object, ctypes.c_char_p)
self.new_capsule = wrap(pythonapi.PyCapsule_New, ctypes.py_object,
ctypes.c_void_p, ctypes.c_char_p,
ctypes.c_void_p)
self.set_capsule_name = wrap(pythonapi.PyCapsule_SetName, ctypes.c_int,
ctypes.py_object, ctypes.c_char_p)
self.set_capsule_context = wrap(pythonapi.PyCapsule_SetContext,
ctypes.c_int, ctypes.py_object,
ctypes.c_char_p)
self.get_capsule_context = wrap(pythonapi.PyCapsule_GetContext,
ctypes.c_char_p, ctypes.py_object)
self.get_capsule_pointer = wrap(pythonapi.PyCapsule_GetPointer,
ctypes.c_void_p, ctypes.py_object,
ctypes.c_char_p)
self.set_capsule_pointer = wrap(pythonapi.PyCapsule_SetPointer,
ctypes.c_int, ctypes.py_object,
ctypes.c_void_p)
self.set_capsule_destructor = wrap(pythonapi.PyCapsule_SetDestructor,
ctypes.c_int, ctypes.py_object,
ctypes.c_void_p)
self.PyCapsule_Destructor = ctypes.CFUNCTYPE(None, ctypes.py_object)
libxml2 = ctypes.CDLL(find_library('xml2'))
self.create_doc = wrap(libxml2.xmlReadMemory, ctypes.c_void_p,
ctypes.c_char_p, ctypes.c_int, ctypes.c_char_p,
ctypes.c_char_p, ctypes.c_int)
self.free_doc = wrap(libxml2.xmlFreeDoc, None, ctypes.c_void_p)
def as_capsule(self, text, capsule_name=DOC_NAME):
if not isinstance(text, bytes):
text = text.encode('utf-8')
doc = self.create_doc(text, len(text), b'base.xml', b'utf-8', 0)
ans = self.new_capsule(doc, capsule_name, None)
self.set_capsule_context(ans, DESTRUCTOR_NAME)
return ans
def test_external_document_adoption(self):
xml = '<r a="1">t</r>'
self.assertRaises(TypeError, etree.adopt_external_document, None)
capsule = self.as_capsule(xml)
self.assertTrue(self.capsule_is_valid(capsule, DOC_NAME))
self.assertEqual(DOC_NAME, self.get_capsule_name(capsule))
# Create an lxml tree from the capsule (this is a move not a copy)
root = etree.adopt_external_document(capsule).getroot()
self.assertIsNone(self.get_capsule_name(capsule))
self.assertEqual(root.text, 't')
root.text = 'new text'
# Now reset the capsule so we can copy it
self.assertEqual(0, self.set_capsule_name(capsule, DOC_NAME))
self.assertEqual(0, self.set_capsule_context(capsule, b'invalid'))
# Create an lxml tree from the capsule (this is a copy not a move)
root2 = etree.adopt_external_document(capsule).getroot()
self.assertEqual(self.get_capsule_context(capsule), b'invalid')
# Check that the modification to the tree using the transferred
# document was successful
self.assertEqual(root.text, root2.text)
# Check that further modifications do not show up in the copy (they are
# disjoint)
root.text = 'other text'
self.assertNotEqual(root.text, root2.text)
# delete root and ensure root2 survives
del root
self.assertEqual(root2.text, 'new text')
def test_suite():
suite = unittest.TestSuite()
if sys.platform != 'win32':
suite.addTests([unittest.makeSuite(ExternalDocumentTestCase)])
return suite
if __name__ == '__main__':
print('to test use test.py %s' % __file__)
|