python-clu 0.8.4__tar.gz → 0.10.0__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 (269) hide show
  1. {python-clu-0.8.4 → python_clu-0.10.0}/CLASSIFIERS.txt +1 -2
  2. {python-clu-0.8.4 → python_clu-0.10.0}/Makefile +2 -2
  3. {python-clu-0.8.4 → python_clu-0.10.0}/PKG-INFO +38 -4
  4. python_clu-0.10.0/clu/__version__.py +1 -0
  5. {python-clu-0.8.4 → python_clu-0.10.0}/clu/abstract.py +29 -25
  6. {python-clu-0.8.4 → python_clu-0.10.0}/clu/config/filebase.py +2 -3
  7. {python-clu-0.8.4 → python_clu-0.10.0}/clu/config/keymap.py +21 -8
  8. {python-clu-0.8.4 → python_clu-0.10.0}/clu/config/ns.py +94 -75
  9. {python-clu-0.8.4 → python_clu-0.10.0}/clu/config/proxy.py +9 -9
  10. {python-clu-0.8.4 → python_clu-0.10.0}/clu/config/settings.py +1 -1
  11. {python-clu-0.8.4 → python_clu-0.10.0}/clu/constants/consts.py +16 -4
  12. {python-clu-0.8.4 → python_clu-0.10.0}/clu/exporting.py +78 -2
  13. {python-clu-0.8.4 → python_clu-0.10.0}/clu/extending.py +29 -29
  14. {python-clu-0.8.4 → python_clu-0.10.0}/clu/fs/filesystem.py +16 -19
  15. {python-clu-0.8.4 → python_clu-0.10.0}/clu/importing/base.py +3 -2
  16. {python-clu-0.8.4 → python_clu-0.10.0}/clu/keyvalue.py +7 -7
  17. {python-clu-0.8.4 → python_clu-0.10.0}/clu/repl/ansi.py +0 -2
  18. python_clu-0.10.0/clu/scripts/dictroast.py +185 -0
  19. {python-clu-0.8.4 → python_clu-0.10.0}/clu/scripts/repl.py +5 -2
  20. {python-clu-0.8.4 → python_clu-0.10.0}/clu/scripts/treeline.py +215 -84
  21. {python-clu-0.8.4 → python_clu-0.10.0}/clu/testing/utils.py +3 -3
  22. {python-clu-0.8.4 → python_clu-0.10.0}/clu/version/__init__.py +15 -9
  23. {python-clu-0.8.4 → python_clu-0.10.0}/noxfile.py +2 -2
  24. {python-clu-0.8.4 → python_clu-0.10.0}/python_clu.egg-info/PKG-INFO +38 -4
  25. {python-clu-0.8.4 → python_clu-0.10.0}/python_clu.egg-info/SOURCES.txt +1 -1
  26. {python-clu-0.8.4 → python_clu-0.10.0}/python_clu.egg-info/requires.txt +1 -0
  27. {python-clu-0.8.4 → python_clu-0.10.0}/requirements/dev.txt +1 -1
  28. {python-clu-0.8.4 → python_clu-0.10.0}/requirements/install.txt +1 -0
  29. {python-clu-0.8.4 → python_clu-0.10.0}/setup.cfg +1 -1
  30. {python-clu-0.8.4 → python_clu-0.10.0}/setup.py +1 -1
  31. {python-clu-0.8.4 → python_clu-0.10.0}/tests/test_abstract.py +68 -0
  32. {python-clu-0.8.4 → python_clu-0.10.0}/tests/test_config.py +5 -4
  33. {python-clu-0.8.4 → python_clu-0.10.0}/tests/test_exporting.py +10 -6
  34. {python-clu-0.8.4 → python_clu-0.10.0}/tests/test_extending.py +6 -8
  35. {python-clu-0.8.4 → python_clu-0.10.0}/tests/test_keyvalue.py +12 -10
  36. {python-clu-0.8.4 → python_clu-0.10.0}/tests/test_repr.py +12 -11
  37. {python-clu-0.8.4 → python_clu-0.10.0}/tests/test_version.py +19 -6
  38. {python-clu-0.8.4 → python_clu-0.10.0}/tox.ini +1 -1
  39. python-clu-0.8.4/.bumpversion.cfg +0 -16
  40. python-clu-0.8.4/clu/__version__.py +0 -1
  41. {python-clu-0.8.4 → python_clu-0.10.0}/.coveragerc +0 -0
  42. {python-clu-0.8.4 → python_clu-0.10.0}/.editorconfig +0 -0
  43. {python-clu-0.8.4 → python_clu-0.10.0}/.gitchangelog.rc +0 -0
  44. {python-clu-0.8.4 → python_clu-0.10.0}/.gitignore +0 -0
  45. {python-clu-0.8.4 → python_clu-0.10.0}/.landscape.yml +0 -0
  46. {python-clu-0.8.4 → python_clu-0.10.0}/.travis.yml +0 -0
  47. {python-clu-0.8.4 → python_clu-0.10.0}/ABOUT.md +0 -0
  48. {python-clu-0.8.4 → python_clu-0.10.0}/CHANGELOG.md +0 -0
  49. {python-clu-0.8.4 → python_clu-0.10.0}/CODE_OF_CONDUCT.md +0 -0
  50. {python-clu-0.8.4 → python_clu-0.10.0}/COPYING.md +0 -0
  51. {python-clu-0.8.4 → python_clu-0.10.0}/LICENSE.txt +0 -0
  52. {python-clu-0.8.4 → python_clu-0.10.0}/MANIFEST.in +0 -0
  53. {python-clu-0.8.4 → python_clu-0.10.0}/README.md +0 -0
  54. {python-clu-0.8.4 → python_clu-0.10.0}/appveyor.yml +0 -0
  55. {python-clu-0.8.4 → python_clu-0.10.0}/clu/__init__.py +0 -0
  56. {python-clu-0.8.4 → python_clu-0.10.0}/clu/__main__.py +0 -0
  57. {python-clu-0.8.4 → python_clu-0.10.0}/clu/all.py +0 -0
  58. {python-clu-0.8.4 → python_clu-0.10.0}/clu/api/__init__.py +0 -0
  59. {python-clu-0.8.4 → python_clu-0.10.0}/clu/api/__main__.py +0 -0
  60. {python-clu-0.8.4 → python_clu-0.10.0}/clu/application.py +0 -0
  61. {python-clu-0.8.4 → python_clu-0.10.0}/clu/compilation/__init__.py +0 -0
  62. {python-clu-0.8.4 → python_clu-0.10.0}/clu/compilation/compiledb.py +0 -0
  63. {python-clu-0.8.4 → python_clu-0.10.0}/clu/compilation/macros.py +0 -0
  64. {python-clu-0.8.4 → python_clu-0.10.0}/clu/config/__init__.py +0 -0
  65. {python-clu-0.8.4 → python_clu-0.10.0}/clu/config/abc.py +0 -0
  66. {python-clu-0.8.4 → python_clu-0.10.0}/clu/config/base.py +0 -0
  67. {python-clu-0.8.4 → python_clu-0.10.0}/clu/config/codecs.py +0 -0
  68. {python-clu-0.8.4 → python_clu-0.10.0}/clu/config/env.py +0 -0
  69. {python-clu-0.8.4 → python_clu-0.10.0}/clu/config/fieldtypes.py +0 -0
  70. {python-clu-0.8.4 → python_clu-0.10.0}/clu/config/formats/__init__.py +0 -0
  71. {python-clu-0.8.4 → python_clu-0.10.0}/clu/config/formats/jsonfile.py +0 -0
  72. {python-clu-0.8.4 → python_clu-0.10.0}/clu/config/formats/picklefile.py +0 -0
  73. {python-clu-0.8.4 → python_clu-0.10.0}/clu/config/formats/tomlfile.py +0 -0
  74. {python-clu-0.8.4 → python_clu-0.10.0}/clu/config/formats/yamlfile.py +0 -0
  75. {python-clu-0.8.4 → python_clu-0.10.0}/clu/config/keymapview.py +0 -0
  76. {python-clu-0.8.4 → python_clu-0.10.0}/clu/constants/__init__.py +0 -0
  77. {python-clu-0.8.4 → python_clu-0.10.0}/clu/constants/__main__.py +0 -0
  78. {python-clu-0.8.4 → python_clu-0.10.0}/clu/constants/data.py +0 -0
  79. {python-clu-0.8.4 → python_clu-0.10.0}/clu/constants/enums.py +0 -0
  80. {python-clu-0.8.4 → python_clu-0.10.0}/clu/constants/exceptions.py +0 -0
  81. {python-clu-0.8.4 → python_clu-0.10.0}/clu/constants/polyfills.py +0 -0
  82. {python-clu-0.8.4 → python_clu-0.10.0}/clu/csv.py +0 -0
  83. {python-clu-0.8.4 → python_clu-0.10.0}/clu/dicts.py +0 -0
  84. {python-clu-0.8.4 → python_clu-0.10.0}/clu/dispatch.py +0 -0
  85. {python-clu-0.8.4 → python_clu-0.10.0}/clu/enums.py +0 -0
  86. {python-clu-0.8.4 → python_clu-0.10.0}/clu/fs/__init__.py +0 -0
  87. {python-clu-0.8.4 → python_clu-0.10.0}/clu/fs/abc.py +0 -0
  88. {python-clu-0.8.4 → python_clu-0.10.0}/clu/fs/appdirectories.py +0 -0
  89. {python-clu-0.8.4 → python_clu-0.10.0}/clu/fs/misc.py +0 -0
  90. {python-clu-0.8.4 → python_clu-0.10.0}/clu/fs/pypath.py +0 -0
  91. {python-clu-0.8.4 → python_clu-0.10.0}/clu/fs/sourcetree.py +0 -0
  92. {python-clu-0.8.4 → python_clu-0.10.0}/clu/importing/__init__.py +0 -0
  93. {python-clu-0.8.4 → python_clu-0.10.0}/clu/importing/__main__.py +0 -0
  94. {python-clu-0.8.4 → python_clu-0.10.0}/clu/importing/proxy.py +0 -0
  95. {python-clu-0.8.4 → python_clu-0.10.0}/clu/mathematics.py +0 -0
  96. {python-clu-0.8.4 → python_clu-0.10.0}/clu/naming.py +0 -0
  97. {python-clu-0.8.4 → python_clu-0.10.0}/clu/predicates.py +0 -0
  98. {python-clu-0.8.4 → python_clu-0.10.0}/clu/repl/__init__.py +0 -0
  99. {python-clu-0.8.4 → python_clu-0.10.0}/clu/repl/banners.py +0 -0
  100. {python-clu-0.8.4 → python_clu-0.10.0}/clu/repl/cli/__init__.py +0 -0
  101. {python-clu-0.8.4 → python_clu-0.10.0}/clu/repl/cli/boilerplate.py +0 -0
  102. {python-clu-0.8.4 → python_clu-0.10.0}/clu/repl/cli/boilerplate_copy.py +0 -0
  103. {python-clu-0.8.4 → python_clu-0.10.0}/clu/repl/cli/print_version.py +0 -0
  104. {python-clu-0.8.4 → python_clu-0.10.0}/clu/repl/columnize.py +0 -0
  105. {python-clu-0.8.4 → python_clu-0.10.0}/clu/repl/modules.py +0 -0
  106. {python-clu-0.8.4 → python_clu-0.10.0}/clu/repr.py +0 -0
  107. {python-clu-0.8.4 → python_clu-0.10.0}/clu/sanitizer.py +0 -0
  108. {python-clu-0.8.4 → python_clu-0.10.0}/clu/scripts/.gitignore +0 -0
  109. {python-clu-0.8.4 → python_clu-0.10.0}/clu/scripts/README.md +0 -0
  110. {python-clu-0.8.4 → python_clu-0.10.0}/clu/scripts/__init__.py +0 -0
  111. {python-clu-0.8.4 → python_clu-0.10.0}/clu/scripts/ansicolors.py +0 -0
  112. {python-clu-0.8.4 → python_clu-0.10.0}/clu/scripts/boilerplate.py +0 -0
  113. {python-clu-0.8.4 → python_clu-0.10.0}/clu/scripts/legacy/forkumask.py +0 -0
  114. {python-clu-0.8.4 → python_clu-0.10.0}/clu/scripts/legacy/repl-bpython.py +0 -0
  115. {python-clu-0.8.4 → python_clu-0.10.0}/clu/scripts/legacy/repl-ipython.py +0 -0
  116. {python-clu-0.8.4 → python_clu-0.10.0}/clu/scripts/legacy/repl-ptpython.py +0 -0
  117. {python-clu-0.8.4 → python_clu-0.10.0}/clu/scripts/legacy/repl-pyzo.py +0 -0
  118. {python-clu-0.8.4 → python_clu-0.10.0}/clu/scripts/legacy/xdg-runtime.py +0 -0
  119. {python-clu-0.8.4 → python_clu-0.10.0}/clu/scripts/prediversus.py +0 -0
  120. {python-clu-0.8.4 → python_clu-0.10.0}/clu/shelving/__init__.py +0 -0
  121. {python-clu-0.8.4 → python_clu-0.10.0}/clu/shelving/redat.py +0 -0
  122. {python-clu-0.8.4 → python_clu-0.10.0}/clu/shelving/redis.conf +0 -0
  123. {python-clu-0.8.4 → python_clu-0.10.0}/clu/stdio.py +0 -0
  124. {python-clu-0.8.4 → python_clu-0.10.0}/clu/testing/__init__.py +0 -0
  125. {python-clu-0.8.4 → python_clu-0.10.0}/clu/testing/hook.py +0 -0
  126. {python-clu-0.8.4 → python_clu-0.10.0}/clu/testing/obsolete.py +0 -0
  127. {python-clu-0.8.4 → python_clu-0.10.0}/clu/testing/pytest.py +0 -0
  128. {python-clu-0.8.4 → python_clu-0.10.0}/clu/typespace/__init__.py +0 -0
  129. {python-clu-0.8.4 → python_clu-0.10.0}/clu/typespace/__main__.py +0 -0
  130. {python-clu-0.8.4 → python_clu-0.10.0}/clu/typespace/namespace.py +0 -0
  131. {python-clu-0.8.4 → python_clu-0.10.0}/clu/typology.py +0 -0
  132. {python-clu-0.8.4 → python_clu-0.10.0}/clu/version/__main__.py +0 -0
  133. {python-clu-0.8.4 → python_clu-0.10.0}/clu/version/git_version.py +0 -0
  134. {python-clu-0.8.4 → python_clu-0.10.0}/clu/version/read_version.py +0 -0
  135. {python-clu-0.8.4 → python_clu-0.10.0}/codecov.yml +0 -0
  136. {python-clu-0.8.4 → python_clu-0.10.0}/conftest.py +0 -0
  137. {python-clu-0.8.4 → python_clu-0.10.0}/docs/Makefile +0 -0
  138. {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/doctrees/api.doctree +0 -0
  139. {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/doctrees/environment.pickle +0 -0
  140. {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/doctrees/generated/clu.doctree +0 -0
  141. {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/doctrees/index.doctree +0 -0
  142. {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/.buildinfo +0 -0
  143. {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_sources/api.rst.txt +0 -0
  144. {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_sources/generated/clu.rst.txt +0 -0
  145. {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_sources/index.rst.txt +0 -0
  146. {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/_sphinx_javascript_frameworks_compat.js +0 -0
  147. {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/alabaster.css +0 -0
  148. {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/basic.css +0 -0
  149. {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/css/badge_only.css +0 -0
  150. {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/css/fonts/Roboto-Slab-Bold.woff +0 -0
  151. {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/css/fonts/Roboto-Slab-Bold.woff2 +0 -0
  152. {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/css/fonts/Roboto-Slab-Regular.woff +0 -0
  153. {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/css/fonts/Roboto-Slab-Regular.woff2 +0 -0
  154. {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/css/fonts/fontawesome-webfont.eot +0 -0
  155. {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/css/fonts/fontawesome-webfont.svg +0 -0
  156. {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/css/fonts/fontawesome-webfont.ttf +0 -0
  157. {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/css/fonts/fontawesome-webfont.woff +0 -0
  158. {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/css/fonts/fontawesome-webfont.woff2 +0 -0
  159. {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/css/fonts/lato-bold-italic.woff +0 -0
  160. {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/css/fonts/lato-bold-italic.woff2 +0 -0
  161. {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/css/fonts/lato-bold.woff +0 -0
  162. {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/css/fonts/lato-bold.woff2 +0 -0
  163. {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/css/fonts/lato-normal-italic.woff +0 -0
  164. {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/css/fonts/lato-normal-italic.woff2 +0 -0
  165. {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/css/fonts/lato-normal.woff +0 -0
  166. {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/css/fonts/lato-normal.woff2 +0 -0
  167. {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/css/theme.css +0 -0
  168. {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/custom.css +0 -0
  169. {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/doctools.js +0 -0
  170. {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/documentation_options.js +0 -0
  171. {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/file.png +0 -0
  172. {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/jquery-3.6.0.js +0 -0
  173. {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/jquery.js +0 -0
  174. {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/js/badge_only.js +0 -0
  175. {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/js/html5shiv-printshiv.min.js +0 -0
  176. {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/js/html5shiv.min.js +0 -0
  177. {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/js/theme.js +0 -0
  178. {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/language_data.js +0 -0
  179. {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/minus.png +0 -0
  180. {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/plus.png +0 -0
  181. {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/pygments.css +0 -0
  182. {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/searchtools.js +0 -0
  183. {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/underscore-1.13.1.js +0 -0
  184. {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/underscore.js +0 -0
  185. {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/api.html +0 -0
  186. {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/generated/clu.html +0 -0
  187. {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/genindex.html +0 -0
  188. {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/index.html +0 -0
  189. {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/objects.inv +0 -0
  190. {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/py-modindex.html +0 -0
  191. {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/search.html +0 -0
  192. {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/searchindex.js +0 -0
  193. {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/man/clu.1 +0 -0
  194. {python-clu-0.8.4 → python_clu-0.10.0}/docs/make.bat +0 -0
  195. {python-clu-0.8.4 → python_clu-0.10.0}/docs/source/api.rst +0 -0
  196. {python-clu-0.8.4 → python_clu-0.10.0}/docs/source/conf.py +0 -0
  197. {python-clu-0.8.4 → python_clu-0.10.0}/docs/source/generated/clu.rst +0 -0
  198. {python-clu-0.8.4 → python_clu-0.10.0}/docs/source/index.rst +0 -0
  199. {python-clu-0.8.4 → python_clu-0.10.0}/hooks/autohook.sh +0 -0
  200. {python-clu-0.8.4 → python_clu-0.10.0}/hooks/post-push/00-coverage.sh +0 -0
  201. {python-clu-0.8.4 → python_clu-0.10.0}/hooks/pre-push/00-noop.sh +0 -0
  202. {python-clu-0.8.4 → python_clu-0.10.0}/hooks/pre-push/01-direnv-stdlib.sh +0 -0
  203. {python-clu-0.8.4 → python_clu-0.10.0}/hooks/scripts/coverage.sh +0 -0
  204. {python-clu-0.8.4 → python_clu-0.10.0}/hooks/scripts/display-issues.sh +0 -0
  205. {python-clu-0.8.4 → python_clu-0.10.0}/hooks/scripts/git-pushex +0 -0
  206. {python-clu-0.8.4 → python_clu-0.10.0}/hooks/scripts/noop.sh +0 -0
  207. {python-clu-0.8.4 → python_clu-0.10.0}/mypy.ini +0 -0
  208. {python-clu-0.8.4 → python_clu-0.10.0}/pyproject.toml +0 -0
  209. {python-clu-0.8.4 → python_clu-0.10.0}/pytest.ini +0 -0
  210. {python-clu-0.8.4 → python_clu-0.10.0}/python_clu.egg-info/dependency_links.txt +0 -0
  211. {python-clu-0.8.4 → python_clu-0.10.0}/python_clu.egg-info/entry_points.txt +0 -0
  212. {python-clu-0.8.4 → python_clu-0.10.0}/python_clu.egg-info/top_level.txt +0 -0
  213. {python-clu-0.8.4 → python_clu-0.10.0}/python_clu.egg-info/zip-safe +0 -0
  214. {python-clu-0.8.4 → python_clu-0.10.0}/pytype.cfg +0 -0
  215. {python-clu-0.8.4 → python_clu-0.10.0}/requirements/changelog.txt +0 -0
  216. {python-clu-0.8.4 → python_clu-0.10.0}/requirements/docs.txt +0 -0
  217. {python-clu-0.8.4 → python_clu-0.10.0}/requirements/nox/codecov.txt +0 -0
  218. {python-clu-0.8.4 → python_clu-0.10.0}/requirements/nox/docs.txt +0 -0
  219. {python-clu-0.8.4 → python_clu-0.10.0}/requirements/nox/manifest.txt +0 -0
  220. {python-clu-0.8.4 → python_clu-0.10.0}/requirements/nox/repl.txt +0 -0
  221. {python-clu-0.8.4 → python_clu-0.10.0}/requirements/nox/tests.txt +0 -0
  222. {python-clu-0.8.4 → python_clu-0.10.0}/requirements/tox.txt +0 -0
  223. {python-clu-0.8.4 → python_clu-0.10.0}/requirements/typecheck.txt +0 -0
  224. {python-clu-0.8.4 → python_clu-0.10.0}/scratch/direnv_transformed_env.py +0 -0
  225. {python-clu-0.8.4 → python_clu-0.10.0}/scratch/inline-tests-ImportError-uggggh.ipynb +0 -0
  226. {python-clu-0.8.4 → python_clu-0.10.0}/scratch/nteract.ipynb +0 -0
  227. {python-clu-0.8.4 → python_clu-0.10.0}/tests/__init__.py +0 -0
  228. {python-clu-0.8.4 → python_clu-0.10.0}/tests/data/1-58.jpg +0 -0
  229. {python-clu-0.8.4 → python_clu-0.10.0}/tests/data/3471426989_aa8e83cac5_o.jpg +0 -0
  230. {python-clu-0.8.4 → python_clu-0.10.0}/tests/data/3472236406_1fbf1a567d_o.jpg +0 -0
  231. {python-clu-0.8.4 → python_clu-0.10.0}/tests/data/8600JC.jpg +0 -0
  232. {python-clu-0.8.4 → python_clu-0.10.0}/tests/data/8ba.png +0 -0
  233. {python-clu-0.8.4 → python_clu-0.10.0}/tests/data/IMG_20180505_205153567.jpg +0 -0
  234. {python-clu-0.8.4 → python_clu-0.10.0}/tests/data/cheetah-003.jpg +0 -0
  235. {python-clu-0.8.4 → python_clu-0.10.0}/tests/data/config/clu-config.toml +0 -0
  236. {python-clu-0.8.4 → python_clu-0.10.0}/tests/data/config/yodogg.toml +0 -0
  237. {python-clu-0.8.4 → python_clu-0.10.0}/tests/data/shutterstock_90194617.jpg +0 -0
  238. {python-clu-0.8.4 → python_clu-0.10.0}/tests/data/yodata/09163d51421853.5608b3c2a1be0.jpg +0 -0
  239. {python-clu-0.8.4 → python_clu-0.10.0}/tests/data/yodata/5d0227342500004e12e3506d.jpg +0 -0
  240. {python-clu-0.8.4 → python_clu-0.10.0}/tests/data/yodata/BlackCat2_large-22.jpg +0 -0
  241. {python-clu-0.8.4 → python_clu-0.10.0}/tests/data/yodogg/Serval_Cat_Kitten-706.jpg +0 -0
  242. {python-clu-0.8.4 → python_clu-0.10.0}/tests/data/yodogg/Servals_Thoiry_19801.jpg +0 -0
  243. {python-clu-0.8.4 → python_clu-0.10.0}/tests/data/yodogg/video-pride-serval.jpg +0 -0
  244. {python-clu-0.8.4 → python_clu-0.10.0}/tests/test_all.py +0 -0
  245. {python-clu-0.8.4 → python_clu-0.10.0}/tests/test_boilerplate.py +0 -0
  246. {python-clu-0.8.4 → python_clu-0.10.0}/tests/test_config_abc.py +0 -0
  247. {python-clu-0.8.4 → python_clu-0.10.0}/tests/test_csv.py +0 -0
  248. {python-clu-0.8.4 → python_clu-0.10.0}/tests/test_dicts.py +0 -0
  249. {python-clu-0.8.4 → python_clu-0.10.0}/tests/test_dispatch.py +0 -0
  250. {python-clu-0.8.4 → python_clu-0.10.0}/tests/test_enum_aliases.py +0 -0
  251. {python-clu-0.8.4 → python_clu-0.10.0}/tests/test_fs_abc.py +0 -0
  252. {python-clu-0.8.4 → python_clu-0.10.0}/tests/test_fs_appdirectories.py +0 -0
  253. {python-clu-0.8.4 → python_clu-0.10.0}/tests/test_fs_filesystem.py +0 -0
  254. {python-clu-0.8.4 → python_clu-0.10.0}/tests/test_fs_misc.py +0 -0
  255. {python-clu-0.8.4 → python_clu-0.10.0}/tests/test_importing.py +0 -0
  256. {python-clu-0.8.4 → python_clu-0.10.0}/tests/test_mathematics.py +0 -0
  257. {python-clu-0.8.4 → python_clu-0.10.0}/tests/test_naming.py +0 -0
  258. {python-clu-0.8.4 → python_clu-0.10.0}/tests/test_predicates.py +0 -0
  259. {python-clu-0.8.4 → python_clu-0.10.0}/tests/test_repl_columnize.py +0 -0
  260. {python-clu-0.8.4 → python_clu-0.10.0}/tests/test_repl_modules.py +0 -0
  261. {python-clu-0.8.4 → python_clu-0.10.0}/tests/test_scripts_repl.py +0 -0
  262. {python-clu-0.8.4 → python_clu-0.10.0}/tests/test_typespace_namespace.py +0 -0
  263. {python-clu-0.8.4 → python_clu-0.10.0}/tests/test_typology.py +0 -0
  264. {python-clu-0.8.4 → python_clu-0.10.0}/tests/yodogg/.tm_properties +0 -0
  265. {python-clu-0.8.4 → python_clu-0.10.0}/tests/yodogg/__init__.py +0 -0
  266. {python-clu-0.8.4 → python_clu-0.10.0}/tests/yodogg/yodogg/__init__.py +0 -0
  267. {python-clu-0.8.4 → python_clu-0.10.0}/tests/yodogg/yodogg/config.py +0 -0
  268. {python-clu-0.8.4 → python_clu-0.10.0}/tests/yodogg/yodogg/exporting.py +0 -0
  269. {python-clu-0.8.4 → python_clu-0.10.0}/tests/yodogg/yodogg/iheard.py +0 -0
@@ -12,7 +12,6 @@ Operating System :: POSIX
12
12
  Operating System :: Unix
13
13
  Programming Language :: Python
14
14
  Programming Language :: Python :: 3
15
- Programming Language :: Python :: 3.7
16
- Programming Language :: Python :: 3.8
15
+ Programming Language :: Python :: 3.10
17
16
  Programming Language :: Python :: Implementation :: CPython
18
17
  Programming Language :: Python :: Implementation :: PyPy
@@ -47,10 +47,10 @@ twine-upload: cython sdist wheel
47
47
  twine upload -s $(PROJECT_BASE)/dist/*
48
48
 
49
49
  bump:
50
- bump2version --verbose patch
50
+ bump-my-version bump patch --verbose
51
51
 
52
52
  bigbump:
53
- bump2version --verbose minor
53
+ bump-my-version bump minor --verbose
54
54
 
55
55
  check: clean-test-artifacts
56
56
  check-manifest -v
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: python-clu
3
- Version: 0.8.4
3
+ Version: 0.10.0
4
4
  Summary: CLU - Common Lightweight Utilities, or Command-Line Utilities (your pick)
5
5
  Home-page: https://github.com/fish2000/clu
6
6
  Download-URL: https://github.com/fish2000/clu/zipball/master
@@ -23,13 +23,47 @@ Classifier: Operating System :: POSIX
23
23
  Classifier: Operating System :: Unix
24
24
  Classifier: Programming Language :: Python
25
25
  Classifier: Programming Language :: Python :: 3
26
- Classifier: Programming Language :: Python :: 3.7
27
- Classifier: Programming Language :: Python :: 3.8
26
+ Classifier: Programming Language :: Python :: 3.10
28
27
  Classifier: Programming Language :: Python :: Implementation :: CPython
29
28
  Classifier: Programming Language :: Python :: Implementation :: PyPy
30
29
  Description-Content-Type: text/markdown
31
30
  License-File: LICENSE.txt
32
31
  License-File: COPYING.md
32
+ Requires-Dist: Click>=7.0
33
+ Requires-Dist: colorama>=0.4.0
34
+ Requires-Dist: dataclasses>=0.6; python_version < "3.7"
35
+ Requires-Dist: dbx-stopwatch>=1.6
36
+ Requires-Dist: enum34>=1.1.0; python_version < "3.4"
37
+ Requires-Dist: heapdict>=1.0.0
38
+ Requires-Dist: humanize>=1.0.0
39
+ Requires-Dist: importlib-metadata>=1.4.0; python_version < "3.8"
40
+ Requires-Dist: mock>=4.0.0
41
+ Requires-Dist: multidict>=4.7.0
42
+ Requires-Dist: packaging
43
+ Requires-Dist: pout>=0.8.13
44
+ Requires-Dist: pygments>=2.0.0
45
+ Requires-Dist: PyYAML>=5.3.0
46
+ Requires-Dist: redis>=3.4.0
47
+ Requires-Dist: setuptools>=30.0.0
48
+ Requires-Dist: six>=1.10.0
49
+ Requires-Dist: termcolor>=1.1.0
50
+ Requires-Dist: toml>=0.10.0
51
+ Requires-Dist: wheel>=0.34.0
52
+ Requires-Dist: zict>=0.1.2
53
+ Requires-Dist: zipp>=2.0.0
54
+ Dynamic: author
55
+ Dynamic: author-email
56
+ Dynamic: classifier
57
+ Dynamic: description
58
+ Dynamic: description-content-type
59
+ Dynamic: download-url
60
+ Dynamic: home-page
61
+ Dynamic: keywords
62
+ Dynamic: license
63
+ Dynamic: license-file
64
+ Dynamic: platform
65
+ Dynamic: requires-dist
66
+ Dynamic: summary
33
67
 
34
68
  CLU – Common Lightweight Utilities (née Command-Line Utilities)
35
69
  ==================================================
@@ -0,0 +1 @@
1
+ __version__ = '0.10.0'
@@ -30,6 +30,33 @@ class Slotted(abc.ABCMeta):
30
30
  attributes,
31
31
  **kwargs)
32
32
 
33
+ class SlotMatch(Slotted):
34
+
35
+ """ A metaclass that ensures its classes, and all subclasses,
36
+ will be slotted types with “__match_args__” set to the
37
+ sum of the “__slots__” values for this and all ancestors.
38
+ """
39
+
40
+ def __new__(metacls, name, bases, attributes, **kwargs):
41
+ """ Override for `abc.ABCMeta.__new__(…)` setting up a
42
+ derived slotted class with “__match_args__” set.
43
+ """
44
+ from clu.predicates import slots_for
45
+
46
+ # Ensure the new class will have a “__match_args__” attribute
47
+ if '__match_args__' not in attributes:
48
+ attributes['__match_args__'] = tuple()
49
+
50
+ # Create the new class via “super(…)” – calling “Slotted.__new__(…)”
51
+ cls = super(SlotMatch, metacls).__new__(metacls, name, # type: ignore
52
+ bases,
53
+ attributes,
54
+ **kwargs)
55
+
56
+ # Set “__match_args__” using “slots_for(…)” and return
57
+ cls.__match_args__ = slots_for(cls)
58
+ return cls
59
+
33
60
  class NonSlotted(abc.ABCMeta):
34
61
 
35
62
  """ A metaclass that ensures its classes, and all subclasses,
@@ -369,30 +396,7 @@ class ManagedContext(contextlib.AbstractContextManager):
369
396
  self.teardown()
370
397
  return exc_type is None
371
398
 
372
- if consts.PYTHON_VERSION >= 3.7: # pragma: no cover
373
-
374
- class AsyncManagedContext(ManagedContext,
375
- contextlib.AbstractAsyncContextManager):
376
-
377
- async def __aenter__(self):
378
- self.setup()
379
- if hasattr(self, '__await__'):
380
- if callable(self.__await__):
381
- await self
382
- return self
383
-
384
- async def __aexit__(self, exc_type=None,
385
- exc_val=None,
386
- exc_tb=None):
387
- self.teardown()
388
- return exc_type is None
389
-
390
- else:
391
-
392
- class AsyncManagedContext(ManagedContext):
393
- pass
394
-
395
- __all__ = ('Slotted', 'NonSlotted',
399
+ __all__ = ('Slotted', 'SlotMatch', 'NonSlotted',
396
400
  'UnhashableMeta', 'Unhashable',
397
401
  'Format', 'NonFormat', 'SlottedFormat', 'Sanitizer',
398
402
  'Cloneable',
@@ -401,6 +405,6 @@ __all__ = ('Slotted', 'NonSlotted',
401
405
  'BaseDescriptor', 'DataDescriptor', 'NamedDescriptor',
402
406
  'CacheDescriptor', 'Descriptor', 'ValueDescriptor',
403
407
  'BasePath', 'AppName',
404
- 'ManagedContext', 'AsyncManagedContext')
408
+ 'ManagedContext')
405
409
 
406
410
  __dir__ = lambda: list(__all__)
@@ -9,8 +9,7 @@ import sys
9
9
  abstract = abc.abstractmethod
10
10
 
11
11
  from clu.constants.enums import System, SYSTEM
12
- # from clu.config.abc import FrozenKeyMap
13
- from clu.config.base import NamespacedMutableMapping
12
+ from clu.config.keymap import Nested
14
13
  from clu.fs.appdirectories import AppDirs
15
14
  from clu.fs.filesystem import TemporaryName, Directory
16
15
  from clu.fs.misc import extension, filesize
@@ -138,7 +137,7 @@ class FileName(clu.abstract.AppName, metaclass=abc.ABCMeta):
138
137
  return Directory(root_dir.realpath()).subpath(file_name)
139
138
 
140
139
  @export
141
- class FileBase(NamespacedMutableMapping, FileName): # type: ignore
140
+ class FileBase(Nested, FileName): # type: ignore
142
141
 
143
142
  """ The FileBase abstract base class furnishes two methods:
144
143
 
@@ -75,7 +75,7 @@ class FrozenFlat(FrozenKeyMap, clu.abstract.ReprWrapper,
75
75
  """ Articulate a flattened KeyMap instance out into one that is nested. """
76
76
  if cls is None:
77
77
  cls = FrozenNested
78
- return cls(tree=articulate(self.dictionary))
78
+ return cls(tree=articulate(self.dictionary, walker=flatwalk))
79
79
 
80
80
  def __iter__(self):
81
81
  yield from self.dictionary
@@ -118,10 +118,14 @@ class Flat(FrozenFlat, KeyMap):
118
118
  del self.dictionary[nskey]
119
119
 
120
120
  @export
121
- def dictify(treeish):
122
- """ Recursively convert a possibly nested mapping to standard dicts. """
121
+ def dictify(treeish, cls=dict):
122
+ """ Recursively convert a possibly nested mapping to dicts.
123
+
124
+ Standard Python dicts will be created by default; specify
125
+ a custom class with the “cls” argument to use your own.
126
+ """
123
127
  if ismapping(treeish):
124
- return { key : dictify(value) for key, value in treeish.items() }
128
+ return cls({ key : dictify(value, cls=cls) for key, value in treeish.items() })
125
129
  return treeish
126
130
 
127
131
  @export
@@ -164,9 +168,18 @@ class FrozenNested(NamespaceWalker, clu.abstract.ReprWrapper,
164
168
  tree = getattr(tree, 'tree')
165
169
  elif hasattr(tree, 'nestify'):
166
170
  tree = getattr(tree.nestify(), 'tree')
167
- self.tree = dictify(dict(tree or {}))
171
+ self.tree = dictify(dict(tree or {}), cls=dict)
168
172
  if updates:
169
- self.tree.update(**updates)
173
+ for nskey, value in updates.items():
174
+ key, namespaces = unpack_ns(nskey)
175
+ d = self.tree
176
+ for namespace in namespaces:
177
+ try:
178
+ d = d[namespace]
179
+ except KeyError:
180
+ d[namespace] = {}
181
+ d = d[namespace]
182
+ d[key] = value
170
183
 
171
184
  def walk(self):
172
185
  """ Iteratively walk the nested KeyMap’s tree of dicts. """
@@ -387,12 +400,12 @@ def test():
387
400
  @inline
388
401
  def test_frozennested_contains():
389
402
  """ FrozenNested contains namespaced key """
390
- nested = FrozenNested(tree=nestedmaps(), **arbitrary())
403
+ nested = FrozenNested(tree=nestedmaps())
391
404
 
392
405
  for mappingpath in mapwalk(nested.tree):
393
406
  *namespaces, key, value = mappingpath
394
407
  nskey = pack_ns(key, *namespaces)
395
- assert nskey in nested or nskey in arbitrary()
408
+ assert nskey in nested
396
409
 
397
410
  @inline
398
411
  def test_nested_contains():
@@ -188,82 +188,14 @@ __all__, __dir__ = exporter.all_and_dir()
188
188
  def test():
189
189
 
190
190
  from clu.testing.utils import inline
191
- from clu.config.keymap import Flat
191
+ from clu.config.keymap import Flat, Nested
192
+ from clu.config.keymap import nestedmaps, flatdict, arbitrary
192
193
  from clu.fs.filesystem import which
193
194
  from pprint import pprint
194
195
  import os, re, textwrap
195
196
 
196
- flat = Flat()
197
-
198
- javaprop_re = re.compile(r"^(?P<name>[\w\.]+): “(?P<value>.*)”", re.IGNORECASE | re.MULTILINE)
199
- java_source = textwrap.dedent("""
200
- package ost.%s;
201
-
202
- import java.util.Enumeration;
203
- import java.util.Properties;
204
-
205
- public class ShowJavaSystemProperties {
206
-
207
- public static void main(String... args) {
208
- Properties properties = System.getProperties();
209
- Enumeration names = properties.propertyNames();
210
- while (names.hasMoreElements()) {
211
- String name = (String) names.nextElement();
212
- String value = properties.getProperty(name);
213
- System.out.println(name + ": “" + value + "”");
214
- }
215
- }
216
-
217
- }
218
- """ % exporter.dotpath)
219
-
220
- @inline.precheck
221
- def load_java_system_properties():
222
- """ Load the Java JDK’s system properties """
223
- from clu.fs.filesystem import back_tick, TemporaryName
224
- from clu.naming import dotpath_to_prefix
225
-
226
- with TemporaryName(prefix="show-java-system-properties-",
227
- suffix="java",
228
- randomized=True) as java_file:
229
- java_file.write(java_source)
230
- java_path = java_file.realpath()
231
- output = back_tick(f"java {java_path}")
232
-
233
- assert not java_file.exists
234
-
235
- for line in output.splitlines():
236
- match = javaprop_re.match(line)
237
- if match:
238
- # BEWARE: dotpath_to_prefix(…) does a casefold():
239
- name = dotpath_to_prefix(match.group('name'),
240
- sep=NAMESPACE_SEP, end='')
241
- value = match.group('value')
242
- flat[name] = value
243
-
244
- pprint(flat)
245
-
246
- @inline.precheck
247
- def show_java_system_properties():
248
- """ Show namespaced Java system properties """
249
- count = flat.namespace_count()
250
- plural = count == 1 and '' or 's'
251
-
252
- print(f"* {count} namespace{plural} total:")
253
- print()
254
-
255
- for namespace in flat.namespaces():
256
- namespaces = split_ns(namespace)
257
- print(f"+ {namespace}:")
258
- for nskey, value in flat.items(*namespaces):
259
- bare_key = strip_ns(nskey)
260
- key = nskey.replace(prefix_for(*namespaces), '', 1)
261
- print(f" {key} : “{value}”")
262
- assert key.endswith(bare_key)
263
- print()
264
-
265
- print("- «unprefixed»:")
266
- pprint(flat.submap(unprefixed=True), indent=4)
197
+ flat = Flat(flatdict())
198
+ nested = Nested(nestedmaps())
267
199
 
268
200
  @inline
269
201
  def test_flat_validate_ns():
@@ -277,6 +209,18 @@ def test():
277
209
  for namespace in flat.freeze().namespaces():
278
210
  assert validate_ns(*split_ns(namespace))
279
211
 
212
+ @inline
213
+ def test_nested_validate_ns():
214
+ """ Validate a Nested keymap’s namespaces """
215
+ for namespace in nested.namespaces():
216
+ assert validate_ns(*split_ns(namespace))
217
+
218
+ @inline
219
+ def test_frozennested_validate_ns():
220
+ """ Validate a FrozenNested keymap’s namespaces """
221
+ for namespace in nested.freeze().namespaces():
222
+ assert validate_ns(*split_ns(namespace))
223
+
280
224
  @inline
281
225
  def test_validate_ns_errors():
282
226
  """ Check “validate_ns(…)” error conditions """
@@ -290,9 +234,84 @@ def test():
290
234
  except ValueError as exc:
291
235
  assert "namespace contains separator" in str(exc)
292
236
 
293
- if not which('java'):
294
- print("[WARNING] skipping `clu.config.ns` tests – `java` executable not found")
295
- return os.EX_OK
237
+ namespaces = ('yo', 'dogg')
238
+ key = 'iheard'
239
+ nskey = "yo:dogg:iheard"
240
+ value = "you like this sort of thing"
241
+
242
+ @inline
243
+ def test_concatenate_ns():
244
+ assert concatenate_ns(*namespaces) == "yo:dogg"
245
+
246
+ @inline
247
+ def test_prefix_for():
248
+ assert prefix_for(*namespaces) == "yo:dogg:"
249
+
250
+ @inline
251
+ def test_strip_ns():
252
+ assert strip_ns(nskey) == "iheard"
253
+
254
+ @inline
255
+ def test_split_ns():
256
+ assert tuple(split_ns(nskey)) == ('yo', 'dogg', 'iheard')
257
+ assert split_ns(nskey) == ['yo', 'dogg', 'iheard']
258
+
259
+ @inline
260
+ def test_startswith_ns():
261
+ assert startswith_ns(namespaces, ('yo', 'dogg'))
262
+
263
+ @inline
264
+ def test_unpack_ns():
265
+ assert unpack_ns(nskey) == (key, list(namespaces))
266
+ assert unpack_ns(nskey) == ('iheard', ['yo', 'dogg'])
267
+
268
+ @inline
269
+ def test_pack_ns():
270
+ assert pack_ns(key, *namespaces) == nskey
271
+ assert pack_ns(key, *namespaces) == "yo:dogg:iheard"
272
+
273
+ @inline
274
+ def test_get_ns():
275
+ assert get_ns(nskey) == "yo:dogg"
276
+
277
+ @inline
278
+ def test_get_ns_and_key():
279
+ assert get_ns_and_key(nskey) == ("yo:dogg", 'iheard')
280
+
281
+ @inline
282
+ def test_compare_ns():
283
+ assert compare_ns(namespaces, ('yo', 'dogg'))
284
+
285
+ appname = 'testing'
286
+ envkey = "TESTING_YO_DOGG_IHEARD"
287
+
288
+ @inline
289
+ def test_concatenate_env():
290
+ assert concatenate_env(*namespaces) == "YO_DOGG"
291
+ assert concatenate_env(*chain(tuplize(appname), namespaces)) == "TESTING_YO_DOGG"
292
+ assert concatenate_env(*chain(tuplize(appname), namespaces, tuplize(key))) == "TESTING_YO_DOGG_IHEARD"
293
+
294
+ @inline
295
+ def test_prefix_env():
296
+ assert prefix_env(appname, *namespaces) == "TESTING_YO_DOGG_"
297
+
298
+ @inline
299
+ def test_pack_env():
300
+ assert pack_env(appname, key, *namespaces) == "TESTING_YO_DOGG_IHEARD"
301
+
302
+ @inline
303
+ def test_unpack_env():
304
+ assert unpack_env(envkey) == (appname, key, list(namespaces))
305
+ assert unpack_env(envkey) == ('testing', 'iheard', ['yo', 'dogg'])
306
+
307
+ @inline
308
+ def test_nskey_from_env():
309
+ assert nskey_from_env(envkey) == (appname, pack_ns(key, *namespaces))
310
+ assert nskey_from_env(envkey) == ('testing', "yo:dogg:iheard")
311
+
312
+ @inline
313
+ def test_nskey_to_env():
314
+ assert nskey_to_env(appname, nskey) == "TESTING_YO_DOGG_IHEARD"
296
315
 
297
316
  return inline.test(100)
298
317
 
@@ -162,7 +162,7 @@ def test():
162
162
 
163
163
  from clu.testing.utils import inline
164
164
  from clu.config.ns import unpack_ns
165
- from clu.config.keymap import FrozenFlat, Flat
165
+ from clu.config.keymap import FrozenFlat, Flat, Nested
166
166
  from clu.config.keymap import nestedmaps, flatdict
167
167
  from pprint import pprint
168
168
 
@@ -311,19 +311,19 @@ def test():
311
311
  return test_fn
312
312
 
313
313
  # Add inline test functions using the metafunction test generators:
314
- inline.add_function(test_one_fn(FrozenFlat, KeyMapView, flatdict), 'test_one')
315
- inline.add_function(test_two_fn(FrozenFlat, KeyMapView, flatdict), 'test_two')
316
- inline.add_function(test_one_fn(Flat, KeyMapView, flatdict), 'test_three')
317
- inline.add_function(test_one_fn(Flat, KeyMapProxy, flatdict), 'test_three_point_five')
314
+ inline.add_function(test_one_fn(FrozenFlat, KeyMapView, flatdict), 'test_one_frozenflat_keymapview')
315
+ inline.add_function(test_two_fn(FrozenFlat, KeyMapView, flatdict), 'test_two_frozenflat_keymapview')
316
+ inline.add_function(test_one_fn(Flat, KeyMapView, flatdict), 'test_one_flat_keymapview')
317
+ inline.add_function(test_one_fn(Flat, KeyMapProxy, flatdict), 'test_one_flat_keymapproxy')
318
318
  inline.add_function(test_two_fn(Flat, KeyMapProxy, flatdict,
319
- KeyMapView), 'test_four')
319
+ KeyMapView), 'test_two_flat_keymapproxy')
320
320
 
321
321
  # N.B. These two take FUCKING FOREVER to run:
322
- # inline.add_function(test_one_fn(Nested, KeyMapView, nestedmaps), 'test_five')
323
- # inline.add_function(test_one_fn(Nested, KeyMapProxy, nestedmaps), 'test_five_point_five')
322
+ inline.add_function(test_one_fn(Nested, KeyMapView, nestedmaps), 'test_one_nested_keymapview')
323
+ inline.add_function(test_one_fn(Nested, KeyMapProxy, nestedmaps), 'test_one_nested_keymapproxy')
324
324
 
325
325
  @inline
326
- def test_six():
326
+ def test_view_proxy_exceptions():
327
327
  """ View/Proxy error conditions """
328
328
  try:
329
329
  KeyMapView(None)
@@ -23,7 +23,7 @@ from clu.exporting import Exporter
23
23
  exporter = Exporter(path=__file__)
24
24
  export = exporter.decorator()
25
25
 
26
- NEED_NAME = PYTHON_VERSION < 3.6
26
+ NEED_NAME = PYTHON_VERSION < "3.6"
27
27
 
28
28
  class Nestifier(abc.ABC):
29
29
 
@@ -17,6 +17,9 @@ else:
17
17
  if not callable(path): # pragma: no cover
18
18
  path = sys.intern
19
19
 
20
+ # Get VersionInfo from clu.version:
21
+ from clu.version import VersionInfo
22
+
20
23
  # Define the “pytuple” shortcut lambda:
21
24
  pytuple = lambda *attrs: tuple(f'__{atx}__' for atx in attrs)
22
25
 
@@ -132,9 +135,9 @@ PY3 = sys.version_info.major > 2
132
135
  # Determine if we’re on PyPy:
133
136
  PYPY = hasattr(sys, 'pypy_version_info')
134
137
 
135
- # A float representation of the Python version:
136
- PYTHON_VERSION = float("%s%s%s" % (sys.version_info.major, os.extsep,
137
- sys.version_info.minor))
138
+ # The current Python major/minor version:
139
+ PYTHON_VERSION = VersionInfo("%s%s%s" % (sys.version_info.major, os.extsep,
140
+ sys.version_info.minor))
138
141
 
139
142
  # Qualifier for qualified-name operations:
140
143
  QUALIFIER = sys.intern(os.extsep)
@@ -206,11 +209,20 @@ VERBOTEN += ('Namespace', 'SimpleNamespace')
206
209
  # Regex for picking up whitespace:
207
210
  WHITESPACE = re.compile(r'\s+')
208
211
 
209
- class NoDefault(object):
212
+ class MetaNoDefault(type):
213
+ """ A metaclasss to make a type Falsey. """
214
+ def __bool__(cls):
215
+ return False
216
+
217
+ class NoDefault(metaclass=MetaNoDefault):
210
218
  """ A singleton object to signify a lack of an argument. """
211
219
  __slots__ = tuple() # type: tuple
220
+
212
221
  def __new__(cls, *args, **kwargs): # pragma: no cover
213
222
  return cls
223
+
224
+ def __bool__(self):
225
+ return False
214
226
 
215
227
  # Manually rename `pytuple(…)` per mechanism of “clu.exporting.Exporter”:
216
228
  pytuple.__lambda_name__ = λ # type: ignore
@@ -9,9 +9,11 @@ import clu.abstract
9
9
  import collections
10
10
  import collections.abc
11
11
  import contextlib
12
+ import hashlib
12
13
  import importlib
13
14
  import inspect
14
15
  import itertools
16
+ import shelve
15
17
  import sys, os
16
18
  import warnings
17
19
  import weakref
@@ -21,7 +23,7 @@ chain = itertools.chain
21
23
  iterchain = itertools.chain.from_iterable
22
24
 
23
25
  from clu.constants.consts import (λ, φ, # type: ignore
24
- APPNAME, BASEPATH, BUILTINS,
26
+ APPNAME, BASEPATH, BUILTINS, ENCODING,
25
27
  EXPORTER_NAME, QUALIFIER, ROOT_PATH,
26
28
  NoDefault, pytuple)
27
29
  from clu.constants.exceptions import BadDotpathWarning, ExportError, ExportWarning
@@ -31,7 +33,6 @@ cache = lambda function: lru_cache(maxsize=128, typed=False)(function)
31
33
 
32
34
  # Not what you are looking for
33
35
  NotYourThing = object()
34
- # NotYourID = id(NotYourThing)
35
36
 
36
37
  def itermodule(module):
37
38
  """ Get an iterable of `(name, thing)` tuples for all things
@@ -182,6 +183,13 @@ def search_modules(thing, *modules):
182
183
  return module, key
183
184
  return None, None
184
185
 
186
+ @cache
187
+ def stringhash(string):
188
+ """ Expediently hash a string to another string """
189
+ digester = hashlib.sha256()
190
+ digester.update(bytes(string, encoding=ENCODING))
191
+ return digester.hexdigest()
192
+
185
193
  def determine_name(thing, name=None, try_repr=False):
186
194
  """ Private module function to find a name for a thing. """
187
195
  # Shortcut everything if a name was explictly specified:
@@ -512,6 +520,44 @@ class ExporterBase(collections.abc.MutableMapping,
512
520
  else:
513
521
  self.__exports__.update(d)
514
522
 
523
+ def hash(self):
524
+ """ Return a stringified hash value corresponding to this
525
+ particular exporter instances’ dotpath.
526
+ """
527
+ return self.dotpath and stringhash(self.dotpath) or None
528
+
529
+ def datafile(self):
530
+ """ Return a unique filename for this instance """
531
+ from clu.fs.appdirectories import AppDirs
532
+ from clu.constants.exceptions import FilesystemError
533
+
534
+ # Initialize an AppDirs instance:
535
+ appdirs = AppDirs(appname=type(self).appname)
536
+
537
+ # Ensure the user config directory exists:
538
+ try:
539
+ appdirs.user_config.makedirs()
540
+ except FilesystemError:
541
+ pass
542
+
543
+ # Construct database filename:
544
+ selfhash = self.hash()
545
+ if not selfhash:
546
+ raise AttributeError("Could not hash the exporter instances’ dotpath")
547
+ return Path(appdirs.user_config / selfhash + ".pkl")
548
+
549
+ @contextlib.contextmanager
550
+ def data(self, path=NoDefault):
551
+ """ Context manager for opening a shelving database, corresponding
552
+ to this particular exporter instances’ dotpath.
553
+ """
554
+ if path is NoDefault:
555
+ path = self.datafile()
556
+
557
+ # Yield out a proper shelving database instance:
558
+ with contextlib.closing(shelve.open(os.fspath(path), writeback=True)) as shelving:
559
+ yield shelving
560
+
515
561
  def exports(self):
516
562
  """ Get a new dictionary instance filled with the exports. """
517
563
  out = {} # type: dict
@@ -864,6 +910,7 @@ with exporter as export:
864
910
  export(search_for_name)
865
911
  export(search_for_module)
866
912
  export(search_modules)
913
+ export(stringhash)
867
914
  export(determine_name)
868
915
  export(path_to_dotpath)
869
916
  export(thismodule, name='thismodule', doc="thismodule() → return the name of the module in which the `thismodule()` function was called")
@@ -948,11 +995,40 @@ def test():
948
995
  format_environment_module = search_for_module(utils.format_environment)
949
996
  assert utils == format_environment_module
950
997
 
998
+ @inline
999
+ def test_hash():
1000
+ """ Test the string-hashing of the exporters’ dotpath """
1001
+ expo = Exporter(path=__file__)
1002
+ assert expo.hash() == exporter.hash()
1003
+ print(expo.hash())
1004
+
1005
+ @inline
1006
+ def test_shelving():
1007
+ """ Test the arbitrary data-shelving context manager """
1008
+ from clu.fs.filesystem import TemporaryName
1009
+
1010
+ with TemporaryName(randomized=True, suffix='pkl') as tempfile:
1011
+ tempname = tempfile.name
1012
+ with exporter.data(path=tempfile.name) as database:
1013
+ database['yo'] = 'dogg'
1014
+ database['i_heard'] = 'you like dicts'
1015
+ with exporter.data(path=tempfile.name) as database:
1016
+ assert database['yo'] == 'dogg'
1017
+ assert database['i_heard'] == 'you like dicts'
1018
+ assert len(database) == 2
1019
+
1020
+ assert not os.path.exists(tempname)
1021
+
951
1022
  @inline.diagnostic
952
1023
  def show_search_by_id_cache_info():
953
1024
  print("SEARCH-BY-ID CACHE INFO:")
954
1025
  print(Exporter.cache_info())
955
1026
 
1027
+ @inline.diagnostic
1028
+ def show_stringhash_cache_info():
1029
+ print("STRINGHASH CACHE INFO:")
1030
+ print(stringhash.cache_info())
1031
+
956
1032
  return inline.test(100)
957
1033
 
958
1034
  if __name__ == '__main__':