csvpath 0.0.464__tar.gz → 0.0.465__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 (196) hide show
  1. {csvpath-0.0.464 → csvpath-0.0.465}/PKG-INFO +7 -6
  2. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/boolean/all.py +1 -1
  3. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/boolean/any.py +1 -1
  4. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/counting/tally.py +7 -1
  5. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/function_factory.py +25 -11
  6. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/lines/first_line.py +3 -3
  7. csvpath-0.0.465/csvpath/matching/functions/print/table.py +133 -0
  8. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/productions/equality.py +3 -0
  9. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/util/printer.py +2 -0
  10. {csvpath-0.0.464 → csvpath-0.0.465}/pyproject.toml +2 -1
  11. {csvpath-0.0.464 → csvpath-0.0.465}/LICENSE +0 -0
  12. {csvpath-0.0.464 → csvpath-0.0.465}/README.md +5 -5
  13. {csvpath-0.0.464 → csvpath-0.0.465}/config/config.ini +0 -0
  14. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/__init__.py +0 -0
  15. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/csvpath.py +0 -0
  16. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/csvpaths.py +0 -0
  17. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/managers/__init__.py +0 -0
  18. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/managers/csvpath_result.py +0 -0
  19. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/managers/csvpaths_manager.py +0 -0
  20. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/managers/files_manager.py +0 -0
  21. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/managers/results_manager.py +0 -0
  22. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/__init__.py +0 -0
  23. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/__init__.py +0 -0
  24. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/boolean/andf.py +0 -0
  25. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/boolean/between.py +0 -0
  26. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/boolean/empty.py +0 -0
  27. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/boolean/exists.py +0 -0
  28. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/boolean/inf.py +0 -0
  29. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/boolean/no.py +0 -0
  30. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/boolean/notf.py +0 -0
  31. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/boolean/orf.py +0 -0
  32. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/boolean/yes.py +0 -0
  33. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/counting/count.py +0 -0
  34. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/counting/count_headers.py +0 -0
  35. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/counting/count_lines.py +0 -0
  36. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/counting/count_scans.py +0 -0
  37. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/counting/every.py +0 -0
  38. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/counting/has_matches.py +0 -0
  39. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/counting/increment.py +0 -0
  40. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/counting/total_lines.py +0 -0
  41. {csvpath-0.0.464/csvpath/matching/functions/misc → csvpath-0.0.465/csvpath/matching/functions/dates}/datef.py +0 -0
  42. {csvpath-0.0.464/csvpath/matching/functions/misc → csvpath-0.0.465/csvpath/matching/functions/dates}/now.py +0 -0
  43. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/function.py +0 -0
  44. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/function_focus.py +0 -0
  45. {csvpath-0.0.464/csvpath/matching/functions/misc → csvpath-0.0.465/csvpath/matching/functions/headers}/collect.py +0 -0
  46. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/headers/end.py +0 -0
  47. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/headers/header_name.py +0 -0
  48. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/headers/header_names_mismatch.py +0 -0
  49. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/headers/headers.py +0 -0
  50. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/headers/mismatch.py +0 -0
  51. {csvpath-0.0.464/csvpath/matching/functions/misc → csvpath-0.0.465/csvpath/matching/functions/headers}/replace.py +0 -0
  52. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/headers/reset_headers.py +0 -0
  53. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/lines/advance.py +0 -0
  54. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/lines/after_blank.py +0 -0
  55. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/lines/dups.py +0 -0
  56. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/lines/first.py +0 -0
  57. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/lines/last.py +0 -0
  58. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/lines/stop.py +0 -0
  59. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/math/above.py +0 -0
  60. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/math/add.py +0 -0
  61. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/math/divide.py +0 -0
  62. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/math/equals.py +0 -0
  63. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/math/mod.py +0 -0
  64. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/math/multiply.py +0 -0
  65. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/math/round.py +0 -0
  66. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/math/subtract.py +0 -0
  67. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/math/sum.py +0 -0
  68. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/misc/importf.py +0 -0
  69. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/misc/intf.py +0 -0
  70. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/misc/nonef.py +0 -0
  71. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/misc/random.py +0 -0
  72. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/print/jinjaf.py +0 -0
  73. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/print/print_line.py +0 -0
  74. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/print/print_queue.py +0 -0
  75. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/print/printf.py +0 -0
  76. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/stats/correlate.py +0 -0
  77. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/stats/minf.py +0 -0
  78. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/stats/percent.py +0 -0
  79. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/stats/percent_unique.py +0 -0
  80. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/stats/stdev.py +0 -0
  81. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/strings/concat.py +0 -0
  82. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/strings/length.py +0 -0
  83. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/strings/lower.py +0 -0
  84. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/strings/metaphone.py +0 -0
  85. {csvpath-0.0.464/csvpath/matching/functions/misc → csvpath-0.0.465/csvpath/matching/functions/strings}/regex.py +0 -0
  86. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/strings/starts_with.py +0 -0
  87. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/strings/strip.py +0 -0
  88. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/strings/substring.py +0 -0
  89. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/strings/upper.py +0 -0
  90. {csvpath-0.0.464/csvpath/matching/functions/misc → csvpath-0.0.465/csvpath/matching/functions/testing}/debug.py +0 -0
  91. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/validation.py +0 -0
  92. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/validity/fail.py +0 -0
  93. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/functions/validity/failed.py +0 -0
  94. {csvpath-0.0.464/csvpath/matching/functions/misc → csvpath-0.0.465/csvpath/matching/functions/variables}/get.py +0 -0
  95. {csvpath-0.0.464/csvpath/matching/functions/misc → csvpath-0.0.465/csvpath/matching/functions/variables}/pushpop.py +0 -0
  96. {csvpath-0.0.464/csvpath/matching/functions/misc → csvpath-0.0.465/csvpath/matching/functions/variables}/track.py +0 -0
  97. {csvpath-0.0.464/csvpath/matching/functions/misc → csvpath-0.0.465/csvpath/matching/functions/variables}/variables.py +0 -0
  98. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/lark_parser.py +0 -0
  99. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/lark_transformer.py +0 -0
  100. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/matcher.py +0 -0
  101. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/productions/__init__.py +0 -0
  102. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/productions/expression.py +0 -0
  103. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/productions/header.py +0 -0
  104. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/productions/matchable.py +0 -0
  105. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/productions/qualified.py +0 -0
  106. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/productions/reference.py +0 -0
  107. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/productions/term.py +0 -0
  108. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/productions/variable.py +0 -0
  109. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/util/exceptions.py +0 -0
  110. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/util/expression_encoder.py +0 -0
  111. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/util/expression_utility.py +0 -0
  112. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/util/lark_print_parser.py +0 -0
  113. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/matching/util/print_parser.py +0 -0
  114. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/scanning/__init__.py +0 -0
  115. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/scanning/exceptions.py +0 -0
  116. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/scanning/parser.out +0 -0
  117. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/scanning/parsetab.py +0 -0
  118. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/scanning/scanner.py +0 -0
  119. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/scanning/scanning_lexer.py +0 -0
  120. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/util/config.py +0 -0
  121. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/util/config_exception.py +0 -0
  122. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/util/error.py +0 -0
  123. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/util/exceptions.py +0 -0
  124. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/util/last_line_stats.py +0 -0
  125. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/util/line_monitor.py +0 -0
  126. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/util/log_utility.py +0 -0
  127. {csvpath-0.0.464 → csvpath-0.0.465}/csvpath/util/metadata_parser.py +0 -0
  128. {csvpath-0.0.464 → csvpath-0.0.465}/docs/asbool.md +0 -0
  129. {csvpath-0.0.464 → csvpath-0.0.465}/docs/assignment.md +0 -0
  130. {csvpath-0.0.464 → csvpath-0.0.465}/docs/config.md +0 -0
  131. {csvpath-0.0.464 → csvpath-0.0.465}/docs/examples.md +0 -0
  132. {csvpath-0.0.464 → csvpath-0.0.465}/docs/files.md +0 -0
  133. {csvpath-0.0.464 → csvpath-0.0.465}/docs/functions/above.md +0 -0
  134. {csvpath-0.0.464 → csvpath-0.0.465}/docs/functions/advance.md +0 -0
  135. {csvpath-0.0.464 → csvpath-0.0.465}/docs/functions/after_blank.md +0 -0
  136. {csvpath-0.0.464 → csvpath-0.0.465}/docs/functions/all.md +0 -0
  137. {csvpath-0.0.464 → csvpath-0.0.465}/docs/functions/andor.md +0 -0
  138. {csvpath-0.0.464 → csvpath-0.0.465}/docs/functions/any.md +0 -0
  139. {csvpath-0.0.464 → csvpath-0.0.465}/docs/functions/average.md +0 -0
  140. {csvpath-0.0.464 → csvpath-0.0.465}/docs/functions/between.md +0 -0
  141. {csvpath-0.0.464 → csvpath-0.0.465}/docs/functions/collect.md +0 -0
  142. {csvpath-0.0.464 → csvpath-0.0.465}/docs/functions/correlate.md +0 -0
  143. {csvpath-0.0.464 → csvpath-0.0.465}/docs/functions/count.md +0 -0
  144. {csvpath-0.0.464 → csvpath-0.0.465}/docs/functions/count_headers.md +0 -0
  145. {csvpath-0.0.464 → csvpath-0.0.465}/docs/functions/date.md +0 -0
  146. {csvpath-0.0.464 → csvpath-0.0.465}/docs/functions/empty.md +0 -0
  147. {csvpath-0.0.464 → csvpath-0.0.465}/docs/functions/end.md +0 -0
  148. {csvpath-0.0.464 → csvpath-0.0.465}/docs/functions/every.md +0 -0
  149. {csvpath-0.0.464 → csvpath-0.0.465}/docs/functions/fail.md +0 -0
  150. {csvpath-0.0.464 → csvpath-0.0.465}/docs/functions/first.md +0 -0
  151. {csvpath-0.0.464 → csvpath-0.0.465}/docs/functions/get.md +0 -0
  152. {csvpath-0.0.464 → csvpath-0.0.465}/docs/functions/has_dups.md +0 -0
  153. {csvpath-0.0.464 → csvpath-0.0.465}/docs/functions/header.md +0 -0
  154. {csvpath-0.0.464 → csvpath-0.0.465}/docs/functions/header_name.md +0 -0
  155. {csvpath-0.0.464 → csvpath-0.0.465}/docs/functions/header_names_mismatch.md +0 -0
  156. {csvpath-0.0.464 → csvpath-0.0.465}/docs/functions/implementing_functions.md +0 -0
  157. {csvpath-0.0.464 → csvpath-0.0.465}/docs/functions/import.md +0 -0
  158. {csvpath-0.0.464 → csvpath-0.0.465}/docs/functions/in.md +0 -0
  159. {csvpath-0.0.464 → csvpath-0.0.465}/docs/functions/increment.md +0 -0
  160. {csvpath-0.0.464 → csvpath-0.0.465}/docs/functions/jinja.md +0 -0
  161. {csvpath-0.0.464 → csvpath-0.0.465}/docs/functions/last.md +0 -0
  162. {csvpath-0.0.464 → csvpath-0.0.465}/docs/functions/line_number.md +0 -0
  163. {csvpath-0.0.464 → csvpath-0.0.465}/docs/functions/max.md +0 -0
  164. {csvpath-0.0.464 → csvpath-0.0.465}/docs/functions/metaphone.md +0 -0
  165. {csvpath-0.0.464 → csvpath-0.0.465}/docs/functions/mismatch.md +0 -0
  166. {csvpath-0.0.464 → csvpath-0.0.465}/docs/functions/no.md +0 -0
  167. {csvpath-0.0.464 → csvpath-0.0.465}/docs/functions/not.md +0 -0
  168. {csvpath-0.0.464 → csvpath-0.0.465}/docs/functions/now.md +0 -0
  169. {csvpath-0.0.464 → csvpath-0.0.465}/docs/functions/percent_unique.md +0 -0
  170. {csvpath-0.0.464 → csvpath-0.0.465}/docs/functions/pop.md +0 -0
  171. {csvpath-0.0.464 → csvpath-0.0.465}/docs/functions/print.md +0 -0
  172. {csvpath-0.0.464 → csvpath-0.0.465}/docs/functions/print_line.md +0 -0
  173. {csvpath-0.0.464 → csvpath-0.0.465}/docs/functions/print_queue.md +0 -0
  174. {csvpath-0.0.464 → csvpath-0.0.465}/docs/functions/regex.md +0 -0
  175. {csvpath-0.0.464 → csvpath-0.0.465}/docs/functions/replace.md +0 -0
  176. {csvpath-0.0.464 → csvpath-0.0.465}/docs/functions/reset_headers.md +0 -0
  177. {csvpath-0.0.464 → csvpath-0.0.465}/docs/functions/stdev.md +0 -0
  178. {csvpath-0.0.464 → csvpath-0.0.465}/docs/functions/stop.md +0 -0
  179. {csvpath-0.0.464 → csvpath-0.0.465}/docs/functions/string_functions.md +0 -0
  180. {csvpath-0.0.464 → csvpath-0.0.465}/docs/functions/subtract.md +0 -0
  181. {csvpath-0.0.464 → csvpath-0.0.465}/docs/functions/sum.md +0 -0
  182. {csvpath-0.0.464 → csvpath-0.0.465}/docs/functions/tally.md +0 -0
  183. {csvpath-0.0.464 → csvpath-0.0.465}/docs/functions/total_lines.md +0 -0
  184. {csvpath-0.0.464 → csvpath-0.0.465}/docs/functions/track.md +0 -0
  185. {csvpath-0.0.464 → csvpath-0.0.465}/docs/functions/variables.md +0 -0
  186. {csvpath-0.0.464 → csvpath-0.0.465}/docs/functions/variables_and_headers.md +0 -0
  187. {csvpath-0.0.464 → csvpath-0.0.465}/docs/functions.md +0 -0
  188. {csvpath-0.0.464 → csvpath-0.0.465}/docs/grammar.md +0 -0
  189. {csvpath-0.0.464 → csvpath-0.0.465}/docs/headers.md +0 -0
  190. {csvpath-0.0.464 → csvpath-0.0.465}/docs/images/logo-wordmark-white-on-black-trimmed-padded.png +0 -0
  191. {csvpath-0.0.464 → csvpath-0.0.465}/docs/images/logo-wordmark-white-trimmed.png +0 -0
  192. {csvpath-0.0.464 → csvpath-0.0.465}/docs/paths.md +0 -0
  193. {csvpath-0.0.464 → csvpath-0.0.465}/docs/qualifiers.md +0 -0
  194. {csvpath-0.0.464 → csvpath-0.0.465}/docs/references.md +0 -0
  195. {csvpath-0.0.464 → csvpath-0.0.465}/docs/terms.md +0 -0
  196. {csvpath-0.0.464 → csvpath-0.0.465}/docs/variables.md +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: csvpath
