Skip to content

Commit 3334af9

Browse files
authored
Merge pull request #171 from cloudfoundry-community/features/add_len_on_entity_manager
Allow to get number of entities
2 parents 6186be6 + 078dcfd commit 3334af9

19 files changed

Lines changed: 243 additions & 81 deletions
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import json
2+
from typing import Callable, TypeVar, Generic, List, Union
3+
4+
5+
class Request(dict):
6+
def __setitem__(self, key, value):
7+
if value is not None:
8+
super(Request, self).__setitem__(key, value)
9+
10+
11+
class JsonObject(dict):
12+
def __init__(self, *args, **kwargs):
13+
super(JsonObject, self).__init__(*args, **kwargs)
14+
15+
json = json.dumps
16+
17+
18+
ENTITY = TypeVar('ENTITY')
19+
20+
21+
class Pagination(Generic[ENTITY]):
22+
def __init__(self, first_page: JsonObject,
23+
total_result: int,
24+
next_page_loader: Callable[[JsonObject], Union[None, JsonObject]],
25+
resources_accessor: Callable[[JsonObject], List[JsonObject]],
26+
instance_creator: Callable[[JsonObject], ENTITY]):
27+
self._first_page = first_page
28+
self._total_results = total_result
29+
self._next_page_loader = next_page_loader
30+
self._resources_accessor = resources_accessor
31+
self._instance_creator = instance_creator
32+
self._cursor = None
33+
self._current_page = None
34+
35+
@property
36+
def total_results(self) -> int:
37+
return self._total_results
38+
39+
def __iter__(self):
40+
return self
41+
42+
def __next__(self) -> ENTITY:
43+
try:
44+
if self._cursor is None:
45+
self._current_page = self._first_page
46+
self._cursor = self._resources_accessor(self._current_page).__iter__()
47+
return self._instance_creator(self._cursor.__next__())
48+
except StopIteration:
49+
self._current_page = self._next_page_loader(self._current_page)
50+
if self._current_page is None:
51+
raise
52+
self._cursor = self._resources_accessor(self._current_page).__iter__()
53+
return self._instance_creator(self._cursor.__next__())

main/cloudfoundry_client/json_object.py

Lines changed: 0 additions & 8 deletions
This file was deleted.

main/cloudfoundry_client/main/command_domain.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
from cloudfoundry_client.client import CloudFoundryClient
1111
from cloudfoundry_client.errors import InvalidStatusCode
12-
from cloudfoundry_client.json_object import JsonObject
12+
from cloudfoundry_client.common_objects import JsonObject
1313

1414

1515
class Command(object):

main/cloudfoundry_client/main/main.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from cloudfoundry_client import __version__
1414
from cloudfoundry_client.client import CloudFoundryClient
1515
from cloudfoundry_client.errors import InvalidStatusCode
16-
from cloudfoundry_client.json_object import JsonObject
16+
from cloudfoundry_client.common_objects import JsonObject
1717
from cloudfoundry_client.main.apps_command_domain import AppCommandDomain
1818
from cloudfoundry_client.main.command_domain import CommandDomain, Command
1919
from cloudfoundry_client.main.operation_commands import generate_push_command

main/cloudfoundry_client/main/tasks_command_domain.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from argparse import Namespace, _SubParsersAction
44

55
from cloudfoundry_client.client import CloudFoundryClient
6-
from cloudfoundry_client.json_object import JsonObject
6+
from cloudfoundry_client.common_objects import JsonObject
77
from cloudfoundry_client.main.command_domain import CommandDomain, Command
88

99

main/cloudfoundry_client/networking/entities.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@
66
from requests import Response
77

88
from cloudfoundry_client.errors import InvalidEntity
9-
from cloudfoundry_client.json_object import JsonObject
10-
from cloudfoundry_client.request_object import Request
9+
from cloudfoundry_client.common_objects import JsonObject, Request
1110

1211
if TYPE_CHECKING:
1312
from cloudfoundry_client.client import CloudFoundryClient

main/cloudfoundry_client/request_object.py

Lines changed: 0 additions & 4 deletions
This file was deleted.

main/cloudfoundry_client/v2/apps.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77

88
from cloudfoundry_client.doppler.client import EnvelopeStream
99
from cloudfoundry_client.errors import InvalidStatusCode
10-
from cloudfoundry_client.json_object import JsonObject
11-
from cloudfoundry_client.v2.entities import Entity, EntityManager, PaginateEntities
10+
from cloudfoundry_client.common_objects import JsonObject, Pagination
11+
from cloudfoundry_client.v2.entities import Entity, EntityManager
1212

1313
if TYPE_CHECKING:
1414
from cloudfoundry_client.client import CloudFoundryClient
@@ -95,13 +95,13 @@ def get_summary(self, application_guid: str) -> JsonObject:
9595
def associate_route(self, application_guid: str, route_guid: str) -> Application:
9696
self._put("%s%s/%s/routes/%s" % (self.target_endpoint, self.entity_uri, application_guid, route_guid))
9797

