From cf51c2b6878806405668b6e8919895639a7093fc Mon Sep 17 00:00:00 2001 From: alexpipipi Date: Tue, 16 Jun 2026 14:24:10 -0400 Subject: [PATCH 1/2] fix: annotate get_fundamentals_data return type as dict (#71) The /api/fundamentals/{ticker} endpoint returns a JSON object (keys like General, Highlights, Valuation, ...), but get_fundamentals_data and get_fundamentals_data_v1_1 were annotated `-> list`, producing misleading type hints and type-checker errors for users. Changed both annotations to `-> dict` and added a regression test asserting the return annotation. Verified against the live API: AAPL.US fundamentals returns a dict. Co-Authored-By: Claude Opus 4.8 (1M context) --- eodhd/apiclient.py | 4 ++-- tests/test_fundamentaldataapi.py | 12 ++++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/eodhd/apiclient.py b/eodhd/apiclient.py index bece975..c86a87f 100644 --- a/eodhd/apiclient.py +++ b/eodhd/apiclient.py @@ -706,7 +706,7 @@ def get_insider_transactions_data( def get_fundamentals_data(self, ticker: str, filter: str = None, historical: int = None, from_date: str = None, to_date: str = None, version: int = None, - no_cache: int = None) -> list: + no_cache: int = None) -> dict: """GET /api/fundamentals/{ticker}""" api_call = FundamentalDataAPI(session=self._session, timeout=self._timeout) return api_call.get_fundamentals_data( @@ -716,7 +716,7 @@ def get_fundamentals_data(self, ticker: str, filter: str = None, historical: int def get_fundamentals_data_v1_1(self, ticker: str, filter: str = None, historical: int = None, from_date: str = None, to_date: str = None, version: int = None, - no_cache: int = None) -> list: + no_cache: int = None) -> dict: """GET /api/v1.1/fundamentals/{ticker} — uses improved Earnings::Trend data""" api_call = FundamentalDataAPI(session=self._session, timeout=self._timeout) return api_call.get_fundamentals_data_v1_1( diff --git a/tests/test_fundamentaldataapi.py b/tests/test_fundamentaldataapi.py index b9bd358..cb36b55 100644 --- a/tests/test_fundamentaldataapi.py +++ b/tests/test_fundamentaldataapi.py @@ -1,6 +1,10 @@ """Unit tests for FundamentalDataAPI""" +import inspect + import pytest + +from eodhd.apiclient import APIClient from eodhd.APIs import FundamentalDataAPI @@ -25,3 +29,11 @@ def test_get_fundamentals_data_v1_1_method_exists(): api = FundamentalDataAPI() assert hasattr(api, "get_fundamentals_data_v1_1") assert callable(api.get_fundamentals_data_v1_1) + + +def test_get_fundamentals_data_return_annotation_is_dict(): + """The /fundamentals endpoint returns a JSON object, so the client methods + must be annotated -> dict, not -> list (see issue #71).""" + client = APIClient.__new__(APIClient) + assert inspect.signature(client.get_fundamentals_data).return_annotation is dict + assert inspect.signature(client.get_fundamentals_data_v1_1).return_annotation is dict From f79460e36bec5310e08ce86d28574502776c0a50 Mon Sep 17 00:00:00 2001 From: alexpipipi Date: Thu, 18 Jun 2026 12:00:26 -0400 Subject: [PATCH 2/2] docs: note filter-reshaping caveat on get_fundamentals_data return type (#71) Follow-up to PR #72 review (Codex GPT-5.4 + Gemini Pro both flagged that -> dict is not universal): document that a narrowing filter (e.g. General::Code) reshapes the response to a scalar/inner value, so -> dict reflects the common unfiltered/top-level case. Annotation kept as dict (a strict improvement over the previous, incorrect -> list). Co-Authored-By: Claude Opus 4.8 (1M context) --- eodhd/apiclient.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/eodhd/apiclient.py b/eodhd/apiclient.py index c86a87f..bebfe78 100644 --- a/eodhd/apiclient.py +++ b/eodhd/apiclient.py @@ -707,7 +707,12 @@ def get_insider_transactions_data( def get_fundamentals_data(self, ticker: str, filter: str = None, historical: int = None, from_date: str = None, to_date: str = None, version: int = None, no_cache: int = None) -> dict: - """GET /api/fundamentals/{ticker}""" + """GET /api/fundamentals/{ticker} + + Returns the parsed JSON object. Note: a ``filter`` that narrows below the + top level reshapes the response (e.g. ``General::Code`` returns a scalar + string), so the ``-> dict`` hint reflects the common unfiltered / top-level + section case rather than every possible filter shape (see issue #71).""" api_call = FundamentalDataAPI(session=self._session, timeout=self._timeout) return api_call.get_fundamentals_data( api_token=self._api_key, ticker=ticker, filter=filter, historical=historical, @@ -717,7 +722,12 @@ def get_fundamentals_data(self, ticker: str, filter: str = None, historical: int def get_fundamentals_data_v1_1(self, ticker: str, filter: str = None, historical: int = None, from_date: str = None, to_date: str = None, version: int = None, no_cache: int = None) -> dict: - """GET /api/v1.1/fundamentals/{ticker} — uses improved Earnings::Trend data""" + """GET /api/v1.1/fundamentals/{ticker} — uses improved Earnings::Trend data + + Returns the parsed JSON object. Note: a ``filter`` that narrows below the + top level reshapes the response (e.g. ``General::Code`` returns a scalar + string), so the ``-> dict`` hint reflects the common unfiltered / top-level + section case rather than every possible filter shape (see issue #71).""" api_call = FundamentalDataAPI(session=self._session, timeout=self._timeout) return api_call.get_fundamentals_data_v1_1( api_token=self._api_key, ticker=ticker, filter=filter, historical=historical,