kensho-kfinance 3.2.5__py3-none-any.whl → 3.2.7__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of kensho-kfinance might be problematic. Click here for more details.

Files changed (43) hide show
  1. {kensho_kfinance-3.2.5.dist-info → kensho_kfinance-3.2.7.dist-info}/METADATA +1 -1
  2. {kensho_kfinance-3.2.5.dist-info → kensho_kfinance-3.2.7.dist-info}/RECORD +43 -43
  3. kfinance/CHANGELOG.md +6 -0
  4. kfinance/client/fetch.py +7 -5
  5. kfinance/client/kfinance.py +38 -39
  6. kfinance/client/models/date_and_period_models.py +8 -7
  7. kfinance/client/tests/test_fetch.py +3 -1
  8. kfinance/client/tests/test_objects.py +38 -95
  9. kfinance/domains/business_relationships/business_relationship_tools.py +4 -4
  10. kfinance/domains/business_relationships/tests/test_business_relationship_tools.py +18 -16
  11. kfinance/domains/capitalizations/capitalization_models.py +3 -3
  12. kfinance/domains/capitalizations/capitalization_tools.py +7 -5
  13. kfinance/domains/capitalizations/tests/test_capitalization_tools.py +46 -36
  14. kfinance/domains/companies/company_models.py +8 -2
  15. kfinance/domains/companies/company_tools.py +8 -12
  16. kfinance/domains/companies/tests/test_company_tools.py +21 -9
  17. kfinance/domains/competitors/competitor_tools.py +2 -3
  18. kfinance/domains/competitors/tests/test_competitor_tools.py +22 -19
  19. kfinance/domains/cusip_and_isin/cusip_and_isin_tools.py +4 -6
  20. kfinance/domains/cusip_and_isin/tests/test_cusip_and_isin_tools.py +13 -8
  21. kfinance/domains/earnings/earning_tools.py +12 -9
  22. kfinance/domains/earnings/tests/test_earnings_tools.py +52 -43
  23. kfinance/domains/line_items/line_item_tools.py +2 -3
  24. kfinance/domains/line_items/tests/test_line_item_tools.py +20 -23
  25. kfinance/domains/mergers_and_acquisitions/merger_and_acquisition_models.py +46 -2
  26. kfinance/domains/mergers_and_acquisitions/merger_and_acquisition_tools.py +13 -68
  27. kfinance/domains/mergers_and_acquisitions/tests/test_merger_and_acquisition_tools.py +61 -59
  28. kfinance/domains/prices/price_tools.py +4 -7
  29. kfinance/domains/prices/tests/test_price_tools.py +47 -39
  30. kfinance/domains/segments/segment_tools.py +2 -3
  31. kfinance/domains/segments/tests/test_segment_tools.py +16 -11
  32. kfinance/domains/statements/statement_tools.py +2 -3
  33. kfinance/domains/statements/tests/test_statement_tools.py +40 -35
  34. kfinance/integrations/tool_calling/static_tools/get_n_quarters_ago.py +5 -0
  35. kfinance/integrations/tool_calling/static_tools/tests/test_get_lastest.py +13 -10
  36. kfinance/integrations/tool_calling/static_tools/tests/test_get_n_quarters_ago.py +2 -1
  37. kfinance/integrations/tool_calling/tests/test_tool_calling_models.py +8 -2
  38. kfinance/integrations/tool_calling/tool_calling_models.py +11 -5
  39. kfinance/version.py +2 -2
  40. {kensho_kfinance-3.2.5.dist-info → kensho_kfinance-3.2.7.dist-info}/WHEEL +0 -0
  41. {kensho_kfinance-3.2.5.dist-info → kensho_kfinance-3.2.7.dist-info}/licenses/AUTHORS.md +0 -0
  42. {kensho_kfinance-3.2.5.dist-info → kensho_kfinance-3.2.7.dist-info}/licenses/LICENSE +0 -0
  43. {kensho_kfinance-3.2.5.dist-info → kensho_kfinance-3.2.7.dist-info}/top_level.txt +0 -0
@@ -5,8 +5,10 @@ from kfinance.conftest import SPGI_TRADING_ITEM_ID
5
5
  from kfinance.domains.companies.company_models import COMPANY_ID_PREFIX
6
6
  from kfinance.domains.prices.price_tools import (
7
7
  GetHistoryMetadataFromIdentifiers,
8
+ GetHistoryMetadataFromIdentifiersResp,
8
9
  GetPricesFromIdentifiers,
9
10
  GetPricesFromIdentifiersArgs,
11
+ GetPricesFromIdentifiersResp,
10
12
  )
11
13
  from kfinance.integrations.tool_calling.tool_calling_models import ToolArgsWithIdentifiers
12
14
 
@@ -27,12 +29,14 @@ class TestGetHistoryMetadataFromIdentifiers:
27
29
  "instrument_type": "Equity",
28
30
  "symbol": "SPGI",
29
31
  }
30
- expected_resp = {
31
- "results": {"SPGI": metadata_resp},
32
- "errors": [
33
- "No identification triple found for the provided identifier: NON-EXISTENT of type: ticker"
34
- ],
35
- }
32
+ expected_resp = GetHistoryMetadataFromIdentifiersResp.model_validate(
33
+ {
34
+ "results": {"SPGI": metadata_resp},
35
+ "errors": [
36
+ "No identification triple found for the provided identifier: NON-EXISTENT of type: ticker"
37
+ ],
38
+ }
39
+ )
36
40
 
37
41
  requests_mock.get(
38
42
  url=f"https://kfinance.kensho.com/api/v1/pricing/{SPGI_TRADING_ITEM_ID}/metadata",
@@ -80,33 +84,35 @@ class TestGetPricesFromIdentifiers:
80
84
  url=f"https://kfinance.kensho.com/api/v1/pricing/{SPGI_TRADING_ITEM_ID}/none/none/day/adjusted",
81
85
  json=self.prices_resp,
82
86
  )
83
- expected_response = {
84
- "results": {
85
- "SPGI": {
86
- "prices": [
87
- {
88
- "date": "2024-04-11",
89
- "open": {"value": "424.26", "unit": "USD"},
90
- "high": {"value": "425.99", "unit": "USD"},
91
- "low": {"value": "422.04", "unit": "USD"},
92
- "close": {"value": "422.92", "unit": "USD"},
93
- "volume": {"value": "1129158", "unit": "Shares"},
94
- },
95
- {
96
- "date": "2024-04-12",
97
- "open": {"value": "419.23", "unit": "USD"},
98
- "high": {"value": "421.94", "unit": "USD"},
99
- "low": {"value": "416.45", "unit": "USD"},
100
- "close": {"value": "417.81", "unit": "USD"},
101
- "volume": {"value": "1182229", "unit": "Shares"},
102
- },
103
- ]
104
- }
105
- },
106
- "errors": [
107
- "No identification triple found for the provided identifier: NON-EXISTENT of type: ticker"
108
- ],
109
- }
87
+ expected_response = GetPricesFromIdentifiersResp.model_validate(
88
+ {
89
+ "results": {
90
+ "SPGI": {
91
+ "prices": [
92
+ {
93
+ "date": "2024-04-11",
94
+ "open": {"value": "424.26", "unit": "USD"},
95
+ "high": {"value": "425.99", "unit": "USD"},
96
+ "low": {"value": "422.04", "unit": "USD"},
97
+ "close": {"value": "422.92", "unit": "USD"},
98
+ "volume": {"value": "1129158", "unit": "Shares"},
99
+ },
100
+ {
101
+ "date": "2024-04-12",
102
+ "open": {"value": "419.23", "unit": "USD"},
103
+ "high": {"value": "421.94", "unit": "USD"},
104
+ "low": {"value": "416.45", "unit": "USD"},
105
+ "close": {"value": "417.81", "unit": "USD"},
106
+ "volume": {"value": "1182229", "unit": "Shares"},
107
+ },
108
+ ]
109
+ }
110
+ },
111
+ "errors": [
112
+ "No identification triple found for the provided identifier: NON-EXISTENT of type: ticker"
113
+ ],
114
+ }
115
+ )
110
116
 
