acex-client 4.2.0__tar.gz → 4.2.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.
- {acex_client-4.2.0 → acex_client-4.2.2}/PKG-INFO +4 -4
- {acex_client-4.2.0 → acex_client-4.2.2}/pyproject.toml +4 -4
- {acex_client-4.2.0 → acex_client-4.2.2}/src/acex_client/acex/resources/neds.py +19 -19
- acex_client-4.2.2/src/acex_client/acex/resources/node_instances.py +11 -0
- acex_client-4.2.2/src/acex_client/acex/resources/resource_base.py +63 -0
- {acex_client-4.2.0 → acex_client-4.2.2}/src/acex_client/models/generated_models.py +1 -1
- {acex_client-4.2.0 → acex_client-4.2.2}/src/acex_client/restclient/restclient.py +2 -2
- acex_client-4.2.0/src/acex_client/acex/resources/node_instances.py +0 -11
- acex_client-4.2.0/src/acex_client/acex/resources/resource_base.py +0 -56
- {acex_client-4.2.0 → acex_client-4.2.2}/README.md +0 -0
- {acex_client-4.2.0 → acex_client-4.2.2}/src/acex_client/__init__.py +0 -0
- {acex_client-4.2.0 → acex_client-4.2.2}/src/acex_client/acex/__init__.py +0 -0
- {acex_client-4.2.0 → acex_client-4.2.2}/src/acex_client/acex/acex.py +0 -0
- {acex_client-4.2.0 → acex_client-4.2.2}/src/acex_client/acex/resources/assets.py +0 -0
- {acex_client-4.2.0 → acex_client-4.2.2}/src/acex_client/acex/resources/logical_nodes.py +0 -0
- {acex_client-4.2.0 → acex_client-4.2.2}/src/acex_client/restclient/__init__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: acex-client
|
|
3
|
-
Version: 4.2.
|
|
3
|
+
Version: 4.2.2
|
|
4
4
|
Summary: ACE-X CLIENT - Client for ACE-X
|
|
5
5
|
License: AGPL-3.0
|
|
6
6
|
Keywords: automation,control
|
|
@@ -11,9 +11,9 @@ Classifier: License :: OSI Approved :: GNU Affero General Public License v3
|
|
|
11
11
|
Classifier: Programming Language :: Python :: 3
|
|
12
12
|
Classifier: Programming Language :: Python :: 3.13
|
|
13
13
|
Classifier: Programming Language :: Python :: 3.14
|
|
14
|
-
Requires-Dist: acex (>=
|
|
15
|
-
Requires-Dist: acex-devkit (>=1.
|
|
16
|
-
Requires-Dist: acex-driver-cisco-ioscli (>=0.
|
|
14
|
+
Requires-Dist: acex (>=5.5.0,<6.0.0)
|
|
15
|
+
Requires-Dist: acex-devkit (>=1.5.1,<2.0.0)
|
|
16
|
+
Requires-Dist: acex-driver-cisco-ioscli (>=0.4.1,<0.5.0)
|
|
17
17
|
Requires-Dist: datamodel-code-generator (>=0.43.1,<0.44.0)
|
|
18
18
|
Requires-Dist: datetime (>=6.0,<7.0)
|
|
19
19
|
Requires-Dist: pydantic (>=2.12.5,<3.0.0)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "acex-client"
|
|
3
|
-
version = "4.2.
|
|
3
|
+
version = "4.2.2"
|
|
4
4
|
description = "ACE-X CLIENT - Client for ACE-X"
|
|
5
5
|
authors = ["Johan Lahti <johan.lahti@acebit.se>"]
|
|
6
6
|
readme = "README.md"
|
|
@@ -18,9 +18,9 @@ requests = "^2.32.5"
|
|
|
18
18
|
datamodel-code-generator = "^0.43.1"
|
|
19
19
|
pydantic = "^2.12.5"
|
|
20
20
|
datetime = "^6.0"
|
|
21
|
-
acex = "^
|
|
22
|
-
acex-devkit = "^1.
|
|
23
|
-
acex-driver-cisco-ioscli = "^0.
|
|
21
|
+
acex = "^5.5.0"
|
|
22
|
+
acex-devkit = "^1.5.1"
|
|
23
|
+
acex-driver-cisco-ioscli = "^0.4.1"
|
|
24
24
|
|
|
25
25
|
[build-system]
|
|
26
26
|
requires = ["poetry-core>=2.0.0,<3.0.0"]
|
|
@@ -13,25 +13,25 @@ class Neds(Resource):
|
|
|
13
13
|
|
|
14
14
|
def __init__(self, rest_client):
|
|
15
15
|
self.rest = rest_client
|
|
16
|
-
self.
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
def
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
16
|
+
self._drivers = None
|
|
17
|
+
|
|
18
|
+
@property
|
|
19
|
+
def drivers(self):
|
|
20
|
+
if self._drivers is None:
|
|
21
|
+
self._drivers = {}
|
|
22
|
+
for entry_point in entry_points(group="acex.neds"):
|
|
23
|
+
try:
|
|
24
|
+
_class = entry_point.load()
|
|
25
|
+
instance = _class()
|
|
26
|
+
version = entry_point.dist.version
|
|
27
|
+
self._drivers[_class.__name__] = {
|
|
28
|
+
"instance": instance,
|
|
29
|
+
"version": version,
|
|
30
|
+
"package_name": entry_point.dist.name,
|
|
31
|
+
}
|
|
32
|
+
except Exception as e:
|
|
33
|
+
print(f"Error when loading {entry_point.name}: {e}")
|
|
34
|
+
return self._drivers
|
|
35
35
|
|
|
36
36
|
def _url_for_wheel(self, ned: Ned) -> str:
|
|
37
37
|
"""
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
class PaginatedResult:
|
|
2
|
+
"""Wraps a paginated API response with iteration support."""
|
|
3
|
+
|
|
4
|
+
def __init__(self, items, total, limit, offset):
|
|
5
|
+
self.items = items
|
|
6
|
+
self.total = total
|
|
7
|
+
self.limit = limit
|
|
8
|
+
self.offset = offset
|
|
9
|
+
|
|
10
|
+
def __iter__(self):
|
|
11
|
+
return iter(self.items)
|
|
12
|
+
|
|
13
|
+
def __len__(self):
|
|
14
|
+
return len(self.items)
|
|
15
|
+
|
|
16
|
+
def __bool__(self):
|
|
17
|
+
return len(self.items) > 0
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class Resource:
|
|
21
|
+
|
|
22
|
+
def __init__(self, rest_client):
|
|
23
|
+
self.rest = rest_client
|
|
24
|
+
|
|
25
|
+
@property
|
|
26
|
+
def ep(self):
|
|
27
|
+
return self.__class__.ENDPOINT or ""
|
|
28
|
+
|
|
29
|
+
@property
|
|
30
|
+
def list_model(self):
|
|
31
|
+
return self.__class__.RESPONSE_MODEL_LIST
|
|
32
|
+
|
|
33
|
+
@property
|
|
34
|
+
def single_model(self):
|
|
35
|
+
return self.__class__.RESPONSE_MODEL_SINGLE
|
|
36
|
+
|
|
37
|
+
def get(self, id):
|
|
38
|
+
data = self.rest.get_item(self.ep, id)
|
|
39
|
+
if data != {}:
|
|
40
|
+
return self.single_model(**data)
|
|
41
|
+
|
|
42
|
+
def query(self, limit=100, offset=0, **filters):
|
|
43
|
+
"""Query with pagination and filters. Returns PaginatedResult."""
|
|
44
|
+
params = {k: v for k, v in filters.items() if v is not None}
|
|
45
|
+
params["limit"] = limit
|
|
46
|
+
params["offset"] = offset
|
|
47
|
+
data = self.rest.query_items(self.ep, params=params)
|
|
48
|
+
|
|
49
|
+
# Handle paginated response: {items: [...], total: N, limit: N, offset: N}
|
|
50
|
+
if isinstance(data, dict) and "items" in data:
|
|
51
|
+
items = [self.list_model(**item) for item in data["items"]]
|
|
52
|
+
return PaginatedResult(items, data["total"], data["limit"], data["offset"])
|
|
53
|
+
|
|
54
|
+
# Handle plain list response (e.g. NEDs endpoint)
|
|
55
|
+
if isinstance(data, list):
|
|
56
|
+
items = [self.list_model(**item) for item in data]
|
|
57
|
+
return PaginatedResult(items, len(items), len(items), 0)
|
|
58
|
+
|
|
59
|
+
return PaginatedResult([], 0, limit, offset)
|
|
60
|
+
|
|
61
|
+
def get_all(self):
|
|
62
|
+
"""Backwards-compatible: returns list of all items."""
|
|
63
|
+
return self.query().items
|
|
@@ -18,8 +18,8 @@ class RestClient:
|
|
|
18
18
|
data = {}
|
|
19
19
|
return data
|
|
20
20
|
|
|
21
|
-
def query_items(self, endpoint: str, params: dict =
|
|
21
|
+
def query_items(self, endpoint: str, params: dict = None):
|
|
22
22
|
url = f"{self.url}{endpoint}"
|
|
23
|
-
response = requests.get(url, verify=self.verify)
|
|
23
|
+
response = requests.get(url, params=params, verify=self.verify)
|
|
24
24
|
data = response.json()
|
|
25
25
|
return data
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
from acex_client.models.generated_models import Node, Ned
|
|
3
|
-
from acex_devkit.models import NodeResponse
|
|
4
|
-
from .resource_base import Resource
|
|
5
|
-
|
|
6
|
-
class NodeInstances(Resource):
|
|
7
|
-
|
|
8
|
-
ENDPOINT = "/inventory/node_instances/"
|
|
9
|
-
RESPONSE_MODEL_SINGLE = NodeResponse
|
|
10
|
-
RESPONSE_MODEL_LIST = Node
|
|
11
|
-
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
class Resource:
|
|
5
|
-
|
|
6
|
-
def __init__(
|
|
7
|
-
self,
|
|
8
|
-
rest_client
|
|
9
|
-
):
|
|
10
|
-
self.rest = rest_client
|
|
11
|
-
|
|
12
|
-
@property
|
|
13
|
-
def ep(self):
|
|
14
|
-
"""
|
|
15
|
-
Each resource that inherits this class
|
|
16
|
-
can set their specific endpoint as a class
|
|
17
|
-
variable and get it using this prop.
|
|
18
|
-
"""
|
|
19
|
-
return self.__class__.ENDPOINT or ""
|
|
20
|
-
|
|
21
|
-
@property
|
|
22
|
-
def list_model(self):
|
|
23
|
-
"""
|
|
24
|
-
Each resource define their specific response model
|
|
25
|
-
as a class variable that can be used via this
|
|
26
|
-
property. this property handles the model
|
|
27
|
-
used when listing multiple items.
|
|
28
|
-
"""
|
|
29
|
-
return self.__class__.RESPONSE_MODEL_LIST
|
|
30
|
-
|
|
31
|
-
@property
|
|
32
|
-
def single_model(self):
|
|
33
|
-
"""
|
|
34
|
-
Each resource define their specific response model
|
|
35
|
-
as a class variable that can be used via this
|
|
36
|
-
property. this property handles the model
|
|
37
|
-
used when getting single item.
|
|
38
|
-
"""
|
|
39
|
-
return self.__class__.RESPONSE_MODEL_SINGLE
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
def get(self, id):
|
|
43
|
-
data = self.rest.get_item(self.ep, id)
|
|
44
|
-
|
|
45
|
-
if data != {}:
|
|
46
|
-
resource = self.single_model(**data)
|
|
47
|
-
return resource
|
|
48
|
-
|
|
49
|
-
def get_all(self):
|
|
50
|
-
response = []
|
|
51
|
-
api_response = self.rest.query_items(self.ep)
|
|
52
|
-
|
|
53
|
-
for resource in api_response:
|
|
54
|
-
response.append(self.list_model(**resource))
|
|
55
|
-
|
|
56
|
-
return response
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|