GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Test Failed
Pull Request — master (#28)
by
unknown
01:57
created

b2blaze.models.file_list   B

Complexity

Total Complexity 44

Size/Duplication

Total Lines 319
Duplicated Lines 0 %

Test Coverage

Coverage 10.63%

Importance

Changes 0
Metric Value
eloc 180
dl 0
loc 319
ccs 17
cts 160
cp 0.1063
rs 8.8798
c 0
b 0
f 0
wmc 44

11 Methods

Rating   Name   Duplication   Size   Complexity  
A B2FileList._get_by_id() 0 12 2
C B2FileList.upload_large_file() 0 68 9
A B2FileList._get_by_name() 0 18 3
B B2FileList.all_file_versions() 0 52 7
A B2FileList.get_versions() 0 21 3
A B2FileList.all() 0 20 3
A B2FileList.__init__() 0 8 1
A B2FileList.get() 0 18 3
B B2FileList._retrieve_file_list() 0 26 5
A B2FileList.upload() 0 30 4
A B2FileList.delete_all() 0 15 4

How to fix   Complexity   

Complexity

Complex classes like b2blaze.models.file_list often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
"""
2
Copyright George Sibble 2018
3
"""
4
5 1
from .b2_file import B2File
6 1
from ..utilities import b2_url_encode, get_content_length, get_part_ranges, decode_error, RangeStream, StreamWithHashProgress
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (125/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
Unused Code introduced by
Unused decode_error imported from utilities
Loading history...
Unused Code introduced by
Unused StreamWithHashProgress imported from utilities
Loading history...
7 1
from ..b2_exceptions import B2Exception, B2FileNotFoundError
8 1
from multiprocessing.dummy import Pool as ThreadPool
0 ignored issues
show
introduced by
standard import "from multiprocessing.dummy import Pool as ThreadPool" should be placed before "from .b2_file import B2File"
Loading history...
9 1
from ..api import API
10
11 1
class B2FileList(object):
0 ignored issues
show
Documentation introduced by
Empty class docstring
Loading history...
12
    """
13
14
    """
15 1
    def __init__(self, connector, bucket):
16
        """
17
18
        :param connector:
19
        :param bucket:
20
        """
21
        self.connector = connector
22
        self.bucket = bucket
23
24 1
    def all(self, include_hidden=False, limit=None):
25
        """ Return an updated list of all files.
26
            (This does not include hidden files unless include_hidden flag set to True)
27
28
            Parameters:
29
                include_hidden:         (bool) Include hidden files
30
                limit:                  (int)  Limit number of file results
31
32
        """
33
        if not include_hidden:
34
            return self._retrieve_file_list(limit=limit)
35
        else:
36
            results = self.all_file_versions(limit=limit)
37
            versions = results['file_versions']
38
            file_ids = results['file_ids']
39
            if versions:
40
                # Return only the first file from a given file with multiple versions
41
                files = [versions[f][0] for f in file_ids]
42
                return files
43
        return []   # Return empty set on no results
44
45 1
    def delete_all(self, confirm=False):
46
        """ Delete all files in the bucket. 
0 ignored issues
show
Coding Style introduced by
Trailing whitespace
Loading history...
47
            Parameters:
48
                confirm:    (bool)  Safety check. Confirm deletion
49
        """ 
0 ignored issues
show
Coding Style introduced by
Trailing whitespace
Loading history...
50
        if not confirm:
51
            raise Exception('This will delete all files! Pass confirm=True')
52
        
0 ignored issues
show
Coding Style introduced by
Trailing whitespace
Loading history...
53
        all_files = self.all(include_hidden=True)
54
        try:
55
            for f in all_files:
0 ignored issues
show
Coding Style Naming introduced by
The name f does not conform to the variable naming conventions ((([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
56
                f.delete_all_versions(confirm=True)
57
        except Exception as E:
0 ignored issues
show
Coding Style Naming introduced by
The name E does not conform to the variable naming conventions ((([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
58
            raise B2Exception.parse(E)
59
        return []
60
61
        
0 ignored issues
show
Coding Style introduced by
Trailing whitespace
Loading history...
62 1
    def _retrieve_file_list(self, limit=10000):
63
        """ Retrieve list of all files in bucket 
0 ignored issues
show
Coding Style introduced by
Trailing whitespace
Loading history...
64
            Parameters:
65
                limit:      (int)  Max number of file results, default 10000
66
        """
67
        path = API.list_all_files
68
        files = []
69
        new_files_to_retrieve = True
70
        params = {
71
            'bucketId': self.bucket.bucket_id,
72
            'maxFileCount': limit,
73
        }
74
        while new_files_to_retrieve:
75
            response = self.connector.make_request(path=path, method='post', params=params)
76
            if response.status_code == 200:
77
                files_json = response.json()
78
                for file_json in files_json['files']:
79
                    new_file = B2File(connector=self.connector, parent_list=self, **file_json)
80
                    files.append(new_file)
81
                if files_json['nextFileName'] is None:
82
                    new_files_to_retrieve = False
83
                else:
84
                    params['startFileName'] = files_json['nextFileName']
85
            else:
86
                raise B2Exception.parse(response)
87
        return files
88
89
90 1
    def get(self, file_name=None, file_id=None):
91
        """ Get a file by file name or id.
92
            Required:
93
                file_name or file_id
94
95
            Parameters:
96
                file_name:          (str) File name 
0 ignored issues
show
Coding Style introduced by
Trailing whitespace
Loading history...
97
                file_id:            (str) File ID 
0 ignored issues
show
Coding Style introduced by
Trailing whitespace
Loading history...
98
        """
99
        if file_name:
100
            file = self._get_by_name(file_name)
0 ignored issues
show
Bug Best Practice introduced by
This seems to re-define the built-in file.

It is generally discouraged to redefine built-ins as this makes code very hard to read.

Loading history...
101
102
        elif file_id:
103
            file = self._get_by_id(file_id)
104
        else:
105
            raise ValueError('file_name or file_id must be passed')
106
        
0 ignored issues
show
Coding Style introduced by
Trailing whitespace
Loading history...
107
        return file
108
109
110 1
    def get_versions(self, file_name=None, file_id=None, limit=None):
0 ignored issues
show
Unused Code introduced by
The argument limit seems to be unused.
Loading history...
111
        """ Return list of all the versions of one file in current bucket. 
0 ignored issues
show
Coding Style introduced by
Trailing whitespace
Loading history...
112
            Required:
113
                file_id or file_name   (either)
114
115
            Params:
116
                file_id:            (str) File id
117
                file_name:          (str) File id
118
                limit:              (int) Limit number of results returned (optional)
119
120
            Returns:
121
                file_versions       (list) B2FileObject of all file versions
122
        """ 
0 ignored issues
show
Coding Style introduced by
Trailing whitespace
Loading history...
123
        if file_name:
124
            file = self.get(file_name)
0 ignored issues
show
Bug Best Practice introduced by
This seems to re-define the built-in file.

It is generally discouraged to redefine built-ins as this makes code very hard to read.

Loading history...
125
126
        elif file_id:
127
            file = self.get(file_id=file_id)
128
        else:
129
            raise ValueError('Either file_id or file_name required for get_versions')
130
        return file.get_versions()
131
        
0 ignored issues
show
Coding Style introduced by
Trailing whitespace
Loading history...
132
133 1
    def all_file_versions(self, limit=None):
134
        """ Return all the versions of all files in a given bucket.
135
136
            Params:
137
                limit:              (int) Limit number of results returned (optional). Defaults to 10000
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (104/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
138
139
            Returns dict: 
0 ignored issues
show
Coding Style introduced by
Trailing whitespace
Loading history...
140
                'file_names':       (list) String filenames
141
                'file_ids':         (list) File IDs
142
                'file_versions':    (dict) b2blaze File objects, keyed by file name
143
        """ 
0 ignored issues
show
Coding Style introduced by
Trailing whitespace
Loading history...
144
145
        path = API.list_file_versions
146
        file_versions = dict()
147
        file_names = []
148
        file_ids = []
149
        new_files_to_retrieve = True
150
        params = {
151
            'bucketId': self.bucket.bucket_id,
152
            'maxFileCount': 10000
153
        }
154
155
        # Limit files
156
        if limit:
157
            params['maxFileCount'] = limit
158
159
        while new_files_to_retrieve:
160
161
            response = self.connector.make_request(path=path, method='post', params=params)
162
            if response.status_code == 200:
163
                files_json = response.json()
164
                for file_json in files_json['files']:
165
                    new_file = B2File(connector=self.connector, parent_list=self, **file_json)
166
167
                    # Append file_id, file_name to lists
168
                    file_name, file_id = file_json['fileName'], file_json['fileId']
169
                    file_names.append(file_name)
170
                    file_ids.append(file_id)
171
                    
0 ignored issues
show
Coding Style introduced by
Trailing whitespace
Loading history...
172
                    # Add file to list keyed by file_id
173
                    if file_id in file_versions:
174
                        file_versions[file_id].append(new_file)
175
                    else:
176
                        file_versions[file_id] = [new_file]
177
178
                if files_json['nextFileName'] is None:
179
                    new_files_to_retrieve = False
180
                else:
181
                    params['startFileName'] = files_json['nextFileName']
182
            else:
183
                raise B2Exception.parse(response)
184
        return {'file_names': file_names, 'file_versions': file_versions, 'file_ids': file_ids}
185
186
187 1
    def _get_by_name(self, file_name):
188
        """ Internal method, return single file by file name """ 
0 ignored issues
show
Coding Style introduced by
Trailing whitespace
Loading history...
189
        path = API.list_all_files
190
        params = {
191
            'prefix': b2_url_encode(file_name),
192
            'bucketId': self.bucket.bucket_id
193
        }
194
195
        response = self.connector.make_request(path, method='post', params=params)
196
        file_json = response.json()
197
198
        # Handle errors and empty files
199
        if not response.status_code == 200:
200
            raise B2Exception.parse(response)
201
        if not len(file_json['files']) > 0:
0 ignored issues
show
Unused Code introduced by
Do not use len(SEQUENCE) as condition value
Loading history...
202
            raise B2FileNotFoundError('Filename {} not found'.format(file_name))
203
        else:
204
            return B2File(connector=self.connector, parent_list=self, **file_json['files'][0])
205
206 1
    def _get_by_id(self, file_id):
207
        """ Internal method, return single file by file id """ 
0 ignored issues
show
Coding Style introduced by
Trailing whitespace
Loading history...
208
        path = API.file_info
209
        params = {
210
            'fileId': file_id
211
        }
212
        response = self.connector.make_request(path, method='post', params=params)
213
        if response.status_code == 200:
214
            file_json = response.json()
215
            return B2File(connector=self.connector, parent_list=self, **file_json)
216
        else:
217
            raise B2Exception.parse(response)
218
            
0 ignored issues
show
Coding Style introduced by
Trailing whitespace
Loading history...
219
220 1
    def upload(self, contents, file_name, mime_content_type=None, content_length=None, progress_listener=None):
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (111/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
best-practice introduced by
Too many arguments (6/5)
Loading history...
Unused Code introduced by
The argument mime_content_type seems to be unused.
Loading history...
221
        """
222
223
        :param contents:
224
        :param file_name:
225
        :param mime_content_type:
226
        :param content_length:
227
        :param progress_listener:
228
        :return:
229
        """
230
        if file_name[0] == '/':
231
            file_name = file_name[1:]
232
        get_upload_url_path = API.upload_url
233
        params = {
234
            'bucketId': self.bucket.bucket_id
235
        }
236
        upload_url_response = self.connector.make_request(path=get_upload_url_path, method='post', params=params)
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (113/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
237
        if upload_url_response.status_code == 200:
238
            upload_url = upload_url_response.json().get('uploadUrl', None)
239
            auth_token = upload_url_response.json().get('authorizationToken', None)
240
            upload_response = self.connector.upload_file(file_contents=contents, file_name=file_name,
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (101/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
241
                                                         upload_url=upload_url, auth_token=auth_token,
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (102/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
242
                                                         content_length=content_length, progress_listener=progress_listener)
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (124/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
243
            if upload_response.status_code == 200:
244
                new_file = B2File(connector=self.connector, parent_list=self, **upload_response.json())
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (103/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
245
                return new_file
246
            else:
247
                raise B2Exception.parse(upload_response)
248
        else:
249
            raise B2Exception.parse(upload_url_response)
250
251 1
    def upload_large_file(self, contents, file_name, part_size=None, num_threads=4,
0 ignored issues
show
best-practice introduced by
Too many arguments (8/5)
Loading history...
Comprehensibility introduced by
This function exceeds the maximum number of variables (19/15).
Loading history...
252
                          mime_content_type=None, content_length=None, progress_listener=None):
253
        """
254
255
        :param contents:
256
        :param file_name:
257
        :param part_size:
258
        :param num_threads:
259
        :param mime_content_type:
260
        :param content_length:
261
        :param progress_listener:
262
        :return:
263
        """
264
        if file_name[0] == '/':
265
            file_name = file_name[1:]
266
        if part_size == None:
0 ignored issues
show
introduced by
Comparison to None should be 'expr is None'
Loading history...
267
            part_size = self.connector.recommended_part_size
268
        if content_length == None:
0 ignored issues
show
introduced by
Comparison to None should be 'expr is None'
Loading history...
269
            content_length = get_content_length(contents)
270
        start_large_file_path = API.upload_large
271
        params = {
272
            'bucketId': self.bucket.bucket_id,
273
            'fileName': b2_url_encode(file_name),
274
            'contentType': mime_content_type or 'b2/x-auto'
275
        }
276
        large_file_response = self.connector.make_request(path=start_large_file_path, method='post', params=params)
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (115/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
277
        if large_file_response.status_code == 200:
278
            file_id = large_file_response.json().get('fileId', None)
279
            get_upload_part_url_path = API.upload_large_part
280
            params = {
281
                'fileId': file_id
282
            }
283
            pool = ThreadPool(num_threads)
284
            def upload_part_worker(args):
0 ignored issues
show
Coding Style introduced by
This function should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
285
                part_number, part_range = args
286
                offset, content_length = part_range
287
                with open(contents.name, 'rb') as file:
0 ignored issues
show
Bug Best Practice introduced by
This seems to re-define the built-in file.

It is generally discouraged to redefine built-ins as this makes code very hard to read.

Loading history...
288
                    file.seek(offset)
289
                    stream = RangeStream(file, offset, content_length)
290
                    upload_part_url_response = self.connector.make_request(path=get_upload_part_url_path, method='post', params=params)
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (135/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
291
                    if upload_part_url_response.status_code == 200:
292
                        upload_url = upload_part_url_response.json().get('uploadUrl')
293
                        auth_token = upload_part_url_response.json().get('authorizationToken')
294
                        upload_part_response = self.connector.upload_part(file_contents=stream, content_length=content_length,
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (126/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
295
                                                                          part_number=part_number, upload_url=upload_url,
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (121/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
296
                                                                          auth_token=auth_token, progress_listener=progress_listener)
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (133/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
297
                        if upload_part_response.status_code == 200:
298
                            return upload_part_response.json().get('contentSha1', None)
299
                        else:
300
                            raise B2Exception.parse(upload_part_response)
301
                    else:
302
                        raise B2Exception.parse(upload_part_url_response)
303
            sha_list = pool.map(upload_part_worker, enumerate(get_part_ranges(content_length, part_size), 1))
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (109/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
304
            pool.close()
305
            pool.join()
306
            finish_large_file_path = API.upload_large_finish
307
            params = {
308
                'fileId': file_id,
309
                'partSha1Array': sha_list
310
            }
311
            finish_large_file_response = self.connector.make_request(path=finish_large_file_path, method='post', params=params)
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (127/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
312
            if finish_large_file_response.status_code == 200:
313
                new_file = B2File(connector=self.connector, parent_list=self, **finish_large_file_response.json())
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (114/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
314
                return new_file
315
            else:
316
                raise B2Exception.parse(finish_large_file_response)
317
        else:
318
            raise B2Exception.parse(large_file_response)
319