diff --git a/pynest/nest/lib/hl_api_helper.py b/pynest/nest/lib/hl_api_helper.py
index f10f577ea9..4ad8a798ba 100644
--- a/pynest/nest/lib/hl_api_helper.py
+++ b/pynest/nest/lib/hl_api_helper.py
@@ -26,8 +26,14 @@
import warnings
import inspect
+import json
import functools
import textwrap
+import subprocess
+import os
+import re
+
+from string import Template
# These variables MUST be set by __init__.py right after importing.
# There is no safety net, whatsoever.
@@ -111,7 +117,6 @@ def deprecated(alt_func_name, text=None):
function:
Decorator function
"""
-
def deprecated_decorator(func):
_deprecation_warning[func.__name__] = True
@@ -172,6 +177,7 @@ def is_string(obj):
"""
return isinstance(obj, uni_str)
+
__debug = False
@@ -229,11 +235,11 @@ def stack_checker_func(*args, **kwargs):
if not get_debug():
return f(*args, **kwargs)
else:
- sr('count')
- stackload_before = spp()
+ sr
+ stackload_before = spp
result = f(*args, **kwargs)
- sr('count')
- num_leftover_elements = spp() - stackload_before
+ sr
+ num_leftover_elements = spp - stackload_before
if num_leftover_elements != 0:
eargs = (f.__name__, num_leftover_elements)
etext = "Function '%s' left %i elements on the stack."
@@ -389,17 +395,146 @@ def broadcast(item, length, allowed_types, name="item"):
"""
if isinstance(item, allowed_types):
- return length * (item, )
+ return length * (item,)
elif len(item) == 1:
return length * item
elif len(item) != length:
- raise TypeError("'%s' must be a single value, a list with " +
- "one element or a list with %i elements."
- % (name, length))
-
+ raise TypeError("'{0}' must be a single value, a list with " +
+ "one element or a list with {1} elements.".format(
+ name, length))
return item
+def __check_nb():
+ """Return true if called from a Jupyter notebook."""
+ try:
+ return get_ipython().__class__.__name__.startswith('ZMQ')
+ except NameError:
+ return False
+
+
+def __show_help_in_modal_window(objname, hlptxt):
+ """Open modal window with help text
+
+ Parameters
+ ----------
+ objname : str
+ filename
+ hlptxt : str
+ Full text
+ """
+
+ hlptxt = json.dumps(hlptxt)
+ style = ""
+ s = Template("""
+ require(
+ ["base/js/dialog"],
+ function(dialog) {
+ dialog.modal({
+ title: '$jstitle',
+ body: $jstext,
+ buttons: {
+ 'close': {}
+ }
+ });
+ }
+ );
+ """)
+
+ from IPython.display import HTML, Javascript, display
+ display(HTML(style))
+
+ display(Javascript(s.substitute(jstitle=objname, jstext=hlptxt)))
+
+
+def show_help_with_pager(hlpobj, pager):
+ """Output of doc in python with pager or print
+
+ Parameters
+ ----------
+ hlpobj : object
+ Object to display
+ pager: str, optional
+ pager to use, NO if you explicity do not want to use a pager
+ """
+ if 'NEST_INSTALL_DIR' not in os.environ:
+ print(
+ 'NEST help needs to know where NEST is installed.'
+ 'Please source nest_vars.sh or define NEST_INSTALL_DIR manually.')
+ return
+
+ helpdir = os.path.join(os.environ['NEST_INSTALL_DIR'], "share", "doc",
+ "nest", "help")
+ objname = hlpobj + '.hlp'
+ consolepager = ['less', 'more', 'vi', 'vim', 'nano', 'emacs -nw',
+ 'ed', 'editor']
+
+ # reading ~/.nestrc lookink for pager to use.
+ if pager is None:
+ # check if .netsrc exist
+ rc_file = os.path.join(os.environ['HOME'], '.nestrc')
+ if os.path.isfile(rc_file):
+ # open ~/.nestrc
+ rc = open(rc_file, 'r')
+ # The loop goes through the .nestrc line by line and checks
+ # it for the definition of a pager. Whether a pager is
+ # found or not, this pager is used or the standard pager 'more'.
+ for line in rc:
+ # the re checks if there are lines beginning with '%'
+ rctst = re.match(r'^\s?%', line)
+ if rctst is None:
+ # the next re checks for a sth. like
+ # '/page << /command (more)'
+ # and returns the given pager.
+ pypagers = re.findall(
+ r'^\s?/page\s?<<\s?/command\s?\((\w*)', line)
+ if pypagers:
+ for pa in pypagers:
+ if pa:
+ pager = pa
+ else:
+ pager = 'more'
+ break
+ else:
+ pager = 'more'
+ rc.close()
+ else:
+ pager = 'more'
+ hlperror = True
+ # Searching the given object in all helpfiles, check the environment
+ # and display the helptext in the pager.
+ for dirpath, dirnames, files in os.walk(helpdir):
+ for hlp in files:
+ if hlp == objname:
+ hlperror = False
+ objf = os.path.join(dirpath, objname)
+ fhlp = open(objf, 'r')
+ hlptxt = fhlp.read()
+ # only for notebook
+ if __check_nb():
+ if pager in consolepager:
+ # only in notebook open modal window
+ __show_help_in_modal_window(objname, hlptxt)
+ fhlp.close()
+ break
+ else:
+ subprocess.call([pager, objf])
+ fhlp.close()
+ break
+ else:
+ if pager in consolepager:
+ subprocess.call([pager, objf])
+ fhlp.close()
+ break
+ else:
+ subprocess.call([pager, objf])
+ fhlp.close()
+ break
+ if hlperror:
+ print("Sorry, there is no help for '" + hlpobj + "'!")
+
+
@check_stack
def get_verbosity():
"""Return verbosity level of NEST's messages.
@@ -412,8 +547,8 @@ def get_verbosity():
# Defined in hl_api_helper to avoid circular inclusion problem with
# hl_api_info.py
- sr('verbosity')
- return spp()
+ sr
+ return spp
@check_stack
@@ -429,7 +564,7 @@ def set_verbosity(level):
# Defined in hl_api_helper to avoid circular inclusion problem with
# hl_api_info.py
- sr("%s setverbosity" % level)
+ sr
def model_deprecation_warning(model):
diff --git a/pynest/nest/lib/hl_api_info.py b/pynest/nest/lib/hl_api_info.py
index e78b43ce6f..9d3da1db75 100644
--- a/pynest/nest/lib/hl_api_info.py
+++ b/pynest/nest/lib/hl_api_info.py
@@ -24,6 +24,9 @@
"""
from .hl_api_helper import *
+import sys
+import os
+import webbrowser
@check_stack
@@ -55,26 +58,38 @@ def authors():
@check_stack
-def helpdesk(browser="firefox"):
- """Open the NEST helpdesk in the given browser.
+def helpdesk():
+ """Open the NEST helpdesk in browser.
- The default browser is firefox.
-
- Parameters
- ----------
- browser : str, optional
- Name of the browser to use
+ Use the system default browser.
"""
+ if 'NEST_DOC_DIR' not in os.environ:
+ print(
+ 'NEST help needs to know where NEST is installed.'
+ 'Please source nest_vars.sh or define NEST_DOC_DIR manually.')
+ return
- sr("/helpdesk << /command (%s) >> SetOptions" % browser)
- sr("helpdesk")
+ helpfile = os.path.join(os.environ['NEST_DOC_DIR'], 'help',
+ 'helpindex.html')
+
+ # Under Windows systems webbrowser.open is incomplete
+ # See
+ if sys.platform[:3] == "win":
+ os.startfile(helpfile)
+
+ # Under MacOs we need to ask for the browser explicitly.
+ # See .
+ if sys.platform[:3] == "dar":
+ webbrowser.get('safari').open_new(helpfile)
+ else:
+ webbrowser.open_new(helpfile)
@check_stack
-def help(obj=None, pager="less"):
+def help(obj=None, pager=None):
"""Show the help page for the given object using the given pager.
- The default pager is less.
+ The default pager is more.
Parameters
----------
@@ -83,17 +98,17 @@ def help(obj=None, pager="less"):
pager : str, optional
Pager to use
"""
+ hlpobj = obj
+ if hlpobj is not None:
+ show_help_with_pager(hlpobj, pager)
- if obj is not None:
- sr("/page << /command (%s) >> SetOptions" % pager)
- sr("/%s help" % obj)
else:
print("Type 'nest.helpdesk()' to access the online documentation "
"in a browser.")
print("Type 'nest.help(object)' to get help on a NEST object or "
"command.\n")
print("Type 'nest.Models()' to see a list of available models "
- "in NEST.\n")
+ "in NEST.")
print("Type 'nest.authors()' for information about the makers "
"of NEST.")
print("Type 'nest.sysinfo()' to see details on the system "
@@ -115,6 +130,7 @@ def get_argv():
tuple:
Argv, as seen by NEST.
"""
+
sr('statusdict')
statusdict = spp()
return statusdict['argv']