[h5py] 120/455: Begin giant move to Cython

Ghislain Vaillant ghisvail-guest at moszumanska.debian.org
Thu Jul 2 18:19:24 UTC 2015


This is an automated email from the git hooks/post-receive script.

ghisvail-guest pushed a commit to annotated tag 1.3.0
in repository h5py.

commit 2a57e26ebf15f1dda9e0d01104fc2ca1a5b5448c
Author: andrewcollette <andrew.collette at gmail.com>
Date:   Sun Sep 21 09:25:05 2008 +0000

    Begin giant move to Cython
---
 h5py/_extras.py             |  74 +++++++
 h5py/defs_c.pxd             |  38 ----
 h5py/extras.py              |  26 ---
 h5py/h5.pxd                 |  19 +-
 h5py/h5.pyx                 |  29 +--
 h5py/h5a.pyx                |   2 +
 h5py/h5d.pyx                |  50 ++---
 h5py/h5f.pyx                |   8 +-
 h5py/h5fd.pyx               |  20 +-
 h5py/h5g.pxd                |  31 ++-
 h5py/h5g.pyx                | 482 ++++++++++++++++++++++++--------------------
 h5py/h5p.pyx                |   2 +-
 h5py/h5s.pxd                |   5 +-
 h5py/h5s.pyx                |  49 ++++-
 h5py/h5t.pxd                |   7 +-
 h5py/h5t.pyx                |  52 ++++-
 h5py/std_code.pxi           |  33 +++
 h5py/std_defs.pxi           |  57 +++++-
 h5py/tests/test_h5g.py      |   3 +-
 h5py/tests/test_threads.py  |   4 +-
 setup.py                    |  28 +--
 setup.py => setup_cython.py | 367 ++++++++++++++++-----------------
 22 files changed, 809 insertions(+), 577 deletions(-)

diff --git a/h5py/_extras.py b/h5py/_extras.py
new file mode 100644
index 0000000..c80abd1
--- /dev/null
+++ b/h5py/_extras.py
@@ -0,0 +1,74 @@
+#+
+# 
+# This file is part of h5py, a low-level Python interface to the HDF5 library.
+# 
+# Copyright (C) 2008 Andrew Collette
+# http://h5py.alfven.org
+# License: BSD  (See LICENSE.txt for full license)
+# 
+# $Date$
+# 
+#-
+from __future__ import with_statement
+
+import logging
+from h5py import config
+
+# Decorator utility for low-level thread safety
+from functools import update_wrapper
+
+def uw_apply(wrap, func):
+    # Cython methods don't have a "module" attribute for some reason
+    if hasattr(func, '__module__'):
+        update_wrapper(wrap, func)
+    else:
+        update_wrapper(wrap, func, assigned=('__name__','__doc__'))
+
+def h5sync(logger=None):
+
+    if logger is None:
+        def sync_simple(func):
+            
+            def wrap(*args, **kwds):
+                with config.lock:
+                    return func(*args, **kwds)
+
+            uw_apply(wrap, func)
+            return wrap
+
+        return sync_simple
+
+    else:
+
+        def sync_debug(func):
+
+            def wrap(*args, **kwds):
+                logger.debug("$ Threadsafe function entry: %s" % func.__name__)
+                with config.lock:
+                    logger.debug("> Acquired lock on %s" % func.__name__)
+                    retval = func(*args, **kwds)
+                logger.debug("< Released lock on %s" % func.__name__)
+                return retval
+
+            uw_apply(wrap, func)
+            return wrap
+
+        return sync_debug
+
+def h5sync_dummy(logger):
+
+    def log_only(func):
+
+        def wrap(*args, **kwds):
+            logger.debug("$ Function entry: %s" % func.__name__)
+            return func(*args, **kwds)
+
+        uw_apply(wrap, func)
+        return wrap
+
+    return log_only
+
+
+
+
+
diff --git a/h5py/defs_c.pxd b/h5py/defs_c.pxd
deleted file mode 100644
index 6ae13c2..0000000
--- a/h5py/defs_c.pxd
+++ /dev/null
@@ -1,38 +0,0 @@
-#+
-# 
-# This file is part of h5py, a low-level Python interface to the HDF5 library.
-# 
-# Copyright (C) 2008 Andrew Collette
-# http://h5py.alfven.org
-# License: BSD  (See LICENSE.txt for full license)
-# 
-# $Date$
-# 
-#-
-
-# This file is based on code from the PyTables project.  The complete PyTables
-# license is available at licenses/pytables.txt, in the distribution root
-# directory.
-
-# Standard C functions.
-
-cdef extern from "stdlib.h":
-  ctypedef long size_t
-  void *malloc(size_t size)
-  void free(void *ptr)
-
-cdef extern from "string.h":
-  char *strchr(char *s, int c)
-  char *strcpy(char *dest, char *src)
-  char *strncpy(char *dest, char *src, size_t n)
-  int strcmp(char *s1, char *s2)
-  char *strdup(char *s)
-  void *memcpy(void *dest, void *src, size_t n)
-
-cdef extern from "time.h":
-  ctypedef int time_t
-
-cdef extern from "unistd.h":
-  ctypedef long ssize_t
-
-
diff --git a/h5py/extras.py b/h5py/extras.py
deleted file mode 100644
index 5135358..0000000
--- a/h5py/extras.py
+++ /dev/null
@@ -1,26 +0,0 @@
-#+
-# 
-# This file is part of h5py, a low-level Python interface to the HDF5 library.
-# 
-# Copyright (C) 2008 Andrew Collette
-# http://h5py.alfven.org
-# License: BSD  (See LICENSE.txt for full license)
-# 
-# $Date$
-# 
-#-
-from __future__ import with_statement
-
-from h5py import config
-
-# Decorator utility for low-level thread safety
-from functools import update_wrapper
-def h5sync(func):
-    
-    def wrap(*args, **kwds):
-        with config.lock:
-            return func(*args, **kwds)
-
-    update_wrapper(wrap, func)
-    return wrap
-
diff --git a/h5py/h5.pxd b/h5py/h5.pxd
index aa1a3c7..d2717fe 100644
--- a/h5py/h5.pxd
+++ b/h5py/h5.pxd
@@ -14,22 +14,10 @@
 # license is available at licenses/pytables.txt, in the distribution root
 # directory.
 
-include "conditions.pxi"
-from defs_c cimport size_t, ssize_t, malloc, free
+include "std_defs.pxi"
 
-# Common structs and types from HDF5
 cdef extern from "hdf5.h":
 
-  ctypedef int hid_t  # In H5Ipublic.h
-  ctypedef int hbool_t
-  ctypedef int herr_t
-  ctypedef int htri_t
-  # hsize_t should be unsigned, but Windows platform does not support
-  # such an unsigned long long type.
-  ctypedef long long hsize_t
-  ctypedef signed long long hssize_t
-  ctypedef signed long long haddr_t  # I suppose this must be signed as well...
-
   ctypedef struct hvl_t:
     size_t len                 # Length of VL data (in base type units)
     void *p                    # Pointer to VL data
@@ -255,7 +243,10 @@ cdef class H5PYConfig:
 
     cdef object _complex_names      # ('r','i')
     cdef object _lock               # Primary HDF5 Interface Lock (PHIL)
-    cdef readonly object compile_opts
+    cdef readonly object API_16
+    cdef readonly object API_18
+    cdef readonly object DEBUG
+    cdef readonly object THREADS
 
 cdef class ObjectID:
     """ Base wrapper class for HDF5 object identifiers """
diff --git a/h5py/h5.pyx b/h5py/h5.pyx
index 6d1604c..4ed3f29 100644
--- a/h5py/h5.pyx
+++ b/h5py/h5.pyx
@@ -30,7 +30,7 @@
     All exception classes and error handling functions are also in this module.
 """
 
-include "conditions.pxi"
+include "config.pxi"
 from python cimport PyErr_SetObject
 
 import atexit
@@ -40,9 +40,10 @@ from weakref import WeakKeyDictionary
 # Logging is only enabled when compiled with H5PY_DEBUG nonzero
 IF H5PY_DEBUG:
     import logging
-    logger = logging.getLogger('h5py')
+    logger = logging.getLogger('h5py')  # Set up the root logger
     logger.setLevel(H5PY_DEBUG)
     logger.addHandler(logging.StreamHandler())
+    log_ident = logging.getLogger('h5py.identifiers')
 
 def get_libversion():
     """ () => TUPLE (major, minor, release)
@@ -79,9 +80,12 @@ cdef class H5PYConfig:
     """
 
     def __init__(self):
+        global logger
         self._complex_names = ('r','i')
-        self.compile_opts = {'IO_NONBLOCK': H5PY_NONBLOCK,
-                             'DEBUG': H5PY_DEBUG}
+        self.API_16 = H5PY_16API
+        self.API_18 = H5PY_18API
+        self.DEBUG = H5PY_DEBUG
+        self.THREADS = H5PY_THREADS
         self._lock = threading.RLock()
 
     property lock:
@@ -123,7 +127,7 @@ cdef object standard_richcmp(object self, object other, int how):
 
     if how == 2 or how == 3:
         
-        if not typecheck(self, ObjectID) and typecheck(other, ObjectID):
+        if not isinstance(self, ObjectID) and isinstance(other, ObjectID):
             return NotImplemented
 
         eq = (hash(self) == hash(other))
@@ -170,12 +174,12 @@ cdef class ObjectID:
         self._locked = 0
         self.id = id_
         IF H5PY_DEBUG:
-            logger.debug("+ %s" % str(self))
+            log_ident.debug("+ %s" % str(self))
 
     def __dealloc__(self):
         """ Automatically decrefs the ID, if it's valid. """
         IF H5PY_DEBUG:
-            logger.debug("- %s" % str(self))
+            log_ident.debug("- %s" % str(self))
         if (not self._locked) and self._valid:
             H5Idec_ref(self.id)
 
