~smoser/ubuntu/trusty/maas/lp-1172566

« back to all changes in this revision

Viewing changes to src/maascli/api.py

  • Committer: Package Import Robot
  • Author(s): Andres Rodriguez
  • Date: 2014-04-03 13:45:02 UTC
  • mto: This revision was merged to the branch mainline in revision 58.
  • Revision ID: package-import@ubuntu.com-20140403134502-8a6wvuqwyuekufh0
Tags: upstream-1.5+bzr2227
ImportĀ upstreamĀ versionĀ 1.5+bzr2227

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
import argparse
20
20
from collections import defaultdict
21
21
from email.message import Message
 
22
from functools import partial
22
23
import httplib
23
24
from itertools import chain
24
25
import json
25
26
from operator import itemgetter
 
27
import re
26
28
import sys
27
29
from textwrap import (
28
30
    dedent,
34
36
    )
35
37
 
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,
 
42
    )
38
43
from apiclient.utils import (
39
44
    ascii_url,
40
45
    urlencode,
166
171
        uri, body, headers = self.prepare_payload(
167
172
            self.op, self.method, uri, options.data)
168
173
 
 
174
        # Headers are returned as a list, but they must be a dict for
 
175
        # the signing machinery.
 
176
        headers = dict(headers)
 
177
 
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)
190
199
 
191
200
    @staticmethod
192
201
    def name_value_pair(string):
193
 
        parts = string.split("=", 1)
194
 
        if len(parts) == 2:
195
 
            return tuple(parts)
 
202
        """Ensure that `string` is a valid ``name:value`` pair.
 
203
 
 
204
        When `string` is of the form ``name=value``, this returns a
 
205
        2-tuple of ``name, value``.
 
206
 
 
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.
 
211
        """
 
212
        parts = re.split(r'(=|@=)', string, 1)
 
213
        if len(parts) == 3:
 
214
            name, what, value = parts
 
215
            if what == "=":
 
216
                return name, value
 
217
            elif what == "@=":
 
218
                return name, partial(open, value, "rb")
 
219
            else:
 
220
                raise AssertionError(
 
221
                    "Unrecognised separator %r" % what)
196
222
        else:
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)
199
225
 
200
 
    @staticmethod
201
 
    def prepare_payload(op, method, uri, data):
 
226
    @classmethod
 
227
    def prepare_payload(cls, op, method, uri, data):
202
228
        """Return the URI (modified perhaps) and body and headers.
203
229
 
204
230
        - For GET requests, encode parameters in the query string.
209
235
 
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.
214
241
        """
 
242
        query = [] if op is None else [("op", op)]
 
243
 
 
244
        def slurp(opener):
 
245
            with opener() as fd:
 
246
                return fd.read()
 
247
 
215
248
        if method == "GET":
216
 
            query = data if op is None else chain([("op", op)], data)
217
 
            body, headers = None, {}
 
249
            query.extend(
 
250
                (name, slurp(value) if callable(value) else value)
 
251
                for name, value in data)
 
252
            body, headers = None, []
218
253
        else:
219
 
            query = [] if op is None else [("op", op)]
220
 
            if data:
221
 
                body, headers = encode_multipart_data(data)
 
254
            if data is None or len(data) == 0:
 
255
                body, headers = None, []
222
256
            else:
223
 
                body, headers = None, {}
 
257
                message = build_multipart_message(data)
 
258
                headers, body = encode_multipart_message(message)
224
259
 
225
260
        uri = urlparse(uri)._replace(query=urlencode(query)).geturl()
226
261
        return uri, body, headers