cloudshell-rest-api 8.2.4.0__tar.gz → 9.0.2__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 (43) hide show
  1. {cloudshell-rest-api-8.2.4.0 → cloudshell_rest_api-9.0.2}/HISTORY.rst +8 -0
  2. cloudshell_rest_api-9.0.2/MANIFEST.in +8 -0
  3. cloudshell_rest_api-9.0.2/PKG-INFO +118 -0
  4. cloudshell_rest_api-9.0.2/README.md +39 -0
  5. cloudshell_rest_api-9.0.2/cloudshell/__init__.py +3 -0
  6. cloudshell_rest_api-9.0.2/cloudshell/rest/__init__.py +3 -0
  7. cloudshell_rest_api-9.0.2/cloudshell/rest/api.py +207 -0
  8. cloudshell_rest_api-9.0.2/cloudshell/rest/exceptions.py +14 -0
  9. cloudshell_rest_api-9.0.2/cloudshell/rest/models.py +74 -0
  10. cloudshell_rest_api-9.0.2/cloudshell/rest/progress_bar.py +66 -0
  11. cloudshell_rest_api-9.0.2/cloudshell_rest_api.egg-info/PKG-INFO +118 -0
  12. {cloudshell-rest-api-8.2.4.0 → cloudshell_rest_api-9.0.2}/cloudshell_rest_api.egg-info/SOURCES.txt +6 -4
  13. cloudshell_rest_api-9.0.2/cloudshell_rest_api.egg-info/requires.txt +5 -0
  14. cloudshell_rest_api-9.0.2/requirements.txt +5 -0
  15. cloudshell_rest_api-9.0.2/setup.cfg +4 -0
  16. cloudshell_rest_api-9.0.2/setup.py +38 -0
  17. cloudshell_rest_api-9.0.2/test_requirements.txt +3 -0
  18. cloudshell_rest_api-9.0.2/tests/__init__.py +1 -0
  19. cloudshell_rest_api-9.0.2/tests/multipart_matcher.py +26 -0
  20. cloudshell_rest_api-9.0.2/tests/test_api.py +487 -0
  21. cloudshell_rest_api-9.0.2/version.txt +1 -0
  22. cloudshell-rest-api-8.2.4.0/MANIFEST.in +0 -15
  23. cloudshell-rest-api-8.2.4.0/PKG-INFO +0 -115
  24. cloudshell-rest-api-8.2.4.0/README.rst +0 -57
  25. cloudshell-rest-api-8.2.4.0/cloudshell/__init__.py +0 -5
  26. cloudshell-rest-api-8.2.4.0/cloudshell/rest/__init__.py +0 -5
  27. cloudshell-rest-api-8.2.4.0/cloudshell/rest/api.py +0 -236
  28. cloudshell-rest-api-8.2.4.0/cloudshell/rest/exceptions.py +0 -6
  29. cloudshell-rest-api-8.2.4.0/cloudshell/version.py +0 -1
  30. cloudshell-rest-api-8.2.4.0/cloudshell_rest_api.egg-info/PKG-INFO +0 -115
  31. cloudshell-rest-api-8.2.4.0/cloudshell_rest_api.egg-info/requires.txt +0 -1
  32. cloudshell-rest-api-8.2.4.0/requirements.txt +0 -1
  33. cloudshell-rest-api-8.2.4.0/setup.cfg +0 -26
  34. cloudshell-rest-api-8.2.4.0/setup.py +0 -47
  35. cloudshell-rest-api-8.2.4.0/test_requirements.txt +0 -2
  36. cloudshell-rest-api-8.2.4.0/tests/__init__.py +0 -1
  37. cloudshell-rest-api-8.2.4.0/tests/test_packaging_rest_api_client.py +0 -379
  38. {cloudshell-rest-api-8.2.4.0 → cloudshell_rest_api-9.0.2}/AUTHORS.rst +0 -0
  39. {cloudshell-rest-api-8.2.4.0 → cloudshell_rest_api-9.0.2}/CONTRIBUTING.rst +0 -0
  40. {cloudshell-rest-api-8.2.4.0 → cloudshell_rest_api-9.0.2}/LICENSE +0 -0
  41. {cloudshell-rest-api-8.2.4.0 → cloudshell_rest_api-9.0.2}/cloudshell_rest_api.egg-info/dependency_links.txt +0 -0
  42. {cloudshell-rest-api-8.2.4.0 → cloudshell_rest_api-9.0.2}/cloudshell_rest_api.egg-info/not-zip-safe +0 -0
  43. {cloudshell-rest-api-8.2.4.0 → cloudshell_rest_api-9.0.2}/cloudshell_rest_api.egg-info/top_level.txt +0 -0