3
- Version: 0.0.464
3
+ Version: 0.0.465
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
@@ -25,6 +25,7 @@ Requires-Dist: lark (>=1.2.2,<2.0.0)
25
25
  Requires-Dist: pandas (>=2.2.2,<3.0.0)
26
26
  Requires-Dist: ply (>=3.11,<4.0)
27
27
  Requires-Dist: python-dateutil (>=2.9.0.post0,<3.0.0)
28
+ Requires-Dist: tabulate (>=0.9.0,<0.10.0)
28
29
  Project-URL: Csvpath.org, https://www.csvpath.org
29
30
  Project-URL: Github, https://github.com/dk107dk/csvpath
30
31
  Description-Content-Type: text/markdown
@@ -34,11 +35,6 @@ Description-Content-Type: text/markdown
34
35
 
35
36
  CsvPath defines a declarative syntax for inspecting and validating CSV files.
36
37
 
37
- Though much simpler, it is inspired by:
38
- - XPath. CsvPath is to CSV files like XPath is to XML files.
39
- - Validation of XML using <a href='https://schematron.com/'>Schematron rules</a>
40
- - The way CSS selectors pick out HTML structures
41
-
42
38
  CsvPath' goal is to make it easy to:
43
39
  - Analyze the content and structure of a CSV
