We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Impossible to install packages with setuptools v.40.6.x, if six isn't installed
Upgrade pip and setuptools to latest versions

```
oleg$ pip install --upgrade pip setuptools
Collecting pip
  Using cached https://files.pythonhosted.org/packages/c2/d7/90f34cb0d83a6c5631cf71dfe64cc1054598c843a92b400e55675cc2ac37/pip-18.1-py2.py3-none-any.whl
Collecting setuptools
  Using cached https://files.pythonhosted.org/packages/4b/47/1417da90ed6f4c88465d08ea2461ff41c94cc6cc223f333d130d7a99199a/setuptools-40.6.1-py2.py3-none-any.whl
Installing collected packages: pip, setuptools
  Found existing installation: pip 9.0.1
    Uninstalling pip-9.0.1:
      Successfully uninstalled pip-9.0.1
  Found existing installation: setuptools 38.2.4
    Uninstalling setuptools-38.2.4:
      Successfully uninstalled setuptools-38.2.4
Successfully installed pip-18.1 setuptools-40.6.1
```

Try to install any package, d2to1 for example

```
oleg$ pip install d2to1
Collecting d2to1
  Downloading https://files.pythonhosted.org/packages/dc/bd/eac45e4e77d76f6c0ae539819c40f1babb891d7855129663e37957a7c2df/d2to1-0.2.12.post1.tar.gz
    Complete output from command python setup.py egg_info:
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
      File "/private/var/folders/ns/71p61z5s3hsd2pv327gmdh1c0000gn/T/pip-install-2J_LhF/d2to1/setup.py", line 17, in <module>
        setup(**cfg_to_args())
      File "d2to1/util.py", line 204, in cfg_to_args
        wrap_commands(kwargs)
      File "d2to1/util.py", line 439, in wrap_commands
        for cmd, _ in dist.get_command_list():
      File "/Users/oleg/.virtualenvs/yandex/lib/python2.7/site-packages/setuptools/dist.py", line 724, in get_command_list
        cmdclass = ep.resolve()
      File "/Users/oleg/.virtualenvs/yandex/lib/python2.7/site-packages/pkg_resources/__init__.py", line 2352, in resolve
        module = __import__(self.module_name, fromlist=['__name__'], level=0)
      File "/Users/oleg/.virtualenvs/yandex/lib/python2.7/site-packages/setuptools/command/upload_docs.py", line 23, in <module>
        from .upload import upload
      File "/Users/oleg/.virtualenvs/yandex/lib/python2.7/site-packages/setuptools/command/upload.py", line 15, in <module>
        from six.moves.urllib.request import urlopen, Request
    ImportError: No module named six.moves.urllib.request
    
    ----------------------------------------
Command "python setup.py egg_info" failed with error code 1 in /private/var/folders/ns/71p61z5s3hsd2pv327gmdh1c0000gn/T/pip-install-2J_LhF/d2to1/
````

```
oleg$ pip list
Package    Version     
---------- ------------
d2to1      0.2.12.post1
pip        18.1        
setuptools 40.6.1      
wheel      0.30.0
```

Downgrade setuptools to v.40.5.0, and try installation again

```
oleg$ pip install --upgrade setuptools==40.5.0
Collecting setuptools==40.5.0
  Downloading https://files.pythonhosted.org/packages/82/a1/ba6fb41367b375f5cb653d1317d8ca263c636cff6566e2da1b0da716069d/setuptools-40.5.0-py2.py3-none-any.whl (569kB)
    100% |████████████████████████████████| 573kB 754kB/s 
Installing collected packages: setuptools
  Found existing installation: setuptools 40.6.1
    Uninstalling setuptools-40.6.1:
      Successfully uninstalled setuptools-40.6.1
Successfully installed setuptools-40.5.0

oleg$ pip install d2to1
Collecting d2to1
  Using cached https://files.pythonhosted.org/packages/dc/bd/eac45e4e77d76f6c0ae539819c40f1babb891d7855129663e37957a7c2df/d2to1-0.2.12.post1.tar.gz
Requirement already satisfied: setuptools in /Users/oleg/.virtualenvs/yandex/lib/python2.7/site-packages (from d2to1) (40.5.0)
Building wheels for collected packages: d2to1
  Running setup.py bdist_wheel for d2to1 ... done
  Stored in directory: /Users/oleg/Library/Caches/pip/wheels/e6/1a/ed/11531583d510d72448e39bfc254147d0e7b2b2ad65722b3a6f
