1import re 2from decimal import Decimal 3from ..metadata import Metadata 4from ..type import Type 5 6 7class NumberType(Type): 8 """Number type implementation. 9 10 API | Usage 11 -------- | -------- 12 Public | `from frictionless import types` 13 14 """ 15 16 code = "number" 17 builtin = True 18 constraints = [ 19 "required", 20 "minimum", 21 "maximum", 22 "enum", 23 ] 24 25 # Read 26 27 def read_cell(self, cell): 28 Primary = Decimal 29 Secondary = float 30 if self.field.float_number: 31 Primary = float 32 Secondary = Decimal 33 if isinstance(cell, str): 34 if self.read_cell_processor: 35 cell = self.read_cell_processor(cell) 36 try: 37 return Primary(cell) 38 except Exception: 39 return None 40 elif isinstance(cell, Primary): 41 return cell 42 elif cell is True or cell is False: 43 return None 44 elif isinstance(cell, int): 45 return cell 46 elif isinstance(cell, Secondary): 47 return Primary(str(cell) if Primary is Decimal else cell) 48 return None 49 50 @Metadata.property(write=False) 51 def read_cell_processor(self): 52 if set(["groupChar", "decimalChar", "bareNumber"]).intersection( 53 self.field.keys() 54 ): 55 56 def processor(cell): 57 cell = cell.replace(self.field.group_char, "") 58 cell = cell.replace(self.field.decimal_char, ".") 59 if self.read_cell_pattern: 60 cell = self.read_cell_pattern.sub("", cell) 61 return cell 62 63 return processor 64 65 @Metadata.property(write=False) 66 def read_cell_pattern(self): 67 if not self.field.bare_number: 68 return re.compile(r"((^\D*)|(\D*$))") 69 70 # Write 71 72 def write_cell(self, cell): 73 if "groupChar" in self.field: 74 cell = f"{cell:,}".replace(",", self.field.group_char) 75 else: 76 cell = str(cell) 77 if "decimalChar" in self.field: 78 cell = cell.replace(".", self.field.decimal_char) 79 return cell 80