Method and getattr wierdness in a C extension

Ignacio Vazquez-Abrams ignacio at openservices.net
Sat Aug 18 20:30:12 EDT 2001


I'm building a Python 1.5 module for libxml2 (not so much for public
consumption so much as to teach myself both libxml2 and Python extensions) and
I'm coming across something odd.

Here's the relevant C code:

---
typedef struct libxml_doc {
  PyObject_HEAD
  PyObject *dict;
  xmlDocPtr doc;
} xmlDocObject;

static PyObject *xmlPyParseFile(PyObject *self, PyObject *args)
{
  char *filename=NULL;
  xmlDocObject *doc;
  xmlDocPtr tree;

  if (!PyArg_ParseTuple(args, "s", &filename)) return NULL;
  Py_BEGIN_ALLOW_THREADS
  tree=xmlParseFile(filename);
  Py_END_ALLOW_THREADS
  if (tree==NULL)
  {
    return NULL;
  };
  doc=xmlDoc_new(tree);
  return ((PyObject *)doc);
};

static struct PyMethodDef libxml_methods[]=
{
  {"ParseFile", xmlPyParseFile, METH_VARARGS},
  {NULL, NULL}
};

static xmlDocObject *xmlDoc_new(xmlDocPtr doc)
{
  xmlDocObject *result=PyObject_NEW(xmlDocObject, &xmlDoc_Type);
  PyObject *dict=NULL, *name=NULL;

  if (result==NULL)
    return NULL;
  dict=PyDict_New();
  if (dict==NULL)
  {
    Py_XDECREF(result);
    return NULL;
  };
  PyDict_SetItemString(dict, "...", (PyObject *)<someobj>);
    ...  // Not important

  result->doc=doc;
  result->dict=dict;
  return result;
};

static PyObject *xmlDoc_copy(PyObject *self, PyObject *args)
{
  xmlDocObject *old=(xmlDocObject *)self;
  xmlDocObject *doc=NULL;

  PyArg_ParseTuple(args, "");
  doc=PyObject_NEW(xmlDocObject, &xmlDoc_Type);
  doc->doc=xmlCopyDoc(old->doc, 1);
  doc->dict=PyDict_New();
  return (PyObject *)doc;
};

static PyMethodDef xmlDoc_methods[]=
{
  {"copy", xmlDoc_copy, METH_VARARGS},
  {NULL, NULL}
};

static int xmlDoc_print(PyObject *self, FILE *fp, int flags)
{
  xmlDocObject *doc=(xmlDocObject *)self;
  xmlChar *out=NULL;

  if (flags & Py_PRINT_RAW)
  {
    out=xmlDoc_Dump(doc->doc);
    fprintf(fp, out);
  }
  else
  {
    fprintf(fp, "<xmlDocument at %lx>", (long int)self);
  };
  return 0;
};

static PyObject *xmlDoc_getattr(PyObject *self, char *name)
{
  PyObject *result=NULL;

  result=Py_FindMethod(xmlDoc_methods, self, name);
  return result;
};

static void xmlDoc_dealloc(PyObject *self)
{
  xmlFreeDoc(((xmlDocObject *)self)->doc);
  Py_XDECREF(((xmlDocObject *)self)->dict);
  PyMem_DEL(self);
};

static PyTypeObject xmlDoc_Type=
{
  PyObject_HEAD_INIT(NULL)
  0,
  "xmlDocument",
  sizeof(xmlDocObject),
  0,
  xmlDoc_dealloc,     /* dealloc      */
  xmlDoc_print,       /* print        */
  xmlDoc_getattr,     /* getattr      */
  0,                  /* setattr      */
   ...
};

void initlibxml(void)
{
  PyObject *module, *dict, *str;

  xmlDoc_Type.ob_type=&PyType_Type;

  module=Py_InitModule("libxml", libxml_methods);
  dict=PyModule_GetDict(module);

  if (PyDict_SetItemString(dict, "xmlDocumentType", (PyObject *)
        &xmlDoc_Type))
    Py_FatalError("Cannot add to libxml dictionary");
};
---

Here's the python script I used to test it:

---
#! /usr/bin/python1.5 -i

import libxml

doc=libxml.ParseFile('<somefile>')
---

Here's what I'm getting at the prompt:

---
>>> doc.copy(123)
<xmlDocument at 80f4fc0>
>>> doc.copy(123)
TypeError: function requires exactly 0 arguments; 1 given
>>> doc.copy(123)
<xmlDocument at 80eac00>
>>> doc.copy(123)
TypeError: function requires exactly 0 arguments; 1 given
>>>
---

Why is it alternating between working and not working?

The actual code is larger and more complete than what's given above; if you
need to see more, just ask.

-- 
Ignacio Vazquez-Abrams  <ignacio at openservices.net>






More information about the Python-list mailing list