kensho-kfinance 3.2.4__py3-none-any.whl → 3.2.6__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.4.dist-info → kensho_kfinance-3.2.6.dist-info}/METADATA +1 -1
  2. {kensho_kfinance-3.2.4.dist-info → kensho_kfinance-3.2.6.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_tools.py +8 -12
  15. kfinance/domains/companies/tests/test_company_tools.py +21 -9
  16. kfinance/domains/competitors/competitor_tools.py +2 -3
  17. kfinance/domains/competitors/tests/test_competitor_tools.py +22 -19
  18. kfinance/domains/cusip_and_isin/cusip_and_isin_tools.py +4 -6
  19. kfinance/domains/cusip_and_isin/tests/test_cusip_and_isin_tools.py +13 -8
  20. kfinance/domains/earnings/earning_tools.py +12 -9
  21. kfinance/domains/earnings/tests/test_earnings_tools.py +52 -43
  22. kfinance/domains/line_items/line_item_models.py +121 -0
  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.4.dist-info → kensho_kfinance-3.2.6.dist-info}/WHEEL +0 -0
  41. {kensho_kfinance-3.2.4.dist-info → kensho_kfinance-3.2.6.dist-info}/licenses/AUTHORS.md +0 -0
  42. {kensho_kfinance-3.2.4.dist-info → kensho_kfinance-3.2.6.dist-info}/licenses/LICENSE +0 -0
  43. {kensho_kfinance-3.2.4.dist-info → kensho_kfinance-3.2.6.dist-info}/top_level.txt +0 -0
@@ -8,6 +8,7 @@ from kfinance.domains.business_relationships.business_relationship_models import
8
8
  from kfinance.domains.business_relationships.business_relationship_tools import (
9
9
  GetBusinessRelationshipFromIdentifiers,
10
10
  GetBusinessRelationshipFromIdentifiersArgs,
11
+ GetBusinessRelationshipFromIdentifiersResp,
11
12
  )
12
13
 
13
14
 
@@ -27,21 +28,23 @@ class TestGetBusinessRelationshipFromIdentifiers:
27
28
  {"company_id": 8182358, "company_name": "Eloqua, Inc."},
28
29
  ],
29
30
  }
30
- expected_result = {
31
- "business_relationship": "supplier",
32
- "results": {
33
- "SPGI": {
34
- "current": [{"company_id": "C_883103", "company_name": "CRISIL Limited"}],
35
- "previous": [
36
- {"company_id": "C_472898", "company_name": "Morgan Stanley"},
37
- {"company_id": "C_8182358", "company_name": "Eloqua, Inc."},
38
- ],
39
- }
40
- },
41
- "errors": [
42
- "No identification triple found for the provided identifier: NON-EXISTENT of type: ticker"
43
- ],
44
- }
31
+ expected_result = GetBusinessRelationshipFromIdentifiersResp.model_validate(
32
+ {
33
+ "business_relationship": "supplier",
34
+ "results": {
35
+ "SPGI": {
36
+ "current": [{"company_id": 883103, "company_name": "CRISIL Limited"}],
37
+ "previous": [
38
+ {"company_id": 472898, "company_name": "Morgan Stanley"},
39
+ {"company_id": 8182358, "company_name": "Eloqua, Inc."},
40
+ ],
41
+ }
42
+ },
43
+ "errors": [
44
+ "No identification triple found for the provided identifier: NON-EXISTENT of type: ticker"
45
+ ],
46
+ }
47
+ )
45
48
 
46
49
  requests_mock.get(
47
50
  url=f"https://kfinance.kensho.com/api/v1/relationship/{SPGI_COMPANY_ID}/supplier",
@@ -54,5 +57,4 @@ class TestGetBusinessRelationshipFromIdentifiers:
54
57
  business_relationship=BusinessRelationshipType.supplier,
55
58
  )
56
59
  resp = tool.run(args.model_dump(mode="json"))
57
- resp["results"]["SPGI"]["previous"].sort(key=lambda x: x["company_id"])
58
60
  assert resp == expected_result
@@ -20,9 +20,9 @@ class DailyCapitalization(BaseModel):
20
20
  """DailyCapitalization represents market cap, TEV, and shares outstanding for a day"""
21
21
 
22
22
  date: date