@@ -2,6 +2,14 @@
2
2
  History
3
3
  =======
4
4
 
5
+ 9.0.0 (2023-05-04)
6
+ --------------------
7
+
8
+ * Added get_shell_as_model, get_installed_standards_as_model
9
+ * Added the ability to connect with an existing token
10
+ * Added progress bar for downloading/uploading files
11
+ * Removed support of Python2
12
+
5
13
  8.2.2.0 (2019-01-08)
6
14
  --------------------
7
15
 
@@ -0,0 +1,8 @@
1
+ include AUTHORS.rst
2
+ include CONTRIBUTING.rst
3
+ include HISTORY.rst
4
+ include LICENSE
5
+ include README.md
6
+ include requirements.txt
7
+ include test_requirements.txt
8
+ include version.txt
@@ -0,0 +1,118 @@
1
+ Metadata-Version: 2.4
2
+ Name: cloudshell-rest-api
3
+ Version: 9.0.2
4
+ Summary: Python client for the CloudShell REST API
5
+ Home-page: https://github.com/QualiSystems/cloudshell-rest-api
6
+ Author: Boris Modylevsky
7
+ Author-email: borismod@gmail.com
8
+ License: Apache Software License 2.0
9
+ Keywords: cloudshell quali sandbox cloud rest api
10
+ Classifier: Development Status :: 5 - Production/Stable
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: Apache Software License
13
+ Classifier: Natural Language :: English
14
+ Classifier: Programming Language :: Python :: 3.7
15
+ Classifier: Programming Language :: Python :: 3.9
16
+ Requires-Python: ~=3.7
17
+ License-File: LICENSE
18
+ License-File: AUTHORS.rst
19
+ Requires-Dist: requests<3,>=2.23
20
+ Requires-Dist: attrs<24,>=21
21
+ Requires-Dist: typing-extensions>=4.4
22
+ Requires-Dist: alive_progress~=3.0
23
+ Requires-Dist: requests_toolbelt~=1.0
24
+ Dynamic: author
25
+ Dynamic: author-email
26
+ Dynamic: classifier
27
+ Dynamic: description
28
+ Dynamic: home-page
29
+ Dynamic: keywords
30
+ Dynamic: license
31
+ Dynamic: license-file
32
+ Dynamic: requires-dist
33
+ Dynamic: requires-python
34
+ Dynamic: summary
35
+
36
+ # cloudshell-rest-api
37
+
38
+ [![Build status](https://github.com/QualiSystems/cloudshell-rest-api/workflows/CI/badge.svg?branch=master)](https://github.com/QualiSystems/cloudshell-rest-api/actions?query=branch%3Amaster)
39
+ [![codecov](https://codecov.io/gh/QualiSystems/cloudshell-rest-api/branch/master/graph/badge.svg)](https://codecov.io/gh/QualiSystems/cloudshell-rest-api)
40
+ [![PyPI version](https://badge.fury.io/py/cloudshell-rest-api.svg)](https://badge.fury.io/py/cloudshell-rest-api)
41
+ [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/python/black)
42
+
43
+ ## Features
44
+
45
+ * Add Shell - adds a new Shell Entity (supported from CloudShell 8.0)
46
+ * Update Shell - updates an existing Shell Entity (supported from CloudShell 8.0)
47
+ * Delete Shell - removes an existing Shell Entity (supported from CloudShell 9.2)
48
+ * Get Shell - get Shell's information
49
+ * Get Installed Standards - gets a list of standards and matching versions installed on CloudShell (supported from CloudShell 8.1)
50
+ * Import Package - imports a package to CloudShell
51
+ * Export Package - exports a package from CloudShell
52
+
53
+
54
+ ## Installation
55
+
56
+ ```bash
57
+ pip install cloudshell-rest-api
58
+ ```
59
+
60
+ ## Getting started
61
+
62
+ ```python
63
+ from cloudshell.rest.api import PackagingRestApiClient
64
+ # Loging to CloudShell
65
+ client = PackagingRestApiClient.login("HOST", "USERNAME", "PASSWORD", "DOMAIN")
66
+ # Or connect with a token
67
+ client = PackagingRestApiClient("HOST", "TOKEN")
68
+ # Add a new Shell to CloudShell
69
+ client.add_shell("SHELL_PATH.zip")
70
+ ```
71
+
72
+ ## License
73
+
74
+ * Free software: Apache Software License 2.0
75
+
76
+
77
+ =======
78
+ History
79
+ =======
80
+
81
+ 9.0.0 (2023-05-04)
82
+ --------------------
83
+
84
+ * Added get_shell_as_model, get_installed_standards_as_model
85
+ * Added the ability to connect with an existing token
86
+ * Added progress bar for downloading/uploading files
87
+ * Removed support of Python2
88
+
89
+ 8.2.2.0 (2019-01-08)
90
+ --------------------
91
+
92
+ * Added delete shell method to rest-api
93
+
94
+ 8.2.0.0 (2017-09-19)
95
+ --------------------
96
+
97
+ * newest addition to rest-api. please welcome get_shell - returns a requested shell information
98
+
99
+ 8.1.1.0 (2017-08-27)
100
+ --------------------
101
+
102
+ * remodeling update_shell to also accept shell name
103
+
104
+ 8.1.0.1 (2017-06-12)
105
+ --------------------
106
+
107
+ * Bug fix
108
+
109
+ 8.1.0.0 (2017-06-04)
110
+ --------------------
111
+
112
+ * Query installed standards on CloudShell server
113
+
114
+ 7.2.0.6 (2016-09-01)
115
+ --------------------
116
+
117
+ * First release of with Add Shell and Update Shell features
118
+
@@ -0,0 +1,39 @@
1
+ # cloudshell-rest-api
2
+
3
+ [![Build status](https://github.com/QualiSystems/cloudshell-rest-api/workflows/CI/badge.svg?branch=master)](https://github.com/QualiSystems/cloudshell-rest-api/actions?query=branch%3Amaster)
4
+ [![codecov](https://codecov.io/gh/QualiSystems/cloudshell-rest-api/branch/master/graph/badge.svg)](https://codecov.io/gh/QualiSystems/cloudshell-rest-api)
5
+ [![PyPI version](https://badge.fury.io/py/cloudshell-rest-api.svg)](https://badge.fury.io/py/cloudshell-rest-api)
6
+ [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/python/black)
7
+
8
+ ## Features
9
+
10
+ * Add Shell - adds a new Shell Entity (supported from CloudShell 8.0)
11
+ * Update Shell - updates an existing Shell Entity (supported from CloudShell 8.0)
12
+ * Delete Shell - removes an existing Shell Entity (supported from CloudShell 9.2)
13
+ * Get Shell - get Shell's information
14
+ * Get Installed Standards - gets a list of standards and matching versions installed on CloudShell (supported from CloudShell 8.1)
15
+ * Import Package - imports a package to CloudShell
16
+ * Export Package - exports a package from CloudShell
17
+
18
+
19
+ ## Installation
20
+
21
+ ```bash
22
+ pip install cloudshell-rest-api
23
+ ```
24
+
25
+ ## Getting started
26
+
27
+ ```python
28
+ from cloudshell.rest.api import PackagingRestApiClient
29
+ # Loging to CloudShell
30
+ client = PackagingRestApiClient.login("HOST", "USERNAME", "PASSWORD", "DOMAIN")
31
+ # Or connect with a token
32
+ client = PackagingRestApiClient("HOST", "TOKEN")
33
+ # Add a new Shell to CloudShell
34
+ client.add_shell("SHELL_PATH.zip")
35
+ ```
36
+
37
+ ## License
38
+
39
+ * Free software: Apache Software License 2.0
@@ -0,0 +1,3 @@
1
+ from pkgutil import extend_path
2
+
3
+ __path__ = extend_path(__path__, __name__)
@@ -0,0 +1,3 @@
1
+ from pkgutil import extend_path
2
+
3
+ __path__ = extend_path(__path__, __name__)
@@ -0,0 +1,207 @@
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ from collections.abc import Generator
5
+ from pathlib import Path
6
+ from typing import BinaryIO
7
+ from urllib.parse import urljoin
8
+
9
+ import requests
10
+ from attrs import define, field
11
+ from typing_extensions import Self
12
+
13
+ from cloudshell.rest.exceptions import (
14
+ FeatureUnavailable,
15
+ LoginFailedError,
16
+ PackagingRestApiError,
17
+ ShellNotFound,
18
+ )
19
+ from cloudshell.rest.models import ShellInfo, StandardInfo
20
+ from cloudshell.rest.progress_bar import iter_resp_with_pb, upload_with_pb
21
+
22
+ DEFAULT_API_TIMEOUT = 15
23
+
24
+
25
+ @define
26
+ class PackagingRestApiClient:
27
+ host: str
28
+ _token: str = field(repr=False)
29
+ port: int = 9000
30
+ _show_progress: bool = field(default=False, repr=False)
31
+ _api_timeout: int = field(default=DEFAULT_API_TIMEOUT, repr=False)
32
+ _api_url: str = field(init=False)
33
+ _headers: dict[str, str] = field(init=False)
34
+
35
+ def __attrs_post_init__(self):
36
+ self._api_url = _get_api_url(self.host, self.port)
37
+ self._headers = {"Authorization": f"Basic {self._token}"}
38
+
39
+ @classmethod
40
+ def login(
41
+ cls,
42
+ host: str,
43
+ username: str,
44
+ password: str,
45
+ domain: str = "Global",
46
+ port: int = 9000,
47
+ show_progress: bool = False,
48
+ api_timeout: int = DEFAULT_API_TIMEOUT,
49
+ ) -> Self:
50
+ url = urljoin(_get_api_url(host, port), "Auth/Login")
51
+ req_data = {
52
+ "username": username,
53
+ "password": password,
54
+ "domain": domain,
55
+ }
56
+ resp = requests.put(url, data=req_data, timeout=api_timeout)
57
+ if resp.status_code == 401:
58
+ raise LoginFailedError(resp.text)
59
+ elif resp.status_code != 200:
60
+ raise PackagingRestApiError(resp.text)
61
+ token = resp.text.strip("'\"")
62
+ return cls(
63
+ host, token, port, show_progress=show_progress, api_timeout=api_timeout
64
+ )
65
+
66
+ def add_shell_from_buffer(self, file_obj: BinaryIO | bytes) -> None:
67
+ """Add a new Shell from the buffer or binary."""
68
+ url = urljoin(self._api_url, "Shells")
69
+ req_data = {"files": ("file", file_obj)}
70
+ headers = self._headers.copy()
71
+
72
+ with upload_with_pb(req_data, headers, show=self._show_progress) as new_data:
73
+ resp = requests.post(
74
+ url, data=new_data, headers=headers, timeout=self._api_timeout
75
+ )
76
+
77
+ if resp.status_code != 201:
78
+ msg = f"Can't add shell, response: {resp.text}"
79
+ raise PackagingRestApiError(msg)
80
+
81
+ def add_shell(self, shell_path: str | Path) -> None:
82
+ """Adds a new Shell Entity to CloudShell.
83
+
84
+ If the shell exists, exception will be thrown
85
+ """
86
+ with open(shell_path, "rb") as f:
87
+ self.add_shell_from_buffer(f)
88
+
89
+ def update_shell_from_buffer(
90
+ self, file_obj: BinaryIO | bytes, shell_name: str
91
+ ) -> None:
92
+ """Updates an existing Shell from the buffer or binary."""
93
+ url = urljoin(self._api_url, f"Shells/{shell_name}")
94
+ req_data = {"files": ("file", file_obj)}
95
+ headers = self._headers.copy()
96
+
97
+ with upload_with_pb(req_data, headers, show=self._show_progress) as new_data:
98
+ resp = requests.put(
99
+ url, data=new_data, headers=headers, timeout=self._api_timeout
100
+ )
101
+
102
+ if resp.status_code == 404:
103
+ raise ShellNotFound()
104
+ elif resp.status_code != 200:
105
+ msg = f"Can't update shell, response: {resp.text}"
106
+ raise PackagingRestApiError(msg)
107
+
108
+ def update_shell(
109
+ self, shell_path: str | Path, shell_name: str | None = None
110
+ ) -> None:
111
+ """Updates an existing Shell Entity in CloudShell."""
112
+ shell_name = shell_name or os.path.basename(shell_path).rsplit(".", 1)[0]
113
+ with open(shell_path, "rb") as f:
114
+ self.update_shell_from_buffer(f, shell_name)
115
+
116
+ def get_installed_standards(self) -> list[dict]:
117
+ """Gets all standards installed on CloudShell."""
118
+ url = urljoin(self._api_url, "Standards")
119
+ resp = requests.get(url, headers=self._headers, timeout=self._api_timeout)
120
+ if resp.status_code == 404:
121
+ raise FeatureUnavailable()
122
+ elif resp.status_code != 200:
123
+ raise PackagingRestApiError(resp.text)
124
+ return resp.json()
125
+
126
+ def get_installed_standards_as_models(self) -> list[StandardInfo]:
127
+ """Get all standards installed on CloudShell as models."""
128
+ return [StandardInfo.from_dict(s) for s in self.get_installed_standards()]
129
+
130
+ def get_shell(self, shell_name: str) -> dict:
131
+ """Get a Shell's information."""
132
+ url = urljoin(self._api_url, f"Shells/{shell_name}")
133
+ resp = requests.get(url, headers=self._headers, timeout=self._api_timeout)
134
+ if resp.status_code == 404:
135
+ raise FeatureUnavailable()
136
+ elif resp.status_code == 400:
137
+ raise ShellNotFound()
138
+ elif resp.status_code != 200:
139
+ raise PackagingRestApiError(resp.text)
140
+ return resp.json()
141
+
142
+ def get_shell_as_model(self, shell_name: str) -> ShellInfo:
143
+ """Get a Shell's information as model."""
144
+ return ShellInfo.from_dict(self.get_shell(shell_name))
145
+
146
+ def delete_shell(self, shell_name: str) -> None:
147
+ """Delete a Shell from the CloudShell."""
148
+ url = urljoin(self._api_url, f"Shells/{shell_name}")
149
+ resp = requests.delete(url, headers=self._headers, timeout=self._api_timeout)
150
+ if resp.status_code == 404:
151
+ raise FeatureUnavailable()
152
+ elif resp.status_code == 400:
153
+ raise ShellNotFound()
154
+ elif resp.status_code != 200:
155
+ raise PackagingRestApiError(resp.text)
156
+
157
+ def export_package(self, topologies: list[str]) -> Generator[bytes, None, None]:
158
+ """Export a package with the topologies from the CloudShell."""
159
+ url = urljoin(self._api_url, "Package/ExportPackage")
160
+ req_data = {"TopologyNames": topologies}
161
+ resp = requests.post(
162
+ url,
163
+ headers=self._headers,
164
+ json=req_data,
165
+ stream=True,
166
+ timeout=self._api_timeout,
167
+ )
168
+
169
+ if resp.status_code == 404:
170
+ raise FeatureUnavailable()
171
+ elif resp.status_code != 200:
172
+ raise PackagingRestApiError(resp.text)
173
+
174
+ yield from iter_resp_with_pb(resp, show=self._show_progress)
175
+
176
+ def export_package_to_file(
177
+ self, topologies: list[str], file_path: str | Path
178
+ ) -> None:
179
+ """Export a package with the topologies and save it to the file."""
180
+ with open(file_path, "wb") as f:
181
+ for data in self.export_package(topologies):
182
+ f.write(data)
183
+
184
+ def import_package_from_buffer(self, file_obj: BinaryIO | bytes) -> None:
185
+ """Import the package from buffer to the CloudShell."""
186
+ url = urljoin(self._api_url, "Package/ImportPackage")
187
+ req_data = {"files": ("file", file_obj)}
188
+ headers = self._headers.copy()
189
+
190
+ with upload_with_pb(req_data, headers, show=self._show_progress) as new_data:
191
+ resp = requests.post(
192
+ url, data=new_data, headers=headers, timeout=self._api_timeout
193
+ )
194
+
195
+ if resp.status_code == 404:
196
+ raise FeatureUnavailable()
197
+ elif resp.status_code != 200:
198
+ raise PackagingRestApiError(resp.text)
199
+
200
+ def import_package(self, package_path: str | Path) -> None:
201
+ """Import the package from the file to the CloudShell."""
202
+ with open(package_path, "rb") as f:
203
+ self.import_package_from_buffer(f)
204
+
205
+
206
+ def _get_api_url(host: str, port: int) -> str:
207
+ return f"http://{host}:{port}/API/"
@@ -0,0 +1,14 @@
1
+ class PackagingRestApiError(Exception):
2
+ """Base packaging REST API Error."""
3
+
4
+
5
+ class ShellNotFound(PackagingRestApiError):
6
+ pass
7
+
8
+
9
+ class FeatureUnavailable(PackagingRestApiError):
10
+ pass
11
+
12
+
13
+ class LoginFailedError(PackagingRestApiError):
14
+ pass
@@ -0,0 +1,74 @@
1
+ from __future__ import annotations
2
+
3
+ from attrs import define, field
4
+ from typing_extensions import Self
5
+
6
+
7
+ @define
8
+ class UserInfo:
9
+ user_name: str
10
+ email: str
11
+
12
+ @classmethod
13
+ def from_dict(cls, info_dict: dict) -> Self:
14
+ return cls(
15
+ user_name=info_dict["Username"],
16
+ email=info_dict["Email"],
17
+ )
18
+
19
+
20
+ @define
21
+ class ExecutionEnvironmentType:
22
+ position: int
23
+ path: str
24
+
25
+ @classmethod
26
+ def from_dict(cls, info_dict: dict) -> Self:
27
+ return cls(
28
+ position=info_dict["Position"],
29
+ path=info_dict["Path"],
30
+ )
31
+
32
+
33
+ @define
34
+ class ShellInfo:
35
+ id: str = field(repr=False) # noqa: A003
36
+ name: str
37
+ version: str
38
+ standard_type: str = field(repr=False)
39
+ modification_date: str = field(repr=False)
40
+ last_modified_by_user: UserInfo = field(repr=False)
41
+ author: str = field(repr=False)
42
+ is_official: bool
43
+ based_on: str = field(repr=False)
44
+ execution_environment_type: ExecutionEnvironmentType = field(repr=False)
45
+
46
+ @classmethod
47
+ def from_dict(cls, info_dict: dict) -> Self:
48
+ return cls(
49
+ id=info_dict["Id"],
50
+ name=info_dict["Name"],
51
+ version=info_dict["Version"],
52
+ standard_type=info_dict["StandardType"],
53
+ modification_date=info_dict["ModificationDate"],
54
+ last_modified_by_user=UserInfo.from_dict(info_dict["LastModifiedByUser"]),
55
+ author=info_dict["Author"],
56
+ is_official=info_dict["IsOfficial"],
57
+ based_on=info_dict["BasedOn"],
58
+ execution_environment_type=ExecutionEnvironmentType.from_dict(
59
+ info_dict["ExecutionEnvironmentType"]
60
+ ),
61
+ )
62
+
63
+
64
+ @define
65
+ class StandardInfo:
66
+ standard_name: str
67
+ versions: list[str]
68
+
69
+ @classmethod
70
+ def from_dict(cls, info_dict: dict) -> Self:
71
+ return cls(
72
+ standard_name=info_dict["StandardName"],
73
+ versions=info_dict["Versions"],
74
+ )
@@ -0,0 +1,66 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Generator
4
+ from contextlib import contextmanager
5
+
6
+ from alive_progress import alive_bar
7
+ from requests import Response
8
+ from requests_toolbelt import MultipartEncoder, MultipartEncoderMonitor
9
+
10
+
11
+ def iter_resp_with_pb(
12
+ resp: Response, show: bool = True, chunk: int = 4096
13
+ ) -> Generator[bytes, None, None]:
14
+ """Iterate over response content with progress bar.
15
+
16
+ The request should be streaming.
17
+ """
18
+ total = int(resp.headers.get("content-length", 0))
19
+
20
+ pb_context = alive_bar(
21
+ total,
22
+ unit="B",
23
+ scale=True,
24
+ disable=not show,
25
+ )
26
+
27
+ with pb_context as bar:
28
+ for data in resp.iter_content(chunk_size=chunk):
29
+ size = len(data)
30
+ bar(size)
31
+ yield data
32
+
33
+
34
+ @contextmanager
35
+ def upload_with_pb(data: dict, headers: dict, show: bool = True):
36
+ """Upload data with progress bar.
37
+
38
+ Returns a new data object which should be used in the request.
39
+ Updates the headers with the new content type.
40
+ """
41
+ e = MultipartEncoder(data)
42
+ pb_context = alive_bar(
43
+ e.len,
44
+ unit="B",
45
+ scale=True,
46
+ disable=not show,
47
+ )
48
+
49
+ with pb_context as bar:
50
+ m = MultipartEncoderMonitor(e, _create_upload_callback(bar))
51
+ headers["Content-Type"] = m.content_type
52
+
53
+ yield m
54
+
55
+
56
+ def _create_upload_callback(bar):
57
+ bytes_read = 0
58
+
59
+ def callback(monitor):
60
+ nonlocal bytes_read
61
+ new_bytes = monitor.bytes_read - bytes_read
62
+ bytes_read = monitor.bytes_read
63
+ if new_bytes:
64
+ bar(new_bytes)
65
+
66
+ return callback
@@ -0,0 +1,118 @@
1
+ Metadata-Version: 2.4
2
+ Name: cloudshell-rest-api
3
+ Version: 9.0.2
4
+ Summary: Python client for the CloudShell REST API
5
+ Home-page: https://github.com/QualiSystems/cloudshell-rest-api
6
+ Author: Boris Modylevsky
7
+ Author-email: borismod@gmail.com
8
+ License: Apache Software License 2.0
9
+ Keywords: cloudshell quali sandbox cloud rest api
10
+ Classifier: Development Status :: 5 - Production/Stable
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: Apache Software License
13
+ Classifier: Natural Language :: English
14
+ Classifier: Programming Language :: Python :: 3.7
15
+ Classifier: Programming Language :: Python :: 3.9
16
+ Requires-Python: ~=3.7
17
+ License-File: LICENSE
18
+ License-File: AUTHORS.rst
19
+ Requires-Dist: requests<3,>=2.23
20
+ Requires-Dist: attrs<24,>=21
21
+ Requires-Dist: typing-extensions>=4.4
22
+ Requires-Dist: alive_progress~=3.0
23
+ Requires-Dist: requests_toolbelt~=1.0
24
+ Dynamic: author
25
+ Dynamic: author-email
26
+ Dynamic: classifier
27
+ Dynamic: description
28
+ Dynamic: home-page
29
+ Dynamic: keywords
30
+ Dynamic: license
31
+ Dynamic: license-file
32
+ Dynamic: requires-dist
33
+ Dynamic: requires-python
34
+ Dynamic: summary
35
+
36
+ # cloudshell-rest-api
37
+
38
+ [![Build status](https://github.com/QualiSystems/cloudshell-rest-api/workflows/CI/badge.svg?branch=master)](https://github.com/QualiSystems/cloudshell-rest-api/actions?query=branch%3Amaster)
39
+ [![codecov](https://codecov.io/gh/QualiSystems/cloudshell-rest-api/branch/master/graph/badge.svg)](https://codecov.io/gh/QualiSystems/cloudshell-rest-api)
40
+ [![PyPI version](https://badge.fury.io/py/cloudshell-rest-api.svg)](https://badge.fury.io/py/cloudshell-rest-api)
41
+ [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/python/black)
42
+
43
+ ## Features
44
+
45
+ * Add Shell - adds a new Shell Entity (supported from CloudShell 8.0)
46
+ * Update Shell - updates an existing Shell Entity (supported from CloudShell 8.0)
47
+ * Delete Shell - removes an existing Shell Entity (supported from CloudShell 9.2)
48
+ * Get Shell - get Shell's information
49
+ * Get Installed Standards - gets a list of standards and matching versions installed on CloudShell (supported from CloudShell 8.1)
50
+ * Import Package - imports a package to CloudShell
51
+ * Export Package - exports a package from CloudShell
52
+
53
+
54
+ ## Installation
55
+
56
+ ```bash
57
+ pip install cloudshell-rest-api
58
+ ```
59
+
60
+ ## Getting started
61
+
62
+ ```python
63
+ from cloudshell.rest.api import PackagingRestApiClient
64
+ # Loging to CloudShell
65
+ client = PackagingRestApiClient.login("HOST", "USERNAME", "PASSWORD", "DOMAIN")
66
+ # Or connect with a token
67
+ client = PackagingRestApiClient("HOST", "TOKEN")
68
+ # Add a new Shell to CloudShell
69
+ client.add_shell("SHELL_PATH.zip")
70
+ ```
71
+
72
+ ## License
73
+
74
+ * Free software: Apache Software License 2.0
75
+
76
+
77
+ =======
78
+ History
79
+ =======
80
+
81
+ 9.0.0 (2023-05-04)
82
+ --------------------
83
+
84
+ * Added get_shell_as_model, get_installed_standards_as_model
85
+ * Added the ability to connect with an existing token
86
+ * Added progress bar for downloading/uploading files
87
+ * Removed support of Python2
88
+
89
+ 8.2.2.0 (2019-01-08)
90
+ --------------------
91
+
92
+ * Added delete shell method to rest-api
93
+
94
+ 8.2.0.0 (2017-09-19)
95
+ --------------------
96
+
97
+ * newest addition to rest-api. please welcome get_shell - returns a requested shell information
98
+
99
+ 8.1.1.0 (2017-08-27)
100
+ --------------------
101
+
102
+ * remodeling update_shell to also accept shell name
103
+
104
+ 8.1.0.1 (2017-06-12)
105
+ --------------------
106
+
107
+ * Bug fix
108
+
109
+ 8.1.0.0 (2017-06-04)
110
+ --------------------
111
+
112
+ * Query installed standards on CloudShell server
113
+
114
+ 7.2.0.6 (2016-09-01)
115
+ --------------------
116
+
117
+ * First release of with Add Shell and Update Shell features
118
+