dimo-python-sdk 1.3.2__tar.gz → 1.3.4__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.
Files changed (34) hide show
  1. {dimo_python_sdk-1.3.2 → dimo_python_sdk-1.3.4}/PKG-INFO +1 -1
  2. {dimo_python_sdk-1.3.2 → dimo_python_sdk-1.3.4}/dimo/api/auth.py +35 -5
  3. {dimo_python_sdk-1.3.2 → dimo_python_sdk-1.3.4}/dimo/api/token_exchange.py +3 -0
  4. dimo_python_sdk-1.3.4/dimo/dimo.py +93 -0
  5. dimo_python_sdk-1.3.4/dimo/request.py +57 -0
  6. {dimo_python_sdk-1.3.2 → dimo_python_sdk-1.3.4}/dimo_python_sdk.egg-info/PKG-INFO +1 -1
  7. {dimo_python_sdk-1.3.2 → dimo_python_sdk-1.3.4}/dimo_python_sdk.egg-info/SOURCES.txt +5 -1
  8. {dimo_python_sdk-1.3.2 → dimo_python_sdk-1.3.4}/pyproject.toml +1 -1
  9. dimo_python_sdk-1.3.4/tests/test_dimo.py +60 -0
  10. dimo_python_sdk-1.3.4/tests/test_errors.py +33 -0
  11. dimo_python_sdk-1.3.4/tests/test_permission_decoder.py +13 -0
  12. dimo_python_sdk-1.3.4/tests/test_request.py +90 -0
  13. dimo_python_sdk-1.3.2/dimo/dimo.py +0 -65
  14. dimo_python_sdk-1.3.2/dimo/request.py +0 -38
  15. {dimo_python_sdk-1.3.2 → dimo_python_sdk-1.3.4}/LICENSE +0 -0
  16. {dimo_python_sdk-1.3.2 → dimo_python_sdk-1.3.4}/README.md +0 -0
  17. {dimo_python_sdk-1.3.2 → dimo_python_sdk-1.3.4}/dimo/__init__.py +0 -0
  18. {dimo_python_sdk-1.3.2 → dimo_python_sdk-1.3.4}/dimo/api/__init__.py +0 -0
  19. {dimo_python_sdk-1.3.2 → dimo_python_sdk-1.3.4}/dimo/api/attestation.py +0 -0
  20. {dimo_python_sdk-1.3.2 → dimo_python_sdk-1.3.4}/dimo/api/device_definitions.py +0 -0
  21. {dimo_python_sdk-1.3.2 → dimo_python_sdk-1.3.4}/dimo/api/trips.py +0 -0
  22. {dimo_python_sdk-1.3.2 → dimo_python_sdk-1.3.4}/dimo/api/valuations.py +0 -0
  23. {dimo_python_sdk-1.3.2 → dimo_python_sdk-1.3.4}/dimo/constants.py +0 -0
  24. {dimo_python_sdk-1.3.2 → dimo_python_sdk-1.3.4}/dimo/environments.py +0 -0
  25. {dimo_python_sdk-1.3.2 → dimo_python_sdk-1.3.4}/dimo/errors.py +0 -0
  26. {dimo_python_sdk-1.3.2 → dimo_python_sdk-1.3.4}/dimo/eth_signer.py +0 -0
  27. {dimo_python_sdk-1.3.2 → dimo_python_sdk-1.3.4}/dimo/graphql/__init__.py +0 -0
  28. {dimo_python_sdk-1.3.2 → dimo_python_sdk-1.3.4}/dimo/graphql/identity.py +0 -0
  29. {dimo_python_sdk-1.3.2 → dimo_python_sdk-1.3.4}/dimo/graphql/telemetry.py +0 -0
  30. {dimo_python_sdk-1.3.2 → dimo_python_sdk-1.3.4}/dimo/permission_decoder.py +0 -0
  31. {dimo_python_sdk-1.3.2 → dimo_python_sdk-1.3.4}/dimo_python_sdk.egg-info/dependency_links.txt +0 -0
  32. {dimo_python_sdk-1.3.2 → dimo_python_sdk-1.3.4}/dimo_python_sdk.egg-info/requires.txt +0 -0
  33. {dimo_python_sdk-1.3.2 → dimo_python_sdk-1.3.4}/dimo_python_sdk.egg-info/top_level.txt +0 -0
  34. {dimo_python_sdk-1.3.2 → dimo_python_sdk-1.3.4}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dimo-python-sdk
