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.
Files changed (54) hide show
  1. SmartlingApiSdk-3.1.7.dist-info/METADATA +11 -0
  2. SmartlingApiSdk-3.1.7.dist-info/RECORD +54 -0
  3. SmartlingApiSdk-3.1.7.dist-info/WHEEL +5 -0
  4. SmartlingApiSdk-3.1.7.dist-info/top_level.txt +4 -0
  5. smartlingApiSdk/ApiResponse.py +67 -0
  6. smartlingApiSdk/ApiV2.py +73 -0
  7. smartlingApiSdk/AuthClient.py +78 -0
  8. smartlingApiSdk/Constants.py +78 -0
  9. smartlingApiSdk/Credentials.py +74 -0
  10. smartlingApiSdk/FileApiBase.py +128 -0
  11. smartlingApiSdk/FileApiV2.py +187 -0
  12. smartlingApiSdk/HttpClient.py +155 -0
  13. smartlingApiSdk/Logger.py +64 -0
  14. smartlingApiSdk/MultipartPostHandler.py +127 -0
  15. smartlingApiSdk/ObsoleteApiV1.py +94 -0
  16. smartlingApiSdk/ObsoleteSmartlingFileApi.py +108 -0
  17. smartlingApiSdk/ProjectsApiV2.py +52 -0
  18. smartlingApiSdk/ProxySettings.py +27 -0
  19. smartlingApiSdk/Settings.py +29 -0
  20. smartlingApiSdk/SmartlingDirective.py +38 -0
  21. smartlingApiSdk/SmartlingFileApiV2.py +189 -0
  22. smartlingApiSdk/SmartlingProjectsApiV2.py +65 -0
  23. smartlingApiSdk/UploadData.py +49 -0
  24. smartlingApiSdk/UrlV2Helper.py +71 -0
  25. smartlingApiSdk/__init__.py +23 -0
  26. smartlingApiSdk/api/AccountProjectsApi.py +120 -0
  27. smartlingApiSdk/api/ContextApi.py +250 -0
  28. smartlingApiSdk/api/EstimatesApi.py +201 -0
  29. smartlingApiSdk/api/FilesApi.py +343 -0
  30. smartlingApiSdk/api/JobBatchesV2Api.py +134 -0
  31. smartlingApiSdk/api/JobsApi.py +612 -0
  32. smartlingApiSdk/api/StringsApi.py +110 -0
  33. smartlingApiSdk/api/TagsApi.py +142 -0
  34. smartlingApiSdk/api/__init__.py +4 -0
  35. smartlingApiSdk/api/patch_nose.py +24 -0
  36. smartlingApiSdk/example/AccountProjectsExample.py +197 -0
  37. smartlingApiSdk/example/ContextExample.py +347 -0
  38. smartlingApiSdk/example/EstimatesExample.py +298 -0
  39. smartlingApiSdk/example/FilesExample.py +498 -0
  40. smartlingApiSdk/example/FilesSimpleExample.py +101 -0
  41. smartlingApiSdk/example/JobBatchesV2Example.py +186 -0
  42. smartlingApiSdk/example/JobsExample.py +672 -0
  43. smartlingApiSdk/example/MultipleAccountsExample.py +74 -0
  44. smartlingApiSdk/example/MultipleProjectsExample.py +118 -0
  45. smartlingApiSdk/example/StringsExample.py +224 -0
  46. smartlingApiSdk/example/TagsExample.py +214 -0
  47. smartlingApiSdk/example/__init__.py +4 -0
  48. smartlingApiSdk/resources/ctx_api_test.png +0 -0
  49. smartlingApiSdk/resources/java.properties +10 -0
  50. smartlingApiSdk/resources/javaUTF16.properties +0 -0
  51. smartlingApiSdk/resources/test.csv +1 -0
  52. smartlingApiSdk/resources/test_import.xml +5 -0
  53. smartlingApiSdk/resources/test_import_es.xml +5 -0
  54. 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,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (73.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,4 @@
1
+ smartlingApiSdk
2
+ smartlingApiSdk/api
3
+ smartlingApiSdk/example
4
+ smartlingApiSdk/resources
@@ -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)
@@ -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