flywheel-sdk 19.5.0rc3__py2.py3-none-any.whl → 20.0.0rc0__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4183,7 +4183,7 @@ class AcquisitionsApi(object):
4183
4183
  auth_settings = ['ApiKey'] # noqa: E501
4184
4184
 
4185
4185
  return self.api_client.call_api(
4186
- '/acquisitions/{cid}/files/{filename}/classification', 'POST',
4186
+ '/acquisitions/{cid}/files/{filename}/classification', 'PATCH',
4187
4187
  path_params,
4188
4188
  query_params,
4189
4189
  header_params,
@@ -4306,7 +4306,7 @@ class AcquisitionsApi(object):
4306
4306
  auth_settings = ['ApiKey'] # noqa: E501
4307
4307
 
4308
4308
  return self.api_client.call_api(
4309
- '/acquisitions/{cid}/files/{filename}/info', 'POST',
4309
+ '/acquisitions/{cid}/files/{filename}/info', 'PATCH',
4310
4310
  path_params,
4311
4311
  query_params,
4312
4312
  header_params,
@@ -4421,7 +4421,7 @@ class AcquisitionsApi(object):
4421
4421
  auth_settings = ['ApiKey'] # noqa: E501
4422
4422
 
4423
4423
  return self.api_client.call_api(
4424
- '/acquisitions/{cid}/info', 'POST',
4424
+ '/acquisitions/{cid}/info', 'PATCH',
4425
4425
  path_params,
4426
4426
  query_params,
4427
4427
  header_params,
@@ -2415,7 +2415,7 @@ class AnalysesApi(object):
2415
2415
  auth_settings = ['ApiKey'] # noqa: E501
2416
2416
 
2417
2417
  return self.api_client.call_api(
2418
- '/analyses/{container_id}/info', 'POST',
2418
+ '/analyses/{container_id}/info', 'PATCH',
2419
2419
  path_params,
2420
2420
  query_params,
2421
2421
  header_params,
@@ -3218,7 +3218,7 @@ class CollectionsApi(object):
3218
3218
  auth_settings = ['ApiKey'] # noqa: E501
3219
3219
 
3220
3220
  return self.api_client.call_api(
3221
- '/collections/{cid}/files/{filename}/classification', 'POST',
3221
+ '/collections/{cid}/files/{filename}/classification', 'PATCH',
3222
3222
  path_params,
3223
3223
  query_params,
3224
3224
  header_params,
@@ -3341,7 +3341,7 @@ class CollectionsApi(object):
3341
3341
  auth_settings = ['ApiKey'] # noqa: E501
3342
3342
 
3343
3343
  return self.api_client.call_api(
3344
- '/collections/{cid}/files/{filename}/info', 'POST',
3344
+ '/collections/{cid}/files/{filename}/info', 'PATCH',
3345
3345
  path_params,
3346
3346
  query_params,
3347
3347
  header_params,
@@ -3456,7 +3456,7 @@ class CollectionsApi(object):
3456
3456
  auth_settings = ['ApiKey'] # noqa: E501
3457
3457
 
3458
3458
  return self.api_client.call_api(
3459
- '/collections/{cid}/info', 'POST',
3459
+ '/collections/{cid}/info', 'PATCH',
3460
3460
  path_params,
3461
3461
  query_params,
3462
3462
  header_params,
@@ -3961,7 +3961,7 @@ class ContainersApi(object):
3961
3961
  auth_settings = ['ApiKey'] # noqa: E501
3962
3962
 
3963
3963
  return self.api_client.call_api(
3964
- '/containers/{cid}/files/{filename}/classification', 'POST',
3964
+ '/containers/{cid}/files/{filename}/classification', 'PATCH',
3965
3965
  path_params,
3966
3966
  query_params,
3967
3967
  header_params,
@@ -4084,7 +4084,7 @@ class ContainersApi(object):
4084
4084
  auth_settings = ['ApiKey'] # noqa: E501
4085
4085
 
4086
4086
  return self.api_client.call_api(
4087
- '/containers/{cid}/files/{filename}/info', 'POST',
4087
+ '/containers/{cid}/files/{filename}/info', 'PATCH',
4088
4088
  path_params,
4089
4089
  query_params,
4090
4090
  header_params,
@@ -4199,7 +4199,7 @@ class ContainersApi(object):
4199
4199
  auth_settings = ['ApiKey'] # noqa: E501
4200
4200
 
4201
4201
  return self.api_client.call_api(
4202
- '/containers/{cid}/info', 'POST',
4202
+ '/containers/{cid}/info', 'PATCH',
4203
4203
  path_params,
4204
4204
  query_params,
4205
4205
  header_params,
@@ -335,6 +335,117 @@ class DevicesApi(object):
335
335
  _request_out=params.get('_request_out'),
336
336
  collection_formats=collection_formats)
337
337
 
338
+ def generate_key(self, device_id, **kwargs): # noqa: E501
339
+ """Generate device API key
340
+
341
+ Regenerate device API key
342
+ This method makes a synchronous HTTP request by default.
343
+
344
+ :param str device_id: (required)
345
+ :param ApiKeyInputWithOptionalLabel body:
346
+ :param bool async_: Perform the request asynchronously
347
+ :return: object
348
+ """
349
+ ignore_simplified_return_value = kwargs.pop('_ignore_simplified_return_value', False)
350
+ kwargs['_return_http_data_only'] = True
351
+
352
+ if kwargs.get('async_'):
353
+ return self.generate_key_with_http_info(device_id, **kwargs) # noqa: E501
354
+ else:
355
+ (data) = self.generate_key_with_http_info(device_id, **kwargs) # noqa: E501
356
+ if (
357
+ data
358
+ and hasattr(data, 'return_value')
359
+ and not ignore_simplified_return_value
360
+ ):
361
+ return data.return_value()
362
+ return data
363
+
364
+
365
+ def generate_key_with_http_info(self, device_id, **kwargs): # noqa: E501
366
+ """Generate device API key
367
+
368
+ Regenerate device API key
369
+ This method makes a synchronous HTTP request by default.
370
+
371
+ :param str device_id: (required)
372
+ :param ApiKeyInputWithOptionalLabel body:
373
+ :param bool async_: Perform the request asynchronously
374
+ :return: object
375
+ """
376
+
377
+ all_params = ['device_id','body',] # noqa: E501
378
+ all_params.append('async_')
379
+ all_params.append('_return_http_data_only')
380
+ all_params.append('_preload_content')
381
+ all_params.append('_request_timeout')
382
+ all_params.append('_request_out')
383
+
384
+ params = locals()
385
+ for key, val in six.iteritems(params['kwargs']):
386
+ if key not in all_params:
387
+ raise TypeError(
388
+ "Got an unexpected keyword argument '%s'"
389
+ " to method generate_key" % key
390
+ )
391
+ params[key] = val
392
+ del params['kwargs']
393
+ # verify the required parameter 'device_id' is set
394
+ if ('device_id' not in params or
395
+ params['device_id'] is None):
396
+ raise ValueError("Missing the required parameter `device_id` when calling `generate_key`") # noqa: E501
397
+
398
+ collection_formats = {}
399
+
400
+ path_params = {}
401
+ if 'device_id' in params:
402
+ path_params['device_id'] = params['device_id'] # noqa: E501
403
+
404
+ query_params = []
405
+
406
+ header_params = {}
407
+
408
+ form_params = []
409
+ local_var_files = {}
410
+
411
+ body_params = None
412
+ if 'body' in params:
413
+ if 'ApiKeyInputWithOptionalLabel'.startswith('union'):
414
+ body_type = type(params['body'])
415
+ if getattr(body_type, 'positional_to_model', None):
416
+ body_params = body_type.positional_to_model(params['body'])
417
+ else:
418
+ body_params = params['body']
419
+ else:
420
+ body_params = flywheel.models.ApiKeyInputWithOptionalLabel.positional_to_model(params['body'])
421
+ # HTTP header `Accept`
422
+ header_params['Accept'] = self.api_client.select_header_accept(
423
+ ['application/json']) # noqa: E501
424
+
425
+ # HTTP header `Content-Type`
426
+ header_params['Content-Type'] = self.api_client.select_header_content_type( # noqa: E501
427
+ ['application/json']) # noqa: E501
428
+
429
+ # Authentication setting
430
+ auth_settings = ['ApiKey'] # noqa: E501
431
+
432
+ return self.api_client.call_api(
433
+ '/devices/{device_id}/key', 'POST',
434
+ path_params,
435
+ query_params,
436
+ header_params,
437
+ body=body_params,
438
+ post_params=form_params,
439
+ files=local_var_files,
440
+ response_type='object', # noqa: E501
441
+ auth_settings=auth_settings,
442
+ async_=params.get('async_'),
443
+ _return_http_data_only=params.get('_return_http_data_only'),
444
+ _preload_content=params.get('_preload_content', True),
445
+ _request_timeout=params.get('_request_timeout'),
446
+ _request_out=params.get('_request_out'),
447
+ collection_formats=collection_formats)
448
+
338
449
  def get_all_devices(self, **kwargs): # noqa: E501
339
450
  """List all devices.
340
451
 
@@ -842,9 +953,8 @@ class DevicesApi(object):
842
953
  collection_formats=collection_formats)
843
954
 
844
955
  def regenerate_key(self, device_id, **kwargs): # noqa: E501
845
- """Regenerate device API key
956
+ """This method is DEPRECATED, use generate_key instead
846
957
 
847
- Regenerate device API key
848
958
  This method makes a synchronous HTTP request by default.
849
959
 
850
960
  :param str device_id: (required)
@@ -869,9 +979,8 @@ class DevicesApi(object):
869
979
 
870
980
 
871
981
  def regenerate_key_with_http_info(self, device_id, **kwargs): # noqa: E501
872
- """Regenerate device API key
982
+ """This method is DEPRECATED, use generate_key instead
873
983
 
874
- Regenerate device API key
875
984
  This method makes a synchronous HTTP request by default.
876
985
 
877
986
  :param str device_id: (required)
@@ -936,7 +1045,7 @@ class DevicesApi(object):
936
1045
  auth_settings = ['ApiKey'] # noqa: E501
937
1046
 
938
1047
  return self.api_client.call_api(
939
- '/devices/{device_id}/key', 'POST',
1048
+ '/devices/{device_id}/key-regen', 'POST',
940
1049
  path_params,
941
1050
  query_params,
942
1051
  header_params,
@@ -5773,7 +5773,7 @@ class ProjectsApi(object):
5773
5773
  auth_settings = ['ApiKey'] # noqa: E501
5774
5774
 
5775
5775
  return self.api_client.call_api(
5776
- '/projects/{cid}/files/{filename}/classification', 'POST',
5776
+ '/projects/{cid}/files/{filename}/classification', 'PATCH',
5777
5777
  path_params,
5778
5778
  query_params,
5779
5779
  header_params,
@@ -5896,7 +5896,7 @@ class ProjectsApi(object):
5896
5896
  auth_settings = ['ApiKey'] # noqa: E501
5897
5897
 
5898
5898
  return self.api_client.call_api(
5899
- '/projects/{cid}/files/{filename}/info', 'POST',
5899
+ '/projects/{cid}/files/{filename}/info', 'PATCH',
5900
5900
  path_params,
5901
5901
  query_params,
5902
5902
  header_params,
@@ -6011,7 +6011,7 @@ class ProjectsApi(object):
6011
6011
  auth_settings = ['ApiKey'] # noqa: E501
6012
6012
 
6013
6013
  return self.api_client.call_api(
6014
- '/projects/{cid}/info', 'POST',
6014
+ '/projects/{cid}/info', 'PATCH',
6015
6015
  path_params,
6016
6016
  query_params,
6017
6017
  header_params,
@@ -4463,7 +4463,7 @@ class SessionsApi(object):
4463
4463
  auth_settings = ['ApiKey'] # noqa: E501
4464
4464
 
4465
4465
  return self.api_client.call_api(
4466
- '/sessions/{cid}/files/{filename}/classification', 'POST',
4466
+ '/sessions/{cid}/files/{filename}/classification', 'PATCH',
4467
4467
  path_params,
4468
4468
  query_params,
4469
4469
  header_params,
@@ -4586,7 +4586,7 @@ class SessionsApi(object):
4586
4586
  auth_settings = ['ApiKey'] # noqa: E501
4587
4587
 
4588
4588
  return self.api_client.call_api(
4589
- '/sessions/{cid}/files/{filename}/info', 'POST',
4589
+ '/sessions/{cid}/files/{filename}/info', 'PATCH',
4590
4590
  path_params,
4591
4591
  query_params,
4592
4592
  header_params,
@@ -4701,7 +4701,7 @@ class SessionsApi(object):
4701
4701
  auth_settings = ['ApiKey'] # noqa: E501
4702
4702
 
4703
4703
  return self.api_client.call_api(
4704
- '/sessions/{cid}/info', 'POST',
4704
+ '/sessions/{cid}/info', 'PATCH',
4705
4705
  path_params,
4706
4706
  query_params,
4707
4707
  header_params,
@@ -4419,7 +4419,7 @@ class SubjectsApi(object):
4419
4419
  auth_settings = ['ApiKey'] # noqa: E501
4420
4420
 
4421
4421
  return self.api_client.call_api(
4422
- '/subjects/{cid}/files/{filename}/classification', 'POST',
4422
+ '/subjects/{cid}/files/{filename}/classification', 'PATCH',
4423
4423
  path_params,
4424
4424
  query_params,
4425
4425
  header_params,
@@ -4542,7 +4542,7 @@ class SubjectsApi(object):
4542
4542
  auth_settings = ['ApiKey'] # noqa: E501
4543
4543
 
4544
4544
  return self.api_client.call_api(
4545
- '/subjects/{cid}/files/{filename}/info', 'POST',
4545
+ '/subjects/{cid}/files/{filename}/info', 'PATCH',
4546
4546
  path_params,
4547
4547
  query_params,
4548
4548
  header_params,
@@ -4657,7 +4657,7 @@ class SubjectsApi(object):
4657
4657
  auth_settings = ['ApiKey'] # noqa: E501
4658
4658
 
4659
4659
  return self.api_client.call_api(
4660
- '/subjects/{cid}/info', 'POST',
4660
+ '/subjects/{cid}/info', 'PATCH',
4661
4661
  path_params,
4662
4662
  query_params,
4663
4663
  header_params,
flywheel/api/users_api.py CHANGED
@@ -1873,7 +1873,7 @@ class UsersApi(object):
1873
1873
  auth_settings = ['ApiKey'] # noqa: E501
1874
1874
 
1875
1875
  return self.api_client.call_api(
1876
- '/users/self/info', 'POST',
1876
+ '/users/self/info', 'PATCH',
1877
1877
  path_params,
1878
1878
  query_params,
1879
1879
  header_params,
flywheel/api_client.py CHANGED
@@ -84,7 +84,7 @@ class ApiClient(object):
84
84
  self.default_query_params = []
85
85
  self.cookie = cookie
86
86
  # Set default User-Agent.
87
- self.user_agent = 'Swagger-Codegen/19.5.0-rc3/python'
87
+ self.user_agent = 'Swagger-Codegen/20.0.0-rc0/python'
88
88
  self.last_response = None
89
89
  self._version_check_fn = None
90
90
  self._context = context
flywheel/configuration.py CHANGED
@@ -252,6 +252,6 @@ class Configuration(six.with_metaclass(TypeWithDefault, object)):
252
252
  return "Python SDK Debug Report:\n"\
253
253
  "OS: {env}\n"\
254
254
  "Python Version: {pyversion}\n"\
255
- "Version of the API: 19.5.0-rc3\n"\
256
- "SDK Package Version: 19.5.0-rc3".\
255
+ "Version of the API: 20.0.0-rc0\n"\
256
+ "SDK Package Version: 20.0.0-rc0".\
257
257
  format(env=sys.platform, pyversion=sys.version)
flywheel/flywheel.py CHANGED
@@ -40,7 +40,7 @@ from flywheel.view_builder import ViewBuilder
40
40
  from flywheel.finder import Finder
41
41
  import flywheel.api
42
42
 
43
- SDK_VERSION = "19.5.0-rc3"
43
+ SDK_VERSION = "20.0.0-rc0"
44
44
 
45
45
  def config_from_api_key(api_key):
46
46
  parts = api_key.split(':')
@@ -2817,6 +2817,19 @@ class Flywheel:
2817
2817
  return self.devices_api.delete_device_key(device_id, key_id, **kwargs)
2818
2818
 
2819
2819
 
2820
+ def generate_key(self, device_id, **kwargs): # noqa: E501
2821
+ """Generate device API key
2822
+
2823
+ Regenerate device API key
2824
+
2825
+ :param str device_id: (required)
2826
+ :param ApiKeyInputWithOptionalLabel body:
2827
+ :param bool async_: Perform the request asynchronously
2828
+ :return: object
2829
+ """
2830
+ return self.devices_api.generate_key(device_id, **kwargs)
2831
+
2832
+
2820
2833
  def get_all_devices(self, **kwargs): # noqa: E501
2821
2834
  """List all devices.
2822
2835
 
@@ -2882,9 +2895,7 @@ class Flywheel:
2882
2895
 
2883
2896
 
2884
2897
  def regenerate_key(self, device_id, **kwargs): # noqa: E501
2885
- """Regenerate device API key
2886
-
2887
- Regenerate device API key
2898
+ """This method is DEPRECATED, use generate_key instead
2888
2899
 
2889
2900
  :param str device_id: (required)
2890
2901
  :param ApiKeyInputWithOptionalLabel body:
@@ -6,7 +6,7 @@
6
6
 
7
7
  Flywheel: API for data import, automated curation, image processing, machine learning workflows, and secure collaboration. # noqa: E501
8
8
 
9
- OpenAPI spec version: 19.5.0-rc3
9
+ OpenAPI spec version: 20.0.0-rc0
10
10
 
11
11
  Generated by: https://github.com/swagger-api/swagger-codegen.git
12
12
  """
@@ -21,31 +21,38 @@ import six
21
21
  class DeletedResult(object):
22
22
 
23
23
  swagger_types = {
24
- 'deleted': 'int'
24
+ 'deleted': 'int',
25
+ 'not_found': 'int'
25
26
  }
26
27
 
27
28
  attribute_map = {
28
- 'deleted': 'deleted'
29
+ 'deleted': 'deleted',
30
+ 'not_found': 'not_found'
29
31
  }
30
32
 
31
33
  rattribute_map = {
32
- 'deleted': 'deleted'
34
+ 'deleted': 'deleted',
35
+ 'not_found': 'not_found'
33
36
  }
34
37
 
35
- def __init__(self, deleted=None): # noqa: E501
38
+ def __init__(self, deleted=None, not_found=0): # noqa: E501
36
39
  """DeletedResult - a model defined in Swagger"""
37
40
  super(DeletedResult, self).__init__()
38
41
 
39
42
  self._deleted = None
43
+ self._not_found = None
40
44
  self.discriminator = None
41
45
  self.alt_discriminator = None
42
46
 
43
47
  self.deleted = deleted
48
+ if not_found is not None:
49
+ self.not_found = not_found
44
50
 
45
51
  @property
46
52
  def deleted(self):
47
53
  """Gets the deleted of this DeletedResult.
48
54
 
55
+ The number of containers that were deleted
49
56
 
50
57
  :return: The deleted of this DeletedResult.
51
58
  :rtype: int
@@ -56,6 +63,7 @@ class DeletedResult(object):
56
63
  def deleted(self, deleted):
57
64
  """Sets the deleted of this DeletedResult.
58
65
 
66
+ The number of containers that were deleted
59
67
 
60
68
  :param deleted: The deleted of this DeletedResult. # noqa: E501
61
69
  :type: int
@@ -63,6 +71,29 @@ class DeletedResult(object):
63
71
 
64
72
  self._deleted = deleted
65
73
 
74
+ @property
75
+ def not_found(self):
76
+ """Gets the not_found of this DeletedResult.
77
+
78
+ The number of containers that were specified by ID to be deleted, but were not found because they don't exist or were already deleted
79
+
80
+ :return: The not_found of this DeletedResult.
81
+ :rtype: int
82
+ """
83
+ return self._not_found
84
+
85
+ @not_found.setter
86
+ def not_found(self, not_found):
87
+ """Sets the not_found of this DeletedResult.
88
+
89
+ The number of containers that were specified by ID to be deleted, but were not found because they don't exist or were already deleted
90
+
91
+ :param not_found: The not_found of this DeletedResult. # noqa: E501
92
+ :type: int
93
+ """
94
+
95
+ self._not_found = not_found
96
+
66
97
 
67
98
  @staticmethod
68
99
  def positional_to_model(value):
flywheel/models/mixins.py CHANGED
@@ -272,6 +272,30 @@ class AnalysisMethods(object):
272
272
 
273
273
 
274
274
  class FileMethods(object):
275
+ def _warn_if_keys_will_be_sanitized(self, key):
276
+ """Log warning message for offending characters"""
277
+ if "$" in key:
278
+ warnings.warn(f"Key {key} contains '$', which will be replaced with '-'.")
279
+ if "." in key:
280
+ warnings.warn(f"Key {key} contains '.', which will be replaced with '_'.")
281
+
282
+ def _check_list(self, values):
283
+ """Check list values"""
284
+ for val in values:
285
+ if isinstance(val, list):
286
+ self._check_list(val)
287
+ elif isinstance(val, dict):
288
+ self._validate_keys(val)
289
+
290
+ def _validate_keys(self, body):
291
+ """Recursively check for keys that contain offending characters"""
292
+ for key, values in body.items():
293
+ self._warn_if_keys_will_be_sanitized(key)
294
+ if isinstance(values, dict):
295
+ self._validate_keys(values)
296
+ elif isinstance(values, list):
297
+ self._check_list(values)
298
+
275
299
  def upload_file(self, file, **kwargs):
276
300
  """Upload a file to a container"""
277
301
  return self._invoke_file_api("upload_file_to_{}", self.id, file, **kwargs)
@@ -303,12 +327,14 @@ class FileMethods(object):
303
327
 
304
328
  def replace_file_info(self, file_name, info, **kwargs):
305
329
  """Fully replace this file's info with the provided value"""
330
+ self._validate_keys(info)
306
331
  return self._invoke_file_api("replace_{}_file_info", self.id, file_name, info, **kwargs)
307
332
 
308
333
  def update_file_info(self, file_name, *args, **kwargs):
309
334
  """Update the file's info with the passed in arguments"""
310
335
  # Could either pass a dictionary or kwargs values
311
336
  body = util.params_to_dict("update_file_info", args, kwargs)
337
+ self._validate_keys(body)
312
338
  return self._invoke_file_api("set_{}_file_info", self.id, file_name, body)
313
339
 
314
340
  def delete_file_info(self, file_name, *args, **kwargs):
@@ -25,7 +25,8 @@ class ProjectCopyFilter(object):
25
25
  'exclude_notes': 'bool',
26
26
  'exclude_tags': 'bool',
27
27
  'include_rules': 'list[str]',
28
- 'exclude_rules': 'list[str]'
28
+ 'exclude_rules': 'list[str]',
29
+ 'exclude_empty_containers': 'bool'
29
30
  }
30
31
 
31
32
  attribute_map = {
@@ -33,7 +34,8 @@ class ProjectCopyFilter(object):
33
34
  'exclude_notes': 'exclude_notes',
34
35
  'exclude_tags': 'exclude_tags',
35
36
  'include_rules': 'include_rules',
36
- 'exclude_rules': 'exclude_rules'
37
+ 'exclude_rules': 'exclude_rules',
38
+ 'exclude_empty_containers': 'exclude_empty_containers'
37
39
  }
38
40
 
39
41
  rattribute_map = {
@@ -41,10 +43,11 @@ class ProjectCopyFilter(object):
41
43
  'exclude_notes': 'exclude_notes',
42
44
  'exclude_tags': 'exclude_tags',
43
45
  'include_rules': 'include_rules',
44
- 'exclude_rules': 'exclude_rules'
46
+ 'exclude_rules': 'exclude_rules',
47
+ 'exclude_empty_containers': 'exclude_empty_containers'
45
48
  }
46
49
 
47
- def __init__(self, exclude_analysis=False, exclude_notes=False, exclude_tags=False, include_rules=None, exclude_rules=None): # noqa: E501
50
+ def __init__(self, exclude_analysis=False, exclude_notes=False, exclude_tags=False, include_rules=None, exclude_rules=None, exclude_empty_containers=True): # noqa: E501
48
51
  """ProjectCopyFilter - a model defined in Swagger"""
49
52
  super(ProjectCopyFilter, self).__init__()
50
53
 
@@ -53,6 +56,7 @@ class ProjectCopyFilter(object):
53
56
  self._exclude_tags = None
54
57
  self._include_rules = None
55
58
  self._exclude_rules = None
59
+ self._exclude_empty_containers = None
56
60
  self.discriminator = None
57
61
  self.alt_discriminator = None
58
62
 
@@ -66,6 +70,8 @@ class ProjectCopyFilter(object):
66
70
  self.include_rules = include_rules
67
71
  if exclude_rules is not None:
68
72
  self.exclude_rules = exclude_rules
73
+ if exclude_empty_containers is not None:
74
+ self.exclude_empty_containers = exclude_empty_containers
69
75
 
70
76
  @property
71
77
  def exclude_analysis(self):
@@ -172,6 +178,27 @@ class ProjectCopyFilter(object):
172
178
 
173
179
  self._exclude_rules = exclude_rules
174
180
 
181
+ @property
182
+ def exclude_empty_containers(self):
183
+ """Gets the exclude_empty_containers of this ProjectCopyFilter.
184
+
185
+
186
+ :return: The exclude_empty_containers of this ProjectCopyFilter.
187
+ :rtype: bool
188
+ """
189
+ return self._exclude_empty_containers
190
+
191
+ @exclude_empty_containers.setter
192
+ def exclude_empty_containers(self, exclude_empty_containers):
193
+ """Sets the exclude_empty_containers of this ProjectCopyFilter.
194
+
195
+
196
+ :param exclude_empty_containers: The exclude_empty_containers of this ProjectCopyFilter. # noqa: E501
197
+ :type: bool
198
+ """
199
+
200
+ self._exclude_empty_containers = exclude_empty_containers
201
+
175
202
 
176
203
  @staticmethod
177
204
  def positional_to_model(value):
@@ -21,49 +21,20 @@ import six
21
21
  class WorkInProgressFeatures(object):
22
22
 
23
23
  swagger_types = {
24
- 'smart_copy_exc_empty': 'bool'
25
24
  }
26
25
 
27
26
  attribute_map = {
28
- 'smart_copy_exc_empty': 'smart_copy_exc_empty'
29
27
  }
30
28
 
31
29
  rattribute_map = {
32
- 'smart_copy_exc_empty': 'smart_copy_exc_empty'
33
30
  }
34
31
 
35
- def __init__(self, smart_copy_exc_empty=False): # noqa: E501
32
+ def __init__(self): # noqa: E501
36
33
  """WorkInProgressFeatures - a model defined in Swagger"""
37
34
  super(WorkInProgressFeatures, self).__init__()
38
-
39
- self._smart_copy_exc_empty = None
40
35
  self.discriminator = None
41
36
  self.alt_discriminator = None
42
37
 
43
- if smart_copy_exc_empty is not None:
44
- self.smart_copy_exc_empty = smart_copy_exc_empty
45
-
46
- @property
47
- def smart_copy_exc_empty(self):
48
- """Gets the smart_copy_exc_empty of this WorkInProgressFeatures.
49
-
50
-
51
- :return: The smart_copy_exc_empty of this WorkInProgressFeatures.
52
- :rtype: bool
53
- """
54
- return self._smart_copy_exc_empty
55
-
56
- @smart_copy_exc_empty.setter
57
- def smart_copy_exc_empty(self, smart_copy_exc_empty):
58
- """Sets the smart_copy_exc_empty of this WorkInProgressFeatures.
59
-
60
-
61
- :param smart_copy_exc_empty: The smart_copy_exc_empty of this WorkInProgressFeatures. # noqa: E501
62
- :type: bool
63
- """
64
-
65
- self._smart_copy_exc_empty = smart_copy_exc_empty
66
-
67
38
 
68
39
  @staticmethod
69
40
  def positional_to_model(value):
flywheel/rest.py CHANGED
@@ -41,7 +41,14 @@ logger = logging.getLogger(__name__)
41
41
 
42
42
  CONNECT_TIMEOUT = int(os.getenv('FLYWHEEL_SDK_CONNECT_TIMEOUT', 10))
43
43
  REQUEST_TIMEOUT = int(os.getenv('FLYWHEEL_SDK_REQUEST_TIMEOUT', 60))
44
- BACKOFF_FACTOR = float(os.getenv('FLYWHEEL_SDK_BACKOFF_FACTOR', 0.5))
44
+
45
+ # Retry logic
46
+ # Total number of times to retry requests that fail due to transient HTTP errors
47
+ TOTAL_RETRIES = int(os.getenv('FLYWHEEL_SDK_TOTAL_RETRIES', 7))
48
+ # Backoff factor--after the initial instant retry, the client will start waiting for
49
+ # {backoff factor} * (2 ** ({number of previous retries})) seconds before each retry
50
+ # So the second retry will happen after waiting for 2 * {backoff_factor} seconds
51
+ BACKOFF_FACTOR = float(os.getenv('FLYWHEEL_SDK_BACKOFF_FACTOR', 7.5 / 4)) / 2
45
52
 
46
53
  class RESTResponse(io.IOBase):
47
54
 
@@ -87,9 +94,10 @@ class RESTClientObject(object):
87
94
  503, # service unavailable
88
95
  504, # gateway timeout
89
96
  }
90
- # retries at 0.0s, 1s, 3s, 7s, 15s after the request by default
97
+ # retries at 0.0s, 1.875s, 3.75s, 7.5s, 15s, 30s, 60s after the request by default
91
98
  # sleeptime is 0 on 1st retry, then backoff * 2^(retry-1)
92
- retry = urllib3.util.Retry(total=5, backoff_factor=BACKOFF_FACTOR,
99
+ retry = urllib3.util.Retry(total=TOTAL_RETRIES,
100
+ backoff_factor=BACKOFF_FACTOR,
93
101
  status_forcelist=transient_http_errors)
94
102
  adapter = requests.adapters.HTTPAdapter(max_retries=retry)
95
103
  self.session.mount('http://', adapter)
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: flywheel-sdk
3
- Version: 19.5.0rc3
3
+ Version: 20.0.0rc0
4
4
  Summary: Flywheel SDK
5
5
  Home-page:
6
6
  Author-email: support@flywheel.io
@@ -16,6 +16,13 @@ Requires-Dist: python-dateutil>=2.8.1
16
16
  Requires-Dist: packaging
17
17
  Requires-Dist: requests>=2.18.4
18
18
  Requires-Dist: requests-toolbelt
19
+ Dynamic: author-email
20
+ Dynamic: description
21
+ Dynamic: keywords
22
+ Dynamic: license
23
+ Dynamic: project-url
24
+ Dynamic: requires-dist
25
+ Dynamic: summary
19
26
 
20
27
 
21
28
  Flywheel SDK
@@ -1,30 +1,30 @@
1
1
  flywheel/__init__.py,sha256=LE9B1Aey0HGrusRPQc8yTl105-kI9h5yEqxUL6CrQzE,44975
2
- flywheel/api_client.py,sha256=cvLdUTq6wzMBehCDpocnIHWImBrxRDgsYLJPg1m_txY,29574
2
+ flywheel/api_client.py,sha256=PdtvEMamUhOfQ2CUYEoja8HGPEPT5zqrsfQdvbpafD0,29574
3
3
  flywheel/client.py,sha256=LMvn2aSdtn-waCpXzux8FKJxEB0469SJg5ZNnB5BqTc,10476
4
- flywheel/configuration.py,sha256=8FOCQkEpN289AC8AAQu39gq5xiuT4r_PFP-kfC1xeXU,8647
4
+ flywheel/configuration.py,sha256=GSSluKNjuWmURxnTUgq7RdiAw9artGf1y9NOmfVRgO8,8647
5
5
  flywheel/drone_login.py,sha256=8nELIBYBJMuPHQ0zdrGjWB20C3OTZbxpFVyxWmQ0kr0,2229
6
6
  flywheel/file_spec.py,sha256=0BnFgyH0qsDxuupJG5_g9LX2cLq7JxRiSODN3HdI-ak,2220
7
7
  flywheel/finder.py,sha256=ueECCweO48TTAJXudzh3xBbqyhV-Vbzt1NnPUSqEU9U,6739
8
- flywheel/flywheel.py,sha256=uK1rG3IurRv1us_0NPFiRNppM949M33-pnVDCOV7Elw,395089
8
+ flywheel/flywheel.py,sha256=P0xe47Md2wCJMi8259-otQg5fbkGCTw3DWvO5lyAXMA,395472
9
9
  flywheel/gear_context.py,sha256=cFJs8cC_on6v184HVUTXSSVS9y5ee73QN0lCkPTQ5jk,13701
10
10
  flywheel/partial_reader.py,sha256=SkMgwaGZeeVaN7f9dzmVitBFnQv8ARLJgEaQP36l92s,1222
11
- flywheel/rest.py,sha256=hRPcmGLghBkiZ06jyFEE39iEdP0-6o4pDWj2Ocl7mSc,13119
11
+ flywheel/rest.py,sha256=Luybe_pjqufXgw3LHSwPrSWFKrrAH6UU3IvTtSeCoAQ,13604
12
12
  flywheel/util.py,sha256=_97fv5qRvxvSFi1eHsli4VszoOBhYMhtC26hz_ukrEA,2198
13
13
  flywheel/view_builder.py,sha256=0hGDvjiljUuyuHezawx-TSO5Nv885No6rGf3lb3qvxo,17758
14
14
  flywheel/api/__init__.py,sha256=S0erMpSONSRh8RUbADUNnAczZwUhe-Lt9s8E4TMGH5M,1760
15
- flywheel/api/acquisitions_api.py,sha256=Kjc5jdEQlXUyn3aH6-I2bqoDVlxfXANzcoVysVQMZ6Y,213201
16
- flywheel/api/analyses_api.py,sha256=0MqBGFQukb-Mm542MOS-Fc764XnkeyNsnin9OcXEFcU,117699
15
+ flywheel/api/acquisitions_api.py,sha256=4VG8y2Iqq9V-G8d--WN3FIg6EHKo642_3oyBCIV6lmA,213204
16
+ flywheel/api/analyses_api.py,sha256=fgnZx3PzJcKcqoGJcDqPC52q-bpiGWNPvFQcXhw-xtI,117700
17
17
  flywheel/api/audit_trail_api.py,sha256=dFinVdTCqO1TsCoRndTT1qqV61J2FWMyYS2FqQwqP54,21492
18
18
  flywheel/api/auth_api.py,sha256=w6wscqpCv-Rc9n9Q1KogyeaByM9YhiDNl4upvErV674,3703
19
19
  flywheel/api/batch_api.py,sha256=zpeo0U6ubk-AxlCQ_j-rTmVuKpjJue9icFq-zBP5ZVo,23287
20
20
  flywheel/api/bulk_api.py,sha256=kSIQUYBHS37yDKdM1TMNYNLhXTrIkfTYznRhtVuEUS0,4776
21
21
  flywheel/api/change_log_api.py,sha256=Nln-mDIsCRLcsDCBDo8e9sYv1jTCf6ql_JX9SfP5-ds,10003
22
- flywheel/api/collections_api.py,sha256=pufAm_gzR6doPFhrMqLYOl_v3m3yPt3klgpa69IPInc,165385
22
+ flywheel/api/collections_api.py,sha256=rXBTYe9L949ZyOgCu1xQTM91Titv-fxV8tthK4xzLEM,165388
23
23
  flywheel/api/config_api.py,sha256=rBURhYVyT22BpOjDIQ_2iJ3UOnfspgjowQnz2cKND_s,9584
24
- flywheel/api/containers_api.py,sha256=2Dzb0Xmc_SUbHf2HUFGTnhLen_p-yqhPnkqtsvj4h0M,202808
24
+ flywheel/api/containers_api.py,sha256=fReONdto78giDqvhU5EjIVf1M4nM5KaOw3X_UvGeR9c,202811
25
25
  flywheel/api/data_view_executions_api.py,sha256=vdQ3vRbebC2InZp0s7WUMGxJjRiq_aaXLrYIHi2lk4s,21544
26
26
  flywheel/api/dataexplorer_api.py,sha256=Qqu916GYB1oMYLshp6zagQtaszkAFGrbT6RnmNyRhLU,37594
27
- flywheel/api/devices_api.py,sha256=BXJt_dJdVQ94We1EYdmrCziAb6OerBGg7IkUlJVQDHk,39380
27
+ flywheel/api/devices_api.py,sha256=VsclxSE_yMSAvST5uxEKMBXNqq_eKJjI6XI4S3RKsas,43568
28
28
  flywheel/api/dimse_api.py,sha256=rTPcy5CTFFnpx1YWSuhsWMNjW4c9nTV85Q8EY1QcGN8,29974
29
29
  flywheel/api/download_api.py,sha256=fFOA8DgRq1yknYQ6YZC26fcaZDhGIDnGuWMjvYD_Ans,10590
30
30
  flywheel/api/files_api.py,sha256=fE8KWWhCsp79I5c8FqVoei6dh5YMnvbtjhZxo8aaK-I,57924
@@ -34,19 +34,19 @@ flywheel/api/jobs_api.py,sha256=VMu1r6k1gng9Sg1b0IlDaIfC1A7rvdqn3gHVXXd39-k,7396
34
34
  flywheel/api/jupyterlab_servers_api.py,sha256=FiwtzKL6SClFXiBnzbf5dtjHCjonMQ3jB7FHlrFNGQM,9180
35
35
  flywheel/api/modalities_api.py,sha256=GyqCWO1_iQ7RUgvKD6KeAOrPx6O7Q3XxxGsqksBBJEM,20862
36
36
  flywheel/api/packfiles_api.py,sha256=3IQHwnmjCYBw7L4gJIxnZwpGdIT6LqEZPb-eIHG3t8o,3847
37
- flywheel/api/projects_api.py,sha256=sTEl6wNlMUJokkik_PwYcTQ4Cy4AtjrtzjRRH9312A0,330414
37
+ flywheel/api/projects_api.py,sha256=ZAL2uJzx1ObIyiQFxNh8c6TldfeJJdfIZ1Ez0HhPl5o,330417
38
38
  flywheel/api/reports_api.py,sha256=6WW5CroopwNrw6GBE0_R34stBWbyqUXgRoyiHkAAZE4,36251
39
39
  flywheel/api/resolve_api.py,sha256=6yuXytZnhpFBPz0x5TN1B57jtRn9kuSqth6WtXWSYaw,11603
40
40
  flywheel/api/roles_api.py,sha256=2FQCdRZgg-bZDVP8Nv4JOb4UYMbGcX0Cstc3x6Cff1Y,20698
41
- flywheel/api/sessions_api.py,sha256=zABPloe1ISaKyGVC8SqzUyrw-YHm4zaeJ-6j2W08_y0,223474
41
+ flywheel/api/sessions_api.py,sha256=pr7qtOFyoE1bSRcMuGB_ApaWASkVn3v_ko5ZzYz-VnM,223477
42
42
  flywheel/api/site_api.py,sha256=6skw2iKO5JAO9AVaTJZCuusBaECbuFDMiiPKE8tIHHY,57379
43
- flywheel/api/subjects_api.py,sha256=oRhSwCZFr8bXeCw3JNkpHVlI_1JrGWIMA09KwNX4Ae8,227081
43
+ flywheel/api/subjects_api.py,sha256=5dckrcHqcGmUmEj2BENfoSZmKqTx5NDOIuhxaQYa544,227084
44
44
  flywheel/api/tree_api.py,sha256=NZ_1QbOIhPodTqx82nmgPvLfxCB7NwmTf7oPgzxgEbI,12337
45
45
  flywheel/api/uids_api.py,sha256=mFStWRKbdgymR_FYDHq8EsOiTfDKjz2XEcWT1XQUYtQ,4946
46
46
  flywheel/api/upload_api.py,sha256=emrzAmurhGb-uBI7Ewckbn5DyP9LBkfn6OI1zxhKnb8,38540
47
- flywheel/api/users_api.py,sha256=-eAz4T9PEhvG0OEOOos3BXLGxs7C8tcI8IjKXknNGEA,85396
47
+ flywheel/api/users_api.py,sha256=t6CgyTGKdr-ojDi_wW3Zpgw3XhiUE7shDXxKLK3__ZY,85397
48
48
  flywheel/api/views_api.py,sha256=ZbPYA_sOQ9qnOjkOUeioV0v08VPbsuuOnMP3EBySEVY,44375
49
- flywheel/models/__init__.py,sha256=HJ5TYbWkv6zYpc-ItYE0zf_f0LTZ9aun5Q2qqvY7MeY,42855
49
+ flywheel/models/__init__.py,sha256=U6yoHgQpLezdyESPz8F-wGzRyl4FGUjtupQtr36A67k,42855
50
50
  flywheel/models/access_level.py,sha256=zSgO2gWTTSo-p1v49ilz3Q5ZizZ7DESA5P6Ur67fgX0,575
51
51
  flywheel/models/access_permission.py,sha256=-IYmy-yb8zecmGZx7iE0bhZW7PvuWpm3zAHr2FwCyLI,5336
52
52
  flywheel/models/access_permission_output.py,sha256=faCnvyMYozmSVSlLFYMdJw84hQc3ugxx7LH2JzBfnoE,5202
@@ -206,7 +206,7 @@ flywheel/models/data_view_zip_filter_spec.py,sha256=60_tTjdrqUw0d-QLl4pHjKMFu1Ya
206
206
  flywheel/models/default_flywheel_role.py,sha256=-AjXC5pWQXf7OmTDAWcGvaadd49ofv4HFuLdpj9iJKU,583
207
207
  flywheel/models/deid_log_skip_reason.py,sha256=KtHQjBrER4gEk8vXd1cjvuJDQ7LajqwgHuDgWDAMs74,615
208
208
  flywheel/models/deleted_file.py,sha256=VrwLIAu1316bVu6gk41czolPCmZnvmUm_4AdKSh9iM0,11647
209
- flywheel/models/deleted_result.py,sha256=CY_hRxhWw7ZItqHYfKrRa6qVBjxCq-wyCTZDJTmGZAo,4514
209
+ flywheel/models/deleted_result.py,sha256=3FAnMsLOoT20mch6-wNRSvFOkEJbetm45_oR7CHEorE,5584
210
210
  flywheel/models/deprecated_action.py,sha256=iuUrtOSr6r2iW-s6dK7YVFf3e-QfGySLE9CmO2sdbD8,602
211
211
  flywheel/models/destination_container_type.py,sha256=o8DNvTa4ccx3bC4S8YCJjyhYy3L9D_NpZhjePz6x4Zk,618
212
212
  flywheel/models/device.py,sha256=fsDxVAPsaUqjFhe8Q_VKnHc3fiZsMXBxyjxCtLWUuo4,10649
@@ -438,7 +438,7 @@ flywheel/models/master_subject_code_dob_input.py,sha256=IWAPS_rR-i7MP2c-yUafiz3M
438
438
  flywheel/models/master_subject_code_input.py,sha256=z1iYzK7jJsXxMBaJnwHLd7O7q1LiRx2cUGFrpiuH6bM,8106
439
439
  flywheel/models/master_subject_code_output.py,sha256=ejSXHL6KRfh2L94bsiFrIjxNHfuct9QLXmFi-dT9tV0,4620
440
440
  flywheel/models/matched_acquisition_output.py,sha256=whZ27xZHKL2ngnQKWI4cxQHcvwtTXFH9zg2NL-hi5Sk,14157
441
- flywheel/models/mixins.py,sha256=-lRQWitOoWqcdhTP1uX09sYaxAvaDdIW3AuT49PABMw,28580
441
+ flywheel/models/mixins.py,sha256=wWgiSEr1dYnXNBhdcKBYStxgI0T74DTnE-l9rKliNk8,29608
442
442
  flywheel/models/ml_set_filter.py,sha256=s7BWp9gbVv8waLmSmJQT5treYHp1y4YT_LL-BqB3_nM,5176
443
443
  flywheel/models/ml_type.py,sha256=lNe0BiH5vu_USajw5HMMa8sKdfjk9ZYWjZlL5yFlX10,602
444
444
  flywheel/models/modality.py,sha256=gsPmZbGNbXLONNqBdS--JKTla9rhljoToxVP17vUX0s,6690
@@ -478,7 +478,7 @@ flywheel/models/project_aet_input.py,sha256=W8mzPlcJyc2KKgLCe05TpQdHmpy3mdJG8-eA
478
478
  flywheel/models/project_catalog_list_output.py,sha256=xeqKCNfqOmT4ms_6DQjqR5Uz6moTSAH_tkZbM6X9am8,542
479
479
  flywheel/models/project_contact.py,sha256=WiCoHfnq62ThKUss5hRCGhVGHv7YI_q5Un2OdqZlZIw,5266
480
480
  flywheel/models/project_container_output.py,sha256=ucS7vWJhh_ApVHqVZH5KNiVEkRpu2pVFdcMeS6sTTdE,1485
481
- flywheel/models/project_copy_filter.py,sha256=wF2beP3GOFdtNdYoweMXHCaiYQ_uEdPJyrwH9j_cVD4,7970
481
+ flywheel/models/project_copy_filter.py,sha256=HqXwcoPqf7pH3_HXVtLA3X5xYqZrIvxT2uOvXbJ3OUw,9006
482
482
  flywheel/models/project_copy_input.py,sha256=BR1AMjA3M77BNI1eBy2pm7bLOV-wlzFvWpuvnlAUfoU,6030
483
483
  flywheel/models/project_copy_output.py,sha256=VBNZPXCni0fMWoSj1s_hBhHkyZkMBXgF3hJnLTcI5jo,5939
484
484
  flywheel/models/project_copy_status.py,sha256=I1UPavaYxo3NDsLOn0-Y7ZlZ-N0Ml7II04NJ7WIZtZ4,657
@@ -703,11 +703,11 @@ flywheel/models/viewer_app_input.py,sha256=J20oeUcH8dkS1zo012sSA0aQazg4rP_RmEqyq
703
703
  flywheel/models/viewer_app_type.py,sha256=J7J_3DXnQz19w1D7AmCEWs8VFK0jTLBa2nCPG5Gzn2E,569
704
704
  flywheel/models/virus_scan.py,sha256=ZZJEwnQ7nkubX4qmQq-qkUPgJp-AvdYqAukxnDRrTp4,4553
705
705
  flywheel/models/virus_scan_state.py,sha256=zBmk7x3ZoDhEozIeD-Gw7CEkU7yWYKFMFXklLdTeu3s,602
706
- flywheel/models/work_in_progress_features.py,sha256=SwsL3txqMpIBJKrv52ljFshaPkxURMaRE9UCzfjfCDc,4912
706
+ flywheel/models/work_in_progress_features.py,sha256=dZ_cJTztcU3wPIUKptwZzb7hdv9mo27wXfWgolkJa1k,3944
707
707
  flywheel/models/zipfile_info.py,sha256=8ivqs0rTQaiC8KirTaK_WqSGkLvCndI_58dylOBKwa4,5243
708
708
  flywheel/models/zipfile_member_info.py,sha256=zAg9wRUeYXbz6bvXdo4xYFHtvv9eRSCjvyaTrQ3zvN4,6346
709
- flywheel_sdk-19.5.0rc3.dist-info/LICENSE.txt,sha256=F_Wp8b8L-2vc2xxcRr402gN1gg-2y0p2oG8aSj3hdMA,1057
710
- flywheel_sdk-19.5.0rc3.dist-info/METADATA,sha256=BnLuhUwNEM1WJWtlxeBPGPs1GFl_X22eiGZYI2ZE8kc,958
711
- flywheel_sdk-19.5.0rc3.dist-info/WHEEL,sha256=pxeNX5JdtCe58PUSYP9upmc7jdRPgvT0Gm9kb1SHlVw,109
712
- flywheel_sdk-19.5.0rc3.dist-info/top_level.txt,sha256=BQ1fXyhiudo2To7zMNcPOOGa6qtZuhx0V_I7CO-vU6w,9
713
- flywheel_sdk-19.5.0rc3.dist-info/RECORD,,
709
+ flywheel_sdk-20.0.0rc0.dist-info/LICENSE.txt,sha256=F_Wp8b8L-2vc2xxcRr402gN1gg-2y0p2oG8aSj3hdMA,1057
710
+ flywheel_sdk-20.0.0rc0.dist-info/METADATA,sha256=g7Q63SpbeIrWZTRuvgcTwTHn0KkDppyVL3bYOuAya1Q,1097
711
+ flywheel_sdk-20.0.0rc0.dist-info/WHEEL,sha256=9Hm2OB-j1QcCUq9Jguht7ayGIIZBRTdOXD1qg9cCgPM,109
712
+ flywheel_sdk-20.0.0rc0.dist-info/top_level.txt,sha256=BQ1fXyhiudo2To7zMNcPOOGa6qtZuhx0V_I7CO-vU6w,9
713
+ flywheel_sdk-20.0.0rc0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.6.0)
2
+ Generator: setuptools (75.8.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py2-none-any
5
5
  Tag: py3-none-any