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.
Files changed (211) hide show
  1. {csvpath-0.0.478 → csvpath-0.0.480}/PKG-INFO +1 -1
  2. {csvpath-0.0.478 → csvpath-0.0.480}/config/config.ini +1 -1
  3. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/csvpath.py +6 -1
  4. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/managers/file_manager.py +1 -1
  5. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/args.py +41 -23
  6. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/dates/datef.py +1 -1
  7. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/dates/now.py +6 -6
  8. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/function_factory.py +3 -0
  9. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/function_finder.py +1 -1
  10. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/lines/first_line.py +1 -1
  11. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/misc/intf.py +3 -3
  12. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/misc/nonef.py +9 -1
  13. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/strings/regex.py +41 -15
  14. csvpath-0.0.480/csvpath/matching/functions/strings/string.py +43 -0
  15. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/strings/substring.py +1 -0
  16. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/productions/expression.py +7 -0
  17. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/productions/matchable.py +19 -4
  18. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/util/exceptions.py +2 -2
  19. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/util/expression_utility.py +33 -0
  20. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/util/print_parser.py +1 -0
  21. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/util/cache.py +1 -1
  22. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/util/config.py +3 -2
  23. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/util/error.py +11 -4
  24. {csvpath-0.0.478 → csvpath-0.0.480}/docs/config.md +2 -1
  25. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/string_functions.md +8 -4
  26. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions.md +1 -0
  27. {csvpath-0.0.478 → csvpath-0.0.480}/docs/qualifiers.md +5 -1
  28. {csvpath-0.0.478 → csvpath-0.0.480}/pyproject.toml +1 -1
  29. {csvpath-0.0.478 → csvpath-0.0.480}/LICENSE +0 -0
  30. {csvpath-0.0.478 → csvpath-0.0.480}/README.md +0 -0
  31. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/__init__.py +0 -0
  32. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/csvpaths.py +0 -0
  33. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/managers/__init__.py +0 -0
  34. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/managers/csvpaths_manager.py +0 -0
  35. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/managers/result.py +0 -0
  36. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/managers/results_manager.py +0 -0
  37. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/__init__.py +0 -0
  38. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/__init__.py +0 -0
  39. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/boolean/all.py +0 -0
  40. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/boolean/andf.py +0 -0
  41. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/boolean/any.py +0 -0
  42. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/boolean/between.py +0 -0
  43. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/boolean/empty.py +0 -0
  44. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/boolean/exists.py +0 -0
  45. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/boolean/inf.py +0 -0
  46. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/boolean/no.py +0 -0
  47. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/boolean/notf.py +0 -0
  48. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/boolean/orf.py +0 -0
  49. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/boolean/yes.py +0 -0
  50. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/counting/count.py +0 -0
  51. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/counting/count_headers.py +0 -0
  52. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/counting/count_lines.py +0 -0
  53. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/counting/count_scans.py +0 -0
  54. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/counting/counter.py +0 -0
  55. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/counting/every.py +0 -0
  56. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/counting/has_matches.py +0 -0
  57. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/counting/increment.py +0 -0
  58. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/counting/tally.py +0 -0
  59. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/counting/total_lines.py +0 -0
  60. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/function.py +0 -0
  61. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/function_focus.py +0 -0
  62. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/headers/append.py +0 -0
  63. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/headers/collect.py +0 -0
  64. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/headers/empty_stack.py +0 -0
  65. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/headers/end.py +0 -0
  66. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/headers/header_name.py +0 -0
  67. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/headers/header_names_mismatch.py +0 -0
  68. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/headers/headers.py +0 -0
  69. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/headers/mismatch.py +0 -0
  70. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/headers/replace.py +0 -0
  71. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/headers/reset_headers.py +0 -0
  72. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/lines/advance.py +0 -0
  73. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/lines/after_blank.py +0 -0
  74. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/lines/dups.py +0 -0
  75. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/lines/first.py +0 -0
  76. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/lines/last.py +0 -0
  77. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/lines/stop.py +0 -0
  78. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/math/above.py +0 -0
  79. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/math/add.py +0 -0
  80. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/math/divide.py +0 -0
  81. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/math/equals.py +0 -0
  82. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/math/mod.py +0 -0
  83. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/math/multiply.py +0 -0
  84. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/math/round.py +0 -0
  85. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/math/subtotal.py +0 -0
  86. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/math/subtract.py +0 -0
  87. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/math/sum.py +0 -0
  88. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/misc/importf.py +0 -0
  89. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/misc/random.py +0 -0
  90. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/print/jinjaf.py +0 -0
  91. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/print/print_line.py +0 -0
  92. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/print/print_queue.py +0 -0
  93. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/print/printf.py +0 -0
  94. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/print/table.py +0 -0
  95. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/stats/minf.py +0 -0
  96. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/stats/percent.py +0 -0
  97. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/stats/percent_unique.py +0 -0
  98. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/stats/stdev.py +0 -0
  99. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/strings/concat.py +0 -0
  100. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/strings/length.py +0 -0
  101. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/strings/lower.py +0 -0
  102. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/strings/metaphone.py +0 -0
  103. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/strings/starts_with.py +0 -0
  104. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/strings/strip.py +0 -0
  105. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/strings/upper.py +0 -0
  106. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/testing/debug.py +0 -0
  107. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/validity/fail.py +0 -0
  108. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/validity/failed.py +0 -0
  109. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/variables/get.py +0 -0
  110. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/variables/pushpop.py +0 -0
  111. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/variables/put.py +0 -0
  112. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/variables/track.py +0 -0
  113. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/functions/variables/variables.py +0 -0
  114. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/lark_parser.py +0 -0
  115. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/lark_transformer.py +0 -0
  116. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/matcher.py +0 -0
  117. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/productions/__init__.py +0 -0
  118. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/productions/equality.py +0 -0
  119. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/productions/header.py +0 -0
  120. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/productions/qualified.py +0 -0
  121. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/productions/reference.py +0 -0
  122. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/productions/term.py +0 -0
  123. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/productions/variable.py +0 -0
  124. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/util/expression_encoder.py +0 -0
  125. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/matching/util/lark_print_parser.py +0 -0
  126. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/scanning/__init__.py +0 -0
  127. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/scanning/exceptions.py +0 -0
  128. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/scanning/parser.out +0 -0
  129. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/scanning/parsetab.py +0 -0
  130. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/scanning/scanner.py +0 -0
  131. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/scanning/scanning_lexer.py +0 -0
  132. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/util/config_exception.py +0 -0
  133. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/util/exceptions.py +0 -0
  134. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/util/last_line_stats.py +0 -0
  135. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/util/line_counter.py +0 -0
  136. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/util/line_monitor.py +0 -0
  137. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/util/log_utility.py +0 -0
  138. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/util/metadata_parser.py +0 -0
  139. {csvpath-0.0.478 → csvpath-0.0.480}/csvpath/util/printer.py +0 -0
  140. {csvpath-0.0.478 → csvpath-0.0.480}/docs/asbool.md +0 -0
  141. {csvpath-0.0.478 → csvpath-0.0.480}/docs/assignment.md +0 -0
  142. {csvpath-0.0.478 → csvpath-0.0.480}/docs/comments.md +0 -0
  143. {csvpath-0.0.478 → csvpath-0.0.480}/docs/examples.md +0 -0
  144. {csvpath-0.0.478 → csvpath-0.0.480}/docs/files.md +0 -0
  145. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/above.md +0 -0
  146. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/advance.md +0 -0
  147. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/after_blank.md +0 -0
  148. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/all.md +0 -0
  149. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/andor.md +0 -0
  150. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/any.md +0 -0
  151. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/average.md +0 -0
  152. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/between.md +0 -0
  153. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/collect.md +0 -0
  154. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/correlate.md +0 -0
  155. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/count.md +0 -0
  156. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/count_headers.md +0 -0
  157. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/counter.md +0 -0
  158. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/date.md +0 -0
  159. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/empty.md +0 -0
  160. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/empty_stack.md +0 -0
  161. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/end.md +0 -0
  162. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/every.md +0 -0
  163. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/fail.md +0 -0
  164. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/first.md +0 -0
  165. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/get.md +0 -0
  166. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/has_dups.md +0 -0
  167. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/has_matches.md +0 -0
  168. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/header.md +0 -0
  169. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/header_name.md +0 -0
  170. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/header_names_mismatch.md +0 -0
  171. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/implementing_functions.md +0 -0
  172. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/import.md +0 -0
  173. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/in.md +0 -0
  174. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/increment.md +0 -0
  175. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/jinja.md +0 -0
  176. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/last.md +0 -0
  177. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/line_number.md +0 -0
  178. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/max.md +0 -0
  179. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/metaphone.md +0 -0
  180. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/mismatch.md +0 -0
  181. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/no.md +0 -0
  182. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/not.md +0 -0
  183. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/now.md +0 -0
  184. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/percent_unique.md +0 -0
  185. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/pop.md +0 -0
  186. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/print.md +0 -0
  187. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/print_line.md +0 -0
  188. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/print_queue.md +0 -0
  189. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/random.md +0 -0
  190. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/regex.md +0 -0
  191. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/replace.md +0 -0
  192. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/reset_headers.md +0 -0
  193. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/stdev.md +0 -0
  194. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/stop.md +0 -0
  195. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/subtotal.md +0 -0
  196. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/subtract.md +0 -0
  197. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/sum.md +0 -0
  198. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/tally.md +0 -0
  199. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/total_lines.md +0 -0
  200. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/track.md +0 -0
  201. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/variables.md +0 -0
  202. {csvpath-0.0.478 → csvpath-0.0.480}/docs/functions/variables_and_headers.md +0 -0
  203. {csvpath-0.0.478 → csvpath-0.0.480}/docs/grammar.md +0 -0
  204. {csvpath-0.0.478 → csvpath-0.0.480}/docs/headers.md +0 -0
  205. {csvpath-0.0.478 → csvpath-0.0.480}/docs/images/logo-wordmark-white-on-black-trimmed-padded.png +0 -0
  206. {csvpath-0.0.478 → csvpath-0.0.480}/docs/images/logo-wordmark-white-trimmed.png +0 -0
  207. {csvpath-0.0.478 → csvpath-0.0.480}/docs/paths.md +0 -0
  208. {csvpath-0.0.478 → csvpath-0.0.480}/docs/printing.md +0 -0
  209. {csvpath-0.0.478 → csvpath-0.0.480}/docs/references.md +0 -0
  210. {csvpath-0.0.478 → csvpath-0.0.480}/docs/terms.md +0 -0
  211. {csvpath-0.0.478 → csvpath-0.0.480}/docs/variables.md +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: csvpath