@@ -187,12 +191,12 @@ cdef class ObjectID:
         """
         cdef ObjectID copy
         copy = type(self)(self.id)
-        assert typecheck(copy, ObjectID), "ObjectID copy encountered invalid type"
+        assert isinstance(copy, ObjectID), "ObjectID copy encountered invalid type"
         if self._valid and not self._locked:
             H5Iinc_ref(self.id)
         copy._locked = self._locked
         IF H5PY_DEBUG:
-            logger.debug("c %s" % str(self))
+            log_ident.debug("c %s" % str(self))
         return copy
 
     def __richcmp__(self, object other, int how):
@@ -608,14 +612,11 @@ import_hdf5()
 
 hdf5_version_tuple = get_libversion()        
 hdf5_version = "%d.%d.%d" % hdf5_version_tuple
-api_version_tuple = (H5PY_API_MAJ, H5PY_API_MIN)
+api_version_tuple = (int(H5PY_API/10), H5PY_API%10)
 api_version = "%d.%d" % api_version_tuple
 
 version = H5PY_VERSION
-version_tuple = []   # no list comprehensions in Pyrex
-for _x in version.split('.'):
-    version_tuple.append(int(_x))
-version_tuple = tuple(version_tuple)
+version_tuple = tuple([int(x) for x in version.split('.')])
 
 _config = H5PYConfig()
 
diff --git a/h5py/h5a.pyx b/h5py/h5a.pyx
index be2d5e6..77a3d6c 100644
--- a/h5py/h5a.pyx
+++ b/h5py/h5a.pyx
@@ -18,6 +18,8 @@
     py_exists(ObjectID, STRING)     Test if a named attribute exists
 """
 
+include "std_code.pxi"
+
 # Pyrex compile-time imports
 from h5p cimport H5P_DEFAULT
 from h5t cimport TypeID, typewrap
diff --git a/h5py/h5d.pyx b/h5py/h5d.pyx
index 9e89354..7c874d3 100644
--- a/h5py/h5d.pyx
+++ b/h5py/h5d.pyx
@@ -13,7 +13,7 @@
 """
     Provides access to the low-level HDF5 "H5D" dataset interface.
 """
-include "conditions.pxi"
+include "std_code.pxi"
 
 # Pyrex compile-time imports
 from h5 cimport standard_richcmp
