prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  Quote command if parentheses exist
  Thank you for contributing to Pipenv!
  
  
  ### The issue
  
  Fixes #3168 
  
  ### The fix
  
  Quote the command if it contains `()`.
  
  ### The checklist
  
  * [x] Associated issue
  * [x] A news fragment in the `news/` directory to describe this fix with the extension `.bugfix`, `.feature`, `.behavior`, `.doc`. `.vendor`. or `.trivial` (this will appear in the release changelog). Use semantic line breaks and name the file after the issue number or the PR #.
  
  <!--
  ### If this is a patch to the `vendor` directory…
  
  Please try to refrain from submitting patches directly to `vendor` or `patched`, but raise your issue to the upstream project instead, and inform Pipenv to upgrade when the upstream project accepts the fix.
  
  A pull request to upgrade vendor packages is strongly discouraged, unless there is a very good reason (e.g. you need to test Pipenv’s integration to a new vendor feature). Pipenv audits and performs vendor upgrades regularly, generally before a new release is about to drop.
  
  If your patch is not or cannot be accepted by upstream, but is essential to Pipenv (make sure to discuss this with maintainers!), please remember to attach a patch file in `tasks/vendoring/patched`, so this divergence from upstream can be recorded and replayed afterwards.
  -->
  
  
  </issue>
  <code>
  [start of pipenv/cmdparse.py]
  1 import re
  2 import shlex
  3 
  4 import six
  5 
  6 
  7 class ScriptEmptyError(ValueError):
  8     pass
  9 
  10 
  11 class Script(object):
  12     """Parse a script line (in Pipfile's [scripts] section).
  13 
  14     This always works in POSIX mode, even on Windows.
  15     """
  16 
  17     def __init__(self, command, args=None):
  18         self._parts = [command]
  19         if args:
  20             self._parts.extend(args)
  21 
  22     @classmethod
  23     def parse(cls, value):
  24         if isinstance(value, six.string_types):
  25             value = shlex.split(value)
  26         if not value:
  27             raise ScriptEmptyError(value)
  28         return cls(value[0], value[1:])
  29 
  30     def __repr__(self):
  31         return "Script({0!r})".format(self._parts)
  32 
  33     @property
  34     def command(self):
  35         return self._parts[0]
  36 
  37     @property
  38     def args(self):
  39         return self._parts[1:]
  40 
  41     def extend(self, extra_args):
  42         self._parts.extend(extra_args)
  43 
  44     def cmdify(self):
  45         """Encode into a cmd-executable string.
  46 
  47         This re-implements CreateProcess's quoting logic to turn a list of
  48         arguments into one single string for the shell to interpret.
  49 
  50         * All double quotes are escaped with a backslash.
  51         * Existing backslashes before a quote are doubled, so they are all
  52           escaped properly.
  53         * Backslashes elsewhere are left as-is; cmd will interpret them
  54           literally.
  55 
  56         The result is then quoted into a pair of double quotes to be grouped.
  57 
  58         An argument is intentionally not quoted if it does not contain
  59         whitespaces. This is done to be compatible with Windows built-in
  60         commands that don't work well with quotes, e.g. everything with `echo`,
  61         and DOS-style (forward slash) switches.
  62 
  63         The intended use of this function is to pre-process an argument list
  64         before passing it into ``subprocess.Popen(..., shell=True)``.
  65 
  66         See also: https://docs.python.org/3/library/subprocess.html#converting-argument-sequence
  67         """
  68         return " ".join(
  69             arg if not next(re.finditer(r'\s', arg), None)
  70             else '"{0}"'.format(re.sub(r'(\\*)"', r'\1\1\\"', arg))
  71             for arg in self._parts
  72         )
  73
  [end of pipenv/cmdparse.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: diff --git a/pipenv/cmdparse.py b/pipenv/cmdparse.py
  --- a/pipenv/cmdparse.py
  +++ b/pipenv/cmdparse.py
  @@ -1,3 +1,4 @@
  +import itertools
   import re
   import shlex
   
  @@ -8,6 +9,12 @@
       pass
   
   
  +def _quote_if_contains(value, pattern):
  +    if next(re.finditer(pattern, value), None):
  +        return '"{0}"'.format(re.sub(r'(\\*)"', r'\1\1\\"', value))
  +    return value
  +
  +
   class Script(object):
       """Parse a script line (in Pipfile's [scripts] section).
   
  @@ -56,17 +63,21 @@
           The result is then quoted into a pair of double quotes to be grouped.
   
           An argument is intentionally not quoted if it does not contain
  -        whitespaces. This is done to be compatible with Windows built-in
  +        foul characters. This is done to be compatible with Windows built-in
           commands that don't work well with quotes, e.g. everything with `echo`,
           and DOS-style (forward slash) switches.
   
  +        Foul characters include:
  +
  +        * Whitespaces.
  +        * Parentheses in the command. (pypa/pipenv#3168)
  +
           The intended use of this function is to pre-process an argument list
           before passing it into ``subprocess.Popen(..., shell=True)``.
   
           See also: https://docs.python.org/3/library/subprocess.html#converting-argument-sequence
           """
  -        return " ".join(
  -            arg if not next(re.finditer(r'\s', arg), None)
  -            else '"{0}"'.format(re.sub(r'(\\*)"', r'\1\1\\"', arg))
  -            for arg in self._parts
  -        )
  +        return " ".join(itertools.chain(
  +            [_quote_if_contains(self.command, r'[\s()]')],
  +            (_quote_if_contains(arg, r'\s') for arg in self.args),
  +        ))
  
verification_info: {"golden_diff": "diff --git a/pipenv/cmdparse.py b/pipenv/cmdparse.py\n--- a/pipenv/cmdparse.py\n+++ b/pipenv/cmdparse.py\n@@ -1,3 +1,4 @@\n+import itertools\n import re\n import shlex\n \n@@ -8,6 +9,12 @@\n     pass\n \n \n+def _quote_if_contains(value, pattern):\n+    if next(re.finditer(pattern, value), None):\n+        return '\"{0}\"'.format(re.sub(r'(\\\\*)\"', r'\\1\\1\\\\\"', value))\n+    return value\n+\n+\n class Script(object):\n     \"\"\"Parse a script line (in Pipfile's [scripts] section).\n \n@@ -56,17 +63,21 @@\n         The result is then quoted into a pair of double quotes to be grouped.\n \n         An argument is intentionally not quoted if it does not contain\n-        whitespaces. This is done to be compatible with Windows built-in\n+        foul characters. This is done to be compatible with Windows built-in\n         commands that don't work well with quotes, e.g. everything with `echo`,\n         and DOS-style (forward slash) switches.\n \n+        Foul characters include:\n+\n+        * Whitespaces.\n+        * Parentheses in the command. (pypa/pipenv#3168)\n+\n         The intended use of this function is to pre-process an argument list\n         before passing it into ``subprocess.Popen(..., shell=True)``.\n \n         See also: https://docs.python.org/3/library/subprocess.html#converting-argument-sequence\n         \"\"\"\n-        return \" \".join(\n-            arg if not next(re.finditer(r'\\s', arg), None)\n-            else '\"{0}\"'.format(re.sub(r'(\\\\*)\"', r'\\1\\1\\\\\"', arg))\n-            for arg in self._parts\n-        )\n+        return \" \".join(itertools.chain(\n+            [_quote_if_contains(self.command, r'[\\s()]')],\n+            (_quote_if_contains(arg, r'\\s') for arg in self.args),\n+        ))\n", "issue": "Quote command if parentheses exist\nThank you for contributing to Pipenv!\r\n\r\n\r\n### The issue\r\n\r\nFixes #3168 \r\n\r\n### The fix\r\n\r\nQuote the command if it contains `()`.\r\n\r\n### The checklist\r\n\r\n* [x] Associated issue\r\n* [x] A news fragment in the `news/` directory to describe this fix with the extension `.bugfix`, `.feature`, `.behavior`, `.doc`. `.vendor`. or `.trivial` (this will appear in the release changelog). Use semantic line breaks and name the file after the issue number or the PR #.\r\n\r\n<!--\r\n### If this is a patch to the `vendor` directory\u2026\r\n\r\nPlease try to refrain from submitting patches directly to `vendor` or `patched`, but raise your issue to the upstream project instead, and inform Pipenv to upgrade when the upstream project accepts the fix.\r\n\r\nA pull request to upgrade vendor packages is strongly discouraged, unless there is a very good reason (e.g. you need to test Pipenv\u2019s integration to a new vendor feature). Pipenv audits and performs vendor upgrades regularly, generally before a new release is about to drop.\r\n\r\nIf your patch is not or cannot be accepted by upstream, but is essential to Pipenv (make sure to discuss this with maintainers!), please remember to attach a patch file in `tasks/vendoring/patched`, so this divergence from upstream can be recorded and replayed afterwards.\r\n-->\r\n\n", "before_files": [{"content": "import re\nimport shlex\n\nimport six\n\n\nclass ScriptEmptyError(ValueError):\n    pass\n\n\nclass Script(object):\n    \"\"\"Parse a script line (in Pipfile's [scripts] section).\n\n    This always works in POSIX mode, even on Windows.\n    \"\"\"\n\n    def __init__(self, command, args=None):\n        self._parts = [command]\n        if args:\n            self._parts.extend(args)\n\n    @classmethod\n    def parse(cls, value):\n        if isinstance(value, six.string_types):\n            value = shlex.split(value)\n        if not value:\n            raise ScriptEmptyError(value)\n        return cls(value[0], value[1:])\n\n    def __repr__(self):\n        return \"Script({0!r})\".format(self._parts)\n\n    @property\n    def command(self):\n        return self._parts[0]\n\n    @property\n    def args(self):\n        return self._parts[1:]\n\n    def extend(self, extra_args):\n        self._parts.extend(extra_args)\n\n    def cmdify(self):\n        \"\"\"Encode into a cmd-executable string.\n\n        This re-implements CreateProcess's quoting logic to turn a list of\n        arguments into one single string for the shell to interpret.\n\n        * All double quotes are escaped with a backslash.\n        * Existing backslashes before a quote are doubled, so they are all\n          escaped properly.\n        * Backslashes elsewhere are left as-is; cmd will interpret them\n          literally.\n\n        The result is then quoted into a pair of double quotes to be grouped.\n\n        An argument is intentionally not quoted if it does not contain\n        whitespaces. This is done to be compatible with Windows built-in\n        commands that don't work well with quotes, e.g. everything with `echo`,\n        and DOS-style (forward slash) switches.\n\n        The intended use of this function is to pre-process an argument list\n        before passing it into ``subprocess.Popen(..., shell=True)``.\n\n        See also: https://docs.python.org/3/library/subprocess.html#converting-argument-sequence\n        \"\"\"\n        return \" \".join(\n            arg if not next(re.finditer(r'\\s', arg), None)\n            else '\"{0}\"'.format(re.sub(r'(\\\\*)\"', r'\\1\\1\\\\\"', arg))\n            for arg in self._parts\n        )\n", "path": "pipenv/cmdparse.py"}]}