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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: acex-client
3
- Version: 4.2.0
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 (>=4.3.0,<5.0.0)
15
- Requires-Dist: acex-devkit (>=1.3.0,<2.0.0)
16
- Requires-Dist: acex-driver-cisco-ioscli (>=0.0.17,<0.0.18)
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.0"
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 = "^4.3.0"
22
- acex-devkit = "^1.3.0"
23
- acex-driver-cisco-ioscli = "^0.0.17"
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.drivers = {}
17
- self._load_installed_drivers()
18
-
19
- def _load_installed_drivers(self):
20
- """
21
- Loads installed drivers into self.drivers
22
- """
23
- for entry_point in entry_points(group="acex.neds"):
24
- try:
25
- _class = entry_point.load()
26
- instance = _class()
27
- version = entry_point.dist.version
28
- self.drivers[_class.__name__] = {
29
- "instance": instance,
30
- "version": version,
31
- "package_name": entry_point.dist.name
32
- }
33
- except Exception as e:
34
- print(f"Error when loading {entry_point.name}: {e}")
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,11 @@
1
+
2
+ from acex_devkit.models import NodeResponse, NodeListItem
3
+ from .resource_base import Resource
4
+
5
+
6
+ class NodeInstances(Resource):
7
+
8
+ ENDPOINT = "/inventory/node_instances/"
9
+ RESPONSE_MODEL_SINGLE = NodeResponse
10
+ RESPONSE_MODEL_LIST = NodeListItem
11
+
@@ -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
@@ -35,7 +35,7 @@ class AssetClusterCreate(BaseModel):
35
35
 
36
36
  class AssetRefType(Enum):
37
37
  asset = 'asset'
38
- assetcluster = 'assetcluster'
38
+ asset_cluster = 'asset_cluster'
39
39
 
40
40
 
41
41
  class AssetResponse(BaseModel):
@@ -18,8 +18,8 @@ class RestClient:
18
18
  data = {}
19
19
  return data
20
20
 
21
- def query_items(self, endpoint: str, params: dict = {}, limit: int = 100, cursor: str = None):
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