From 2efc2178a7ce1cb1cc4a0d51ab4616496685dc7f Mon Sep 17 00:00:00 2001 From: Will Sackfield Date: Fri, 3 Jan 2025 16:56:43 -0500 Subject: [PATCH 1/2] Use global session on NBAHTTP --- src/nba_api/library/http.py | 16 ++++++++- tests/unit/test_http.py | 68 +++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 tests/unit/test_http.py diff --git a/src/nba_api/library/http.py b/src/nba_api/library/http.py index d6b51ef..05e94ed 100644 --- a/src/nba_api/library/http.py +++ b/src/nba_api/library/http.py @@ -64,6 +64,20 @@ class NBAHTTP: headers = None + _session: requests.Session | None = None + + @classmethod + def get_session(cls) -> requests.Session: + session = cls._session + if session is None: + session = requests.Session() + cls._session = session + return session + + @classmethod + def set_session(cls, session: requests.Session) -> None: + cls._session = session + def clean_contents(self, contents): return contents @@ -143,7 +157,7 @@ def send_api_request( print("loading from file...") if not contents: - response = requests.get( + response = self.get_session().get( url=base_url, params=parameters, headers=request_headers, diff --git a/tests/unit/test_http.py b/tests/unit/test_http.py new file mode 100644 index 0000000..f200ca6 --- /dev/null +++ b/tests/unit/test_http.py @@ -0,0 +1,68 @@ +import pytest +import requests +from unittest.mock import Mock +from nba_api.library.http import NBAHTTP +from nba_api.stats.endpoints import AllTimeLeadersGrids + +@pytest.fixture +def mock_session(): + session = Mock(spec=requests.Session) + # Mock the get method to return a response-like object + mock_response = Mock() + mock_response.text = '{"resource": "alltimeleadersgrids", "resultSets": {}}' + mock_response.status_code = 200 + mock_response.url = "http://stats.nba.com/stats/alltimeleadersgrids" + session.get.return_value = mock_response + return session + +def test_nbahttp_session_management(): + # Test default session creation + assert NBAHTTP._session is None + session = NBAHTTP.get_session() + assert isinstance(session, requests.Session) + + # Test setting custom session + custom_session = requests.Session() + NBAHTTP.set_session(custom_session) + assert NBAHTTP.get_session() == custom_session + +def test_endpoint_uses_global_session(mock_session): + # Set up global session + NBAHTTP.set_session(mock_session) + + # Create endpoint and make request + try: + _ = AllTimeLeadersGrids(topx=5) + except KeyError: + # This is expected due to the mock response. + pass + + # Verify the session's get method was called + assert mock_session.get.called + + # Verify the call parameters + call_kwargs = mock_session.get.call_args.kwargs + assert 'params' in call_kwargs + assert 'TopX' in dict(call_kwargs['params']) + assert dict(call_kwargs['params'])['TopX'] == 5 + +def test_session_headers_persistence(): + # Create session with custom headers + session = requests.Session() + custom_user_agent = 'CustomBot/1.0' + session.headers.update({'User-Agent': custom_user_agent}) + + # Set as global session + NBAHTTP.set_session(session) + + # Verify headers are maintained + current_session = NBAHTTP.get_session() + assert current_session.headers['User-Agent'] == custom_user_agent + +@pytest.fixture(autouse=True) +def cleanup(): + # Reset session before each test + NBAHTTP._session = None + yield + # Clean up after each test + NBAHTTP._session = None From f6ac647cef8ce3131e11e398cf5e7aa12a9ec002 Mon Sep 17 00:00:00 2001 From: Will Sackfield Date: Fri, 3 Jan 2025 16:57:56 -0500 Subject: [PATCH 2/2] Fix modern typing syntax --- src/nba_api/library/http.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/nba_api/library/http.py b/src/nba_api/library/http.py index 05e94ed..1c33f8e 100644 --- a/src/nba_api/library/http.py +++ b/src/nba_api/library/http.py @@ -64,10 +64,10 @@ class NBAHTTP: headers = None - _session: requests.Session | None = None + _session = None @classmethod - def get_session(cls) -> requests.Session: + def get_session(cls): session = cls._session if session is None: session = requests.Session() @@ -75,7 +75,7 @@ def get_session(cls) -> requests.Session: return session @classmethod - def set_session(cls, session: requests.Session) -> None: + def set_session(cls, session) -> None: cls._session = session def clean_contents(self, contents):