Skip to content

Commit

Permalink
Merge pull request #330 from tangkong/startup_hook
Browse files Browse the repository at this point in the history
ENH: add post-IPython-initialization routines, better banner
  • Loading branch information
ZLLentz authored Apr 21, 2022
2 parents 5f77e01 + a65c59e commit 954d4cc
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 19 deletions.
2 changes: 1 addition & 1 deletion conda-recipe/meta.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ requirements:
- jinja2 >=2.11.0
- lightpath >=0.6.0
- matplotlib >=3.4.0
- nabs >=0.1.0
- nabs >=1.3.0
- pcdscalc >=0.3.0
- pcdsdaq >=2.3.0
- pcdsdevices >=4.7.0
Expand Down
12 changes: 7 additions & 5 deletions hutch_python/cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,13 @@ def doc(self, **docs):
documentation about that object and why it is included.
"""
for key, value in docs.items():
obj = self.objs[key]
if obj.__doc__:
obj.__doc__ = value + '\n' + textwrap.dedent(obj.__doc__)
else:
obj.__doc__ = value
obj = getattr(self.objs, key, None)
if obj:
if obj.__doc__:
obj.__doc__ = value + '\n' + textwrap.dedent(obj.__doc__)
else:
obj.__doc__ = value
obj._desc = value


# For writing the files
Expand Down
25 changes: 12 additions & 13 deletions hutch_python/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from traitlets.config import Config

from .constants import CONDA_BASE, DIR_MODULE
from .env_version import get_env_info, log_env
from .env_version import log_env
from .load_conf import load
from .log_setup import configure_log_directory, debug_mode, setup_logging

Expand Down Expand Up @@ -83,7 +83,8 @@ def configure_ipython_session():
# Important Utilities
ipy_config.InteractiveShellApp.extensions = [
'hutch_python.ipython_log',
'hutch_python.bug'
'hutch_python.bug',
'hutch_python.pt_app_config'
]
# Matplotlib setup for ipython (automatically do %matplotlib)
backend = matplotlib.get_backend().replace('Agg', '').lower()
Expand All @@ -98,17 +99,15 @@ def configure_ipython_session():
# Set up tab completion modifications
configure_tab_completion(ipy_config)

# remove force exit key bind from <ctrl-\\>
ipy_config.InteractiveShellApp.exec_lines = (
"import IPython; "
"from prompt_toolkit.keys import Keys; "
"ip = IPython.get_ipython(); "
"cb = Keys.ControlBackslash; "
"ip.pt_app.key_bindings.remove(cb) "
)

# add env info to ipython banner
ipy_config.TerminalInteractiveShell.banner2 = get_env_info()
# disable default banner
ipy_config.TerminalIPythonApp.display_banner = False

# Run startup hook code, print banner after startup hook files
files = [
str(DIR_MODULE / 'startup_script.py'),
str(DIR_MODULE / 'print_hint_banner.py')
]
ipy_config.InteractiveShellApp.exec_files = files

return ipy_config

Expand Down
51 changes: 51 additions & 0 deletions hutch_python/print_hint_banner.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
"""
Print a custom banner with some more helpful hints and information
for hutch-python sessions.
Startup script files to be run after ipython is initialized via:
``c.InteractiveTerminalApp.exec_files``
Code here will take executed after both IPython has been loaded and
the namespace has been populated with hutch objects.
These will be run as standalone python files, and should not be
imported from.
"""

from typing import List

from hutch_python.env_version import get_env_info

default_namespaces = ['a', 'm', 's', 'd', 'x', 'sim', 'camviewer',
'bp', 're']
default_objects = ['RE', 'daq', 'elog', 'archive']


def gather_hint_table(namespace: List[str]) -> str:
"""
Gather variable name and short description into a table if the
variable name is in the current global namespace
"""
global_ns = globals()
ns = [x for x in namespace if x in global_ns]

out = ''
for k in ns:
out += f" {k} - {getattr(global_ns[k], '_desc', 'N/A')}\n"

return out


base_banner = f"""
-----------------------------------
{get_env_info()}
-----------------------------------
Helpful Namespaces:
{gather_hint_table(default_namespaces)}
Useful objects:
{gather_hint_table(default_objects)}
"""


if __name__ == '__main__':
print(base_banner)
21 changes: 21 additions & 0 deletions hutch_python/pt_app_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
"""
This file defines an ipython extension to configure the terminal app.
Currently this configures:
- disabling the Ctrl+\\ keybind
"""

import logging

from prompt_toolkit.keys import Keys

from .utils import safe_load

logger = logging.getLogger(__name__)


def load_ipython_extension(ipython):
# Unbind Ctrl+\\
with safe_load('disable ctrl+\\'):
ipython.pt_app.key_bindings.remove(
Keys.ControlBackslash
)
32 changes: 32 additions & 0 deletions hutch_python/startup_script.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"""
Initialize the ELogPoster callback and subscribe it to the RunEngine
Startup script files to be run after ipython is initialized via:
``c.InteractiveTerminalApp.exec_files``
Code here will take executed after both IPython has been loaded and
the namespace has been populated with hutch objects.
These will be run as standalone python files, and should not be
imported from.
"""


def _configure_elog_poster():
import IPython
from nabs.callbacks import ELogPoster

from hutch_python.utils import safe_load

with safe_load('ELogPoster'):
# RE, ELog will already exist by now
elog = globals().get('elog', None)
RE = globals().get('RE', None)
assert elog is not None

elogc = ELogPoster(elog, IPython.get_ipython())
RE.subscribe(elogc)


if __name__ == '__main__':
_configure_elog_poster()

0 comments on commit 954d4cc

Please sign in to comment.