Here's the patch.  This includes:

* the OS X build fixes I included in my previous patches, with a
  few tweaks (actually check for Python.h)

* changes to the Python bindings to properly support 'L' fields,
  handle overflow, and throw dummy exceptions

* the beginnings of a test suite for the Python bindings, using
  the test.regrtest module since it's the closest standard module
  Python has to MetaKit's Tcl tests; a corresponding test-python
  target in Makefile.in

* a few more build changes - scxx dependencies were wrong

A couple of further questions:

* The other problem I had with Mk4py was its inability to deal with
  Unicode strings.  Is there any precedent in the other language
  bindings for what to do here?  Do 'S' fields have any encoding
  information associated with them?

* Currently, the int type conversion matrix looks something like this:

  Python type         MetaKit type    Result 
  -----------         ------------    ------
  int                 I               ok
  long int <= 32 bits I               ok
  long int > 32 bits  I               TypeError
  float               I               ok, truncated
  float/int > 32 bits I               TypeError
  long int <= 64 bits L               ok
  long int > 64 bits  L               ValueError
  float               L               ok, truncated
  float/int > 64 bits L               ValueError
  string              I, L            TypeError
  
  A few of these conversions are debatable - should Mk4py truncate a
  float?  Should it try to convert a string to an int/long int if
  possible?

I've got finals coming up so I won't be able to do anything further
until next Tuesday.

-- 
=Nicholas Riley <[EMAIL PROTECTED]> | <http://www.uiuc.edu/ph/www/njriley>
        Pablo Research Group, Department of Computer Science and
  Medical Scholars Program, University of Illinois at Urbana-Champaign
diff -uNr -X metakit-files-to-ignore-when-diffing metakit-2.4.8/python/PyRowRef.cpp 
metakit-2.4.8+njr2/python/PyRowRef.cpp
--- metakit-2.4.8/python/PyRowRef.cpp   Wed Dec 19 10:26:00 2001
+++ metakit-2.4.8+njr2/python/PyRowRef.cpp      Fri Dec 13 09:56:04 2002
@@ -58,7 +58,7 @@
     PyErr_Clear();
     return Py_FindMethod(RowRefMethods, (PyObject* )o, nm);
   }
-  catch (...) { return 0; }
+  catch (...) { return NULL; }
 }
 
 static int PyRowRef_setattr(PyRowRef *o, char *nm, PyObject* v) {
@@ -72,7 +72,7 @@
       Py_DECREF(p);
       return 0;
     }
-    PyErr_SetString(PyExc_AttributeError, "delete of non-existing attribute");
+    PyErr_SetString(PyExc_AttributeError, "delete of nonexistent attribute");
     return -1;
   }
   catch (...) { return -1; }
@@ -122,8 +122,8 @@
   // with thanks to Niki Spahiev for improving conversions and error checks
 void PyRowRef::setFromPython(const c4_RowRef& row, const c4_Property& prop, PyObject* 
attr) {
   switch (prop.Type()) {
-    case 'I': 
-      if (PyInt_Check(attr))
+    case 'I':
+      if (PyInt_CheckExact(attr))
         ((const c4_IntProp&) prop) (row) = PyInt_AS_LONG(attr);
       else if (attr != Py_None)
       {
@@ -132,16 +132,20 @@
       }
       break;
 #ifdef HAVE_LONG_LONG
-    case 'L':   
-      if (PyInt_Check(attr))
+    case 'L':
+      if (PyInt_CheckExact(attr))
        ((const c4_LongProp&) prop) (row) = PyInt_AS_LONG(attr);
-      else if (PyLong_Check(attr))
-       ((const c4_LongProp&) prop) (row) = PyLong_AsLong(attr);
+      else if (PyLong_Check(attr)) {
+       long long number = PyLong_AsLongLong(attr);
+       if (number == -1 && PyErr_Occurred() != NULL)
+         Fail(PyExc_ValueError, "long int too large to convert to C long long");
+       ((const c4_LongProp&) prop) (row) = number;
+      }
       else if (attr != Py_None)
-       {
-         PWONumber number (attr);
-         ((const c4_LongProp&) prop) (row) = (long) number;
-       }
+      {
+       PWONumber number (attr);
+       ((const c4_LongProp&) prop) (row) = (long long) number;
+      }
       break;
 #endif
     case 'F': 
@@ -163,7 +167,7 @@
       }
       break;
     case 'S': 
-      if (PyString_Check(attr)) {
+      if (PyString_CheckExact(attr)) {
         c4_Bytes temp (PyString_AS_STRING(attr),
         PyString_GET_SIZE(attr) + 1, false);
         prop (row).SetData(temp);
@@ -191,13 +195,16 @@
       break;
     case 'B':
     case 'M': 
-      if (PyString_Check(attr)) {
+      if (PyString_CheckExact(attr)) {
         c4_Bytes temp (PyString_AS_STRING(attr),
         PyString_GET_SIZE(attr), false);
         prop (row).SetData(temp);
       }
       else if (attr != Py_None)
        Fail(PyExc_TypeError, "wrong type for ByteProp");
+    default:
+      PyErr_Format(PyExc_TypeError, "unknown property type '%c'", prop.Type());
+      throw PWDPyException;
   }
 }
 
@@ -214,9 +221,9 @@
     case 'F': 
       ((const c4_FloatProp&) prop) (row) = 0.0;
       break;
-     case 'D':
-       ((const c4_DoubleProp&) prop) (row) = 0.0;
-       break;
+    case 'D':
+      ((const c4_DoubleProp&) prop) (row) = 0.0;
+      break;
     case 'S':
       ((const c4_StringProp&) prop) (row) = "";
       break;
@@ -229,6 +236,10 @@
         c4_Bytes temp;
         prop (row).SetData(temp);
       }
+      break;
+    default:
+      PyErr_Format(PyExc_TypeError, "unknown property type '%c'", prop.Type());
+      throw PWDPyException;
   }
 }
 
