Skip to content

Commit b8ba1f3

Browse files
authored
Merge branch 'master' into windows-compatibility
2 parents ed8fcb6 + f58e942 commit b8ba1f3

File tree

8 files changed

+129
-177
lines changed

8 files changed

+129
-177
lines changed

devtests.ipynb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
"cell_type": "code",
2525
"execution_count": null,
2626
"metadata": {
27-
"collapsed": true
27+
"collapsed": false
2828
},
2929
"outputs": [],
3030
"source": []

setup.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@
5757
'matplotlib>=1.5.1',
5858
'requests>=2.10.0',
5959
'pandas>=0.19.1',
60-
'ipython>=5.1.0',
6160
],
6261

6362
# List additional groups of dependencies here (e.g. development

wfdb/_headers.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import numpy as np
22
import re
33
import os
4-
import sys
54
from collections import OrderedDict
65
from calendar import monthrange
76
from . import _signals
@@ -193,7 +192,7 @@ def checkfieldcohesion(self, recwritefields, sigwritefields):
193192
# even if some of its elements are None.
194193
for f in sigwritefields:
195194
if len(getattr(self, f)) != self.nsig:
196-
sys.exit('The length of field: '+f+' must match field nsig.')
195+
raise ValueError('The length of field: '+f+' must match field nsig.')
197196

198197
# Each filename must correspond to only one fmt, (and only one byte offset if defined).
199198
datfmts = {}
@@ -202,7 +201,7 @@ def checkfieldcohesion(self, recwritefields, sigwritefields):
202201
datfmts[self.filename[ch]] = self.fmt[ch]
203202
else:
204203
if datfmts[self.filename[ch]] != self.fmt[ch]:
205-
sys.exit('Each filename (dat file) specified must have the same fmt')
204+
raise ValueError('Each filename (dat file) specified must have the same fmt')
206205

207206
datoffsets = {}
208207
if self.byteoffset is not None:
@@ -214,7 +213,7 @@ def checkfieldcohesion(self, recwritefields, sigwritefields):
214213
datoffsets[self.filename[ch]] = self.byteoffset[ch]
215214
else:
216215
if datoffsets[self.filename[ch]] != self.byteoffset[ch]:
217-
sys.exit('Each filename (dat file) specified must have the same byte offset')
216+
raise ValueError('Each filename (dat file) specified must have the same byte offset')
218217

219218

220219
# Write a header file using the specified fields
@@ -320,11 +319,11 @@ def checkfieldcohesion(self):
320319
# The length of segname and seglen must match nseg
321320
for f in ['segname', 'seglen']:
322321
if len(getattr(self, f)) != self.nseg:
323-
sys.exit('The length of field: '+f+' does not match field nseg.')
322+
raise ValueError('The length of field: '+f+' does not match field nseg.')
324323

325324
# Check the sum of the 'seglen' fields against 'siglen'
326325
if np.sum(self.seglen) != self.siglen:
327-
sys.exit("The sum of the 'seglen' fields do not match the 'siglen' field")
326+
raise ValueError("The sum of the 'seglen' fields do not match the 'siglen' field")
328327

329328

330329
# Write a header file using the specified fields

wfdb/_signals.py

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import numpy as np
22
import os
3-
import sys
43
from . import downloads
54

65
# All defined WFDB dat formats
@@ -32,11 +31,10 @@ def checksignalcohesion(self, writefields):
3231

3332
# Match the actual signal shape against stated length and number of channels
3433
if (self.siglen, self.nsig) != self.d_signals.shape:
35-
print('siglen and nsig do not match shape of d_signals')
3634
print('siglen: ', self.siglen)
3735
print('nsig: ', self.nsig)
3836
print('d_signals.shape: ', self.d_signals.shape)
39-
sys.exit()
37+
raise ValueError('siglen and nsig do not match shape of d_signals')
4038

