Source code for fabtools.python

"""
Python environments and packages
================================

This module provides tools for using Python `virtual environments`_
and installing Python packages using the `pip`_ installer.

.. _virtual environments: http://www.virtualenv.org/
.. _pip: http://www.pip-installer.org/

"""
from __future__ import with_statement

from contextlib import contextmanager
from distutils.version import StrictVersion as V
from pipes import quote
import os
import posixpath
import re

from fabric.api import cd, hide, prefix, run, settings, sudo
from fabric.utils import puts

from fabtools.files import is_file
from fabtools.utils import abspath, download, run_as_root


GET_PIP_URL = 'https://raw.githubusercontent.com/pypa/pip/master/contrib/get-pip.py'


[docs]def is_pip_installed(version=None, pip_cmd='pip'): """ Check if `pip`_ is installed. .. _pip: http://www.pip-installer.org/ """ with settings(hide('running', 'warnings', 'stderr', 'stdout'), warn_only=True): res = run('%(pip_cmd)s --version 2>/dev/null' % locals()) if res.failed: return False if version is None: return res.succeeded else: m = re.search(r'pip (?P<version>.*) from', res) if m is None: return False installed = m.group('version') if V(installed) < V(version): puts("pip %s found (version >= %s required)" % (installed, version)) return False else: return True
[docs]def install_pip(python_cmd='python', use_sudo=True): """ Install the latest version of `pip`_, using the given Python interpreter. :: import fabtools if not fabtools.python.is_pip_installed(): fabtools.python.install_pip() .. note:: pip is automatically installed inside a virtualenv, so there is no need to install it yourself in this case. .. _pip: http://www.pip-installer.org/ """ with cd('/tmp'): download(GET_PIP_URL) command = '%(python_cmd)s get-pip.py' % locals() if use_sudo: run_as_root(command, pty=False) else: run(command, pty=False) run('rm -f get-pip.py')
[docs]def is_installed(package, pip_cmd='pip'): """ Check if a Python package is installed (using pip). Package names are case insensitive. Example:: from fabtools.python import virtualenv import fabtools with virtualenv('/path/to/venv'): fabtools.python.install('Flask') assert fabtools.python.is_installed('flask') .. _pip: http://www.pip-installer.org/ """ with settings(hide('running', 'stdout', 'stderr', 'warnings'), warn_only=True): res = run('%(pip_cmd)s freeze' % locals()) packages = [line.split('==')[0].lower() for line in res.splitlines()] return (package.lower() in packages)
[docs]def install(packages, upgrade=False, download_cache=None, allow_external=None, allow_unverified=None, quiet=False, pip_cmd='pip', use_sudo=False, user=None, exists_action=None): """ Install Python package(s) using `pip`_. Package names are case insensitive. Starting with version 1.5, pip no longer scrapes insecure external urls by default and no longer installs externally hosted files by default. Use ``allow_external=['foo', 'bar']`` or ``allow_unverified=['bar', 'baz']`` to change these behaviours for specific packages. Examples:: import fabtools # Install a single package fabtools.python.install('package', use_sudo=True) # Install a list of packages fabtools.python.install(['pkg1', 'pkg2'], use_sudo=True) .. _pip: http://www.pip-installer.org/ """ if isinstance(packages, basestring): packages = [packages] if allow_external in (None, False): allow_external = [] elif allow_external == True: allow_external = packages if allow_unverified in (None, False): allow_unverified = [] elif allow_unverified == True: allow_unverified = packages options = [] if upgrade: options.append('--upgrade') if download_cache: options.append('--download-cache="%s"' % download_cache) if quiet: options.append('--quiet') for package in allow_external: options.append('--allow-external="%s"' % package) for package in allow_unverified: options.append('--allow-unverified="%s"' % package) if exists_action: options.append('--exists-action=%s' % exists_action) options = ' '.join(options) packages = ' '.join(packages) command = '%(pip_cmd)s install %(options)s %(packages)s' % locals() if use_sudo: sudo(command, user=user, pty=False) else: run(command, pty=False)
[docs]def install_requirements(filename, upgrade=False, download_cache=None, allow_external=None, allow_unverified=None, quiet=False, pip_cmd='pip', use_sudo=False, user=None, exists_action=None): """ Install Python packages from a pip `requirements file`_. :: import fabtools fabtools.python.install_requirements('project/requirements.txt') .. _requirements file: http://www.pip-installer.org/en/latest/requirements.html """ if allow_external is None: allow_external = [] if allow_unverified is None: allow_unverified = [] options = [] if upgrade: options.append('--upgrade') if download_cache: options.append('--download-cache="%s"' % download_cache) for package in allow_external: options.append('--allow-external="%s"' % package) for package in allow_unverified: options.append('--allow-unverified="%s"' % package) if quiet: options.append('--quiet') if exists_action: options.append('--exists-action=%s' % exists_action) options = ' '.join(options) command = '%(pip_cmd)s install %(options)s -r %(filename)s' % locals() if use_sudo: sudo(command, user=user, pty=False) else: run(command, pty=False)
def create_virtualenv(directory, system_site_packages=False, venv_python=None, use_sudo=False, user=None, clear=False, prompt=None, virtualenv_cmd='virtualenv'): """ Create a Python `virtual environment`_. :: import fabtools fabtools.python.create_virtualenv('/path/to/venv') .. _virtual environment: http://www.virtualenv.org/ """ options = ['--quiet'] if system_site_packages: options.append('--system-site-packages') if venv_python: options.append('--python=%s' % quote(venv_python)) if clear: options.append('--clear') if prompt: options.append('--prompt=%s' % quote(prompt)) options = ' '.join(options) directory = quote(directory) command = '%(virtualenv_cmd)s %(options)s %(directory)s' % locals() if use_sudo: sudo(command, user=user) else: run(command) def virtualenv_exists(directory): """ Check if a Python `virtual environment`_ exists. .. _virtual environment: http://www.virtualenv.org/ """ return is_file(posixpath.join(directory, 'bin', 'python')) @contextmanager
[docs]def virtualenv(directory, local=False): """ Context manager to activate an existing Python `virtual environment`_. :: from fabric.api import run from fabtools.python import virtualenv with virtualenv('/path/to/virtualenv'): run('python -V') .. _virtual environment: http://www.virtualenv.org/ """ path_mod = os.path if local else posixpath # Build absolute path to the virtualenv activation script venv_path = abspath(directory) activate_path = path_mod.join(venv_path, 'bin', 'activate') # Source the activation script with prefix('. %s' % quote(activate_path)): yield