44
40
  - Validate that the file matches expectations
@@ -47,6 +43,11 @@ CsvPath' goal is to make it easy to:
47
43
 
48
44
  And do it all in an automation-friendly way.
49
45
 
46
+ Though much simpler, it is inspired by:
47
+ - XPath. CsvPath is to CSV files like XPath is to XML files.
48
+ - Validation of XML using <a href='https://schematron.com/'>Schematron rules</a>
49
+ - The way CSS selectors pick out HTML structures
50
+
50
51
  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.
51
52
 
52
53
  Read more about CsvPath and see realistic CSV validation examples at <a href='https://www.csvpath.org'>csvpath.org</a>.
@@ -4,7 +4,7 @@ from typing import Any
4
4
  from csvpath.matching.productions import Equality
5
5
  from csvpath.matching.util.exceptions import ChildrenException
6
6
  from ..function_focus import MatchDecider
7
- from ..misc.variables import Variables
7
+ from ..variables.variables import Variables
8
8
  from ..headers.headers import Headers
9
9
 
10
10
 
@@ -2,7 +2,7 @@
2
2
  from csvpath.matching.productions import Equality, Term
3
3
  from csvpath.matching.util.exceptions import ChildrenException
4
4
  from csvpath.matching.util.expression_utility import ExpressionUtility