3
- Version: 0.0.478
3
+ Version: 0.0.480
4
4
  Summary: A declarative language for data extraction and validation of CSV files
5
5
  Author: David Kershaw
6
6
  Author-email: dk107dk@hotmail.com
@@ -5,7 +5,7 @@ extensions = txt, csvpath, csvpaths
5
5
  extensions = txt, csv, tsv, dat, tab, psv, ssv
6
6
 
7
7
  [errors]
8
- csvpath = raise, collect, stop, fail
8
+ csvpath = raise, collect, stop, fail, print
9
9
  csvpaths = raise, collect
10
10
 
11
11
  [logging]
@@ -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 argset {self.argset_number}"
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
- mismatches.append(
271
- f"Values received {actuals} are too few for argset {self.argset_number}"
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
- msg = "Wrong type or number of args."
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 arguments in {self.matchable.name} because it has the notnone qualifier"
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
- c = ""
374
- if mismatch_count == 1:
375
- c = "all"
376
- elif mismatch_count == 2:
377
- c = "both"
378
- else:
379
- c = f"all {mismatch_count}"
380
- pm = f"mismatches with args expectations in {self.matchable.name} for {c} arg sets: {mismatches}"
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)
@@ -37,4 +37,4 @@ class Date(ValueProducer):
37
37
  self.value = d
