Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hhhrrrttt222111
GitHub Repository: hhhrrrttt222111/Dorkify
Path: blob/master/venv/Lib/site-packages/setuptools/command/upload_docs.py
811 views
1
# -*- coding: utf-8 -*-
2
"""upload_docs
3
4
Implements a Distutils 'upload_docs' subcommand (upload documentation to
5
PyPI's pythonhosted.org).
6
"""
7
8
from base64 import standard_b64encode
9
from distutils import log
10
from distutils.errors import DistutilsOptionError
11
import os
12
import socket
13
import zipfile
14
import tempfile
15
import shutil
16
import itertools
17
import functools
18
19
from setuptools.extern import six
20
from setuptools.extern.six.moves import http_client, urllib
21
22
from pkg_resources import iter_entry_points
23
from .upload import upload
24
25
26
def _encode(s):
27
errors = 'strict' if six.PY2 else 'surrogateescape'
28
return s.encode('utf-8', errors)
29
30
31
class upload_docs(upload):
32
# override the default repository as upload_docs isn't
33
# supported by Warehouse (and won't be).
34
DEFAULT_REPOSITORY = 'https://pypi.python.org/pypi/'
35
36
description = 'Upload documentation to PyPI'
37
38
user_options = [
39
('repository=', 'r',
40
"url of repository [default: %s]" % upload.DEFAULT_REPOSITORY),
41
('show-response', None,
42
'display full response text from server'),
43
('upload-dir=', None, 'directory to upload'),
44
]
45
boolean_options = upload.boolean_options
46
47
def has_sphinx(self):
48
if self.upload_dir is None:
49
for ep in iter_entry_points('distutils.commands', 'build_sphinx'):
50
return True
51
52
sub_commands = [('build_sphinx', has_sphinx)]
53
54
def initialize_options(self):
55
upload.initialize_options(self)
56
self.upload_dir = None
57
self.target_dir = None
58
59
def finalize_options(self):
60
upload.finalize_options(self)
61
if self.upload_dir is None:
62
if self.has_sphinx():
63
build_sphinx = self.get_finalized_command('build_sphinx')
64
self.target_dir = build_sphinx.builder_target_dir
65
else:
66
build = self.get_finalized_command('build')
67
self.target_dir = os.path.join(build.build_base, 'docs')
68
else:
69
self.ensure_dirname('upload_dir')
70
self.target_dir = self.upload_dir
71
if 'pypi.python.org' in self.repository:
72
log.warn("Upload_docs command is deprecated. Use RTD instead.")
73
self.announce('Using upload directory %s' % self.target_dir)
74
75
def create_zipfile(self, filename):
76
zip_file = zipfile.ZipFile(filename, "w")
77
try:
78
self.mkpath(self.target_dir) # just in case
79
for root, dirs, files in os.walk(self.target_dir):
80
if root == self.target_dir and not files:
81
tmpl = "no files found in upload directory '%s'"
82
raise DistutilsOptionError(tmpl % self.target_dir)
83
for name in files:
84
full = os.path.join(root, name)
85
relative = root[len(self.target_dir):].lstrip(os.path.sep)
86
dest = os.path.join(relative, name)
87
zip_file.write(full, dest)
88
finally:
89
zip_file.close()
90
91
def run(self):
92
# Run sub commands
93
for cmd_name in self.get_sub_commands():
94
self.run_command(cmd_name)
95
96
tmp_dir = tempfile.mkdtemp()
97
name = self.distribution.metadata.get_name()
98
zip_file = os.path.join(tmp_dir, "%s.zip" % name)
99
try:
100
self.create_zipfile(zip_file)
101
self.upload_file(zip_file)
102
finally:
103
shutil.rmtree(tmp_dir)
104
105
@staticmethod
106
def _build_part(item, sep_boundary):
107
key, values = item
108
title = '\nContent-Disposition: form-data; name="%s"' % key
109
# handle multiple entries for the same name
110
if not isinstance(values, list):
111
values = [values]
112
for value in values:
113
if isinstance(value, tuple):
114
title += '; filename="%s"' % value[0]
115
value = value[1]
116
else:
117
value = _encode(value)
118
yield sep_boundary
119
yield _encode(title)
120
yield b"\n\n"
121
yield value
122
if value and value[-1:] == b'\r':
123
yield b'\n' # write an extra newline (lurve Macs)
124
125
@classmethod
126
def _build_multipart(cls, data):
127
"""
128
Build up the MIME payload for the POST data
129
"""
130
boundary = '--------------GHSKFJDLGDS7543FJKLFHRE75642756743254'
131
sep_boundary = b'\n--' + boundary.encode('ascii')
132
end_boundary = sep_boundary + b'--'
133
end_items = end_boundary, b"\n",
134
builder = functools.partial(
135
cls._build_part,
136
sep_boundary=sep_boundary,
137
)
138
part_groups = map(builder, data.items())
139
parts = itertools.chain.from_iterable(part_groups)
140
body_items = itertools.chain(parts, end_items)
141
content_type = 'multipart/form-data; boundary=%s' % boundary
142
return b''.join(body_items), content_type
143
144
def upload_file(self, filename):
145
with open(filename, 'rb') as f:
146
content = f.read()
147
meta = self.distribution.metadata
148
data = {
149
':action': 'doc_upload',
150
'name': meta.get_name(),
151
'content': (os.path.basename(filename), content),
152
}
153
# set up the authentication
154
credentials = _encode(self.username + ':' + self.password)
155
credentials = standard_b64encode(credentials)
156
if not six.PY2:
157
credentials = credentials.decode('ascii')
158
auth = "Basic " + credentials
159
160
body, ct = self._build_multipart(data)
161
162
msg = "Submitting documentation to %s" % (self.repository)
163
self.announce(msg, log.INFO)
164
165
# build the Request
166
# We can't use urllib2 since we need to send the Basic
167
# auth right with the first request
168
schema, netloc, url, params, query, fragments = \
169
urllib.parse.urlparse(self.repository)
170
assert not params and not query and not fragments
171
if schema == 'http':
172
conn = http_client.HTTPConnection(netloc)
173
elif schema == 'https':
174
conn = http_client.HTTPSConnection(netloc)
175
else:
176
raise AssertionError("unsupported schema " + schema)
177
178
data = ''
179
try:
180
conn.connect()
181
conn.putrequest("POST", url)
182
content_type = ct
183
conn.putheader('Content-type', content_type)
184
conn.putheader('Content-length', str(len(body)))
185
conn.putheader('Authorization', auth)
186
conn.endheaders()
187
conn.send(body)
188
except socket.error as e:
189
self.announce(str(e), log.ERROR)
190
return
191
192
r = conn.getresponse()
193
if r.status == 200:
194
msg = 'Server response (%s): %s' % (r.status, r.reason)
195
self.announce(msg, log.INFO)
196
elif r.status == 301:
197
location = r.getheader('Location')
198
if location is None:
199
location = 'https://pythonhosted.org/%s/' % meta.get_name()
200
msg = 'Upload successful. Visit %s' % location
201
self.announce(msg, log.INFO)
202
else:
203
msg = 'Upload failed (%s): %s' % (r.status, r.reason)
204
self.announce(msg, log.ERROR)
205
if self.show_response:
206
print('-' * 75, r.read(), '-' * 75)
207
208