On 9/19/07, Landlord Bulfleet <[EMAIL PROTECTED]> wrote:
...
>
> sum is property of a model object in our database
> (models.DecimalField(max_digits=7, decimal_places=2)) & f_c.rate is a
> Decimal constructed using Decimal(string) construction (Decimal is imported
> with "from decimal import Decimal")
>
> We have some doubts that this may be a result of the django's python 2.3
> _decimal compatibility.

You're using PsycoPG with multiple interpreters.  :)

http://www.initd.org/tracker/psycopg/ticket/192
http://groups.google.com/group/django-developers/browse_thread/thread/63046b2fca27673c/898dbf8da327ce71

Anyway, I did run into this using psycopg1, but switched to psycopg2
and patched it since 1) it's being maintained and 2) it was easier to
fix that way.

I emailed the psycopg list a couple weeks ago with a patch but never
heard back from them.  I don't have rights to add the patch to their
ticket tracker, or I'd do that, too.

I'm attaching a patch against psycopg2's source code here.   This is
for r896 on the 2.0.x branch.

Alternatively, you could run separate apache processes for each needed
interpreter or switch to mod_wsgi.

I wasn't prepared to swtich to mod_wsgi in a hurry, so patched
psycopg2 instead.

Apparently not that many people are using multiple interpreters and
decimal fields with psycopg...

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To post to this group, send email to django-users@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/django-users?hl=en
-~----------~----~----~----~------~----~------~--~---

Index: psycopg/psycopg.h
===================================================================
--- psycopg/psycopg.h	(revision 896)
+++ psycopg/psycopg.h	(working copy)
@@ -129,8 +129,7 @@
     char *pyenc;
 } encodingPair;
 
-/* the Decimal type, used by the DECIMAL typecaster */
-extern PyObject *decimalType;
+extern PyObject *psyco_decimal_type(void);
 
 /* some utility functions */
 extern void psyco_set_error(PyObject *exc, PyObject *curs,  char *msg,
Index: psycopg/psycopgmodule.c
===================================================================
--- psycopg/psycopgmodule.c	(revision 896)
+++ psycopg/psycopgmodule.c	(working copy)
@@ -62,7 +62,6 @@
 PyObject *pyPsycopgTzFixedOffsetTimezone = NULL;
 
 PyObject *psycoEncodings = NULL;
-PyObject *decimalType = NULL;
 
 /** connect module-level function **/
 #define psyco_connect_doc \
@@ -330,7 +329,7 @@
 #endif
 
 #ifdef HAVE_DECIMAL
-    microprotocols_add((PyTypeObject*)decimalType, NULL, (PyObject*)&asisType);
+    microprotocols_add((PyTypeObject*)psyco_decimal_type(), NULL, (PyObject*)&asisType);
 #endif
 }
 
@@ -554,27 +553,7 @@
     }
 }
 
-/* psyco_decimal_init
 
-   Initialize the module's pointer to the decimal type. */
-
-void
-psyco_decimal_init(void)
-{
-#ifdef HAVE_DECIMAL
-    PyObject *decimal = PyImport_ImportModule("decimal");
-    if (decimal) {
-        decimalType = PyObject_GetAttrString(decimal, "Decimal");
-    }
-    else {
-        PyErr_Clear();
-        decimalType = (PyObject *)&PyFloat_Type;
-        Py_INCREF(decimalType);
-    }
-#endif
-}
-
-
 /** method table and module initialization **/
 
 static PyMethodDef psycopgMethods[] = {
@@ -730,7 +709,6 @@
     /* other mixed initializations of module-level variables */
     psycoEncodings = PyDict_New();
     psyco_encodings_fill(psycoEncodings);
-    psyco_decimal_init();
 
     /* set some module's parameters */
     PyModule_AddStringConstant(module, "__version__", PSYCOPG_VERSION);
Index: psycopg/typecast_basic.c
===================================================================
--- psycopg/typecast_basic.c	(revision 896)
+++ psycopg/typecast_basic.c	(working copy)
@@ -113,6 +113,40 @@
     return res;
 }
 
