Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor subcommands #264

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 10 additions & 81 deletions flit/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,13 @@
import sys

from . import common
from .subcommand import register
from .log import enable_colourful_output

__version__ = '1.3'

log = logging.getLogger(__name__)

def add_shared_install_options(parser):
parser.add_argument('--user', action='store_true', default=None,
help="Do a user-local install (default if site.ENABLE_USER_SITE is True)"
)
parser.add_argument('--env', action='store_false', dest='user',
help="Install into sys.prefix (default if site.ENABLE_USER_SITE is False, i.e. in virtualenvs)"
)
parser.add_argument('--python', default=sys.executable,
help="Target Python executable, if different from the one running flit"
)

def main(argv=None):
ap = argparse.ArgumentParser()
ap.add_argument('-f', '--ini-file', type=pathlib.Path, default='pyproject.toml')
Expand All @@ -31,53 +21,13 @@ def main(argv=None):
)
ap.add_argument('--debug', action='store_true', help=argparse.SUPPRESS)
ap.add_argument('--logo', action='store_true', help=argparse.SUPPRESS)
subparsers = ap.add_subparsers(title='subcommands', dest='subcmd')

parser_build = subparsers.add_parser('build',
help="Build wheel and sdist",
)

parser_build.add_argument('--format', action='append',
help="Select a format to build. Options: 'wheel', 'sdist'"
)

parser_publish = subparsers.add_parser('publish',
help="Upload wheel and sdist",
)

parser_publish.add_argument('--format', action='append',
help="Select a format to publish. Options: 'wheel', 'sdist'"
)

parser_install = subparsers.add_parser('install',
help="Install the package",
)
parser_install.add_argument('-s', '--symlink', action='store_true',
help="Symlink the module/package into site packages instead of copying it"
)
parser_install.add_argument('--pth-file', action='store_true',
help="Add .pth file for the module/package to site packages instead of copying it"
)
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. 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"
)
parser_installfrom.add_argument('location',
help="A URL to download, or a shorthand like github:takluyver/flit"
)
add_shared_install_options(parser_installfrom)

parser_init = subparsers.add_parser('init',
help="Prepare pyproject.toml for a new package"
)
subparsers = ap.add_subparsers(title='subcommands', dest='subcmd')
register(subparsers, 'build')
register(subparsers, 'publish')
register(subparsers, 'install')
register(subparsers, 'installfrom')
register(subparsers, 'info')

args = ap.parse_args(argv)

Expand All @@ -104,30 +54,9 @@ def main(argv=None):
print(clogo.format(version=__version__))
sys.exit(0)

if args.subcmd == 'build':
from .build import main
try:
main(args.ini_file, formats=set(args.format or []))
except(common.NoDocstringError, common.VCSError, common.NoVersionError) as e:
sys.exit(e.args[0])
elif args.subcmd == 'publish':
from .upload import main
main(args.ini_file, args.repository, formats=set(args.format or []))