111
117
  tool = GetPricesFromIdentifiers(kfinance_client=mock_client)
112
118
  response = tool.run(
@@ -142,12 +148,14 @@ class TestGetPricesFromIdentifiers:
142
148
  }
143
149
  ]
144
150
  }
145
- expected_response = {
146
- "results": {
147
- "C_1": expected_single_company_response,
148
- "C_2": expected_single_company_response,
149
- },
150
- }
151
+ expected_response = GetPricesFromIdentifiersResp.model_validate(
152
+ {
153
+ "results": {
154
+ "C_1": expected_single_company_response,
155
+ "C_2": expected_single_company_response,
156
+ },
157
+ }
158
+ )
151
159
  tool = GetPricesFromIdentifiers(kfinance_client=mock_client)
152
160
  response = tool.run(
153
161
  GetPricesFromIdentifiersArgs(
@@ -43,7 +43,7 @@ class GetSegmentsFromIdentifiers(KfinanceTool):
43
43
  end_year: int | None = None,
44
44
  start_quarter: Literal[1, 2, 3, 4] | None = None,
45
45
  end_quarter: Literal[1, 2, 3, 4] | None = None,
46
- ) -> dict:
46
+ ) -> GetSegmentsFromIdentifiersResp:
47
47
  """Sample Response:
48
48
 
49
49
  {
@@ -102,7 +102,6 @@ class GetSegmentsFromIdentifiers(KfinanceTool):
102
102
  most_recent_year_data = segments_response.segments[most_recent_year]
103
103
  segments_response.segments = {most_recent_year: most_recent_year_data}
104
104
 
105
- output_model = GetSegmentsFromIdentifiersResp(
105
+ return GetSegmentsFromIdentifiersResp(
106
106
  results=segments_responses, errors=list(id_triple_resp.errors.values())
107
107
  )
108
- return output_model.model_dump(mode="json")
@@ -7,6 +7,7 @@ from kfinance.domains.segments.segment_models import SegmentType
7
7
  from kfinance.domains.segments.segment_tools import (
8
8
  GetSegmentsFromIdentifiers,
9
9
  GetSegmentsFromIdentifiersArgs,
10
+ GetSegmentsFromIdentifiersResp,
10
11
  )
11
12
 
12
13
 
@@ -43,12 +44,14 @@ class TestGetSegmentsFromIdentifier:
43
44
  json=self.segments_response,
44
45
  )
45
46
 
46
- expected_response = {
47
- "results": {"SPGI": self.segments_response},
48
- "errors": [
49
- "No identification triple found for the provided identifier: NON-EXISTENT of type: ticker"
50
- ],
51
- }
47
+ expected_response = GetSegmentsFromIdentifiersResp.model_validate(
48
+ {
49
+ "results": {"SPGI": self.segments_response},
50
+ "errors": [
51
+ "No identification triple found for the provided identifier: NON-EXISTENT of type: ticker"
52
+ ],
53
+ }
54
+ )
52
55
 
53
56
  tool = GetSegmentsFromIdentifiers(kfinance_client=mock_client)
54
57
  args = GetSegmentsFromIdentifiersArgs(
@@ -65,12 +68,14 @@ class TestGetSegmentsFromIdentifier:
65
68
  """
66
69
 
67
70
  company_ids = [1, 2]