23
- market_cap: Money
24
- tev: Money
25
- shares_outstanding: Shares
23
+ market_cap: Money | None
24
+ tev: Money | None
25
+ shares_outstanding: Shares | None
26
26
 
27
27
 
28
28
  class Capitalizations(BaseModel):
@@ -26,6 +26,7 @@ class GetCapitalizationFromIdentifiersArgs(ToolArgsWithIdentifiers):
26
26
 
27
27
 
28
28
  class GetCapitalizationFromIdentifiersResp(ToolRespWithErrors):
29
+ capitalization: Capitalization
29
30
  results: dict[str, Capitalizations]
30
31
 
31
32
 
@@ -50,13 +51,13 @@ class GetCapitalizationFromIdentifiers(KfinanceTool):
50
51
  capitalization: Capitalization,
51
52
  start_date: str | None = None,
52
53
  end_date: str | None = None,
53
- ) -> dict:
54
+ ) -> GetCapitalizationFromIdentifiersResp:
54
55
  """Sample response:
55
56
 
56
57
  {
58
+ 'capitalization': 'market_cap'
57
59
  'results': {
58
60
  'SPGI': {
59
- 'capitalizations': [
60
61
  {'date': '2024-04-10', 'market_cap': {'value': '132766738270.00', 'unit': 'USD'}},
61
62
  {'date': '2024-04-11', 'market_cap': {'value': '132416066761.00', 'unit': 'USD'}}
62
63
  ]
@@ -100,7 +101,8 @@ class GetCapitalizationFromIdentifiers(KfinanceTool):
100
101
  if capitalization is not Capitalization.shares_outstanding:
101
102
  daily_capitalization.shares_outstanding = None
102
103
 
103
- resp_model = GetCapitalizationFromIdentifiersResp(
104
- results=capitalization_responses, errors=list(id_triple_resp.errors.values())
104
+ return GetCapitalizationFromIdentifiersResp(
105
+ capitalization=capitalization,
106
+ results=capitalization_responses,
107
+ errors=list(id_triple_resp.errors.values()),
105
108
  )
106
- return resp_model.model_dump(mode="json", exclude_none=True)
@@ -1,11 +1,20 @@
1
+ from datetime import date
2
+ from decimal import Decimal
3
+
1
4
  from requests_mock import Mocker
2
5
 
3
6
  from kfinance.client.kfinance import Client
7
+ from kfinance.client.models.decimal_with_unit import Money
4
8
  from kfinance.conftest import SPGI_COMPANY_ID
5
- from kfinance.domains.capitalizations.capitalization_models import Capitalization
9
+ from kfinance.domains.capitalizations.capitalization_models import (
10
+ Capitalization,
11
+ Capitalizations,
12
+ DailyCapitalization,
13
+ )
6
14
  from kfinance.domains.capitalizations.capitalization_tools import (
7
15
  GetCapitalizationFromIdentifiers,
8
16
  GetCapitalizationFromIdentifiersArgs,
17
+ GetCapitalizationFromIdentifiersResp,
9
18
  )
10
19
  from kfinance.domains.companies.company_models import COMPANY_ID_PREFIX
11
20
 
@@ -40,25 +49,30 @@ class TestGetCapitalizationFromCompanyIds:
40
49
  json=self.market_caps_resp,
41
50
  )
42
51
 
43
- expected_response = {
44
- "results": {
45
- "SPGI": {
46
- "capitalizations": [
47
- {
48
- "date": "2024-04-10",
49
- "market_cap": {"value": "132766738270.00", "unit": "USD"},
50
- },
51
- {
52
- "date": "2024-04-11",
53
- "market_cap": {"value": "132416066761.00", "unit": "USD"},
54
- },
52
+ expected_response = GetCapitalizationFromIdentifiersResp(
53
+ capitalization=Capitalization.market_cap,
54
+ results={
55
+ "SPGI": Capitalizations(
56
+ market_caps=[
57
+ DailyCapitalization(
58
+ date=date(2024, 4, 10),
59
+ market_cap=Money(value=Decimal(132766738270), unit="USD"),
60
+ tev=None,
61
+ shares_outstanding=None,
62
+ ),
63
+ DailyCapitalization(
64
+ date=date(2024, 4, 11),
65
+ market_cap=Money(value=Decimal(132416066761), unit="USD"),
66
+ tev=None,
67
+ shares_outstanding=None,
68
+ ),
55
69
  ]
56
- }
70
+ )
57
71
  },
58
- "errors": [
72
+ errors=[
59
73
  "No identification triple found for the provided identifier: NON-EXISTENT of type: ticker"
60
74
  ],
61
- }
75
+ )
62
76
 
63
77
  tool = GetCapitalizationFromIdentifiers(kfinance_client=mock_client)
64
78
  args = GetCapitalizationFromIdentifiersArgs(
@@ -73,26 +87,22 @@ class TestGetCapitalizationFromCompanyIds:
73
87
  WHEN we request most recent market caps for multiple companies
74
88
  THEN we only get back the most recent market cap for each company
75
89
  """
