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 2527 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]203205 # 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 substr216218 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, state228 229231 try: 232 if IS_PYTHON3: 233 val = next(it) 234 else: 235 val = it.next() 236 except StopIteration: 237 val = default 238 return val239 240242 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 250252 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 292294 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 317319 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 |