68
- expected_response = {
69
- "results": {
70
- "C_1": {"segments": {"2021": self.segments_response["segments"]["2021"]}},
71
- "C_2": {"segments": {"2021": self.segments_response["segments"]["2021"]}},
71
+ expected_response = GetSegmentsFromIdentifiersResp.model_validate(
72
+ {
73
+ "results": {
74
+ "C_1": {"segments": {"2021": self.segments_response["segments"]["2021"]}},
75
+ "C_2": {"segments": {"2021": self.segments_response["segments"]["2021"]}},
76
+ }
72
77
  }
73
- }
78
+ )
74
79
 
75
80
  for company_id in company_ids:
76
81
  requests_mock.get(
@@ -55,7 +55,7 @@ class GetFinancialStatementFromIdentifiers(KfinanceTool):
55
55
  end_year: int | None = None,
56
56
  start_quarter: Literal[1, 2, 3, 4] | None = None,
57
57
  end_quarter: Literal[1, 2, 3, 4] | None = None,
58
- ) -> dict:
58
+ ) -> GetFinancialStatementFromIdentifiersResp:
59
59
  """Sample response:
60
60
 
61
61
  {
@@ -109,7 +109,6 @@ class GetFinancialStatementFromIdentifiers(KfinanceTool):
109
109
  most_recent_year_data = statement_response.statements[most_recent_year]
110
110
  statement_response.statements = {most_recent_year: most_recent_year_data}
111
111
 
112
- output_model = GetFinancialStatementFromIdentifiersResp(
112
+ return GetFinancialStatementFromIdentifiersResp(
113
113
  results=statement_responses, errors=list(id_triple_resp.errors.values())
114
114
  )
115
- return output_model.model_dump(mode="json")
@@ -7,6 +7,7 @@ from kfinance.domains.statements.statement_models import StatementType
7
7
  from kfinance.domains.statements.statement_tools import (
8
8
  GetFinancialStatementFromIdentifiers,
9
9
  GetFinancialStatementFromIdentifiersArgs,
10
+ GetFinancialStatementFromIdentifiersResp,
10
11
  )
11
12
 
12
13
 
@@ -31,25 +32,27 @@ class TestGetFinancialStatementFromIdentifiers:
31
32
  url=f"https://kfinance.kensho.com/api/v1/statements/{SPGI_COMPANY_ID}/income_statement/none/none/none/none/none",
32
33
  json=self.statement_resp,
33
34
  )
34
- expected_response = {
35
- "results": {
36
- "SPGI": {
37
- "statements": {
38
- "2020": {
39
- "Revenues": "7442000000.000000",
40
- "Total Revenues": "7442000000.000000",
41
- },
42
- "2021": {
43
- "Revenues": "8243000000.000000",
44
- "Total Revenues": "8243000000.000000",
45
- },
35
+ expected_response = GetFinancialStatementFromIdentifiersResp.model_validate(
36
+ {
37
+ "results": {
38
+ "SPGI": {
39
+ "statements": {
40
+ "2020": {
41
+ "Revenues": "7442000000.000000",
42
+ "Total Revenues": "7442000000.000000",
43
+ },
44
+ "2021": {
45
+ "Revenues": "8243000000.000000",
46
+ "Total Revenues": "8243000000.000000",
47
+ },
48
+ }
46
49
  }
47
- }
48
- },
49
- "errors": [
50
- "No identification triple found for the provided identifier: NON-EXISTENT of type: ticker"
51
- ],
52
- }
50
+ },
51
+ "errors": [
52
+ "No identification triple found for the provided identifier: NON-EXISTENT of type: ticker"
53
+ ],
54
+ }
55
+ )
53
56
 
54
57
  tool = GetFinancialStatementFromIdentifiers(kfinance_client=mock_client)
55
58
  args = GetFinancialStatementFromIdentifiersArgs(
@@ -66,26 +69,28 @@ class TestGetFinancialStatementFromIdentifiers:
66
69
  """
67
70
 
68
71
  company_ids = [1, 2]
