csvpath 0.0.484__tar.gz → 0.0.485__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 (220) hide show
  1. {csvpath-0.0.484 → csvpath-0.0.485}/PKG-INFO +5 -5
  2. {csvpath-0.0.484 → csvpath-0.0.485}/README.md +2 -2
  3. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/csvpath.py +148 -37
  4. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/csvpaths.py +4 -2
  5. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/managers/csvpaths_manager.py +31 -5
  6. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/args.py +19 -8
  7. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/boolean/any.py +1 -1
  8. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/boolean/empty.py +2 -2
  9. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/function.py +41 -8
  10. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/lines/first_line.py +2 -2
  11. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/math/sum.py +1 -1
  12. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/misc/importf.py +10 -3
  13. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/stats/percent.py +1 -1
  14. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/strings/regex.py +1 -1
  15. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/types/datef.py +10 -18
  16. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/types/decimal.py +6 -8
  17. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/validity/failed.py +1 -1
  18. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/validity/line.py +7 -11
  19. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/matcher.py +92 -0
  20. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/productions/equality.py +27 -4
  21. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/productions/expression.py +3 -1
  22. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/productions/header.py +6 -2
  23. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/productions/matchable.py +44 -0
  24. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/productions/reference.py +53 -15
  25. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/productions/variable.py +9 -2
  26. {csvpath-0.0.484 → csvpath-0.0.485}/docs/comments.md +4 -0
  27. csvpath-0.0.485/docs/functions/import.md +95 -0
  28. {csvpath-0.0.484 → csvpath-0.0.485}/pyproject.toml +3 -3
  29. csvpath-0.0.484/docs/functions/import.md +0 -47
  30. {csvpath-0.0.484 → csvpath-0.0.485}/LICENSE +0 -0
  31. {csvpath-0.0.484 → csvpath-0.0.485}/config/config.ini +0 -0
  32. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/__init__.py +0 -0
  33. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/managers/__init__.py +0 -0
  34. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/managers/file_manager.py +0 -0
  35. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/managers/result.py +0 -0
  36. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/managers/results_manager.py +0 -0
  37. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/__init__.py +0 -0
  38. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/__init__.py +0 -0
  39. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/boolean/all.py +0 -0
  40. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/boolean/andf.py +0 -0
  41. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/boolean/between.py +0 -0
  42. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/boolean/exists.py +0 -0
  43. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/boolean/inf.py +0 -0
  44. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/boolean/no.py +0 -0
  45. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/boolean/notf.py +0 -0
  46. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/boolean/orf.py +0 -0
  47. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/boolean/yes.py +0 -0
  48. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/counting/count.py +0 -0
  49. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/counting/count_headers.py +0 -0
  50. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/counting/count_lines.py +0 -0
  51. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/counting/count_scans.py +0 -0
  52. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/counting/counter.py +0 -0
  53. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/counting/every.py +0 -0
  54. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/counting/has_matches.py +0 -0
  55. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/counting/increment.py +0 -0
  56. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/counting/tally.py +0 -0
  57. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/counting/total_lines.py +0 -0
  58. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/dates/now.py +0 -0
  59. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/function_factory.py +0 -0
  60. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/function_finder.py +0 -0
  61. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/function_focus.py +0 -0
  62. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/headers/append.py +0 -0
  63. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/headers/collect.py +0 -0
  64. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/headers/empty_stack.py +0 -0
  65. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/headers/end.py +0 -0
  66. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/headers/header_name.py +0 -0
  67. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/headers/header_names_mismatch.py +0 -0
  68. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/headers/headers.py +0 -0
  69. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/headers/mismatch.py +0 -0
  70. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/headers/replace.py +0 -0
  71. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/headers/reset_headers.py +0 -0
  72. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/lines/advance.py +0 -0
  73. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/lines/after_blank.py +0 -0
  74. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/lines/dups.py +0 -0
  75. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/lines/first.py +0 -0
  76. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/lines/last.py +0 -0
  77. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/lines/stop.py +0 -0
  78. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/math/above.py +0 -0
  79. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/math/add.py +0 -0
  80. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/math/divide.py +0 -0
  81. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/math/equals.py +0 -0
  82. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/math/intf.py +0 -0
  83. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/math/mod.py +0 -0
  84. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/math/multiply.py +0 -0
  85. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/math/round.py +0 -0
  86. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/math/subtotal.py +0 -0
  87. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/math/subtract.py +0 -0
  88. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/misc/random.py +0 -0
  89. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/print/jinjaf.py +0 -0
  90. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/print/print_line.py +0 -0
  91. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/print/print_queue.py +0 -0
  92. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/print/printf.py +0 -0
  93. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/print/table.py +0 -0
  94. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/stats/minf.py +0 -0
  95. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/stats/percent_unique.py +0 -0
  96. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/stats/stdev.py +0 -0
  97. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/strings/concat.py +0 -0
  98. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/strings/length.py +0 -0
  99. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/strings/lower.py +0 -0
  100. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/strings/metaphone.py +0 -0
  101. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/strings/starts_with.py +0 -0
  102. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/strings/strip.py +0 -0
  103. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/strings/substring.py +0 -0
  104. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/strings/upper.py +0 -0
  105. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/testing/debug.py +0 -0
  106. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/types/__init__.py +0 -0
  107. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/types/boolean.py +0 -0
  108. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/types/nonef.py +0 -0
  109. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/types/string.py +0 -0
  110. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/validity/fail.py +0 -0
  111. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/variables/get.py +0 -0
  112. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/variables/pushpop.py +0 -0
  113. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/variables/put.py +0 -0
  114. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/variables/track.py +0 -0
  115. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/functions/variables/variables.py +0 -0
  116. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/lark_parser.py +0 -0
  117. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/lark_transformer.py +0 -0
  118. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/productions/__init__.py +0 -0
  119. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/productions/qualified.py +0 -0
  120. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/productions/term.py +0 -0
  121. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/util/exceptions.py +0 -0
  122. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/util/expression_encoder.py +0 -0
  123. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/util/expression_utility.py +0 -0
  124. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/util/lark_print_parser.py +0 -0
  125. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/matching/util/print_parser.py +0 -0
  126. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/scanning/__init__.py +0 -0
  127. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/scanning/exceptions.py +0 -0
  128. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/scanning/parser.out +0 -0
  129. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/scanning/parsetab.py +0 -0
  130. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/scanning/scanner.py +0 -0
  131. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/scanning/scanning_lexer.py +0 -0
  132. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/util/cache.py +0 -0
  133. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/util/config.py +0 -0
  134. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/util/config_exception.py +0 -0
  135. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/util/error.py +0 -0
  136. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/util/exceptions.py +0 -0
  137. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/util/file_readers.py +0 -0
  138. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/util/last_line_stats.py +0 -0
  139. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/util/line_counter.py +0 -0
  140. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/util/line_monitor.py +0 -0
  141. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/util/log_utility.py +0 -0
  142. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/util/metadata_parser.py +0 -0
  143. {csvpath-0.0.484 → csvpath-0.0.485}/csvpath/util/printer.py +0 -0
  144. {csvpath-0.0.484 → csvpath-0.0.485}/docs/asbool.md +0 -0
  145. {csvpath-0.0.484 → csvpath-0.0.485}/docs/assignment.md +0 -0
  146. {csvpath-0.0.484 → csvpath-0.0.485}/docs/config.md +0 -0
  147. {csvpath-0.0.484 → csvpath-0.0.485}/docs/examples.md +0 -0
  148. {csvpath-0.0.484 → csvpath-0.0.485}/docs/files.md +0 -0
  149. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/above.md +0 -0
  150. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/advance.md +0 -0
  151. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/after_blank.md +0 -0
  152. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/all.md +0 -0
  153. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/andor.md +0 -0
  154. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/any.md +0 -0
  155. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/average.md +0 -0
  156. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/between.md +0 -0
  157. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/collect.md +0 -0
  158. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/correlate.md +0 -0
  159. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/count.md +0 -0
  160. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/count_headers.md +0 -0
  161. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/counter.md +0 -0
  162. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/date.md +0 -0
  163. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/empty.md +0 -0
  164. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/empty_stack.md +0 -0
  165. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/end.md +0 -0
  166. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/every.md +0 -0
  167. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/fail.md +0 -0
  168. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/first.md +0 -0
  169. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/get.md +0 -0
  170. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/has_dups.md +0 -0
  171. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/has_matches.md +0 -0
  172. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/header.md +0 -0
  173. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/header_name.md +0 -0
  174. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/header_names_mismatch.md +0 -0
  175. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/implementing_functions.md +0 -0
  176. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/in.md +0 -0
  177. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/increment.md +0 -0
  178. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/intf.md +0 -0
  179. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/jinja.md +0 -0
  180. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/last.md +0 -0
  181. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/line.md +0 -0
  182. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/line_number.md +0 -0
  183. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/max.md +0 -0
  184. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/metaphone.md +0 -0
  185. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/mismatch.md +0 -0
  186. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/no.md +0 -0
  187. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/not.md +0 -0
  188. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/now.md +0 -0
  189. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/percent_unique.md +0 -0
  190. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/pop.md +0 -0
  191. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/print.md +0 -0
  192. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/print_line.md +0 -0
  193. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/print_queue.md +0 -0
  194. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/random.md +0 -0
  195. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/regex.md +0 -0
  196. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/replace.md +0 -0
  197. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/reset_headers.md +0 -0
  198. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/stdev.md +0 -0
  199. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/stop.md +0 -0
  200. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/string_functions.md +0 -0
  201. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/subtotal.md +0 -0
  202. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/subtract.md +0 -0
  203. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/sum.md +0 -0
  204. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/tally.md +0 -0
  205. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/total_lines.md +0 -0
  206. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/track.md +0 -0
  207. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/types.md +0 -0
  208. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/variables.md +0 -0
  209. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions/variables_and_headers.md +0 -0
  210. {csvpath-0.0.484 → csvpath-0.0.485}/docs/functions.md +0 -0
  211. {csvpath-0.0.484 → csvpath-0.0.485}/docs/grammar.md +0 -0
  212. {csvpath-0.0.484 → csvpath-0.0.485}/docs/headers.md +0 -0
  213. {csvpath-0.0.484 → csvpath-0.0.485}/docs/images/logo-wordmark-white-on-black-trimmed-padded.png +0 -0
  214. {csvpath-0.0.484 → csvpath-0.0.485}/docs/images/logo-wordmark-white-trimmed.png +0 -0
  215. {csvpath-0.0.484 → csvpath-0.0.485}/docs/paths.md +0 -0
  216. {csvpath-0.0.484 → csvpath-0.0.485}/docs/printing.md +0 -0
  217. {csvpath-0.0.484 → csvpath-0.0.485}/docs/qualifiers.md +0 -0
  218. {csvpath-0.0.484 → csvpath-0.0.485}/docs/references.md +0 -0
  219. {csvpath-0.0.484 → csvpath-0.0.485}/docs/terms.md +0 -0
  220. {csvpath-0.0.484 → csvpath-0.0.485}/docs/variables.md +0 -0
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: csvpath
3
- Version: 0.0.484
4
- Summary: A declarative language for data extraction and validation of CSV files
3
+ Version: 0.0.485
4
+ Summary: A declarative language for validation of CSV files
5
5
  Author: David Kershaw