76
- expected_response = {
77
- "results": {
78
- "C_1": {
79
- "capitalizations": [
80
- {
81
- "date": "2024-04-11",
82
- "market_cap": {"unit": "USD", "value": "132416066761.00"},
83
- }
84
- ]
85
- },
86
- "C_2": {
87
- "capitalizations": [
88
- {
89
- "date": "2024-04-11",
90
- "market_cap": {"unit": "USD", "value": "132416066761.00"},
91
- }
92
- ]
93
- },
94
- }
95
- }
90
+
91
+ capitalization = Capitalizations(
92
+ market_caps=[
93
+ DailyCapitalization(
94
+ date=date(2024, 4, 11),
95
+ market_cap=Money(value=Decimal(132416066761), unit="USD"),
96
+ tev=None,
97
+ shares_outstanding=None,
98
+ )
99
+ ]
100
+ )
101
+
102
+ expected_response = GetCapitalizationFromIdentifiersResp(
103
+ capitalization=Capitalization.market_cap,
104
+ results={"C_1": capitalization, "C_2": capitalization},
105
+ )
96
106
 
97
107
  company_ids = [1, 2]
98
108
  for company_id in company_ids:
@@ -27,7 +27,7 @@ class GetInfoFromIdentifiers(KfinanceTool):
27
27
  args_schema: Type[BaseModel] = ToolArgsWithIdentifiers
28
28
  accepted_permissions: set[Permission] | None = None
29
29
 
