#!/usr/bin/env python
# encoding: utf-8
from __future__ import print_function
"""
dotfiles.venv.ipython_config
==============================
ipython_config.py (venv)
- set variables for standard paths in the environment dict
- define IPython aliases
- serialize variables and aliases to
- IPython configuration (variables, aliases)
- Bash/zsh configuration (variables, aliases, macros)
- JSON (variables, aliases)
"""
import distutils.spawn
import logging
import os
import site
import sys
from collections import OrderedDict
from os.path import join as joinpath
if sys.version_info[0] == 2:
STR_TYPES = basestring
else:
STR_TYPES = str
[docs]class IPYMock(object):
"""
Provide a few mocked methods for testing
"""
[docs] def system(self, *args, **kwargs):
print(args, kwargs)
[docs] def magic(self, *args, **kwargs):
print(args, kwargs)
pyver = 'python%d.%d' % sys.version_info[:2]
log = logging.getLogger('Venv')
__THISFILE = os.path.abspath(__file__)
# __VENV_CMD = "python {~ipython_config.py}"
__VENV_CMD = "python %s" % __THISFILE
[docs]def get_workon_home_default():
"""
Returns:
str: Best path for a virtualenvwrapper ``$WORKON_HOME``
"""
workon_home = os.environ.get('WORKON_HOME')
if workon_home:
return workon_home
workon_home = os.path.expanduser('~/wrk/.ve')
if os.path.exists(workon_home):
return workon_home
return os.path.expanduser('~/.virtualenvs/')
[docs]class Env(OrderedDict):
"""
OrderedDict of variables for/from ``os.environ``.
"""
osenviron_keys = (
'__DOCSWWW',
'__DOTFILES',
'PAGER',
'PROJECTS',
'USRLOG',
'VIMBIN',
'GVIMBIN',
'MVIMBIN',
'GUIVIMBIN',
'VIMCONF',
'EDITOR_',
'VIRTUAL_ENV',
'VIRTUAL_ENV_NAME',
'WORKON_HOME',
'WORKSPACE',
'_APP',
'_BIN',
'_CFG',
'_ETC',
'_LIB',
'_LOG',
'_MNT',
'_OPT',
'_PYLIB',
'_PYSITE',
'_SRC',
'_SRV',
'_VAR',
'_WRD',
'_WRD_SETUPY',
'_WWW',
'__SRC',
'_src',
)
def __getattribute__(self, attr):
return dict.__getattribute__(self, attr)
@classmethod
[docs] def from_environ(cls, environ):
"""
Build an ``Env`` from a dict (e.g. ``os.environ``)
Args:
environ (dict): a dict with variable name keys and values
Returns:
Env: an Env environment built from the given environ dict
"""
return cls((k, environ.get(k, '')) for k in cls.osenviron_keys)
[docs] def set_standard_paths(env, prefix):
"""
Set variables for standard paths in the environment
Args:
prefix (str): a path prefix (e.g. ``$VIRTUAL_ENV`` or ``$PREFIX``)
see:
- https://en.wikipedia.org/wiki/Unix_directory_structure
- https://en.wikipedia.org/wiki/Filesystem_Hierarchy_Standard
"""
#
env['_BIN'] = joinpath(prefix, "bin") # ./bin
env['_ETC'] = joinpath(prefix, "etc") # ./etc
env['_ETCOPT'] = joinpath(prefix, "etc/opt") # ./etc/opt
env['_HOME'] = joinpath(prefix, "home") # ./home
env['_ROOT'] = joinpath(prefix, "root") # ./root
env['_LIB'] = joinpath(prefix, "lib") # ./lib
env['_PYLIB'] = joinpath(prefix, "lib", pyver) # ./lib/pythonN.N
env['_PYSITE'] = joinpath(prefix, "lib", pyver, 'site-packages')
env['_MNT'] = joinpath(prefix, "mnt") # ./mnt
env['_MEDIA'] = joinpath(prefix, "media") # ./media
env['_OPT'] = joinpath(prefix, "opt") # ./opt
env['_SBIN'] = joinpath(prefix, "sbin") # ./sbin
env['_SRC'] = joinpath(prefix, "src") # ./src
env['_SRV'] = joinpath(prefix, "srv") # ./srv
env['_TMP'] = joinpath(prefix, "tmp") # ./tmp
env['_USR'] = joinpath(prefix, "usr") # ./usr
env['_USRBIN'] = joinpath(prefix, "usr/bin") # ./usr/bin
env['_USRINCLUDE'] = joinpath(prefix, "usr/include") # ./usr/include
env['_USRLIB'] = joinpath(prefix, "usr/lib") # ./usr/lib
env['_USRLOCAL'] = joinpath(prefix, "usr/local") # ./usr/local
env['_USRSBIN'] = joinpath(prefix, "usr/sbin") # ./usr/sbin
env['_USRSHARE'] = joinpath(prefix, "usr/share") # ./usr/share
env['_USRSRC'] = joinpath(prefix, "usr/src") # ./usr/src
env['_VAR'] = joinpath(prefix, "var") # ./var
env['_VARCACHE'] = joinpath(prefix, "var/cache") # ./var/cache
env['_VARLIB'] = joinpath(prefix, "var/lib") # ./var/lib
env['_VARLOCK'] = joinpath(prefix, "var/lock") # ./var/lock
env['_LOG'] = joinpath(prefix, "var/log") # ./var/log
env['_VARMAIL'] = joinpath(prefix, "var/mail") # ./var/mail
env['_VAROPT'] = joinpath(prefix, "var/opt") # ./var/opt
env['_VARRUN'] = joinpath(prefix, "var/run") # ./var/run
env['_VARSPOOL'] = joinpath(prefix, "var/spool") # ./var/spool
env['_VARTMP'] = joinpath(prefix, "var/tmp") # ./var/tmp
env['_WWW'] = joinpath(prefix, "var/www") # ./var/www
[docs] def paths_to_variables(self, path_):
"""
Replace components of a path string with variables configured
in this Env.
Args:
path_ (str): a path string
Returns:
str: path string containing ``${VARNAME}`` variables
"""
compress = sorted(
((k, v) for (k, v) in self.items()
if isinstance(v, STR_TYPES) and v.startswith('/')),
key=lambda v: (len(v[1]), v[0]),
reverse=True)
for varname, value in compress:
_path = path_.replace(value, '${%s}' % varname)
return _path
[docs]def shell_quote(var):
"""
Escape single quotes and add double quotes around a given variable.
Args:
_str (str): string to add quotes to
Returns:
str: string wrapped in quotes
.. warning:: This is not safe for untrusted input and only valid
in this context (``os.environ``).
"""
_repr = repr(var)
if _repr.startswith('\''):
return "\"%s\"" % _repr[1:-1]
[docs]def shell_varquote(str_):
"""
Add doublequotes and shell variable brackets to a string
Args:
str_ (str): string to varquote (e.g. ``VIRTUAL_ENV``)
Returns:
str: "${VIRTUAL_ENV}"
"""
return shell_quote('${%s}' % str_)
def _get_shell_version():
"""
Returns:
tuple: (shell_namestr, versionstr) of the current ``$SHELL``
"""
import os
import subprocess
shell = os.environ.get('SHELL')
if not shell:
raise Exception('SHELL is not set')
output = subprocess.check_output(
(shell, '--version')).split('\n', 1)[0]
if output.startswith('GNU bash, version '):
verstr = output.lstrip('GNU bash, version ')
return ('bash', verstr)
if output.startswith('zsh '):
return output.split(' ', 1)
def _shell_supports_declare_g():
"""
Returns:
bool: True only if the ``$SHELL`` is known to support ``declare -g``
"""
# NOTE: OSX still has bash 3.2, which does not support '-g'
shell, verstr = _get_shell_version()
if shell == 'zsh':
return True
if shell == 'bash':
if verstr.startswith('4'):
return True
return False
[docs]class Venv(object):
"""
A virtual environment configuration generator
"""
@staticmethod
[docs] def get_virtualenv_path(virtualenv=None, from_environ=False):
"""
Get the path to a virtualenv
Args:
virtualenv (str): a path to a virtualenv containing ``/``
OR just the name of a virtualenv in ``$WORKON_HOME``
from_environ (bool): whether to try and read from
``os.environ["VIRTUAL_ENV"]``
Returns:
str: a path to a virtualenv (for ``$VIRTUAL_ENV``)
"""
_virtualenv = None
if virtualenv is None:
if from_environ:
_virtualenv = os.environ.get('VIRTUAL_ENV')
else:
log.error("Virtualenv not specified")
else:
if '/' not in virtualenv:
_virtualenv = joinpath(
get_workon_home_default(),
virtualenv)
else:
_virtualenv = virtualenv
if _virtualenv and not os.path.exists(_virtualenv):
log.debug("virtualenv %r does not exist" % _virtualenv)
return _virtualenv
def __init__(self, virtualenv=None, appname=None,
env=None,
from_environ=False,
open_editors=False,
open_terminals=False,
dont_reflect=True):
"""
Initialize a new Venv
Args:
virtualenv (str): None, a path to a virtualenv, or the basename
of a virtualenv in ``$WORKON_HOME``
appname (str): path component under ``$VIRTUAL_ENV/src/<appname>``.
``$_APP`` (and thus ``$_WRD``) are set from this variable.
if not specified, ``$_APP`` will default to the basename of
``$VIRTUAL_ENV``.
env (Env): an already-configured Env object
if ``env`` is None (the default), a new Env will be created
from_environ (bool): True if ``os.environ`` should be read from
(default: False)
open_editors (bool): Whether to open an editor of the Venv
(default: False)
open_terminals (bool): Whether to open terminals of the Venv
(default: False)
dont_reflect (bool): Whether to always create aliases and functions
referencing ``$_WRD`` even if ``$_WRD`` doesn't exist.
(default: True)
Raises:
Exception: if virtualenv is not specified or incalculable
from the given combination of
``virtualenv`` and ``from_environ`` arguments
Exception: if both ``env`` and ``from_environ=True`` are specified
"""
self.log = logging.getLogger('venv.%s' % appname)
_virtualenv = self.get_virtualenv_path(virtualenv,
from_environ=from_environ)
if _virtualenv is None:
errmsg = '''
You specified virtualenv=%r
virtualenv must be:
A. a relative or absolute path to a virtualenv
B. a virtualenv name (a path in $WORKON_HOME)
Did you mean to specify -E (--from-shell-environ)?
''' % virtualenv
raise Exception(errmsg)
else:
self.virtualenv = _virtualenv
self.name = os.path.basename(self.virtualenv)
if appname is None:
appname = self.name
apppath = joinpath(self.virtualenv, 'src', appname) #
if not os.path.exists(apppath):
logging.debug("apppath %r does not exist" % apppath)
# TODO
if appname is None:
appname = os.path.basename(self.virtualenv)
self.appname = appname
self.log = logging.getLogger('venv.%s' % appname)
if env and from_environ:
raise Exception("both 'env' and 'from_environ=True' were specified")
if from_environ:
self.env = Env.from_environ(os.environ)
else:
if env is None:
self.env = Env()
else:
self.env = env
env = self.env
env['VIRTUAL_ENV'] = self.virtualenv
env['VIRTUAL_ENV_NAME'] = self.name
env.set_standard_paths(self.virtualenv)
env['_USRLOG'] = joinpath(self.virtualenv, ".usrlog")
env['HISTFILE'] = joinpath(self.virtualenv, ".bash_history")
env['HISTSIZE'] = 1000000
env['HISTFILESIZE'] = 1000000
# env['HISTTIMEFORMAT'] = "%F %T " # see etc/bash/usrlog.sh
env['PAGER'] = '/usr/bin/less -R'
env['_APP'] = self.appname
env['_WRD'] = joinpath(env['_SRC'], self.appname) # working directory
self.aliases = self.get_user_aliases_base()
self.aliases.update(self.get_user_aliases(dont_reflect=dont_reflect))
if open_editors:
self.open_editors()
if open_terminals:
self.open_terminals()
@staticmethod
def _configure_sys(env=None, from_environ=False):
"""
Configure sys.path with the given env, or from from_environ
Args:
env (Env): Env to configure sys.path according to
(default: None)
from_environ (bool): whether to read Env from ``os.environ``
(default: False)
.. note:: This method adds
``/usr/local/python.ver.ver/dist-packages/IPython/extensions``
to ``sys.path``
Why? When working in a virtualenv which does not have
an additional local copy of IPython installed,
the lack of an extensions path was causing errors
in regards to missing extensions.
"""
if from_environ:
env = Env.from_environ(os.environ)
env['_PYLIB'] = joinpath(env['_LIB'], pyver)
env['_PYSITE'] = joinpath(env['_PYLIB'], 'site-packages')
no_global_site_packages = joinpath(
env('_PYLIB'), 'no-global-site-packages.txt')
if not os.path.exists(no_global_site_packages):
sys_libdir = joinpath("/usr/lib", pyver)
sys.path = [joinpath(sys_libdir, p) for p in (
"", "plat-linux2", "lib-tk", "lib-dynload")]
# TODO
ipython_extensions = (
'/usr/local/lib/%s/dist-packages/IPython/extensions'
% pyver)
if not os.path.exists(ipython_extensions):
log.info("IPython extensions not found: %r",
ipython_extensions)
if ipython_extensions not in sys.path:
sys.path.append(ipython_extensions)
# optimize_python_path(sys.path)
site.addsitedir(env['_PYSITE'])
return sys.path
[docs] def get_user_aliases_base(self):
"""
Returns:
OrderedDict: dict of ``cd`` command aliases
.. note:: These do not work in IPython as they run in a subshell.
See: :py:mod:`dotfiles.venv.ipython_magics`.
"""
aliases = OrderedDict()
env = self.env
def cdalias(varname):
return 'cd {}/%l'.format(shell_varquote(varname))
aliases['cdb'] = cdalias('_BIN')
aliases['cde'] = cdalias('_ETC')
aliases['cdh'] = cdalias('HOME')
aliases['cdl'] = cdalias('_LIB')
aliases['cdlog'] = cdalias('_LOG')
aliases['cdp'] = cdalias('PROJECT_HOME')
aliases['cdph'] = cdalias('PROJECT_HOME')
aliases['cdpylib'] = cdalias('_PYLIB')
aliases['cdpysite'] = cdalias('_PYSITE')
aliases['cds'] = cdalias('_SRC')
aliases['cdv'] = cdalias('VIRTUAL_ENV')
aliases['cdve'] = cdalias('VIRTUAL_ENV')
aliases['cdvar'] = cdalias('_VAR')
aliases['cdwh'] = cdalias('WORKON_HOME')
aliases['cdwrk'] = cdalias('WORKON_HOME')
aliases['cdw'] = cdalias('_WRD')
aliases['cd-'] = cdalias('_WRD')
aliases['cdww'] = cdalias('_WWW')
aliases['cdwww'] = cdalias('_WWW')
aliases['cdhelp'] = """set | grep "^cd.*()" | cut -f1 -d" " #%l"""
return aliases
[docs] def get_user_aliases(self, dont_reflect=False):
"""
Configure env variables and return an OrderedDict of aliases
Args:
dont_reflect (bool): Whether to always create aliases and functions
referencing ``$_WRD`` even if ``$_WRD`` doesn't exist.
(default: False)
Returns:
OrderedDict: dict of aliases
"""
aliases = OrderedDict()
env = self.env
env['VIMBIN'] = distutils.spawn.find_executable('vim')
env['GVIMBIN'] = distutils.spawn.find_executable('gvim')
env['MVIMBIN'] = distutils.spawn.find_executable('mvim')
env['GUIVIMBIN'] = env.get('MVIMBIN', env.get('GVIMBIN'))
env['VIMCONF'] = "--servername %s" % (
shell_quote(self.appname).strip('"'))
if not env.get('GUIVIMBIN'):
env['_EDIT_'] = "%s -f" % env.get('VIMBIN')
else:
env['_EDIT_'] = '%s %s --remote-tab-silent' % (
env.get('GUIVIMBIN'),
env.get('VIMCONF'))
env['EDITOR_'] = env['_EDIT_']
aliases['edit-'] = env['_EDIT_']
aliases['gvim-'] = env['_EDIT_']
env['_IPSESSKEY'] = joinpath(env['_SRC'], '.sessionkey')
env['_NOTEBOOKS'] = joinpath(env['_SRC'], 'notebooks')
if sys.version_info.major == 2:
_new_ipnbkey="print os.urandom(128).encode(\\\"base64\\\")"
elif sys.version_info.major == 3:
_new_ipnbkey="print(os.urandom(128).encode(\\\"base64\\\"))"
else:
raise KeyError(sys.version_info.major)
aliases['ipskey'] = ('(python -c \"'
'import os;'
' {_new_ipnbkey}\"'
' > {_IPSESSKEY} )'
' && chmod 0600 {_IPSESSKEY};'
' # %l'
).format(
_new_ipnbkey=_new_ipnbkey,
_IPSESSKEY=shell_varquote('_IPSESSKEY'))
aliases['ipnb'] = ('ipython notebook'
' --secure'
' --Session.keyfile={_IPSESSKEY}'
' --notebook-dir={_NOTEBOOKS}'
' --deep-reload'
' %l').format(
_IPSESSKEY=shell_varquote('_IPSESSKEY'),
_NOTEBOOKS=shell_varquote('_NOTEBOOKS'))
env['_IPQTLOG'] = joinpath(env['VIRTUAL_ENV'], '.ipqt.log')
aliases['ipqt'] = ('ipython qtconsole'
' --secure'
' --Session.keyfile={_IPSESSKEY}'
' --logappend={_IPQTLOG}'
' --deep-reload'
#' --gui-completion'
#' --existing=${_APP}'
' --pprint'
#' --pdb'
' --colors=linux'
' --ConsoleWidget.font_family="Monaco"'
' --ConsoleWidget.font_size=11'
' %l').format(
_IPSESSKEY=shell_varquote('_IPSESSKEY'),
_APP=shell_varquote('_APP'),
_IPQTLOG=shell_varquote('_IPQTLOG'))
aliases['grinv'] = 'grin --follow %%l %s' % shell_varquote('VIRTUAL_ENV')
aliases['grindv'] = 'grind --follow %%l --dirs %s' % shell_varquote('VIRTUAL_ENV')
aliases['grins'] = 'grin --follow %%l %s' % shell_varquote('_SRC')
aliases['grinds'] = 'grind --follow %%l --dirs %s' % shell_varquote('_SRC')
_WRD = env['_WRD']
if os.path.exists(_WRD) or dont_reflect:
env['_WRD'] = _WRD
env['_WRD_SETUPY'] = joinpath(_WRD, 'setup.py')
env['_TEST_'] = "(cd {_WRD} && python {_WRD_SETUPY} test)".format(
_WRD=shell_varquote('_WRD'),
_WRD_SETUPY=shell_varquote('_WRD_SETUPY')
)
aliases['test-'] = env['_TEST_']
aliases['testr-'] = 'reset && %s' % env['_TEST_']
aliases['nose-'] = '(cd {_WRD} && nosetests)'.format(
_WRD=shell_varquote('_WRD'))
aliases['grinw'] = 'grin --follow %l {_WRD}'.format(
_WRD=shell_varquote('_WRD'))
aliases['grin-'] = aliases['grinw']
aliases['grindw'] = 'grind --follow %l --dirs {_WRD}'.format(
_WRD=shell_varquote('_WRD'))
aliases['grind-'] = aliases['grindw']
aliases['hgv-'] = "hg view -R {_WRD}".format(
_WRD=shell_varquote('_WRD'))
aliases['hgl-'] = "hg -R {_WRD} log".format(
_WRD=shell_varquote('_WRD'))
else:
self.log.error('app working directory %r not found' % _WRD)
_CFG = joinpath(env['_ETC'], 'development.ini')
if os.path.exists(_CFG) or dont_reflect:
env['_CFG'] = _CFG
env['_EDITCFG_'] = "{_EDIT_} {_CFG}".format(
_EDIT_=env['_EDIT_'],
_CFG=env['_CFG'])
aliases['editcfg'] = "{_EDITCFG} %l".format(
_EDITCFG=shell_varquote('_EDITCFG_'))
# Pyramid pshell & pserve (#TODO: test -f manage.py (django))
env['_SHELL_'] = "(cd {_WRD} && {_BIN}/pshell {_CFG})".format(
_BIN=shell_varquote('_BIN'),
_CFG=shell_varquote('_CFG'),
_WRD=shell_varquote('_WRD'))
env['_SERVE_'] =("(cd {_WRD} && {_BIN}/pserve"
" --app-name=main"
" --reload"
" --monitor-restart {_CFG})").format(
_BIN=shell_varquote('_BIN'),
_WRD=shell_varquote('_WRD'),
_CFG=shell_varquote('_CFG'))
aliases['serve-'] = env['_SERVE_']
aliases['shell-'] = env['_SHELL_']
else:
self.log.error('app configuration %r not found' % _CFG)
env['_CFG'] = ""
aliases['edit-'] = "${_EDIT_} %l"
aliases['e'] = aliases['edit-']
env['PROJECT_FILES']= " ".join(
str(x) for x in self._project_files)
aliases['editp'] = "$GUIVIMBIN $VIMCONF $PROJECT_FILES %l"
aliases['makewrd'] = "(cd {_WRD} && make %l)".format(
_WRD=shell_varquote('_WRD'))
aliases['make-'] = aliases['makewrd']
aliases['mw'] = aliases['makewrd']
_SVCFG = env.get('_SVCFG', joinpath(env['_ETC'], 'supervisord.conf'))
if os.path.exists(_SVCFG) or dont_reflect:
env['_SVCFG'] = _SVCFG
env['_SVCFG_'] = ' -c %s' % shell_quote(env['_SVCFG'])
else:
self.log.error('supervisord configuration %r not found' % _SVCFG)
env['_SVCFG_'] = ''
aliases['ssv'] = 'supervisord -c "${_SVCFG}"'
aliases['sv'] = 'supervisorctl -c "${_SVCFG}"'
aliases['svt'] = 'sv tail -f'
aliases['svd'] = ('supervisorctl -c "${_SVCFG}" restart dev'
' && supervisorctl -c "${_SVCFG}" tail -f dev')
return aliases
@classmethod
[docs] def workon_project(cls, virtualenv, **kwargs):
"""
Args:
virtualenv (str): a path to a virtualenv containing ``/``
OR just the name of a virtualenv in ``$WORKON_HOME``
kwargs (dict): kwargs to pass to Venv (see ``Venv.__init__``)
Returns:
Venv: an intialized ``Venv``
"""
return cls(virtualenv=virtualenv, **kwargs)
@staticmethod
def _configure_ipython(c=None, setup_func=None, platform=None):
"""
Configure IPython with ``autoreload=True``, ``deep_reload=True``,
the **storemagic** extension, the **parallelmagic**
extension if ``import zmq`` succeeds,
and ``DEFAULT_ALIASES`` (``cd`` aliases are not currently working).
Args:
c (object): An IPython configuration object (e.g. ``get_ipython()``)
setup_func (function): a function to call (default: None)
Docs:
* http://ipython.org/ipython-doc/dev/config/
* http://ipython.org/ipython-doc/dev/config/options/terminal.html
"""
if c is None:
if not in_ipython_config():
# skip IPython configuration
log.error("not in_ipython_config")
return
else:
c = get_config()
c.InteractiveShellApp.ignore_old_config = True
c.InteractiveShellApp.log_level = 20
c.InteractiveShellApp.extensions = [
# 'autoreload',
'storemagic',
]
#try:
# import sympy
# c.InteractiveShellApp.extensions.append('sympyprinting')
#except ImportError, e:
# pass
try:
import zmq
zmq
c.InteractiveShellApp.extensions.append('parallelmagic')
except ImportError:
pass
c.InteractiveShell.autoreload = True
c.InteractiveShell.deep_reload = True
# %store [name]
c.StoreMagic.autorestore = True
additional = get_DEFAULT_ALIASES(platform=platform).items()
c.AliasManager.default_aliases.extend(additional)
if setup_func:
setup_func(c)
def _ipython_alias_to_bash_alias(self, name, alias):
"""
Convert an IPython alias declaration to an ``alias`` command
or a ``function()`` with ``%l`` replaced with ``$@``.
Args:
name (str): alias name
alias (str): command string (possibly containing an ``%l``)
Returns:
str: either an ``alias name='command'`` string or a function
"""
alias = self.env.paths_to_variables(alias)
if '%s' in alias or '%l' in alias:
# alias = '# %s' % alias
# chunks = alias.split('%s')
_alias = alias[:]
count = 0
while '%s' in _alias:
count += 1
_alias = _alias.replace('%s', '${%d}' % count, 1)
_aliasmacro = (
'eval \'{cmdname} () {{\n {aliasfunc}\n}}\';'.format(
cmdname=name,
aliasfunc=_alias))
return _aliasmacro.replace('%l', '$@')
return 'alias %s=%r' % (name, alias)
[docs] def bash_env(self, output=sys.stdout):
"""
Generate a ``source``-able script for the environment variables,
aliases, and functions defined by the current ``Venv``.
Args:
output (file-like): object to ``print`` to
(``print`` calls ``.write()`` and then ``.flush()``)
"""
for k, v in self.env.items():
print("export %s=%r" % (k, v), file=output)
# if _shell_supports_declare_g():
# print("declare -grx %s=%r" % (k, v), file=output)
# else:
# print("export %s=%r" % (k, v), file=output)
# print("declare -r %k" % k, file=output)
for k, v in self.aliases.items():
bash_alias = self._ipython_alias_to_bash_alias(k, v)
print(bash_alias, file=output)
@property
def _project_files(self):
"""
Default list of project files for ``_EDITCMD_``.
Returns:
list: list of paths relative to ``$_WRD``.
"""
default_project_files = (
'README.rst',
'CHANGES.rst',
'TODO.rst',
'Makefile',
'setup.py',
'requirements.txt',
'.hgignore',
'.gitignore',
'.hg/hgrc',
'',
self.appname,
'docs',
)
return default_project_files
@property
def _edit_project_cmd(self):
"""
Command to edit ``self._project_files``
Returns:
str: ``$_EDIT_`` ``self._project_files``
"""
return "%s %s" % (
self.env['_EDIT_'],
' '.join(
shell_quote(joinpath(self.env['_WRD'], p))
for p in (self._project_files))
)
@property
def _terminal_cmd(self):
"""
Command to open a terminal
Returns:
str: env.get('TERMINAL') or ``/usr/bin/gnome-terminal``
"""
# TODO: add Terminal.app
return self.env.get('TERMINAL', '/usr/bin/gnome-terminal')
@property
def _open_terminals_cmd(self):
"""
Command to open ``self._terminal_cmd`` with a list of initial
named terminals.
"""
# TODO: add Terminal.app (man Terminal.app?)
cmd = (
self._terminal_cmd,
'--working-directory', self.env['_WRD'],
'--tab', '--title', '%s: bash' % self.appname,
'--command', 'bash',
'--tab', '--title', '%s: serve' % self.appname,
'--command', "bash -c 'we %s %s'; bash" % (
self.virtualenv, self.appname), #
'--tab', '--title', '%s: shell' % self.appname,
'--command', "bash -c %r; bash" % self.env['_SHELL_']
)
return cmd
[docs] def system(self, cmd=None):
"""
Call ``os.system`` with the given command string
Args:
cmd (string): command string to call ``os.system`` with
Raises:
Exception: if ``cmd`` is None
NotImplementedError: if ``cmd`` is a tuple
"""
if cmd is None:
raise Exception()
if isinstance(cmd, (tuple, list)):
_cmd = ' '.join(cmd)
# TODO: (subprocess.Popen)
raise NotImplementedError()
elif isinstance(cmd, (str,)):
_cmd = cmd
os.system(_cmd)
[docs] def open_editors(self):
"""
Run ``self._edit_project_cmd``
"""
cmd = self._edit_project_cmd
self.system(cmd=cmd)
[docs] def open_terminals(self):
"""
Run ``self._open_terminals_cmd``
"""
cmd = self._open_terminals_cmd
self.system(cmd=cmd)
[docs] def asdict(self):
"""
Returns:
OrderedDict: OrderedDict(env=self.env, aliases=self.aliases)
"""
return OrderedDict(
env=self.env,
aliases=self.aliases,
)
[docs] def to_json(self, indent=None):
"""
Args:
indent (int): number of spaces with which to indent JSON output
Returns:
str: json.dumps(self.asdict())
"""
import json
return json.dumps(self.asdict(), indent=indent)
[docs]def get_DEFAULT_ALIASES(platform=None):
if platform is None:
platform = sys.platform
IS_DARWIN = platform == 'darwin'
LS_COLOR_AUTO = "--color=auto"
if IS_DARWIN:
LS_COLOR_AUTO = "-G"
PSX_COMMAND = 'ps uxaw'
PSF_COMMAND = 'ps uxawf'
PS_SORT_CPU = '--sort=-pcpu'
PS_SORT_MEM = '--sort=-pmem'
if IS_DARWIN:
PSX_COMMAND = 'ps uxaw'
PSF_COMMAND = 'ps uxaw'
PS_SORT_CPU = '-c'
PS_SORT_MEM = '-m'
DEFAULT_ALIASES = OrderedDict((
('cp', 'cp'),
('bash', 'bash'),
('cat', 'cat'),
('chmodr', 'chmod -R'),
('chownr', 'chown -R'),
('egrep', 'egrep --color=auto'),
('fgrep', 'fgrep --color=auto'),
('git', 'git'),
('ga', 'git add'),
('gd', 'git diff'),
('gdc', 'git diff --cached'),
('gs', 'git status'),
('gl', 'git log'),
('grep', 'grep --color=auto'),
('grin', 'grin'),
('grind', 'grind'),
('grinpath', 'grin --sys-path'),
('grindpath', 'grind --sys-path'),
('grunt', 'grunt'),
('gvim', 'gvim'),
('head', 'head'),
('hg', 'hg'),
('hgl', 'hg log -l10'),
('hgs', 'hg status'),
('htop', 'htop'),
('ifconfig', 'ifconfig'),
('ip', 'ip'),
('last', 'last'),
('la', 'ls {} -A'.format(LS_COLOR_AUTO)),
('ll', 'ls {} -al'.format(LS_COLOR_AUTO)),
('ls', 'ls {}'.format(LS_COLOR_AUTO)),
('lt', 'ls {} -altr'.format(LS_COLOR_AUTO)),
('lz', 'ls {} -alZ'.format(LS_COLOR_AUTO)),
('lxc', 'lxc'),
('make', 'make'),
('mkdir', 'mkdir'),
('netstat', 'netstat'),
('nslookup', 'nslookup'),
('ping', 'ping'),
('mv', 'mv'),
('ps', 'ps'),
('psf', PSF_COMMAND),
('psx', PSX_COMMAND),
('psh', '{} | head'.format(PSX_COMMAND)),
('psc', '{} {}'.format(PSX_COMMAND, PS_SORT_CPU)),
('psch', '{} {} | head'.format(PSX_COMMAND, PS_SORT_CPU)),
('psm', '{} {}'.format(PSX_COMMAND, PS_SORT_MEM)),
('psmh', '{} {} | head'.format(PSX_COMMAND, PS_SORT_MEM)),
('psfx', PSF_COMMAND),
('pydoc', 'pydoc'),
('pyline', 'pyline'),
('pyrpo', 'pyrpo'),
('route', 'route'),
('rm', 'rm'),
('rsync', 'rsync'),
('sqlite3', 'sqlite3'),
('ss', 'ss'),
('ssv', 'supervisord'),
('stat', 'stat'),
('sudo', 'sudo'),
('sv', 'supervisorctl'),
('t', 'tail -f'),
('tail', 'tail'),
('thg', 'thg'),
('top', 'top'),
('tracepath', 'tracepath'),
('tracepath6', 'tracepath6'),
('vim', 'vim'),
('uptime', 'uptime'),
('which', 'which'),
('who_', 'who'),
('whoami', 'whoami'),
('zsh', 'zsh'),
))
return DEFAULT_ALIASES
[docs]def in_ipython_config():
"""
Returns:
bool: True if ``get_ipython`` is in ``globals()``
"""
return 'get_config' in globals()
[docs]def ipython_main():
"""
Function to call if running within IPython,
as determined by ``in_ipython_config``.
"""
venv = None
if 'VIRTUAL_ENV' in os.environ:
venv = Venv(from_environ=True)
venv.configure_ipython()
else:
Venv._configure_ipython()
if in_ipython_config():
print("### ipython_config.py: configuring IPython")
ipython_main()
[docs]def ipython_imports():
"""
Default imports for IPython (currently unused)
"""
from IPython.external.path import path
path
from pprint import pprint as pp
pp
from pprint import pformat as pf
pf
def ppd(self, *args, **kwargs):
import json
print(type(self))
print(
json.dumps(*args, indent=2))
import unittest
[docs]class Test_Env(unittest.TestCase):
[docs] def test_Env(self):
e = Env()
assert 'WORKON_HOME' not in e
[docs] def test_Env_from_environ(self):
import os
e = Env.from_environ(os.environ)
assert 'WORKON_HOME' in e
[docs]class Test_venv(unittest.TestCase):
[docs] def setUp(self):
self.TEST_VIRTUALENV = 'dotfiles'
self.TEST_APPNAME = 'dotfiles'
self.TEST_VIRTUAL_ENV = joinpath(get_workon_home_default(), 'dotfiles')
[docs] def test_venv(self):
venv = Venv(self.TEST_VIRTUALENV)
assert 'VIRTUAL_ENV' in venv.env
self.assertEqual(venv.virtualenv, self.TEST_VIRTUAL_ENV)
[docs] def test_venv_appname(self):
venv = Venv(self.TEST_VIRTUALENV, self.TEST_APPNAME)
self.assertEqual(venv.appname, self.TEST_APPNAME)
[docs] def test_venv_from_null_environ(self):
self.failUnlessRaises(Exception, Venv)
[docs] def test_venv_without_environ(self):
os.environ['VIRTUAL_ENV'] = self.TEST_VIRTUAL_ENV
self.failUnlessRaises(Exception, Venv)
[docs] def test_venv_with_environ(self):
os.environ['VIRTUAL_ENV'] = self.TEST_VIRTUAL_ENV
venv = Venv(from_environ=True)
venv
[docs]def get_venv_parser():
"""
Returns:
optparse.OptionParser: options for the commandline interface
"""
import optparse
prs = optparse.OptionParser(
usage=("%prog [-b|--print-bash] [-t] [-e] [-E<virtualenv>] [appname]"),
description="dotfiles.venv.ipython_config.py",
epilog="Copyright 2014 Wes Turner. New BSD License\n")
prs.add_option('-E', '--from-shell-environ',
dest='load_environ',
action='store_true')
prs.add_option('-p', '--print', '--print-json', '--json',
dest='print_env',
action='store_true',
help="Print venv configuration as JSON")
prs.add_option('-b', '--bash', '--print-bash', '--zsh', '--print-zsh',
dest='print_bash',
action='store_true',
help="Print venv configuration for Bash, ZSH"
)
prs.add_option('-x', '--cmd', '--command',
dest='run_command',
action='store',
help="Run a command in a venv-configured shell")
prs.add_option('-t', '--terminals', '--open-terminals',
dest='open_terminals',
action='store_true',
default=False,
help="Open terminals within the venv [gnome-terminal]"
)
prs.add_option('-e', '--editors', '--open-editors',
dest='open_editors',
action='store_true',
default=False,
help=("Open an editor with venv._project_files"
" [$PROJECT_FILES]")
)
prs.add_option('--platform',
dest='platform',
action='store',
default=None,
help='Platform to generate configuration for')
prs.add_option('-v', '--verbose',
dest='verbose',
action='store_true',)
prs.add_option('-q', '--quiet',
dest='quiet',
action='store_true',)
prs.add_option('-T', '--test',
dest='run_tests',
action='store_true',)
return prs
[docs]def main():
"""
Commandline main function called if ``__name__=="__main__"``
Returns:
int: nonzero on error
"""
import logging
prs = get_venv_parser()
(opts, args) = prs.parse_args()
if not opts.quiet:
logging.basicConfig()
if opts.verbose:
logging.getLogger().setLevel(logging.DEBUG)
if opts.run_tests:
sys.argv = [sys.argv[0]] + args
sys.exit(unittest.main())
if opts.load_environ:
import os
if 'VIRTUAL_ENV' in os.environ:
args.insert(0, os.environ['VIRTUAL_ENV'])
venv = Venv(*args,
open_editors=opts.open_editors,
open_terminals=opts.open_terminals)
if opts.print_env:
output = sys.stdout
print(venv.to_json(indent=2), file=output)
if opts.print_bash:
venv.bash_env()
if opts.run_command:
import os
import subprocess
os.environ.update((k, str(v)) for (k, v) in venv.env.items())
subprocess.call(opts.run_command,
shell=True,
env=os.environ,
cwd=venv.virtualenv)
return 0
if __name__ == "__main__":
main()