6
6
  Author-email: dk107dk@hotmail.com
7
7
  Requires-Python: >=3.9,<4.0
@@ -30,7 +30,7 @@ Requires-Dist: pylightxl (>=1.61,<2.0)
30
30
  Requires-Dist: python-dateutil (>=2.9.0.post0,<3.0.0)
31
31
  Requires-Dist: tabulate (>=0.9.0,<0.10.0)
32
32
  Project-URL: Csvpath.org, https://www.csvpath.org
33
- Project-URL: Github, https://github.com/dk107dk/csvpath
33
+ Project-URL: Github, https://github.com/csvpath/csvpath.git
34
34
  Description-Content-Type: text/markdown
35
35
 
36
36
 
@@ -141,12 +141,12 @@ Interactive use of csvpaths can be valuable, too, of course. There is a trivial
141
141
  <a name="running"></a>
142
142
  ## Running CsvPath
143
143
 
144
- CsvPath is <a href='https://pypi.org/project/csvpath/'>available on Pypi here</a>. The <a href='https://github.com/dk107dk/csvpath'>git repo is here</a>.
144
+ CsvPath is <a href='https://pypi.org/project/csvpath/'>available on Pypi here</a>. The <a href='https://github.com/csvpath/csvpath'>git repo is here</a>.
145
145
 