5
- from ..misc.variables import Variables
5
+ from ..variables.variables import Variables
6
6
  from ..function_focus import MatchDecider
7
7
  from ..headers.headers import Headers
8
8
 
@@ -18,18 +18,24 @@ class Tally(ValueProducer):
18
18
  else:
19
19
  siblings = [child]
20
20
  tally = ""
21
+
21
22
  for _ in siblings:
22
23
  tally += f"{_.to_value(skip=skip)}|"
23
24
  value = f"{_.to_value(skip=skip)}"
24
25
  self._store(_.name, value)
25
26
  if len(siblings) > 1:
26
27
  self._store(
27
- self.first_non_term_qualifier("tally"),
28
+ "", # we don't need to pass a name. this data just
29
+ # goes under "tally" or the qualifier
28
30
  tally[0 : len(tally) - 1],
29
31
  )
30
32
  self.value = True
31
33
 
32
34
  def _store(self, name, value):
35
+ if name == "":
36
+ name = self.first_non_term_qualifier("tally")
37
+ else:
38
+ name = f"""{self.first_non_term_qualifier("tally")}_{name}"""
33
39
  count = self.matcher.get_variable(name, tracking=value)
34
40
  if count is None:
35
41
  count = 0
@@ -1,12 +1,15 @@
1
1
  # pylint: disable=C0114