4139
# For each channel (if any), make sure the digital format has no values out of bounds
4240
for ch in range(0, self.nsig):
@@ -46,20 +44,20 @@ def checksignalcohesion(self, writefields):
4644
chmin = min(self.d_signals[:,ch])
4745
chmax = max(self.d_signals[:,ch])
4846
if (chmin < dmin) or (chmax > dmax):
49-
sys.exit("Channel "+str(ch)+" contain values outside allowed range ["+str(dmin)+", "+str(dmax)+"] for fmt "+str(fmt))
47+
raise IndexError("Channel "+str(ch)+" contain values outside allowed range ["+str(dmin)+", "+str(dmax)+"] for fmt "+str(fmt))
5048

5149
# Ensure that the checksums and initial value fields match the digital signal (if the fields are present)
5250
if self.nsig>0:
5351
if 'checksum' in writefields:
5452
realchecksum = self.calc_checksum()
5553
if self.checksum != realchecksum:
56-
print("checksum field does not match actual checksum of d_signals: ", realchecksum)
57-
sys.exit()
54+
print("The actual checksum of d_signals is: ", realchecksum)
55+
raise ValueError("checksum field does not match actual checksum of d_signals")
5856
if 'initvalue' in writefields:
5957
realinitvalue = list(self.d_signals[0,:])
6058
if self.initvalue != realinitvalue:
61-
print("initvalue field does not match actual initvalue of d_signals: ", realinitvalue)
62-
sys.exit()
59+
print("The actual initvalue of d_signals is: ", realinitvalue)
60+
raise ValueError("initvalue field does not match actual initvalue of d_signals")
6361

6462

6563
def set_p_features(self, do_dac = False):
@@ -116,7 +114,7 @@ def set_d_features(self, do_adc = False, singlefmt = 1):
116114
if self.fmt is None:
117115
# Make sure that neither adcgain nor baseline are set
118116
if self.adcgain is not None or self.baseline is not None:
119-
sys.exit('If fmt is not set, gain and baseline may not be set either.')
117+
raise Exception('If fmt is not set, gain and baseline may not be set either.')
120118
# Choose appropriate fmts based on estimated signal resolutions.
121119
res = estres(self.p_signals)
122120
self.fmt = wfdbfmt(res, singlefmt)
@@ -130,7 +128,7 @@ def set_d_features(self, do_adc = False, singlefmt = 1):
130128
self.adcgain, self.baseline = self.calculate_adcparams()
131129
# Exactly one field set
132130
elif (self.adcgain is None) ^ (self.baseline is None):
133-
sys.exit('If fmt is set, gain and baseline should both be set or not set.')
131+
raise Exception('If fmt is set, gain and baseline should both be set or not set.')
134132

135133
self.checkfield('adcgain', 'all')
136134
self.checkfield('baseline', 'all')
@@ -230,7 +228,7 @@ def calculate_adcparams(self):
230228

231229
# WFDB library limits...
232230
if abs(gain)>214748364 or abs(baseline)>2147483648:
233-
sys.exit('Chen, please fix this')
231+
raise Exception('cx1111, please fix this!')
234232

235233
gains.append(gain)
236234
baselines.append(baseline)
@@ -853,7 +851,7 @@ def wfdbfmtres(fmt):
853851
elif fmt == '32':
854852
return 32
855853
else:
856-
sys.exit('Invalid WFDB format.')
854+
raise ValueError('Invalid WFDB format.')
857855

858856
# Write a dat file.
859857
# All bytes are written one at a time
@@ -956,7 +954,7 @@ def wrdatfile(filename, fmt, d_signals, byteoffset):
956954
# Convert to unsigned 8 bit dtype to write
957955
bwrite = bwrite.astype('uint8')
958956
else:
959-
sys.exit('This library currently only supports the following formats: 80, 16, 24, 32')
957+
raise ValueError('This library currently only supports writing the following formats: 80, 16, 24, 32')
960958

961959
# Byte offset in the file
962960
if byteoffset is not None and byteoffset>0:

wfdb/annotations.py

Lines changed: 22 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
import numpy as np
22
import pandas as pd
3-
import sys
43
import re
54
import os
6-
from IPython.display import display
75
from . import _headers
86
from . import downloads
97

