accsyn-python-api 2.2.1__tar.gz → 3.0.1__tar.gz
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.
- accsyn-python-api-3.0.1/.gitignore +9 -0
- accsyn-python-api-3.0.1/PKG-INFO +56 -0
- {accsyn-python-api-2.2.1 → accsyn-python-api-3.0.1}/README.md +7 -0
- {accsyn-python-api-2.2.1 → accsyn-python-api-3.0.1}/doc/release_notes.rst +14 -0
- {accsyn-python-api-2.2.1 → accsyn-python-api-3.0.1}/setup.py +1 -1
- {accsyn-python-api-2.2.1 → accsyn-python-api-3.0.1}/source/accsyn_api/session.py +182 -277
- accsyn-python-api-3.0.1/source/accsyn_python_api.egg-info/PKG-INFO +56 -0
- accsyn-python-api-2.2.1/.gitignore +0 -1
- accsyn-python-api-2.2.1/PKG-INFO +0 -50
- accsyn-python-api-2.2.1/source/accsyn_python_api.egg-info/PKG-INFO +0 -50
- {accsyn-python-api-2.2.1 → accsyn-python-api-3.0.1}/.github/workflows/github-actions-black.yml +0 -0
- {accsyn-python-api-2.2.1 → accsyn-python-api-3.0.1}/.pre-commit-config.yaml +0 -0
- {accsyn-python-api-2.2.1 → accsyn-python-api-3.0.1}/.readthedocs.yaml +0 -0
- {accsyn-python-api-2.2.1 → accsyn-python-api-3.0.1}/doc/_static/accsyn.css +0 -0
- {accsyn-python-api-2.2.1 → accsyn-python-api-3.0.1}/doc/api_reference/index.rst +0 -0
- {accsyn-python-api-2.2.1 → accsyn-python-api-3.0.1}/doc/api_reference/session.rst +0 -0
- {accsyn-python-api-2.2.1 → accsyn-python-api-3.0.1}/doc/clients.rst +0 -0
- {accsyn-python-api-2.2.1 → accsyn-python-api-3.0.1}/doc/conf.py +0 -0
- {accsyn-python-api-2.2.1 → accsyn-python-api-3.0.1}/doc/datatypes.rst +0 -0
- {accsyn-python-api-2.2.1 → accsyn-python-api-3.0.1}/doc/file.rst +0 -0
- {accsyn-python-api-2.2.1 → accsyn-python-api-3.0.1}/doc/glossary.rst +0 -0
- {accsyn-python-api-2.2.1 → accsyn-python-api-3.0.1}/doc/index.rst +0 -0
- {accsyn-python-api-2.2.1 → accsyn-python-api-3.0.1}/doc/installing.rst +0 -0
- {accsyn-python-api-2.2.1 → accsyn-python-api-3.0.1}/doc/introduction.rst +0 -0
- {accsyn-python-api-2.2.1 → accsyn-python-api-3.0.1}/doc/jobs.rst +0 -0
- {accsyn-python-api-2.2.1 → accsyn-python-api-3.0.1}/doc/misc.rst +0 -0
- {accsyn-python-api-2.2.1 → accsyn-python-api-3.0.1}/doc/publish.rst +0 -0
- {accsyn-python-api-2.2.1 → accsyn-python-api-3.0.1}/doc/queues.rst +0 -0
- {accsyn-python-api-2.2.1 → accsyn-python-api-3.0.1}/doc/render.rst +0 -0
- {accsyn-python-api-2.2.1 → accsyn-python-api-3.0.1}/doc/requirements.txt +0 -0
- {accsyn-python-api-2.2.1 → accsyn-python-api-3.0.1}/doc/shares.rst +0 -0
- {accsyn-python-api-2.2.1 → accsyn-python-api-3.0.1}/doc/users.rst +0 -0
- {accsyn-python-api-2.2.1 → accsyn-python-api-3.0.1}/doc/using.rst +0 -0
- {accsyn-python-api-2.2.1 → accsyn-python-api-3.0.1}/pyproject.toml +0 -0
- {accsyn-python-api-2.2.1 → accsyn-python-api-3.0.1}/readthedocs.yaml +0 -0
- {accsyn-python-api-2.2.1 → accsyn-python-api-3.0.1}/setup.cfg +0 -0
- {accsyn-python-api-2.2.1 → accsyn-python-api-3.0.1}/source/accsyn_api/__init__.py +0 -0
- {accsyn-python-api-2.2.1 → accsyn-python-api-3.0.1}/source/accsyn_api/_version.py +0 -0
- {accsyn-python-api-2.2.1 → accsyn-python-api-3.0.1}/source/accsyn_python_api.egg-info/SOURCES.txt +0 -0
- {accsyn-python-api-2.2.1 → accsyn-python-api-3.0.1}/source/accsyn_python_api.egg-info/dependency_links.txt +0 -0
- {accsyn-python-api-2.2.1 → accsyn-python-api-3.0.1}/source/accsyn_python_api.egg-info/requires.txt +0 -0
- {accsyn-python-api-2.2.1 → accsyn-python-api-3.0.1}/source/accsyn_python_api.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: accsyn-python-api
|
|
3
|
+
Version: 3.0.1
|
|
4
|
+
Summary: A Python API for accsyn programmable fast and secure data delivery software
|
|
5
|
+
Home-page: https://github.com/accsyn/accsyn-python-api.git
|
|
6
|
+
Author: Henrik Norin
|
|
7
|
+
Author-email: henrik.norin@accsyn.com
|
|
8
|
+
License: Apache License (2.0)
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Requires-Python: >=2.7.9, <4.0
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
|
|
15
|
+
# accsyn-python-api
|
|
16
|
+
Official accsyn fast film delivery Python API
|
|
17
|
+
|
|
18
|
+
Complete Python API reference can be found [here](https://support.accsyn.com/python-api).
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
Changelog:
|
|
22
|
+
----------
|
|
23
|
+
|
|
24
|
+
See doc/release_notes.rst
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
Documentation:
|
|
28
|
+
--------------
|
|
29
|
+
|
|
30
|
+
[https://accsyn-python-api.readthedocs.io/en/latest](https://accsyn-python-api.readthedocs.io/en/latest)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
Building:
|
|
34
|
+
---------
|
|
35
|
+
|
|
36
|
+
To build the documentation locally, run:
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
cd doc
|
|
40
|
+
pip install -r requirements.txt
|
|
41
|
+
python -m sphinx -T -E -b html -d _build/doctrees -D language=en . ../dist/doc
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Deploying:
|
|
45
|
+
----------
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
python setup.py sdist bdist_wheel
|
|
49
|
+
twine upload --verbose --username accsyn dist/*
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Henrik Norin, HDR AB, 2023
|
|
53
|
+
accsyn(r) - secure data delivery and workflow sync
|
|
54
|
+
https://accsyn.com
|
|
55
|
+
https://support.accsyn.com
|
|
56
|
+
|
|
@@ -27,6 +27,13 @@ To build the documentation locally, run:
|
|
|
27
27
|
python -m sphinx -T -E -b html -d _build/doctrees -D language=en . ../dist/doc
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
+
Deploying:
|
|
31
|
+
----------
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
python setup.py sdist bdist_wheel
|
|
35
|
+
twine upload --verbose --username accsyn dist/*
|
|
36
|
+
```
|
|
30
37
|
|
|
31
38
|
Henrik Norin, HDR AB, 2023
|
|
32
39
|
accsyn(r) - secure data delivery and workflow sync
|
|
@@ -13,6 +13,20 @@ Release Notes
|
|
|
13
13
|
|
|
14
14
|
`https://support.accsyn.com <https://support.accsyn.com>`_.
|
|
15
15
|
|
|
16
|
+
.. release:: 3.0.1
|
|
17
|
+
:date: 2024-11-18
|
|
18
|
+
|
|
19
|
+
.. change:: fix
|
|
20
|
+
|
|
21
|
+
* Bug fixes.
|
|
22
|
+
|
|
23
|
+
.. release:: 3.0.0
|
|
24
|
+
:date: 2024-11-17
|
|
25
|
+
|
|
26
|
+
.. change:: feat
|
|
27
|
+
|
|
28
|
+
* Compliance with new accsyn v3 workspaces.
|
|
29
|
+
* Removed pwd and session key authentication, accsyn v3 only support API key basic auth.
|
|
16
30
|
|
|
17
31
|
.. release:: 2.2.0
|
|
18
32
|
:date: 2023-11-09
|
|
@@ -43,15 +43,16 @@ logging.basicConfig(
|
|
|
43
43
|
datefmt="%Y-%m-%d %H:%M:%S",
|
|
44
44
|
)
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
|
|
46
|
+
ACCSYN_BACKEND_DOMAIN = "accsyn.com"
|
|
47
|
+
ACCSYN_BACKEND_MASTER_HOSTNAME = "master.{}".format(ACCSYN_BACKEND_DOMAIN)
|
|
48
48
|
ACCSYN_PORT = 443
|
|
49
49
|
DEFAULT_EVENT_PAYLOAD_COMPRESS_SIZE_TRESHOLD = 100 * 1024 # Compress event data payloads above 100k
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
CLEARANCE_SUPPORT = "support"
|
|
52
52
|
CLEARANCE_ADMIN = "admin"
|
|
53
53
|
CLEARANCE_EMPLOYEE = "employee"
|
|
54
|
-
|
|
54
|
+
CLEARANCE_STANDARD = "standard"
|
|
55
|
+
CLEARANCE_CLIENT = CLEARANCE_STANDARD # BWCOMP
|
|
55
56
|
CLEARANCE_NONE = "none"
|
|
56
57
|
|
|
57
58
|
|
|
@@ -65,7 +66,7 @@ class JSONEncoder(json.JSONEncoder):
|
|
|
65
66
|
|
|
66
67
|
|
|
67
68
|
class JSONDecoder(json.JSONDecoder):
|
|
68
|
-
"""JSON
|
|
69
|
+
"""JSON deserialize."""
|
|
69
70
|
|
|
70
71
|
def decode(self, json_string):
|
|
71
72
|
json_data = json.loads(json_string)
|
|
@@ -116,6 +117,8 @@ class Session(object):
|
|
|
116
117
|
DEFAULT_CONNECT_TIMEOUT = 10 # Wait 10 seconds for connection
|
|
117
118
|
DEFAULT_TIMEOUT = 2 * 60 # Wait 2 minutes for response
|
|
118
119
|
|
|
120
|
+
_p_logfile = None
|
|
121
|
+
|
|
119
122
|
@property
|
|
120
123
|
def username(self):
|
|
121
124
|
return self._username
|
|
@@ -133,8 +136,6 @@ class Session(object):
|
|
|
133
136
|
domain=None,
|
|
134
137
|
username=None,
|
|
135
138
|
api_key=None,
|
|
136
|
-
pwd=None,
|
|
137
|
-
session_key=None,
|
|
138
139
|
hostname=None,
|
|
139
140
|
port=None,
|
|
140
141
|
proxy=None,
|
|
@@ -151,8 +152,6 @@ class Session(object):
|
|
|
151
152
|
:param domain: The accsyn domain (or read from ACCSYN_DOMAIN environment variable)
|
|
152
153
|
:param username: The accsyn username (or read from ACCSYN_API_USER environment variable)
|
|
153
154
|
:param api_key: The secret API key for authentication (or read from ACCSYN_API_KEY environment variable)
|
|
154
|
-
:param pwd: (No API key supplied) The secret password for authentication
|
|
155
|
-
:param session_key: (No API key or password supplied) The secret session key to use for authentication.
|
|
156
155
|
:param hostname: Override hostname/IP to connect to.
|
|
157
156
|
:param port: Override default port 443.
|
|
158
157
|
:param proxy: The proxy settings (or read from ACCSYN_PROXY environment variable).
|
|
@@ -165,81 +164,70 @@ class Session(object):
|
|
|
165
164
|
"""
|
|
166
165
|
# Generate a session ID
|
|
167
166
|
self.__version__ = __version__
|
|
168
|
-
self._pwd = None
|
|
169
167
|
self._session_id = str(uuid.uuid4())
|
|
170
|
-
self.
|
|
171
|
-
self.
|
|
168
|
+
self._uid = None
|
|
169
|
+
self._api_key = None
|
|
172
170
|
self._be_verbose = verbose
|
|
173
171
|
self._pretty_json = pretty_json
|
|
174
172
|
self._proxy = proxy
|
|
175
173
|
self._dev = dev is True or os.environ.get('ACCSYN_DEV', 'false') in ['true', '1']
|
|
176
174
|
Session._p_logfile = path_logfile
|
|
177
|
-
self.
|
|
175
|
+
self._role = CLEARANCE_NONE
|
|
178
176
|
self._verbose("Creating accsyn Python API session (v{})".format(__version__))
|
|
179
177
|
for key in os.environ:
|
|
180
178
|
if key.startswith("FILMHUB_"):
|
|
181
179
|
Session._warning('Found old FilmHUB product environment variable "{}", ' "please migrate!".format(key))
|
|
182
|
-
if domain
|
|
183
|
-
|
|
184
|
-
"ACCSYN_DOMAIN"
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
):
|
|
189
|
-
raise accsynException(
|
|
190
|
-
"Please supply your accsyn domain/organization or set " "ACCSYN_DOMAIN environment!"
|
|
180
|
+
if not domain:
|
|
181
|
+
domain = (
|
|
182
|
+
os.environ["ACCSYN_DOMAIN"]
|
|
183
|
+
if "ACCSYN_DOMAIN" in os.environ
|
|
184
|
+
else os.environ.get(
|
|
185
|
+
"ACCSYN_ORG",
|
|
191
186
|
)
|
|
192
|
-
self._domain = domain or (
|
|
193
|
-
os.environ["ACCSYN_DOMAIN"]
|
|
194
|
-
if "ACCSYN_DOMAIN" in os.environ
|
|
195
|
-
else os.environ.get(
|
|
196
|
-
"ACCSYN_ORG",
|
|
197
|
-
os.environ.get("FILMHUB_DOMAIN", os.environ.get("FILMHUB_ORG")),
|
|
198
187
|
)
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
188
|
+
if not domain:
|
|
189
|
+
raise AccsynException(
|
|
190
|
+
"Please supply your accsyn domain/organization or set " "ACCSYN_DOMAIN environment!"
|
|
191
|
+
)
|
|
192
|
+
if not username:
|
|
193
|
+
username = os.environ.get("ACCSYN_API_USER")
|
|
194
|
+
if not username:
|
|
195
|
+
if not ("ACCSYN_API_USER" in os.environ):
|
|
196
|
+
raise AccsynException(
|
|
197
|
+
"Please supply your accsyn user name (E-mail) or set ACCSYN_API_USER environment!"
|
|
204
198
|
)
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
self._api_key = os.environ.get("ACCSYN_API_KEY") or os.environ.get("FILMHUB_API_KEY")
|
|
210
|
-
if len(session_key or "") == 0:
|
|
211
|
-
session_key = os.environ.get("ACCSYN_SESSION_KEY")
|
|
212
|
-
if 0 < len(session_key or ""):
|
|
213
|
-
# User has a session key for us to use, validate at login, store it
|
|
214
|
-
# temporarily
|
|
215
|
-
self._session_key_provided = session_key
|
|
216
|
-
elif len(self._api_key or "") == 0:
|
|
217
|
-
if 0 < len(pwd or ""):
|
|
218
|
-
# Store it temporarily
|
|
219
|
-
self._pwd = pwd
|
|
220
|
-
else:
|
|
221
|
-
raise accsynException("Please supply your accsyn API KEY or set ACCSYN_API_KEY " "environment!")
|
|
199
|
+
if not api_key:
|
|
200
|
+
api_key = os.environ.get("ACCSYN_API_KEY")
|
|
201
|
+
if not api_key:
|
|
202
|
+
raise AccsynException("Please supply your accsyn API KEY or set ACCSYN_API_KEY environment!")
|
|
222
203
|
self._hostname = hostname
|
|
223
|
-
self._port = port
|
|
204
|
+
self._port = port
|
|
224
205
|
self._timeout = timeout or Session.DEFAULT_TIMEOUT
|
|
225
206
|
self._connect_timeout = connect_timeout or Session.DEFAULT_CONNECT_TIMEOUT
|
|
226
207
|
if self._hostname is None:
|
|
227
208
|
if self._dev:
|
|
228
|
-
self._hostname = "
|
|
209
|
+
self._hostname = "127.0.0.1"
|
|
229
210
|
else:
|
|
230
211
|
# Get domain
|
|
231
|
-
|
|
232
|
-
"
|
|
233
|
-
|
|
234
|
-
"
|
|
235
|
-
{"
|
|
212
|
+
response = self._rest(
|
|
213
|
+
"GET",
|
|
214
|
+
ACCSYN_BACKEND_MASTER_HOSTNAME,
|
|
215
|
+
"J3PKTtDvolDMBtTy6AFGA",
|
|
216
|
+
{"ident": domain},
|
|
236
217
|
)
|
|
237
218
|
# Store hostname
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
219
|
+
if "message" in response:
|
|
220
|
+
raise AccsynException(response["message"])
|
|
221
|
+
result = response.get('result', {})
|
|
222
|
+
assert "hostname" in result, "No API endpoint hostname were provided for us!"
|
|
223
|
+
self._hostname = result["hostname"]
|
|
224
|
+
if self._port is None:
|
|
225
|
+
self._port = result["port"]
|
|
226
|
+
if self._port is None:
|
|
227
|
+
self._port = ACCSYN_PORT if not self._dev else 8181
|
|
228
|
+
self._domain = domain
|
|
229
|
+
self._username = username
|
|
230
|
+
self._api_key = api_key
|
|
243
231
|
self._last_message = None
|
|
244
232
|
self.login()
|
|
245
233
|
|
|
@@ -286,66 +274,32 @@ class Session(object):
|
|
|
286
274
|
"""Retreive error message from last API call."""
|
|
287
275
|
return self._last_message
|
|
288
276
|
|
|
289
|
-
def login(self
|
|
277
|
+
def login(self):
|
|
290
278
|
"""Attempt to login to accsyn and get a session."""
|
|
291
279
|
# TODO: Load session key from safe disk storage/key chain?
|
|
292
|
-
assert self.
|
|
293
|
-
|
|
294
|
-
|
|
280
|
+
assert self._uid is None, "Already logged in!"
|
|
281
|
+
payload = dict(
|
|
282
|
+
session_id=self._session_id,
|
|
283
|
+
)
|
|
284
|
+
headers = {
|
|
285
|
+
"Authorization": "basic {}:{}".format(
|
|
286
|
+
Session._base64_encode(self._username),
|
|
287
|
+
Session._base64_encode(self._api_key),
|
|
288
|
+
),
|
|
289
|
+
"X-Accsyn-Workspace": self._domain,
|
|
295
290
|
}
|
|
296
|
-
|
|
297
|
-
d["session_key_reuse"] = revive_session_key
|
|
298
|
-
if self._api_key:
|
|
299
|
-
headers = {
|
|
300
|
-
"Authorization": "ASCredentials {}".format(
|
|
301
|
-
Session._base64_encode(
|
|
302
|
-
'{"domain":"%s","username":"%s","api_key":"%s"}'
|
|
303
|
-
% (self._domain, self._username, self._api_key)
|
|
304
|
-
)
|
|
305
|
-
)
|
|
306
|
-
}
|
|
307
|
-
elif self._pwd:
|
|
308
|
-
headers = {
|
|
309
|
-
"Authorization": "ASCredentials {}".format(
|
|
310
|
-
Session._base64_encode(
|
|
311
|
-
'{"domain":"%s","username":"%s","pwd":"%s"}'
|
|
312
|
-
% (
|
|
313
|
-
self._domain,
|
|
314
|
-
self._username,
|
|
315
|
-
Session._base64_encode(self._pwd),
|
|
316
|
-
)
|
|
317
|
-
)
|
|
318
|
-
)
|
|
319
|
-
}
|
|
320
|
-
self._pwd = None # Forget this now
|
|
321
|
-
elif self._session_key_provided:
|
|
322
|
-
headers = {
|
|
323
|
-
"Authorization": "ASSession {}".format(
|
|
324
|
-
Session._base64_encode(
|
|
325
|
-
'{"domain":"%s","username":"%s","session_key":"%s"}'
|
|
326
|
-
% (
|
|
327
|
-
self._domain,
|
|
328
|
-
self._username,
|
|
329
|
-
self._session_key_provided,
|
|
330
|
-
)
|
|
331
|
-
)
|
|
332
|
-
)
|
|
333
|
-
}
|
|
334
|
-
self._session_key_provided = None # Forget this now
|
|
335
|
-
else:
|
|
336
|
-
raise Exception("No means of authentication available!")
|
|
337
|
-
result = self._rest(
|
|
291
|
+
response = self._rest(
|
|
338
292
|
"PUT",
|
|
339
293
|
self._hostname,
|
|
340
|
-
"/
|
|
341
|
-
|
|
294
|
+
"/api/login",
|
|
295
|
+
payload,
|
|
342
296
|
headers=headers,
|
|
343
297
|
port=self._port,
|
|
344
298
|
)
|
|
345
299
|
# Store session key
|
|
346
|
-
assert "
|
|
347
|
-
|
|
348
|
-
self.
|
|
300
|
+
assert "result" in response, "No result were provided!"
|
|
301
|
+
result = response["result"]
|
|
302
|
+
self._role = result["role"]
|
|
349
303
|
self._uid = result["id"]
|
|
350
304
|
return True
|
|
351
305
|
|
|
@@ -373,7 +327,7 @@ class Session(object):
|
|
|
373
327
|
if os.path.exists(data):
|
|
374
328
|
data = json.load(open(data, "r"))
|
|
375
329
|
else:
|
|
376
|
-
raise
|
|
330
|
+
raise AccsynException(
|
|
377
331
|
"Cannot build JSON payload data, not a valid JSON " "string or path to a JSON file!"
|
|
378
332
|
)
|
|
379
333
|
else:
|
|
@@ -998,7 +952,7 @@ class Session(object):
|
|
|
998
952
|
:return: Processed publish data, see documentation.
|
|
999
953
|
"""
|
|
1000
954
|
if data is None or not isinstance(data, list):
|
|
1001
|
-
raise
|
|
955
|
+
raise AccsynException("None or empty data supplied!")
|
|
1002
956
|
|
|
1003
957
|
# Check entries, calculate size
|
|
1004
958
|
def recursive_get_size(files):
|
|
@@ -1046,19 +1000,6 @@ class Session(object):
|
|
|
1046
1000
|
"""Fetch API key, by default disabled in backend."""
|
|
1047
1001
|
return self._event("GET", "user/api_key", {})["api_key"]
|
|
1048
1002
|
|
|
1049
|
-
def get_session_key(self):
|
|
1050
|
-
"""Return the current API session key."""
|
|
1051
|
-
return self._session_key
|
|
1052
|
-
|
|
1053
|
-
def generate_session_key(self, lifetime=None):
|
|
1054
|
-
"""Generate a new API session key, with the given *lifetime*."""
|
|
1055
|
-
return self._event(
|
|
1056
|
-
"POST",
|
|
1057
|
-
"user/generate_session_key",
|
|
1058
|
-
{"lifetime": lifetime},
|
|
1059
|
-
query=self._username,
|
|
1060
|
-
)["session_key"]
|
|
1061
|
-
|
|
1062
1003
|
def gui_is_running(self):
|
|
1063
1004
|
"""
|
|
1064
1005
|
Check if a GUI is running on the same machine (hostname match) and with same username.
|
|
@@ -1168,7 +1109,7 @@ class Session(object):
|
|
|
1168
1109
|
if port is None:
|
|
1169
1110
|
port = self._port or ACCSYN_PORT
|
|
1170
1111
|
if hostname is None:
|
|
1171
|
-
hostname = "
|
|
1112
|
+
hostname = "{}.{}".format(self._domain, ACCSYN_BACKEND_DOMAIN)
|
|
1172
1113
|
# Proxy set?
|
|
1173
1114
|
proxy_type = None
|
|
1174
1115
|
proxy_hostname = None
|
|
@@ -1196,12 +1137,12 @@ class Session(object):
|
|
|
1196
1137
|
if proxy_type == "accsyn":
|
|
1197
1138
|
if proxy_port == -1:
|
|
1198
1139
|
proxy_port = 80
|
|
1199
|
-
self._verbose("Using accsyn proxy @
|
|
1140
|
+
self._verbose("Using accsyn proxy @ {}:{}".format(proxy_hostname, proxy_port))
|
|
1200
1141
|
hostname = proxy_hostname
|
|
1201
1142
|
port = proxy_port
|
|
1202
1143
|
elif proxy_type in ["socks", "socks5"]:
|
|
1203
1144
|
try:
|
|
1204
|
-
self._verbose("Using SOCKS5 proxy @
|
|
1145
|
+
self._verbose("Using SOCKS5 proxy @ {}:{}".format(proxy_hostname, proxy_port))
|
|
1205
1146
|
import socks
|
|
1206
1147
|
|
|
1207
1148
|
socks.setdefaultproxy(socks.PROXY_TYPE_SOCKS5, proxy_hostname, proxy_port)
|
|
@@ -1210,8 +1151,8 @@ class Session(object):
|
|
|
1210
1151
|
Session._warning('Python lacks SOCKS support, please install "pysocks" and' " try again...")
|
|
1211
1152
|
raise ie
|
|
1212
1153
|
elif proxy_type is not None:
|
|
1213
|
-
raise
|
|
1214
|
-
url = "http{}://{}:{}/api/
|
|
1154
|
+
raise AccsynException('Unknown proxy type "{}"!'.format(proxy_type))
|
|
1155
|
+
url = "http{}://{}:{}/api/v3{}".format(
|
|
1215
1156
|
"s" if ssl else "",
|
|
1216
1157
|
hostname,
|
|
1217
1158
|
port,
|
|
@@ -1224,161 +1165,125 @@ class Session(object):
|
|
|
1224
1165
|
# Wait 10s to reach machine, 2min for it to send back data
|
|
1225
1166
|
CONNECT_TO, READ_TO = (self.connect_timeout, timeout)
|
|
1226
1167
|
r = None
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1168
|
+
retval = None
|
|
1169
|
+
|
|
1170
|
+
headers_effective = dict()
|
|
1171
|
+
if headers:
|
|
1172
|
+
headers_effective = copy.deepcopy(headers)
|
|
1173
|
+
elif self._api_key:
|
|
1174
|
+
headers_effective = {
|
|
1175
|
+
"Authorization": "basic {}:{}".format(
|
|
1176
|
+
Session._base64_encode(self._username),
|
|
1177
|
+
Session._base64_encode(self._api_key)
|
|
1178
|
+
),
|
|
1179
|
+
"X-Accsyn-Workspace": self._domain,
|
|
1180
|
+
}
|
|
1181
|
+
headers_effective["X-Accsyn-Device"] = "PythonAPI v%s @ %s %s(%s)" % (
|
|
1182
|
+
__version__,
|
|
1183
|
+
sys.platform,
|
|
1184
|
+
Session.get_hostname(),
|
|
1185
|
+
os.name,
|
|
1186
|
+
)
|
|
1187
|
+
if 3 <= sys.version_info.major:
|
|
1188
|
+
t_start = int(round(time.time() * 1000))
|
|
1189
|
+
else:
|
|
1190
|
+
t_start = long(round(time.time() * 1000))
|
|
1191
|
+
try:
|
|
1192
|
+
self._verbose(
|
|
1193
|
+
"REST %s %s, data: %s"
|
|
1194
|
+
% (
|
|
1195
|
+
method,
|
|
1196
|
+
url,
|
|
1197
|
+
data if not self._pretty_json else Session.str(data),
|
|
1198
|
+
)
|
|
1246
1199
|
)
|
|
1247
|
-
if
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
% (
|
|
1255
|
-
method,
|
|
1256
|
-
url,
|
|
1257
|
-
data if not self._pretty_json else Session.str(data),
|
|
1258
|
-
)
|
|
1200
|
+
if method.lower() == "get":
|
|
1201
|
+
r = requests.get(
|
|
1202
|
+
url,
|
|
1203
|
+
params=Session._url_quote(data),
|
|
1204
|
+
timeout=(CONNECT_TO, READ_TO),
|
|
1205
|
+
verify=False,
|
|
1206
|
+
headers=headers_effective,
|
|
1259
1207
|
)
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
)
|
|
1268
|
-
elif method.lower() == "put":
|
|
1269
|
-
r = requests.put(
|
|
1270
|
-
url,
|
|
1271
|
-
Session._safe_dumps(data),
|
|
1272
|
-
timeout=(CONNECT_TO, READ_TO),
|
|
1273
|
-
verify=False,
|
|
1274
|
-
headers=headers_effective,
|
|
1275
|
-
)
|
|
1276
|
-
elif method.lower() == "post":
|
|
1277
|
-
r = requests.post(
|
|
1278
|
-
url,
|
|
1279
|
-
Session._safe_dumps(data),
|
|
1280
|
-
timeout=(CONNECT_TO, READ_TO),
|
|
1281
|
-
verify=False,
|
|
1282
|
-
headers=headers_effective,
|
|
1283
|
-
)
|
|
1284
|
-
elif method.lower() == "delete":
|
|
1285
|
-
r = requests.delete(
|
|
1286
|
-
url,
|
|
1287
|
-
params=Session._url_quote(data),
|
|
1288
|
-
timeout=(CONNECT_TO, READ_TO),
|
|
1289
|
-
verify=False,
|
|
1290
|
-
headers=headers_effective,
|
|
1291
|
-
)
|
|
1292
|
-
t_end = int(round(time.time() * 1000))
|
|
1293
|
-
# break
|
|
1294
|
-
except BaseException:
|
|
1295
|
-
# if timeout <= 0:
|
|
1296
|
-
raise accsynException(
|
|
1297
|
-
"Could not reach {}:{}! Make sure cloud server({}) can"
|
|
1298
|
-
" be reached from you location and no firewall is "
|
|
1299
|
-
"blocking outgoing TCP traffic at port {}. "
|
|
1300
|
-
"Details: {}".format(
|
|
1301
|
-
hostname,
|
|
1302
|
-
port,
|
|
1303
|
-
hostname,
|
|
1304
|
-
port,
|
|
1305
|
-
traceback.format_exc() if not quiet else "(quiet)",
|
|
1306
|
-
)
|
|
1208
|
+
elif method.lower() == "put":
|
|
1209
|
+
r = requests.put(
|
|
1210
|
+
url,
|
|
1211
|
+
Session._safe_dumps(data),
|
|
1212
|
+
timeout=(CONNECT_TO, READ_TO),
|
|
1213
|
+
verify=False,
|
|
1214
|
+
headers=headers_effective,
|
|
1307
1215
|
)
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
method,
|
|
1334
|
-
Session._obscure_dict_string(
|
|
1335
|
-
Session._safely_printable(
|
|
1336
|
-
str(retval) if not self._pretty_json else Session.str(retval)
|
|
1337
|
-
).replace("'", '"')
|
|
1338
|
-
),
|
|
1339
|
-
t_start - t_end + 1,
|
|
1340
|
-
)
|
|
1341
|
-
)
|
|
1342
|
-
do_retry = False
|
|
1343
|
-
if not retval.get("message") is None:
|
|
1344
|
-
# Something went wrong
|
|
1345
|
-
if retval.get("session_expired") is True:
|
|
1346
|
-
if self._api_key is not None:
|
|
1347
|
-
# We should be able to get a new session and retry
|
|
1348
|
-
revive_session_key = self._session_key
|
|
1349
|
-
self._session_key = None
|
|
1350
|
-
self.login(revive_session_key=revive_session_key)
|
|
1351
|
-
self._info('Authenticated using API KEY and reused expired session...')
|
|
1352
|
-
do_retry = True
|
|
1353
|
-
if not do_retry:
|
|
1354
|
-
self._last_message = retval["message"]
|
|
1355
|
-
if not do_retry:
|
|
1356
|
-
break
|
|
1357
|
-
except BaseException:
|
|
1358
|
-
sys.stderr.write(traceback.format_exc())
|
|
1359
|
-
message = 'The {}:{}/{} REST {} {} operation failed! Details: '
|
|
1360
|
-
'{} {}'.format(
|
|
1216
|
+
elif method.lower() == "post":
|
|
1217
|
+
r = requests.post(
|
|
1218
|
+
url,
|
|
1219
|
+
Session._safe_dumps(data),
|
|
1220
|
+
timeout=(CONNECT_TO, READ_TO),
|
|
1221
|
+
verify=False,
|
|
1222
|
+
headers=headers_effective,
|
|
1223
|
+
)
|
|
1224
|
+
elif method.lower() == "delete":
|
|
1225
|
+
r = requests.delete(
|
|
1226
|
+
url,
|
|
1227
|
+
params=Session._url_quote(data),
|
|
1228
|
+
timeout=(CONNECT_TO, READ_TO),
|
|
1229
|
+
verify=False,
|
|
1230
|
+
headers=headers_effective,
|
|
1231
|
+
)
|
|
1232
|
+
t_end = int(round(time.time() * 1000))
|
|
1233
|
+
# break
|
|
1234
|
+
except BaseException:
|
|
1235
|
+
# if timeout <= 0:
|
|
1236
|
+
raise AccsynException(
|
|
1237
|
+
"Could not reach {}:{}! Make sure backend({}) can"
|
|
1238
|
+
" be reached from you location and no firewall is "
|
|
1239
|
+
"blocking outgoing TCP traffic at port {}. "
|
|
1240
|
+
"Details: {}".format(
|
|
1361
1241
|
hostname,
|
|
1362
1242
|
port,
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1243
|
+
hostname,
|
|
1244
|
+
port,
|
|
1245
|
+
traceback.format_exc() if not quiet else "(quiet)",
|
|
1246
|
+
)
|
|
1247
|
+
)
|
|
1248
|
+
try:
|
|
1249
|
+
retval = json.loads(r.text, cls=JSONDecoder)
|
|
1250
|
+
if not quiet:
|
|
1251
|
+
self._verbose(
|
|
1252
|
+
"{}/{} REST {} result: {} (~{}ms)".format(
|
|
1253
|
+
hostname,
|
|
1254
|
+
uri,
|
|
1255
|
+
method,
|
|
1256
|
+
Session._obscure_dict_string(
|
|
1257
|
+
Session._safely_printable(
|
|
1258
|
+
str(retval) if not self._pretty_json else Session.str(retval)
|
|
1259
|
+
).replace("'", '"')
|
|
1260
|
+
),
|
|
1261
|
+
t_start - t_end + 1,
|
|
1262
|
+
)
|
|
1368
1263
|
)
|
|
1369
|
-
|
|
1370
|
-
|
|
1264
|
+
except BaseException:
|
|
1265
|
+
sys.stderr.write(traceback.format_exc())
|
|
1266
|
+
message = 'The {} REST {} {} operation failed! Details: {} {}'.format(
|
|
1267
|
+
url,
|
|
1268
|
+
method,
|
|
1269
|
+
Session._obscure_dict_string(Session._safely_printable(str(data)).replace("'", '"')),
|
|
1270
|
+
r.text,
|
|
1271
|
+
traceback.format_exc(),
|
|
1272
|
+
)
|
|
1273
|
+
Session._warning(message)
|
|
1274
|
+
raise AccsynException(message)
|
|
1275
|
+
|
|
1371
1276
|
if "exception" in retval:
|
|
1372
1277
|
message = "{} caused an exception! Please contact {} admin for more"
|
|
1373
1278
|
" further support.".format(uri, self._domain)
|
|
1374
1279
|
Session._warning(message)
|
|
1375
|
-
if self.
|
|
1280
|
+
if self._role in [CLEARANCE_ADMIN, CLEARANCE_SUPPORT]:
|
|
1376
1281
|
Session._warning(retval["exception"])
|
|
1377
|
-
raise
|
|
1282
|
+
raise AccsynException(message)
|
|
1378
1283
|
elif "message" in retval:
|
|
1379
1284
|
message_effective = retval.get("message_hr") or retval["message"]
|
|
1380
1285
|
Session._warning(message_effective)
|
|
1381
|
-
raise
|
|
1286
|
+
raise AccsynException(message_effective)
|
|
1382
1287
|
return retval
|
|
1383
1288
|
|
|
1384
1289
|
# REST get
|
|
@@ -1395,7 +1300,7 @@ class Session(object):
|
|
|
1395
1300
|
quiet=False,
|
|
1396
1301
|
):
|
|
1397
1302
|
"""Utility; Construct an event and send using REST to accsyn backend."""
|
|
1398
|
-
assert self.
|
|
1303
|
+
assert self._uid, "Login before posting event!"
|
|
1399
1304
|
event = {
|
|
1400
1305
|
"audience": "api",
|
|
1401
1306
|
"domain": self._domain,
|
|
@@ -1608,6 +1513,6 @@ class Session(object):
|
|
|
1608
1513
|
return binascii.b2a_base64(s)
|
|
1609
1514
|
|
|
1610
1515
|
|
|
1611
|
-
class
|
|
1516
|
+
class AccsynException(Exception):
|
|
1612
1517
|
def __init__(self, message):
|
|
1613
|
-
super(
|
|
1518
|
+
super(AccsynException, self).__init__(message)
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: accsyn-python-api
|
|
3
|
+
Version: 3.0.1
|
|
4
|
+
Summary: A Python API for accsyn programmable fast and secure data delivery software
|
|
5
|
+
Home-page: https://github.com/accsyn/accsyn-python-api.git
|
|
6
|
+
Author: Henrik Norin
|
|
7
|
+
Author-email: henrik.norin@accsyn.com
|
|
8
|
+
License: Apache License (2.0)
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Requires-Python: >=2.7.9, <4.0
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
|
|
15
|
+
# accsyn-python-api
|
|
16
|
+
Official accsyn fast film delivery Python API
|
|
17
|
+
|
|
18
|
+
Complete Python API reference can be found [here](https://support.accsyn.com/python-api).
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
Changelog:
|
|
22
|
+
----------
|
|
23
|
+
|
|
24
|
+
See doc/release_notes.rst
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
Documentation:
|
|
28
|
+
--------------
|
|
29
|
+
|
|
30
|
+
[https://accsyn-python-api.readthedocs.io/en/latest](https://accsyn-python-api.readthedocs.io/en/latest)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
Building:
|
|
34
|
+
---------
|
|
35
|
+
|
|
36
|
+
To build the documentation locally, run:
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
cd doc
|
|
40
|
+
pip install -r requirements.txt
|
|
41
|
+
python -m sphinx -T -E -b html -d _build/doctrees -D language=en . ../dist/doc
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Deploying:
|
|
45
|
+
----------
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
python setup.py sdist bdist_wheel
|
|
49
|
+
twine upload --verbose --username accsyn dist/*
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Henrik Norin, HDR AB, 2023
|
|
53
|
+
accsyn(r) - secure data delivery and workflow sync
|
|
54
|
+
https://accsyn.com
|
|
55
|
+
https://support.accsyn.com
|
|
56
|
+
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
*.pyc
|
accsyn-python-api-2.2.1/PKG-INFO
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.1
|
|
2
|
-
Name: accsyn-python-api
|
|
3
|
-
Version: 2.2.1
|
|
4
|
-
Summary: A Python API for accsyn programmable fast and secure data delivery software
|
|
5
|
-
Home-page: https://github.com/accsyn/accsyn-python-api.git
|
|
6
|
-
Author: Henrik Norin
|
|
7
|
-
Author-email: henrik.norin@accsyn.com
|
|
8
|
-
License: Apache License (2.0)
|
|
9
|
-
Description: # accsyn-python-api
|
|
10
|
-
Official accsyn fast film delivery Python API
|
|
11
|
-
|
|
12
|
-
Complete Python API reference can be found [here](https://support.accsyn.com/python-api).
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
Changelog:
|
|
16
|
-
----------
|
|
17
|
-
|
|
18
|
-
See doc/release_notes.rst
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
Documentation:
|
|
22
|
-
--------------
|
|
23
|
-
|
|
24
|
-
[https://accsyn-python-api.readthedocs.io/en/latest](https://accsyn-python-api.readthedocs.io/en/latest)
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
Building:
|
|
28
|
-
---------
|
|
29
|
-
|
|
30
|
-
To build the documentation locally, run:
|
|
31
|
-
|
|
32
|
-
```
|
|
33
|
-
cd doc
|
|
34
|
-
pip install -r requirements.txt
|
|
35
|
-
python -m sphinx -T -E -b html -d _build/doctrees -D language=en . ../dist/doc
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
Henrik Norin, HDR AB, 2023
|
|
40
|
-
accsyn(r) - secure data delivery and workflow sync
|
|
41
|
-
https://accsyn.com
|
|
42
|
-
https://support.accsyn.com
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
Platform: UNKNOWN
|
|
46
|
-
Classifier: Programming Language :: Python :: 3
|
|
47
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
48
|
-
Classifier: Operating System :: OS Independent
|
|
49
|
-
Requires-Python: >=2.7.9, <4.0
|
|
50
|
-
Description-Content-Type: text/markdown
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.1
|
|
2
|
-
Name: accsyn-python-api
|
|
3
|
-
Version: 2.2.1
|
|
4
|
-
Summary: A Python API for accsyn programmable fast and secure data delivery software
|
|
5
|
-
Home-page: https://github.com/accsyn/accsyn-python-api.git
|
|
6
|
-
Author: Henrik Norin
|
|
7
|
-
Author-email: henrik.norin@accsyn.com
|
|
8
|
-
License: Apache License (2.0)
|
|
9
|
-
Description: # accsyn-python-api
|
|
10
|
-
Official accsyn fast film delivery Python API
|
|
11
|
-
|
|
12
|
-
Complete Python API reference can be found [here](https://support.accsyn.com/python-api).
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
Changelog:
|
|
16
|
-
----------
|
|
17
|
-
|
|
18
|
-
See doc/release_notes.rst
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
Documentation:
|
|
22
|
-
--------------
|
|
23
|
-
|
|
24
|
-
[https://accsyn-python-api.readthedocs.io/en/latest](https://accsyn-python-api.readthedocs.io/en/latest)
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
Building:
|
|
28
|
-
---------
|
|
29
|
-
|
|
30
|
-
To build the documentation locally, run:
|
|
31
|
-
|
|
32
|
-
```
|
|
33
|
-
cd doc
|
|
34
|
-
pip install -r requirements.txt
|
|
35
|
-
python -m sphinx -T -E -b html -d _build/doctrees -D language=en . ../dist/doc
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
Henrik Norin, HDR AB, 2023
|
|
40
|
-
accsyn(r) - secure data delivery and workflow sync
|
|
41
|
-
https://accsyn.com
|
|
42
|
-
https://support.accsyn.com
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
Platform: UNKNOWN
|
|
46
|
-
Classifier: Programming Language :: Python :: 3
|
|
47
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
48
|
-
Classifier: Operating System :: OS Independent
|
|
49
|
-
Requires-Python: >=2.7.9, <4.0
|
|
50
|
-
Description-Content-Type: text/markdown
|
{accsyn-python-api-2.2.1 → accsyn-python-api-3.0.1}/.github/workflows/github-actions-black.yml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{accsyn-python-api-2.2.1 → accsyn-python-api-3.0.1}/source/accsyn_python_api.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{accsyn-python-api-2.2.1 → accsyn-python-api-3.0.1}/source/accsyn_python_api.egg-info/requires.txt
RENAMED
|
File without changes
|
{accsyn-python-api-2.2.1 → accsyn-python-api-3.0.1}/source/accsyn_python_api.egg-info/top_level.txt
RENAMED
|
File without changes
|