2
2
  from csvpath.matching.productions.expression import Matchable
3
3
  from .function import Function
4
+ from .dates.now import Now
5
+ from .dates.datef import Date
4
6
  from .strings.lower import Lower
5
7
  from .strings.upper import Upper
6
8
  from .strings.substring import Substring
7
9
  from .strings.starts_with import StartsWith
8
10
  from .strings.strip import Strip
9
11
  from .strings.length import Length, MinMaxLength
12
+ from .strings.regex import Regex
10
13
  from .strings.concat import Concat
11
14
  from .strings.metaphone import Metaphone
12
15
  from .counting.count import Count
@@ -21,6 +24,8 @@ from .counting.increment import Increment
21
24
  from .headers.reset_headers import ResetHeaders
22
25
  from .headers.header_name import HeaderName
23
26
  from .headers.header_names_mismatch import HeaderNamesMismatch
27
+ from .headers.collect import Collect
28
+ from .headers.replace import Replace
24
29
  from .headers.headers import Headers
25
30
  from .headers.mismatch import Mismatch
26
31
  from .headers.end import End
@@ -50,6 +55,7 @@ from .stats.percent_unique import PercentUnique
50
55
  from .stats.stdev import Stdev
51
56
  from .stats.correlate import Correlate
52
57
  from .print.printf import Print
