dealcloud-sdk 0.1.0__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.
- dealcloud_sdk/__init__.py +6 -0
- dealcloud_sdk/base/__init__.py +0 -0
- dealcloud_sdk/base/dealcloud_base.py +174 -0
- dealcloud_sdk/constants/__init__.py +0 -0
- dealcloud_sdk/constants/auth.py +1 -0
- dealcloud_sdk/constants/data.py +4 -0
- dealcloud_sdk/constants/env_var_names.py +3 -0
- dealcloud_sdk/constants/field_types.py +13 -0
- dealcloud_sdk/constants/request.py +3 -0
- dealcloud_sdk/data/__init__.py +0 -0
- dealcloud_sdk/data/dealcloud_data.py +805 -0
- dealcloud_sdk/dealcloud.py +25 -0
- dealcloud_sdk/factories/__init__.py +0 -0
- dealcloud_sdk/factories/from_env.py +53 -0
- dealcloud_sdk/factories/from_json.py +27 -0
- dealcloud_sdk/factories/from_yaml.py +28 -0
- dealcloud_sdk/models/__init__.py +0 -0
- dealcloud_sdk/models/auth.py +10 -0
- dealcloud_sdk/models/data.py +8 -0
- dealcloud_sdk/models/factory_models.py +7 -0
- dealcloud_sdk/models/schema.py +116 -0
- dealcloud_sdk/schema/__init__.py +0 -0
- dealcloud_sdk/schema/dealcloud_schema.py +145 -0
- dealcloud_sdk/utils/__init__.py +0 -0
- dealcloud_sdk/utils/common_argument_parse.py +10 -0
- dealcloud_sdk/utils/data_utils.py +78 -0
- dealcloud_sdk/utils/get_key.py +15 -0
- dealcloud_sdk/utils/process_response_errors.py +19 -0
- dealcloud_sdk/utils/request_retry.py +168 -0
- dealcloud_sdk/utils/resolve_references.py +9 -0
- dealcloud_sdk/utils/validation.py +8 -0
- dealcloud_sdk-0.1.0.dist-info/LICENSE +114 -0
- dealcloud_sdk-0.1.0.dist-info/METADATA +920 -0
- dealcloud_sdk-0.1.0.dist-info/RECORD +35 -0
- dealcloud_sdk-0.1.0.dist-info/WHEEL +4 -0
|
File without changes
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from time import time
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
from requests.exceptions import HTTPError
|
|
6
|
+
|
|
7
|
+
from dealcloud_sdk.constants.auth import AVAILABLE_SCOPES
|
|
8
|
+
from dealcloud_sdk.constants.env_var_names import (
|
|
9
|
+
SITE_URL_ENV_NAME,
|
|
10
|
+
CLIENT_ID_ENV_NAME,
|
|
11
|
+
CLIENT_SECRET_ENV_NAME,
|
|
12
|
+
)
|
|
13
|
+
from dealcloud_sdk.factories.from_json import dc_from_json_config
|
|
14
|
+
from dealcloud_sdk.factories.from_yaml import dc_from_yaml_config
|
|
15
|
+
from dealcloud_sdk.factories.from_env import dc_from_environment_variables
|
|
16
|
+
from dealcloud_sdk.models.auth import Tokens
|
|
17
|
+
from dealcloud_sdk.utils.get_key import get_key
|
|
18
|
+
from dealcloud_sdk.utils.request_retry import request_with_retry
|
|
19
|
+
from dealcloud_sdk.utils.validation import validate_scope
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class DealCloudBase:
|
|
23
|
+
"""DealCloudBase provides the base definition for authentication, etc. to provide DealCloud python wrappers"""
|
|
24
|
+
|
|
25
|
+
def __init__(
|
|
26
|
+
self,
|
|
27
|
+
site_url: str = None,
|
|
28
|
+
client_id: str = None,
|
|
29
|
+
client_secret: str = None,
|
|
30
|
+
scope: tuple[str] = AVAILABLE_SCOPES,
|
|
31
|
+
refresh_id_maps: bool = True,
|
|
32
|
+
):
|
|
33
|
+
"""
|
|
34
|
+
Init function for DealCloudBase
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
site_url(str): the target DealCloud site in the format "{client}.dealcloud.com" - i.e. no https:// or /
|
|
38
|
+
client_id(int): the client id from the user api key
|
|
39
|
+
client_secret(str): the client secret from the user api key
|
|
40
|
+
scope(tuple[str]): the authentication scopes, defaults to ("data", "user_management", "publish")
|
|
41
|
+
"""
|
|
42
|
+
# log with provided logger
|
|
43
|
+
self._logger = logging.getLogger(__name__)
|
|
44
|
+
|
|
45
|
+
# api credentials
|
|
46
|
+
self._site = site_url
|
|
47
|
+
self._client_id = client_id
|
|
48
|
+
self._client_secret = client_secret
|
|
49
|
+
|
|
50
|
+
# encode auth string for authentication using request header
|
|
51
|
+
self._basic_auth = get_key(self._client_id, self._client_secret)
|
|
52
|
+
|
|
53
|
+
# validate provided scopes against available scopes
|
|
54
|
+
validate_scope(scope)
|
|
55
|
+
self._scope = " ".join(scope)
|
|
56
|
+
|
|
57
|
+
# id map refresh flag
|
|
58
|
+
self._refresh_id_maps = refresh_id_maps
|
|
59
|
+
|
|
60
|
+
# base urls
|
|
61
|
+
self._url_root = f"https://{self._site}/api/rest/v4"
|
|
62
|
+
self._url_root_v1 = f"https://{self._site}/api/rest/v1"
|
|
63
|
+
|
|
64
|
+
# schema endpoint
|
|
65
|
+
self._schema_url = f"{self._url_root}/schema"
|
|
66
|
+
|
|
67
|
+
# data endpoints
|
|
68
|
+
self._data_url = f"{self._url_root}/data"
|
|
69
|
+
self._entrydata_url = f"{self._data_url}/entrydata"
|
|
70
|
+
self._rows_url = f"{self._entrydata_url}/rows"
|
|
71
|
+
self._query_url = f"{self._rows_url}/query"
|
|
72
|
+
self._views_url = f"{self._data_url}/rows/view"
|
|
73
|
+
|
|
74
|
+
# setup token storage
|
|
75
|
+
self._access_token = None
|
|
76
|
+
self._expiry_time = None
|
|
77
|
+
|
|
78
|
+
# check valid credentials
|
|
79
|
+
self._logger.debug("validating credentials")
|
|
80
|
+
self._auth()
|
|
81
|
+
self._logger.debug("credentials validated")
|
|
82
|
+
|
|
83
|
+
# store schema
|
|
84
|
+
self._site_schema = self.get_schema()
|
|
85
|
+
# store users
|
|
86
|
+
self._user_map = dict({u.email.lower(): u.id for u in self.get_users()})
|
|
87
|
+
|
|
88
|
+
# id mapping store
|
|
89
|
+
self._id_map = {}
|
|
90
|
+
|
|
91
|
+
@classmethod
|
|
92
|
+
def from_env(
|
|
93
|
+
cls,
|
|
94
|
+
site_url_env_name: str = SITE_URL_ENV_NAME,
|
|
95
|
+
client_id_env_name: str = CLIENT_ID_ENV_NAME,
|
|
96
|
+
client_secret_env_name: str = CLIENT_SECRET_ENV_NAME,
|
|
97
|
+
):
|
|
98
|
+
config = dc_from_environment_variables(
|
|
99
|
+
site_url_env_name,
|
|
100
|
+
client_id_env_name,
|
|
101
|
+
client_secret_env_name,
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
return cls(
|
|
105
|
+
config.site_url,
|
|
106
|
+
config.client_id,
|
|
107
|
+
config.client_secret,
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
@classmethod
|
|
111
|
+
def from_json(
|
|
112
|
+
cls, json_file_path: str, json_path_to_credentials: Optional[str] = None
|
|
113
|
+
):
|
|
114
|
+
config = dc_from_json_config(json_file_path, json_path_to_credentials)
|
|
115
|
+
return cls(
|
|
116
|
+
config.site_url,
|
|
117
|
+
config.client_id,
|
|
118
|
+
config.client_secret,
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
@classmethod
|
|
122
|
+
def from_yaml(
|
|
123
|
+
cls, yaml_file_path: str, yaml_path_to_credentials: Optional[str] = None
|
|
124
|
+
):
|
|
125
|
+
config = dc_from_yaml_config(yaml_file_path, yaml_path_to_credentials)
|
|
126
|
+
return cls(
|
|
127
|
+
config.site_url,
|
|
128
|
+
config.client_id,
|
|
129
|
+
config.client_secret,
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
def _auth(self) -> Tokens:
|
|
133
|
+
"""
|
|
134
|
+
Authenticate with the DealCloud API
|
|
135
|
+
|
|
136
|
+
Returns:
|
|
137
|
+
tokens (Tokens): Pydantic model containing auth tokens
|
|
138
|
+
"""
|
|
139
|
+
url = f"{self._url_root_v1}/oauth/token"
|
|
140
|
+
payload = f"grant_type=client_credentials&scope={self._scope}"
|
|
141
|
+
|
|
142
|
+
response = request_with_retry(
|
|
143
|
+
"GET",
|
|
144
|
+
url,
|
|
145
|
+
self._basic_auth,
|
|
146
|
+
data=payload,
|
|
147
|
+
status_force_list=[429],
|
|
148
|
+
auth_type="Basic",
|
|
149
|
+
max_retries=5,
|
|
150
|
+
content_type="application/x-www-form-urlencoded",
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
if response.status_code != 200:
|
|
154
|
+
self._logger.warning(response.text)
|
|
155
|
+
raise HTTPError("Could not authenticate! - check credentials")
|
|
156
|
+
tokens = Tokens(**response.json())
|
|
157
|
+
|
|
158
|
+
self._access_token = tokens.access_token
|
|
159
|
+
self._expiry_time = time() + (tokens.expires_in - 120)
|
|
160
|
+
|
|
161
|
+
return tokens
|
|
162
|
+
|
|
163
|
+
def _get_access_token(self) -> str:
|
|
164
|
+
if time() > self._expiry_time:
|
|
165
|
+
self._logger.warning("RE-AUTHENTICATING")
|
|
166
|
+
self._auth()
|
|
167
|
+
|
|
168
|
+
return self._access_token
|
|
169
|
+
|
|
170
|
+
def get_schema(self):
|
|
171
|
+
pass
|
|
172
|
+
|
|
173
|
+
def get_users(self):
|
|
174
|
+
pass
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
AVAILABLE_SCOPES = ("data", "user_management", "publish")
|
|
File without changes
|