@@ -240,7 +251,7 @@
     }
 #ifdef HAVE_LONG_LONG
     case 'L': {
-      return PyLong_FromLong((long) ((const c4_LongProp&)prop)(*this));
+      return PyLong_FromLongLong((long long) ((const c4_LongProp&)prop)(*this));
     }
 #endif
     case 'F': {
@@ -265,6 +276,7 @@
       PWOString rslt((const char*)temp.Contents(), temp.Size());
       return rslt.disOwn();
     }
+    default:
+      return PyErr_Format(PyExc_TypeError, "unknown property type '%c'", prop.Type());
   }
-  return 0;
 }
diff -uNr -X metakit-files-to-ignore-when-diffing metakit-2.4.8/python/scxx/PWOBase.h 
metakit-2.4.8+njr2/python/scxx/PWOBase.h
--- metakit-2.4.8/python/scxx/PWOBase.h Mon Dec  3 16:50:59 2001
+++ metakit-2.4.8+njr2/python/scxx/PWOBase.h    Fri Dec 13 09:11:20 2002
@@ -10,7 +10,17 @@
 #include <Python.h>
 #include <limits.h>
 
+// Dummy, minimal exception thrown when a Python exception is generated
+// (after PyErr_Format, PyErr_SetString, etc.)
+class PWDException
+{
+ public:
+  PWDException() {}
+} extern const& PWDPyException;
+
+// functions throw PWDPyException
 void Fail(PyObject*, const char* msg);
