44from typing import AsyncIterator , Dict , Optional , Set
55import uuid
66
7- from planet .exceptions import ClientError
7+ from planet .exceptions import APIError
88
99# Collections of fake subscriptions and results for testing. Tests will
1010# monkeypatch these attributes.
11- _fake_subs : Optional [ Dict [str , dict ]] = None
12- _fake_sub_results : Optional [ Dict [str , list ]] = None
11+ _fake_subs : Dict [str , dict ] = {}
12+ _fake_sub_results : Dict [str , list ] = {}
1313
1414
15- class PlaceholderSubscriptionsClient :
16- """A placeholder client.
15+ async def _server_subscriptions_post (request ):
16+ missing_keys = {'name' , 'delivery' , 'source' } - request .keys ()
17+ if missing_keys :
18+ raise RuntimeError (f"Request lacks required members: { missing_keys !r} " )
1719
18- This class and its methods are derived from tests of a skeleton
19- Subscriptions CLI. It is evolving into the real API client.
20+ id = str (uuid .uuid4 ())
21+ _fake_subs [id ] = request
22+ sub = _fake_subs [id ].copy ()
23+ sub .update (id = id )
24+ return sub
25+
26+
27+ async def _server_subscriptions_get (status = None , limit = None ):
28+ select_subs = (dict (** sub , id = sub_id ) for sub_id ,
29+ sub in _fake_subs .items ()
30+ if not status or sub ['status' ] in status )
31+ filtered_subs = itertools .islice (select_subs , limit )
32+ for sub in filtered_subs :
33+ yield sub
34+
35+
36+ async def _server_subscriptions_id_cancel_post (subscription_id ):
37+ sub = _fake_subs .pop (subscription_id )
38+ sub .update (id = subscription_id )
39+ return sub
40+
41+
42+ async def _server_subscriptions_id_put (subscription_id , request ):
43+ _fake_subs [subscription_id ].update (** request )
44+ sub = _fake_subs [subscription_id ].copy ()
45+ sub .update (id = subscription_id )
46+ return sub
47+
48+
49+ async def _server_subscriptions_id_get (subscription_id ):
50+ sub = _fake_subs [subscription_id ].copy ()
51+ sub .update (id = subscription_id )
52+ return sub
53+
54+
55+ async def _server_subscriptions_id_results_get (subscription_id ,
56+ status = None ,
57+ limit = None ):
58+ select_results = (result for result in _fake_sub_results [subscription_id ]
59+ if not status or result ['status' ] in status )
60+ filtered_results = itertools .islice (select_results , limit )
61+ for result in filtered_results :
62+ yield result
63+
64+
65+ class SubscriptionsClient :
66+ """The Planet Subscriptions API client.
67+
68+ TODO: make requests to the production API. Currently, the backend
69+ is fake and exists at the top of this class's module.
2070
2171 """
2272
2373 def __init__ (self , session = None ) -> None :
2474 self ._session = session
2575
2676 async def list_subscriptions (self ,
27- status : Set [str ] = None ,
77+ status : Optional [ Set [str ] ] = None ,
2878 limit : int = 100 ) -> AsyncIterator [dict ]:
2979 """Get account subscriptions with optional filtering.
3080
31- The name of this method is based on the API's method name. This
32- method provides iteration over subcriptions, it does not return
33- a list.
81+ Note:
82+ The name of this method is based on the API's method name. This
83+ method provides iteration over subcriptions, it does not return
84+ a list.
3485
3586 Args:
3687 status (Set[str]): pass subscriptions with status in this
3788 set, filter out subscriptions with status not in this
3889 set.
3990 limit (int): limit the number of subscriptions in the
4091 results.
92+ TODO: user_id
4193
4294 Yields:
4395 dict: a description of a subscription.
4496
4597 Raises:
46- ClientError
98+ APIError: on an API server error.
99+ ClientError: on a client error.
47100
48101 """
49- # Temporary marker for behavior of module with unpatched state.
50- if _fake_subs is None :
51- raise NotImplementedError
52-
53- if status :
54- select_subs = (dict (** sub , id = sub_id ) for sub_id ,
55- sub in _fake_subs .items ()
56- if sub ['status' ] in status )
57- else :
58- select_subs = (
59- dict (** sub , id = sub_id ) for sub_id , sub in _fake_subs .items ())
60-
61- filtered_subs = itertools .islice (select_subs , limit )
62-
63- for sub in filtered_subs :
64- yield sub
102+ try :
103+ # TODO: replace with httpx request.
104+ async for sub in _server_subscriptions_get (status = status ,
105+ limit = limit ):
106+ yield sub
107+ except Exception as server_error :
108+ # TODO: remove "from server_error" clause. It's useful
109+ # during development but may invite users to depend on the
110+ # value of server_error.
111+ raise APIError ("Subscription failure" ) from server_error
65112
66113 async def create_subscription (self , request : dict ) -> dict :
67114 """Create a Subscription.
@@ -73,23 +120,20 @@ async def create_subscription(self, request: dict) -> dict:
73120 dict: description of created subscription.
74121
75122 Raises:
76- ClientError
123+ APIError: on an API server error.
124+ ClientError: on a client error.
77125
78126 """
79- # Temporary marker for behavior of module with unpatched state.
80- if _fake_subs is None :
81- raise NotImplementedError
82-
83- missing_keys = {'name' , 'delivery' , 'source' } - request .keys ()
84- if missing_keys :
85- raise ClientError (
86- f"Request lacks required members: { missing_keys !r} " )
87-
88- id = str (uuid .uuid4 ())
89- _fake_subs [id ] = request
90- sub = _fake_subs [id ].copy ()
91- sub .update (id = id )
92- return sub
127+ try :
128+ # TODO: replace with httpx request.
129+ sub = await _server_subscriptions_post (request )
130+ except Exception as server_error :
131+ # TODO: remove "from server_error" clause. It's useful
132+ # during development but may invite users to depend on the
133+ # value of server_error.
134+ raise APIError ("Subscription failure" ) from server_error
135+ else :
136+ return sub
93137
94138 async def cancel_subscription (self , subscription_id : str ) -> dict :
95139 """Cancel a Subscription.
@@ -101,20 +145,20 @@ async def cancel_subscription(self, subscription_id: str) -> dict:
101145 dict: description of cancelled subscription.
102146
103147 Raises:
104- ClientError
148+ APIError: on an API server error.
149+ ClientError: on a client error.
105150
106151 """
107- # Temporary marker for behavior of module with unpatched state.
108- if _fake_subs is None :
109- raise NotImplementedError
110-
111152 try :
112- sub = _fake_subs .pop (subscription_id )
113- except KeyError :
114- raise ClientError (f"No such subscription: { subscription_id !r} " )
115-
116- sub .update (id = subscription_id )
117- return sub
153+ # TODO: replace with httpx request.
154+ sub = await _server_subscriptions_id_cancel_post (subscription_id )
155+ except Exception as server_error :
156+ # TODO: remove "from server_error" clause. It's useful
157+ # during development but may invite users to depend on the
158+ # value of server_error.
159+ raise APIError ("Subscription failure." ) from server_error
160+ else :
161+ return sub
118162
119163 async def update_subscription (self , subscription_id : str ,
120164 request : dict ) -> dict :
@@ -128,21 +172,20 @@ async def update_subscription(self, subscription_id: str,
128172 dict: description of the updated subscription.
129173
130174 Raises:
131- ClientError
175+ APIError: on an API server error.
176+ ClientError: on a client error.
132177
133178 """
134- # Temporary marker for behavior of module with unpatched state.
135- if _fake_subs is None :
136- raise NotImplementedError
137-
138179 try :
139- _fake_subs [subscription_id ].update (** request )
140- sub = _fake_subs [subscription_id ].copy ()
141- except KeyError :
142- raise ClientError (f"No such subscription: { subscription_id !r} " )
143-
144- sub .update (id = subscription_id )
145- return sub
180+ # TODO: replace with httpx request.
181+ sub = await _server_subscriptions_id_put (subscription_id , request )
182+ except Exception as server_error :
183+ # TODO: remove "from server_error" clause. It's useful
184+ # during development but may invite users to depend on the
185+ # value of server_error.
186+ raise APIError ("Subscription failure." ) from server_error
187+ else :
188+ return sub
146189
147190 async def get_subscription (self , subscription_id : str ) -> dict :
148191 """Get a description of a Subscription.
@@ -154,61 +197,55 @@ async def get_subscription(self, subscription_id: str) -> dict:
154197 dict: description of the subscription.
155198
156199 Raises:
157- ClientError
200+ APIError: on an API server error.
201+ ClientError: on a client error.
158202
159203 """
160- # Temporary marker for behavior of module with unpatched state.
161- if _fake_subs is None :
162- raise NotImplementedError
163-
164204 try :
165- sub = _fake_subs [subscription_id ].copy ()
166- except KeyError :
167- raise ClientError (f"No such subscription: { subscription_id !r} " )
168-
169- sub .update (id = subscription_id )
170- return sub
205+ # TODO: replace with httpx request.
206+ sub = await _server_subscriptions_id_get (subscription_id )
207+ except Exception as server_error :
208+ # TODO: remove "from server_error" clause. It's useful
209+ # during development but may invite users to depend on the
210+ # value of server_error.
211+ raise APIError ("Subscription failure." ) from server_error
212+ else :
213+ return sub
171214
172215 async def get_results (self ,
173216 subscription_id : str ,
174- status : Set [str ] = None ,
217+ status : Optional [ Set [str ] ] = None ,
175218 limit : int = 100 ) -> AsyncIterator [dict ]:
176219 """Get Results of a Subscription.
177220
178- The name of this method is based on the API's method name. This
179- method provides iteration over results, it does not get a
180- single result description or return a list of descriptions.
221+ Note:
222+ The name of this method is based on the API's method name. This
223+ method provides iteration over results, it does not get a
224+ single result description or return a list of descriptions.
181225
182226 Args:
183227 subscription_id (str): id of a subscription.
184228 status (Set[str]): pass result with status in this set,
185229 filter out results with status not in this set.
186230 limit (int): limit the number of subscriptions in the
187231 results.
232+ TODO: created, updated, completed, user_id
188233
189234 Yields:
190235 dict: description of a subscription results.
191236
192237 Raises:
193- ClientError
238+ APIError: on an API server error.
239+ ClientError: on a client error.
194240
195241 """
196- # Temporary marker for behavior of module with unpatched state.
197- if _fake_sub_results is None :
198- raise NotImplementedError
199-
200242 try :
201- if status :
202- select_results = (
203- result for result in _fake_sub_results [subscription_id ]
204- if result ['status' ] in status )
205- else :
206- select_results = (
207- result for result in _fake_sub_results [subscription_id ])
208-
209- filtered_results = itertools .islice (select_results , limit )
210- except KeyError :
211- raise ClientError (f"No such subscription: { subscription_id !r} " )
212-
213- for result in filtered_results :
214- yield result
243+ # TODO: replace with httpx request.
244+ async for result in _server_subscriptions_id_results_get (
245+ subscription_id , status = status , limit = limit ):
246+ yield result
247+ except Exception as server_error :
248+ # TODO: remove "from server_error" clause. It's useful
249+ # during development but may invite users to depend on the
250+ # value of server_error.
251+ raise APIError ("Subscription failure." ) from server_error
0 commit comments