30
- def _run(self, identifiers: list[str]) -> dict:
30
+ def _run(self, identifiers: list[str]) -> GetInfoFromIdentifiersResp:
31
31
  """Sample response:
32
32
 
33
33
  { "results": {
@@ -65,10 +65,9 @@ class GetInfoFromIdentifiers(KfinanceTool):
65
65
  info_responses: dict[str, dict] = process_tasks_in_thread_pool_executor(
66
66
  api_client=api_client, tasks=tasks
67
67
  )
68
- resp_model = GetInfoFromIdentifiersResp(
68
+ return GetInfoFromIdentifiersResp(
69
69
  results=info_responses, errors=list(id_triple_resp.errors.values())
70
70
  )
71
- return resp_model.model_dump(mode="json")
72
71
 
73
72
 
74
73
  class GetCompanyOtherNamesFromIdentifiersResp(ToolRespWithErrors):
@@ -88,7 +87,7 @@ class GetCompanyOtherNamesFromIdentifiers(KfinanceTool):
88
87
  def _run(
89
88
  self,
90
89
  identifiers: list[str],
91
- ) -> dict:
90
+ ) -> GetCompanyOtherNamesFromIdentifiersResp:
92
91
  api_client = self.kfinance_client.kfinance_api_client
93
92
  id_triple_resp = api_client.unified_fetch_id_triples(identifiers=identifiers)
94
93
  tasks = [
@@ -102,10 +101,9 @@ class GetCompanyOtherNamesFromIdentifiers(KfinanceTool):
102
101
  info_responses: dict[str, CompanyOtherNames] = process_tasks_in_thread_pool_executor(
103
102
  api_client=api_client, tasks=tasks
104
103
  )
105
- resp_model = GetCompanyOtherNamesFromIdentifiersResp(
104
+ return GetCompanyOtherNamesFromIdentifiersResp(
106
105
  results=info_responses, errors=list(id_triple_resp.errors.values())
107
106
  )
108
- return resp_model.model_dump(mode="json")
109
107
 
110
108
 
111
109
  class GetCompanySummaryFromIdentifiersResp(ToolRespWithErrors):
@@ -125,7 +123,7 @@ class GetCompanySummaryFromIdentifiers(KfinanceTool):
125
123
  def _run(
126
124
  self,
127
125
  identifiers: list[str],
128
- ) -> dict:
126
+ ) -> GetCompanySummaryFromIdentifiersResp:
129
127
  api_client = self.kfinance_client.kfinance_api_client
130
128
  id_triple_resp = api_client.unified_fetch_id_triples(identifiers=identifiers)
131
129
 
@@ -147,10 +145,9 @@ class GetCompanySummaryFromIdentifiers(KfinanceTool):
147
145
  for identifier, descriptions in company_description_responses.items()
148
146
  }
149
147
 
150
- resp_model = GetCompanySummaryFromIdentifiersResp(
148
+ return GetCompanySummaryFromIdentifiersResp(
151
149
  results=summary_results, errors=list(id_triple_resp.errors.values())
152
150
  )
153
- return resp_model.model_dump(mode="json")
154
151
 
155
152
 
156
153
  class GetCompanyDescriptionFromIdentifiersResp(ToolRespWithErrors):
@@ -170,7 +167,7 @@ class GetCompanyDescriptionFromIdentifiers(KfinanceTool):
170
167
  def _run(
171
168
  self,
172
169
  identifiers: list[str],
173
- ) -> dict:
170
+ ) -> GetCompanyDescriptionFromIdentifiersResp:
174
171
  api_client = self.kfinance_client.kfinance_api_client
175
172
  id_triple_resp = api_client.unified_fetch_id_triples(identifiers=identifiers)
176
173
 
@@ -192,7 +189,6 @@ class GetCompanyDescriptionFromIdentifiers(KfinanceTool):
192
189
  for identifier, descriptions in company_description_responses.items()
193
190
  }
194
191
 
195
- resp_model = GetCompanyDescriptionFromIdentifiersResp(
192
+ return GetCompanyDescriptionFromIdentifiersResp(
196
193
  results=description_results, errors=list(id_triple_resp.errors.values())
197
194
  )
198
- return resp_model.model_dump(mode="json")
@@ -4,9 +4,13 @@ from kfinance.client.kfinance import Client
4
4
  from kfinance.conftest import SPGI_COMPANY_ID
5
5
  from kfinance.domains.companies.company_tools import (
6
6
  GetCompanyDescriptionFromIdentifiers,
7
+ GetCompanyDescriptionFromIdentifiersResp,
7
8
  GetCompanyOtherNamesFromIdentifiers,
9
+ GetCompanyOtherNamesFromIdentifiersResp,
8
10
  GetCompanySummaryFromIdentifiers,
11
+ GetCompanySummaryFromIdentifiersResp,
9
12
  GetInfoFromIdentifiers,
13
+ GetInfoFromIdentifiersResp,
10
14
  )
11
15
  from kfinance.integrations.tool_calling.tool_calling_models import ToolArgsWithIdentifiers
12
16
 
@@ -20,12 +24,14 @@ class TestGetInfoFromIdentifiers:
20
24
  """
21
25
 
22
26
  info_resp = {"name": "S&P Global Inc.", "status": "Operating"}