+void FailIfPyErr();
 
 class PWOBase  
 {
diff -uNr -X metakit-files-to-ignore-when-diffing metakit-2.4.8/python/scxx/PWOImp.cpp 
metakit-2.4.8+njr2/python/scxx/PWOImp.cpp
--- metakit-2.4.8/python/scxx/PWOImp.cpp        Mon Dec  3 16:50:59 2001
+++ metakit-2.4.8+njr2/python/scxx/PWOImp.cpp   Fri Dec 13 09:12:05 2002
@@ -7,6 +7,10 @@
 #include "PWOMapping.h"
 #include "PWOCallable.h"
 
+// dummy exception singleton
+const PWDException PWDPyExceptionObj;
+const PWDException& PWDPyException = PWDPyExceptionObj;
+
   // incref new owner, and decref old owner, and adjust to new owner
 void PWOBase::GrabRef(PyObject* newObj)
 {
@@ -37,24 +41,30 @@
   static PWOTuple _empty;
   PyObject *rslt = PyEval_CallObjectWithKeywords(*this, _empty, NULL);
   if (rslt == 0)
-    throw 1;
+    throw PWDPyException;
   return rslt;
 }
 PWOBase PWOCallable::call(PWOTuple& args) const {
   PyObject *rslt = PyEval_CallObjectWithKeywords(*this, args, NULL);
   if (rslt == 0)
-    throw 1;
+    throw PWDPyException;
   return rslt;
 }
 PWOBase PWOCallable::call(PWOTuple& args, PWOMapping& kws) const {
   PyObject *rslt = PyEval_CallObjectWithKeywords(*this, args, kws);
   if (rslt == 0)
-    throw 1;
+    throw PWDPyException;
   return rslt;
 }
 
 void Fail(PyObject* exc, const char* msg)
 {
   PyErr_SetString(exc, msg);
-  throw 1;
+  throw PWDPyException;
+}
+
+void FailIfPyErr()
+{
+  PyObject *exc = PyErr_Occurred();
+  if (exc != NULL) throw PWDPyException;
 }
diff -uNr -X metakit-files-to-ignore-when-diffing 
metakit-2.4.8/python/scxx/PWOMapping.h metakit-2.4.8+njr2/python/scxx/PWOMapping.h
--- metakit-2.4.8/python/scxx/PWOMapping.h      Fri Feb  1 09:32:51 2002
+++ metakit-2.4.8+njr2/python/scxx/PWOMapping.h Tue Dec 10 17:10:37 2002
@@ -56,7 +56,7 @@
   //PyDict_GetItemString
   PWOMappingMmbr operator [] (const char* key) {
     PyObject* rslt = PyMapping_GetItemString(_obj, (char*) key);
-    if (rslt==0)
+    if (rslt == NULL)
       PyErr_Clear();
     PWOString _key(key);
     return PWOMappingMmbr(rslt, *this, _key);
@@ -64,7 +64,7 @@
   //PyDict_GetItem
   PWOMappingMmbr operator [] (PyObject* key) {
     PyObject* rslt = PyDict_GetItem(_obj, key);
-    //if (rslt==0)
+    //if (rslt == NULL)
     //  Fail(PyExc_KeyError, "Key not found");
     return PWOMappingMmbr(rslt, *this, key);
   };
diff -uNr -X metakit-files-to-ignore-when-diffing 
metakit-2.4.8/python/scxx/PWONumber.h metakit-2.4.8+njr2/python/scxx/PWONumber.h
--- metakit-2.4.8/python/scxx/PWONumber.h       Mon Dec  3 16:50:59 2001
+++ metakit-2.4.8+njr2/python/scxx/PWONumber.h  Fri Dec 13 09:56:23 2002
@@ -15,6 +15,9 @@
   PWONumber(int i) : PWOBase (PyInt_FromLong(i)) { LoseRef(_obj); }
   PWONumber(long i) : PWOBase (PyInt_FromLong(i)) { LoseRef(_obj); }
   PWONumber(unsigned long i) : PWOBase (PyLong_FromUnsignedLong(i)) { LoseRef(_obj); }
+#ifdef HAVE_LONG_LONG
+  PWONumber(long long i) : PWOBase (PyLong_FromLongLong(i)) { LoseRef(_obj); }
+#endif
   PWONumber(double d) : PWOBase (PyFloat_FromDouble(d)) { LoseRef(_obj); }
 
   PWONumber(const PWONumber& other) : PWOBase(other) {};
@@ -35,27 +38,27 @@
   virtual void _violentTypeCheck() {
     if (!PyNumber_Check(_obj)) {
       GrabRef(0);
-      Fail(PyExc_TypeError, "Not a number");
+      Fail(PyExc_TypeError, "not a number");
     }
   };
   //PyNumber_Absolute
   PWONumber abs() const {
     PyObject* rslt = PyNumber_Absolute(_obj);
-    if (rslt==0)
+    if (rslt == NULL)
       Fail(PyExc_TypeError, "Failed to get absolute value");
     return LoseRef(rslt);
   };
   //PyNumber_Add
   PWONumber operator+(const PWONumber& rhs) const {
     PyObject*  rslt = PyNumber_Add(_obj, rhs);
-    if (rslt==0)
+    if (rslt == NULL)
       Fail(PyExc_TypeError, "Improper rhs for +");
     return LoseRef(rslt);
   };
   //PyNumber_And
   PWONumber operator&(const PWONumber& rhs) const {
     PyObject*  rslt = PyNumber_And(_obj, rhs);
-    if (rslt==0)
+    if (rslt == NULL)
       Fail(PyExc_TypeError, "Improper rhs for &");
     return LoseRef(rslt);
   };
@@ -63,115 +66,126 @@
   //PyNumber_Divide
   PWONumber operator/(const PWONumber& rhs) const {
     PyObject*  rslt = PyNumber_Divide(_obj, rhs);
-    if (rslt==0)
+    if (rslt == NULL)
       Fail(PyExc_TypeError, "Improper rhs for /");
     return LoseRef(rslt);
   };
   //PyNumber_Divmod
   PWOSequence divmod(const PWONumber& rhs) const {
     PyObject*  rslt = PyNumber_Divmod(_obj, rhs);
-    if (rslt==0)
+    if (rslt == NULL)
       Fail(PyExc_TypeError, "Improper rhs for divmod");
     return LoseRef(rslt);
   };
   //PyNumber_Float
-    operator double () const {
-  PyObject*  F = PyNumber_Float(_obj);
-  if (F==0)
+  operator double () const {
+    PyObject*  F = PyNumber_Float(_obj);
+    if (F == NULL)
       Fail(PyExc_TypeError, "Cannot convert to double");
-  double r = PyFloat_AS_DOUBLE(F);
-  Py_DECREF(F);
-  return r;
-    };
+    double r = PyFloat_AS_DOUBLE(F);
+    Py_DECREF(F);
+    return r;
+  };
+  /* // no easy, safe way to do this 
   operator float () const {
     double rslt = (double) *this;
-    //if (rslt > INT_MAX)
-    //  Fail(PyExc_TypeError, "Cannot convert to a float");
     return (float) rslt;
-  };
+  }; */
   //PyNumber_Int
-    operator long () const {
-  PyObject*  Int = PyNumber_Int(_obj);
-  if (Int==0)
-      Fail(PyExc_TypeError, "Cannot convert to long");
-  long r = PyInt_AS_LONG(Int);
-  Py_DECREF(Int);
-  return r;
-    };
+  operator long () const {
+    PyObject* Int = PyNumber_Int(_obj);
+    if (Int == NULL)
+      Fail(PyExc_TypeError, "can't convert to int");
+    long r = PyInt_AsLong(_obj);
+    if (r == -1) FailIfPyErr();
+    return r;
+  };
   operator int () const {
     long rslt = (long) *this;
     if (rslt > INT_MAX)
-      Fail(PyExc_TypeError, "Cannot convert to an int");
+      Fail(PyExc_ValueError, "int too large to convert to C int");
     return (int) rslt;
   };
   //PyNumber_Invert
   PWONumber operator~ () const {
     PyObject* rslt = PyNumber_Invert(_obj);
-    if (rslt==0)
+    if (rslt == NULL)
       Fail(PyExc_TypeError, "Improper type for ~");
     return LoseRef(rslt);
   };
   //PyNumber_Long
+#ifdef HAVE_LONG_LONG
+  operator long long () const {
+    PyObject* Long = PyNumber_Long(_obj);
+    if (Long == NULL)
+      Fail(PyExc_TypeError, "can't convert to long int");
+    long r = PyLong_AsLongLong(Long);
+    if (r == -1 && PyErr_Occurred() != NULL)
+      Fail(PyExc_ValueError, "long int too large to convert to C long long");
+    Py_DECREF(Long);
+    return r;
+  };
+#endif
   //PyNumber_Lshift
   PWONumber operator<<(const PWONumber& rhs) const {
     PyObject*  rslt = PyNumber_Lshift(_obj, rhs);
-    if (rslt==0)
+    if (rslt == NULL)
       Fail(PyExc_TypeError, "Improper rhs for <<");
     return LoseRef(rslt);
   };
   //PyNumber_Multiply
   PWONumber operator*(const PWONumber& rhs) const {
     PyObject*  rslt = PyNumber_Multiply(_obj, rhs);
-    if (rslt==0)
+    if (rslt == NULL)
       Fail(PyExc_TypeError, "Improper rhs for *");
     return LoseRef(rslt);
   };
   //PyNumber_Negative
   PWONumber operator- () const {
     PyObject* rslt = PyNumber_Negative(_obj);
-    if (rslt==0)
+    if (rslt == NULL)
       Fail(PyExc_TypeError, "Improper type for unary -");
     return LoseRef(rslt);
   };
   //PyNumber_Or
   PWONumber operator|(const PWONumber& rhs) const {
-    PyObject*  rslt = PyNumber_Or(_obj, rhs);
-    if (rslt==0)
+    PyObject* rslt = PyNumber_Or(_obj, rhs);
+    if (rslt == NULL)
       Fail(PyExc_TypeError, "Improper rhs for |");
     return LoseRef(rslt);
   };
   //PyNumber_Positive
   PWONumber operator+ () const {
     PyObject* rslt = PyNumber_Positive(_obj);
-    if (rslt==0)
+    if (rslt == NULL)
       Fail(PyExc_TypeError, "Improper type for unary +");
     return LoseRef(rslt);
   };
   //PyNumber_Remainder
   PWONumber operator%(const PWONumber& rhs) const {
     PyObject*  rslt = PyNumber_Remainder(_obj, rhs);
-    if (rslt==0)
+    if (rslt == NULL)
       Fail(PyExc_TypeError, "Improper rhs for %");
     return LoseRef(rslt);
   };
   //PyNumber_Rshift
   PWONumber operator>>(const PWONumber& rhs) const {
     PyObject*  rslt = PyNumber_Rshift(_obj, rhs);
-    if (rslt==0)
+    if (rslt == NULL)
       Fail(PyExc_TypeError, "Improper rhs for >>");
     return LoseRef(rslt);
   };
   //PyNumber_Subtract
   PWONumber operator-(const PWONumber& rhs) const {
     PyObject*  rslt = PyNumber_Subtract(_obj, rhs);
-    if (rslt==0)
+    if (rslt == NULL)
       Fail(PyExc_TypeError, "Improper rhs for -");
     return LoseRef(rslt);
   };
   //PyNumber_Xor
   PWONumber operator^(const PWONumber& rhs) const {
     PyObject*  rslt = PyNumber_Xor(_obj, rhs);
-    if (rslt==0)
+    if (rslt == NULL)
       Fail(PyExc_TypeError, "Improper rhs for ^");
     return LoseRef(rslt);
   };
diff -uNr -X metakit-files-to-ignore-when-diffing 
metakit-2.4.8/python/scxx/PWOSequence.h metakit-2.4.8+njr2/python/scxx/PWOSequence.h
--- metakit-2.4.8/python/scxx/PWOSequence.h     Mon Dec  3 16:50:59 2001
+++ metakit-2.4.8+njr2/python/scxx/PWOSequence.h        Tue Dec 10 17:10:17 2002
@@ -35,7 +35,7 @@
   //PySequence_Concat
   PWOSequence operator+(const PWOSequence& rhs) const {
     PyObject*  rslt = PySequence_Concat(_obj, rhs);
-    if (rslt==0)
+    if (rslt == NULL)
       Fail(PyExc_TypeError, "Improper rhs for +");
     return LoseRef(rslt);
   };
@@ -82,7 +82,7 @@
   //PySequence_Repeat
   PWOSequence operator * (int count) const {
     PyObject* rslt = PySequence_Repeat(_obj, count);
-    if (rslt==0)
+    if (rslt == NULL)
       Fail(PyExc_RuntimeError, "sequence repeat failed");
     return LoseRef(rslt);
   };
@@ -159,7 +159,7 @@
   };
   static PWOString format(const PWOString& fmt, PWOTuple& args){
     PyObject * rslt =PyString_Format(fmt, args);
-    if (rslt==0)
+    if (rslt == NULL)
       Fail(PyExc_RuntimeError, "string format failed");
     return LoseRef(rslt);
   };
diff -uNr -X metakit-files-to-ignore-when-diffing metakit-2.4.8/python/test/all.py 
metakit-2.4.8+njr2/python/test/all.py
--- metakit-2.4.8/python/test/all.py    Wed Dec 31 18:00:00 1969
+++ metakit-2.4.8+njr2/python/test/all.py       Thu Dec 12 17:51:54 2002
@@ -0,0 +1,29 @@
+# all.py -- Run all tests for the MetaKit Python bindings
+# $Id$
+# This is part of MetaKit, see http://www.equi4.com/metakit/
+
+import sys
+import os
+import test.regrtest
+
+def canonicalPath(path):
+    """Do everything but resolve symbolic links to create an absolute path."""
+    return os.path.abspath(os.path.expanduser(os.path.expandvars(path)))
+
+# from Python 2.2's regrtest module
+def findtestdir():
+    if __name__ == '__main__':
+        file = sys.argv[0]
+    else:
+        file = __file__
+    testdir = os.path.dirname(file) or os.curdir
+    return testdir
+
+testdir = canonicalPath(findtestdir())
+
+# Don't run the standard Python tests, just run MetaKit tests
+test.regrtest.STDTESTS = []
+test.regrtest.NOTTESTS = []
+
+# Take a look at the 
+test.regrtest.main(testdir=testdir)
diff -uNr -X metakit-files-to-ignore-when-diffing 
metakit-2.4.8/python/test/test_inttypes.py 
metakit-2.4.8+njr2/python/test/test_inttypes.py
--- metakit-2.4.8/python/test/test_inttypes.py  Wed Dec 31 18:00:00 1969
+++ metakit-2.4.8+njr2/python/test/test_inttypes.py     Fri Dec 13 09:57:14 2002
@@ -0,0 +1,178 @@
+# test_inttypes.py -- Test MetaKit Python bindings for integral types
+# $Id$
+# This is part of MetaKit, see http://www.equi4.com/metakit/
+
+from test.test_support import TestFailed, verbose
+import os
+import sys
+
+# Keep track of failures as they happen, but don't die on the first
+# one unless it's unrecoverable.  If failure_count > 0 when script
+# finishes, raise TestFailed.
+failure_count = 0
+
+def fail(op, args, err=None, expected=None, actual=None):
+    global failure_count
+    print 'FAIL:', op, args
+    print '     ',
+    if err is not None: print err,
+    if actual is not None: print 'got', actual, actual.__class__,
+    if expected is not None: print 'expected', expected,
+    print
+    failure_count = failure_count + 1
+
+# for overflow testing
+MAXINT = sys.maxint
+MININT = -MAXINT - 1
+MAXLONGLONG = 2**63 - 1
+MINLONGLONG = -2**63
+MAXULONGLONG = 2**64
+
+# Make sure we're using modules from the builds directory, assuming
+# that's the current directory at the time we're run.
+sys.path.insert(0, os.getcwd())
+
+import metakit
+
+# Check that data types are as we expect (will break with Python 2.4
+# int/long integration?)
+try:
+    MAXLONGLONG = int(MAXLONGLONG)
+    raise TestFailed('not expecting 2^63 - 1 to be a valid Python integer')
+except OverflowError:
+    pass
+
+storage = metakit.storage()
+v = storage.getas('test[intf:I,longf:L]')
+
+# insert rows into view and Python array
+arr = []
+
+def checklen(**args):
+    alen = len(arr)
+    vlen = len(v)
+    if alen != vlen:
+        fail('append', args, 'view length mismatch', actual=vlen, expected=alen)
+        try:
+            print 'ARRAY CONTENTS:'
+            for arow in arr: print arow
+            metakit.dump(v, 'VIEW CONTENTS:')
+        except: pass
+        raise TestFailed('unexpected number of rows in view, aborting; run in verbose 
+mode for details')
+
+def insert(**args):
+    try:
+        v.append(args)
+        arr.append(args)
+    except Exception, e:
+        fail('append', args, actual=e)
+    try:
+        checklen(**args)
+    except TestFailed:
+        raise
+    except Exception, e:
+        fail('append', args, 'spurious', actual=e)
+   
+def reject(exception_class=Exception, **args):
+    try:
+        ix = v.append(args)
+        fail('append', args, 'succeeded', expected=exception_class)
+        v.delete(ix)
+    except Exception, e:
+        if isinstance(e, exception_class):
+            if verbose:
+                print 'PASS: rejected', args
+                print '      as expected <%s> %s' % (e.__class__, e)
+        else:
+            fail('append', args, expected=exception_class, actual=e)
+    try:
+        checklen(**args)
+    except TestFailed:
+        raise
+    except Exception, e:
+        fail('append', args, 'spurious', actual=e)
+
+# defaults
+insert(intf=0, longf=0)
+
+# int field
+insert(intf=1, longf=0)
+insert(intf=-5, longf=0)
+insert(intf=MAXINT, longf=0)
+insert(intf=MININT, longf=0)
+reject(TypeError, intf=MAXINT + 1, longf=0)
+reject(TypeError, intf=MININT - 1, longf=0)
+
+# long field
+insert(intf=0, longf=-1L)
+insert(intf=0, longf=5L)
+insert(intf=0, longf=MAXLONGLONG)
+insert(intf=0, longf=MINLONGLONG)
+reject(ValueError, intf=0, longf=MAXULONGLONG)
+reject(ValueError, intf=0, longf=MAXLONGLONG + 1)
+reject(ValueError, intf=0, longf=MAXULONGLONG)
+reject(ValueError, intf=0, longf=MINLONGLONG - 1)
+
+# mixed valid int/long
+insert(intf=1, longf=2)
+insert(intf=-5, longf=-2**30)
+
+# implicit conversion to int
+insert(intf=14L, longf=0)
+insert(intf=-30L, longf=0)
+insert(intf=45.0, longf=0)
+insert(intf=21.4, longf=0)
+reject(TypeError, intf=float(MAXINT + 1), longf=0)
+reject(TypeError, intf=float(MININT - 1), longf=0)
+reject(TypeError, intf='215', longf=0)
+reject(TypeError, intf='-318.19', longf=0)
+reject(TypeError, intf=str(MAXINT + 1), longf=0)
+
+# implicit conversion to long
+insert(intf=0, longf=278)
+insert(intf=0, longf=-213)
+insert(intf=0, longf=95.0)
+insert(intf=0, longf=27.3)
+reject(ValueError, intf=0, longf=float(2 * MAXLONGLONG))
+reject(ValueError, intf=0, longf=float(2 * MINLONGLONG))
+reject(TypeError, intf=0, longf=str(MAXLONGLONG))
+reject(TypeError, intf=0, longf=str(MINLONGLONG))
+reject(TypeError, intf=0, longf='-21.39')
+reject(TypeError, intf=0, longf=str(MAXULONGLONG))
+
+# XXX should repeat with assignment instead of appending
+# XXX test v.select()
+
+if verbose:
+    metakit.dump(v, 'VIEW CONTENTS:')
+
+# compare view with array
+for arow, vrow in zip(arr, v):
+    failed = False
+    for f in arow.keys():
+        try:
+           vf = getattr(vrow, f)
+            af = arow[f]
+            if af == vf:
+                continue
+            # Perform the same implicit coercion as Mk4py should
+            if type(af) != type(vf):
+                try:
+                    af = type(vf)(af)
+                    if af == vf:
+                        continue
+                except:
+                    pass
+            # If we get here, we got an exception or the values didn't match
+            # even with coercion
+            failed = True
+            fail('%s access' % f, arow, expected=af, actual=vf)
+       except Exception, e:
+            failed = True
+            fail('%s access' % f, arow, expected=arow[f], actual=e)
+    if not failed:
+        if verbose:
+            print 'PASS: retrieved', arow
+
+if failure_count > 0:
+    raise TestFailed('%d failures; run in verbose mode for details' % failure_count)
diff -uNr -X metakit-files-to-ignore-when-diffing metakit-2.4.8/unix/Makefile.in 
metakit-2.4.8+njr2/unix/Makefile.in
--- metakit-2.4.8/unix/Makefile.in      Sat Nov  2 16:29:13 2002
+++ metakit-2.4.8+njr2/unix/Makefile.in Fri Dec 13 10:30:01 2002
@@ -34,12 +34,16 @@
 srcdir = @srcdir@
 top_builddir = .
 
-pyincludedir = @includedir@/python2.2
-pylibdir = @libdir@/python2.2/site-packages
+python = python
+pyincludedir = @PY_INCLUDE_DIR@
+pylibdir = @PY_LIB_DIR@
 
 tclsh = tclsh
 tclincludedir = @TCL_INCLUDE_DIR@
-tcllibdir = @TCL_INCLUDE_DIR@/../lib
+tcllibdir = @TCL_LIB_DIR@
+
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
 
 # Compiling without frame pointers can play tricks with exception handling
 # (e.g. in Mk4py).  This does not affect standard operation, *only* errors.
@@ -55,7 +59,8 @@
 INSTALL_DATA = $L --mode=install @INSTALL_DATA@
 INSTALL_PROGRAM = $L --mode=install @INSTALL_PROGRAM@
 
-LIBTOOL_FLAGS = @LIBTOOL_FLAGS@
+LIBTOOL_SHLIB_FLAGS = $(LDFLAGS) @LIBTOOL_SHLIB_FLAGS@
+LIBTOOL_MODULE_FLAGS = $(LDFLAGS) @LIBTOOL_MODULE_FLAGS@
 
 STRIP_FLAGS = @STRIP_FLAGS@
 
@@ -63,20 +68,20 @@
 
 #---------- Do not change, shorthand only
 
-CXX_SWITCHES      = $(CXXFLAGS) \
+CXX_SWITCHES      = $(CPPFLAGS) $(CXXFLAGS) \
                        -I$(srcdir)/../include \
                        -I$(srcdir)/../src -I.
-CXX_SWITCHES_TCL  = $(CXXFLAGS) \
+CXX_SWITCHES_TCL  = $(CPPFLAGS) $(CXXFLAGS) \
                        -I$(srcdir)/../include \
                        -I$(tclincludedir)/generic \
                        -I$(tclincludedir)
-CXX_SWITCHES_PY   = $(CXXFLAGS) \
+CXX_SWITCHES_PY   = $(CPPFLAGS) $(CXXFLAGS) \
                        -I$(srcdir)/../include \
                        -I$(srcdir)/../python/scxx \
                        -I$(pyincludedir)
-CXX_SWITCHES_LUA  = $(CXXFLAGS) \
+CXX_SWITCHES_LUA  = $(CPPFLAGS) $(CXXFLAGS) \
                        -I$(srcdir)/../include
-CXX_SWITCHES_TEST = $(CXXFLAGS) \
+CXX_SWITCHES_TEST = $(CPPFLAGS) $(CXXFLAGS) \
                        -I$(srcdir)/../include
 
 #---------- The targets normally specified when calling "make"
@@ -87,7 +92,7 @@
 
 tcl: Makefile Mk4tcl@SHLIB_SUFFIX@
 
-python: Makefile Mk4py@SHLIB_SUFFIX@
+python: Makefile Mk4py@MODULE_SUFFIX@
 
 test: Makefile libmk4.la regress
        test -d tests || mkdir tests
@@ -99,6 +104,9 @@
 test-tcl: tcl
        cd $(srcdir)/../tcl/test && $(tclsh) all.tcl
 
+test-python: python
+       $(python) $(srcdir)/../python/test/all.py
+
 install: @MK_INSTALL@
 
 install-mk: libmk4.la
@@ -114,9 +122,9 @@
        $(INSTALL_PROGRAM) Mk4tcl@SHLIB_SUFFIX@ $(DESTDIR)$(tcllibdir)/Mk4tcl
        echo 'package ifneeded Mk4tcl 2.4.8 [list load [file join $$dir 
Mk4tcl@SHLIB_SUFFIX@] Mk4tcl]' >$(DESTDIR)$(tcllibdir)/Mk4tcl/pkgIndex.tcl
 