146
146
  Two classes provide the functionality: CsvPath and CsvPaths. Each has only a few external methods.
147
147
 
148
148
  ### CsvPath
149
- (<a href='https://github.com/dk107dk/csvpath/blob/main/csvpath/csvpath.py'>code</a>)
149
+ (<a href='https://github.com/csvpath/csvpath/blob/main/csvpath/csvpath.py'>code</a>)
150
150
  The CsvPath class is the basic entry point for running csvpaths.
151
151
  |method |function |
152
152
  |----------------------------|----------------------------------------------------------------|
@@ -106,12 +106,12 @@ Interactive use of csvpaths can be valuable, too, of course. There is a trivial
106
106
  <a name="running"></a>
107
107
  ## Running CsvPath
108
108
 
109
- CsvPath is <a href='https://pypi.org/project/csvpath/'>available on Pypi here</a>. The <a href='https://github.com/dk107dk/csvpath'>git repo is here</a>.
109
+ CsvPath is <a href='https://pypi.org/project/csvpath/'>available on Pypi here</a>. The <a href='https://github.com/csvpath/csvpath'>git repo is here</a>.
110
110
 
111
111
  Two classes provide the functionality: CsvPath and CsvPaths. Each has only a few external methods.
112
112
 
113
113
  ### CsvPath
114
- (<a href='https://github.com/dk107dk/csvpath/blob/main/csvpath/csvpath.py'>code</a>)
114
+ (<a href='https://github.com/csvpath/csvpath/blob/main/csvpath/csvpath.py'>code</a>)
115
115
  The CsvPath class is the basic entry point for running csvpaths.
116
116
  |method |function |
117
117
  |----------------------------|----------------------------------------------------------------|
@@ -37,7 +37,9 @@ class CsvPathPublic(ABC):
37
37
  """Reads a csvpath prepares to match against CSV file lines"""
38
38
 
39
39
  @abstractmethod
40
- def parse_named_path(self, name): # pragma: no cover
40
+ def parse_named_path(
41
+ self, name, *, disposably=False, specific=None
42
+ ): # pragma: no cover
41
43
  """Parses a csvpath found in this CsvPath's CsvPaths parent's
42
44
  collection of named csvpaths"""
43
45
 
@@ -155,6 +157,16 @@ class CsvPath(CsvPathPublic, ErrorCollector, Printer): # pylint: disable=R0902,
155
157
  #
156
158
  self._freeze_path = False
157
159
  #
160
+ # explain-mode: explain
161
+ # turns on capturing match reasoning and dumps the captured decisions to INFO
162
+ # at the end of a match. the reasoning is already present in the DEBUG but it
163
+ # is harder to see amid all the noise. we don't want to dump explainations
164
+ # all the time tho because it is very expensive -- potentially 25% worse
165
+ # performance. the explainations could be improved. atm this is an experimental
166
+ # feature.
167
+ #
168
+ self._explain = False
169
+ #
158
170
  # counts are 1-based
