agilicus 1.305.0__py3-none-any.whl → 1.306.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.
- agilicus/__init__.py +7 -1
- agilicus/agilicus_api/api_client.py +1 -1
- agilicus/agilicus_api/configuration.py +1 -1
- agilicus/agilicus_api_README.md +1 -1
- agilicus/main.py +4 -2
- agilicus/pagination/auto_iterator.py +173 -0
- agilicus/pagination/input.py +3 -0
- agilicus/patches.py +17 -0
- agilicus/resources.py +8 -5
- agilicus/ssh.py +13 -3
- agilicus/tests/pagination/test_auto_iterator.py +340 -0
- {agilicus-1.305.0.dist-info → agilicus-1.306.0.dist-info}/METADATA +1 -1
- {agilicus-1.305.0.dist-info → agilicus-1.306.0.dist-info}/RECORD +16 -14
- {agilicus-1.305.0.dist-info → agilicus-1.306.0.dist-info}/LICENSE.txt +0 -0
- {agilicus-1.305.0.dist-info → agilicus-1.306.0.dist-info}/WHEEL +0 -0
- {agilicus-1.305.0.dist-info → agilicus-1.306.0.dist-info}/entry_points.txt +0 -0
agilicus/__init__.py
CHANGED
|
@@ -15,13 +15,19 @@ from .version import __version__ # noqa
|
|
|
15
15
|
sys.path.append(os.path.dirname(__file__)) # noqa
|
|
16
16
|
|
|
17
17
|
from .agilicus_api import * # noqa
|
|
18
|
+
from .agilicus_api.api_client import Endpoint
|
|
18
19
|
from .agilicus_api import exceptions # noqa
|
|
19
20
|
from . import patches # noqa
|
|
20
|
-
from
|
|
21
|
+
from pagination.pagination import get_many_entries
|
|
22
|
+
|
|
23
|
+
import agilicus_api.api_client
|
|
24
|
+
|
|
25
|
+
endpoint_class = agilicus_api.api_client.Endpoint
|
|
21
26
|
|
|
22
27
|
from .create import create_or_update, add_list_resources, AddInfo, AddResult, find_guid
|
|
23
28
|
|
|
24
29
|
ApiClient = patches.patched_api_client()
|
|
30
|
+
patches.patch_endpoint_class(endpoint_class)
|
|
25
31
|
|
|
26
32
|
|
|
27
33
|
@dataclasses.dataclass
|
|
@@ -77,7 +77,7 @@ class ApiClient(object):
|
|
|
77
77
|
self.default_headers[header_name] = header_value
|
|
78
78
|
self.cookie = cookie
|
|
79
79
|
# Set default User-Agent.
|
|
80
|
-
self.user_agent = 'OpenAPI-Generator/1.
|
|
80
|
+
self.user_agent = 'OpenAPI-Generator/1.306.0/python'
|
|
81
81
|
|
|
82
82
|
def __enter__(self):
|
|
83
83
|
return self
|
|
@@ -387,7 +387,7 @@ class Configuration(object):
|
|
|
387
387
|
"OS: {env}\n"\
|
|
388
388
|
"Python Version: {pyversion}\n"\
|
|
389
389
|
"Version of the API: 2025.10.29\n"\
|
|
390
|
-
"SDK Package Version: 1.
|
|
390
|
+
"SDK Package Version: 1.306.0".\
|
|
391
391
|
format(env=sys.platform, pyversion=sys.version)
|
|
392
392
|
|
|
393
393
|
def get_host_settings(self):
|
agilicus/agilicus_api_README.md
CHANGED
|
@@ -4,7 +4,7 @@ Agilicus is API-first. Modern software is controlled by other software, is open,
|
|
|
4
4
|
The `agilicus_api` package is automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project:
|
|
5
5
|
|
|
6
6
|
- API version: 2025.10.29
|
|
7
|
-
- Package version: 1.
|
|
7
|
+
- Package version: 1.306.0
|
|
8
8
|
- Build package: org.openapitools.codegen.languages.PythonClientCodegen
|
|
9
9
|
For more information, please visit [https://www.agilicus.com/api](https://www.agilicus.com/api)
|
|
10
10
|
|
agilicus/main.py
CHANGED
|
@@ -6199,7 +6199,8 @@ def bulk_delete_resource_permission(ctx, **kwargs):
|
|
|
6199
6199
|
type=resources.resource_type_enum,
|
|
6200
6200
|
)
|
|
6201
6201
|
@click.option("--page-at-id", default=None)
|
|
6202
|
-
@click.option("--limit", default=
|
|
6202
|
+
@click.option("--limit", default=None, type=int)
|
|
6203
|
+
@click.option("--get-all", default=False, is_flag=True)
|
|
6203
6204
|
@click.option("--show-columns", type=str, default=None)
|
|
6204
6205
|
@click.option("--reset-columns", is_flag=True, default=False)
|
|
6205
6206
|
@click.option("--show-stats", is_flag=True, default=None)
|
|
@@ -8471,7 +8472,8 @@ def get_connector_stats_config(ctx, **kwargs):
|
|
|
8471
8472
|
@click.option("--name-slug", default=None)
|
|
8472
8473
|
@click.option("--updated-since", default=None, type=click.DateTime())
|
|
8473
8474
|
@click.option("--resource-id", default=None)
|
|
8474
|
-
@click.option("--limit", default=
|
|
8475
|
+
@click.option("--limit", type=int, default=None)
|
|
8476
|
+
@click.option("--get-all", is_flag=True, default=False)
|
|
8475
8477
|
@click.option(
|
|
8476
8478
|
"--page-on", multiple=True, type=click.Choice(ssh.page_fields), default=None
|
|
8477
8479
|
)
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
"""
|
|
2
|
+
AutoIterator for paginating API client list functions.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
from agilicus_api.exceptions import ApiException
|
|
7
|
+
|
|
8
|
+
_page_on_preference = ["name", "created", "id"]
|
|
9
|
+
_default_page_on = "id"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def get_page_on(list_function):
|
|
13
|
+
"""
|
|
14
|
+
tries to figure out the pagination key to use based on the endpoint:
|
|
15
|
+
- If it's an enum, uses the preferred one in the list, otherwise the first
|
|
16
|
+
- If it's not an enum, just tries the 'default', which is id.
|
|
17
|
+
"""
|
|
18
|
+
# yes, the key here is a tuple or some reason
|
|
19
|
+
result = list(list_function.allowed_values.get(("page_on",), {}).values())
|
|
20
|
+
if not result and "page_on" in list_function.params_map["all"]:
|
|
21
|
+
return [_default_page_on]
|
|
22
|
+
return result
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _determine_page_on(list_function):
|
|
26
|
+
page_on_list = get_page_on(list_function)
|
|
27
|
+
if not page_on_list:
|
|
28
|
+
raise NotImplementedError("pagination not implemented on this endpoint")
|
|
29
|
+
for page_on in _page_on_preference:
|
|
30
|
+
if page_on in page_on_list:
|
|
31
|
+
return [page_on]
|
|
32
|
+
|
|
33
|
+
return [page_on_list[0]]
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def patch_endpoint(list_function):
|
|
37
|
+
setattr(list_function, "auto_paging_iter", AutoIteratorWrapper(list_function))
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class AutoIteratorWrapper:
|
|
41
|
+
def __init__(self, list_function):
|
|
42
|
+
self.list_function = list_function
|
|
43
|
+
|
|
44
|
+
def __call__(self, *args, limit=None, page_size=100, page_sort=None, **kwargs):
|
|
45
|
+
return AutoIterator(
|
|
46
|
+
self.list_function, limit, page_size, page_sort, *args, **kwargs
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class AutoIterator:
|
|
51
|
+
def __init__(
|
|
52
|
+
self, list_function, limit, page_size, page_sort, *args, page_on=None, **kwargs
|
|
53
|
+
):
|
|
54
|
+
"""
|
|
55
|
+
Initializes the AutoIterator.
|
|
56
|
+
|
|
57
|
+
:param list_function: The API client list function to paginate.
|
|
58
|
+
:param args: Positional arguments to pass to the list_function.
|
|
59
|
+
:param kwargs: Keyword arguments to pass to the list_function.
|
|
60
|
+
"""
|
|
61
|
+
self._list_function = list_function
|
|
62
|
+
self._args = args
|
|
63
|
+
self._kwargs = kwargs
|
|
64
|
+
self.page_sort = page_sort or []
|
|
65
|
+
self.limit = limit
|
|
66
|
+
self.page_size = page_size
|
|
67
|
+
self.configured_page_on = page_on or _determine_page_on(self._list_function)
|
|
68
|
+
self._reset()
|
|
69
|
+
|
|
70
|
+
def _reset(self):
|
|
71
|
+
self._total_items = 0
|
|
72
|
+
self._page_on = self.configured_page_on
|
|
73
|
+
self._next_page = []
|
|
74
|
+
self._has_more = True
|
|
75
|
+
self._current_page_items = []
|
|
76
|
+
|
|
77
|
+
def __iter__(self):
|
|
78
|
+
"""
|
|
79
|
+
Returns the iterator object itself.
|
|
80
|
+
"""
|
|
81
|
+
return self
|
|
82
|
+
|
|
83
|
+
def __next__(self):
|
|
84
|
+
"""
|
|
85
|
+
Fetches the next item from the paginated results.
|
|
86
|
+
"""
|
|
87
|
+
if not self._current_page_items and self._has_more:
|
|
88
|
+
self._fetch_next_page()
|
|
89
|
+
|
|
90
|
+
if self._current_page_items:
|
|
91
|
+
return self._current_page_items.pop(0)
|
|
92
|
+
else:
|
|
93
|
+
raise StopIteration
|
|
94
|
+
|
|
95
|
+
def _get_page_list(self, response):
|
|
96
|
+
for key in response.attribute_map:
|
|
97
|
+
if isinstance(response.get(key), list):
|
|
98
|
+
return response.get(key)
|
|
99
|
+
return []
|
|
100
|
+
|
|
101
|
+
def _fetch_next_page(self):
|
|
102
|
+
limit = self.page_size
|
|
103
|
+
if self.limit is not None:
|
|
104
|
+
limit = min(limit, self.limit - self._total_items)
|
|
105
|
+
|
|
106
|
+
try:
|
|
107
|
+
response = self._list_function(
|
|
108
|
+
page_on=self._page_on,
|
|
109
|
+
page_at_key=self._next_page,
|
|
110
|
+
limit=limit,
|
|
111
|
+
page_sort=self.page_sort,
|
|
112
|
+
**self._kwargs,
|
|
113
|
+
)
|
|
114
|
+
except ApiException as exc:
|
|
115
|
+
if exc.status != 400:
|
|
116
|
+
raise
|
|
117
|
+
|
|
118
|
+
_handle_page_failure(exc.body)
|
|
119
|
+
# Shut up the linter, which thinks the above doesn't always throw even
|
|
120
|
+
# though it does
|
|
121
|
+
assert False
|
|
122
|
+
|
|
123
|
+
self._current_page_items = self._get_page_list(response)
|
|
124
|
+
self._total_items = self._total_items + len(self._current_page_items)
|
|
125
|
+
page_info = response.page_info
|
|
126
|
+
if (
|
|
127
|
+
not page_info
|
|
128
|
+
or not self._current_page_items
|
|
129
|
+
or (self.limit and self._total_items >= self.limit)
|
|
130
|
+
):
|
|
131
|
+
self._has_more = False
|
|
132
|
+
return
|
|
133
|
+
|
|
134
|
+
self._next_page = page_info.page_at_key
|
|
135
|
+
self._page_on = page_info.page_on.value
|
|
136
|
+
|
|
137
|
+
# Additional functionality when interacted with as an object
|
|
138
|
+
def all(self):
|
|
139
|
+
"""
|
|
140
|
+
Returns all items by iterating through all pages.
|
|
141
|
+
"""
|
|
142
|
+
all_items = []
|
|
143
|
+
for item in self:
|
|
144
|
+
all_items.append(item)
|
|
145
|
+
return all_items
|
|
146
|
+
|
|
147
|
+
def first(self):
|
|
148
|
+
"""
|
|
149
|
+
Returns the first item, or None if no items.
|
|
150
|
+
"""
|
|
151
|
+
self._reset()
|
|
152
|
+
try:
|
|
153
|
+
return next(self)
|
|
154
|
+
except StopIteration:
|
|
155
|
+
return None
|
|
156
|
+
|
|
157
|
+
def __repr__(self):
|
|
158
|
+
return f"<AutoIterator for {self._list_function.__name__}>"
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def _handle_page_failure(body):
|
|
162
|
+
if not body:
|
|
163
|
+
raise
|
|
164
|
+
result = {}
|
|
165
|
+
try:
|
|
166
|
+
result = json.loads(body)
|
|
167
|
+
except Exception:
|
|
168
|
+
pass
|
|
169
|
+
error_message = result.get("error_message", "")
|
|
170
|
+
if "pagination key" not in error_message:
|
|
171
|
+
raise
|
|
172
|
+
|
|
173
|
+
raise NotImplementedError("Pagination not implemented on this key") from None
|
agilicus/pagination/input.py
CHANGED
agilicus/patches.py
CHANGED
|
@@ -5,6 +5,8 @@ import certifi
|
|
|
5
5
|
from .agilicus_api.api_client import ApiClient
|
|
6
6
|
from .agilicus_api.configuration import Configuration
|
|
7
7
|
|
|
8
|
+
from agilicus.pagination.auto_iterator import get_page_on, patch_endpoint
|
|
9
|
+
|
|
8
10
|
|
|
9
11
|
class _ApiClientWrapper(ApiClient):
|
|
10
12
|
def __init__(self, configuration: Configuration = None, **kwargs):
|
|
@@ -43,3 +45,18 @@ def patched_api_client():
|
|
|
43
45
|
class _Response:
|
|
44
46
|
def __init__(self, data):
|
|
45
47
|
self.data = data
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def patch_endpoint_class(endpoint_class):
|
|
51
|
+
"""
|
|
52
|
+
patches the Endpoint class to inject the AutoIterator into itself if needed.
|
|
53
|
+
"""
|
|
54
|
+
original_init = endpoint_class.__init__
|
|
55
|
+
|
|
56
|
+
def init_wrapper(self, *args, **kwargs):
|
|
57
|
+
original_init(self, *args, **kwargs)
|
|
58
|
+
if not get_page_on(self):
|
|
59
|
+
return
|
|
60
|
+
patch_endpoint(self)
|
|
61
|
+
|
|
62
|
+
endpoint_class.__init__ = init_wrapper
|
agilicus/resources.py
CHANGED
|
@@ -113,7 +113,7 @@ def bulk_delete_permission(ctx, **kwargs):
|
|
|
113
113
|
)
|
|
114
114
|
|
|
115
115
|
|
|
116
|
-
def query_resources(ctx, org_id=None, **kwargs):
|
|
116
|
+
def query_resources(ctx, org_id=None, get_all=False, limit=None, **kwargs):
|
|
117
117
|
org_id = get_org_from_input_or_ctx(ctx, org_id=org_id)
|
|
118
118
|
token = context.get_token(ctx)
|
|
119
119
|
apiclient = context.get_apiclient(ctx, token)
|
|
@@ -121,10 +121,13 @@ def query_resources(ctx, org_id=None, **kwargs):
|
|
|
121
121
|
params = {}
|
|
122
122
|
update_if_not_none(params, kwargs)
|
|
123
123
|
params = normalize_page_args(params)
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
124
|
+
if not get_all:
|
|
125
|
+
if limit is None:
|
|
126
|
+
limit = 500
|
|
127
|
+
return apiclient.resources_api.list_resources(limit=limit, **params).resources
|
|
128
|
+
return apiclient.resources_api.list_resources.auto_paging_iter(
|
|
129
|
+
limit=limit, **params
|
|
130
|
+
).all()
|
|
128
131
|
|
|
129
132
|
|
|
130
133
|
def format_resources(ctx, resources, show_columns=None, reset_columns=None):
|
agilicus/ssh.py
CHANGED
|
@@ -21,13 +21,23 @@ from .resource_helpers import map_resource_published, standard_page_fields
|
|
|
21
21
|
page_fields = standard_page_fields
|
|
22
22
|
|
|
23
23
|
|
|
24
|
-
def list_ssh_resources(ctx, **kwargs):
|
|
24
|
+
def list_ssh_resources(ctx, get_all=False, limit=None, **kwargs):
|
|
25
25
|
apiclient = context.get_apiclient_from_ctx(ctx)
|
|
26
26
|
update_org_from_input_or_ctx(kwargs, ctx, **kwargs)
|
|
27
27
|
params = strip_none(kwargs)
|
|
28
28
|
params = normalize_page_args(params)
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
if not get_all:
|
|
30
|
+
if limit is None:
|
|
31
|
+
limit = 500
|
|
32
|
+
return apiclient.app_services_api.list_ssh_resources(
|
|
33
|
+
limit=limit, **params
|
|
34
|
+
).ssh_resources
|
|
35
|
+
return [
|
|
36
|
+
x
|
|
37
|
+
for x in apiclient.app_services_api.list_ssh_resources.auto_paging_iter(
|
|
38
|
+
limit=limit, **params
|
|
39
|
+
)
|
|
40
|
+
]
|
|
31
41
|
|
|
32
42
|
|
|
33
43
|
def add_ssh_resource(ctx, port, **kwargs):
|
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from unittest.mock import Mock
|
|
3
|
+
from agilicus.pagination.auto_iterator import (
|
|
4
|
+
AutoIterator,
|
|
5
|
+
AutoIteratorWrapper,
|
|
6
|
+
get_page_on,
|
|
7
|
+
_determine_page_on,
|
|
8
|
+
patch_endpoint,
|
|
9
|
+
_handle_page_failure,
|
|
10
|
+
)
|
|
11
|
+
from agilicus_api.exceptions import ApiException
|
|
12
|
+
from agilicus import ListSSHResourcesResponse
|
|
13
|
+
from agilicus_api.api_client import Endpoint
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class MockPageInfo:
|
|
17
|
+
def __init__(self, page_at_key, page_on_value):
|
|
18
|
+
self.page_at_key = page_at_key
|
|
19
|
+
self.page_on = Mock(value=page_on_value)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class MockResponse:
|
|
23
|
+
def __init__(self, items, page_at_key=None, page_on_value=None):
|
|
24
|
+
self.items = items
|
|
25
|
+
self.attribute_map = {"items": "list[object]"}
|
|
26
|
+
self.page_info = (
|
|
27
|
+
MockPageInfo(page_at_key, page_on_value)
|
|
28
|
+
if page_at_key and page_on_value
|
|
29
|
+
else None
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
def get(self, key):
|
|
33
|
+
if key == "items":
|
|
34
|
+
return self.items
|
|
35
|
+
return None
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class MockItem:
|
|
39
|
+
def __init__(self, name, index):
|
|
40
|
+
self.name = name
|
|
41
|
+
self.id = index
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class MockListFunction:
|
|
45
|
+
def __init__(self, items_per_page, total_items, page_on_allowed=None):
|
|
46
|
+
self._all_items = [MockItem(f"item_{i}", i) for i in range(total_items)]
|
|
47
|
+
self._items_per_page = items_per_page
|
|
48
|
+
self.call_count = 0
|
|
49
|
+
self.allowed_values = {}
|
|
50
|
+
self.params_map = {"all": []}
|
|
51
|
+
if page_on_allowed is None:
|
|
52
|
+
page_on_allowed = ["id"]
|
|
53
|
+
if page_on_allowed:
|
|
54
|
+
self.allowed_values = {("page_on",): {k: k for k in page_on_allowed}}
|
|
55
|
+
self.params_map["all"].append("page_on")
|
|
56
|
+
|
|
57
|
+
def __call__(
|
|
58
|
+
self, page_on=None, page_at_key=None, limit=None, page_sort=None, **kwargs
|
|
59
|
+
):
|
|
60
|
+
self.call_count += 1
|
|
61
|
+
start_index = 0
|
|
62
|
+
if page_at_key and page_at_key[0] is not None:
|
|
63
|
+
try:
|
|
64
|
+
start_index = len(self._all_items)
|
|
65
|
+
for idx, item in enumerate(self._all_items):
|
|
66
|
+
compare_tuple = [getattr(item, key) for key in page_on]
|
|
67
|
+
if page_at_key < compare_tuple:
|
|
68
|
+
start_index = idx
|
|
69
|
+
break
|
|
70
|
+
except ValueError:
|
|
71
|
+
start_index = len(self._all_items)
|
|
72
|
+
|
|
73
|
+
end_index = min(start_index + limit, len(self._all_items))
|
|
74
|
+
current_items = self._all_items[start_index:end_index]
|
|
75
|
+
|
|
76
|
+
next_page_at_key = None
|
|
77
|
+
if end_index < len(self._all_items):
|
|
78
|
+
next_page_at_key = [self._all_items[end_index - 1].id]
|
|
79
|
+
|
|
80
|
+
return MockResponse(
|
|
81
|
+
current_items,
|
|
82
|
+
page_at_key=next_page_at_key,
|
|
83
|
+
page_on_value=page_on if page_on else None,
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def test_auto_iterator_basic_pagination():
|
|
88
|
+
mock_list_function = MockListFunction(items_per_page=2, total_items=5)
|
|
89
|
+
iterator = AutoIterator(mock_list_function, limit=None, page_size=2, page_sort=[])
|
|
90
|
+
|
|
91
|
+
items = list(iterator)
|
|
92
|
+
assert len(items) == 5
|
|
93
|
+
assert mock_list_function.call_count == 3 # 5 items, 2 per page = 3 calls (2,2,1)
|
|
94
|
+
assert [item.name for item in items] == [
|
|
95
|
+
"item_0",
|
|
96
|
+
"item_1",
|
|
97
|
+
"item_2",
|
|
98
|
+
"item_3",
|
|
99
|
+
"item_4",
|
|
100
|
+
]
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def test_auto_iterator_with_limit():
|
|
104
|
+
mock_list_function = MockListFunction(items_per_page=2, total_items=5)
|
|
105
|
+
iterator = AutoIterator(mock_list_function, limit=3, page_size=2, page_sort=[])
|
|
106
|
+
|
|
107
|
+
items = list(iterator)
|
|
108
|
+
assert len(items) == 3
|
|
109
|
+
assert mock_list_function.call_count == 2 # 3 items, 2 per page = 2 calls (2,1)
|
|
110
|
+
assert [item.name for item in items] == ["item_0", "item_1", "item_2"]
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def test_auto_iterator_empty_result():
|
|
114
|
+
mock_list_function = MockListFunction(items_per_page=2, total_items=0)
|
|
115
|
+
iterator = AutoIterator(mock_list_function, limit=None, page_size=2, page_sort=[])
|
|
116
|
+
|
|
117
|
+
items = list(iterator)
|
|
118
|
+
assert len(items) == 0
|
|
119
|
+
assert mock_list_function.call_count == 1
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def test_auto_iterator_first_method():
|
|
123
|
+
mock_list_function = MockListFunction(items_per_page=2, total_items=5)
|
|
124
|
+
iterator = AutoIterator(mock_list_function, limit=None, page_size=2, page_sort=[])
|
|
125
|
+
|
|
126
|
+
first_item = iterator.first()
|
|
127
|
+
assert first_item.name == "item_0"
|
|
128
|
+
assert mock_list_function.call_count == 1
|
|
129
|
+
|
|
130
|
+
# Calling first again should re-initialize and get the first item again
|
|
131
|
+
first_item = iterator.first()
|
|
132
|
+
assert first_item.name == "item_0"
|
|
133
|
+
assert mock_list_function.call_count == 2
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def test_auto_iterator_first_method_empty():
|
|
137
|
+
mock_list_function = MockListFunction(items_per_page=2, total_items=0)
|
|
138
|
+
iterator = AutoIterator(mock_list_function, limit=None, page_size=2, page_sort=[])
|
|
139
|
+
|
|
140
|
+
first_item = iterator.first()
|
|
141
|
+
assert first_item is None
|
|
142
|
+
assert mock_list_function.call_count == 1
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def test_auto_iterator_all_method():
|
|
146
|
+
mock_list_function = MockListFunction(items_per_page=2, total_items=5)
|
|
147
|
+
iterator = AutoIterator(mock_list_function, limit=None, page_size=2, page_sort=[])
|
|
148
|
+
|
|
149
|
+
all_items = iterator.all()
|
|
150
|
+
assert len(all_items) == 5
|
|
151
|
+
assert mock_list_function.call_count == 3
|
|
152
|
+
assert [item.name for item in all_items] == [
|
|
153
|
+
"item_0",
|
|
154
|
+
"item_1",
|
|
155
|
+
"item_2",
|
|
156
|
+
"item_3",
|
|
157
|
+
"item_4",
|
|
158
|
+
]
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def test_auto_iterator_all_method_empty():
|
|
162
|
+
mock_list_function = MockListFunction(items_per_page=2, total_items=0)
|
|
163
|
+
iterator = AutoIterator(mock_list_function, limit=None, page_size=2, page_sort=[])
|
|
164
|
+
|
|
165
|
+
all_items = iterator.all()
|
|
166
|
+
assert len(all_items) == 0
|
|
167
|
+
assert mock_list_function.call_count == 1
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def test_auto_iterator_wrapper():
|
|
171
|
+
mock_list_function = MockListFunction(items_per_page=2, total_items=5)
|
|
172
|
+
wrapper = AutoIteratorWrapper(mock_list_function)
|
|
173
|
+
iterator = wrapper(limit=3, page_size=2, page_sort=["name"])
|
|
174
|
+
|
|
175
|
+
assert isinstance(iterator, AutoIterator)
|
|
176
|
+
assert iterator.limit == 3
|
|
177
|
+
assert iterator.page_size == 2
|
|
178
|
+
assert iterator.page_sort == ["name"]
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def test_get_page_on_with_allowed_values():
|
|
182
|
+
mock_list_function = Mock()
|
|
183
|
+
mock_list_function.allowed_values = {("page_on",): {"id": "id", "name": "name"}}
|
|
184
|
+
mock_list_function.params_map = {"all": ["page_on"]}
|
|
185
|
+
assert get_page_on(mock_list_function) == ["id", "name"]
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def test_get_page_on_without_allowed_values_but_in_params_map():
|
|
189
|
+
mock_list_function = Mock()
|
|
190
|
+
mock_list_function.allowed_values = {}
|
|
191
|
+
mock_list_function.params_map = {"all": ["page_on"]}
|
|
192
|
+
assert get_page_on(mock_list_function) == ["id"]
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def test_get_page_on_not_in_params_map():
|
|
196
|
+
mock_list_function = Mock()
|
|
197
|
+
mock_list_function.allowed_values = {}
|
|
198
|
+
mock_list_function.params_map = {"all": []}
|
|
199
|
+
assert get_page_on(mock_list_function) == []
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def test_determine_page_on_preference():
|
|
203
|
+
mock_list_function = Mock()
|
|
204
|
+
mock_list_function.allowed_values = {
|
|
205
|
+
("page_on",): {"created": "created", "id": "id"}
|
|
206
|
+
}
|
|
207
|
+
mock_list_function.params_map = {"all": ["page_on"]}
|
|
208
|
+
assert _determine_page_on(mock_list_function) == ["created"]
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def test_determine_page_on_default():
|
|
212
|
+
mock_list_function = Mock()
|
|
213
|
+
mock_list_function.allowed_values = {("page_on",): {"foo": "foo"}}
|
|
214
|
+
mock_list_function.params_map = {"all": ["page_on"]}
|
|
215
|
+
assert _determine_page_on(mock_list_function) == ["foo"]
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def test_determine_page_on_not_implemented():
|
|
219
|
+
mock_list_function = Mock()
|
|
220
|
+
mock_list_function.allowed_values = {}
|
|
221
|
+
mock_list_function.params_map = {"all": []}
|
|
222
|
+
with pytest.raises(NotImplementedError):
|
|
223
|
+
_determine_page_on(mock_list_function)
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
def test_patch_endpoint():
|
|
227
|
+
mock_list_function = Mock()
|
|
228
|
+
patch_endpoint(mock_list_function)
|
|
229
|
+
assert hasattr(mock_list_function, "auto_paging_iter")
|
|
230
|
+
assert isinstance(mock_list_function.auto_paging_iter, AutoIteratorWrapper)
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def test_handle_page_failure_pagination_key_error():
|
|
234
|
+
exc = ApiException(status=400, reason="Bad Request", http_resp=Mock())
|
|
235
|
+
exc.body = '{"error_message": "Invalid pagination key"}'
|
|
236
|
+
with pytest.raises(
|
|
237
|
+
NotImplementedError, match="Pagination not implemented on this key"
|
|
238
|
+
):
|
|
239
|
+
_handle_page_failure(exc.body)
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def test_handle_page_failure_other_400_error():
|
|
243
|
+
exc = ApiException(status=400, reason="Bad Request", http_resp=Mock())
|
|
244
|
+
exc.body = '{"error_message": "Some other error"}'
|
|
245
|
+
with pytest.raises(ApiException):
|
|
246
|
+
try:
|
|
247
|
+
raise exc
|
|
248
|
+
except Exception as exc:
|
|
249
|
+
_handle_page_failure(exc.body)
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
def test_handle_page_failure_no_body():
|
|
253
|
+
exc = ApiException(status=400, reason="Bad Request", http_resp=Mock())
|
|
254
|
+
exc.body = None
|
|
255
|
+
with pytest.raises(ApiException):
|
|
256
|
+
try:
|
|
257
|
+
raise exc
|
|
258
|
+
except Exception as exc:
|
|
259
|
+
_handle_page_failure(exc.body)
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
def test_handle_page_failure_invalid_json():
|
|
263
|
+
exc = ApiException(status=400, reason="Bad Request", http_resp=Mock())
|
|
264
|
+
exc.body = "invalid json"
|
|
265
|
+
with pytest.raises(ApiException):
|
|
266
|
+
try:
|
|
267
|
+
raise exc
|
|
268
|
+
except Exception as exc:
|
|
269
|
+
_handle_page_failure(exc.body)
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
def test_auto_iterator_api_exception_other_status():
|
|
273
|
+
mock_list_function = Mock()
|
|
274
|
+
mock_list_function.allowed_values = {("page_on",): {"foo": "foo"}}
|
|
275
|
+
mock_list_function.params_map = {"all": ["page_on"]}
|
|
276
|
+
mock_list_function.side_effect = ApiException(
|
|
277
|
+
status=500, reason="Internal Server Error"
|
|
278
|
+
)
|
|
279
|
+
iterator = AutoIterator(mock_list_function, limit=None, page_size=2, page_sort=[])
|
|
280
|
+
|
|
281
|
+
with pytest.raises(ApiException):
|
|
282
|
+
list(iterator)
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
def test_auto_iterator_repr():
|
|
286
|
+
mock_list_function = Mock(
|
|
287
|
+
__name__="mock_list_function",
|
|
288
|
+
allowed_values={("page_on",): {"id": "id"}},
|
|
289
|
+
params_map={"all": ["page_on"]},
|
|
290
|
+
)
|
|
291
|
+
iterator = AutoIterator(mock_list_function, limit=None, page_size=2, page_sort=[])
|
|
292
|
+
assert repr(iterator) == "<AutoIterator for mock_list_function>"
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
def test_auto_patch_endpoint():
|
|
296
|
+
mock_list_function = MockListFunction(items_per_page=2, total_items=5)
|
|
297
|
+
|
|
298
|
+
def wrap_list(*args, **kwargs):
|
|
299
|
+
return mock_list_function(**kwargs)
|
|
300
|
+
|
|
301
|
+
foo = Endpoint(
|
|
302
|
+
settings={
|
|
303
|
+
"response_type": (ListSSHResourcesResponse,),
|
|
304
|
+
"auth": ["token-valid"],
|
|
305
|
+
"endpoint_path": "/v1/ssh_resources",
|
|
306
|
+
"operation_id": "list_ssh_resources",
|
|
307
|
+
"http_method": "GET",
|
|
308
|
+
"servers": None,
|
|
309
|
+
},
|
|
310
|
+
params_map={
|
|
311
|
+
"all": [
|
|
312
|
+
"page_on",
|
|
313
|
+
"page_at_key",
|
|
314
|
+
"page_sort",
|
|
315
|
+
"search_direction",
|
|
316
|
+
],
|
|
317
|
+
"required": [],
|
|
318
|
+
"nullable": [],
|
|
319
|
+
"enum": [
|
|
320
|
+
"page_sort",
|
|
321
|
+
"search_direction",
|
|
322
|
+
],
|
|
323
|
+
"validation": [
|
|
324
|
+
"name",
|
|
325
|
+
"limit",
|
|
326
|
+
],
|
|
327
|
+
},
|
|
328
|
+
root_map={
|
|
329
|
+
"validations": [],
|
|
330
|
+
"allowed_values": {("page_on,"): ["name"]},
|
|
331
|
+
"openapi_types": {},
|
|
332
|
+
"attribute_map": {},
|
|
333
|
+
"location_map": {},
|
|
334
|
+
"collection_format_map": {},
|
|
335
|
+
},
|
|
336
|
+
callable=wrap_list,
|
|
337
|
+
)
|
|
338
|
+
|
|
339
|
+
assert foo.auto_paging_iter is not None
|
|
340
|
+
assert next(foo.auto_paging_iter()).name == "item_0"
|
|
@@ -2,7 +2,7 @@ agilicus/.gitignore,sha256=TyHq6BCuVrFiqgUb1QAayLxWcBseKwEOoKJTQb_-iW8,5
|
|
|
2
2
|
agilicus/.openapi-generator/FILES,sha256=DXwz0MJeKwW9W6-L-Mfel3mqKF_B0kJid1W73EM8X7o,129275
|
|
3
3
|
agilicus/.openapi-generator/VERSION,sha256=LXsIFraL1muXBEww1sZWaewc9ji87Ih3gIa04Z37RYM,14
|
|
4
4
|
agilicus/.openapi-generator-ignore,sha256=pu2PTide7pJtJ-DFLzDy0cTYQJRlrB-8RRH3zGLeUds,1040
|
|
5
|
-
agilicus/__init__.py,sha256=
|
|
5
|
+
agilicus/__init__.py,sha256=130H3LJRZOJa3OR8KdoowHj4qnKRGg6ainocRnwCE20,4310
|
|
6
6
|
agilicus/access.py,sha256=UEHHhE3cCaCjxXQDjhKxQAoUEMWandygN0d-yEIIf8A,5457
|
|
7
7
|
agilicus/admin.py,sha256=rPXaddSiGpq3MBMQyFagy2RAHPhZkKN8ZGkMuN-MZqg,9991
|
|
8
8
|
agilicus/agilicus_api/__init__.py,sha256=RmgWcMhdjLQZTgjB6a8Joy1kwQRQhklwWpf3XuK7jZg,73056
|
|
@@ -73,9 +73,9 @@ agilicus/agilicus_api/api/users_api.py,sha256=wx8eoilVRiPysdhonffkjmv9OfmoOraWTL
|
|
|
73
73
|
agilicus/agilicus_api/api/users_api_mock.py,sha256=8FL2tkK1zGGN_SuPxtZ7CX-B6gqfZaqq37TuY9ETVV0,20960
|
|
74
74
|
agilicus/agilicus_api/api/whoami_api.py,sha256=bP9mGQqHRV8QAnWqPw7Nbjrjpn2iD57JwwDJmtJvnlA,7941
|
|
75
75
|
agilicus/agilicus_api/api/whoami_api_mock.py,sha256=rlvZoWnMCqORMZBg7SOv6d3xp52kELdh6wXcCaIZ93w,346
|
|
76
|
-
agilicus/agilicus_api/api_client.py,sha256=
|
|
76
|
+
agilicus/agilicus_api/api_client.py,sha256=IsH-RU6JbltsOsWvk39wrxJQWjXaujI3jq42Wk0DXqM,38845
|
|
77
77
|
agilicus/agilicus_api/apis/__init__.py,sha256=ijG84bKeWq8lCvqXBtmWXrEnDMfw2t5qu5nQwgAyckU,2280
|
|
78
|
-
agilicus/agilicus_api/configuration.py,sha256=
|
|
78
|
+
agilicus/agilicus_api/configuration.py,sha256=ARuiW8Yjhg79MJcSvEWOXJpuNG9IXJT87ucXgY5WJgI,18447
|
|
79
79
|
agilicus/agilicus_api/docs/APIKey.md,sha256=4cKuz4_l9HcEDnUrLwYbEnn9C2WoDayrjfrY1Ixgaf4,1747
|
|
80
80
|
agilicus/agilicus_api/docs/APIKeyIntrospect.md,sha256=nJ-zkuFm3JMbWFDYYN_vYyQk1snGBtBvIxtCQxamhAU,1019
|
|
81
81
|
agilicus/agilicus_api/docs/APIKeyIntrospectAuthorizationInfo.md,sha256=7RApOOLjvWQs5sw2jb25g7i3Kta1BiEY-s8VRXfppH8,725
|
|
@@ -2863,7 +2863,7 @@ agilicus/agilicus_api/test/test_x509_root_certificate.py,sha256=684W7MatZX4HjDCB
|
|
|
2863
2863
|
agilicus/agilicus_api/test/test_x509_root_certificate_spec.py,sha256=iVMIlsCMevxkvbE83LOEDuSVFAF6lci545Ofa9YcSt4,2832
|
|
2864
2864
|
agilicus/agilicus_api/test/test_x509_root_certificate_status.py,sha256=eUU7Yy12elYYGxVI0R1UbdJZjySsde3oMyuXBOFJsbQ,2846
|
|
2865
2865
|
agilicus/agilicus_api/test/test_xss_settings.py,sha256=9pWZAyjWsOtFk21wPyrKXCveTHdftsgAXnUtetSOBq4,2746
|
|
2866
|
-
agilicus/agilicus_api_README.md,sha256=
|
|
2866
|
+
agilicus/agilicus_api_README.md,sha256=xkeNoK4THBPSemYBPP7C85JpMEHaVa92B4gVp1Ex3H4,182663
|
|
2867
2867
|
agilicus/aliases.ini,sha256=MxqiVo2f2xdUDVF1YDkNW36AIqN8hrYjlTVfraEUZXY,455
|
|
2868
2868
|
agilicus/amq.py,sha256=yxi-YTbJPVl10s78Hlr1dmrQR63iaSIoROGVILzFPmE,1775
|
|
2869
2869
|
agilicus/apps.py,sha256=_HUI-_nqhRKL1bRoNqEBzpLqb9oEBKi8wia3Kp07jP8,60886
|
|
@@ -2924,7 +2924,7 @@ agilicus/licensing/licensing_main.py,sha256=VzDuONgpCIPnGxWdTQzpVNKDc22tFZTXW65L
|
|
|
2924
2924
|
agilicus/licensing/product_table_versions.py,sha256=Zk8L--z8wu6DPnbtYMGifc2J2KdNtnTBgyJv-CRAbr8,3038
|
|
2925
2925
|
agilicus/logs.py,sha256=Y4XVcLctY-2O-Q_CXbJs9sAqu0NknHKSsqilKiDM_A0,804
|
|
2926
2926
|
agilicus/lookups.py,sha256=MNmNsKpP7Fq_poLAnL9xo_iptFilKM9ziGLyIe8VKaw,669
|
|
2927
|
-
agilicus/main.py,sha256=
|
|
2927
|
+
agilicus/main.py,sha256=DdSakkZEL6AH0dy4kL_WFxsfaxvXjHXYE4qwhDX2T44,303865
|
|
2928
2928
|
agilicus/messages/__init__.py,sha256=cVqfaKUndO-AYfppkdFICM5WvYFFB1hRjXihFWmiGPQ,174
|
|
2929
2929
|
agilicus/messages/messages.py,sha256=b2eO6BaWI9UZTLETcdy1NotyuNlKIJf6CS_TUzehuk4,9175
|
|
2930
2930
|
agilicus/messages/messages_main.py,sha256=A0xucYwwUZFIuUc0bAyAqVwofErakmyawq5bwhZKcOU,1598
|
|
@@ -2938,10 +2938,11 @@ agilicus/output/table.py,sha256=GvWzDo_nfg-mBn3_3rFzvRCiYC_EnkEOUVIepYJwjG8,1334
|
|
|
2938
2938
|
agilicus/output/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2939
2939
|
agilicus/output/tests/column_builder_test.py,sha256=fKP4V5sqXtmEIr-Q0gWVSFdBqCUtugZkP6G5gML_T7I,2130
|
|
2940
2940
|
agilicus/pagination/__init__.py,sha256=aQ9h8E0nkKwvhYY3LqRNlpDJNjcXgRm6SYCjXVcpOfQ,74
|
|
2941
|
-
agilicus/pagination/
|
|
2941
|
+
agilicus/pagination/auto_iterator.py,sha256=CF0Qxii_Yund8ggFOa4Fst92hj3Nouh_5qXO5StuCMk,5171
|
|
2942
|
+
agilicus/pagination/input.py,sha256=lSyBTKxIG8Ag0MkrMHS0AaMlbHSMsBghrUfPjgYV3qE,287
|
|
2942
2943
|
agilicus/pagination/pagination.py,sha256=4DtFTRkk1HlF6dbjVaXFk3GgbAzDqhlXHRVs9hhOh9A,2339
|
|
2943
2944
|
agilicus/pagination/pagination_test.py,sha256=6s4ARvxt8ku93Fjr4s_vmthT4z9RoXPGwTQRf3hEHLA,2874
|
|
2944
|
-
agilicus/patches.py,sha256=
|
|
2945
|
+
agilicus/patches.py,sha256=DN47GvNmmpQY76iwk1-ssT_GERuzI9FCTXQPfqFXUlI,1861
|
|
2945
2946
|
agilicus/permissions.py,sha256=uB65yuDFICp1N10m0cdUjgizx9MQzAbLbAsBSTw1Rcc,2117
|
|
2946
2947
|
agilicus/policy/policies.py,sha256=eAy1iRlYKvkuc-10ssw_iuchY-I24LvtHiruvyzo5Pg,11440
|
|
2947
2948
|
agilicus/policy/policy_main.py,sha256=W91CxqQP1ye9UjsiMqgZNeULMvrzMB5TiPJZW3hogPM,4573
|
|
@@ -2954,16 +2955,17 @@ agilicus/products/products.py,sha256=he27jN3MUyXBdTdV2HRyvUYb0zD3W1TGsuC7NHLKngQ
|
|
|
2954
2955
|
agilicus/products/products_main.py,sha256=saa2-e5oeHW6D5AWPcld99KwgQ9nBY3hoW8Jz_5nfMQ,3421
|
|
2955
2956
|
agilicus/regions.py,sha256=T2Xsp2L7eVORSKyYuBofMto3yp4QlnNI7MNqm48h0xM,13059
|
|
2956
2957
|
agilicus/resource_helpers.py,sha256=pOHz2Nd7HjqU7GCepyKyBZC02gH38PvNKhx5hHOFsoE,1350
|
|
2957
|
-
agilicus/resources.py,sha256=
|
|
2958
|
+
agilicus/resources.py,sha256=_tKu53Eb4PpjmwJ2yeLo_ycBPE5s3QLILBffPi_VsHw,11405
|
|
2958
2959
|
agilicus/response.py,sha256=tI2-dAJwhBuuDplSsouuMmCmKHSwR_Mx71af8tgsuYo,468
|
|
2959
2960
|
agilicus/rules/rules.py,sha256=gpu7g308fTlE0LVuBcUXikho6TBx4-kdPUM6mPmawdY,30980
|
|
2960
2961
|
agilicus/rules/rules_main.py,sha256=aOH4mcxb4-_azgzcz5kuOSzI-CvLhCwq1rZxDvaoHe4,15026
|
|
2961
2962
|
agilicus/scopes.py,sha256=OgPUksJSOSaJ3XcHPP8WJQ3e_p8B9wVmRXr-oZDfZP0,1344
|
|
2962
2963
|
agilicus/service_configuration.py,sha256=WlsvTKA_bkle1PthJK0S96lpPK7GNr-BWWp8a_-MgtM,490
|
|
2963
2964
|
agilicus/service_token.py,sha256=YDVFeBe9Yv0qYvfUenwnpGHuj2x1J06YUe5A_C8L6L4,7162
|
|
2964
|
-
agilicus/ssh.py,sha256=
|
|
2965
|
+
agilicus/ssh.py,sha256=OnMHdq5TP-Aa4WMvoUkg6gsUyfNrdh5-DZTnSlvOOG4,3324
|
|
2965
2966
|
agilicus/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2966
2967
|
agilicus/tests/keyring_test.py,sha256=Uwp2VS2_NffYBgHAS9bXuXnIxRoK0_VOWaaYCZKv0lg,1452
|
|
2968
|
+
agilicus/tests/pagination/test_auto_iterator.py,sha256=hxT0sLecgqh2_gIOVobbdmlojbTjxMnRUc0Stw0zvPg,11129
|
|
2967
2969
|
agilicus/tests/test_pop_utils.py,sha256=gdSMOmE0pNSDA0UgUWdbLKpFzUGwfBwkFSrk1p1JdSo,1083
|
|
2968
2970
|
agilicus/tokens.py,sha256=JLileUHs5PcGjOdvQl-_9dv7DVtGa76nz1iUEIlivOU,20584
|
|
2969
2971
|
agilicus/transfers.py,sha256=PYr_fW7dyXNUXzi5Wp5mUjZOvU7MbRzoN-D8Omo-YSQ,1523
|
|
@@ -2972,8 +2974,8 @@ agilicus/trusted_certs/trusted_certs_main.py,sha256=6dHHWXvNIcUa_nA9ptigL4Vibe4n
|
|
|
2972
2974
|
agilicus/users.py,sha256=DusnnWKg4gkkKkdUjuz1NXpC6FKvE9xwHKdKm3kjHZo,44910
|
|
2973
2975
|
agilicus/version.py,sha256=G9OFdL1v_4dLDfk6I6taDNypM5bbO-JHAwilsu9LYgg,23
|
|
2974
2976
|
agilicus/whoami.py,sha256=kqghtWMgZOd2rhKmfguDwCTm6A3gNS8Kj-S2IBxBtl0,206
|
|
2975
|
-
agilicus-1.
|
|
2976
|
-
agilicus-1.
|
|
2977
|
-
agilicus-1.
|
|
2978
|
-
agilicus-1.
|
|
2979
|
-
agilicus-1.
|
|
2977
|
+
agilicus-1.306.0.dist-info/LICENSE.txt,sha256=Zq4tqiCroC2CVrBB_PWjapRdvpae23nljdiaSkOzUho,1061
|
|
2978
|
+
agilicus-1.306.0.dist-info/METADATA,sha256=bhBs8Abt5x_L965mnaBIPwWvZqIGLoSY3letvptNxXM,3838
|
|
2979
|
+
agilicus-1.306.0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
|
2980
|
+
agilicus-1.306.0.dist-info/entry_points.txt,sha256=a66hGozzLkHu0IewFzIMbSAhMTNTddUaA2T3_16Gb_s,51
|
|
2981
|
+
agilicus-1.306.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|