VerityPy 1.1
Python library for Verity data profiling, quality control, remediation
recfuncs.py
Go to the documentation of this file.
1#!/usr/bin/env python
2"""
3Record Functions
4
5Various worker functions to process data records.
6
7char_aliases is a dictionary of alias to actual token and allow specifying disruptive
8characters in transforms. For example, -lsquare- is the left square [ character which has special
9meaning in Python and the coded data strings used within the classes and therefore
10cannot be included within a simple string value. In this case, use -lsquare- which
11will be interpreted and replaced in processing.
12"""
13
14__all__ = ['delim_get_char',
15 'split_quoted_line',
16 'convert_special_notation',
17 'convert_char_aliases',
18 'is_math_alias',
19 'get_math_alias',
20 'is_field_its_datatype',
21 'is_field_its_format',
22 'char_aliases',
23 'char_aliases_reverse',
24 ]
25
26__version__ = '1.1'
27__author__ = 'Geoffrey Malafsky'
28__email__ = 'gmalafsky@technikinterlytics.com'
29__date__ = '20240804'
30
31import math
32from VerityPy.processing import datefuncs, numfuncs, field
33
34DQ:str="\""
35LF:str="\n"
36LCURLY:str="{"
37RCURLY:str="}"
38LSQUARE:str="["
39RSQUARE:str="]"
40COMMA:str=","
41
42char_aliases = {"-comma-": ",",
43 "-space-":" ",
44 "-tab-": "\t",
45 "-pipe-": "|",
46 "-bslash-": "\\",
47 "-fslash-": "/",
48 "-lparen-": "(",
49 "-rparen-": ")",
50 "-lcurly-": "{",
51 "-rcurly-": "}",
52 "-lsquare-": "[",
53 "-rsquare-": "]",
54 "-mathpi-": str(math.pi),
55 "-mathe-": str(math.e),
56 "-dblquote-":"\""
57 }
58
59char_aliases_reverse = {",":"-comma-",
60 "\t":"-tab-",
61 "|":"-pipe-",
62 "\\":"-bslash-",
63 "/":"-fslash-",
64 "(":"-lparen-",
65 ")":"-rparen-",
66 "{":"-lcurly-",
67 "}":"-rcurly-",
68 "[":"-lsquare-",
69 "]":"-rsquare-",
70 "\"":"-dblquote-"
71 }
72
73def convert_char_aliases(strin:str) -> str:
74 """
75 Finds and converts character aliases in a string such as -comma- to ,
76 Returns new string. Starts with notok: if error occurs
77 """
78
79 result:str=""
80 try:
81 result=strin
82 for k,v in char_aliases.items():
83 if k in result:
84 result=result.replace(k, v)
85 except (RuntimeError,ValueError,OSError) as err:
86 result="notok:" + str(err)
87 return result
88
89def extract_char_aliases(strin:str,ignore:list) -> str:
90 """
91 Finds and converts troublesome characters into aliases in a string
92 ignore: list of characters to not extract such as ["|",","]
93 Returns new string. Starts with notok: if error occurs
94 """
95
96 result:str=""
97 try:
98 result=strin
99 if ignore is None:
100 ignore=[]
101 for k,v in char_aliases_reverse.items():
102 if k not in ignore and k in result:
103 result=result.replace(k, v)
104 except (RuntimeError,ValueError,OSError) as err:
105 result="notok:" + str(err)
106 return result
107
108def is_math_alias(valnum:str) -> bool:
109 """
110 Checks if string is -mathpi- or -mathe-
111 Returns bool
112 """
113
114 result:bool=False
115 try :
116 if valnum.lower() in ["-mathpi-","-mathe-"]:
117 result=True
118 except (RuntimeError, ValueError):
119 result=False
120 return result
121
122def get_math_alias(valnum:str) -> str:
123 """
124 Checks if string is -mathpi- or -mathe-
125
126 Returns string of Python value math.pi or math.e if string is -mathpi- or -mathe- which are Verity aliases.
127 Otherwise, returns original string unless error in which case starts with notok:reason
128 """
129
130 result:str=""
131 try :
132 if valnum.lower() in ["-mathpi-","-mathe-"]:
133 valnum=valnum.lower()
134 if valnum=="-mathpi-":
135 result= str(math.pi)
136 elif valnum=="-mathe-":
137 result= str(math.e)
138 else:
139 result=valnum
140 except (RuntimeError, ValueError) as err:
141 result="notok:" + str(err)
142 return result
143
144def delim_get_char(delimin:str) -> str:
145 """
146 Converts name of delim into its character
147
148 Delim can be words or char for: comma, pipe, tab, colon, caret, hyphen to become
149 char (, | \t : ^ -) . If not one of these then return is 'false:xxx'
150 """
151
152 delim_char:str=""
153 delim:str=""
154 try:
155 delim= delimin.strip()
156 if len(delim)==0:
157 raise ValueError("delim is empty")
158 delim=delim.lower()
159 if delim in ("comma",","):
160 delim_char=","
161 elif delim in ("pipe","|"):
162 delim_char="|"
163 elif delim in("tab","\t"):
164 delim_char="\t"
165 elif delim==("colon",":"):
166 delim_char=":"
167 elif delim==("caret","^"):
168 delim_char="^"
169 elif delim==("hyphen","-"):
170 delim_char="-"
171 else:
172 raise ValueError("unknown delim")
173 except (ValueError,RuntimeError) as err:
174 delim_char= "false:" + str(err)
175 return delim_char
176
177def convert_special_notation(strin:str) -> str:
178 """
179 Convert VerityX special notation
180
181 Converts the VerityX product special notations into their mapped
182 strings. Returns decoded string or original value if not matched
183
184 Notations:
185 -comma- -> ,
186 -tab- -> \t
187 -space- ->
188 -pipe- -> |
189 -bslash- -> \\
190 -fslash- -> /
191 -lparen- -> (
192 -rparen- -> )
193 -lcurly- -> {
194 -rcurly- -> }
195 -lsquare- -> [
196 -rsquare- -> ]
197 -mathpi- -> math.pi value
198 -mathe- -> math.e value
199 -crlf- -> \r\n
200 -lf- -> \n
201 """
202
203 str_out:str=""
204 str_in:str=""
205 try:
206 str_in= strin.strip().lower()
207 if len(str_in)==0:
208 raise ValueError("str_in is empty")
209 if str_in== "-comma-":
210 str_out=","
211 elif str_in== "-tab-":
212 str_out="\t"
213 elif str_in== "-space-":
214 str_out=" "
215 elif str_in== "-pipe-":
216 str_out="|"
217 elif str_in== "-bslash-":
218 str_out="\\"
219 elif str_in== "-fslash-":
220 str_out="/"
221 elif str_in== "-lparen-":
222 str_out="("
223 elif str_in== "-rparen-":
224 str_out=")"
225 elif str_in== "-lcurly-":
226 str_out="{"
227 elif str_in== "-rcurly-":
228 str_out="}"
229 elif str_in== "-lsquare-":
230 str_out="["
231 elif str_in== "-rsquare-":
232 str_out="]"
233 elif str_in== "-mathpi-":
234 str_out= str(math.pi)
235 elif str_in== "-mathe-":
236 str_out= str(math.e)
237 elif str_in== "-crlf-":
238 str_out= "\r\n"
239 elif str_in== "-lf-":
240 str_out= "\n"
241 else:
242 raise ValueError("unknown notation: " + str_in)
243 except (RuntimeError,ValueError):
244 str_out= strin
245 return str_out
246
247def split_quoted_line(line_in:str,delim:str) -> list:
248 """
249 Decompose quoted record line.
250 line_in: string data record
251 delim: name of delimiter (comma, pipe, tab, colon)
252 Returns list of parsed values. If error, 0th entry starts with notok:
253 """
254
255 delim_char:str=""
256 out_rec:list=[]
257 cur_line:str
258 cur_str:str
259 dq:str= "\""
260 dq_delim:str
261 nqf:int
262 nqb:int
263 ndelim:int
264 nqdelim:int
265 has_last:bool=False
266 try:
267 if len(line_in)==0:
268 return out_rec
269 if len(delim)>1:
270 delim_char= delim_get_char(delim)
271 else:
272 delim_char=delim
273 if len(delim_char)==0 or delim_char.startswith("notok:"):
274 raise ValueError("incorrect delim:" + delim)
275 dq_delim= dq + delim_char
276 cur_line=line_in
277 while len(cur_line)>0:
278 nqf=-1
279 nqb=-1
280 ndelim=-1
281 nqdelim=-1
282 nqf= cur_line.find(dq)
283 cur_str=""
284 if -1 < nqf < len(cur_line)-1:
285 nqb= cur_line.find(dq,nqf+1)
286 if delim_char in cur_line:
287 ndelim= cur_line.find(delim_char)
288 nqdelim= cur_line.find(dq_delim)
289 if ndelim==0:
290 if cur_line==delim_char:
291 has_last=True
292 cur_line=""
293 elif len(cur_line)> 0:
294 cur_line= cur_line[1:]
295 else:
296 cur_line=""
297 elif nqf<0:
298 if ndelim<0:
299 cur_str=cur_line
300 cur_line=""
301 elif ndelim==len(cur_line)-1:
302 cur_str=cur_line[:ndelim]
303 has_last=True
304 cur_line=""
305 else:
306 cur_str=cur_line[:ndelim]
307 cur_line=cur_line[ndelim+1:]
308 elif nqf>=0:
309 if 0< ndelim <nqf:
310 cur_str=cur_line[:ndelim]
311 cur_line=cur_line[ndelim+1:]
312 elif nqb> nqf:
313 if nqdelim>= nqb:
314 # intermediate quotes within fld
315 cur_str=cur_line[nqf:nqdelim]
316 cur_line=cur_line[nqdelim+2:] # remove quote and delim (1 char delim)
317 if len(cur_line)==0:
318 has_last=True
319 elif nqdelim==nqf:
320 # missing leading quote so 1st instance is actual end of fld
321 cur_str=cur_line[:nqdelim]
322 cur_line=cur_line[nqdelim+2:]
323 else:
324 cur_str=cur_line[nqf:nqb]
325 cur_line=cur_line[nqb+1:]
326 elif ndelim>nqf:
327 # assume errant quote
328 cur_str=cur_line[:ndelim]
329 cur_line=cur_line[ndelim+1:]
330 else:
331 cur_str=cur_line[nqf+1:]
332 cur_line=""
333 if dq in cur_str:
334 cur_str=cur_str.replace(dq,'')
335 else:
336 cur_str=cur_line
337 cur_line=""
338 if dq in cur_str:
339 cur_str=cur_str.replace(dq,'')
340
341 out_rec.append(cur_str)
342 if has_last:
343 out_rec.append("")
344 break
345 except (RuntimeError,ValueError) as err:
346 out_rec.clear()
347 out_rec.append("notok:" + str(err))
348 return out_rec
349
350def detect_datatype(strin:str) -> str:
351 """
352 Detect Value Datatype
353
354 Detect a value's data type by looking for known patterns of
355 characters and evaluating likely datatype.
356 Returns datatype or starts with notok: if error
357 """
358
359 txt:str=""
360 txt1:str=""
361 txt2:str=""
362 dtype:str=""
363 try:
364 if strin is None:
365 raise ValueError("no value supplied")
366 strin=strin.lower().strip()
367 if len(strin)==0:
368 return dtype
369 if strin in ["true", "false"]:
370 dtype="bool"
371 elif strin in ["0", "-0"]:
372 dtype="int"
373 elif strin.startswith("00"):
374 dtype="string"
375 elif any(x in strin for x in ["e+","e-","e"]):
376 txt= numfuncs.get_value_from_suspect_exp(strin)
377 if len(txt)>0 and txt!=strin and not txt.startswith("notok:"):
378 if "." in txt:
379 dtype="real"
380 else:
381 dtype="int"
382 else:
383 dtype="string"
384 elif 8<= len(strin) <=30 and ("/" in strin or "-" in strin):
385 if strin.startswith("/") or strin.startswith("-"):
386 dtype="string"
387 else:
388 txt=strin
389 txt1=""
390 if "t" in txt:
391 txt1=txt[txt.find("t")+1:].strip()
392 txt=txt[:txt.find("t")].strip()
393 if 6> len(txt) >=50:
394 dtype="string"
395 else:
396 txt2= datefuncs.convert_date_to_iso(txt,"",True)
397 if txt2.startswith("notok:") or len(txt2)<8:
398 dtype="string"
399 elif txt2.startswith("00"):
400 dtype="string"
401 elif txt2[4:6]=="00" or txt2[6:8]=="00":
402 dtype="string"
403 elif txt2.endswith(")") and "(" in txt2:
404 txt2=txt2[txt2.find("(")+1:-1]
405 if len(txt2)>=4:
406 if len(txt1)>0:
407 if ":" in txt1:
408 txt1=txt1.replace(":","")
409 if "+" in txt1:
410 txt1=txt1[:txt1.find("+")].strip()
411 elif "-" in txt1:
412 txt1=txt1[:txt1.find("-")].strip()
413 elif " " in txt1:
414 txt1=txt1[:txt1.find(" ")].strip()
415 if len(txt1)>0 and numfuncs.is_real(txt1):
416 dtype="date"
417 else:
418 dtype="string"
419 else:
420 dtype="date"
421 else:
422 dtype="string"
423 else:
424 dtype="string"
425 elif "." in strin and len(strin)>1:
426 if strin.startswith("."):
427 txt= strin[1:]
428 if "." not in txt and numfuncs.is_real(txt):
429 dtype="real"
430 else:
431 dtype="string"
432 elif numfuncs.is_real(strin):
433 dtype="real"
434 else:
435 dtype="string"
436 elif numfuncs.is_int(strin):
437 dtype="int"
438 else:
439 dtype="string"
440
441 except (RuntimeError,OSError, ValueError) as err:
442 dtype="notok:" + str(err)
443 return dtype
444
445def assign_datatype_to_fields(datatype_dist_fields:list, settings:dict) -> list:
446 """
447 Uses list of distribution of detected datatypes for each fld to determine the most likely
448 datatype appropriate to assign to it. This uses threshhold settings and knowledge from
449 curated data sets across multiple domains and data systems.
450
451 datatype_dist_fields: list of dict objects with keys [string, int, real, date, bool, empty]
452 and for each values = number of instances for each fld.
453 This should come from results of analyzequality.do_qualityinspect()
454 settings: dict with keys for various settings including
455 - include_empty: bool whether to include number of empty values in statistical calculation. Default is True
456 - minfrac: real number minimum threshhold in either percentage (any value great than 1) or fraction (0-1). Default is 0.75
457
458 returns: string list with datatypes (string, int, real, date, bool) per fld (or empty if cannot be determined).
459 0th entry will start with notok: if an error occurs
460 """
461
462 field_dtypes:list=[]
463 try:
464 if datatype_dist_fields is None or not isinstance(datatype_dist_fields, list) or len(datatype_dist_fields)==0:
465 raise ValueError("datatype_dist_fields is not a list")
466 for i in range(len(datatype_dist_fields)):
467 if datatype_dist_fields[i] is None or not isinstance(datatype_dist_fields[i], dict):
468 raise ValueError("datatype_dist at index " + str(i) + " is not a dict")
469 elif "int" not in datatype_dist_fields[i] or not isinstance(datatype_dist_fields[i]["int"], int):
470 raise ValueError("datatype_dist at index " + str(i) + " missing int key")
471 elif "real" not in datatype_dist_fields[i] or not isinstance(datatype_dist_fields[i]["real"], int):
472 raise ValueError("datatype_dist at index " + str(i) + " missing real key")
473 elif "bool" not in datatype_dist_fields[i] or not isinstance(datatype_dist_fields[i]["bool"], int):
474 raise ValueError("datatype_dist at index " + str(i) + " missing bool key")
475 elif "date" not in datatype_dist_fields[i] or not isinstance(datatype_dist_fields[i]["date"], int):
476 raise ValueError("datatype_dist at index " + str(i) + " missing date key")
477 elif "string" not in datatype_dist_fields[i] or not isinstance(datatype_dist_fields[i]["string"], int):
478 raise ValueError("datatype_dist at index " + str(i) + " missing string key")
479 elif "empty" not in datatype_dist_fields[i] or not isinstance(datatype_dist_fields[i]["empty"], int):
480 raise ValueError("datatype_dist at index " + str(i) + " missing empty key")
481 for i in range(len(datatype_dist_fields)):
482 field_dtypes.append(assign_datatype(datatype_dist_fields[i],settings))
483 except (RuntimeError, OSError, ValueError) as err:
484 field_dtypes.insert(0,"notok:" + str(err))
485 return field_dtypes
486
487def assign_datatype(datatype_dist:dict, settings:dict) -> str:
488 """
489 Uses distribution of detected datatypes for a fld to determine the most likely
490 datatype appropriate to assign to it. This uses threshhold settings and knowledge from
491 curated data sets across multiple domains and data systems.
492
493 datatype_dist: dict object with keys [string, int, real, date, bool, empty]
494 and for each values = number of instances. This should come from results of analyzequality.do_qualityinspect()
495 settings: dict with keys for various settings including
496 - include_empty: bool whether to include number of empty values in statistical calculation. Default is True
497 - minfrac: real number minimum threshhold in either percentage (any value great than 1) or fraction (0-1). Default is 0.75
498
499 returns: string with datatype (string, int, real, date, bool) or empty if cannot be determined. will start with notok: if an error occurs
500 """
501
502 dtype:str=""
503 dint:float=0
504 dreal:float=0
505 dbool:float=0
506 ddate:float=0
507 dstr:float=0
508 dempty:float=0
509 ntotal:int=0
510 ntotal_not_empty:int=0
511 dmin:float=0
512 dmax_count:float=0
513 minfrac:float=.75
514 inc_empty:bool=True
515 dt_max:str=""
516 try:
517 if datatype_dist is None or not isinstance(datatype_dist, dict):
518 raise ValueError("datatype_dist is not a dict")
519 if not settings is None and isinstance(settings, dict):
520 if "include_empty" in settings and settings["include_empty"].lower() =="false":
521 inc_empty=False
522 if "minfrac" in settings:
523 minfrac= numfuncs.is_real_get(settings["minfrac"],"number")
524 if 1< minfrac <= 100:
525 minfrac /= 100
526 elif 0>= minfrac or minfrac>100:
527 minfrac=.75
528 if "int" not in datatype_dist or not isinstance(datatype_dist["int"], int):
529 raise ValueError("datatype_dist missing int key")
530 elif "real" not in datatype_dist or not isinstance(datatype_dist["real"], int):
531 raise ValueError("datatype_dist missing real key")
532 elif "bool" not in datatype_dist or not isinstance(datatype_dist["bool"], int):
533 raise ValueError("datatype_dist missing bool key")
534 elif "date" not in datatype_dist or not isinstance(datatype_dist["date"], int):
535 raise ValueError("datatype_dist missing date key")
536 elif "string" not in datatype_dist or not isinstance(datatype_dist["string"], int):
537 raise ValueError("datatype_dist missing string key")
538 elif "empty" not in datatype_dist or not isinstance(datatype_dist["empty"], int):
539 raise ValueError("datatype_dist missing empty key")
540 dint=datatype_dist["int"] if datatype_dist["int"]>0 else 0
541 dreal=datatype_dist["real"] if datatype_dist["real"]>0 else 0
542 dbool=datatype_dist["bool"] if datatype_dist["bool"]>0 else 0
543 ddate=datatype_dist["date"] if datatype_dist["date"]>0 else 0
544 dstr=datatype_dist["string"] if datatype_dist["string"]>0 else 0
545 dempty=datatype_dist["empty"] if datatype_dist["empty"]>0 else 0
546 ntotal_not_empty= dint + dreal + dbool + ddate + dstr
547 ntotal= ntotal_not_empty + dempty
548 if ntotal==0:
549 raise ValueError("no counts of any datatype")
550
551 if inc_empty:
552 dmin = math.floor(minfrac * ntotal)
553 if dempty>=dmax_count:
554 dmax_count=dempty
555 dt_max="empty"
556 else:
557 if ntotal_not_empty==0:
558 raise ValueError("no counts of any datatype excluding empty values")
559 dmin = math.floor(minfrac * ntotal_not_empty)
560
561 if dint>=dmax_count:
562 dmax_count=dint
563 dt_max="int"
564 if dreal>=dmax_count:
565 dmax_count=dreal
566 dt_max="real"
567 if dbool>=dmax_count:
568 dmax_count=dbool
569 dt_max="bool"
570 if ddate>=dmax_count:
571 dmax_count=ddate
572 dt_max="date"
573 if dstr>=dmax_count:
574 dmax_count=dstr
575 dt_max="string"
576 if dmax_count<dmin:
577 # no single type above min so try combining int and real
578 if (dint + dreal)>= dmin:
579 dt_max="real"
580 dmax_count= dint + dreal
581 if dmax_count<dmin and inc_empty:
582 # still no clear datatype so combine date and string
583 if (ddate + dempty)>= dmin:
584 dt_max="date"
585 dmax_count= ddate + dempty
586 if dmax_count<dmin and inc_empty:
587 # still no clear datatype so combine empty and string
588 if (dstr + dempty)>= dmin:
589 dt_max="string"
590 dmax_count= dstr + dempty
591 if dmax_count>=dmin:
592 dtype= dt_max
593 except (RuntimeError,OSError, ValueError) as err:
594 dtype="notok:" + str(err)
595 return dtype
596
597
598def is_field_its_datatype(dtype:str, fieldval:str, datefmt:str="")->bool:
599 """IsFieldItsDatatype
600 Determines if a field's value is in its specified datatype
601
602 dtype: field's defined datatype (int, real, bool, date, string)
603 fieldval: field value
604 datefmt: date format if checking for a date
605 returns: bool
606 """
607
608 result:bool=False
609 try:
610 if dtype is None or fieldval is None:
611 raise ValueError("missing dtype or fieldval since = None")
612 dtype=dtype.lower()
613 if len(dtype)==0:
614 return True
615 if dtype=="real":
616 if numfuncs.is_real(fieldval):
617 result=True
618 elif dtype=="int":
619 if numfuncs.is_int(fieldval):
620 result=True
621 elif dtype.startswith("date"):
622 if len(fieldval)==0:
623 result=False
624 elif dtype=="datetime":
625 result= datefuncs.is_iso_date_str(fieldval, True).startswith("true")
626 elif datefmt=="iso":
627 result= datefuncs.is_iso_date_str(fieldval, False).startswith("true")
628 else:
629 result= datefuncs.is_date_format(fieldval, datefmt)
630 elif dtype=="bool":
631 result = fieldval.lower() in ("true","false")
632 elif dtype=="string":
633 result= True
634 except (OSError, RuntimeError, ValueError) as err:
635 result=False
636 print("ERROR:" + str(err) + "\n")
637 return result
638
639
640def is_field_its_format(fieldval:str, fld:field.Field, allow_empty:bool=False)->str:
641 """IsFieldItsFormat
642 Determines if field value conforms to its defined format (if set)
643
644 fieldVal: field value to check
645 fld: Field Object
646 allow_empty: bool whether empty values (e.g null) are allowed
647 returns: string as bool:message with bool =(true,false) and message= reason. If error, starts with notok:message
648 """
649
650 result:bool=False
651 outmsg:str=""
652 msg:str=""
653 txt:str=""
654 flag:bool=False
655 flag1:bool=False
656 n1:int=0
657 try:
658 if fieldval is None:
659 raise ValueError("missing fieldval since = None")
660 if fld is None:
661 raise ValueError("missing field since = None")
662 elif not isinstance(fld, field.Field):
663 raise ValueError("field is not Field object")
664 fld.datatype= fld.datatype.lower()
665 fld.fmt_strcase= fld.fmt_strcase.lower()
666 if len(fieldval.strip())==0:
667 result=allow_empty
668 msg="empty"
669 elif fld.datatype.startswith("date"):
670 if len(fld.fmt_date)>0:
671 if is_field_its_datatype(fld.datatype, fieldval, fld.fmt_date):
672 result=True
673 else:
674 msg="faildate"
675 else:
676 msg="missing date format"
677 elif fld.datatype=="bool":
678 if is_field_its_datatype(fld.datatype, fieldval):
679 result=True
680 else:
681 msg="failbool"
682 elif fld.datatype=="string":
683 flag=False
684 flag1=False
685 if fld.fmt_strlen>0 and len(fieldval)!=fld.fmt_strlen:
686 flag=True
687 msg="faillength(" + str(len(fieldval)) + "/" + str(fld.fmt_strlen) + ")"
688 if fld.fmt_strcase in ("upper","lower"):
689 if fld.fmt_strcase=="upper":
690 txt= fieldval.upper()
691 elif fld.fmt_strcase=="lower":
692 txt= fieldval.lower()
693 if txt != fieldval:
694 flag=True
695 if len(msg)>0:
696 msg += ","
697 msg += "failcase(" + fld.fmt_strcase + ")"
698 if not flag and not flag1:
699 result= True
700 elif fld.datatype in ("int","real"):
701 if fld.datatype=="int":
702 flag= numfuncs.is_int(fieldval)
703 else:
704 txt= numfuncs.is_real_get(fieldval, "string", False)
705 flag= not txt.startswith("false")
706 if not flag:
707 msg="failnumber"
708 elif fld.datatype=="real" and fld.fmt_decimal>0:
709 n1=0
710 if "." in txt:
711 n1= len(txt)-1 - txt.index(".")
712 if n1 != fld.fmt_decimal:
713 msg= "faildecimal(" + str(n1) + "/" + str(fld.fmt_decimal) + ")"
714 else:
715 result=True
716 else:
717 result=True
718 outmsg= str(result).lower()
719 if len(msg)>0:
720 outmsg += ":" + msg
721 except (OSError, RuntimeError, ValueError) as err:
722 outmsg="notok:" + str(err)
723 return outmsg
724
str delim_get_char(str delimin)
Definition recfuncs.py:144
list split_quoted_line(str line_in, str delim)
Definition recfuncs.py:247
list assign_datatype_to_fields(list datatype_dist_fields, dict settings)
Definition recfuncs.py:445
str convert_special_notation(str strin)
Definition recfuncs.py:177
str convert_char_aliases(str strin)
Definition recfuncs.py:73
str detect_datatype(str strin)
Definition recfuncs.py:350
str assign_datatype(dict datatype_dist, dict settings)
Definition recfuncs.py:487
str extract_char_aliases(str strin, list ignore)
Definition recfuncs.py:89
bool is_math_alias(str valnum)
Definition recfuncs.py:108
str is_field_its_format(str fieldval, field.Field fld, bool allow_empty=False)
Definition recfuncs.py:640
str get_math_alias(str valnum)
Definition recfuncs.py:122
bool is_field_its_datatype(str dtype, str fieldval, str datefmt="")
Definition recfuncs.py:598