38
38
 
39
39
  def _decide_match(self, skip=None) -> None:
40
- self.match = self.default_match() # pragma: no cover
40
+ self.match = self.to_value(skip=skip) is not None # pragma: no cover
@@ -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
- if len(self.children) > 0:
24
- raise ChildrenException(f"Function {self.name} cannot have arguments")
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":
@@ -24,7 +24,7 @@ class FunctionFinder:
24
24
  f"[functions][imports] path in {config.configpath} does not exist"
25
25
  )
26
26
  return
27
- with open(path, "r") as file:
27
+ with open(path, "r", encoding="utf-8") as file:
28
28
  i = 0
29
29
  for line in file:
30
30
  i += 1
@@ -22,7 +22,7 @@ class FirstLine(MatchDecider):
22
22
  super().check_valid()
23
23
 
24
24
  def _produce_value(self, skip=None) -> None:
25
- self.value = self.match(skip=skip)
25
+ self.value = self.matches(skip=skip)
26
26
 
27
27
  def _decide_match(self, skip=None) -> None:
28
28
  t = self.name
@@ -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, str, float])
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, str])
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, str, int, float, bool],
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.match = False
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(types=[Term, Variable, Header, Function, Reference], actuals=[str])
17
- a.arg(types=[Term, Variable, Header, Function, Reference], actuals=[str])
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
- if isinstance(left, Term):
23
- restr = left.to_value()
24
- re.compile(restr)
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
- regex = siblings[0]
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
- cn = str(self.__class__)
37
- name = cn[(cn.rfind(".") + 1) :]
38
- name = name[0 : name.rfind("'>")]
39
- return name
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(Exception):
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(Exception):
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 error.error
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. Quiet and raise do not coexist well. Raise will win because seeing problems lets you fix them.
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
- Same as you would expect.
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
- Same as you would expect.
40
+ Uppercases a string.
37
41
 
38
42
  ## Examples
39
43