diff --git a/flit/__init__.py b/flit/__init__.py index c3535a1d..e4554ff3 100644 --- a/flit/__init__.py +++ b/flit/__init__.py @@ -60,7 +60,12 @@ def main(argv=None): ) add_shared_install_options(parser_install) parser_install.add_argument('--deps', choices=['all', 'production', 'develop', 'none'], default='all', - help="Which set of dependencies to install") + help="Which set of dependencies to install. If --deps=develop, the extras dev, doc, and test are installed" + ) + parser_install.add_argument('--extras', default=(), type=lambda l: l.split(',') if l else (), + help="Install the dependencies of these (comma separated) extras additionally to the ones implied by --deps. " + "--extras=all can be useful in combination with --deps=production, --deps=none precludes using --extras" + ) parser_installfrom = subparsers.add_parser('installfrom', help="Download and install a package using flit from source" @@ -107,7 +112,8 @@ def main(argv=None): from .install import Installer try: Installer(args.ini_file, user=args.user, python=args.python, - symlink=args.symlink, deps=args.deps, pth=args.pth_file).install() + symlink=args.symlink, deps=args.deps, extras=args.extras, + pth=args.pth_file).install() except (common.NoDocstringError, common.NoVersionError) as e: sys.exit(e.args[0]) elif args.subcmd == 'installfrom': diff --git a/flit/install.py b/flit/install.py index 8d14f695..2c9cdd26 100644 --- a/flit/install.py +++ b/flit/install.py @@ -84,17 +84,24 @@ def __str__(self): return ("Installing packages as root is not recommended. " "To allow this, set FLIT_ROOT_INSTALL=1 and try again.") +class DependencyError(Exception): + def __str__(self): + return 'To install dependencies for extras, you cannot set deps=none.' + class Installer(object): def __init__(self, ini_path, user=None, python=sys.executable, - symlink=False, deps='all', pth=False): + symlink=False, deps='all', extras=(), pth=False): self.ini_path = ini_path self.python = python self.symlink = symlink self.pth = pth self.deps = deps + self.extras = extras if deps != 'none' and os.environ.get('FLIT_NO_NETWORK', ''): self.deps = 'none' log.warning('Not installing dependencies, because FLIT_NO_NETWORK is set') + if deps == 'none' and extras: + raise DependencyError() self.ini_info = inifile.read_pkg_ini(ini_path) self.module = common.Module(self.ini_info['module'], ini_path.parent) @@ -196,10 +203,15 @@ def install_requirements(self): return if self.deps in ('all', 'production'): requirements.extend(self.ini_info['metadata'].get('requires_dist', [])) - if self.deps in ('all', 'develop'): - extra_reqs = self.ini_info['metadata'].get('extras_require', {}) - for extra in ['dev', 'doc', 'test']: - requirements.extend(extra_reqs.get(extra, [])) + + extra_reqs = self.ini_info['metadata'].get('extras_require', {}) + extras_to_install = set(self.extras) + if self.deps == 'all': + extras_to_install |= set(extra_reqs.keys()) + elif self.deps == 'dev': + extras_to_install |= {'dev', 'doc', 'test'} + for extra in extras_to_install: + requirements.extend(extra_reqs.get(extra, [])) # there aren't any requirements, so return if len(requirements) == 0: