20
20
from collections import defaultdict
21
21
from email.message import Message
22
from functools import partial
23
24
from itertools import chain
25
26
from operator import itemgetter
27
29
from textwrap import (
36
38
from apiclient.maas_client import MAASOAuth
37
from apiclient.multipart import encode_multipart_data
39
from apiclient.multipart import (
40
build_multipart_message,
41
encode_multipart_message,
38
43
from apiclient.utils import (
166
171
uri, body, headers = self.prepare_payload(
167
172
self.op, self.method, uri, options.data)
174
# Headers are returned as a list, but they must be a dict for
175
# the signing machinery.
176
headers = dict(headers)
169
178
# Sign request if credentials have been provided.
170
179
if self.credentials is not None:
171
180
self.sign(uri, headers, self.credentials)
192
201
def name_value_pair(string):
193
parts = string.split("=", 1)
202
"""Ensure that `string` is a valid ``name:value`` pair.
204
When `string` is of the form ``name=value``, this returns a
205
2-tuple of ``name, value``.
207
However, when `string` is of the form ``name@=value``, this
208
returns a ``name, opener`` tuple, where ``opener`` is a function
209
that will return an open file handle when called. The file will
210
be opened in binary mode for reading only.
212
parts = re.split(r'(=|@=)', string, 1)
214
name, what, value = parts
218
return name, partial(open, value, "rb")
220
raise AssertionError(
221
"Unrecognised separator %r" % what)
197
223
raise CommandError(
198
"%r is not a name=value pair" % string)
224
"%r is not a name=value or name@=filename pair" % string)
201
def prepare_payload(op, method, uri, data):
227
def prepare_payload(cls, op, method, uri, data):
202
228
"""Return the URI (modified perhaps) and body and headers.
204
230
- For GET requests, encode parameters in the query string.
210
236
:param method: The HTTP method.
211
237
:param uri: The URI of the action.
212
:param data: A dict or iterable of name=value pairs to pack into the
213
body or headers, depending on the type of request.
238
:param data: An iterable of ``name, value`` or ``name, opener``
239
tuples (see `name_value_pair`) to pack into the body or
240
query, depending on the type of request.
242
query = [] if op is None else [("op", op)]
215
248
if method == "GET":
216
query = data if op is None else chain([("op", op)], data)
217
body, headers = None, {}
250
(name, slurp(value) if callable(value) else value)
251
for name, value in data)
252
body, headers = None, []
219
query = [] if op is None else [("op", op)]
221
body, headers = encode_multipart_data(data)
254
if data is None or len(data) == 0:
255
body, headers = None, []
223
body, headers = None, {}
257
message = build_multipart_message(data)
258
headers, body = encode_multipart_message(message)
225
260
uri = urlparse(uri)._replace(query=urlencode(query)).geturl()
226
261
return uri, body, headers