datacrunch 1.15.0__py3-none-any.whl → 1.16.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.
Files changed (58) hide show
  1. datacrunch/InferenceClient/inference_client.py +200 -65
  2. datacrunch/__init__.py +2 -0
  3. datacrunch/_version.py +6 -0
  4. datacrunch/authentication/authentication.py +7 -14
  5. datacrunch/balance/balance.py +1 -3
  6. datacrunch/constants.py +19 -17
  7. datacrunch/containers/containers.py +151 -123
  8. datacrunch/datacrunch.py +18 -18
  9. datacrunch/helpers.py +7 -2
  10. datacrunch/http_client/http_client.py +14 -14
  11. datacrunch/images/images.py +9 -3
  12. datacrunch/instance_types/instance_types.py +42 -35
  13. datacrunch/instances/instances.py +62 -50
  14. datacrunch/locations/locations.py +1 -2
  15. datacrunch/ssh_keys/ssh_keys.py +3 -4
  16. datacrunch/startup_scripts/startup_scripts.py +10 -8
  17. datacrunch/volume_types/volume_types.py +10 -8
  18. datacrunch/volumes/volumes.py +60 -73
  19. {datacrunch-1.15.0.dist-info → datacrunch-1.16.0.dist-info}/METADATA +46 -72
  20. datacrunch-1.16.0.dist-info/RECORD +35 -0
  21. datacrunch-1.16.0.dist-info/WHEEL +4 -0
  22. datacrunch/__version__.py +0 -1
  23. datacrunch-1.15.0.dist-info/RECORD +0 -69
  24. datacrunch-1.15.0.dist-info/WHEEL +0 -5
  25. datacrunch-1.15.0.dist-info/licenses/LICENSE +0 -21
  26. datacrunch-1.15.0.dist-info/top_level.txt +0 -2
  27. tests/__init__.py +0 -0
  28. tests/integration_tests/__init__.py +0 -0
  29. tests/integration_tests/conftest.py +0 -20
  30. tests/integration_tests/test_instances.py +0 -36
  31. tests/integration_tests/test_locations.py +0 -65
  32. tests/integration_tests/test_volumes.py +0 -94
  33. tests/unit_tests/__init__.py +0 -0
  34. tests/unit_tests/authentication/__init__.py +0 -0
  35. tests/unit_tests/authentication/test_authentication.py +0 -202
  36. tests/unit_tests/balance/__init__.py +0 -0
  37. tests/unit_tests/balance/test_balance.py +0 -25
  38. tests/unit_tests/conftest.py +0 -21
  39. tests/unit_tests/containers/__init__.py +0 -1
  40. tests/unit_tests/containers/test_containers.py +0 -959
  41. tests/unit_tests/http_client/__init__.py +0 -0
  42. tests/unit_tests/http_client/test_http_client.py +0 -193
  43. tests/unit_tests/images/__init__.py +0 -0
  44. tests/unit_tests/images/test_images.py +0 -41
  45. tests/unit_tests/instance_types/__init__.py +0 -0
  46. tests/unit_tests/instance_types/test_instance_types.py +0 -87
  47. tests/unit_tests/instances/__init__.py +0 -0
  48. tests/unit_tests/instances/test_instances.py +0 -483
  49. tests/unit_tests/ssh_keys/__init__.py +0 -0
  50. tests/unit_tests/ssh_keys/test_ssh_keys.py +0 -198
  51. tests/unit_tests/startup_scripts/__init__.py +0 -0
  52. tests/unit_tests/startup_scripts/test_startup_scripts.py +0 -196
  53. tests/unit_tests/test_datacrunch.py +0 -65
  54. tests/unit_tests/test_exceptions.py +0 -33
  55. tests/unit_tests/volume_types/__init__.py +0 -0
  56. tests/unit_tests/volume_types/test_volume_types.py +0 -50
  57. tests/unit_tests/volumes/__init__.py +0 -0
  58. tests/unit_tests/volumes/test_volumes.py +0 -641