69
- expected_response = {
70
- "results": {
71
- "C_1": {
72
- "statements": {
73
- "2021": {
74
- "Revenues": "8243000000.000000",
75
- "Total Revenues": "8243000000.000000",
72
+ expected_response = GetFinancialStatementFromIdentifiersResp.model_validate(
73
+ {
74
+ "results": {
75
+ "C_1": {
76
+ "statements": {
77
+ "2021": {
78
+ "Revenues": "8243000000.000000",
79
+ "Total Revenues": "8243000000.000000",
80
+ }
76
81
  }
77
- }
78
- },
79
- "C_2": {
80
- "statements": {
81
- "2021": {
82
- "Revenues": "8243000000.000000",
83
- "Total Revenues": "8243000000.000000",
82
+ },
83
+ "C_2": {
84
+ "statements": {
85
+ "2021": {
86
+ "Revenues": "8243000000.000000",
87
+ "Total Revenues": "8243000000.000000",
88
+ }
84
89
  }
85
- }
86
- },
90
+ },
91
+ }
87
92
  }
88
- }
93
+ )
89
94
 
90
95
  for company_id in company_ids:
91
96
  requests_mock.get(
@@ -11,6 +11,11 @@ class GetNQuartersAgoArgs(BaseModel):
11
11
  n: int = Field(description="Number of quarters before the current quarter")
12
12
 
13
13
 
14
+ class GetNQuartersAgoResp(BaseModel):
15
+ year: int
16
+ quarter: int
17
+
18
+
14
19
  class GetNQuartersAgo(KfinanceTool):
15
20
  name: str = "get_n_quarters_ago"
16
21
  description: str = (
@@ -3,6 +3,7 @@ from datetime import datetime
3
3
  import time_machine
4
4
 
5
5
  from kfinance.client.kfinance import Client
6
+ from kfinance.client.models.date_and_period_models import LatestPeriods
6
7
  from kfinance.integrations.tool_calling.static_tools.get_latest import GetLatest, GetLatestArgs
7
8
 
8
9
 
@@ -15,16 +16,18 @@ class TestGetLatest:
15
16
  THEN we get back latest info
16
17
  """
17
18
 
18
- expected_resp = {
19
- "annual": {"latest_year": 2024},
20
- "now": {
21
- "current_date": "2025-01-01",
22
- "current_month": 1,
23
- "current_quarter": 1,
24
- "current_year": 2025,
25
- },
26
- "quarterly": {"latest_quarter": 4, "latest_year": 2024},
27
- }
19
+ expected_resp = LatestPeriods.model_validate(
20
+ {
21
+ "annual": {"latest_year": 2024},
22
+ "now": {
23
+ "current_date": "2025-01-01",
24
+ "current_month": 1,
25
+ "current_quarter": 1,
26
+ "current_year": 2025,
27
+ },
28
+ "quarterly": {"latest_quarter": 4, "latest_year": 2024},
29
+ }
30
+ )
28
31
  tool = GetLatest(kfinance_client=mock_client)
29
32
  resp = tool.run(GetLatestArgs().model_dump(mode="json"))
30
33
  assert resp == expected_resp
@@ -3,6 +3,7 @@ from datetime import datetime
3
3
  import time_machine
4
4
 
5
5
  from kfinance.client.kfinance import Client
6
+ from kfinance.client.models.date_and_period_models import YearAndQuarter
6
7
  from kfinance.integrations.tool_calling.static_tools.get_n_quarters_ago import (
7
8
  GetNQuartersAgo,
8
9
  GetNQuartersAgoArgs,
@@ -18,7 +19,7 @@ class TestGetNQuartersAgo:
18
19
  THEN we get back 3 quarters ago
19
20
  """
20
21
 
21
- expected_resp = {"quarter": 2, "year": 2024}
22
+ expected_resp = YearAndQuarter(year=2024, quarter=2)
22
23
  tool = GetNQuartersAgo(kfinance_client=mock_client)
23
24
  resp = tool.run(GetNQuartersAgoArgs(n=3).model_dump(mode="json"))
24
25
  assert resp == expected_resp
@@ -7,7 +7,10 @@ from requests_mock import Mocker
7
7
 
8
8
  from kfinance.client.kfinance import Client
9
9
  from kfinance.conftest import SPGI_COMPANY_ID
10
- from kfinance.domains.companies.company_tools import GetInfoFromIdentifiers
10
+ from kfinance.domains.companies.company_tools import (
11
+ GetInfoFromIdentifiers,
12
+ GetInfoFromIdentifiersResp,
13
+ )
11
14
  from kfinance.integrations.tool_calling.tool_calling_models import ValidQuarter
12
15
 
13
16
 
@@ -27,7 +30,10 @@ class TestGetEndpointsFromToolCallsWithGrounding:
27
30
  "https://kfinance.kensho.com/api/v1/ids",
28
31
  "https://kfinance.kensho.com/api/v1/info/21719",
29
32
  ]
30
- expected_resp = {"data": {"results": {"SPGI": resp_data}}, "endpoint_urls": resp_endpoint}
33
+ expected_resp = {
34
+ "data": GetInfoFromIdentifiersResp.model_validate({"results": {"SPGI": resp_data}}),
35
+ "endpoint_urls": resp_endpoint,
36
+ }
31
37
 
32
38
  requests_mock.get(
33
39
  url=f"https://kfinance.kensho.com/api/v1/info/{SPGI_COMPANY_ID}",
@@ -1,3 +1,4 @@
1
+ import abc
1
2
  from typing import Annotated, Any, Callable, Dict, Literal, Type
2
3
 
3
4
  from langchain_core.tools import BaseTool
@@ -22,7 +23,7 @@ class KfinanceTool(BaseTool):
22
23
 
23
24
  model_config = ConfigDict(extra="forbid")
24
25
 
25
- def run_without_langchain(self, *args: Any, **kwargs: Any) -> Any:
26
+ def run_without_langchain(self, *args: Any, **kwargs: Any) -> dict:
26
27
  """Execute a Kfinance tool without langchain.
27
28
 
28
29
  Langchain converts json input params into the pydantic args_schema, which means that
@@ -38,7 +39,8 @@ class KfinanceTool(BaseTool):
38
39
  # This behavior matches the langchain handling. See
39
40
  # https://github.com/langchain-ai/langchain/blob/ca39680d2ab0d786bc035930778a5787e7bb5e01/libs/core/langchain_core/tools/base.py#L595-L597
40
41
  args_dict = {k: v for k, v in args_dict.items() if k in kwargs}
41
- return self._run(**args_dict)
42
+ result_model = self._run(**args_dict)
43
+ return result_model.model_dump(mode="json", exclude_none=True)
42
44
 
43
45
  def run_with_grounding(self, *args: Any, **kwargs: Any) -> Any:
44
46
  """Execute a Kfinance tool with grounding support.
@@ -47,7 +49,10 @@ class KfinanceTool(BaseTool):
47
49
  support, for returning the endpoint urls along with the data as citation info for the LRA Data Agent.
48
50
  """
49
51
  with self.kfinance_client.kfinance_api_client.endpoint_tracker() as endpoint_tracker_queue:
50
- data = self.run_without_langchain(*args, **kwargs)
52
+ args_model = self.args_schema.model_validate(kwargs)
53
+ args_dict = args_model.model_dump()
54
+ args_dict = {k: v for k, v in args_dict.items() if k in kwargs}
55
+ result_model = self._run(**args_dict)
51
56
 
52
57
  # After completion of tool data fetching and within the endpoint_tracker context manager scope, dequeue the endpoint_tracker_queue
53
58
  endpoint_urls = []
@@ -55,11 +60,12 @@ class KfinanceTool(BaseTool):
55
60
  endpoint_urls.append(endpoint_tracker_queue.get())
56
61
 
57
62
  return {
58
- "data": data,
63
+ "data": result_model,
59
64
  "endpoint_urls": endpoint_urls,
60
65
  }
61
66
 
62
- def _run(self, *args: Any, **kwargs: Any) -> Any:
67
+ @abc.abstractmethod
68
+ def _run(self, *args: Any, **kwargs: Any) -> BaseModel:
63
69
  """The code to execute the tool.
64
70
 
65
71
  Where feasible and useful, tools should use batch processing to parallelize
kfinance/version.py CHANGED
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '3.2.5'
32
- __version_tuple__ = version_tuple = (3, 2, 5)
31
+ __version__ = version = '3.2.7'
32
+ __version_tuple__ = version_tuple = (3, 2, 7)
33
33
 
34
34
  __commit_id__ = commit_id = None