Successfully built d2to1
Installing collected packages: d2to1
Successfully installed d2to1-0.2.12.post1
```

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `setuptools/command/upload.py`
Content:
```
1 import io
2 import os
3 import hashlib
4 import getpass
5 import platform
6 
7 from base64 import standard_b64encode
8 
9 from distutils import log
10 from distutils.command import upload as orig
11 from distutils.spawn import spawn
12 
13 from distutils.errors import DistutilsError
14 
15 from six.moves.urllib.request import urlopen, Request
16 from six.moves.urllib.error import HTTPError
17 from six.moves.urllib.parse import urlparse
18 
19 class upload(orig.upload):
20     """
21     Override default upload behavior to obtain password
22     in a variety of different ways.
23     """
24     def run(self):
25         try:
26             orig.upload.run(self)
27         finally:
28             self.announce(
29                 "WARNING: Uploading via this command is deprecated, use twine "
30                 "to upload instead (https://pypi.org/p/twine/)",
31                 log.WARN
32             )
33 
34     def finalize_options(self):
35         orig.upload.finalize_options(self)
36         self.username = (
37             self.username or
38             getpass.getuser()
39         )
40         # Attempt to obtain password. Short circuit evaluation at the first
41         # sign of success.
42         self.password = (
43             self.password or
44             self._load_password_from_keyring() or
45             self._prompt_for_password()
46         )
47 
48     def upload_file(self, command, pyversion, filename):
49         # Makes sure the repository URL is compliant
50         schema, netloc, url, params, query, fragments = \
51             urlparse(self.repository)
52         if params or query or fragments:
53             raise AssertionError("Incompatible url %s" % self.repository)
54 
55         if schema not in ('http', 'https'):
56             raise AssertionError("unsupported schema " + schema)
57 
58         # Sign if requested
59         if self.sign:
60             gpg_args = ["gpg", "--detach-sign", "-a", filename]
61             if self.identity:
62                 gpg_args[2:2] = ["--local-user", self.identity]
63             spawn(gpg_args,
64                   dry_run=self.dry_run)
65 
66         # Fill in the data - send all the meta-data in case we need to
67         # register a new release
68         with open(filename, 'rb') as f:
69             content = f.read()
70 
71         meta = self.distribution.metadata
72 
73         data = {
74             # action
75             ':action': 'file_upload',
76             'protocol_version': '1',
77 
78             # identify release
79             'name': meta.get_name(),
80             'version': meta.get_version(),
81 
82             # file content
83             'content': (os.path.basename(filename),content),
84             'filetype': command,
85             'pyversion': pyversion,
86             'md5_digest': hashlib.md5(content).hexdigest(),
87 
88             # additional meta-data
89             'metadata_version': str(meta.get_metadata_version()),
90             'summary': meta.get_description(),
91             'home_page': meta.get_url(),
92             'author': meta.get_contact(),
93             'author_email': meta.get_contact_email(),
94             'license': meta.get_licence(),
95             'description': meta.get_long_description(),
96             'keywords': meta.get_keywords(),
97             'platform': meta.get_platforms(),
98             'classifiers': meta.get_classifiers(),
99             'download_url': meta.get_download_url(),
100             # PEP 314
101             'provides': meta.get_provides(),
102             'requires': meta.get_requires(),
103             'obsoletes': meta.get_obsoletes(),
104             }
105 
106         data['comment'] = ''
107 
108         if self.sign:
109             data['gpg_signature'] = (os.path.basename(filename) + ".asc",
110                                      open(filename+".asc", "rb").read())
111 
112         # set up the authentication
113         user_pass = (self.username + ":" + self.password).encode('ascii')
114         # The exact encoding of the authentication string is debated.
115         # Anyway PyPI only accepts ascii for both username or password.
116         auth = "Basic " + standard_b64encode(user_pass).decode('ascii')
117 
118         # Build up the MIME payload for the POST data
119         boundary = '--------------GHSKFJDLGDS7543FJKLFHRE75642756743254'
120         sep_boundary = b'\r\n--' + boundary.encode('ascii')
121         end_boundary = sep_boundary + b'--\r\n'
122         body = io.BytesIO()
123         for key, value in data.items():
124             title = '\r\nContent-Disposition: form-data; name="%s"' % key
125             # handle multiple entries for the same name
126             if not isinstance(value, list):
127                 value = [value]
128             for value in value:
129                 if type(value) is tuple:
130                     title += '; filename="%s"' % value[0]
131                     value = value[1]
132                 else:
133                     value = str(value).encode('utf-8')
134                 body.write(sep_boundary)
135                 body.write(title.encode('utf-8'))
136                 body.write(b"\r\n\r\n")
137                 body.write(value)
138         body.write(end_boundary)
139         body = body.getvalue()
140 
141         msg = "Submitting %s to %s" % (filename, self.repository)
142         self.announce(msg, log.INFO)
143 
144         # build the Request
145         headers = {
146             'Content-type': 'multipart/form-data; boundary=%s' % boundary,
147             'Content-length': str(len(body)),
148             'Authorization': auth,
149         }
150 
151         request = Request(self.repository, data=body,
152                           headers=headers)
153         # send the data
154         try:
155             result = urlopen(request)
156             status = result.getcode()
157             reason = result.msg
158         except HTTPError as e:
159             status = e.code
160             reason = e.msg
161         except OSError as e:
162             self.announce(str(e), log.ERROR)
163             raise
164 
165         if status == 200:
166             self.announce('Server response (%s): %s' % (status, reason),
167                           log.INFO)
168             if self.show_response:
169                 text = getattr(self, '_read_pypi_response',
170                                lambda x: None)(result)
171                 if text is not None:
172                     msg = '\n'.join(('-' * 75, text, '-' * 75))
173                     self.announce(msg, log.INFO)
174         else:
175             msg = 'Upload failed (%s): %s' % (status, reason)
176             self.announce(msg, log.ERROR)
177             raise DistutilsError(msg)
178 
179     def _load_password_from_keyring(self):
180         """
181         Attempt to load password from keyring. Suppress Exceptions.
182         """
183         try:
184             keyring = __import__('keyring')
185             return keyring.get_password(self.repository, self.username)
186         except Exception:
187             pass
188 
189     def _prompt_for_password(self):
190         """
191         Prompt for a password on the tty. Suppress Exceptions.
192         """
193         try:
194             return getpass.getpass()
195         except (Exception, KeyboardInterrupt):
196             pass
197
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/setuptools/command/upload.py b/setuptools/command/upload.py
--- a/setuptools/command/upload.py
+++ b/setuptools/command/upload.py
@@ -12,9 +12,9 @@
 
 from distutils.errors import DistutilsError
 