File without changes
@@ -1,193 +0,0 @@
1
- import pytest
2
- import responses # https://github.com/getsentry/responses
3
- from unittest.mock import Mock
4
- from datacrunch.exceptions import APIException
5
-
6
- INVALID_REQUEST = 'invalid_request'
7
- INVALID_REQUEST_MESSAGE = 'Your existence is invalid'
8
-
9
- UNAUTHORIZED_REQUEST = 'unauthorized_request'
10
- UNAUTHORIZED_REQUEST_MESSAGE = 'Access token is missing or invalid'
11
-
12
-
13
- class TestHttpClient:
14
- def test_add_base_url(self, http_client):
15
- # arrange
16
- path = "/test"
17
- base = http_client._base_url
18
-
19
- # act
20
- url = http_client._add_base_url(path)
21
-
22
- # assert
23
- assert base == http_client._base_url
24
- assert url == base + path
25
-
26
- def test_generate_bearer_header(self, http_client):
27
- bearer_string = http_client._generate_bearer_header()
28
- access_token = http_client._auth_service._access_token
29
-
30
- assert type(bearer_string) == str
31
- assert bearer_string == f'Bearer {access_token}'
32
-
33
- def test_generate_user_agent(self, http_client):
34
- # arrange
35
- version = http_client._version
36
- client_id_truncated = http_client._auth_service._client_id[0:10]
37
-
38
- # act
39
- user_agent_string = http_client._generate_user_agent()
40
-
41
- # assert
42
- assert type(user_agent_string) == str
43
- assert user_agent_string == f'datacrunch-python-v{version}-{client_id_truncated}'
44
-
45
- def test_generate_headers(self, http_client):
46
- # arrange / act
47
- headers = http_client._generate_headers()
48
- authorization_string = http_client._generate_bearer_header()
49
- user_agent_string = http_client._generate_user_agent()
50
-
51
- # assert
52
- assert type(headers) == dict
53
- assert type(headers['Content-Type']) == str
54
- assert type(headers['Authorization']) == str
55
- assert type(headers['User-Agent']) == str
56
- assert headers['Content-Type'] == 'application/json'
57
- assert headers['Authorization'] == authorization_string
58
- assert headers['User-Agent'] == user_agent_string
59
-
60
- def test_refresh_token_if_expired_refresh_successful(self, http_client):
61
- # act
62
- http_client._refresh_token_if_expired()
63
-
64
- # assert
65
- http_client._auth_service.refresh.assert_called_once()
66
- http_client._auth_service.is_expired.assert_called()
67
- http_client._auth_service.authenticate.assert_called_once()
68
-
69
- def test_refresh_token_if_expired_refresh_failed(self, http_client):
70
- # arrange - make refresh raise an exception
71
- http_client._auth_service.refresh = Mock(side_effect=Exception())
72
-
73
- # act
74
- http_client._refresh_token_if_expired()
75
-
76
- # assert
77
- http_client._auth_service.refresh.assert_called_once()
78
- http_client._auth_service.is_expired.assert_called()
79
- assert http_client._auth_service.authenticate.call_count == 2
80
-
81
- def test_get_successful(self, http_client):
82
- # arrange - add response mock
83
- responses.add(
84
- method=responses.GET,
85
- url=(http_client._base_url + '/test'),
86
- status=200, body='{}',
87
- content_type='application/json'
88
- )
89
-
90
- # act
91
- response = http_client.get('/test')
92
-
93
- # assert
94
- assert response.ok is True
95
- assert response.status_code == 200
96
- assert response.text == '{}'
97
- assert response.headers['Content-Type'] == 'application/json'
98
- assert response.json() == {}
99
- assert responses.assert_call_count(http_client._base_url + '/test', 1) is True
100
-
101
- def test_post_successful(self, http_client):
102
- # arrange - add response mock
103
- responses.add(
104
- method=responses.POST,
105
- url=(http_client._base_url + '/test'),
106
- status=200, body='{}',
107
- content_type='application/json'
108
- )
109
-
110
- # act
111
- response = http_client.post('/test', params={})
112
-
113
- # assert
114
- assert response.ok is True
115
- assert response.status_code == 200
116
- assert response.text == '{}'
117
- assert response.headers['Content-Type'] == 'application/json'
118
- assert response.json() == {}
119
- assert responses.assert_call_count(http_client._base_url + '/test', 1) is True
120
-
121
- def test_delete_successful(self, http_client):
122
- # arrange - add response mock
123
- responses.add(
124
- method=responses.DELETE,
125
- url=(http_client._base_url + '/test'),
126
- status=200,
127
- content_type='application/json'
128
- )
129
-
130
- # act
131
- response = http_client.delete('/test')
132
-
133
- # assert
134
- assert response.ok is True
135
- assert response.status_code == 200
136
- assert response.headers['Content-Type'] == 'application/json'
137
- assert responses.assert_call_count(http_client._base_url + '/test', 1) is True
138
-
139
- def test_get_failed(self, http_client):
140
- # arrange - add response mock
141
- responses.add(
142
- method=responses.GET,
143
- url=(http_client._base_url + '/test'),
144
- status=401,
145
- json={'code': UNAUTHORIZED_REQUEST, 'message': UNAUTHORIZED_REQUEST_MESSAGE},
146
- content_type='application/json'
147
- )
148
- error_str = f'error code: {UNAUTHORIZED_REQUEST}\nmessage: {UNAUTHORIZED_REQUEST_MESSAGE}'
149
-
150
- # act
151
- with pytest.raises(APIException) as excinfo:
152
- http_client.get('/test')
153
-
154
- # assert
155
- assert excinfo.value.code == UNAUTHORIZED_REQUEST
156
- assert excinfo.value.message == UNAUTHORIZED_REQUEST_MESSAGE
157
- assert excinfo.value.__str__() == error_str
158
-
159
- def test_post_failed(self, http_client):
160
- # arrange - add response mock
161
- responses.add(
162
- method=responses.POST,
163
- url=(http_client._base_url + '/test'),
164
- status=400,
165
- json={'code': INVALID_REQUEST, 'message': INVALID_REQUEST_MESSAGE},
166
- content_type='application/json'
167
- )
168
-
169
- # act
170
- with pytest.raises(APIException) as excinfo:
171
- http_client.post('/test', json={'data': '42'})
172
-
173
- # assert
174
- assert excinfo.value.code == INVALID_REQUEST
175
- assert excinfo.value.message == INVALID_REQUEST_MESSAGE
176
-
177
- def test_delete_failed(self, http_client):
178
- # arrange - add response mock
179
- responses.add(
180
- method=responses.DELETE,
181
- url=(http_client._base_url + '/test'),
182
- status=400,
183
- json={'code': INVALID_REQUEST, 'message': INVALID_REQUEST_MESSAGE},
184
- content_type='application/json'
185
- )
186
-
187
- # act
188
- with pytest.raises(APIException) as excinfo:
189
- http_client.delete('/test', json={'data': '42'})
190
-
191
- # assert
192
- assert excinfo.value.code == INVALID_REQUEST
193
- assert excinfo.value.message == INVALID_REQUEST_MESSAGE
File without changes
@@ -1,41 +0,0 @@
1
- import responses # https://github.com/getsentry/responses
2
-
3
- from datacrunch.images.images import ImagesService, Image
4
-
5
-
6
- def test_images(http_client):
7
- # arrange - add response mock
8
- responses.add(
9
- responses.GET,
10
- http_client._base_url + "/images",
11
- json=[
12
- {
13
- "id": "0888da25-bb0d-41cc-a191-dccae45d96fd",
14
- "name": "Ubuntu 20.04 + CUDA 11.0",
15
- "details": [
16
- "Ubuntu 20.04",
17
- "CUDA 11.0"
18
- ],
19
- "image_type": "ubuntu-20.04-cuda-11.0"
20
- }
21
- ],
22
- status=200
23
- )
24
-
25
- image_service = ImagesService(http_client)
26
-
27
- # act
28
- images = image_service.get()
29
-
30
- # assert
31
- assert type(images) == list
32
- assert len(images) == 1
33
- assert type(images[0]) == Image
34
- assert images[0].id == '0888da25-bb0d-41cc-a191-dccae45d96fd'
35
- assert images[0].name == 'Ubuntu 20.04 + CUDA 11.0'
36
- assert images[0].image_type == 'ubuntu-20.04-cuda-11.0'
37
- assert type(images[0].details) == list
38
- assert images[0].details[0] == "Ubuntu 20.04"
39
- assert images[0].details[1] == "CUDA 11.0"
40
- assert type(images[0].__str__()) == str
41
-
File without changes
@@ -1,87 +0,0 @@
1
- import responses # https://github.com/getsentry/responses
2
-
3
- from datacrunch.instance_types.instance_types import InstanceTypesService, InstanceType
4
-
5
- TYPE_ID = "01cf5dc1-a5d2-4972-ae4e-d429115d055b"
6
- CPU_DESCRIPTION = "48 CPU 3.5GHz"
7
- NUMBER_OF_CORES = 48
8
- GPU_DESCRIPTION = "8x NVidia Tesla V100"
9
- NUMBER_OF_GPUS = 8
10
- MEMORY_DESCRIPTION = "192GB RAM"
11
- MEMORY_SIZE = 192
12
- GPU_MEMORY_DESCRIPTION = "128GB VRAM"
13
- GPU_MEMORY_SIZE = 128
14
- STORAGE_DESCRIPTION = "1800GB NVME"
15
- STORAGE_SIZE = 1800
16
- INSTANCE_TYPE_DESCRIPTION = "Dedicated Bare metal Server"
17
- PRICE_PER_HOUR = 5.0
18
- SPOT_PRICE_PER_HOUR = 2.5
19
- INSTANCE_TYPE = "8V100.48M"
20
-
21
-
22
- def test_instance_types(http_client):
23
- # arrange - add response mock
24
- responses.add(
25
- responses.GET,
26
- http_client._base_url + "/instance-types",
27
- json=[
28
- {
29
- "id": TYPE_ID,
30
- "cpu": {
31
- "description": CPU_DESCRIPTION,
32
- "number_of_cores": NUMBER_OF_CORES
33
- },
34
- "gpu": {
35
- "description": GPU_DESCRIPTION,
36
- "number_of_gpus": NUMBER_OF_GPUS
37
- },
38
- "memory": {
39
- "description": MEMORY_DESCRIPTION,
40
- "size_in_gigabytes": MEMORY_SIZE
41
- },
42
- "gpu_memory": {
43
- "description": GPU_MEMORY_DESCRIPTION,
44
- "size_in_gigabytes": GPU_MEMORY_SIZE
45
- },
46
- "storage": {
47
- "description": STORAGE_DESCRIPTION,
48
- "size_in_gigabytes": STORAGE_SIZE
49
- },
50
- "description": INSTANCE_TYPE_DESCRIPTION,
51
- "price_per_hour": "5.00",
52
- "spot_price": "2.50",
53
- "instance_type": INSTANCE_TYPE
54
- }
55
- ],
56
- status=200
57
- )
58
-
59
- instance_types_service = InstanceTypesService(http_client)
60
-
61
- # act
62
- instance_types = instance_types_service.get()
63
- instance_type = instance_types[0]
64
-
65
- # assert
66
- assert type(instance_types) == list
67
- assert len(instance_types) == 1
68
- assert type(instance_type) == InstanceType
69
- assert instance_type.id == TYPE_ID
70
- assert instance_type.description == INSTANCE_TYPE_DESCRIPTION
71
- assert instance_type.price_per_hour == PRICE_PER_HOUR
72
- assert instance_type.spot_price_per_hour == SPOT_PRICE_PER_HOUR
73
- assert instance_type.instance_type == INSTANCE_TYPE
74
- assert type(instance_type.cpu) == dict
75
- assert type(instance_type.gpu) == dict
76
- assert type(instance_type.memory) == dict
77
- assert type(instance_type.storage) == dict
78
- assert instance_type.cpu['description'] == CPU_DESCRIPTION
79
- assert instance_type.gpu['description'] == GPU_DESCRIPTION
80
- assert instance_type.memory['description'] == MEMORY_DESCRIPTION
81
- assert instance_type.gpu_memory['description'] == GPU_MEMORY_DESCRIPTION
82
- assert instance_type.storage['description'] == STORAGE_DESCRIPTION
83
- assert instance_type.cpu['number_of_cores'] == NUMBER_OF_CORES
84
- assert instance_type.gpu['number_of_gpus'] == NUMBER_OF_GPUS
85
- assert instance_type.memory['size_in_gigabytes'] == MEMORY_SIZE
86
- assert instance_type.gpu_memory['size_in_gigabytes'] == GPU_MEMORY_SIZE
87
- assert instance_type.storage['size_in_gigabytes'] == STORAGE_SIZE
File without changes