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.
Files changed (54) hide show
  1. csvpath/__init__.py +1 -0
  2. csvpath/csvpath.py +368 -0
  3. csvpath/matching/__init__.py +1 -0
  4. csvpath/matching/expression_encoder.py +108 -0
  5. csvpath/matching/expression_math.py +123 -0
  6. csvpath/matching/expression_utility.py +29 -0
  7. csvpath/matching/functions/above.py +36 -0
  8. csvpath/matching/functions/add.py +24 -0
  9. csvpath/matching/functions/below.py +36 -0
  10. csvpath/matching/functions/concat.py +25 -0
  11. csvpath/matching/functions/count.py +44 -0
  12. csvpath/matching/functions/count_lines.py +12 -0
  13. csvpath/matching/functions/count_scans.py +13 -0
  14. csvpath/matching/functions/divide.py +30 -0
  15. csvpath/matching/functions/end.py +18 -0
  16. csvpath/matching/functions/every.py +33 -0
  17. csvpath/matching/functions/first.py +46 -0
  18. csvpath/matching/functions/function.py +31 -0
  19. csvpath/matching/functions/function_factory.py +114 -0
  20. csvpath/matching/functions/inf.py +38 -0
  21. csvpath/matching/functions/is_instance.py +95 -0
  22. csvpath/matching/functions/length.py +33 -0
  23. csvpath/matching/functions/lower.py +21 -0
  24. csvpath/matching/functions/minf.py +167 -0
  25. csvpath/matching/functions/multiply.py +27 -0
  26. csvpath/matching/functions/no.py +10 -0
  27. csvpath/matching/functions/notf.py +26 -0
  28. csvpath/matching/functions/now.py +33 -0
  29. csvpath/matching/functions/orf.py +28 -0
  30. csvpath/matching/functions/percent.py +29 -0
  31. csvpath/matching/functions/random.py +33 -0
  32. csvpath/matching/functions/regex.py +38 -0
  33. csvpath/matching/functions/subtract.py +28 -0
  34. csvpath/matching/functions/tally.py +36 -0
  35. csvpath/matching/functions/upper.py +21 -0
  36. csvpath/matching/matcher.py +215 -0
  37. csvpath/matching/matching_lexer.py +66 -0
  38. csvpath/matching/parser.out +1287 -0
  39. csvpath/matching/parsetab.py +1427 -0
  40. csvpath/matching/productions/equality.py +158 -0
  41. csvpath/matching/productions/expression.py +16 -0
  42. csvpath/matching/productions/header.py +30 -0
  43. csvpath/matching/productions/matchable.py +41 -0
  44. csvpath/matching/productions/term.py +11 -0
  45. csvpath/matching/productions/variable.py +15 -0
  46. csvpath/parser_utility.py +39 -0
  47. csvpath/scanning/__init__.py +1 -0
  48. csvpath/scanning/parser.out +1 -0
  49. csvpath/scanning/parsetab.py +231 -0
  50. csvpath/scanning/scanner.py +165 -0
  51. csvpath/scanning/scanning_lexer.py +47 -0
  52. csvpath-0.0.2.dist-info/METADATA +184 -0
  53. csvpath-0.0.2.dist-info/RECORD +54 -0
  54. 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,10 @@
1
+ from typing import Any
2
+ from csvpath.matching.functions.function import Function
3
+
4
+
5
+ class No(Function):
6
+ def to_value(self, *, skip=[]) -> Any:
7
+ return False
8
+
9
+ def matches(self, *, skip=[]) -> bool:
10
+ return False
@@ -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