-from six.moves.urllib.request import urlopen, Request
-from six.moves.urllib.error import HTTPError
-from six.moves.urllib.parse import urlparse
+from setuptools.extern.six.moves.urllib.request import urlopen, Request
+from setuptools.extern.six.moves.urllib.error import HTTPError
+from setuptools.extern.six.moves.urllib.parse import urlparse
 
 class upload(orig.upload):
     """

{"golden_diff": "diff --git a/setuptools/command/upload.py b/setuptools/command/upload.py\n--- a/setuptools/command/upload.py\n+++ b/setuptools/command/upload.py\n@@ -12,9 +12,9 @@\n \n from distutils.errors import DistutilsError\n \n-from six.moves.urllib.request import urlopen, Request\n-from six.moves.urllib.error import HTTPError\n-from six.moves.urllib.parse import urlparse\n+from setuptools.extern.six.moves.urllib.request import urlopen, Request\n+from setuptools.extern.six.moves.urllib.error import HTTPError\n+from setuptools.extern.six.moves.urllib.parse import urlparse\n \n class upload(orig.upload):\n     \"\"\"\n", "issue": "Impossible to install packages with setuptools v.40.6.x, if six isn't installed\nUpgrade pip and setuptools to latest versions\r\n\r\n```\r\noleg$ pip install --upgrade pip setuptools\r\nCollecting pip\r\n  Using cached https://files.pythonhosted.org/packages/c2/d7/90f34cb0d83a6c5631cf71dfe64cc1054598c843a92b400e55675cc2ac37/pip-18.1-py2.py3-none-any.whl\r\nCollecting setuptools\r\n  Using cached https://files.pythonhosted.org/packages/4b/47/1417da90ed6f4c88465d08ea2461ff41c94cc6cc223f333d130d7a99199a/setuptools-40.6.1-py2.py3-none-any.whl\r\nInstalling collected packages: pip, setuptools\r\n  Found existing installation: pip 9.0.1\r\n    Uninstalling pip-9.0.1:\r\n      Successfully uninstalled pip-9.0.1\r\n  Found existing installation: setuptools 38.2.4\r\n    Uninstalling setuptools-38.2.4:\r\n      Successfully uninstalled setuptools-38.2.4\r\nSuccessfully installed pip-18.1 setuptools-40.6.1\r\n```\r\n\r\nTry to install any package, d2to1 for example\r\n\r\n```\r\noleg$ pip install d2to1\r\nCollecting d2to1\r\n  Downloading https://files.pythonhosted.org/packages/dc/bd/eac45e4e77d76f6c0ae539819c40f1babb891d7855129663e37957a7c2df/d2to1-0.2.12.post1.tar.gz\r\n    Complete output from command python setup.py egg_info:\r\n    Traceback (most recent call last):\r\n      File \"<string>\", line 1, in <module>\r\n      File \"/private/var/folders/ns/71p61z5s3hsd2pv327gmdh1c0000gn/T/pip-install-2J_LhF/d2to1/setup.py\", line 17, in <module>\r\n        setup(**cfg_to_args())\r\n      File \"d2to1/util.py\", line 204, in cfg_to_args\r\n        wrap_commands(kwargs)\r\n      File \"d2to1/util.py\", line 439, in wrap_commands\r\n        for cmd, _ in dist.get_command_list():\r\n      File \"/Users/oleg/.virtualenvs/yandex/lib/python2.7/site-packages/setuptools/dist.py\", line 724, in get_command_list\r\n        cmdclass = ep.resolve()\r\n      File \"/Users/oleg/.virtualenvs/yandex/lib/python2.7/site-packages/pkg_resources/__init__.py\", line 2352, in resolve\r\n        module = __import__(self.module_name, fromlist=['__name__'], level=0)\r\n      File \"/Users/oleg/.virtualenvs/yandex/lib/python2.7/site-packages/setuptools/command/upload_docs.py\", line 23, in <module>\r\n        from .upload import upload\r\n      File \"/Users/oleg/.virtualenvs/yandex/lib/python2.7/site-packages/setuptools/command/upload.py\", line 15, in <module>\r\n        from six.moves.urllib.request import urlopen, Request\r\n    ImportError: No module named six.moves.urllib.request\r\n    \r\n    ----------------------------------------\r\nCommand \"python setup.py egg_info\" failed with error code 1 in /private/var/folders/ns/71p61z5s3hsd2pv327gmdh1c0000gn/T/pip-install-2J_LhF/d2to1/\r\n````\r\n\r\n```\r\noleg$ pip list\r\nPackage    Version     \r\n---------- ------------\r\nd2to1      0.2.12.post1\r\npip        18.1        \r\nsetuptools 40.6.1      \r\nwheel      0.30.0\r\n```\r\n\r\nDowngrade setuptools to v.40.5.0, and try installation again\r\n\r\n```\r\noleg$ pip install --upgrade setuptools==40.5.0\r\nCollecting setuptools==40.5.0\r\n  Downloading https://files.pythonhosted.org/packages/82/a1/ba6fb41367b375f5cb653d1317d8ca263c636cff6566e2da1b0da716069d/setuptools-40.5.0-py2.py3-none-any.whl (569kB)\r\n    100% |\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588| 573kB 754kB/s \r\nInstalling collected packages: setuptools\r\n  Found existing installation: setuptools 40.6.1\r\n    Uninstalling setuptools-40.6.1:\r\n      Successfully uninstalled setuptools-40.6.1\r\nSuccessfully installed setuptools-40.5.0\r\n\r\noleg$ pip install d2to1\r\nCollecting d2to1\r\n  Using cached https://files.pythonhosted.org/packages/dc/bd/eac45e4e77d76f6c0ae539819c40f1babb891d7855129663e37957a7c2df/d2to1-0.2.12.post1.tar.gz\r\nRequirement already satisfied: setuptools in /Users/oleg/.virtualenvs/yandex/lib/python2.7/site-packages (from d2to1) (40.5.0)\r\nBuilding wheels for collected packages: d2to1\r\n  Running setup.py bdist_wheel for d2to1 ... done\r\n  Stored in directory: /Users/oleg/Library/Caches/pip/wheels/e6/1a/ed/11531583d510d72448e39bfc254147d0e7b2b2ad65722b3a6f\r\nSuccessfully built d2to1\r\nInstalling collected packages: d2to1\r\nSuccessfully installed d2to1-0.2.12.post1\r\n```\n", "before_files": [{"content": "import io\nimport os\nimport hashlib\nimport getpass\nimport platform\n\nfrom base64 import standard_b64encode\n\nfrom distutils import log\nfrom distutils.command import upload as orig\nfrom distutils.spawn import spawn\n\nfrom distutils.errors import DistutilsError\n\nfrom six.moves.urllib.request import urlopen, Request\nfrom six.moves.urllib.error import HTTPError\nfrom six.moves.urllib.parse import urlparse\n\nclass upload(orig.upload):\n    \"\"\"\n    Override default upload behavior to obtain password\n    in a variety of different ways.\n    \"\"\"\n    def run(self):\n        try:\n            orig.upload.run(self)\n        finally:\n            self.announce(\n                \"WARNING: Uploading via this command is deprecated, use twine \"\n                \"to upload instead (https://pypi.org/p/twine/)\",\n                log.WARN\n            )\n\n    def finalize_options(self):\n        orig.upload.finalize_options(self)\n        self.username = (\n            self.username or\n            getpass.getuser()\n        )\n        # Attempt to obtain password. Short circuit evaluation at the first\n        # sign of success.\n        self.password = (\n            self.password or\n            self._load_password_from_keyring() or\n            self._prompt_for_password()\n        )\n\n    def upload_file(self, command, pyversion, filename):\n        # Makes sure the repository URL is compliant\n        schema, netloc, url, params, query, fragments = \\\n            urlparse(self.repository)\n        if params or query or fragments:\n            raise AssertionError(\"Incompatible url %s\" % self.repository)\n\n        if schema not in ('http', 'https'):\n            raise AssertionError(\"unsupported schema \" + schema)\n\n        # Sign if requested\n        if self.sign:\n            gpg_args = [\"gpg\", \"--detach-sign\", \"-a\", filename]\n            if self.identity:\n                gpg_args[2:2] = [\"--local-user\", self.identity]\n            spawn(gpg_args,\n                  dry_run=self.dry_run)\n\n        # Fill in the data - send all the meta-data in case we need to\n        # register a new release\n        with open(filename, 'rb') as f:\n            content = f.read()\n\n        meta = self.distribution.metadata\n\n        data = {\n            # action\n            ':action': 'file_upload',\n            'protocol_version': '1',\n\n            # identify release\n            'name': meta.get_name(),\n            'version': meta.get_version(),\n\n            # file content\n            'content': (os.path.basename(filename),content),\n            'filetype': command,\n            'pyversion': pyversion,\n            'md5_digest': hashlib.md5(content).hexdigest(),\n\n            # additional meta-data\n            'metadata_version': str(meta.get_metadata_version()),\n            'summary': meta.get_description(),\n            'home_page': meta.get_url(),\n            'author': meta.get_contact(),\n            'author_email': meta.get_contact_email(),\n            'license': meta.get_licence(),\n            'description': meta.get_long_description(),\n            'keywords': meta.get_keywords(),\n            'platform': meta.get_platforms(),\n            'classifiers': meta.get_classifiers(),\n            'download_url': meta.get_download_url(),\n            # PEP 314\n            'provides': meta.get_provides(),\n            'requires': meta.get_requires(),\n            'obsoletes': meta.get_obsoletes(),\n            }\n\n        data['comment'] = ''\n\n        if self.sign:\n            data['gpg_signature'] = (os.path.basename(filename) + \".asc\",\n                                     open(filename+\".asc\", \"rb\").read())\n\n        # set up the authentication\n        user_pass = (self.username + \":\" + self.password).encode('ascii')\n        # The exact encoding of the authentication string is debated.\n        # Anyway PyPI only accepts ascii for both username or password.\n        auth = \"Basic \" + standard_b64encode(user_pass).decode('ascii')\n\n        # Build up the MIME payload for the POST data\n        boundary = '--------------GHSKFJDLGDS7543FJKLFHRE75642756743254'\n        sep_boundary = b'\\r\\n--' + boundary.encode('ascii')\n        end_boundary = sep_boundary + b'--\\r\\n'\n        body = io.BytesIO()\n        for key, value in data.items():\n            title = '\\r\\nContent-Disposition: form-data; name=\"%s\"' % key\n            # handle multiple entries for the same name\n            if not isinstance(value, list):\n                value = [value]\n            for value in value:\n                if type(value) is tuple:\n                    title += '; filename=\"%s\"' % value[0]\n                    value = value[1]\n                else:\n                    value = str(value).encode('utf-8')\n                body.write(sep_boundary)\n                body.write(title.encode('utf-8'))\n                body.write(b\"\\r\\n\\r\\n\")\n                body.write(value)\n        body.write(end_boundary)\n        body = body.getvalue()\n\n        msg = \"Submitting %s to %s\" % (filename, self.repository)\n        self.announce(msg, log.INFO)\n\n        # build the Request\n        headers = {\n            'Content-type': 'multipart/form-data; boundary=%s' % boundary,\n            'Content-length': str(len(body)),\n            'Authorization': auth,\n        }\n\n        request = Request(self.repository, data=body,\n                          headers=headers)\n        # send the data\n        try:\n            result = urlopen(request)\n            status = result.getcode()\n            reason = result.msg\n        except HTTPError as e:\n            status = e.code\n            reason = e.msg\n        except OSError as e:\n            self.announce(str(e), log.ERROR)\n            raise\n\n        if status == 200:\n            self.announce('Server response (%s): %s' % (status, reason),\n                          log.INFO)\n            if self.show_response:\n                text = getattr(self, '_read_pypi_response',\n                               lambda x: None)(result)\n                if text is not None:\n                    msg = '\\n'.join(('-' * 75, text, '-' * 75))\n                    self.announce(msg, log.INFO)\n        else:\n            msg = 'Upload failed (%s): %s' % (status, reason)\n            self.announce(msg, log.ERROR)\n            raise DistutilsError(msg)\n\n    def _load_password_from_keyring(self):\n        \"\"\"\n        Attempt to load password from keyring. Suppress Exceptions.\n        \"\"\"\n        try:\n            keyring = __import__('keyring')\n            return keyring.get_password(self.repository, self.username)\n        except Exception:\n            pass\n\n    def _prompt_for_password(self):\n        \"\"\"\n        Prompt for a password on the tty. Suppress Exceptions.\n        \"\"\"\n        try:\n            return getpass.getpass()\n        except (Exception, KeyboardInterrupt):\n            pass\n", "path": "setuptools/command/upload.py"}], "after_files": [{"content": "import io\nimport os\nimport hashlib\nimport getpass\nimport platform\n\nfrom base64 import standard_b64encode\n\nfrom distutils import log\nfrom distutils.command import upload as orig\nfrom distutils.spawn import spawn\n\nfrom distutils.errors import DistutilsError\n\nfrom setuptools.extern.six.moves.urllib.request import urlopen, Request\nfrom setuptools.extern.six.moves.urllib.error import HTTPError\nfrom setuptools.extern.six.moves.urllib.parse import urlparse\n\nclass upload(orig.upload):\n    \"\"\"\n    Override default upload behavior to obtain password\n    in a variety of different ways.\n    \"\"\"\n    def run(self):\n        try:\n            orig.upload.run(self)\n        finally:\n            self.announce(\n                \"WARNING: Uploading via this command is deprecated, use twine \"\n                \"to upload instead (https://pypi.org/p/twine/)\",\n                log.WARN\n            )\n\n    def finalize_options(self):\n        orig.upload.finalize_options(self)\n        self.username = (\n            self.username or\n            getpass.getuser()\n        )\n        # Attempt to obtain password. Short circuit evaluation at the first\n        # sign of success.\n        self.password = (\n            self.password or\n            self._load_password_from_keyring() or\n            self._prompt_for_password()\n        )\n\n    def upload_file(self, command, pyversion, filename):\n        # Makes sure the repository URL is compliant\n        schema, netloc, url, params, query, fragments = \\\n            urlparse(self.repository)\n        if params or query or fragments:\n            raise AssertionError(\"Incompatible url %s\" % self.repository)\n\n        if schema not in ('http', 'https'):\n            raise AssertionError(\"unsupported schema \" + schema)\n\n        # Sign if requested\n        if self.sign:\n            gpg_args = [\"gpg\", \"--detach-sign\", \"-a\", filename]\n            if self.identity:\n                gpg_args[2:2] = [\"--local-user\", self.identity]\n            spawn(gpg_args,\n                  dry_run=self.dry_run)\n\n        # Fill in the data - send all the meta-data in case we need to\n        # register a new release\n        with open(filename, 'rb') as f:\n            content = f.read()\n\n        meta = self.distribution.metadata\n\n        data = {\n            # action\n            ':action': 'file_upload',\n            'protocol_version': '1',\n\n            # identify release\n            'name': meta.get_name(),\n            'version': meta.get_version(),\n\n            # file content\n            'content': (os.path.basename(filename),content),\n            'filetype': command,\n            'pyversion': pyversion,\n            'md5_digest': hashlib.md5(content).hexdigest(),\n\n            # additional meta-data\n            'metadata_version': str(meta.get_metadata_version()),\n            'summary': meta.get_description(),\n            'home_page': meta.get_url(),\n            'author': meta.get_contact(),\n            'author_email': meta.get_contact_email(),\n            'license': meta.get_licence(),\n            'description': meta.get_long_description(),\n            'keywords': meta.get_keywords(),\n            'platform': meta.get_platforms(),\n            'classifiers': meta.get_classifiers(),\n            'download_url': meta.get_download_url(),\n            # PEP 314\n            'provides': meta.get_provides(),\n            'requires': meta.get_requires(),\n            'obsoletes': meta.get_obsoletes(),\n            }\n\n        data['comment'] = ''\n\n        if self.sign:\n            data['gpg_signature'] = (os.path.basename(filename) + \".asc\",\n                                     open(filename+\".asc\", \"rb\").read())\n\n        # set up the authentication\n        user_pass = (self.username + \":\" + self.password).encode('ascii')\n        # The exact encoding of the authentication string is debated.\n        # Anyway PyPI only accepts ascii for both username or password.\n        auth = \"Basic \" + standard_b64encode(user_pass).decode('ascii')\n\n        # Build up the MIME payload for the POST data\n        boundary = '--------------GHSKFJDLGDS7543FJKLFHRE75642756743254'\n        sep_boundary = b'\\r\\n--' + boundary.encode('ascii')\n        end_boundary = sep_boundary + b'--\\r\\n'\n        body = io.BytesIO()\n        for key, value in data.items():\n            title = '\\r\\nContent-Disposition: form-data; name=\"%s\"' % key\n            # handle multiple entries for the same name\n            if not isinstance(value, list):\n                value = [value]\n            for value in value:\n                if type(value) is tuple:\n                    title += '; filename=\"%s\"' % value[0]\n                    value = value[1]\n                else:\n                    value = str(value).encode('utf-8')\n                body.write(sep_boundary)\n                body.write(title.encode('utf-8'))\n                body.write(b\"\\r\\n\\r\\n\")\n                body.write(value)\n        body.write(end_boundary)\n        body = body.getvalue()\n\n        msg = \"Submitting %s to %s\" % (filename, self.repository)\n        self.announce(msg, log.INFO)\n\n        # build the Request\n        headers = {\n            'Content-type': 'multipart/form-data; boundary=%s' % boundary,\n            'Content-length': str(len(body)),\n            'Authorization': auth,\n        }\n\n        request = Request(self.repository, data=body,\n                          headers=headers)\n        # send the data\n        try:\n            result = urlopen(request)\n            status = result.getcode()\n            reason = result.msg\n        except HTTPError as e:\n            status = e.code\n            reason = e.msg\n        except OSError as e:\n            self.announce(str(e), log.ERROR)\n            raise\n\n        if status == 200:\n            self.announce('Server response (%s): %s' % (status, reason),\n                          log.INFO)\n            if self.show_response:\n                text = getattr(self, '_read_pypi_response',\n                               lambda x: None)(result)\n                if text is not None:\n                    msg = '\\n'.join(('-' * 75, text, '-' * 75))\n                    self.announce(msg, log.INFO)\n        else:\n            msg = 'Upload failed (%s): %s' % (status, reason)\n            self.announce(msg, log.ERROR)\n            raise DistutilsError(msg)\n\n    def _load_password_from_keyring(self):\n        \"\"\"\n        Attempt to load password from keyring. Suppress Exceptions.\n        \"\"\"\n        try:\n            keyring = __import__('keyring')\n            return keyring.get_password(self.repository, self.username)\n        except Exception:\n            pass\n\n    def _prompt_for_password(self):\n        \"\"\"\n        Prompt for a password on the tty. Suppress Exceptions.\n        \"\"\"\n        try:\n            return getpass.getpass()\n        except (Exception, KeyboardInterrupt):\n            pass\n", "path": "setuptools/command/upload.py"}]}