3
- Version: 1.3.2
3
+ Version: 1.3.4
4
4
  Summary: DIMO SDK in Python
5
5
  Author-email: Barrett Kowalsky <barrettkowalsky@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/DIMO-Network/dimo-python-sdk
@@ -2,6 +2,7 @@ from dimo.eth_signer import EthSigner
2
2
  from dimo.errors import check_type, check_optional_type
3
3
  from urllib.parse import urlencode
4
4
  from typing import Dict, Optional
5
+ import json
5
6
 
6
7
 
7
8
  class Auth:
@@ -36,13 +37,18 @@ class Auth:
36
37
  "address": address,
37
38
  }
38
39
 
39
- return self._request(
40
+ response = self._request(
40
41
  "POST",
41
42
  "Auth",
42
43
  "/auth/web3/generate_challenge",
43
44
  data=urlencode(body),
44
45
  headers=headers,
45
46
  )
47
+
48
+ if isinstance(response, bytes):
49
+ response = json.loads(response.decode('utf-8'))
50
+
51
+ return response
46
52
 
47
53
  def sign_challenge(self, message: str, private_key: str) -> str:
48
54
  check_type("message", message, str)
@@ -78,13 +84,18 @@ class Auth:
78
84
 
79
85
  encoded_data = urlencode(form_data)
80
86
 
81
- return self._request(
87
+ response = self._request(
82
88
  "POST",
83
89
  "Auth",
84
90
  "/auth/web3/submit_challenge",
85
91
  data=encoded_data,
86
92
  headers=headers,
87
93
  )
94
+
95
+ if isinstance(response, bytes):
96
+ response = json.loads(response.decode('utf-8'))
97
+
98
+ return response
88
99
 
89
100
  # Requires client_id, domain, and private_key. Address defaults to client_id.
90
101
  def get_dev_jwt(
@@ -96,7 +107,18 @@ class Auth:
96
107
  scope="openid email",
97
108
  response_type="code",
98
109
  ) -> Dict:
99
-
110
+ """
111
+ Generate a signed developer JWT in one step.
112
+ For testing, mocks and POCs.
113
+
114
+ Args:
115
+ client_id (str): The Ethereum address of the client
116
+ domain (str): The domain name for the client
117
+ private_key (str): The private key to sign the challenge
118
+
119
+ Returns:
120
+ dict: The authentication response containing access_token
121
+ """
100
122
  check_type("client_id", client_id, str)
101
123
  check_type("domain", domain, str)
102
124
  check_type("private_key", private_key, str)
@@ -109,6 +131,7 @@ class Auth:
109
131
 
110
132
  headers = {"Content-Type": "application/x-www-form-urlencoded"}
111
133
 
134
+ # Generate a challenge
112
135
  challenge = self.generate_challenge(
113
136
  headers=headers,
114
137
  client_id=client_id,
@@ -117,14 +140,21 @@ class Auth:
117
140
  response_type=response_type,
118
141
  address=address,
119
142
  )
120
-
143
+
144
+ if isinstance(challenge, bytes):
145
+ challenge = json.loads(challenge.decode('utf-8'))
146
+
121
147
  sign = self.sign_challenge(
122
148
  message=challenge["challenge"],
123
149
  private_key=private_key,
124
150
  )
125
-
151
+
126
152
  state = challenge["state"]
127
153
  signature = sign
128
154
 
129
155
  submit = self.submit_challenge(client_id, domain, state, signature, headers)
156
+
157
+ if isinstance(submit, bytes):
158
+ submit = json.loads(submit.decode('utf-8'))
159
+
130
160
  return submit
@@ -1,6 +1,7 @@
1
1
  from dimo.constants import dimo_constants
2
2
  from dimo.errors import check_type, check_optional_type
3
3
  from dimo.permission_decoder import PermissionDecoder
4
+ import json
4
5
 
5
6
 
6
7
  class TokenExchange:
@@ -17,6 +18,8 @@ class TokenExchange:
17
18
  def _decode_vehicle_permissions(self, token_id: int, client_id: str) -> dict:
18
19
  response = self._identity.check_vehicle_privileges(token_id)
19
20
  try:
21
+ # If response is bytes
22
+ response = json.loads(response.decode('utf-8'))
20
23
  nodes = (
21
24
  response.get("data", {})
22
25
  .get("vehicle", {})
@@ -0,0 +1,93 @@
1
+ from typing_extensions import Optional
2
+ from requests import Session
3
+
4
+ from .api.attestation import Attestation
5
+ from .api.auth import Auth
6
+ from .api.device_definitions import DeviceDefinitions
7
+ from .api.token_exchange import TokenExchange
8
+ from .api.trips import Trips
9
+ from .api.valuations import Valuations
10
+
11
+ from .graphql.identity import Identity
12
+ from .graphql.telemetry import Telemetry
13
+
14
+ from .request import Request
15
+ from .environments import dimo_environment
16
+ from typing import Optional
17
+ from typing_extensions import Dict
18
+ from typing import Any
19
+ from urllib.parse import urljoin
20
+
21
+
22
+ class DIMO:
23
+
24
+ def __init__(self, env: str = "Production", session: Optional[Session] = None) -> None:
25
+
26
+ self.env = env
27
+ # Assert valid environment specified
28
+ if env not in dimo_environment:
29
+ raise ValueError(f"Unknown environment: {env}")
30
+
31
+ self.urls = dimo_environment[env]
32
+
33
+ self._client_id: Optional[str] = None
34
+ self._services: Dict[str, Any] = {}
35
+ self.session = session or Session() # Use the provided session or create a new one
36
+
37
+ # Creates a full path for endpoints combining DIMO service, specific endpoint, and optional params
38
+ def _get_full_path(self, service: str, path: str, params=None) -> str:
39
+ base_path = self.urls[service]
40
+ path_formatted = path.format(**(params or {}))
41
+ return urljoin(base_path, path_formatted)
42
+
43
+ # Sets headers based on access_token or privileged_token
44
+ def _get_auth_headers(self, token):
45
+ return {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
46
+
47
+ # request method for HTTP requests for the REST API
48
+ def request(self, http_method, service, path, **kwargs):
49
+ full_path = self._get_full_path(service, path)
50
+ return Request(http_method, full_path, self.session)(**kwargs)
51
+
52
+ # query method for graphQL queries, identity and telemetry
53
+ def query(self, service, query, variables=None, token=None):
54
+ headers = self._get_auth_headers(token) if token else {}
55
+ headers["Content-Type"] = "application/json"
56
+ headers["User-Agent"] = "dimo-python-sdk"
57
+
58
+ data = {"query": query, "variables": variables or {}}
59
+
60
+ response = self.request("POST", service, "", headers=headers, data=data)
61
+ return response
62
+
63
+ def __getattr__(self, name: str) -> Any:
64
+ """
65
+ Lazy-load and cache service modules as attributes
66
+ """
67
+ # If service is already created, return from cache
68
+ if name in self._services:
69
+ return self._services[name]
70
+ # Otherwise, see if its a known service
71
+ mapping = {
72
+ "attestation": (Attestation, ("request", "_get_auth_headers")),
73
+ "auth": (Auth, ("request", "_get_auth_headers", "env", "self")),
74
+ "device_definitions": (DeviceDefinitions, ("request", "_get_auth_headers")),
75
+ "token_exchange": (
76
+ TokenExchange,
77
+ ("request", "_get_auth_headers", "identity", "self"),
78
+ ),
79
+ "trips": (Trips, ("request", "_get_auth_headers")),
80
+ "valuations": (Valuations, ("request", "_get_auth_headers")),
81
+ "identity": (Identity, ("self",)),
82
+ "telemetry": (Telemetry, ("self",)),
83
+ }
84
+ if name in mapping:
85
+ cls, deps = mapping[name]
86
+ args = [getattr(self, dep) if dep != "self" else self for dep in deps]
87
+ instance = cls(*args)
88
+ # And cache the service for future use
89
+ self._services[name] = instance
90
+ return instance
91
+ raise AttributeError(
92
+ f"{self.__class__.__name__!r} object has no attribute {name!r}"
93
+ )
@@ -0,0 +1,57 @@
1
+ import json
2
+ from typing import Any
3
+ from requests import Session, RequestException
4
+
5
+
6
+ class HTTPError(Exception):
7
+ """Http error wrapper with status code and (optional) response body"""
8
+
9
+ def __init__(self, status: int, message: str, body: Any = None):
10
+ super().__init__(f"HTTP {status}: {message}")
11
+ self.status = status
12
+ self.body = body
13
+
14
+
15
+ class Request:
16
+
17
+ def __init__(self, http_method: str, url: str, session: Session):
18
+ self.http_method = http_method
19
+ self.url = url
20
+ self.session = session
21
+
22
+ def __call__(self, headers=None, data=None, params=None, **kwargs):
23
+ headers = headers or {}
24
+ headers.update(kwargs.pop("headers", {}))
25
+
26
+ if (
27
+ data
28
+ and isinstance(data, dict)
29
+ and headers.get("Content-Type") == "application/json"
30
+ ):
31
+ data = json.dumps(data)
32
+
33
+ try:
34
+ response = self.session.request(
35
+ method=self.http_method,
36
+ url=self.url,
37
+ headers=headers,
38
+ params=params,
39
+ data=data,
40
+ **kwargs,
41
+ )
42
+
43
+ response.raise_for_status()
44
+ except RequestException as exc:
45
+ status = getattr(exc.response, "status_code", None)
46
+ body = None
47
+ try:
48
+ body = exc.response.json()
49
+ except Exception:
50
+ body = exc.response.txt if exc.response else None
51
+ raise HTTPError(status=status or -1, message=str(exc), body=body)
52
+
53
+ content_type = response.headers.get("Content-Type", "")
54
+ if "application/json" in content_type:
55
+ return response.json()
56
+
57
+ return response.content
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dimo-python-sdk
3
- Version: 1.3.2
3
+ Version: 1.3.4
4
4
  Summary: DIMO SDK in Python
5
5
  Author-email: Barrett Kowalsky <barrettkowalsky@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/DIMO-Network/dimo-python-sdk
@@ -23,4 +23,8 @@ dimo_python_sdk.egg-info/PKG-INFO
23
23
  dimo_python_sdk.egg-info/SOURCES.txt
24
24
  dimo_python_sdk.egg-info/dependency_links.txt
25
25
  dimo_python_sdk.egg-info/requires.txt
26
- dimo_python_sdk.egg-info/top_level.txt
26
+ dimo_python_sdk.egg-info/top_level.txt
27
+ tests/test_dimo.py
28
+ tests/test_errors.py
29
+ tests/test_permission_decoder.py
30
+ tests/test_request.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "dimo-python-sdk"
7
- version = "1.3.2"
7
+ version = "1.3.4"
8
8
  authors = [
9
9
  { name="Barrett Kowalsky", email="barrettkowalsky@gmail.com" },
10
10
  ]
@@ -0,0 +1,60 @@
1
+ from unittest.mock import MagicMock
2
+
3
+ from dimo.dimo import DIMO
4
+
5
+
6
+ def test_get_full_path_no_params():
7
+ client = DIMO(env="Dev")
8
+ result = client._get_full_path("Valuations", "/v2/vehicles/1234/valuations")
9
+ assert result == "https://valuations-api.dev.dimo.zone/v2/vehicles/1234/valuations"
10
+
11
+
12
+ def test_get_full_path_with_params():
13
+ client = DIMO(env="Dev")
14
+ result = client._get_full_path(
15
+ "Telemetry",
16
+ "/items/{item_id}",
17
+ {"item_id": 123},
18
+ )
19
+ assert result == "https://telemetry-api.dev.dimo.zone/items/123"
20
+
21
+
22
+ def test_get_auth_headers():
23
+ client = DIMO(env="Dev")
24
+ headers = client._get_auth_headers("token123")
25
+ assert headers == {
26
+ "Authorization": "Bearer token123",
27
+ "Content-Type": "application/json",
28
+ }
29
+
30
+
31
+ def test_query_calls_request_with_correct_payload(monkeypatch):
32
+ client = DIMO(env="Dev")
33
+ # Create a fake request method on the client
34
+ fake_request = MagicMock(return_value={"data": {"result": True}})
35
+ monkeypatch.setattr(client, "request", fake_request)
36
+
37
+ query_str = "query { test }"
38
+ variables = {"key": "value"}
39
+ result = client.query("Trips", query_str, variables=variables, token="mocked_token")
40
+
41
+ # Verify the fake request was invoked once
42
+ fake_request.assert_called_once()
43
+ # Inspect call arguments
44
+ args, kwargs = fake_request.call_args
45
+ assert args[0] == "POST"
46
+ assert args[1] == "Trips"
47
+ assert args[2] == ""
48
+
49
+ # Assert correct headers
50
+ headers = kwargs["headers"]
51
+ assert headers["Authorization"] == "Bearer mocked_token"
52
+ assert headers["Content-Type"] == "application/json"
53
+ assert headers["User-Agent"] == "dimo-python-sdk"
54
+
55
+ # Check payload data
56
+ data = kwargs["data"]
57
+ assert data["query"] == query_str
58
+ assert data["variables"] == variables
59
+
60
+ assert result == {"data": {"result": True}}
@@ -0,0 +1,33 @@
1
+ import pytest
2
+ from dimo.errors import DimoTypeError, check_type, check_optional_type
3
+
4
+
5
+ def test_check_type_passes_for_correct_type():
6
+ # call check_type with valid args which should not raise anything
7
+ check_type("count", 5, int)
8
+
9
+
10
+ def test_check_type_raises_for_incorrect_type():
11
+ with pytest.raises(DimoTypeError) as exc:
12
+ check_type("name", 123, str)
13
+ err = exc.value
14
+ assert err.param_name == "name"
15
+ assert err.expected_type is str
16
+ assert isinstance(err.actual_value, int)
17
+
18
+ assert "name must be a str" in str(err)
19
+ assert "but was entered as type int" in str(err)
20
+
21
+
22
+ def test_check_optional_type_allows_none():
23
+ # None is allowed
24
+ check_optional_type("maybe", None, dict)
25
+
26
+
27
+ def test_check_optional_type_raises_for_wrong_non_none():
28
+ with pytest.raises(DimoTypeError) as exc:
29
+ check_optional_type("maybe", 3.14, str)
30
+ err = exc.value
31
+ assert err.param_name == "maybe"
32
+ assert err.expected_type is str
33
+ assert isinstance(err.actual_value, float)
@@ -0,0 +1,13 @@
1
+ from dimo.permission_decoder import PermissionDecoder
2
+
3
+
4
+ def test_dimo_client_hex_to_permissions():
5
+ permissions_hex = "0x3ffc"
6
+ permissions_list = PermissionDecoder.decode_permission_bits(permissions_hex)
7
+ assert permissions_list == [1, 2, 3, 4, 5, 6]
8
+
9
+ one_to_five_hex = "0xffc"
10
+ assert PermissionDecoder.decode_permission_bits(one_to_five_hex) == [1, 2, 3, 4, 5]
11
+
12
+ another_hex = "0x3fcc"
13
+ assert PermissionDecoder.decode_permission_bits(another_hex) == [1, 3, 4, 5, 6]
@@ -0,0 +1,90 @@
1
+ import json
2
+ import pytest
3
+ from requests import RequestException
4
+ from unittest.mock import Mock
5
+
6
+ from dimo.request import Request, HTTPError
7
+
8
+
9
+ class DummyResponse:
10
+ def __init__(
11
+ self, status_code=200, headers=None, json_data=None, content=b"", txt=""
12
+ ):
13
+ self.status_code = status_code
14
+ self.headers = headers or {}
15
+ self._json_data = json_data
16
+ self.content = content
17
+ self.txt = txt
18
+ # .raise_for_status will be set per-test via side_effect
19
+
20
+ def json(self):
21
+ if isinstance(self._json_data, Exception):
22
+ raise self._json_data
23
+ return self._json_data
24
+
25
+
26
+ @pytest.fixture
27
+ def session():
28
+ return Mock()
29
+
30
+
31
+ def make_request(session, **kwargs):
32
+ req = Request("POST", "https://api.example.com/endpoint", session)
33
+ return req(**kwargs)
34
+
35
+
36
+ def test_json_request_body_is_serialized_and_passed_through(session):
37
+ data = {"foo": "bar"}
38
+ headers = {"Content-Type": "application/json"}
39
+ resp = DummyResponse(
40
+ status_code=200,
41
+ headers={"Content-Type": "application/json"},
42
+ json_data={"ok": True},
43
+ )
44
+ resp.raise_for_status = Mock()
45
+ session.request.return_value = resp
46
+
47
+ result = make_request(session, headers=headers, data=data)
48
+
49
+ # ensure data was JSON-dumped
50
+ _, call_kwargs = session.request.call_args
51
+ assert call_kwargs["data"] == json.dumps(data)
52
+
53
+ # ensure we got the parsed JSON back
54
+ assert result == {"ok": True}
55
+
56
+
57
+ def test_non_json_response_returns_raw_content(session):
58
+ resp = DummyResponse(
59
+ status_code=200,
60
+ headers={"Content-Type": "text/plain"},
61
+ content=b"hello world",
62
+ )
63
+ resp.raise_for_status = Mock()
64
+ session.request.return_value = resp
65
+
66
+ result = make_request(session)
67
+ assert result == b"hello world"
68
+
69
+
70
+ def test_http_error_wraps_json_body(session):
71
+ # prepare a RequestException with a response whose .json() returns a dict
72
+ err_resp = DummyResponse(
73
+ status_code=400,
74
+ json_data={"error": "Bad things"},
75
+ txt="Bad things text",
76
+ )
77
+ exc = RequestException("Bad Request")
78
+ exc.response = err_resp
79
+
80
+ # have raise_for_status raise that exception
81
+ good_resp = DummyResponse()
82
+ good_resp.raise_for_status = Mock(side_effect=exc)
83
+ session.request.return_value = good_resp
84
+
85
+ with pytest.raises(HTTPError) as ei:
86
+ make_request(session)
87
+ err = ei.value
88
+ assert err.status == 400
89
+ assert err.body == {"error": "Bad things"}
90
+ assert "Bad Request" in str(err)
@@ -1,65 +0,0 @@
1
- from .api.attestation import Attestation
2
- from .api.auth import Auth
3
- from .api.device_definitions import DeviceDefinitions
4
- from .api.token_exchange import TokenExchange
5
- from .api.trips import Trips
6
- from .api.valuations import Valuations
7
-
8
- from .graphql.identity import Identity
9
- from .graphql.telemetry import Telemetry
10
-
11
- from .request import Request
12
- from .environments import dimo_environment
13
- import re
14
-
15
-
16
- class DIMO:
17
-
18
- def __init__(self, env="Production"):
19
- self.env = env
20
- self.urls = dimo_environment[env]
21
- self._client_id = None
22
- self.attestation = Attestation(self.request, self._get_auth_headers)
23
- self.auth = Auth(self.request, self._get_auth_headers, self.env, self)
24
- self.device_definitions = DeviceDefinitions(
25
- self.request, self._get_auth_headers
26
- )
27
- self.identity = Identity(self)
28
- self.token_exchange = TokenExchange(
29
- self.request, self._get_auth_headers, self.identity, self
30
- )
31
- self.trips = Trips(self.request, self._get_auth_headers)
32
- self.valuations = Valuations(self.request, self._get_auth_headers)
33
- self.telemetry = Telemetry(self)
34
- self._session = Request.session
35
-
36
- # Creates a full path for endpoints combining DIMO service, specific endpoint, and optional params
37
- def _get_full_path(self, service, path, params=None):
38
- base_path = self.urls[service]
39
- full_path = f"{base_path}{path}"
40
-
41
- if params:
42
- for key, value in params.items():
43
- pattern = f":{key}"
44
- full_path = re.sub(pattern, str(value), full_path)
45
- return full_path
46
-
47
- # Sets headers based on access_token or privileged_token
48
- def _get_auth_headers(self, token):
49
- return {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
50
-
51
- # request method for HTTP requests for the REST API
52
- def request(self, http_method, service, path, **kwargs):
53
- full_path = self._get_full_path(service, path)
54
- return Request(http_method, full_path)(**kwargs)
55
-
56
- # query method for graphQL queries, identity and telemetry
57
- def query(self, service, query, variables=None, token=None):
58
- headers = self._get_auth_headers(token) if token else {}
59
- headers["Content-Type"] = "application/json"
60
- headers["User-Agent"] = "dimo-python-sdk"
61
-
62
- data = {"query": query, "variables": variables or {}}
63
-
64
- response = self.request("POST", service, "", headers=headers, data=data)
65
- return response
@@ -1,38 +0,0 @@
1
- import json
2
- import requests
3
-
4
-
5
- class Request:
6
-
7
- session = requests.Session()
8
-
9
- def __init__(self, http_method, url):
10
- self.http_method = http_method
11
- self.url = url
12
-
13
- def __call__(self, headers=None, data=None, params=None, **kwargs):
14
- headers = headers or {}
15
- headers.update(kwargs.pop("headers", {}))
16
-
17
- if (
18
- data
19
- and isinstance(data, dict)
20
- and headers.get("Content-Type") == "application/json"
21
- ):
22
- data = json.dumps(data)
23
-
24
- response = self.session.request(
25
- method=self.http_method,
26
- url=self.url,
27
- headers=headers,
28
- params=params,
29
- data=data,
30
- **kwargs,
31
- )
32
-
33
- # TODO: Better error responses
34
- response.raise_for_status()
35
-
36
- if response.content:
37
- return response.json()
38
- return None
File without changes