1 #include <Python.h>
2 #include <inttypes.h>
3 #include "pyBigWig.h"
4 
5 #ifdef WITHNUMPY
6 #include <float.h>
7 #include "numpy/npy_common.h"
8 #include "numpy/halffloat.h"
9 #include "numpy/ndarrayobject.h"
10 #include "numpy/arrayscalars.h"
11 
12 int lsize = NPY_SIZEOF_LONG;
13 
14 //Raises an exception on error, which should be checked
getNumpyU32(PyArrayObject * obj,Py_ssize_t i)15 uint32_t getNumpyU32(PyArrayObject *obj, Py_ssize_t i) {
16     int dtype;
17     char *p;
18     uint32_t o = 0;
19     npy_intp stride;
20 
21     //Get the dtype
22     dtype = PyArray_TYPE(obj);
23     //Get the stride
24     stride = PyArray_STRIDE(obj, 0);
25     p = PyArray_BYTES(obj) + i*stride;
26 
27     switch(dtype) {
28     case NPY_INT8:
29         if(((int8_t *) p)[0] < 0) {
30             PyErr_SetString(PyExc_RuntimeError, "Received an integer < 0!\n");
31             goto error;
32         }
33         o += ((int8_t *) p)[0];
34         break;
35     case NPY_INT16:
36         if(((int16_t *) p)[0] < 0) {
37             PyErr_SetString(PyExc_RuntimeError, "Received an integer < 0!\n");
38             goto error;
39         }
40         o += ((int16_t *) p)[0];
41         break;
42     case NPY_INT32:
43         if(((int32_t *) p)[0] < 0) {
44             PyErr_SetString(PyExc_RuntimeError, "Received an integer < 0!\n");
45             goto error;
46         }
47         o += ((int32_t *) p)[0];
48         break;
49     case NPY_INT64:
50         if(((int64_t *) p)[0] < 0) {
51             PyErr_SetString(PyExc_RuntimeError, "Received an integer < 0!\n");
52             goto error;
53         }
54         o += ((int64_t *) p)[0];
55         break;
56     case NPY_UINT8:
57         o += ((uint8_t *) p)[0];
58         break;
59     case NPY_UINT16:
60         o += ((uint16_t *) p)[0];
61         break;
62     case NPY_UINT32:
63         o += ((uint32_t *) p)[0];
64         break;
65     case NPY_UINT64:
66         if(((uint64_t *) p)[0] > (uint32_t) -1) {
67             PyErr_SetString(PyExc_RuntimeError, "Received an integer larger than possible for a 32bit unsigned integer!\n");
68             goto error;
69         }
70         o += ((uint64_t *) p)[0];
71         break;
72     default:
73         PyErr_SetString(PyExc_RuntimeError, "Received unknown data type for conversion to uint32_t!\n");
74         goto error;
75         break;
76     }
77     return o;
78 
79 error:
80     return 0;
81 };
82 
getNumpyL(PyObject * obj)83 long getNumpyL(PyObject *obj) {
84     short s;
85     int i;
86     long l;
87     long long ll;
88     unsigned short us;
89     unsigned int ui;
90     unsigned long ul;
91     unsigned long long ull;
92 
93     if(!PyArray_IsIntegerScalar(obj)) {
94         PyErr_SetString(PyExc_RuntimeError, "Received non-Integer scalar type for conversion to long!\n");
95         return 0;
96     }
97 
98     if(PyArray_IsScalar(obj, Short)) {
99         s = ((PyShortScalarObject *)obj)->obval;
100         l = s;
101     } else if(PyArray_IsScalar(obj, Int)) {
102         i = ((PyLongScalarObject *)obj)->obval;
103         l = i;
104     } else if(PyArray_IsScalar(obj, Long)) {
105         l = ((PyLongScalarObject *)obj)->obval;
106     } else if(PyArray_IsScalar(obj, LongLong)) {
107         ll = ((PyLongScalarObject *)obj)->obval;
108         l = ll;
109     } else if(PyArray_IsScalar(obj, UShort)) {
110         us = ((PyLongScalarObject *)obj)->obval;
111         l = us;
112     } else if(PyArray_IsScalar(obj, UInt)) {
113         ui = ((PyLongScalarObject *)obj)->obval;
114         l = ui;
115     } else if(PyArray_IsScalar(obj, ULong)) {
116         ul = ((PyLongScalarObject *)obj)->obval;
117         l = ul;
118     } else if(PyArray_IsScalar(obj, ULongLong)) {
119         ull = ((PyLongScalarObject *)obj)->obval;
120         l = ull;
121     } else {
122         PyErr_SetString(PyExc_RuntimeError, "Received unknown scalar type for conversion to long!\n");
123         return 0;
124     }
125 
126     return l;
127 }
128 
129 //Raises an exception on error, which should be checked
getNumpyF(PyArrayObject * obj,Py_ssize_t i)130 float getNumpyF(PyArrayObject *obj, Py_ssize_t i) {
131     int dtype;
132     char *p;
133     float o = 0.0;
134     npy_intp stride;
135 
136     //Get the dtype
137     dtype = PyArray_TYPE(obj);
138     //Get the stride
139     stride = PyArray_STRIDE(obj, 0);
140     p = PyArray_BYTES(obj) + i*stride;
141 
142     switch(dtype) {
143     case NPY_FLOAT16:
144         return npy_half_to_float(((npy_half*)p)[0]);
145     case NPY_FLOAT32:
146         return ((float*)p)[0];
147     case NPY_FLOAT64:
148         if(((double*)p)[0] > FLT_MAX) {
149             PyErr_SetString(PyExc_RuntimeError, "Received a floating point value greater than possible for a 32-bit float!\n");
150             goto error;
151         }
152         if(((double*)p)[0] < -FLT_MAX) {
153             PyErr_SetString(PyExc_RuntimeError, "Received a floating point value less than possible for a 32-bit float!\n");
154             goto error;
155         }
156         o += ((double*)p)[0];
157         return o;
158     default:
159         PyErr_SetString(PyExc_RuntimeError, "Received unknown data type for conversion to float!\n");
160         goto error;
161         break;
162     }
163     return o;
164 
165 error:
166     return 0;
167 }
168 
169 //The calling function needs to free the result
getNumpyStr(PyArrayObject * obj,Py_ssize_t i)170 char *getNumpyStr(PyArrayObject *obj, Py_ssize_t i) {
171     char *p , *o = NULL;
172     npy_intp stride, j;
173     int dtype;
174 
175     //Get the dtype
176     dtype = PyArray_TYPE(obj);
177     //Get the stride
178     stride = PyArray_STRIDE(obj, 0);
179     p = PyArray_BYTES(obj) + i*stride;
180 
181     switch(dtype) {
182     case NPY_STRING:
183         o = calloc(1, stride + 1);
184         strncpy(o, p, stride);
185         return o;
186     case NPY_UNICODE:
187         o = calloc(1, stride/4 + 1);
188         for(j=0; j<stride/4; j++) o[j] = (char) ((uint32_t*)p)[j];
189         return o;
190     default:
191         PyErr_SetString(PyExc_RuntimeError, "Received unknown data type!\n");
192         break;
193     }
194     return NULL;
195 }
196 #endif
197 
198 //Return 1 if there are any entries at all
hasEntries(bigWigFile_t * bw)199 int hasEntries(bigWigFile_t *bw) {
200     if(bw->hdr->indexOffset != 0) return 1;  // No index, no entries pyBigWig issue #111
201     //if(bw->hdr->nBasesCovered > 0) return 1;  // Sometimes headers are broken
202     return 0;
203 }
204 
pyBwEnter(pyBigWigFile_t * self,PyObject * args)205 PyObject* pyBwEnter(pyBigWigFile_t*self, PyObject *args) {
206     bigWigFile_t *bw = self->bw;
207 
208     if(!bw) {
209         PyErr_SetString(PyExc_RuntimeError, "The bigWig file handle is not opened!");
210         return NULL;
211     }
212 
213     Py_INCREF(self);
214 
215     return (PyObject*) self;
216 }
217 
pyBwOpen(PyObject * self,PyObject * pyFname)218 PyObject* pyBwOpen(PyObject *self, PyObject *pyFname) {
219     char *fname = NULL;
220     char *mode = "r";
221     pyBigWigFile_t *pybw;
222     bigWigFile_t *bw = NULL;
223 
224     if(!PyArg_ParseTuple(pyFname, "s|s", &fname, &mode)) goto error;
225 
226     //Open the local/remote file
227     if(strchr(mode, 'w') != NULL || bwIsBigWig(fname, NULL)) {
228         bw = bwOpen(fname, NULL, mode);
229     } else {
230         bw = bbOpen(fname, NULL);
231     }
232     if(!bw) {
233         fprintf(stderr, "[pyBwOpen] bw is NULL!\n");
234         goto error;
235     }
236     if(!mode || !strchr(mode, 'w')) {
237         if(!bw->cl) goto error;
238     }
239 
240     pybw = PyObject_New(pyBigWigFile_t, &bigWigFile);
241     if(!pybw) {
242         fprintf(stderr, "[pyBwOpen] PyObject_New() returned NULL (out of memory?)!\n");
243         goto error;
244     }
245     pybw->bw = bw;
246     pybw->lastTid = -1;
247     pybw->lastType = -1;
248     pybw->lastSpan = (uint32_t) -1;
249     pybw->lastStep = (uint32_t) -1;
250     pybw->lastStart = (uint32_t) -1;
251     return (PyObject*) pybw;
252 
253 error:
254     if(bw) bwClose(bw);
255     PyErr_SetString(PyExc_RuntimeError, "Received an error during file opening!");
256     return NULL;
257 }
258 
pyBwDealloc(pyBigWigFile_t * self)259 static void pyBwDealloc(pyBigWigFile_t *self) {
260     if(self->bw) bwClose(self->bw);
261     PyObject_DEL(self);
262 }
263 
pyBwClose(pyBigWigFile_t * self,PyObject * args)264 static PyObject *pyBwClose(pyBigWigFile_t *self, PyObject *args) {
265     bwClose(self->bw);
266     self->bw = NULL;
267     Py_INCREF(Py_None);
268     return Py_None;
269 }
270 
271 //Accessor for the header (version, nLevels, nBasesCovered, minVal, maxVal, sumData, sumSquared
pyBwGetHeader(pyBigWigFile_t * self,PyObject * args)272 static PyObject *pyBwGetHeader(pyBigWigFile_t *self, PyObject *args) {
273     bigWigFile_t *bw = self->bw;
274     PyObject *ret, *val;
275 
276     if(!bw) {
277         PyErr_SetString(PyExc_RuntimeError, "The bigWig file handle is not opened!");
278         return NULL;
279     }
280     if(bw->isWrite == 1) {
281         PyErr_SetString(PyExc_RuntimeError, "The header cannot be accessed in files opened for writing!");
282         return NULL;
283     }
284 
285     ret = PyDict_New();
286     val = PyLong_FromUnsignedLong(bw->hdr->version);
287     if(PyDict_SetItemString(ret, "version", val) == -1) goto error;
288     Py_DECREF(val);
289     val = PyLong_FromUnsignedLong(bw->hdr->nLevels);
290     if(PyDict_SetItemString(ret, "nLevels", val) == -1) goto error;
291     Py_DECREF(val);
292     val = PyLong_FromUnsignedLongLong(bw->hdr->nBasesCovered);
293     if(PyDict_SetItemString(ret, "nBasesCovered", val) == -1) goto error;
294     Py_DECREF(val);
295     val = PyLong_FromDouble(bw->hdr->minVal);
296     if(PyDict_SetItemString(ret, "minVal", val) == -1) goto error;
297     Py_DECREF(val);
298     val = PyLong_FromDouble(bw->hdr->maxVal);
299     if(PyDict_SetItemString(ret, "maxVal", val) == -1) goto error;
300     Py_DECREF(val);
301     val = PyLong_FromDouble(bw->hdr->sumData);
302     if(PyDict_SetItemString(ret, "sumData", val) == -1) goto error;
303     Py_DECREF(val);
304     val = PyLong_FromDouble(bw->hdr->sumSquared);
305     if(PyDict_SetItemString(ret, "sumSquared", val) == -1) goto error;
306     Py_DECREF(val);
307 
308     return ret;
309 
310 error :
311     Py_XDECREF(val);
312     Py_XDECREF(ret);
313     PyErr_SetString(PyExc_RuntimeError, "Received an error while getting the bigWig header!");
314     return NULL;
315 }
316 
317 //Accessor for the chroms, args is optional
pyBwGetChroms(pyBigWigFile_t * self,PyObject * args)318 static PyObject *pyBwGetChroms(pyBigWigFile_t *self, PyObject *args) {
319     PyObject *ret = NULL, *val;
320     bigWigFile_t *bw = self->bw;
321     char *chrom = NULL;
322     uint32_t i;
323 
324     if(!bw) {
325         PyErr_SetString(PyExc_RuntimeError, "The bigWig file handle is not opened!");
326         return NULL;
327     }
328 
329     if(bw->isWrite == 1) {
330         PyErr_SetString(PyExc_RuntimeError, "Chromosomes cannot be accessed in files opened for writing!");
331         return NULL;
332     }
333 
334     if(!(PyArg_ParseTuple(args, "|s", &chrom)) || !chrom) {
335         ret = PyDict_New();
336         for(i=0; i<bw->cl->nKeys; i++) {
337             val = PyLong_FromUnsignedLong(bw->cl->len[i]);
338             if(PyDict_SetItemString(ret, bw->cl->chrom[i], val) == -1) goto error;
339             Py_DECREF(val);
340         }
341     } else {
342         for(i=0; i<bw->cl->nKeys; i++) {
343             if(strcmp(bw->cl->chrom[i],chrom) == 0) {
344                 ret = PyLong_FromUnsignedLong(bw->cl->len[i]);
345                 break;
346             }
347         }
348     }
349 
350     if(!ret) {
351         Py_INCREF(Py_None);
352         ret = Py_None;
353     }
354 
355     return ret;
356 
357 error :
358     Py_XDECREF(val);
359     Py_XDECREF(ret);
360     PyErr_SetString(PyExc_RuntimeError, "Received an error while adding an item to the output dictionary!");
361     return NULL;
362 }
363 
char2enum(char * s)364 enum bwStatsType char2enum(char *s) {
365     if(strcmp(s, "mean") == 0) return mean;
366     if(strcmp(s, "std") == 0) return stdev;
367     if(strcmp(s, "dev") == 0) return dev;
368     if(strcmp(s, "max") == 0) return max;
369     if(strcmp(s, "min") == 0) return min;
370     if(strcmp(s, "cov") == 0) return cov;
371     if(strcmp(s, "coverage") == 0) return cov;
372     if(strcmp(s, "sum") == 0) return sum;
373     return -1;
374 };
375 
376 //Fetch summary statistics, default is the mean of the entire chromosome.
pyBwGetStats(pyBigWigFile_t * self,PyObject * args,PyObject * kwds)377 static PyObject *pyBwGetStats(pyBigWigFile_t *self, PyObject *args, PyObject *kwds) {
378     bigWigFile_t *bw = self->bw;
379     double *val;
380     uint32_t start, end = -1, tid;
381     unsigned long startl = 0, endl = -1;
382     static char *kwd_list[] = {"chrom", "start", "end", "type", "nBins", "exact", "numpy", NULL};
383     char *chrom, *type = "mean";
384     PyObject *ret, *exact = Py_False, *starto = NULL, *endo = NULL;
385     PyObject *outputNumpy = Py_False;
386     int i, nBins = 1;
387     errno = 0; //In the off-chance that something elsewhere got an error and didn't clear it...
388 
389     if(!bw) {
390         PyErr_SetString(PyExc_RuntimeError, "The bigWig file handle is not open!");
391         return NULL;
392     }
393 
394     if(bw->isWrite == 1) {
395         PyErr_SetString(PyExc_RuntimeError, "Statistics cannot be accessed in files opened for writing!");
396         return NULL;
397     }
398 
399     if(bw->type == 1) {
400         PyErr_SetString(PyExc_RuntimeError, "bigBed files have no statistics!");
401         return NULL;
402     }
403 
404     if(!PyArg_ParseTupleAndKeywords(args, kwds, "s|OOsiOO", kwd_list, &chrom, &starto, &endo, &type, &nBins, &exact, &outputNumpy)) {
405         PyErr_SetString(PyExc_RuntimeError, "You must supply at least a chromosome!");
406         return NULL;
407     }
408 
409     //Check inputs, reset to defaults if nothing was input
410     if(!nBins) nBins = 1; //For some reason, not specifying this overrides the default!
411     if(!type) type = "mean";
412     tid = bwGetTid(bw, chrom);
413 
414     if(starto) {
415 #ifdef WITHNUMPY
416         if(PyArray_IsScalar(starto, Integer)) {
417             startl = (long) getNumpyL(starto);
418         } else
419 #endif
420         if(PyLong_Check(starto)) {
421             startl = PyLong_AsLong(starto);
422 #if PY_MAJOR_VERSION < 3
423         } else if(PyInt_Check(starto)) {
424             startl = PyInt_AsLong(starto);
425 #endif
426         } else {
427             PyErr_SetString(PyExc_RuntimeError, "The start coordinate must be a number!");
428             return NULL;
429         }
430     }
431 
432     if(endo) {
433 #ifdef WITHNUMPY
434         if(PyArray_IsScalar(endo, Integer)) {
435             endl = (long) getNumpyL(endo);
436         } else
437 #endif
438         if(PyLong_Check(endo)) {
439             endl = PyLong_AsLong(endo);
440 #if PY_MAJOR_VERSION < 3
441         } else if(PyInt_Check(endo)) {
442             endl = PyInt_AsLong(endo);
443 #endif
444         } else {
445             PyErr_SetString(PyExc_RuntimeError, "The end coordinate must be a number!");
446             return NULL;
447         }
448     }
449 
450     if(endl == (unsigned long) -1 && tid != (uint32_t) -1) endl = bw->cl->len[tid];
451     if(tid == (uint32_t) -1 || startl > end || endl > end) {
452         PyErr_SetString(PyExc_RuntimeError, "Invalid interval bounds!");
453         return NULL;
454     }
455     start = (uint32_t) startl;
456     end = (uint32_t) endl;
457     if(end <= start || end > bw->cl->len[tid] || start >= end) {
458         PyErr_SetString(PyExc_RuntimeError, "Invalid interval bounds!");
459         return NULL;
460     }
461 
462     if(char2enum(type) == doesNotExist) {
463         PyErr_SetString(PyExc_RuntimeError, "Invalid type!");
464         return NULL;
465     }
466 
467     //Return a list of None if there are no entries at all
468     if(!hasEntries(bw)) {
469 #ifdef WITHNUMPY
470         if(outputNumpy == Py_True) {
471             val = malloc(sizeof(double)*nBins);
472             for(i=0; i<nBins; i++) {
473                 val[i] = NPY_NAN;
474             }
475             npy_intp len = nBins;
476             ret = PyArray_SimpleNewFromData(1, &len, NPY_FLOAT64, (void *) val);
477             //This will break if numpy ever stops using malloc!
478             PyArray_ENABLEFLAGS((PyArrayObject*) ret, NPY_ARRAY_OWNDATA);
479         } else {
480 #endif
481             ret = PyList_New(nBins);
482             for(i=0; i<nBins; i++) {
483                 Py_INCREF(Py_None);
484                 PyList_SetItem(ret, i, Py_None);
485             }
486 #ifdef WITHNUMPY
487         }
488 #endif
489         return ret;
490     }
491 
492     //Get the actual statistics
493     if(exact == Py_True) {
494         val = bwStatsFromFull(bw, chrom, start, end, nBins, char2enum(type));
495     } else {
496         val = bwStats(bw, chrom, start, end, nBins, char2enum(type));
497     }
498 
499     if(!val) {
500         PyErr_SetString(PyExc_RuntimeError, "An error was encountered while fetching statistics.");
501         return NULL;
502     }
503 
504 #ifdef WITHNUMPY
505     if(outputNumpy == Py_True) {
506         npy_intp len = nBins;
507         ret = PyArray_SimpleNewFromData(1, &len, NPY_FLOAT64, (void *) val);
508         //This will break if numpy ever stops using malloc!
509         PyArray_ENABLEFLAGS((PyArrayObject*) ret, NPY_ARRAY_OWNDATA);
510     } else {
511 #endif
512         ret = PyList_New(nBins);
513         for(i=0; i<nBins; i++) {
514             if(isnan(val[i])) {
515                 Py_INCREF(Py_None);
516                 PyList_SetItem(ret, i, Py_None);
517             } else {
518                 PyList_SetItem(ret, i, PyFloat_FromDouble(val[i]));
519             }
520         }
521         free(val);
522 #ifdef WITHNUMPY
523     }
524 #endif
525     return ret;
526 }
527 
528 //Fetch a list of individual values
529 //For bases with no coverage, the value should be None
530 #ifdef WITHNUMPY
pyBwGetValues(pyBigWigFile_t * self,PyObject * args,PyObject * kwds)531 static PyObject *pyBwGetValues(pyBigWigFile_t *self, PyObject *args, PyObject *kwds) {
532 #else
533 static PyObject *pyBwGetValues(pyBigWigFile_t *self, PyObject *args) {
534 #endif
535     bigWigFile_t *bw = self->bw;
536     int i;
537     uint32_t start, end = -1, tid;
538     unsigned long startl, endl;
539     char *chrom;
540     PyObject *ret, *starto = NULL, *endo = NULL;
541     bwOverlappingIntervals_t *o;
542 
543     if(!bw) {
544         PyErr_SetString(PyExc_RuntimeError, "The bigWig file handle is not open!");
545         return NULL;
546     }
547 
548     if(bw->type == 1) {
549         PyErr_SetString(PyExc_RuntimeError, "bigBed files have no values! Use 'entries' instead.");
550         return NULL;
551     }
552 
553 #ifdef WITHNUMPY
554     static char *kwd_list[] = {"chrom", "start", "end", "numpy", NULL};
555     PyObject *outputNumpy = Py_False;
556 
557     if(!PyArg_ParseTupleAndKeywords(args, kwds, "sOO|O", kwd_list, &chrom, &starto, &endo, &outputNumpy)) {
558 #else
559     if(!PyArg_ParseTuple(args, "sOO", &chrom, &starto, &endo)) {
560 #endif
561         PyErr_SetString(PyExc_RuntimeError, "You must supply a chromosome, start and end position.\n");
562         return NULL;
563     }
564 
565     tid = bwGetTid(bw, chrom);
566 
567 #ifdef WITHNUMPY
568     if(PyArray_IsScalar(starto, Integer)) {
569         startl = (long) getNumpyL(starto);
570     } else
571 #endif
572     if(PyLong_Check(starto)) {
573         startl = PyLong_AsLong(starto);
574 #if PY_MAJOR_VERSION < 3
575     } else if(PyInt_Check(starto)) {
576         startl = PyInt_AsLong(starto);
577 #endif
578     } else {
579         PyErr_SetString(PyExc_RuntimeError, "The start coordinate must be a number!");
580         return NULL;
581     }
582 
583 #ifdef WITHNUMPY
584     if(PyArray_IsScalar(endo, Integer)) {
585         endl = (long) getNumpyL(endo);
586     } else
587 #endif
588     if(PyLong_Check(endo)) {
589         endl = PyLong_AsLong(endo);
590 #if PY_MAJOR_VERSION < 3
591     } else if(PyInt_Check(endo)) {
592         endl = PyInt_AsLong(endo);
593 #endif
594     } else {
595         PyErr_SetString(PyExc_RuntimeError, "The end coordinate must be a number!");
596         return NULL;
597     }
598 
599     if(endl == (unsigned long) -1 && tid != (uint32_t) -1) endl = bw->cl->len[tid];
600     if(tid == (uint32_t) -1 || startl > end || endl > end) {
601         PyErr_SetString(PyExc_RuntimeError, "Invalid interval bounds!");
602         return NULL;
603     }
604 
605     start = (uint32_t) startl;
606     end = (uint32_t) endl;
607     if(end <= start || end > bw->cl->len[tid] || start >= end) {
608         PyErr_SetString(PyExc_RuntimeError, "Invalid interval bounds!");
609         return NULL;
610     }
611 
612     if(!hasEntries(self->bw)) {
613 #ifdef WITHNUMPY
614         if(outputNumpy == Py_True) {
615             return PyArray_SimpleNew(0, NULL, NPY_FLOAT);
616         } else {
617 #endif
618             return PyList_New(0);
619 #ifdef WITHNUMPY
620         }
621 #endif
622     }
623 
624     o = bwGetValues(self->bw, chrom, start, end, 1);
625     if(!o) {
626         PyErr_SetString(PyExc_RuntimeError, "An error occurred while fetching values!");
627         return NULL;
628     }
629 
630 #ifdef WITHNUMPY
631     if(outputNumpy == Py_True) {
632         npy_intp len = end - start;
633         ret = PyArray_SimpleNewFromData(1, &len, NPY_FLOAT, (void *) o->value);
634         //This will break if numpy ever stops using malloc!
635         PyArray_ENABLEFLAGS((PyArrayObject*) ret, NPY_ARRAY_OWNDATA);
636         free(o->start);
637         free(o->end);
638         free(o);
639     } else {
640 #endif
641         ret = PyList_New(end-start);
642         for(i=0; i<(int) o->l; i++) PyList_SetItem(ret, i, PyFloat_FromDouble(o->value[i]));
643         bwDestroyOverlappingIntervals(o);
644 #ifdef WITHNUMPY
645     }
646 #endif
647 
648     return ret;
649 }
650 
651 static PyObject *pyBwGetIntervals(pyBigWigFile_t *self, PyObject *args, PyObject *kwds) {
652     bigWigFile_t *bw = self->bw;
653     uint32_t start, end = -1, tid, i;
654     unsigned long startl = 0, endl = -1;
655     static char *kwd_list[] = {"chrom", "start", "end", NULL};
656     bwOverlappingIntervals_t *intervals = NULL;
657     char *chrom;
658     PyObject *ret, *starto = NULL, *endo = NULL;
659 
660     if(!bw) {
661         PyErr_SetString(PyExc_RuntimeError, "The bigWig file handle is not opened!");
662         return NULL;
663     }
664 
665     if(bw->isWrite == 1) {
666         PyErr_SetString(PyExc_RuntimeError, "Intervals cannot be accessed in files opened for writing!");
667         return NULL;
668     }
669 
670     if(bw->type == 1) {
671         PyErr_SetString(PyExc_RuntimeError, "bigBed files have no intervals! Use 'entries()' instead.");
672         return NULL;
673     }
674 
675     if(!PyArg_ParseTupleAndKeywords(args, kwds, "s|OO", kwd_list, &chrom, &starto, &endo)) {
676         PyErr_SetString(PyExc_RuntimeError, "You must supply at least a chromosome.\n");
677         return NULL;
678     }
679 
680     //Sanity check
681     tid = bwGetTid(bw, chrom);
682     if(endl == (unsigned long) -1 && tid != (uint32_t) -1) endl = bw->cl->len[tid];
683     if(tid == (uint32_t) -1 || startl > end || endl > end) {
684         PyErr_SetString(PyExc_RuntimeError, "Invalid interval bounds!");
685         return NULL;
686     }
687 
688     if(starto) {
689 #ifdef WITHNUMPY
690         if(PyArray_IsScalar(starto, Integer)) {
691             startl = (long) getNumpyL(starto);
692         } else
693 #endif
694         if(PyLong_Check(starto)) {
695             startl = PyLong_AsLong(starto);
696 #if PY_MAJOR_VERSION < 3
697         } else if(PyInt_Check(starto)) {
698             startl = PyInt_AsLong(starto);
699 #endif
700         } else {
701             PyErr_SetString(PyExc_RuntimeError, "The start coordinate must be a number!");
702             return NULL;
703         }
704     }
705 
706     if(endo) {
707 #ifdef WITHNUMPY
708         if(PyArray_IsScalar(endo, Integer)) {
709             endl = (long) getNumpyL(endo);
710         } else
711 #endif
712         if(PyLong_Check(endo)) {
713             endl = PyLong_AsLong(endo);
714 #if PY_MAJOR_VERSION < 3
715         } else if(PyInt_Check(endo)) {
716             endl = PyInt_AsLong(endo);
717 #endif
718         } else {
719             PyErr_SetString(PyExc_RuntimeError, "The end coordinate must be a number!");
720             return NULL;
721         }
722     }
723 
724     start = (uint32_t) startl;
725     end = (uint32_t) endl;
726     if(end <= start || end > bw->cl->len[tid] || start >= end) {
727         PyErr_SetString(PyExc_RuntimeError, "Invalid interval bounds!");
728         return NULL;
729     }
730 
731     //Check for empty files
732     if(!hasEntries(bw)) {
733         Py_INCREF(Py_None);
734         return Py_None;
735     }
736 
737     //Get the intervals
738     intervals = bwGetOverlappingIntervals(bw, chrom, start, end);
739     if(!intervals) {
740         PyErr_SetString(PyExc_RuntimeError, "An error occurred while fetching the overlapping intervals!");
741         return NULL;
742     }
743     if(!intervals->l) {
744         Py_INCREF(Py_None);
745         return Py_None;
746     }
747 
748     ret = PyTuple_New(intervals->l);
749     for(i=0; i<intervals->l; i++) {
750         if(PyTuple_SetItem(ret, i, Py_BuildValue("(iif)", intervals->start[i], intervals->end[i], intervals->value[i]))) {
751             Py_DECREF(ret);
752             bwDestroyOverlappingIntervals(intervals);
753             PyErr_SetString(PyExc_RuntimeError, "An error occurred while constructing the output tuple!");
754             return NULL;
755         }
756     }
757 
758     bwDestroyOverlappingIntervals(intervals);
759     return ret;
760 }
761 
762 #if PY_MAJOR_VERSION >= 3
763 //Return 1 iff obj is a ready unicode type
764 int PyString_Check(PyObject *obj) {
765     if(PyUnicode_Check(obj)) {
766         return PyUnicode_READY(obj)+1;
767     }
768     return 0;
769 }
770 
771 //I don't know what happens if PyBytes_AsString(NULL) is used...
772 char *PyString_AsString(PyObject *obj) {
773     return PyUnicode_AsUTF8(obj);
774 }
775 #endif
776 
777 //Will return 1 for long or int types currently
778 int isNumeric(PyObject *obj) {
779 #ifdef WITHNUMPY
780     if(PyArray_IsScalar(obj, Integer)) return 1;
781 #endif
782 #if PY_MAJOR_VERSION < 3
783     if(PyInt_Check(obj)) return 1;
784 #endif
785     return PyLong_Check(obj);
786 }
787 
788 //On error, throws a runtime error, so use PyErr_Occurred() after this
789 uint32_t Numeric2Uint(PyObject *obj) {
790     long l;
791 #if PY_MAJOR_VERSION < 3
792     if(PyInt_Check(obj)) {
793         return (uint32_t) PyInt_AsLong(obj);
794     }
795 #endif
796     l = PyLong_AsLong(obj);
797     //Check bounds
798     if(l > 0xFFFFFFFF) {
799         PyErr_SetString(PyExc_RuntimeError, "Length out of bounds for a bigWig file!");
800         return (uint32_t) -1;
801     }
802     return (uint32_t) l;
803 }
804 
805 //This runs bwCreateHdr, bwCreateChromList, and bwWriteHdr
806 PyObject *pyBwAddHeader(pyBigWigFile_t *self, PyObject *args, PyObject *kwds) {
807     bigWigFile_t *bw = self->bw;
808     char **chroms = NULL;
809     int64_t n;
810     uint32_t *lengths = NULL, len;
811     int32_t maxZooms = 10;
812     long zoomTmp = 10;
813     static char *kwd_list[] = {"cl", "maxZooms", NULL};
814     PyObject *InputTuple = NULL, *tmpObject, *tmpObject2;
815     Py_ssize_t i, pyLen;
816 
817     if(!bw) {
818         PyErr_SetString(PyExc_RuntimeError, "The bigWig file handle is not open!");
819         return NULL;
820     }
821 
822     if(!PyArg_ParseTupleAndKeywords(args, kwds, "O|k", kwd_list, &InputTuple, &zoomTmp)) {
823         PyErr_SetString(PyExc_RuntimeError, "Illegal arguments");
824         return NULL;
825     }
826     maxZooms = zoomTmp;
827 
828     //Ensure that we received a list
829     if(!PyList_Check(InputTuple)) {
830         PyErr_SetString(PyExc_RuntimeError, "You MUST input a list of tuples (e.g., [('chr1', 1000), ('chr2', 2000)]!");
831         goto error;
832     }
833     pyLen = PyList_Size(InputTuple);
834     if(pyLen < 1) {
835         PyErr_SetString(PyExc_RuntimeError, "You input an empty list!");
836         goto error;
837     }
838     n = pyLen;
839 
840     lengths = calloc(n, sizeof(uint32_t));
841     chroms = calloc(n, sizeof(char*));
842     if(!lengths || !chroms) {
843         PyErr_SetString(PyExc_RuntimeError, "Couldn't allocate lengths or chroms!");
844         goto error;
845     }
846 
847     //Convert the tuple into something more useful in C
848     for(i=0; i<pyLen; i++) {
849         tmpObject = PyList_GetItem(InputTuple, i);
850         if(!tmpObject) {
851             PyErr_SetString(PyExc_RuntimeError, "Couldn't get a tuple!");
852             goto error;
853         }
854         if(!PyTuple_Check(tmpObject)) {
855             PyErr_SetString(PyExc_RuntimeError, "The input list is not made up of tuples!");
856             goto error;
857         }
858         if(PyTuple_Size(tmpObject) != 2) {
859             PyErr_SetString(PyExc_RuntimeError, "One tuple does not contain exactly 2 members!");
860             goto error;
861         }
862 
863         //Chromosome
864         tmpObject2 = PyTuple_GetItem(tmpObject, 0); //This returns NULL in python3?!?
865         if(!PyString_Check(tmpObject2)) {
866             PyErr_SetString(PyExc_RuntimeError, "The first element of each tuple MUST be a string!");
867             goto error;
868         }
869         chroms[i] = PyString_AsString(tmpObject2);
870         if(!chroms[i]) {
871             PyErr_SetString(PyExc_RuntimeError, "Received something other than a string for a chromosome name!");
872             goto error;
873         }
874 
875         //Length
876         tmpObject2 = PyTuple_GetItem(tmpObject, 1);
877         if(!isNumeric(tmpObject2)) {
878             PyErr_SetString(PyExc_RuntimeError, "The second element of each tuple MUST be an integer!");
879             goto error;
880         }
881         len = Numeric2Uint(tmpObject2);
882         if(PyErr_Occurred()) goto error;
883         if(zoomTmp > 0xFFFFFFFF) {
884             PyErr_SetString(PyExc_RuntimeError, "A requested length is longer than what can be stored in a bigWig file!");
885             goto error;
886         }
887         lengths[i] = len;
888     }
889 
890     //Create the header
891     if(bwCreateHdr(bw, maxZooms)) {
892         PyErr_SetString(PyExc_RuntimeError, "Received an error in bwCreateHdr");
893         goto error;
894     }
895 
896     //Create the chromosome list
897     bw->cl = bwCreateChromList(chroms, lengths, n);
898     if(!bw->cl) {
899         PyErr_SetString(PyExc_RuntimeError, "Received an error in bwCreateChromList");
900         goto error;
901     }
902 
903     //Write the header
904     if(bwWriteHdr(bw)) {
905         PyErr_SetString(PyExc_RuntimeError, "Received an error while writing the bigWig header");
906         goto error;
907     }
908 
909     if(lengths) free(lengths);
910     if(chroms) free(chroms);
911 
912     Py_INCREF(Py_None);
913     return Py_None;
914 
915 error:
916     if(lengths) free(lengths);
917     if(chroms) free(chroms);
918     return NULL;
919 }
920 
921 //1 on true, 0 on false
922 int isType0(PyObject *chroms, PyObject *starts, PyObject *ends, PyObject *values) {
923     int rv = 0;
924     Py_ssize_t i, sz = 0;
925     PyObject *tmp;
926 
927     if(!PyList_Check(chroms)
928 #ifdef WITHNUMPY
929         && !PyArray_Check(chroms)
930 #endif
931         ) return rv;
932     if(!PyList_Check(starts)
933 #ifdef WITHNUMPY
934         && !PyArray_Check(starts)
935 #endif
936         ) return rv;
937     if(!PyList_Check(ends)
938 #ifdef WITHNUMPY
939         && !PyArray_Check(ends)
940 #endif
941         ) return rv;
942     if(!PyList_Check(values)
943 #ifdef WITHNUMPY
944         && !PyArray_Check(values)
945 #endif
946         ) return rv;
947     if(PyList_Check(chroms)) sz = PyList_Size(chroms);
948 #ifdef WITHNUMPY
949     if(PyArray_Check(chroms)) sz += PyArray_Size(chroms);
950 #endif
951 
952     if(PyList_Check(starts)) {
953         if(sz != PyList_Size(starts)) return rv;
954 #ifdef WITHNUMPY
955     } else {
956         if(sz != PyArray_Size(starts)) return rv;
957 #endif
958     }
959     if(PyList_Check(ends)) {
960         if(sz != PyList_Size(ends)) return rv;
961 #ifdef WITHNUMPY
962     } else {
963         if(sz != PyArray_Size(ends)) return rv;
964 #endif
965     }
966     if(PyList_Check(values)) {
967         if(sz != PyList_Size(values)) return rv;
968 #ifdef WITHNUMPY
969     } else {
970         if(sz != PyArray_Size(values)) return rv;
971 #endif
972     }
973 
974     //Ensure chroms contains strings, etc.
975     if(PyList_Check(chroms)) {
976         for(i=0; i<sz; i++) {
977             tmp = PyList_GetItem(chroms, i);
978             if(!PyString_Check(tmp)) return rv;
979         }
980 #ifdef WITHNUMPY
981     } else {
982         if(!PyArray_ISSTRING( (PyArrayObject*) chroms)) return rv;
983 #endif
984     }
985     if(PyList_Check(starts)) {
986         for(i=0; i<sz; i++) {
987             tmp = PyList_GetItem(starts, i);
988             if(!isNumeric(tmp)) return rv;
989         }
990 #ifdef WITHNUMPY
991     } else {
992         if(!PyArray_ISINTEGER( (PyArrayObject*) starts)) return rv;
993 #endif
994     }
995     if(PyList_Check(ends)) {
996         for(i=0; i<sz; i++) {
997             tmp = PyList_GetItem(ends, i);
998             if(!isNumeric(tmp)) return rv;
999         }
1000 #ifdef WITHNUMPY
1001     } else {
1002         if(!PyArray_ISINTEGER( (PyArrayObject*) ends)) return rv;
1003 #endif
1004     }
1005     if(PyList_Check(values)) {
1006         for(i=0; i<sz; i++) {
1007             tmp = PyList_GetItem(values, i);
1008             if(!PyFloat_Check(tmp)) return rv;
1009         }
1010 #ifdef WITHNUMPY
1011     } else {
1012         if(!PyArray_ISFLOAT((PyArrayObject*) values)) return rv;
1013 #endif
1014     }
1015     return 1;
1016 }
1017 
1018 //single chrom, multiple starts, single span
1019 int isType1(PyObject *chroms, PyObject *starts, PyObject *values, PyObject *span) {
1020     int rv = 0;
1021     Py_ssize_t i, sz = 0;
1022     PyObject *tmp;
1023 
1024     if(!PyString_Check(chroms)) return rv;
1025     if(!PyList_Check(starts)
1026 #ifdef WITHNUMPY
1027         && !PyArray_Check(starts)
1028 #endif
1029         ) return rv;
1030     if(!PyList_Check(values)
1031 #ifdef WITHNUMPY
1032         && !PyArray_Check(values)
1033 #endif
1034         ) return rv;
1035     if(!isNumeric(span)) return rv;
1036 
1037     if(PyList_Check(starts)) sz = PyList_Size(starts);
1038 #ifdef WITHNUMPY
1039     if(PyArray_Check(starts)) sz += PyArray_Size(starts);
1040 #endif
1041 
1042     if(PyList_Check(values)) if(sz != PyList_Size(values)) return rv;
1043 #ifdef WITHNUMPY
1044     if(PyArray_Check(values)) if(sz != PyArray_Size(values)) return rv;
1045 #endif
1046 
1047     if(PyList_Check(starts)) {
1048         for(i=0; i<sz; i++) {
1049             tmp = PyList_GetItem(starts, i);
1050             if(!isNumeric(tmp)) return rv;
1051         }
1052 #ifdef WITHNUMPY
1053     } else {
1054         if(!PyArray_ISINTEGER( (PyArrayObject*) starts)) return rv;
1055 #endif
1056     }
1057     if(PyList_Check(values)) {
1058         for(i=0; i<sz; i++) {
1059             tmp = PyList_GetItem(values, i);
1060             if(!PyFloat_Check(tmp)) return rv;
1061         }
1062 #ifdef WITHNUMPY
1063     } else {
1064         if(!PyArray_ISFLOAT( (PyArrayObject*) values)) return rv;
1065 #endif
1066     }
1067     return 1;
1068 }
1069 
1070 //Single chrom, single start, single span, single step, multiple values
1071 int isType2(PyObject *chroms, PyObject *starts, PyObject *values, PyObject *span, PyObject *step) {
1072     int rv = 0;
1073     Py_ssize_t i, sz;
1074     PyObject *tmp;
1075 
1076     if(!isNumeric(span)) return rv;
1077     if(!isNumeric(step)) return rv;
1078     if(!PyString_Check(chroms)) return rv;
1079     if(!isNumeric(starts)) return rv;
1080 
1081     if(PyList_Check(values)) {
1082         sz = PyList_Size(values);
1083         for(i=0; i<sz; i++) {
1084             tmp = PyList_GetItem(values, i);
1085             if(!PyFloat_Check(tmp)) return rv;
1086         }
1087 #ifdef WITHNUMPY
1088     } else {
1089         if(!PyArray_ISFLOAT( (PyArrayObject*) values)) return rv;
1090 #endif
1091     }
1092     rv = 1;
1093     return rv;
1094 }
1095 
1096 int getType(PyObject *chroms, PyObject *starts, PyObject *ends, PyObject *values, PyObject *span, PyObject *step) {
1097     if(!chroms) return -1;
1098     if(!starts) return -1;
1099     if(!values) return -1;
1100     if(chroms && starts && ends && values && isType0(chroms, starts, ends, values)) return 0;
1101     if(chroms && starts && span && values && isType1(chroms, starts, values, span)) return 1;
1102     if(chroms && starts && values && span && step && isType2(chroms, starts, values, span, step)) return 2;
1103     return -1;
1104 }
1105 
1106 //1: Can use a bwAppend* function. 0: must use a bwAdd* function
1107 int canAppend(pyBigWigFile_t *self, int desiredType, PyObject *chroms, PyObject *starts, PyObject *span, PyObject *step) {
1108     bigWigFile_t *bw = self->bw;
1109     Py_ssize_t i, sz = 0;
1110     uint32_t tid, uspan, ustep, ustart;
1111     PyObject *tmp;
1112 #ifdef WITHNUMPY
1113     char *chrom;
1114 #endif
1115 
1116     if(self->lastType == -1) return 0;
1117     if(self->lastTid == -1) return 0;
1118     if(self->lastType != desiredType) return 0;
1119 
1120     //We can only append if (A) we have the same type or (B) the same chromosome (and compatible span/step/starts
1121     if(desiredType == 0) {
1122         //We need (A) chrom == lastTid and (B) all chroms to be the same
1123         if(PyList_Check(chroms)) sz = PyList_Size(chroms);
1124 #ifdef WITHNUMPY
1125         if(PyArray_Check(chroms)) sz = PyArray_Size(chroms);
1126 #endif
1127 
1128         for(i=0; i<sz; i++) {
1129 #ifdef WITHNUMPY
1130             if(PyArray_Check(chroms)) {
1131                 chrom = getNumpyStr((PyArrayObject*)chroms, i);
1132                 tid = bwGetTid(bw, chrom);
1133                 free(chrom);
1134             } else {
1135 #endif
1136                 tmp = PyList_GetItem(chroms, i);
1137                 tid = bwGetTid(bw, PyString_AsString(tmp));
1138 #ifdef WITHNUMPY
1139             }
1140 #endif
1141             if(tid != (uint32_t) self->lastTid) return 0;
1142         }
1143 
1144 #ifdef WITHNUMPY
1145         if(PyArray_Check(starts)) {
1146             ustart = getNumpyU32((PyArrayObject*)starts, 0);
1147         } else {
1148 #endif
1149             ustart = Numeric2Uint(PyList_GetItem(starts, 0));
1150 #ifdef WITHNUMPY
1151         }
1152 #endif
1153         if(PyErr_Occurred()) return 0;
1154         if(ustart < self->lastStart) return 0;
1155         return 1;
1156     } else if(desiredType == 1) {
1157         //We need (A) chrom == lastTid, (B) all chroms to be the same, and (C) equal spans
1158         uspan = Numeric2Uint(span);
1159         if(PyErr_Occurred()) return 0;
1160         if(uspan != self->lastSpan) return 0;
1161         if(!PyString_Check(chroms)) return 0;
1162         tid = bwGetTid(bw, PyString_AsString(chroms));
1163         if(tid != (uint32_t) self->lastTid) return 0;
1164 
1165 #ifdef WITHNUMPY
1166         if(PyList_Check(starts)) ustart = Numeric2Uint(PyList_GetItem(starts, 0));
1167         else ustart = getNumpyU32((PyArrayObject*) starts, 0);
1168 #else
1169         ustart = Numeric2Uint(PyList_GetItem(starts, 0));
1170 #endif
1171         if(PyErr_Occurred()) return 0;
1172         if(ustart < self->lastStart) return 0;
1173         return 1;
1174     } else if(desiredType == 2) {
1175         //We need (A) chrom == lastTid, (B) span/step to be equal and (C) compatible starts
1176         tid = bwGetTid(bw, PyString_AsString(chroms));
1177         if(tid != (uint32_t) self->lastTid) return 0;
1178         uspan = Numeric2Uint(span);
1179         if(PyErr_Occurred()) return 0;
1180         if(uspan != self->lastSpan) return 0;
1181         ustep = Numeric2Uint(step);
1182         if(PyErr_Occurred()) return 0;
1183         if(ustep != self->lastStep) return 0;
1184 
1185         //But is the start position compatible?
1186         ustart = Numeric2Uint(starts);
1187         if(PyErr_Occurred()) return 0;
1188         if(ustart != self->lastStart) return 0;
1189         return 1;
1190     }
1191 
1192     return 0;
1193 }
1194 
1195 //Returns 0 on success, 1 on error. Sets self->lastTid && self->lastStart (unless there was an error)
1196 int PyAddIntervals(pyBigWigFile_t *self, PyObject *chroms, PyObject *starts, PyObject *ends, PyObject *values) {
1197     bigWigFile_t *bw = self->bw;
1198     Py_ssize_t i, sz = 0;
1199     char **cchroms = NULL;
1200     uint32_t n, *ustarts = NULL, *uends = NULL;
1201     float *fvalues = NULL;
1202     int rv;
1203 
1204     if(PyList_Check(starts)) sz = PyList_Size(starts);
1205 #ifdef WITHNUMPY
1206     if(PyArray_Check(starts)) sz += PyArray_Size(starts);
1207 #endif
1208     n = (uint32_t) sz;
1209 
1210     //Allocate space
1211     cchroms = calloc(n, sizeof(char*));
1212     ustarts = calloc(n, sizeof(uint32_t));
1213     uends = calloc(n, sizeof(uint32_t));
1214     fvalues = calloc(n, sizeof(float));
1215     if(!cchroms || !ustarts || !uends || !fvalues) goto error;
1216 
1217     for(i=0; i<sz; i++) {
1218         if(PyList_Check(chroms)) {
1219             cchroms[i] = PyString_AsString(PyList_GetItem(chroms, i));
1220 #ifdef WITHNUMPY
1221         } else {
1222             cchroms[i] = getNumpyStr((PyArrayObject*)chroms, i);
1223 #endif
1224         }
1225         if(PyList_Check(starts)) {
1226             ustarts[i] = (uint32_t) PyLong_AsLong(PyList_GetItem(starts, i));
1227 #ifdef WITHNUMPY
1228         } else {
1229             ustarts[i] = getNumpyU32((PyArrayObject*)starts, i);
1230 #endif
1231         }
1232         if(PyErr_Occurred()) goto error;
1233         if(PyList_Check(ends)) {
1234             uends[i] = (uint32_t) PyLong_AsLong(PyList_GetItem(ends, i));
1235 #ifdef WITHNUMPY
1236         } else {
1237             uends[i] = getNumpyU32((PyArrayObject*)ends, i);
1238 #endif
1239         }
1240         if(PyErr_Occurred()) goto error;
1241         if(PyList_Check(values)) {
1242             fvalues[i] = (float) PyFloat_AsDouble(PyList_GetItem(values, i));
1243 #ifdef WITHNUMPY
1244         } else {
1245             fvalues[i] = getNumpyF((PyArrayObject*)values, i);
1246 #endif
1247         }
1248         if(PyErr_Occurred()) goto error;
1249     }
1250 
1251     rv = bwAddIntervals(bw, cchroms, ustarts, uends, fvalues, n);
1252     if(!rv) {
1253         self->lastTid = bwGetTid(bw, cchroms[n-1]);
1254         self->lastStart = uends[n-1];
1255     }
1256     if(!PyList_Check(chroms)) {
1257         for(i=0; i<n; i++) free(cchroms[i]);
1258     }
1259     free(cchroms);
1260     free(ustarts);
1261     free(uends);
1262     free(fvalues);
1263     return rv;
1264 
1265 error:
1266     if(cchroms) free(cchroms);
1267     if(ustarts) free(ustarts);
1268     if(uends) free(uends);
1269     if(fvalues) free(fvalues);
1270     return 1;
1271 }
1272 
1273 //Returns 0 on success, 1 on error. Update self->lastStart
1274 int PyAppendIntervals(pyBigWigFile_t *self, PyObject *starts, PyObject *ends, PyObject *values) {
1275     bigWigFile_t *bw = self->bw;
1276     Py_ssize_t i, sz = 0;
1277     uint32_t n, *ustarts = NULL, *uends = NULL;
1278     float *fvalues = NULL;
1279     int rv;
1280 
1281     if(PyList_Check(starts)) sz = PyList_Size(starts);
1282 #ifdef WITHNUMPY
1283     if(PyArray_Check(starts)) sz += PyArray_Size(starts);
1284 #endif
1285     n = (uint32_t) sz;
1286 
1287     //Allocate space
1288     ustarts = calloc(n, sizeof(uint32_t));
1289     uends = calloc(n, sizeof(uint32_t));
1290     fvalues = calloc(n, sizeof(float));
1291     if(!ustarts || !uends || !fvalues) goto error;
1292 
1293     for(i=0; i<sz; i++) {
1294         if(PyList_Check(starts)) {
1295             ustarts[i] = (uint32_t) PyLong_AsLong(PyList_GetItem(starts, i));
1296 #ifdef WITHNUMPY
1297         } else {
1298             ustarts[i] = getNumpyU32((PyArrayObject*) starts, i);
1299 #endif
1300         }
1301         if(PyErr_Occurred()) goto error;
1302         if(PyList_Check(ends)) {
1303             uends[i] = (uint32_t) PyLong_AsLong(PyList_GetItem(ends, i));
1304 #ifdef WITHNUMPY
1305         } else {
1306             uends[i] = getNumpyU32((PyArrayObject*) ends, i);
1307 #endif
1308         }
1309         if(PyErr_Occurred()) goto error;
1310         if(PyList_Check(values)) {
1311             fvalues[i] = (float) PyFloat_AsDouble(PyList_GetItem(values, i));
1312 #ifdef WITHNUMPY
1313         } else {
1314             fvalues[i] = getNumpyF((PyArrayObject*) values, i);
1315 #endif
1316         }
1317         if(PyErr_Occurred()) goto error;
1318     }
1319     rv = bwAppendIntervals(bw, ustarts, uends, fvalues, n);
1320     if(rv) self->lastStart = uends[n-1];
1321     free(ustarts);
1322     free(uends);
1323     free(fvalues);
1324     return rv;
1325 
1326 error:
1327     if(ustarts) free(ustarts);
1328     if(uends) free(uends);
1329     if(fvalues) free(fvalues);
1330     return 1;
1331 }
1332 
1333 //Returns 0 on success, 1 on error. Sets self->lastTid/lastStart/lastSpan (unless there was an error)
1334 int PyAddIntervalSpans(pyBigWigFile_t *self, PyObject *chroms, PyObject *starts, PyObject *values, PyObject *span) {
1335     bigWigFile_t *bw = self->bw;
1336     Py_ssize_t i, sz = 0;
1337     char *cchroms = NULL;
1338     uint32_t n, *ustarts = NULL, uspan;
1339     float *fvalues = NULL;
1340     int rv;
1341 
1342     if(PyList_Check(starts)) sz = PyList_Size(starts);
1343 #ifdef WITHNUMPY
1344     else if(PyArray_Check(starts)) sz += PyArray_Size(starts);
1345 #endif
1346     n = (uint32_t) sz;
1347 
1348     //Allocate space
1349     ustarts = calloc(n, sizeof(uint32_t));
1350     fvalues = calloc(n, sizeof(float));
1351     if(!ustarts || !fvalues) goto error;
1352     uspan = (uint32_t) PyLong_AsLong(span);
1353     cchroms = PyString_AsString(chroms);
1354 
1355     if(PyList_Check(starts)) {
1356         for(i=0; i<sz; i++) {
1357             ustarts[i] = (uint32_t) PyLong_AsLong(PyList_GetItem(starts, i));
1358             if(PyErr_Occurred()) goto error;
1359         }
1360 #ifdef WITHNUMPY
1361     } else {
1362         for(i=0; i<sz; i++) {
1363             ustarts[i] = getNumpyU32((PyArrayObject*) starts, i);
1364             if(PyErr_Occurred()) goto error;
1365         }
1366 #endif
1367     }
1368     if(PyList_Check(values)) {
1369         for(i=0; i<sz; i++) {
1370             fvalues[i] = (float) PyFloat_AsDouble(PyList_GetItem(values, i));
1371             if(PyErr_Occurred()) goto error;
1372         }
1373 #ifdef WITHNUMPY
1374     } else {
1375         for(i=0; i<sz; i++) {
1376             fvalues[i] = getNumpyF((PyArrayObject*) values, i);
1377             if(PyErr_Occurred()) goto error;
1378         }
1379 #endif
1380     }
1381 
1382     rv = bwAddIntervalSpans(bw, cchroms, ustarts, uspan, fvalues, n);
1383     if(!rv) {
1384         self->lastTid = bwGetTid(bw, cchroms);
1385         self->lastSpan = uspan;
1386         self->lastStart = ustarts[n-1]+uspan;
1387     }
1388     free(ustarts);
1389     free(fvalues);
1390     return rv;
1391 
1392 error:
1393     if(ustarts) free(ustarts);
1394     if(fvalues) free(fvalues);
1395     return 1;
1396 }
1397 
1398 //Returns 0 on success, 1 on error. Updates self->lastStart
1399 int PyAppendIntervalSpans(pyBigWigFile_t *self, PyObject *starts, PyObject *values) {
1400     bigWigFile_t *bw = self->bw;
1401     Py_ssize_t i, sz = 0;
1402     uint32_t n, *ustarts = NULL;
1403     float *fvalues = NULL;
1404     int rv;
1405 
1406     if(PyList_Check(starts)) sz = PyList_Size(starts);
1407 #ifdef WITHNUMPY
1408     else if(PyArray_Check(starts)) sz += PyArray_Size(starts);
1409 #endif
1410     n = (uint32_t) sz;
1411 
1412     //Allocate space
1413     ustarts = calloc(n, sizeof(uint32_t));
1414     fvalues = calloc(n, sizeof(float));
1415     if(!ustarts || !fvalues) goto error;
1416 
1417     if(PyList_Check(starts)) {
1418         for(i=0; i<sz; i++) {
1419             ustarts[i] = (uint32_t) PyLong_AsLong(PyList_GetItem(starts, i));
1420             if(PyErr_Occurred()) goto error;
1421         }
1422 #ifdef WITHNUMPY
1423     } else {
1424         for(i=0; i<sz; i++) {
1425             ustarts[i] = getNumpyU32((PyArrayObject*) starts, i);
1426             if(PyErr_Occurred()) goto error;
1427         }
1428 #endif
1429     }
1430     if(PyList_Check(values)) {
1431         for(i=0; i<sz; i++) {
1432             fvalues[i] = (float) PyFloat_AsDouble(PyList_GetItem(values, i));
1433             if(PyErr_Occurred()) goto error;
1434         }
1435 #ifdef WITHNUMPY
1436     } else {
1437         for(i=0; i<sz; i++) {
1438             fvalues[i] = getNumpyF((PyArrayObject*) values, i);
1439             if(PyErr_Occurred()) goto error;
1440         }
1441 #endif
1442     }
1443 
1444     rv = bwAppendIntervalSpans(bw, ustarts, fvalues, n);
1445     if(rv) self->lastStart = ustarts[n-1] + self->lastSpan;
1446     free(ustarts);
1447     free(fvalues);
1448     return rv;
1449 
1450 error:
1451     if(ustarts) free(ustarts);
1452     if(fvalues) free(fvalues);
1453     return 1;
1454 }
1455 
1456 //Returns 0 on success, 1 on error. Sets self->lastTid/self->lastSpan/lastStep/lastStart (unless there was an error)
1457 int PyAddIntervalSpanSteps(pyBigWigFile_t *self, PyObject *chroms, PyObject *starts, PyObject *values, PyObject *span, PyObject *step) {
1458     bigWigFile_t *bw = self->bw;
1459     Py_ssize_t i, sz = 0;
1460     char *cchrom = NULL;
1461     uint32_t n, ustarts, uspan, ustep;
1462     float *fvalues = NULL;
1463     int rv;
1464 
1465     if(PyList_Check(values)) sz = PyList_Size(values);
1466 #ifdef WITHNUMPY
1467     else if(PyArray_Check(values)) sz += PyArray_Size(values);
1468 #endif
1469     n = (uint32_t) sz;
1470 
1471     //Allocate space
1472     fvalues = calloc(n, sizeof(float));
1473     if(!fvalues) goto error;
1474     uspan = (uint32_t) PyLong_AsLong(span);
1475     ustep = (uint32_t) PyLong_AsLong(step);
1476     ustarts = (uint32_t) PyLong_AsLong(starts);
1477     cchrom = PyString_AsString(chroms);
1478 
1479     if(PyList_Check(values)) {
1480         for(i=0; i<sz; i++) fvalues[i] = (float) PyFloat_AsDouble(PyList_GetItem(values, i));
1481 #ifdef WITHNUMPY
1482     } else {
1483         for(i=0; i<sz; i++) {
1484             fvalues[i] = getNumpyF((PyArrayObject*) values, i);
1485             if(PyErr_Occurred()) goto error;
1486         }
1487 #endif
1488     }
1489 
1490     rv = bwAddIntervalSpanSteps(bw, cchrom, ustarts, uspan, ustep, fvalues, n);
1491     if(!rv) {
1492         self->lastTid = bwGetTid(bw, cchrom);
1493         self->lastSpan = uspan;
1494         self->lastStep = ustep;
1495         self->lastStart = ustarts + ustep*n;
1496     }
1497     free(fvalues);
1498     return rv;
1499 
1500 error:
1501     if(fvalues) free(fvalues);
1502     return 1;
1503 }
1504 
1505 //Returns 0 on success, 1 on error. Sets self->lastStart
1506 int PyAppendIntervalSpanSteps(pyBigWigFile_t *self, PyObject *values) {
1507     bigWigFile_t *bw = self->bw;
1508     Py_ssize_t i, sz = 0;
1509     uint32_t n;
1510     float *fvalues = NULL;
1511     int rv;
1512 
1513     if(PyList_Check(values)) sz = PyList_Size(values);
1514 #ifdef WITHNUMPY
1515     else if(PyArray_Check(values)) sz += PyArray_Size(values);
1516 #endif
1517     n = (uint32_t) sz;
1518 
1519     //Allocate space
1520     fvalues = calloc(n, sizeof(float));
1521     if(!fvalues) goto error;
1522 
1523     if(PyList_Check(values)) {
1524         for(i=0; i<sz; i++) fvalues[i] = (float) PyFloat_AsDouble(PyList_GetItem(values, i));
1525 #ifdef WITHNUMPY
1526     } else {
1527         for(i=0; i<sz; i++) {
1528             fvalues[i] = getNumpyF((PyArrayObject*) values, i);
1529             if(PyErr_Occurred()) goto error;
1530         }
1531 #endif
1532     }
1533 
1534     rv = bwAppendIntervalSpanSteps(bw, fvalues, n);
1535     if(!rv) self->lastStart += self->lastStep * n;
1536     free(fvalues);
1537     return rv;
1538 
1539 error:
1540     if(fvalues) free(fvalues);
1541     return 1;
1542 }
1543 
1544 //Checks and ensures that (A) the entries are sorted correctly and don't overlap and (B) that the come after things that have already been added.
1545 //Returns 1 on correct input, 0 on incorrect input
1546 int addEntriesInputOK(pyBigWigFile_t *self, PyObject *chroms, PyObject *starts, PyObject *ends, PyObject *span, PyObject *step, int type) {
1547     uint32_t lastTid = self->lastTid;
1548     uint32_t lastEnd = self->lastStart;
1549     uint32_t cTid, ustart, uend, uspan, ustep;
1550     Py_ssize_t i, sz = 0;
1551     PyObject *tmp;
1552 #ifdef WITHNUMPY
1553     char *tmpStr;
1554 #endif
1555 
1556     if(type == 0) {
1557         //Each chrom:start-end needs to be properly formed and come after prior entries
1558         if(PyList_Check(starts)) sz = PyList_Size(starts);
1559 #ifdef WITHNUMPY
1560         if(PyArray_Check(starts)) sz += PyArray_Size(starts);
1561 #endif
1562         if(sz == 0) return 0;
1563         for(i=0; i<sz; i++) {
1564 #ifdef WITHNUMPY
1565             if(PyArray_Check(chroms)) {
1566                 tmpStr = getNumpyStr((PyArrayObject*)chroms, i);
1567                 cTid = bwGetTid(self->bw, tmpStr);
1568                 free(tmpStr);
1569             } else {
1570 #endif
1571                 tmp = PyList_GetItem(chroms, i);
1572                 cTid = bwGetTid(self->bw, PyString_AsString(tmp));
1573 #ifdef WITHNUMPY
1574             }
1575 #endif
1576             if(PyErr_Occurred()) return 0;
1577             if(cTid == (uint32_t) -1) return 0;
1578 
1579 #ifdef WITHNUMPY
1580             if(PyArray_Check(starts)) {
1581                 ustart = getNumpyU32((PyArrayObject*)starts, i);
1582             } else {
1583 #endif
1584                 ustart = Numeric2Uint(PyList_GetItem(starts, i));
1585 #ifdef WITHNUMPY
1586             }
1587 #endif
1588             if(PyErr_Occurred()) return 0;
1589 #ifdef WITHNUMPY
1590             if(PyArray_Check(ends)) {
1591                 uend = getNumpyU32((PyArrayObject*) ends, i);
1592             } else {
1593 #endif
1594                 uend = Numeric2Uint(PyList_GetItem(ends, i));
1595 #ifdef WITHNUMPY
1596             }
1597 #endif
1598             if(PyErr_Occurred()) return 0;
1599 
1600             if(ustart >= uend) return 0;
1601             if(lastTid != (uint32_t) -1) {
1602                 if(lastTid > cTid) return 0;
1603                 if(lastTid == cTid) {
1604                     if(ustart < lastEnd) return 0;
1605                 }
1606             }
1607             lastTid = cTid;
1608             lastEnd = uend;
1609         }
1610         return 1;
1611     } else if(type == 1) {
1612         //each chrom:start-(start+span) needs to be properly formed and come after prior entries
1613         if(!PyList_Check(starts)
1614 #ifdef WITHNUMPY
1615             && !PyArray_Check(starts)
1616 #endif
1617         ) return 0;
1618         if(PyList_Check(starts)) sz = PyList_Size(starts);
1619 #ifdef WITHNUMPY
1620         else if(PyArray_Check(starts)) sz += PyArray_Size(starts);
1621 #endif
1622         uspan = Numeric2Uint(span);
1623         if(PyErr_Occurred()) return 0;
1624         if(uspan < 1) return 0;
1625         if(sz == 0) return 0;
1626         cTid = bwGetTid(self->bw, PyString_AsString(chroms));
1627         if(cTid == (uint32_t) -1) return 0;
1628         if(lastTid != (uint32_t) -1) {
1629             if(lastTid > cTid) return 0;
1630         }
1631         for(i=0; i<sz; i++) {
1632 #ifdef WITHNUMPY
1633             if(PyArray_Check(starts)) {
1634                 ustart = getNumpyU32((PyArrayObject*)starts, i);
1635             } else {
1636 #endif
1637                 ustart = Numeric2Uint(PyList_GetItem(starts, i));
1638 #ifdef WITHNUMPY
1639             }
1640 #endif
1641             if(PyErr_Occurred()) return 0;
1642             uend = ustart + uspan;
1643 
1644             if(lastTid == cTid) {
1645                 if(ustart < lastEnd) return 0;
1646             }
1647             lastTid = cTid;
1648             lastEnd = uend;
1649         }
1650         return 1;
1651     } else if(type == 2) {
1652         //The chrom and start need to be appropriate
1653         cTid = bwGetTid(self->bw, PyString_AsString(chroms));
1654         if(cTid == (uint32_t) -1) return 0;
1655         ustart = Numeric2Uint(starts);
1656         if(PyErr_Occurred()) return 0;
1657         uspan = Numeric2Uint(span);
1658         if(PyErr_Occurred()) return 0;
1659         if(uspan < 1) return 0;
1660         ustep = Numeric2Uint(step);
1661         if(PyErr_Occurred()) return 0;
1662         if(ustep < 1) return 0;
1663         if(lastTid != (uint32_t) -1) {
1664             if(lastTid > cTid) return 0;
1665             if(lastTid == cTid) {
1666                 if(ustart < lastEnd) return 0;
1667             }
1668         }
1669         return 1;
1670     }
1671     return 0;
1672 }
1673 
1674 PyObject *pyBwAddEntries(pyBigWigFile_t *self, PyObject *args, PyObject *kwds) {
1675     static char *kwd_list[] = {"chroms", "starts", "ends", "values", "span", "step", "validate", NULL};
1676     PyObject *chroms = NULL, *starts = NULL, *ends = NULL, *values = NULL, *span = NULL, *step = NULL;
1677     PyObject *validate = Py_True;
1678     int desiredType;
1679 
1680     if(!self->bw) {
1681         PyErr_SetString(PyExc_RuntimeError, "The bigWig file handle is not open!");
1682         return NULL;
1683     }
1684 
1685     if(!PyArg_ParseTupleAndKeywords(args, kwds, "OO|OOOOO", kwd_list, &chroms, &starts, &ends, &values, &span, &step, &validate)) {
1686         PyErr_SetString(PyExc_RuntimeError, "Illegal arguments");
1687         return NULL;
1688     }
1689 
1690     desiredType = getType(chroms, starts, ends, values, span, step);
1691     if(desiredType == -1) {
1692         PyErr_SetString(PyExc_RuntimeError, "You must provide a valid set of entries. These can be comprised of any of the following: \n"
1693 "1. A list of each of chromosomes, start positions, end positions and values.\n"
1694 "2. A list of each of start positions and values. Also, a chromosome and span must be specified.\n"
1695 "3. A list values, in which case a single chromosome, start position, span and step must be specified.\n");
1696         return NULL;
1697     }
1698 
1699     if(validate == Py_True  && !addEntriesInputOK(self, chroms, starts, ends, span, step, desiredType)) {
1700         PyErr_SetString(PyExc_RuntimeError, "The entries you tried to add are out of order, precede already added entries, or otherwise use illegal values.\n"
1701 " Please correct this and try again.\n");
1702         return NULL;
1703     }
1704 
1705     if(canAppend(self, desiredType, chroms, starts, span, step)) {
1706         switch(desiredType) {
1707             case 0:
1708                 if(PyAppendIntervals(self, starts, ends, values)) goto error;
1709                 break;
1710             case 1:
1711                 if(PyAppendIntervalSpans(self, starts, values)) goto error;
1712                 break;
1713             case 2:
1714                 if(PyAppendIntervalSpanSteps(self, values)) goto error;
1715                 break;
1716         }
1717     } else {
1718         switch(desiredType) {
1719             case 0:
1720                 if(PyAddIntervals(self, chroms, starts, ends, values)) goto error;
1721                 break;
1722             case 1:
1723                 if(PyAddIntervalSpans(self, chroms, starts, values, span)) goto error;
1724                 break;
1725             case 2:
1726                 if(PyAddIntervalSpanSteps(self, chroms, starts, values, span, step)) goto error;
1727                 break;
1728         }
1729     }
1730     self->lastType = desiredType;
1731 
1732     Py_INCREF(Py_None);
1733     return Py_None;
1734 
1735 error:
1736     return NULL;
1737 }
1738 
1739 /**************************************************************
1740 *
1741 * BigBed functions, added in 0.3.0
1742 *
1743 **************************************************************/
1744 
1745 static PyObject *pyBBGetEntries(pyBigWigFile_t *self, PyObject *args, PyObject *kwds) {
1746     bigWigFile_t *bw = self->bw;
1747     uint32_t i;
1748     uint32_t start, end = -1, tid;
1749     unsigned long startl, endl;
1750     char *chrom;
1751     static char *kwd_list[] = {"chrom", "start", "end", "withString", NULL};
1752     PyObject *ret, *t, *starto = NULL, *endo = NULL;
1753     PyObject *withStringPy = Py_True;
1754     int withString = 1;
1755     bbOverlappingEntries_t *o;
1756 
1757     if(!bw) {
1758         PyErr_SetString(PyExc_RuntimeError, "The bigBed file handle is not open!");
1759         return NULL;
1760     }
1761 
1762     if(bw->type == 0) {
1763         PyErr_SetString(PyExc_RuntimeError, "bigWig files have no entries! Use 'intervals' or 'values' instead.");
1764         return NULL;
1765     }
1766 
1767     if(!PyArg_ParseTupleAndKeywords(args, kwds, "sOO|O", kwd_list, &chrom, &starto, &endo, &withStringPy)) {
1768         PyErr_SetString(PyExc_RuntimeError, "You must supply a chromosome, start and end position.\n");
1769         return NULL;
1770     }
1771 
1772     tid = bwGetTid(bw, chrom);
1773 
1774 #ifdef WITHNUMPY
1775     if(PyArray_IsScalar(starto, Integer)) {
1776         startl = (long) getNumpyL(starto);
1777     } else
1778 #endif
1779     if(PyLong_Check(starto)) {
1780         startl = PyLong_AsLong(starto);
1781 #if PY_MAJOR_VERSION < 3
1782     } else if(PyInt_Check(starto)) {
1783         startl = PyInt_AsLong(starto);
1784 #endif
1785     } else {
1786         PyErr_SetString(PyExc_RuntimeError, "The start coordinate must be a number!");
1787         return NULL;
1788     }
1789 
1790 #ifdef WITHNUMPY
1791     if(PyArray_IsScalar(endo, Integer)) {
1792         endl = (long) getNumpyL(endo);
1793     } else
1794 #endif
1795     if(PyLong_Check(endo)) {
1796         endl = PyLong_AsLong(endo);
1797 #if PY_MAJOR_VERSION < 3
1798     } else if(PyInt_Check(endo)) {
1799         endl = PyInt_AsLong(endo);
1800 #endif
1801     } else {
1802         PyErr_SetString(PyExc_RuntimeError, "The end coordinate must be a number!");
1803         return NULL;
1804     }
1805 
1806     if(endl == (unsigned long) -1 && tid != (uint32_t) -1) endl = bw->cl->len[tid];
1807     if(tid == (uint32_t) -1 || startl > end || endl > end) {
1808         PyErr_SetString(PyExc_RuntimeError, "Invalid interval bounds!");
1809         return NULL;
1810     }
1811     start = (uint32_t) startl;
1812     end = (uint32_t) endl;
1813     if(end <= start || end > bw->cl->len[tid] || start >= end) {
1814         PyErr_SetString(PyExc_RuntimeError, "Invalid interval bounds!");
1815         return NULL;
1816     }
1817 
1818     if(withStringPy == Py_False) withString = 0;
1819 
1820     o = bbGetOverlappingEntries(bw, chrom, start, end, withString);
1821     if(!o) {
1822         PyErr_SetString(PyExc_RuntimeError, "An error occurred while fetching the overlapping entries!\n");
1823         return NULL;
1824     }
1825     if(!o->l) {
1826         Py_INCREF(Py_None);
1827         return Py_None;
1828     }
1829 
1830     ret = PyList_New(o->l);
1831     if(!ret) goto error;
1832 
1833     for(i=0; i<o->l; i++) {
1834         if(withString) {
1835             t = Py_BuildValue("(iis)", o->start[i], o->end[i], o->str[i]);
1836         } else {
1837             t = Py_BuildValue("(ii)", o->start[i], o->end[i]);
1838         }
1839         if(!t) goto error;
1840         PyList_SetItem(ret, i, t);
1841     }
1842 
1843     bbDestroyOverlappingEntries(o);
1844     return ret;
1845 
1846 error:
1847     Py_DECREF(ret);
1848     bbDestroyOverlappingEntries(o);
1849     PyErr_SetString(PyExc_RuntimeError, "An error occurred while constructing the output list and tuple!");
1850     return NULL;
1851 }
1852 
1853 static PyObject *pyBBGetSQL(pyBigWigFile_t *self, PyObject *args) {
1854     bigWigFile_t *bw = self->bw;
1855     char *str = bbGetSQL(bw);
1856     size_t len = 0;
1857     PyObject *o = NULL;
1858 
1859     if(!bw) {
1860         PyErr_SetString(PyExc_RuntimeError, "The bigBed file handle is not open!");
1861         return NULL;
1862     }
1863 
1864     if(!str) {
1865         Py_INCREF(Py_None);
1866         return Py_None;
1867     }
1868     len = strlen(str);
1869 
1870 #if PY_MAJOR_VERSION >= 3
1871     o = PyBytes_FromStringAndSize(str, len);
1872 #else
1873     o = PyString_FromStringAndSize(str, len);
1874 #endif
1875     if(str) free(str);
1876 
1877     return o;
1878 }
1879 
1880 static PyObject *pyIsBigWig(pyBigWigFile_t *self, PyObject *args) {
1881     bigWigFile_t *bw = self->bw;
1882     if(bw->type == 0) {
1883         Py_INCREF(Py_True);
1884         return Py_True;
1885     }
1886 
1887     Py_INCREF(Py_False);
1888     return Py_False;
1889 }
1890 
1891 static PyObject *pyIsBigBed(pyBigWigFile_t *self, PyObject *args) {
1892     bigWigFile_t *bw = self->bw;
1893 
1894     if(!bw) {
1895         PyErr_SetString(PyExc_RuntimeError, "The bigBed file handle is not open!");
1896         return NULL;
1897     }
1898 
1899     if(bw->type == 1) {
1900         Py_INCREF(Py_True);
1901         return Py_True;
1902     }
1903 
1904     Py_INCREF(Py_False);
1905     return Py_False;
1906 }
1907 
1908 /**************************************************************
1909 *
1910 * End of bigBed functions
1911 *
1912 **************************************************************/
1913 
1914 #if PY_MAJOR_VERSION >= 3
1915 PyMODINIT_FUNC PyInit_pyBigWig(void) {
1916 #else
1917 PyMODINIT_FUNC initpyBigWig(void) {
1918 #endif
1919     PyObject *res;
1920     errno = 0; //just in case
1921 
1922 #if PY_MAJOR_VERSION >= 3
1923     if(Py_AtExit(bwCleanup)) return NULL;
1924     if(PyType_Ready(&bigWigFile) < 0) return NULL;
1925     if(bwInit(128000)) return NULL;
1926     res = PyModule_Create(&pyBigWigmodule);
1927     if(!res) return NULL;
1928 #else
1929     if(Py_AtExit(bwCleanup)) return;
1930     if(PyType_Ready(&bigWigFile) < 0) return;
1931     if(bwInit(128000)) return;
1932     res = Py_InitModule3("pyBigWig", bwMethods, "A module for handling bigWig files");
1933 #endif
1934 
1935     Py_INCREF(&bigWigFile);
1936     PyModule_AddObject(res, "pyBigWig", (PyObject *) &bigWigFile);
1937 
1938 #ifdef WITHNUMPY
1939     //Add the numpy constant
1940     import_array(); //Needed for numpy stuff to work
1941     PyModule_AddIntConstant(res, "numpy", 1);
1942 #else
1943     PyModule_AddIntConstant(res, "numpy", 0);
1944 #endif
1945 #ifdef NOCURL
1946     PyModule_AddIntConstant(res, "remote", 0);
1947 #else
1948     PyModule_AddIntConstant(res, "remote", 1);
1949 #endif
1950     PyModule_AddStringConstant(res, "__version__", pyBigWigVersion);
1951 
1952 #if PY_MAJOR_VERSION >= 3
1953     return res;
1954 #endif
1955 }
1956