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,36 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
from csvpath.matching.functions.function import Function, ChildrenException
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class Below(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"In.to_value: must have 1 equality child: {self.children}"
|
|
12
|
+
)
|
|
13
|
+
raise ChildrenException("Below function must have 1 child")
|
|
14
|
+
if self.children[0].op != ",":
|
|
15
|
+
raise ChildrenException(
|
|
16
|
+
f"Below function must have an equality with the ',' operation, not {self.children[0].op}"
|
|
17
|
+
)
|
|
18
|
+
thischild = self.children[0].children[0]
|
|
19
|
+
belowthatchild = self.children[0].children[1]
|
|
20
|
+
|
|
21
|
+
this_is = thischild.to_value(skip=skip)
|
|
22
|
+
below_that = belowthatchild.to_value(skip=skip)
|
|
23
|
+
this = -1
|
|
24
|
+
that = -1
|
|
25
|
+
try:
|
|
26
|
+
this = float(this_is)
|
|
27
|
+
that = float(below_that)
|
|
28
|
+
except Exception:
|
|
29
|
+
raise Exception(
|
|
30
|
+
f"Below.to_value: this: {this}, a {this.__class__}, and {that}, a {that.__class__}"
|
|
31
|
+
)
|
|
32
|
+
b = this < that
|
|
33
|
+
return b
|
|
34
|
+
|
|
35
|
+
def matches(self, *, skip=[]) -> bool:
|
|
36
|
+
return self.to_value(skip=skip)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
from csvpath.matching.functions.function import Function, ChildrenException
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class Concat(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"In.to_value: must have 1 equality child: {self.children}"
|
|
12
|
+
)
|
|
13
|
+
raise ChildrenException("In function must have 1 child")
|
|
14
|
+
if self.children[0].op != ",":
|
|
15
|
+
raise ChildrenException(
|
|
16
|
+
f"In function must have an equality with the ',' operation, not {self.children[0].op}"
|
|
17
|
+
)
|
|
18
|
+
left = self.children[0].children[0]
|
|
19
|
+
right = self.children[0].children[1]
|
|
20
|
+
value = f"{left.to_value(skip=skip)}{right.to_value(skip=skip)}"
|
|
21
|
+
return value
|
|
22
|
+
|
|
23
|
+
def matches(self, *, skip=[]) -> bool:
|
|
24
|
+
v = self.to_value(skip=skip)
|
|
25
|
+
return v is not None
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
from csvpath.matching.functions.function import Function
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class Count(Function):
|
|
6
|
+
def print(self, msg):
|
|
7
|
+
if self.matcher:
|
|
8
|
+
self.matcher.print(msg)
|
|
9
|
+
|
|
10
|
+
def to_value(self, *, skip=[]) -> Any:
|
|
11
|
+
if self in skip:
|
|
12
|
+
return True
|
|
13
|
+
if self.value is None:
|
|
14
|
+
if self._function_or_equality:
|
|
15
|
+
self.value = self._get_contained_value(skip=skip)
|
|
16
|
+
else:
|
|
17
|
+
self.value = (
|
|
18
|
+
self._get_match_count() + 1
|
|
19
|
+
) # we're eager to +1 because we don't
|
|
20
|
+
# contribute to if there's a match
|
|
21
|
+
return self.value # or not. we have to act as if.
|
|
22
|
+
|
|
23
|
+
def _get_match_count(self) -> int:
|
|
24
|
+
if not self.matcher or not self.matcher.csvpath:
|
|
25
|
+
print("WARNING: no csvpath. are we testing?")
|
|
26
|
+
return -1
|
|
27
|
+
return self.matcher.csvpath.current_match_count()
|
|
28
|
+
|
|
29
|
+
def _get_contained_value(self, *, skip=[]) -> Any:
|
|
30
|
+
#
|
|
31
|
+
# need to apply this count function to the contained obj's value
|
|
32
|
+
#
|
|
33
|
+
b = self._function_or_equality.matches(skip=skip)
|
|
34
|
+
self._id = self.get_id(self._function_or_equality)
|
|
35
|
+
#
|
|
36
|
+
# to_value() is often going to be a bool based on matches().
|
|
37
|
+
# but in a case like: count(now('yyyy-mm-dd')) it would not be
|
|
38
|
+
#
|
|
39
|
+
tracked_value = self._function_or_equality.to_value(skip=skip)
|
|
40
|
+
cnt = self.matcher.get_variable(self._id, tracking=tracked_value, set_if_none=0)
|
|
41
|
+
if b:
|
|
42
|
+
cnt += 1
|
|
43
|
+
self.matcher.set_variable(self._id, tracking=tracked_value, value=cnt)
|
|
44
|
+
return cnt
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
from csvpath.matching.functions.function import Function
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class CountLines(Function):
|
|
6
|
+
def print(self, msg):
|
|
7
|
+
if self.matcher:
|
|
8
|
+
self.matcher.print(msg)
|
|
9
|
+
|
|
10
|
+
def to_value(self, *, skip=[]) -> Any:
|
|
11
|
+
if self.matcher:
|
|
12
|
+
return self.matcher.csvpath.current_line_number()
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
from csvpath.matching.functions.function import Function
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class CountScans(Function):
|
|
6
|
+
def print(self, msg):
|
|
7
|
+
if self.matcher:
|
|
8
|
+
self.matcher.print(msg)
|
|
9
|
+
|
|
10
|
+
def to_value(self, *, skip=[]) -> Any:
|
|
11
|
+
if self in skip:
|
|
12
|
+
return True
|
|
13
|
+
return self.matcher.csvpath.current_scan_count()
|
|
@@ -0,0 +1,30 @@
|
|
|
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 Divide(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
|
+
if ret == float("nan") or v == 0:
|
|
23
|
+
ret = float("nan")
|
|
24
|
+
else:
|
|
25
|
+
ret = ret / v
|
|
26
|
+
self.value = ret
|
|
27
|
+
return self.value
|
|
28
|
+
|
|
29
|
+
def matches(self, *, skip=[]) -> bool:
|
|
30
|
+
return True
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
from csvpath.matching.functions.function import Function, ChildrenException
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class End(Function):
|
|
6
|
+
def to_value(self, *, skip=[]) -> Any:
|
|
7
|
+
if self in skip:
|
|
8
|
+
return True
|
|
9
|
+
if self.children and len(self.children) > 0:
|
|
10
|
+
ChildrenException("end must not have a child")
|
|
11
|
+
if not self.value:
|
|
12
|
+
i = self.matcher.last_header_index()
|
|
13
|
+
if i:
|
|
14
|
+
self.value = self.matcher.line[i]
|
|
15
|
+
return self.value
|
|
16
|
+
|
|
17
|
+
def matches(self, *, skip=[]) -> bool:
|
|
18
|
+
return self.to_value(skip=skip) is not None
|
|
@@ -0,0 +1,33 @@
|
|
|
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 Every(Function):
|
|
7
|
+
def to_value(self, *, skip=[]) -> Any:
|
|
8
|
+
return self.matches(skip=skip)
|
|
9
|
+
|
|
10
|
+
def matches(self, *, skip=[]) -> bool:
|
|
11
|
+
if self.value is None:
|
|
12
|
+
if len(self.children) != 1:
|
|
13
|
+
raise ChildrenException("no children. there must be 1 equality child")
|
|
14
|
+
child = self.children[0]
|
|
15
|
+
if not isinstance(child, Equality):
|
|
16
|
+
raise ChildrenException("must be 1 equality child")
|
|
17
|
+
|
|
18
|
+
tracked_value = self.children[0].left.matches(skip=skip)
|
|
19
|
+
if tracked_value:
|
|
20
|
+
every = self.children[0].right.to_value()
|
|
21
|
+
self._id = self.get_id(self)
|
|
22
|
+
cnt = self.matcher.get_variable(
|
|
23
|
+
self._id, tracking=tracked_value, set_if_none=0
|
|
24
|
+
)
|
|
25
|
+
cnt += 1
|
|
26
|
+
self.matcher.set_variable(self._id, tracking=tracked_value, value=cnt)
|
|
27
|
+
if cnt % every == 0:
|
|
28
|
+
self.value = True
|
|
29
|
+
else:
|
|
30
|
+
self.value = False
|
|
31
|
+
else:
|
|
32
|
+
self.value = False
|
|
33
|
+
return self.value
|
|
@@ -0,0 +1,46 @@
|
|
|
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 First(Function):
|
|
7
|
+
def __init__(self, matcher, name: str = None, child: Any = None):
|
|
8
|
+
super().__init__(matcher, child=child, name=name)
|
|
9
|
+
self._my_value_or_none = -9999 # when this var is None we match
|
|
10
|
+
|
|
11
|
+
def to_value(self, *, skip=[]) -> Any:
|
|
12
|
+
if len(self.children) != 1:
|
|
13
|
+
self.matcher.print(f"First.to_value: must have 1 child: {self.children}")
|
|
14
|
+
raise ChildrenException("First function must have 1 child")
|
|
15
|
+
if self._my_value_or_none == -9999:
|
|
16
|
+
|
|
17
|
+
child = self.children[0]
|
|
18
|
+
value = ""
|
|
19
|
+
if isinstance(child, Equality):
|
|
20
|
+
for _ in child.commas_to_list():
|
|
21
|
+
value += f"{_.to_value(skip=skip)}"
|
|
22
|
+
else:
|
|
23
|
+
value = f"{child.to_value(skip=skip)}"
|
|
24
|
+
|
|
25
|
+
my_id = self.get_id()
|
|
26
|
+
v = self.matcher.get_variable(my_id, tracking=value)
|
|
27
|
+
if v is None:
|
|
28
|
+
self.matcher.set_variable(
|
|
29
|
+
my_id,
|
|
30
|
+
tracking=value,
|
|
31
|
+
value=self.matcher.csvpath.current_line_number(),
|
|
32
|
+
)
|
|
33
|
+
#
|
|
34
|
+
# when we have no earlier value we are first, so we match
|
|
35
|
+
#
|
|
36
|
+
self._my_value_or_none = v
|
|
37
|
+
return self._my_value_or_none
|
|
38
|
+
|
|
39
|
+
def matches(self, *, skip=[]) -> bool:
|
|
40
|
+
#
|
|
41
|
+
# when there is no earlier value we match
|
|
42
|
+
#
|
|
43
|
+
if self._my_value_or_none == -9999:
|
|
44
|
+
self.to_value(skip=skip)
|
|
45
|
+
v = self._my_value_or_none
|
|
46
|
+
return v is None
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
from csvpath.matching.productions.matchable import Matchable
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class NoChildrenException(Exception):
|
|
6
|
+
pass
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ChildrenException(Exception):
|
|
10
|
+
pass
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class Function(Matchable):
|
|
14
|
+
def __init__(self, matcher: Any, name: str, child: Matchable = None) -> None:
|
|
15
|
+
super().__init__(matcher, name=name)
|
|
16
|
+
self.matcher = matcher # atm, circular dep
|
|
17
|
+
self._function_or_equality = child
|
|
18
|
+
if child:
|
|
19
|
+
self.add_child(child)
|
|
20
|
+
|
|
21
|
+
def __str__(self) -> str:
|
|
22
|
+
return f"""\n{self.__class__}{self.name}({self._function_or_equality})"""
|
|
23
|
+
|
|
24
|
+
def to_value(self, *, skip=[]) -> bool:
|
|
25
|
+
if self in skip:
|
|
26
|
+
return True
|
|
27
|
+
if self._function_or_equality:
|
|
28
|
+
if not self._function_or_equality.matches(skip=skip):
|
|
29
|
+
return False
|
|
30
|
+
print("WARNING: function getting to_value defaulting to True")
|
|
31
|
+
return True # leave this for now for testing
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
from csvpath.matching.productions.expression import Matchable
|
|
2
|
+
from csvpath.matching.functions.function import Function
|
|
3
|
+
from csvpath.matching.functions.count import Count
|
|
4
|
+
from csvpath.matching.functions.regex import Regex
|
|
5
|
+
from csvpath.matching.functions.length import Length
|
|
6
|
+
from csvpath.matching.functions.notf import Not
|
|
7
|
+
from csvpath.matching.functions.now import Now
|
|
8
|
+
from csvpath.matching.functions.inf import In
|
|
9
|
+
from csvpath.matching.functions.concat import Concat
|
|
10
|
+
from csvpath.matching.functions.lower import Lower
|
|
11
|
+
from csvpath.matching.functions.upper import Upper
|
|
12
|
+
from csvpath.matching.functions.percent import Percent
|
|
13
|
+
from csvpath.matching.functions.below import Below
|
|
14
|
+
from csvpath.matching.functions.above import Above
|
|
15
|
+
from csvpath.matching.functions.first import First
|
|
16
|
+
from csvpath.matching.functions.count_lines import CountLines
|
|
17
|
+
from csvpath.matching.functions.count_scans import CountScans
|
|
18
|
+
from csvpath.matching.functions.is_instance import IsInstance
|
|
19
|
+
from csvpath.matching.functions.orf import Or
|
|
20
|
+
from csvpath.matching.functions.no import No
|
|
21
|
+
from csvpath.matching.functions.minf import Min, Max, Average
|
|
22
|
+
from csvpath.matching.functions.end import End
|
|
23
|
+
from csvpath.matching.functions.random import Random
|
|
24
|
+
from csvpath.matching.functions.add import Add
|
|
25
|
+
from csvpath.matching.functions.subtract import Subtract
|
|
26
|
+
from csvpath.matching.functions.multiply import Multiply
|
|
27
|
+
from csvpath.matching.functions.divide import Divide
|
|
28
|
+
from csvpath.matching.functions.tally import Tally
|
|
29
|
+
from csvpath.matching.functions.every import Every
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class UnknownFunctionException(Exception):
|
|
33
|
+
pass
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class InvalidChildException(Exception):
|
|
37
|
+
pass
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class FunctionFactory:
|
|
41
|
+
@classmethod
|
|
42
|
+
def get_function( # noqa: C901
|
|
43
|
+
cls, matcher, *, name: str, child: Matchable = None
|
|
44
|
+
) -> Function:
|
|
45
|
+
if child and not isinstance(child, Matchable):
|
|
46
|
+
raise InvalidChildException(f"{child} is not a valid child")
|
|
47
|
+
f = None
|
|
48
|
+
if name == "count":
|
|
49
|
+
f = Count(matcher, name, child)
|
|
50
|
+
elif name == "length":
|
|
51
|
+
f = Length(matcher, name, child)
|
|
52
|
+
elif name == "regex":
|
|
53
|
+
f = Regex(matcher, name, child)
|
|
54
|
+
elif name == "not":
|
|
55
|
+
f = Not(matcher, name, child)
|
|
56
|
+
elif name == "now":
|
|
57
|
+
f = Now(matcher, name, child)
|
|
58
|
+
elif name == "in":
|
|
59
|
+
f = In(matcher, name, child)
|
|
60
|
+
elif name == "concat":
|
|
61
|
+
f = Concat(matcher, name, child)
|
|
62
|
+
elif name == "lower":
|
|
63
|
+
f = Lower(matcher, name, child)
|
|
64
|
+
elif name == "upper":
|
|
65
|
+
f = Upper(matcher, name, child)
|
|
66
|
+
elif name == "percent":
|
|
67
|
+
f = Percent(matcher, name, child)
|
|
68
|
+
elif name == "below":
|
|
69
|
+
f = Below(matcher, name, child)
|
|
70
|
+
elif name == "above":
|
|
71
|
+
f = Above(matcher, name, child)
|
|
72
|
+
elif name == "first":
|
|
73
|
+
f = First(matcher, name, child)
|
|
74
|
+
elif name == "count_lines":
|
|
75
|
+
f = CountLines(matcher, name, child)
|
|
76
|
+
elif name == "count_scans":
|
|
77
|
+
f = CountScans(matcher, name, child)
|
|
78
|
+
elif name == "isinstance":
|
|
79
|
+
f = IsInstance(matcher, name, child)
|
|
80
|
+
elif name == "or":
|
|
81
|
+
f = Or(matcher, name, child)
|
|
82
|
+
elif name == "no":
|
|
83
|
+
f = No(matcher, name, child)
|
|
84
|
+
elif name == "max":
|
|
85
|
+
f = Max(matcher, name, child)
|
|
86
|
+
elif name == "min":
|
|
87
|
+
f = Min(matcher, name, child)
|
|
88
|
+
elif name == "average":
|
|
89
|
+
f = Average(matcher, name, child, "average")
|
|
90
|
+
elif name == "median":
|
|
91
|
+
f = Average(matcher, name, child, "median")
|
|
92
|
+
elif name == "random":
|
|
93
|
+
f = Random(matcher, name, child)
|
|
94
|
+
elif name == "end":
|
|
95
|
+
f = End(matcher, name, child)
|
|
96
|
+
elif name == "length":
|
|
97
|
+
f = Length(matcher, name, child)
|
|
98
|
+
elif name == "add":
|
|
99
|
+
f = Add(matcher, name, child)
|
|
100
|
+
elif name == "subtract":
|
|
101
|
+
f = Subtract(matcher, name, child)
|
|
102
|
+
elif name == "multiply":
|
|
103
|
+
f = Multiply(matcher, name, child)
|
|
104
|
+
elif name == "divide":
|
|
105
|
+
f = Divide(matcher, name, child)
|
|
106
|
+
elif name == "tally":
|
|
107
|
+
f = Tally(matcher, name, child)
|
|
108
|
+
elif name == "every":
|
|
109
|
+
f = Every(matcher, name, child)
|
|
110
|
+
else:
|
|
111
|
+
raise UnknownFunctionException(f"{name}")
|
|
112
|
+
if child:
|
|
113
|
+
child.parent = f
|
|
114
|
+
return f
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
from csvpath.matching.functions.function import Function, ChildrenException
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class In(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"In.to_value: must have 1 equality child: {self.children}"
|
|
12
|
+
)
|
|
13
|
+
raise ChildrenException("In function must have 1 child")
|
|
14
|
+
if self.children[0].op != ",":
|
|
15
|
+
raise ChildrenException(
|
|
16
|
+
f"In function must have an equality with the ',' operation, not {self.children[0].op}"
|
|
17
|
+
)
|
|
18
|
+
vchild = self.children[0].children[0]
|
|
19
|
+
lchild = self.children[0].children[1]
|
|
20
|
+
|
|
21
|
+
mylist = []
|
|
22
|
+
liststr = lchild.to_value(skip=skip)
|
|
23
|
+
# print(f"In.to_value: list str: {liststr}")
|
|
24
|
+
mylist = liststr.split("|")
|
|
25
|
+
# print(f"In.to_value: child: {vchild}, a {vchild.__class__}")
|
|
26
|
+
v = vchild.to_value()
|
|
27
|
+
# print(f"In.to_value: self.matcher.csvpath.headers: {self.matcher.csvpath.headers}")
|
|
28
|
+
|
|
29
|
+
# print(f"In.to_value: list: {mylist}, value: {v}")
|
|
30
|
+
if v in mylist:
|
|
31
|
+
return True
|
|
32
|
+
elif v.__class__ != str and f"{v}" in mylist:
|
|
33
|
+
return True
|
|
34
|
+
else:
|
|
35
|
+
return False
|
|
36
|
+
|
|
37
|
+
def matches(self, *, skip=[]) -> bool:
|
|
38
|
+
return self.to_value(skip=skip)
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
from csvpath.matching.functions.function import Function, ChildrenException
|
|
3
|
+
from csvpath.matching.productions.equality import Equality
|
|
4
|
+
from dateutil import parser
|
|
5
|
+
from numbers import Number
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class IsInstance(Function):
|
|
9
|
+
def to_value(self, *, skip=[]) -> Any:
|
|
10
|
+
return self.matches(skip=skip)
|
|
11
|
+
|
|
12
|
+
def matches(self, *, skip=[]) -> bool:
|
|
13
|
+
if self.value is not None:
|
|
14
|
+
return self.value
|
|
15
|
+
elif self in skip:
|
|
16
|
+
return True
|
|
17
|
+
if len(self.children) != 1:
|
|
18
|
+
raise ChildrenException(
|
|
19
|
+
"no children. there must be 1 equality child with 2 non-equality children"
|
|
20
|
+
)
|
|
21
|
+
child = self.children[0]
|
|
22
|
+
if not isinstance(child, Equality):
|
|
23
|
+
raise ChildrenException(
|
|
24
|
+
"must be 1 equality child with 2 non-equality children"
|
|
25
|
+
)
|
|
26
|
+
left = child.left
|
|
27
|
+
right = child.right
|
|
28
|
+
thevalue = left.to_value(skip=skip)
|
|
29
|
+
thetype = right.to_value(skip=skip)
|
|
30
|
+
self.value = self._get_match_value(thetype, thevalue)
|
|
31
|
+
return self.value
|
|
32
|
+
|
|
33
|
+
def _get_match_value(self, thetype, thevalue) -> bool:
|
|
34
|
+
ret = False
|
|
35
|
+
if thetype == "int":
|
|
36
|
+
try:
|
|
37
|
+
v = int(thevalue)
|
|
38
|
+
ret = f"{v}" == f"{thevalue}"
|
|
39
|
+
except Exception:
|
|
40
|
+
pass
|
|
41
|
+
elif thetype == "float":
|
|
42
|
+
try:
|
|
43
|
+
v = float(thevalue)
|
|
44
|
+
ret = f"{v}" == f"{thevalue}"
|
|
45
|
+
except Exception:
|
|
46
|
+
pass
|
|
47
|
+
elif thetype == "str":
|
|
48
|
+
v = str(thevalue)
|
|
49
|
+
ret = f"{v}" == f"{thevalue}"
|
|
50
|
+
elif thetype == "complex":
|
|
51
|
+
try:
|
|
52
|
+
v = complex(thevalue)
|
|
53
|
+
ret = f"{v}" == f"{thevalue}"
|
|
54
|
+
except Exception:
|
|
55
|
+
pass
|
|
56
|
+
elif thetype == "bool":
|
|
57
|
+
v = isinstance(thevalue, bool)
|
|
58
|
+
if not v:
|
|
59
|
+
if thevalue == 1 or thevalue == 0:
|
|
60
|
+
v = True
|
|
61
|
+
if thevalue == "None":
|
|
62
|
+
v = True
|
|
63
|
+
ret = v
|
|
64
|
+
elif thetype == "usd":
|
|
65
|
+
ret = self.to_usd(thevalue)
|
|
66
|
+
elif thetype == "datetime":
|
|
67
|
+
ret = self.to_datetime(thevalue)
|
|
68
|
+
else:
|
|
69
|
+
raise Exception(
|
|
70
|
+
f"""the type must one of:
|
|
71
|
+
"int","float","str","bool",
|
|
72
|
+
"complex","usd","datetime, not {thetype}"
|
|
73
|
+
"""
|
|
74
|
+
)
|
|
75
|
+
return ret
|
|
76
|
+
|
|
77
|
+
def to_usd(self, v) -> bool:
|
|
78
|
+
if isinstance(v, Number):
|
|
79
|
+
return False
|
|
80
|
+
try:
|
|
81
|
+
float(f"{v}".replace("$", "").replace(",", ""))
|
|
82
|
+
except Exception:
|
|
83
|
+
return False
|
|
84
|
+
v = v.strip().lower()
|
|
85
|
+
if v[0] == "$":
|
|
86
|
+
return True
|
|
87
|
+
return False
|
|
88
|
+
|
|
89
|
+
def to_datetime(self, v) -> bool:
|
|
90
|
+
try:
|
|
91
|
+
parser.parse(f"{v}")
|
|
92
|
+
except Exception as e:
|
|
93
|
+
print(e)
|
|
94
|
+
return False
|
|
95
|
+
return True
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
from csvpath.matching.functions.function import (
|
|
3
|
+
Function,
|
|
4
|
+
NoChildrenException,
|
|
5
|
+
ChildrenException,
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Length(Function):
|
|
10
|
+
def to_value(self, *, skip=[]) -> Any:
|
|
11
|
+
if self in skip:
|
|
12
|
+
return True
|
|
13
|
+
if not self.children:
|
|
14
|
+
NoChildrenException(
|
|
15
|
+
"length function must have a child that produces a value"
|
|
16
|
+
)
|
|
17
|
+
if not len(self.children) == 1:
|
|
18
|
+
self.matcher.print(
|
|
19
|
+
f"Length.to_value: should be 1 children: {self.children}"
|
|
20
|
+
)
|
|
21
|
+
ChildrenException(
|
|
22
|
+
"length function must have a single child that produces a value"
|
|
23
|
+
)
|
|
24
|
+
val = self.children[0].to_value(skip=skip)
|
|
25
|
+
self.matcher.print(f"Length.to_value: val: {val}")
|
|
26
|
+
ret = 0
|
|
27
|
+
if val:
|
|
28
|
+
ret = len(f"{val}")
|
|
29
|
+
self.matcher.print(f"Length.to_value: val: {val}")
|
|
30
|
+
return ret
|
|
31
|
+
|
|
32
|
+
def matches(self, *, skip=[]) -> bool:
|
|
33
|
+
return self.to_value(skip=skip) > 0
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
from csvpath.matching.functions.function import Function, ChildrenException
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class Lower(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"Lower.to_value: must have 1 equality child: {self.children}"
|
|
12
|
+
)
|
|
13
|
+
raise ChildrenException("Lower function must have 1 child")
|
|
14
|
+
|
|
15
|
+
value = self.children[0].to_value(skip=skip)
|
|
16
|
+
value = f"{value}".lower()
|
|
17
|
+
return value
|
|
18
|
+
|
|
19
|
+
def matches(self, *, skip=[]) -> bool:
|
|
20
|
+
v = self.to_value(skip=skip)
|
|
21
|
+
return v is not None
|