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.
- {kensho_kfinance-3.2.5.dist-info → kensho_kfinance-3.2.7.dist-info}/METADATA +1 -1
- {kensho_kfinance-3.2.5.dist-info → kensho_kfinance-3.2.7.dist-info}/RECORD +43 -43
- kfinance/CHANGELOG.md +6 -0
- kfinance/client/fetch.py +7 -5
- kfinance/client/kfinance.py +38 -39
- kfinance/client/models/date_and_period_models.py +8 -7
- kfinance/client/tests/test_fetch.py +3 -1
- kfinance/client/tests/test_objects.py +38 -95
- kfinance/domains/business_relationships/business_relationship_tools.py +4 -4
- kfinance/domains/business_relationships/tests/test_business_relationship_tools.py +18 -16
- kfinance/domains/capitalizations/capitalization_models.py +3 -3
- kfinance/domains/capitalizations/capitalization_tools.py +7 -5
- kfinance/domains/capitalizations/tests/test_capitalization_tools.py +46 -36
- kfinance/domains/companies/company_models.py +8 -2
- kfinance/domains/companies/company_tools.py +8 -12
- kfinance/domains/companies/tests/test_company_tools.py +21 -9
- kfinance/domains/competitors/competitor_tools.py +2 -3
- kfinance/domains/competitors/tests/test_competitor_tools.py +22 -19
- kfinance/domains/cusip_and_isin/cusip_and_isin_tools.py +4 -6
- kfinance/domains/cusip_and_isin/tests/test_cusip_and_isin_tools.py +13 -8
- kfinance/domains/earnings/earning_tools.py +12 -9
- kfinance/domains/earnings/tests/test_earnings_tools.py +52 -43
- kfinance/domains/line_items/line_item_tools.py +2 -3
- kfinance/domains/line_items/tests/test_line_item_tools.py +20 -23
- kfinance/domains/mergers_and_acquisitions/merger_and_acquisition_models.py +46 -2
- kfinance/domains/mergers_and_acquisitions/merger_and_acquisition_tools.py +13 -68
- kfinance/domains/mergers_and_acquisitions/tests/test_merger_and_acquisition_tools.py +61 -59
- kfinance/domains/prices/price_tools.py +4 -7
- kfinance/domains/prices/tests/test_price_tools.py +47 -39
- kfinance/domains/segments/segment_tools.py +2 -3
- kfinance/domains/segments/tests/test_segment_tools.py +16 -11
- kfinance/domains/statements/statement_tools.py +2 -3
- kfinance/domains/statements/tests/test_statement_tools.py +40 -35
- kfinance/integrations/tool_calling/static_tools/get_n_quarters_ago.py +5 -0
- kfinance/integrations/tool_calling/static_tools/tests/test_get_lastest.py +13 -10
- kfinance/integrations/tool_calling/static_tools/tests/test_get_n_quarters_ago.py +2 -1
- kfinance/integrations/tool_calling/tests/test_tool_calling_models.py +8 -2
- kfinance/integrations/tool_calling/tool_calling_models.py +11 -5
- kfinance/version.py +2 -2
- {kensho_kfinance-3.2.5.dist-info → kensho_kfinance-3.2.7.dist-info}/WHEEL +0 -0
- {kensho_kfinance-3.2.5.dist-info → kensho_kfinance-3.2.7.dist-info}/licenses/AUTHORS.md +0 -0
- {kensho_kfinance-3.2.5.dist-info → kensho_kfinance-3.2.7.dist-info}/licenses/LICENSE +0 -0
- {kensho_kfinance-3.2.5.dist-info → kensho_kfinance-3.2.7.dist-info}/top_level.txt +0 -0
|
@@ -7,10 +7,13 @@ from kfinance.client.kfinance import Client
|
|
|
7
7
|
from kfinance.conftest import SPGI_COMPANY_ID
|
|
8
8
|
from kfinance.domains.earnings.earning_tools import (
|
|
9
9
|
GetEarningsFromIdentifiers,
|
|
10
|
+
GetEarningsFromIdentifiersResp,
|
|
10
11
|
GetLatestEarningsFromIdentifiers,
|
|
11
12
|
GetNextEarningsFromIdentifiers,
|
|
13
|
+
GetNextOrLatestEarningsFromIdentifiersResp,
|
|
12
14
|
GetTranscriptFromKeyDevId,
|
|
13
15
|
GetTranscriptFromKeyDevIdArgs,
|
|
16
|
+
GetTranscriptFromKeyDevIdResp,
|
|
14
17
|
)
|
|
15
18
|
from kfinance.integrations.tool_calling.tool_calling_models import ToolArgsWithIdentifiers
|
|
16
19
|
|
|
@@ -43,27 +46,29 @@ class TestGetEarnings:
|
|
|
43
46
|
json=self.earnings_response,
|
|
44
47
|
)
|
|
45
48
|
|
|
46
|
-
expected_response =
|
|
47
|
-
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
"
|
|
65
|
-
|
|
66
|
-
|
|
49
|
+
expected_response = GetEarningsFromIdentifiersResp.model_validate(
|
|
50
|
+
{
|
|
51
|
+
"results": {
|
|
52
|
+
"SPGI": {
|
|
53
|
+
"earnings": [
|
|
54
|
+
{
|
|
55
|
+
"name": "SPGI Q1 2025 Earnings Call",
|
|
56
|
+
"key_dev_id": 12346,
|
|
57
|
+
"datetime": "2025-04-29T12:30:00Z",
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"name": "SPGI Q4 2024 Earnings Call",
|
|
61
|
+
"key_dev_id": 12345,
|
|
62
|
+
"datetime": "2025-02-11T13:30:00Z",
|
|
63
|
+
},
|
|
64
|
+
]
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
"errors": [
|
|
68
|
+
"No identification triple found for the provided identifier: NON-EXISTENT of type: ticker"
|
|
69
|
+
],
|
|
70
|
+
}
|
|
71
|
+
)
|
|
67
72
|
|
|
68
73
|
tool = GetEarningsFromIdentifiers(kfinance_client=mock_client)
|
|
69
74
|
response = tool.run(
|
|
@@ -95,16 +100,18 @@ class TestGetEarnings:
|
|
|
95
100
|
json={"earnings": []},
|
|
96
101
|
)
|
|
97
102
|
|
|
98
|
-
expected_response =
|
|
99
|
-
|
|
100
|
-
"
|
|
101
|
-
"
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
103
|
+
expected_response = GetNextOrLatestEarningsFromIdentifiersResp.model_validate(
|
|
104
|
+
{
|
|
105
|
+
"results": {
|
|
106
|
+
"SPGI": {
|
|
107
|
+
"name": "SPGI Q1 2025 Earnings Call",
|
|
108
|
+
"key_dev_id": 12346,
|
|
109
|
+
"datetime": "2025-04-29T12:30:00Z",
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
"errors": ["No latest earnings available for private_company."],
|
|
113
|
+
}
|
|
114
|
+
)
|
|
108
115
|
|
|
109
116
|
tool = GetLatestEarningsFromIdentifiers(kfinance_client=mock_client)
|
|
110
117
|
response = tool.run(
|
|
@@ -136,16 +143,18 @@ class TestGetEarnings:
|
|
|
136
143
|
json={"earnings": []},
|
|
137
144
|
)
|
|
138
145
|
|
|
139
|
-
expected_response =
|
|
140
|
-
|
|
141
|
-
"
|
|
142
|
-
"
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
146
|
+
expected_response = GetNextOrLatestEarningsFromIdentifiersResp.model_validate(
|
|
147
|
+
{
|
|
148
|
+
"results": {
|
|
149
|
+
"SPGI": {
|
|
150
|
+
"datetime": "2025-04-29T12:30:00Z",
|
|
151
|
+
"key_dev_id": 12346,
|
|
152
|
+
"name": "SPGI Q1 2025 Earnings Call",
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
"errors": ["No next earnings available for private_company."],
|
|
156
|
+
}
|
|
157
|
+
)
|
|
149
158
|
|
|
150
159
|
tool = GetNextEarningsFromIdentifiers(kfinance_client=mock_client)
|
|
151
160
|
response = tool.run(
|
|
@@ -181,8 +190,8 @@ class TestGetTranscript:
|
|
|
181
190
|
json=transcript_data,
|
|
182
191
|
)
|
|
183
192
|
|
|
184
|
-
expected_response = (
|
|
185
|
-
"Operator: Good morning, everyone.\n\nCEO: Thank you for joining us today."
|
|
193
|
+
expected_response = GetTranscriptFromKeyDevIdResp(
|
|
194
|
+
transcript="Operator: Good morning, everyone.\n\nCEO: Thank you for joining us today."
|
|
186
195
|
)
|
|
187
196
|
|
|
188
197
|
tool = GetTranscriptFromKeyDevId(kfinance_client=mock_client)
|
|
@@ -63,7 +63,7 @@ class GetFinancialLineItemFromIdentifiers(KfinanceTool):
|
|
|
63
63
|
end_year: int | None = None,
|
|
64
64
|
start_quarter: Literal[1, 2, 3, 4] | None = None,
|
|
65
65
|
end_quarter: Literal[1, 2, 3, 4] | None = None,
|
|
66
|
-
) ->
|
|
66
|
+
) -> GetFinancialLineItemFromIdentifiersResp:
|
|
67
67
|
"""Sample response:
|
|
68
68
|
|
|
69
69
|
{
|
|
@@ -113,7 +113,6 @@ class GetFinancialLineItemFromIdentifiers(KfinanceTool):
|
|
|
113
113
|
most_recent_year_data = line_item_response.line_item[most_recent_year]
|
|
114
114
|
line_item_response.line_item = {most_recent_year: most_recent_year_data}
|
|
115
115
|
|
|
116
|
-
|
|
116
|
+
return GetFinancialLineItemFromIdentifiersResp(
|
|
117
117
|
results=line_item_responses, errors=list(id_triple_resp.errors.values())
|
|
118
118
|
)
|
|
119
|
-
return output_model.model_dump(mode="json")
|
|
@@ -1,12 +1,16 @@
|
|
|
1
|
+
from decimal import Decimal
|
|
2
|
+
|
|
1
3
|
from langchain_core.utils.function_calling import convert_to_openai_tool
|
|
2
4
|
from requests_mock import Mocker
|
|
3
5
|
|
|
4
6
|
from kfinance.client.kfinance import Client
|
|
5
7
|
from kfinance.conftest import SPGI_COMPANY_ID
|
|
6
8
|
from kfinance.domains.companies.company_models import COMPANY_ID_PREFIX
|
|
9
|
+
from kfinance.domains.line_items.line_item_models import LineItemResponse
|
|
7
10
|
from kfinance.domains.line_items.line_item_tools import (
|
|
8
11
|
GetFinancialLineItemFromIdentifiers,
|
|
9
12
|
GetFinancialLineItemFromIdentifiersArgs,
|
|
13
|
+
GetFinancialLineItemFromIdentifiersResp,
|
|
10
14
|
)
|
|
11
15
|
|
|
12
16
|
|
|
@@ -28,27 +32,20 @@ class TestGetFinancialLineItemFromCompanyIds:
|
|
|
28
32
|
THEN we get back the SPGI revenue and an error for the non-existent company
|
|
29
33
|
"""
|
|
30
34
|
|
|
31
|
-
expected_response =
|
|
32
|
-
|
|
33
|
-
"
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
expected_response = {
|
|
39
|
-
"results": {
|
|
40
|
-
"SPGI": {
|
|
41
|
-
"line_item": {
|
|
42
|
-
"2022": "11181000000.000000",
|
|
43
|
-
"2023": "12497000000.000000",
|
|
44
|
-
"2024": "14208000000.000000",
|
|
35
|
+
expected_response = GetFinancialLineItemFromIdentifiersResp(
|
|
36
|
+
results={
|
|
37
|
+
"SPGI": LineItemResponse(
|
|
38
|
+
line_item={
|
|
39
|
+
"2022": Decimal(11181000000),
|
|
40
|
+
"2023": Decimal(12497000000),
|
|
41
|
+
"2024": Decimal(14208000000),
|
|
45
42
|
}
|
|
46
|
-
|
|
43
|
+
)
|
|
47
44
|
},
|
|
48
|
-
|
|
45
|
+
errors=[
|
|
49
46
|
"No identification triple found for the provided identifier: NON-EXISTENT of type: ticker"
|
|
50
47
|
],
|
|
51
|
-
|
|
48
|
+
)
|
|
52
49
|
|
|
53
50
|
requests_mock.get(
|
|
54
51
|
url=f"https://kfinance.kensho.com/api/v1/line_item/{SPGI_COMPANY_ID}/revenue/none/none/none/none/none",
|
|
@@ -70,12 +67,12 @@ class TestGetFinancialLineItemFromCompanyIds:
|
|
|
70
67
|
"""
|
|
71
68
|
|
|
72
69
|
company_ids = [1, 2]
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
70
|
+
|
|
71
|
+
line_item_resp = LineItemResponse(line_item={"2024": Decimal(14208000000)})
|
|
72
|
+
expected_response = GetFinancialLineItemFromIdentifiersResp(
|
|
73
|
+
results={"C_1": line_item_resp, "C_2": line_item_resp},
|
|
74
|
+
)
|
|
75
|
+
|
|
79
76
|
for company_id in company_ids:
|
|
80
77
|
requests_mock.get(
|
|
81
78
|
url=f"https://kfinance.kensho.com/api/v1/line_item/{company_id}/revenue/none/none/none/none/none",
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
from datetime import date
|
|
2
|
+
from decimal import Decimal
|
|
2
3
|
|
|
3
|
-
from pydantic import BaseModel
|
|
4
|
+
from pydantic import BaseModel, field_serializer
|
|
5
|
+
|
|
6
|
+
from kfinance.domains.companies.company_models import COMPANY_ID_PREFIX, CompanyIdAndName
|
|
4
7
|
|
|
5
8
|
|
|
6
9
|
class MergerSummary(BaseModel):
|
|
@@ -16,6 +19,47 @@ class MergersResp(BaseModel):
|
|
|
16
19
|
|
|
17
20
|
|
|
18
21
|
class AdvisorResp(BaseModel):
|
|
19
|
-
advisor_company_id:
|
|
22
|
+
advisor_company_id: int
|
|
20
23
|
advisor_company_name: str
|
|
21
24
|
advisor_type_name: str | None
|
|
25
|
+
|
|
26
|
+
@field_serializer("advisor_company_id")
|
|
27
|
+
def serialize_with_prefix(self, company_id: int) -> str:
|
|
28
|
+
"""Serialize the advisor_company_id with a prefix ("C_<company_id>").
|
|
29
|
+
|
|
30
|
+
Including the prefix allows us to distinguish tickers and company_ids.
|
|
31
|
+
"""
|
|
32
|
+
return f"{COMPANY_ID_PREFIX}{company_id}"
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class MergerTimelineElement(BaseModel):
|
|
36
|
+
status: str
|
|
37
|
+
date: date
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class MergerParticipants(BaseModel):
|
|
41
|
+
target: CompanyIdAndName
|
|
42
|
+
buyers: list[CompanyIdAndName]
|
|
43
|
+
sellers: list[CompanyIdAndName]
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class MergerConsiderationDetail(BaseModel):
|
|
47
|
+
scenario: str | None = None
|
|
48
|
+
subtype: str | None = None
|
|
49
|
+
cash_or_cash_equivalent_per_target_share_unit: Decimal | None = None
|
|
50
|
+
number_of_target_shares_sought: Decimal | None = None
|
|
51
|
+
current_calculated_gross_value_of_consideration: Decimal | None = None
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class MergerConsideration(BaseModel):
|
|
55
|
+
currency_name: str | None = None
|
|
56
|
+
current_calculated_gross_total_transaction_value: Decimal | None = None
|
|
57
|
+
current_calculated_implied_equity_value: Decimal | None = None
|
|
58
|
+
current_calculated_implied_enterprise_value: Decimal | None = None
|
|
59
|
+
details: list[MergerConsiderationDetail]
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class MergerInfo(BaseModel):
|
|
63
|
+
timeline: list[MergerTimelineElement]
|
|
64
|
+
participants: MergerParticipants
|
|
65
|
+
consideration: MergerConsideration
|
|
@@ -4,11 +4,11 @@ from typing import Type
|
|
|
4
4
|
from pydantic import BaseModel, Field
|
|
5
5
|
|
|
6
6
|
from kfinance.client.batch_request_handling import Task, process_tasks_in_thread_pool_executor
|
|
7
|
-
from kfinance.client.kfinance import Company,
|
|
7
|
+
from kfinance.client.kfinance import Company, ParticipantInMerger
|
|
8
8
|
from kfinance.client.permission_models import Permission
|
|
9
|
-
from kfinance.domains.companies.company_models import prefix_company_id
|
|
10
9
|
from kfinance.domains.mergers_and_acquisitions.merger_and_acquisition_models import (
|
|
11
10
|
AdvisorResp,
|
|
11
|
+
MergerInfo,
|
|
12
12
|
MergersResp,
|
|
13
13
|
)
|
|
14
14
|
from kfinance.integrations.tool_calling.tool_calling_models import (
|
|
@@ -31,7 +31,7 @@ class GetMergersFromIdentifiers(KfinanceTool):
|
|
|
31
31
|
args_schema: Type[BaseModel] = ToolArgsWithIdentifiers
|
|
32
32
|
accepted_permissions: set[Permission] | None = {Permission.MergersPermission}
|
|
33
33
|
|
|
34
|
-
def _run(self, identifiers: list[str]) ->
|
|
34
|
+
def _run(self, identifiers: list[str]) -> GetMergersFromIdentifiersResp:
|
|
35
35
|
"""Sample Response:
|
|
36
36
|
|
|
37
37
|
{
|
|
@@ -79,10 +79,9 @@ class GetMergersFromIdentifiers(KfinanceTool):
|
|
|
79
79
|
merger_responses: dict[str, MergersResp] = process_tasks_in_thread_pool_executor(
|
|
80
80
|
api_client=api_client, tasks=tasks
|
|
81
81
|
)
|
|
82
|
-
|
|
82
|
+
return GetMergersFromIdentifiersResp(
|
|
83
83
|
results=merger_responses, errors=list(id_triple_resp.errors.values())
|
|
84
84
|
)
|
|
85
|
-
return output_model.model_dump(mode="json")
|
|
86
85
|
|
|
87
86
|
|
|
88
87
|
class GetMergerInfoFromTransactionIdArgs(BaseModel):
|
|
@@ -97,64 +96,10 @@ class GetMergerInfoFromTransactionId(KfinanceTool):
|
|
|
97
96
|
args_schema: Type[BaseModel] = GetMergerInfoFromTransactionIdArgs
|
|
98
97
|
accepted_permissions: set[Permission] | None = {Permission.MergersPermission}
|
|
99
98
|
|
|
100
|
-
def _run(self, transaction_id: int) ->
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
transaction_id=transaction_id,
|
|
104
|
-
merger_title=None,
|
|
105
|
-
closed_date=None,
|
|
99
|
+
def _run(self, transaction_id: int) -> MergerInfo:
|
|
100
|
+
return self.kfinance_client.kfinance_api_client.fetch_merger_info(
|
|
101
|
+
transaction_id=transaction_id
|
|
106
102
|
)
|
|
107
|
-
merger_timeline = merger_or_acquisition.get_timeline
|
|
108
|
-
merger_participants = merger_or_acquisition.get_participants
|
|
109
|
-
merger_consideration = merger_or_acquisition.get_consideration
|
|
110
|
-
|
|
111
|
-
return {
|
|
112
|
-
"timeline": [
|
|
113
|
-
{"status": timeline["status"], "date": timeline["date"].strftime("%Y-%m-%d")}
|
|
114
|
-
for timeline in merger_timeline.to_dict(orient="records")
|
|
115
|
-
]
|
|
116
|
-
if merger_timeline is not None
|
|
117
|
-
else None,
|
|
118
|
-
"participants": {
|
|
119
|
-
"target": {
|
|
120
|
-
"company_id": prefix_company_id(
|
|
121
|
-
merger_participants["target"].company.company_id
|
|
122
|
-
),
|
|
123
|
-
"company_name": merger_participants["target"].company.name,
|
|
124
|
-
},
|
|
125
|
-
"buyers": [
|
|
126
|
-
{
|
|
127
|
-
"company_id": prefix_company_id(buyer.company.company_id),
|
|
128
|
-
"company_name": buyer.company.name,
|
|
129
|
-
}
|
|
130
|
-
for buyer in merger_participants["buyers"]
|
|
131
|
-
],
|
|
132
|
-
"sellers": [
|
|
133
|
-
{
|
|
134
|
-
"company_id": prefix_company_id(seller.company.company_id),
|
|
135
|
-
"company_name": seller.company.name,
|
|
136
|
-
}
|
|
137
|
-
for seller in merger_participants["sellers"]
|
|
138
|
-
],
|
|
139
|
-
}
|
|
140
|
-
if merger_participants is not None
|
|
141
|
-
else None,
|
|
142
|
-
"consideration": {
|
|
143
|
-
"currency_name": merger_consideration["currency_name"],
|
|
144
|
-
"current_calculated_gross_total_transaction_value": merger_consideration[
|
|
145
|
-
"current_calculated_gross_total_transaction_value"
|
|
146
|
-
],
|
|
147
|
-
"current_calculated_implied_equity_value": merger_consideration[
|
|
148
|
-
"current_calculated_implied_equity_value"
|
|
149
|
-
],
|
|
150
|
-
"current_calculated_implied_enterprise_value": merger_consideration[
|
|
151
|
-
"current_calculated_implied_enterprise_value"
|
|
152
|
-
],
|
|
153
|
-
"details": merger_consideration["details"].to_dict(orient="records"),
|
|
154
|
-
}
|
|
155
|
-
if merger_consideration is not None
|
|
156
|
-
else None,
|
|
157
|
-
}
|
|
158
103
|
|
|
159
104
|
|
|
160
105
|
class GetAdvisorsForCompanyInTransactionFromIdentifierArgs(ToolArgsWithIdentifier):
|
|
@@ -173,15 +118,16 @@ class GetAdvisorsForCompanyInTransactionFromIdentifier(KfinanceTool):
|
|
|
173
118
|
args_schema: Type[BaseModel] = GetAdvisorsForCompanyInTransactionFromIdentifierArgs
|
|
174
119
|
accepted_permissions: set[Permission] | None = {Permission.MergersPermission}
|
|
175
120
|
|
|
176
|
-
def _run(
|
|
121
|
+
def _run(
|
|
122
|
+
self, identifier: str, transaction_id: int
|
|
123
|
+
) -> GetAdvisorsForCompanyInTransactionFromIdentifierResp:
|
|
177
124
|
api_client = self.kfinance_client.kfinance_api_client
|
|
178
125
|
id_triple_resp = api_client.unified_fetch_id_triples(identifiers=[identifier])
|
|
179
126
|
# If the identifier cannot be resolved, return the associated error.
|
|
180
127
|
if id_triple_resp.errors:
|
|
181
|
-
|
|
128
|
+
return GetAdvisorsForCompanyInTransactionFromIdentifierResp(
|
|
182
129
|
results=[], errors=list(id_triple_resp.errors.values())
|
|
183
130
|
)
|
|
184
|
-
return output_model.model_dump(mode="json")
|
|
185
131
|
|
|
186
132
|
id_triple = id_triple_resp.identifiers_to_id_triples[identifier]
|
|
187
133
|
|
|
@@ -201,13 +147,12 @@ class GetAdvisorsForCompanyInTransactionFromIdentifier(KfinanceTool):
|
|
|
201
147
|
for advisor in advisors:
|
|
202
148
|
advisors_response.append(
|
|
203
149
|
AdvisorResp(
|
|
204
|
-
advisor_company_id=
|
|
150
|
+
advisor_company_id=advisor.company.company_id,
|
|
205
151
|
advisor_company_name=advisor.company.name,
|
|
206
152
|
advisor_type_name=advisor.advisor_type_name,
|
|
207
153
|
)
|
|
208
154
|
)
|
|
209
155
|
|
|
210
|
-
|
|
156
|
+
return GetAdvisorsForCompanyInTransactionFromIdentifierResp(
|
|
211
157
|
results=advisors_response, errors=list(id_triple_resp.errors.values())
|
|
212
158
|
)
|
|
213
|
-
return output_model.model_dump(mode="json")
|
|
@@ -8,13 +8,18 @@ from kfinance.client.tests.test_objects import (
|
|
|
8
8
|
ordered,
|
|
9
9
|
)
|
|
10
10
|
from kfinance.conftest import SPGI_COMPANY_ID
|
|
11
|
-
from kfinance.domains.
|
|
11
|
+
from kfinance.domains.mergers_and_acquisitions.merger_and_acquisition_models import (
|
|
12
|
+
AdvisorResp,
|
|
13
|
+
MergerInfo,
|
|
14
|
+
)
|
|
12
15
|
from kfinance.domains.mergers_and_acquisitions.merger_and_acquisition_tools import (
|
|
13
16
|
GetAdvisorsForCompanyInTransactionFromIdentifier,
|
|
14
17
|
GetAdvisorsForCompanyInTransactionFromIdentifierArgs,
|
|
18
|
+
GetAdvisorsForCompanyInTransactionFromIdentifierResp,
|
|
15
19
|
GetMergerInfoFromTransactionId,
|
|
16
20
|
GetMergerInfoFromTransactionIdArgs,
|
|
17
21
|
GetMergersFromIdentifiers,
|
|
22
|
+
GetMergersFromIdentifiersResp,
|
|
18
23
|
)
|
|
19
24
|
from kfinance.integrations.tool_calling.tool_calling_models import ToolArgsWithIdentifiers
|
|
20
25
|
|
|
@@ -27,12 +32,14 @@ class TestGetMergersFromIdentifiers:
|
|
|
27
32
|
THEN we get back the SPGI mergers and an error for the non-existent company"""
|
|
28
33
|
|
|
29
34
|
merger_data = MERGERS_RESP.model_dump(mode="json")
|
|
30
|
-
expected_response =
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
"
|
|
34
|
-
|
|
35
|
-
|
|
35
|
+
expected_response = GetMergersFromIdentifiersResp.model_validate(
|
|
36
|
+
{
|
|
37
|
+
"results": {"SPGI": merger_data},
|
|
38
|
+
"errors": [
|
|
39
|
+
"No identification triple found for the provided identifier: NON-EXISTENT of type: ticker"
|
|
40
|
+
],
|
|
41
|
+
}
|
|
42
|
+
)
|
|
36
43
|
requests_mock.get(
|
|
37
44
|
url=f"https://kfinance.kensho.com/api/v1/mergers/{SPGI_COMPANY_ID}", json=merger_data
|
|
38
45
|
)
|
|
@@ -51,13 +58,21 @@ class TestGetCompaniesAdvisingCompanyInTransactionFromIdentifier:
|
|
|
51
58
|
"advisor_company_name": "Kensho Technologies, Inc.",
|
|
52
59
|
"advisor_type_name": "Professional Mongo Enjoyer",
|
|
53
60
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
61
|
+
expected_response = GetAdvisorsForCompanyInTransactionFromIdentifierResp(
|
|
62
|
+
results=[
|
|
63
|
+
AdvisorResp(
|
|
64
|
+
advisor_company_id=251994106,
|
|
65
|
+
advisor_company_name="Kensho Technologies, Inc.",
|
|
66
|
+
advisor_type_name="Professional Mongo Enjoyer",
|
|
67
|
+
)
|
|
68
|
+
],
|
|
69
|
+
errors=[],
|
|
70
|
+
)
|
|
71
|
+
|
|
57
72
|
transaction_id = 554979212
|
|
58
73
|
requests_mock.get(
|
|
59
74
|
url=f"https://kfinance.kensho.com/api/v1/merger/info/{transaction_id}/advisors/{SPGI_COMPANY_ID}",
|
|
60
|
-
json=
|
|
75
|
+
json={"advisors": [deepcopy(advisor_data)]},
|
|
61
76
|
)
|
|
62
77
|
tool = GetAdvisorsForCompanyInTransactionFromIdentifier(kfinance_client=mock_client)
|
|
63
78
|
args = GetAdvisorsForCompanyInTransactionFromIdentifierArgs(
|
|
@@ -67,14 +82,14 @@ class TestGetCompaniesAdvisingCompanyInTransactionFromIdentifier:
|
|
|
67
82
|
assert response == expected_response
|
|
68
83
|
|
|
69
84
|
def test_get_companies_advising_company_in_transaction_from_bad_identifier(
|
|
70
|
-
self,
|
|
85
|
+
self, mock_client: Client
|
|
71
86
|
):
|
|
72
|
-
expected_response =
|
|
73
|
-
|
|
74
|
-
|
|
87
|
+
expected_response = GetAdvisorsForCompanyInTransactionFromIdentifierResp(
|
|
88
|
+
results=[],
|
|
89
|
+
errors=[
|
|
75
90
|
"No identification triple found for the provided identifier: NON-EXISTENT of type: ticker"
|
|
76
91
|
],
|
|
77
|
-
|
|
92
|
+
)
|
|
78
93
|
transaction_id = 554979212
|
|
79
94
|
tool = GetAdvisorsForCompanyInTransactionFromIdentifier(kfinance_client=mock_client)
|
|
80
95
|
args = GetAdvisorsForCompanyInTransactionFromIdentifierArgs(
|
|
@@ -86,30 +101,11 @@ class TestGetCompaniesAdvisingCompanyInTransactionFromIdentifier:
|
|
|
86
101
|
|
|
87
102
|
class TestGetMergerInfoFromTransactionId:
|
|
88
103
|
def test_get_merger_info_from_transaction_id(self, requests_mock: Mocker, mock_client: Client):
|
|
89
|
-
|
|
90
|
-
"
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
"participants": {},
|
|
95
|
-
"consideration": {
|
|
96
|
-
"currency_name": "US Dollar",
|
|
97
|
-
"current_calculated_gross_total_transaction_value": "51609375.000000",
|
|
98
|
-
"current_calculated_implied_equity_value": "51609375.000000",
|
|
99
|
-
"current_calculated_implied_enterprise_value": "51609375.000000",
|
|
100
|
-
"details": [
|
|
101
|
-
{
|
|
102
|
-
"scenario": "Stock Lump Sum",
|
|
103
|
-
"subtype": "Common Equity",
|
|
104
|
-
"cash_or_cash_equivalent_per_target_share_unit": None,
|
|
105
|
-
"number_of_target_shares_sought": "1000000.000000",
|
|
106
|
-
"current_calculated_gross_value_of_consideration": "51609375.000000",
|
|
107
|
-
}
|
|
108
|
-
],
|
|
109
|
-
},
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
participants_api_response = {
|
|
104
|
+
timeline_resp = [
|
|
105
|
+
{"status": "Announced", "date": "2000-09-12"},
|
|
106
|
+
{"status": "Closed", "date": "2000-09-12"},
|
|
107
|
+
]
|
|
108
|
+
participants_resp = {
|
|
113
109
|
"target": {"company_id": 31696, "company_name": "MongoMusic, Inc."},
|
|
114
110
|
"buyers": [{"company_id": 21835, "company_name": "Microsoft Corporation"}],
|
|
115
111
|
"sellers": [
|
|
@@ -117,33 +113,39 @@ class TestGetMergerInfoFromTransactionId:
|
|
|
117
113
|
{"company_id": 20087, "company_name": "Draper Richards, L.P."},
|
|
118
114
|
],
|
|
119
115
|
}
|
|
120
|
-
api_response = deepcopy(response_base)
|
|
121
|
-
api_response["participants"] = participants_api_response
|
|
122
116
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
"
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
"buyers": [
|
|
130
|
-
{"company_id": f"{COMPANY_ID_PREFIX}21835", "company_name": "Microsoft Corporation"}
|
|
131
|
-
],
|
|
132
|
-
"sellers": [
|
|
133
|
-
{"company_id": f"{COMPANY_ID_PREFIX}18805", "company_name": "Angel Investors L.P."},
|
|
117
|
+
consideration_resp = {
|
|
118
|
+
"currency_name": "US Dollar",
|
|
119
|
+
"current_calculated_gross_total_transaction_value": "51609375.000000",
|
|
120
|
+
"current_calculated_implied_equity_value": "51609375.000000",
|
|
121
|
+
"current_calculated_implied_enterprise_value": "51609375.000000",
|
|
122
|
+
"details": [
|
|
134
123
|
{
|
|
135
|
-
"
|
|
136
|
-
"
|
|
137
|
-
|
|
124
|
+
"scenario": "Stock Lump Sum",
|
|
125
|
+
"subtype": "Common Equity",
|
|
126
|
+
"cash_or_cash_equivalent_per_target_share_unit": None,
|
|
127
|
+
"number_of_target_shares_sought": "1000000.000000",
|
|
128
|
+
"current_calculated_gross_value_of_consideration": "51609375.000000",
|
|
129
|
+
}
|
|
138
130
|
],
|
|
139
131
|
}
|
|
140
|
-
|
|
141
|
-
expected_response
|
|
132
|
+
|
|
133
|
+
expected_response = MergerInfo.model_validate(
|
|
134
|
+
{
|
|
135
|
+
"timeline": timeline_resp,
|
|
136
|
+
"participants": participants_resp,
|
|
137
|
+
"consideration": consideration_resp,
|
|
138
|
+
}
|
|
139
|
+
)
|
|
142
140
|
|
|
143
141
|
transaction_id = 517414
|
|
144
142
|
requests_mock.get(
|
|
145
143
|
url=f"https://kfinance.kensho.com/api/v1/merger/info/{transaction_id}",
|
|
146
|
-
json=
|
|
144
|
+
json={
|
|
145
|
+
"timeline": timeline_resp,
|
|
146
|
+
"participants": participants_resp,
|
|
147
|
+
"consideration": consideration_resp,
|
|
148
|
+
},
|
|
147
149
|
)
|
|
148
150
|
tool = GetMergerInfoFromTransactionId(kfinance_client=mock_client)
|
|
149
151
|
args = GetMergerInfoFromTransactionIdArgs(transaction_id=transaction_id)
|
|
@@ -60,7 +60,7 @@ class GetPricesFromIdentifiers(KfinanceTool):
|
|
|
60
60
|
end_date: date | None = None,
|
|
61
61
|
periodicity: Periodicity = Periodicity.day,
|
|
62
62
|
adjusted: bool = True,
|
|
63
|
-
) ->
|
|
63
|
+
) -> GetPricesFromIdentifiersResp:
|
|
64
64
|
"""Sample Response:
|
|
65
65
|
|
|
66
66
|
{
|
|
@@ -116,10 +116,9 @@ class GetPricesFromIdentifiers(KfinanceTool):
|
|
|
116
116
|
for price_response in price_responses.values():
|
|
117
117
|
price_response.prices = price_response.prices[-1:]
|
|
118
118
|
|
|
119
|
-
|
|
119
|
+
return GetPricesFromIdentifiersResp(
|
|
120
120
|
results=price_responses, errors=list(id_triple_resp.errors.values())
|
|
121
121
|
)
|
|
122
|
-
return output_model.model_dump(mode="json")
|
|
123
122
|
|
|
124
123
|
|
|
125
124
|
class GetHistoryMetadataFromIdentifiersResp(ToolRespWithErrors):
|
|
@@ -136,7 +135,7 @@ class GetHistoryMetadataFromIdentifiers(KfinanceTool):
|
|
|
136
135
|
args_schema: Type[BaseModel] = ToolArgsWithIdentifiers
|
|
137
136
|
accepted_permissions: set[Permission] | None = None
|
|
138
137
|
|
|
139
|
-
def _run(self, identifiers: list[str]) ->
|
|
138
|
+
def _run(self, identifiers: list[str]) -> GetHistoryMetadataFromIdentifiersResp:
|
|
140
139
|
"""Sample response:
|
|
141
140
|
|
|
142
141
|
{
|
|
@@ -169,8 +168,6 @@ class GetHistoryMetadataFromIdentifiers(KfinanceTool):
|
|
|
169
168
|
history_metadata_responses: dict[str, HistoryMetadataResp] = (
|
|
170
169
|
process_tasks_in_thread_pool_executor(api_client=api_client, tasks=tasks)
|
|
171
170
|
)
|
|
172
|
-
|
|
171
|
+
return GetHistoryMetadataFromIdentifiersResp(
|
|
173
172
|
results=history_metadata_responses, errors=list(id_triple_resp.errors.values())
|
|
174
173
|
)
|
|
175
|
-
|
|
176
|
-
return output_model.model_dump(mode="json")
|