SmartlingApiSdk 3.1.7__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.
- SmartlingApiSdk-3.1.7.dist-info/METADATA +11 -0
- SmartlingApiSdk-3.1.7.dist-info/RECORD +54 -0
- SmartlingApiSdk-3.1.7.dist-info/WHEEL +5 -0
- SmartlingApiSdk-3.1.7.dist-info/top_level.txt +4 -0
- smartlingApiSdk/ApiResponse.py +67 -0
- smartlingApiSdk/ApiV2.py +73 -0
- smartlingApiSdk/AuthClient.py +78 -0
- smartlingApiSdk/Constants.py +78 -0
- smartlingApiSdk/Credentials.py +74 -0
- smartlingApiSdk/FileApiBase.py +128 -0
- smartlingApiSdk/FileApiV2.py +187 -0
- smartlingApiSdk/HttpClient.py +155 -0
- smartlingApiSdk/Logger.py +64 -0
- smartlingApiSdk/MultipartPostHandler.py +127 -0
- smartlingApiSdk/ObsoleteApiV1.py +94 -0
- smartlingApiSdk/ObsoleteSmartlingFileApi.py +108 -0
- smartlingApiSdk/ProjectsApiV2.py +52 -0
- smartlingApiSdk/ProxySettings.py +27 -0
- smartlingApiSdk/Settings.py +29 -0
- smartlingApiSdk/SmartlingDirective.py +38 -0
- smartlingApiSdk/SmartlingFileApiV2.py +189 -0
- smartlingApiSdk/SmartlingProjectsApiV2.py +65 -0
- smartlingApiSdk/UploadData.py +49 -0
- smartlingApiSdk/UrlV2Helper.py +71 -0
- smartlingApiSdk/__init__.py +23 -0
- smartlingApiSdk/api/AccountProjectsApi.py +120 -0
- smartlingApiSdk/api/ContextApi.py +250 -0
- smartlingApiSdk/api/EstimatesApi.py +201 -0
- smartlingApiSdk/api/FilesApi.py +343 -0
- smartlingApiSdk/api/JobBatchesV2Api.py +134 -0
- smartlingApiSdk/api/JobsApi.py +612 -0
- smartlingApiSdk/api/StringsApi.py +110 -0
- smartlingApiSdk/api/TagsApi.py +142 -0
- smartlingApiSdk/api/__init__.py +4 -0
- smartlingApiSdk/api/patch_nose.py +24 -0
- smartlingApiSdk/example/AccountProjectsExample.py +197 -0
- smartlingApiSdk/example/ContextExample.py +347 -0
- smartlingApiSdk/example/EstimatesExample.py +298 -0
- smartlingApiSdk/example/FilesExample.py +498 -0
- smartlingApiSdk/example/FilesSimpleExample.py +101 -0
- smartlingApiSdk/example/JobBatchesV2Example.py +186 -0
- smartlingApiSdk/example/JobsExample.py +672 -0
- smartlingApiSdk/example/MultipleAccountsExample.py +74 -0
- smartlingApiSdk/example/MultipleProjectsExample.py +118 -0
- smartlingApiSdk/example/StringsExample.py +224 -0
- smartlingApiSdk/example/TagsExample.py +214 -0
- smartlingApiSdk/example/__init__.py +4 -0
- smartlingApiSdk/resources/ctx_api_test.png +0 -0
- smartlingApiSdk/resources/java.properties +10 -0
- smartlingApiSdk/resources/javaUTF16.properties +0 -0
- smartlingApiSdk/resources/test.csv +1 -0
- smartlingApiSdk/resources/test_import.xml +5 -0
- smartlingApiSdk/resources/test_import_es.xml +5 -0
- smartlingApiSdk/version.py +20 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: SmartlingApiSdk
|
|
3
|
+
Version: 3.1.7
|
|
4
|
+
Summary: python library to work with Smartling translation services APIs
|
|
5
|
+
Home-page:
|
|
6
|
+
Author: Smartling, Inc.
|
|
7
|
+
Author-email: aartamonov@smartling.com
|
|
8
|
+
License: Apache License v2.0
|
|
9
|
+
Keywords: translation localization internationalization
|
|
10
|
+
|
|
11
|
+
python SDK to work with Smartling API for computer assisted translation
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
smartlingApiSdk/ApiResponse.py,sha256=COT-y66h1t7vkBwMtEPoizQwa91U_TdWxLBcfE_RP10,2286
|
|
2
|
+
smartlingApiSdk/ApiV2.py,sha256=AfqfFKTXKSY4XA9wcK3DyC7rDvX8gIOaTq6ttqrDXCI,3105
|
|
3
|
+
smartlingApiSdk/AuthClient.py,sha256=Owbv-FzOByHdOlnhfmoPmhi1yScRh0rkEgIy53kdStE,2831
|
|
4
|
+
smartlingApiSdk/Constants.py,sha256=T4EZjJf-2x6VWBb8nCZD6rbbYvCpCWglLKJuakko2ps,2155
|
|
5
|
+
smartlingApiSdk/Credentials.py,sha256=MrR-1v76loT9EJDrd1C7QiF7CCI1qQ-Eic227hXQcAU,2565
|
|
6
|
+
smartlingApiSdk/FileApiBase.py,sha256=IbSZiL4uiM7R0OrlncfudUva56HQ1xNH97TzBVov_Rs,5090
|
|
7
|
+
smartlingApiSdk/FileApiV2.py,sha256=dxWCYHNQX8cNjb8lGvvx4_BH2y5QrcrlBCxlxni_0O8,7756
|
|
8
|
+
smartlingApiSdk/HttpClient.py,sha256=CFmi3BkEvzqVVfIDLIsxBfAUUoiFAewgHJ6sfaMLlH0,5982
|
|
9
|
+
smartlingApiSdk/Logger.py,sha256=seUEhL0axRwFuF68Uh6JTNNohDc3XBn-kmDS8ZKTXpc,1954
|
|
10
|
+
smartlingApiSdk/MultipartPostHandler.py,sha256=uSH8gVF27_8GI_APGqynJ_sCM-Lni1g-a9IWfZ88NF4,4681
|
|
11
|
+
smartlingApiSdk/ObsoleteApiV1.py,sha256=JGKhhkmDgKyyZ9P1hI6T1Jjl0z3Ws5b99-N-j1dP_wo,3769
|
|
12
|
+
smartlingApiSdk/ObsoleteSmartlingFileApi.py,sha256=k4VI8DL4lsN5urHX7FYy4SjpORFSq6L4X1yDM8qgE_c,5208
|
|
13
|
+
smartlingApiSdk/ProjectsApiV2.py,sha256=kEb7JmIsSsk0VBvfVH0rc83rbrItm2dkz8HyE4rftqo,1970
|
|
14
|
+
smartlingApiSdk/ProxySettings.py,sha256=ZILRR8ktpznDudCp2IldvKotSF7CY7CGfGxOqYRDydU,1025
|
|
15
|
+
smartlingApiSdk/Settings.py,sha256=agZxZ8zFYQjdVZQYPyqfdmDg673NVsrveO_sNBRUoTY,993
|
|
16
|
+
smartlingApiSdk/SmartlingDirective.py,sha256=WkCO20gkUZiX_bIBSbF7PCev9gb_MWiNcMMoVRvdOoM,1191
|
|
17
|
+
smartlingApiSdk/SmartlingFileApiV2.py,sha256=JfT4Tcvcm-e_0vyD7Rp0EWySBRSUe4wJNkvC0_JHsMg,9839
|
|
18
|
+
smartlingApiSdk/SmartlingProjectsApiV2.py,sha256=AJmqx3tVEYRBkogm3oOgL7RpVlsx1SAdDfKYUFPUnqM,2697
|
|
19
|
+
smartlingApiSdk/UploadData.py,sha256=fPibrkVjkWRfC_G3snKB7VemoJnBFaIrldFV4uG0b2k,1457
|
|
20
|
+
smartlingApiSdk/UrlV2Helper.py,sha256=NcqHig2YZzr9GchALO4kfnViFm9iFVyRiYX9zcHANSI,2958
|
|
21
|
+
smartlingApiSdk/__init__.py,sha256=SHtzLS5iUbHZfKmzpWscfgPKtPFcvkUKgUhfXkOg0sw,743
|
|
22
|
+
smartlingApiSdk/version.py,sha256=XjhZAURDBMNqGbmjxTF7huXxhRSXzmk5PyuqdDaB0h8,686
|
|
23
|
+
smartlingApiSdk/api/AccountProjectsApi.py,sha256=2xz5bdQHQbCJKDbPIcXkUpRqF38F4_DJmI0Hrd3y9v8,4752
|
|
24
|
+
smartlingApiSdk/api/ContextApi.py,sha256=zS0Z3-TsE9WSEsL_pQR8pLbaSoPTotvb2t5JyarRTKk,9896
|
|
25
|
+
smartlingApiSdk/api/EstimatesApi.py,sha256=N4qsl2cDeTf4QJ7zVbdJk-QfKlUKYADdtZi_SfacGLQ,8471
|
|
26
|
+
smartlingApiSdk/api/FilesApi.py,sha256=6sbjGFEsoDoFLpsKmt7Hcc8p84BeKae3REC8r3srztY,15936
|
|
27
|
+
smartlingApiSdk/api/JobBatchesV2Api.py,sha256=N1ZhvYa5AToqAkOFhbuYKrh2xG7VVvzbSUfUgBRIYs8,6368
|
|
28
|
+
smartlingApiSdk/api/JobsApi.py,sha256=9Ea0SRq2ZBOF81B8P9R-e4iT_7qCIvzgIZ063uunYow,25353
|
|
29
|
+
smartlingApiSdk/api/StringsApi.py,sha256=2Dr4COMKsPIaq8OzTMLEhMEQlHcI_m5asP2tSRz9Xy0,4792
|
|
30
|
+
smartlingApiSdk/api/TagsApi.py,sha256=SY59ds2wsHIttzmExBzJBtjWPkogphir_X776K3hhaY,6151
|
|
31
|
+
smartlingApiSdk/api/__init__.py,sha256=SKWZ9FbAuABhf__YLJJ1Ca9FGKJMl6QcXRx47M-enlo,48
|
|
32
|
+
smartlingApiSdk/api/patch_nose.py,sha256=hts7Uxm5GJDKB3kdDx1Zi_j1mZq3q1oyqIOstRGRLOg,914
|
|
33
|
+
smartlingApiSdk/example/AccountProjectsExample.py,sha256=gIm3zAl1aidDtAws3K7UzHgrd94CSiikQA8L7a0igGo,7185
|
|
34
|
+
smartlingApiSdk/example/ContextExample.py,sha256=4ku-vCM3rBtoi_UyAxuVYMNsZLLIx7EEOxmHY6TSvLQ,13260
|
|
35
|
+
smartlingApiSdk/example/EstimatesExample.py,sha256=1kNzhnSXFTGW-c4TVqO22cp8-NPqIVhVHK7bkUVgYGU,11738
|
|
36
|
+
smartlingApiSdk/example/FilesExample.py,sha256=RQPuKTj7QA01A995n15jhgtlmA60f1XuhlN0ZYFlHO8,21115
|
|
37
|
+
smartlingApiSdk/example/FilesSimpleExample.py,sha256=2b2X84vjFQVz99McD9_4HJMdL-IqBmUzH4rBWLDpvG0,3171
|
|
38
|
+
smartlingApiSdk/example/JobBatchesV2Example.py,sha256=MvRKPW8TABazV9gL_9UwDAM5xNlqZaNoAhBQT8824tw,8143
|
|
39
|
+
smartlingApiSdk/example/JobsExample.py,sha256=xgvBX3EiPA1bBJvnyx4x3zkg99vGRJSHWCWLJ0PmzzE,27326
|
|
40
|
+
smartlingApiSdk/example/MultipleAccountsExample.py,sha256=dCZdKAlgOcEm-l2yxEzdivWOKD8ODLBdnmAUQHwTUQE,2770
|
|
41
|
+
smartlingApiSdk/example/MultipleProjectsExample.py,sha256=LH49S8KHwPzEC1yKwErasKtmOGRK_ZeKki2Tm8_F9dQ,4647
|
|
42
|
+
smartlingApiSdk/example/StringsExample.py,sha256=JI-ba8qiE_-3gQvvoTW_H344jwjmA0UCYAEW5LQS1gA,9083
|
|
43
|
+
smartlingApiSdk/example/TagsExample.py,sha256=tmBo9HCMlkCtlRdI7Rq1VbM_XDUcx6PNynkLJV0LMuA,8496
|
|
44
|
+
smartlingApiSdk/example/__init__.py,sha256=SKWZ9FbAuABhf__YLJJ1Ca9FGKJMl6QcXRx47M-enlo,48
|
|
45
|
+
smartlingApiSdk/resources/ctx_api_test.png,sha256=QuHjmQp7LQK36XjdSPP7xsnVMab3tmS1WkYyc8Uwvyc,86324
|
|
46
|
+
smartlingApiSdk/resources/java.properties,sha256=rnVIRoE_ZcKPCNRbpyKeP44gAV2pMsYcGv6ZVINB9f4,131
|
|
47
|
+
smartlingApiSdk/resources/javaUTF16.properties,sha256=qdf-viEU2xkzzFW6foepsvtoT1BGGzJfyYP7OMOljRk,442
|
|
48
|
+
smartlingApiSdk/resources/test.csv,sha256=5KiwUBT6oMFg_FtODmVPbLO1bP3BY2j8eNIu4CtW9OU,32
|
|
49
|
+
smartlingApiSdk/resources/test_import.xml,sha256=TM_flmNi8kp4eRI5QONKj-k0F8o29qe0Bp4x_F13V0U,155
|
|
50
|
+
smartlingApiSdk/resources/test_import_es.xml,sha256=Lgw-dZnmvsmM1uS7iSZjwE7eYKbWKf1h5lIdpa4x4sU,152
|
|
51
|
+
SmartlingApiSdk-3.1.7.dist-info/METADATA,sha256=Ee4GeTyEuLN85AuOrPEulueeH_u-7t1im3k1XgxJ2Mg,365
|
|
52
|
+
SmartlingApiSdk-3.1.7.dist-info/WHEEL,sha256=Mdi9PDNwEZptOjTlUcAth7XJDFtKrHYaQMPulZeBCiQ,91
|
|
53
|
+
SmartlingApiSdk-3.1.7.dist-info/top_level.txt,sha256=e38w7yd0va1Chiw-UZcdu7NkI0jewljDg-OR21eenL0,86
|
|
54
|
+
SmartlingApiSdk-3.1.7.dist-info/RECORD,,
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
#!/usr/bin/python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
""" Copyright 2012-2025 Smartling, Inc.
|
|
6
|
+
*
|
|
7
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
* you may not use this work except in compliance with the License.
|
|
9
|
+
* You may obtain a copy of the License in the LICENSE file, or at:
|
|
10
|
+
*
|
|
11
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
*
|
|
13
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
* See the License for the specific language governing permissions and
|
|
17
|
+
* limitations under the License.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
import json
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class Data:
|
|
24
|
+
""" provides dictionary items to be object attributes """
|
|
25
|
+
def __init__(self, dict):
|
|
26
|
+
self.dict = dict
|
|
27
|
+
|
|
28
|
+
def __getattr__(self, key):
|
|
29
|
+
return self.dict[key]
|
|
30
|
+
|
|
31
|
+
def __str__(self):
|
|
32
|
+
return repr(self.dict)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class ApiResponse:
|
|
36
|
+
""" response object to store parsed json response as python object, it also behaves like string for backward
|
|
37
|
+
compatibility with previous SDK versions where response was a string """
|
|
38
|
+
def __init__(self, responseString, statusCode, headers):
|
|
39
|
+
self.statusCode = statusCode
|
|
40
|
+
self.responseString = responseString
|
|
41
|
+
self.responseDict = json.loads(responseString)
|
|
42
|
+
self.isApiResonse = self.responseDict.get('response', None) and dict == type(self.responseDict['response'])
|
|
43
|
+
self.headers = headers
|
|
44
|
+
if self.isApiResonse:
|
|
45
|
+
self.parseResponse()
|
|
46
|
+
|
|
47
|
+
def parseResponse(self):
|
|
48
|
+
""" parses json and fills object attributes according json attributes """
|
|
49
|
+
|
|
50
|
+
for k, v in list(self.responseDict['response'].items()):
|
|
51
|
+
if k == 'data':
|
|
52
|
+
self.data = Data(v)
|
|
53
|
+
else:
|
|
54
|
+
setattr(self, k, v)
|
|
55
|
+
|
|
56
|
+
def __getattr__(self, key):
|
|
57
|
+
""" provides string object methods to be available for response to behave like a string """
|
|
58
|
+
if hasattr(self.responseDict, key):
|
|
59
|
+
return getattr(self.responseDict, key)
|
|
60
|
+
|
|
61
|
+
try:
|
|
62
|
+
return self.__dict__[key]
|
|
63
|
+
except:
|
|
64
|
+
raise AttributeError("ApiResponse has no attribute %r" % ( key ))
|
|
65
|
+
|
|
66
|
+
def __str__(self):
|
|
67
|
+
return str(self.responseString)
|
smartlingApiSdk/ApiV2.py
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
#!/usr/bin/python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
""" Copyright 2012-2025 Smartling, Inc.
|
|
6
|
+
*
|
|
7
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
* you may not use this work except in compliance with the License.
|
|
9
|
+
* You may obtain a copy of the License in the LICENSE file, or at:
|
|
10
|
+
*
|
|
11
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
*
|
|
13
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
* See the License for the specific language governing permissions and
|
|
17
|
+
* limitations under the License.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
# FileApi class implementation
|
|
21
|
+
|
|
22
|
+
from .AuthClient import AuthClient
|
|
23
|
+
from .Constants import FileTypes
|
|
24
|
+
from .Constants import Params
|
|
25
|
+
from .FileApiBase import FileApiBase
|
|
26
|
+
from .SmartlingDirective import SmartlingDirective
|
|
27
|
+
from .UrlV2Helper import UrlV2Helper
|
|
28
|
+
from .version import version
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class ApiV2(FileApiBase):
|
|
32
|
+
""" Api v2 basic functionality """
|
|
33
|
+
hostProd = 'api.smartling.com'
|
|
34
|
+
hostStg = 'api.stg.smartling.net'
|
|
35
|
+
clientUid = "{\"client\":\"smartling-api-sdk-python\",\"version\":\"%s\"}" % version
|
|
36
|
+
|
|
37
|
+
def __init__(self, userIdentifier, userSecret, projectId, proxySettings=None, permanentHeaders={}, env='prod'):
|
|
38
|
+
self.host = self.hostProd
|
|
39
|
+
self.userIdentifier = userIdentifier
|
|
40
|
+
if 'stg'==env:
|
|
41
|
+
self.host = self.hostStg
|
|
42
|
+
FileApiBase.__init__(self, self.host, userIdentifier, userSecret, proxySettings, permanentHeaders=permanentHeaders)
|
|
43
|
+
self.authClient = AuthClient(self.host, userIdentifier, userSecret, proxySettings)
|
|
44
|
+
self.urlHelper = UrlV2Helper(projectId)
|
|
45
|
+
|
|
46
|
+
def addAuth(self, params):
|
|
47
|
+
token = self.authClient.getToken()
|
|
48
|
+
if token is None:
|
|
49
|
+
raise Exception("Error getting token, userIdentifier:%s" % (self.userIdentifier))
|
|
50
|
+
return {"Authorization": "Bearer " + token}
|
|
51
|
+
|
|
52
|
+
def validateFileTypes(self, kw):
|
|
53
|
+
fileTypes = kw.get("fileTypes", [])
|
|
54
|
+
if type(fileTypes) != type([]) and type(fileTypes) != type(()):
|
|
55
|
+
fileTypes = [fileTypes]
|
|
56
|
+
for t in fileTypes:
|
|
57
|
+
if not getattr(FileTypes, t, None):
|
|
58
|
+
unsupported = "\nUnsupported file type:%s\n" % t
|
|
59
|
+
raise Exception(unsupported)
|
|
60
|
+
|
|
61
|
+
def checkRetrievalType(self, kw):
|
|
62
|
+
if Params.RETRIEVAL_TYPE in kw and not kw[Params.RETRIEVAL_TYPE] in Params.allowedRetrievalTypes:
|
|
63
|
+
Exception("Not allowed value `%s` for parameter:%s try one of %s" % (kw[Params.RETRIEVAL_TYPE],
|
|
64
|
+
Params.RETRIEVAL_TYPE,
|
|
65
|
+
Params.allowedRetrievalTypes))
|
|
66
|
+
|
|
67
|
+
def processDirectives(self, params, directives):
|
|
68
|
+
for name, value in list(directives.items()):
|
|
69
|
+
params[SmartlingDirective.SL_PREFIX + name] = value
|
|
70
|
+
|
|
71
|
+
def addLibIdDirective(self, params):
|
|
72
|
+
name = "client_lib_id"
|
|
73
|
+
params[SmartlingDirective.SL_PREFIX + name] = self.clientUid
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
#!/usr/bin/python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
""" Copyright 2012-2025 Smartling, Inc.
|
|
6
|
+
*
|
|
7
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
* you may not use this work except in compliance with the License.
|
|
9
|
+
* You may obtain a copy of the License in the LICENSE file, or at:
|
|
10
|
+
*
|
|
11
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
*
|
|
13
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
* See the License for the specific language governing permissions and
|
|
17
|
+
* limitations under the License.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from .HttpClient import HttpClient
|
|
21
|
+
from .ApiResponse import ApiResponse
|
|
22
|
+
from .Constants import ReqMethod
|
|
23
|
+
|
|
24
|
+
import time
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class AuthClient:
|
|
28
|
+
authUri = "/auth-api/v2/authenticate"
|
|
29
|
+
refreshUri = "/auth-api/v2/authenticate/refresh"
|
|
30
|
+
timeJitter = 5 # Seconds off server expiration time
|
|
31
|
+
|
|
32
|
+
def __init__(self, host, userIdentifier, userSecret, proxySettings=None):
|
|
33
|
+
self.httpClient = HttpClient(host, proxySettings)
|
|
34
|
+
self.userIdentifier = userIdentifier
|
|
35
|
+
self.userSecret = userSecret
|
|
36
|
+
self.accessExpiresAt = 0
|
|
37
|
+
self.refreshExpiresAt = 0
|
|
38
|
+
|
|
39
|
+
def request(self, uri, body):
|
|
40
|
+
header = {"Content-Type": "application/json"}
|
|
41
|
+
body = body.encode()
|
|
42
|
+
response_data, status_code, headers = self.httpClient.getHttpResponseAndStatus(
|
|
43
|
+
ReqMethod.POST, uri, params={}, extraHeaders=header, requestBody=body)
|
|
44
|
+
apiResponse = ApiResponse(response_data, status_code, headers)
|
|
45
|
+
|
|
46
|
+
now = time.time()
|
|
47
|
+
try:
|
|
48
|
+
self.accessToken = apiResponse.data.accessToken
|
|
49
|
+
self.refreshToken = apiResponse.data.refreshToken
|
|
50
|
+
self.accessExpiresAt = now + apiResponse.data.expiresIn - self.timeJitter
|
|
51
|
+
self.refreshExpiresAt = now + apiResponse.data.refreshExpiresIn - self.timeJitter
|
|
52
|
+
except Exception as e:
|
|
53
|
+
print(e)
|
|
54
|
+
self.accessToken = None
|
|
55
|
+
|
|
56
|
+
def authenticate(self):
|
|
57
|
+
body = '{"userIdentifier": "%s", "userSecret": "%s"}' % (self.userIdentifier, self.userSecret)
|
|
58
|
+
if '@smartling.com' in self.userIdentifier:
|
|
59
|
+
self.request(self.authUri + '/user', body)
|
|
60
|
+
else:
|
|
61
|
+
self.request(self.authUri, body)
|
|
62
|
+
|
|
63
|
+
def refresh(self):
|
|
64
|
+
body = '{"refreshToken":"%s"}' % self.refreshToken
|
|
65
|
+
self.request(self.refreshUri, body)
|
|
66
|
+
|
|
67
|
+
def getToken(self):
|
|
68
|
+
if not getattr(self, 'accessToken', None):
|
|
69
|
+
self.authenticate()
|
|
70
|
+
return self.accessToken
|
|
71
|
+
|
|
72
|
+
now = time.time()
|
|
73
|
+
if now >= self.accessExpiresAt:
|
|
74
|
+
if now < self.refreshExpiresAt:
|
|
75
|
+
self.refresh()
|
|
76
|
+
else:
|
|
77
|
+
self.authenticate()
|
|
78
|
+
return self.accessToken
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
#!/usr/bin/python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
""" Copyright 2012-2025 Smartling, Inc.
|
|
6
|
+
*
|
|
7
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
* you may not use this work except in compliance with the License.
|
|
9
|
+
* You may obtain a copy of the License in the LICENSE file, or at:
|
|
10
|
+
*
|
|
11
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
*
|
|
13
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
* See the License for the specific language governing permissions and
|
|
17
|
+
* limitations under the License.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
#constants for File API
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class Params:
|
|
24
|
+
allowedRetrievalTypes = ('pending', 'published', 'pseudo', 'contextMatchingInstrumented')
|
|
25
|
+
|
|
26
|
+
API_KEY = 'apiKey'
|
|
27
|
+
PROJECT_ID = 'projectId'
|
|
28
|
+
FILE_PATH = 'file_path'
|
|
29
|
+
FILE_URI = 'fileUri'
|
|
30
|
+
FILE_TYPE = 'fileType'
|
|
31
|
+
LOCALE = 'locale'
|
|
32
|
+
FILE = 'file'
|
|
33
|
+
APPROVED = 'approved'
|
|
34
|
+
RETRIEVAL_TYPE = 'retrievalType'
|
|
35
|
+
FILE_URI_NEW = 'newFileUri'
|
|
36
|
+
CALLBACK_URL = 'callbackUrl'
|
|
37
|
+
LOCALES_TO_APPROVE = 'localesToApprove'
|
|
38
|
+
LOCALE_IDS = 'localeIds'
|
|
39
|
+
LOCALE_IDS_BRACKET = 'localeIds[]'
|
|
40
|
+
FILE_URIS = 'fileUris'
|
|
41
|
+
|
|
42
|
+
class Uri:
|
|
43
|
+
base = '/v1/file/'
|
|
44
|
+
UPLOAD = base + 'upload'
|
|
45
|
+
LIST = base + 'list'
|
|
46
|
+
GET = base + 'get'
|
|
47
|
+
STATUS = base + 'status'
|
|
48
|
+
DELETE = base + 'delete'
|
|
49
|
+
RENAME = base + 'rename'
|
|
50
|
+
IMPORT = base + 'import'
|
|
51
|
+
LAST_MODIFIED = base + 'last_modified'
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class ReqMethod:
|
|
55
|
+
POST = "POST"
|
|
56
|
+
GET = "GET"
|
|
57
|
+
DELETE = "DELETE"
|
|
58
|
+
PUT = "PUT"
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class FileTypes:
|
|
62
|
+
android = "android"
|
|
63
|
+
ios = "ios"
|
|
64
|
+
gettext = "gettext"
|
|
65
|
+
html = "html"
|
|
66
|
+
javaProperties = "javaProperties"
|
|
67
|
+
yaml = "yaml"
|
|
68
|
+
xliff = "xliff"
|
|
69
|
+
xml = "xml"
|
|
70
|
+
json = "json"
|
|
71
|
+
docx = "docx"
|
|
72
|
+
pptx = "pptx"
|
|
73
|
+
xlsx = "xlsx"
|
|
74
|
+
idml = "idml"
|
|
75
|
+
qt = "qt"
|
|
76
|
+
resx = "resx"
|
|
77
|
+
plaintext = "plaintext"
|
|
78
|
+
cvs = "cvs"
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
#!/usr/bin/python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
""" Copyright 2012-2025 Smartling, Inc.
|
|
6
|
+
*
|
|
7
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
* you may not use this work except in compliance with the License.
|
|
9
|
+
* You may obtain a copy of the License in the LICENSE file, or at:
|
|
10
|
+
*
|
|
11
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
*
|
|
13
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
* See the License for the specific language governing permissions and
|
|
17
|
+
* limitations under the License.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
import os
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class CredentialsNotSet(Exception):
|
|
24
|
+
noKeyMessage = """
|
|
25
|
+
don't forget to set real MY_PROJECT_ID, MY_USER_IDENTIFIER, MY_USER_SECRET, MY_LOCALE
|
|
26
|
+
in Credentials class
|
|
27
|
+
or use environment variables:
|
|
28
|
+
export SL_LOCALE=**-**
|
|
29
|
+
export SL_USER_IDENTIFIER=******************************
|
|
30
|
+
export SL_USER_SECRET=*******************************************************
|
|
31
|
+
|
|
32
|
+
#optional
|
|
33
|
+
export SL_ACCOUNT_UID=******* #required only to list projects api call
|
|
34
|
+
export SL_PROJECT_ID=******* #required for api calls `projects` and `project_details`
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
def __init__(self, id, env):
|
|
38
|
+
self.id = id
|
|
39
|
+
self.env = env
|
|
40
|
+
|
|
41
|
+
def getMessage(self):
|
|
42
|
+
res = self.noKeyMessage
|
|
43
|
+
if 'stg' == self.env:
|
|
44
|
+
res = res.replace('SL_USER_IDENTIFIER=', 'SL_USER_IDENTIFIER_STG=')
|
|
45
|
+
res = res.replace('SL_USER_SECRET=', 'SL_USER_SECRET_STG=')
|
|
46
|
+
return res
|
|
47
|
+
|
|
48
|
+
def __str__(self):
|
|
49
|
+
return "Missing:" + self.id + self.getMessage()
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class Credentials():
|
|
53
|
+
|
|
54
|
+
MY_PROJECT_ID = "CHANGE_ME"
|
|
55
|
+
MY_ACCOUNT_UID = "CHANGE_ME"
|
|
56
|
+
MY_USER_IDENTIFIER = "CHANGE_ME"
|
|
57
|
+
MY_USER_SECRET = "CHANGE_ME"
|
|
58
|
+
MY_LOCALE ="CHANGE_ME"
|
|
59
|
+
|
|
60
|
+
CREDS = ("PROJECT_ID", "ACCOUNT_UID", "USER_IDENTIFIER", "USER_SECRET", "LOCALE")
|
|
61
|
+
OPTIONAL_CREDS = ("ACCOUNT_UID", "LOCALE")
|
|
62
|
+
|
|
63
|
+
def __init__(self, env='prod'):
|
|
64
|
+
for id in self.CREDS:
|
|
65
|
+
cred = "MY_"+id
|
|
66
|
+
suffix = ''
|
|
67
|
+
if env == 'stg' and id.startswith("USER_"):
|
|
68
|
+
suffix = '_STG'
|
|
69
|
+
value = getattr(self, cred + suffix, "CHANGE_ME")
|
|
70
|
+
if "CHANGE_ME" == value:
|
|
71
|
+
value = os.environ.get('SL_' + id + suffix, getattr(self, cred))
|
|
72
|
+
if "CHANGE_ME" == value and id not in self.OPTIONAL_CREDS:
|
|
73
|
+
raise CredentialsNotSet('SL_' + id + suffix, env)
|
|
74
|
+
setattr(self, cred, value)
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
#!/usr/bin/python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
""" Copyright 2012-2025 Smartling, Inc.
|
|
6
|
+
*
|
|
7
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
* you may not use this work except in compliance with the License.
|
|
9
|
+
* You may obtain a copy of the License in the LICENSE file, or at:
|
|
10
|
+
*
|
|
11
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
*
|
|
13
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
* See the License for the specific language governing permissions and
|
|
17
|
+
* limitations under the License.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
#FileApi class implementation
|
|
21
|
+
|
|
22
|
+
from .HttpClient import HttpClient, isPython3
|
|
23
|
+
from .MultipartPostHandler import MultipartPostHandler
|
|
24
|
+
from .Constants import Params, ReqMethod
|
|
25
|
+
from .ApiResponse import ApiResponse
|
|
26
|
+
from .Logger import Logger
|
|
27
|
+
from .Settings import Settings
|
|
28
|
+
import io
|
|
29
|
+
import sys
|
|
30
|
+
import logging
|
|
31
|
+
import json
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class FileApiBase:
|
|
35
|
+
""" basic class implementing low-level api calls """
|
|
36
|
+
response_as_string = False
|
|
37
|
+
|
|
38
|
+
def __init__(self, host, apiKey, projectId, proxySettings=None, permanentHeaders={}):
|
|
39
|
+
self.host = host
|
|
40
|
+
self.apiKey = apiKey
|
|
41
|
+
self.projectId = projectId
|
|
42
|
+
self.proxySettings = proxySettings
|
|
43
|
+
self.httpClient = HttpClient(host, proxySettings, permanentHeaders=permanentHeaders)
|
|
44
|
+
if Settings.printToLogfile:
|
|
45
|
+
sys.stdout = Logger('python-sdk', Settings.logLevel, Settings.logPath)
|
|
46
|
+
sys.stderr = Logger('STDERR', logging.ERROR, Settings.logPath)
|
|
47
|
+
|
|
48
|
+
def addAuth(self, params):
|
|
49
|
+
params[Params.API_KEY] = self.apiKey
|
|
50
|
+
params[Params.PROJECT_ID] = self.projectId
|
|
51
|
+
return {}
|
|
52
|
+
|
|
53
|
+
def processFile(self, file):
|
|
54
|
+
""""
|
|
55
|
+
returns file-like object form string or file
|
|
56
|
+
tries to treat string as file path or make it file-like object to be uploaded
|
|
57
|
+
"""
|
|
58
|
+
if not file or file==type(file):
|
|
59
|
+
return file
|
|
60
|
+
try:
|
|
61
|
+
f = open(file, 'rb')
|
|
62
|
+
except:
|
|
63
|
+
f = io.StringIO(file)
|
|
64
|
+
f.seek(0)
|
|
65
|
+
f.name = 'String'
|
|
66
|
+
return f
|
|
67
|
+
|
|
68
|
+
def filterOutDefaults(self, params):
|
|
69
|
+
if hasattr(params, 'items'):
|
|
70
|
+
for k, v in list(params.items()):
|
|
71
|
+
if k == 'namespace':
|
|
72
|
+
continue #when namespace is not specified it's replaced with 'smartling.strings-api.default.namespace' for strings api
|
|
73
|
+
if bool == type(v): continue
|
|
74
|
+
if not v: del params[k]
|
|
75
|
+
if k == 'projectId': del params[k]
|
|
76
|
+
|
|
77
|
+
def uploadMultipart(self, uri, params, response_as_string=False):
|
|
78
|
+
self.filterOutDefaults(params)
|
|
79
|
+
authHeader = self.addAuth(params)
|
|
80
|
+
if Params.FILE_PATH in params:
|
|
81
|
+
params[Params.FILE] = open(params[Params.FILE_PATH], 'rb')
|
|
82
|
+
del params[Params.FILE_PATH] # no need in extra field in POST
|
|
83
|
+
|
|
84
|
+
response_data, status_code, headers = self.getHttpResponseAndStatus(ReqMethod.POST ,uri, params, MultipartPostHandler, extraHeaders = authHeader)
|
|
85
|
+
response_data = response_data.strip()
|
|
86
|
+
if self.response_as_string or response_as_string or not self.isJsonResponse(headers):
|
|
87
|
+
return response_data, status_code
|
|
88
|
+
return ApiResponse(response_data, status_code, headers), status_code
|
|
89
|
+
|
|
90
|
+
def commandJson(self, method, uri, params):
|
|
91
|
+
authHeader = self.addAuth(params)
|
|
92
|
+
authHeader['Content-Type'] = 'application/json'
|
|
93
|
+
self.filterOutDefaults(params)
|
|
94
|
+
jsonBody = json.dumps(params).encode('utf8')
|
|
95
|
+
|
|
96
|
+
data, code, headers = self.httpClient.getHttpResponseAndStatus(method, uri, params={}, requestBody = jsonBody, extraHeaders = authHeader)
|
|
97
|
+
if not code in [200,202]:
|
|
98
|
+
rId = headers.get("X-SL-RequestId","Unknown")
|
|
99
|
+
print ("code:%d RequestId:%s jsonBody=%s" % (code, rId, jsonBody))
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
if self.response_as_string or not self.isJsonResponse(headers):
|
|
103
|
+
return data, code
|
|
104
|
+
return ApiResponse(data, code, headers), code
|
|
105
|
+
|
|
106
|
+
def getHttpResponseAndStatus(self, method, uri, params, handler=None, extraHeaders = None):
|
|
107
|
+
return self.httpClient.getHttpResponseAndStatus(method, uri, params, handler, extraHeaders = extraHeaders)
|
|
108
|
+
|
|
109
|
+
def getResponseAndStatus(self, method, uri, params):
|
|
110
|
+
authHeader = self.addAuth(params)
|
|
111
|
+
return self.getHttpResponseAndStatus(method, uri, params, extraHeaders = authHeader)
|
|
112
|
+
|
|
113
|
+
def isJsonResponse(self, headers):
|
|
114
|
+
if isPython3:
|
|
115
|
+
hdr = 'Content-Type'
|
|
116
|
+
else:
|
|
117
|
+
hdr = 'content-type'
|
|
118
|
+
return 'json' in headers.get(hdr,'')
|
|
119
|
+
|
|
120
|
+
def command(self, method, uri, params):
|
|
121
|
+
self.filterOutDefaults(params)
|
|
122
|
+
data, code, headers = self.getResponseAndStatus(method, uri, params)
|
|
123
|
+
if self.response_as_string or not self.isJsonResponse(headers):
|
|
124
|
+
return data, code
|
|
125
|
+
result = ApiResponse(data, code, headers)
|
|
126
|
+
if result.isApiResonse:
|
|
127
|
+
return result, code
|
|
128
|
+
return data, code
|