Repository URL to install this package:
|
Version:
3.9.0 ▾
|
flit
/
__init__.py
|
|---|
"""A simple packaging tool for simple packages."""
import argparse
import logging
import os
import pathlib
import shutil
import subprocess
import sys
from typing import Optional
from flit_core import common
from .config import ConfigError
from .log import enable_colourful_output
__version__ = '3.9.0'
log = logging.getLogger(__name__)
class PythonNotFoundError(FileNotFoundError): pass
def find_python_executable(python: Optional[str] = None) -> str:
"""Returns an absolute filepath to the executable of Python to use."""
if not python:
python = os.environ.get("FLIT_INSTALL_PYTHON")
if not python:
return sys.executable
if os.path.isabs(python): # sys.executable is absolute too
return python
# get absolute filepath of {python}
# shutil.which may give a different result to the raw subprocess call
# see https://github.com/pypa/flit/pull/300 and https://bugs.python.org/issue38905
resolved_python = shutil.which(python)
if resolved_python is None:
raise PythonNotFoundError("Unable to resolve Python executable {!r}".format(python))
try:
return subprocess.check_output(
[resolved_python, "-c", "import sys; print(sys.executable)"],
universal_newlines=True,
).strip()
except Exception as e:
raise PythonNotFoundError(
"{} occurred trying to find the absolute filepath of Python executable {!r} ({!r})".format(
e.__class__.__name__, python, resolved_python
)
) from e
def add_shared_install_options(parser: argparse.ArgumentParser):
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',
help="Target Python executable, if different from the one running flit"
)
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('--only-deps', action='store_true',
help="Install only dependencies of this package, and not the package itself"
)
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"
)
def add_shared_build_options(parser: argparse.ArgumentParser):
parser.add_argument('--format', action='append',
help="Select a format to publish. Options: 'wheel', 'sdist'"
)
setup_py_grp = parser.add_mutually_exclusive_group()
setup_py_grp.add_argument('--setup-py', action='store_true',
help=("Generate a setup.py file in the sdist. "
"The sdist will work with older tools that predate PEP 517. "
)
)
setup_py_grp.add_argument('--no-setup-py', action='store_true',
help=("Don't generate a setup.py file in the sdist. This is the default. "
"The sdist will only work with tools that support PEP 517, "
"but the wheel will still be usable by any compatible tool."
)
)
vcs_grp = parser.add_mutually_exclusive_group()
vcs_grp.add_argument('--use-vcs', action='store_true',
help=("Choose which files to include in the sdist using git or hg. "
"This is a convenient way to include all checked-in files, like "
"tests and doc source files, in your sdist, but requires that git "
"or hg is available on the command line. This is currently the "
"default, but it will change in a future version. "
)
)
vcs_grp.add_argument('--no-use-vcs', action='store_true',
help=("Select the files to include in the sdist without using git or hg. "
"This should include all essential files to install and use your "
"package; see the documentation for precisely what is included. "
"This will become the default in a future version."
)
)
def main(argv=None):
ap = argparse.ArgumentParser()
ap.add_argument('-f', '--ini-file', type=pathlib.Path, default='pyproject.toml')
ap.add_argument('-V', '--version', action='version', version='Flit '+__version__)
# --repository now belongs on 'flit publish' - it's still here for
# compatibility with scripts passing it before the subcommand.
ap.add_argument('--repository', dest='deprecated_repository', help=argparse.SUPPRESS)
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')
# flit build --------------------------------------------
parser_build = subparsers.add_parser('build',
help="Build wheel and sdist",
)
add_shared_build_options(parser_build)
# flit publish --------------------------------------------
parser_publish = subparsers.add_parser('publish',
help="Upload wheel and sdist",
)
add_shared_build_options(parser_publish)
parser_publish.add_argument('--pypirc',
help="The .pypirc config file to be used. DEFAULT = \"~/.pypirc\""
)
parser_publish.add_argument('--repository',
help="Name of the repository to upload to (must be in the specified .pypirc file)"
)
# flit install --------------------------------------------
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)
# flit init --------------------------------------------
parser_init = subparsers.add_parser('init',
help="Prepare pyproject.toml for a new package"
)
args = ap.parse_args(argv)
if args.ini_file.suffix == '.ini':
sys.exit("flit.ini format is no longer supported. You can use "
"'python3 -m flit.tomlify' to convert it to pyproject.toml")
if args.subcmd not in {'init'} and not args.ini_file.is_file():
sys.exit('Config file {} does not exist'.format(args.ini_file))
enable_colourful_output(logging.DEBUG if args.debug else logging.INFO)
log.debug("Parsed arguments %r", args)
if args.logo:
from .logo import clogo
print(clogo.format(version=__version__))
sys.exit(0)
def gen_setup_py():
if not (args.setup_py or args.no_setup_py):
return False
return args.setup_py
def sdist_use_vcs():
return not args.no_use_vcs
if args.subcmd == 'build':
from .build import main
try:
main(args.ini_file, formats=set(args.format or []),
gen_setup_py=gen_setup_py(), use_vcs=sdist_use_vcs())
except(common.NoDocstringError, common.VCSError, common.NoVersionError) as e:
sys.exit(e.args[0])
elif args.subcmd == 'publish':
if args.deprecated_repository:
log.warning("Passing --repository before the 'upload' subcommand is deprecated: pass it after")
repository = args.repository or args.deprecated_repository
from .upload import main
main(args.ini_file, repository, args.pypirc, formats=set(args.format or []),
gen_setup_py=gen_setup_py(), use_vcs=sdist_use_vcs())
elif args.subcmd == 'install':
from .install import Installer
try:
python = find_python_executable(args.python)
installer = Installer.from_ini_path(
args.ini_file,
user=args.user,
python=python,
symlink=args.symlink,
deps=args.deps,
extras=args.extras,
pth=args.pth_file
)
if args.only_deps:
installer.install_requirements()
else:
installer.install()
except (ConfigError, PythonNotFoundError, common.NoDocstringError, common.NoVersionError) as e:
sys.exit(e.args[0])
elif args.subcmd == 'init':
from .init import TerminalIniter
TerminalIniter().initialise()
else:
ap.print_help()
sys.exit(1)