csvpath 0.0.482__tar.gz → 0.0.484__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 (223) hide show
  1. {csvpath-0.0.482 → csvpath-0.0.484}/PKG-INFO +2 -2
  2. {csvpath-0.0.482 → csvpath-0.0.484}/README.md +0 -1
  3. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/csvpath.py +20 -9
  4. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/csvpaths.py +100 -94
  5. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/managers/file_manager.py +11 -2
  6. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/managers/result.py +10 -2
  7. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/args.py +16 -9
  8. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/boolean/all.py +3 -1
  9. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/boolean/andf.py +3 -7
  10. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/boolean/any.py +3 -3
  11. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/boolean/empty.py +2 -26
  12. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/boolean/inf.py +2 -2
  13. csvpath-0.0.484/csvpath/matching/functions/boolean/orf.py +57 -0
  14. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/counting/count.py +2 -5
  15. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/counting/every.py +2 -2
  16. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/counting/increment.py +3 -3
  17. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/counting/tally.py +2 -8
  18. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/dates/now.py +2 -4
  19. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/function.py +5 -3
  20. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/function_factory.py +11 -8
  21. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/headers/collect.py +1 -1
  22. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/headers/end.py +1 -5
  23. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/headers/reset_headers.py +4 -2
  24. {csvpath-0.0.482/csvpath/matching/functions/types → csvpath-0.0.484/csvpath/matching/functions/math}/intf.py +6 -4
  25. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/print/jinjaf.py +1 -1
  26. csvpath-0.0.484/csvpath/matching/functions/types/__init__.py +7 -0
  27. csvpath-0.0.484/csvpath/matching/functions/types/boolean.py +49 -0
  28. csvpath-0.0.484/csvpath/matching/functions/types/datef.py +138 -0
  29. csvpath-0.0.484/csvpath/matching/functions/types/decimal.py +92 -0
  30. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/types/nonef.py +28 -3
  31. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/types/string.py +8 -6
  32. csvpath-0.0.484/csvpath/matching/functions/validity/line.py +166 -0
  33. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/variables/get.py +4 -1
  34. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/variables/pushpop.py +1 -1
  35. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/matcher.py +45 -3
  36. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/productions/matchable.py +14 -1
  37. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/productions/qualified.py +1 -1
  38. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/util/expression_utility.py +32 -9
  39. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/util/error.py +5 -30
  40. csvpath-0.0.484/csvpath/util/file_readers.py +70 -0
  41. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/util/line_counter.py +21 -20
  42. {csvpath-0.0.482 → csvpath-0.0.484}/docs/comments.md +2 -2
  43. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/header_names_mismatch.md +2 -0
  44. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/line.md +2 -2
  45. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/now.md +5 -0
  46. csvpath-0.0.484/docs/functions/types.md +48 -0
  47. {csvpath-0.0.482 → csvpath-0.0.484}/pyproject.toml +2 -1
  48. csvpath-0.0.482/csvpath/matching/functions/boolean/orf.py +0 -37
  49. csvpath-0.0.482/csvpath/matching/functions/types/boolean.py +0 -31
  50. csvpath-0.0.482/csvpath/matching/functions/types/datef.py +0 -40
  51. csvpath-0.0.482/csvpath/matching/functions/validity/line.py +0 -92
  52. {csvpath-0.0.482 → csvpath-0.0.484}/LICENSE +0 -0
  53. {csvpath-0.0.482 → csvpath-0.0.484}/config/config.ini +0 -0
  54. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/__init__.py +0 -0
  55. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/managers/__init__.py +0 -0
  56. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/managers/csvpaths_manager.py +0 -0
  57. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/managers/results_manager.py +0 -0
  58. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/__init__.py +0 -0
  59. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/__init__.py +0 -0
  60. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/boolean/between.py +0 -0
  61. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/boolean/exists.py +0 -0
  62. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/boolean/no.py +0 -0
  63. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/boolean/notf.py +0 -0
  64. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/boolean/yes.py +0 -0
  65. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/counting/count_headers.py +0 -0
  66. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/counting/count_lines.py +0 -0
  67. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/counting/count_scans.py +0 -0
  68. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/counting/counter.py +0 -0
  69. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/counting/has_matches.py +0 -0
  70. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/counting/total_lines.py +0 -0
  71. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/function_finder.py +0 -0
  72. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/function_focus.py +0 -0
  73. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/headers/append.py +0 -0
  74. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/headers/empty_stack.py +0 -0
  75. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/headers/header_name.py +0 -0
  76. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/headers/header_names_mismatch.py +0 -0
  77. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/headers/headers.py +0 -0
  78. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/headers/mismatch.py +0 -0
  79. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/headers/replace.py +0 -0
  80. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/lines/advance.py +0 -0
  81. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/lines/after_blank.py +0 -0
  82. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/lines/dups.py +0 -0
  83. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/lines/first.py +0 -0
  84. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/lines/first_line.py +0 -0
  85. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/lines/last.py +0 -0
  86. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/lines/stop.py +0 -0
  87. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/math/above.py +0 -0
  88. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/math/add.py +0 -0
  89. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/math/divide.py +0 -0
  90. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/math/equals.py +0 -0
  91. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/math/mod.py +0 -0
  92. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/math/multiply.py +0 -0
  93. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/math/round.py +0 -0
  94. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/math/subtotal.py +0 -0
  95. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/math/subtract.py +0 -0
  96. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/math/sum.py +0 -0
  97. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/misc/importf.py +0 -0
  98. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/misc/random.py +0 -0
  99. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/print/print_line.py +0 -0
  100. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/print/print_queue.py +0 -0
  101. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/print/printf.py +0 -0
  102. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/print/table.py +0 -0
  103. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/stats/minf.py +0 -0
  104. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/stats/percent.py +0 -0
  105. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/stats/percent_unique.py +0 -0
  106. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/stats/stdev.py +0 -0
  107. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/strings/concat.py +0 -0
  108. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/strings/length.py +0 -0
  109. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/strings/lower.py +0 -0
  110. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/strings/metaphone.py +0 -0
  111. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/strings/regex.py +0 -0
  112. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/strings/starts_with.py +0 -0
  113. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/strings/strip.py +0 -0
  114. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/strings/substring.py +0 -0
  115. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/strings/upper.py +0 -0
  116. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/testing/debug.py +0 -0
  117. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/validity/fail.py +0 -0
  118. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/validity/failed.py +0 -0
  119. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/variables/put.py +0 -0
  120. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/variables/track.py +0 -0
  121. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/functions/variables/variables.py +0 -0
  122. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/lark_parser.py +0 -0
  123. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/lark_transformer.py +0 -0
  124. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/productions/__init__.py +0 -0
  125. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/productions/equality.py +0 -0
  126. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/productions/expression.py +0 -0
  127. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/productions/header.py +0 -0
  128. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/productions/reference.py +0 -0
  129. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/productions/term.py +0 -0
  130. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/productions/variable.py +0 -0
  131. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/util/exceptions.py +0 -0
  132. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/util/expression_encoder.py +0 -0
  133. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/util/lark_print_parser.py +0 -0
  134. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/matching/util/print_parser.py +0 -0
  135. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/scanning/__init__.py +0 -0
  136. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/scanning/exceptions.py +0 -0
  137. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/scanning/parser.out +0 -0
  138. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/scanning/parsetab.py +0 -0
  139. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/scanning/scanner.py +0 -0
  140. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/scanning/scanning_lexer.py +0 -0
  141. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/util/cache.py +0 -0
  142. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/util/config.py +0 -0
  143. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/util/config_exception.py +0 -0
  144. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/util/exceptions.py +0 -0
  145. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/util/last_line_stats.py +0 -0
  146. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/util/line_monitor.py +0 -0
  147. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/util/log_utility.py +0 -0
  148. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/util/metadata_parser.py +0 -0
  149. {csvpath-0.0.482 → csvpath-0.0.484}/csvpath/util/printer.py +0 -0
  150. {csvpath-0.0.482 → csvpath-0.0.484}/docs/asbool.md +0 -0
  151. {csvpath-0.0.482 → csvpath-0.0.484}/docs/assignment.md +0 -0
  152. {csvpath-0.0.482 → csvpath-0.0.484}/docs/config.md +0 -0
  153. {csvpath-0.0.482 → csvpath-0.0.484}/docs/examples.md +0 -0
  154. {csvpath-0.0.482 → csvpath-0.0.484}/docs/files.md +0 -0
  155. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/above.md +0 -0
  156. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/advance.md +0 -0
  157. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/after_blank.md +0 -0
  158. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/all.md +0 -0
  159. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/andor.md +0 -0
  160. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/any.md +0 -0
  161. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/average.md +0 -0
  162. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/between.md +0 -0
  163. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/collect.md +0 -0
  164. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/correlate.md +0 -0
  165. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/count.md +0 -0
  166. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/count_headers.md +0 -0
  167. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/counter.md +0 -0
  168. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/date.md +0 -0
  169. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/empty.md +0 -0
  170. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/empty_stack.md +0 -0
  171. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/end.md +0 -0
  172. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/every.md +0 -0
  173. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/fail.md +0 -0
  174. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/first.md +0 -0
  175. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/get.md +0 -0
  176. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/has_dups.md +0 -0
  177. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/has_matches.md +0 -0
  178. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/header.md +0 -0
  179. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/header_name.md +0 -0
  180. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/implementing_functions.md +0 -0
  181. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/import.md +0 -0
  182. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/in.md +0 -0
  183. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/increment.md +0 -0
  184. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/intf.md +0 -0
  185. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/jinja.md +0 -0
  186. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/last.md +0 -0
  187. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/line_number.md +0 -0
  188. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/max.md +0 -0
  189. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/metaphone.md +0 -0
  190. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/mismatch.md +0 -0
  191. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/no.md +0 -0
  192. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/not.md +0 -0
  193. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/percent_unique.md +0 -0
  194. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/pop.md +0 -0
  195. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/print.md +0 -0
  196. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/print_line.md +0 -0
  197. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/print_queue.md +0 -0
  198. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/random.md +0 -0
  199. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/regex.md +0 -0
  200. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/replace.md +0 -0
  201. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/reset_headers.md +0 -0
  202. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/stdev.md +0 -0
  203. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/stop.md +0 -0
  204. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/string_functions.md +0 -0
  205. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/subtotal.md +0 -0
  206. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/subtract.md +0 -0
  207. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/sum.md +0 -0
  208. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/tally.md +0 -0
  209. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/total_lines.md +0 -0
  210. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/track.md +0 -0
  211. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/variables.md +0 -0
  212. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions/variables_and_headers.md +0 -0
  213. {csvpath-0.0.482 → csvpath-0.0.484}/docs/functions.md +0 -0
  214. {csvpath-0.0.482 → csvpath-0.0.484}/docs/grammar.md +0 -0
  215. {csvpath-0.0.482 → csvpath-0.0.484}/docs/headers.md +0 -0
  216. {csvpath-0.0.482 → csvpath-0.0.484}/docs/images/logo-wordmark-white-on-black-trimmed-padded.png +0 -0
  217. {csvpath-0.0.482 → csvpath-0.0.484}/docs/images/logo-wordmark-white-trimmed.png +0 -0
  218. {csvpath-0.0.482 → csvpath-0.0.484}/docs/paths.md +0 -0
  219. {csvpath-0.0.482 → csvpath-0.0.484}/docs/printing.md +0 -0
  220. {csvpath-0.0.482 → csvpath-0.0.484}/docs/qualifiers.md +0 -0
  221. {csvpath-0.0.482 → csvpath-0.0.484}/docs/references.md +0 -0
  222. {csvpath-0.0.482 → csvpath-0.0.484}/docs/terms.md +0 -0
  223. {csvpath-0.0.482 → csvpath-0.0.484}/docs/variables.md +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: csvpath