58
+ from .print.table import HeaderTable, RowTable, VarTable
53
59
  from .print.print_line import PrintLine
54
60
  from .print.jinjaf import Jinjaf
55
61
  from .print.print_queue import PrintQueue
@@ -60,20 +66,15 @@ from .lines.dups import HasDups, DupLines, CountDups
60
66
  from .lines.first_line import FirstLine
61
67
  from .lines.advance import Advance
62
68
  from .lines.after_blank import AfterBlank
69
+ from .variables.variables import Variables
70
+ from .variables.pushpop import Push, PushDistinct, Pop, Peek, PeekSize, Stack
71
+ from .variables.get import Get
72
+ from .variables.track import Track
63
73
  from .misc.random import Random
64
- from .misc.regex import Regex
65
- from .misc.now import Now
66
- from .misc.variables import Variables
67
74
  from .misc.nonef import Nonef
68
- from .misc.pushpop import Push, PushDistinct, Pop, Peek, PeekSize, Stack
69
- from .misc.datef import Date
70
- from .misc.collect import Collect
71
- from .misc.replace import Replace
72
75
  from .misc.intf import Int
73
- from .misc.get import Get
74
- from .misc.track import Track
75
76
  from .misc.importf import Import
76
- from .misc.debug import Debug, BriefStackTrace, VoteStack, DoWhenStack
77
+ from .testing.debug import Debug, BriefStackTrace, VoteStack, DoWhenStack
77
78
  from .validity.failed import Failed
78
79
  from .validity.fail import Fail
79
80
 
@@ -176,7 +177,14 @@ class FunctionFactory:
176
177
  f = AboveBelow(matcher, name, child)
177
178
  elif name == "first":
178
179
  f = First(matcher, name, child)
179
- elif name in ["firstline", "firstmatch", "firstscan"]:
180
+ elif name in [
181
+ "firstline",
182
+ "firstmatch",
183
+ "firstscan",
184
+ "first_line",
185
+ "first_scan",
186
+ "first_match",
187
+ ]:
180
188
  f = FirstLine(matcher, name, child)
181
189
  elif name == "count_lines":
182
190
  f = CountLines(matcher, name, child)
@@ -337,6 +345,12 @@ class FunctionFactory:
337
345
  f = DoWhenStack(matcher, name, child)
338
346
  elif name == "metaphone":
339
347
  f = Metaphone(matcher, name, child)
348
+ elif name == "header_table":
349
+ f = HeaderTable(matcher, name, child)
350
+ elif name == "row_table":
351
+ f = RowTable(matcher, name, child)
352
+ elif name == "var_table":
353
+ f = VarTable(matcher, name, child)
340
354
  else:
