NullAuth   A
last analyzed

Complexity

Total Complexity 1

Size/Duplication

Total Lines 16
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 16
rs 10
wmc 1

1 Method

Rating   Name   Duplication   Size   Complexity  
A __call__() 0 2 1
1
from __future__ import unicode_literals
2
3
import codecs
4
import logging
5
6
from io import BytesIO, StringIO
7
8
import six
9
import requests
10
11
from requests.packages.urllib3.filepost import choose_boundary, iter_fields
12
13
logger = logging.getLogger('binstar.requests_ext')
14
15
16
def encode_multipart_formdata_stream(fields, boundary=None):
17
    """
18
    Encode a dictionary of ``fields`` using the multipart/form-data MIME format.
19
20
    :param fields:
21
        Dictionary of fields or list of (key, value) or (key, value, MIME type)
22
        field tuples.  The key is treated as the field name, and the value as
23
        the body of the form-data bytes. If the value is a tuple of two
24
        elements, then the first element is treated as the filename of the
25
        form-data section and a suitable MIME type is guessed based on the
26
        filename. If the value is a tuple of three elements, then the third
27
        element is treated as an explicit MIME type of the form-data section.
28
29
        Field names and filenames must be unicode.
30
31
    :param boundary:
32
        If not specified, then a random boundary will be generated using
33
        :func:`mimetools.choose_boundary`.
34
    """
35
    body = []
36
37
    def body_write(item):
38
        if isinstance(item, six.binary_type):
39
            item = BytesIO(item)
40
        elif isinstance(item, six.text_type):
41
            item = StringIO(item)
42
        body.append(item)
43
44
    body_write_encode = lambda item: body.append(BytesIO(item.encode('utf-8')))
45
46
    if boundary is None:
47
        boundary = choose_boundary()
48
49
    for fieldname, value in iter_fields(fields):
50
        body_write_encode('--%s\r\n' % (boundary))
51
52
        if isinstance(value, tuple):
53
            if len(value) == 3:
54
                filename, data, content_type = value
55
            else:
56
                filename, data = value
57
                from mimetypes import guess_type
58
                content_type, _ = guess_type(filename)
59
                if content_type is None:
60
                    content_type = 'application/octet-stream'
61
            body_write_encode('Content-Disposition: form-data; name="%s"; '
62
                              'filename="%s"\r\n' % (fieldname, filename))
63
            body_write_encode('Content-Type: %s\r\n\r\n' %
64
                              (content_type,))
65
        else:
66
            data = value
67
            body_write_encode('Content-Disposition: form-data; name="%s"\r\n'
68
                               % (fieldname))
69
            body_write(b'\r\n')
70
71
        if isinstance(data, six.integer_types):
72
            data = six.text_type(data)  # Backwards compatibility
73
74
        if isinstance(data, six.text_type):
75
            body_write_encode(data)
76
        else:
77
            body_write(data)
78
79
        body_write(b'\r\n')
80
81
    body_write_encode('--%s--\r\n' % (boundary))
82
83
    content_type = 'multipart/form-data; boundary=%s' % (boundary)
84
85
    return body, content_type
86
87
88
class MultiPartIO(object):
89
    def __init__(self, body, callback=None):
90
        self.to_read = body
91
        self.have_read = []
92
        self._total = 0
93
        self.callback = callback
94
95
    def read(self, n= -1):
96
        if self.callback:
97
            self.callback(self.tell(), self._total)
98
99
        if n == -1:
100
            return b''.join(fd.read() for fd in self.to_read)
101
102
        if not self.to_read:
103
            return b''
104
105
        while self.to_read:
106
            data = self.to_read[0].read(n)
107
108
            if data:
109
                return data
110
111
            fd = self.to_read.pop(0)
112
            self.have_read.append(fd)
113
114
        return b''
115
116
    def tell(self):
117
        cursor = sum(fd.tell() for fd in self.have_read)
118
        if self.to_read:
119
            cursor += self.to_read[0].tell()
120
        return cursor
121
122
    def seek(self, pos, mode=0):
123
        assert pos == 0
124
        if mode is 0:
125
            self.to_read = self.have_read + self.to_read
126
            self.have_read = []
127
            [fd.seek(pos, mode) for fd in self.to_read]
128
            self.cursor = 0
129
130
        elif mode is 2:
131
            self.have_read = self.have_read + self.to_read
132
            self.to_read = []
133
            [fd.seek(pos, mode) for fd in self.have_read]
134
            self._total = self.tell()
135
136
137
def stream_multipart(data, files=None, callback=None):
138
    from itertools import chain
139
    if files:
140
        fields = chain(iter_fields(data), iter_fields(files))
141
    else:
142
        fields = data
143
144
    body, content_type = encode_multipart_formdata_stream(fields)
145
    data = MultiPartIO(body, callback=callback)
146
    headers = {'Content-Type':content_type}
147
    return data, headers
148
149
150
class NullAuth(requests.auth.AuthBase):
151
    """force requests to ignore the ``.netrc``
152
153
    Some sites do not support regular authentication, but we still
154
    want to store credentials in the ``.netrc`` file and submit them
155
    as form elements. Without this, requests would otherwise use the
156
    .netrc which leads, on some sites, to a 401 error.
157
158
    https://github.com/kennethreitz/requests/issues/2773
159
160
    Use with::
161
162
        requests.get(url, auth=NullAuth())
163
    """
164
    def __call__(self, r):
165
        return r
166