3
- Version: 0.0.482
3
+ Version: 0.0.484
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
@@ -26,6 +26,7 @@ Requires-Dist: jinja2 (>=3.1.4,<4.0.0)
26
26
  Requires-Dist: lark (>=1.2.2,<2.0.0)
27
27
  Requires-Dist: metaphone (>=0.6,<0.7)
28
28
  Requires-Dist: ply (>=3.11,<4.0)
29
+ Requires-Dist: pylightxl (>=1.61,<2.0)
29
30
  Requires-Dist: python-dateutil (>=2.9.0.post0,<3.0.0)
30
31
  Requires-Dist: tabulate (>=0.9.0,<0.10.0)
31
32
  Project-URL: Csvpath.org, https://www.csvpath.org
@@ -48,7 +49,6 @@ And do it all in an automation-friendly way.
48
49
  Though much simpler, it is inspired by:
49
50
  - XPath. CsvPath is to CSV files like XPath is to XML files.
50
51
  - Validation of XML using <a href='https://schematron.com/'>Schematron rules</a>
51
- - The way CSS selectors pick out HTML structures
52
52
 
53
53
  CsvPath is intended to fit with other DataOps and data quality tools. Files are streamed. The interface is simple. New functions are easy to create.
54
54
 
@@ -14,7 +14,6 @@ And do it all in an automation-friendly way.
14
14
  Though much simpler, it is inspired by:
15
15
  - XPath. CsvPath is to CSV files like XPath is to XML files.
16
16
  - Validation of XML using <a href='https://schematron.com/'>Schematron rules</a>
17
- - The way CSS selectors pick out HTML structures
18
17
 
19
18
  CsvPath is intended to fit with other DataOps and data quality tools. Files are streamed. The interface is simple. New functions are easy to create.
20
19
 
@@ -14,7 +14,7 @@ from csvpath.util.log_utility import LogUtility
14
14
  from .matching.matcher import Matcher
15
15
  from .scanning.scanner import Scanner
16
16
  from .util.metadata_parser import MetadataParser
17
- from .util.error import Error, ErrorCollector
17
+ from .util.error import Error, ErrorCollector, ErrorCommsManager
18
18
  from .util.printer import StdOutPrinter
19
19
  from .util.line_counter import LineCounter
20
20
  from .util.exceptions import VariableException, InputException, ParsingException
@@ -26,6 +26,7 @@ from .util.exceptions import (
26
26
  )
27
27
  from .matching.util.exceptions import MatchException
28
28
  from csvpath.util.printer import Printer
29
+ from csvpath.util.file_readers import CsvDataFileReader
29
30
 
30
31
 
31
32
  class CsvPathPublic(ABC):
@@ -262,6 +263,10 @@ class CsvPath(CsvPathPublic, ErrorCollector, Printer): # pylint: disable=R0902,
262
263
  #
263
264
  self.logger = LogUtility.logger(self)
264
265
  self.logger.info("initialized CsvPath")
266
+ self._ecoms = ErrorCommsManager(csvpath=self)
267
+
268
+ def do_i_raise(self) -> bool:
269
+ return self._ecoms.do_i_raise()
265
270
 
266
271
  @property