-install-python: Mk4py@SHLIB_SUFFIX@
-       $(INSTALL_PROGRAM) Mk4py@SHLIB_SUFFIX@ $(DESTDIR)$(pylibdir)
-       $(INSTALL_PROGRAM) $(srcdir)/../python/metakit.py $$(DESTDIR)(pylibdir)
+install-python: Mk4py@MODULE_SUFFIX@
+       $(INSTALL_PROGRAM) Mk4py@MODULE_SUFFIX@ $(DESTDIR)$(pylibdir)
+       $(INSTALL_PROGRAM) $(srcdir)/../python/metakit.py $(DESTDIR)$(pylibdir)
 
 clean:
        $L rm -f *.la *.o *.lo
@@ -138,7 +146,7 @@
        cd $(srcdir) && autoconf
 
 libmk4.la: $(LIBOBJS) $(LINK_SPECIAL_FILES)
-       $L --mode=link $(CXX) -o $@ $(CXX_SWITCHES) $(LIBTOOL_FLAGS) -avoid-version \
+       $L --mode=link $(CXX) -o $@ $(CXX_SWITCHES) $(LIBTOOL_SHLIB_FLAGS) 
+-avoid-version \
                -rpath $(libdir) $(SHLOBJS) $(LINK_SPECIAL_FLAGS)
 
 Mk4tcl@SHLIB_SUFFIX@: libmk4tcl.la
