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.
- {python-clu-0.8.4 → python_clu-0.10.0}/CLASSIFIERS.txt +1 -2
- {python-clu-0.8.4 → python_clu-0.10.0}/Makefile +2 -2
- {python-clu-0.8.4 → python_clu-0.10.0}/PKG-INFO +38 -4
- python_clu-0.10.0/clu/__version__.py +1 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/abstract.py +29 -25
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/config/filebase.py +2 -3
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/config/keymap.py +21 -8
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/config/ns.py +94 -75
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/config/proxy.py +9 -9
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/config/settings.py +1 -1
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/constants/consts.py +16 -4
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/exporting.py +78 -2
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/extending.py +29 -29
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/fs/filesystem.py +16 -19
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/importing/base.py +3 -2
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/keyvalue.py +7 -7
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/repl/ansi.py +0 -2
- python_clu-0.10.0/clu/scripts/dictroast.py +185 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/scripts/repl.py +5 -2
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/scripts/treeline.py +215 -84
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/testing/utils.py +3 -3
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/version/__init__.py +15 -9
- {python-clu-0.8.4 → python_clu-0.10.0}/noxfile.py +2 -2
- {python-clu-0.8.4 → python_clu-0.10.0}/python_clu.egg-info/PKG-INFO +38 -4
- {python-clu-0.8.4 → python_clu-0.10.0}/python_clu.egg-info/SOURCES.txt +1 -1
- {python-clu-0.8.4 → python_clu-0.10.0}/python_clu.egg-info/requires.txt +1 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/requirements/dev.txt +1 -1
- {python-clu-0.8.4 → python_clu-0.10.0}/requirements/install.txt +1 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/setup.cfg +1 -1
- {python-clu-0.8.4 → python_clu-0.10.0}/setup.py +1 -1
- {python-clu-0.8.4 → python_clu-0.10.0}/tests/test_abstract.py +68 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/tests/test_config.py +5 -4
- {python-clu-0.8.4 → python_clu-0.10.0}/tests/test_exporting.py +10 -6
- {python-clu-0.8.4 → python_clu-0.10.0}/tests/test_extending.py +6 -8
- {python-clu-0.8.4 → python_clu-0.10.0}/tests/test_keyvalue.py +12 -10
- {python-clu-0.8.4 → python_clu-0.10.0}/tests/test_repr.py +12 -11
- {python-clu-0.8.4 → python_clu-0.10.0}/tests/test_version.py +19 -6
- {python-clu-0.8.4 → python_clu-0.10.0}/tox.ini +1 -1
- python-clu-0.8.4/.bumpversion.cfg +0 -16
- python-clu-0.8.4/clu/__version__.py +0 -1
- {python-clu-0.8.4 → python_clu-0.10.0}/.coveragerc +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/.editorconfig +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/.gitchangelog.rc +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/.gitignore +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/.landscape.yml +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/.travis.yml +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/ABOUT.md +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/CHANGELOG.md +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/CODE_OF_CONDUCT.md +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/COPYING.md +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/LICENSE.txt +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/MANIFEST.in +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/README.md +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/appveyor.yml +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/__init__.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/__main__.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/all.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/api/__init__.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/api/__main__.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/application.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/compilation/__init__.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/compilation/compiledb.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/compilation/macros.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/config/__init__.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/config/abc.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/config/base.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/config/codecs.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/config/env.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/config/fieldtypes.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/config/formats/__init__.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/config/formats/jsonfile.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/config/formats/picklefile.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/config/formats/tomlfile.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/config/formats/yamlfile.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/config/keymapview.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/constants/__init__.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/constants/__main__.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/constants/data.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/constants/enums.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/constants/exceptions.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/constants/polyfills.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/csv.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/dicts.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/dispatch.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/enums.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/fs/__init__.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/fs/abc.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/fs/appdirectories.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/fs/misc.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/fs/pypath.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/fs/sourcetree.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/importing/__init__.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/importing/__main__.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/importing/proxy.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/mathematics.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/naming.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/predicates.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/repl/__init__.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/repl/banners.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/repl/cli/__init__.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/repl/cli/boilerplate.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/repl/cli/boilerplate_copy.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/repl/cli/print_version.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/repl/columnize.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/repl/modules.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/repr.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/sanitizer.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/scripts/.gitignore +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/scripts/README.md +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/scripts/__init__.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/scripts/ansicolors.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/scripts/boilerplate.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/scripts/legacy/forkumask.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/scripts/legacy/repl-bpython.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/scripts/legacy/repl-ipython.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/scripts/legacy/repl-ptpython.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/scripts/legacy/repl-pyzo.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/scripts/legacy/xdg-runtime.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/scripts/prediversus.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/shelving/__init__.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/shelving/redat.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/shelving/redis.conf +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/stdio.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/testing/__init__.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/testing/hook.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/testing/obsolete.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/testing/pytest.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/typespace/__init__.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/typespace/__main__.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/typespace/namespace.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/typology.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/version/__main__.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/version/git_version.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/clu/version/read_version.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/codecov.yml +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/conftest.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/Makefile +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/doctrees/api.doctree +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/doctrees/environment.pickle +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/doctrees/generated/clu.doctree +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/doctrees/index.doctree +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/.buildinfo +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_sources/api.rst.txt +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_sources/generated/clu.rst.txt +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_sources/index.rst.txt +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/_sphinx_javascript_frameworks_compat.js +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/alabaster.css +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/basic.css +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/css/badge_only.css +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/css/fonts/Roboto-Slab-Bold.woff +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/css/fonts/Roboto-Slab-Bold.woff2 +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/css/fonts/Roboto-Slab-Regular.woff +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/css/fonts/Roboto-Slab-Regular.woff2 +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/css/fonts/fontawesome-webfont.eot +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/css/fonts/fontawesome-webfont.svg +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/css/fonts/fontawesome-webfont.ttf +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/css/fonts/fontawesome-webfont.woff +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/css/fonts/fontawesome-webfont.woff2 +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/css/fonts/lato-bold-italic.woff +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/css/fonts/lato-bold-italic.woff2 +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/css/fonts/lato-bold.woff +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/css/fonts/lato-bold.woff2 +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/css/fonts/lato-normal-italic.woff +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/css/fonts/lato-normal-italic.woff2 +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/css/fonts/lato-normal.woff +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/css/fonts/lato-normal.woff2 +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/css/theme.css +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/custom.css +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/doctools.js +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/documentation_options.js +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/file.png +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/jquery-3.6.0.js +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/jquery.js +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/js/badge_only.js +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/js/html5shiv-printshiv.min.js +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/js/html5shiv.min.js +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/js/theme.js +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/language_data.js +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/minus.png +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/plus.png +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/pygments.css +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/searchtools.js +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/underscore-1.13.1.js +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/_static/underscore.js +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/api.html +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/generated/clu.html +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/genindex.html +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/index.html +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/objects.inv +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/py-modindex.html +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/search.html +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/html/searchindex.js +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/build/man/clu.1 +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/make.bat +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/source/api.rst +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/source/conf.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/source/generated/clu.rst +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/docs/source/index.rst +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/hooks/autohook.sh +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/hooks/post-push/00-coverage.sh +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/hooks/pre-push/00-noop.sh +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/hooks/pre-push/01-direnv-stdlib.sh +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/hooks/scripts/coverage.sh +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/hooks/scripts/display-issues.sh +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/hooks/scripts/git-pushex +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/hooks/scripts/noop.sh +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/mypy.ini +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/pyproject.toml +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/pytest.ini +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/python_clu.egg-info/dependency_links.txt +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/python_clu.egg-info/entry_points.txt +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/python_clu.egg-info/top_level.txt +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/python_clu.egg-info/zip-safe +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/pytype.cfg +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/requirements/changelog.txt +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/requirements/docs.txt +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/requirements/nox/codecov.txt +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/requirements/nox/docs.txt +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/requirements/nox/manifest.txt +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/requirements/nox/repl.txt +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/requirements/nox/tests.txt +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/requirements/tox.txt +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/requirements/typecheck.txt +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/scratch/direnv_transformed_env.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/scratch/inline-tests-ImportError-uggggh.ipynb +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/scratch/nteract.ipynb +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/tests/__init__.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/tests/data/1-58.jpg +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/tests/data/3471426989_aa8e83cac5_o.jpg +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/tests/data/3472236406_1fbf1a567d_o.jpg +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/tests/data/8600JC.jpg +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/tests/data/8ba.png +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/tests/data/IMG_20180505_205153567.jpg +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/tests/data/cheetah-003.jpg +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/tests/data/config/clu-config.toml +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/tests/data/config/yodogg.toml +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/tests/data/shutterstock_90194617.jpg +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/tests/data/yodata/09163d51421853.5608b3c2a1be0.jpg +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/tests/data/yodata/5d0227342500004e12e3506d.jpg +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/tests/data/yodata/BlackCat2_large-22.jpg +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/tests/data/yodogg/Serval_Cat_Kitten-706.jpg +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/tests/data/yodogg/Servals_Thoiry_19801.jpg +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/tests/data/yodogg/video-pride-serval.jpg +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/tests/test_all.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/tests/test_boilerplate.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/tests/test_config_abc.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/tests/test_csv.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/tests/test_dicts.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/tests/test_dispatch.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/tests/test_enum_aliases.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/tests/test_fs_abc.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/tests/test_fs_appdirectories.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/tests/test_fs_filesystem.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/tests/test_fs_misc.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/tests/test_importing.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/tests/test_mathematics.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/tests/test_naming.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/tests/test_predicates.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/tests/test_repl_columnize.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/tests/test_repl_modules.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/tests/test_scripts_repl.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/tests/test_typespace_namespace.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/tests/test_typology.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/tests/yodogg/.tm_properties +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/tests/yodogg/__init__.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/tests/yodogg/yodogg/__init__.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/tests/yodogg/yodogg/config.py +0 -0
- {python-clu-0.8.4 → python_clu-0.10.0}/tests/yodogg/yodogg/exporting.py +0 -0
- {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.
|
|
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
|
-
|
|
50
|
+
bump-my-version bump patch --verbose
|
|
51
51
|
|
|
52
52
|
bigbump:
|
|
53
|
-
|
|
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
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: python-clu
|
|
3
|
-
Version: 0.
|
|
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.
|
|
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
|
-
|
|
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'
|
|
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
|
-
|
|
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(
|
|
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
|
|
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
|
-
|
|
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()
|
|
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
|
|
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
|
-
|
|
294
|
-
|
|
295
|
-
|
|
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), '
|
|
315
|
-
inline.add_function(test_two_fn(FrozenFlat, KeyMapView, flatdict), '
|
|
316
|
-
inline.add_function(test_one_fn(Flat, KeyMapView, flatdict), '
|
|
317
|
-
inline.add_function(test_one_fn(Flat, KeyMapProxy, flatdict), '
|
|
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), '
|
|
319
|
+
KeyMapView), 'test_two_flat_keymapproxy')
|
|
320
320
|
|
|
321
321
|
# N.B. These two take FUCKING FOREVER to run:
|
|
322
|
-
|
|
323
|
-
|
|
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
|
|
326
|
+
def test_view_proxy_exceptions():
|
|
327
327
|
""" View/Proxy error conditions """
|
|
328
328
|
try:
|
|
329
329
|
KeyMapView(None)
|
|
@@ -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
|
-
#
|
|
136
|
-
PYTHON_VERSION =
|
|
137
|
-
|
|
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
|
|
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__':
|