Source code for nest
# -*- coding: utf-8 -*-
#
# __init__.py
#
# This file is part of NEST.
#
# Copyright (C) 2004 The NEST Initiative
#
# NEST is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# NEST is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with NEST. If not, see <http://www.gnu.org/licenses/>.
"""
Initializer of PyNEST.
"""
import sys
import os
# This is a workaround for readline import errors encountered with Anaconda
# Python running on Ubuntu, when invoked from the terminal
# "python -c 'import nest'"
if 'linux' in sys.platform and 'Anaconda' in sys.version:
import readline
# This is a workaround to avoid segmentation faults when importing
# scipy *after* nest. See https://github.com/numpy/numpy/issues/2521
try:
import scipy
except:
pass
# Make MPI-enabled NEST import properly. The underlying problem is that the
# shared object pynestkernel dynamically opens other libraries that open
# yet other libraries.
try:
# Python 3.3 and later has flags in os
sys.setdlopenflags(os.RTLD_NOW | os.RTLD_GLOBAL)
except AttributeError:
# Python 2.6 and 2.7 have flags in ctypes, but RTLD_NOW may only
# be available in dl or DLFCN and is required at least under
# Ubuntu 14.04. The latter two are not available under OSX,
# but OSX does not have and does not need RTLD_NOW. We therefore
# first try dl and DLFCN, then ctypes just for OSX.
try:
import dl
sys.setdlopenflags(dl.RTLD_GLOBAL | dl.RTLD_NOW)
except (ImportError, AttributeError):
try:
import DLFCN
sys.setdlopenflags(DLFCN.RTLD_GLOBAL | DLFCN.RTLD_NOW)
except (ImportError, AttributeError):
import ctypes
try:
sys.setdlopenflags(ctypes.RTLD_GLOBAL | ctypes.RTLD_NOW)
except AttributeError:
# We must test this last, since it is the only case without
# RTLD_NOW (OSX)
sys.setdlopenflags(ctypes.RTLD_GLOBAL)
from . import pynestkernel as _kernel # noqa
from .lib import hl_api_helper as hl_api # noqa
engine = _kernel.NESTEngine()
sli_push = hl_api.sps = engine.push
sli_pop = hl_api.spp = engine.pop
hl_api.pcd = engine.push_connection_datums
hl_api.kernel = _kernel
initialized = False
[docs]def catching_sli_run(cmd):
"""Send a command string to the NEST kernel to be executed, catch
SLI errors and re-raise them in Python.
Parameters
----------
cmd : str
The SLI command to be executed.
Raises
------
NESTError
SLI errors are bubbled to the Python API as NESTErrors.
"""
if sys.version_info >= (3, ):
def encode(s):
return s
def decode(s):
return s
else:
def encode(s):
return s.encode('utf-8')
def decode(s):
return s.decode('utf-8')
engine.run('{%s} runprotected' % decode(cmd))
if not sli_pop():
errorname = sli_pop()
message = sli_pop()
commandname = sli_pop()
engine.run('clear')
errorstring = '%s in %s%s' % (errorname, commandname, message)
raise _kernel.NESTError(encode(errorstring))
sli_run = hl_api.sr = catching_sli_run
[docs]def sli_func(s, *args, **kwargs):
"""Convenience function for executing an SLI command s with
arguments args.
This executes the SLI sequence:
``sli_push(args); sli_run(s); y=sli_pop()``
Parameters
----------
s : str
Function to call
*args
Arbitrary number of arguments to pass to the SLI function
**kwargs
namespace : str
The sli code is executed in the given SLI namespace.
litconv : bool
Convert string args beginning with / to literals.
Returns
-------
The function may have multiple return values. The number of return values
is determined by the SLI function that was called.
Examples
--------
r,q = sli_func('dup rollu add',2,3)
r = sli_func('add',2,3)
r = sli_func('add pop',2,3)
l = sli_func('CreateLayer', {...}, namespace='topology')
"""
# check for namespace
slifun = 'sli_func' # version not converting to literals
if 'namespace' in kwargs:
s = kwargs['namespace'] + ' using ' + s + ' endusing'
elif 'litconv' in kwargs:
if kwargs['litconv']:
slifun = 'sli_func_litconv'
elif len(kwargs) > 0:
_kernel.NESTError(
"'namespace' and 'litconv' are the only valid keyword arguments.")
sli_push(args) # push array of arguments on SLI stack
sli_push(s) # push command string
sli_run(slifun) # SLI support code to execute s on args
r = sli_pop() # return value is an array
if len(r) == 1: # 1 return value is no tuple
return r[0]
if len(r) != 0:
return r
hl_api.sli_func = sli_func
[docs]def init(argv):
"""Initializes NEST.
Parameters
----------
argv : list
Command line arguments, passed to the NEST kernel
Raises
------
_kernel.NESTError
"""
global initialized
if initialized:
raise _kernel.NESTError("NEST already initialized.")
return
quiet = False
# Some commandline arguments of NEST and Python have the same
# name, but different meaning. To avoid unintended behavior, we
# handle NEST's arguments here and pass it a modified copy, while
# we leave the original list unchanged for further use by the user
# or other modules.
nest_argv = argv[:]
if "--quiet" in nest_argv:
quiet = True
nest_argv.remove("--quiet")
if "--debug" in nest_argv:
nest_argv.remove("--debug")
if "--sli-debug" in nest_argv:
nest_argv.remove("--sli-debug")
nest_argv.append("--debug")
initialized = engine.init(nest_argv, __path__[0])
if initialized:
if not quiet:
engine.run("pywelcome")
# Dirty hack to get tab-completion for models in IPython.
try:
__IPYTHON__
except NameError:
pass
else:
try:
import keyword
keyword.kwlist += Models()
except ImportError:
pass
else:
_kernel.NESTError("Initiatization of NEST failed.")
[docs]def test():
"""Runs all PyNEST unit tests."""
from . import tests
import unittest
debug = hl_api.get_debug()
hl_api.set_debug(True)
runner = unittest.TextTestRunner(verbosity=2)
runner.run(tests.suite())
hl_api.set_debug(debug)
from .pynestkernel import * # noqa
from .lib.hl_api_helper import * # noqa
# We search through the subdirectory "lib" of the "nest" module
# directory and import the content of all Python files therein into
# the global namespace. This makes the API functions of PyNEST itself
# and those of extra modules available to the user.
for name in os.listdir(os.path.join(os.path.dirname(__file__), "lib")):
if name.endswith(".py") and not name.startswith('__'):
exec("from .lib.{0} import *".format(name[:-3]))
if 'DELAY_PYNEST_INIT' not in os.environ:
init(sys.argv)