23
- expected_response = {
24
- "results": {"SPGI": info_resp},
25
- "errors": [
26
- "No identification triple found for the provided identifier: NON-EXISTENT of type: ticker"
27
- ],
28
- }
27
+ expected_response = GetInfoFromIdentifiersResp.model_validate(
28
+ {
29
+ "results": {"SPGI": info_resp},
30
+ "errors": [
31
+ "No identification triple found for the provided identifier: NON-EXISTENT of type: ticker"
32
+ ],
33
+ }
34
+ )
29
35
  requests_mock.get(
30
36
  url=f"https://kfinance.kensho.com/api/v1/info/{SPGI_COMPANY_ID}",
31
37
  json=info_resp,
@@ -61,7 +67,9 @@ class TestGetCompanyDescriptions:
61
67
  tool = GetCompanySummaryFromIdentifiers(kfinance_client=mock_client)
62
68
  args = ToolArgsWithIdentifiers(identifiers=["SPGI"])
63
69
  response = tool.run(args.model_dump(mode="json"))
64
- expected_response = {"results": {"SPGI": self.summary}}
70
+ expected_response = GetCompanySummaryFromIdentifiersResp.model_validate(
71
+ {"results": {"SPGI": self.summary}}
72
+ )
65
73
  assert response == expected_response
66
74
 
67
75
  def test_get_company_description_from_identifier(
@@ -81,7 +89,9 @@ class TestGetCompanyDescriptions:
81
89
  tool = GetCompanyDescriptionFromIdentifiers(kfinance_client=mock_client)
82
90
  args = ToolArgsWithIdentifiers(identifiers=["SPGI"])
83
91
  response = tool.run(args.model_dump(mode="json"))
84
- expected_response = {"results": {"SPGI": self.description}}
92
+ expected_response = GetCompanyDescriptionFromIdentifiersResp.model_validate(
93
+ {"results": {"SPGI": self.description}}
94
+ )
85
95
  assert response == expected_response
86
96
 
87
97
 
@@ -121,5 +131,7 @@ class TestGetCompanyOtherNames:
121
131
  tool = GetCompanyOtherNamesFromIdentifiers(kfinance_client=mock_client)
122
132
  args = ToolArgsWithIdentifiers(identifiers=["SPGI"])
123
133
  response = tool.run(args.model_dump(mode="json"))
124
- expected_response = {"results": {"SPGI": self.company_other_names_info}}
134
+ expected_response = GetCompanyOtherNamesFromIdentifiersResp.model_validate(
135
+ {"results": {"SPGI": self.company_other_names_info}}
136
+ )
125
137
  assert response == expected_response
@@ -27,7 +27,7 @@ class GetCompetitorsFromIdentifiers(KfinanceTool):
27
27
  self,
28
28
  identifiers: list[str],
29
29
  competitor_source: CompetitorSource,
30
- ) -> dict:
30
+ ) -> GetCompetitorsFromIdentifiersResp:
31
31
  """Sample response:
32
32
 
33
33
  {
@@ -56,7 +56,6 @@ class GetCompetitorsFromIdentifiers(KfinanceTool):
56
56
  competitor_responses: dict[str, CompetitorResponse] = process_tasks_in_thread_pool_executor(
57
57
  api_client=api_client, tasks=tasks
58
58
  )
59
- resp_model = GetCompetitorsFromIdentifiersResp(
59
+ return GetCompetitorsFromIdentifiersResp(
60
60
  results=competitor_responses, errors=list(id_triple_resp.errors.values())
61
61
  )
62
- return resp_model.model_dump(mode="json")
@@ -6,6 +6,7 @@ from kfinance.domains.competitors.competitor_models import CompetitorSource
6
6
  from kfinance.domains.competitors.competitor_tools import (
7
7
  GetCompetitorsFromIdentifiers,
8
8
  GetCompetitorsFromIdentifiersArgs,
9
+ GetCompetitorsFromIdentifiersResp,
9
10
  )
10
11
 
11
12
 
@@ -24,25 +25,27 @@ class TestGetCompetitorsFromIdentifiers:
24
25
  {"company_id": 4003514, "company_name": "London Stock Exchange Group plc"},
25
26
  ]
26
27
  }
27
- expected_response = {
28
- "results": {
29
- "SPGI": {
30
- "competitors": [
31
- {
32
- "company_id": "C_35352",
33
- "company_name": "The Descartes Systems Group Inc.",
34
- },
35
- {
36
- "company_id": "C_4003514",
37
- "company_name": "London Stock Exchange Group plc",
38
- },
39
- ]
40
- }
41
- },
42
- "errors": [
43
- "No identification triple found for the provided identifier: NON-EXISTENT of type: ticker"
44
- ],
45
- }
28
+ expected_response = GetCompetitorsFromIdentifiersResp.model_validate(
29
+ {
30
+ "results": {
31
+ "SPGI": {
32
+ "competitors": [
33
+ {
34
+ "company_id": 35352,
35
+ "company_name": "The Descartes Systems Group Inc.",
36
+ },
37
+ {
38
+ "company_id": 4003514,
39
+ "company_name": "London Stock Exchange Group plc",
40
+ },
41
+ ]
42
+ }
43
+ },
44
+ "errors": [
45
+ "No identification triple found for the provided identifier: NON-EXISTENT of type: ticker"
46
+ ],
47
+ }
48
+ )
46
49
 
47
50
  requests_mock.get(
48
51
  url=f"https://kfinance.kensho.com/api/v1/competitors/{SPGI_COMPANY_ID}/named_by_competitor",
@@ -23,7 +23,7 @@ class GetCusipFromIdentifiers(KfinanceTool):
23
23
  args_schema: Type[BaseModel] = ToolArgsWithIdentifiers
24
24
  accepted_permissions: set[Permission] | None = {Permission.IDPermission}
25
25
 
26
- def _run(self, identifiers: list[str]) -> dict[str, str]:
26
+ def _run(self, identifiers: list[str]) -> GetCusipOrIsinFromIdentifiersResp:
27
27
  """Sample response:
