Skip to content

Commit 446b0c6

Browse files
committed
fix: sync API/Datamaxi close() + context manager, fixes #155
mirrors AsyncAPI/AsyncDatamaxi aclose/__aenter__/__aexit__
1 parent e3b011a commit 446b0c6

4 files changed

Lines changed: 47 additions & 1 deletion

File tree

datamaxi/api.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,15 @@ def __repr__(self):
114114
type(self).__name__, self.base_url, bool(self.api_key)
115115
)
116116

117+
def close(self):
118+
self.session.close()
119+
120+
def __enter__(self):
121+
return self
122+
123+
def __exit__(self, *exc):
124+
self.close()
125+
117126
def query(self, url_path, payload=None):
118127
return self.send_request("GET", url_path, payload=payload)
119128

datamaxi/resources/__init__.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,11 @@
3131

3232

3333
class Datamaxi:
34-
"""Client to fetch unified data from DataMaxi+ API."""
34+
"""Client to fetch unified data from DataMaxi+ API.
35+
36+
Use as a context manager so the underlying ``requests.Session`` is
37+
closed, or call :meth:`close` explicitly.
38+
"""
3539

3640
def __init__(self, api_key=None, **kwargs: Any):
3741
"""Initialize the object.
@@ -64,6 +68,15 @@ def __init__(self, api_key=None, **kwargs: Any):
6468
self.margin_borrow = MarginBorrow(api=api)
6569
self.index_price = IndexPrice(api=api)
6670

71+
def close(self):
72+
self._api.close()
73+
74+
def __enter__(self):
75+
return self
76+
77+
def __exit__(self, *exc):
78+
self.close()
79+
6780
def __repr__(self):
6881
return "Datamaxi(base_url={!r}, has_key={})".format(
6982
self._api.base_url, bool(self._api.api_key)

tests/test_api.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,3 +118,19 @@ def test_API_with_show_header():
118118
with pytest.warns(DeprecationWarning, match="show_header"):
119119
client = API(show_header=True)
120120
assert client.show_header is True
121+
122+
123+
def test_API_close_closes_session():
124+
"""`close()` closes the underlying `requests.Session`."""
125+
client = API()
126+
client.session.close = lambda: setattr(client.session, "closed", True)
127+
client.close()
128+
assert client.session.closed is True
129+
130+
131+
def test_API_context_manager_closes_session():
132+
"""`with API(...)` closes the session on exit."""
133+
with API() as client:
134+
client.session.close = lambda: setattr(client.session, "closed", True)
135+
assert client.__enter__() is client
136+
assert client.session.closed is True

tests/test_repr_and_lazy_pandas.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,14 @@ def test_datamaxi_repr_and_no_key_leak(monkeypatch):
3434
assert "has_key=False" in repr(Datamaxi(base_url=BASE_URL))
3535

3636

37+
def test_datamaxi_context_manager_closes_session():
38+
"""`with Datamaxi(...)` closes the shared session on exit (see #155)."""
39+
with Datamaxi(api_key="secret", base_url=BASE_URL) as c:
40+
c._api.session.close = lambda: setattr(c._api.session, "closed", True)
41+
assert c.__enter__() is c
42+
assert c._api.session.closed is True
43+
44+
3745
def test_importing_datamaxi_does_not_load_pandas():
3846
# Isolated subprocess: other tests in this session load pandas, so a
3947
# same-process sys.modules check would be unreliable.

0 commit comments

Comments
 (0)