267
272
  def advance_count(self) -> int: # pragma: no cover
@@ -569,7 +574,7 @@ class CsvPath(CsvPathPublic, ErrorCollector, Printer): # pylint: disable=R0902,
569
574
  #
570
575
  # settings:
571
576
  # - logic-mode: AND | OR
572
- # - match-mode: matches | no-matches
577
+ # - return-mode: matches | no-matches
573
578
  # - print-mode: default | no-default
574
579
  # - validation-mode: (no-)print | log | (no-)raise | quiet | (no-)match
575
580
  #
@@ -606,15 +611,15 @@ class CsvPath(CsvPathPublic, ErrorCollector, Printer): # pylint: disable=R0902,
606
611
  )
607
612
 
608
613
  def update_match_mode_if(self) -> None:
609
- if "match-mode" in self.metadata:
610
- if f"{self.metadata['match-mode']}".strip() == "matches":
614
+ if "return-mode" in self.metadata:
615
+ if f"{self.metadata['return-mode']}".strip() == "matches":
611
616
  self.collect_when_not_matched = False
612
- elif f"{self.metadata['match-mode']}".strip() == "no-matches":
617
+ elif f"{self.metadata['return-mode']}".strip() == "no-matches":
613
618
  self.collect_when_not_matched = True
614
619
  else:
615
620
  self.logger.warning(
616
- "Incorrect metadata field value 'match-mode': %s",
617
- self.metadata["match-mode"],
621
+ "Incorrect metadata field value 'return-mode': %s",
622
+ self.metadata["return-mode"],
618
623
  )
619
624
 
620
625
  def update_print_mode_if(self) -> None:
@@ -891,13 +896,19 @@ class CsvPath(CsvPathPublic, ErrorCollector, Printer): # pylint: disable=R0902,
891
896
  #
892
897
  if self.scanner.filename is None:
893
898
  raise FileException("There is no filename")
899
+ """
894
900
  with open(self.scanner.filename, "r", encoding="utf-8") as file:
895
901
  reader = csv.reader(
896
902
  file, delimiter=self.delimiter, quotechar=self.quotechar
897
903
  )
898
904
  for line in reader:
899
- self.track_line(line=line)
900
- yield line
905
+ """
906
+ reader = CsvDataFileReader(
907
+ self.scanner.filename, delimiter=self.delimiter, quotechar=self.quotechar
908
+ )
909
+ for line in reader.next():
910
+ self.track_line(line=line)
911
+ yield line
901
912
  self.finalize()
902
913
 
903
914
  """
@@ -273,14 +273,14 @@ class CsvPaths(CsvPathsPublic, CsvPathsCoordinator, ErrorCollector):
273
273
  self.logger.info("Cleaning out any %s and %s results", filename, pathsname)
274
274
  self.clean(paths=pathsname)
275
275
  self.logger.info(
276
- "Beginning fast_forward_paths %s with %s paths against file %s",
276
+ "Beginning FF %s with %s paths against file %s. No match results will be held.",
277
277
  pathsname,
278
278
  len(paths),
279
279
  filename,
280
280
  )
281
281
  for i, path in enumerate(paths):
282
282
  csvpath = self.csvpath()
283
- self.logger.info("Beginning CsvPath instance: %s", csvpath)
283
+ self.logger.debug("Beginning to FF CsvPath instance: %s", csvpath)
284
284
  result = Result(csvpath=csvpath, file_name=filename, paths_name=pathsname)
285
285
  try:
286
286
  self.results_manager.add_named_result(result)
@@ -439,6 +439,7 @@ class CsvPaths(CsvPathsPublic, CsvPathsCoordinator, ErrorCollector):
439
439
  # but we'll do it for consistency.
440
440
  #
441
441
  self.logger.info("Beginning next_by_line with %s paths", len(csvpath_objects))
442
+ """
442
443
  with open(fn, "r", encoding="utf-8") as file:
