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