prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  Exception when a command-line parametter contains a non-ascii character
  Hey,
  
  We've just upgraded to Luigi 1.1.2, and now we get an error when launching Tasks that have utf-8 characters on the parameters.  (using python 2.7.3)
  
  Here's the stacktrace we get : 
  
  ```
  Traceback (most recent call last):
    File "examples/top_artists.py", line 283, in <module>
      luigi.run()
    File "/home/jonas/.virtualenvs/website/local/lib/python2.7/site-packages/luigi/interface.py", line 434, in run
      return interface.run(tasks, worker_scheduler_factory, override_defaults=override_defaults)
    File "/home/jonas/.virtualenvs/website/local/lib/python2.7/site-packages/luigi/interface.py", line 165, in run
      not(lock.acquire_for(env_params.lock_pid_dir, env_params.lock_size))):
    File "/home/jonas/.virtualenvs/website/local/lib/python2.7/site-packages/luigi/lock.py", line 59, in acquire_for
      my_pid, my_cmd, pid_file = get_info(pid_dir)
    File "/home/jonas/.virtualenvs/website/local/lib/python2.7/site-packages/luigi/lock.py", line 44, in get_info
      pid_file = os.path.join(pid_dir, hashlib.md5(my_cmd.encode('utf8')).hexdigest()) + '.pid'
  UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 97: ordinal not in range(128)
  ```
  
  Here I've just added a `plop = luigi.Parameter()` to `AggregateArtists`, and called it with 
  `python examples/top_artists.py AggregateArtists --local-scheduler --date-interval 2012-06 --plop à`
  
  The error seems to come from the [Python3 refactoring](https://github.com/spotify/luigi/pull/745). Removing `.encode('utf8')` on [this line](https://github.com/spotify/luigi/blob/master/luigi/lock.py#L44) seems to solve the problem, but I guess it was added for a reason ^^.
  
  Any ideas of how we could solve this on our side, other than removing the encode?  (I'll try to add a test for it later)
  
  
  </issue>
  <code>
  [start of luigi/lock.py]
  1 # -*- coding: utf-8 -*-
  2 #
  3 # Copyright 2012-2015 Spotify AB
  4 #
  5 # Licensed under the Apache License, Version 2.0 (the "License");
  6 # you may not use this file except in compliance with the License.
  7 # You may obtain a copy of the License at
  8 #
  9 # http://www.apache.org/licenses/LICENSE-2.0
  10 #
  11 # Unless required by applicable law or agreed to in writing, software
  12 # distributed under the License is distributed on an "AS IS" BASIS,
  13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14 # See the License for the specific language governing permissions and
  15 # limitations under the License.
  16 #
  17 """
  18 Locking functionality when launching things from the command line.
  19 Uses a pidfile.
  20 This prevents multiple identical workflows to be launched simultaneously.
  21 """
  22 from __future__ import print_function
  23 
  24 import hashlib
  25 import os
  26 
  27 
  28 def getpcmd(pid):
  29     """
  30     Returns command of process.
  31 
  32     :param pid:
  33     """
  34     cmd = 'ps -p %s -o command=' % (pid,)
  35     p = os.popen(cmd, 'r')
  36     return p.readline().strip()
  37 
  38 
  39 def get_info(pid_dir):
  40     # Check the name and pid of this process
  41     my_pid = os.getpid()
  42     my_cmd = getpcmd(my_pid)
  43 
  44     pid_file = os.path.join(pid_dir, hashlib.md5(my_cmd.encode('utf8')).hexdigest()) + '.pid'
  45 
  46     return my_pid, my_cmd, pid_file
  47 
  48 
  49 def acquire_for(pid_dir, num_available=1):
  50     """
  51     Makes sure the process is only run once at the same time with the same name.
  52 
  53     Notice that we since we check the process name, different parameters to the same
  54     command can spawn multiple processes at the same time, i.e. running
  55     "/usr/bin/my_process" does not prevent anyone from launching
  56     "/usr/bin/my_process --foo bar".
  57     """
  58 
  59     my_pid, my_cmd, pid_file = get_info(pid_dir)
  60 
  61     # Check if there is a pid file corresponding to this name
  62     if not os.path.exists(pid_dir):
  63         os.mkdir(pid_dir)
  64         os.chmod(pid_dir, 0o777)
  65 
  66     pids = set()
  67     pid_cmds = {}
  68     if os.path.exists(pid_file):
  69         # There is such a file - read the pid and look up its process name
  70         pids.update(filter(None, map(str.strip, open(pid_file))))
  71         pid_cmds = dict((pid, getpcmd(pid)) for pid in pids)
  72         matching_pids = list(filter(lambda pid: pid_cmds[pid] == my_cmd, pids))
  73 
  74         if len(matching_pids) >= num_available:
  75             # We are already running under a different pid
  76             print('Pid(s)', ', '.join(matching_pids), 'already running')
  77             return False
  78         else:
  79             # The pid belongs to something else, we could
  80             pass
  81     pid_cmds[str(my_pid)] = my_cmd
  82 
  83     # Write pids
  84     pids.add(str(my_pid))
  85     with open(pid_file, 'w') as f:
  86         f.writelines('%s\n' % (pid, ) for pid in filter(pid_cmds.__getitem__, pids))
  87 
  88     # Make the file writable by all
  89     if os.name == 'nt':
  90         pass
  91     else:
  92         s = os.stat(pid_file)
  93         if os.getuid() == s.st_uid:
  94             os.chmod(pid_file, s.st_mode | 0o777)
  95 
  96     return True
  97
  [end of luigi/lock.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/luigi/lock.py b/luigi/lock.py
  --- a/luigi/lock.py
  +++ b/luigi/lock.py
  @@ -24,6 +24,8 @@
   import hashlib
   import os
   
  +from luigi import six
  +
   
   def getpcmd(pid):
       """
  @@ -32,16 +34,23 @@
       :param pid:
       """
       cmd = 'ps -p %s -o command=' % (pid,)
  -    p = os.popen(cmd, 'r')
  -    return p.readline().strip()
  +    with os.popen(cmd, 'r') as p:
  +        return p.readline().strip()
   
   
  -def get_info(pid_dir):
  +def get_info(pid_dir, my_pid=None):
       # Check the name and pid of this process
  -    my_pid = os.getpid()
  +    if my_pid is None:
  +        my_pid = os.getpid()
  +
       my_cmd = getpcmd(my_pid)
   
  -    pid_file = os.path.join(pid_dir, hashlib.md5(my_cmd.encode('utf8')).hexdigest()) + '.pid'
  +    if six.PY3:
  +        cmd_hash = my_cmd.encode('utf8')
  +    else:
  +        cmd_hash = my_cmd
  +
  +    pid_file = os.path.join(pid_dir, hashlib.md5(cmd_hash).hexdigest()) + '.pid'
   
       return my_pid, my_cmd, pid_file
  
verification_info: {"golden_diff": "diff --git a/luigi/lock.py b/luigi/lock.py\n--- a/luigi/lock.py\n+++ b/luigi/lock.py\n@@ -24,6 +24,8 @@\n import hashlib\n import os\n \n+from luigi import six\n+\n \n def getpcmd(pid):\n     \"\"\"\n@@ -32,16 +34,23 @@\n     :param pid:\n     \"\"\"\n     cmd = 'ps -p %s -o command=' % (pid,)\n-    p = os.popen(cmd, 'r')\n-    return p.readline().strip()\n+    with os.popen(cmd, 'r') as p:\n+        return p.readline().strip()\n \n \n-def get_info(pid_dir):\n+def get_info(pid_dir, my_pid=None):\n     # Check the name and pid of this process\n-    my_pid = os.getpid()\n+    if my_pid is None:\n+        my_pid = os.getpid()\n+\n     my_cmd = getpcmd(my_pid)\n \n-    pid_file = os.path.join(pid_dir, hashlib.md5(my_cmd.encode('utf8')).hexdigest()) + '.pid'\n+    if six.PY3:\n+        cmd_hash = my_cmd.encode('utf8')\n+    else:\n+        cmd_hash = my_cmd\n+\n+    pid_file = os.path.join(pid_dir, hashlib.md5(cmd_hash).hexdigest()) + '.pid'\n \n     return my_pid, my_cmd, pid_file\n", "issue": "Exception when a command-line parametter contains a non-ascii character\nHey,\n\nWe've just upgraded to Luigi 1.1.2, and now we get an error when launching Tasks that have utf-8 characters on the parameters.  (using python 2.7.3)\n\nHere's the stacktrace we get : \n\n```\nTraceback (most recent call last):\n  File \"examples/top_artists.py\", line 283, in <module>\n    luigi.run()\n  File \"/home/jonas/.virtualenvs/website/local/lib/python2.7/site-packages/luigi/interface.py\", line 434, in run\n    return interface.run(tasks, worker_scheduler_factory, override_defaults=override_defaults)\n  File \"/home/jonas/.virtualenvs/website/local/lib/python2.7/site-packages/luigi/interface.py\", line 165, in run\n    not(lock.acquire_for(env_params.lock_pid_dir, env_params.lock_size))):\n  File \"/home/jonas/.virtualenvs/website/local/lib/python2.7/site-packages/luigi/lock.py\", line 59, in acquire_for\n    my_pid, my_cmd, pid_file = get_info(pid_dir)\n  File \"/home/jonas/.virtualenvs/website/local/lib/python2.7/site-packages/luigi/lock.py\", line 44, in get_info\n    pid_file = os.path.join(pid_dir, hashlib.md5(my_cmd.encode('utf8')).hexdigest()) + '.pid'\nUnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 97: ordinal not in range(128)\n```\n\nHere I've just added a `plop = luigi.Parameter()` to `AggregateArtists`, and called it with \n`python examples/top_artists.py AggregateArtists --local-scheduler --date-interval 2012-06 --plop \u00e0`\n\nThe error seems to come from the [Python3 refactoring](https://github.com/spotify/luigi/pull/745). Removing `.encode('utf8')` on [this line](https://github.com/spotify/luigi/blob/master/luigi/lock.py#L44) seems to solve the problem, but I guess it was added for a reason ^^.\n\nAny ideas of how we could solve this on our side, other than removing the encode?  (I'll try to add a test for it later)\n\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n#\n# Copyright 2012-2015 Spotify AB\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\"\"\"\nLocking functionality when launching things from the command line.\nUses a pidfile.\nThis prevents multiple identical workflows to be launched simultaneously.\n\"\"\"\nfrom __future__ import print_function\n\nimport hashlib\nimport os\n\n\ndef getpcmd(pid):\n    \"\"\"\n    Returns command of process.\n\n    :param pid:\n    \"\"\"\n    cmd = 'ps -p %s -o command=' % (pid,)\n    p = os.popen(cmd, 'r')\n    return p.readline().strip()\n\n\ndef get_info(pid_dir):\n    # Check the name and pid of this process\n    my_pid = os.getpid()\n    my_cmd = getpcmd(my_pid)\n\n    pid_file = os.path.join(pid_dir, hashlib.md5(my_cmd.encode('utf8')).hexdigest()) + '.pid'\n\n    return my_pid, my_cmd, pid_file\n\n\ndef acquire_for(pid_dir, num_available=1):\n    \"\"\"\n    Makes sure the process is only run once at the same time with the same name.\n\n    Notice that we since we check the process name, different parameters to the same\n    command can spawn multiple processes at the same time, i.e. running\n    \"/usr/bin/my_process\" does not prevent anyone from launching\n    \"/usr/bin/my_process --foo bar\".\n    \"\"\"\n\n    my_pid, my_cmd, pid_file = get_info(pid_dir)\n\n    # Check if there is a pid file corresponding to this name\n    if not os.path.exists(pid_dir):\n        os.mkdir(pid_dir)\n        os.chmod(pid_dir, 0o777)\n\n    pids = set()\n    pid_cmds = {}\n    if os.path.exists(pid_file):\n        # There is such a file - read the pid and look up its process name\n        pids.update(filter(None, map(str.strip, open(pid_file))))\n        pid_cmds = dict((pid, getpcmd(pid)) for pid in pids)\n        matching_pids = list(filter(lambda pid: pid_cmds[pid] == my_cmd, pids))\n\n        if len(matching_pids) >= num_available:\n            # We are already running under a different pid\n            print('Pid(s)', ', '.join(matching_pids), 'already running')\n            return False\n        else:\n            # The pid belongs to something else, we could\n            pass\n    pid_cmds[str(my_pid)] = my_cmd\n\n    # Write pids\n    pids.add(str(my_pid))\n    with open(pid_file, 'w') as f:\n        f.writelines('%s\\n' % (pid, ) for pid in filter(pid_cmds.__getitem__, pids))\n\n    # Make the file writable by all\n    if os.name == 'nt':\n        pass\n    else:\n        s = os.stat(pid_file)\n        if os.getuid() == s.st_uid:\n            os.chmod(pid_file, s.st_mode | 0o777)\n\n    return True\n", "path": "luigi/lock.py"}]}