csvpath 0.0.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- csvpath/__init__.py +1 -0
- csvpath/csvpath.py +368 -0
- csvpath/matching/__init__.py +1 -0
- csvpath/matching/expression_encoder.py +108 -0
- csvpath/matching/expression_math.py +123 -0
- csvpath/matching/expression_utility.py +29 -0
- csvpath/matching/functions/above.py +36 -0
- csvpath/matching/functions/add.py +24 -0
- csvpath/matching/functions/below.py +36 -0
- csvpath/matching/functions/concat.py +25 -0
- csvpath/matching/functions/count.py +44 -0
- csvpath/matching/functions/count_lines.py +12 -0
- csvpath/matching/functions/count_scans.py +13 -0
- csvpath/matching/functions/divide.py +30 -0
- csvpath/matching/functions/end.py +18 -0
- csvpath/matching/functions/every.py +33 -0
- csvpath/matching/functions/first.py +46 -0
- csvpath/matching/functions/function.py +31 -0
- csvpath/matching/functions/function_factory.py +114 -0
- csvpath/matching/functions/inf.py +38 -0
- csvpath/matching/functions/is_instance.py +95 -0
- csvpath/matching/functions/length.py +33 -0
- csvpath/matching/functions/lower.py +21 -0
- csvpath/matching/functions/minf.py +167 -0
- csvpath/matching/functions/multiply.py +27 -0
- csvpath/matching/functions/no.py +10 -0
- csvpath/matching/functions/notf.py +26 -0
- csvpath/matching/functions/now.py +33 -0
- csvpath/matching/functions/orf.py +28 -0
- csvpath/matching/functions/percent.py +29 -0
- csvpath/matching/functions/random.py +33 -0
- csvpath/matching/functions/regex.py +38 -0
- csvpath/matching/functions/subtract.py +28 -0
- csvpath/matching/functions/tally.py +36 -0
- csvpath/matching/functions/upper.py +21 -0
- csvpath/matching/matcher.py +215 -0
- csvpath/matching/matching_lexer.py +66 -0
- csvpath/matching/parser.out +1287 -0
- csvpath/matching/parsetab.py +1427 -0
- csvpath/matching/productions/equality.py +158 -0
- csvpath/matching/productions/expression.py +16 -0
- csvpath/matching/productions/header.py +30 -0
- csvpath/matching/productions/matchable.py +41 -0
- csvpath/matching/productions/term.py +11 -0
- csvpath/matching/productions/variable.py +15 -0
- csvpath/parser_utility.py +39 -0
- csvpath/scanning/__init__.py +1 -0
- csvpath/scanning/parser.out +1 -0
- csvpath/scanning/parsetab.py +231 -0
- csvpath/scanning/scanner.py +165 -0
- csvpath/scanning/scanning_lexer.py +47 -0
- csvpath-0.0.2.dist-info/METADATA +184 -0
- csvpath-0.0.2.dist-info/RECORD +54 -0
- csvpath-0.0.2.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
from csvpath.matching.functions.function import Function, ChildrenException
|
|
3
|
+
from csvpath.matching.productions.equality import Equality
|
|
4
|
+
from csvpath.matching.productions.expression import Matchable
|
|
5
|
+
from statistics import mean, median
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class MinMax(Function):
|
|
9
|
+
"""
|
|
10
|
+
// longest value
|
|
11
|
+
// quintile
|
|
12
|
+
// median
|
|
13
|
+
// decile
|
|
14
|
+
// std div
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
def __init__(self, matcher: Any, name: str, child: Matchable = None) -> None:
|
|
18
|
+
super().__init__(matcher, name, child)
|
|
19
|
+
|
|
20
|
+
def get_the_value(self) -> Any:
|
|
21
|
+
if isinstance(self.children[0], Equality):
|
|
22
|
+
return self.children[0].left.to_value()
|
|
23
|
+
else:
|
|
24
|
+
return self.children[0].to_value()
|
|
25
|
+
|
|
26
|
+
def get_the_name(self) -> Any:
|
|
27
|
+
if isinstance(self.children[0], Equality):
|
|
28
|
+
return self.children[0].left.name
|
|
29
|
+
else:
|
|
30
|
+
return self.children[0].name
|
|
31
|
+
|
|
32
|
+
def get_the_line(self) -> int:
|
|
33
|
+
if isinstance(self.children[0], Equality):
|
|
34
|
+
v = self.children[0].right.to_value()
|
|
35
|
+
v = f"{v}".strip()
|
|
36
|
+
if v == "match":
|
|
37
|
+
return self.matcher.csvpath.current_match_count()
|
|
38
|
+
elif v == "scan":
|
|
39
|
+
return self.matcher.csvpath.current_scan_count()
|
|
40
|
+
else:
|
|
41
|
+
return self.matcher.csvpath.current_line_number()
|
|
42
|
+
else:
|
|
43
|
+
return self.matcher.csvpath.current_line_number()
|
|
44
|
+
|
|
45
|
+
def is_match(self) -> bool:
|
|
46
|
+
if isinstance(self.children[0], Equality):
|
|
47
|
+
v = self.children[0].right.to_value()
|
|
48
|
+
v = f"{v}".strip()
|
|
49
|
+
return v == "match"
|
|
50
|
+
else:
|
|
51
|
+
return False
|
|
52
|
+
|
|
53
|
+
def line_matches(self):
|
|
54
|
+
es = self.matcher.expressions
|
|
55
|
+
for e in es:
|
|
56
|
+
if not e[0].matches(skip=[self]):
|
|
57
|
+
return False
|
|
58
|
+
return True
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class Min(MinMax):
|
|
62
|
+
def __init__(self, matcher: Any, name: str, child: Matchable = None) -> None:
|
|
63
|
+
super().__init__(matcher, name, child)
|
|
64
|
+
|
|
65
|
+
def to_value(self, *, skip=[]) -> Any:
|
|
66
|
+
if self in skip:
|
|
67
|
+
return True
|
|
68
|
+
if self.children and len(self.children) == 1:
|
|
69
|
+
ChildrenException("must have a child")
|
|
70
|
+
if not self.value:
|
|
71
|
+
v = self.get_the_value()
|
|
72
|
+
if (
|
|
73
|
+
self.get_the_name() in self.matcher.csvpath.headers
|
|
74
|
+
and self.matcher.csvpath.current_line_number() == 0
|
|
75
|
+
):
|
|
76
|
+
return self.value
|
|
77
|
+
if self.is_match() and not self.line_matches():
|
|
78
|
+
return self.value
|
|
79
|
+
self.matcher.set_variable("min", tracking=f"{self.get_the_line()}", value=v)
|
|
80
|
+
all_values = self.matcher.get_variable("min")
|
|
81
|
+
m = None
|
|
82
|
+
for k, v in enumerate(all_values.items()):
|
|
83
|
+
v = v[1]
|
|
84
|
+
if not m or v < m:
|
|
85
|
+
m = v
|
|
86
|
+
|
|
87
|
+
self.value = m
|
|
88
|
+
return self.value
|
|
89
|
+
|
|
90
|
+
def matches(self, *, skip=[]) -> bool:
|
|
91
|
+
return True
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class Max(MinMax):
|
|
95
|
+
def __init__(self, matcher: Any, name: str, child: Matchable = None) -> None:
|
|
96
|
+
super().__init__(matcher, name, child)
|
|
97
|
+
|
|
98
|
+
def to_value(self, *, skip=[]) -> Any:
|
|
99
|
+
if self in skip:
|
|
100
|
+
return True
|
|
101
|
+
if self.children and len(self.children) == 1:
|
|
102
|
+
ChildrenException("must have a child")
|
|
103
|
+
if not self.value:
|
|
104
|
+
v = self.get_the_value()
|
|
105
|
+
if (
|
|
106
|
+
self.get_the_name() in self.matcher.csvpath.headers
|
|
107
|
+
and self.matcher.csvpath.current_line_number() == 0
|
|
108
|
+
):
|
|
109
|
+
return self.value
|
|
110
|
+
if self.is_match() and not self.line_matches():
|
|
111
|
+
return self.value
|
|
112
|
+
self.matcher.set_variable("max", tracking=f"{self.get_the_line()}", value=v)
|
|
113
|
+
all_values = self.matcher.get_variable("max")
|
|
114
|
+
m = None
|
|
115
|
+
for k, v in enumerate(all_values.items()):
|
|
116
|
+
v = v[1]
|
|
117
|
+
if not m or v > m:
|
|
118
|
+
m = v
|
|
119
|
+
|
|
120
|
+
self.value = m
|
|
121
|
+
return self.value
|
|
122
|
+
|
|
123
|
+
def matches(self, *, skip=[]) -> bool:
|
|
124
|
+
return True
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
class Average(MinMax):
|
|
128
|
+
def __init__(
|
|
129
|
+
self, matcher: Any, name: str, child: Matchable = None, ave_or_med="average"
|
|
130
|
+
) -> None:
|
|
131
|
+
super().__init__(matcher, name, child)
|
|
132
|
+
self.ave_or_med = ave_or_med
|
|
133
|
+
|
|
134
|
+
def to_value(self, *, skip=[]) -> Any:
|
|
135
|
+
if self in skip:
|
|
136
|
+
return True
|
|
137
|
+
if self.children and len(self.children) == 1:
|
|
138
|
+
ChildrenException("must have a child")
|
|
139
|
+
if not self.value:
|
|
140
|
+
v = self.get_the_value()
|
|
141
|
+
if (
|
|
142
|
+
self.get_the_name() in self.matcher.csvpath.headers
|
|
143
|
+
and self.matcher.csvpath.current_line_number() == 0
|
|
144
|
+
):
|
|
145
|
+
return self.value
|
|
146
|
+
if self.is_match() and not self.line_matches():
|
|
147
|
+
return self.value
|
|
148
|
+
self.matcher.set_variable(
|
|
149
|
+
self.ave_or_med, tracking=f"{self.get_the_line()}", value=v
|
|
150
|
+
)
|
|
151
|
+
all_values = self.matcher.get_variable(self.ave_or_med)
|
|
152
|
+
m = []
|
|
153
|
+
for k, v in enumerate(all_values.items()):
|
|
154
|
+
v = v[1]
|
|
155
|
+
try:
|
|
156
|
+
v = float(v)
|
|
157
|
+
m.append(v)
|
|
158
|
+
except Exception:
|
|
159
|
+
return self.value
|
|
160
|
+
if self.ave_or_med == "average":
|
|
161
|
+
self.value = mean(m)
|
|
162
|
+
else:
|
|
163
|
+
self.value = median(m)
|
|
164
|
+
return self.value
|
|
165
|
+
|
|
166
|
+
def matches(self, *, skip=[]) -> bool:
|
|
167
|
+
return True
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
from csvpath.matching.functions.function import Function, ChildrenException
|
|
3
|
+
from csvpath.matching.productions.equality import Equality
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Multiply(Function):
|
|
7
|
+
def to_value(self, *, skip=[]) -> Any:
|
|
8
|
+
if not self.value:
|
|
9
|
+
if len(self.children) != 1:
|
|
10
|
+
raise ChildrenException("no children. there must be 1 equality child")
|
|
11
|
+
child = self.children[0]
|
|
12
|
+
if not isinstance(child, Equality):
|
|
13
|
+
raise ChildrenException("must be 1 equality child")
|
|
14
|
+
|
|
15
|
+
siblings = child.commas_to_list()
|
|
16
|
+
ret = 0
|
|
17
|
+
for i, sib in enumerate(siblings):
|
|
18
|
+
v = sib.to_value(skip=skip)
|
|
19
|
+
if i == 0:
|
|
20
|
+
ret = v
|
|
21
|
+
else:
|
|
22
|
+
ret = v * ret
|
|
23
|
+
self.value = ret
|
|
24
|
+
return self.value
|
|
25
|
+
|
|
26
|
+
def matches(self, *, skip=[]) -> bool:
|
|
27
|
+
return True
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
from csvpath.matching.functions.function import (
|
|
3
|
+
Function,
|
|
4
|
+
NoChildrenException,
|
|
5
|
+
ChildrenException,
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Not(Function):
|
|
10
|
+
def to_value(self, *, skip=[]) -> Any:
|
|
11
|
+
if self in skip:
|
|
12
|
+
return True
|
|
13
|
+
if not self.children:
|
|
14
|
+
NoChildrenException("Not function must have a child that produces a value")
|
|
15
|
+
if not len(self.children) == 1:
|
|
16
|
+
self.matcher.print(f"Not.to_value: should be 1 children: {self.children}")
|
|
17
|
+
ChildrenException(
|
|
18
|
+
"not function must have a single child that produces a value"
|
|
19
|
+
)
|
|
20
|
+
m = self.children[0].matches(skip=skip)
|
|
21
|
+
self.matcher.print(f"Not.to_value: matches: {m}")
|
|
22
|
+
m = not m
|
|
23
|
+
return m
|
|
24
|
+
|
|
25
|
+
def matches(self, *, skip=[]) -> bool:
|
|
26
|
+
return self.to_value(skip=skip)
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
from csvpath.matching.functions.function import Function, ChildrenException
|
|
3
|
+
import datetime
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Now(Function):
|
|
7
|
+
def to_value(self, *, skip=[]) -> Any:
|
|
8
|
+
if self in skip:
|
|
9
|
+
return True
|
|
10
|
+
if len(self.children) > 1:
|
|
11
|
+
self.matcher.print(
|
|
12
|
+
f"Now.to_value: should be 0 or 1 children: {self.children}"
|
|
13
|
+
)
|
|
14
|
+
ChildrenException(
|
|
15
|
+
"now function may have only a single child that gives a format"
|
|
16
|
+
)
|
|
17
|
+
format = None
|
|
18
|
+
if self.children and len(self.children) == 1:
|
|
19
|
+
format = self.children[0].to_value(skip=skip)
|
|
20
|
+
self.matcher.print(f"Now.to_value: format: {format}")
|
|
21
|
+
x = datetime.datetime.now()
|
|
22
|
+
self.matcher.print(f"Now.to_value: x: {x}")
|
|
23
|
+
xs = None
|
|
24
|
+
if format:
|
|
25
|
+
xs = x.strftime(format)
|
|
26
|
+
self.matcher.print(f"Now.to_value: format: {format}, xs: {xs}")
|
|
27
|
+
else:
|
|
28
|
+
xs = f"{x}"
|
|
29
|
+
self.matcher.print(f"Now.to_value: returning: {xs}")
|
|
30
|
+
return xs
|
|
31
|
+
|
|
32
|
+
def matches(self, *, skip=[]) -> bool:
|
|
33
|
+
return True # always matches because not internally matchable
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
from csvpath.matching.functions.function import Function, ChildrenException
|
|
3
|
+
from csvpath.matching.productions.equality import Equality
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Or(Function):
|
|
7
|
+
def to_value(self, *, skip=[]) -> Any:
|
|
8
|
+
return self.matches(skip=skip)
|
|
9
|
+
|
|
10
|
+
def matches(self, *, skip=[]) -> bool:
|
|
11
|
+
if self in skip:
|
|
12
|
+
return True
|
|
13
|
+
else:
|
|
14
|
+
skip.append(self)
|
|
15
|
+
if not self.value:
|
|
16
|
+
if len(self.children) != 1:
|
|
17
|
+
raise ChildrenException("no children. there must be 1 equality child")
|
|
18
|
+
child = self.children[0]
|
|
19
|
+
if not isinstance(child, Equality):
|
|
20
|
+
raise ChildrenException("must be 1 equality child")
|
|
21
|
+
|
|
22
|
+
siblings = child.commas_to_list()
|
|
23
|
+
ret = False
|
|
24
|
+
for i, sib in enumerate(siblings):
|
|
25
|
+
if sib.matches(skip=skip):
|
|
26
|
+
ret = True
|
|
27
|
+
self.value = ret
|
|
28
|
+
return self.value
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
from csvpath.matching.functions.function import Function, ChildrenException
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class Percent(Function):
|
|
6
|
+
def to_value(self, *, skip=[]) -> Any:
|
|
7
|
+
if self in skip:
|
|
8
|
+
return True
|
|
9
|
+
if len(self.children) != 1:
|
|
10
|
+
self.matcher.print(f"Lower.to_value: must have 1 child: {self.children}")
|
|
11
|
+
raise ChildrenException("Lower function must have 1 child: line|scan|match")
|
|
12
|
+
which = self.children[0].to_value()
|
|
13
|
+
|
|
14
|
+
if which not in ["scan", "match", "line"]:
|
|
15
|
+
raise Exception("must be scan or match or line")
|
|
16
|
+
|
|
17
|
+
if which == "line":
|
|
18
|
+
count = self.matcher.csvpath.current_line_number()
|
|
19
|
+
elif which == "scan":
|
|
20
|
+
count = self.matcher.csvpath.current_scan_count()
|
|
21
|
+
else:
|
|
22
|
+
count = self.matcher.csvpath.current_match_count()
|
|
23
|
+
total = self.matcher.csvpath.get_total_lines()
|
|
24
|
+
value = count / total
|
|
25
|
+
return value
|
|
26
|
+
|
|
27
|
+
def matches(self, *, skip=[]) -> bool:
|
|
28
|
+
v = self.to_value(skip=skip)
|
|
29
|
+
return v is not None
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
from csvpath.matching.functions.function import Function, ChildrenException
|
|
3
|
+
from random import randrange
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Random(Function):
|
|
7
|
+
def to_value(self, *, skip=[]) -> Any:
|
|
8
|
+
if self in skip:
|
|
9
|
+
return True
|
|
10
|
+
if len(self.children) != 1:
|
|
11
|
+
self.matcher.print(
|
|
12
|
+
f"Random.to_value: must have 1 equality child: {self.children}"
|
|
13
|
+
)
|
|
14
|
+
raise ChildrenException("Random function must have 1 child")
|
|
15
|
+
if self.value is None:
|
|
16
|
+
lower = self.children[0].left.to_value()
|
|
17
|
+
upper = self.children[0].right.to_value()
|
|
18
|
+
if lower is None:
|
|
19
|
+
lower == 0
|
|
20
|
+
if upper is None or upper <= lower:
|
|
21
|
+
upper == 1
|
|
22
|
+
try:
|
|
23
|
+
lower = int(lower)
|
|
24
|
+
upper = int(upper)
|
|
25
|
+
# we are inclusive, but randrange is not
|
|
26
|
+
upper += 1
|
|
27
|
+
self.value = randrange(lower, upper, 1)
|
|
28
|
+
except Exception:
|
|
29
|
+
pass
|
|
30
|
+
return self.value
|
|
31
|
+
|
|
32
|
+
def matches(self, *, skip=[]) -> bool:
|
|
33
|
+
return True
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
from csvpath.matching.productions.term import Term
|
|
3
|
+
from csvpath.matching.functions.function import Function
|
|
4
|
+
import re
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Regex(Function):
|
|
8
|
+
def to_value(self, *, skip=[]) -> Any:
|
|
9
|
+
self.matches(skip=skip)
|
|
10
|
+
|
|
11
|
+
def matches(self, *, skip=[]) -> bool:
|
|
12
|
+
if self in skip:
|
|
13
|
+
return True
|
|
14
|
+
left = self._function_or_equality.left
|
|
15
|
+
right = self._function_or_equality.right
|
|
16
|
+
|
|
17
|
+
self.matcher.print(f"Regex.matches: equality.left: {left} .right: {right}")
|
|
18
|
+
|
|
19
|
+
regex = None
|
|
20
|
+
value = None
|
|
21
|
+
if isinstance(left, Term):
|
|
22
|
+
regex = left
|
|
23
|
+
value = right
|
|
24
|
+
else:
|
|
25
|
+
regex = right
|
|
26
|
+
value = left
|
|
27
|
+
|
|
28
|
+
thevalue = value.to_value(skip=skip)
|
|
29
|
+
theregex = regex.to_value(skip=skip)
|
|
30
|
+
if theregex[0] == "/":
|
|
31
|
+
theregex = theregex[1:]
|
|
32
|
+
if theregex[len(theregex) - 1] == "/":
|
|
33
|
+
theregex = theregex[0 : len(theregex) - 1]
|
|
34
|
+
|
|
35
|
+
self.matcher.print(
|
|
36
|
+
f"regex.matches: thevalue: {thevalue}, the regex: {theregex}"
|
|
37
|
+
)
|
|
38
|
+
return re.fullmatch(theregex, thevalue)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
from csvpath.matching.functions.function import Function, ChildrenException
|
|
3
|
+
from csvpath.matching.productions.equality import Equality
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Subtract(Function):
|
|
7
|
+
def to_value(self, *, skip=[]) -> Any:
|
|
8
|
+
if not self.value:
|
|
9
|
+
if len(self.children) != 1:
|
|
10
|
+
raise ChildrenException("no children. there must be 1 equality child")
|
|
11
|
+
child = self.children[0]
|
|
12
|
+
if not isinstance(child, Equality):
|
|
13
|
+
raise ChildrenException("must be 1 equality child")
|
|
14
|
+
|
|
15
|
+
siblings = child.commas_to_list()
|
|
16
|
+
ret = 0
|
|
17
|
+
for i, sib in enumerate(siblings):
|
|
18
|
+
v = sib.to_value(skip=skip)
|
|
19
|
+
print(f"Subtract.to_value: {ret} = {ret} - {v} == {ret - v}")
|
|
20
|
+
if i == 0:
|
|
21
|
+
ret = v
|
|
22
|
+
else:
|
|
23
|
+
ret = ret - v
|
|
24
|
+
self.value = ret
|
|
25
|
+
return self.value
|
|
26
|
+
|
|
27
|
+
def matches(self, *, skip=[]) -> bool:
|
|
28
|
+
return True
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
from csvpath.matching.functions.function import Function, ChildrenException
|
|
3
|
+
from csvpath.matching.productions.equality import Equality
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Tally(Function):
|
|
7
|
+
def to_value(self, *, skip=[]) -> Any:
|
|
8
|
+
if len(self.children) != 1:
|
|
9
|
+
raise ChildrenException("Tally function must have 1 child")
|
|
10
|
+
if self not in skip and self.value is None:
|
|
11
|
+
child = self.children[0]
|
|
12
|
+
kids = child.commas_to_list() if isinstance(child, Equality) else [child]
|
|
13
|
+
tally = ""
|
|
14
|
+
for _ in kids:
|
|
15
|
+
tally += f"{_.to_value(skip=skip)}"
|
|
16
|
+
value = f"{_.to_value(skip=skip)}"
|
|
17
|
+
self._store(_.name, value)
|
|
18
|
+
if len(kids) > 1:
|
|
19
|
+
self._store("tally", tally)
|
|
20
|
+
|
|
21
|
+
self.value = "tally" if isinstance(child, Equality) else child.name
|
|
22
|
+
return self.value
|
|
23
|
+
|
|
24
|
+
def _store(self, name, value):
|
|
25
|
+
count = self.matcher.get_variable(name, tracking=value)
|
|
26
|
+
if count is None:
|
|
27
|
+
count = 0
|
|
28
|
+
count += 1
|
|
29
|
+
self.matcher.set_variable(
|
|
30
|
+
name,
|
|
31
|
+
tracking=value,
|
|
32
|
+
value=count,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
def matches(self, *, skip=[]) -> bool:
|
|
36
|
+
return self.to_value(skip=skip) is not None
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
from csvpath.matching.functions.function import Function, ChildrenException
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class Upper(Function):
|
|
6
|
+
def to_value(self, *, skip=[]) -> Any:
|
|
7
|
+
if self in skip:
|
|
8
|
+
return True
|
|
9
|
+
if len(self.children) != 1:
|
|
10
|
+
self.matcher.print(
|
|
11
|
+
f"Upper.to_value: must have 1 equality child: {self.children}"
|
|
12
|
+
)
|
|
13
|
+
raise ChildrenException("Upper function must have 1 child")
|
|
14
|
+
|
|
15
|
+
value = self.children[0].to_value(skip=skip)
|
|
16
|
+
value = f"{value}".upper()
|
|
17
|
+
return value
|
|
18
|
+
|
|
19
|
+
def matches(self, *, skip=[]) -> bool:
|
|
20
|
+
v = self.to_value(skip=skip)
|
|
21
|
+
return v is not None
|