443
444
  reader = csv.reader(
444
445
  file, delimiter=self.delimiter, quotechar=self.quotechar
@@ -446,105 +447,110 @@ class CsvPaths(CsvPathsPublic, CsvPathsCoordinator, ErrorCollector):
446
447
  #
447
448
  # re: R1702 -- totally agreed! deferring.
448
449
  #
449
- stopped_count: List[int] = []
450
- for line in reader: # pylint: disable=R1702
451
- # question to self: should this default be in a central place
452
- # so that we can switch to OR, in part by changing the default?
453
- keep = if_all_agree
454
- self._skip_all = False
455
- self._advance_all = 0
456
- try:
457
- # p is a (CsvPath, List[List[str]]) where the second item is
458
- # the line-by-line results of the first item's matching
459
- for p in csvpath_objects:
460
- self.current_matcher = p[0]
461
- if self._fail_all:
462
- self.logger.warning(
463
- "Fail-all set. Setting CsvPath is_valid to False."
464
- )
465
- self.current_matcher.is_valid = False
466
- if self._stop_all:
467
- self.logger.warning("Stop-all set. Shutting down run.")
468
- self.current_matcher.stopped = True
469
- continue
470
- if self._skip_all:
471
- self.logger.warning("Skip-all set. Continuing to next.")
472
- #
473
- # all following CsvPaths must have their
474
- # line_monitors incremented
475
- #
476
- self.current_matcher.track_line(line)
477
- continue
478
- if self._advance_all > 0:
479
- logtxt = "Advance-all set. Setting advance. "
480
- logtxt = f"{logtxt}CsvPath and its Matcher will handle the advancing."
481
- self.logger.info(logtxt)
482
- #
483
- # CsvPath will handle advancing so we don't need to do
484
- # anything, including track_line(line). we just need to
485
- # see if we're setting advance or increasing it.
486
- #
487
- a = self.current_matcher.advance_count
488
- if self._advance_all > a:
489
- self.current_matcher.advance_count = self._advance_all
490
- #
491
- # all following CsvPaths must have their
492
- # advance incremented -- with the advance not being simply
493
- # additive, have to be mindful of any existing advance
494
- # count!
495
- #
496
- if self.current_matcher.stopped: # pylint: disable=R1724
497
- continue
498
-
450
+ """
451
+ reader = FileManager.get_reader(
452
+ fn, delimiter=self.delimiter, quotechar=self.quotechar
453
+ )
454
+ stopped_count: List[int] = []
455
+ for line in reader.next():
456
+ # for line in reader: # pylint: disable=R1702
457
+ # question to self: should this default be in a central place
458
+ # so that we can switch to OR, in part by changing the default?
459
+ keep = if_all_agree
460
+ self._skip_all = False
461
+ self._advance_all = 0
462
+ try:
463
+ # p is a (CsvPath, List[List[str]]) where the second item is
464
+ # the line-by-line results of the first item's matching
465
+ for p in csvpath_objects:
466
+ self.current_matcher = p[0]
467
+ if self._fail_all:
468
+ self.logger.warning(
469
+ "Fail-all set. Setting CsvPath is_valid to False."
470
+ )
471
+ self.current_matcher.is_valid = False
472
+ if self._stop_all:
473
+ self.logger.warning("Stop-all set. Shutting down run.")
474
+ self.current_matcher.stopped = True
475
+ continue
476
+ if self._skip_all:
477
+ self.logger.warning("Skip-all set. Continuing to next.")
499
478
  #
500
- # allowing the match to happen regardless of keep
501
- # because we may want side-effects or to have different
502
- # results in different named-results, as well as the
503
- # union
479
+ # all following CsvPaths must have their
480
+ # line_monitors incremented
504
481
  #
505
- self.logger.debug(
506
- "considering line with csvpath identified as: %s",
507
- self.current_matcher.identity,
508
- )
509
- matched = False
510
482
  self.current_matcher.track_line(line)
483
+ continue
484
+ if self._advance_all > 0:
485
+ logtxt = "Advance-all set. Setting advance. "
486
+ logtxt = f"{logtxt}CsvPath and its Matcher will handle the advancing."
487
+ self.logger.info(logtxt)
511
488
  #
512
- # re: W0212: treating _consider_line something like package private
489
+ # CsvPath will handle advancing so we don't need to do
490
+ # anything, including track_line(line). we just need to
491
+ # see if we're setting advance or increasing it.
513
492
  #
514
- matched = (
515
- self.current_matcher._consider_line( # pylint:disable=W0212
516
- line
517
- )
518
- )
519
- if self.current_matcher.stopped:
520
- stopped_count.append(1)
521
- if if_all_agree:
522
- keep = keep and matched
523
- else:
524
- keep = keep or matched
493
+ a = self.current_matcher.advance_count
494
+ if self._advance_all > a:
495
+ self.current_matcher.advance_count = self._advance_all
525
496
  #
526
- # not doing continue if we have if_all_agree and not keep as we
527
- # used to do allows individual results to have lines that in
528
- # aggregate we do not keep.
497
+ # all following CsvPaths must have their
498
+ # advance incremented -- with the advance not being simply
499
+ # additive, have to be mindful of any existing advance
500
+ # count!
529
501
  #
530
- if matched and collect:
531
- line = self.current_matcher.limit_collection(line)
532
- p[1].append(line)
533
- except Exception as ex: # pylint: disable=W0718
534
- ex.trace = traceback.format_exc()
535
- ex.source = self
536
- ErrorHandler(
537
- csvpaths=self, error_collector=self.current_matcher
538
- ).handle_error(ex)
539
- # we yield even if we stopped in this iteration.
540
- # caller needs to see what we stopped on.
541
- #
542
- # ! we only yield if keep is True
543
- #
544
- if keep:
545
- yield line
546
- if sum(stopped_count) == len(csvpath_objects):
547
- break
502
+ if self.current_matcher.stopped: # pylint: disable=R1724
503
+ continue
504
+
505
+ #
506
+ # allowing the match to happen regardless of keep
507
+ # because we may want side-effects or to have different
508
+ # results in different named-results, as well as the
509
+ # union
510
+ #
511
+ self.logger.debug(
512
+ "considering line with csvpath identified as: %s",
513
+ self.current_matcher.identity,
514
+ )
515
+ matched = False
516
+ self.current_matcher.track_line(line)
517
+ #
518
+ # re: W0212: treating _consider_line something like package private
519
+ #
520
+ matched = (
521
+ self.current_matcher._consider_line( # pylint:disable=W0212
522
+ line
523
+ )
524
+ )
525
+ if self.current_matcher.stopped:
526
+ stopped_count.append(1)
527
+ if if_all_agree:
528
+ keep = keep and matched
529
+ else:
530
+ keep = keep or matched
531
+ #
532
+ # not doing continue if we have if_all_agree and not keep as we
533
+ # used to do allows individual results to have lines that in
534
+ # aggregate we do not keep.
535
+ #
536
+ if matched and collect:
537
+ line = self.current_matcher.limit_collection(line)
538
+ p[1].append(line)
539
+ except Exception as ex: # pylint: disable=W0718
540
+ ex.trace = traceback.format_exc()
541
+ ex.source = self
542
+ ErrorHandler(
543
+ csvpaths=self, error_collector=self.current_matcher
544
+ ).handle_error(ex)
545
+ # we yield even if we stopped in this iteration.
546
+ # caller needs to see what we stopped on.
547
+ #
548
+ # ! we only yield if keep is True
549
+ #
550
+ if keep:
551
+ yield line
552
+ if sum(stopped_count) == len(csvpath_objects):
553
+ break
548
554
  self.clear_run_coordination()
549
555
 
550
556
  def _load_csvpath_objects(
@@ -3,13 +3,14 @@ import os
3
3
  import json
4
4
  import csv
5
5
  import hashlib
6
+ from abc import ABC, abstractmethod
6
7
  from json import JSONDecodeError
7
8
  from typing import Dict, List, Tuple
8
- from abc import ABC, abstractmethod
9
9
  from ..util.line_counter import LineCounter
10
10
  from ..util.line_monitor import LineMonitor
11
11
  from ..util.error import ErrorHandler
12
12
  from ..util.cache import Cache
13
+ from ..util.file_readers import CsvDataFileReader
13
14
 
14
15
 
15
16
  class CsvPathsFileManager(ABC):
@@ -53,7 +54,7 @@ class CsvPathsFileManager(ABC):
53
54
 
54
55
 
55
56
  class FileManager(CsvPathsFileManager): # pylint: disable=C0115
56
- def __init__(self, *, named_files: Dict[str, str] = None, csvpaths):
57
+ def __init__(self, *, named_files: Dict[str, str] = None, csvpaths=None):
57
58
  if named_files is None:
58
59
  named_files = {}
59
60
  self.named_files: Dict[str, str] = named_files
@@ -142,6 +143,14 @@ class FileManager(CsvPathsFileManager): # pylint: disable=C0115
142
143
  return None
143
144
  return self.named_files[name]
144
145
 
146
+ def get_named_file_reader(self, name: str) -> CsvDataFileReader:
147
+ path = self.get_named_file(name)
148
+ return FileManager.get_reader(path)
149
+
150
+ @classmethod
151
+ def get_reader(cls, path: str, delimiter=None, quotechar=None) -> CsvDataFileReader:
152
+ return CsvDataFileReader(path, delimiter=delimiter, quotechar=quotechar)
153
+
145
154
  def remove_named_file(self, name: str) -> None:
146
155
  if name in self.named_files:
147
156
  del self.named_files[name]
@@ -163,14 +163,22 @@ class Result(ErrorCollector, Printer): # pylint: disable=R0902
163
163
  return i
164
164
 
165
165
  def __str__(self) -> str:
166
+ lastline = 0
167
+ endline = -1
168
+ try:
169
+ # if we haven't started yet -- common situation -- we may blow up.
170
+ lastline = self.csvpath.line_monitor.physical_line_number
171
+ endline = self.csvpath.line_monitor.physical_end_line_number
172
+ except Exception:
173
+ pass
166
174
  return f"""Result
167
175
  file:{self.csvpath.scanner.filename if self.csvpath.scanner else None};
168
176
  name of paths:{self.paths_name};
169
177
  name of file:{self.file_name};
170
178
  valid:{self.csvpath.is_valid};
171
179
  stopped:{self.csvpath.stopped};
172
- last line processed:{self.csvpath.line_monitor.physical_line_number};
173
- total file lines:{self.csvpath.line_monitor.physical_end_line_number};
180
+ last line processed:{lastline};
181
+ total file lines:{endline};
174
182
  matches:{self.csvpath.match_count};
175
183
  lines captured:{len(self.lines) if self.lines else 0};
176
184
  print statements:{self.print_statements_count()};
@@ -16,9 +16,12 @@ from csvpath.util.config_exception import ConfigurationException
16
16
 
17
17
 
18
18
  class Arg:
19
- def __init__(self, *, types: list[Type] = None, actuals: list[Type] = None):
19
+ def __init__(
20
+ self, *, name: str = None, types: list[Type] = None, actuals: list[Type] = None
21
+ ):
20
22
  self.is_noneable = False
21
23
  self._types = None
24
+ self._name = name
22
25
  self._x_actuals = None
23
26
  self.types: list[Type] = types or [None]
24
27
  self.actuals: list[Type] = actuals or []
@@ -100,8 +103,10 @@ class ArgSet:
100
103
  # setup time
101
104
  # ----------------------------
102
105
 
103
- def arg(self, *, types: list[Type] = None, actuals: list[Type] = None) -> Arg:
104
- arg = Arg(types=types, actuals=actuals)
106
+ def arg(
107
+ self, *, name: str = None, types: list[Type] = None, actuals: list[Type] = None
108
+ ) -> Arg:
109
+ arg = Arg(name=name, types=types, actuals=actuals)
105
110
  self._args.append(arg)
106
111
  if len(self._args) > self.max_length and self.max_length != -1:
107
112
  self.max_length = len(self._args)
@@ -194,16 +199,17 @@ class ArgSet:
194
199
  self._args = args
195
200
  self.max_length = len(self._args)
196
201
 
197
- def validate_structure(self, siblings: List[Matchable]) -> None:
202
+ def validate_structure(self, siblings: List[Matchable]) -> None | str:
198
203
  b = self._validate_length(siblings)
199
204
  if b is False:
200
- return False
205
+ return "incorrect number of args"
201
206
  self._pad_or_shrink(siblings)
202
207
  for i, s in enumerate(siblings):
203
208
  t = tuple(self._args[i].types)
204
209
  if not isinstance(s, t):
205
- return False
206
- return True
210
+ ii = i + 1
211
+ return f"type mismatch at arg {ii}"
212
+ return None
207
213
 
208
214
  # ----------------------------
209
215
  # match actuals line-by-line
@@ -390,11 +396,12 @@ class Args:
390
396
  #
391
397
  good = False
392
398
  for aset in self._argsets:
393
- if aset.validate_structure(siblings):
399
+ _m = aset.validate_structure(siblings)
400
+ if _m is None:
394
401
  good = True
395
402
  if not good:
396
403
  _ = f" at {self.matchable.my_chain}" if self.matchable else ""
397
- msg = f"{self._csvpath_id()} Incorrectly written{_}. Wrong type or number of args."
404
+ msg = f"{self._csvpath_id()} Incorrectly written{_}. Wrong type or number of args: {_m}."
398
405
  raise ChildrenException(msg)
399
406
  self.validated = True
400
407
 
@@ -19,7 +19,9 @@ class All(MatchDecider):
19
19
  self.args = Args(matchable=self)
20
20
  self.args.argset(0)
21
21
  self.args.argset(1).arg(types=[None, Variables, Headers], actuals=[])
22
- self.args.argset().arg(types=[None, Function, Variable, Header], actuals=[])
22
+ self.args.argset().arg(
23
+ types=[None, Function, Variable, Header], actuals=[None, Any]
24
+ )
23
25
  self.args.validate(self.siblings())
24
26
  super().check_valid()
25
27
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  from typing import Any
4
4
  from ..function_focus import MatchDecider
5
- from csvpath.matching.productions import Term, Variable, Header, Reference, Equality
5
+ from csvpath.matching.productions import Matchable
6
6
  from ..function import Function
7
7
  from ..args import Args
8
8
 
@@ -15,12 +15,8 @@ class And(MatchDecider):
15
15
  def check_valid(self) -> None: # pragma: no cover
16
16
  self.args = Args(matchable=self)
17
17
  a = self.args.argset()
18
- a.arg(
19
- types=[Term, Variable, Header, Function, Reference, Equality], actuals=[Any]
20
- )
21
- a.arg(
22
- types=[Term, Variable, Header, Function, Reference, Equality], actuals=[Any]
23
- )
18
+ a.arg(types=[Matchable], actuals=[None, Any])
19
+ a.arg(types=[Matchable], actuals=[None, Any])
24
20
  self.args.validate(self.siblings_or_equality())
25
21
  super().check_valid()
26
22
 
@@ -24,11 +24,11 @@ class Any(MatchDecider):
24
24
  a = self.args.argset(0)
25
25
 
26
26
  a = self.args.argset(2)
27
- a.arg(types=[Variables, Headers], actuals=[Any])
28
- a.arg(types=[typing.Any], actuals=[typing.Any])
27
+ a.arg(types=[Variables, Headers], actuals=[None, typing.Any])
28
+ a.arg(types=[typing.Any], actuals=[None, typing.Any])
29
29
 
30
30
  a = self.args.argset(1)
31
- a.arg(types=[typing.Any, Variables, Headers], actuals=[typing.Any])
31
+ a.arg(types=[typing.Any, Variables, Headers], actuals=[None, typing.Any])
32
32
 
33
33
  self.args.validate(self.siblings())
34
34
  super().check_valid()
@@ -33,7 +33,7 @@ class Empty(MatchDecider):
33
33
  def _validate(self):
34
34
  sibs = self.siblings()
35
35
  for s in sibs:
36
- # both definitely structure / children exceptions
36
+ # both structure / children exceptions
37
37
  if isinstance(s, Headers) and len(sibs) > 1:
38
38
  raise ChildrenException(
39
39
  "If empty() has a headers() argument it can only have 1 argument"
@@ -73,12 +73,7 @@ class Empty(MatchDecider):
73
73
  self.match = ret
74
74
 
75
75
  def _do_many(self, skip=None):
76
- siblings = None
77
- if isinstance(self.children[0], Equality):
78
- siblings = self.children[0].commas_to_list()
79
- else:
80
- siblings = self.children[0]
81
-
76
+ siblings = self.siblings()
82
77
  for s in siblings:
83
78
  self._do_one(s)
84
79
  if self.match is False:
@@ -87,22 +82,3 @@ class Empty(MatchDecider):
87
82
  def _do_one(self, child, skip=None):
88
83
  v = child.to_value(skip=skip)
89
84
  self.match = ExpressionUtility.is_empty(v)
90
-
91
- """
92
- def _is_empty(self, v):
93
- ret = True
94
- if v is None:
95
- ret = True
96
- elif f"{v}".strip() == "":
97
- ret = True
98
- elif isinstance(v, list) or isinstance(v, tuple):
99
- for item in v:
100
- ret = self._is_empty(item)
101
- if not ret:
102
- break
103
- elif isinstance(v, dict):
104
- ret = len(v) > 0
105
- else:
106
- ret = False
107
- return ret
108
- """
@@ -13,8 +13,8 @@ class In(MatchDecider):
13
13
  def check_valid(self) -> None:
14
14
  self.args = Args(matchable=self)
15
15
  a = self.args.argset()
16
- a.arg(types=[Term, Variable, Header, Function, Reference], actuals=[Any])
17
- a.arg(types=[Term, Variable, Header, Function, Reference], actuals=[Any])
16
+ a.arg(types=[Term, Variable, Header, Function, Reference], actuals=[None, Any])
17
+ a.arg(types=[Term, Variable, Header, Function, Reference], actuals=[None, Any])
18
18
  self.args.validate(self.siblings())
19
19
  super().check_valid()
20
20
 
@@ -0,0 +1,57 @@
1
+ # pylint: disable=C0114
2
+ from typing import Any
3
+ from ..function_focus import MatchDecider
4
+ from csvpath.matching.productions import (
5
+ Term,
6
+ Variable,
7
+ Header,
8
+ Reference,
9
+ Equality,
10
+ Matchable,
11
+ )
12
+ from ..function import Function
13
+ from ..args import Args
14
+
15
+
16
+ class Or(MatchDecider):
17
+ """does a logical OR of match components"""
18
+
19
+ def __init__(self, matcher: Any, name: str, child: Matchable = None) -> None:
20
+ super().__init__(matcher, name=name, child=child)
21
+ self.hold = []
22
+
23
+ def reset(self) -> None:
24
+ self.hold = []
25
+ super().reset()
26
+
27
+ def check_valid(self) -> None:
28
+ self.args = Args(matchable=self)
29
+ a = self.args.argset()
30
+ a.arg(types=[Matchable], actuals=[None, Any])
31
+ a.arg(types=[Matchable], actuals=[None, Any])
32
+ self.args.validate(self.siblings_or_equality())
33
+ super().check_valid()
34
+
35
+ def raise_if(self, e, *, cause=None) -> None:
36
+ # not bubbling up until we know we don't have a
37
+ # match on all options
38
+ self.hold.append((e, cause))
39
+
40
+ def _produce_value(self, skip=None) -> None:
41
+ self.value = self.matches(skip=skip)
42
+
43
+ def _decide_match(self, skip=None) -> None:
44
+ child = self.children[0]
45
+ siblings = child.commas_to_list()
46
+ for sib in siblings:
47
+ b = sib.matches(skip=skip)
48
+ if b:
49
+ self.match = True
50
+ # if we find a True we succeed and dump any errors
51
+ self.hold = []
52
+ return
53
+ self.match = False
54
+ # if we fail we progress any errors up the stack
55
+ for err in self.hold:
56
+ super().raise_if(err[0], cause=err[1])
57
+ self.hold = []
@@ -3,7 +3,7 @@ from typing import Any
3
3
  from ..function_focus import ValueProducer
4
4
  from ..function import Function
5
5
  from ..args import Args
6
- from csvpath.matching.productions import Equality, Variable, Header, Term
6
+ from csvpath.matching.productions import Matchable
7
7
 
8
8
 
9
9
  class Count(ValueProducer):
@@ -16,10 +16,7 @@ class Count(ValueProducer):
16
16
  self.args = Args(matchable=self)
17
17
  a = self.args.argset(0)
18
18
  a = self.args.argset()
19
- a.arg(
20
- types=[None, Variable, Function, Header, Term, Equality],
21
- actuals=[None, Any],
22
- )
19
+ a.arg(types=[None, Matchable], actuals=[None, Any])
23
20
  self.args.validate(self.siblings())
24
21
  #
25
22
  super().check_valid() # pylint: disable=W0246