159
171
  #
160
172
  self.scan_count = 0
@@ -256,6 +268,14 @@ class CsvPath(CsvPathPublic, ErrorCollector, Printer): # pylint: disable=R0902,
256
268
  self._stop_on_validation_errors = None
257
269
  self._fail_on_validation_errors = None
258
270
  #
271
+ # run mode determines if a csvpath gets run or if it is skipped. the
272
+ # main reasons to set run-mode: no-run vs. run are: you want to import
273
+ # it into other csvpaths that are in the same named-paths group, or
274
+ # you want to switch off a csvpath in a named-paths group for testing
275
+ # a similar reason.
276
+ #
277
+ self._run_mode = True
278
+ #
259
279
  # there are two logger components one for CsvPath and one for CsvPaths.
260
280
  # the default levels are set in config.ini. to change the levels pass LogUtility
261
281
  # your component instance and the logging level. e.g.:
@@ -264,6 +284,38 @@ class CsvPath(CsvPathPublic, ErrorCollector, Printer): # pylint: disable=R0902,
264
284
  self.logger = LogUtility.logger(self)
265
285
  self.logger.info("initialized CsvPath")
266
286
  self._ecoms = ErrorCommsManager(csvpath=self)
287
+ self._function_times_match = {}
288
+ self._function_times_value = {}
289
+
290
+ @property
291
+ def run_mode(self) -> bool:
292
+ return self._run_mode
293
+
294
+ @run_mode.setter
295
+ def run_mode(self, mode) -> None:
296
+ self._run_mode = mode
297
+
298
+ def _up_function_time_match(self, c, t) -> None:
299
+ if c not in self.function_times_match:
300
+ self.function_times_match[c] = 0
301
+ st = self.function_times_match[c]
302
+ st += t
303
+ self.function_times_match[c] = st
304
+
305
+ @property
306
+ def function_times_match(self) -> int:
307
+ return self._function_times_match
308
+
309
+ def _up_function_time_value(self, c, t) -> None:
310
+ if c not in self.function_times_value:
311
+ self.function_times_value[c] = 0
312
+ st = self.function_times_value[c]
313
+ st += t
314
+ self.function_times_value[c] = st
315
+
316
+ @property
317
+ def function_times_value(self) -> int:
318
+ return self._function_times_value
267
319
 
268
320
  def do_i_raise(self) -> bool:
269
321
  return self._ecoms.do_i_raise()
@@ -507,6 +559,18 @@ class CsvPath(CsvPathPublic, ErrorCollector, Printer): # pylint: disable=R0902,
507
559
  def is_frozen(self, freeze: bool) -> None:
508
560
  self._freeze_path = freeze
509
561
 
562
+ @property
563
+ def explain(self) -> bool:
564
+ """when this property is True CsvPath dumps a match explaination
565
+ to INFO. this can be expensive. a 25% performance hit wouldn't
566
+ be unexpected.
567
+ """
568
+ return self._explain
569
+
570
+ @explain.setter
571
+ def explain(self, yesno: bool) -> None:
572
+ self._explain = yesno
573
+
510
574
  @property
511
575
  def collect_when_not_matched(self) -> bool:
512
576
  """when this property is True CsvPath returns the lines that do not
@@ -579,8 +643,10 @@ class CsvPath(CsvPathPublic, ErrorCollector, Printer): # pylint: disable=R0902,
579
643
  # - validation-mode: (no-)print | log | (no-)raise | quiet | (no-)match
580
644
  #
581
645
  self.update_logic_mode_if()
646
+ self.update_run_mode_if()
582
647
  self.update_match_mode_if()
583
648
  self.update_print_mode_if()
649
+ self.update_explain_mode_if()
584
650
  self.update_arg_validation_mode_if()
585
651
 
586
652
  def update_arg_validation_mode_if(self) -> None:
@@ -598,6 +664,18 @@ class CsvPath(CsvPathPublic, ErrorCollector, Printer): # pylint: disable=R0902,
598
664
  self.metadata["validation-mode"],
599
665
  )
600
666
 
667
+ def update_run_mode_if(self) -> None:
668
+ if self.metadata and "run-mode" in self.metadata:
669
+ if f"{self.metadata['run-mode']}".strip() == "no-run":
670
+ self.run_mode = False
671
+ elif f"{self.metadata['run-mode']}".strip() == "run":
672
+ self.run_mode = True
673
+ else:
674
+ self.logger.warning(
675
+ "Incorrect metadata field value 'run-mode': %s",
676
+ self.metadata["run-mode"],
677
+ )
678
+
601
679
  def update_logic_mode_if(self) -> None:
602
680
  if self.metadata and "logic-mode" in self.metadata:
603
681
  if f"{self.metadata['logic-mode']}".strip() == "AND":
@@ -622,6 +700,15 @@ class CsvPath(CsvPathPublic, ErrorCollector, Printer): # pylint: disable=R0902,
622
700
  self.metadata["return-mode"],
623
701
  )
624
702
 
703
+ def update_explain_mode_if(self) -> None:
704
+ if "explain-mode" in self.metadata:
705
+ if f"{self.metadata['explain-mode']}".strip() == "no-explain":
706
+ self._explain = False
707
+ elif f"{self.metadata['explain-mode']}".strip() == "explain":
708
+ self._explain = True
709
+ else:
710
+ self._explain = False
711
+
625
712
  def update_print_mode_if(self) -> None:
626
713
  if "print-mode" in self.metadata:
627
714
  if f"{self.metadata['print-mode']}".strip() == "no-default":
@@ -646,32 +733,50 @@ class CsvPath(CsvPathPublic, ErrorCollector, Printer): # pylint: disable=R0902,
646
733
  self.metadata["print-mode"],
647
734
  )
648
735
 
649
- def parse_named_path(self, name, disposably=False):
650
- """disposably is True when a Matcher is needed for some purpose other than
651
- the run we were created to do. could be that a match component wanted a
652
- parsed csvpath for its own purposes. import() uses this method.
653
-
654
- when True, we create and return the Matcher, but then forget it ever existed.
655
-
656
- also note: the path must have a name or full filename. $[*] is not enough.
657
- """
736
+ def _pick_named_path(self, name, *, specific=None) -> str:
658
737
  if not self.csvpaths:
659
738
  raise CsvPathsException("No CsvPaths object available")
660
739
  np = self.csvpaths.paths_manager.get_named_paths(name)
661
740
  if not np:
662
- raise CsvPathsException(f"Named paths {name} not found")
741
+ raise CsvPathsException(f"Named-paths '{name}' not found")
663
742
  if len(np) == 0:
664
- raise CsvPathsException(f"Named paths {name} has no csvpaths")
665
- if len(np) > 1:
743
+ raise CsvPathsException(f"Named-paths '{name}' has no csvpaths")
744
+ if len(np) == 1:
745
+ return np[0]
746
+ if specific is None:
666
747
  self.logger.warning(
667
- "parse_named_path %s has %s csvpaths. Parsing just the first one.",
748
+ "Parse_named_path %s has %s csvpaths. Using just the first one.",
668
749
  name,
669
750
  len(np),
670
751
  )
671
- path = np[0]
672
- path = MetadataParser(self).extract_metadata(instance=self, csvpath=path)
673
- path = self._update_file_path(path)
674
- dis = self.parse(path, disposably=disposably)
752
+ return np[0]
753
+ for p in np:
754
+ # this ends up being redundant to the caller. we do it 1x so it's not
755
+ # a big lift and is consistent.
756
+ c = CsvPath()
757
+ MetadataParser(c).extract_metadata(instance=c, csvpath=p)
758
+ if c.identity == specific:
759
+ return p
760
+ self.logger.error(
761
+ "Cannot find csvpath identified as %s in named-paths %s", specific, name
762
+ )
763
+ raise ParsingException(f"Cannot find path '{specific}' in named-paths '{name}'")
764
+
765
+ def parse_named_path(self, name, *, disposably=False, specific=None):
766
+ """disposably is True when a Matcher is needed for some purpose other than
767
+ the run we were created to do. could be that a match component wanted a
768
+ parsed csvpath for its own purposes. import() uses this method.
769
+ when True, we create and return the Matcher, but then forget it ever existed.
770
+ also note: the path must have a name or full filename. $[*] is not enough.
771
+ """
772
+ if not self.csvpaths:
773
+ raise CsvPathsException("No CsvPaths object available")
774
+
775
+ path = self._pick_named_path(name, specific=specific)
776
+ c = CsvPath()
777
+ path = MetadataParser(c).extract_metadata(instance=c, csvpath=path)
778
+ path = c._update_file_path(path)
779
+ dis = c.parse(path, disposably=disposably)
675
780
  if disposably is True:
676
781
  return dis
677
782
  return None
@@ -753,6 +858,7 @@ class CsvPath(CsvPathPublic, ErrorCollector, Printer): # pylint: disable=R0902,
753
858
  def __str__(self):
754
859
  return f"""
755
860
  path: {self.scanner.path if self.scanner else None}
861
+ identity: {self.identity}
756
862
  parsers: [scanner=Ply, matcher=Lark, print=Lark]
757
863
  from_line: {self.scanner.from_line if self.scanner else None}
758
864
  to_line: {self.scanner.to_line if self.scanner else None}
@@ -852,25 +958,30 @@ class CsvPath(CsvPathPublic, ErrorCollector, Printer): # pylint: disable=R0902,
852
958
  the csvpath. collect() and fast_forward() call next() behind the scenes.