@@ -100,7 +98,7 @@ def checkfields(self):
10098
for field in ['recordname', 'annotator', 'annsamp', 'anntype']:
10199
if getattr(self, field) is None:
102100
print('The ', field, ' field is mandatory for writing annotation files')
103-
sys.exit()
101+
raise Exception('Missing required annotation field')
104102

105103
# Check all set fields
106104
for field in annfields:
@@ -115,79 +113,77 @@ def checkfield(self, field):
115113
if field in ['recordname', 'annotator', 'fs']:
116114
# Check the field type
117115
if type(getattr(self, field)) not in annfieldtypes[field]:
118-
print('The '+field+' field must be one of the following types:')
119-
display(annfieldtypes[field])
120-
sys.exit()
116+
print(annfieldtypes[field])
117+
raise TypeError('The '+field+' field must be one of the above types.')
121118

122119
# Field specific checks
123120
if field == 'recordname':
124121
# Allow letters, digits, hyphens, and underscores.
125122
acceptedstring = re.match('[-\w]+', self.recordname)
126123
if not acceptedstring or acceptedstring.string != self.recordname:
127-
sys.exit('recordname must only comprise of letters, digits, hyphens, and underscores.')
124+
raise ValueError('recordname must only comprise of letters, digits, hyphens, and underscores.')
128125
elif field == 'annotator':
129126
# Allow letters only
130127
acceptedstring = re.match('[a-zA-Z]+', self.annotator)
131128
if not acceptedstring or acceptedstring.string != self.annotator:
132-
sys.exit('annotator must only comprise of letters')
129+
raise ValueError('annotator must only comprise of letters')
133130
elif field == 'fs':
134131
if self.fs <=0:
135-
sys.exit('The fs field must be a non-negative number')
132+
raise ValueError('The fs field must be a non-negative number')
136133

137134
else:
138135
fielditem = getattr(self, field)
139136

140137
# Ensure the field item is a list or array.
141138
if type(fielditem) not in [list, np.ndarray]:
142-
print('The ', field, ' field must be a list or numpy array')
143-
sys.exit()
139+
raise TypeError('The '+field+' field must be a list or numpy array')
144140

145141
# Check the data types of the elements
146142
# annsamp and anntype may NOT have nones. Others may.
147143
if field in ['annsamp','anntype']:
148144
for item in fielditem:
149145
if type(item) not in annfieldtypes[field]:
150146
print("All elements of the '", field, "' field must be one of the following types:")
151-
display(annfieldtypes[field])
147+
print(annfieldtypes[field])
152148
print("All elements must be present")
153-
sys.exit()
149+
raise Exception()
154150
else:
155151
for item in fielditem:
156152
if item is not None and type(item) not in annfieldtypes[field]:
157153
print("All elements of the '", field, "' field must be one of the following types:")
158-
display(annfieldtypes[field])
154+
print(annfieldtypes[field])
159155
print("Elements may also be set to 'None'")
160-
sys.exit()
156+
raise Exception()
161157

162158
# Field specific checks
163159
# The C WFDB library stores num/sub/chan as chars.
164160
if field == 'annsamp':
165161
sampdiffs = np.concatenate(([self.annsamp[0]], np.diff(self.annsamp)))
166162
if min(self.annsamp) < 0 :
167-
sys.exit("The 'annsamp' field must only contain non-negative integers")
163+
raise ValueError("The 'annsamp' field must only contain non-negative integers")
168164
if min(sampdiffs) < 0 :
169-
sys.exit("The 'annsamp' field must contain monotonically increasing sample numbers")
165+
raise ValueError("The 'annsamp' field must contain monotonically increasing sample numbers")
170166
if max(sampdiffs) > 2147483648:
171-
sys.exit('WFDB annotation files cannot store sample differences greater than 2**31')
167+
raise ValueError('WFDB annotation files cannot store sample differences greater than 2**31')
172168
elif field == 'anntype':
173169
# Ensure all fields lie in standard WFDB annotation codes
174170
if set(self.anntype) - set(annsyms.values()) != set():
175171
print("The 'anntype' field contains items not encoded in the WFDB annotation library.")
176172
print('To see the valid annotation codes call: showanncodes()')
177173
print('To transfer non-encoded anntype items into the aux field call: self.type2aux()')
178-
sys.exit()
174+
raise Exception()
179175
elif field == 'subtype':
180176
# signed character
181177
if min(self.subtype) < 0 or max(self.subtype) >127:
182-
sys.exit("The 'subtype' field must only contain non-negative integers up to 127")
178+
raise ValueError("The 'subtype' field must only contain non-negative integers up to 127")
183179
elif field == 'chan':
184180
# unsigned character
185181
if min(self.chan) < 0 or max(self.chan) >255:
186-
sys.exit("The 'chan' field must only contain non-negative integers up to 255")
182+
raise ValueErrort("The 'chan' field must only contain non-negative integers up to 255")
187183
elif field == 'num':
188184
# signed character
189185
if min(self.num) < 0 or max(self.num) >127:
190-
sys.exit("The 'num' field must only contain non-negative integers up to 127")
186+
raise ValueError("The 'num' field must only contain non-negative integers up to 127")
191187
#elif field == 'aux': # No further conditions for aux field.
192188

