From 36b06fa74e6ebf83870a45c319a03311000912d7 Mon Sep 17 00:00:00 2001 From: Andre Caron Date: Fri, 3 Mar 2017 10:44:16 -0500 Subject: [PATCH] Add support for running as Python module This change makes it easier to run pip-tools on systems which use multiple Python versions by enabling workflows like ``py -X.Y -m piptools ...`` on Windows and ``pythonX.Y -m piptools ...` elsewhere.` --- README.md | 8 ++++++++ piptools/__main__.py | 16 +++++++++++++++ piptools/scripts/sync.py | 1 + tests/test_cli.py | 44 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 69 insertions(+) create mode 100644 piptools/__main__.py diff --git a/README.md b/README.md index ede76d986..a64c175af 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,10 @@ $ pip-compile --upgrade-package flask --upgrade-package requests # update both $ pip-compile -P flask -P requests==2.0.0 # update the flask package to the latest, and requests to v2.0.0 ``` +If you use multiple Python versions, you can run ``pip-compile`` as ``py -X.Y +-m piptools compile ...`` on Windows and ``pythonX.Y -m piptools compile ...`` +on other systems. + Example usage for `pip-sync` ============================ @@ -87,3 +91,7 @@ To sync multiple `*.txt` dependency lists, just pass them in via command line ar $ pip-sync dev-requirements.txt requirements.txt ``` Passing in empty arguments would cause it to default to `requirements.txt`. + +If you use multiple Python versions, you can run ``pip-sync`` as ``py -X.Y -m +piptools sync ...`` on Windows and ``pythonX.Y -m piptools sync ...`` on other +systems. diff --git a/piptools/__main__.py b/piptools/__main__.py new file mode 100644 index 000000000..22bd78797 --- /dev/null +++ b/piptools/__main__.py @@ -0,0 +1,16 @@ +import click +from piptools.scripts import compile, sync + + +@click.group() +def cli(): + pass + + +cli.add_command(compile.cli, 'compile') +cli.add_command(sync.cli, 'sync') + + +# Enable ``python -m piptools ...``. +if __name__ == '__main__': # pragma: no cover + cli() diff --git a/piptools/scripts/sync.py b/piptools/scripts/sync.py index 2c6fe4c4b..8708621eb 100755 --- a/piptools/scripts/sync.py +++ b/piptools/scripts/sync.py @@ -28,6 +28,7 @@ @click.option('--no-index', is_flag=True, help="Ignore package index (only looking at --find-links URLs instead)") @click.argument('src_files', required=False, type=click.Path(exists=True), nargs=-1) def cli(dry_run, force, find_links, index_url, extra_index_url, no_index, src_files): + """Synchronize virtual environment with requirements.txt.""" if not src_files: if os.path.exists(DEFAULT_REQUIREMENTS_FILE): src_files = (DEFAULT_REQUIREMENTS_FILE,) diff --git a/tests/test_cli.py b/tests/test_cli.py index d8a973c60..7c23b7264 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -1,6 +1,7 @@ import os from textwrap import dedent import subprocess +import sys from click.testing import CliRunner @@ -125,3 +126,46 @@ def test_realistic_complex_sub_dependencies(tmpdir): print(out.output) assert out.exit_code == 0 + + +def invoke(command): + """Invoke sub-process.""" + try: + output = subprocess.check_output( + command, + stderr=subprocess.STDOUT, + ) + status = 0 + except subprocess.CalledProcessError as error: + output = error.output + status = error.returncode + + return status, output + + +def test_run_as_module_compile(tmpdir): + """piptools can be run as ``python -m piptools ...``.""" + + status, output = invoke([ + sys.executable, '-m', 'piptools', 'compile', '--help', + ]) + + # Should have run pip-compile successfully. + output = output.decode('utf-8') + assert output.startswith('Usage:') + assert 'Compiles requirements.txt from requirements.in specs.' in output + assert status == 0 + + +def test_run_as_module_sync(): + """piptools can be run as ``python -m piptools ...``.""" + + status, output = invoke([ + sys.executable, '-m', 'piptools', 'sync', '--help', + ]) + + # Should have run pip-compile successfully. + output = output.decode('utf-8') + assert output.startswith('Usage:') + assert 'Synchronize virtual environment with requirements.txt.' in output + assert status == 0