+/* psyco_decimal_type
+
+   Retrieve the decimal type from the current interpreter.
+   Can't cache due to each interpreter having separate sys.modules, 
+     which causes isinstance(Decimal(), Decimal) to fail between interpreters.
+
+   //FIXME: dropping refs every time it's called; dangerous if 
+   //  there are no other references in interp.
+   //We should have a pre-compiler
+   //  WITH_MULTI_INTERPRETER to store typecasters per interpreter.
+*/
+
+PyObject *psyco_decimal_type(void)
+{
+#ifdef HAVE_DECIMAL
+   
+   PyObject *decimal = PyImport_ImportModule("decimal");
+   PyObject *decimalClass;
+   
+   if (decimal) {
+       Py_DECREF(decimal);
+       decimalClass = PyObject_GetAttrString(decimal, "Decimal");
+       Py_DECREF(decimalClass);
+   }
+   else {
+       PyErr_Clear();
+       decimalClass = (PyObject *)&PyFloat_Type;
+   }
+   return decimalClass;
+#endif
+}
+
+
+
 /** DECIMAL - cast any kind of number into a Python Decimal object **/
 
 #ifdef HAVE_DECIMAL
@@ -127,7 +161,7 @@
     if ((buffer = PyMem_Malloc(len+1)) == NULL)
         PyErr_NoMemory();
     strncpy(buffer, s, (size_t) len); buffer[len] = '\0';
-    res = PyObject_CallFunction(decimalType, "s", buffer);
+    res = PyObject_CallFunction(psyco_decimal_type(), "s", buffer);
     PyMem_Free(buffer);
 
     return res;
Index: setup.py
===================================================================
--- setup.py	(revision 896)
+++ setup.py	(working copy)
@@ -55,7 +55,7 @@
 from distutils.ccompiler import get_default_compiler
 
 PSYCOPG_VERSION = '2.0.6'
-version_flags   = []
+version_flags   = ['895+pegasus']
 
 PLATFORM_IS_WINDOWS = sys.platform.lower().startswith('win')
 
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 896)
+++ ChangeLog	(working copy)
@@ -1,7 +1,3 @@
-2007-09-01  Federico Di Gregorio  <[EMAIL PROTECTED]>
-
-	* Added "name" parameter to all .cursor() calls in extras.py.
-
 2007-05-29  Federico Di Gregorio  <[EMAIL PROTECTED]>
 
 	* Release 2.0.6.
Index: lib/extras.py
===================================================================
--- lib/extras.py	(revision 896)
+++ lib/extras.py	(working copy)
@@ -69,11 +69,8 @@
 
 class DictConnection(_connection):
     """A connection that uses DictCursor automatically."""
-    def cursor(self, name=None):
-        if name is None:
-            return _connection.cursor(self, cursor_factory=DictCursor)
-        else:
-	    return _connection.cursor(self, name, cursor_factory=DictCursor)
+    def cursor(self):
+        return _connection.cursor(self, cursor_factory=DictCursor)
 
 class DictCursor(DictCursorBase):
     """A cursor that keeps a list of column name -> index mappings."""
@@ -138,11 +135,8 @@
 
 class RealDictConnection(_connection):
     """A connection that uses RealDictCursor automatically."""
-    def cursor(self, name=None):
-        if name is None:
-            return _connection.cursor(self, cursor_factory=RealDictCursor)
-        else:
-	    return _connection.cursor(self, name, cursor_factory=RealDictCursor)
+    def cursor(self):
+        return _connection.cursor(self, cursor_factory=RealDictCursor)
 
 class RealDictCursor(DictCursorBase):
     """A cursor that uses a real dict as the base type for rows.
@@ -221,13 +215,10 @@
             raise self.ProgrammingError(
                 "LoggingConnection object has not been initialize()d")
             
-    def cursor(self, name=None):
+    def cursor(self):
         self._check()
-	if name is None:
-            return _connection.cursor(self, cursor_factory=LoggingCursor)
-        else:
-	    return _connection.cursor(self, name, cursor_factory=LoggingCursor)
-
+        return _connection.cursor(self, cursor_factory=LoggingCursor)
+    
 class LoggingCursor(_cursor):
     """A cursor that logs queries using its connection logging facilities."""
 
@@ -263,12 +254,9 @@
         if t > self._mintime:
             return msg + os.linesep + "  (execution time: %d ms)" % t
 
-    def cursor(self, name=None):
+    def cursor(self):
         self._check()
-	if name is None:
-            return _connection.cursor(self, cursor_factory=MinTimeLoggingCursor)
-        else:
-	    return _connection.cursor(self, name, cursor_factory=MinTimeLoggingCursor)
+        return _connection.cursor(self, cursor_factory=MinTimeLoggingCursor)
     
 class MinTimeLoggingCursor(LoggingCursor):
     """The cursor sub-class companion to MinTimeLoggingConnection."""

Reply via email to