csvpath 0.0.478__tar.gz → 0.0.480__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.478 → csvpath-0.0.480}/PKG-INFO +1 -1
- {csvpath-0.0.478 → csvpath-0.0.480}/config/config.ini +1 -1
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/csvpath.py +6 -1
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/managers/file_manager.py +1 -1
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/args.py +41 -23
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/dates/datef.py +1 -1
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/dates/now.py +6 -6
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/function_factory.py +3 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/function_finder.py +1 -1
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/lines/first_line.py +1 -1
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/misc/intf.py +3 -3
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/misc/nonef.py +9 -1
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/strings/regex.py +41 -15
- csvpath-0.0.480/csvpath/matching/functions/strings/string.py +43 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/strings/substring.py +1 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/productions/expression.py +7 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/productions/matchable.py +19 -4
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/util/exceptions.py +2 -2
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/util/expression_utility.py +33 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/util/print_parser.py +1 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/util/cache.py +1 -1
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/util/config.py +3 -2
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/util/error.py +11 -4
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/config.md +2 -1
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/string_functions.md +8 -4
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions.md +1 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/qualifiers.md +5 -1
- {csvpath-0.0.478 → csvpath-0.0.480}/pyproject.toml +1 -1
- {csvpath-0.0.478 → csvpath-0.0.480}/LICENSE +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/README.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/__init__.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/csvpaths.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/managers/__init__.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/managers/csvpaths_manager.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/managers/result.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/managers/results_manager.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/__init__.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/__init__.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/boolean/all.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/boolean/andf.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/boolean/any.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/boolean/between.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/boolean/empty.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/boolean/exists.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/boolean/inf.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/boolean/no.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/boolean/notf.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/boolean/orf.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/boolean/yes.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/counting/count.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/counting/count_headers.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/counting/count_lines.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/counting/count_scans.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/counting/counter.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/counting/every.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/counting/has_matches.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/counting/increment.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/counting/tally.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/counting/total_lines.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/function.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/function_focus.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/headers/append.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/headers/collect.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/headers/empty_stack.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/headers/end.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/headers/header_name.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/headers/header_names_mismatch.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/headers/headers.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/headers/mismatch.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/headers/replace.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/headers/reset_headers.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/lines/advance.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/lines/after_blank.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/lines/dups.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/lines/first.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/lines/last.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/lines/stop.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/math/above.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/math/add.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/math/divide.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/math/equals.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/math/mod.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/math/multiply.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/math/round.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/math/subtotal.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/math/subtract.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/math/sum.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/misc/importf.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/misc/random.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/print/jinjaf.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/print/print_line.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/print/print_queue.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/print/printf.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/print/table.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/stats/minf.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/stats/percent.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/stats/percent_unique.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/stats/stdev.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/strings/concat.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/strings/length.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/strings/lower.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/strings/metaphone.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/strings/starts_with.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/strings/strip.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/strings/upper.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/testing/debug.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/validity/fail.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/validity/failed.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/variables/get.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/variables/pushpop.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/variables/put.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/variables/track.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/variables/variables.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/lark_parser.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/lark_transformer.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/matcher.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/productions/__init__.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/productions/equality.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/productions/header.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/productions/qualified.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/productions/reference.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/productions/term.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/productions/variable.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/util/expression_encoder.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/util/lark_print_parser.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/scanning/__init__.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/scanning/exceptions.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/scanning/parser.out +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/scanning/parsetab.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/scanning/scanner.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/scanning/scanning_lexer.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/util/config_exception.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/util/exceptions.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/util/last_line_stats.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/util/line_counter.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/util/line_monitor.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/util/log_utility.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/util/metadata_parser.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/util/printer.py +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/asbool.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/assignment.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/comments.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/examples.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/files.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/above.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/advance.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/after_blank.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/all.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/andor.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/any.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/average.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/between.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/collect.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/correlate.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/count.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/count_headers.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/counter.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/date.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/empty.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/empty_stack.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/end.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/every.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/fail.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/first.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/get.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/has_dups.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/has_matches.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/header.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/header_name.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/header_names_mismatch.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/implementing_functions.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/import.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/in.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/increment.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/jinja.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/last.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/line_number.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/max.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/metaphone.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/mismatch.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/no.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/not.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/now.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/percent_unique.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/pop.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/print.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/print_line.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/print_queue.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/random.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/regex.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/replace.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/reset_headers.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/stdev.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/stop.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/subtotal.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/subtract.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/sum.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/tally.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/total_lines.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/track.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/variables.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/variables_and_headers.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/grammar.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/headers.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/images/logo-wordmark-white-on-black-trimmed-padded.png +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/images/logo-wordmark-white-trimmed.png +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/paths.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/printing.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/references.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/terms.md +0 -0
- {csvpath-0.0.478 → csvpath-0.0.480}/docs/variables.md +0 -0
|
@@ -242,7 +242,12 @@ class CsvPath(CsvPathPublic, ErrorCollector, Printer): # pylint: disable=R0902,
|
|
|
242
242
|
#
|
|
243
243
|
# these settings determine how we report function args validation
|
|
244
244
|
# errors. e.g. if print(True) the validation check fails because
|
|
245
|
-
# print() expects a string.
|
|
245
|
+
# print() expects a string. the more recent trend is to get all
|
|
246
|
+
# the errors and print statements in the same place controlled by
|
|
247
|
+
# the same properties. for now this stays because there is a minor
|
|
248
|
+
# benefit to being able to suppress runtime arg validation and only
|
|
249
|
+
# use match component rules and exceptions to generate validation
|
|
250
|
+
# info. but long term this capability may go away.
|
|
246
251
|
#
|
|
247
252
|
self._log_validation_errors = False
|
|
248
253
|
self._print_validation_errors = True
|
|
@@ -110,7 +110,7 @@ class FileManager(CsvPathsFileManager): # pylint: disable=C0115
|
|
|
110
110
|
|
|
111
111
|
def set_named_files_from_json(self, filename: str) -> None:
|
|
112
112
|
try:
|
|
113
|
-
with open(filename, encoding="utf-8") as f:
|
|
113
|
+
with open(filename, "r", encoding="utf-8") as f:
|
|
114
114
|
j = json.load(f)
|
|
115
115
|
self.named_files = j
|
|
116
116
|
except (OSError, ValueError, TypeError, JSONDecodeError) as ex:
|
|
@@ -10,7 +10,6 @@ from csvpath.matching.productions.equality import Equality
|
|
|
10
10
|
from csvpath.matching.util.expression_utility import ExpressionUtility
|
|
11
11
|
from ..util.exceptions import ChildrenException
|
|
12
12
|
from csvpath.util.config_exception import ConfigurationException
|
|
13
|
-
from csvpath.util.printer import Printer
|
|
14
13
|
|
|
15
14
|
# from csvpath.util.log_utility import LogUtility
|
|
16
15
|
# LogUtility.log_brief_trace()
|
|
@@ -199,7 +198,6 @@ class ArgSet:
|
|
|
199
198
|
b = self._validate_length(siblings)
|
|
200
199
|
if b is False:
|
|
201
200
|
return False
|
|
202
|
-
|
|
203
201
|
self._pad_or_shrink(siblings)
|
|
204
202
|
for i, s in enumerate(siblings):
|
|
205
203
|
t = tuple(self._args[i].types)
|
|
@@ -263,13 +261,23 @@ class ArgSet:
|
|
|
263
261
|
found = False
|
|
264
262
|
break
|
|
265
263
|
if not found:
|
|
264
|
+
self._parent._csvpath.logger.debug(
|
|
265
|
+
"%s(%s) not allowed in arg %s of argset %s",
|
|
266
|
+
type(a),
|
|
267
|
+
a,
|
|
268
|
+
i,
|
|
269
|
+
self.argset_number,
|
|
270
|
+
)
|
|
266
271
|
mismatches.append(
|
|
267
|
-
f"{type(a)}({a}) not allowed in arg {i} of
|
|
272
|
+
f"{type(a)}({a}) not allowed in arg {i + 1} of {len(actuals)}"
|
|
268
273
|
)
|
|
269
274
|
if len(actuals) < self.min_length:
|
|
270
|
-
|
|
271
|
-
|
|
275
|
+
self._parent._csvpath.logger.debug(
|
|
276
|
+
"Values received %s are too few for argset %s",
|
|
277
|
+
actuals,
|
|
278
|
+
self.argset_number,
|
|
272
279
|
)
|
|
280
|
+
mismatches.append(f"Too few values received: {actuals}")
|
|
273
281
|
found = False
|
|
274
282
|
if found:
|
|
275
283
|
mismatches = []
|
|
@@ -334,7 +342,8 @@ class Args:
|
|
|
334
342
|
if aset.validate(siblings):
|
|
335
343
|
good = True
|
|
336
344
|
if not good:
|
|
337
|
-
|
|
345
|
+
_ = " at {self.matchable.my_chain}" if self.matchable else ""
|
|
346
|
+
msg = f"{self._csvpath_id()} Incorrectly written{_}. Wrong type or number of args."
|
|
338
347
|
raise ChildrenException(msg)
|
|
339
348
|
self.validated = True
|
|
340
349
|
|
|
@@ -346,7 +355,7 @@ class Args:
|
|
|
346
355
|
if self.matchable.notnone and self._has_none(actuals):
|
|
347
356
|
mismatch_count = len(self._argsets)
|
|
348
357
|
mismatches = [
|
|
349
|
-
f"Cannot have None
|
|
358
|
+
f"Cannot have None in {self.matchable.my_chain} because it has the notnone qualifier"
|
|
350
359
|
]
|
|
351
360
|
else:
|
|
352
361
|
for aseti, aset in enumerate(self._argsets):
|
|
@@ -368,23 +377,32 @@ class Args:
|
|
|
368
377
|
return True
|
|
369
378
|
return False
|
|
370
379
|
|
|
380
|
+
def _csvpath_id(self) -> str:
|
|
381
|
+
cid = ""
|
|
382
|
+
if self._csvpath is None:
|
|
383
|
+
return cid
|
|
384
|
+
if self._csvpath.csvpaths:
|
|
385
|
+
cid = self._csvpath.identity
|
|
386
|
+
if not cid or cid.strip() == "":
|
|
387
|
+
cid = "<<no ID or name>>"
|
|
388
|
+
cid = f"[Csvpath {cid}]"
|
|
389
|
+
return cid
|
|
390
|
+
|
|
371
391
|
def handle_errors_if(self, mismatch_count, mismatches):
|
|
372
392
|
if mismatch_count == len(self._argsets):
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
cid = ""
|
|
382
|
-
if self._csvpath:
|
|
383
|
-
cid = self._csvpath.identity
|
|
384
|
-
if not self._csvpath or not cid or cid.strip() == "":
|
|
385
|
-
cid = "<<no ID or name>>"
|
|
386
|
-
pln = self._csvpath.line_monitor.physical_line_number
|
|
387
|
-
pm = f"[In csvpath {cid}] Wrong values of args: {pm} at line {pln}"
|
|
388
|
-
self._csvpath.report_validation_errors(pm)
|
|
393
|
+
pm = f"mismatch in {self.matchable.my_chain}: {mismatches}"
|
|
394
|
+
# when would we not have a csvpath?
|
|
395
|
+
pln = (
|
|
396
|
+
self._csvpath.line_monitor.physical_line_number if self._csvpath else 0
|
|
397
|
+
)
|
|
398
|
+
csvpathid = self._csvpath_id()
|
|
399
|
+
pm = f"{csvpathid} Wrong value(s) at line {pln}: {pm}"
|
|
400
|
+
# self._csvpath.report_validation_errors(pm)
|
|
389
401
|
if self._csvpath is None or self._csvpath.raise_validation_errors:
|
|
390
402
|
raise ChildrenException(pm)
|
|
403
|
+
# we print in-run validation errors as part of the raise handle,
|
|
404
|
+
# so this is a bit extra. We can suppress the exceptions completely
|
|
405
|
+
# but still print args validation errors. not sure that is anything
|
|
406
|
+
# more than a deep corner case. defering removing it.
|
|
407
|
+
if self._csvpath and self._csvpath.print_validation_errors:
|
|
408
|
+
self._csvpath.report_validation_errors(pm)
|
|
@@ -15,13 +15,13 @@ class Now(ValueProducer):
|
|
|
15
15
|
def check_valid(self) -> None:
|
|
16
16
|
self.args = Args(matchable=self)
|
|
17
17
|
self.args.argset(0)
|
|
18
|
-
self.args.argset(1).arg(
|
|
19
|
-
types=[None, Term, Function, Header, Variable], actuals=[str]
|
|
20
|
-
)
|
|
21
|
-
self.args.validate(self.siblings())
|
|
22
18
|
if self.name in ["thisyear", "thismonth", "today"]:
|
|
23
|
-
|
|
24
|
-
|
|
19
|
+
self.args.validate(self.siblings())
|
|
20
|
+
else:
|
|
21
|
+
self.args.argset(1).arg(
|
|
22
|
+
types=[None, Term, Function, Header, Variable], actuals=[str]
|
|
23
|
+
)
|
|
24
|
+
self.args.validate(self.siblings())
|
|
25
25
|
super().check_valid()
|
|
26
26
|
|
|
27
27
|
def _produce_value(self, skip=None) -> None:
|
|
@@ -7,6 +7,7 @@ from .dates.datef import Date
|
|
|
7
7
|
from .strings.lower import Lower
|
|
8
8
|
from .strings.upper import Upper
|
|
9
9
|
from .strings.substring import Substring
|
|
10
|
+
from .strings.string import String
|
|
10
11
|
from .strings.starts_with import StartsWith
|
|
11
12
|
from .strings.strip import Strip
|
|
12
13
|
from .strings.length import Length, MinMaxLength
|
|
@@ -221,6 +222,8 @@ class FunctionFactory:
|
|
|
221
222
|
f = Length(matcher, name, child)
|
|
222
223
|
elif name == "add":
|
|
223
224
|
f = Add(matcher, name, child)
|
|
225
|
+
elif name == "string":
|
|
226
|
+
f = String(matcher, name, child)
|
|
224
227
|
elif name in ["subtract", "minus"]:
|
|
225
228
|
f = Subtract(matcher, name, child)
|
|
226
229
|
elif name == "multiply":
|
|
@@ -12,7 +12,7 @@ class Int(ValueProducer):
|
|
|
12
12
|
def check_valid(self) -> None:
|
|
13
13
|
self.args = Args(matchable=self)
|
|
14
14
|
a = self.args.argset(1)
|
|
15
|
-
a.arg(types=[Term, Variable, Header, Function], actuals=[None, int,
|
|
15
|
+
a.arg(types=[Term, Variable, Header, Function], actuals=[None, int, float])
|
|
16
16
|
self.args.validate(self.siblings())
|
|
17
17
|
super().check_valid()
|
|
18
18
|
|
|
@@ -33,7 +33,7 @@ class Float(ValueProducer):
|
|
|
33
33
|
def check_valid(self) -> None:
|
|
34
34
|
self.args = Args(matchable=self)
|
|
35
35
|
a = self.args.argset(1)
|
|
36
|
-
a.arg(types=[Term, Variable, Header, Function], actuals=[None, float, int
|
|
36
|
+
a.arg(types=[Term, Variable, Header, Function], actuals=[None, float, int])
|
|
37
37
|
self.args.validate(self.siblings())
|
|
38
38
|
super().check_valid()
|
|
39
39
|
|
|
@@ -57,7 +57,7 @@ class Num(ValueProducer):
|
|
|
57
57
|
a = self.args.argset(1)
|
|
58
58
|
a.arg(
|
|
59
59
|
types=[Term, Variable, Header, Function],
|
|
60
|
-
actuals=[None,
|
|
60
|
+
actuals=[None, int, float, bool],
|
|
61
61
|
)
|
|
62
62
|
self.args.validate(self.siblings())
|
|
63
63
|
super().check_valid()
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
# pylint: disable=C0114
|
|
2
2
|
from typing import Any
|
|
3
3
|
from ..function_focus import ValueProducer
|
|
4
|
+
from csvpath.matching.util.expression_utility import ExpressionUtility
|
|
5
|
+
from csvpath.matching.productions import Variable, Header, Reference
|
|
6
|
+
from csvpath.matching.functions.function import Function
|
|
4
7
|
from ..args import Args
|
|
5
8
|
|
|
6
9
|
|
|
@@ -10,6 +13,8 @@ class Nonef(ValueProducer):
|
|
|
10
13
|
def check_valid(self) -> None:
|
|
11
14
|
self.args = Args(matchable=self)
|
|
12
15
|
self.args.argset(0)
|
|
16
|
+
a = self.args.argset(1)
|
|
17
|
+
a.arg(types=[Variable, Header, Function, Reference], actuals=[None, Any])
|
|
13
18
|
self.args.validate(self.siblings())
|
|
14
19
|
super().check_valid()
|
|
15
20
|
|
|
@@ -18,4 +23,7 @@ class Nonef(ValueProducer):
|
|
|
18
23
|
self.value = None
|
|
19
24
|
|
|
20
25
|
def _decide_match(self, *, skip=None) -> None: # pragma: no cover
|
|
21
|
-
self.
|
|
26
|
+
if len(self.children) == 0:
|
|
27
|
+
self.match = True
|
|
28
|
+
else:
|
|
29
|
+
self.match = ExpressionUtility.is_none(self._value_one(skip=skip))
|
|
@@ -3,6 +3,7 @@ import re
|
|
|
3
3
|
from csvpath.matching.util.expression_utility import ExpressionUtility
|
|
4
4
|
from ..function_focus import MatchDecider
|
|
5
5
|
from csvpath.matching.productions import Term, Variable, Header, Reference
|
|
6
|
+
from csvpath.matching.util.exceptions import ChildrenException
|
|
6
7
|
from ..function import Function
|
|
7
8
|
from ..args import Args
|
|
8
9
|
|
|
@@ -13,29 +14,54 @@ class Regex(MatchDecider):
|
|
|
13
14
|
def check_valid(self) -> None:
|
|
14
15
|
self.args = Args(matchable=self)
|
|
15
16
|
a = self.args.argset(3)
|
|
16
|
-
a.arg(
|
|
17
|
-
|
|
17
|
+
a.arg(
|
|
18
|
+
types=[Term, Variable, Header, Function, Reference],
|
|
19
|
+
actuals=[str, self.args.EMPTY_STRING],
|
|
20
|
+
)
|
|
21
|
+
a.arg(
|
|
22
|
+
types=[Term, Variable, Header, Function, Reference],
|
|
23
|
+
actuals=[str, self.args.EMPTY_STRING],
|
|
24
|
+
)
|
|
18
25
|
a.arg(types=[None, Term, Variable, Header, Function, Reference], actuals=[int])
|
|
19
26
|
self.args.validate(self.siblings())
|
|
20
27
|
super().check_valid()
|
|
21
28
|
left = self._function_or_equality.left
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
29
|
+
self.is_regex_if(left)
|
|
30
|
+
right = self._function_or_equality.right
|
|
31
|
+
self.is_regex_if(right)
|
|
32
|
+
|
|
33
|
+
def is_regex_if(self, t):
|
|
34
|
+
if isinstance(t, Term):
|
|
35
|
+
v = t.to_value()
|
|
36
|
+
if v and len(v) > 0 and v[0] == "/":
|
|
37
|
+
re.compile(v)
|
|
38
|
+
|
|
39
|
+
def _the_regex(self, siblings, skip=None):
|
|
40
|
+
# group
|
|
41
|
+
group = 0 if len(siblings) == 2 else siblings[2].to_value(skip=skip)
|
|
42
|
+
group = int(group)
|
|
43
|
+
c1 = siblings[0]
|
|
44
|
+
c2 = siblings[1]
|
|
45
|
+
v1 = c1.to_value(skip=skip)
|
|
46
|
+
v2 = c2.to_value(skip=skip)
|
|
47
|
+
|
|
48
|
+
if v1.startswith("/"):
|
|
49
|
+
theregex = v1.lstrip("/")
|
|
50
|
+
theregex = theregex.rstrip("/")
|
|
51
|
+
thevalue = v2
|
|
52
|
+
return theregex, thevalue, group
|
|
53
|
+
elif v2.startswith("/"):
|
|
54
|
+
theregex = v2.lstrip("/")
|
|
55
|
+
theregex = theregex.rstrip("/")
|
|
56
|
+
thevalue = v1
|
|
57
|
+
return theregex, thevalue, group
|
|
58
|
+
else:
|
|
59
|
+
raise ChildrenException("No regular expression available")
|
|
25
60
|
|
|
26
61
|
def _produce_value(self, skip=None) -> None:
|
|
27
62
|
child = self.children[0]
|
|
28
63
|
siblings = child.commas_to_list()
|
|
29
|
-
|
|
30
|
-
value = siblings[1]
|
|
31
|
-
group = 0 if len(siblings) == 2 else siblings[2].to_value(skip=skip)
|
|
32
|
-
group = int(group)
|
|
33
|
-
thevalue = value.to_value(skip=skip)
|
|
34
|
-
theregex = regex.to_value(skip=skip)
|
|
35
|
-
if theregex[0] == "/":
|
|
36
|
-
theregex = theregex[1:]
|
|
37
|
-
if theregex[len(theregex) - 1] == "/":
|
|
38
|
-
theregex = theregex[0 : len(theregex) - 1]
|
|
64
|
+
theregex, thevalue, group = self._the_regex(siblings, skip=skip)
|
|
39
65
|
if thevalue is None:
|
|
40
66
|
# this could happen if the line is blank
|
|
41
67
|
pass
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# pylint: disable=C0114
|
|
2
|
+
from csvpath.matching.util.exceptions import ChildrenException
|
|
3
|
+
from ..function_focus import ValueProducer
|
|
4
|
+
from csvpath.matching.productions import Term, Variable, Header, Reference
|
|
5
|
+
from ..function import Function
|
|
6
|
+
from ..args import Args
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class String(ValueProducer):
|
|
10
|
+
def check_valid(self) -> None:
|
|
11
|
+
self.args = Args(matchable=self)
|
|
12
|
+
a = self.args.argset(1)
|
|
13
|
+
a.arg(
|
|
14
|
+
types=[Term, Variable, Function],
|
|
15
|
+
actuals=[None, str, self.args.EMPTY_STRING],
|
|
16
|
+
)
|
|
17
|
+
a = self.args.argset(3)
|
|
18
|
+
a.arg(
|
|
19
|
+
types=[Term, Variable, Function],
|
|
20
|
+
actuals=[None, str, self.args.EMPTY_STRING],
|
|
21
|
+
)
|
|
22
|
+
a.arg(types=[Term, Variable, Header, Function], actuals=[int])
|
|
23
|
+
a.arg(types=[None, Term, Variable, Header, Function], actuals=[int])
|
|
24
|
+
self.args.validate(self.siblings())
|
|
25
|
+
super().check_valid()
|
|
26
|
+
|
|
27
|
+
def _produce_value(self, skip=None) -> None:
|
|
28
|
+
self.matches(skip=skip)
|
|
29
|
+
self.value = f"{self._value_one()}" if self.match else None
|
|
30
|
+
|
|
31
|
+
def _decide_match(self, skip=None) -> None:
|
|
32
|
+
value = self._value_one(skip=skip)
|
|
33
|
+
value = f"{value}" if value is not None else None
|
|
34
|
+
if value is None:
|
|
35
|
+
self.match = False
|
|
36
|
+
else:
|
|
37
|
+
maxlen = self._value_two(skip=skip)
|
|
38
|
+
minlen = self._value_three(skip=skip)
|
|
39
|
+
if minlen is None:
|
|
40
|
+
minlen = 0
|
|
41
|
+
if maxlen is None:
|
|
42
|
+
maxlen = len(value)
|
|
43
|
+
self.match = minlen <= len(value) <= maxlen
|
|
@@ -18,6 +18,7 @@ class Substring(ValueProducer):
|
|
|
18
18
|
actuals=[str, self.args.EMPTY_STRING],
|
|
19
19
|
)
|
|
20
20
|
a.arg(types=[Term, Variable, Header, Function, Reference], actuals=[int])
|
|
21
|
+
self.args.validate(self.siblings())
|
|
21
22
|
super().check_valid()
|
|
22
23
|
|
|
23
24
|
def _produce_value(self, skip=None) -> None:
|
|
@@ -40,6 +40,13 @@ class Expression(Matchable):
|
|
|
40
40
|
e.trace = traceback.format_exc()
|
|
41
41
|
e.source = self
|
|
42
42
|
e.json = self.matcher.to_json(self)
|
|
43
|
+
#
|
|
44
|
+
# for output ErrorHandler has:
|
|
45
|
+
# - the print() on the CsvPath
|
|
46
|
+
# - the error_collector
|
|
47
|
+
# - the logger on the CsvPath or CsvPaths
|
|
48
|
+
# - exceptions dumped on system.err
|
|
49
|
+
#
|
|
43
50
|
ErrorHandler(
|
|
44
51
|
csvpath=self.matcher.csvpath, error_collector=self.matcher.csvpath
|
|
45
52
|
).handle_error(e)
|
|
@@ -33,10 +33,11 @@ class Matchable(Qualified):
|
|
|
33
33
|
don't want that info after a run completes"""
|
|
34
34
|
|
|
35
35
|
def _simple_class_name(self) -> str:
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
36
|
+
return ExpressionUtility.simple_class_name(self)
|
|
37
|
+
|
|
38
|
+
@property
|
|
39
|
+
def my_chain(self) -> str:
|
|
40
|
+
return ExpressionUtility.my_chain(self)
|
|
40
41
|
|
|
41
42
|
def _noop_match(self) -> bool:
|
|
42
43
|
"""deprecated. use self.default_match()"""
|
|
@@ -124,6 +125,20 @@ class Matchable(Qualified):
|
|
|
124
125
|
# with the current parse tree this shouldn't happen
|
|
125
126
|
return None
|
|
126
127
|
|
|
128
|
+
def _value_three(self, skip=None):
|
|
129
|
+
c = self._child_three()
|
|
130
|
+
if c is None:
|
|
131
|
+
return None
|
|
132
|
+
return c.to_value(skip=skip)
|
|
133
|
+
|
|
134
|
+
def _child_three(self):
|
|
135
|
+
if len(self.children) == 0:
|
|
136
|
+
# validation should have already caught this, if it is a problem
|
|
137
|
+
return None
|
|
138
|
+
if len(self.children) >= 3:
|
|
139
|
+
return self.children[0].children[2]
|
|
140
|
+
return None
|
|
141
|
+
|
|
127
142
|
def siblings_or_equality(self) -> list:
|
|
128
143
|
if (
|
|
129
144
|
len(self.children) == 1
|
|
@@ -2,7 +2,7 @@ class MatchException(Exception):
|
|
|
2
2
|
"""most general exception when matching"""
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
class MatchComponentException(
|
|
5
|
+
class MatchComponentException(MatchException):
|
|
6
6
|
"""most general exception for the matching part of a csvpath"""
|
|
7
7
|
|
|
8
8
|
|
|
@@ -10,7 +10,7 @@ class ChildrenException(MatchComponentException):
|
|
|
10
10
|
"""raised when the structure of a match part is incorrect"""
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
class DataException(
|
|
13
|
+
class DataException(MatchException):
|
|
14
14
|
"""raised when a datium is unexpected or incorrect"""
|
|
15
15
|
|
|
16
16
|
pass
|
|
@@ -363,6 +363,39 @@ class ExpressionUtility:
|
|
|
363
363
|
break
|
|
364
364
|
return hashlib.sha256(id.encode("utf-8")).hexdigest()
|
|
365
365
|
|
|
366
|
+
@classmethod
|
|
367
|
+
def my_chain(cls, thing):
|
|
368
|
+
ancs = []
|
|
369
|
+
p = thing.parent
|
|
370
|
+
while p is not None:
|
|
371
|
+
ancs.append(p)
|
|
372
|
+
p = p.parent
|
|
373
|
+
chain = cls.name_or_class(thing)
|
|
374
|
+
for o in ancs:
|
|
375
|
+
n = cls.name_or_class(o)
|
|
376
|
+
if n != "":
|
|
377
|
+
chain = f"{n}.{chain}"
|
|
378
|
+
return chain
|
|
379
|
+
|
|
380
|
+
@classmethod
|
|
381
|
+
def name_or_class(cls, thing, show_eq_and_exp=False):
|
|
382
|
+
if not show_eq_and_exp and f"{type(thing)}".find("Equality") > -1:
|
|
383
|
+
return ""
|
|
384
|
+
if not show_eq_and_exp and f"{type(thing)}".find("Expression") > -1:
|
|
385
|
+
return ""
|
|
386
|
+
if not hasattr(thing, "name"):
|
|
387
|
+
return cls.simple_class_name(thing)
|
|
388
|
+
if f"{type(thing)}".find("Term") != -1:
|
|
389
|
+
return thing.to_value()
|
|
390
|
+
if thing.name is None:
|
|
391
|
+
return cls.simple_class_name(thing)
|
|
392
|
+
return thing.name
|
|
393
|
+
|
|
394
|
+
@classmethod
|
|
395
|
+
def simple_class_name(cls, thing):
|
|
396
|
+
ts = f"{type(thing)}"
|
|
397
|
+
return ts[ts.rfind(".") + 1 : ts.rfind("'")]
|
|
398
|
+
|
|
366
399
|
@classmethod
|
|
367
400
|
def get_my_expression(cls, thing):
|
|
368
401
|
p = thing.parent
|
|
@@ -262,6 +262,7 @@ class PrintParser:
|
|
|
262
262
|
local,
|
|
263
263
|
False,
|
|
264
264
|
)
|
|
265
|
+
self._set(runtime, identity, "identity", identity, local, False)
|
|
265
266
|
self._set(runtime, identity, "count_matches", csvpath.match_count, local, False)
|
|
266
267
|
self._set(runtime, identity, "count_scans", csvpath.scan_count, local, False)
|
|
267
268
|
self._set(runtime, identity, "scan_part", csvpath.scan, local, False)
|
|
@@ -45,5 +45,5 @@ class Cache:
|
|
|
45
45
|
def cache_text(self, filename, strtype: str, data: str) -> None:
|
|
46
46
|
cn = self._cache_name(filename)
|
|
47
47
|
cachepath = os.path.join(self._cachedir(), f"{cn}.{strtype}")
|
|
48
|
-
with open(cachepath, "w") as file:
|
|
48
|
+
with open(cachepath, "w", encoding="utf-8") as file:
|
|
49
49
|
file.write(str(data))
|
|
@@ -22,6 +22,7 @@ class OnError(Enum):
|
|
|
22
22
|
COLLECT = "collect"
|
|
23
23
|
STOP = "stop"
|
|
24
24
|
FAIL = "fail"
|
|
25
|
+
PRINT = "print"
|
|
25
26
|
|
|
26
27
|
|
|
27
28
|
class LogLevels(Enum):
|
|
@@ -134,14 +135,14 @@ class Config:
|
|
|
134
135
|
if directory != "":
|
|
135
136
|
if not path.exists(directory):
|
|
136
137
|
os.makedirs(directory)
|
|
137
|
-
with open(self._configpath, "w") as file:
|
|
138
|
+
with open(self._configpath, "w", encoding="utf-8") as file:
|
|
138
139
|
c = """
|
|
139
140
|
[csvpath_files]
|
|
140
141
|
extensions = txt, csvpath, csvpaths
|
|
141
142
|
[csv_files]
|
|
142
143
|
extensions = txt, csv, tsv, dat, tab, psv, ssv
|
|
143
144
|
[errors]
|
|
144
|
-
csvpath = raise, collect, stop, fail
|
|
145
|
+
csvpath = raise, collect, stop, fail, print
|
|
145
146
|
csvpaths = raise, collect
|
|
146
147
|
[logging]
|
|
147
148
|
csvpath = info
|
|
@@ -6,6 +6,7 @@ import traceback
|
|
|
6
6
|
from csvpath.util.config import OnError
|
|
7
7
|
from .exceptions import InputException
|
|
8
8
|
from .log_utility import LogException
|
|
9
|
+
from ..matching.util.exceptions import MatchException
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
class ErrorHandlingException(Exception):
|
|
@@ -126,9 +127,9 @@ class ErrorHandler:
|
|
|
126
127
|
raise InputException("Error handler cannot handle a None error")
|
|
127
128
|
if OnError.QUIET.value in policy:
|
|
128
129
|
self.logger.error(f"Quiet error: {error.exception}")
|
|
129
|
-
self.logger.error(f"Quiet class: {error.exception_class}")
|
|
130
|
-
self.logger.error(f"Quiet file: {error.filename}")
|
|
131
|
-
self.logger.error(f"Quiet line_count: {error.line_count}")
|
|
130
|
+
self.logger.error(f"Quiet error class: {error.exception_class}")
|
|
131
|
+
self.logger.error(f"Quiet error file: {error.filename}")
|
|
132
|
+
self.logger.error(f"Quiet error line_count: {error.line_count}")
|
|
132
133
|
else:
|
|
133
134
|
self.logger.error(f"{error}")
|
|
134
135
|
if OnError.STOP.value in policy:
|
|
@@ -139,8 +140,14 @@ class ErrorHandler:
|
|
|
139
140
|
if OnError.FAIL.value in policy:
|
|
140
141
|
if self._csvpath:
|
|
141
142
|
self._csvpath.is_valid = False
|
|
143
|
+
if OnError.PRINT.value in policy:
|
|
144
|
+
msg = f"{error.error}"
|
|
145
|
+
if self._csvpath:
|
|
146
|
+
self._csvpath.print(msg)
|
|
142
147
|
if OnError.RAISE.value in policy:
|
|
143
|
-
raise
|
|
148
|
+
raise MatchException(
|
|
149
|
+
f"Exception triggered by error policy {policy}"
|
|
150
|
+
) from error.error
|
|
144
151
|
|
|
145
152
|
def build(self, ex: Exception) -> Error:
|
|
146
153
|
error = Error()
|
|
@@ -34,8 +34,9 @@ The error settings are for when CsvPath or CsvPaths instances encounter problems
|
|
|
34
34
|
- `raise` - Raise the exception in as noisy a way as possible
|
|
35
35
|
- `quiet` - Do nothing that affects the system out; this protects command line redirection of `print()` output. Logging is also minimized such that errors that would release a lot of metadata are slimmed down.
|
|
36
36
|
- `collect` - Collect the errors in the error results for the CsvPath. This option is available with and without a CsvPaths instance.
|
|
37
|
+
- `print` - Prints the errors using the Printer interface to whatever printers are available. By default this goes to standard out.
|
|
37
38
|
|
|
38
|
-
Multiple of these settings can be configured together
|
|
39
|
+
Multiple of these settings can be configured together.`quiet` and `raise` do not coexist well; likewise `quiet` and `print`. `raise` will win over `quiet` because seeing problems lets you fix them. `print` is most useful in getting simple inline error messages when `raise` is off.
|
|
39
40
|
|
|
40
41
|
## Logging
|
|
41
42
|
|
|
@@ -13,11 +13,15 @@ Same as you would expect.
|
|
|
13
13
|
|
|
14
14
|
### min_length(value, int) and max_length(value, int)
|
|
15
15
|
|
|
16
|
-
`min_length()` and `max_length()` return True if the stringified value is more than or less than the integer provided. The functionality can also be achieved using `above()` and `below()` or `between()`, but the min and max functions are obviously simpler.
|
|
16
|
+
`min_length()` and `max_length()` return True if the stringified value is more than or less than the integer provided. The functionality can also be achieved using `above()` and `below()` or `between()`, but the min and max functions are obviously simpler. Likewise, there is overlap with the newer `string()`; however, you cannot use `string()` to set a min without also setting a max; for that you would need `min_length()`.
|
|
17
|
+
|
|
18
|
+
### string(value, max, min)
|
|
19
|
+
|
|
20
|
+
`string()` is an evolved approach that enables a simpler declaration of a string. Think of it like a VARCHAR declaration in SQL's DDL. You can add the `notnone` qualifier to force `string()` to be not None. `string()` stringifies its value. The value of `string()` is the value it wraps. Standing alone it is an existance test that the wrapped value is not None.
|
|
17
21
|
|
|
18
22
|
### lower(value)
|
|
19
23
|
|
|
20
|
-
|
|
24
|
+
Lowercases a string.
|
|
21
25
|
|
|
22
26
|
### starts_with(does_this, start_with_this)
|
|
23
27
|
|
|
@@ -25,7 +29,7 @@ Checks if the first value, stringified, starts with the second value. The values
|
|
|
25
29
|
|
|
26
30
|
### strip(value)
|
|
27
31
|
|
|
28
|
-
Same as you would expect from the Python function.
|
|
32
|
+
Trims whitespace. Same as you would expect from the Python function.
|
|
29
33
|
|
|
30
34
|
### substring(value, int)
|
|
31
35
|
|
|
@@ -33,7 +37,7 @@ Substring starting from left and including the number of characters indicated. T
|
|
|
33
37
|
|
|
34
38
|
### upper(value)
|
|
35
39
|
|
|
36
|
-
|
|
40
|
+
Uppercases a string.
|
|
37
41
|
|
|
38
42
|
## Examples
|
|
39
43
|
|