Re: [xml] python hash code suggestions for libxslt types
- From: Nic James Ferrier <nferrier tapsellferrier co uk>
- To: veillard redhat com
- Cc: libxml <xml gnome org>
- Subject: Re: [xml] python hash code suggestions for libxslt types
- Date: Tue, 19 Sep 2006 11:05:34 +0100
Daniel Veillard <veillard redhat com> writes:
The address of the underlying C pointer to the object ?
Yes. That's what I decided on in the end. It's not perfect but since I
am doing compares that way...
I've attached my modified diff.
Will you accept this patch as it is? Or is there something you'd like
me to do to it before it gets into CVS?
I still haven't solved the problem of returning a PyObject from the
libxsltmod. But I'm not sure I'm going to without quite a change to
the generator code.
--
Nic Ferrier
http://www.tapsellferrier.co.uk for all your tapsell ferrier needs
diff -u --unidirectional-new-file -r -x '*~' ./configure ../../libxslt-1.1.17/configure
--- ./configure 2006-09-01 03:14:20.000000000 +0100
+++ ../../libxslt-1.1.17/configure 2006-09-09 21:38:06.000000000 +0100
@@ -22987,6 +22987,7 @@
fi
if test "$PYTHON" != ""
then
+ echo "PYTHON is pointing at $PYTHON"
PYTHON_VERSION=`$PYTHON -c "import sys; print sys.version[0:3]"`
echo Found Python version $PYTHON_VERSION
LIBXML2_PYTHON=`$PYTHON -c "try : import libxml2 ; print 1
Only in ./libexslt: exsltconfig.h
Only in ./libxslt: xsltconfig.h
Only in ./libxslt: xsltwin32config.h
Only in .: libxslt.spec
diff -u --unidirectional-new-file -r -x '*~' ./python/generator.py ../../libxslt-1.1.17/python/generator.py
--- ./python/generator.py 2004-01-22 17:40:16.000000000 +0000
+++ ../../libxslt-1.1.17/python/generator.py 2006-09-07 14:54:21.000000000 +0100
@@ -564,6 +564,8 @@
classes_ancestor = {
"xpathContext" : "libxml2.xpathContext",
"xpathParserContext" : "libxml2.xpathParserContext",
+ "transformCtxt": "transformCtxtBase",
+ "stylesheet": "stylesheetBase",
}
classes_destructors = {
"xpathContext" : "pass"
diff -u --unidirectional-new-file -r -x '*~' ./python/libxsl.py ../../libxslt-1.1.17/python/libxsl.py
--- ./python/libxsl.py 2004-07-11 12:12:33.000000000 +0100
+++ ../../libxslt-1.1.17/python/libxsl.py 2006-09-19 09:46:13.000000000 +0100
@@ -56,6 +56,37 @@
import libxsltmod
import libxml2
+
+class transformCtxtBase:
+ def __init__(self, _obj=None):
+ if _obj != None:
+ self._o = _obj;
+ return
+ self._o = None
+ def __hash__(self):
+ v = libxsltmod.xsltGetTransformContextHashCode(self._o)
+ return v
+ def __eq__(self, other):
+ if other == None:
+ return 0
+ v = libxsltmod.xsltCompareTransformContextsEqual(self._o, other._o)
+ return v
+
+class stylesheetBase:
+ def __init__(self, _obj=None):
+ if _obj != None:
+ self._o = _obj;
+ return
+ self._o = None
+ def __hash__(self):
+ v = libxsltmod.xsltGetStylesheetHashCode(self._o)
+ return v
+ def __eq__(self, other):
+ if other == None:
+ return 0
+ v = libxsltmod.xsltCompareStylesheetsEqual(self._o, other._o)
+ return v
+
class extensionModule:
def _styleInit(self, style, URI):
return self.styleInit(stylesheet(_obj=style), URI)
Only in ./python: libxslt-py.c
diff -u --unidirectional-new-file -r -x '*~' ./python/libxslt-python-api.xml
../../libxslt-1.1.17/python/libxslt-python-api.xml
--- ./python/libxslt-python-api.xml 2006-09-01 03:14:20.000000000 +0100
+++ ../../libxslt-1.1.17/python/libxslt-python-api.xml 2006-09-19 09:48:14.000000000 +0100
@@ -11,6 +11,56 @@
<arg name='style' type='xsltStylesheetPtr' info='a parsed XSLT stylesheet'/>
<arg name='result' type='xmlDocPtr' info='The result document'/>
</function>
+ <function name='xsltSetLoaderFunc' file='python'>
+ <info>Set the function for controlling document loading</info>
+ <return type='long' info='0 for failure or 1 for success'/>
+ <arg name='loader' type='pythonObject' info='the loader function; should take: string URI,
xsltParserContext, context, type; when type == 1 the context is a stylesheet, when type == 0 the context is a
transformCtxt'/>
+ </function>
+ <function name='xsltGetLoaderFunc' file='python'>
+ <info>Get the function for controlling document loading</info>
+ <return type='pythonObject *' info='the function'/>
+ </function>
+ <function name='xsltNewTransformContext' file='python'>
+ <info>Create a new XSLT TransformContext</info>
+ <return type='xsltTransformContextPtr' info='an xslt TransformContext'/>
+ <arg name='style' type='xsltStylesheetPtr' info='a parsed XSLT stylesheet'/>
+ <arg name='doc' type='xmlDocPtr' info='the input document'/>
+ </function>
+ <function name='xsltFreeTransformContext' file='python'>
+ <info>Free up an existing XSLT TransformContext</info>
+ <return type='void' info='None'/>
+ <arg name='transformCtxt' type='xsltTransformContextPtr' info='an existing tranformCtxt'/>
+ </function>
+ <function name='xsltGetTransformContextHashCode' file='python'>
+ <info>Get the hash code of the transformContext</info>
+ <return type='int' info='the hash code' />
+ <arg name='transformCtxt' type='xsltTransformContextPtr' info='a parsed XSLT transformContext'/>
+ </function>
+ <function name='xsltGetStylesheetHashCode' file='python'>
+ <info>Get the hash code of the stylesheet</info>
+ <return type='int' info='the hash code' />
+ <arg name='stylesheet' type='xsltStylesheetPtr' info='a parsed XSLT stylesheet'/>
+ </function>
+ <function name='xsltCompareTransformContextsEqual' file='python'>
+ <info>Compare one transformCtxt with another</info>
+ <return type='int' info='1 in case of success, 0 or -1 in error' />
+ <arg name='transformCtxt' type='xsltTransformContextPtr' info='a parsed XSLT transformContext'/>
+ <arg name='other' type='xsltTransformContextPtr' info='a parsed XSLT transformContext'/>
+ </function>
+ <function name='xsltCompareStylesheetsEqual' file='python'>
+ <info>Compare one stylesheet with another</info>
+ <return type='int' info='1 in case of success, 0 or -1 in error' />
+ <arg name='stylesheet' type='xsltStylesheetPtr' info='a parsed XSLT stylesheet'/>
+ <arg name='other' type='xsltStylesheetPtr' info='a parsed XSLT stylesheet'/>
+ </function>
+ <function name='xsltApplyStylesheetUser' file='python'>
+ <info>Apply the stylesheet to the document</info>
+ <return type='xmlDocPtr' info="the result document or NULL in case of error"/>
+ <arg name='style' type='xsltStylesheetPtr' info='a parsed XSLT stylesheet'/>
+ <arg name='doc' type='xmlDocPtr' info='a parsed XML document'/>
+ <arg name='params' type='pythonObject' info='the parameters dictionnary'/>
+ <arg name='transformCtxt' type='xsltTransformContextPtr' info='transformation context'/>
+ </function>
<function name='xsltApplyStylesheet' file='python'>
<info>Apply the stylesheet to the document</info>
<return type='xmlDocPtr' info="the result document or NULL in case of error"/>
diff -u --unidirectional-new-file -r -x '*~' ./python/libxslt.c ../../libxslt-1.1.17/python/libxslt.c
--- ./python/libxslt.c 2004-07-02 14:49:07.000000000 +0100
+++ ../../libxslt-1.1.17/python/libxslt.c 2006-09-19 09:57:03.000000000 +0100
@@ -20,6 +20,8 @@
#include "libxslt_wrap.h"
#include "libxslt-py.h"
+#include <stdio.h>
+
#if (defined(_MSC_VER) || defined(__MINGW32__)) && !defined(vsnprintf)
#define vsnprintf(b,c,f,a) _vsnprintf(b,c,f,a)
#elif defined(XSLT_NEED_TRIO)
@@ -55,6 +57,9 @@
}
ret = PyCObject_FromVoidPtrAndDesc((void *) style,
(char *)"xsltStylesheetPtr", NULL);
+
+ // Py_AddAttr(ret, cmp_function_impl);
+
return(ret);
}
@@ -90,6 +95,81 @@
return(ret);
}
+PyObject *
+libxslt_xsltGetTransformContextHashCode(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
+ PyObject *py_tctxt;
+ PyObject *ret;
+ long hash_code;
+ xsltTransformContextPtr tctxt;
+
+ if (!PyArg_ParseTuple(args, (char *)"O:getTransformContextHashCode",
+ &py_tctxt))
+ return NULL;
+
+ tctxt = (xsltTransformContextPtr) PytransformCtxt_Get(py_tctxt);
+ hash_code = (long) tctxt;
+
+ ret = PyInt_FromLong(hash_code);
+ return ret;
+}
+
+PyObject *
+libxslt_xsltCompareTransformContextsEqual(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
+
+ PyObject *py_tctxt1, *py_tctxt2;
+ xsltTransformContextPtr tctxt1, tctxt2;
+
+ if (!PyArg_ParseTuple(args, (char *)"OO:compareTransformContextsEqual",
+ &py_tctxt1, &py_tctxt2))
+ return NULL;
+
+ tctxt1 = (xsltTransformContextPtr) PytransformCtxt_Get(py_tctxt1);
+ tctxt2 = (xsltTransformContextPtr) PytransformCtxt_Get(py_tctxt2);
+
+ if ( tctxt1 == tctxt2 )
+ return Py_BuildValue((char *)"i", 1);
+ else
+ return Py_BuildValue((char *)"i", 0);
+}
+
+PyObject *
+libxslt_xsltGetStylesheetHashCode(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
+ PyObject *py_style;
+ PyObject *ret;
+ long hash_code;
+ xsltStylesheetPtr style;
+
+ if (!PyArg_ParseTuple(args, (char *)"O:getStylesheetHashCode",
+ &py_style))
+ return NULL;
+
+ style = (xsltStylesheetPtr) Pystylesheet_Get(py_style);
+ hash_code = (long) style;
+
+ ret = PyInt_FromLong(hash_code);
+ return ret;
+}
+
+
+PyObject *
+libxslt_xsltCompareStylesheetsEqual(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
+
+ PyObject *py_style1, *py_style2;
+ xsltStylesheetPtr style1, style2;
+
+ if (!PyArg_ParseTuple(args, (char *)"OO:compareStylesheetsEqual",
+ &py_style1, &py_style2))
+ return NULL;
+
+ style1 = (xsltStylesheetPtr) Pystylesheet_Get(py_style1);
+ style2 = (xsltStylesheetPtr) Pystylesheet_Get(py_style2);
+
+ if ( style1 == style2 )
+ return Py_BuildValue((char *)"i", 1);
+ else
+ return Py_BuildValue((char *)"i", 0);
+}
+
/************************************************************************
* *
* Extending the API *
@@ -423,6 +503,109 @@
return(py_retval);
}
+
+/************************************************************************
+ * *
+ * Document loading front-ends *
+ * *
+ ************************************************************************/
+
+static PyObject *pythonDocLoaderObject = NULL;
+
+static xmlDocPtr
+pythonDocLoaderFuncWrapper(const xmlChar * URI, xmlDictPtr dict, int options,
+ void *ctxt ATTRIBUTE_UNUSED,
+ xsltLoadType type ATTRIBUTE_UNUSED)
+{
+ xmlParserCtxtPtr pctxt;
+ xmlDocPtr doc;
+
+ pctxt = xmlNewParserCtxt();
+ if (pctxt == NULL)
+ return(NULL);
+ if ((dict != NULL) && (pctxt->dict != NULL)) {
+ xmlDictFree(pctxt->dict);
+ pctxt->dict = NULL;
+ }
+ if (dict != NULL) {
+ pctxt->dict = dict;
+ xmlDictReference(pctxt->dict);
+#ifdef WITH_XSLT_DEBUG
+ xsltGenericDebug(xsltGenericDebugContext,
+ "Reusing dictionary for document\n");
+#endif
+ }
+ xmlCtxtUseOptions(pctxt, options);
+
+ // Now pass to python the URI, the xsltParserContext and the context
+ // (either a transformContext or a stylesheet) and get back an xmlDocPtr
+ if (pythonDocLoaderObject != NULL) {
+ PyObject *ctxtobj, *pctxtobj, *result;
+ pctxtobj = libxml_xmlParserCtxtPtrWrap(pctxt);
+
+ if (type == XSLT_LOAD_DOCUMENT) {
+ ctxtobj = libxslt_xsltTransformContextPtrWrap(ctxt);
+ result = PyObject_CallFunction(pythonDocLoaderObject,
+ (char *) "(sOOi)", URI, pctxtobj, ctxtobj, 0);
+ }
+ else {
+ ctxtobj = libxslt_xsltStylesheetPtrWrap(ctxt);
+ result = PyObject_CallFunction(pythonDocLoaderObject,
+ (char *) "(sOOi)", URI, pctxtobj, ctxtobj, 1);
+ }
+
+ Py_XDECREF(pctxtobj);
+
+ if (result != NULL) {
+ // The return value should be the document
+ // Should we test it somehow before getting the C object from it?
+ PyObject *py_doc = PyObject_GetAttrString(result, "_o");
+ doc = PyxmlNode_Get(py_doc);
+ // do we have to DECCREF the result??
+ }
+ }
+
+ if (! pctxt->wellFormed) {
+ if (doc != NULL) {
+ xmlFreeDoc(doc);
+ }
+ if (pctxt->myDoc != NULL) {
+ doc = NULL;
+ xmlFreeDoc(pctxt->myDoc);
+ pctxt->myDoc = NULL;
+ }
+ }
+ // xmlFreeParserCtxt(pctxt); // libc complains about double free-ing with this line
+
+ return(doc);
+}
+
+
+PyObject *
+libxslt_xsltSetLoaderFunc(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
+ PyObject *py_retval;
+ PyObject *loader;
+
+ if (!PyArg_ParseTuple(args, (char *)"O:libxslt_xsltSetLoaderFunc",
+ &loader))
+ return(NULL);
+
+ pythonDocLoaderObject = loader;
+ xsltSetLoaderFunc(pythonDocLoaderFuncWrapper);
+
+ py_retval = PyInt_FromLong(0);
+ return(py_retval);
+}
+
+PyObject *
+libxslt_xsltGetLoaderFunc(void) {
+ PyObject *py_retval;
+
+ py_retval = pythonDocLoaderObject;
+ return(py_retval);
+}
+
+
/************************************************************************
* *
* Some customized front-ends *
@@ -430,6 +613,119 @@
************************************************************************/
PyObject *
+libxslt_xsltNewTransformContext(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
+ PyObject *py_retval;
+ PyObject *pyobj_style;
+ PyObject *pyobj_doc;
+ xsltStylesheetPtr style;
+ xmlDocPtr doc;
+ xsltTransformContextPtr c_retval;
+
+ if (!PyArg_ParseTuple(args, (char *) "OO:xsltNewTransformContext",
+ &pyobj_style, &pyobj_doc))
+ return(NULL);
+
+ style = (xsltStylesheetPtr) Pystylesheet_Get(pyobj_style);
+ doc = (xmlDocPtr) PyxmlNode_Get(pyobj_doc);
+
+ c_retval = xsltNewTransformContext(style, doc);
+ py_retval = libxslt_xsltTransformContextPtrWrap((xsltTransformContextPtr) c_retval);
+ return (py_retval);
+}
+
+PyObject *
+libxslt_xsltFreeTransformContext(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
+ PyObject *py_tctxt;
+ xsltTransformContextPtr tctxt;
+
+ if (!PyArg_ParseTuple(args, (char *) "O:xsltFreeTransformContext", &py_tctxt))
+ return(NULL);
+
+ tctxt = (xsltTransformContextPtr) PytransformCtxt_Get(py_tctxt);
+ xsltFreeTransformContext(tctxt);
+
+ // Return None
+ Py_INCREF(Py_None);
+ return(Py_None);
+}
+
+PyObject *
+libxslt_xsltApplyStylesheetUser(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
+ PyObject *py_retval;
+ xmlDocPtr c_retval;
+ xsltStylesheetPtr style;
+ PyObject *pyobj_style;
+ xmlDocPtr doc;
+ xsltTransformContextPtr transformCtxt;
+ PyObject *pyobj_doc;
+ PyObject *pyobj_params;
+ PyObject *pyobj_transformCtxt;
+ const char **params = NULL;
+ int len = 0, i = 0, j;
+ PyObject *name;
+ PyObject *value;
+
+ if (!PyArg_ParseTuple(args, (char *) "OOOO:xsltApplyStylesheetUser",
+ &pyobj_style, &pyobj_doc, &pyobj_params, &pyobj_transformCtxt))
+ return(NULL);
+
+ if (pyobj_params != Py_None) {
+ if (PyDict_Check(pyobj_params)) {
+ len = PyDict_Size(pyobj_params);
+ if (len > 0) {
+ params = (const char **) xmlMalloc((len + 1) * 2 *
+ sizeof(char *));
+ if (params == NULL) {
+ printf("libxslt_xsltApplyStylesheet: out of memory\n");
+ Py_INCREF(Py_None);
+ return(Py_None);
+ }
+ j = 0;
+ while (PyDict_Next(pyobj_params, &i, &name, &value)) {
+ const char *tmp;
+ int size;
+
+ tmp = PyString_AS_STRING(name);
+ size = PyString_GET_SIZE(name);
+ params[j * 2] = (char *) xmlCharStrndup(tmp, size);
+ if (PyString_Check(value)) {
+ tmp = PyString_AS_STRING(value);
+ size = PyString_GET_SIZE(value);
+ params[(j * 2) + 1] = (char *)
+ xmlCharStrndup(tmp, size);
+ } else {
+ params[(j * 2) + 1] = NULL;
+ }
+ j = j + 1;
+ }
+ params[j * 2] = NULL;
+ params[(j * 2) + 1] = NULL;
+ }
+ } else {
+ printf("libxslt_xsltApplyStylesheet: parameters not a dict\n");
+ Py_INCREF(Py_None);
+ return(Py_None);
+ }
+ }
+ style = (xsltStylesheetPtr) Pystylesheet_Get(pyobj_style);
+ doc = (xmlDocPtr) PyxmlNode_Get(pyobj_doc);
+ transformCtxt = (xsltTransformContextPtr) PytransformCtxt_Get(pyobj_transformCtxt);
+
+ c_retval = xsltApplyStylesheetUser(style, doc, params, NULL, NULL, transformCtxt);
+ py_retval = libxml_xmlDocPtrWrap((xmlDocPtr) c_retval);
+ if (params != NULL) {
+ if (len > 0) {
+ for (i = 0;i < 2 * len;i++) {
+ if (params[i] != NULL)
+ xmlFree((char *)params[i]);
+ }
+ xmlFree(params);
+ }
+ }
+ return(py_retval);
+}
+
+PyObject *
libxslt_xsltApplyStylesheet(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
PyObject *py_retval;
xmlDocPtr c_retval;
diff -u --unidirectional-new-file -r -x '*~' ./python/tests/2stage.py
../../libxslt-1.1.17/python/tests/2stage.py
--- ./python/tests/2stage.py 1970-01-01 01:00:00.000000000 +0100
+++ ../../libxslt-1.1.17/python/tests/2stage.py 2006-09-07 20:31:36.000000000 +0100
@@ -0,0 +1,22 @@
+#!/usr/bin/python
+
+import libxslt
+import libxml2
+import sys
+
+styledoc = libxml2.parseDoc("""
+<xsl:stylesheet version='1.0'
+ xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
+ <xsl:template match='/'>
+ <x><xsl:value-of select='*'/></x>
+ </xsl:template>
+</xsl:stylesheet>
+""")
+style = libxslt.newStylesheet()
+style.parseStylesheetProcess(styledoc)
+
+testdoc = libxml2.parseDoc("<a>hello!</a>")
+result = style.applyStylesheet(testdoc, {})
+result.dump(sys.stdout)
+
+# End
diff -u --unidirectional-new-file -r -x '*~' ./python/tests/loader.py
../../libxslt-1.1.17/python/tests/loader.py
--- ./python/tests/loader.py 1970-01-01 01:00:00.000000000 +0100
+++ ../../libxslt-1.1.17/python/tests/loader.py 2006-09-19 10:08:31.000000000 +0100
@@ -0,0 +1,116 @@
+import libxslt
+import libxml2
+import sys
+import pdb
+
+
+style_store = {}
+tctxt_store = {}
+
+savedTC1 = None
+savedTC2 = None
+savedStyle1 = None
+savedStyle2 = None
+
+def fn(url, pctx, ctx, type):
+ global savedTC1
+ global savedTC2
+ global savedStyle1
+ global savedStyle2
+
+ try:
+ if type == 0:
+ tc = libxslt.transformCtxt(_obj=ctx)
+
+ if savedTC1 == tc:
+ print "matched TC1!"
+
+ if savedTC2 == tc:
+ print "matched TC2!"
+
+ global tctxt_store
+ storedTC = tctxt_store[tc]
+ if storedTC == tc:
+ print "matched stored TC!"
+ if storedTC == savedTC2:
+ print "stored matched TC2!"
+
+
+ pctxt = libxml2.parserCtxt(_obj=pctx)
+ doc = pctxt.ctxtReadDoc("""<?xml version='1.0'?><b>Goodbye</b>""", url, "UTF-8", 2)
+ return doc
+
+ else:
+ style = libxslt.stylesheet(_obj=ctx)
+
+ if savedStyle1 == style:
+ print "matched savedStyle1!"
+
+ if savedStyle2 == style:
+ print "matched savedStyle2!"
+
+ global style_store
+ storedStyle = style_store[style]
+ if storedStyle == style:
+ print "matched stored style!"
+ if storedStyle == savedStyle2:
+ print "stored matched style2!"
+
+ pctxt = libxml2.parserCtxt(_obj=pctx)
+ doc = pctxt.ctxtReadDoc("""
+<xsl:stylesheet version='1.0'
+ xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
+</xsl:stylesheet>""", url, "UTF-8", 2)
+ return doc
+
+ except Exception, e:
+ print >>sys.stderr, "something went wrong: ", e
+ return None
+
+def run():
+ libxslt.setLoaderFunc(fn)
+ styledoc = libxml2.parseDoc("""
+<xsl:stylesheet version='1.0'
+ xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
+ <xsl:import href='import1.xslt'/>
+ <xsl:template match='/'>
+ <x><xsl:value-of select='document("b.xml")'/></x>
+ </xsl:template>
+</xsl:stylesheet>
+""")
+ style = libxslt.newStylesheet()
+ if style:
+ global style_store
+ global savedStyle1
+ global savedTC1
+ global savedTC2
+ savedStyle1 = style
+
+ style_store[style] = style
+
+ style.parseStylesheetProcess(styledoc)
+
+ src_doc1 = libxml2.parseDoc("<a/>")
+ transform_ctxt1 = style.newTransformContext(src_doc1)
+ savedTC1 = transform_ctxt1
+ tctxt_store[transform_ctxt1] = transform_ctxt1
+
+ src_doc2 = libxml2.parseDoc("<c/>")
+ transform_ctxt2 = style.newTransformContext(src_doc2)
+ savedTC2 = transform_ctxt2
+
+ result = style.applyStylesheetUser(src_doc1, {}, transform_ctxt1)
+ result.dump(sys.stdout)
+
+ style.freeStylesheet()
+ src_doc1.freeDoc()
+ src_doc2.freeDoc()
+
+ transform_ctxt1.freeTransformContext()
+ transform_ctxt2.freeTransformContext()
+
+ #print libxslt.getLoaderFunc()
+
+pdb.runcall(run)
+
+# End
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]