csvpath 0.0.465__tar.gz → 0.0.467__tar.gz
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-0.0.465 → csvpath-0.0.467}/PKG-INFO +1 -1
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/csvpath.py +5 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/boolean/empty.py +4 -4
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/function_factory.py +7 -0
- csvpath-0.0.467/csvpath/matching/functions/headers/empty_stack.py +50 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/variables/get.py +2 -6
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/variables/pushpop.py +12 -11
- csvpath-0.0.467/csvpath/matching/functions/variables/put.py +30 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/util/expression_utility.py +16 -1
- csvpath-0.0.467/docs/functions/empty_stack.md +32 -0
- csvpath-0.0.467/docs/functions/get.md +31 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/pop.md +3 -1
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/tally.md +12 -12
- csvpath-0.0.467/docs/functions.md +248 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/pyproject.toml +1 -1
- csvpath-0.0.465/docs/functions/get.md +0 -23
- csvpath-0.0.465/docs/functions.md +0 -199
- {csvpath-0.0.465 → csvpath-0.0.467}/LICENSE +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/README.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/config/config.ini +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/__init__.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/csvpaths.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/managers/__init__.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/managers/csvpath_result.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/managers/csvpaths_manager.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/managers/files_manager.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/managers/results_manager.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/__init__.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/__init__.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/boolean/all.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/boolean/andf.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/boolean/any.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/boolean/between.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/boolean/exists.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/boolean/inf.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/boolean/no.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/boolean/notf.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/boolean/orf.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/boolean/yes.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/counting/count.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/counting/count_headers.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/counting/count_lines.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/counting/count_scans.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/counting/every.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/counting/has_matches.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/counting/increment.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/counting/tally.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/counting/total_lines.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/dates/datef.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/dates/now.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/function.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/function_focus.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/headers/collect.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/headers/end.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/headers/header_name.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/headers/header_names_mismatch.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/headers/headers.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/headers/mismatch.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/headers/replace.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/headers/reset_headers.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/lines/advance.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/lines/after_blank.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/lines/dups.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/lines/first.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/lines/first_line.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/lines/last.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/lines/stop.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/math/above.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/math/add.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/math/divide.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/math/equals.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/math/mod.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/math/multiply.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/math/round.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/math/subtract.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/math/sum.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/misc/importf.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/misc/intf.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/misc/nonef.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/misc/random.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/print/jinjaf.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/print/print_line.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/print/print_queue.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/print/printf.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/print/table.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/stats/correlate.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/stats/minf.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/stats/percent.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/stats/percent_unique.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/stats/stdev.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/strings/concat.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/strings/length.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/strings/lower.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/strings/metaphone.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/strings/regex.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/strings/starts_with.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/strings/strip.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/strings/substring.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/strings/upper.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/testing/debug.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/validation.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/validity/fail.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/validity/failed.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/variables/track.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/variables/variables.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/lark_parser.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/lark_transformer.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/matcher.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/productions/__init__.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/productions/equality.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/productions/expression.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/productions/header.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/productions/matchable.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/productions/qualified.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/productions/reference.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/productions/term.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/productions/variable.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/util/exceptions.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/util/expression_encoder.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/util/lark_print_parser.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/util/print_parser.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/scanning/__init__.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/scanning/exceptions.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/scanning/parser.out +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/scanning/parsetab.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/scanning/scanner.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/scanning/scanning_lexer.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/util/config.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/util/config_exception.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/util/error.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/util/exceptions.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/util/last_line_stats.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/util/line_monitor.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/util/log_utility.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/util/metadata_parser.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/util/printer.py +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/asbool.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/assignment.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/config.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/examples.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/files.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/above.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/advance.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/after_blank.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/all.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/andor.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/any.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/average.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/between.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/collect.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/correlate.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/count.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/count_headers.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/date.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/empty.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/end.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/every.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/fail.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/first.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/has_dups.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/header.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/header_name.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/header_names_mismatch.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/implementing_functions.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/import.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/in.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/increment.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/jinja.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/last.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/line_number.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/max.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/metaphone.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/mismatch.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/no.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/not.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/now.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/percent_unique.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/print.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/print_line.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/print_queue.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/regex.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/replace.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/reset_headers.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/stdev.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/stop.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/string_functions.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/subtract.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/sum.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/total_lines.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/track.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/variables.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/variables_and_headers.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/grammar.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/headers.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/images/logo-wordmark-white-on-black-trimmed-padded.png +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/images/logo-wordmark-white-trimmed.png +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/paths.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/qualifiers.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/references.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/terms.md +0 -0
- {csvpath-0.0.465 → csvpath-0.0.467}/docs/variables.md +0 -0
|
@@ -728,6 +728,11 @@ class CsvPath(CsvPathPublic, ErrorCollector): # pylint: disable=R0902, R0904
|
|
|
728
728
|
self.logger.debug(
|
|
729
729
|
"CsvPath.matches:703: %s: matches: %s", self.identity, matches
|
|
730
730
|
)
|
|
731
|
+
#
|
|
732
|
+
# if we are done scanning we can stop
|
|
733
|
+
#
|
|
734
|
+
if self.scanner.is_last(self.line_monitor.physical_line_number):
|
|
735
|
+
self.stop()
|
|
731
736
|
if matches is True:
|
|
732
737
|
#
|
|
733
738
|
# _current_match_count is a placeholder that
|
|
@@ -48,7 +48,6 @@ class Empty(MatchDecider):
|
|
|
48
48
|
# empty(ref)
|
|
49
49
|
#
|
|
50
50
|
def _decide_match(self, skip=None) -> None:
|
|
51
|
-
print(f"empty._decide: chs: {self.children}")
|
|
52
51
|
if len(self.children) == 1 and isinstance(self.children[0], Headers):
|
|
53
52
|
self._do_headers(skip=skip)
|
|
54
53
|
elif len(self.children) == 1 and isinstance(self.children[0], Equality):
|
|
@@ -61,7 +60,7 @@ class Empty(MatchDecider):
|
|
|
61
60
|
def _do_headers(self, skip=None):
|
|
62
61
|
ret = True
|
|
63
62
|
for i, h in enumerate(self.matcher.line):
|
|
64
|
-
ret =
|
|
63
|
+
ret = ExpressionUtility.is_empty(h)
|
|
65
64
|
if ret is False:
|
|
66
65
|
break
|
|
67
66
|
self.match = ret
|
|
@@ -74,15 +73,15 @@ class Empty(MatchDecider):
|
|
|
74
73
|
siblings = self.children[0]
|
|
75
74
|
|
|
76
75
|
for s in siblings:
|
|
77
|
-
print(f"empty._do_many: a sib: {s}")
|
|
78
76
|
self._do_one(s)
|
|
79
77
|
if self.match is False:
|
|
80
78
|
break
|
|
81
79
|
|
|
82
80
|
def _do_one(self, child, skip=None):
|
|
83
81
|
v = child.to_value(skip=skip)
|
|
84
|
-
self.match =
|
|
82
|
+
self.match = ExpressionUtility.is_empty(v)
|
|
85
83
|
|
|
84
|
+
"""
|
|
86
85
|
def _is_empty(self, v):
|
|
87
86
|
ret = True
|
|
88
87
|
if v is None:
|
|
@@ -99,3 +98,4 @@ class Empty(MatchDecider):
|
|
|
99
98
|
else:
|
|
100
99
|
ret = False
|
|
101
100
|
return ret
|
|
101
|
+
"""
|
|
@@ -27,6 +27,7 @@ from .headers.header_names_mismatch import HeaderNamesMismatch
|
|
|
27
27
|
from .headers.collect import Collect
|
|
28
28
|
from .headers.replace import Replace
|
|
29
29
|
from .headers.headers import Headers
|
|
30
|
+
from .headers.empty_stack import EmptyStack
|
|
30
31
|
from .headers.mismatch import Mismatch
|
|
31
32
|
from .headers.end import End
|
|
32
33
|
from .math.above import AboveBelow
|
|
@@ -69,6 +70,7 @@ from .lines.after_blank import AfterBlank
|
|
|
69
70
|
from .variables.variables import Variables
|
|
70
71
|
from .variables.pushpop import Push, PushDistinct, Pop, Peek, PeekSize, Stack
|
|
71
72
|
from .variables.get import Get
|
|
73
|
+
from .variables.put import Put
|
|
72
74
|
from .variables.track import Track
|
|
73
75
|
from .misc.random import Random
|
|
74
76
|
from .misc.nonef import Nonef
|
|
@@ -335,6 +337,8 @@ class FunctionFactory:
|
|
|
335
337
|
f = Between(matcher, name, child)
|
|
336
338
|
elif name == "get":
|
|
337
339
|
f = Get(matcher, name, child)
|
|
340
|
+
elif name == "put":
|
|
341
|
+
f = Put(matcher, name, child)
|
|
338
342
|
elif name == "debug":
|
|
339
343
|
f = Debug(matcher, name, child)
|
|
340
344
|
elif name == "brief_stack_trace":
|
|
@@ -351,6 +355,9 @@ class FunctionFactory:
|
|
|
351
355
|
f = RowTable(matcher, name, child)
|
|
352
356
|
elif name == "var_table":
|
|
353
357
|
f = VarTable(matcher, name, child)
|
|
358
|
+
elif name == "empty_stack":
|
|
359
|
+
f = EmptyStack(matcher, name, child)
|
|
360
|
+
|
|
354
361
|
else:
|
|
355
362
|
if (
|
|
356
363
|
f is None
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# pylint: disable=C0114
|
|
2
|
+
from csvpath.matching.productions import Equality, Header, Variable
|
|
3
|
+
from csvpath.matching.util.exceptions import ChildrenException
|
|
4
|
+
from csvpath.matching.util.expression_utility import ExpressionUtility
|
|
5
|
+
from ..function_focus import ValueProducer
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class EmptyStack(ValueProducer):
|
|
9
|
+
"""collects empty header names and/or indexes in a stack var."""
|
|
10
|
+
|
|
11
|
+
def check_valid(self) -> None:
|
|
12
|
+
self.validate_zero_or_more_args(types=[Header, Variable])
|
|
13
|
+
super().check_valid() # pragma: no cover
|
|
14
|
+
|
|
15
|
+
def _produce_value(self, skip=None) -> None:
|
|
16
|
+
if len(self.children) == 0:
|
|
17
|
+
self._do_all()
|
|
18
|
+
elif len(self.children) == 1 and isinstance(self.children[0], Equality):
|
|
19
|
+
self._do_some()
|
|
20
|
+
else:
|
|
21
|
+
self._do_one()
|
|
22
|
+
|
|
23
|
+
def _decide_match(self, skip=None) -> None:
|
|
24
|
+
st = self.to_value(skip=skip)
|
|
25
|
+
self.match = st and len(st) != 0
|
|
26
|
+
|
|
27
|
+
def _do_all(self, skip=None):
|
|
28
|
+
self.value = []
|
|
29
|
+
ml = len(self.matcher.line)
|
|
30
|
+
for i, h in enumerate(self.matcher.csvpath.headers):
|
|
31
|
+
if ml > i:
|
|
32
|
+
if ExpressionUtility.is_empty(self.matcher.line[i]):
|
|
33
|
+
self.value.append(h)
|
|
34
|
+
else:
|
|
35
|
+
self.value.append(h)
|
|
36
|
+
|
|
37
|
+
def _do_some(self, skip=None):
|
|
38
|
+
siblings = self.children[0].commas_to_list()
|
|
39
|
+
print(f"emmpty_stack: do_some: sibs: {siblings}")
|
|
40
|
+
self.value = []
|
|
41
|
+
for s in siblings:
|
|
42
|
+
v = s.to_value(skip=skip)
|
|
43
|
+
b = ExpressionUtility.is_empty(v)
|
|
44
|
+
if b:
|
|
45
|
+
self.value.append(s.name)
|
|
46
|
+
print(f"sib: {s}: {v} = {b}")
|
|
47
|
+
|
|
48
|
+
def _do_one(self, child, skip=None):
|
|
49
|
+
v = child.to_value(skip=skip)
|
|
50
|
+
self.value = [ExpressionUtility.is_empty(v)]
|
|
@@ -9,7 +9,7 @@ class Get(ValueProducer):
|
|
|
9
9
|
|
|
10
10
|
def check_valid(self) -> None:
|
|
11
11
|
self.validate_one_or_two_args(
|
|
12
|
-
one=[Header, Term, Function],
|
|
12
|
+
one=[Header, Term, Function, Variable],
|
|
13
13
|
left=[Header, Term, Function, Variable],
|
|
14
14
|
right=[Header, Term, Function, Variable],
|
|
15
15
|
)
|
|
@@ -17,11 +17,7 @@ class Get(ValueProducer):
|
|
|
17
17
|
|
|
18
18
|
def _produce_value(self, skip=None) -> None:
|
|
19
19
|
varname = None
|
|
20
|
-
|
|
21
|
-
if isinstance(c1, Variable):
|
|
22
|
-
varname = c1.name
|
|
23
|
-
else:
|
|
24
|
-
varname = self._value_one(skip=skip)
|
|
20
|
+
varname = self._value_one(skip=skip)
|
|
25
21
|
c2 = self._child_two()
|
|
26
22
|
v = self.matcher.get_variable(varname)
|
|
27
23
|
if v is None:
|
|
@@ -16,23 +16,24 @@ class Push(SideEffect):
|
|
|
16
16
|
k = eq.left.to_value(skip=skip)
|
|
17
17
|
v = eq.right.to_value(skip=skip)
|
|
18
18
|
stack = self.matcher.get_variable(k, set_if_none=[])
|
|
19
|
-
if
|
|
20
|
-
pass
|
|
21
|
-
elif isinstance(stack, tuple):
|
|
19
|
+
if stack is None or isinstance(stack, tuple):
|
|
22
20
|
self.matcher.csvpath.logger.warning( # pragma: no cover
|
|
23
|
-
"Push cannot add to the stack
|
|
21
|
+
"Push cannot add to the stack. The run may be ending."
|
|
24
22
|
)
|
|
25
|
-
elif
|
|
26
|
-
|
|
23
|
+
elif self.has_qualifier("distinct") and v in stack:
|
|
24
|
+
pass
|
|
25
|
+
elif self.notnone and ExpressionUtility.is_empty(v):
|
|
26
|
+
pass
|
|
27
27
|
else:
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
)
|
|
31
|
-
self.value = True
|
|
28
|
+
stack.append(v)
|
|
29
|
+
self.value = stack
|
|
32
30
|
|
|
33
31
|
def _decide_match(self, skip=None) -> None:
|
|
34
32
|
self.to_value(skip=skip)
|
|
35
|
-
|
|
33
|
+
if self.notnone:
|
|
34
|
+
self.match = not ExpressionUtility.is_empty(self.value)
|
|
35
|
+
else:
|
|
36
|
+
self.match = self.default_match()
|
|
36
37
|
|
|
37
38
|
|
|
38
39
|
class PushDistinct(Push):
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# pylint: disable=C0114
|
|
2
|
+
from csvpath.matching.productions import Header, Variable, Term
|
|
3
|
+
from ..function_focus import ValueProducer
|
|
4
|
+
from ..function import Function
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Put(ValueProducer):
|
|
8
|
+
"""Sets a variable with or without a tracking value"""
|
|
9
|
+
|
|
10
|
+
def check_valid(self) -> None:
|
|
11
|
+
self.validate_two_or_three_args()
|
|
12
|
+
super().check_valid()
|
|
13
|
+
|
|
14
|
+
def _produce_value(self, skip=None) -> None:
|
|
15
|
+
varname = None
|
|
16
|
+
c1 = self._child_one()
|
|
17
|
+
varname = c1.to_value(skip=skip)
|
|
18
|
+
c2 = self._child_two()
|
|
19
|
+
key = c2.to_value(skip=skip)
|
|
20
|
+
value = None
|
|
21
|
+
if len(self.children[0].children) > 2:
|
|
22
|
+
value = self.children[0].children[2].to_value(skip=skip)
|
|
23
|
+
else:
|
|
24
|
+
value = key
|
|
25
|
+
key = None
|
|
26
|
+
self.matcher.set_variable(varname, value=value, tracking=key)
|
|
27
|
+
self.value = self._apply_default_value()
|
|
28
|
+
|
|
29
|
+
def _decide_match(self, skip=None) -> None:
|
|
30
|
+
self.match = self.to_value(skip=skip) is not None # pragma: no cover
|
|
@@ -38,12 +38,27 @@ class ExpressionUtility:
|
|
|
38
38
|
return True
|
|
39
39
|
elif v == "None":
|
|
40
40
|
return True
|
|
41
|
-
elif
|
|
41
|
+
elif cls.isnan(v) or v == "nan":
|
|
42
42
|
return True
|
|
43
43
|
elif f"{v}".strip() == "":
|
|
44
44
|
return True
|
|
45
45
|
return False
|
|
46
46
|
|
|
47
|
+
@classmethod
|
|
48
|
+
def is_empty(cls, v):
|
|
49
|
+
ret = cls.is_none(v)
|
|
50
|
+
if not ret and (isinstance(v, list) or isinstance(v, tuple)):
|
|
51
|
+
if len(v) == 0:
|
|
52
|
+
ret = True
|
|
53
|
+
else:
|
|
54
|
+
for item in v:
|
|
55
|
+
ret = cls.is_empty(item)
|
|
56
|
+
if not ret:
|
|
57
|
+
break
|
|
58
|
+
elif not ret and isinstance(v, dict):
|
|
59
|
+
ret = len(v) == 0
|
|
60
|
+
return ret
|
|
61
|
+
|
|
47
62
|
@classmethod
|
|
48
63
|
def isnan(cls, v) -> bool:
|
|
49
64
|
try:
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
|
|
2
|
+
# Empty Stack
|
|
3
|
+
|
|
4
|
+
The `empty_stack()` function collects the names of empty values. Its primary job is identifying headers without values. However, it can also check on variables.
|
|
5
|
+
|
|
6
|
+
`empty_stack()` without arguments scans all the headers for values and creates a stack of the names of any that are empty. You can provide any number of arguments to `empty_stack()` to narrow its search down to just those values, both headers and variables.
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
## Example
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
$file.csv[*][
|
|
13
|
+
push("empties", empty_stack())
|
|
14
|
+
last() -> var_table("empties")
|
|
15
|
+
]
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
This csvpath creates an `empties` variable that is a stack of stacks. Each item in the `empties` stack represents the empty headers in a line. The result might look like:
|
|
19
|
+
|
|
20
|
+
┌───────────────────────────┐
|
|
21
|
+
│ empties │
|
|
22
|
+
├───────────────────────────┤
|
|
23
|
+
│ ['firstname', 'lastname'] │
|
|
24
|
+
├───────────────────────────┤
|
|
25
|
+
│ ['firstname'] │
|
|
26
|
+
├───────────────────────────┤
|
|
27
|
+
│ ['lastname'] │
|
|
28
|
+
├───────────────────────────┤
|
|
29
|
+
│ [] │
|
|
30
|
+
└───────────────────────────┘
|
|
31
|
+
|
|
32
|
+
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
|
|
2
|
+
# Get and Put
|
|
3
|
+
|
|
4
|
+
## `get()`
|
|
5
|
+
|
|
6
|
+
`get()` returns the value of a variable. It can access tracking values and stack indexes. Note that this function is important in a few cases but generally duplicates the ability to use `@varname.tracking` syntax.
|
|
7
|
+
|
|
8
|
+
The variable access by `get()` is dynamic. If you pass a term, e.g. "my_var", you access the named variable. Likewise, if you pass a header, the value of the header names the variable `get()` retrieves.
|
|
9
|
+
|
|
10
|
+
If there is a second argument then the variable must be either a dictionary or a list. In CsvPaths terminology, a variable with tracking values or a stack.
|
|
11
|
+
|
|
12
|
+
If any reference doesn't work -- i.e. the variable isn't found or the tracking value or index doesn't exist -- the return is None. A warning will be logged.
|
|
13
|
+
|
|
14
|
+
## `put()`
|
|
15
|
+
|
|
16
|
+
`put()` lets you set a variable dynamically. It's most important use is for setting tracking values.
|
|
17
|
+
|
|
18
|
+
The syntax is `put(varname, value)` or `put(varname, tracking_key, tracking_value)`. The names and values are dynamic. This means that the name of the value could be the value of a header or another variable. If the variable doesn't exist it will be created.
|
|
19
|
+
|
|
20
|
+
## Examples
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
$[1*][
|
|
24
|
+
tally(#firstname)
|
|
25
|
+
@john = get("tally_firstname", "John")
|
|
26
|
+
@john == 2 -> print("We have seen $.variables.john humans")
|
|
27
|
+
]
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
This contrived csvpath creates a tally of `#firstname`. The `@john` variable pulls the tally count keyed by the "John" tracking value. When the count hits `2` we print a message.
|
|
31
|
+
|
|
@@ -14,7 +14,9 @@ This family of functions allows you to create list variables.
|
|
|
14
14
|
|
|
15
15
|
Push can be called in the form `push_distinct()` or it can take a `distinct` qualifier. (The `distinct` qualifier may become well-known, but at the moment is ad hoc just for `push()`).
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
Push can also take a `notnone` qualifier. When `notnone` is set `push()` will not add an empty value to the stack. It will also not match lines while the stack is empty.
|
|
18
|
+
|
|
19
|
+
`peek()` will return None if you attempt to peek an index that doesn't exist. Likewise Popping when there is nothing on the list to pop returns None.
|
|
18
20
|
|
|
19
21
|
Peek and Pop can take the `asbool` qualifier in order to make their match depend on interpreting the value returned as a bool.
|
|
20
22
|
|
|
@@ -3,31 +3,31 @@
|
|
|
3
3
|
|
|
4
4
|
Tracks the value of a variable, function, or header. Tally always matches. It also collects its tally regardless of other matches or failures to match, unless you add the `onmatch` qualifier.
|
|
5
5
|
|
|
6
|
-
Tally keeps its count in variables named for the values it is tracking. A header would be tracked under its name, as:
|
|
6
|
+
Tally keeps its count in variables named for the values it is tracking. A header would be tracked under its name, prefixed by `tally_`, as:
|
|
7
7
|
|
|
8
|
-
{'
|
|
8
|
+
{'tally_firstname': {'Fred':3}}
|
|
9
9
|
|
|
10
10
|
Tally can track multiple values. Each of the values becomes a variable under its own name.
|
|
11
11
|
|
|
12
|
-
Tally also tracks the concatenation of the multiple values under the key `tally`. To use another key name add a non-keyword qualifier to tally.
|
|
12
|
+
Tally also tracks the concatenation of the multiple values under the key `tally`. To use another key name add a non-keyword qualifier to tally. E.g. `tally.birds(#bird_color, #bird_name)` has a tally variable of `birds` with values like `blue|bluebird`,`red|redbird`.
|
|
13
13
|
|
|
14
14
|
## Examples
|
|
15
15
|
|
|
16
16
|
$file.csv[*][tally(#lastname)]
|
|
17
17
|
|
|
18
|
-
This path creates a `
|
|
18
|
+
This path creates a `tally_lastname` variable like:
|
|
19
19
|
|
|
20
|
-
{'
|
|
20
|
+
{'tally_lastname': {'Kermet': 1, 'Smith':3}}
|
|
21
21
|
|
|
22
22
|
Multiple values can be used as arguments to tally().
|
|
23
23
|
|
|
24
24
|
$file.csv[*][tally(#firstname, #lastname)]
|
|
25
25
|
|
|
26
|
-
This path creates variables for firstname and lastname. In addition it creates a `tally`
|
|
26
|
+
This path creates variables for firstname and lastname. In addition it creates a variable named `tally` that holds the concatenation of the values, pipe delimited. The set of variables are like:
|
|
27
27
|
|
|
28
28
|
{
|
|
29
|
-
'
|
|
30
|
-
'
|
|
29
|
+
'tally_firstname': {'David': 3, 'Bob':5},
|
|
30
|
+
'tally_lastname':{'Jones':2, 'Smith':5},
|
|
31
31
|
'tally':{'David|Jones':1, 'Bob|Smith':1, ...
|
|
32
32
|
}
|
|
33
33
|
|
|
@@ -35,14 +35,14 @@ To limit tally to only matching rows use the `onmatch` qualifier like this:
|
|
|
35
35
|
|
|
36
36
|
$file.csv[*][
|
|
37
37
|
or( #firstname == "Frog", #firstname == "Ants" )
|
|
38
|
-
tally.
|
|
38
|
+
tally.my_tally.onmatch(#firstname, #lastname)
|
|
39
39
|
]
|
|
40
40
|
|
|
41
41
|
Which would result in variables like these:
|
|
42
42
|
|
|
43
43
|
{
|
|
44
|
-
'
|
|
45
|
-
'
|
|
46
|
-
'
|
|
44
|
+
'my_tally_firstname': {'Frog': 2, 'Ants': 1},
|
|
45
|
+
'my_tally_lastname': {'Bat': 3},
|
|
46
|
+
'my_tally': {'Frog|Bat': 2, 'Ants|Bat': 1}
|
|
47
47
|
}
|
|
48
48
|
|