Skip to content

Commit c6c2e67

Browse files
committed
Explicitly log out
Space-Track requested that logout requests are made. - Explicit logout method added - logout() is called by close() method - with SpaceTrackClient() promoted more in docs - ResourceWarning emitted if close is not called
1 parent a7c3129 commit c6c2e67

File tree

6 files changed

+299
-187
lines changed

6 files changed

+299
-187
lines changed

docs/usage.rst

Lines changed: 92 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@ Usage
44

55
.. code-block:: python
66
7-
import spacetrack.operators as op
8-
from spacetrack import SpaceTrackClient
7+
import spacetrack.operators as op
8+
from spacetrack import SpaceTrackClient
99
10-
st = SpaceTrackClient(identity='user@example.com', password='password')
10+
with SpaceTrackClient(identity="user@example.com", password="password") as st:
11+
...
1112
1213
Request classes are presented as methods on the
1314
:class:`~spacetrack.base.SpaceTrackClient` object. For example,
@@ -19,10 +20,10 @@ in several ways. All the following are equivalent:
1920
.. code-block:: python
2021
2122
st.tle_publish()
22-
st.tle_publish(controller='basicspacedata')
23+
st.tle_publish(controller="basicspacedata")
2324
st.basicspacedata.tle_publish()
24-
st.generic_request('tle_publish')
25-
st.generic_request('tle_publish', controller='basicspacedata')
25+
st.generic_request("tle_publish")
26+
st.generic_request("tle_publish", controller="basicspacedata")
2627
2728
Request predicates are passed as keyword arguments. Valid
2829
arguments can be checked using the
@@ -32,19 +33,21 @@ are equivalent:
3233
.. code-block:: python
3334
3435
st.tle_publish.get_predicates()
35-
st.tle_publish.get_predicates(controller='basicspacedata')
36+
st.tle_publish.get_predicates(controller="basicspacedata")
3637
st.basicspacedata.tle_publish.get_predicates()
37-
st.basicspacedata.get_predicates('tle_publish')
38-
st.get_predicates('tle_publish')
39-
st.get_predicates('tle_publish', controller='basicspacedata')
38+
st.basicspacedata.get_predicates("tle_publish")
39+
st.get_predicates("tle_publish")
40+
st.get_predicates("tle_publish", controller="basicspacedata")
4041
4142
Returned object:
4243

4344
.. code-block:: python
4445
45-
[Predicate(name='publish_epoch', type_='datetime', nullable=False),
46-
Predicate(name='tle_line1', type_='str', nullable=False),
47-
Predicate(name='tle_line2', type_='str', nullable=False)]
46+
[
47+
Predicate(name="publish_epoch", type_="datetime", nullable=False),
48+
Predicate(name="tle_line1", type_="str", nullable=False),
49+
Predicate(name="tle_line2", type_="str", nullable=False),
50+
]
4851
4952
Internally, the client uses this mechanism to verify the keyword arguments.
5053
Types are not currently checked.
@@ -65,15 +68,19 @@ The same example is shown below synchronously and asynchronously.
6568
import spacetrack.operators as op
6669
from spacetrack import SpaceTrackClient
6770
68-
st = SpaceTrackClient(identity='user@example.com', password='password')
69-
70-
data = st.tle_latest(iter_lines=True, ordinal=1, epoch='>now-30',
71-
mean_motion=op.inclusive_range(0.99, 1.01),
72-
eccentricity=op.less_than(0.01), format='tle')
71+
with SpaceTrackClient(identity="user@example.com", password="password") as st:
72+
data = st.tle_latest(
73+
iter_lines=True,
74+
ordinal=1,
75+
epoch=">now-30",
76+
mean_motion=op.inclusive_range(0.99, 1.01),
77+
eccentricity=op.less_than(0.01),
78+
ormat="tle",
79+
)
7380
74-
with open('tle_latest.txt', 'w') as fp:
75-
for line in data:
76-
fp.write(line + '\n')
81+
with open("tle_latest.txt", "w") as fp:
82+
for line in data:
83+
fp.write(line + "\n")
7784
7885
.. code-block:: python
7986
@@ -84,18 +91,22 @@ The same example is shown below synchronously and asynchronously.
8491
8592
8693
async def download_latest_tles():
87-
st = AsyncSpaceTrackClient(identity='user@example.com',
88-
password='password')
89-
90-
async with st:
94+
async with AsyncSpaceTrackClient(
95+
identity="user@example.com", password="password"
96+
) as st:
9197
data = await st.tle_latest(
92-
iter_lines=True, ordinal=1, epoch='>now-30',
98+
iter_lines=True,
99+
ordinal=1,
100+
epoch=">now-30",
93101
mean_motion=op.inclusive_range(0.99, 1.01),
94-
eccentricity=op.less_than(0.01), format='tle')
102+
eccentricity=op.less_than(0.01),
103+
format="tle",
104+
)
95105
96-
with open('tle_latest.txt', 'w') as fp:
106+
with open("tle_latest.txt", "w") as fp:
97107
async for line in data:
98-
fp.write(line + '\n')
108+
fp.write(line + "\n")
109+
99110
100111
loop = asyncio.get_event_loop()
101112
loop.run_until_complete(download_latest_tles())
@@ -111,10 +122,9 @@ opened file:
111122
112123
from spacetrack import SpaceTrackClient
113124
114-
st = SpaceTrackClient(identity='user@example.com', password='password')
115-
116-
with open('somefile.txt', 'rb') as fp:
117-
st.upload(file=fp)
125+
with SpaceTrackClient(identity="user@example.com", password="password") as st:
126+
with open("somefile.txt", "rb") as fp:
127+
st.upload(file=fp)
118128
119129
120130
Rate Limiter
@@ -137,12 +147,14 @@ value to be compared against :func:`time.monotonic` to get the remaining time:
137147
138148
from spacetrack import SpaceTrackClient
139149
150+
140151
def mycallback(until):
141152
duration = int(round(until - time.monotonic()))
142-
print('Sleeping for {:d} seconds.'.format(duration))
153+
print("Sleeping for {:d} seconds.".format(duration))
154+
143155
144-
st = SpaceTrackClient(identity='user@example.com', password='password')
145-
st.callback = mycallback
156+
with SpaceTrackClient(identity="user@example.com", password="password") as st:
157+
st.callback = mycallback
146158
147159
Sample Queries
148160
==============
@@ -152,40 +164,50 @@ the Python module.
152164

153165
.. code-block:: python
154166
155-
output = st.boxscore(format='csv')
167+
output = st.boxscore(format="csv")
156168
157169
.. code-block:: python
158170
159171
decay_epoch = op.inclusive_range(date(2012, 7, 2), date(2012, 7, 9))
160-
st.decay(decay_epoch=decay_epoch, orderby=['norad_cat_id', 'precedence'], format='xml')
172+
st.decay(decay_epoch=decay_epoch, orderby=["norad_cat_id", "precedence"], format="xml")
161173
162174
.. code-block:: python
163175
164-
st.satcat(launch='>now-7', current='Y', orderby='launch desc', format='html')
176+
st.satcat(launch=">now-7", current="Y", orderby="launch desc", format="html")
165177
166178
.. code-block:: python
167179
168-
st.satcat(period=op.inclusive_range(1430, 1450), current='Y',
169-
decay=None, orderby='norad_cat_id', format='html')
180+
st.satcat(
181+
period=op.inclusive_range(1430, 1450),
182+
current="Y",
183+
decay=None,
184+
orderby="norad_cat_id",
185+
format="html",
186+
)
170187
171188
.. code-block:: python
172189
173-
st.satcat(period=op.less_than(128), decay=None, current='Y')
190+
st.satcat(period=op.less_than(128), decay=None, current="Y")
174191
175192
.. code-block:: python
176193
177-
st.tle_latest(ordinal=1, epoch='>now-30',
178-
mean_motion=op.inclusive_range(0.99, 1.01),
179-
eccentricity=op.less_than(0.01), format='tle')
194+
st.tle_latest(
195+
ordinal=1,
196+
epoch=">now-30",
197+
mean_motion=op.inclusive_range(0.99, 1.01),
198+
eccentricity=op.less_than(0.01),
199+
format="tle",
200+
)
180201
181202
.. code-block:: python
182203
183-
st.tle_latest(ordinal=1, epoch='>now-30', mean_motion=op.greater_than(11.25),
184-
format='3le')
204+
st.tle_latest(
205+
ordinal=1, epoch=">now-30", mean_motion=op.greater_than(11.25), format="3le"
206+
)
185207
186208
.. code-block:: python
187209
188-
st.tle_latest(favorites='Amateur', ordinal=1, epoch='>now-30', format='3le')
210+
st.tle_latest(favorites="Amateur", ordinal=1, epoch=">now-30", format="3le")
189211
190212
.. code-block:: python
191213
@@ -196,41 +218,49 @@ the Python module.
196218
op.inclusive_range(36001, 36004),
197219
op.like(36005),
198220
op.startswith(3600),
199-
36010
221+
36010,
200222
],
201-
orderby='norad_cat_id',
202-
format='html')
223+
orderby="norad_cat_id",
224+
format="html",
225+
)
203226
204227
.. code-block:: python
205228
206-
st.tle(norad_cat_id=25544, orderby='epoch desc', limit=22, format='tle')
229+
st.tle(norad_cat_id=25544, orderby="epoch desc", limit=22, format="tle")
207230
208231
.. code-block:: python
209232
210-
st.omm(norad_cat_id=25544, orderby='epoch desc', limit=22, format='xml')
233+
st.omm(norad_cat_id=25544, orderby="epoch desc", limit=22, format="xml")
211234
212235
.. code-block:: python
213236
214-
st.tip(norad_cat_id=[60, 38462, 38351], format='html')
237+
st.tip(norad_cat_id=[60, 38462, 38351], format="html")
215238
216239
.. code-block:: python
217240
218-
st.cdm(constellation='iridium', limit=10, orderby='creation_date desc', format='html')
241+
st.cdm(constellation="iridium", limit=10, orderby="creation_date desc", format="html")
219242
220243
.. code-block:: python
221244
222-
st.cdm(constellation='iridium', limit=10, orderby='creation_date desc', format='kvn')
245+
st.cdm(constellation="iridium", limit=10, orderby="creation_date desc", format="kvn")
223246
224247
.. code-block:: python
225248
226249
st.cdm(
227-
constellation='intelsat', tca='>now',
228-
predicates=['message_for', 'tca', 'miss_distance'],
229-
orderby='miss_distance', format='html', metadata=True)
250+
constellation="intelsat",
251+
tca=">now",
252+
predicates=["message_for", "tca", "miss_distance"],
253+
orderby="miss_distance",
254+
format="html",
255+
metadata=True,
256+
)
230257
231258
.. code-block:: python
232259
233260
st.cdm(
234-
constellation='intelsat', tca='>now',
235-
predicates=['message_for', 'tca', 'miss_distance'],
236-
orderby='miss_distance', format='kvn')
261+
constellation="intelsat",
262+
tca=">now",
263+
predicates=["message_for", "tca", "miss_distance"],
264+
orderby="miss_distance",
265+
format="kvn",
266+
)