98-
def list_routes(self, application_guid: str, **kwargs) -> PaginateEntities:
98+
def list_routes(self, application_guid: str, **kwargs) -> Pagination[Entity]:
9999
return self.client.v2.routes._list("%s/%s/routes" % (self.entity_uri, application_guid), **kwargs)
100100

101101
def remove_route(self, application_guid: str, route_guid: str):
102102
self._delete("%s%s/%s/routes/%s" % (self.target_endpoint, self.entity_uri, application_guid, route_guid))
103103

104-
def list_service_bindings(self, application_guid: str, **kwargs) -> PaginateEntities:
104+
def list_service_bindings(self, application_guid: str, **kwargs) -> Pagination[Entity]:
105105
return self.client.v2.service_bindings._list("%s/%s/service_bindings" % (self.entity_uri, application_guid), **kwargs)
106106

107107
def start(

main/cloudfoundry_client/v2/entities.py

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
from functools import partial, reduce
2-
from typing import Callable, List, Tuple, Any, Optional, Generator, TYPE_CHECKING
2+
from typing import Callable, List, Tuple, Any, Optional, TYPE_CHECKING, Union
33
from urllib.parse import quote
44
from requests import Response
55

66
from cloudfoundry_client.errors import InvalidEntity
7-
from cloudfoundry_client.json_object import JsonObject
8-
from cloudfoundry_client.request_object import Request
7+
from cloudfoundry_client.common_objects import JsonObject, Request, Pagination
98

109
if TYPE_CHECKING:
1110
from cloudfoundry_client.client import CloudFoundryClient
@@ -42,8 +41,6 @@ def __init__(self, target_endpoint: str, client: "CloudFoundryClient", *args, **
4241

4342
EntityBuilder = Callable[[List[Tuple[str, Any]]], Entity]
4443

45-
PaginateEntities = Generator[Entity, None, None]
46-
4744

4845
class EntityManager(object):
4946
list_query_parameters = ["page", "results-per-page", "order-direction"]
@@ -62,19 +59,21 @@ def __init__(
6259
entity_builder if entity_builder is not None else lambda pairs: Entity(target_endpoint, client, pairs)
6360
)
6461

65-
def _list(self, requested_path: str, entity_builder: Optional[EntityBuilder] = None, **kwargs) -> PaginateEntities:
62+
def _list(self, requested_path: str, entity_builder: Optional[EntityBuilder] = None, **kwargs) -> Pagination[Entity]:
6663
url_requested = self._get_url_filtered("%s%s" % (self.target_endpoint, requested_path), **kwargs)
67-
response = self.client.get(url_requested)
68-
entity_builder = self._get_entity_builder(entity_builder)
69-
while True:
70-
response_json = self._read_response(response, JsonObject)
71-
for resource in response_json["resources"]:
72-
yield entity_builder(list(resource.items()))
73-
if response_json["next_url"] is None:
74-
break
75-
else:
76-
url_requested = "%s%s" % (self.target_endpoint, response_json["next_url"])
77-
response = self.client.get(url_requested)
64+
current_builder = self._get_entity_builder(entity_builder)
65+
response_json = self._read_response(self.client.get(url_requested), JsonObject)
66+
return Pagination(response_json, response_json.get("total_results", 0),
67+
self._next_page,
68+
lambda page: page["resources"],
69+
lambda json_object: current_builder(list(json_object.items())))
70+
71+
def _next_page(self, current_page: JsonObject) -> Union[None, JsonObject]:
72+
next_url = current_page.get("next_url")
73+
if next_url is None:
74+
return None
75+
url_requested = "%s%s" % (self.target_endpoint, next_url)
76+
return self._read_response(self.client.get(url_requested), JsonObject)
7877

7978
def _create(self, data: dict, **kwargs) -> Entity:
8079
url = "%s%s" % (self.target_endpoint, self.entity_uri)
@@ -104,13 +103,13 @@ def _put(self, url: str, data: Optional[dict] = None, **kwargs):
104103
def _delete(self, url: str, **kwargs):
105104
self.client.delete(url, **kwargs)
106105

107-
def __iter__(self) -> PaginateEntities:
106+
def __iter__(self) -> Pagination[Entity]:
108107
return self.list()
109108

110109
def __getitem__(self, entity_guid) -> Entity:
111110
return self.get(entity_guid)
112111

113-
def list(self, **kwargs) -> PaginateEntities:
112+
def list(self, **kwargs) -> Pagination[Entity]:
114113
return self._list(self.entity_uri, **kwargs)
115114

116115
def get_first(self, **kwargs) -> Optional[Entity]:

main/cloudfoundry_client/v2/jobs.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from typing import TYPE_CHECKING
22

3-
from cloudfoundry_client.json_object import JsonObject
3+
from cloudfoundry_client.common_objects import JsonObject
44

55
if TYPE_CHECKING:
66
from cloudfoundry_client.client import CloudFoundryClient

0 commit comments

Comments
 (0)