csvpath 0.0.465__tar.gz → 0.0.467__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 (201) hide show
  1. {csvpath-0.0.465 → csvpath-0.0.467}/PKG-INFO +1 -1
  2. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/csvpath.py +5 -0
  3. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/boolean/empty.py +4 -4
  4. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/function_factory.py +7 -0
  5. csvpath-0.0.467/csvpath/matching/functions/headers/empty_stack.py +50 -0
  6. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/variables/get.py +2 -6
  7. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/variables/pushpop.py +12 -11
  8. csvpath-0.0.467/csvpath/matching/functions/variables/put.py +30 -0
  9. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/util/expression_utility.py +16 -1
  10. csvpath-0.0.467/docs/functions/empty_stack.md +32 -0
  11. csvpath-0.0.467/docs/functions/get.md +31 -0
  12. {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/pop.md +3 -1
  13. {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/tally.md +12 -12
  14. csvpath-0.0.467/docs/functions.md +248 -0
  15. {csvpath-0.0.465 → csvpath-0.0.467}/pyproject.toml +1 -1
  16. csvpath-0.0.465/docs/functions/get.md +0 -23
  17. csvpath-0.0.465/docs/functions.md +0 -199
  18. {csvpath-0.0.465 → csvpath-0.0.467}/LICENSE +0 -0
  19. {csvpath-0.0.465 → csvpath-0.0.467}/README.md +0 -0
  20. {csvpath-0.0.465 → csvpath-0.0.467}/config/config.ini +0 -0
  21. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/__init__.py +0 -0
  22. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/csvpaths.py +0 -0
  23. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/managers/__init__.py +0 -0
  24. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/managers/csvpath_result.py +0 -0
  25. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/managers/csvpaths_manager.py +0 -0
  26. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/managers/files_manager.py +0 -0
  27. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/managers/results_manager.py +0 -0
  28. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/__init__.py +0 -0
  29. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/__init__.py +0 -0
  30. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/boolean/all.py +0 -0
  31. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/boolean/andf.py +0 -0
  32. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/boolean/any.py +0 -0
  33. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/boolean/between.py +0 -0
  34. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/boolean/exists.py +0 -0
  35. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/boolean/inf.py +0 -0
  36. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/boolean/no.py +0 -0
  37. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/boolean/notf.py +0 -0
  38. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/boolean/orf.py +0 -0
  39. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/boolean/yes.py +0 -0
  40. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/counting/count.py +0 -0
  41. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/counting/count_headers.py +0 -0
  42. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/counting/count_lines.py +0 -0
  43. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/counting/count_scans.py +0 -0
  44. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/counting/every.py +0 -0
  45. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/counting/has_matches.py +0 -0
  46. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/counting/increment.py +0 -0
  47. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/counting/tally.py +0 -0
  48. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/counting/total_lines.py +0 -0
  49. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/dates/datef.py +0 -0
  50. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/dates/now.py +0 -0
  51. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/function.py +0 -0
  52. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/function_focus.py +0 -0
  53. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/headers/collect.py +0 -0
  54. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/headers/end.py +0 -0
  55. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/headers/header_name.py +0 -0
  56. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/headers/header_names_mismatch.py +0 -0
  57. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/headers/headers.py +0 -0
  58. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/headers/mismatch.py +0 -0
  59. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/headers/replace.py +0 -0
  60. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/headers/reset_headers.py +0 -0
  61. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/lines/advance.py +0 -0
  62. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/lines/after_blank.py +0 -0
  63. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/lines/dups.py +0 -0
  64. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/lines/first.py +0 -0
  65. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/lines/first_line.py +0 -0
  66. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/lines/last.py +0 -0
  67. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/lines/stop.py +0 -0
  68. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/math/above.py +0 -0
  69. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/math/add.py +0 -0
  70. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/math/divide.py +0 -0
  71. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/math/equals.py +0 -0
  72. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/math/mod.py +0 -0
  73. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/math/multiply.py +0 -0
  74. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/math/round.py +0 -0
  75. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/math/subtract.py +0 -0
  76. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/math/sum.py +0 -0
  77. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/misc/importf.py +0 -0
  78. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/misc/intf.py +0 -0
  79. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/misc/nonef.py +0 -0
  80. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/misc/random.py +0 -0
  81. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/print/jinjaf.py +0 -0
  82. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/print/print_line.py +0 -0
  83. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/print/print_queue.py +0 -0
  84. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/print/printf.py +0 -0
  85. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/print/table.py +0 -0
  86. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/stats/correlate.py +0 -0
  87. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/stats/minf.py +0 -0
  88. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/stats/percent.py +0 -0
  89. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/stats/percent_unique.py +0 -0
  90. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/stats/stdev.py +0 -0
  91. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/strings/concat.py +0 -0
  92. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/strings/length.py +0 -0
  93. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/strings/lower.py +0 -0
  94. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/strings/metaphone.py +0 -0
  95. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/strings/regex.py +0 -0
  96. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/strings/starts_with.py +0 -0
  97. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/strings/strip.py +0 -0
  98. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/strings/substring.py +0 -0
  99. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/strings/upper.py +0 -0
  100. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/testing/debug.py +0 -0
  101. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/validation.py +0 -0
  102. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/validity/fail.py +0 -0
  103. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/validity/failed.py +0 -0
  104. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/variables/track.py +0 -0
  105. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/functions/variables/variables.py +0 -0
  106. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/lark_parser.py +0 -0
  107. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/lark_transformer.py +0 -0
  108. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/matcher.py +0 -0
  109. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/productions/__init__.py +0 -0
  110. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/productions/equality.py +0 -0
  111. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/productions/expression.py +0 -0
  112. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/productions/header.py +0 -0
  113. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/productions/matchable.py +0 -0
  114. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/productions/qualified.py +0 -0
  115. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/productions/reference.py +0 -0
  116. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/productions/term.py +0 -0
  117. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/productions/variable.py +0 -0
  118. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/util/exceptions.py +0 -0
  119. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/util/expression_encoder.py +0 -0
  120. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/util/lark_print_parser.py +0 -0
  121. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/matching/util/print_parser.py +0 -0
  122. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/scanning/__init__.py +0 -0
  123. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/scanning/exceptions.py +0 -0
  124. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/scanning/parser.out +0 -0
  125. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/scanning/parsetab.py +0 -0
  126. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/scanning/scanner.py +0 -0
  127. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/scanning/scanning_lexer.py +0 -0
  128. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/util/config.py +0 -0
  129. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/util/config_exception.py +0 -0
  130. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/util/error.py +0 -0
  131. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/util/exceptions.py +0 -0
  132. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/util/last_line_stats.py +0 -0
  133. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/util/line_monitor.py +0 -0
  134. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/util/log_utility.py +0 -0
  135. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/util/metadata_parser.py +0 -0
  136. {csvpath-0.0.465 → csvpath-0.0.467}/csvpath/util/printer.py +0 -0
  137. {csvpath-0.0.465 → csvpath-0.0.467}/docs/asbool.md +0 -0
  138. {csvpath-0.0.465 → csvpath-0.0.467}/docs/assignment.md +0 -0
  139. {csvpath-0.0.465 → csvpath-0.0.467}/docs/config.md +0 -0
  140. {csvpath-0.0.465 → csvpath-0.0.467}/docs/examples.md +0 -0
  141. {csvpath-0.0.465 → csvpath-0.0.467}/docs/files.md +0 -0
  142. {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/above.md +0 -0
  143. {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/advance.md +0 -0
  144. {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/after_blank.md +0 -0
  145. {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/all.md +0 -0
  146. {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/andor.md +0 -0
  147. {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/any.md +0 -0
  148. {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/average.md +0 -0
  149. {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/between.md +0 -0
  150. {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/collect.md +0 -0
  151. {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/correlate.md +0 -0
  152. {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/count.md +0 -0
  153. {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/count_headers.md +0 -0
  154. {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/date.md +0 -0
  155. {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/empty.md +0 -0
  156. {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/end.md +0 -0
  157. {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/every.md +0 -0
  158. {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/fail.md +0 -0
  159. {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/first.md +0 -0
  160. {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/has_dups.md +0 -0
  161. {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/header.md +0 -0
  162. {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/header_name.md +0 -0
  163. {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/header_names_mismatch.md +0 -0
  164. {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/implementing_functions.md +0 -0
  165. {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/import.md +0 -0
  166. {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/in.md +0 -0
  167. {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/increment.md +0 -0
  168. {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/jinja.md +0 -0
  169. {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/last.md +0 -0
  170. {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/line_number.md +0 -0
  171. {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/max.md +0 -0
  172. {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/metaphone.md +0 -0
  173. {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/mismatch.md +0 -0
  174. {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/no.md +0 -0
  175. {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/not.md +0 -0
  176. {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/now.md +0 -0
  177. {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/percent_unique.md +0 -0
  178. {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/print.md +0 -0
  179. {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/print_line.md +0 -0
  180. {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/print_queue.md +0 -0
  181. {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/regex.md +0 -0
  182. {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/replace.md +0 -0
  183. {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/reset_headers.md +0 -0
  184. {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/stdev.md +0 -0
  185. {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/stop.md +0 -0
  186. {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/string_functions.md +0 -0
  187. {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/subtract.md +0 -0
  188. {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/sum.md +0 -0
  189. {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/total_lines.md +0 -0
  190. {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/track.md +0 -0
  191. {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/variables.md +0 -0
  192. {csvpath-0.0.465 → csvpath-0.0.467}/docs/functions/variables_and_headers.md +0 -0
  193. {csvpath-0.0.465 → csvpath-0.0.467}/docs/grammar.md +0 -0
  194. {csvpath-0.0.465 → csvpath-0.0.467}/docs/headers.md +0 -0
  195. {csvpath-0.0.465 → csvpath-0.0.467}/docs/images/logo-wordmark-white-on-black-trimmed-padded.png +0 -0
  196. {csvpath-0.0.465 → csvpath-0.0.467}/docs/images/logo-wordmark-white-trimmed.png +0 -0
  197. {csvpath-0.0.465 → csvpath-0.0.467}/docs/paths.md +0 -0
  198. {csvpath-0.0.465 → csvpath-0.0.467}/docs/qualifiers.md +0 -0
  199. {csvpath-0.0.465 → csvpath-0.0.467}/docs/references.md +0 -0
  200. {csvpath-0.0.465 → csvpath-0.0.467}/docs/terms.md +0 -0
  201. {csvpath-0.0.465 → csvpath-0.0.467}/docs/variables.md +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: csvpath
3
- Version: 0.0.465
3
+ Version: 0.0.467
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
@@ -728,6 +728,11 @@ class CsvPath(CsvPathPublic, ErrorCollector): # pylint: disable=R0902, R0904
728
728
  self.logger.debug(
729
729
  "CsvPath.matches:703: %s: matches: %s", self.identity, matches
730
730
  )
731
+ #
732
+ # if we are done scanning we can stop
733
+ #
734
+ if self.scanner.is_last(self.line_monitor.physical_line_number):
735
+ self.stop()
731
736
  if matches is True:
732
737
  #
733
738
  # _current_match_count is a placeholder that
@@ -48,7 +48,6 @@ class Empty(MatchDecider):
48
48
  # empty(ref)
49
49
  #
50
50
  def _decide_match(self, skip=None) -> None:
51
- print(f"empty._decide: chs: {self.children}")
52
51
  if len(self.children) == 1 and isinstance(self.children[0], Headers):
53
52
  self._do_headers(skip=skip)
54
53
  elif len(self.children) == 1 and isinstance(self.children[0], Equality):
@@ -61,7 +60,7 @@ class Empty(MatchDecider):
61
60
  def _do_headers(self, skip=None):
62
61
  ret = True
63
62
  for i, h in enumerate(self.matcher.line):
64
- ret = self._is_empty(h)
63
+ ret = ExpressionUtility.is_empty(h)
65
64
  if ret is False:
66
65
  break
67
66
  self.match = ret
@@ -74,15 +73,15 @@ class Empty(MatchDecider):
74
73
  siblings = self.children[0]
75
74
 
76
75
  for s in siblings:
77
- print(f"empty._do_many: a sib: {s}")
78
76
  self._do_one(s)
79
77
  if self.match is False:
80
78
  break
81
79
 
82
80
  def _do_one(self, child, skip=None):
83
81
  v = child.to_value(skip=skip)
84
- self.match = self._is_empty(v)
82
+ self.match = ExpressionUtility.is_empty(v)
85
83
 
84
+ """
86
85
  def _is_empty(self, v):
87
86
  ret = True
88
87
  if v is None:
@@ -99,3 +98,4 @@ class Empty(MatchDecider):
99
98
  else:
100
99
  ret = False
101
100
  return ret
101
+ """
@@ -27,6 +27,7 @@ from .headers.header_names_mismatch import HeaderNamesMismatch
27
27
  from .headers.collect import Collect
28
28
  from .headers.replace import Replace
29
29
  from .headers.headers import Headers
30
+ from .headers.empty_stack import EmptyStack
30
31
  from .headers.mismatch import Mismatch
31
32
  from .headers.end import End
32
33
  from .math.above import AboveBelow
@@ -69,6 +70,7 @@ from .lines.after_blank import AfterBlank
69
70
  from .variables.variables import Variables
70
71
  from .variables.pushpop import Push, PushDistinct, Pop, Peek, PeekSize, Stack
71
72
  from .variables.get import Get
73
+ from .variables.put import Put
72
74
  from .variables.track import Track
73
75
  from .misc.random import Random
74
76
  from .misc.nonef import Nonef
@@ -335,6 +337,8 @@ class FunctionFactory:
335
337
  f = Between(matcher, name, child)
336
338
  elif name == "get":
337
339
  f = Get(matcher, name, child)
340
+ elif name == "put":
341
+ f = Put(matcher, name, child)
338
342
  elif name == "debug":
339
343
  f = Debug(matcher, name, child)
340
344
  elif name == "brief_stack_trace":
@@ -351,6 +355,9 @@ class FunctionFactory:
351
355
  f = RowTable(matcher, name, child)
352
356
  elif name == "var_table":
353
357
  f = VarTable(matcher, name, child)
358
+ elif name == "empty_stack":
359
+ f = EmptyStack(matcher, name, child)
360
+
354
361
  else:
355
362
  if (
356
363
  f is None
@@ -0,0 +1,50 @@
1
+ # pylint: disable=C0114
2
+ from csvpath.matching.productions import Equality, Header, Variable
3
+ from csvpath.matching.util.exceptions import ChildrenException
4
+ from csvpath.matching.util.expression_utility import ExpressionUtility
5
+ from ..function_focus import ValueProducer
6
+
7
+
8
+ class EmptyStack(ValueProducer):
9
+ """collects empty header names and/or indexes in a stack var."""
10
+
11
+ def check_valid(self) -> None:
12
+ self.validate_zero_or_more_args(types=[Header, Variable])
13
+ super().check_valid() # pragma: no cover
14
+
15
+ def _produce_value(self, skip=None) -> None:
16
+ if len(self.children) == 0:
17
+ self._do_all()
18
+ elif len(self.children) == 1 and isinstance(self.children[0], Equality):
19
+ self._do_some()
20
+ else:
21
+ self._do_one()
22
+
23
+ def _decide_match(self, skip=None) -> None:
24
+ st = self.to_value(skip=skip)
25
+ self.match = st and len(st) != 0
26
+
27
+ def _do_all(self, skip=None):
28
+ self.value = []
29
+ ml = len(self.matcher.line)
30
+ for i, h in enumerate(self.matcher.csvpath.headers):
31
+ if ml > i:
32
+ if ExpressionUtility.is_empty(self.matcher.line[i]):
33
+ self.value.append(h)
34
+ else:
35
+ self.value.append(h)
36
+
37
+ def _do_some(self, skip=None):
38
+ siblings = self.children[0].commas_to_list()
39
+ print(f"emmpty_stack: do_some: sibs: {siblings}")
40
+ self.value = []
41
+ for s in siblings:
42
+ v = s.to_value(skip=skip)
43
+ b = ExpressionUtility.is_empty(v)
44
+ if b:
45
+ self.value.append(s.name)
46
+ print(f"sib: {s}: {v} = {b}")
47
+
48
+ def _do_one(self, child, skip=None):
49
+ v = child.to_value(skip=skip)
50
+ self.value = [ExpressionUtility.is_empty(v)]
@@ -9,7 +9,7 @@ class Get(ValueProducer):
9
9
 
10
10
  def check_valid(self) -> None:
11
11
  self.validate_one_or_two_args(
12
- one=[Header, Term, Function],
12
+ one=[Header, Term, Function, Variable],
13
13
  left=[Header, Term, Function, Variable],
14
14
  right=[Header, Term, Function, Variable],
15
15
  )
@@ -17,11 +17,7 @@ class Get(ValueProducer):
17
17
 
18
18
  def _produce_value(self, skip=None) -> None:
19
19
  varname = None
20
- c1 = self._child_one()
21
- if isinstance(c1, Variable):
22
- varname = c1.name
23
- else:
24
- varname = self._value_one(skip=skip)
20
+ varname = self._value_one(skip=skip)
25
21
  c2 = self._child_two()
26
22
  v = self.matcher.get_variable(varname)
27
23
  if v is None:
@@ -16,23 +16,24 @@ class Push(SideEffect):
16
16
  k = eq.left.to_value(skip=skip)
17
17
  v = eq.right.to_value(skip=skip)
18
18
  stack = self.matcher.get_variable(k, set_if_none=[])
19
- if self.has_qualifier("distinct") and v in stack:
20
- pass
21
- elif isinstance(stack, tuple):
19
+ if stack is None or isinstance(stack, tuple):
22
20
  self.matcher.csvpath.logger.warning( # pragma: no cover
23
- "Push cannot add to the stack because it is a tuple. The run may be ending."
21
+ "Push cannot add to the stack. The run may be ending."
24
22
  )
25
- elif stack is not None:
26
- stack.append(v)
23
+ elif self.has_qualifier("distinct") and v in stack:
24
+ pass
25
+ elif self.notnone and ExpressionUtility.is_empty(v):
26
+ pass
27
27
  else:
28
- self.matcher.csvpath.logger.warning( # pragma: no cover
29
- "No default stack was created. Run may be ending."
30
- )
31
- self.value = True
28
+ stack.append(v)
29
+ self.value = stack
32
30
 
33
31
  def _decide_match(self, skip=None) -> None:
34
32
  self.to_value(skip=skip)
35
- self.match = self.default_match()
33
+ if self.notnone:
34
+ self.match = not ExpressionUtility.is_empty(self.value)
35
+ else:
36
+ self.match = self.default_match()
36
37
 
37
38
 
38
39
  class PushDistinct(Push):
@@ -0,0 +1,30 @@
1
+ # pylint: disable=C0114
2
+ from csvpath.matching.productions import Header, Variable, Term
3
+ from ..function_focus import ValueProducer
4
+ from ..function import Function
5
+
6
+
7
+ class Put(ValueProducer):
8
+ """Sets a variable with or without a tracking value"""
9
+
10
+ def check_valid(self) -> None:
11
+ self.validate_two_or_three_args()
12
+ super().check_valid()
13
+
14
+ def _produce_value(self, skip=None) -> None:
15
+ varname = None
16
+ c1 = self._child_one()
17
+ varname = c1.to_value(skip=skip)
18
+ c2 = self._child_two()
19
+ key = c2.to_value(skip=skip)
20
+ value = None
21
+ if len(self.children[0].children) > 2:
22
+ value = self.children[0].children[2].to_value(skip=skip)
23
+ else:
24
+ value = key
25
+ key = None
26
+ self.matcher.set_variable(varname, value=value, tracking=key)
27
+ self.value = self._apply_default_value()
28
+
29
+ def _decide_match(self, skip=None) -> None:
30
+ self.match = self.to_value(skip=skip) is not None # pragma: no cover
@@ -38,12 +38,27 @@ class ExpressionUtility:
38
38
  return True
39
39
  elif v == "None":
40
40
  return True
41
- elif f"{v}" == "nan":
41
+ elif cls.isnan(v) or v == "nan":
42
42
  return True
43
43
  elif f"{v}".strip() == "":
44
44
  return True
45
45
  return False
46
46
 
47
+ @classmethod
48
+ def is_empty(cls, v):
49
+ ret = cls.is_none(v)
50
+ if not ret and (isinstance(v, list) or isinstance(v, tuple)):
51
+ if len(v) == 0:
52
+ ret = True
53
+ else:
54
+ for item in v:
55
+ ret = cls.is_empty(item)
56
+ if not ret:
57
+ break
58
+ elif not ret and isinstance(v, dict):
59
+ ret = len(v) == 0
60
+ return ret
61
+
47
62
  @classmethod
48
63
  def isnan(cls, v) -> bool:
49
64
  try:
@@ -0,0 +1,32 @@
1
+
2
+ # Empty Stack
3
+
4
+ The `empty_stack()` function collects the names of empty values. Its primary job is identifying headers without values. However, it can also check on variables.
5
+
6
+ `empty_stack()` without arguments scans all the headers for values and creates a stack of the names of any that are empty. You can provide any number of arguments to `empty_stack()` to narrow its search down to just those values, both headers and variables.
7
+
8
+
9
+ ## Example
10
+
11
+ ```bash
12
+ $file.csv[*][
13
+ push("empties", empty_stack())
14
+ last() -> var_table("empties")
15
+ ]
16
+ ```
17
+
18
+ This csvpath creates an `empties` variable that is a stack of stacks. Each item in the `empties` stack represents the empty headers in a line. The result might look like:
19
+
20
+ ┌───────────────────────────┐
21
+ │ empties │
22
+ ├───────────────────────────┤
23
+ │ ['firstname', 'lastname'] │
24
+ ├───────────────────────────┤
25
+ │ ['firstname'] │
26
+ ├───────────────────────────┤
27
+ │ ['lastname'] │
28
+ ├───────────────────────────┤
29
+ │ [] │
30
+ └───────────────────────────┘
31
+
32
+
@@ -0,0 +1,31 @@
1
+
2
+ # Get and Put
3
+
4
+ ## `get()`
5
+
6
+ `get()` returns the value of a variable. It can access tracking values and stack indexes. Note that this function is important in a few cases but generally duplicates the ability to use `@varname.tracking` syntax.
7
+
8
+ The variable access by `get()` is dynamic. If you pass a term, e.g. "my_var", you access the named variable. Likewise, if you pass a header, the value of the header names the variable `get()` retrieves.
9
+
10
+ If there is a second argument then the variable must be either a dictionary or a list. In CsvPaths terminology, a variable with tracking values or a stack.
11
+
12
+ If any reference doesn't work -- i.e. the variable isn't found or the tracking value or index doesn't exist -- the return is None. A warning will be logged.
13
+
14
+ ## `put()`
15
+
16
+ `put()` lets you set a variable dynamically. It's most important use is for setting tracking values.
17
+
18
+ The syntax is `put(varname, value)` or `put(varname, tracking_key, tracking_value)`. The names and values are dynamic. This means that the name of the value could be the value of a header or another variable. If the variable doesn't exist it will be created.
19
+
20
+ ## Examples
21
+
22
+ ```bash
23
+ $[1*][
24
+ tally(#firstname)
25
+ @john = get("tally_firstname", "John")
26
+ @john == 2 -> print("We have seen $.variables.john humans")
27
+ ]
28
+ ```
29
+
30
+ This contrived csvpath creates a tally of `#firstname`. The `@john` variable pulls the tally count keyed by the "John" tracking value. When the count hits `2` we print a message.
31
+
@@ -14,7 +14,9 @@ This family of functions allows you to create list variables.
14
14
 
15
15
  Push can be called in the form `push_distinct()` or it can take a `distinct` qualifier. (The `distinct` qualifier may become well-known, but at the moment is ad hoc just for `push()`).
16
16
 
17
- Peek will return None if you attempt to peek an index that doesn't exist. Likewise Popping when there is nothing on the list to pop returns None.
17
+ Push can also take a `notnone` qualifier. When `notnone` is set `push()` will not add an empty value to the stack. It will also not match lines while the stack is empty.
18
+
19
+ `peek()` will return None if you attempt to peek an index that doesn't exist. Likewise Popping when there is nothing on the list to pop returns None.
18
20
 
19
21
  Peek and Pop can take the `asbool` qualifier in order to make their match depend on interpreting the value returned as a bool.
20
22
 
@@ -3,31 +3,31 @@
3
3
 
4
4
  Tracks the value of a variable, function, or header. Tally always matches. It also collects its tally regardless of other matches or failures to match, unless you add the `onmatch` qualifier.
5
5
 
6
- Tally keeps its count in variables named for the values it is tracking. A header would be tracked under its name, as:
6
+ Tally keeps its count in variables named for the values it is tracking. A header would be tracked under its name, prefixed by `tally_`, as:
7
7
 
8
- {'firstname': {'Fred':3}}
8
+ {'tally_firstname': {'Fred':3}}
9
9
 
10
10
  Tally can track multiple values. Each of the values becomes a variable under its own name.
11
11
 
12
- Tally also tracks the concatenation of the multiple values under the key `tally`. To use another key name add a non-keyword qualifier to tally.
12
+ Tally also tracks the concatenation of the multiple values under the key `tally`. To use another key name add a non-keyword qualifier to tally. E.g. `tally.birds(#bird_color, #bird_name)` has a tally variable of `birds` with values like `blue|bluebird`,`red|redbird`.
13
13
 
14
14
  ## Examples
15
15
 
16
16
  $file.csv[*][tally(#lastname)]
17
17
 
18
- This path creates a `lastname` variable like:
18
+ This path creates a `tally_lastname` variable like:
19
19
 
20
- {'lastname': {'Kermet': 1, 'Smith':3}}
20
+ {'tally_lastname': {'Kermet': 1, 'Smith':3}}
21
21
 
22
22
  Multiple values can be used as arguments to tally().
23
23
 
24
24
  $file.csv[*][tally(#firstname, #lastname)]
25
25
 
26
- This path creates variables for firstname and lastname. In addition it creates a `tally` variable that holds the concatenation of the values, pipe delimited. The set of variables are like:
26
+ This path creates variables for firstname and lastname. In addition it creates a variable named `tally` that holds the concatenation of the values, pipe delimited. The set of variables are like:
27
27
 
28
28
  {
29
- 'firstname': {'David': 3, 'Bob':5},
30
- 'lastname':{'Jones':2, 'Smith':5},
29
+ 'tally_firstname': {'David': 3, 'Bob':5},
30
+ 'tally_lastname':{'Jones':2, 'Smith':5},
31
31
  'tally':{'David|Jones':1, 'Bob|Smith':1, ...
32
32
  }
33
33
 
@@ -35,14 +35,14 @@ To limit tally to only matching rows use the `onmatch` qualifier like this:
35
35
 
36
36
  $file.csv[*][
37
37
  or( #firstname == "Frog", #firstname == "Ants" )
38
- tally.my_name_tally.onmatch(#firstname, #lastname)
38
+ tally.my_tally.onmatch(#firstname, #lastname)
39
39
  ]
40
40
 
41
41
  Which would result in variables like these:
42
42
 
43
43
  {
44
- 'firstname': {'Frog': 2, 'Ants': 1},
45
- 'lastname': {'Bat': 3},
46
- 'my_name_tally': {'Frog|Bat': 2, 'Ants|Bat': 1}
44
+ 'my_tally_firstname': {'Frog': 2, 'Ants': 1},
45
+ 'my_tally_lastname': {'Bat': 3},
46
+ 'my_tally': {'Frog|Bat': 2, 'Ants|Bat': 1}
47
47
  }
48
48