first version

This commit is contained in:
2021-10-23 19:53:47 +02:00
parent f06a24f5cb
commit 25462f27d3
3 changed files with 363 additions and 0 deletions

129
.gitignore vendored Normal file
View File

@ -0,0 +1,129 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
.python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/

136
example.ipynb Normal file
View File

@ -0,0 +1,136 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"id": "QK02kUNCW63R"
},
"outputs": [],
"source": [
"from inspector import inspector"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "c4f3180b10df4882b0f997beb81bedf3",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"Box(children=(HTML(value='<div class=\"rendered_html jp-RenderedHTMLCommon\"><table><thead><tr><th>Name</th><th>…"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"inspector"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "wVqNvnUmW63Z"
},
"source": [
"### Change values below"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"id": "eDNtIZIWW63Z"
},
"outputs": [],
"source": [
"a = 10"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"id": "rXgxHVioW63a"
},
"outputs": [],
"source": [
"a = b = 3.5\n",
"A = B = 123"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"id": "btIFCR7PW63c"
},
"outputs": [],
"source": [
"ccccccccccccc = a * b"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {
"id": "AFDITWxlW63c"
},
"outputs": [],
"source": [
"d = \"String\" * 3"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"id": "lCf_CGRYW63d"
},
"outputs": [],
"source": [
"del b"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"colab": {
"name": "Variable Inspector.ipynb",
"provenance": []
},
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.13"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

98
inspector.py Normal file
View File

@ -0,0 +1,98 @@
import inspect
import re
import weakref
import ipywidgets
HEADER = '<div class="rendered_html jp-RenderedHTMLCommon"><table><thead><tr><th>Name</th><th>Type</th><th>Value</th></tr></thead><tr><td>'
FOOTER = '</td></tr></table></div>'
SEP = '</td></tr><tr><td>'
LINE = '{0}</td><td>{1}</td><td>{2}'
IGNORE = ["In", "Out", "exit", "quit", "get_ipython"]
RE_DIGITS = re.compile("([0-9]+)")
class Singleton(type):
def __init__(cls, name, bases, namespace):
super().__init__(name, bases, namespace) # creates the class
cls.__signature__ = inspect.signature(cls.__init__) # restore the constructor signature (instead of that of __call__ below)
cls.__instance__ = lambda: None # fake dead weakref
def __call__(cls, *args, **kwargs):
inst = cls.__instance__()
if not inst:
inst = super().__call__(*args, **kwargs) # creates the instance (calls __new__ and __init__ methods)
cls.__instance__ = weakref.ref(inst)
return inst
class VariableInspector(object, metaclass=Singleton):
def __init__(self, ipython=None):
self._box = ipywidgets.Box()
self._box.layout.overflow_y = "scroll"
self._table = ipywidgets.HTML(value="Loading...")
self._box.children = [self._table]
self._ipython = ipython or get_ipython()
self.start()
def start(self):
"""Add update callback if not already registered"""
if self.is_running:
raise RuntimeError("Cannot start. Update callback is already registered")
self._ipython.events.register("post_run_cell", self._update)
def stop(self):
"""Remove update callback if registered"""
if not self.is_running:
raise RuntimeError("Cannot stop. Update callback is not registered")
self._ipython.events.unregister("post_run_cell", self._update)
@property
def is_running(self):
"""Test if update callback is registered"""
return self._update in self._ipython.events.callbacks["post_run_cell"]
def _update(self, _):
"""Fill table with variable information"""
namespace = self._ipython.user_ns.items()
lines = (format_line(k, v) for k, v in sorted_naturally(namespace) if is_good_entry(k, v))
self._table.value = HEADER + SEP.join(lines) + FOOTER
def _ipython_display_(self):
"""Called when display() or pyout is used to display the Variable Inspector"""
try:
self._box._ipython_display_()
except:
pass
def format_line(k, v):
return LINE.format(k, typename(v), v)
def sorted_naturally(iterable, reverse=False):
natural = lambda item: [int(c) if c.isdigit() else c.casefold() for c in RE_DIGITS.split(str(item))]
return sorted(iterable, key=natural, reverse=reverse)
def is_good_entry(k, v):
return not k.startswith("_") and k not in IGNORE and not isinstance(v, VariableInspector)
def typename(obj):
return type(obj).__name__
inspector = VariableInspector()