@@ -146,15 +154,15 @@
        -strip $(STRIP_FLAGS) $@ 2>/dev/null
 
 libmk4tcl.la: mk4tcl.o mk4too.o $(LIBOBJS) $(LINK_SPECIAL_FILES)
-       $L --mode=link $(CXX) -o $@ $(CXX_SWITCHES) $(LIBTOOL_FLAGS) -avoid-version \
+       $L --mode=link $(CXX) -o $@ $(CXX_SWITCHES) $(LIBTOOL_SHLIB_FLAGS) 
+-avoid-version \
                -rpath $(libdir) mk4tcl.lo mk4too.lo $(SHLOBJS) $(LINK_SPECIAL_FLAGS)
 
-Mk4py@SHLIB_SUFFIX@: libmk4py.la
-       cp .libs/libmk4py@SHLIB_SUFFIX@ $@
+Mk4py@MODULE_SUFFIX@: libmk4py.la
+       cp .libs/libmk4py@MODULE_SUFFIX@ $@
        -strip $(STRIP_FLAGS) $@ 2>/dev/null
 
 libmk4py.la: $(PYOBJS) $(LIBOBJS)
-       $L --mode=link $(CXX) -o $@ $(CXX_SWITCHES) $(LIBTOOL_FLAGS) -avoid-version \
+       $L --mode=link $(CXX) -o $@ $(CXX_SWITCHES) $(LIBTOOL_MODULE_FLAGS) 
+-avoid-version \
                -rpath $(libdir) $(SPYOBJS) $(SHLOBJS)
 
 Mk4lua@SHLIB_SUFFIX@: mk4lua.o libmk4.la