28
28
 
29
29
  {
@@ -45,14 +45,13 @@ class GetCusipFromIdentifiers(KfinanceTool):
45
45
  ]
46
46
 
47
47
  cusip_responses = process_tasks_in_thread_pool_executor(api_client=api_client, tasks=tasks)
48
- resp_model = GetCusipOrIsinFromIdentifiersResp(
48
+ return GetCusipOrIsinFromIdentifiersResp(
49
49
  results={
50
50
  identifier: cusip_resp["cusip"]
51
51
  for identifier, cusip_resp in cusip_responses.items()
52
52
  },
53
53
  errors=list(id_triple_resp.errors.values()),
54
54
  )
55
- return resp_model.model_dump(mode="json")
56
55
 
57
56
 
58
57
  class GetIsinFromIdentifiers(KfinanceTool):
@@ -61,7 +60,7 @@ class GetIsinFromIdentifiers(KfinanceTool):
61
60
  args_schema: Type[BaseModel] = ToolArgsWithIdentifiers
62
61
  accepted_permissions: set[Permission] | None = {Permission.IDPermission}
63
62
 
64
- def _run(self, identifiers: list[str]) -> dict:
63
+ def _run(self, identifiers: list[str]) -> GetCusipOrIsinFromIdentifiersResp:
65
64
  """Sample response:
66
65
 
67
66
  {
@@ -83,10 +82,9 @@ class GetIsinFromIdentifiers(KfinanceTool):
83
82
  ]
84
83
 
85
84
  isin_responses = process_tasks_in_thread_pool_executor(api_client=api_client, tasks=tasks)
86
- resp_model = GetCusipOrIsinFromIdentifiersResp(
85
+ return GetCusipOrIsinFromIdentifiersResp(
87
86
  results={
88
87
  identifier: isin_resp["isin"] for identifier, isin_resp in isin_responses.items()
89
88
  },
90
89
  errors=list(id_triple_resp.errors.values()),
91
90
  )
92
- return resp_model.model_dump(mode="json")
@@ -4,6 +4,7 @@ from kfinance.client.kfinance import Client
4
4
  from kfinance.conftest import SPGI_SECURITY_ID
5
5
  from kfinance.domains.cusip_and_isin.cusip_and_isin_tools import (
6
6
  GetCusipFromIdentifiers,
7
+ GetCusipOrIsinFromIdentifiersResp,
7
8
  GetIsinFromIdentifiers,
8
9
  )
9
10
  from kfinance.integrations.tool_calling.tool_calling_models import ToolArgsWithIdentifiers
@@ -18,10 +19,12 @@ class TestGetCusipFromIdentifiers:
18
19
  """
19
20
 
20
21
  spgi_cusip = "78409V104"
21
- expected_response = {
22
- "results": {"SPGI": "78409V104"},
23
- "errors": ["private_company is a private company without a security_id."],
24
- }
22
+ expected_response = GetCusipOrIsinFromIdentifiersResp.model_validate(
23
+ {
24
+ "results": {"SPGI": "78409V104"},
25
+ "errors": ["private_company is a private company without a security_id."],
26
+ }
27
+ )
25
28
  requests_mock.get(
26
29
  url=f"https://kfinance.kensho.com/api/v1/cusip/{SPGI_SECURITY_ID}",
27
30
  json={"cusip": spgi_cusip},
@@ -43,10 +46,12 @@ class TestGetIsinFromIdentifiers:
43
46
 
44
47
  spgi_isin = "US78409V1044"
45
48
 
46
- expected_response = {
47
- "results": {"SPGI": "US78409V1044"},
48
- "errors": ["private_company is a private company without a security_id."],
49
- }
49
+ expected_response = GetCusipOrIsinFromIdentifiersResp.model_validate(
50
+ {
51
+ "results": {"SPGI": "US78409V1044"},
52
+ "errors": ["private_company is a private company without a security_id."],
53
+ }
54
+ )
50
55
  requests_mock.get(
51
56
  url=f"https://kfinance.kensho.com/api/v1/isin/{SPGI_SECURITY_ID}",
52
57
  json={"isin": spgi_isin},
@@ -35,7 +35,7 @@ class GetEarningsFromIdentifiers(KfinanceTool):
35
35
  Permission.TranscriptsPermission,
36
36
  }
37
37
 
38
- def _run(self, identifiers: list[str]) -> dict:
38
+ def _run(self, identifiers: list[str]) -> GetEarningsFromIdentifiersResp:
39
39
  """Sample response:
40
40
 
41
41
  {
@@ -52,10 +52,9 @@ class GetEarningsFromIdentifiers(KfinanceTool):
52
52
  }
53
53
 
54
54
  """
55
- earnings_responses = get_earnings_from_identifiers(
55
+ return get_earnings_from_identifiers(
56
56
  identifiers=identifiers, kfinance_api_client=self.kfinance_client.kfinance_api_client
57
57
  )
58
- return earnings_responses.model_dump(mode="json")
59
58
 
60
59
 
61
60
  class GetLatestEarningsFromIdentifiers(KfinanceTool):
@@ -71,7 +70,7 @@ class GetLatestEarningsFromIdentifiers(KfinanceTool):
71
70
  Permission.TranscriptsPermission,
72
71
  }
73
72
 
74
- def _run(self, identifiers: list[str]) -> dict:
73
+ def _run(self, identifiers: list[str]) -> GetNextOrLatestEarningsFromIdentifiersResp:
75
74
  """Sample response:
76
75
 
77
76
  {
@@ -95,7 +94,7 @@ class GetLatestEarningsFromIdentifiers(KfinanceTool):
95
94
  output_model.results[identifier] = most_recent_earnings
96
95
  else:
97
96
  output_model.errors.append(f"No latest earnings available for {identifier}.")
98
- return output_model.model_dump(mode="json")
97
+ return output_model
99
98
 
100
99
 
101
100
  class GetNextEarningsFromIdentifiers(KfinanceTool):
@@ -111,7 +110,7 @@ class GetNextEarningsFromIdentifiers(KfinanceTool):
111
110
  Permission.TranscriptsPermission,
112
111
  }
113
112
 
114
- def _run(self, identifiers: list[str]) -> dict:
113
+ def _run(self, identifiers: list[str]) -> GetNextOrLatestEarningsFromIdentifiersResp:
115
114
  """Sample response:
116
115
 
117
116
  {
@@ -135,7 +134,7 @@ class GetNextEarningsFromIdentifiers(KfinanceTool):
135
134
  output_model.results[identifier] = next_earnings
136
135
  else:
137
136
  output_model.errors.append(f"No next earnings available for {identifier}.")
138
- return output_model.model_dump(mode="json")
137
+ return output_model
139
138
 
140
139
 
141
140
  def get_earnings_from_identifiers(
@@ -170,12 +169,16 @@ class GetTranscriptFromKeyDevIdArgs(BaseModel):
170
169
  key_dev_id: int = Field(description="The key dev ID for the earnings call")
171
170
 
172
171
 
172
+ class GetTranscriptFromKeyDevIdResp(BaseModel):
173
+ transcript: str
174
+
175
+
173
176
  class GetTranscriptFromKeyDevId(KfinanceTool):
174
177
  name: str = "get_transcript_from_key_dev_id"
175
178
  description: str = "Get the raw transcript text for an earnings call by key dev ID."
176
179
  args_schema: Type[BaseModel] = GetTranscriptFromKeyDevIdArgs
177
180
  accepted_permissions: set[Permission] | None = {Permission.TranscriptsPermission}
178
181
 
179
- def _run(self, key_dev_id: int) -> str:
182
+ def _run(self, key_dev_id: int) -> GetTranscriptFromKeyDevIdResp:
180
183
  transcript = self.kfinance_client.transcript(key_dev_id)
181
- return transcript.raw
184
+ return GetTranscriptFromKeyDevIdResp(transcript=transcript.raw)