Skip to content

Commit 0df4cfd

Browse files
committed
fix setdefaults and checkfieldtype
1 parent 0f19848 commit 0df4cfd

File tree

5 files changed

+109
-182
lines changed

5 files changed

+109
-182
lines changed

wfdbdemo.ipynb renamed to demo.ipynb

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -178,15 +178,38 @@
178178
},
179179
"outputs": [],
180180
"source": [
181-
"# Demo 8 - Read a WFDB record and create a copy \n",
181+
"# Demo 8 - Read a WFDB record's digital samples and create a copy via the wrsamp() instance method \n",
182+
"# of the Record object.\n",
183+
"\n",
184+
"# Read a record as a Record object.\n",
182185
"record = wfdb.rdsamp('sampledata/100', physical = False)\n",
183186
"record.recordname = '100x'\n",
187+
"\n",
188+
"# Call the instance method of the object\n",
184189
"record.wrsamp()\n",
185190
"\n",
186191
"# The new file can be read\n",
187192
"recordx = wfdb.rdsamp('100x')"
188193
]
189194
},
195+
{
196+
"cell_type": "code",
197+
"execution_count": null,
198+
"metadata": {
199+
"collapsed": true
200+
},
201+
"outputs": [],
202+
"source": [
203+
"# Demo 9 - Write a WFDB record without using a Record object via the gateway wrsamp function.\n",
204+
"# This is the easiest way to write physical signals to a WFDB file. \n",
205+
"\n",
206+
"# Read part of a record from Physiobank\n",
207+
"sig, fields = wfdb.srdsamp('a103l', sampfrom = 50000, channels = [0,1], pbdir = 'challenge/2015/training')\n",
208+
"\n",
209+
"# Call the gateway wrsamp function, manually inserting fields as function input parameters\n",
210+
"wfdb.wrsamp('ecgrecord', fs = 250, units = ['mV', 'mV'], signames = ['I', 'II'], p_signals = sig, fmt = ['16', '16'])"
211+
]
212+
},
190213
{
191214
"cell_type": "code",
192215
"execution_count": null,
@@ -195,7 +218,7 @@
195218
},
196219
"outputs": [],
197220
"source": [
198-
"# Demo 9 - Read a WFDB annotation file and create a copy under a new extension.\n",
221+
"# Demo 10 - Read a WFDB annotation file and create a copy under a new extension.\n",
199222
"annotation = wfdb.rdann('sampledata/100', 'atr')\n",
200223
"annotation.annotator = 'copy'\n",
201224
"annotation.wrann()\n",
@@ -212,7 +235,7 @@
212235
},
213236
"outputs": [],
214237
"source": [
215-
"# Demo 10 - View what the 'anntype' symbols mean in the standard WFDB library\n",
238+
"# Demo 11 - View what the 'anntype' symbols mean in the standard WFDB library\n",
216239
"wfdb.showanncodes()"
217240
]
218241
},
@@ -235,7 +258,7 @@
235258
},
236259
"outputs": [],
237260
"source": [
238-
"# Demo 11 - List the Physiobank Databases\n",
261+
"# Demo 12 - List the Physiobank Databases\n",
239262
"\n",
240263
"dbs = wfdb.getdblist()\n",
241264
"display(dbs)"
@@ -249,7 +272,7 @@
249272
},
250273
"outputs": [],
251274
"source": [
252-
"# Demo 12 - Download all the WFDB records and annotations from a small Physiobank Database\n",
275+
"# Demo 13 - Download all the WFDB records and annotations from a small Physiobank Database\n",
253276
"\n",
254277
"# Make a temporary download directory in your current working directory\n",
255278
"cwd = os.getcwd()\n",
@@ -273,7 +296,7 @@
273296
},
274297
"outputs": [],
275298
"source": [
276-
"# Demo 13 - Download specified files from a Physiobank database\n",
299+
"# Demo 14 - Download specified files from a Physiobank database\n",
277300
"\n",
278301
"# The files to download\n",
279302
"filelist = ['STAFF-Studies-bibliography-2016.pdf', 'data/001a.hea', 'data/001a.dat', 'data/001b.hea', 'data/001b.dat']\n",

devtests.ipynb

Lines changed: 4 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -13,59 +13,19 @@
1313
"metadata": {
1414
"collapsed": false
1515
},
16-
"outputs": [
17-
{
18-
"name": "stdout",
19-
"output_type": "stream",
20-
"text": [
21-
"Help on function __init__ in module wfdb.records:\n",
22-
"\n",
23-
"__init__(self, p_signals=None, d_signals=None, recordname=None, nsig=None, fs=None, counterfreq=None, basecounter=None, siglen=None, basetime=None, basedate=None, filename=None, fmt=None, sampsperframe=None, skew=None, byteoffset=None, adcgain=None, baseline=None, units=None, adcres=None, adczero=None, initvalue=None, checksum=None, blocksize=None, signame=None, comments=None)\n",
24-
" Initialize self. See help(type(self)) for accurate signature.\n",
25-
"\n"
26-
]
27-
}
28-
],
16+
"outputs": [],
2917
"source": [
30-
"import wfdb\n",
31-
"\n",
32-
"help(wfdb.Record.__init__)"
18+
"import wfdb"
3319
]
3420
},
3521
{
3622
"cell_type": "code",
37-
"execution_count": 1,
23+
"execution_count": 3,
3824
"metadata": {
3925
"collapsed": false,
4026
"scrolled": true
4127
},
42-
"outputs": [
43-
{
44-
"name": "stdout",
45-
"output_type": "stream",
46-
"text": [
47-
"checking field: p_signals\n",
48-
"inner ch: None\n",
49-
"checking field: fmt\n",
50-
"inner ch: None\n"
51-
]
52-
},
53-
{
54-
"ename": "TypeError",
55-
"evalue": "list indices must be integers or slices, not NoneType",
56-
"output_type": "error",
57-
"traceback": [
58-
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
59-
"\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)",
60-
"\u001b[0;32m<ipython-input-1-e7b74ff452fd>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0msig\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfields\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mwfdb\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msrdsamp\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'a103l'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0msampfrom\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m50000\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mchannels\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mpbdir\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m'challenge/2015/training'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;31m# Write a local WFDB record (manually inserting fields)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 5\u001b[0;31m \u001b[0mwfdb\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mwrsamp\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'ecgrecord'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfs\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m250\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0munits\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m'mV'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'mV'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0msignames\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m'I'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'II'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mp_signals\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0msig\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfmt\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m'16'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'16'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
61-
"\u001b[0;32m/home/chen/Projects/wfdb-python/wfdb/records.py\u001b[0m in \u001b[0;36mwrsamp\u001b[0;34m(recordname, fs, units, signames, p_signals, d_signals, fmt, gain, baseline, comments)\u001b[0m\n\u001b[1;32m 944\u001b[0m signame = signames, adcgain = gain, baseline = baseline, comments = comments)\n\u001b[1;32m 945\u001b[0m \u001b[0;31m# Compute optimal fields to store the digital signal, carry out adc, and set the fields.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 946\u001b[0;31m \u001b[0mrecord\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mset_d_features\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdo_adc\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 947\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 948\u001b[0m \u001b[0;31m# Create the Record object\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
62-
"\u001b[0;32m/home/chen/Projects/wfdb-python/wfdb/_signals.py\u001b[0m in \u001b[0;36mset_d_features\u001b[0;34m(self, do_adc, singlefmt)\u001b[0m\n\u001b[1;32m 123\u001b[0m \u001b[0;31m# If there is a fmt set\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 124\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 125\u001b[0;31m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcheckfield\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'fmt'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 126\u001b[0m \u001b[0;31m# Neither field set\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 127\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0madcgain\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mNone\u001b[0m \u001b[0;32mand\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mbaseline\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
63-
"\u001b[0;32m/home/chen/Projects/wfdb-python/wfdb/records.py\u001b[0m in \u001b[0;36mcheckfield\u001b[0;34m(self, field, ch)\u001b[0m\n\u001b[1;32m 45\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 46\u001b[0m \u001b[0;31m# Check the type of the field (and of its elements if it is to be a list)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 47\u001b[0;31m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcheckfieldtype\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfield\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mch\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 48\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 49\u001b[0m \u001b[0;31m# Individual specific field checks:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
64-
"\u001b[0;32m/home/chen/Projects/wfdb-python/wfdb/records.py\u001b[0m in \u001b[0;36mcheckfieldtype\u001b[0;34m(self, field, ch)\u001b[0m\n\u001b[1;32m 195\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0mfield\u001b[0m \u001b[0;32min\u001b[0m \u001b[0m_headers\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msigfieldspecs\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 196\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcheckfieldlist\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfield\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 197\u001b[0;31m \u001b[0mcheckitemtype\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mgetattr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfield\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mch\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfield\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0m_headers\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msigfieldspecs\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mfield\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mallowedtypes\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;32mTrue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;32mFalse\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 198\u001b[0m \u001b[0;31m# Segment specification field. List. elements cannot be None\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 199\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0mfield\u001b[0m \u001b[0;32min\u001b[0m \u001b[0m_headers\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msegfieldspecs\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
65-
"\u001b[0;31mTypeError\u001b[0m: list indices must be integers or slices, not NoneType"
66-
]
67-
}
68-
],
28+
"outputs": [],
6929
"source": [
7030
"import wfdb\n",
7131
"# Read part of a record from Physiobank\n",
@@ -74,82 +34,6 @@
7434
"wfdb.wrsamp('ecgrecord', fs = 250, units = ['mV', 'mV'], signames = ['I', 'II'], p_signals = sig, fmt = ['16', '16'])"
7535
]
7636
},
77-
{
78-
"cell_type": "code",
79-
"execution_count": 3,
80-
"metadata": {
81-
"collapsed": false
82-
},
83-
"outputs": [
84-
{
85-
"data": {
86-
"text/plain": [
87-
"array([[-0.0709259 , 0.8128327 ],\n",
88-
" [-0.06733821, 0.81872624],\n",
89-
" [-0.06292259, 0.82851711],\n",
90-
" ..., \n",
91-
" [-0.04084449, 0.7493346 ],\n",
92-
" [-0.04719194, 0.7581749 ],\n",
93-
" [-0.04677798, 0.7615019 ]])"
94-
]
95-
},
96-
"execution_count": 3,
97-
"metadata": {},
98-
"output_type": "execute_result"
99-
}
100-
],
101-
"source": [
102-
"sig"
103-
]
104-
},
105-
{
106-
"cell_type": "code",
107-
"execution_count": 4,
108-
"metadata": {
109-
"collapsed": false
110-
},
111-
"outputs": [
112-
{
113-
"data": {
114-
"text/plain": [
115-
"{'comments': ['Asystole', 'False alarm'],\n",
116-
" 'fs': 250.0,\n",
117-
" 'signame': ['II', 'V'],\n",
118-
" 'units': ['mV', 'mV']}"
119-
]
120-
},
121-
"execution_count": 4,
122-
"metadata": {},
123-
"output_type": "execute_result"
124-
}
125-
],
126-
"source": [
127-
"\n",
128-
"fields"
129-
]
130-
},
131-
{
132-
"cell_type": "code",
133-
"execution_count": 2,
134-
"metadata": {
135-
"collapsed": false
136-
},
137-
"outputs": [
138-
{
139-
"data": {
140-
"text/plain": [
141-
"[0, 1, 2]"
142-
]
143-
},
144-
"execution_count": 2,
145-
"metadata": {},
146-
"output_type": "execute_result"
147-
}
148-
],
149-
"source": [
150-
"list(range(len([1,2,3])))"
151-
]
152-
},
15337
{
15438
"cell_type": "code",
15539
"execution_count": null,

wfdb/_headers.py

Lines changed: 48 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,6 @@
1111
class BaseHeadersMixin(object):
1212

1313

14-
# Set defaults for fields needed to write the header if they have defaults.
15-
# This is NOT called by rdheader. It is only called by wrsamp for convenience.
16-
# It is also not called by wrhea (this may be changed in the future) since
17-
# it is supposed to be an explicit function.
18-
19-
# Not responsible for initializing the
20-
# attribute. That is done by the constructor.
21-
def setdefaults(self):
22-
for field in self.getwritefields():
23-
self.setdefault(field)
24-
2514
# Helper function for getwritefields
2615
# specfields is the set of specification fields
2716
# For record specs, it returns a list of all fields needed.
@@ -99,6 +88,21 @@ def getwritesubset(self, specfields):
9988
# Class with single-segment header methods
10089
# To be inherited by WFDBrecord from records.py.
10190
class HeadersMixin(BaseHeadersMixin):
91+
92+
# Set defaults for fields needed to write the header if they have defaults.
93+
# This is NOT called by rdheader. It is only called by the gateway wrsamp for convenience.
94+
# It is also not called by wrhea (this may be changed in the future) since
95+
# it is supposed to be an explicit function.
96+
97+
# Not responsible for initializing the
98+
# attribute. That is done by the constructor.
99+
def setdefaults(self):
100+
101+
rfields, sfields = self.getwritefields()
102+
for f in rfields:
103+
self.setdefault(f)
104+
for f in sfields:
105+
self.setdefault(f)
102106

103107
# Write a wfdb header file. The signals or segments fields are not used.
104108
def wrheader(self):
@@ -152,36 +156,32 @@ def setdefault(self, field):
152156

153157
# Record specification fields
154158
if field in recfieldspecs:
155-
# Return if nothing to set. Only set a field if it is empty
156-
if sigfieldspecs[field].write_def is None or getattr(self, field) is not None:
159+
# Return if no default to set, or if the field is already present.
160+
if recfieldspecs[field].write_def is None or getattr(self, field) is not None:
157161
return
158162
setattr(self, field, recfieldspecs[field].write_def)
163+
159164
# Signal specification fields
165+
# Setting entire list default, not filling in blanks in lists.
160166
elif field in sigfieldspecs:
161167

162-
if field == 'filename':
168+
# Specific dynamic case
169+
if field == 'filename' and self.filename is None:
163170
self.filename = self.nsig*[self.recordname+'.dat']
164-
165-
166-
# Return if nothing to set. Only set a field if it is empty
167-
if sigfieldspecs[field].write_def is None or getattr(self, field) is not None:
168171
return
169-
170-
# Check/set one channel at a time
172+
171173
item = getattr(self, field)
172174

173-
for ch in range(0, self.nsig):
175+
# Return if no default to set, or if the field is already present.
176+
if sigfieldspecs[field].write_def is None or item is not None:
177+
return
174178

175-
# Only set if it is empty
176-
if item[ch] is not None:
177-
continue
178-
179-
item[ch] = sigfieldspecs[field].write_def
180-
# Set more specific defaults if possible
181-
if field == 'adcres' and self.fmt is not None:
182-
self.adcres=_signals.wfdbfmtres(self.fmt)
179+
# Set more specific defaults if possible
180+
if field == 'adcres' and self.fmt is not None:
181+
self.adcres=_signals.wfdbfmtres(self.fmt)
182+
return
183183

184-
setattr(self, field, item)
184+
setattr(self, field, [sigfieldspecs[field].write_def]*self.nsig)
185185

186186
# Check the cohesion of fields used to write the header
187187
def checkfieldcohesion(self, recwritefields, sigwritefields):
@@ -238,7 +238,7 @@ def wrheaderfile(self, recwritefields, sigwritefields):
238238
# Traverse the ordered dictionary
239239
for field in sigfieldspecs:
240240
# If the field is being used, add each of its elements with the delimiter to the appropriate line
241-
if field in sigwritefields[ch]:
241+
if field in sigwritefields and sigwritefields[field][ch]:
242242
signallines[ch]=signallines[ch] + sigfieldspecs[field].delimiter + str(getattr(self, field)[ch])
243243
# The 'baseline' field needs to be closed with ')'
244244
if field== 'baseline':
@@ -259,6 +259,17 @@ def wrheaderfile(self, recwritefields, sigwritefields):
259259
# To be inherited by WFDBmultirecord from records.py.
260260
class MultiHeadersMixin(BaseHeadersMixin):
261261

262+
# Set defaults for fields needed to write the header if they have defaults.
263+
# This is NOT called by rdheader. It is only called by the gateway wrsamp for convenience.
264+
# It is also not called by wrhea (this may be changed in the future) since
265+
# it is supposed to be an explicit function.
266+
267+
# Not responsible for initializing the
268+
# attribute. That is done by the constructor.
269+
def setdefaults(self):
270+
for field in self.getwritefields():
271+
self.setdefault(field)
272+
262273
# Write a wfdb header file. The signals or segments fields are not used.
263274
def wrheader(self):
264275

@@ -294,13 +305,13 @@ def getwritefields(self):
294305
# Set a field to its default value if there is a default.
295306
def setdefault(self, field):
296307

297-
# Check whether the field is empty before trying to set.
298-
if getattr(self, field) != None:
299-
return
300-
301308
# Record specification fields
302-
if field == 'basetime':
303-
self.basetime = '00:00:00'
309+
if field in recfieldspecs:
310+
# Return if no default to set, or if the field is already present.
311+
if recfieldspecs[field].write_def is None or getattr(self, field) is not None:
312+
return
313+
setattr(self, field, recfieldspecs[field].write_def)
314+
304315

305316

306317
# Check the cohesion of fields used to write the header

0 commit comments

Comments
 (0)