853
959
  """
854
960
  start = time.time()
855
- for line in self._next_line():
856
- b = self._consider_line(line)
857
- if b:
858
- line = self.limit_collection(line)
859
- if line is None:
860
- msg = "Line cannot be None"
861
- self.logger.error(msg)
862
- raise MatchException(msg)
863
- if len(line) == 0:
864
- msg = "Line cannot be len() == 0"
865
- self.logger.error(msg)
866
- raise MatchException(msg)
867
- yield line
868
- if self.stopped:
869
- self.logger.info(
870
- "CsvPath has been stopped at line %s",
871
- self.line_monitor.physical_line_number,
872
- )
873
- break
961
+ if self.run_mode is True:
962
+ for line in self._next_line():
963
+ b = self._consider_line(line)
964
+ if b:
965
+ line = self.limit_collection(line)
966
+ if line is None:
967
+ msg = "Line cannot be None"
968
+ self.logger.error(msg)
969
+ raise MatchException(msg)
970
+ if len(line) == 0:
971
+ msg = "Line cannot be len() == 0"
972
+ self.logger.error(msg)
973
+ raise MatchException(msg)
974
+ yield line
975
+ if self.stopped:
976
+ self.logger.info(
977
+ "CsvPath has been stopped at line %s",
978
+ self.line_monitor.physical_line_number,
979
+ )
980
+ break
981
+ else:
982
+ self.logger.warning(
983
+ "Csvpath identified as {self.identity} is disabled by run-mode:no-run"
984
+ )
874
985
  self.finalize()
875
986
  # moving to finalize
876
987
  # self._freeze_path = True
@@ -206,9 +206,11 @@ class CsvPaths(CsvPathsPublic, CsvPathsCoordinator, ErrorCollector):
206
206
  self.results_manager.clean_named_results(paths)
207
207
 
208
208
  def _validate_paths_and_file(self, *, pathsname, filename) -> None:
209
- if pathsname not in self.paths_manager.named_paths: # pragma: no cover
209
+ if not self.paths_manager.has_named_paths(pathsname): # pragma: no cover
210
210
  keys = list(self.paths_manager.named_paths.keys())
211
- raise InputException(f"Pathsname must be a named set of paths in {keys}")
211
+ raise InputException(
212
+ f"Pathsname '{pathsname}' must be a named set of paths in {keys}"
213
+ )
212
214
  if filename not in self.file_manager.named_files: # pragma: no cover
213
215
  keys = self.file_manager.named_files.keys()
214
216
  raise InputException(f"Filename must be a named file in {keys}")
@@ -7,6 +7,9 @@ from abc import ABC, abstractmethod
7
7
  from ..util.exceptions import InputException
8
8
  from ..util.error import ErrorHandler
9
9
 
10
+ from csvpath import CsvPath
11
+ from csvpath.util.metadata_parser import MetadataParser
12
+
10
13
 
11
14
  class CsvPathsManager(ABC):
12
15
  """holds paths (the path itself, not a file name or reference) in a named set.
@@ -169,10 +172,33 @@ class PathsManager(CsvPathsManager): # pylint: disable=C0115, C0116
169
172
  # files_manager and let csvpaths call the shots.
170
173
  #
171
174
  def get_named_paths(self, name: str) -> List[str]:
172
- if name in self.named_paths:
173
- return self.named_paths[name]
174
- return None
175
- # raise InputException("{name} not found")
175
+ ret = None
176
+ p2 = self._paths_name_path(name)
177
+ if p2[1] is None and p2[0] in self.named_paths:
178
+ ret = self.named_paths[p2[0]]
179
+ elif p2[1] is not None:
180
+ ret = self._find_one(p2)
181
+ return ret
182
+
183
+ def _paths_name_path(self, pathsname) -> tuple[str, str]:
184
+ specificpath = None
185
+ i = pathsname.find("#")
186
+ if i > 0:
187
+ specificpath = pathsname[i + 1 :]
188
+ pathsname = pathsname[0:i]
189
+ return (pathsname, specificpath)
190
+
191
+ def _find_one(self, p2: tuple[str]) -> str:
192
+ if p2[1] is not None:
193
+ paths = self.get_named_paths(p2[0])
194
+ for path in paths:
195
+ c = CsvPath()
196
+ MetadataParser(c).extract_metadata(instance=c, csvpath=path)
197
+ if c.identity == p2[1]:
198
+ return [path]
199
+ raise InputException(
200
+ f"Path identified as '{p2[1]}' must be in the group identitied as '{p2[0]}'"
201
+ )
176
202
 
177
203
  def remove_named_paths(self, name: str) -> None:
178
204
  if name in self.named_paths:
@@ -181,7 +207,7 @@ class PathsManager(CsvPathsManager): # pylint: disable=C0115, C0116
181
207
  raise InputException("{name} not found")
182
208
 
183
209
  def has_named_paths(self, name: str) -> bool:
184
- return name in self.named_paths
210
+ return self.get_named_paths(name)
185
211
 
186
212
  def number_of_named_paths(self) -> bool:
187
213
  return len(self.named_paths) # pragma: no cover
@@ -400,9 +400,16 @@ class Args:
400
400
  if _m is None:
401
401
  good = True
402
402
  if not good:
403
+ # _ = f" at {self.matchable.my_chain}" if self.matchable else ""
404
+ # msg = f"{self._csvpath_id()} Incorrectly written{_}. Wrong type or number of args: {_m}."
405
+ # raise ChildrenException(msg)
406
+ #
403
407
  _ = f" at {self.matchable.my_chain}" if self.matchable else ""
404
- msg = f"{self._csvpath_id()} Incorrectly written{_}. Wrong type or number of args: {_m}."
405
- raise ChildrenException(msg)
408
+ msg = f"Incorrectly written{_}. Wrong type or number of args: {_m}."
409
+ if self._matchable is None:
410
+ # this should only be testing
411
+ raise ChildrenException(msg)
412
+ self._matchable.raiseChildrenException(msg)
406
413
  self.validated = True
