Mercurial > repos > shellac > guppy_basecaller
comparison env/lib/python3.7/site-packages/setuptools/command/upload.py @ 0:26e78fe6e8c4 draft
"planemo upload commit c699937486c35866861690329de38ec1a5d9f783"
| author | shellac |
|---|---|
| date | Sat, 02 May 2020 07:14:21 -0400 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 0:26e78fe6e8c4 |
|---|---|
| 1 import io | |
| 2 import os | |
| 3 import hashlib | |
| 4 import getpass | |
| 5 | |
| 6 from base64 import standard_b64encode | |
| 7 | |
| 8 from distutils import log | |
| 9 from distutils.command import upload as orig | |
| 10 from distutils.spawn import spawn | |
| 11 | |
| 12 from distutils.errors import DistutilsError | |
| 13 | |
| 14 from setuptools.extern.six.moves.urllib.request import urlopen, Request | |
| 15 from setuptools.extern.six.moves.urllib.error import HTTPError | |
| 16 from setuptools.extern.six.moves.urllib.parse import urlparse | |
| 17 | |
| 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 |
