/* * Objects representing netCDF files and variables. * * Written by Konrad Hinsen * last revision: 2007-10-31 */ #ifdef _WIN32 #define DLL_NETCDF #endif #include "Python.h" #if defined(NUMPY) #include "numpy/arrayobject.h" #else #if defined(NUMARRAY) #include "numarray/arrayobject.h" #else #include "Numeric/arrayobject.h" #endif #endif #include "netcdf.h" #define _NETCDF_MODULE #include "Scientific/netcdfmodule.h" staticforward int netcdf_file_init(PyNetCDFFileObject *self); staticforward PyNetCDFVariableObject * netcdf_variable_new(PyNetCDFFileObject *file, char *name, int id, int type, int ndims, int *dimids, int nattrs); /* Lock granting access to netCDF routines (netCDF isn't thread-safe) */ #ifdef WITH_THREAD #include "pythread.h" PyThread_type_lock netCDF_lock; #define acquire_netCDF_lock() { PyThread_acquire_lock(netCDF_lock, 1); } #define release_netCDF_lock() { PyThread_release_lock(netCDF_lock); } #else #define acquire_netCDF_lock() {} #define release_netCDF_lock() {} #endif /* Typedef for Numeric/NumPy compatibility */ #if !defined(NUMPY) typedef int npy_intp; #endif /* Set error string */ static void netcdf_seterror(void) { char *error; switch (ncerr) { case NC_NOERR: error = "No error"; break; case NC_EBADID: error = "Not a netCDF id"; break; case NC_ENFILE: error = "Too many netCDF files open"; break; case NC_EEXIST: error = "netCDF file exists && NC_NOCLOBBER"; break; case NC_EINVAL: error = "Invalid argument"; break; case NC_EPERM: error = "Write to read only"; break; case NC_ENOTINDEFINE: error = "Operation not allowed in data mode"; break; case NC_EINDEFINE: error = "Operation not allowed in define mode"; break; case NC_EINVALCOORDS: error = "Index exceeds dimension bound"; break; case NC_EMAXDIMS: error = "NC_MAX_DIMS exceeded"; break; case NC_ENAMEINUSE: error = "String match to name in use"; break; case NC_ENOTATT: error = "Attribute not found"; break; case NC_EMAXATTS: error = "NC_MAX_ATTRS exceeded"; break; case NC_EBADTYPE: error = "Not a netCDF data type or _FillValue type mismatch"; break; case NC_EBADDIM: error = "Invalid dimension id or name"; break; case NC_EUNLIMPOS: error = "NC_UNLIMITED in the wrong index"; break; case NC_EMAXVARS: error = "NC_MAX_VARS exceeded"; break; case NC_ENOTVAR: error = "Variable not found"; break; case NC_EGLOBAL: error = "Action prohibited on NC_GLOBAL varid"; break; case NC_ENOTNC: error = "Not a netCDF file"; break; case NC_ESTS: error = "In Fortran, string too short"; break; case NC_EMAXNAME: error = "NC_MAX_NAME exceeded"; break; case NC_EUNLIMIT: error = "NC_UNLIMITED size already in use"; break; case NC_ENORECVARS: error = "nc_rec op when there are no record vars"; break; case NC_ECHAR: error = "Attempt to convert between text & numbers"; break; case NC_EEDGE: error = "Edge+start exceeds dimension bound"; break; case NC_ESTRIDE: error = "Illegal stride"; break; case NC_EBADNAME: error = "Attribute or variable name contains illegal characters"; break; case NC_ERANGE: error = "Numeric conversion not representable"; break; case NC_ENOMEM: error = "Memory allocation (malloc) failure"; break; case NC_EXDR: error = "XDR error"; break; default: error = "Unknown error"; break; } PyErr_SetString(PyExc_IOError, error); } static void netcdf_signalerror(int code) { static char buffer[200]; if (code != NC_NOERR) { Py_BEGIN_ALLOW_THREADS; acquire_netCDF_lock(); sprintf(buffer, "netcdf: %s", nc_strerror(code)); release_netCDF_lock(); Py_END_ALLOW_THREADS; PyErr_SetString(PyExc_IOError, buffer); } } /* * Python equivalents to netCDF data types * * Caution: the following specification may not be fully portable. * The comments indicate the correct netCDF specification. The assignment * of Python types assumes that 'short' is 16-bit and 'int' is 32-bit. */ int data_types[] = {-1, /* not used */ #if defined(NUMPY) PyArray_BYTE, /* signed 8-bit int */ #else PyArray_SBYTE, /* signed 8-bit int */ #endif PyArray_CHAR, /* 8-bit character */ PyArray_SHORT, /* 16-bit signed int */ PyArray_INT, /* 32-bit signed int */ PyArray_FLOAT, /* 32-bit IEEE float */ PyArray_DOUBLE /* 64-bit IEEE float */ }; /* Generic data type functions, similar to those in the netCDF 2 interface. */ static int nc_put_att_any(int ncid, int varid, const char *name, nc_type xtype, size_t len, const void *data) { switch (xtype) { case NC_BYTE: return nc_put_att_uchar(ncid, varid, name, xtype, len, (unsigned char *)data); break; case NC_CHAR: return nc_put_att_text(ncid, varid, name, len, (char *)data); break; case NC_SHORT: return nc_put_att_short(ncid, varid, name, xtype, len, (short *)data); break; case NC_INT: return nc_put_att_int(ncid, varid, name, xtype, len, (int *)data); break; case NC_FLOAT: return nc_put_att_float(ncid, varid, name, xtype, len, (float *)data); break; case NC_DOUBLE: return nc_put_att_double(ncid, varid, name, xtype, len, (double *)data); break; default: return NC_EINVAL; } } static int nc_put_var1_any(int ncid, int varid, nc_type xtype, const size_t *indexp, const void *data) { switch (xtype) { case NC_BYTE: return nc_put_var1_uchar(ncid, varid, indexp, (unsigned char *)data); break; case NC_CHAR: return nc_put_var1_text(ncid, varid, indexp, (char *)data); break; case NC_SHORT: return nc_put_var1_short(ncid, varid, indexp, (short *)data); break; case NC_INT: return nc_put_var1_int(ncid, varid, indexp, (int *)data); break; case NC_FLOAT: return nc_put_var1_float(ncid, varid, indexp, (float *)data); break; case NC_DOUBLE: return nc_put_var1_double(ncid, varid, indexp, (double *)data); break; default: return NC_EINVAL; } } static int nc_put_vars_any(int ncid, int varid, nc_type xtype, const size_t start[], const size_t count[], const ptrdiff_t stride[], const void *data) { switch (xtype) { case NC_BYTE: return nc_put_vars_uchar(ncid, varid, start, count, stride, (unsigned char *)data); break; case NC_CHAR: return nc_put_vars_text(ncid, varid, start, count, stride, (char *)data); break; case NC_SHORT: return nc_put_vars_short(ncid, varid, start, count, stride, (short *)data); break; break; case NC_INT: return nc_put_vars_int(ncid, varid, start, count, stride, (int *)data); break; break; case NC_FLOAT: return nc_put_vars_float(ncid, varid, start, count, stride, (float *)data); break; break; case NC_DOUBLE: return nc_put_vars_double(ncid, varid, start, count, stride, (double *)data); break; default: return NC_EINVAL; } } /* Utility functions */ static void define_mode(PyNetCDFFileObject *file, int define_flag) { if (file->define != define_flag) { Py_BEGIN_ALLOW_THREADS; acquire_netCDF_lock(); if (file->define) nc_enddef(file->id); else nc_redef(file->id); release_netCDF_lock(); file->define = define_flag; Py_END_ALLOW_THREADS; } } static char typecode(int type) { char t; switch(type) { #if defined(NUMPY) case PyArray_STRING: case PyArray_CHAR: t = PyArray_CHARLTR; break; case PyArray_BYTE: t = PyArray_BYTELTR; break; case PyArray_SHORT: t = PyArray_SHORTLTR; break; case PyArray_INT: t = PyArray_INTLTR; break; case PyArray_LONG: t = PyArray_LONGLTR; break; case PyArray_FLOAT: t = PyArray_FLOATLTR; break; case PyArray_DOUBLE: t = PyArray_DOUBLELTR; break; #else case PyArray_UBYTE: t = 'b'; break; case PyArray_SBYTE: t = '1'; break; case PyArray_CHAR: t = 'c'; break; case PyArray_SHORT: t = 's'; break; case PyArray_LONG: t = 'l'; break; case PyArray_INT: t = 'i'; break; case PyArray_FLOAT: t = 'f'; break; case PyArray_DOUBLE: t = 'd'; break; #endif default: t = ' '; } return t; } static nc_type netcdf_type_from_code(char code) { int type; switch(code) { case 'c': case 'S': type = NC_CHAR; break; case 'b': case 'B': case '1': type = NC_BYTE; break; case 's': case 'h': type = NC_SHORT; break; case 'i': case 'l': type = NC_INT; break; case 'f': type = NC_FLOAT; break; case 'd': type = NC_DOUBLE; break; default: type = 0; } return type; } static int netcdf_type_from_type(char array_type) { int type; switch(array_type) { #if !defined(NUMARRAY) case PyArray_CHAR: #if defined(NUMPY) case PyArray_STRING: #endif type = NC_CHAR; break; #endif case PyArray_UBYTE: #if defined(NUMPY) case PyArray_BYTE: #else case PyArray_SBYTE: #endif type = NC_BYTE; break; case PyArray_SHORT: type = NC_SHORT; break; #if !defined(NUMARRAY) case PyArray_INT: #endif case PyArray_LONG: type = NC_INT; break; case PyArray_FLOAT: type = NC_FLOAT; break; case PyArray_DOUBLE: type = NC_DOUBLE; break; default: type = 0; } return type; } static void collect_attributes(int fileid, int varid, PyObject *attributes, int nattrs) { char name[MAX_NC_NAME]; nc_type type; size_t length; npy_intp lengthp; int py_type; int i; for (i = 0; i < nattrs; i++) { Py_BEGIN_ALLOW_THREADS; acquire_netCDF_lock(); nc_inq_attname(fileid, varid, i, name); nc_inq_att(fileid, varid, name, &type, &length); lengthp = length; release_netCDF_lock(); Py_END_ALLOW_THREADS; py_type = data_types[type]; if (py_type == PyArray_CHAR) { char *s = (char *)malloc((length+1)*sizeof(char)); if (s != NULL) { PyObject *string; *s = '\0'; Py_BEGIN_ALLOW_THREADS; acquire_netCDF_lock(); nc_get_att_text(fileid, varid, name, s); release_netCDF_lock(); Py_END_ALLOW_THREADS; s[length] = '\0'; string = PyString_FromString(s); free(s); if (string != NULL) { PyDict_SetItemString(attributes, name, string); Py_DECREF(string); } } } else { #if defined(NUMPY) PyObject *array = PyArray_SimpleNew(1, &lengthp, py_type); #else PyObject *array = PyArray_FromDims(1, &lengthp, py_type); #endif if (array != NULL) { Py_BEGIN_ALLOW_THREADS; acquire_netCDF_lock(); ncattget(fileid, varid, name, ((PyArrayObject *)array)->data); release_netCDF_lock(); Py_END_ALLOW_THREADS; array = PyArray_Return((PyArrayObject *)array); if (array != NULL) { PyDict_SetItemString(attributes, name, array); Py_DECREF(array); } } } } } static int set_attribute(int fileid, int varid, PyObject *attributes, char *name, PyObject *value) { if (value == NULL) { int ret; Py_BEGIN_ALLOW_THREADS; acquire_netCDF_lock(); ret = nc_del_att(fileid, varid, name); release_netCDF_lock(); Py_END_ALLOW_THREADS; if (ret != NC_NOERR) { netcdf_signalerror(ret); return -1; } PyDict_DelItemString(attributes, name); return 0; } else if (PyString_Check(value)) { Py_ssize_t len = PyString_Size(value); char *string = PyString_AsString(value); int ret; Py_BEGIN_ALLOW_THREADS; acquire_netCDF_lock(); ret = nc_put_att_text(fileid, varid, name, (size_t)len, string); release_netCDF_lock(); Py_END_ALLOW_THREADS; if (ret != NC_NOERR) { netcdf_signalerror(ret); return -1; } PyDict_SetItemString(attributes, name, value); return 0; } else { int ret; PyArrayObject *array = (PyArrayObject *)PyArray_ContiguousFromObject(value, PyArray_NOTYPE, 0, 1); if (array != NULL) { int len = (array->nd == 0) ? 1 : array->dimensions[0]; int type = netcdf_type_from_code(array->descr->type); if (data_types[type] != array->descr->type_num) { PyArrayObject *array2 = (PyArrayObject *) PyArray_Cast(array, data_types[type]); Py_DECREF(array); array = array2; if (array == NULL) return -1; } Py_BEGIN_ALLOW_THREADS; acquire_netCDF_lock(); ret = nc_put_att_any(fileid, varid, name, type, len, array->data); release_netCDF_lock(); Py_END_ALLOW_THREADS; if (ret != NC_NOERR) { netcdf_signalerror(ret); return -1; } PyDict_SetItemString(attributes, name, (PyObject *)array); return 0; } else return -1; } } static int check_if_open(PyNetCDFFileObject *file, int mode) { /* mode: -1 read, 1 write, 0 other */ if (file == NULL || !file->open) { PyErr_SetString(PyExc_IOError, "netcdf: file has been closed"); return 0; } else { if (mode != 1 || file->write) { return 1; } else { PyErr_SetString(PyExc_IOError, "netcdf: write access to read-only file"); return 0; } } } /* * NetCDFFile object * (type declaration in netcdfmodule.h) */ /* Destroy file object */ static void PyNetCDFFileObject_dealloc(PyNetCDFFileObject *self) { if (self->open) PyNetCDFFile_Close(self); Py_XDECREF(self->dimensions); Py_XDECREF(self->variables); Py_XDECREF(self->attributes); Py_XDECREF(self->name); Py_XDECREF(self->mode); self->ob_type->tp_free((PyObject*)self); } /* Create file object */ static PyObject * PyNetCDFFileObject_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { PyNetCDFFileObject *self; self = (PyNetCDFFileObject *)type->tp_alloc(type, 0); if (self != NULL) { self->dimensions = NULL; self->variables = NULL; self->attributes = NULL; self->name = NULL; self->mode = NULL; } return (PyObject *)self; } /* Open file */ static int open_netcdf_file(PyNetCDFFileObject *self, char *filename, char *mode) { int rw, share, ret; rw = share = ret = 0; if (strlen(mode) > 1) { if (mode[1] == '+') rw = 1; else if (mode[1] == 's') share = NC_SHARE; else ret = -1; } if (strlen(mode) > 2) { if (mode[2] == '+') rw = 1; else if (mode[2] == 's') share = NC_SHARE; else ret = -1; } if (ret == -1 || strlen(mode) > 3 || (mode[0] != 'r' && mode[0] != 'w' && mode[0] != 'a')) { PyErr_SetString(PyExc_IOError, "netcdf: illegal mode specification"); return -1; } self->open = 0; if (mode[0] == 'w') { Py_BEGIN_ALLOW_THREADS; acquire_netCDF_lock(); ret = nc_create(filename, NC_CLOBBER|share, &self->id); release_netCDF_lock(); Py_END_ALLOW_THREADS; self->define = 1; self->write = 1; if (ret == NC_NOERR) { self->open = 1; netcdf_file_init(self); } } else if (mode[0] == 'a') { Py_BEGIN_ALLOW_THREADS; acquire_netCDF_lock(); ret = nc_open(filename, NC_WRITE|share, &self->id); self->define = 0; if (ret == ENOENT) { ret = nc_create(filename, NC_NOCLOBBER|share, &self->id); self->define = 1; } release_netCDF_lock(); Py_END_ALLOW_THREADS; self->write = 1; if (ret == NC_NOERR) { self->open = 1; netcdf_file_init(self); } } else if (mode[0] == 'r') { Py_BEGIN_ALLOW_THREADS; acquire_netCDF_lock(); ret = nc_open(filename, rw ? (NC_WRITE|share) : (NC_NOWRITE|share), &self->id); release_netCDF_lock(); Py_END_ALLOW_THREADS; self->define = 0; self->write = rw; if (ret == NC_NOERR) { self->open = 1; netcdf_file_init(self); } } else { return -1; } if (ret != NC_NOERR) { netcdf_signalerror(ret); return -1; } self->name = PyString_FromString(filename); self->mode = PyString_FromString(mode); return 0; } static int PyNetCDFFileObject_init(PyNetCDFFileObject *self, PyObject *args, PyObject *kwds) { char *filename; char *mode = NULL; char *history = NULL; if (!PyArg_ParseTuple(args, "s|ss:NetCDFFile", &filename, &mode, &history)) return -1; if (mode == NULL) mode = "r"; if (open_netcdf_file(self, filename, mode) < 0) { return -1; } if (history != NULL) PyNetCDFFile_AddHistoryLine(self, history); return 0; } static PyNetCDFFileObject * PyNetCDFFile_Open(char *filename, char *mode) { PyNetCDFFileObject *self = (PyNetCDFFileObject *) PyNetCDFFileObject_new(&PyNetCDFFile_Type, NULL, NULL); if (self == NULL) return NULL; if (open_netcdf_file(self, filename, mode) < 0) { PyNetCDFFileObject_dealloc(self); return NULL; } return self; } /* Create variables from file */ static int netcdf_file_init(PyNetCDFFileObject *self) { int ndims, nvars, ngattrs, recdim; int i; self->dimensions = PyDict_New(); self->variables = PyDict_New(); self->attributes = PyDict_New(); Py_BEGIN_ALLOW_THREADS; acquire_netCDF_lock(); nc_inq(self->id, &ndims, &nvars, &ngattrs, &recdim); release_netCDF_lock(); Py_END_ALLOW_THREADS; self->recdim = recdim; for (i = 0; i < ndims; i++) { char name[MAX_NC_NAME]; unsigned long size; PyObject *size_ob; Py_BEGIN_ALLOW_THREADS; acquire_netCDF_lock(); nc_inq_dim(self->id, i, name, &size); release_netCDF_lock(); Py_END_ALLOW_THREADS; if (i == recdim) PyDict_SetItemString(self->dimensions, name, Py_None); else { size_ob = PyInt_FromLong(size); PyDict_SetItemString(self->dimensions, name, size_ob); Py_DECREF(size_ob); } } for (i = 0; i < nvars; i++) { char name[MAX_NC_NAME]; nc_type datatype; int ndimensions, nattrs; int *dimids; PyNetCDFVariableObject *variable; Py_BEGIN_ALLOW_THREADS; acquire_netCDF_lock(); nc_inq_varname(self->id, i, name); nc_inq_vartype(self->id, i, &datatype); nc_inq_varndims(self->id, i, &ndimensions); nc_inq_varnatts(self->id, i, &nattrs); release_netCDF_lock(); Py_END_ALLOW_THREADS; if (ndimensions > 0) { dimids = (int *)malloc(ndimensions*sizeof(int)); if (dimids == NULL) { PyErr_NoMemory(); return 0; } Py_BEGIN_ALLOW_THREADS; acquire_netCDF_lock(); nc_inq_vardimid(self->id, i, dimids); release_netCDF_lock(); Py_END_ALLOW_THREADS; } else dimids = NULL; variable = netcdf_variable_new(self, name, i, data_types[datatype], ndimensions, dimids, nattrs); if (variable != NULL) { PyDict_SetItemString(self->variables, name, (PyObject *)variable); Py_DECREF(variable); } else free(dimids); } collect_attributes(self->id, NC_GLOBAL, self->attributes, ngattrs); return 1; } /* Create dimension */ static int PyNetCDFFile_CreateDimension(PyNetCDFFileObject *file, char *name, long size) { PyObject *size_ob; int id, ret; if (check_if_open(file, 1)) { if (size == 0 && file->recdim != -1) { PyErr_SetString(PyExc_IOError, "netcdf: there is already an unlimited dimension"); return -1; } define_mode(file, 1); Py_BEGIN_ALLOW_THREADS; acquire_netCDF_lock(); ret = nc_def_dim(file->id, name, (size == 0) ? NC_UNLIMITED : size, &id); release_netCDF_lock(); Py_END_ALLOW_THREADS; if (ret != NC_NOERR) { netcdf_signalerror(ret); return -1; } else { if (size == 0) { PyDict_SetItemString(file->dimensions, name, Py_None); file->recdim = id; } else { size_ob = PyInt_FromLong(size); PyDict_SetItemString(file->dimensions, name, size_ob); Py_DECREF(size_ob); } return 0; } } else return -1; } static PyObject * PyNetCDFFileObject_new_dimension(PyNetCDFFileObject *self, PyObject *args) { char *name; PyObject *size_ob; long size; if (!PyArg_ParseTuple(args, "sO", &name, &size_ob)) return NULL; if (size_ob == Py_None) size = 0; else if (PyInt_Check(size_ob)) size = PyInt_AsLong(size_ob); else { PyErr_SetString(PyExc_TypeError, "size must be None or integer"); return NULL; } if (PyNetCDFFile_CreateDimension(self, name, size) == 0) { Py_INCREF(Py_None); return Py_None; } else return NULL; } static char createDimension_doc[] = ""; /* Create variable */ static PyNetCDFVariableObject * PyNetCDFFile_CreateVariable(PyNetCDFFileObject *file, char *name, int typecode, char **dimension_names, int ndim) { int *dimids; PyNetCDFVariableObject *variable; int ntype, i, ret; if (check_if_open(file, 1)) { define_mode(file, 1); if (ndim == 0) dimids = NULL; else { dimids = (int *)malloc(ndim*sizeof(int)); if (dimids == NULL) return (PyNetCDFVariableObject *)PyErr_NoMemory(); } for (i = 0; i < ndim; i++) { Py_BEGIN_ALLOW_THREADS; acquire_netCDF_lock(); dimids[i] = ncdimid(file->id, dimension_names[i]); ret = nc_inq_dimid(file->id, dimension_names[i], dimids+i); release_netCDF_lock(); Py_END_ALLOW_THREADS; if (ret != NC_NOERR) { netcdf_signalerror(ret); free(dimids); return NULL; } if (dimids[i] == file->recdim && i > 0) { PyErr_SetString(PyExc_IOError, "netcdf: unlimited dimension must be first"); free(dimids); return NULL; } } ntype = netcdf_type_from_code((char)typecode); Py_BEGIN_ALLOW_THREADS; acquire_netCDF_lock(); ret = nc_def_var(file->id, name, ntype, ndim, dimids, &i); release_netCDF_lock(); Py_END_ALLOW_THREADS; if (ret != NC_NOERR) { netcdf_signalerror(ret); if (dimids != NULL) free(dimids); return NULL; } variable = netcdf_variable_new(file, name, i, data_types[ntype], ndim, dimids, 0); if (variable != NULL) { PyDict_SetItemString(file->variables, name, (PyObject *)variable); return variable; } else { free(dimids); return NULL; } } else return NULL; } static PyObject * PyNetCDFFileObject_new_variable(PyNetCDFFileObject *self, PyObject *args) { PyNetCDFVariableObject *var; char **dimension_names; PyObject *item, *dim; char *name; Py_ssize_t len_dim; int ndim; char type; int i; if (!PyArg_ParseTuple(args, "scO!", &name, &type, &PyTuple_Type, &dim)) return NULL; len_dim = PyTuple_Size(dim); if (len_dim > INT_MAX) { PyErr_SetString(PyExc_ValueError, "too many dimensions"); return NULL; } ndim = (int)len_dim; if (ndim == 0) dimension_names = NULL; else { dimension_names = (char **)malloc(ndim*sizeof(char *)); if (dimension_names == NULL) { PyErr_SetString(PyExc_MemoryError, "out of memory"); return NULL; } } for (i = 0; i < ndim; i++) { item = PyTuple_GetItem(dim, (Py_ssize_t)i); if (PyString_Check(item)) dimension_names[i] = PyString_AsString(item); else { PyErr_SetString(PyExc_TypeError, "dimension name must be a string"); free(dimension_names); return NULL; } } var = PyNetCDFFile_CreateVariable(self, name, type, dimension_names, ndim); free(dimension_names); return (PyObject *)var; } static char createVariable_doc[] = ""; /* Return a variable object referring to an existing variable */ static PyNetCDFVariableObject * PyNetCDFFile_GetVariable(PyNetCDFFileObject *file, char *name) { return (PyNetCDFVariableObject *)PyDict_GetItemString(file->variables, name); } /* Synchronize output */ static int PyNetCDFFile_Sync(PyNetCDFFileObject *file) { int ret; if (check_if_open(file, 0)) { define_mode(file, 0); Py_BEGIN_ALLOW_THREADS; acquire_netCDF_lock(); ret = nc_sync(file->id); release_netCDF_lock(); Py_END_ALLOW_THREADS; if (ret == -1) { netcdf_seterror(); return -1; } else return 0; } else return -1; } static PyObject * PyNetCDFFileObject_sync(PyNetCDFFileObject *self, PyObject *args) { if (!PyArg_ParseTuple(args, "")) return NULL; if (PyNetCDFFile_Sync(self) == 0) { Py_INCREF(Py_None); return Py_None; } else return NULL; } static char sync_doc[] = ""; static char flush_doc[] = "ensures that all modified data is written to the file"; /* Close file */ static int PyNetCDFFile_Close(PyNetCDFFileObject *file) { PyObject *name; PyNetCDFVariableObject *variable; int ret; Py_ssize_t pos; if (!check_if_open(file, 0)) return -1; Py_BEGIN_ALLOW_THREADS; acquire_netCDF_lock(); ret = nc_close(file->id); release_netCDF_lock(); Py_END_ALLOW_THREADS; if (ret != NC_NOERR) { netcdf_signalerror(ret); ret = -1; } else ret = 0; file->open = 0; pos = 0; while (PyDict_Next(file->variables, &pos, &name, (PyObject **)&variable)) { Py_DECREF(variable->file); variable->file = NULL; } return ret; } static PyObject * PyNetCDFFileObject_close(PyNetCDFFileObject *self, PyObject *args) { char *history = NULL; if (!PyArg_ParseTuple(args, "|s", &history)) return NULL; if (history != NULL) PyNetCDFFile_AddHistoryLine(self, history); if (PyNetCDFFile_Close(self) == 0) { Py_INCREF(Py_None); return Py_None; } else return NULL; } static char close_doc[] = ""; /* Method table */ static PyMethodDef PyNetCDFFileObject_methods[] = { {"close", (PyCFunction)PyNetCDFFileObject_close, 1, close_doc}, {"createDimension", (PyCFunction)PyNetCDFFileObject_new_dimension, 1, createDimension_doc}, {"createVariable", (PyCFunction)PyNetCDFFileObject_new_variable, 1, createVariable_doc}, {"sync", (PyCFunction)PyNetCDFFileObject_sync, 1, sync_doc}, {"flush", (PyCFunction)PyNetCDFFileObject_sync, 1, flush_doc}, {NULL, NULL} /* sentinel */ }; /* Attribute access */ static PyObject * PyNetCDFFile_GetAttribute(PyNetCDFFileObject *self, char *name) { PyObject *value; if (check_if_open(self, -1)) { if (strcmp(name, "dimensions") == 0) { Py_INCREF(self->dimensions); return self->dimensions; } if (strcmp(name, "variables") == 0) { Py_INCREF(self->variables); return self->variables; } if (strcmp(name, "__dict__") == 0) { Py_INCREF(self->attributes); return self->attributes; } value = PyDict_GetItemString(self->attributes, name); if (value != NULL) { Py_INCREF(value); return value; } else { PyErr_Clear(); return Py_FindMethod(PyNetCDFFileObject_methods, (PyObject *)self, name); } } else return NULL; } static int PyNetCDFFile_SetAttribute(PyNetCDFFileObject *self, char *name, PyObject *value) { if (check_if_open(self, 1)) { if (strcmp(name, "dimensions") == 0 || strcmp(name, "variables") == 0 || strcmp(name, "__dict__") == 0) { PyErr_SetString(PyExc_TypeError, "object has read-only attributes"); return -1; } define_mode(self, 1); return set_attribute(self->id, NC_GLOBAL, self->attributes, name, value); } else return -1; } static int PyNetCDFFile_SetAttributeString(PyNetCDFFileObject *self, char *name, char *value) { PyObject *string = PyString_FromString(value); if (string != NULL) return PyNetCDFFile_SetAttribute(self, name, string); else return -1; } static int PyNetCDFFile_AddHistoryLine(PyNetCDFFileObject *self, char *text) { static char *history = "history"; Py_ssize_t alloc, old, new, new_alloc; PyStringObject *new_string; PyObject *h = PyNetCDFFile_GetAttribute(self, history); if (h == NULL) { PyErr_Clear(); alloc = 0; old = 0; new = strlen(text); } else { alloc = PyString_Size(h); old = strlen(PyString_AsString(h)); new = old + strlen(text) + 1; } new_alloc = (new <= alloc) ? alloc : new + 500; new_string = (PyStringObject *)PyString_FromStringAndSize(NULL, new_alloc); if (new_string) { char *s = new_string->ob_sval; int len, ret; memset(s, 0, new_alloc+1); if (h == NULL) len = -1; else { strcpy(s, PyString_AsString(h)); len = strlen(s); s[len] = '\n'; } strcpy(s+len+1, text); ret = PyNetCDFFile_SetAttribute(self, history, (PyObject *)new_string); Py_XDECREF(h); Py_DECREF(new_string); return ret; } else return -1; } /* Printed representation */ static PyObject * PyNetCDFFileObject_repr(PyNetCDFFileObject *file) { char buf[300]; sprintf(buf, "<%s netCDF file '%.256s', mode '%.10s' at %lx>", file->open ? "open" : "closed", PyString_AsString(file->name), PyString_AsString(file->mode), (long)file); return PyString_FromString(buf); } /* Type definition */ statichere PyTypeObject PyNetCDFFile_Type = { PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ "NetCDFFile", /*tp_name*/ sizeof(PyNetCDFFileObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ (destructor)PyNetCDFFileObject_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ (getattrfunc)PyNetCDFFile_GetAttribute, /*tp_getattr*/ (setattrfunc)PyNetCDFFile_SetAttribute, /*tp_setattr*/ 0, /*tp_compare*/ (reprfunc)PyNetCDFFileObject_repr, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash*/ 0, /*tp_call*/ 0, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT, /*tp_flags*/ "NetCDFFile(filename, mode, history_line)\n\nopens a netCDF file\n", /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ PyNetCDFFileObject_methods, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ (initproc)PyNetCDFFileObject_init, /* tp_init */ 0, /* tp_alloc */ PyNetCDFFileObject_new, /* tp_new */ }; /* * NetCDFVariable object * (type declaration in netcdfmodule.h) */ /* Destroy variable object */ static void PyNetCDFVariableObject_dealloc(PyNetCDFVariableObject *self) { if (self->dimids != NULL) free(self->dimids); if (self->dimensions != NULL) free(self->dimensions); if (self->name != NULL) free(self->name); Py_XDECREF(self->file); Py_XDECREF(self->attributes); self->ob_type->tp_free((PyObject*)self); } /* Create variable object */ static PyNetCDFVariableObject * netcdf_variable_new(PyNetCDFFileObject *file, char *name, int id, int type, int ndims, int *dimids, int nattrs) { PyNetCDFVariableObject *self; int recdim; int i; if (check_if_open(file, -1)) { self = PyObject_NEW(PyNetCDFVariableObject, &PyNetCDFVariable_Type); if (self == NULL) return NULL; self->file = file; Py_INCREF(file); self->id = id; self->type = type; self->nd = ndims; self->dimids = dimids; self->unlimited = 0; Py_BEGIN_ALLOW_THREADS; acquire_netCDF_lock(); nc_inq_unlimdim(file->id, &recdim); self->dimensions = (size_t *)malloc(ndims*sizeof(size_t)); if (self->dimensions != NULL) { for (i = 0; i < ndims; i++) nc_inq_dimlen(file->id, dimids[i], &self->dimensions[i]); if (ndims > 0 && self->dimids[0] == self->file->recdim) self->unlimited = 1; } release_netCDF_lock(); Py_END_ALLOW_THREADS; self->name = (char *)malloc(strlen(name)+1); if (self->name != NULL) strcpy(self->name, name); self->attributes = PyDict_New(); collect_attributes(file->id, self->id, self->attributes, nattrs); return self; } else return NULL; } /* Return value */ static PyObject * PyNetCDFVariableObject_value(PyNetCDFVariableObject *self, PyObject *args) { PyNetCDFIndex *indices; if (!PyArg_ParseTuple(args, "")) return NULL; if (self->nd == 0) indices = NULL; else indices = PyNetCDFVariable_Indices(self); return PyArray_Return(PyNetCDFVariable_ReadAsArray(self, indices)); } /* Assign value */ static PyObject * PyNetCDFVariableObject_assign(PyNetCDFVariableObject *self, PyObject *args) { PyObject *value; PyNetCDFIndex *indices; if (!PyArg_ParseTuple(args, "O", &value)) return NULL; if (self->nd == 0) indices = NULL; else indices = PyNetCDFVariable_Indices(self); if (PyNetCDFVariable_WriteArray(self, indices, value) < 0) return NULL; Py_INCREF(Py_None); return Py_None; } /* Return typecode */ static PyObject * PyNetCDFVariableObject_typecode(PyNetCDFVariableObject *self, PyObject *args) { char t; if (!PyArg_ParseTuple(args, "")) return NULL; t = typecode(self->type); return PyString_FromStringAndSize(&t, (Py_ssize_t)1); } /* Method table */ static PyMethodDef PyNetCDFVariableObject_methods[] = { {"assignValue", (PyCFunction)PyNetCDFVariableObject_assign, 1}, {"getValue", (PyCFunction)PyNetCDFVariableObject_value, 1}, {"typecode", (PyCFunction)PyNetCDFVariableObject_typecode, 1}, {NULL, NULL} /* sentinel */ }; /* Attribute access */ static int PyNetCDFVariable_GetRank(PyNetCDFVariableObject *var) { return var->nd; } static size_t * PyNetCDFVariable_GetShape(PyNetCDFVariableObject *var) { int i; if (check_if_open(var->file, -1)) { Py_BEGIN_ALLOW_THREADS; acquire_netCDF_lock(); for (i = 0; i < var->nd; i++) nc_inq_dimlen(var->file->id, var->dimids[i], &var->dimensions[i]); release_netCDF_lock(); Py_END_ALLOW_THREADS; return var->dimensions; } else return NULL; } static PyObject * PyNetCDFVariable_GetAttribute(PyNetCDFVariableObject *self, char *name) { PyObject *value; if (strcmp(name, "shape") == 0) { PyObject *tuple; int i; if (check_if_open(self->file, -1)) { PyNetCDFVariable_GetShape(self); tuple = PyTuple_New((Py_ssize_t)self->nd); for (i = 0; i < self->nd; i++) PyTuple_SetItem(tuple, (Py_ssize_t)i, PyInt_FromLong(self->dimensions[i])); return tuple; } else return NULL; } if (strcmp(name, "dimensions") == 0) { PyObject *tuple; char name[MAX_NC_NAME]; int i; if (check_if_open(self->file, -1)) { tuple = PyTuple_New((Py_ssize_t)self->nd); for (i = 0; i < self->nd; i++) { Py_BEGIN_ALLOW_THREADS; acquire_netCDF_lock(); nc_inq_dimname(self->file->id, self->dimids[i], name); release_netCDF_lock(); Py_END_ALLOW_THREADS; PyTuple_SetItem(tuple, (Py_ssize_t)i, PyString_FromString(name)); } return tuple; } else return NULL; } if (strcmp(name, "__dict__") == 0) { Py_INCREF(self->attributes); return self->attributes; } value = PyDict_GetItemString(self->attributes, name); if (value != NULL) { Py_INCREF(value); return value; } else { PyErr_Clear(); return Py_FindMethod(PyNetCDFVariableObject_methods, (PyObject *)self,name); } } static int PyNetCDFVariable_SetAttribute(PyNetCDFVariableObject *self, char *name, PyObject *value) { if (check_if_open(self->file, 1)) { if (strcmp(name, "shape") == 0 || strcmp(name, "dimensions") == 0 || strcmp(name, "__dict__") == 0) { PyErr_SetString(PyExc_TypeError, "object has read-only attributes"); return -1; } define_mode(self->file, 1); return set_attribute(self->file->id, self->id, self->attributes, name, value); } else return -1; } static int PyNetCDFVariable_SetAttributeString(PyNetCDFVariableObject *self, char *name, char *value) { PyObject *string = PyString_FromString(value); if (string != NULL) return PyNetCDFVariable_SetAttribute(self, name, string); else return -1; } /* Subscripting */ static Py_ssize_t PyNetCDFVariableObject_length(PyNetCDFVariableObject *self) { if (self->nd > 0) return (Py_ssize_t)self->dimensions[0]; else return (Py_ssize_t)0; } static PyNetCDFIndex * PyNetCDFVariable_Indices(PyNetCDFVariableObject *var) { PyNetCDFIndex *indices = (PyNetCDFIndex *)malloc(var->nd*sizeof(PyNetCDFIndex)); int i; if (indices != NULL) for (i = 0; i < var->nd; i++) { indices[i].start = 0; indices[i].stop = var->dimensions[i]; indices[i].stride = 1; indices[i].item = 0; } else PyErr_SetString(PyExc_MemoryError, "out of memory"); return indices; } static PyArrayObject * PyNetCDFVariable_ReadAsArray(PyNetCDFVariableObject *self, PyNetCDFIndex *indices) { npy_intp *dims; PyArrayObject *array; int i, d; int nitems; int error = 0; d = 0; nitems = 1; if (!check_if_open(self->file, -1)) { free(indices); return NULL; } define_mode(self->file, 0); if (self->nd == 0) dims = NULL; else { dims = (npy_intp *)malloc(self->nd*sizeof(npy_intp)); if (dims == NULL) { free(indices); return (PyArrayObject *)PyErr_NoMemory(); } } for (i = 0; i < self->nd; i++) { error = error || (indices[i].stride <= 0); if (indices[i].start < 0) indices[i].start += self->dimensions[i]; if (indices[i].start < 0) indices[i].start = 0; if (indices[i].start > self->dimensions[i]) indices[i].start = self->dimensions[i]; if (indices[i].item != 0) indices[i].stop = indices[i].start + 1; else { if (indices[i].stop < 0) indices[i].stop += self->dimensions[i]; if (indices[i].stop < 0) indices[i].stop = 0; if (indices[i].stop > self->dimensions[i]) indices[i].stop = self->dimensions[i]; dims[d] = (indices[i].stop-indices[i].start-1)/indices[i].stride+1; if (dims[d] < 0) dims[d] = 0; nitems *= dims[d]; d++; } } if (error) { PyErr_SetString(PyExc_IndexError, "illegal index"); if (dims != NULL) free(dims); if (indices != NULL) free(indices); return NULL; } #if defined(NUMPY) array = (PyArrayObject *)PyArray_SimpleNew (d, dims, self->type); #else array = (PyArrayObject *)PyArray_FromDims(d, dims, self->type); #endif if (array != NULL && nitems > 0) { if (self->nd == 0) { long zero = 0; int ret; Py_BEGIN_ALLOW_THREADS; acquire_netCDF_lock(); ret = ncvarget1(self->file->id, self->id, &zero, array->data); release_netCDF_lock(); Py_END_ALLOW_THREADS; if (ret == -1) { netcdf_seterror(); Py_DECREF(array); array = NULL; } } else { long *start; long *count; long *stride; start = (long *)malloc(self->nd*sizeof(long)); count = (long *)malloc(self->nd*sizeof(long)); stride = (long *)malloc(self->nd*sizeof(long)); if (start != NULL && count != NULL && stride != NULL) { int ret; for (i = 0; i < self->nd; i++) { start[i] = indices[i].start; stride[i] = indices[i].stride; count[i] = (indices[i].stop-indices[i].start-1)/indices[i].stride+1; } Py_BEGIN_ALLOW_THREADS; acquire_netCDF_lock(); ret = ncvargetg(self->file->id, self->id, start, count, stride, NULL, array->data); release_netCDF_lock(); Py_END_ALLOW_THREADS; if (ret == -1) { netcdf_seterror(); Py_DECREF(array); array = NULL; } } if (start != NULL) free(start); if (count != NULL) free(count); if (stride != NULL) free(stride); } } free(dims); free(indices); return array; } static PyStringObject * PyNetCDFVariable_ReadAsString(PyNetCDFVariableObject *self) { if (self->type != PyArray_CHAR || self->nd != 1) { PyErr_SetString(PyExc_IOError, "netcdf: not a string variable"); return NULL; } if (check_if_open(self->file, -1)) { int ret; char *temp; PyObject *string; define_mode(self->file, 0); temp = (char *)malloc((self->dimensions[0]+1)*sizeof(char)); if (temp == NULL) return (PyStringObject *)PyErr_NoMemory(); Py_BEGIN_ALLOW_THREADS; acquire_netCDF_lock(); ret = nc_get_var_text(self->file->id, self->id, temp); release_netCDF_lock(); Py_END_ALLOW_THREADS; if (ret != NC_NOERR) { netcdf_signalerror(ret); string = NULL; } else { temp[self->dimensions[0]] = '\0'; string = PyString_FromString(temp); } free(temp); return (PyStringObject *)string; } else return NULL; } #include "time.h" static int PyNetCDFVariable_WriteArray(PyNetCDFVariableObject *self, PyNetCDFIndex *indices, PyObject *value) { int *dims; PyArrayObject *array; int i, j, d; int nitems; int error = 0; int ret = 0; d = 0; nitems = 1; if (!check_if_open(self->file, 1)) { free(indices); return -1; } if (self->nd == 0) dims = NULL; else { dims = (int *)malloc(self->nd*sizeof(int)); if (dims == NULL) { free(indices); PyErr_SetString(PyExc_MemoryError, "out of memory"); return -1; } } define_mode(self->file, 0); for (i = 0; i < self->nd; i++) { error = error || (indices[i].stride <= 0); if (indices[i].start < 0) indices[i].start += self->dimensions[i]; if (indices[i].start < 0) indices[i].start = 0; if (indices[i].stop < 0) indices[i].stop += self->dimensions[i]; if (indices[i].stop < 0) indices[i].stop = 0; if (i > 0 || !self->unlimited) { if (indices[i].start > self->dimensions[i]) indices[i].start = self->dimensions[i]; if (indices[i].stop > self->dimensions[i]) indices[i].stop = self->dimensions[i]; } if (indices[i].item == 0) { dims[d] = (indices[i].stop-indices[i].start-1)/indices[i].stride+1; if (dims[d] < 0) dims[d] = 0; nitems *= dims[d]; d++; } else indices[i].stop = indices[i].start + 1; } if (error) { PyErr_SetString(PyExc_IndexError, "illegal index"); free(dims); free(indices); return -1; } array = (PyArrayObject *)PyArray_ContiguousFromObject(value, self->type, 0, d); if (array != NULL) { if (self->nd == 0) { size_t zero = 0; Py_BEGIN_ALLOW_THREADS; acquire_netCDF_lock(); error = nc_put_var1_any(self->file->id, self->id, netcdf_type_from_type(self->type), &zero, array->data); release_netCDF_lock(); Py_END_ALLOW_THREADS; if (error != NC_NOERR) { netcdf_signalerror(ret); ret = -1; } } else { size_t *start; size_t *count, *count1; ptrdiff_t *stride; size_t *current; char *loop; long repeat = 1; int lastloop = 0; start = (size_t *)malloc(self->nd*sizeof(size_t)); count = (size_t *)malloc(self->nd*sizeof(size_t)); count1 = (size_t *)malloc(self->nd*sizeof(size_t)); stride = (ptrdiff_t *)malloc(self->nd*sizeof(ptrdiff_t)); current = (size_t *)malloc(self->nd*sizeof(size_t)); loop = (char *)malloc(self->nd*sizeof(char)); if (start != NULL && count != NULL && count1 != NULL && stride != NULL && current != NULL && loop != NULL) { for (i = 0; i < self->nd; i++) { start[i] = indices[i].start; stride[i] = indices[i].stride; count[i] = (indices[i].stop-indices[i].start-1)/indices[i].stride+1; count1[i] = count[i]; current[i] = 0; loop[i] = 0; } for (i = array->nd-1, j = self->nd-1; i >= 0 && j >= 0; i--, j--) { while (j >= 0 && indices[j].item) j--; if (j < 0) { ret = -1; break; } if (array->dimensions[i] != count[j]) { if (self->unlimited && j == 0 && indices[j].stop == self->dimensions[j] && array->dimensions[i] > count[j]) { count[j] = array->dimensions[i]; count1[j] = array->dimensions[i]; } else ret = -1; } } if (i == -1) { lastloop = -1; while (j >= 0) { loop[j] = !indices[j].item; if (loop[j]) { if (lastloop < 0) lastloop = j; repeat *= count[j]; count1[j] = 1; } j--; } } else ret = -1; if (ret == -1) PyErr_SetString(PyExc_ValueError, "shapes are not aligned"); Py_BEGIN_ALLOW_THREADS; acquire_netCDF_lock(); error = NC_NOERR; while (repeat--) { error = nc_put_vars_any(self->file->id, self->id, netcdf_type_from_type(self->type), start, count1, stride, array->data); if (error != NC_NOERR) break; if (lastloop >= 0) { for (i = lastloop; i >= 0; i--) { while (!loop[i] && i >= 0) i--; if (i >= 0) { start[i] += stride[i]; if (++current[i] != count[i]) break; start[i] -= count[i]*stride[i]; current[i] = 0; } } } } if (self->unlimited) error = nc_inq_dimlen(self->file->id, self->dimids[0], &self->dimensions[0]); release_netCDF_lock(); Py_END_ALLOW_THREADS; if (error != NC_NOERR) { netcdf_signalerror(error); ret = -1; } } if (start != NULL) free(start); if (count != NULL) free(count); if (count1 != NULL) free(count1); if (stride != NULL) free(stride); if (current != NULL) free(current); if (loop != NULL) free(loop); } Py_DECREF(array); free(dims); free(indices); return ret; } else { free(dims); free(indices); return -1; } } static int PyNetCDFVariable_WriteString(PyNetCDFVariableObject *self, PyStringObject *value) { if (self->type != PyArray_CHAR || self->nd != 1) { PyErr_SetString(PyExc_IOError, "netcdf: not a string variable"); return -1; } if (PyString_Size((PyObject *)value) > self->dimensions[0]) { PyErr_SetString(PyExc_ValueError, "string too long"); return -1; } if (check_if_open(self->file, 1)) { int ret; define_mode(self->file, 0); Py_BEGIN_ALLOW_THREADS; acquire_netCDF_lock(); ret = nc_put_var_text(self->file->id, self->id, PyString_AsString((PyObject *)value)); release_netCDF_lock(); Py_END_ALLOW_THREADS; if (ret != NC_NOERR) { netcdf_signalerror(ret); return -1; } return 0; } else return -1; } static PyObject * PyNetCDFVariableObject_item(PyNetCDFVariableObject *self, Py_ssize_t i) { PyNetCDFIndex *indices; if (self->nd == 0) { PyErr_SetString(PyExc_TypeError, "Not a sequence"); return NULL; } indices = PyNetCDFVariable_Indices(self); if (indices != NULL) { indices[0].start = i; indices[0].stop = i+1; indices[0].item = 1; return PyArray_Return(PyNetCDFVariable_ReadAsArray(self, indices)); } return NULL; } static PyObject * PyNetCDFVariableObject_slice(PyNetCDFVariableObject *self, Py_ssize_t low, Py_ssize_t high) { PyNetCDFIndex *indices; if (self->nd == 0) { PyErr_SetString(PyExc_TypeError, "Not a sequence"); return NULL; } indices = PyNetCDFVariable_Indices(self); if (indices != NULL) { indices[0].start = low; indices[0].stop = high; return PyArray_Return(PyNetCDFVariable_ReadAsArray(self, indices)); } return NULL; } static PyObject * PyNetCDFVariableObject_subscript(PyNetCDFVariableObject *self, PyObject *index) { PyNetCDFIndex *indices; if (PyInt_Check(index)) { int i = PyInt_AsLong(index); return PyNetCDFVariableObject_item(self, i); } if (self->nd == 0) { PyErr_SetString(PyExc_TypeError, "Not a sequence"); return NULL; } indices = PyNetCDFVariable_Indices(self); if (indices != NULL) { if (PySlice_Check(index)) { PySlice_GetIndices((PySliceObject *)index, (Py_ssize_t)self->dimensions[0], &indices->start, &indices->stop, &indices->stride); return PyArray_Return(PyNetCDFVariable_ReadAsArray(self, indices)); } if (PyTuple_Check(index)) { int ni; Py_ssize_t len_dim = PyTuple_Size(index); if (len_dim > INT_MAX) { PyErr_SetString(PyExc_ValueError, "too many dimensions"); return NULL; } ni = (int)len_dim; if (ni <= self->nd) { int i, d; d = 0; for (i = 0; i < ni; i++) { PyObject *subscript = PyTuple_GetItem(index, (Py_ssize_t)i); if (PyInt_Check(subscript)) { int n = PyInt_AsLong(subscript); indices[d].start = n; indices[d].stop = n+1; indices[d].item = 1; d++; } else if (PySlice_Check(subscript)) { PySlice_GetIndices((PySliceObject *)subscript, self->dimensions[d], &indices[d].start, &indices[d].stop, &indices[d].stride); d++; } else if (subscript == Py_Ellipsis) { d = self->nd - ni + i + 1; } else { PyErr_SetString(PyExc_TypeError, "illegal subscript type"); free(indices); return NULL; } } return PyArray_Return(PyNetCDFVariable_ReadAsArray(self, indices)); } else { PyErr_SetString(PyExc_IndexError, "too many subscripts"); free(indices); return NULL; } } PyErr_SetString(PyExc_TypeError, "illegal subscript type"); free(indices); } return NULL; } static int PyNetCDFVariableObject_ass_item(PyNetCDFVariableObject *self, Py_ssize_t i, PyObject *value) { PyNetCDFIndex *indices; if (value == NULL) { PyErr_SetString(PyExc_ValueError, "Can't delete elements."); return -1; } if (self->nd == 0) { PyErr_SetString(PyExc_TypeError, "Not a sequence"); return -1; } indices = PyNetCDFVariable_Indices(self); if (indices != NULL) { indices[0].start = i; indices[0].stop = i+1; indices[0].item = 1; return PyNetCDFVariable_WriteArray(self, indices, value); } return -1; } static int PyNetCDFVariableObject_ass_slice(PyNetCDFVariableObject *self, Py_ssize_t low, Py_ssize_t high, PyObject *value) { PyNetCDFIndex *indices; if (value == NULL) { PyErr_SetString(PyExc_ValueError, "Can't delete elements."); return -1; } if (self->nd == 0) { PyErr_SetString(PyExc_TypeError, "Not a sequence"); return -1; } if (low < -(long)self->dimensions[0]) low = -self->dimensions[0]; if (low < 0) low += self->dimensions[0]; if (high < low) high = low; if (self->unlimited && self->dimids[0] == self->file->recdim) { if (high > self->dimensions[0]) high = self->dimensions[0]; } indices = PyNetCDFVariable_Indices(self); if (indices != NULL) { indices[0].start = low; indices[0].stop = high; return PyNetCDFVariable_WriteArray(self, indices, value); } return -1; } static int PyNetCDFVariableObject_ass_subscript(PyNetCDFVariableObject *self, PyObject *index, PyObject *value) { PyNetCDFIndex *indices; if (PyInt_Check(index)) { int i = PyInt_AsLong(index); return PyNetCDFVariableObject_ass_item(self, i, value); } if (value == NULL) { PyErr_SetString(PyExc_ValueError, "Can't delete elements."); return -1; } if (self->nd == 0) { PyErr_SetString(PyExc_TypeError, "Not a sequence"); return -1; } indices = PyNetCDFVariable_Indices(self); if (indices != NULL) { if (PySlice_Check(index)) { PySlice_GetIndices((PySliceObject *)index, self->dimensions[0], &indices->start, &indices->stop, &indices->stride); return PyNetCDFVariable_WriteArray(self, indices, value); } if (PyTuple_Check(index)) { int ni; Py_ssize_t len_dim = PyTuple_Size(index); if (len_dim > INT_MAX) { PyErr_SetString(PyExc_ValueError, "too many dimensions"); return -1; } ni = (int)len_dim; if (ni <= self->nd) { int i, d; d = 0; for (i = 0; i < ni; i++) { PyObject *subscript = PyTuple_GetItem(index, (Py_ssize_t)i); if (PyInt_Check(subscript)) { int n = PyInt_AsLong(subscript); indices[d].start = n; indices[d].stop = n+1; indices[d].item = 1; d++; } else if (PySlice_Check(subscript)) { PySlice_GetIndices((PySliceObject *)subscript, self->dimensions[d], &indices[d].start, &indices[d].stop, &indices[d].stride); d++; } else if (subscript == Py_Ellipsis) { d = self->nd - ni + i + 1; } else { PyErr_SetString(PyExc_TypeError, "illegal subscript type"); free(indices); return -1; } } return PyNetCDFVariable_WriteArray(self, indices, value); } else { PyErr_SetString(PyExc_IndexError, "too many subscripts"); free(indices); return -1; } } PyErr_SetString(PyExc_TypeError, "illegal subscript type"); free(indices); } return -1; } /* Type definition */ static PyObject * PyNetCDFVariableObject_error1(PyNetCDFVariableObject *self, PyNetCDFVariableObject *other) { PyErr_SetString(PyExc_TypeError, "can't add netCDF variables"); return NULL; } static PyObject * PyNetCDFVariableObject_error2(PyNetCDFVariableObject *self, Py_ssize_t n) { PyErr_SetString(PyExc_TypeError, "can't multiply netCDF variables"); return NULL; } static PySequenceMethods PyNetCDFVariableObject_as_sequence = { (lenfunc)PyNetCDFVariableObject_length, /*sq_length*/ (binaryfunc)PyNetCDFVariableObject_error1, /*nb_add*/ (ssizeargfunc)PyNetCDFVariableObject_error2, /*nb_multiply*/ (ssizeargfunc)PyNetCDFVariableObject_item, /*sq_item*/ (ssizessizeargfunc)PyNetCDFVariableObject_slice, /*sq_slice*/ (ssizeobjargproc)PyNetCDFVariableObject_ass_item, /*sq_ass_item*/ (ssizessizeobjargproc)PyNetCDFVariableObject_ass_slice, /*sq_ass_slice*/ }; static PyMappingMethods PyNetCDFVariableObject_as_mapping = { (lenfunc)PyNetCDFVariableObject_length, /*mp_length*/ (binaryfunc)PyNetCDFVariableObject_subscript, /*mp_subscript*/ (objobjargproc)PyNetCDFVariableObject_ass_subscript, /*mp_ass_subscript*/ }; statichere PyTypeObject PyNetCDFVariable_Type = { PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ "NetCDFVariable", /*tp_name*/ sizeof(PyNetCDFVariableObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ (destructor)PyNetCDFVariableObject_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ (getattrfunc)PyNetCDFVariable_GetAttribute, /*tp_getattr*/ (setattrfunc)PyNetCDFVariable_SetAttribute, /*tp_setattr*/ 0, /*tp_compare*/ 0, /*tp_repr*/ 0, /*tp_as_number*/ &PyNetCDFVariableObject_as_sequence, /*tp_as_sequence*/ &PyNetCDFVariableObject_as_mapping, /*tp_as_mapping*/ 0, /*tp_hash*/ 0, /*tp_call*/ 0, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT, /*tp_flags*/ "NetCDF Variable", /* tp_doc */ }; /* Table of functions defined in the module */ static PyMethodDef netcdf_methods[] = { {NULL, NULL} /* sentinel */ }; /* Module initialization */ DL_EXPORT(void) initScientific_netcdf(void) { PyObject *m; static void *PyNetCDF_API[PyNetCDF_API_pointers]; /* Initialize netcdf variables */ ncopts = 0; /* Initialize type objects */ PyNetCDFFile_Type.tp_new = PyType_GenericNew; if (PyType_Ready(&PyNetCDFFile_Type) < 0) return; PyNetCDFVariable_Type.tp_new = PyType_GenericNew; if (PyType_Ready(&PyNetCDFVariable_Type) < 0) return; /* Create netCDF lock */ #ifdef WITH_THREAD netCDF_lock = PyThread_allocate_lock(); #endif /* Create the module and add the functions */ m = Py_InitModule("Scientific_netcdf", netcdf_methods); /* Import the array module */ import_array(); /* Initialize C API pointer array and store in module */ PyNetCDF_API[PyNetCDFFile_Type_NUM] = (void *)&PyNetCDFFile_Type; PyNetCDF_API[PyNetCDFVariable_Type_NUM] = (void *)&PyNetCDFVariable_Type; PyNetCDF_API[PyNetCDFFile_Open_NUM] = (void *)&PyNetCDFFile_Open; PyNetCDF_API[PyNetCDFFile_Close_NUM] = (void *)&PyNetCDFFile_Close; PyNetCDF_API[PyNetCDFFile_Sync_NUM] = (void *)&PyNetCDFFile_Sync; PyNetCDF_API[PyNetCDFFile_CreateDimension_NUM] = (void *)&PyNetCDFFile_CreateDimension; PyNetCDF_API[PyNetCDFFile_CreateVariable_NUM] = (void *)&PyNetCDFFile_CreateVariable; PyNetCDF_API[PyNetCDFFile_GetVariable_NUM] = (void *)&PyNetCDFFile_GetVariable; PyNetCDF_API[PyNetCDFVariable_GetRank_NUM] = (void *)&PyNetCDFVariable_GetRank; PyNetCDF_API[PyNetCDFVariable_GetShape_NUM] = (void *)&PyNetCDFVariable_GetShape; PyNetCDF_API[PyNetCDFVariable_Indices_NUM] = (void *)&PyNetCDFVariable_Indices; PyNetCDF_API[PyNetCDFVariable_ReadAsArray_NUM] = (void *)&PyNetCDFVariable_ReadAsArray; PyNetCDF_API[PyNetCDFVariable_ReadAsString_NUM] = (void *)&PyNetCDFVariable_ReadAsString; PyNetCDF_API[PyNetCDFVariable_WriteArray_NUM] = (void *)&PyNetCDFVariable_WriteArray; PyNetCDF_API[PyNetCDFVariable_WriteString_NUM] = (void *)&PyNetCDFVariable_WriteString; PyNetCDF_API[PyNetCDFFile_GetAttribute_NUM] = (void *)&PyNetCDFFile_GetAttribute; PyNetCDF_API[PyNetCDFFile_SetAttribute_NUM] = (void *)&PyNetCDFFile_SetAttribute; PyNetCDF_API[PyNetCDFFile_SetAttributeString_NUM] = (void *)&PyNetCDFFile_SetAttributeString; PyNetCDF_API[PyNetCDFVariable_GetAttribute_NUM] = (void *)&PyNetCDFVariable_GetAttribute; PyNetCDF_API[PyNetCDFVariable_SetAttribute_NUM] = (void *)&PyNetCDFVariable_SetAttribute; PyNetCDF_API[PyNetCDFVariable_SetAttributeString_NUM] = (void *)&PyNetCDFVariable_SetAttributeString; PyNetCDF_API[PyNetCDFFile_AddHistoryLine_NUM] = (void *)&PyNetCDFFile_AddHistoryLine; PyModule_AddObject(m, "_C_API", PyCObject_FromVoidPtr((void *)PyNetCDF_API, NULL)); /* Add the netCDF file type object */ Py_INCREF(&PyNetCDFFile_Type); PyModule_AddObject(m, "NetCDFFile", (PyObject *)&PyNetCDFFile_Type); /* Check for errors */ if (PyErr_Occurred()) Py_FatalError("can't initialize module Scientific_netcdf"); }