[PyObjC-svn] r1997 - in trunk/pyobjc/pyobjc-core: Lib/objc Modules/objc

[email protected]
Newsgroups gmane.comp.python.pyobjc.cvs
Message-ID <[email protected]>
Author: ronaldoussoren
Date: Thu May  1 04:13:02 2008
New Revision: 1997

Log:
* Finish OC_PythonNumber (but: still no unittests for this)
* Add some documentation to _pycoder


Modified:
   trunk/pyobjc/pyobjc-core/Lib/objc/_pycoder.py
   trunk/pyobjc/pyobjc-core/Modules/objc/OC_PythonNumber.m

Modified: trunk/pyobjc/pyobjc-core/Lib/objc/_pycoder.py
==============================================================================
--- trunk/pyobjc/pyobjc-core/Lib/objc/_pycoder.py	(original)
+++ trunk/pyobjc/pyobjc-core/Lib/objc/_pycoder.py	Thu May  1 04:13:02 2008
@@ -4,8 +4,11 @@
 NOTE: this only works with a keyed archiver, not with a plain archiver. It 
 should be easy enough to change this later on if needed.
 
-FIXME: encoding for lists and tuples is far from optimal
-FIXME: need versioning
+A minor problem with NSCoding support is that NSCoding restores
+graphs recusively while Pickle does so depth-first (more of less). 
+This can cause problems when the object state contains the
+object itself, which is why we need a 'setValue' callback for the
+load_* functions below.
 """
 import objc
 from types import *
@@ -283,6 +286,10 @@
                     cls.__name__, str(err)), sys.exc_info()[2]
 
             
+        # We now have the object, but haven't set the correct
+        # state yet.  Tell the bridge about this value right
+        # away, that's needed because `value` might be part
+        # of the object state which we'll retrieve next.
         setValue(value)
 
         state = coder.decodeObjectForKey_(kSTATE)
@@ -312,13 +319,14 @@
 
     def load_reduce(coder, setValue):
         func = coder.decodeObjectForKey_(kFUNC)
-
-        # XXX: a problem: ``args`` might contain
-        # the object we want to recover (either
-        # directly or somewhere in the object graph)
         args = coder.decodeObjectForKey_(kARGS)
 
         value = func(*args)
+
+        # We now have the object, but haven't set the correct
+        # state yet.  Tell the bridge about this value right
+        # away, that's needed because `value` might be part
+        # of the object state which we'll retrieve next.
         setValue(value)
 
         listitems = coder.decodeObjectForKey_(kLIST)

Modified: trunk/pyobjc/pyobjc-core/Modules/objc/OC_PythonNumber.m
==============================================================================
--- trunk/pyobjc/pyobjc-core/Modules/objc/OC_PythonNumber.m	(original)
+++ trunk/pyobjc/pyobjc-core/Modules/objc/OC_PythonNumber.m	Thu May  1 04:13:02 2008
@@ -104,9 +104,89 @@
 
 -(NSDecimal)decimalValue
 {
-	/* FIXME */
-	[NSException raise:NSInvalidArgumentException
-	              format:@"Cannot convert python number to NSDecimal"];
+	NSDecimal result;
+	NSDecimalNumber* num;
+
+	unsigned long long mantissa = 0;
+	unsigned short exponent = 0;
+	BOOL negative = NO;
+
+	PyObjC_BEGIN_WITH_GIL
+		if (PyInt_Check(value)) {
+			long lng = PyInt_AsLong(value);
+			if (lng < 0) {
+				mantissa = -lng;
+				exponent = 0;
+				negative = YES;
+			} else {
+				mantissa = lng;
+				exponent = 0;
+				negative = NO;
+			}
+
+		} else if (PyLong_Check(value)) {
+			mantissa = PyLong_AsUnsignedLongLong(value);
+			if (PyErr_Occurred()) {
+				long long lng;
+				PyErr_Clear();
+				lng = PyLong_AsLongLong(value);
+				if (PyErr_Occurred()) {
+					PyObjC_GIL_FORWARD_EXC();
+				}
+
+				if (lng < 0) {
+					mantissa = -lng;
+					exponent = 0;
+					negative = YES;
+				} else {
+					mantissa = lng;
+					exponent = 0;
+					negative = NO;
+				}
+			} else {
+				exponent = 0;
+				negative = NO;
+			}
+
+		} else if (PyFloat_Check(value)) {
+			PyObject* strVal = PyObject_Repr(value);
+			PyObject* uniVal = NULL;
+
+			if (strVal == NULL) {
+				PyObjC_GIL_FORWARD_EXC();
+			}
+
+			uniVal = PyUnicode_FromEncodedObject(strVal, "ascii", "strict");
+			Py_DECREF(strVal);
+			if (uniVal == NULL) {
+				PyObjC_GIL_FORWARD_EXC();
+			}
+
+			NSString* stringVal = PyObjC_PythonToId(uniVal);
+			Py_DECREF(uniVal);
+			
+			num = [[NSDecimalNumber alloc] initWithString:stringVal];
+			result = [num decimalValue];
+			[num release];
+			PyObjC_GIL_RETURN(result);
+
+		} else {
+			PyErr_Format(PyExc_TypeError, "cannot convert object of %s to NSDecimal",
+					value->ob_type->tp_name);
+			PyObjC_GIL_FORWARD_EXC();
+		}
+
+	PyObjC_END_WITH_GIL
+
+
+
+	num = [[NSDecimalNumber alloc] 
+		initWithMantissa:mantissa
+			exponent:exponent
+		      isNegative:negative];
+	result = [num decimalValue];
+	[num release];
+	return result;
 }
 
 -(double)doubleValue
@@ -296,7 +376,7 @@
 			} else {
 				[self release];
 				[proxy retain];
-				self = (OC_PythonObject*)proxy;
+				self = (OC_PythonNumber*)proxy;
 			}
 
 

-------------------------------------------------------------------------
This SF.net email is sponsored by the 2008 JavaOne(SM) Conference 
Don't miss this year's exciting event. There's still time to save $100. 
Use priority code J8TL2D2. 
http://ad.doubleclick.net/clk;198757673;13503038;p?http://java.sun.com/javaone
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.