import os
import sysconfig
# Set to False to not utilize the system PATH environment variable
use_path = 'PYSB_PATHFINDER_IGNORE_PATH' not in os.environ
_path_config = {
'atomizer': {
'name': 'Atomizer',
'executable': {
'posix': 'sbmlTranslator',
'nt': 'sbmlTranslator.exe'
},
'env_var': 'BNGPATH',
'env_var_subdir': 'bin',
'search_paths': {
'posix': ('/usr/local/share/BioNetGen/bin',),
'nt': ('c:/Program Files/BioNetGen/bin',)
},
'conda_install_cmd': 'conda install -c alubbock atomizer'
},
'bng': {
'name': 'BioNetGen',
'executable': 'BNG2.pl',
'batch_file': 'BNG2.bat',
'env_var': 'BNGPATH',
'search_paths': {
'posix': ('/usr/local/share/BioNetGen', ),
'nt': ('c:/Program Files/BioNetGen', )
},
'conda_install_cmd': 'conda install -c alubbock bionetgen'
},
'kasa': {
'name': 'KaSa (Kappa)',
'executable': {
'posix': 'KaSa',
'nt': 'KaSa.exe'
},
'env_var': 'KAPPAPATH',
'search_paths': {
'posix': ('/usr/local/share/KaSa', ),
'nt': ('c:/Program Files/KaSa', )
},
'conda_install_cmd': 'conda install -c alubbock kappa'
},
'kasim': {
'name': 'KaSim (Kappa)',
'executable': {
'posix': 'KaSim',
'nt': 'KaSim.exe'
},
'env_var': 'KAPPAPATH',
'search_paths': {
'posix': ('/usr/local/share/KaSim',),
'nt': ('c:/Program Files/KaSim',)
},
'conda_install_cmd': 'conda install -c alubbock kappa'
},
'cupsoda': {
'name': 'cupSODA',
'executable': {
'posix': 'cupSODA',
'nt': 'cupsoda.exe'
},
'env_var': 'CUPSODAPATH',
'search_paths': {
'posix': ('/usr/local/share/cupSODA',),
'nt': ('c:/Program Files/cupSODA',)
},
'conda_install_cmd': 'conda install -c alubbock cupsoda'
},
'stochkit_ssa': {
'name': 'StochKit [SSA]',
'executable': {
'posix': 'ssa',
'nt': 'ssa.exe'
},
'batch_file': 'ssa.bat',
'env_var': 'STOCHKITPATH',
'search_paths': {
'posix': ('/usr/local/share/StochKit', ),
'nt': ('c:/Program Files/StochKit',)
},
'conda_install_cmd': 'conda install -c alubbock stochkit'
},
'stochkit_tau_leaping': {
'name': 'StochKit [Tau Leaping]',
'executable': {
'posix': 'tau_leaping',
'nt': 'tau_leaping.exe'
},
'batch_file': 'tau_leaping.bat',
'env_var': 'STOCHKITPATH',
'search_paths': {
'posix': ('/usr/local/share/StochKit',),
'nt': ('c:/Program Files/StochKit',)
},
'conda_install_cmd': 'conda install -c alubbock stochkit'
},
'nvcc': {
'name': 'NVIDIA CUDA compiler',
'executable': {
'posix': 'nvcc',
'nt': 'nvcc.exe'
},
'env_var': 'CUDAPATH',
'search_paths': {
'posix': ('/usr/local/cuda/bin', '/usr/bin', '/opt/cuda/bin'),
'nt': (
r'C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.0\bin',)
}
}
}
_path_cache = {}
[docs]def list_programs():
"""
Return the list of available external programs as a dictionary
Returns
-------
A dictionary containing the internal program name (key) and the
human-readable name and environment variable (value) to adjust the path
for that program.
"""
keep_keys = ('name', 'env_var')
return {prog_name: {
k: v for k, v in prog_data.items() if k in keep_keys
} for prog_name, prog_data in _path_config.items()}
[docs]def get_path(prog_name):
"""
Gets the currently active path to an external executable
The path will be determined automatically if not set (see return value).
To override, call :func:`set_path`.
Parameters
----------
prog_name: str
The PySB internal program name for an executable (run
:func:`list_programs` for a list).
Returns
-------
The currently active path to an external executable. If the path hasn't
previously been set, the relevant environment variable for that
program's path will be searched. Failing that, a list of default paths
for the operating system will be checked. An Exception is raised if none
of these approaches works.
"""
try:
return _path_cache[prog_name]
except KeyError:
pass
if prog_name not in _path_config.keys():
raise ValueError('%s is not a known external executable' % prog_name)
path_conf = _path_config[prog_name]
# Try environment variable, if set
if path_conf['env_var'] in os.environ:
env_var_val = os.environ[path_conf['env_var']]
subdir_msg = ''
try:
_path_cache[prog_name] = _validate_path(prog_name, env_var_val)
return _path_cache[prog_name]
except ValueError:
try:
_path_cache[prog_name] = _validate_path(
prog_name, os.path.join(env_var_val,
path_conf['env_var_subdir']))
return _path_cache[prog_name]
except KeyError:
# No subdirectory set
pass
except ValueError:
# Subdirectory set, but no binary found
subdir_msg = ', or in that path\'s "%s" subdirectory' %\
path_conf['env_var_subdir']
raise ValueError('Environment variable %s is set to %s, but the '
'program %s or its executable %s could not be '
'found there%s. Check file existence and '
'permissions.' % (
path_conf['env_var'],
env_var_val,
path_conf['name'],
_get_executable(prog_name),
subdir_msg)
)
# Check the Anaconda environment, if applicable, or BINDIR
try:
_path_cache[prog_name] = _validate_path(prog_name,
_get_anaconda_bindir())
return _path_cache[prog_name]
except ValueError:
pass
# Check default paths for this operating system
if os.name not in path_conf['search_paths'].keys():
raise Exception('No default path is known for %s on your '
'operating system "%s". Set the path using the '
'environment variable %s or by calling the function '
'%s.%s()' % (path_conf['name'],
os.name,
path_conf['env_var'],
set_path.__module__,
set_path.__name__))
search_paths = path_conf['search_paths'][os.name]
if use_path:
search_paths = list(search_paths) + os.environ.get('PATH', '').split(
os.pathsep)
for search_path in search_paths:
try:
_path_cache[prog_name] = _validate_path(prog_name, search_path)
return _path_cache[prog_name]
except ValueError:
pass
try:
conda_install_help = '\n\nConda users can install %s using the ' \
'following command:\n\n%s' % \
(path_conf['name'], path_conf['conda_install_cmd'])
except KeyError:
conda_install_help = ''
raise Exception('The program %s was not found in the default search '
'path(s) for your operating system:\n\n%s\n\nEither '
'install it to one of those paths, or set a custom path '
'using the environment variable %s or by calling the '
'function %s.%s()%s' % (path_conf['name'],
"\n".join(search_paths),
path_conf['env_var'],
set_path.__module__,
set_path.__name__,
conda_install_help)
)
[docs]def set_path(prog_name, full_path):
"""
Sets the full path to an external executable at runtime
External program paths can also be adjusted by environment variable prior
to first use; run :func:`list_programs` for a list of programs.
Parameters
----------
prog_name: str
The internal program name for an executable. (see
:func:`list_programs`)
full_path: str
The full path to the external executable or its enclosing directory.
If the path is a directory, it will be searched for the executable.
A ValueError will be raised if there's an issue with the path (not
found, permissions etc.).
"""
if prog_name not in _path_config.keys():
raise ValueError('%s is not a known external executable' % prog_name)
_path_cache[prog_name] = _validate_path(prog_name, full_path)
def _get_anaconda_bindir():
""" Get the binary path from python build time (for anaconda) """
# Is this an anaconda virtual environment?
conda_env = os.environ.get('CONDA_PREFIX', None)
if conda_env:
return os.path.join(conda_env, 'Scripts' if os.name == 'nt' else 'bin')
# Otherwise, try the default anaconda/python bin directory
bindir = sysconfig.get_config_var('BINDIR')
if os.name == 'nt':
# bindir doesn't point to scripts directory on Windows
return os.path.join(bindir, 'Scripts')
else:
return bindir
def _get_batch_file(prog_name):
try:
return _path_config[prog_name]['batch_file']
except KeyError:
return None
def _get_executable(prog_name):
executable = _path_config[prog_name]['executable']
if isinstance(executable, str):
return executable
else:
try:
return executable[os.name]
except KeyError:
raise Exception('No executable for "%s" is available for your '
'operating system: "%s"' %
(_path_config[prog_name]['name'],
os.name))
def _validate_path(prog_name, full_path):
if not os.access(full_path, os.F_OK):
raise ValueError('Unable to access path %s. Check the file exists '
'and the current user has permission to access it.' %
full_path)
if not os.path.isfile(full_path):
# On anaconda, check batch file on Windows, if applicable
batch_file = _get_batch_file(prog_name)
if os.name == 'nt' and batch_file:
try:
return _validate_path(prog_name,
os.path.join(full_path, batch_file))
except ValueError:
pass
# It's a directory, try appending the executable name
return _validate_path(prog_name, os.path.join(full_path,
_get_executable(
prog_name)))
if not os.access(full_path, os.X_OK):
raise ValueError('The file %s does not have executable permissions.' %
full_path)
return full_path