@@ -202,8 +210,16 @@
        $L --mode=compile $(CXX) -c $(CXX_SWITCHES_PY) $?
 PyView.o: $(srcdir)/../python/PyView.cpp
        $L --mode=compile $(CXX) -c $(CXX_SWITCHES_PY) $?
-PWOImp.o: $(srcdir)/../python/scxx/PWOImp.cpp
-       $L --mode=compile $(CXX) -c $(CXX_SWITCHES_PY) $?
+
+PWOImp.o: $(srcdir)/../python/scxx/PWOImp.cpp \
+         $(srcdir)/../python/scxx/PWOBase.h \
+         $(srcdir)/../python/scxx/PWOCallable.h \
+         $(srcdir)/../python/scxx/PWOMSequence.h \
+         $(srcdir)/../python/scxx/PWOMapping.h \
+         $(srcdir)/../python/scxx/PWONumber.h \
+         $(srcdir)/../python/scxx/PWOSequence.h
+       $L --mode=compile $(CXX) -c $(CXX_SWITCHES_PY) \
+            $(srcdir)/../python/scxx/PWOImp.cpp
 
 column.o: $(srcdir)/../src/column.cpp
        $L --mode=compile $(CXX) -c $(CXX_SWITCHES) $?
diff -uNr -X metakit-files-to-ignore-when-diffing metakit-2.4.8/unix/configure.in 
metakit-2.4.8+njr2/unix/configure.in
--- metakit-2.4.8/unix/configure.in     Fri Oct  4 15:54:02 2002
+++ metakit-2.4.8+njr2/unix/configure.in        Fri Dec 13 10:28:41 2002
@@ -8,25 +8,75 @@
 MK_TARGETS="core"
 MK_INSTALL="install-mk"
 