src/spacetrack/aio.py

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import asyncio
22
import time
3+
import weakref
34

45
import httpx
56
import sniffio
@@ -53,6 +54,17 @@ def __init__(
5354
additional_rate_limit=additional_rate_limit,
5455
)
5556

57+
def _setup_finalizer(self):
58+
self._finalizer = weakref.finalize(
59+
self,
60+
self._cleanup,
61+
warn_message=(
62+
f"{self!r} was collected without being closed explicitly. It "
63+
"is recommended to use `async with SpaceTrackClient(...) as "
64+
"client:` or `await client.close()`."
65+
),
66+
)
67+
5668
async def _handle_event(self, event):
5769
if isinstance(event, NormalRequest):
5870
return await self.client.send(
@@ -98,6 +110,28 @@ async def authenticate(self):
98110
"""
99111
await self._run_event_generator(self._auth_generator())
100112

113+
async def logout(self):
114+
"""Log out of Space-Track.
115+
116+
.. note::
117+
118+
This method is called automatically when using
119+
:class:`AsyncSpaceTrackClient` as a context manager:
120+
121+
.. code-block:: python
122+
123+
async with AsyncSpaceTrackClient(...) as client:
124+
...
125+
126+
otherwise, :meth:`close` should be used:
127+
128+
.. code-block:: python
129+
130+
client = AsyncSpaceTrackClient(...)
131+
await client.close()
132+
"""
133+
await self._run_event_generator(self._logout_generator())
134+
101135
async def generic_request(
102136
self,
103137
class_,
@@ -225,7 +259,9 @@ async def __aexit__(self, exc_type, exc_val, exc_tb):
225259
await self.close()
226260

227261
async def close(self):
228-
"""Close aiohttp session."""
262+
"""Log out of Space-Track (if necessary) and close any open connections."""
263+
self._finalizer.detach()
264+
await self.logout()
229265
await self.client.aclose()
230266

231267

0 commit comments

Comments
 (0)