@@ -156,6 +156,7 @@ cdef class DatasetID(ObjectID):
         """
         H5Dclose(self.id)
 
+    @sync
     def read(self, SpaceID mspace not None, SpaceID fspace not None, 
                    ndarray arr_obj not None, PropDXID dxpl=None):
         """ (SpaceID mspace, SpaceID fspace, NDARRAY arr_obj, 
@@ -177,8 +178,8 @@ cdef class DatasetID(ObjectID):
 
             The actual read is non-blocking; the array object is temporarily
             marked read-only, but attempting to mutate it in another thread
-            is a bad idea.  Also, this DatasetID object acquires its own lock
-            (obj.pylock) until the operation completes.
+            is a bad idea.  All HDF5 API calls are locked until the read
+            completes.
         """
         cdef TypeID mtype
         cdef hid_t self_id, mtype_id, mspace_id, fspace_id, plist_id
@@ -195,20 +196,14 @@ cdef class DatasetID(ObjectID):
         plist_id = pdefault(dxpl)
         data = PyArray_DATA(arr_obj)
 
-        IF H5PY_NONBLOCK:
-            lock = config.lock
-            lock.acquire()
-            oldflags = arr_obj.flags
-            arr_obj.flags = oldflags & (~NPY_WRITEABLE) # Wish-it-was-a-mutex approach
-            try:
-                with nogil:
-                    H5PY_H5Dread(self_id, mtype_id, mspace_id, fspace_id, plist_id, data)
-            finally:
-                arr_obj.flags = oldflags
-                lock.release()
-        ELSE:
-            H5PY_H5Dread(self_id, mtype_id, mspace_id, fspace_id, plist_id, data)
+        arr_obj.flags &= (~NPY_WRITEABLE) # Wish-it-was-a-mutex approach
+        try:
+            with nogil:
+                H5PY_H5Dread(self_id, mtype_id, mspace_id, fspace_id, plist_id, data)
+        finally:
+            arr_obj.flags |= NPY_WRITEABLE
 
+    @sync
     def write(self, SpaceID mspace not None, SpaceID fspace not None, 
                     ndarray arr_obj not None, PropDXID dxpl=None):
         """ (SpaceID mspace, SpaceID fspace, NDARRAY arr_obj, 
@@ -223,8 +218,8 @@ cdef class DatasetID(ObjectID):
 
             The actual write is non-blocking; the array object is temporarily
             marked read-only, but attempting to mutate it in another thread
-            is a bad idea.  Also, this DatasetID object acquires its own lock
-            (obj.pylock) until the operation completes.
+            is a bad idea.  All HDF5 API calls are locked until the write
+            completes.
         """
         cdef TypeID mtype
         cdef hid_t self_id, mtype_id, mspace_id, fspace_id, plist_id
@@ -241,19 +236,12 @@ cdef class DatasetID(ObjectID):
         plist_id = pdefault(dxpl)
         data = PyArray_DATA(arr_obj)
 
-        IF H5PY_NONBLOCK:
-            lock = config.lock
-            lock.acquire()
-            oldflags = arr_obj.flags
-            arr_obj.flags = oldflags & (~NPY_WRITEABLE) # Wish-it-was-a-mutex approach
-            try:
-                with nogil:
-                    H5PY_H5Dwrite(self_id, mtype_id, mspace_id, fspace_id, plist_id, data)
-            finally:
-                arr_obj.flags = oldflags
-                lock.release()
-        ELSE:
-            H5PY_H5Dwrite(self_id, mtype_id, mspace_id, fspace_id, plist_id, data)
+        arr_obj.flags &= (~NPY_WRITEABLE) # Wish-it-was-a-mutex approach
+        try:
+            with nogil:
+                H5PY_H5Dwrite(self_id, mtype_id, mspace_id, fspace_id, plist_id, data)
+        finally:
+            arr_obj.flags |= NPY_WRITEABLE
 
     def extend(self, object shape):
         """ (TUPLE shape)
diff --git a/h5py/h5f.pyx b/h5py/h5f.pyx
index 96ef323..602cac7 100644
--- a/h5py/h5f.pyx
+++ b/h5py/h5f.pyx
@@ -146,9 +146,9 @@ def get_obj_count(object where=OBJ_ALL, int types=H5F_OBJ_ALL):
                 identifier.
     """
     cdef hid_t where_id
-    if typecheck(where, FileID):
+    if isinstance(where, FileID):
         where_id = where.id
-    elif typecheck(where, int) or typecheck(where, long):
+    elif isinstance(where, int) or isinstance(where, long):
         where_id = where
     else:
         raise TypeError("Location must be a FileID or OBJ_ALL.")
@@ -201,9 +201,9 @@ def get_obj_ids(object where=OBJ_ALL, int types=H5F_OBJ_ALL):
     obj_list = NULL
     py_obj_list = []
 
-    if typecheck(where, FileID):
+    if isinstance(where, FileID):
         where_id = where.id
-    elif typecheck(where, int) or typecheck(where, long):
+    elif isinstance(where, int) or isinstance(where, long):
         where_id = where
     else:
         raise TypeError("Location must be a FileID or OBJ_ALL.")
diff --git a/h5py/h5fd.pyx b/h5py/h5fd.pyx
index fe234e9..d1fe854 100644
--- a/h5py/h5fd.pyx
+++ b/h5py/h5fd.pyx
@@ -41,29 +41,29 @@ LOG_LOC_WRITE = H5FD_LOG_LOC_WRITE  # 0x0002
 LOG_LOC_SEEK  = H5FD_LOG_LOC_SEEK   # 0x0004
 LOG_LOC_IO    = H5FD_LOG_LOC_IO     # (H5FD_LOG_LOC_READ|H5FD_LOG_LOC_WRITE|H5FD_LOG_LOC_SEEK)
 
-# /* Flags for tracking number of times each byte is read/written */
+# Flags for tracking number of times each byte is read/written 
 LOG_FILE_READ = H5FD_LOG_FILE_READ  # 0x0008
 LOG_FILE_WRITE= H5FD_LOG_FILE_WRITE # 0x0010
 LOG_FILE_IO   = H5FD_LOG_FILE_IO    # (H5FD_LOG_FILE_READ|H5FD_LOG_FILE_WRITE)
 
-# /* Flag for tracking "flavor" (type) of information stored at each byte */
+# Flag for tracking "flavor" (type) of information stored at each byte 
 LOG_FLAVOR    = H5FD_LOG_FLAVOR     # 0x0020
 
-# /* Flags for tracking total number of reads/writes/seeks */
+# Flags for tracking total number of reads/writes/seeks 
 LOG_NUM_READ  = H5FD_LOG_NUM_READ   # 0x0040
 LOG_NUM_WRITE = H5FD_LOG_NUM_WRITE  # 0x0080
 LOG_NUM_SEEK  = H5FD_LOG_NUM_SEEK   # 0x0100
 LOG_NUM_IO    = H5FD_LOG_NUM_IO     # (H5FD_LOG_NUM_READ|H5FD_LOG_NUM_WRITE|H5FD_LOG_NUM_SEEK)
 
-# /* Flags for tracking time spent in open/read/write/seek/close */
-LOG_TIME_OPEN = H5FD_LOG_TIME_OPEN  # 0x0200        # /* Not implemented yet */
-LOG_TIME_READ = H5FD_LOG_TIME_READ  # 0x0400        # /* Not implemented yet */
-LOG_TIME_WRITE= H5FD_LOG_TIME_WRITE # 0x0800        # /* Partially implemented (need to track total time) */
-LOG_TIME_SEEK = H5FD_LOG_TIME_SEEK  # 0x1000        # /* Partially implemented (need to track total time & track time for seeks during reading) */
-LOG_TIME_CLOSE= H5FD_LOG_TIME_CLOSE # 0x2000        # /* Fully implemented */
+# Flags for tracking time spent in open/read/write/seek/close 
+LOG_TIME_OPEN = H5FD_LOG_TIME_OPEN  # 0x0200        # Not implemented yet 
+LOG_TIME_READ = H5FD_LOG_TIME_READ  # 0x0400        # Not implemented yet 
+LOG_TIME_WRITE= H5FD_LOG_TIME_WRITE # 0x0800        # Partially implemented (need to track total time) 
+LOG_TIME_SEEK = H5FD_LOG_TIME_SEEK  # 0x1000        # Partially implemented (need to track total time & track time for seeks during reading) 
+LOG_TIME_CLOSE= H5FD_LOG_TIME_CLOSE # 0x2000        # Fully implemented 
 LOG_TIME_IO   = H5FD_LOG_TIME_IO    # (H5FD_LOG_TIME_OPEN|H5FD_LOG_TIME_READ|H5FD_LOG_TIME_WRITE|H5FD_LOG_TIME_SEEK|H5FD_LOG_TIME_CLOSE)
 
-# /* Flag for tracking allocation of space in file */
+# Flag for tracking allocation of space in file 
 LOG_ALLOC     = H5FD_LOG_ALLOC      # 0x4000
 LOG_ALL       = H5FD_LOG_ALL        # (H5FD_LOG_ALLOC|H5FD_LOG_TIME_IO|H5FD_LOG_NUM_IO|H5FD_LOG_FLAVOR|H5FD_LOG_FILE_IO|H5FD_LOG_LOC_IO)
 
diff --git a/h5py/h5g.pxd b/h5py/h5g.pxd
index dc2c758..bb5dd72 100644
--- a/h5py/h5g.pxd
+++ b/h5py/h5g.pxd
@@ -14,7 +14,6 @@
 # license is available at licenses/pytables.txt, in the distribution root
 # directory.
 
-include "conditions.pxi"
 include "std_defs.pxi"
 from h5 cimport class ObjectID
 
@@ -51,13 +50,10 @@ cdef extern from "hdf5.h":
   hid_t  H5Gcreate(hid_t loc_id, char *name, size_t size_hint ) except *
   hid_t  H5Gopen(hid_t loc_id, char *name ) except *
   herr_t H5Gclose(hid_t group_id) except *
-#  herr_t H5Glink (hid_t file_id, H5G_link_t link_type,
-#                  char *current_name, char *new_name) except *
   herr_t H5Glink2( hid_t curr_loc_id, char *current_name, 
                    H5G_link_t link_type, hid_t new_loc_id, char *new_name ) except *
 
   herr_t H5Gunlink (hid_t file_id, char *name) except *
-#  herr_t H5Gmove(hid_t loc_id, char *src, char *dst) except *
   herr_t H5Gmove2(hid_t src_loc_id, char *src_name,
                   hid_t dst_loc_id, char *dst_name ) except *
   herr_t H5Gget_num_objs(hid_t loc_id, hsize_t*  num_obj) except *
@@ -72,7 +68,34 @@ cdef extern from "hdf5.h":
   herr_t H5Gset_comment(hid_t loc_id, char *name, char *comment ) except *
   int H5Gget_comment(hid_t loc_id, char *name, size_t bufsize, char *comment ) except *
 
+  # --- New 1.8.X functions ---------------------------------------------------
+
   IF H5PY_18API:
+    ctypedef enum H5G_storage_type_t:
+        H5G_STORAGE_TYPE_UNKNOWN = -1,
+        H5G_STORAGE_TYPE_SYMBOL_TABLE,
+        H5G_STORAGE_TYPE_COMPACT,
+        H5G_STORAGE_TYPE_DENSE 
+   
+    ctypedef struct H5G_info_t:
+        H5G_storage_type_t 	storage_type
+        hsize_t 	 nlinks
+        long int     max_corder  # FIXME: not really long int
+
     hid_t H5Gcreate_anon( hid_t loc_id, hid_t gcpl_id, hid_t gapl_id  ) except *
+    hid_t H5Gcreate2(hid_t loc_id, char *name, hid_t lcpl_id, hid_t gcpl_id, hid_t gapl_id) except *
+    hid_t H5Gopen2( hid_t loc_id, char * name, hid_t gapl_id  ) except *
+    herr_t H5Gget_info( hid_t group_id, H5G_info_t *group_info  ) except *
+    herr_t H5Gget_info_by_name( hid_t loc_id, char *group_name, H5G_info_t *group_info, hid_t lapl_id  ) except *
+
+
+
+
+
+
+
+
+
+
 
 
diff --git a/h5py/h5g.pyx b/h5py/h5g.pyx
index 5d05b35..1ad2bbf 100644
--- a/h5py/h5g.pyx
+++ b/h5py/h5g.pyx
@@ -13,12 +13,12 @@
 """
     Low-level HDF5 "H5G" group interface.
 """
-include "conditions.pxi"
+include "std_code.pxi"
 
 # Pyrex compile-time imports
 from utils cimport emalloc, efree
 from h5 cimport standard_richcmp
-from h5p cimport H5P_DEFAULT
+from h5p cimport H5P_DEFAULT, PropID, pdefault
 IF H5PY_18API:
     from h5l cimport LinkProxy
 
@@ -118,21 +118,43 @@ cdef class GroupIter:
 
 # === Basic group management ==================================================
 
-def open(ObjectID loc not None, char* name):
-    """ (ObjectID loc, STRING name) => GroupID
+# COMPAT: 1.8 update
+IF H5PY_18API:
+    def open(ObjectID loc not None, char* name, PropID gapl=None):
+        """ (ObjectID loc, STRING name, PropGAID gapl=None)
 
-        Open an existing HDF5 group, attached to some other group.
-    """
-    return GroupID(H5Gopen(loc.id, name))
+            Open an existing HDF5 group, attached to some other group.
+        """
+        return GroupID(H5Gopen2(loc.id, name, pdefault(gapl)))
+ELSE:
+    def open(ObjectID loc not None, char* name):
+        """ (ObjectID loc, STRING name) => GroupID
+
+            Open an existing HDF5 group, attached to some other group.
+        """
+        return GroupID(H5Gopen(loc.id, name))
 
-def create(ObjectID loc not None, char* name, int size_hint=-1):
-    """ (ObjectID loc, STRING name, INT size_hint=-1) => GroupID
+# COMPAT: 1.8 update
+IF H5PY_18API:
+    def create(ObjectID loc not None, char* name, PropID lcpl=None,
+               PropID gcpl=None, PropID gapl=None):
+        """ (ObjectID loc, STRING name, PropLCID lcpl=None, PropGCID gcpl=None,
+             PropGAID gapl=None) => GroupID
 
-        Create a new group, under a given parent group.  If given, size_hint
-        is an estimate of the space to reserve (in bytes) for group member
-        names.
-    """
-    return GroupID(H5Gcreate(loc.id, name, size_hint))
+            Create a new group, under a given parent group.
+        """
+        return GroupID(H5Gcreate2(loc.id, name, pdefault(lcpl),
+                                                pdefault(gcpl),
+                                                pdefault(gapl)))
+ELSE:
+    def create(ObjectID loc not None, char* name, int size_hint=-1):
+        """ (ObjectID loc, STRING name, INT size_hint=-1) => GroupID
+
+            Create a new group, under a given parent group.  If given, size_hint
+            is an estimate of the space to reserve (in bytes) for group member
+            names.
+        """
+        return GroupID(H5Gcreate(loc.id, name, size_hint))
 
 cdef herr_t iter_cb_helper(hid_t gid, char *name, object int_tpl) except -1:
     # Callback function for H5Giterate
@@ -152,60 +174,64 @@ cdef herr_t iter_cb_helper(hid_t gid, char *name, object int_tpl) except -1:
 
     return 0
 
-def iterate(GroupID loc not None, char* name, object func, object data=None, 
-            int startidx=0):
-    """ (GroupID loc, STRING name, FUNCTION func, OBJECT data=None, 
-            UINT startidx=0) => INT last_index_processed
-
-        Iterate an arbitrary Python function over a group.  Note that the
-        group is specified by a parent and a name; if you have a group
-        identifier and want to iterate over it; pass in "." for the name.
-        You can also start at an arbitrary member by specifying its 
-        (zero-based) index.
-
-        Your function:
-        1.  Should accept three arguments: the GroupID of the group, the 
-            (STRING) name of the member, and an arbitary Python object you 
-            provide as data.  Any return value is ignored.
-        2.  Raise StopIteration to bail out before all members are processed.
-        3.  Raising anything else immediately aborts iteration, and the
-            exception is propagated.
-    """
-    cdef int i
-    cdef list err_list
-    err_list = []
+# COMPAT: 1.8 deprecation
+IF H5PY_16API:
+    def iterate(GroupID loc not None, char* name, object func, object data=None, 
+                int startidx=0):
+        """ (GroupID loc, STRING name, FUNCTION func, OBJECT data=None, 
+                UINT startidx=0) => INT last_index_processed
+
+            Iterate an arbitrary Python function over a group.  Note that the
+            group is specified by a parent and a name; if you have a group
+            identifier and want to iterate over it; pass in "." for the name.
+            You can also start at an arbitrary member by specifying its 
+            (zero-based) index.
+
+            Your function:
+            1.  Should accept three arguments: the GroupID of the group, the 
+                (STRING) name of the member, and an arbitary Python object you 
+                provide as data.  Any return value is ignored.
+            2.  Raise StopIteration to bail out before all members are processed.
+            3.  Raising anything else immediately aborts iteration, and the
+                exception is propagated.
+        """
+        cdef int i
+        cdef list err_list
+        err_list = []
 
-    if startidx < 0:
-        raise ValueError("Starting index must be non-negative.")
-    i = startidx
+        if startidx < 0:
+            raise ValueError("Starting index must be non-negative.")
+        i = startidx
 
-    int_tpl = (loc, func, data, err_list)
+        int_tpl = (loc, func, data, err_list)
 
-    H5Giterate(loc.id, name, &i, <H5G_iterate_t>iter_cb_helper, int_tpl)
+        H5Giterate(loc.id, name, &i, <H5G_iterate_t>iter_cb_helper, int_tpl)
 
-    if len(err_list) > 0:
-        raise err_list[0]
+        if len(err_list) > 0:
+            raise err_list[0]
 
-def get_objinfo(ObjectID obj not None, object name='.', int follow_link=1):
-    """ (ObjectID obj, STRING name='.', BOOL follow_link=True) => GroupStat object
+# COMPAT: 1.8 deprecation
+IF H5PY_16API:
+    def get_objinfo(ObjectID obj not None, object name='.', int follow_link=1):
+        """ (ObjectID obj, STRING name='.', BOOL follow_link=True) => GroupStat object
 
-        Obtain information about a named object.  If "name" is provided,
-        "obj" is taken to be a GroupID object containing the target.
-        The return value is a GroupStat object; see that class's docstring
-        for a description of its attributes.  
+            Obtain information about a named object.  If "name" is provided,
+            "obj" is taken to be a GroupID object containing the target.
+            The return value is a GroupStat object; see that class's docstring
+            for a description of its attributes.  
 
-        If follow_link is True (default) and the object is a symbolic link, 
-        the information returned describes its target.  Otherwise the 
-        information describes the link itself.
-    """
-    cdef GroupStat statobj
-    statobj = GroupStat()
-    cdef char* _name
-    _name = name
+            If follow_link is True (default) and the object is a symbolic link, 
+            the information returned describes its target.  Otherwise the 
+            information describes the link itself.
+        """
+        cdef GroupStat statobj
+        statobj = GroupStat()
+        cdef char* _name
+        _name = name
 
-    H5Gget_objinfo(obj.id, _name, follow_link, &statobj.infostruct)
+        H5Gget_objinfo(obj.id, _name, follow_link, &statobj.infostruct)
 
-    return statobj
+        return statobj
 
 # === Group member management =================================================
 
@@ -238,159 +264,178 @@ cdef class GroupID(ObjectID):
             when their Python wrappers are freed.
         """
         H5Gclose(self.id)
-
-    def link(self, char* current_name, char* new_name, 
-             int link_type=H5G_LINK_HARD, GroupID remote=None):
-        """ (STRING current_name, STRING new_name, INT link_type=LINK_HARD, 
-             GroupID remote=None)
-
-            Create a new hard or soft link.  current_name identifies
-            the link target (object the link will point to).  The new link is
-            identified by new_name and (optionally) another group "remote".
-
-            Link types are:
-                LINK_HARD:  Hard link to existing object (default)
-                LINK_SOFT:  Symbolic link; link target need not exist.
-        """
-        cdef hid_t remote_id
-        if remote is None:
-            remote_id = self.id
-        else:
-            remote_id = remote.id
-
-        H5Glink2(self.id, current_name, <H5G_link_t>link_type, remote_id, new_name)
-
-    def unlink(self, char* name):
-        """ (STRING name)
-
-            Remove a link to an object from this group.
-        """
-        H5Gunlink(self.id, name)
-
-    def move(self, char* current_name, char* new_name, GroupID remote=None):
-        """ (STRING current_name, STRING new_name, GroupID remote=None)
-
-            Relink an object.  current_name identifies the object.
-            new_name and (optionally) another group "remote" determine
-            where it should be moved.
-        """
-        cdef hid_t remote_id
-        if remote is None:
-            remote_id = self.id
-        else:
-            remote_id = remote.id
-
-        H5Gmove2(self.id, current_name, remote_id, new_name)
-
-    def get_num_objs(self):
-        """ () => INT number_of_objects
-
-            Get the number of objects directly attached to a given group.
-        """
-        cdef hsize_t size
-        H5Gget_num_objs(self.id, &size)
-        return size
-
-    def get_objname_by_idx(self, hsize_t idx):
-        """ (INT idx) => STRING object_name
-
-            Get the name of a group member given its zero-based index.
-
-            Due to a limitation of the HDF5 library, the generic exception
-            H5Error (errno 1) is raised if the idx parameter is out-of-range.
-        """
-        cdef int size
-        cdef char* buf
-        buf = NULL
-
-        # This function does not properly raise an exception
-        size = H5Gget_objname_by_idx(self.id, idx, NULL, 0)
-        if size < 0:
-            raise H5Error((1,"Invalid argument"))
-
-        buf = <char*>emalloc(sizeof(char)*(size+1))
-        try:
-            H5Gget_objname_by_idx(self.id, idx, buf, size+1)
-            pystring = buf
-            return pystring
-        finally:
-            efree(buf)
-
-    def get_objtype_by_idx(self, hsize_t idx):
-        """ (INT idx) => INT object_type_code
-
-            Get the type of an object attached to a group, given its zero-based
-            index.  Possible return values are:
-                - LINK
-                - GROUP
-                - DATASET
-                - DATATYPE
-
-            Due to a limitation of the HDF5 library, the generic exception
-            H5Error (errno 1) is raised if the idx parameter is out-of-range.
-        """
-        # This function does not properly raise an exception
-        cdef herr_t retval
-        retval = H5Gget_objtype_by_idx(self.id, idx)
-        if retval < 0:
-            raise H5Error((1,"Invalid argument."))
-        return retval
-
-
-    def get_linkval(self, char* name):
-        """ (STRING name) => STRING link_value
-
-            Retrieve the value (target name) of a symbolic link.
-            Limited to 2048 characters on Windows.
-        """
-        cdef char* value
-        cdef H5G_stat_t statbuf
-        value = NULL
-
-        H5Gget_objinfo(self.id, name, 0, &statbuf)
-
-        if statbuf.type != H5G_LINK:
-            raise ValueError('"%s" is not a symbolic link.' % name)
-
-        IF UNAME_SYSNAME == "Windows":
-            linklen = 2049  # Windows statbuf.linklen seems broken
-        ELSE:
-            linklen = statbuf.linklen+1
-        value = <char*>emalloc(sizeof(char)*linklen)
-        try:
-            H5Gget_linkval(self.id, name, linklen, value)
-            value[linklen-1] = c'\0'  # in case HDF5 doesn't null terminate on Windows
-            pyvalue = value
-            return pyvalue
-        finally:
-            efree(value)
-
-    def set_comment(self, char* name, char* comment):
-        """ (STRING name, STRING comment)
-
-            Set the comment on a group member.
-        """
-        H5Gset_comment(self.id, name, comment)
-
-    def get_comment(self, char* name):
-        """ (STRING name) => STRING comment
-
-            Retrieve the comment for a group member.
-        """
-        cdef int cmnt_len
-        cdef char* cmnt
-        cmnt = NULL
-
-        cmnt_len = H5Gget_comment(self.id, name, 0, NULL)
-        assert cmnt_len >= 0
-
-        cmnt = <char*>emalloc(sizeof(char)*(cmnt_len+1))
-        try:
-            H5Gget_comment(self.id, name, cmnt_len+1, cmnt)
-            py_cmnt = cmnt
-            return py_cmnt
-        finally:
-            efree(cmnt)
+        IF H5PY_18API:
+            H5Gclose(self.id)  # extra ref in the LinkProxy
+
+    # COMPAT: 1.8 deprecation
+    IF H5PY_16API:
+        def link(self, char* current_name, char* new_name, 
+                 int link_type=H5G_LINK_HARD, GroupID remote=None):
+            """ (STRING current_name, STRING new_name, INT link_type=LINK_HARD, 
+                 GroupID remote=None)
+
+                Create a new hard or soft link.  current_name identifies
+                the link target (object the link will point to).  The new link is
+                identified by new_name and (optionally) another group "remote".
+
+                Link types are:
+                    LINK_HARD:  Hard link to existing object (default)
+                    LINK_SOFT:  Symbolic link; link target need not exist.
+            """
+            cdef hid_t remote_id
+            if remote is None:
+                remote_id = self.id
+            else:
+                remote_id = remote.id
+
+            H5Glink2(self.id, current_name, <H5G_link_t>link_type, remote_id, new_name)
+
+    # COMPAT: 1.8 deprecation
+    IF H5PY_16API:
+        def unlink(self, char* name):
+            """ (STRING name)
+
+                Remove a link to an object from this group.
+            """
+            H5Gunlink(self.id, name)
+   
+    # COMPAT: 1.8 deprecation 
+    IF H5PY_16API:
+        def move(self, char* current_name, char* new_name, GroupID remote=None):
+            """ (STRING current_name, STRING new_name, GroupID remote=None)
+
+                Relink an object.  current_name identifies the object.
+                new_name and (optionally) another group "remote" determine
+                where it should be moved.
+            """
+            cdef hid_t remote_id
+            if remote is None:
+                remote_id = self.id
+            else:
+                remote_id = remote.id
+
+            H5Gmove2(self.id, current_name, remote_id, new_name)
+
+    # COMPAT: 1.8 deprecation
+    IF H5PY_16API:
+        def get_num_objs(self):
+            """ () => INT number_of_objects
+
+                Get the number of objects directly attached to a given group.
+            """
+            cdef hsize_t size
+            H5Gget_num_objs(self.id, &size)
+            return size
+
+    # COMPAT: 1.8 deprecation
+    IF H5PY_16API:
+        def get_objname_by_idx(self, hsize_t idx):
+            """ (INT idx) => STRING object_name
+
+                Get the name of a group member given its zero-based index.
+
+                Due to a limitation of the HDF5 library, the generic exception
+                H5Error (errno 1) is raised if the idx parameter is out-of-range.
+            """
+            cdef int size
+            cdef char* buf
+            buf = NULL
+
+            # This function does not properly raise an exception
+            size = H5Gget_objname_by_idx(self.id, idx, NULL, 0)
+            if size < 0:
+                raise H5Error((1,"Invalid argument"))
+
+            buf = <char*>emalloc(sizeof(char)*(size+1))
+            try:
+                H5Gget_objname_by_idx(self.id, idx, buf, size+1)
+                pystring = buf
+                return pystring
+            finally:
+                efree(buf)
+
+    # COMPAT: 1.8 deprecation
+    IF H5PY_16API:
+        def get_objtype_by_idx(self, hsize_t idx):
+            """ (INT idx) => INT object_type_code
+
+                Get the type of an object attached to a group, given its zero-based
+                index.  Possible return values are:
+                    - LINK
+                    - GROUP
+                    - DATASET
+                    - DATATYPE
+
+                Due to a limitation of the HDF5 library, the generic exception
+                H5Error (errno 1) is raised if the idx parameter is out-of-range.
+            """
+            # This function does not properly raise an exception
+            cdef herr_t retval
+            retval = H5Gget_objtype_by_idx(self.id, idx)
+            if retval < 0:
+                raise H5Error((1,"Invalid argument."))
+            return retval
+
+    # COMPAT: 1.8 deprecation
+    IF H5PY_16API:
+        def get_linkval(self, char* name):
+            """ (STRING name) => STRING link_value
+
+                Retrieve the value (target name) of a symbolic link.
+                Limited to 2048 characters on Windows.
+            """
+            cdef char* value
+            cdef H5G_stat_t statbuf
+            value = NULL
+
+            H5Gget_objinfo(self.id, name, 0, &statbuf)
+
+            if statbuf.type != H5G_LINK:
+                raise ValueError('"%s" is not a symbolic link.' % name)
+
+            IF UNAME_SYSNAME == "Windows":
+                linklen = 2049  # Windows statbuf.linklen seems broken
+            ELSE:
+                linklen = statbuf.linklen+1
+            value = <char*>emalloc(sizeof(char)*linklen)
+            try:
+                H5Gget_linkval(self.id, name, linklen, value)
+                value[linklen-1] = c'\0'  # in case HDF5 doesn't null terminate on Windows
+                pyvalue = value
+                return pyvalue
+            finally:
+                efree(value)
+
+    # COMPAT: 1.8 deprecation
+    IF H5PY_16API:
+        def set_comment(self, char* name, char* comment):
+            """ (STRING name, STRING comment)
+
+                Set the comment on a group member.
+            """
+            H5Gset_comment(self.id, name, comment)
+
+    # COMPAT: 1.8 deprecation
+    IF H5PY_16API:
+        def get_comment(self, char* name):
+            """ (STRING name) => STRING comment
+
+                Retrieve the comment for a group member.
+            """
+            cdef int cmnt_len
+            cdef char* cmnt
+            cmnt = NULL
+
+            cmnt_len = H5Gget_comment(self.id, name, 0, NULL)
+            assert cmnt_len >= 0
+
+            cmnt = <char*>emalloc(sizeof(char)*(cmnt_len+1))
+            try:
+                H5Gget_comment(self.id, name, cmnt_len+1, cmnt)
+                py_cmnt = cmnt
+                return py_cmnt
+            finally:
+                efree(cmnt)
 
     # === Special methods =====================================================
 
@@ -400,7 +445,7 @@ cdef class GroupID(ObjectID):
             Determine if a group member of the given name is present
         """
         try:
-            info = get_objinfo(self,name)
+            H5Gget_objinfo(self.id, name, 1, NULL)
             return True
         except H5Error:
             return False    
@@ -411,14 +456,19 @@ cdef class GroupID(ObjectID):
 
     def __len__(self):
         """ Number of group members """
-        return self.get_num_objs()
+        cdef hsize_t size
+        H5Gget_num_objs(self.id, &size)
+        return size
 
     def __richcmp__(self, object other, int how):
         return standard_richcmp(self, other, how)
 
     def __hash__(self):
         if self._hash is None:
-            info = get_objinfo(self)
-            self._hash = hash( (info.fileno, info.objno) )
+            IF H5PY_16API:
+                info = get_objinfo(self)
+                self._hash = hash( (info.fileno, info.objno) )
+            ELSE:
+                self._hash = self.id
         return self._hash
 
diff --git a/h5py/h5p.pyx b/h5py/h5p.pyx
index 489ee72..3cfc98e 100644
--- a/h5py/h5p.pyx
+++ b/h5py/h5p.pyx
@@ -625,7 +625,7 @@ cdef class PropFAID(PropInstanceID):
         """
         cdef hid_t plist_id
         plist_id = pdefault(memb_fapl)
-        H5Pset_fapl(self.id, memb_size, plist_id)
+        H5Pset_fapl_family(self.id, memb_size, plist_id)
 
     def get_fapl_family(self):
         """ () => TUPLE info
diff --git a/h5py/h5s.pxd b/h5py/h5s.pxd
index d4f4bab..0c2864d 100644
--- a/h5py/h5s.pxd
+++ b/h5py/h5s.pxd
@@ -18,6 +18,7 @@
 # license is available in the file licenses/hdf5.txt in the distribution
 # root directory.
 
+include "config.pxi"
 include "std_defs.pxi"
 from h5 cimport class ObjectID
 from numpy cimport ndarray
@@ -102,7 +103,9 @@ cdef extern from "hdf5.h":
                              hsize_t start[], hsize_t _stride[],
                              hsize_t count[], hsize_t _block[]) except *
 
-
+  IF H5PY_18API:
+    herr_t  H5Sencode(hid_t obj_id, void *buf, size_t *nalloc)
+    hid_t   H5Sdecode(void *buf)
 
 
 
diff --git a/h5py/h5s.pyx b/h5py/h5s.pyx
index f440f9e..600af26 100644
--- a/h5py/h5s.pyx
+++ b/h5py/h5s.pyx
@@ -13,10 +13,12 @@
 """
     Low-level interface to the "H5S" family of data-space functions.
 """
+include "std_code.pxi"
 
 # Pyrex compile-time imports
 from utils cimport  require_tuple, require_list, convert_dims, convert_tuple, \
                     emalloc, efree, pybool, create_numpy_hsize, create_hsize_array
+from python cimport PyString_FromStringAndSize
 
 # Runtime imports
 import h5
@@ -67,6 +69,7 @@ def create(int class_code):
     """
     return SpaceID(H5Screate(<H5S_class_t>class_code))
 
+ at sync
 def create_simple(object dims_tpl, object max_dims_tpl=None):
     """ (TUPLE dims_tpl, TUPLE max_dims_tpl) => INT new_space_id
 
@@ -101,6 +104,17 @@ def create_simple(object dims_tpl, object max_dims_tpl=None):
         efree(dims)
         efree(max_dims)
 
+IF H5PY_18API:
+    def decode(buf):
+        """ (STRING buf) => SpaceID
+
+            Unserialize a dataspace.  Bear in mind you can also use the native
+            Python pickling machinery to do this.
+        """
+        cdef char* buf_
+        buf_ = buf
+        return SpaceID(H5Sdecode(buf_))
+
 # === H5S class API ===========================================================
 
 cdef class SpaceID(ObjectID):
@@ -134,6 +148,39 @@ cdef class SpaceID(ObjectID):
         """
         return SpaceID(H5Scopy(self.id))
 
+    IF H5PY_18API:
+        def encode(self):
+            """ () => STRING
+
+                Serialize a dataspace, including its selection.  Bear in mind you
+                can also use the native Python pickling machinery to do this.
+            """
+            cdef void* buf
+            cdef size_t nalloc
+            buf = NULL
+            nalloc = 0
+
+            H5Sencode(self.id, NULL, &nalloc)
+            buf = emalloc(nalloc)
+            try:
+                H5Sencode(self.id, buf, &nalloc)
+                pystr = PyString_FromStringAndSize(<char*>buf, nalloc)
+            finally:
+                efree(buf)
+
+            return pystr
+
+    IF H5PY_18API:
+        # Enable pickling
+
+        def __reduce__(self):
+            return (type(self), (-1,), self.encode())
+
+        def __setstate__(self, state):
+            cdef char* buf
+            buf = state
+            self.id = H5Sdecode(buf)
+
     # === Simple dataspaces ===================================================
 
     def is_simple(self):
@@ -158,7 +205,7 @@ cdef class SpaceID(ObjectID):
 
         try:
             if not H5Sis_simple(self.id):
-                raise ValueError("%d is not a simple dataspace" % space_id)
+                raise ValueError("%d is not a simple dataspace" % self.id)
 
             rank = H5Sget_simple_extent_ndims(self.id)
             
diff --git a/h5py/h5t.pxd b/h5py/h5t.pxd
index dfeab53..b63aee4 100644
--- a/h5py/h5t.pxd
+++ b/h5py/h5t.pxd
@@ -14,6 +14,7 @@
 # license is available at licenses/pytables.txt, in the distribution root
 # directory.
 
+include "config.pxi"
 include "std_defs.pxi"
 from h5 cimport class ObjectID
 
@@ -302,9 +303,9 @@ cdef extern from "hdf5.h":
   herr_t    H5Tset_tag(hid_t type_id, char* tag) except *
   char*     H5Tget_tag(hid_t type_id) except? NULL
 
-
-
-
+  IF H5PY_18API:
+    hid_t H5Tdecode(unsigned char *buf) except *
+    herr_t H5Tencode(hid_t obj_id, unsigned char *buf, size_t *nalloc) except *
 
 
 
diff --git a/h5py/h5t.pyx b/h5py/h5t.pyx
index 06a2f3e..9ba53fa 100644
--- a/h5py/h5t.pyx
+++ b/h5py/h5t.pyx
@@ -53,14 +53,16 @@
 
         VLEN types can be manipulated, but reading and writing data in VLEN
         format is not supported.  This applies to VLEN strings as well.
+
+    5. Datatypes can be pickled if HDF5 1.8.X is available.
 """
 
-include "conditions.pxi"
+include "config.pxi"
 
 # Pyrex compile-time imports
-from defs_c cimport free
 from h5 cimport err_c, pause_errors, resume_errors
 from numpy cimport dtype, ndarray
+from python cimport PyString_FromStringAndSize
 
 from utils cimport  emalloc, efree, pybool, \
                     create_ieee_complex64, create_ieee_complex128, \
@@ -299,6 +301,17 @@ def vlen_create(TypeID base not None):
     """
     return typewrap(H5Tvlen_create(base.id))
 
+IF H5PY_18API:
+    def decode(buf):
+        """ (STRING buf) => TypeID
+
+            Unserialize an HDF5 type.  Bear in mind that you can also use the
+            Python pickle/unpickle machinery to do this.
+        """
+        cdef char* buf_
+        buf_ = buf
+        return typewrap(H5Tdecode(<unsigned char*>buf_))
+
 # === Base type class =========================================================
 
 cdef class TypeID(ObjectID):
@@ -310,7 +323,6 @@ cdef class TypeID(ObjectID):
     def __copy__(self):
         cdef TypeID cpy
         cpy = ObjectID.__copy__(self)
-        assert typecheck(cpy, TypeID), "TypeID copy encounted invalid type"
         return cpy
 
     property dtype:
@@ -413,6 +425,40 @@ cdef class TypeID(ObjectID):
         if not self._locked:
             H5Tclose(self.id)
 
+    IF H5PY_18API:
+        def encode(self):
+            """ () => STRING
+
+                Serialize an HDF5 type.  Bear in mind you can also use the
+                native Python pickle/unpickle machinery to do this.  The
+                returned string may contain binary values, including NULLs.
+            """
+            cdef size_t nalloc
+            cdef char* buf
+            buf = NULL
+            nalloc = 0
+
+            H5Tencode(self.id, NULL, &nalloc)
+            buf = <char*>emalloc(sizeof(char)*nalloc)
+            try:
+                H5Tencode(self.id, <unsigned char*>buf, &nalloc)
+                pystr = PyString_FromStringAndSize(buf, nalloc)
+            finally:
+                efree(buf)
+
+            return pystr
+
+    IF H5PY_18API:
+        # Enable pickling
+
+        def __reduce__(self):
+            return (type(self), (-1,), self.encode())
+
+        def __setstate__(self, state):
+            cdef char* buf
+            buf = state
+            self.id = H5Tdecode(<unsigned char*>buf)
+
 # === Top-level classes (inherit directly from TypeID) ========================
 
 cdef class TypeArrayID(TypeID):
diff --git a/h5py/std_code.pxi b/h5py/std_code.pxi
new file mode 100644
index 0000000..9f794e9
--- /dev/null
+++ b/h5py/std_code.pxi
@@ -0,0 +1,33 @@
+#+
+# 
+# This file is part of h5py, a low-level Python interface to the HDF5 library.
+# 
+# Copyright (C) 2008 Andrew Collette
+# http://h5py.alfven.org
+# License: BSD  (See LICENSE.txt for full license)
+# 
+# $Date$
+# 
+#-
+
+# Common, stateless code safe for inclusion in each .pyx file.  Also brings
+# in config.pxi.
+
+include "config.pxi"
+
+# Set up synchronization decorator for threads
+IF H5PY_THREADS:
+    from _extras import h5sync
+    IF H5PY_DEBUG:
+        import logging
+        sync = h5sync(logging.getLogger('h5py.functions'))
+    ELSE:
+        sync = h5sync()
+ELSE:
+    IF H5PY_DEBUG:
+        import logging
+        from _extras import h5sync_dummy
+        sync = h5sync_dummy(logging.getLogger('h5py.functions'))
+    ELSE:
+        cdef inline object sync(object func):
+            return func
diff --git a/h5py/std_defs.pxi b/h5py/std_defs.pxi
index ac4dc91..7805324 100644
--- a/h5py/std_defs.pxi
+++ b/h5py/std_defs.pxi
@@ -10,15 +10,32 @@
 # 
 #-
 
-# "Boilerplate" includes which are so common I don't want to repeat them
-# in every file.  These include all basic HDF5 and C typedefs.
-# This file is designed to be included in *.pxd files; only definitions
-# are allowed.
+# "Boilerplate" definitions which are used in every .pxd file.  Also includes
+# the dynamically-generated config.pxi interface file.  A companion file
+# "std_code.pxi" goes in every .pyx file.
 
-from h5 cimport hid_t, hbool_t, herr_t, htri_t, hsize_t, \
-                hssize_t, haddr_t, hvl_t
+include "config.pxi"
 
-from defs_c cimport size_t, time_t, ssize_t
+# === Standard C functions and definitions ===
+
+cdef extern from "stdlib.h":
+  ctypedef long size_t
+  void *malloc(size_t size)
+  void free(void *ptr)
+
+cdef extern from "string.h":
+  char *strchr(char *s, int c)
+  char *strcpy(char *dest, char *src)
+  char *strncpy(char *dest, char *src, size_t n)
+  int strcmp(char *s1, char *s2)
+  char *strdup(char *s)
+  void *memcpy(void *dest, void *src, size_t n)
+
+cdef extern from "time.h":
+  ctypedef int time_t
+
+cdef extern from "unistd.h":
+  ctypedef long ssize_t
 
 cdef extern from "stdint.h":
   ctypedef signed char int8_t
@@ -29,3 +46,29 @@ cdef extern from "stdint.h":
   ctypedef unsigned long int uint32_t
   ctypedef signed long long int int64_t
   ctypedef signed long long int uint64_t 
+
+# === HDF5 types ===
+
+cdef extern from "hdf5.h":
+
+  ctypedef int hid_t  # In H5Ipublic.h
+  ctypedef int hbool_t
+  ctypedef int herr_t
+  ctypedef int htri_t
+  # hsize_t should be unsigned, but Windows platform does not support
+  # such an unsigned long long type.
+  ctypedef long long hsize_t
+  ctypedef signed long long hssize_t
+  ctypedef signed long long haddr_t  # I suppose this must be signed as well...
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/h5py/tests/test_h5g.py b/h5py/tests/test_h5g.py
index 2ca4ad6..77ceea5 100644
--- a/h5py/tests/test_h5g.py
+++ b/h5py/tests/test_h5g.py
@@ -39,8 +39,9 @@ class TestH5G(TestBase):
         for name in TEST_GROUPS:
             grp = h5g.open(self.obj, name)
             self.assert_(self.is_grp(grp))
+            pr = str(grp)
             grp._close()
-            self.assert_(not self.is_grp(grp))
+            self.assert_(not self.is_grp(grp), pr+"::"+str(grp))
         
         self.assertRaises(H5Error, h5g.open, self.obj, 'Some other group')
 
diff --git a/h5py/tests/test_threads.py b/h5py/tests/test_threads.py
index 14f5eb1..593cb77 100644
--- a/h5py/tests/test_threads.py
+++ b/h5py/tests/test_threads.py
@@ -178,7 +178,7 @@ class TestThreads(unittest.TestCase):
         if write_time < DELAY:
             raise Exception("Write was too fast to test blocking (%f sec; need %f)" % (write_time, DELAY))
 
-        if h5py.config.compile_opts['IO_NONBLOCK']:
+        if h5py.config.THREADS:
             self.assert_(thread_b.time < thread_a.timestop, "%f !< %f" % (thread_b.time, thread_a.timestop))
         else:
             self.assert_(thread_b.time > thread_a.timestop, "%f !> %f" % (thread_b.time, thread_a.timestop))
@@ -199,7 +199,7 @@ class TestThreads(unittest.TestCase):
             time.sleep(2)
         writethread.join()
 
-        if h5py.config.compile_opts['IO_NONBLOCK']:
+        if h5py.config.THREADS:
             # With non-blocking I/O, the library will double-check that the
             # global lock isn't held, to prevent more than one thread from
             # calling into the HDF5 API.
diff --git a/setup.py b/setup.py
index cc2e7c6..2847481 100644
--- a/setup.py
+++ b/setup.py
@@ -71,8 +71,8 @@ opts.PYREX_ONLY = False          # Flag: Run Pyrex, but don't perform build
 opts.PYREX_FORCE = False         # Flag: Disable Pyrex timestamp checking
 opts.PYREX_FORCE_OFF = False     # Flag: Don't run Pyrex, no matter what
 
-opts.API_MAJ = 1                 # API interface version (not library version)
-opts.API_MIN = 6
+opts.API_16 = True               # Include 1.6.X-specific functions
+opts.API_18 = False              # Include new 1.8.X functions
 opts.DEBUG_LEVEL = 0             # Logging-module number, 0 to turn off
 opts.HDF5_DIR = None             # Custom HDF5 directory, or None
 opts.IO_NONBLOCK = False         # Experimental non-blocking I/O
@@ -95,15 +95,13 @@ for arg in sys.argv[:]:
     elif arg.find('--api=') == 0:
         opts.ENABLE_PYREX=True
         api = arg[6:]
-        if api == '16':
-            opts.API_MAJ = 1
-            opts.API_MIN = 6
-        elif api == '18':
-            opts.API_MAJ = 1
-            opts.API_MIN = 8
-            warn('1.8.X API is still under development')
-        else:
-            fatal('Unrecognized API version "%s" (only "16", "18" currently allowed)' % api)
+        api = api.split(',')
+        if not all(x in ("16","18") for x in api):
+            fatal('Illegal option to --api (legal values are "16" and "18")')
+        if not ("16" in api or "18" in api):
+            fatal("At least one of 1.6 or 1.8 compatibility must be specified.")
+        opts.API_16 = "16" in api
+        opts.API_18 = "18" in api
         sys.argv.remove(arg)
     elif arg.find('--debug=') == 0:
         opts.ENABLE_PYREX=True
@@ -123,6 +121,9 @@ for arg in sys.argv[:]:
         opts.IO_NONBLOCK = True
         sys.argv.remove(arg)
 
+opts.API_MAJ = 1
+opts.API_MIN = 8 if opts.API_18 else 6
+
 if 'sdist' in sys.argv:
     if os.path.exists('MANIFEST'):
         warn("Cleaning up stale MANIFEST file")
@@ -218,8 +219,8 @@ DEF H5PY_API_MAJ = %(API_MAJ)d
 DEF H5PY_API_MIN = %(API_MIN)d
 DEF H5PY_DEBUG = %(DEBUG_LEVEL)d
 
-DEF H5PY_16API = H5PY_API_MIN == 6
-DEF H5PY_18API = H5PY_API_MIN == 8
+DEF H5PY_16API = %(API_16)d
+DEF H5PY_18API = %(API_18)d
 
 DEF H5PY_NONBLOCK = %(IO_NONBLOCK)d
 """ \
@@ -235,6 +236,7 @@ DEF H5PY_NONBLOCK = %(IO_NONBLOCK)d
             # is useless.  So only replace it if it's out of date.
             if cond_present != cond:
                 print "Replacing conditions file..."
+                print cond
                 cond_file = open(cond_path,'w')
                 cond_file.write(cond)
                 cond_file.close()
diff --git a/setup.py b/setup_cython.py
similarity index 54%
copy from setup.py
copy to setup_cython.py
index cc2e7c6..52b93f9 100644
--- a/setup.py
+++ b/setup_cython.py
@@ -15,7 +15,7 @@
 """
     Setup script for the h5py package.  
 
-    All commands take the usual distutils options, like --home, etc.  Pyrex is
+    All commands take the usual distutils options, like --home, etc.  Cython is
     not required for installation, but will be invoked if the .c files are
     missing, one of the --pyrex options is used, or if a non-default API 
     version or debug level is requested.
@@ -32,24 +32,65 @@
     See INSTALL.txt or the h5py manual for additional build options.
 """
 
-# === Global constants ========================================================
-
-NAME = 'h5py'
-VERSION = '0.3.1'
-
-MIN_PYREX = '0.9.8.4'  # for compile_multiple
-MIN_NUMPY = '1.0.3'
-
-# === Initial imports and utilities ===========================================
+import os
+import sys
+import shutil
+import os.path as op
 
 from distutils.cmd import Command
 from distutils.errors import DistutilsError, DistutilsExecError
 from distutils.core import setup
 from distutils.extension import Extension
-import os
-import sys
-import shutil
-import os.path as op
+
+class CmdOptions(object):
+
+    """ Manages package and compiler options. """
+
+    def __init__(self):
+
+        # Basic package options
+        self.NAME = 'h5py'
+        self.VERSION = '0.3.1'
+        self.MIN_NUMPY = '1.0.3'
+        self.MIN_CYTHON = '0.9.8.1'
+        self.KNOWN_API = (16,18)    # Legal API levels (1.8.X or 1.6.X)
+        self.SRC_PATH = 'h5py'      # Name of directory with .pyx files
+        self.CMD_CLASS = {}         # Custom command classes for setup()
+
+        # Compilation flags
+        self.CYTHON = False # Run Cython.  Default is OFF for distribution.
+        self.API = (16,)    # API levels to include.  Default is 1.6.X only.
+        self.DEBUG = 0      # Compile-time debug level.  Default is OFF.
+        self.HDF5 = None    # Custom HDF5 directory.
+
+        # Feature flags
+        self.THREADS = False    # Thread-aware (safety & non-blocking IO)
+
+    def get_pxi(self):
+        """ Return a string with compile-time defines. """
+
+        pxi_str = \
+"""# This file is automatically generated.  Do not edit.
+
+DEF H5PY_VERSION = "%(VERSION)s"
+
+DEF H5PY_API = %(API_MAX)d     # Highest API level (i.e. 18 or 16)
+DEF H5PY_16API = %(API_16)d    # 1.6.X API available
+DEF H5PY_18API = %(API_18)d    # 1.8.X API available
+
+DEF H5PY_DEBUG = %(DEBUG)d    # Logging-level number, or 0 to disable
+
+DEF H5PY_THREADS = %(THREADS)d  # Enable thread-safety and non-blocking reads
+
+"""
+        opts = dict(self.__dict__)
+        opts.update({   "API_MAX": max(self.API),
+                        "API_16": 16 in self.API,
+                        "API_18": 18 in self.API})
+        return pxi_str % opts
+
+        
+opts = CmdOptions()     # Global to hold compilation options
 
 def fatal(instring, code=1):
     print >> sys.stderr, "Fatal: "+instring
@@ -58,133 +99,151 @@ def fatal(instring, code=1):
 def warn(instring):
     print >> sys.stderr, "Warning: "+instring
 
-# === Parse command line arguments ============================================
+# === Required imports ========================================================
 
-class CmdOptions(object):
-    pass
-opts = CmdOptions()
-
-opts.AUTO_HDR = "# This file is automatically generated.  Do not edit."
-opts.VERSION = VERSION
-opts.ENABLE_PYREX = False        # Flag: Pyrex must be run
-opts.PYREX_ONLY = False          # Flag: Run Pyrex, but don't perform build
-opts.PYREX_FORCE = False         # Flag: Disable Pyrex timestamp checking
-opts.PYREX_FORCE_OFF = False     # Flag: Don't run Pyrex, no matter what
-
-opts.API_MAJ = 1                 # API interface version (not library version)
-opts.API_MIN = 6
-opts.DEBUG_LEVEL = 0             # Logging-module number, 0 to turn off
-opts.HDF5_DIR = None             # Custom HDF5 directory, or None
-opts.IO_NONBLOCK = False         # Experimental non-blocking I/O
+# Check Python version (2.5 or greater required)
+if not (sys.version_info[0:2] >= (2,5)):
+    fatal("At least Python 2.5 is required to install h5py")
+
+# Check for Numpy (required)
+try:
+    import numpy
+    if numpy.version.version < opts.MIN_NUMPY:
+        fatal("Numpy version %s is out of date (>= %s needed)" % (numpy.version.version, opts.MIN_NUMPY))
+
+except ImportError:
+    fatal("Numpy not installed (version >= %s required)" % opts.MIN_NUMPY)
+
+# === Parse command line arguments ============================================
 
 for arg in sys.argv[:]:
-    if arg == '--pyrex':
-        opts.ENABLE_PYREX = True
-        sys.argv.remove(arg)
-    elif arg == '--pyrex-only':
-        opts.ENABLE_PYREX = True
-        opts.PYREX_ONLY = True
-        sys.argv.remove(arg)
-    elif arg == '--pyrex-force':
-        opts.ENABLE_PYREX=True
-        opts.PYREX_FORCE = True
-        sys.argv.remove(arg)
-    elif arg == '--no-pyrex':
-        opts.PYREX_FORCE_OFF = True
+
+    if arg == '--cython':
+        opts.CYTHON = True
         sys.argv.remove(arg)
+
     elif arg.find('--api=') == 0:
-        opts.ENABLE_PYREX=True
-        api = arg[6:]
-        if api == '16':
-            opts.API_MAJ = 1
-            opts.API_MIN = 6
-        elif api == '18':
-            opts.API_MAJ = 1
-            opts.API_MIN = 8
-            warn('1.8.X API is still under development')
-        else:
-            fatal('Unrecognized API version "%s" (only "16", "18" currently allowed)' % api)
+        try:
+            api = arg[6:]
+            api = tuple(int(x) for x in api.split(',') if len(x) > 0)
+            if len(api) == 0 or not all(x in opts.KNOWN_API for x in api):
+                raise Exception
+        except Exception:
+            fatal('Illegal option to --api= (legal values are %s)' % ','.join(str(x) for x in opts.KNOWN_API))
+        opts.API = api
+        opts.CYTHON = True
         sys.argv.remove(arg)
+
     elif arg.find('--debug=') == 0:
-        opts.ENABLE_PYREX=True
         try:
-            opts.DEBUG_LEVEL = int(arg[8:])
+            opts.DEBUG = int(arg[8:])
         except:
             fatal('Debuglevel not understood (wants --debug=<n>)')
+        opts.CYTHON = True
         sys.argv.remove(arg)
+
     elif arg.find('--hdf5=') == 0:
         splitarg = arg.split('=',1)
         if len(splitarg) != 2:
             fatal("HDF5 directory not understood (wants --hdf5=/path/to/hdf5)")
-        opts.HDF5_DIR = op.abspath(splitarg[1])
+        path = op.abspath(splitarg[1])
+        if not op.exists(path):
+            fatal("HDF5 path is illegal: %s" % path)
+        opts.HDF5 = path
+        opts.CYTHON = True
         sys.argv.remove(arg)
-    elif arg.find('--io-nonblock') == 0:
-        opts.ENABLE_PYREX=True
-        opts.IO_NONBLOCK = True
+
+    elif arg.find('--threads') == 0:
+        opts.THREADS = True
+        opts.CYTHON = True
         sys.argv.remove(arg)
 
+# Check if the config.pxi file needs to be updated for the given
+# command-line options.
+pxi_path = op.join(opts.SRC_PATH, 'config.pxi')
+pxi = opts.get_pxi()
+if not op.exists(pxi_path):
+    try:
+        f = open(pxi_path, 'w')
+        f.write(pxi)
+        f.close()
+    except IOError:
+        fatal('Failed write to "%s"' % pxi_path)
+    opts.CYTHON = True
+    if not "--force" in sys.argv: sys.argv.append("--force")  # Cython ignores .pxi change
+else:
+    try:
+        f = open(pxi_path, 'r+')
+    except IOError:
+        fatal("Can't read file %s" % pxi_path)
+    if f.read() != pxi:
+        f.close()
+        f = open(pxi_path, 'w')
+        f.write(pxi)
+        opts.CYTHON = True
+        if not "--force" in sys.argv: sys.argv.append("--force")  # Cython ignores .pxi change
+    f.close()
+
 if 'sdist' in sys.argv:
     if os.path.exists('MANIFEST'):
         warn("Cleaning up stale MANIFEST file")
         os.remove('MANIFEST')
     shutil.copyfile(reduce(op.join, ('docs', 'source', 'build.rst')), 'INSTALL.txt')
-
-# === Required imports ========================================================
-
-# Check Python version (2.5 or greater required)
-if not (sys.version_info[0] == 2 and sys.version_info[1] >= 5):
-    fatal("At least Python 2.5 is required to install h5py")
-
-# Check for Numpy (required)
-try:
-    import numpy
-    if numpy.version.version < MIN_NUMPY:
-        fatal("Numpy version %s is out of date (>= %s needed)" % (numpy.version.version, MIN_NUMPY))
-
-except ImportError:
-    fatal("Numpy not installed (version >= %s required)" % MIN_NUMPY)
         
-# === Platform configuration & Pyrex check ====================================
+# === Platform configuration & Cython check ====================================
 
-# Pyrex modules (without extension)
+# Cython modules (without extension)
 modules = ['h5' , 'h5f', 'h5g', 'h5s', 'h5t', 'h5d',
-           'h5a', 'h5p', 'h5z', 'h5i', 'h5r', 'h5fd', 'utils']
+                'h5a', 'h5p', 'h5z', 'h5i', 'h5r', 'h5fd', 'utils']
 
-if (opts.API_MAJ, opts.API_MIN) >= (1,8):
+# Only enable H5O and H5L interface if we're building against 1.8.X
+if 18 in opts.API:
     modules += ['h5o','h5l']
 
-# C source files required for Pyrex code (with extension)
+# C source files required for Cython code (with extension)
 extra_src = ['utils_low.c']    
 
-# Where these live, relative to setup.py
-src_path = 'h5py'
+
+if opts.CYTHON:
+    try:
+        from Cython.Compiler.Main import Version
+        from Cython.Distutils import build_ext
+    except ImportError:
+        fatal("Cython recompilation required, but Cython not installed.")
+
+    if Version.version < opts.MIN_CYTHON:
+        fatal("Old Cython version detected; at least %s required" % opts.MIN_CYTHON)
+
+    # This is what enables Cython.  Explicit calls to compile() don't work yet,
+    # which is really annoying and breaks a lot of the options behavior.
+    opts.CMD_CLASS.update({'build_ext': build_ext})
+
 
 # Platform-dependent arguments to setup() or Extension()
 if os.name == 'nt':
-
-    if opts.HDF5_DIR is None:
+    if opts.HDF5 is None:
         fatal("On Windows, HDF5 directory must be specified.")
 
     libraries = ['hdf5dll']
-    include_dirs = [numpy.get_include(), op.join(opts.HDF5_DIR, 'include')]
-    library_dirs = [op.join(opts.HDF5_DIR, 'dll2')]  # Must contain only "hdf5dll.dll.a"
+    include_dirs = [numpy.get_include(), op.join(opts.HDF5, 'include')]
+    library_dirs = [op.join(opts.HDF5, 'dll2')]  # Must contain only "hdf5dll.dll.a"
     runtime_dirs = []
     extra_compile_args = ['-DH5_USE_16_API', '-D_HDF5USEDLL_', '-DH5_SIZEOF_SSIZE_T=4']
     extra_link_args = []
     package_data = {'h5py': ['*.pyx', '*.dll', 
-                                'Microsoft.VC90.CRT/*.manifest',
-                                'Microsoft.VC90.CRT/*.dll'],
-                   'h5py.tests': ['data/*.hdf5']}
+                                    'Microsoft.VC90.CRT/*.manifest',
+                                    'Microsoft.VC90.CRT/*.dll'],
+                       'h5py.tests': ['data/*.hdf5']}
 
-else:
+else:   # Assume Unix-like
 
     libraries = ['hdf5']
-    if opts.HDF5_DIR is None:
+    if opts.HDF5 is None:
         include_dirs = [numpy.get_include(), '/usr/include', '/usr/local/include']
         library_dirs = ['/usr/lib/', '/usr/local/lib']
     else:
-        include_dirs = [numpy.get_include(), op.join(opts.HDF5_DIR, 'include')]
-        library_dirs = [op.join(opts.HDF5_DIR, 'lib')]
+        include_dirs = [numpy.get_include(), op.join(opts.HDF5, 'include')]
+        library_dirs = [op.join(opts.HDF5, 'lib')]
     runtime_dirs = library_dirs
     extra_compile_args = ['-DH5_USE_16_API', '-Wno-unused', '-Wno-uninitialized']
     extra_link_args = []
@@ -192,92 +251,29 @@ else:
     package_data = {'h5py': ['*.pyx'],
                    'h5py.tests': ['data/*.hdf5']}
 
-# If for some reason the .c files are missing, Pyrex is required.
-cfiles = [op.join(src_path, x+'.c') for x in modules]
-
-if not all( [op.exists(x) for x in cfiles]):
-    opts.ENABLE_PYREX = True
-
-if opts.ENABLE_PYREX and not opts.PYREX_FORCE_OFF:
-    print "Running Pyrex..."
-
-    try:
-        from Pyrex.Compiler.Main import Version
-
-        if Version.version >= MIN_PYREX:
-            from Pyrex.Compiler.Main import compile_multiple, CompilationOptions
-
-            # Check if the conditions.pxi file is up-to-date
-            cond_path = op.join(src_path, 'conditions.pxi')
-            cond = \
-"""
-%(AUTO_HDR)s
+# Explicit list of source files for each module.
+mod_paths = [op.join(opts.SRC_PATH, x) for x in modules]
+extra_paths = [op.join(opts.SRC_PATH, x) for x in extra_src]
+if opts.CYTHON:
+    module_sources = [[x+'.pyx']+extra_paths for x in mod_paths]
+else:
+    module_sources = [[x+'.c']+extra_paths for x in mod_paths]
 
-DEF H5PY_VERSION = "%(VERSION)s"
-DEF H5PY_API_MAJ = %(API_MAJ)d
-DEF H5PY_API_MIN = %(API_MIN)d
-DEF H5PY_DEBUG = %(DEBUG_LEVEL)d
-
-DEF H5PY_16API = H5PY_API_MIN == 6
-DEF H5PY_18API = H5PY_API_MIN == 8
-
-DEF H5PY_NONBLOCK = %(IO_NONBLOCK)d
-""" \
-            % opts.__dict__
-            try:
-                cond_file = open(cond_path,'r')
-                cond_present = cond_file.read()
-                cond_file.close()
-            except IOError:
-                cond_present = ""
-
-            # If we regenerate the file every time, Pyrex's timestamp checking
-            # is useless.  So only replace it if it's out of date.
-            if cond_present != cond:
-                print "Replacing conditions file..."
-                cond_file = open(cond_path,'w')
-                cond_file.write(cond)
-                cond_file.close()
-
-            pyxopts = CompilationOptions(verbose=True, timestamps=(not opts.PYREX_FORCE))
-            results = compile_multiple( [op.join(src_path,x+'.pyx') for x in modules], pyxopts)
-
-            if results.num_errors != 0:
-                fatal("%d Pyrex compilation errors encountered; aborting." % results.num_errors)
-            if opts.PYREX_ONLY:
-                exit(0)
-        else:
-            fatal("Old Pyrex version %s detected (min %s)" % (Version.version, MIN_PYREX))
+extensions = [ Extension(opts.NAME+'.'+module,
+                        sources, 
+                        include_dirs = include_dirs, 
+                        libraries = libraries,
+                        library_dirs = library_dirs,
+                        runtime_library_dirs = runtime_dirs,
+                        extra_compile_args = extra_compile_args,
+                        extra_link_args = extra_link_args)
+                for module, sources in zip(modules, module_sources) ]
 
-    except ImportError:
-        fatal("Pyrex recompilation required, but Pyrex not installed.")
-else:
-    pass
-    #print "Skipping Pyrex..."
-
-# One extension is built for each module
-extensions = []
-for module in modules:
-    mod_sources  = [op.join(src_path, module) +'.c']
-    mod_sources += [op.join(src_path, x) for x in extra_src]
-
-    extensions.append(
-        Extension( 
-            NAME+'.'+module,
-            mod_sources, 
-            include_dirs = include_dirs, 
-            libraries = libraries,
-            library_dirs = library_dirs,
-            runtime_library_dirs = runtime_dirs,
-            extra_compile_args = extra_compile_args,
-            extra_link_args = extra_link_args
-        )
-    )
 
 # === Custom extensions for distutils =========================================
 
 class test(Command):
-    description = "Build %s and run unit tests" % NAME
+    description = "Build and run unit tests"
     user_options = [('sections=','s','Comma separated list of tests ("-" prefix to NOT run)')]
 
     def initialize_options(self):
@@ -302,7 +298,7 @@ class dev(Command):
 
     description = "Developer commands (--doc, --clean, --readme=<file>)"
     user_options = [('doc','d','Rebuild documentation'),
-                    ('clean', 'c', 'Remove built files and Pyrex temp files.')]
+                    ('clean', 'c', 'Remove built files and Cython temp files.')]
     boolean_options = ['doc']
 
     def initialize_options(self):
@@ -320,8 +316,8 @@ class dev(Command):
                     shutil.rmtree(x)
                 except OSError:
                     pass
-            fnames = [ op.join(src_path, x+'.dep') for x in modules ] + \
-                     [ op.join(src_path, x+'.c') for x in modules ] + \
+            fnames = [ op.join(opts.SRC_PATH, x+'.dep') for x in modules ] + \
+                     [ op.join(opts.SRC_PATH, x+'.c') for x in modules ] + \
                      [ 'MANIFEST']
 
             for name in fnames:
@@ -354,14 +350,9 @@ class dev(Command):
 
 # New commands for setup (e.g. "python setup.py test")
 if os.name == 'nt':
-    CMD_CLASS = {'test': test}
+    opts.CMD_CLASS.update({'test': test})
 else:
-    CMD_CLASS = {'dev': dev, 'test': test}
-
-#print "Configuration"
-#print '-'*40
-#for key in sorted(opts.__dict__):
-#    print "%-20s %s" % (key, opts.__dict__[key])
+    opts.CMD_CLASS.update({'dev': dev, 'test': test})
 
 
 cls_txt = \
@@ -395,8 +386,8 @@ reading and writing data from Python.
 """
 
 setup(
-  name = NAME,
-  version = VERSION,
+  name = opts.NAME,
+  version = opts.VERSION,
   description = short_desc,
   long_description = long_desc,
   classifiers = [x for x in cls_txt.split("\n") if x],
@@ -408,8 +399,8 @@ setup(
   packages = ['h5py','h5py.tests'],
   package_data = package_data,
   ext_modules = extensions,
-  requires = ['numpy (>=1.0.3)'],
-  cmdclass = CMD_CLASS
+  requires = ['numpy (>=%s)' % opts.MIN_NUMPY],
+  cmdclass = opts.CMD_CLASS
 )
 
 

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/h5py.git



More information about the debian-science-commits mailing list