xpipe_api 0.1.26__py3-none-any.whl → 0.1.28__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.
- xpipe_api/clients.py +33 -14
- xpipe_api-0.1.28.dist-info/METADATA +44 -0
- xpipe_api-0.1.28.dist-info/RECORD +7 -0
- {xpipe_api-0.1.26.dist-info → xpipe_api-0.1.28.dist-info}/WHEEL +1 -1
- xpipe_api-0.1.26.dist-info/METADATA +0 -103
- xpipe_api-0.1.26.dist-info/RECORD +0 -7
- {xpipe_api-0.1.26.dist-info → xpipe_api-0.1.28.dist-info}/LICENSE +0 -0
xpipe_api/clients.py
CHANGED
@@ -19,7 +19,7 @@ class Client:
|
|
19
19
|
base_url: str
|
20
20
|
raise_errors: bool
|
21
21
|
session: Optional[str] = None
|
22
|
-
min_version: Version = Version("
|
22
|
+
min_version: Version = Version("15.2")
|
23
23
|
|
24
24
|
def __init__(
|
25
25
|
self, token: Optional[str] = None, base_url: Optional[str] = None, ptb: bool = False, raise_errors: bool = True
|
@@ -36,7 +36,7 @@ class Client:
|
|
36
36
|
except PermissionError:
|
37
37
|
raise NoTokenFoundException("Bad permissions on xpipe_auth: is the daemon running as another user?")
|
38
38
|
except Exception as e:
|
39
|
-
raise NoTokenFoundException(f"No auth provided and couldn't load xpipe_auth: {e!r}")
|
39
|
+
raise NoTokenFoundException(f"No auth provided and couldn't load xpipe_auth: {e!r}. Is the XPipe daemon running?")
|
40
40
|
|
41
41
|
if not base_url:
|
42
42
|
base_url = "http://127.0.0.1:21722" if ptb else "http://127.0.0.1:21721"
|
@@ -57,11 +57,12 @@ class Client:
|
|
57
57
|
session = response.get("sessionToken", None)
|
58
58
|
if session:
|
59
59
|
self.session = session
|
60
|
+
daemon_version = self.daemon_version()["version"]
|
61
|
+
assert (
|
62
|
+
daemon_version == "dev" or Version(daemon_version) >= self.min_version
|
63
|
+
), f"xpipe_api requires XPipe of at least {self.min_version}"
|
60
64
|
else:
|
61
65
|
raise AuthFailedException(json.dumps(response))
|
62
|
-
assert (
|
63
|
-
Version(self.daemon_version()["version"]) >= self.min_version
|
64
|
-
), f"xpipe_api requires XPipe of at least {self.min_version}"
|
65
66
|
|
66
67
|
def _post(self, *args, **kwargs) -> requests.Response:
|
67
68
|
if not self.session:
|
@@ -109,7 +110,7 @@ class Client:
|
|
109
110
|
def get(self, *args, **kwargs) -> bytes:
|
110
111
|
return self._get(*args, **kwargs).content
|
111
112
|
|
112
|
-
def connection_query(self, categories: str = "
|
113
|
+
def connection_query(self, categories: str = "**", connections: str = "**", types: str = "*") -> List[str]:
|
113
114
|
endpoint = f"{self.base_url}/connection/query"
|
114
115
|
data = {"categoryFilter": categories, "connectionFilter": connections, "typeFilter": types}
|
115
116
|
response = self.post(endpoint, json=data)
|
@@ -124,12 +125,20 @@ class Client:
|
|
124
125
|
response = self.post(endpoint, json=data)
|
125
126
|
return json.loads(response).get("infos", [])
|
126
127
|
|
127
|
-
def connection_add(self, name: str, conn_data: dict, validate: bool = False) -> str:
|
128
|
+
def connection_add(self, name: str, conn_data: dict, validate: bool = False, category: str = None) -> str:
|
128
129
|
endpoint = f"{self.base_url}/connection/add"
|
129
130
|
data = {"name": name, "data": conn_data, "validate": validate}
|
131
|
+
if category:
|
132
|
+
data["category"] = category
|
130
133
|
response = self.post(endpoint, json=data)
|
131
134
|
return json.loads(response)["connection"]
|
132
135
|
|
136
|
+
def category_add(self, name: str, parent: str) -> str:
|
137
|
+
endpoint = f"{self.base_url}/category/add"
|
138
|
+
data = {"name": name, "parent": parent}
|
139
|
+
response = self.post(endpoint, json=data)
|
140
|
+
return json.loads(response)["category"]
|
141
|
+
|
133
142
|
def connection_remove(self, uuids: Union[str, List[str]]):
|
134
143
|
endpoint = f"{self.base_url}/connection/remove"
|
135
144
|
if not isinstance(uuids, list):
|
@@ -161,7 +170,7 @@ class Client:
|
|
161
170
|
data = {"connection": connection}
|
162
171
|
self.post(endpoint, json=data)
|
163
172
|
|
164
|
-
def get_connections(self, categories: str = "
|
173
|
+
def get_connections(self, categories: str = "**", connections: str = "**", types: str = "*") -> List[dict]:
|
165
174
|
"""Convenience method to chain connection/query with connection/info"""
|
166
175
|
uuids = self.connection_query(categories, connections, types)
|
167
176
|
return self.connection_info(uuids) if uuids else []
|
@@ -237,11 +246,13 @@ class AsyncClient(Client):
|
|
237
246
|
session_token = parsed.get("sessionToken", None)
|
238
247
|
if session_token:
|
239
248
|
self.session = session_token
|
249
|
+
daemon_version = (await self.daemon_version())["version"]
|
250
|
+
assert (
|
251
|
+
daemon_version == "dev" or Version(daemon_version) >= self.min_version
|
252
|
+
), f"xpipe_api requires XPipe of at least {self.min_version}"
|
240
253
|
else:
|
241
254
|
raise AuthFailedException(json.dumps(parsed))
|
242
|
-
|
243
|
-
Version((await self.daemon_version())["version"]) >= self.min_version
|
244
|
-
), f"xpipe_api requires XPipe of at least {self.min_version}"
|
255
|
+
|
245
256
|
|
246
257
|
async def _post(self, *args, **kwargs) -> aiohttp.ClientResponse:
|
247
258
|
if not self.session:
|
@@ -301,7 +312,7 @@ class AsyncClient(Client):
|
|
301
312
|
resp = await self._get(*args, **kwargs)
|
302
313
|
return await resp.read()
|
303
314
|
|
304
|
-
async def connection_query(self, categories: str = "
|
315
|
+
async def connection_query(self, categories: str = "**", connections: str = "**", types: str = "*") -> List[str]:
|
305
316
|
endpoint = f"{self.base_url}/connection/query"
|
306
317
|
data = {"categoryFilter": categories, "connectionFilter": connections, "typeFilter": types}
|
307
318
|
response = await self.post(endpoint, json=data)
|
@@ -316,12 +327,20 @@ class AsyncClient(Client):
|
|
316
327
|
response = await self.post(endpoint, json=data)
|
317
328
|
return json.loads(response).get("infos", [])
|
318
329
|
|
319
|
-
async def connection_add(self, name: str, conn_data: dict, validate: bool = False) -> str:
|
330
|
+
async def connection_add(self, name: str, conn_data: dict, validate: bool = False, category: str = None) -> str:
|
320
331
|
endpoint = f"{self.base_url}/connection/add"
|
321
332
|
data = {"name": name, "data": conn_data, "validate": validate}
|
333
|
+
if category:
|
334
|
+
data["category"] = category
|
322
335
|
response = await self.post(endpoint, json=data)
|
323
336
|
return json.loads(response)["connection"]
|
324
337
|
|
338
|
+
async def category_add(self, name: str, parent: str) -> str:
|
339
|
+
endpoint = f"{self.base_url}/category/add"
|
340
|
+
data = {"name": name, "parent": parent}
|
341
|
+
response = await self.post(endpoint, json=data)
|
342
|
+
return json.loads(response)["category"]
|
343
|
+
|
325
344
|
async def connection_remove(self, uuids: Union[str, List[str]]):
|
326
345
|
endpoint = f"{self.base_url}/connection/remove"
|
327
346
|
if not isinstance(uuids, list):
|
@@ -353,7 +372,7 @@ class AsyncClient(Client):
|
|
353
372
|
data = {"connection": connection}
|
354
373
|
await self.post(endpoint, json=data)
|
355
374
|
|
356
|
-
async def get_connections(self, categories: str = "
|
375
|
+
async def get_connections(self, categories: str = "**", connections: str = "**", types: str = "*") -> List[dict]:
|
357
376
|
uuids = await self.connection_query(categories, connections, types)
|
358
377
|
return (await self.connection_info(uuids)) if uuids else []
|
359
378
|
|
@@ -0,0 +1,44 @@
|
|
1
|
+
Metadata-Version: 2.3
|
2
|
+
Name: xpipe_api
|
3
|
+
Version: 0.1.28
|
4
|
+
Summary: Client for the XPipe API
|
5
|
+
License: MIT
|
6
|
+
Author: Clint Olson
|
7
|
+
Author-email: coandco@gmail.com
|
8
|
+
Requires-Python: >=3.10,<4.0
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
11
|
+
Classifier: Programming Language :: Python :: 3.10
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
15
|
+
Requires-Dist: aiohttp-requests (>=0.2.4,<0.3.0)
|
16
|
+
Requires-Dist: packaging (>=24.1,<25.0)
|
17
|
+
Requires-Dist: requests (>=2.32.3,<3.0.0)
|
18
|
+
Project-URL: Repository, https://github.com/xpipe-io/xpipe-python-api
|
19
|
+
Description-Content-Type: text/markdown
|
20
|
+
|
21
|
+
# XPipe Python API
|
22
|
+
|
23
|
+
[](https://github.com/xpipe-io/xpipe-python-api/blob/master/LICENSE)
|
24
|
+
[](https://pypi.org/project/xpipe_api/)
|
25
|
+
|
26
|
+
Python client for the XPipe API. This library is a wrapper for the raw [HTTP API](https://github.com/xpipe-io/xpipe/blob/master/openapi.yaml) and intended to make working with it more convenient.
|
27
|
+
|
28
|
+
```bash
|
29
|
+
python3 -m pip install xpipe_api
|
30
|
+
```
|
31
|
+
|
32
|
+
You can find the documentation at https://docs.xpipe.io/guide/python-api.
|
33
|
+
|
34
|
+
## Development
|
35
|
+
|
36
|
+
To run the test suite, you'll need to define the XPIPE_APIKEY env var. This will allow the two "log in with the ApiKey
|
37
|
+
rather than Local method" tests to work. Here's the recommended method for running the tests with poetry:
|
38
|
+
|
39
|
+
```bash
|
40
|
+
cd /path/to/xpipe-python-api
|
41
|
+
poetry install
|
42
|
+
XPIPE_APIKEY=<api_key> poetry run pytest
|
43
|
+
```
|
44
|
+
|
@@ -0,0 +1,7 @@
|
|
1
|
+
xpipe_api/__init__.py,sha256=XLv-a-mt7OcGS9OQbDBHKBsI4mO-4lgWDA13nZ0njFY,108
|
2
|
+
xpipe_api/clients.py,sha256=ZbNjpuOSsNtt_ge9XQYxNdYB_zQppBbJOUvg1IFg9Qo,19661
|
3
|
+
xpipe_api/exceptions.py,sha256=FdkNKLV1gOH8mOuNM9wH_q3hYNFEdMbQwAEZUX4yZQU,410
|
4
|
+
xpipe_api-0.1.28.dist-info/LICENSE,sha256=hWd_i4lSck0lBXcxe-2P4VCUyPAecKW-X1oOiXv21wE,1089
|
5
|
+
xpipe_api-0.1.28.dist-info/METADATA,sha256=sOkrtJfXrwEpfYmCW3nsbDI24hUqR8X5tSKH1ZWcKKU,1660
|
6
|
+
xpipe_api-0.1.28.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
|
7
|
+
xpipe_api-0.1.28.dist-info/RECORD,,
|
@@ -1,103 +0,0 @@
|
|
1
|
-
Metadata-Version: 2.1
|
2
|
-
Name: xpipe_api
|
3
|
-
Version: 0.1.26
|
4
|
-
Summary: Client for the XPipe API
|
5
|
-
Home-page: https://github.com/xpipe-io/xpipe-python-api
|
6
|
-
License: MIT
|
7
|
-
Author: Clint Olson
|
8
|
-
Author-email: coandco@gmail.com
|
9
|
-
Requires-Python: >=3.10,<4.0
|
10
|
-
Classifier: License :: OSI Approved :: MIT License
|
11
|
-
Classifier: Programming Language :: Python :: 3
|
12
|
-
Classifier: Programming Language :: Python :: 3.10
|
13
|
-
Classifier: Programming Language :: Python :: 3.11
|
14
|
-
Classifier: Programming Language :: Python :: 3.12
|
15
|
-
Requires-Dist: aiohttp-requests (>=0.2.4,<0.3.0)
|
16
|
-
Requires-Dist: packaging (>=24.1,<25.0)
|
17
|
-
Requires-Dist: requests (>=2.32.3,<3.0.0)
|
18
|
-
Project-URL: Repository, https://github.com/xpipe-io/xpipe-python-api
|
19
|
-
Description-Content-Type: text/markdown
|
20
|
-
|
21
|
-
# XPipe Python API
|
22
|
-
|
23
|
-
[](https://github.com/coandco/python_xpipe_api/blob/master/LICENSE)
|
24
|
-
[](https://pypi.org/project/xpipe_api/)
|
25
|
-
|
26
|
-
Python client for the XPipe API. This library is a wrapper for the raw [HTTP API](https://github.com/xpipe-io/xpipe/blob/master/openapi.yaml) and intended to make working with it more convenient.
|
27
|
-
|
28
|
-
## Installation
|
29
|
-
```
|
30
|
-
python3 -m pip install xpipe_api
|
31
|
-
```
|
32
|
-
|
33
|
-
## Usage
|
34
|
-
|
35
|
-
```python
|
36
|
-
from xpipe_api import Client
|
37
|
-
|
38
|
-
# By default, Client() will read an access key from the file xpipe_auth on the local filesystem
|
39
|
-
# and talk to the XPipe HTTP server on localhost. To connect to a remote instance with an API
|
40
|
-
# key, use Client(token="foo", base_url = "http://servername:21721")
|
41
|
-
client = Client()
|
42
|
-
|
43
|
-
# connection_query accepts glob-based filters on the category, connection name, and connection type
|
44
|
-
all_connections = client.connection_query()
|
45
|
-
|
46
|
-
# Each connection includes uuid, category, connection, and type information
|
47
|
-
first_connection_uuid = all_connections[0]["uuid"]
|
48
|
-
|
49
|
-
# Before any shell commands can be run, a shell session must be started on a connection
|
50
|
-
client.shell_start(first_connection_uuid)
|
51
|
-
|
52
|
-
# Prints {'exitCode': 0, 'stdout': 'hello world', 'stderr': ''}
|
53
|
-
print(client.shell_exec(first_connection_uuid, "echo hello world"))
|
54
|
-
|
55
|
-
# Clean up after ourselves by stopping the shell session
|
56
|
-
client.shell_stop(first_connection_uuid)
|
57
|
-
```
|
58
|
-
|
59
|
-
There's also an async version of the client that can be accessed as AsyncClient:
|
60
|
-
|
61
|
-
```python
|
62
|
-
import asyncio
|
63
|
-
from xpipe_api import AsyncClient
|
64
|
-
|
65
|
-
|
66
|
-
async def main():
|
67
|
-
# By default, Client() will read an access key from the file xpipe_auth on the local filesystem
|
68
|
-
# and talk to the XPipe HTTP server on localhost. To connect to a remote instance with an API
|
69
|
-
# key, use Client(token="foo", base_url = "http://servername:21721")
|
70
|
-
client = AsyncClient()
|
71
|
-
|
72
|
-
# connection_query accepts glob-based filters on the category, connection name, and connection type
|
73
|
-
all_connections = await client.connection_query()
|
74
|
-
|
75
|
-
# Each connection includes uuid, category, connection, and type information
|
76
|
-
first_connection_uuid = all_connections[0]["uuid"]
|
77
|
-
|
78
|
-
# Before any shell commands can be run, a shell session must be started on a connection
|
79
|
-
await client.shell_start(first_connection_uuid)
|
80
|
-
|
81
|
-
# Prints {'exitCode': 0, 'stdout': 'hello world', 'stderr': ''}
|
82
|
-
print(await client.shell_exec(first_connection_uuid, "echo hello world"))
|
83
|
-
|
84
|
-
# Clean up after ourselves by stopping the shell session
|
85
|
-
await client.shell_stop(first_connection_uuid)
|
86
|
-
|
87
|
-
|
88
|
-
if __name__ == "__main__":
|
89
|
-
asyncio.run(main())
|
90
|
-
```
|
91
|
-
|
92
|
-
This is only a short summary of the library. You can find more supported functionalities in the source itself.
|
93
|
-
|
94
|
-
## Tests
|
95
|
-
|
96
|
-
To run the test suite, you'll need to define the XPIPE_APIKEY env var. This will allow the two "log in with the ApiKey
|
97
|
-
rather than Local method" tests to work. Here's the recommended method for running the tests with poetry:
|
98
|
-
|
99
|
-
```commandline
|
100
|
-
cd /path/to/python_xpipe_api
|
101
|
-
poetry install
|
102
|
-
XPIPE_APIKEY=<api_key> poetry run pytest
|
103
|
-
```
|
@@ -1,7 +0,0 @@
|
|
1
|
-
xpipe_api/__init__.py,sha256=XLv-a-mt7OcGS9OQbDBHKBsI4mO-4lgWDA13nZ0njFY,108
|
2
|
-
xpipe_api/clients.py,sha256=Pg0jyrJpjv8bB0Xo4vdQUiqK3RsLdlAmJXorJLNBwhw,18740
|
3
|
-
xpipe_api/exceptions.py,sha256=FdkNKLV1gOH8mOuNM9wH_q3hYNFEdMbQwAEZUX4yZQU,410
|
4
|
-
xpipe_api-0.1.26.dist-info/LICENSE,sha256=hWd_i4lSck0lBXcxe-2P4VCUyPAecKW-X1oOiXv21wE,1089
|
5
|
-
xpipe_api-0.1.26.dist-info/METADATA,sha256=EMi4uQvxYDAw6jGDTK_ViCmUzgb9BNOZVeqyJbwIGvY,3900
|
6
|
-
xpipe_api-0.1.26.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
7
|
-
xpipe_api-0.1.26.dist-info/RECORD,,
|
File without changes
|