| Home | Trees | Indices | Help |
|---|
|
|
1 import re
2 import pdb
3 import sys
4 IS_PYTHON3 = sys.version_info[0] >= 3
5
6 if IS_PYTHON3:
7 exec('from ._edit_descriptors import *')
8 exec('from ._misc import expand_edit_descriptors, has_next_iterator')
9 exec('from . import config')
10 else:
11 exec('from _edit_descriptors import *')
12 exec('from _misc import expand_edit_descriptors, has_next_iterator')
13 exec('import config')
14
15 WIDTH_OPTIONAL_EDS = [A]
16 NON_WIDTH_EDS = [BN, BZ, P, SP, SS, S, X, T, TR, TL, Colon, Slash]
17 FORBIDDEN_EDS = [QuotedString, H]
18
19 # Some problems without pre written input vars:
20 # Cannot say when reversion conditions are met
21 # Cannot determine width of A edit descriptor
22 # Cannot determine complex input
23 # Cannot determine proper input for G edit descriptors
24
25
27
28 state = { \
29 'position' : 0,
30 'scale' : 0,
31 'incl_plus' : False,
32 'blanks_as_zeros' : config.PROC_BLANKS_AS_ZEROS,
33 # TODO: Implement halt if no more record input
34 'halt_if_no_vals' : False,
35 'exception_on_fail' : True,
36 }
37
38 # pdb.set_trace()
39
40 for ed in eds + reversion_eds:
41 if isinstance(ed, tuple(FORBIDDEN_EDS)):
42 raise InvalidFormat("%d edit descriptr not permitted on input")
43
44 # Expand repeated edit decriptors
45 eds = expand_edit_descriptors(eds)
46 reversion_eds = expand_edit_descriptors(reversion_eds)
47 # Assume one-to-one correspondance between edit descriptors and output
48 # values if number of output values is not defined
49 num_out_eds = 0
50 for ed in eds:
51 if isinstance(ed, OUTPUT_EDS):
52 num_out_eds += 1
53 num_rev_out_eds = 0
54 if num_vals is None:
55 num_vals = num_out_eds
56 for ed in reversion_eds:
57 if isinstance(ed, OUTPUT_EDS):
58 num_rev_out_eds += 1
59
60
61 # Will loop forever is no output edit descriptors
62 if (num_out_eds == 0):
63 return []
64 # Will loop forever if no output eds in reversion format and is more values
65 # requested than in the format
66 if (num_vals > num_out_eds) and (num_rev_out_eds == 0):
67 raise ValueError('Not enough output edit descriptors in reversion format to output %d values' % num_vals)
68
69 # May need to process multiple records, down to a higher function to supply
70 # appropriate string for format
71 if not hasattr(records, 'next'):
72 records = iter(re.split('\r\n|\r|\n', records))
73 record = _next(records, None)
74 if record is None:
75 return []
76
77 # if a_widths is not None:
78 # a_widths = itertools.cycle(a_widths)
79
80 vals = []
81 finish_up = False
82 ed_ind = -1
83 while True:
84 ed_ind += 1
85 # Signal to stop when Colon edit descriptor or end of format or end of
86 # reversion format reached. Also not to output any more data
87 if len(vals) >= num_vals:
88 finish_up = True
89 # Select the appropriate edit descriptor
90 if ed_ind < len(eds):
91 ed = eds[ed_ind]
92 else:
93 rev_ed_ind = (ed_ind - len(eds)) % len(reversion_eds)
94 # Reversion begun and has been instructed to halt
95 if finish_up and (rev_ed_ind == 0):
96 break
97 ed = reversion_eds[rev_ed_ind]
98
99 if isinstance(ed, QuotedString):
100 raise InvalidFormat('Cannot have string literal in an input format')
101 elif isinstance(ed, BN):
102 state['blanks_as_zeros'] = False
103 elif isinstance(ed, BZ):
104 state['blanks_as_zeros'] = True
105 elif isinstance(ed, P):
106 state['scale'] = ed.scale
107 elif isinstance(ed, SP):
108 state['incl_plus'] = True
109 elif isinstance(ed, SS):
110 state['incl_plus'] = False
111 elif isinstance(ed, S):
112 state['incl_plus'] = config.PROC_INCL_PLUS
113 elif isinstance(ed, (X, TR)):
114 state['position'] = min(state['position'] + ed.num_chars, len(record))
115 elif isinstance(ed, TL):
116 state['position'] = max(state['position'] - ed.num_chars, 0)
117 elif isinstance(ed, T):
118 if (ed.num_chars - 1) < 0:
119 state['position'] = 0
120 elif ed.num_chars > len(record):
121 state['position'] = len(record)
122 else:
123 state['position'] = ed.num_chars - 1
124 elif isinstance(ed, Slash):
125 # End of record
126 record = _next(records, None)
127 state['position'] = 0
128 if record is None:
129 break
130 elif isinstance(ed, Colon):
131 # Break if input value satisfied
132 if finish_up:
133 break
134 elif isinstance(ed, (Z, O, B, I)):
135 val, state = read_integer(ed, state, record)
136 vals.append(val)
137 elif isinstance(ed, A):
138 val, state = read_string(ed, state, record)
139 vals.append(val)
140 elif isinstance(ed, L):
141 val, state = read_logical(ed, state, record)
142 vals.append(val)
143 elif isinstance(ed, (F, E, D, EN, ES)):
144 val, state = read_float(ed, state, record)
145 vals.append(val)
146 elif isinstance(ed, G):
147 # Difficult to know what wanted since do not know type of input variable
148 # Use the G_INPUT_TRIAL_EDS variable to try the variables
149 # until one sticks
150 # n.b. vals and state do not get written to if
151 # exception id raised
152 resolved = False
153 g_trial_eds = iter(config.G_INPUT_TRIAL_EDS)
154 while not resolved:
155 ed_name = _next(g_trial_eds, '')
156 if ed_name.upper() in ('F', 'E', 'D', 'EN', 'ES'):
157 trial_ed = F()
158 trial_ed.width = ed.width
159 trial_ed.decimal_places = ed.decimal_places
160 # pdb.set_trace()
161 try:
162 val, state = read_float(trial_ed, state.copy(), record)
163 vals.append(val)
164 resolved = True
165 except ValueError:
166 continue
167 elif ed_name.upper() in ('Z', 'O', 'B', 'I'):
168 trial_ed = globals()[ed_name]()
169 trial_ed.width = ed.width
170 trial_ed.min_digits = ed.decimal_places
171 try:
172 val, state = read_integer(trial_ed, state.copy(), record)
173 vals.append(val)
174 resolved = True
175 except ValueError:
176 continue
177 elif ed_name.upper() in ('L'):
178 trial_ed = L()
179 trial_ed.width = ed.width
180 try:
181 val, state = read_logical(trial_ed, state.copy(), record)
182 vals.append(val)
183 resolved = True
184 except ValueError:
185 continue
186 elif ed_name.upper() in ('A'):
187 trial_ed = A()
188 trial_ed.width = ed.width
189 try:
190 val, state = read_string(trial_ed, state.copy(), record)
191 vals.append(val)
192 resolved = True
193 except ValueError:
194 continue
195 elif ed_name in ('G'):
196 raise ValueError('G edit descriptor not permitted in config.G_INPUT_TRIAL_EDS')
197 else:
198 raise ValueError('Unrecognised trial edit descriptor string in config.G_INPUT_TRIAL_EDS')
199
200 if config.RET_WRITTEN_VARS_ONLY:
201 vals = [val for val in vals if val is not None]
202 return vals[:num_vals]
203
205 # Save leading blanks
206 len_str = len(substr)
207 if state['blanks_as_zeros']:
208 # TODO: Are tabs blank characters?
209 substr = substr.replace(' ', '0')
210 else:
211 substr = substr.replace(' ', '')
212 # If were blanks but have been stripped away, replace with a zero
213 if len(substr) == 0 and (len_str > 0):
214 substr = '0'
215 return substr
216
218 start = max(state['position'], 0)
219 end = start + w
220 # if end > len(record):
221 # substr = ''
222 # # TODO: test if no chars transmitted, then poition does not change
223 # w = 0
224 # else:
225 substr = record[start:end]
226 state['position'] = min(state['position'] + w, len(record))
227 return substr, state
228
229
231 try:
232 if IS_PYTHON3:
233 val = next(it)
234 else:
235 val = it.next()
236 except StopIteration:
237 val = default
238 return val
239
240
242 if ed.width is None:
243 # Will assume rest of record is fair game for the
244 # unsized A edit descriptor
245 ed.width = len(record) - state['position']
246 substr, state = _get_substr(ed.width, record, state)
247 val = substr.ljust(ed.width, config.PROC_PAD_CHAR)
248 return (val, state)
249
250
252 substr, state = _get_substr(ed.width, record, state)
253 if ('-' in substr) and (not config.PROC_ALLOW_NEG_BOZ) and isinstance(ed, (Z, O, B)):
254 if state['exception_on_fail']:
255 raise ValueError('Negative numbers not permitted for binary, octal or hex')
256 else:
257 return (None, state)
258 if isinstance(ed, Z):
259 base = 16
260 elif isinstance(ed, I):
261 base = 10
262 elif isinstance(ed, O):
263 base = 8
264 elif isinstance(ed, B):
265 base = 2
266 # If a negative is followed by blanks, Gfortran and ifort
267 # interpret as a zero
268 if re.match(r'^ *- +$', substr):
269 substr = '0'
270 # If a negative or negative and blanks, ifort interprets as
271 # zero for an I edit descriptor
272 if config.PROC_NEG_AS_ZERO and isinstance(ed, I) and re.match(r'^( *- *| +)$', substr):
273 substr = '0'
274 # If string is zero length (reading off end of record?),
275 # interpret as zero so as to match what would be found in an
276 # unwritten FORTRAN variable
277 if substr == '':
278 if config.RET_UNWRITTEN_VARS_NONE or config.RET_WRITTEN_VARS_ONLY:
279 return (None, state)
280 else:
281 substr = '0'
282 teststr = _interpret_blanks(substr, state)
283 try:
284 val = int(teststr, base)
285 except ValueError:
286 if state['exception_on_fail']:
287 raise ValueError('%s is not a valid input for one of integer, octal, hex or binary' % substr)
288 else:
289 return (None, state)
290 return (val, state)
291
292
294 substr, state = _get_substr(ed.width, record, state)
295 # Deal with case where there is no more input to read from
296 if (substr == '') and (config.RET_UNWRITTEN_VARS_NONE or config.RET_WRITTEN_VARS_ONLY):
297 return (None, state)
298 # Remove preceding whitespace and take the first two letters as
299 # uppercase for testing
300 teststr = substr.upper().lstrip().lstrip('.')
301 if len(teststr):
302 teststr = teststr[0]
303 else:
304 # This is case where just a preceding period is read in
305 raise ValueError('%s is not a valid boolean input' % substr)
306 if teststr == 'T':
307 val = True
308 elif teststr == 'F':
309 val = False
310 else:
311 if state['exception_on_fail']:
312 raise ValueError('%s is not a valid boolean input' % substr)
313 else:
314 val = None
315 return (val, state)
316
317
319 substr, state = _get_substr(ed.width, record, state)
320 teststr = _interpret_blanks(substr, state)
321 # When reading off end of record, get empty string,
322 # interpret as 0
323 if teststr == '':
324 if config.RET_UNWRITTEN_VARS_NONE or config.RET_WRITTEN_VARS_ONLY:
325 return (None, state)
326 else:
327 teststr = '0'
328 # Python only understands 'E' as an exponential letter
329 teststr = teststr.upper().replace('D', 'E')
330 # Prepend an exponential letter if only a '-' or '+' denotes an exponent
331 if 'E' not in teststr:
332 teststr = teststr[0] + teststr[1:].replace('+', 'E+').replace('-', 'E-')
333 # ifort allows '.' to be interpreted as 0
334 if re.match(r'^ *\. *$', teststr):
335 teststr = '0'
336 # ifort allows '-' to be interpreted as 0
337 if re.match(r'^ *- *$', teststr):
338 teststr = '0'
339 # ifort allows numbers to end with 'E', 'E+', 'E-' and 'D'
340 # equivalents
341 res = re.match(r'(.*)(E|E\+|E\-)$', teststr)
342 if res:
343 teststr = res.group(1)
344 try:
345 val = float(teststr)
346 except ValueError:
347 if state['exception_on_fail']:
348 raise ValueError('%s is not a valid input as for an E, ES, EN or D edit descriptor' % substr)
349 else:
350 return (None, state)
351 # Special cases: insert a decimal if none specified
352 if ('.' not in teststr) and (ed.decimal_places is not None):
353 val = val / 10 ** ed.decimal_places
354 # Apply scale factor if exponent not supplied
355 if 'E' not in teststr:
356 val = val / 10 ** state['scale']
357 return (val, state)
358
| Home | Trees | Indices | Help |
|---|
| Generated by Epydoc 3.0.1 on Sun Feb 7 12:06:09 2016 | http://epydoc.sourceforge.net |