-AC_ARG_ENABLE(python, [  --enable-python         build the Mk4py extension for 
Python], [python_ok=$enableval], [python_ok=no])
+AC_ARG_WITH(python,
+[  --with-python=PATH      build the Mk4py extension for Python with headers in
+                          `PATH/include/python2.2'; install the Mk4py modules in
+                          `PATH/lib/python2.2/site-packages'.  If PATH is of the
+                          form `HEADER:LIB', search for header files in HEADER,
+                          and install Mk4py in LIB.  If you omit the `=PATH'
+                          part completely, the configure script will use the
+                          provided includedir and libdir.],
+                          [with_python=${withval}], [with_python=no])
 
 AC_MSG_CHECKING([for Python configuration])
-if test "$python_ok" = yes; then
-  MK_TARGETS="$MK_TARGETS python"
-  MK_INSTALL="$MK_INSTALL install-python"
-  AC_MSG_RESULT(enabled)
+case "$with_python" in
+  "yes" )
+       PY_INCLUDE_DIR='${includedir}/python2.2'
+       PY_LIB_DIR='${libdir}/python2.2/site-packages'
+  ;;
+  "no" )
+       PY_INCLUDE_DIR=""
+  ;;
+  *":"* )
+       PY_INCLUDE_DIR="`echo $with_python | sed -e 's/:.*$//'`"
+       PY_LIB_DIR="`echo $with_python | sed -e 's/^.*://'`"
+  ;;
+  * )
+    PY_INCLUDE_DIR="$with_python/include/python2.2"
+    PY_LIB_DIR="$with_python/lib/python2.2/site-packages"
+  ;;
+esac
+
+if test x"${PY_INCLUDE_DIR}" != x; then
+  if test -f "${PY_INCLUDE_DIR}/Python.h" ; then
+    MK_TARGETS="$MK_TARGETS python"
+    MK_INSTALL="$MK_INSTALL install-python"
+    AC_MSG_RESULT($PY_INCLUDE_DIR and $PY_LIB_DIR)
+  else
+    AC_MSG_RESULT(can't find $(PY_INCLUDE_DIR)/Python.h)
+  fi
 else
   AC_MSG_RESULT(not enabled)
 fi
 
-AC_ARG_WITH(tcl, [  --with-tcl=DIR          location of tcl.h header file], 
[TCL_INCLUDE_DIR=${withval}])
+AC_ARG_WITH(tcl, 
+[  --with-tcl=PATH         build the Mk4tcl extension for Tcl with tcl.h in
+                          `PATH/include/tcl.h'; install the Mk4tcl package
+                          in `PATH/lib'.  If PATH is of the form `HEADER:LIB',
+                          search for tcl.h in HEADER, and install Mk4tcl in
+                          LIB.], [with_tcl=${withval}], [with_tcl=no])
 
 AC_MSG_CHECKING([for Tcl headers])
+case "$with_tcl" in
+  "no" )
+       TCL_INCLUDE_DIR=""
+  ;;
+  *":"* )
+       TCL_INCLUDE_DIR="`echo $with_tcl | sed -e 's/:.*$//'`"
+       TCL_LIB_DIR="`echo $with_tcl | sed -e 's/^.*://'`"
+  ;;
+  * )
+    TCL_INCLUDE_DIR="$with_tcl/include"
+    TCL_LIB_DIR="$with_tcl/lib"
+  ;;
+esac
 if test x"${TCL_INCLUDE_DIR}" != x ; then
   if test -f "${TCL_INCLUDE_DIR}/tcl.h" ; then
     AC_MSG_RESULT(found ${TCL_INCLUDE_DIR}/tcl.h)
     MK_TARGETS="$MK_TARGETS tcl"
     MK_INSTALL="$MK_INSTALL install-tcl"
+    AC_MSG_CHECKING(for Tcl package installation location)
+    AC_MSG_RESULT(${TCL_LIB_DIR})
   else
     AC_MSG_ERROR([${TCL_INCLUDE_DIR} directory doesn't contain tcl.h])
   fi
@@ -59,24 +109,29 @@
 
 # Deal with shared lib differences
 SHLIB_SUFFIX=".so"
+MODULE_SUFFIX=".so"
 STRIP_FLAGS=
-LIBTOOL_FLAGS=-module
+LIBTOOL_SHLIB_FLAGS=
+LIBTOOL_MODULE_FLAGS=-module
 
 case $build_os in
   darwin*)
     SHLIB_SUFFIX=".dylib"
+    # MODULE_SUFFIX remains .so (Darwin doesn't care)
     STRIP_FLAGS=-S
-    LIBTOOL_FLAGS=
     ;;
   hpux*)
     SHLIB_SUFFIX=".sl"
+    MODULE_SUFFIX=".sl"
     if test "X$build_cpu" = "Xia64" ; then
-       # libtools insists on .so files for HPUX/Itanium :(
+       # libtool insists on .so files for HP-UX/Itanium :(
         SHLIB_SUFFIX=".so"
+        MODULE_SUFFIX=".so"
     fi
     ;;
   cyg*)
     SHLIB_SUFFIX=".dll"
+    MODULE_SUFFIX=".dll"
     ;;
 esac
 
@@ -126,10 +181,17 @@
 
 AC_SUBST(MK_TARGETS)
 AC_SUBST(MK_INSTALL)
+AC_SUBST(PY_INCLUDE_DIR)
+AC_SUBST(PY_LIB_DIR)
 AC_SUBST(TCL_INCLUDE_DIR)
+AC_SUBST(TCL_LIB_DIR)
 AC_SUBST(EXEEXT)
+AC_SUBST(CPPFLAGS)
+AC_SUBST(LDFLAGS)
 AC_SUBST(SHLIB_SUFFIX)
-AC_SUBST(LIBTOOL_FLAGS)
+AC_SUBST(MODULE_SUFFIX)
+AC_SUBST(LIBTOOL_SHLIB_FLAGS)
+AC_SUBST(LIBTOOL_MODULE_FLAGS)
 AC_SUBST(STRIP_FLAGS)
 
 AC_OUTPUT(Makefile)

Reply via email to