341
355
  if (
342
356
  f is None
@@ -22,16 +22,16 @@ class FirstLine(MatchDecider):
22
22
 
23
23
  def _decide_match(self, skip=None) -> None:
24
24
  t = self.name
25
- if t == "firstmatch":
25
+ if t in ["firstmatch", "first_match"]:
26
26
  if self.matcher.csvpath.match_count == 0 and self.line_matches(): # 1-based
27
27
  self.match = True
28
28
  else:
29
29
  self.match = False
30
- elif t == "firstscan":
30
+ elif t in ["firstscan", "first_scan"]:
31
31
  self.match = (
32
32
  self.matcher.csvpath.scan_count == 1
33
33
  ) # 1-based, set before matcher is called.
34
- elif t == "firstline":
34
+ elif t in ["firstline", "first_line"]:
35
35
  self.match = (
36
36
  self.matcher.csvpath.line_monitor.data_line_number == 0
37
37
  ) # 0-based, updated after matcher is called.
@@ -0,0 +1,133 @@
1
+ # pylint: disable=C0114
2
+ import textwrap
3
+ from tabulate import tabulate
4
+ from ..function_focus import SideEffect
5
+
6
+
7
+ class HeaderTable(SideEffect):
8
+ """prints a header table"""
9
+
10
+ def check_valid(self) -> None:
11
+ self.validate_zero_args()
12
+ super().check_valid()
13
+
14
+ def _produce_value(self, skip=None) -> None:
15
+ self.value = self.matches(skip=skip)
16
+
17
+ def _decide_match(self, skip=None) -> None:
18
+ table = []
19
+ headers = ["#N", "#Name"]
20
+ for i, h in enumerate(self.matcher.csvpath.headers):
21
+ table.append([i, h])
22
+ self.matcher.csvpath.print(
23
+ tabulate(table, headers=headers, tablefmt="simple_grid")
24
+ )
25
+ self.match = self.default_match()
26
+
27
+
28
+ class RowTable(SideEffect):
29
+ """prints a row table"""
30
+
31
+ def check_valid(self) -> None:
32
+ self.validate_zero_one_or_two_args()
33
+ super().check_valid()
34
+
35
+ def _produce_value(self, skip=None) -> None:
36
+ self.value = self.matches(skip=skip)
37
+
38
+ def _decide_match(self, skip=None) -> None:
39
+ v1 = self._value_one()
40
+ v2 = self._value_two()
41
+ i = -1
42
+ j = -1
43
+ if v1 is None and v2 is None:
44
+ i = 0
45
+ j = len(self.matcher.csvpath.headers)
46
+ elif v2 is None:
47
+ i = v1
48
+ j = i
49
+ else:
50
+ i = v1
51
+ j = v2
52
+ headers = []
53
+ row = None
54
+ print(f"tables.i: {i}, {j}")
55
+ if i == j:
56
+ headers.append(self.matcher.csvpath.headers[i])
57
+ row = [[self.matcher.line[i]]]
58
+ else:
59
+ for k, h in enumerate(self.matcher.csvpath.headers[i : j + 1]):
60
+ headers.append(f"#{h} (#{k + i})")
61
+ row = [self.matcher.line[i : j + 1]]
62
+
63
+ self.matcher.csvpath.print(
64
+ tabulate(row, headers=headers, tablefmt="simple_grid")
65
+ )
66
+ self.match = self.default_match()
67
+
68
+
69
+ class VarTable(SideEffect):
70
+ """prints a variables table"""
71
+
72
+ def check_valid(self) -> None:
73
+ self.validate_zero_or_more_args()
74
+ super().check_valid()
75
+
76
+ def _produce_value(self, skip=None) -> None:
77
+ self.value = self.matches(skip=skip)
78
+
79
+ def _decide_match(self, skip=None) -> None:
80
+ v1 = self._value_one()
81
+ v2 = self._value_two()
82
+ if v1 is None:
83
+ self.print_all_vars()
84
+ elif v2 is None:
85
+ self.print_one_var()
86
+ else:
87
+ self.print_some_vars(skip)
88
+ self.match = self.default_match()
89
+
90
+ def print_all_vars(self):
91
+ headers = []
92
+ rows = [[]]
93
+ for k, v in self.matcher.csvpath.variables.items():
94
+ headers.append(k)
95
+ v = str(v)
96
+ if len(v) > 20:
97
+ v = textwrap.fill(v, width=20)
98
+ rows[0].append(v)
99
+ self.matcher.csvpath.print(
100
+ tabulate(rows, headers=headers, tablefmt="simple_grid")
101
+ )
102
+
103
+ def print_one_var(self):
104
+ h = self._value_one()
105
+ headers = [h]
106
+ rows = []
107
+ v = self.matcher.csvpath.variables[h]
108
+ if isinstance(v, list):
109
+ for a in v:
110
+ rows.append([a])
111
+ elif isinstance(v, dict):
112
+ headers.append("Tracking")
113
+ for k, _ in v.items():
114
+ rows.append([k, _])
115
+ self.matcher.csvpath.print(
116
+ tabulate(rows, headers=headers, tablefmt="simple_grid")
117
+ )
118
+
119
+ def print_some_vars(self, skip):
120
+ siblings = self[0].commas_to_list()
121
+ headers = []
122
+ for s in siblings:
123
+ headers.append(s.to_value(skip=skip))
124
+ rows = []
125
+ for h in headers:
126
+ v = self.matcher.csvpath.variables[h]
127
+ v = f"{v}"
128
+ if len(v) > 30:
129
+ v = textwrap.fill(v, width=30)
130
+ rows.append([v])
131
+ self.matcher.csvpath.print(
132
+ tabulate(rows, headers=headers, tablefmt="simple_grid")
133
+ )
@@ -88,10 +88,13 @@ class Equality(Matchable):
88
88
 
89
89
  def commas_to_list(self) -> List[Any]:
90
90
  """gets the children of op==',' equalities as a list of args"""
91
+ """
91
92
  ls = []
92
93
  for _ in self.children:
93
94
  ls.append(_)
94
95
  return ls
96
+ """
97
+ return self.children[:]
95
98
 
96
99
  def set_operation(self, op): # pylint: disable=C0116
97
100
  self.op = op
@@ -57,6 +57,8 @@ class StdOutPrinter(Printer):
57
57
 
58
58
 
59
59
  class TestPrinter(Printer):
60
+ __test__ = False
61
+
60
62
  def __init__(self):
61
63
  self.lines = []
62
64
 
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "csvpath"
3
- version = "0.0.464"
3
+ version = "0.0.465"
4
4
  description = "A declarative language for data extraction and validation of CSV files"
5
5
  authors = ["David Kershaw <dk107dk@hotmail.com>"]
6
6
  readme = "README.md"
@@ -32,6 +32,7 @@ jinja2 = "^3.1.4"
32
32
  inflect = "^7.3.1"
33
33
  lark = "^1.2.2"
34
34
  jellyfish = "^1.1.0"
35
+ tabulate = "^0.9.0"
35
36
 
36
37
  [tool.poetry.group.dev.dependencies]
37
38
  flake8 = "^7.1.0"
File without changes
@@ -3,11 +3,6 @@
3
3
 
4
4
  CsvPath defines a declarative syntax for inspecting and validating CSV files.
5
5
 
6
- Though much simpler, it is inspired by:
7
- - XPath. CsvPath is to CSV files like XPath is to XML files.
8
- - Validation of XML using <a href='https://schematron.com/'>Schematron rules</a>
9
- - The way CSS selectors pick out HTML structures
10
-
11
6
  CsvPath' goal is to make it easy to:
12
7
  - Analyze the content and structure of a CSV
13
8
  - Validate that the file matches expectations
@@ -16,6 +11,11 @@ CsvPath' goal is to make it easy to:
16
11
 
17
12
  And do it all in an automation-friendly way.
18
13
 
14
+ Though much simpler, it is inspired by:
15
+ - XPath. CsvPath is to CSV files like XPath is to XML files.
16
+ - Validation of XML using <a href='https://schematron.com/'>Schematron rules</a>
17
+ - The way CSS selectors pick out HTML structures
18
+
19
19
  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
20
 
21
21
  Read more about CsvPath and see realistic CSV validation examples at <a href='https://www.csvpath.org'>csvpath.org</a>.
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes