[h5py] 122/455: Modify module h5 for PHIL, decorators
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 787e7800e1294e44caf5c1c4bf10c103b00e20c8
Author: andrewcollette <andrew.collette at gmail.com>
Date: Mon Sep 22 01:16:54 2008 +0000
Modify module h5 for PHIL, decorators
---
h5py/_extras.py | 10 +-
h5py/h5.pxd | 197 +++++----------------
h5py/h5.pyx | 243 ++++++++++++-------------
h5py/h5a.pyx | 18 +-
h5py/h5t.pyx | 7 +-
h5py/std_code.pxi | 36 ++--
setup.py | 520 ++++++++++++++++++++++++++++--------------------------
setup_cython.py | 430 --------------------------------------------
8 files changed, 477 insertions(+), 984 deletions(-)
diff --git a/h5py/_extras.py b/h5py/_extras.py
index c80abd1..1cbcc94 100644
--- a/h5py/_extras.py
+++ b/h5py/_extras.py
@@ -12,11 +12,11 @@
from __future__ import with_statement
import logging
-from h5py import config
-
-# Decorator utility for low-level thread safety
from functools import update_wrapper
+from h5py.h5 import get_phil
+phil = get_phil()
+
def uw_apply(wrap, func):
# Cython methods don't have a "module" attribute for some reason
if hasattr(func, '__module__'):
@@ -30,7 +30,7 @@ def h5sync(logger=None):
def sync_simple(func):
def wrap(*args, **kwds):
- with config.lock:
+ with phil:
return func(*args, **kwds)
uw_apply(wrap, func)
@@ -44,7 +44,7 @@ def h5sync(logger=None):
def wrap(*args, **kwds):
logger.debug("$ Threadsafe function entry: %s" % func.__name__)
- with config.lock:
+ with phil:
logger.debug("> Acquired lock on %s" % func.__name__)
retval = func(*args, **kwds)
logger.debug("< Released lock on %s" % func.__name__)
diff --git a/h5py/h5.pxd b/h5py/h5.pxd
index d2717fe..3a0571d 100644
--- a/h5py/h5.pxd
+++ b/h5py/h5.pxd
@@ -16,6 +16,43 @@
include "std_defs.pxi"
+# === Custom C extensions =====================================================
+
+cdef int _enable_exceptions() except -1
+cdef int _disable_exceptions() except -1
+
+cdef object standard_richcmp(object self, object other, int how)
+
+cdef class PHIL:
+
+ cdef object lock
+
+ cpdef int __enter__(self) except -1
+ cpdef int __exit__(self, a, b, c) except -1
+ cpdef int acquire(self) except -1
+ cpdef int release(self) except -1
+
+cpdef PHIL get_phil()
+
+cdef class H5PYConfig:
+
+ # Global
+ cdef object _complex_names # ('r','i')
+ 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 """
+ cdef object __weakref__
+ cdef readonly hid_t id
+ cdef readonly int _locked
+ cdef object _hash # Used by subclasses to cache a hash value,
+ # which may be expensive to compute.
+
+# === HDF5 API ================================================================
+
cdef extern from "hdf5.h":
ctypedef struct hvl_t:
@@ -27,11 +64,11 @@ cdef extern from "hdf5.h":
herr_t H5open() except *
herr_t H5close() except *
- # reflection
- ctypedef enum H5I_type_t:
- H5I_BADID = -1, # /*invalid Group */
# --- Reflection ------------------------------------------------------------
+ ctypedef enum H5I_type_t:
+ H5I_BADID = -1
+
H5I_type_t H5Iget_type(hid_t obj_id) except *
int H5Idec_ref(hid_t obj_id) except *
int H5Iget_ref(hid_t obj_id) except *
@@ -74,132 +111,8 @@ cdef extern from "hdf5.h":
H5E_ERROR, # Error API
H5E_SLIST # Skip Lists
- # Minor error numbers
ctypedef enum H5E_minor_t:
- H5E_NONE_MINOR = 0
-
- # Argument errors
- H5E_UNINITIALIZED, # information is unitialized
- H5E_UNSUPPORTED, # feature is unsupported
- H5E_BADTYPE, # incorrect type found
- H5E_BADRANGE, # argument out of range
- H5E_BADVALUE, # bad value for argument
-
- # Resource errors
- H5E_NOSPACE, # no space available for allocation
- H5E_CANTCOPY, # unable to copy object
- H5E_CANTFREE, # unable to free object
- H5E_ALREADYEXISTS, # Object already exists
- H5E_CANTLOCK, # Unable to lock object
- H5E_CANTUNLOCK, # Unable to unlock object
- H5E_CANTGC, # Unable to garbage collect
- H5E_CANTGETSIZE, # Unable to compute size
-
- # File accessability errors
- H5E_FILEEXISTS, # file already exists
- H5E_FILEOPEN, # file already open
- H5E_CANTCREATE, # Can't create file
- H5E_CANTOPENFILE, # Can't open file
- H5E_CANTCLOSEFILE, # Can't close file
- H5E_NOTHDF5, # not an HDF5 format file
- H5E_BADFILE, # bad file ID accessed
- H5E_TRUNCATED, # file has been truncated
- H5E_MOUNT, # file mount error
-
- # Generic low-level file I/O errors
- H5E_SEEKERROR, # seek failed
- H5E_READERROR, # read failed
- H5E_WRITEERROR, # write failed
- H5E_CLOSEERROR, # close failed
- H5E_OVERFLOW, # address overflowed
- H5E_FCNTL, # file fcntl failed
-
- # Function entry/exit interface errors
- H5E_CANTINIT, # Can't initialize object
- H5E_ALREADYINIT, # object already initialized
- H5E_CANTRELEASE, # Can't release object
-
- # Object atom related errors
- H5E_BADATOM, # Can't find atom information
- H5E_BADGROUP, # Can't find group information
- H5E_CANTREGISTER, # Can't register new atom
- H5E_CANTINC, # Can't increment reference count
- H5E_CANTDEC, # Can't decrement reference count
- H5E_NOIDS, # Out of IDs for group
-
- # Cache related errors
- H5E_CANTFLUSH, # Can't flush object from cache
- H5E_CANTSERIALIZE, # Unable to serialize data from cache
- H5E_CANTLOAD, # Can't load object into cache
- H5E_PROTECT, # protected object error
- H5E_NOTCACHED, # object not currently cached
- H5E_SYSTEM, # Internal error detected
- H5E_CANTINS, # Unable to insert metadata into cache
- H5E_CANTRENAME, # Unable to rename metadata
- H5E_CANTPROTECT, # Unable to protect metadata
- H5E_CANTUNPROTECT, # Unable to unprotect metadata
-
- # B-tree related errors
- H5E_NOTFOUND, # object not found
- H5E_EXISTS, # object already exists
- H5E_CANTENCODE, # Can't encode value
- H5E_CANTDECODE, # Can't decode value
- H5E_CANTSPLIT, # Can't split node
- H5E_CANTINSERT, # Can't insert object
- H5E_CANTLIST, # Can't list node
-
- # Object header related errors
- H5E_LINKCOUNT, # bad object header link count
- H5E_VERSION, # wrong version number
- H5E_ALIGNMENT, # alignment error
- H5E_BADMESG, # unrecognized message
- H5E_CANTDELETE, # Can't delete message
- H5E_BADITER, # Iteration failed
-
- # Group related errors
- H5E_CANTOPENOBJ, # Can't open object
- H5E_CANTCLOSEOBJ, # Can't close object
- H5E_COMPLEN, # name component is too long
- H5E_LINK, # link count failure
- H5E_SLINK, # symbolic link error
- H5E_PATH, # Problem with path to object
-
- # Datatype conversion errors
- H5E_CANTCONVERT, # Can't convert datatypes TypeError?
- H5E_BADSIZE, # Bad size for object
-
- # Dataspace errors
- H5E_CANTCLIP, # Can't clip hyperslab region
- H5E_CANTCOUNT, # Can't count elements
- H5E_CANTSELECT, # Can't select hyperslab
- H5E_CANTNEXT, # Can't move to next iterator location
- H5E_BADSELECT, # Invalid selection
- H5E_CANTCOMPARE, # Can't compare objects
-
- # Property list errors
- H5E_CANTGET, # Can't get value
- H5E_CANTSET, # Can't set value
- H5E_DUPCLASS, # Duplicate class name in parent class
-
- # Parallel errors
- H5E_MPI, # some MPI function failed
- H5E_MPIERRSTR, # MPI Error String
-
- # Heap errors
- H5E_CANTRESTORE, # Can't restore condition
-
- # TBBT errors
- H5E_CANTMAKETREE, # Can't create TBBT tree
-
- # I/O pipeline errors
- H5E_NOFILTER, # requested filter is not available
- H5E_CALLBACK, # callback failed
- H5E_CANAPPLY, # error from filter "can apply" callback
- H5E_SETLOCAL, # error from filter "set local" callback
- H5E_NOENCODER, # Filter present, but encoding disabled
-
- # System level errors
- H5E_SYSERRSTR # System error message
+ pass
cdef enum H5E_direction_t:
H5E_WALK_UPWARD = 0 # begin deep, end at API function
@@ -213,8 +126,6 @@ cdef extern from "hdf5.h":
unsigned line # line in file where error occurs
char *desc # optional supplied description
- # --- Error handling --------------------------------------------------------
-
char *H5Eget_major(H5E_major_t n)
char *H5Eget_minor(H5E_minor_t n)
herr_t H5Eclear() except *
@@ -228,33 +139,7 @@ cdef extern from "hdf5.h":
int H5Fget_obj_ids(hid_t file_id, unsigned int types, int max_objs, hid_t *obj_id_list) except *
int H5F_OBJ_ALL
-# === Custom C extensions =====================================================
-
-ctypedef H5E_auto_t err_c
-cdef int _enable_exceptions() except -1
-cdef int _disable_exceptions() except -1
-
-cdef err_c pause_errors() except? NULL
-cdef int resume_errors(err_c cookie) except -1
-
-cdef object standard_richcmp(object self, object other, int how)
-
-cdef class H5PYConfig:
- cdef object _complex_names # ('r','i')
- cdef object _lock # Primary HDF5 Interface Lock (PHIL)
- 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 """
- cdef object __weakref__
- cdef readonly hid_t id
- cdef readonly int _locked
- cdef object _hash # Used by subclasses to cache a hash value,
- # which may be expensive to compute.
diff --git a/h5py/h5.pyx b/h5py/h5.pyx
index 4ed3f29..8ef1678 100644
--- a/h5py/h5.pyx
+++ b/h5py/h5.pyx
@@ -35,7 +35,7 @@ from python cimport PyErr_SetObject
import atexit
import threading
-from weakref import WeakKeyDictionary
+# --- Module init -------------------------------------------------------------
# Logging is only enabled when compiled with H5PY_DEBUG nonzero
IF H5PY_DEBUG:
@@ -45,98 +45,80 @@ IF H5PY_DEBUG:
logger.addHandler(logging.StreamHandler())
log_ident = logging.getLogger('h5py.identifiers')
-def get_libversion():
- """ () => TUPLE (major, minor, release)
+# --- C extensions and classes ------------------------------------------------
- Retrieve the HDF5 library version as a 3-tuple.
- """
- cdef unsigned int major
- cdef unsigned int minor
- cdef unsigned int release
- cdef herr_t retval
-
- H5get_libversion(&major, &minor, &release)
+cdef object standard_richcmp(object self, object other, int how):
+ # This needs to be shared because of weird CPython quirks involving
+ # subclasses and the __hash__ method.
- return (major, minor, release)
+ if how == 2 or how == 3:
+
+ if not isinstance(self, ObjectID) and isinstance(other, ObjectID):
+ return NotImplemented
-def _close():
- """ Internal function; do not call unless you want to lose all your data.
- """
- H5close()
+ eq = (hash(self) == hash(other))
-def _open():
- """ Internal function; do not call unless you want to lose all your data.
- """
- H5open()
+ if how == 2:
+ return eq
+ return not eq
+
+ return NotImplemented
cdef class H5PYConfig:
"""
Global configuration object for the h5py package.
-
- Properties:
- lock Global reentrant lock for threading support
- compile_opts Dictionary of compile-time flags
"""
def __init__(self):
- global logger
- self._complex_names = ('r','i')
self.API_16 = H5PY_16API
self.API_18 = H5PY_18API
self.DEBUG = H5PY_DEBUG
self.THREADS = H5PY_THREADS
- self._lock = threading.RLock()
-
- property lock:
- """ Reentrant lock instance; default is threading.RLock().
-
- Whatever you provide MUST support the Python context manager
- protocol, and provide the methods acquire() and release(). It
- also MUST be reentrant, or dataset reads/writes will deadlock.
- """
- def __get__(self):
- return self._lock
-
- def __set__(self, val):
- if not (hasattr(val, 'acquire') and hasattr(val, 'release') and\
- hasattr(val, '__enter__') and hasattr(val, '__exit__')):
- raise ValueError("Generated locks must provide __enter__, __exit__, acquire, release")
- current_lock = self._lock
- current_lock.acquire()
- try:
- self._lock = val
- finally:
- current_lock.release()
-
- property complex_names:
- """ Unused
- """
- def __get__(self):
- return self._complex_names
-
- def __set__(self, val):
- # TODO: validation
- self._complex_names = val
-
-
-cdef object standard_richcmp(object self, object other, int how):
- # This needs to be shared because of weird CPython quirks involving
- # subclasses and the __hash__ method.
-
- if how == 2 or how == 3:
-
- if not isinstance(self, ObjectID) and isinstance(other, ObjectID):
- return NotImplemented
+cdef class PHIL:
- eq = (hash(self) == hash(other))
-
- if how == 2:
- return eq
- return not eq
+ """
+ The Primary HDF5 Interface Lock (PHIL) is a global reentrant lock
+ which manages access to the library. HDF5 is not guaranteed to
+ be thread-safe, and certain callbacks in h5py can execute arbitrary
+ threaded Python code. Therefore, in threading mode all routines
+ acquire this lock first. With threading support disabled, the
+ object's methods do nothing.
+ """
- return NotImplemented
+ IF H5PY_THREADS:
+ def __init__(self):
+ self.lock = threading.RLock()
+ cpdef int __enter__(self) except -1:
+ self.lock.acquire()
+ return 0
+ cpdef int __exit__(self,a,b,c) except -1:
+ self.lock.release()
+ return 0
+ cpdef int acquire(self) except -1:
+ self.lock.acquire()
+ return 0
+ cpdef int release(self) except -1:
+ self.lock.release()
+ return 0
+ ELSE:
+ cpdef int __enter__(self) except -1:
+ return 0
+ cpdef int __exit__(self,a,b,c) except -1:
+ return 0
+ cpdef int acquire(self) except -1:
+ return 0
+ cpdef int release(self) except -1:
+ return 0
+
+cdef PHIL phil = PHIL()
+cpdef PHIL get_phil():
+ """ Obtain a reference to the PHIL. """
+ return phil
+
+# Now that the PHIL is defined we can import the decorator
+include "std_code.pxi"
cdef class ObjectID:
@@ -163,8 +145,13 @@ cdef class ObjectID:
""" Indicates whether or not this identifier points to an HDF5 object.
"""
def __get__(self):
- return H5Iget_type(self.id) != H5I_BADID
+ phil.acquire()
+ try:
+ return H5Iget_type(self.id) != H5I_BADID
+ finally:
+ phil.release()
+
def __nonzero__(self):
""" Truth value for object identifiers (like _valid) """
return self._valid
@@ -178,11 +165,16 @@ cdef class ObjectID:
def __dealloc__(self):
""" Automatically decrefs the ID, if it's valid. """
- IF H5PY_DEBUG:
- log_ident.debug("- %s" % str(self))
- if (not self._locked) and self._valid:
- H5Idec_ref(self.id)
+ phil.acquire()
+ try:
+ IF H5PY_DEBUG:
+ log_ident.debug("- %s" % str(self))
+ if (not self._locked) and self._valid:
+ H5Idec_ref(self.id)
+ finally:
+ phil.release()
+
def __copy__(self):
""" Create another object wrapper which points to the same id.
@@ -209,22 +201,46 @@ cdef class ObjectID:
"""
return self.id
+
def __str__(self):
- if self._valid:
- ref = str(H5Iget_ref(self.id))
- else:
- ref = "X"
-
- if self._locked:
- lstr = "L"
- else:
- lstr = "U"
+ ref = str(H5Iget_ref(self.id)) if self._valid else "X"
+ lck = "L" if self._locked else "U"
- return "%9d [%s] (%s) %s" % (self.id, ref, lstr, self.__class__.__name__)
+ return "%9d [%s] (%s) %s" % (self.id, ref, lck, self.__class__.__name__)
def __repr__(self):
return self.__str__()
+# === HDF5 "H5" API ===========================================================
+
+
+def get_libversion():
+ """ () => TUPLE (major, minor, release)
+
+ Retrieve the HDF5 library version as a 3-tuple.
+ """
+ cdef unsigned int major
+ cdef unsigned int minor
+ cdef unsigned int release
+ cdef herr_t retval
+
+ H5get_libversion(&major, &minor, &release)
+
+ return (major, minor, release)
+
+
+def _close():
+ """ Internal function; do not call unless you want to lose all your data.
+ """
+ H5close()
+
+
+def _open():
+ """ Internal function; do not call unless you want to lose all your data.
+ """
+ H5open()
+
+
# === Public exception hierarchy ==============================================
class H5Error(Exception):
@@ -420,6 +436,7 @@ cdef class ErrorStackElement:
cdef readonly unsigned int line
cdef readonly object desc
+
def __str__(self):
return '%2d:%2d "%s" at %s (%s: %s)' % (self.maj_num, self.min_num,
self.desc, self.func_name, H5Eget_major(<H5E_major_t>self.maj_num),
@@ -442,6 +459,7 @@ cdef herr_t walk_cb(int n, H5E_error_t *err_desc, void* stack_in):
return 0
+
def error_stack():
""" () => LIST error_stack
@@ -452,6 +470,7 @@ def error_stack():
H5Ewalk(H5E_WALK_DOWNWARD, walk_cb, <void*>stack)
return stack
+
def error_string():
""" () => STRING error_stack
@@ -484,6 +503,7 @@ def error_string():
return msg
+
def clear():
""" ()
@@ -491,20 +511,6 @@ def clear():
"""
H5Eclear()
-def get_major(int error):
- """ (INT error) => STRING description
-
- Get a description associated with an HDF5 minor error code.
- """
- return H5Eget_major(<H5E_major_t>error)
-
-def get_minor(int error):
- """ (INT error) => STRING description
-
- Get a description associated with an HDF5 minor error code.
- """
- return H5Eget_minor(<H5E_minor_t>error)
-
# === Automatic exception API =================================================
cdef herr_t extract_cb(int n, H5E_error_t *err_desc, void* data_in):
@@ -520,7 +526,8 @@ cdef herr_t err_callback(void* client_data) with gil:
# Can't use the standard Pyrex raise because then the traceback
# points here. MUST be "with gil" as it can be called by nogil HDF5
- # routines.
+ # routines. By definition any function for which this can be called
+ # already holds the PHIL.
cdef H5E_error_t err_struct
cdef H5E_major_t mj
@@ -548,34 +555,9 @@ cdef int _disable_exceptions() except -1:
raise RuntimeError("Failed to unregister HDF5 exception callback.")
return 0
-cdef err_c pause_errors() except? NULL:
- # Temporarily disable automatic exception handling, and return a cookie
- # which can later be used to re-enable it.
- cdef err_c cookie
- cdef void* whatever
- cookie = NULL
-
- if H5Eget_auto(&cookie, &whatever) < 0:
- raise RuntimeError("Failed to retrieve the current error handler.")
-
- if H5Eset_auto(NULL, NULL) < 0:
- raise RuntimeError("Failed to temporarily disable error handling.")
-
- return cookie
-
-cdef int resume_errors(err_c cookie) except -1:
- # Resume automatic exception handling, using a cookie from a previous
- # call to pause_errors(). Also clears the error stack.
- if H5Eset_auto(cookie, NULL) < 0:
- raise RuntimeError("Failed to re-enable error handling.")
-
- if H5Eclear() < 0:
- raise RuntimeError("Failed to clear error stack.")
-
- return 0
-
# === Library init ============================================================
+
def _exithack():
""" Internal function; do not call unless you want to lose all your data.
"""
@@ -626,4 +608,3 @@ _config = H5PYConfig()
-
diff --git a/h5py/h5a.pyx b/h5py/h5a.pyx
index 77a3d6c..2c55166 100644
--- a/h5py/h5a.pyx
+++ b/h5py/h5a.pyx
@@ -38,6 +38,7 @@ import_array()
# === General attribute operations ============================================
+ at sync
def create(ObjectID loc not None, char* name, TypeID tid not None,
SpaceID space not None):
""" (ObjectID loc, STRING name, TypeID tid, SpaceID space)
@@ -48,6 +49,7 @@ def create(ObjectID loc not None, char* name, TypeID tid not None,
"""
return AttrID(H5Acreate(loc.id, name, tid.id, space.id, H5P_DEFAULT))
+ at sync
def open_idx(ObjectID loc not None, int idx):
""" (ObjectID loc_id, UINT idx) => INT attr_id
@@ -60,6 +62,7 @@ def open_idx(ObjectID loc not None, int idx):
raise ValueError("Index must be a non-negative integer.")
return AttrID(H5Aopen_idx(loc.id, idx))
+ at sync
def open_name(ObjectID loc not None, char* name):
""" (ObjectID loc, STRING name) => INT attr_id
@@ -67,6 +70,7 @@ def open_name(ObjectID loc not None, char* name):
"""
return AttrID(H5Aopen_name(loc.id, name))
+ at sync
def delete(ObjectID loc not None, char* name):
""" (ObjectID loc, STRING name)
@@ -74,6 +78,7 @@ def delete(ObjectID loc not None, char* name):
"""
H5Adelete(loc.id, name)
+ at sync
def get_num_attrs(ObjectID loc not None):
""" (ObjectID loc) => INT number_of_attributes
@@ -93,6 +98,7 @@ cdef herr_t iter_cb(hid_t loc_id, char *attr_name, object int_tpl) except -1:
return 0
+ at sync
def iterate(ObjectID loc not None, object func, object data=None, int startidx=0):
""" (ObjectID loc, FUNCTION func, OBJECT data=None, UINT startidx=0)
=> INT last_attribute_index
@@ -126,6 +132,7 @@ cdef herr_t list_cb(hid_t loc_id, char *attr_name, object listin):
thelist.append(attr_name)
return 0
+ at sync
def py_listattrs(ObjectID loc not None):
""" (ObjectID loc) => LIST
@@ -144,6 +151,7 @@ cdef herr_t cb_exist(hid_t loc_id, char* attr_name, object ref_name):
return 1
return 0
+ at sync
def py_exists(ObjectID loc not None, object ref_name):
""" (ObjectID loc, STRING ref_name) => BOOL
@@ -196,9 +204,10 @@ cdef class AttrID(ObjectID):
def __get__(self):
cdef TypeID tid
- tid = typewrap(H5Aget_type(self.id))
+ tid = self.get_type()
return tid.py_dtype()
+ @sync
def _close(self):
""" ()
@@ -208,6 +217,7 @@ cdef class AttrID(ObjectID):
"""
H5Aclose(self.id)
+ @sync
def read(self, ndarray arr_obj not None):
""" (NDARRAY arr_obj)
@@ -234,6 +244,7 @@ cdef class AttrID(ObjectID):
if space_id:
H5Sclose(space_id)
+ @sync
def write(self, ndarray arr_obj not None):
""" (NDARRAY arr_obj)
@@ -259,6 +270,7 @@ cdef class AttrID(ObjectID):
if space_id:
H5Sclose(space_id)
+ @sync
def get_name(self):
""" () => STRING name
@@ -279,6 +291,7 @@ cdef class AttrID(ObjectID):
return strout
+ @sync
def get_space(self):
""" () => INT space_id
@@ -286,8 +299,9 @@ cdef class AttrID(ObjectID):
"""
return SpaceID(H5Aget_space(self.id))
+ @sync
def get_type(self):
- """ () => INT type_id
+ """ () => TypeID
Create and return a copy of the attribute's datatype.
"""
diff --git a/h5py/h5t.pyx b/h5py/h5t.pyx
index 9ba53fa..7484a3b 100644
--- a/h5py/h5t.pyx
+++ b/h5py/h5t.pyx
@@ -60,7 +60,7 @@
include "config.pxi"
# Pyrex compile-time imports
-from h5 cimport err_c, pause_errors, resume_errors
+from h5 cimport PHIL, get_phil
from numpy cimport dtype, ndarray
from python cimport PyString_FromStringAndSize
@@ -72,6 +72,11 @@ from utils cimport emalloc, efree, pybool, \
import h5
import sys
+cdef PHIL phil
+phil = get_phil()
+phil.acquire()
+phil.release()
+
# === Custom C API ============================================================
cdef object typewrap(hid_t id_):
diff --git a/h5py/std_code.pxi b/h5py/std_code.pxi
index 9f794e9..8d80420 100644
--- a/h5py/std_code.pxi
+++ b/h5py/std_code.pxi
@@ -15,19 +15,35 @@
include "config.pxi"
-# Set up synchronization decorator for threads
-IF H5PY_THREADS:
- from _extras import h5sync
- IF H5PY_DEBUG:
- import logging
+# Defines the following decorators:
+#
+# sync: Acquire PHIL for this function, and log function entry and lock
+# acquisition in debug mode
+# nosync: Don't acquire PHIL, but log function entry in debug mode.
+#
+
+IF H5PY_DEBUG:
+ import logging
+ from _extras import h5sync_dummy
+ nosync = h5sync_dummy(logging.getLogger('h5py.functions'))
+
+ IF H5PY_THREADS:
+ from _extras import h5sync
sync = h5sync(logging.getLogger('h5py.functions'))
ELSE:
- sync = h5sync()
+ sync = nosync
+
ELSE:
- IF H5PY_DEBUG:
- import logging
- from _extras import h5sync_dummy
- sync = h5sync_dummy(logging.getLogger('h5py.functions'))
+ cdef inline object nosync(object func):
+ return func
+
+ IF H5PY_THREADS:
+ from _extras import h5sync
+ sync = h5sync()
ELSE:
cdef inline object sync(object func):
return func
+
+
+
+
diff --git a/setup.py b/setup.py
index 2847481..2b53405 100644
--- a/setup.py
+++ b/setup.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,37 @@
See INSTALL.txt or the h5py manual for additional build options.
"""
-# === Global constants ========================================================
+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
+from distutils.command.build import build
+from distutils.command.clean import clean
+from distutils.command.sdist import sdist
+
+# Basic package options
NAME = 'h5py'
VERSION = '0.3.1'
-
-MIN_PYREX = '0.9.8.4' # for compile_multiple
MIN_NUMPY = '1.0.3'
+MIN_CYTHON = '0.9.8.1'
+KNOWN_API = (16,18) # Legal API levels (1.8.X or 1.6.X)
+SRC_PATH = 'h5py' # Name of directory with .pyx files
+CMD_CLASS = {} # Custom command classes for setup()
+HDF5 = None # Custom HDF5 directory.
-# === Initial imports and utilities ===========================================
+# The list of modules depends on max API version
+MODULES = {16: ['h5', 'h5f', 'h5g', 'h5s', 'h5t', 'h5d', 'h5a', 'h5p', 'h5z',
+ 'h5i', 'h5r', 'h5fd', 'utils'],
+ 18: ['h5', 'h5f', 'h5g', 'h5s', 'h5t', 'h5d', 'h5a', 'h5p', 'h5z',
+ 'h5i', 'h5r', 'h5fd', 'utils', 'h5o', 'h5l']}
-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
+# C source files required for all modules
+EXTRA_SRC = ['utils_low.c']
def fatal(instring, code=1):
print >> sys.stderr, "Fatal: "+instring
@@ -58,82 +71,10 @@ def fatal(instring, code=1):
def warn(instring):
print >> sys.stderr, "Warning: "+instring
-# === Parse command line arguments ============================================
-
-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_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
-
-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
- sys.argv.remove(arg)
- elif arg.find('--api=') == 0:
- opts.ENABLE_PYREX=True
- api = arg[6:]
- 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
- try:
- opts.DEBUG_LEVEL = int(arg[8:])
- except:
- fatal('Debuglevel not understood (wants --debug=<n>)')
- 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])
- sys.argv.remove(arg)
- elif arg.find('--io-nonblock') == 0:
- opts.ENABLE_PYREX=True
- 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")
- 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):
+if not (sys.version_info[0:2] >= (2,5)):
fatal("At least Python 2.5 is required to install h5py")
# Check for Numpy (required)
@@ -141,51 +82,46 @@ 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 ====================================
-
-# Pyrex modules (without extension)
-modules = ['h5' , 'h5f', 'h5g', 'h5s', 'h5t', 'h5d',
- 'h5a', 'h5p', 'h5z', 'h5i', 'h5r', 'h5fd', 'utils']
-
-if (opts.API_MAJ, opts.API_MIN) >= (1,8):
- modules += ['h5o','h5l']
-# C source files required for Pyrex code (with extension)
-extra_src = ['utils_low.c']
-
-# Where these live, relative to setup.py
-src_path = 'h5py'
+for arg in sys.argv[:]:
+ if arg.find('--hdf5=') == 0:
+ splitarg = arg.split('=',1)
+ if len(splitarg) != 2:
+ fatal("HDF5 directory not understood (wants --hdf5=/path/to/hdf5)")
+ path = op.abspath(splitarg[1])
+ if not op.exists(path):
+ fatal("HDF5 path is illegal: %s" % path)
+ HDF5 = path
+ sys.argv.remove(arg)
+
+# === Platform-dependent compiler config ======================================
-# Platform-dependent arguments to setup() or Extension()
if os.name == 'nt':
-
- if opts.HDF5_DIR is None:
+ if 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(HDF5, 'include')]
+ library_dirs = [op.join(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 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(HDF5, 'include')]
+ library_dirs = [op.join(HDF5, 'lib')]
runtime_dirs = library_dirs
extra_compile_args = ['-DH5_USE_16_API', '-Wno-unused', '-Wno-uninitialized']
extra_link_args = []
@@ -193,177 +129,263 @@ 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]
+# The actual extensions themselves are created at runtime, as the list of
+# modules depends on command-line options.
+def create_extension(name):
+ """ Create a distutils Extension object for the given module. Uses the
+ globals in this file for things like the include directory.
+ """
+ sources = [op.join(SRC_PATH, name+'.c')]+[op.join(SRC_PATH,x) for x in EXTRA_SRC]
+ ext = Extension(NAME+'.'+name,
+ 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)
+ return ext
-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..."
+# === Custom extensions for distutils =========================================
- try:
- from Pyrex.Compiler.Main import Version
+class cybuild(build):
- if Version.version >= MIN_PYREX:
- from Pyrex.Compiler.Main import compile_multiple, CompilationOptions
+ """ Cython-aware subclass of the distutils build command
- # Check if the conditions.pxi file is up-to-date
- cond_path = op.join(src_path, 'conditions.pxi')
- cond = \
-"""
-%(AUTO_HDR)s
+ It handles the h5py-centric configuration for the build processing,
+ generating the compile-time definitions file "config.pxi" and
+ running Cython before handing control over to the native distutils
+ build. The advantage is that Cython is run on all files before
+ building begins, and is only run when the distribution is actually
+ being built (and not, for example, when "sdist" is called for).
+ """
-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
+ user_options = build.user_options + \
+ [('cython','y','Run Cython'),
+ ('cython-only','Y', 'Run Cython and stop'),
+ ('diag', 'd','Enable library logging'),
+ ('api=', 'a', 'Set API levels (--api=16,18)'),
+ ('threads', 't', 'Thread-aware')]
+ boolean_options = build.boolean_options + ['cython', 'threads','diag']
-DEF H5PY_16API = %(API_16)d
-DEF H5PY_18API = %(API_18)d
+ def initialize_options(self):
+ self.cython = False
+ self.cython_only = False
+ self.threads = False
+ self.api = (16,)
+ self.diag = False
+ self._explicit_only = False # Hack for test subclass
+ build.initialize_options(self)
+
+ def finalize_options(self):
-DEF H5PY_NONBLOCK = %(IO_NONBLOCK)d
-""" \
- % opts.__dict__
+ if self.cython_only or \
+ self.api != (16,) or \
+ self.threads or \
+ self.diag:
+ self.cython = True
+
+ # Validate API levels
+ if self.api != (16,):
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..."
- print cond
- 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))
+ self.api = tuple(int(x) for x in self.api.split(',') if len(x) > 0)
+ if len(self.api) == 0 or not all(x in KNOWN_API for x in self.api):
+ raise Exception
+ except Exception:
+ fatal('Illegal option %s to --api= (legal values are %s)' % (self.api, ','.join(str(x) for x in KNOWN_API)))
- 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
- )
- )
+ build.finalize_options(self)
-# === Custom extensions for distutils =========================================
+ def _get_pxi(self):
+ """ Get the configuration .pxi for the current options. """
+
+ pxi_str = \
+"""# This file is automatically generated. Do not edit.
+# HDF5: %(HDF5)s
-class test(Command):
- description = "Build %s and run unit tests" % NAME
- user_options = [('sections=','s','Comma separated list of tests ("-" prefix to NOT run)')]
+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
+"""
+ pxi_str %= {"VERSION": VERSION, "API_MAX": max(self.api),
+ "API_16": 16 in self.api, "API_18": 18 in self.api,
+ "DEBUG": 10 if self.diag else 0, "THREADS": self.threads,
+ "HDF5": HDF5}
+
+ return pxi_str
+
+ def run(self, *args, **kwds):
+
+ modules = MODULES[max(self.api)]
+ self.distribution.ext_modules = [create_extension(x) for x in modules]
+
+ # Necessary because Cython doesn't detect changes to the .pxi
+ recompile_all = False
+
+ # Check if the config.pxi file needs to be updated for the given
+ # command-line options.
+ if self.cython or not self._explicit_only:
+ pxi_path = op.join(SRC_PATH, 'config.pxi')
+ pxi = self._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)
+ recompile_all = True
+ 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)
+ recompile_all = True
+ f.close()
+
+ if self.cython or recompile_all:
+ print "Running Cython..."
+ try:
+ from Cython.Compiler.Main import Version, compile, CompilationOptions
+ from Cython.Distutils import build_ext
+ except ImportError:
+ fatal("Cython recompilation required, but Cython not installed.")
+
+ if Version.version < MIN_CYTHON:
+ fatal("Old Cython version detected; at least %s required" % MIN_CYTHON)
+
+ print " API levels: %s" % ','.join(str(x) for x in self.api)
+ print " Thread-aware: %s" % ('yes' if self.threads else 'no')
+ print " Diagnostic mode: %s" % ('yes' if self.diag else 'no')
+ print " HDF5: %s" % ('default' if HDF5 is None else HDF5)
+
+ cyopts = CompilationOptions(verbose=False)
+
+ # Build each extension
+ # This should be a single call to compile_multiple, but it's
+ # broken in Cython 0.9.8.1.1
+ for module in modules:
+ pyx_path = op.join(SRC_PATH,module+'.pyx')
+ c_path = op.join(SRC_PATH,module+'.c')
+ if not op.exists(c_path) or \
+ os.stat(pyx_path).st_mtime > os.stat(c_path).st_mtime or \
+ recompile_all or\
+ self.force:
+ print "Cythoning %s" % pyx_path
+ result = compile(pyx_path, cyopts)
+ if result.num_errors != 0:
+ fatal("Cython error; aborting.")
+
+ if self.cython_only:
+ exit(0)
+
+ build.run(self, *args, **kwds)
+
+class test(cybuild):
+ description = "Build and run unit tests"
+ user_options = cybuild.user_options + \
+ [('sections=','s','Comma separated list of tests ("-" prefix to NOT run)')]
def initialize_options(self):
self.sections = None
+ cybuild.initialize_options(self)
def finalize_options(self):
pass
+ cybuild.finalize_options(self)
def run(self):
- buildobj = self.distribution.get_command_obj('build')
- buildobj.run()
+ self._explicit_only = True
+ cybuild.run(self)
oldpath = sys.path
try:
- sys.path = [op.abspath(buildobj.build_lib)] + oldpath
+ sys.path = [op.abspath(self.build_lib)] + oldpath
import h5py.tests
if not h5py.tests.runtests(None if self.sections is None else tuple(self.sections.split(','))):
raise DistutilsError("Unit tests failed.")
finally:
sys.path = oldpath
-class dev(Command):
+class doc(cybuild):
- description = "Developer commands (--doc, --clean, --readme=<file>)"
- user_options = [('doc','d','Rebuild documentation'),
- ('clean', 'c', 'Remove built files and Pyrex temp files.')]
- boolean_options = ['doc']
+ """ Regenerate documentation. Unix only, requires epydoc/sphinx. """
- def initialize_options(self):
- self.doc = False
- self.readme = False
- self.clean = False
+ description = "Rebuild documentation"
- def finalize_options(self):
- pass
+ def run(self):
+
+ cybuild.run(self)
+
+ for x in ('docs', 'docs/api-html'):
+ if not op.exists(x):
+ os.mkdir(x, 0755)
+
+ retval = os.spawnlp(os.P_WAIT, 'epydoc', '-q', '--html',
+ '-o', 'docs/api-html', '--config', 'docs.cfg',
+ os.path.join(self.build_lib, NAME) )
+ if retval != 0:
+ warn("Could not run epydoc to build documentation.")
+
+
+ retval = os.system("cd docs; make html")
+ if retval != 0:
+ warn("Could not run Sphinx doc generator")
+ else:
+ if op.exists('docs/manual-html'):
+ shutil.rmtree('docs/manual-html')
+ shutil.copytree('docs/build/html', 'docs/manual-html')
+
+class cyclean(clean):
def run(self):
- if self.clean:
- for x in ('build','docs/api-html', 'docs/manual-html'):
- try:
- 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 ] + \
- [ 'MANIFEST']
-
- for name in fnames:
- try:
- os.remove(name)
- except OSError:
- pass
-
- if self.doc:
- buildobj = self.distribution.get_command_obj('build')
- buildobj.run()
- for x in ('docs', 'docs/api-html'):
- if not op.exists(x):
- os.mkdir(x, 0755)
-
- retval = os.spawnlp(os.P_WAIT, 'epydoc', '-q', '--html',
- '-o', 'docs/api-html', '--config', 'docs.cfg',
- os.path.join(buildobj.build_lib, NAME) )
- if retval != 0:
- warn("Could not run epydoc to build documentation.")
-
-
- retval = os.system("cd docs; make html")
- if retval != 0:
- warn("Could not run Sphinx doc generator")
- else:
- if op.exists('docs/manual-html'):
- shutil.rmtree('docs/manual-html')
- shutil.copytree('docs/build/html', 'docs/manual-html')
+
+ allmodules = set()
+ for x in MODULES.values():
+ allmodules.update(x)
+
+ for x in ('build','docs/api-html', 'docs/manual-html'):
+ try:
+ shutil.rmtree(x)
+ except OSError:
+ pass
+ fnames = [ op.join(SRC_PATH, x+'.dep') for x in allmodules ] + \
+ [ op.join(SRC_PATH, x+'.c') for x in allmodules ] + \
+ [ 'MANIFEST']
+
+ for name in fnames:
+ try:
+ os.remove(name)
+ except OSError:
+ pass
+
+ clean.run(self)
+
+class new_sdist(sdist):
+
+ def run(self):
+ if os.path.exists('MANIFEST'):
+ os.remove('MANIFEST')
+ shutil.copyfile(reduce(op.join, ('docs', 'source', 'build.rst')), 'INSTALL.txt')
+
+ sdist.run(self)
# New commands for setup (e.g. "python setup.py test")
if os.name == 'nt':
- CMD_CLASS = {'test': test}
+ CMD_CLASS.update({'build': cybuild, 'test': test, 'sdist': new_sdist})
else:
- CMD_CLASS = {'dev': dev, 'test': test}
-
-#print "Configuration"
-#print '-'*40
-#for key in sorted(opts.__dict__):
-# print "%-20s %s" % (key, opts.__dict__[key])
+ CMD_CLASS.update({'build': cybuild, 'test': test, 'sdist': new_sdist,
+ 'doc': doc, 'clean': cyclean, })
cls_txt = \
@@ -409,8 +431,8 @@ setup(
url = 'h5py.alfven.org',
packages = ['h5py','h5py.tests'],
package_data = package_data,
- ext_modules = extensions,
- requires = ['numpy (>=1.0.3)'],
+ ext_modules = [],
+ requires = ['numpy (>=%s)' % MIN_NUMPY],
cmdclass = CMD_CLASS
)
diff --git a/setup_cython.py b/setup_cython.py
deleted file mode 100644
index a49d8dd..0000000
--- a/setup_cython.py
+++ /dev/null
@@ -1,430 +0,0 @@
-#!/usr/bin/env python
-
-#+
-#
-# 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$
-#
-#-
-
-"""
- Setup script for the h5py package.
-
- 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.
-
- To build:
- python setup.py build
-
- To install:
- sudo python setup.py install
-
- To run the test suite locally (won't install anything):
- python setup.py test
-
- See INSTALL.txt or the h5py manual for additional build options.
-"""
-
-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
-from distutils.command.build import build
-
-
-# Basic package options
-NAME = 'h5py'
-VERSION = '0.3.1'
-MIN_NUMPY = '1.0.3'
-MIN_CYTHON = '0.9.8.1'
-KNOWN_API = (16,18) # Legal API levels (1.8.X or 1.6.X)
-SRC_PATH = 'h5py' # Name of directory with .pyx files
-CMD_CLASS = {} # Custom command classes for setup()
-
-# Compilation flags
-HDF5 = None # Custom HDF5 directory.
-API = "16"
-
-def fatal(instring, code=1):
- print >> sys.stderr, "Fatal: "+instring
- exit(code)
-
-def warn(instring):
- print >> sys.stderr, "Warning: "+instring
-
-# === Required imports ========================================================
-
-# 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 < 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)
-
-# === Parse command line arguments ============================================
-
-for arg in sys.argv[:]:
-
- if arg.find('--hdf5=') == 0:
- splitarg = arg.split('=',1)
- if len(splitarg) != 2:
- fatal("HDF5 directory not understood (wants --hdf5=/path/to/hdf5)")
- path = op.abspath(splitarg[1])
- if not op.exists(path):
- fatal("HDF5 path is illegal: %s" % path)
- HDF5 = path
- sys.argv.remove(arg)
-
- if arg.find('--api=') == 0:
- # We need to know this in order to generate the correct module list,
- # although it's technically handled by the build object.
- API = arg[5:]
-
-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')
-
-# === Platform configuration & Cython check ====================================
-
-# Cython modules (without extension)
-modules = ['h5' , 'h5f', 'h5g', 'h5s', 'h5t', 'h5d',
- 'h5a', 'h5p', 'h5z', 'h5i', 'h5r', 'h5fd', 'utils']
-
-# Only enable H5O and H5L interface if we're building against 1.8.X
-if "18" in API:
- modules += ['h5o','h5l']
-
-# C source files required for Cython code (with extension)
-extra_src = ['utils_low.c']
-
-
-# Platform-dependent arguments to setup() or Extension()
-if os.name == 'nt':
- if HDF5 is None:
- fatal("On Windows, HDF5 directory must be specified.")
-
- libraries = ['hdf5dll']
- include_dirs = [numpy.get_include(), op.join(HDF5, 'include')]
- library_dirs = [op.join(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']}
-
-else: # Assume Unix-like
-
- libraries = ['hdf5']
- if 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(HDF5, 'include')]
- library_dirs = [op.join(HDF5, 'lib')]
- runtime_dirs = library_dirs
- extra_compile_args = ['-DH5_USE_16_API', '-Wno-unused', '-Wno-uninitialized']
- extra_link_args = []
-
- package_data = {'h5py': ['*.pyx'],
- 'h5py.tests': ['data/*.hdf5']}
-
-# Explicit list of C source files for each module.
-mod_paths = [op.join(SRC_PATH, x) for x in modules]
-extra_paths = [op.join(SRC_PATH, x) for x in extra_src]
-module_sources = [[x+'.c']+extra_paths for x in mod_paths]
-
-extensions = [ Extension(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) ]
-
-
-# === Custom extensions for distutils =========================================
-
-class cybuild(build):
-
- """ Cython-aware subclass of build """
-
- user_options = build.user_options + \
- [('cython','c','Run Cython'),
- ('hdebug=', 'q','Set debug level'),
- ('api=', 'a', 'API levels'),
- ('threads', 't', 'Thread-aware')]
- boolean_options = build.boolean_options + ['cython', 'threads']
-
- def initialize_options(self):
- self.cython = False
- self.threads = False
- self.api = (16,)
- self.hdebug = 0
- build.initialize_options(self)
-
- def finalize_options(self):
-
- print "finalizing"
- # Validate API levels
- if self.api != (16,):
- self.cython = True
- print self.api
- try:
- self.api = tuple(int(x) for x in self.api.split(',') if len(x) > 0)
- if len(self.api) == 0 or not all(x in KNOWN_API for x in self.api):
- raise Exception
- except Exception:
- fatal('Illegal option %s to --api= (legal values are %s)' % (self.api, ','.join(str(x) for x in KNOWN_API)))
-
- # Validate debug level
- if self.hdebug != 0:
- print self.hdebug
- self.cython = True
- try:
- self.hdebug = int(self.hdebug)
- except TypeError:
- fatal('Debuglevel not understood (wants --debug=<integer>)')
- build.finalize_options(self)
-
- def _get_pxi(self):
- """ Get the configuration .pxi for the current options. """
-
- pxi_str = \
-"""# This file is automatically generated. Do not edit.
-# HDF5: %(HDF5)s
-
-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
-"""
- pxi_str %= {"VERSION": VERSION, "API_MAX": max(self.api),
- "API_16": 16 in self.api, "API_18": 18 in self.api,
- "DEBUG": self.hdebug, "THREADS": self.threads,
- "HDF5": HDF5}
-
- return pxi_str
-
- def run(self, *args, **kwds):
-
- # Necessary because Cython doesn't detect changes to the .pxi
- recompile_all = False
-
- # Check if the config.pxi file needs to be updated for the given
- # command-line options.
- pxi_path = op.join(SRC_PATH, 'config.pxi')
- pxi = self._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)
- recompile_all = True
- 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)
- recompile_all = True
- f.close()
-
- if self.force: forceall = True
-
- if self.cython:
- print "Running Cython..."
- try:
- from Cython.Compiler.Main import Version, compile, CompilationOptions
- from Cython.Distutils import build_ext
- except ImportError:
- fatal("Cython recompilation required, but Cython not installed.")
-
- if Version.version < MIN_CYTHON:
- fatal("Old Cython version detected; at least %s required" % MIN_CYTHON)
-
- cyopts = CompilationOptions(verbose=False)
-
- # Build each extension
- # This should be a single call to compile_multiple, but it's
- # broken in Cython 0.9.8.1.1
- for module in modules:
- pyx_path = op.join(SRC_PATH,module+'.pyx')
- c_path = op.join(SRC_PATH,module+'.c')
- if not op.exists(c_path) or \
- os.stat(pyx_path).st_mtime > os.stat(c_path).st_mtime or \
- recompile_all:
- print "Cythoning %s" % pyx_path
- result = compile(pyx_path, cyopts)
- if result.num_errors != 0:
- fatal("Cython error; aborting.")
-
- build.run(self, *args, **kwds)
-
-class test(cybuild):
- description = "Build and run unit tests"
- user_options = cybuild.user_options + [('sections=','s','Comma separated list of tests ("-" prefix to NOT run)')]
-
- def initialize_options(self):
- self.sections = None
- cybuild.initialize_options(self)
-
- def finalize_options(self):
- pass
- cybuild.finalize_options(self)
-
- def run(self):
- cybuild.run(self)
- oldpath = sys.path
- try:
- sys.path = [op.abspath(self.build_lib)] + oldpath
- import h5py.tests
- if not h5py.tests.runtests(None if self.sections is None else tuple(self.sections.split(','))):
- raise DistutilsError("Unit tests failed.")
- finally:
- sys.path = oldpath
-
-class dev(Command):
-
- description = "Developer commands (--doc, --clean, --readme=<file>)"
- user_options = [('doc','d','Rebuild documentation'),
- ('clean', 'c', 'Remove built files and Cython temp files.')]
- boolean_options = ['doc']
-
- def initialize_options(self):
- self.doc = False
- self.readme = False
- self.clean = False
-
- def finalize_options(self):
- pass
-
- def run(self):
- if self.clean:
- for x in ('build','docs/api-html', 'docs/manual-html'):
- try:
- 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 ] + \
- [ 'MANIFEST']
-
- for name in fnames:
- try:
- os.remove(name)
- except OSError:
- pass
-
- if self.doc:
- buildobj = self.distribution.get_command_obj('build')
- buildobj.run()
- for x in ('docs', 'docs/api-html'):
- if not op.exists(x):
- os.mkdir(x, 0755)
-
- retval = os.spawnlp(os.P_WAIT, 'epydoc', '-q', '--html',
- '-o', 'docs/api-html', '--config', 'docs.cfg',
- os.path.join(buildobj.build_lib, NAME) )
- if retval != 0:
- warn("Could not run epydoc to build documentation.")
-
-
- retval = os.system("cd docs; make html")
- if retval != 0:
- warn("Could not run Sphinx doc generator")
- else:
- if op.exists('docs/manual-html'):
- shutil.rmtree('docs/manual-html')
- shutil.copytree('docs/build/html', 'docs/manual-html')
-
-# New commands for setup (e.g. "python setup.py test")
-if os.name == 'nt':
- CMD_CLASS.update({'build': cybuild, 'test': test})
-else:
- CMD_CLASS.update({'build': cybuild, 'dev': dev, 'test': test})
-
-
-cls_txt = \
-"""
-Development Status :: 4 - Beta
-Intended Audience :: Developers
-Intended Audience :: Information Technology
-Intended Audience :: Science/Research
-License :: OSI Approved :: BSD License
-Programming Language :: Python
-Topic :: Scientific/Engineering
-Topic :: Software Development :: Libraries :: Python Modules
-Operating System :: Unix
-Operating System :: POSIX :: Linux
-Operating System :: MacOS :: MacOS X
-Operating System :: Microsoft :: Windows
-"""
-
-short_desc = "General-purpose Python bindings for the HDF5 library"
-
-long_desc = \
-"""
-The h5py package provides both a high- and low-level interface to the HDF5
-library from Python. The low-level interface is intended to be a complete
-wrapping of the HDF5 API, while the high-level component supports Python-style
-object-oriented access to HDF5 files, datasets and groups.
-
-A strong emphasis on automatic conversion between Python (Numpy) datatypes and
-data structures and their HDF5 equivalents vastly simplifies the process of
-reading and writing data from Python.
-"""
-
-setup(
- name = NAME,
- version = VERSION,
- description = short_desc,
- long_description = long_desc,
- classifiers = [x for x in cls_txt.split("\n") if x],
- author = 'Andrew Collette',
- author_email = '"h5py" at the domain "alfven.org"',
- maintainer = 'Andrew Collette',
- maintainer_email = '"h5py" at the domain "alfven.org"',
- url = 'h5py.alfven.org',
- packages = ['h5py','h5py.tests'],
- package_data = package_data,
- ext_modules = extensions,
- requires = ['numpy (>=%s)' % MIN_NUMPY],
- cmdclass = 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