407
414
 
408
415
  def matches(self, actuals: List[Any]) -> None:
@@ -451,10 +458,14 @@ class Args:
451
458
  self._args_match = False
452
459
  pm = f"mismatch in {self.matchable.my_chain}: {mismatches}"
453
460
  # when would we not have a csvpath?
454
- pln = (
455
- self._csvpath.line_monitor.physical_line_number if self._csvpath else 0
456
- )
457
- csvpathid = f"{self._csvpath_id()} " if self._csvpath_id() else ""
461
+ # pln = (
462
+ # self._csvpath.line_monitor.physical_line_number if self._csvpath else 0
463
+ # )
464
+ # csvpathid = f"{self._csvpath_id()} " if self._csvpath_id() else ""
465
+ # ei = ExpressionUtility.get_my_expressions_index(self._matchable)
466
+ # pm = f"{csvpathid}Wrong value in match component {ei} at line {pln}: {pm}"
467
+ # raise ChildrenValidationException(pm)
468
+ #
458
469
  ei = ExpressionUtility.get_my_expressions_index(self._matchable)
459
- pm = f"{csvpathid}Wrong value in match component {ei} at line {pln}: {pm}"
460
- raise ChildrenValidationException(pm)
470
+ pm = f"Wrong value in match component {ei}: {pm}"
471
+ self._matchable.raiseChildrenException(pm)
@@ -115,6 +115,6 @@ class Any(MatchDecider):
115
115
  else:
116
116
  c = self.children[0].left
117
117
  # definitely a structure / children exception
