@@ -814,6 +814,176 @@ element_sizeof(PyObject* _self, PyObject* args)
814814 return PyLong_FromSsize_t (result );
815815}
816816
817+ /* dict keys for getstate/setstate. */
818+ #define PICKLED_TAG "tag"
819+ #define PICKLED_CHILDREN "_children"
820+ #define PICKLED_ATTRIB "attrib"
821+ #define PICKLED_TAIL "tail"
822+ #define PICKLED_TEXT "text"
823+
824+ /* __getstate__ returns a fabricated instance dict as in the pure-Python
825+ * Element implementation, for interoperability/interchangeability. This
826+ * makes the pure-Python implementation details an API, but (a) there aren't
827+ * any unnecessary structures there; and (b) it buys compatibility with 3.2
828+ * pickles. See issue #16076.
829+ */
830+ static PyObject *
831+ element_getstate (ElementObject * self )
832+ {
833+ int i , noattrib ;
834+ PyObject * instancedict = NULL , * children ;
835+
836+ /* Build a list of children. */
837+ children = PyList_New (self -> extra ? self -> extra -> length : 0 );
838+ if (!children )
839+ return NULL ;
840+ for (i = 0 ; i < PyList_GET_SIZE (children ); i ++ ) {
841+ PyObject * child = self -> extra -> children [i ];
842+ Py_INCREF (child );
843+ PyList_SET_ITEM (children , i , child );
844+ }
845+
846+ /* Construct the state object. */
847+ noattrib = (self -> extra == NULL || self -> extra -> attrib == Py_None );
848+ if (noattrib )
849+ instancedict = Py_BuildValue ("{sOsOs{}sOsO}" ,
850+ PICKLED_TAG , self -> tag ,
851+ PICKLED_CHILDREN , children ,
852+ PICKLED_ATTRIB ,
853+ PICKLED_TEXT , self -> text ,
854+ PICKLED_TAIL , self -> tail );
855+ else
856+ instancedict = Py_BuildValue ("{sOsOsOsOsO}" ,
857+ PICKLED_TAG , self -> tag ,
858+ PICKLED_CHILDREN , children ,
859+ PICKLED_ATTRIB , self -> extra -> attrib ,
860+ PICKLED_TEXT , self -> text ,
861+ PICKLED_TAIL , self -> tail );
862+ if (instancedict )
863+ return instancedict ;
864+ else {
865+ for (i = 0 ; i < PyList_GET_SIZE (children ); i ++ )
866+ Py_DECREF (PyList_GET_ITEM (children , i ));
867+ Py_DECREF (children );
868+
869+ return NULL ;
870+ }
871+ }
872+
873+ static PyObject *
874+ element_setstate_from_attributes (ElementObject * self ,
875+ PyObject * tag ,
876+ PyObject * attrib ,
877+ PyObject * text ,
878+ PyObject * tail ,
879+ PyObject * children )
880+ {
881+ Py_ssize_t i , nchildren ;
882+
883+ if (!tag ) {
884+ PyErr_SetString (PyExc_TypeError , "tag may not be NULL" );
885+ return NULL ;
886+ }
887+ if (!text ) {
888+ Py_INCREF (Py_None );
889+ text = Py_None ;
890+ }
891+ if (!tail ) {
892+ Py_INCREF (Py_None );
893+ tail = Py_None ;
894+ }
895+
896+ Py_CLEAR (self -> tag );
897+ self -> tag = tag ;
898+ Py_INCREF (self -> tag );
899+
900+ Py_CLEAR (self -> text );
901+ self -> text = text ;
902+ Py_INCREF (self -> text );
903+
904+ Py_CLEAR (self -> tail );
905+ self -> tail = tail ;
906+ Py_INCREF (self -> tail );
907+
908+ /* Handle ATTRIB and CHILDREN. */
909+ if (!children && !attrib )
910+ Py_RETURN_NONE ;
911+
912+ /* Compute 'nchildren'. */
913+ if (children ) {
914+ if (!PyList_Check (children )) {
915+ PyErr_SetString (PyExc_TypeError , "'_children' is not a list" );
916+ return NULL ;
917+ }
918+ nchildren = PyList_Size (children );
919+ }
920+ else {
921+ nchildren = 0 ;
922+ }
923+
924+ /* Allocate 'extra'. */
925+ if (element_resize (self , nchildren )) {
926+ return NULL ;
927+ }
928+ assert (self -> extra && self -> extra -> allocated >= nchildren );
929+
930+ /* Copy children */
931+ for (i = 0 ; i < nchildren ; i ++ ) {
932+ self -> extra -> children [i ] = PyList_GET_ITEM (children , i );
933+ Py_INCREF (self -> extra -> children [i ]);
934+ }
935+
936+ self -> extra -> length = nchildren ;
937+ self -> extra -> allocated = nchildren ;
938+
939+ /* Stash attrib. */
940+ if (attrib ) {
941+ Py_CLEAR (self -> extra -> attrib );
942+ self -> extra -> attrib = attrib ;
943+ Py_INCREF (attrib );
944+ }
945+
946+ Py_RETURN_NONE ;
947+ }
948+
949+ /* __setstate__ for Element instance from the Python implementation.
950+ * 'state' should be the instance dict.
951+ */
952+ static PyObject *
953+ element_setstate_from_Python (ElementObject * self , PyObject * state )
954+ {
955+ static char * kwlist [] = {PICKLED_TAG , PICKLED_ATTRIB , PICKLED_TEXT ,
956+ PICKLED_TAIL , PICKLED_CHILDREN , 0 };
957+ PyObject * args ;
958+ PyObject * tag , * attrib , * text , * tail , * children ;
959+ int error ;
960+
961+ /* More instance dict members than we know to handle? */
962+ tag = attrib = text = tail = children = NULL ;
963+ args = PyTuple_New (0 );
964+ error = ! PyArg_ParseTupleAndKeywords (args , state , "|$OOOOO" , kwlist , & tag ,
965+ & attrib , & text , & tail , & children );
966+ Py_DECREF (args );
967+ if (error )
968+ return NULL ;
969+ else
970+ return element_setstate_from_attributes (self , tag , attrib , text ,
971+ tail , children );
972+ }
973+
974+ static PyObject *
975+ element_setstate (ElementObject * self , PyObject * state )
976+ {
977+ if (!PyDict_CheckExact (state )) {
978+ PyErr_Format (PyExc_TypeError ,
979+ "Don't know how to unpickle \"%.200R\" as an Element" ,
980+ state );
981+ return NULL ;
982+ }
983+ else
984+ return element_setstate_from_Python (self , state );
985+ }
986+
817987LOCAL (int )
818988checkpath (PyObject * tag )
819989{
@@ -1587,6 +1757,8 @@ static PyMethodDef element_methods[] = {
15871757 {"__copy__" , (PyCFunction ) element_copy , METH_VARARGS },
15881758 {"__deepcopy__" , (PyCFunction ) element_deepcopy , METH_VARARGS },
15891759 {"__sizeof__" , element_sizeof , METH_NOARGS },
1760+ {"__getstate__" , (PyCFunction )element_getstate , METH_NOARGS },
1761+ {"__setstate__" , (PyCFunction )element_setstate , METH_O },
15901762
15911763 {NULL , NULL }
15921764};
@@ -1691,7 +1863,7 @@ static PyMappingMethods element_as_mapping = {
16911863
16921864static PyTypeObject Element_Type = {
16931865 PyVarObject_HEAD_INIT (NULL , 0 )
1694- "Element" , sizeof (ElementObject ), 0 ,
1866+ "xml.etree.ElementTree. Element" , sizeof (ElementObject ), 0 ,
16951867 /* methods */
16961868 (destructor )element_dealloc , /* tp_dealloc */
16971869 0 , /* tp_print */
@@ -1913,6 +2085,8 @@ elementiter_next(ElementIterObject *it)
19132085
19142086static PyTypeObject ElementIter_Type = {
19152087 PyVarObject_HEAD_INIT (NULL , 0 )
2088+ /* Using the module's name since the pure-Python implementation does not
2089+ have such a type. */
19162090 "_elementtree._element_iterator" , /* tp_name */
19172091 sizeof (ElementIterObject ), /* tp_basicsize */
19182092 0 , /* tp_itemsize */
@@ -2458,7 +2632,7 @@ static PyMethodDef treebuilder_methods[] = {
24582632
24592633static PyTypeObject TreeBuilder_Type = {
24602634 PyVarObject_HEAD_INIT (NULL , 0 )
2461- "TreeBuilder" , sizeof (TreeBuilderObject ), 0 ,
2635+ "xml.etree.ElementTree. TreeBuilder" , sizeof (TreeBuilderObject ), 0 ,
24622636 /* methods */
24632637 (destructor )treebuilder_dealloc , /* tp_dealloc */
24642638 0 , /* tp_print */
@@ -3420,7 +3594,7 @@ xmlparser_getattro(XMLParserObject* self, PyObject* nameobj)
34203594
34213595static PyTypeObject XMLParser_Type = {
34223596 PyVarObject_HEAD_INIT (NULL , 0 )
3423- "XMLParser" , sizeof (XMLParserObject ), 0 ,
3597+ "xml.etree.ElementTree. XMLParser" , sizeof (XMLParserObject ), 0 ,
34243598 /* methods */
34253599 (destructor )xmlparser_dealloc , /* tp_dealloc */
34263600 0 , /* tp_print */
0 commit comments