files-com 1.6.208__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.
Potentially problematic release.
This version of files-com might be problematic. Click here for more details.
- README.md +758 -0
- _VERSION +1 -0
- files_com-1.6.208.dist-info/METADATA +770 -0
- files_com-1.6.208.dist-info/RECORD +126 -0
- files_com-1.6.208.dist-info/WHEEL +5 -0
- files_com-1.6.208.dist-info/licenses/LICENSE +21 -0
- files_com-1.6.208.dist-info/top_level.txt +1 -0
- files_sdk/__init__.py +309 -0
- files_sdk/api.py +63 -0
- files_sdk/api_client.py +336 -0
- files_sdk/error.py +2981 -0
- files_sdk/list_obj.py +42 -0
- files_sdk/models/__init__.py +119 -0
- files_sdk/models/account_line_item.py +51 -0
- files_sdk/models/action.py +49 -0
- files_sdk/models/action_notification_export.py +153 -0
- files_sdk/models/action_notification_export_result.py +88 -0
- files_sdk/models/agent_push_update.py +44 -0
- files_sdk/models/api_key.py +318 -0
- files_sdk/models/api_request_log.py +105 -0
- files_sdk/models/app.py +89 -0
- files_sdk/models/as2_incoming_message.py +117 -0
- files_sdk/models/as2_outgoing_message.py +113 -0
- files_sdk/models/as2_partner.py +415 -0
- files_sdk/models/as2_station.py +282 -0
- files_sdk/models/auto.py +36 -0
- files_sdk/models/automation.py +823 -0
- files_sdk/models/automation_log.py +94 -0
- files_sdk/models/automation_run.py +112 -0
- files_sdk/models/bandwidth_snapshot.py +91 -0
- files_sdk/models/behavior.py +340 -0
- files_sdk/models/bundle.py +686 -0
- files_sdk/models/bundle_action.py +93 -0
- files_sdk/models/bundle_download.py +94 -0
- files_sdk/models/bundle_notification.py +252 -0
- files_sdk/models/bundle_path.py +37 -0
- files_sdk/models/bundle_recipient.py +133 -0
- files_sdk/models/bundle_registration.py +82 -0
- files_sdk/models/child_site_management_policy.py +278 -0
- files_sdk/models/clickwrap.py +268 -0
- files_sdk/models/dns_record.py +59 -0
- files_sdk/models/email_incoming_message.py +102 -0
- files_sdk/models/email_log.py +84 -0
- files_sdk/models/errors.py +37 -0
- files_sdk/models/exavault_api_request_log.py +102 -0
- files_sdk/models/external_event.py +148 -0
- files_sdk/models/file.py +851 -0
- files_sdk/models/file_action.py +39 -0
- files_sdk/models/file_comment.py +191 -0
- files_sdk/models/file_comment_reaction.py +125 -0
- files_sdk/models/file_migration.py +69 -0
- files_sdk/models/file_migration_log.py +88 -0
- files_sdk/models/file_upload_part.py +54 -0
- files_sdk/models/folder.py +186 -0
- files_sdk/models/form_field.py +43 -0
- files_sdk/models/form_field_set.py +265 -0
- files_sdk/models/ftp_action_log.py +104 -0
- files_sdk/models/gpg_key.py +333 -0
- files_sdk/models/group.py +338 -0
- files_sdk/models/group_user.py +235 -0
- files_sdk/models/history.py +236 -0
- files_sdk/models/history_export.py +238 -0
- files_sdk/models/history_export_result.py +98 -0
- files_sdk/models/holiday_region.py +58 -0
- files_sdk/models/image.py +37 -0
- files_sdk/models/inbound_s3_log.py +95 -0
- files_sdk/models/inbox_recipient.py +124 -0
- files_sdk/models/inbox_registration.py +79 -0
- files_sdk/models/inbox_upload.py +80 -0
- files_sdk/models/invoice.py +91 -0
- files_sdk/models/invoice_line_item.py +51 -0
- files_sdk/models/ip_address.py +119 -0
- files_sdk/models/key_lifecycle_rule.py +243 -0
- files_sdk/models/lock.py +174 -0
- files_sdk/models/message.py +244 -0
- files_sdk/models/message_comment.py +223 -0
- files_sdk/models/message_comment_reaction.py +181 -0
- files_sdk/models/message_reaction.py +170 -0
- files_sdk/models/notification.py +451 -0
- files_sdk/models/outbound_connection_log.py +105 -0
- files_sdk/models/partner.py +307 -0
- files_sdk/models/payment.py +91 -0
- files_sdk/models/payment_line_item.py +42 -0
- files_sdk/models/permission.py +190 -0
- files_sdk/models/preview.py +40 -0
- files_sdk/models/priority.py +63 -0
- files_sdk/models/project.py +205 -0
- files_sdk/models/public_hosting_request_log.py +101 -0
- files_sdk/models/public_ip_address.py +42 -0
- files_sdk/models/public_key.py +269 -0
- files_sdk/models/remote_bandwidth_snapshot.py +91 -0
- files_sdk/models/remote_mount_backend.py +438 -0
- files_sdk/models/remote_server.py +1854 -0
- files_sdk/models/remote_server_configuration_file.py +73 -0
- files_sdk/models/remote_server_credential.py +855 -0
- files_sdk/models/request.py +184 -0
- files_sdk/models/restore.py +142 -0
- files_sdk/models/scim_log.py +88 -0
- files_sdk/models/session.py +100 -0
- files_sdk/models/settings_change.py +71 -0
- files_sdk/models/sftp_action_log.py +108 -0
- files_sdk/models/sftp_host_key.py +215 -0
- files_sdk/models/share_group.py +228 -0
- files_sdk/models/share_group_member.py +41 -0
- files_sdk/models/siem_http_destination.py +1074 -0
- files_sdk/models/site.py +1289 -0
- files_sdk/models/snapshot.py +255 -0
- files_sdk/models/sso_strategy.py +168 -0
- files_sdk/models/status.py +42 -0
- files_sdk/models/style.py +152 -0
- files_sdk/models/sync.py +588 -0
- files_sdk/models/sync_log.py +86 -0
- files_sdk/models/sync_run.py +124 -0
- files_sdk/models/usage_by_top_level_dir.py +41 -0
- files_sdk/models/usage_daily_snapshot.py +93 -0
- files_sdk/models/usage_snapshot.py +73 -0
- files_sdk/models/user.py +1232 -0
- files_sdk/models/user_cipher_use.py +91 -0
- files_sdk/models/user_lifecycle_rule.py +355 -0
- files_sdk/models/user_request.py +166 -0
- files_sdk/models/user_sftp_client_use.py +68 -0
- files_sdk/models/web_dav_action_log.py +104 -0
- files_sdk/models/webhook_test.py +116 -0
- files_sdk/models/workspace.py +202 -0
- files_sdk/path_util.py +42 -0
- files_sdk/util.py +34 -0
files_sdk/api_client.py
ADDED
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import random
|
|
3
|
+
import requests
|
|
4
|
+
import time
|
|
5
|
+
from urllib.parse import urljoin
|
|
6
|
+
|
|
7
|
+
import files_sdk
|
|
8
|
+
from files_sdk.error import (
|
|
9
|
+
APIConnectionError,
|
|
10
|
+
APIError,
|
|
11
|
+
AuthenticationError,
|
|
12
|
+
Error,
|
|
13
|
+
)
|
|
14
|
+
import files_sdk.util as util
|
|
15
|
+
from requests_toolbelt.adapters import source
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ApiClient:
|
|
19
|
+
"""
|
|
20
|
+
The Files.com API Client.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
def __init__(self):
|
|
24
|
+
pass
|
|
25
|
+
|
|
26
|
+
self.session = requests.Session()
|
|
27
|
+
|
|
28
|
+
if (
|
|
29
|
+
files_sdk.get_source_ip() is not None
|
|
30
|
+
and self.session.adapters.get(files_sdk.base_url, None) is None
|
|
31
|
+
):
|
|
32
|
+
self.session.mount(
|
|
33
|
+
files_sdk.base_url,
|
|
34
|
+
source.SourceAddressAdapter(files_sdk.get_source_ip()),
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
def send_remote_request(self, method, url, headers=None, body=None):
|
|
38
|
+
if headers is None:
|
|
39
|
+
headers = {}
|
|
40
|
+
req = requests.Request(method, url=url, headers=headers, data=body)
|
|
41
|
+
|
|
42
|
+
response = self.execute_request_with_auto_retry(req)
|
|
43
|
+
return response
|
|
44
|
+
|
|
45
|
+
def send_request(
|
|
46
|
+
self,
|
|
47
|
+
method,
|
|
48
|
+
path,
|
|
49
|
+
api_key=None,
|
|
50
|
+
session_id=None,
|
|
51
|
+
language=None,
|
|
52
|
+
headers=None,
|
|
53
|
+
params=None,
|
|
54
|
+
):
|
|
55
|
+
if headers is None:
|
|
56
|
+
headers = {}
|
|
57
|
+
full_path = files_sdk.base_path + path
|
|
58
|
+
url = urljoin(files_sdk.base_url, full_path)
|
|
59
|
+
|
|
60
|
+
if files_sdk.session_id:
|
|
61
|
+
session_id = files_sdk.session_id
|
|
62
|
+
|
|
63
|
+
if session_id and session_id != "":
|
|
64
|
+
self.check_session_id(session_id)
|
|
65
|
+
elif not path.startswith("/sessions"):
|
|
66
|
+
if not api_key:
|
|
67
|
+
api_key = files_sdk.get_api_key()
|
|
68
|
+
self.check_api_key(api_key)
|
|
69
|
+
|
|
70
|
+
if files_sdk.language:
|
|
71
|
+
language = files_sdk.language
|
|
72
|
+
|
|
73
|
+
headers = {
|
|
74
|
+
**headers,
|
|
75
|
+
**self.request_headers(api_key, session_id, language),
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
data = None
|
|
79
|
+
query_params = None
|
|
80
|
+
if params:
|
|
81
|
+
if method in ["GET", "HEAD", "DELETE"]:
|
|
82
|
+
data = None
|
|
83
|
+
_params = {}
|
|
84
|
+
for k, v in params.items():
|
|
85
|
+
if isinstance(v, dict):
|
|
86
|
+
for k2, v2 in v.items():
|
|
87
|
+
_params[f"{k}[{k2}]"] = v2
|
|
88
|
+
else:
|
|
89
|
+
_params[k] = v
|
|
90
|
+
query_params = _params
|
|
91
|
+
else:
|
|
92
|
+
data = params
|
|
93
|
+
query_params = None
|
|
94
|
+
|
|
95
|
+
req = requests.Request(
|
|
96
|
+
method, url=url, headers=headers, params=query_params, json=data
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
response = self.execute_request_with_auto_retry(req)
|
|
100
|
+
|
|
101
|
+
if response.status_code != 204:
|
|
102
|
+
try:
|
|
103
|
+
response.data = response.json()
|
|
104
|
+
except json.decoder.JSONDecodeError:
|
|
105
|
+
if response.status_code == 403:
|
|
106
|
+
raise AuthenticationError(
|
|
107
|
+
response.content,
|
|
108
|
+
http_status=response.status_code,
|
|
109
|
+
headers=response.headers,
|
|
110
|
+
)
|
|
111
|
+
if response.status_code >= 500:
|
|
112
|
+
raise APIConnectionError(
|
|
113
|
+
response.content,
|
|
114
|
+
http_status=response.status_code,
|
|
115
|
+
headers=response.headers,
|
|
116
|
+
)
|
|
117
|
+
raise self.general_api_error(
|
|
118
|
+
response, "Error parsing JSON response"
|
|
119
|
+
)
|
|
120
|
+
else:
|
|
121
|
+
response.data = None
|
|
122
|
+
|
|
123
|
+
return response
|
|
124
|
+
|
|
125
|
+
def stream_download(self, uri, io, is_string_io=False):
|
|
126
|
+
# NOTE the stream=True parameter below
|
|
127
|
+
with requests.get(uri, stream=True) as r:
|
|
128
|
+
r.raise_for_status() # TODO check this later
|
|
129
|
+
for chunk in r.iter_content(
|
|
130
|
+
chunk_size=8192, decode_unicode=is_string_io
|
|
131
|
+
):
|
|
132
|
+
# If you have chunk encoded response uncomment if
|
|
133
|
+
# and set chunk_size parameter to None.
|
|
134
|
+
# if chunk:
|
|
135
|
+
io.write(chunk)
|
|
136
|
+
|
|
137
|
+
def execute_request_with_auto_retry(
|
|
138
|
+
self, request, skip_body_logging=False
|
|
139
|
+
):
|
|
140
|
+
for try_num in range(0, files_sdk.max_network_retries):
|
|
141
|
+
response = None
|
|
142
|
+
request_start = time.time()
|
|
143
|
+
try:
|
|
144
|
+
self.log_request(request, try_num)
|
|
145
|
+
prepped = request.prepare()
|
|
146
|
+
settings = self.session.merge_environment_settings(
|
|
147
|
+
prepped.url, {}, None, None, None
|
|
148
|
+
)
|
|
149
|
+
response = self.session.send(
|
|
150
|
+
prepped,
|
|
151
|
+
timeout=(files_sdk.open_timeout, files_sdk.read_timeout),
|
|
152
|
+
**settings,
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
self.log_response(
|
|
156
|
+
request,
|
|
157
|
+
request_start,
|
|
158
|
+
response.status_code,
|
|
159
|
+
response.content,
|
|
160
|
+
)
|
|
161
|
+
response.raise_for_status()
|
|
162
|
+
return response
|
|
163
|
+
except Exception as e:
|
|
164
|
+
if response is not None:
|
|
165
|
+
self.log_response(
|
|
166
|
+
request,
|
|
167
|
+
request_start,
|
|
168
|
+
response.status_code,
|
|
169
|
+
response.content,
|
|
170
|
+
)
|
|
171
|
+
else:
|
|
172
|
+
self.log_response_error(request, request_start, e)
|
|
173
|
+
|
|
174
|
+
if try_num + 1 == files_sdk.max_network_retries:
|
|
175
|
+
if response is not None:
|
|
176
|
+
self.handle_error_response(response)
|
|
177
|
+
else:
|
|
178
|
+
raise self.handle_network_error(
|
|
179
|
+
e, request, try_num
|
|
180
|
+
) from None
|
|
181
|
+
raise
|
|
182
|
+
|
|
183
|
+
time.sleep(ApiClient.sleep_time(try_num))
|
|
184
|
+
raise APIConnectionError(
|
|
185
|
+
f"Request failed after {files_sdk.max_network_retries} attempts"
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
@staticmethod
|
|
189
|
+
def sleep_time(num_retries):
|
|
190
|
+
sleep_seconds = min(
|
|
191
|
+
files_sdk.initial_network_retry_delay * (2 ** (num_retries - 1)),
|
|
192
|
+
files_sdk.max_network_retry_delay,
|
|
193
|
+
)
|
|
194
|
+
sleep_seconds *= 0.5 * (1 + random.random())
|
|
195
|
+
return max(files_sdk.initial_network_retry_delay, sleep_seconds)
|
|
196
|
+
|
|
197
|
+
def request_headers(self, api_key, session_id, language):
|
|
198
|
+
user_agent = "Files.com Python SDK v{version}".format(
|
|
199
|
+
version=files_sdk.version
|
|
200
|
+
)
|
|
201
|
+
# user_agent += " " + format_app_info(Files.app_info) unless Files.app_info.nil?
|
|
202
|
+
|
|
203
|
+
headers = {
|
|
204
|
+
"User-Agent": user_agent,
|
|
205
|
+
"Content-Type": "application/json",
|
|
206
|
+
}
|
|
207
|
+
if api_key:
|
|
208
|
+
headers["X-FilesAPI-Key"] = api_key
|
|
209
|
+
if session_id:
|
|
210
|
+
headers["X-FilesAPI-Auth"] = session_id
|
|
211
|
+
if language:
|
|
212
|
+
headers["Accept-Language"] = language
|
|
213
|
+
|
|
214
|
+
return headers
|
|
215
|
+
|
|
216
|
+
def check_api_key(self, api_key):
|
|
217
|
+
if not api_key:
|
|
218
|
+
raise AuthenticationError(
|
|
219
|
+
"No Files.com API key provided. "
|
|
220
|
+
'Set your API key using "Files.api_key = <API-KEY>". '
|
|
221
|
+
"You can generate API keys from the Files.com's web interface. "
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
if not api_key.isalnum():
|
|
225
|
+
raise AuthenticationError(
|
|
226
|
+
"Your API key is invalid (it contains whitespace)"
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
def check_session_id(self, session_id):
|
|
230
|
+
if not session_id.isalnum():
|
|
231
|
+
raise AuthenticationError(
|
|
232
|
+
"The provided Session ID is invalid (it contains whitespace)"
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
def general_api_error(self, response, extra_info=None):
|
|
236
|
+
msg = "Unexpected response object from API: {body} (HTTP response code was {status})".format(
|
|
237
|
+
body=repr(response.content), status=response.status_code
|
|
238
|
+
)
|
|
239
|
+
if extra_info is not None:
|
|
240
|
+
msg += " Additional Information: {}".format(extra_info)
|
|
241
|
+
return APIError(msg)
|
|
242
|
+
|
|
243
|
+
def handle_error_response(self, response):
|
|
244
|
+
error_data = None
|
|
245
|
+
|
|
246
|
+
try:
|
|
247
|
+
response.data = response.json()
|
|
248
|
+
except json.decoder.JSONDecodeError:
|
|
249
|
+
response.data = ""
|
|
250
|
+
|
|
251
|
+
try:
|
|
252
|
+
if "error" in response.data:
|
|
253
|
+
error_data = response.data["error"]
|
|
254
|
+
elif "errors" in response.data:
|
|
255
|
+
error_data = response.data["errors"]
|
|
256
|
+
if isinstance(error_data, list) and len(error_data) > 0:
|
|
257
|
+
error_data = error_data[0]
|
|
258
|
+
if isinstance(error_data, str):
|
|
259
|
+
error_data = {"message": error_data}
|
|
260
|
+
|
|
261
|
+
if not error_data:
|
|
262
|
+
raise Error("Unknown error")
|
|
263
|
+
except Error:
|
|
264
|
+
raise self.general_api_error(response, "Unknown error")
|
|
265
|
+
|
|
266
|
+
error = self.specific_api_error(response, error_data)
|
|
267
|
+
|
|
268
|
+
error.response = response
|
|
269
|
+
raise error
|
|
270
|
+
|
|
271
|
+
def specific_api_error(self, response, error_data):
|
|
272
|
+
import files_sdk.error
|
|
273
|
+
|
|
274
|
+
util.log_error(
|
|
275
|
+
"API error", status=response.status_code, error_message=error_data
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
opts = {
|
|
279
|
+
"http_body": response.content,
|
|
280
|
+
"headers": response.headers,
|
|
281
|
+
"http_status": response.status_code,
|
|
282
|
+
"json_body": response.data,
|
|
283
|
+
"code": error_data.get("code", response.status_code),
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
error_type = response.data["type"].split("/")[-1]
|
|
287
|
+
error_class_name = (
|
|
288
|
+
"".join(list(map(str.capitalize, error_type.split("-")))) + "Error"
|
|
289
|
+
)
|
|
290
|
+
try:
|
|
291
|
+
return getattr(files_sdk.error, error_class_name)(
|
|
292
|
+
error_data["message"], **opts
|
|
293
|
+
)
|
|
294
|
+
except AttributeError:
|
|
295
|
+
return APIError(error_data["message"], **opts)
|
|
296
|
+
|
|
297
|
+
def handle_network_error(self, error, request, num_retries):
|
|
298
|
+
util.log_error("Network error", error_message=error)
|
|
299
|
+
msg = "Could not connect to Files.com at URL {}. Please check your internet connection and try again. If this problem persists, you should check Files.com's service status at https://status.files.com, or contact your primary account representative.".format(
|
|
300
|
+
files_sdk.base_url
|
|
301
|
+
)
|
|
302
|
+
if num_retries > 0:
|
|
303
|
+
msg += " Request was retried {} times.".format(num_retries)
|
|
304
|
+
msg += "\n\n(Network error: {})".format(error)
|
|
305
|
+
|
|
306
|
+
return APIConnectionError(msg)
|
|
307
|
+
|
|
308
|
+
def log_request(self, request, num_retries):
|
|
309
|
+
util.log_info(
|
|
310
|
+
"Request",
|
|
311
|
+
method=request.method,
|
|
312
|
+
num_retries=num_retries,
|
|
313
|
+
url=request.url,
|
|
314
|
+
)
|
|
315
|
+
util.log_debug(
|
|
316
|
+
"Request details", body=request.data, query_params=request.params
|
|
317
|
+
)
|
|
318
|
+
|
|
319
|
+
def log_response(self, request, request_start, status, body):
|
|
320
|
+
util.log_info(
|
|
321
|
+
"Response",
|
|
322
|
+
elapsed=(time.time() - request_start),
|
|
323
|
+
method=request.method,
|
|
324
|
+
url=request.url,
|
|
325
|
+
status=status,
|
|
326
|
+
)
|
|
327
|
+
util.log_debug("Response details", body=body)
|
|
328
|
+
|
|
329
|
+
def log_response_error(self, request, request_start, error):
|
|
330
|
+
util.log_error(
|
|
331
|
+
"Error",
|
|
332
|
+
elapsed=(time.time() - request_start),
|
|
333
|
+
error_message=error,
|
|
334
|
+
method=request.method,
|
|
335
|
+
url=request.url,
|
|
336
|
+
)
|