elif args.subcmd == 'install':
from .install import Installer
try:
Installer(args.ini_file, user=args.user, python=args.python,
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':
from .installfrom import installfrom
sys.exit(installfrom(args.location, user=args.user, python=args.python))
elif args.subcmd == 'init':
from .init import TerminalIniter
TerminalIniter().initialise()
if args.subcmd:
exitcode = args.subcmd_entrypoint(args)
sys.exit(exitcode)
else:
ap.print_help()
sys.exit(1)
38 changes: 38 additions & 0 deletions flit/subcommand/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
"""
The "subcommand" package contains implementations for CLI commands in flit.

Subcommands must:

* Contain an implementation in ``flit/subcommand/<name>.py``
* Be registered using ``flit.subcommand.register`` before parsing the arguments

Each subcommand module must contain the following names:

* NAME: the name of the command which is exposed in the CLI args (this is what
the user types to trigger that subcommand).
* HELP: A short 1-line help which is displayed when the user runs
``flit --help``
* setup: A callable which sets up the subparsers. As a single argument it gets
a reference to the sub-parser. No return required.
* run: A callable which gets executed when the subcommand is selected by the
end-user. As a single argument it gets a reference to the root
argument-parser. It should return an integer representing the exit-code of
the application.
"""
from importlib import import_module


def register(main_parser, module_name):
"""
This registers a new subcommand with the main argument parser.

:param main_parser: A reference to the main argument parser instance.
:param module_name: The base-name of the subcommand module. If a module is
added as ``flit/subcommand/foo.py``, this should be ``foo``. This value
is used to dynamically import the subcommend so it must be a valid
module name.
"""
subcmd = import_module('flit.subcommand.%s' % module_name)
parser = main_parser.add_parser(subcmd.NAME,help=subcmd.HELP)
parser.set_defaults(subcmd_entrypoint=subcmd.run)
subcmd.setup(parser)
25 changes: 25 additions & 0 deletions flit/subcommand/build.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
"""
This module contains the implementation for the "build" subcommand.
"""
import sys

from .. import common
from ..build import main

NAME = 'build'
HELP = "Build wheel and sdist"


def setup(parser):
parser.add_argument(
'--format', action='append',
help="Select a format to build. Options: 'wheel', 'sdist'"
)


def run(args):
try:
main(args.ini_file, formats=set(args.format or []))
except(common.NoDocstringError, common.VCSError, common.NoVersionError) as e:
return e.args[0]
return 0
27 changes: 27 additions & 0 deletions flit/subcommand/info.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
"""
This module contains the implementation for the "info" subcommand
"""

import sys

from .. import inifile
from ..common import Module, make_metadata

NAME = 'info'
HELP = "Retrieve metadata information from the project"


def setup(parser):
parser.add_argument(
'--version', default=False, action='store_true', dest='show_version',
help="Print the version number of the project to stdout"
)


def run(args):
ini_info = inifile.read_pkg_ini(args.ini_file)
module = Module(ini_info['module'], args.ini_file.parent)
metadata = make_metadata(module, ini_info)
output = metadata.version
print(output)
return 0
17 changes: 17 additions & 0 deletions flit/subcommand/init.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
"""
This module contains the implementation for the "init" subcommand
"""

from ..init import TerminalIniter

NAME = 'init'
HELP = "Prepare pyproject.toml for a new package"


def setup(parser):
pass


def run(args):
TerminalIniter().initialise()
return 0
52 changes: 52 additions & 0 deletions flit/subcommand/install.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
"""
This module contains the implementation for the "install" subcommand

This module also contains a definition of ``add_shared_install_options`` which
can be used to set up additional arguments for an "install-type" subcommand.
"""

import sys
from ..install import Installer
from .. import common

NAME = 'install'
HELP = "Install the package"


def add_shared_install_options(parser):
parser.add_argument('--user', action='store_true', default=None,
help="Do a user-local install (default if site.ENABLE_USER_SITE is True)"
)
parser.add_argument('--env', action='store_false', dest='user',
help="Install into sys.prefix (default if site.ENABLE_USER_SITE is False, i.e. in virtualenvs)"
)
parser.add_argument('--python', default=sys.executable,
help="Target Python executable, if different from the one running flit"
)


def setup(parser):
parser.add_argument('-s', '--symlink', action='store_true',
help="Symlink the module/package into site packages instead of copying it"
)
parser.add_argument('--pth-file', action='store_true',
help="Add .pth file for the module/package to site packages instead of copying it"
)
parser.add_argument('--deps', choices=['all', 'production', 'develop', 'none'], default='all',
help="Which set of dependencies to install. If --deps=develop, the extras dev, doc, and test are installed"
)
parser.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"
)
add_shared_install_options(parser)


def run(args):
try:
Installer(args.ini_file, user=args.user, python=args.python,
symlink=args.symlink, deps=args.deps, extras=args.extras,
pth=args.pth_file).install()
except (common.NoDocstringError, common.NoVersionError) as e:
return e.args[0]
return 0
24 changes: 24 additions & 0 deletions flit/subcommand/installfrom.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
"""
This module contains the implementation of the "installfrom" subcommand.
"""

import sys

from ..installfrom import installfrom
from .install import add_shared_install_options

NAME = 'installfrom'
HELP = "Download and install a package using flit from source"


def setup(parser):
parser.add_argument(
'location',
help="A URL to download, or a shorthand like github:takluyver/flit"
)
add_shared_install_options(parser)


def run(args):
returncode = installfrom(args.location, user=args.user, python=args.python)
return returncode
18 changes: 18 additions & 0 deletions flit/subcommand/publish.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
"""
This module contains the implementation of the "installfrom" subcommand.
"""
from ..upload import main

NAME = 'publish'
HELP = "Upload wheel and sdist"


def setup(parser):
parser.add_argument('--format', action='append',
help="Select a format to publish. Options: 'wheel', 'sdist'"
)


def run(args):
main(args.ini_file, args.repository, formats=set(args.format or []))
return 0
Loading