omdev 0.0.0.dev196__tar.gz → 0.0.0.dev198__tar.gz
Sign up to get free protection for your applications and to get access to all the features.
- {omdev-0.0.0.dev196/omdev.egg-info → omdev-0.0.0.dev198}/PKG-INFO +2 -2
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/.manifests.json +12 -0
- omdev-0.0.0.dev198/omdev/tools/linehisto.py +335 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198/omdev.egg-info}/PKG-INFO +2 -2
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev.egg-info/SOURCES.txt +1 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev.egg-info/requires.txt +1 -1
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/pyproject.toml +2 -2
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/LICENSE +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/MANIFEST.in +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/README.rst +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/__about__.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/__init__.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/amalg/__init__.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/amalg/__main__.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/amalg/gen.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/amalg/imports.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/amalg/main.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/amalg/manifests.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/amalg/resources.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/amalg/srcfiles.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/amalg/strip.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/amalg/types.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/amalg/typing.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/antlr/__init__.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/antlr/consts.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/antlr/gen.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/bracepy.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/cache/__init__.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/cache/compute/__init__.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/cache/compute/cache.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/cache/compute/contexts.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/cache/compute/currents.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/cache/compute/fns.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/cache/compute/resolvers.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/cache/compute/storage.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/cache/compute/types.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/cache/data/__init__.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/cache/data/actions.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/cache/data/cache.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/cache/data/consts.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/cache/data/defaults.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/cache/data/manifests.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/cache/data/specs.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/cexts/__init__.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/cexts/_boilerplate.cc +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/cexts/_distutils/LICENSE +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/cexts/_distutils/__init__.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/cexts/_distutils/build_ext.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/cexts/_distutils/compilers/__init__.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/cexts/_distutils/compilers/ccompiler.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/cexts/_distutils/compilers/options.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/cexts/_distutils/compilers/unixccompiler.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/cexts/_distutils/dir_util.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/cexts/_distutils/errors.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/cexts/_distutils/extension.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/cexts/_distutils/file_util.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/cexts/_distutils/modified.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/cexts/_distutils/spawn.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/cexts/_distutils/sysconfig.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/cexts/_distutils/util.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/cexts/_distutils/version.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/cexts/build.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/cexts/cmake.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/cexts/importhook.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/cexts/magic.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/cexts/scan.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/classdot.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/cli/__init__.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/cli/__main__.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/cli/_pathhack.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/cli/clicli.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/cli/install.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/cli/main.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/cli/managers.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/cli/types.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/clipboard/__init__.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/clipboard/clipboard.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/clipboard/darwin_cf.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/clipboard/linux_x11.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/cmake.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/findimports.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/git/__init__.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/git/revisions.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/git/status.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/git/subtrees.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/imgur.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/interp/__init__.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/interp/__main__.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/interp/cli.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/interp/default.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/interp/inject.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/interp/inspect.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/interp/providers/__init__.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/interp/providers/base.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/interp/providers/inject.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/interp/providers/running.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/interp/providers/standalone.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/interp/providers/system.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/interp/pyenv/__init__.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/interp/pyenv/inject.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/interp/pyenv/install.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/interp/pyenv/provider.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/interp/pyenv/pyenv.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/interp/resolvers.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/interp/types.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/interp/uv/__init__.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/interp/uv/inject.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/interp/uv/provider.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/interp/uv/uv.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/interp/venvs.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/magic/__init__.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/magic/__main__.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/magic/cli.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/magic/find.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/magic/magic.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/magic/prepare.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/magic/styles.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/manifests/__init__.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/manifests/__main__.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/manifests/build.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/manifests/main.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/mypy/__init__.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/mypy/debug.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/packaging/__init__.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/packaging/marshal.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/packaging/names.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/packaging/requires.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/packaging/specifiers.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/packaging/versions.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/pip.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/precheck/__init__.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/precheck/__main__.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/precheck/base.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/precheck/git.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/precheck/lite.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/precheck/main.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/precheck/manifests.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/precheck/scripts.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/ptk/__init__.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/ptk/apps/__init__.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/ptk/apps/ncdu.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/pycharm/__init__.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/pycharm/__main__.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/pycharm/cli.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/pyproject/__init__.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/pyproject/__main__.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/pyproject/cexts.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/pyproject/cli.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/pyproject/configs.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/pyproject/inject.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/pyproject/pkg.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/pyproject/reqs.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/pyproject/resources/__init__.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/pyproject/resources/docker-dev.sh +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/pyproject/resources/python.sh +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/pyproject/venvs.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/revisions.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/scripts/__init__.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/scripts/bumpversion.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/scripts/execrss.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/scripts/exectime.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/scripts/importtrace.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/scripts/interp.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/scripts/pyproject.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/scripts/slowcat.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/scripts/tmpexec.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/secrets.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/tagstrings.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/tokens.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/tools/__init__.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/tools/cloc.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/tools/doc.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/tools/docker.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/tools/git.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/tools/importscan.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/tools/json/__init__.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/tools/json/__main__.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/tools/json/cli.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/tools/json/formats.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/tools/json/io.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/tools/json/parsing.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/tools/json/processing.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/tools/json/rendering.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/tools/mkrelimp.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/tools/notebook.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/tools/pawk/__init__.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/tools/pawk/__main__.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/tools/pawk/pawk.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/tools/pip.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/tools/prof.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/tools/qr.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/tools/sqlrepl.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev/wheelfile.py +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev.egg-info/dependency_links.txt +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev.egg-info/entry_points.txt +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/omdev.egg-info/top_level.txt +0 -0
- {omdev-0.0.0.dev196 → omdev-0.0.0.dev198}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: omdev
|
3
|
-
Version: 0.0.0.
|
3
|
+
Version: 0.0.0.dev198
|
4
4
|
Summary: omdev
|
5
5
|
Author: wrmsr
|
6
6
|
License: BSD-3-Clause
|
@@ -12,7 +12,7 @@ Classifier: Operating System :: OS Independent
|
|
12
12
|
Classifier: Operating System :: POSIX
|
13
13
|
Requires-Python: >=3.12
|
14
14
|
License-File: LICENSE
|
15
|
-
Requires-Dist: omlish==0.0.0.
|
15
|
+
Requires-Dist: omlish==0.0.0.dev198
|
16
16
|
Provides-Extra: all
|
17
17
|
Requires-Dist: black~=24.10; extra == "all"
|
18
18
|
Requires-Dist: pycparser~=2.22; extra == "all"
|
@@ -302,6 +302,18 @@
|
|
302
302
|
}
|
303
303
|
}
|
304
304
|
},
|
305
|
+
{
|
306
|
+
"module": ".tools.linehisto",
|
307
|
+
"attr": "_CLI_MODULE",
|
308
|
+
"file": "omdev/tools/linehisto.py",
|
309
|
+
"line": 330,
|
310
|
+
"value": {
|
311
|
+
"$.cli.types.CliModule": {
|
312
|
+
"cmd_name": "linehisto",
|
313
|
+
"mod_name": "omdev.tools.linehisto"
|
314
|
+
}
|
315
|
+
}
|
316
|
+
},
|
305
317
|
{
|
306
318
|
"module": ".tools.mkrelimp",
|
307
319
|
"attr": "_CLI_MODULE",
|
@@ -0,0 +1,335 @@
|
|
1
|
+
"""
|
2
|
+
TODO:
|
3
|
+
- cmd line options
|
4
|
+
- truncation
|
5
|
+
- mean/min/max/median/stddev
|
6
|
+
- delta mean/min/max/median/stddev
|
7
|
+
- heat - red rapidly changing blue stale
|
8
|
+
- paging
|
9
|
+
- find
|
10
|
+
- stdin/stdout redir (ttyname(0))
|
11
|
+
- graph
|
12
|
+
"""
|
13
|
+
import curses
|
14
|
+
import heapq
|
15
|
+
import operator
|
16
|
+
import sys
|
17
|
+
import time
|
18
|
+
import typing as ta
|
19
|
+
|
20
|
+
from ..cli import CliModule
|
21
|
+
|
22
|
+
|
23
|
+
##
|
24
|
+
|
25
|
+
|
26
|
+
def with_timer(interval=5.):
|
27
|
+
def outer(fn):
|
28
|
+
start = time.time()
|
29
|
+
last = start
|
30
|
+
|
31
|
+
def inner(*args, **kwargs):
|
32
|
+
nonlocal last
|
33
|
+
|
34
|
+
now = time.time()
|
35
|
+
if (now - last) < interval:
|
36
|
+
return None
|
37
|
+
|
38
|
+
last = now
|
39
|
+
return fn(*args, **kwargs)
|
40
|
+
|
41
|
+
return inner
|
42
|
+
|
43
|
+
return outer
|
44
|
+
|
45
|
+
|
46
|
+
def calc_percent(a: float, b: float) -> float:
|
47
|
+
if not a or not b:
|
48
|
+
return 0.
|
49
|
+
return ((a * 1e9) // (b * 1e5)) / 100.
|
50
|
+
|
51
|
+
|
52
|
+
##
|
53
|
+
|
54
|
+
|
55
|
+
class KeyedHisto:
|
56
|
+
def __init__(
|
57
|
+
self,
|
58
|
+
*,
|
59
|
+
max_entries: int | None = None,
|
60
|
+
) -> None:
|
61
|
+
super().__init__()
|
62
|
+
|
63
|
+
self.entries: dict[str, int] = {}
|
64
|
+
self.total_seen = 0
|
65
|
+
self.total_evicted = 0
|
66
|
+
|
67
|
+
self.max_entries = max_entries
|
68
|
+
if max_entries is not None:
|
69
|
+
self.eviction_len = int(max_entries * 2)
|
70
|
+
|
71
|
+
self.num_evicted = 0
|
72
|
+
|
73
|
+
def __len__(self) -> int:
|
74
|
+
return len(self.entries)
|
75
|
+
|
76
|
+
@property
|
77
|
+
def total_tracked(self) -> int:
|
78
|
+
return self.total_seen - self.total_evicted
|
79
|
+
|
80
|
+
def inc(self, key: str, n: int = 1) -> int:
|
81
|
+
if self.max_entries is not None and len(self) >= self.eviction_len:
|
82
|
+
self.evict(len(self) - self.max_entries)
|
83
|
+
|
84
|
+
self.total_seen += n
|
85
|
+
|
86
|
+
ct = self.entries.get(key, 0) + n
|
87
|
+
self.entries[key] = ct
|
88
|
+
|
89
|
+
return ct
|
90
|
+
|
91
|
+
@property
|
92
|
+
def items(self) -> ta.Iterable[tuple[str, int]]:
|
93
|
+
return self.entries.items()
|
94
|
+
|
95
|
+
@property
|
96
|
+
def sorted(self) -> list[tuple[str, int]]:
|
97
|
+
items = sorted(self.items, key=operator.itemgetter(1))
|
98
|
+
return items[::-1]
|
99
|
+
|
100
|
+
def evict(self, n: int = 1) -> None:
|
101
|
+
self.num_evicted += n
|
102
|
+
|
103
|
+
for key, ct in heapq.nsmallest(n, self.items, key=operator.itemgetter(1)):
|
104
|
+
self.total_evicted += ct
|
105
|
+
|
106
|
+
del self.entries[key]
|
107
|
+
|
108
|
+
def nlargest(self, n: int = 20) -> list[tuple[str, int]]:
|
109
|
+
return heapq.nlargest(n, self.items, key=operator.itemgetter(1))
|
110
|
+
|
111
|
+
def nsmallest(self, n: int = 20) -> list[tuple[str, int]]:
|
112
|
+
return heapq.nsmallest(n, self.items, key=operator.itemgetter(1))
|
113
|
+
|
114
|
+
|
115
|
+
class KeyedHistoRenderer:
|
116
|
+
def __init__(
|
117
|
+
self,
|
118
|
+
histo: KeyedHisto,
|
119
|
+
*,
|
120
|
+
max_lines: int | None = None,
|
121
|
+
) -> None:
|
122
|
+
super().__init__()
|
123
|
+
|
124
|
+
self.histo = histo
|
125
|
+
self.max_lines = max_lines
|
126
|
+
|
127
|
+
@property
|
128
|
+
def entries_to_render(self) -> list[tuple[str, int]]:
|
129
|
+
if self.max_lines is None:
|
130
|
+
return list(self.histo.sorted)
|
131
|
+
|
132
|
+
nlines = min(self.max_lines, len(self.histo))
|
133
|
+
|
134
|
+
return self.histo.nlargest(nlines)
|
135
|
+
|
136
|
+
def render_header(self, count_width: int) -> str:
|
137
|
+
header = 'count : % sen : % tkd : line'
|
138
|
+
|
139
|
+
if count_width > 5:
|
140
|
+
header = (' ' * (count_width - 5)) + header
|
141
|
+
|
142
|
+
return header
|
143
|
+
|
144
|
+
def render_entry(self, entry: tuple[str, int], count_width: int) -> str:
|
145
|
+
line, count = entry
|
146
|
+
|
147
|
+
line_fmt = '%' + str(count_width) + 'd : %5s : %5s : %s'
|
148
|
+
|
149
|
+
percent_seen_str = f'{calc_percent(count, self.histo.total_seen):3.2f}'
|
150
|
+
percent_tracked_str = f'{calc_percent(count, self.histo.total_tracked):3.2f}'
|
151
|
+
|
152
|
+
return line_fmt % (count, percent_seen_str, percent_tracked_str, line)
|
153
|
+
|
154
|
+
def render_entries(self, entries: ta.Iterable[tuple[str, int]], count_width: int) -> list[str]:
|
155
|
+
return [self.render_entry(entry, count_width) for entry in entries]
|
156
|
+
|
157
|
+
def render_status(self) -> str:
|
158
|
+
parts = [f'{self.histo.total_seen} total seen']
|
159
|
+
|
160
|
+
total_tracked_percent = calc_percent(self.histo.total_tracked, self.histo.total_seen)
|
161
|
+
parts.extend([
|
162
|
+
f'{len(self.histo)} tracked',
|
163
|
+
f'{self.histo.total_tracked} / {total_tracked_percent:.2f} % total tracked',
|
164
|
+
])
|
165
|
+
|
166
|
+
parts.extend([
|
167
|
+
f'{self.histo.num_evicted} evicted',
|
168
|
+
f'{self.histo.total_evicted} / {100.0 - total_tracked_percent:.2f} % total evicted',
|
169
|
+
])
|
170
|
+
|
171
|
+
duplicate_evictions = self.histo.total_evicted - self.histo.num_evicted
|
172
|
+
parts.append(
|
173
|
+
f'{duplicate_evictions} / {calc_percent(duplicate_evictions, self.histo.total_evicted):.2f} '
|
174
|
+
f'% duplicate evictions',
|
175
|
+
)
|
176
|
+
|
177
|
+
# tracked % + duplicate evicted %
|
178
|
+
parts.append(
|
179
|
+
f'{calc_percent(self.histo.total_tracked - duplicate_evictions, self.histo.total_seen):.2f} % correct',
|
180
|
+
)
|
181
|
+
|
182
|
+
return ', '.join(parts)
|
183
|
+
|
184
|
+
class Rendered(ta.NamedTuple):
|
185
|
+
status_line: str
|
186
|
+
header_line: str
|
187
|
+
entry_lines: list[str]
|
188
|
+
|
189
|
+
def render(self, entries: ta.Sequence[tuple[str, int]] | None = None) -> Rendered:
|
190
|
+
if entries is None:
|
191
|
+
entries = self.entries_to_render
|
192
|
+
|
193
|
+
max_count = entries[0][1] if entries else 0
|
194
|
+
count_width = len(str(max_count))
|
195
|
+
|
196
|
+
status_line = self.render_status()
|
197
|
+
header_line = self.render_header(count_width)
|
198
|
+
entry_lines = self.render_entries(entries, count_width)
|
199
|
+
|
200
|
+
return self.Rendered(
|
201
|
+
status_line,
|
202
|
+
header_line,
|
203
|
+
entry_lines,
|
204
|
+
)
|
205
|
+
|
206
|
+
def render_to_str(self) -> str:
|
207
|
+
status_line, header_line, entry_lines = self.render()
|
208
|
+
|
209
|
+
return '\n'.join([status_line, '', header_line, *entry_lines, ''])
|
210
|
+
|
211
|
+
|
212
|
+
class CursesKeyedHistoRenderer(KeyedHistoRenderer):
|
213
|
+
color_normal = 0
|
214
|
+
color_green = 1
|
215
|
+
color_yellow = 2
|
216
|
+
color_red = 3
|
217
|
+
|
218
|
+
def __init__(
|
219
|
+
self,
|
220
|
+
window,
|
221
|
+
histo: KeyedHisto,
|
222
|
+
*,
|
223
|
+
redraw_interval: float = .1,
|
224
|
+
) -> None:
|
225
|
+
self.window = window
|
226
|
+
self.redraw_interval = redraw_interval
|
227
|
+
|
228
|
+
h, w = self.window.getmaxyx()
|
229
|
+
max_lines = h - 3
|
230
|
+
|
231
|
+
self.max_line_len = w - 30
|
232
|
+
|
233
|
+
super().__init__(
|
234
|
+
histo,
|
235
|
+
max_lines=max_lines,
|
236
|
+
)
|
237
|
+
|
238
|
+
self.timed_redraw = with_timer(redraw_interval)(self.draw)
|
239
|
+
|
240
|
+
self.last_drawn_entries: list[tuple[str, int]] = []
|
241
|
+
|
242
|
+
curses.init_pair(self.color_green, curses.COLOR_GREEN, curses.COLOR_BLACK)
|
243
|
+
curses.init_pair(self.color_yellow, curses.COLOR_YELLOW, curses.COLOR_BLACK)
|
244
|
+
curses.init_pair(self.color_red, curses.COLOR_RED, curses.COLOR_BLACK)
|
245
|
+
|
246
|
+
def get_entry_color(
|
247
|
+
self,
|
248
|
+
cur_pos: int,
|
249
|
+
last_pos: int | None,
|
250
|
+
) -> int:
|
251
|
+
if last_pos is None:
|
252
|
+
return self.color_green
|
253
|
+
elif last_pos > cur_pos:
|
254
|
+
return self.color_yellow
|
255
|
+
elif last_pos < cur_pos:
|
256
|
+
return self.color_red
|
257
|
+
else:
|
258
|
+
return self.color_normal
|
259
|
+
|
260
|
+
def get_entry_colors(self, entries: ta.Iterable[tuple[str, int]]) -> list[int]:
|
261
|
+
last_pos_map = {s: i for i, (s, _) in enumerate(self.last_drawn_entries)}
|
262
|
+
|
263
|
+
return [
|
264
|
+
self.get_entry_color(i, last_pos_map.get(key))
|
265
|
+
for i, (key, _) in enumerate(entries)
|
266
|
+
]
|
267
|
+
|
268
|
+
def draw(self) -> None:
|
269
|
+
entries = self.entries_to_render
|
270
|
+
|
271
|
+
status_line, header_line, entry_lines = self.render(entries)
|
272
|
+
entry_colors = self.get_entry_colors(entries)
|
273
|
+
|
274
|
+
self.last_drawn_entries = entries
|
275
|
+
|
276
|
+
self.window.clear()
|
277
|
+
self.window.addstr(0, 0, status_line)
|
278
|
+
self.window.addstr(2, 0, header_line)
|
279
|
+
|
280
|
+
for i, (line, color) in enumerate(zip(entry_lines, entry_colors)):
|
281
|
+
self.window.addstr(i + 3, 0, line[:120], curses.color_pair(color))
|
282
|
+
|
283
|
+
self.window.refresh()
|
284
|
+
|
285
|
+
|
286
|
+
def main() -> None:
|
287
|
+
screen = curses.initscr()
|
288
|
+
curses.start_color()
|
289
|
+
curses.curs_set(0)
|
290
|
+
|
291
|
+
histo = KeyedHisto(max_entries=10_000)
|
292
|
+
renderer = CursesKeyedHistoRenderer(screen, histo)
|
293
|
+
|
294
|
+
try:
|
295
|
+
while True:
|
296
|
+
try:
|
297
|
+
line = sys.stdin.readline()
|
298
|
+
except UnicodeDecodeError:
|
299
|
+
# FIXME
|
300
|
+
continue
|
301
|
+
|
302
|
+
if not line:
|
303
|
+
break
|
304
|
+
|
305
|
+
if len(line) > renderer.max_line_len:
|
306
|
+
line = line[renderer.max_line_len:]
|
307
|
+
|
308
|
+
line = line.strip()
|
309
|
+
|
310
|
+
if not line:
|
311
|
+
continue
|
312
|
+
|
313
|
+
histo.inc(line)
|
314
|
+
renderer.timed_redraw()
|
315
|
+
|
316
|
+
# screen.nodelay(1)
|
317
|
+
# ch = screen.getch()
|
318
|
+
# if ch != curses.ERR:
|
319
|
+
# histo.inc(ch, 100)
|
320
|
+
|
321
|
+
except (OSError, KeyboardInterrupt):
|
322
|
+
pass
|
323
|
+
|
324
|
+
finally:
|
325
|
+
curses.endwin()
|
326
|
+
|
327
|
+
sys.stdout.write(KeyedHistoRenderer(histo).render_to_str())
|
328
|
+
|
329
|
+
|
330
|
+
# @omlish-manifest
|
331
|
+
_CLI_MODULE = CliModule('linehisto', __name__)
|
332
|
+
|
333
|
+
|
334
|
+
if __name__ == '__main__':
|
335
|
+
main()
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: omdev
|
3
|
-
Version: 0.0.0.
|
3
|
+
Version: 0.0.0.dev198
|
4
4
|
Summary: omdev
|
5
5
|
Author: wrmsr
|
6
6
|
License: BSD-3-Clause
|
@@ -12,7 +12,7 @@ Classifier: Operating System :: OS Independent
|
|
12
12
|
Classifier: Operating System :: POSIX
|
13
13
|
Requires-Python: >=3.12
|
14
14
|
License-File: LICENSE
|
15
|
-
Requires-Dist: omlish==0.0.0.
|
15
|
+
Requires-Dist: omlish==0.0.0.dev198
|
16
16
|
Provides-Extra: all
|
17
17
|
Requires-Dist: black~=24.10; extra == "all"
|
18
18
|
Requires-Dist: pycparser~=2.22; extra == "all"
|
@@ -12,7 +12,7 @@ authors = [
|
|
12
12
|
urls = {source = 'https://github.com/wrmsr/omlish'}
|
13
13
|
license = {text = 'BSD-3-Clause'}
|
14
14
|
requires-python = '>=3.12'
|
15
|
-
version = '0.0.0.
|
15
|
+
version = '0.0.0.dev198'
|
16
16
|
classifiers = [
|
17
17
|
'License :: OSI Approved :: BSD License',
|
18
18
|
'Development Status :: 2 - Pre-Alpha',
|
@@ -22,7 +22,7 @@ classifiers = [
|
|
22
22
|
]
|
23
23
|
description = 'omdev'
|
24
24
|
dependencies = [
|
25
|
-
'omlish == 0.0.0.
|
25
|
+
'omlish == 0.0.0.dev198',
|
26
26
|
]
|
27
27
|
|
28
28
|
[project.optional-dependencies]
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|