diff --git a/pipenv/cmdparse.py b/pipenv/cmdparse.py index 6240f0ba..0c2eebad 100644 --- a/pipenv/cmdparse.py +++ b/pipenv/cmdparse.py @@ -4,22 +4,27 @@ import shlex import six +class ScriptEmptyError(ValueError): + pass + + class Script(object): """Parse a script line (in Pipfile's [scripts] section). This always works in POSIX mode, even on Windows. """ - def __init__(self, parts): - if not parts: - raise ValueError('invalid script') - self._parts = parts - + def __init__(self, command, args=None): + self._parts = [command] + if args: + self._parts.extend(args) @classmethod def parse(cls, value): if isinstance(value, six.string_types): value = shlex.split(value) - return cls(value) + if not value: + raise ScriptEmptyError(value) + return cls(value[0], value[1:]) def __repr__(self): return 'Script({0!r})'.format(self._parts) diff --git a/pipenv/core.py b/pipenv/core.py index 89a167ba..a4f438b3 100644 --- a/pipenv/core.py +++ b/pipenv/core.py @@ -4,7 +4,6 @@ import logging import os import sys import shutil -import shlex import signal import time import tempfile @@ -25,6 +24,7 @@ from blindspin import spinner from requests.packages import urllib3 from requests.packages.urllib3.exceptions import InsecureRequestWarning +from .cmdparse import ScriptEmptyError from .project import Project from .utils import ( convert_deps_from_pip, @@ -2195,23 +2195,14 @@ def inline_activate_virtualenv(): ) -def do_run_nt(command, args): - """Run command by appending space-joined args to it!""" +def do_run_nt(script): import subprocess - p = subprocess.Popen( - project.build_script(command, args).cmdify(), - shell=True, universal_newlines=True, - ) + p = subprocess.Popen(script.cmdify(), shell=True, universal_newlines=True) p.communicate() sys.exit(p.returncode) -def do_run_posix(command, args): - """Attempt to run command either pulling from project or interpreting as executable. - - Args are appended to the command in [scripts] section of project if found. - """ - script = project.build_script(command, args) +def do_run_posix(script, command): command_path = system_which(script.command) if not command_path: if project.has_script(command): @@ -2241,15 +2232,23 @@ def do_run_posix(command, args): def do_run(command, args, three=None, python=False): + """Attempt to run command either pulling from project or interpreting as executable. + + Args are appended to the command in [scripts] section of project if found. + """ # Ensure that virtualenv is available. ensure_project(three=three, python=python, validate=False) load_dot_env() # Activate virtualenv under the current interpreter's environment inline_activate_virtualenv() + try: + script = project.build_script(command, args) + except ScriptEmptyError: + click.echo("Can't run script {0!r}—it's empty?", err=True) if os.name == 'nt': - do_run_nt(command, args) + do_run_nt(script) else: - do_run_posix(command, args) + do_run_posix(script, command=command) def do_check(three=None, python=False, system=False, unused=False, args=None): diff --git a/pipenv/project.py b/pipenv/project.py index 7ca2a916..001652fe 100644 --- a/pipenv/project.py +++ b/pipenv/project.py @@ -399,9 +399,7 @@ class Project(object): try: script = Script.parse(self.parsed_pipfile['scripts'][name]) except KeyError: - script = Script([name]) - except ValueError: - raise ValueError('invalid script entry {0!r}'.format(name)) + script = Script(name) if extra_args: script.extend(extra_args) return script diff --git a/tests/test_cmdparse.py b/tests/test_cmdparse.py index f54a276a..064eda79 100644 --- a/tests/test_cmdparse.py +++ b/tests/test_cmdparse.py @@ -1,8 +1,7 @@ -import textwrap - -from pipenv.cmdparse import Script import pytest +from pipenv.cmdparse import Script, ScriptEmptyError + @pytest.mark.run @pytest.mark.script @@ -12,9 +11,17 @@ def test_parse(): assert script.args == ['-c', "print('hello')"], script +@pytest.mark.run +@pytest.mark.script +def test_parse_error(): + with pytest.raises(ScriptEmptyError) as e: + Script.parse('') + assert str(e.value) == "[]" + + @pytest.mark.run def test_extend(): - script = Script.parse(['python', '-c', "print('hello')"]) + script = Script('python', ['-c', "print('hello')"]) script.extend(['--verbose']) assert script.command == 'python' assert script.args == ['-c', "print('hello')", "--verbose"], script @@ -23,7 +30,7 @@ def test_extend(): @pytest.mark.run @pytest.mark.script def test_cmdify(): - script = Script.parse(['python', '-c', "print('hello')"]) + script = Script('python', ['-c', "print('hello')"]) cmd = script.cmdify() assert cmd == '"python" "-c" "print(\'hello\')"', script