193189

@@ -199,7 +195,7 @@ def checkfieldcohesion(self):
199195
for field in ['annsamp', 'anntype', 'num', 'subtype', 'chan', 'aux']:
200196
if getattr(self, field) is not None:
201197
if len(getattr(self, field)) != nannots:
202-
sys.exit("All written annotation fields: ['annsamp', 'anntype', 'num', 'subtype', 'chan', 'aux'] must have the same length")
198+
raise ValueError("All written annotation fields: ['annsamp', 'anntype', 'num', 'subtype', 'chan', 'aux'] must have the same length")
203199

204200
# Write an annotation file
205201
def wrannfile(self):
@@ -261,10 +257,10 @@ def type2aux(self):
261257

262258
# Ensure that anntype is a list of strings
263259
if type(self.anntype)!= list:
264-
sys.exit('anntype must be a list')
260+
raise TypeError('anntype must be a list')
265261
for at in self.anntype:
266262
if type(at) != str:
267-
sys.exit('anntype elements must all be strings')
263+
raise TypeError('anntype elements must all be strings')
268264

269265
external_anntypes = set(self.anntype) - set(annsyms.values())
270266

@@ -409,7 +405,7 @@ def showanncodes():
409405
Usage:
410406
showanncodes()
411407
"""
412-
display(symcodes)
408+
print(symcodes)
413409

414410
## ------------- Reading Annotations ------------- ##
415411

wfdb/downloads.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@
22
import re
33
import os
44
import posixpath
5-
import sys
65
import requests
7-
from IPython.display import display
86

97
# Read a header file from physiobank
108
def streamheader(recordname, pbdir):
@@ -112,7 +110,7 @@ def getrecordlist(dburl, records):
112110
if records == 'all':
113111
r = requests.get(posixpath.join(dburl, 'RECORDS'))
114112
if r.status_code == 404:
115-
sys.exit('The database '+dburl+' has no WFDB files to download')
113+
raise ValueError('The database '+dburl+' has no WFDB files to download')
116114

117115
# Get each line as a string
118116
recordlist = r.content.decode('ascii').splitlines()
@@ -131,7 +129,7 @@ def getannotators(dburl, annotators):
131129
if annotators == 'all':
132130
return
133131
else:
134-
sys.exit('The database '+dburl+' has no annotation files to download')
132+
raise ValueError('The database '+dburl+' has no annotation files to download')
135133
# Make sure the input annotators are present in the database
136134
annlist = r.content.decode('ascii').splitlines()
137135
annlist = [a.split('\t')[0] for a in annlist]
@@ -147,7 +145,7 @@ def getannotators(dburl, annotators):
147145
# user input ones. Check validity.
148146
for a in annotators:
149147
if a not in annlist:
150-
sys.exit('The database contains no annotators with extension: ', a)
148+
raise ValueError('The database contains no annotators with extension: '+a)
151149

152150
return annotators
153151

0 commit comments

Comments
 (0)