118
- raise ChildrenException(
118
+ self.raiseChildrenException(
119
119
  f"Left child of any() must be header or variable, not {c}"
120
120
  )
@@ -35,11 +35,11 @@ class Empty(MatchDecider):
35
35
  for s in sibs:
36
36
  # both structure / children exceptions
37
37
  if isinstance(s, Headers) and len(sibs) > 1:
38
- raise ChildrenException(
38
+ self.raiseChildrenException(
39
39
  "If empty() has a headers() argument it can only have 1 argument"
40
40
  )
41
41
  if isinstance(s, Term):
42
- raise ChildrenException(
42
+ self.raiseChildrenException(
43
43
  "empty() arguments cannot include terms"
44
44
  ) # pragma: no cover
45
45
 
@@ -1,6 +1,7 @@
1
1
  # pylint: disable=C0114
2
2
  import traceback
3
3
  import signal
4
+ import time
4
5
  from typing import Any
5
6
  from ..productions.matchable import Matchable
6
7
  from ..util.exceptions import ChildrenException
@@ -39,7 +40,14 @@ class Function(Matchable):
39
40
  if not skip:
40
41
  skip = []
41
42
  if self in skip: # pragma: no cover
42
- return self._noop_value()
43
+ ret = self._noop_value()
44
+ self.valuing().result(ret).because("skip")
45
+ return ret
46
+ #
47
+ # experiment -- timing
48
+ #
49
+ startval = time.perf_counter_ns()
50
+ # exp end
43
51
  if self.do_frozen():
44
52
  # doing frozen means not doing anything else. this is the
45
53
  # inverse of onmatch and other qualifiers. but it makes sense
@@ -80,17 +88,29 @@ class Function(Matchable):
80
88
  # Term and Header, but maybe not for Function?
81
89
  if isinstance(self.value, str):
82
90
  self.value = self.value.strip()
91
+ #
92
+ # experiment - timing
93
+ #
94
+ endval = time.perf_counter_ns()
95
+ t = (endval - startval) / 1000000
96
+ self.matcher.csvpath._up_function_time_value(self.__class__, t)
97
+ #
98
+ # exp end
99
+ #
83
100
  return self.value
84
101
 
85
102
  def matches(self, *, skip=None) -> bool:
86
103
  if not skip:
87
104
  skip = []
88
105
  if self in skip: # pragma: no cover
89
- return self.default_match()
106
+ ret = self.default_match()
107
+ self.matching().result(ret).because("skip")
108
+ return ret
90
109
  #
91
- # experiment: catch all exceptions within here vvvv and have the expression handle
92
- # them at the end of the line.
110
+ # experiment -- timing
93
111
  #
112
+ startmatch = time.perf_counter_ns()
113
+ # exp end
94
114
  try:
95
115
  #
96
116
  #
@@ -101,7 +121,9 @@ class Function(Matchable):
101
121
  # and we're not talking about a qualifier, in any case. the
102
122
  # csvpath writer doesn't know anything about this.
103
123
  self.matcher.csvpath.logger.debug("We're frozen in %s", self)
104
- return self._noop_value()
124
+ ret = self._noop_value()
125
+ self.matching().result(ret).because("frozen")
126
+ return ret
105
127
  if self.match is None:
106
128
  if self.do_onmatch():
107
129
  #
@@ -136,9 +158,9 @@ class Function(Matchable):
136
158
  #
137
159
  sibs = self.sibling_values(skip=skip)
138
160
  if Matchable.FAILED_VALUE in sibs:
139
- pln = self.matcher.csvpath.line_monitor.physical_line_number
140
- raise ChildrenException(
141
- f"Line {pln}: Cannot continue with {self.my_chain} due to an invalid child"
161
+ # pln = self.matcher.csvpath.line_monitor.physical_line_number
162
+ self.raiseChildrenException(
163
+ f"Cannot continue with {self.my_chain} due to an invalid child"
142
164
  )
143
165
  #
144
166
  # ready to run the match!
@@ -178,16 +200,27 @@ class Function(Matchable):
178
200
  self.matcher.csvpath.logger.debug(
179
201
  "Function.matches _decide_match returned %s", self.match
180
202
  )
203
+ self.matching().result(self.match)
181
204
  else:
182
205
  self.match = self.default_match()
183
206
  self.matcher.csvpath.logger.debug(
184
207
  f"@{self}: appling default match, {self.match}, because !do_onmatch"
185
208
  )
209
+ self.matching().result(self.match).because("onmatch")
186
210
  except Exception as e:
187
211
  e.trace = traceback.format_exc()
188
212
  e.source = self
189
213
  e.json = self.to_json()
190
214
  self.my_expression.handle_error(e)
215
+ #
216
+ # experiment - timing
217
+ #
218
+ endmatch = time.perf_counter_ns()
219
+ t = (endmatch - startmatch) / 1000000
220
+ self.matcher.csvpath._up_function_time_match(self.__class__, t)
221
+ #
222
+ # exp end
223
+ #
191
224
  return self.match
192
225
 
193
226
  def _produce_value(self, skip=None) -> None:
@@ -17,12 +17,12 @@ class FirstLine(MatchDecider):
17
17
  if len(self.children) == 1 and isinstance(self.children[0], Equality):
18
18
  if not self.children[0].op == "=":
19
19
  # correct as structure / children exception
20
- raise ChildrenException(
20
+ self.raiseChildrenException(
21
21
  "Child can only be either a function or a variable assignment"
22
22
  )
23
23
  if self.name not in ["firstmatch", "firstscan", "firstline"]:
24
24
  # correct as structure / children exception
25
- raise ChildrenException(f"Unknown function name: {self.name}")
25
+ self.raiseChildrenException(f"Unknown function name: {self.name}")
26
26
  super().check_valid()
27
27
 
28
28
  def _produce_value(self, skip=None) -> None:
@@ -12,7 +12,7 @@ class Sum(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=[Variable, Function, Term, Header], actuals=[int])
15
+ a.arg(types=[Variable, Function, Term, Header], actuals=[int, float])
16
16
  self.args.validate(self.siblings())
17
17
  super().check_valid()
18
18
 
@@ -1,6 +1,6 @@
1
1
  # pylint: disable=C0114
2
2
  from typing import Any
3
- from csvpath.matching.productions import Term
3
+ from csvpath.matching.productions import Term, Reference
4
4
  from csvpath.matching.util.exceptions import MatchComponentException
5
5
  from csvpath.matching.util.expression_utility import ExpressionUtility
6
6
  from csvpath.matching.util.expression_encoder import ExpressionEncoder
@@ -18,7 +18,7 @@ class Import(SideEffect):
18
18
  def check_valid(self) -> None:
19
19
  self.args = Args(matchable=self)
20
20
  a = self.args.argset(1)
21
- a.arg(types=[Term], actuals=[str])
21
+ a.arg(types=[Term, Reference], actuals=[str])
22
22
  self.args.validate(self.siblings())
23
23
  super().check_valid()
24
24
  #
@@ -43,13 +43,20 @@ class Import(SideEffect):
43
43
  if name is None:
44
44
  raise MatchComponentException("Name of import csvpath cannot be None")
45
45
 
46
+ specific = None
47
+ if name.find("#") > -1:
48
+ specific = name[name.find("#") + 1 :]
49
+ name = name[0 : name.find("#")]
50
+
46
51
  self.matcher.csvpath.logger.info("Starting import from %s", name)
47
52
 
48
53
  e = ExpressionUtility.get_my_expression(self)
49
54
  if e is None:
50
55
  raise MatchComponentException("Cannot find my expression: {self}")
51
56
 
52
- amatcher = self.matcher.csvpath.parse_named_path(name=name, disposably=True)
57
+ amatcher = self.matcher.csvpath.parse_named_path(
58
+ name=name, disposably=True, specific=specific
59
+ )
53
60
  if (
54
61
  amatcher is None
55
62
  or not amatcher.expressions
@@ -21,7 +21,7 @@ class Percent(ValueProducer):
21
21
  if which not in ["scan", "match", "line"]:
22
22
  # correct structure / children exception. we could probably do this
23
23
  # in check_validate since we're requiring a Term, but this is fine.
24
- raise ChildrenException(
24
+ self.raiseChildrenException(
25
25
  "percent() argument must be scan, match, or line"
26
26
  ) # pragma: no cover
27
27
  if which == "line":
@@ -57,7 +57,7 @@ class Regex(MatchDecider):
57
57
  return theregex, thevalue, group
58
58
  else:
59
59
  # correct structure / children exception
60
- raise ChildrenException("No regular expression available")
60
+ self.raiseChildrenException("No regular expression available")
61
61
 
62
62
  def _produce_value(self, skip=None) -> None:
63
63
  child = self.children[0]