kensho-kfinance 2.8.0__py3-none-any.whl → 3.0.0__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-2.8.0.dist-info → kensho_kfinance-3.0.0.dist-info}/METADATA +2 -2
- kensho_kfinance-3.0.0.dist-info/RECORD +110 -0
- kfinance/CHANGELOG.md +6 -0
- kfinance/__init__.py +1 -0
- kfinance/client/README.md +9 -0
- kfinance/{batch_request_handling.py → client/batch_request_handling.py} +63 -27
- kfinance/{fetch.py → client/fetch.py} +23 -29
- kfinance/{kfinance.py → client/kfinance.py} +105 -111
- kfinance/{meta_classes.py → client/meta_classes.py} +26 -35
- kfinance/{decimal_with_unit.py → client/models/decimal_with_unit.py} +1 -1
- kfinance/{tests → client/models/tests}/test_decimal_with_unit.py +1 -1
- kfinance/client/tests/__init__.py +0 -0
- kfinance/{tests → client/tests}/test_batch_requests.py +8 -6
- kfinance/{tests → client/tests}/test_client.py +25 -19
- kfinance/{tests → client/tests}/test_fetch.py +11 -29
- kfinance/{tests → client/tests}/test_group_objects.py +1 -1
- kfinance/{tests → client/tests}/test_objects.py +111 -63
- kfinance/{tests/conftest.py → conftest.py} +14 -2
- kfinance/domains/README.md +14 -0
- kfinance/domains/__init__.py +0 -0
- kfinance/domains/business_relationships/__init__.py +0 -0
- kfinance/{models → domains/business_relationships}/business_relationship_models.py +10 -0
- kfinance/domains/business_relationships/business_relationship_tools.py +74 -0
- kfinance/domains/business_relationships/tests/__init__.py +0 -0
- kfinance/domains/business_relationships/tests/test_business_relationship_tools.py +55 -0
- kfinance/domains/capitalizations/__init__.py +0 -0
- kfinance/{models → domains/capitalizations}/capitalization_models.py +24 -17
- kfinance/domains/capitalizations/capitalization_tools.py +89 -0
- kfinance/domains/capitalizations/tests/__init__.py +0 -0
- kfinance/{tests/test_models → domains/capitalizations/tests}/test_capitalization_models.py +8 -10
- kfinance/domains/capitalizations/tests/test_capitalization_tools.py +85 -0
- kfinance/domains/companies/__init__.py +0 -0
- kfinance/domains/companies/company_identifiers.py +175 -0
- kfinance/domains/companies/company_models.py +27 -0
- kfinance/domains/companies/company_tools.py +66 -0
- kfinance/domains/companies/tests/__init__.py +0 -0
- kfinance/domains/companies/tests/test_company_tools.py +26 -0
- kfinance/domains/competitors/__init__.py +0 -0
- kfinance/{models → domains/competitors}/competitor_models.py +7 -0
- kfinance/domains/competitors/competitor_tools.py +62 -0
- kfinance/domains/competitors/tests/__init__.py +0 -0
- kfinance/domains/competitors/tests/test_competitor_tools.py +45 -0
- kfinance/domains/cusip_and_isin/__init__.py +0 -0
- kfinance/domains/cusip_and_isin/cusip_and_isin_tools.py +80 -0
- kfinance/domains/cusip_and_isin/tests/__init__.py +0 -0
- kfinance/domains/cusip_and_isin/tests/test_cusip_and_isin_tools.py +57 -0
- kfinance/domains/earnings/__init__.py +0 -0
- kfinance/domains/earnings/earning_models.py +41 -0
- kfinance/domains/earnings/earning_tools.py +174 -0
- kfinance/domains/earnings/tests/__init__.py +0 -0
- kfinance/domains/earnings/tests/test_earnings_tools.py +195 -0
- kfinance/domains/line_items/__init__.py +0 -0
- kfinance/domains/line_items/line_item_tools.py +114 -0
- kfinance/domains/line_items/tests/__init__.py +0 -0
- kfinance/domains/line_items/tests/test_line_item_tools.py +86 -0
- kfinance/domains/mergers_and_acquisitions/__init__.py +0 -0
- kfinance/domains/mergers_and_acquisitions/merger_and_acquisition_tools.py +176 -0
- kfinance/domains/mergers_and_acquisitions/tests/__init__.py +0 -0
- kfinance/domains/mergers_and_acquisitions/tests/test_merger_and_acquisition_tools.py +124 -0
- kfinance/domains/prices/__init__.py +0 -0
- kfinance/{models → domains/prices}/price_models.py +1 -1
- kfinance/domains/prices/price_tools.py +165 -0
- kfinance/domains/prices/tests/__init__.py +0 -0
- kfinance/{tests/test_models → domains/prices/tests}/test_price_models.py +2 -2
- kfinance/domains/prices/tests/test_price_tools.py +141 -0
- kfinance/domains/segments/__init__.py +0 -0
- kfinance/domains/segments/segment_tools.py +91 -0
- kfinance/domains/segments/tests/__init__.py +0 -0
- kfinance/domains/segments/tests/test_segment_tools.py +80 -0
- kfinance/domains/statements/__init__.py +0 -0
- kfinance/domains/statements/statement_tools.py +113 -0
- kfinance/domains/statements/tests/__init__.py +0 -0
- kfinance/domains/statements/tests/test_statement_tools.py +73 -0
- kfinance/integrations/README.md +8 -0
- kfinance/integrations/__init__.py +0 -0
- kfinance/integrations/mcp/__init__.py +0 -0
- kfinance/{mcp.py → integrations/mcp/mcp.py} +2 -2
- kfinance/integrations/tests/__init__.py +0 -0
- kfinance/{tests → integrations/tests}/test_example_notebook.py +4 -4
- kfinance/{tool_calling → integrations/tool_calling}/README.md +2 -2
- kfinance/integrations/tool_calling/__init__.py +0 -0
- kfinance/integrations/tool_calling/all_tools.py +55 -0
- kfinance/{tool_calling → integrations/tool_calling}/prompts.py +3 -2
- kfinance/integrations/tool_calling/static_tools/README.md +4 -0
- kfinance/integrations/tool_calling/static_tools/__init__.py +0 -0
- kfinance/{tool_calling → integrations/tool_calling/static_tools}/get_latest.py +3 -3
- kfinance/{tool_calling → integrations/tool_calling/static_tools}/get_n_quarters_ago.py +3 -3
- kfinance/integrations/tool_calling/static_tools/tests/__init__.py +0 -0
- kfinance/integrations/tool_calling/static_tools/tests/test_get_lastest.py +30 -0
- kfinance/integrations/tool_calling/static_tools/tests/test_get_n_quarters_ago.py +24 -0
- kfinance/integrations/tool_calling/tests/__init__.py +0 -0
- kfinance/integrations/tool_calling/tests/test_tool_calling_models.py +69 -0
- kfinance/{tool_calling/shared_models.py → integrations/tool_calling/tool_calling_models.py} +37 -7
- kfinance/version.py +2 -2
- kensho_kfinance-2.8.0.dist-info/RECORD +0 -70
- kfinance/models/id_models.py +0 -7
- kfinance/prompt.py +0 -526
- kfinance/pydantic_models.py +0 -33
- kfinance/tests/test_tools.py +0 -804
- kfinance/tool_calling/__init__.py +0 -53
- kfinance/tool_calling/get_advisors_for_company_in_transaction_from_identifier.py +0 -39
- kfinance/tool_calling/get_business_relationship_from_identifier.py +0 -30
- kfinance/tool_calling/get_capitalization_from_identifier.py +0 -35
- kfinance/tool_calling/get_competitors_from_identifier.py +0 -25
- kfinance/tool_calling/get_cusip_from_ticker.py +0 -20
- kfinance/tool_calling/get_earnings.py +0 -33
- kfinance/tool_calling/get_financial_line_item_from_identifier.py +0 -48
- kfinance/tool_calling/get_financial_statement_from_identifier.py +0 -44
- kfinance/tool_calling/get_history_metadata_from_identifier.py +0 -17
- kfinance/tool_calling/get_info_from_identifier.py +0 -16
- kfinance/tool_calling/get_isin_from_ticker.py +0 -20
- kfinance/tool_calling/get_latest_earnings.py +0 -30
- kfinance/tool_calling/get_merger_info_from_transaction_id.py +0 -68
- kfinance/tool_calling/get_mergers_from_identifier.py +0 -41
- kfinance/tool_calling/get_next_earnings.py +0 -30
- kfinance/tool_calling/get_prices_from_identifier.py +0 -46
- kfinance/tool_calling/get_segments_from_identifier.py +0 -44
- kfinance/tool_calling/get_transcript.py +0 -23
- kfinance/tool_calling/resolve_identifier.py +0 -18
- {kensho_kfinance-2.8.0.dist-info → kensho_kfinance-3.0.0.dist-info}/WHEEL +0 -0
- {kensho_kfinance-2.8.0.dist-info → kensho_kfinance-3.0.0.dist-info}/licenses/AUTHORS.md +0 -0
- {kensho_kfinance-2.8.0.dist-info → kensho_kfinance-3.0.0.dist-info}/licenses/LICENSE +0 -0
- {kensho_kfinance-2.8.0.dist-info → kensho_kfinance-3.0.0.dist-info}/top_level.txt +0 -0
- /kfinance/{models → client}/__init__.py +0 -0
- /kfinance/{models → client}/industry_models.py +0 -0
- /kfinance/{tests → client/models}/__init__.py +0 -0
- /kfinance/{models → client/models}/currency_models.py +0 -0
- /kfinance/{models → client/models}/date_and_period_models.py +0 -0
- /kfinance/{tests/test_models → client/models/tests}/__init__.py +0 -0
- /kfinance/{models → client}/permission_models.py +0 -0
- /kfinance/{server_thread.py → client/server_thread.py} +0 -0
- /kfinance/{models → domains/line_items}/line_item_models.py +0 -0
- /kfinance/{models → domains/segments}/segment_models.py +0 -0
- /kfinance/{models → domains/statements}/statement_models.py +0 -0
|
@@ -2,7 +2,6 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from collections.abc import Sequence
|
|
4
4
|
from concurrent.futures import ThreadPoolExecutor
|
|
5
|
-
from copy import deepcopy
|
|
6
5
|
from datetime import date, datetime, timezone
|
|
7
6
|
from io import BytesIO
|
|
8
7
|
import logging
|
|
@@ -18,29 +17,32 @@ from langchain_google_genai._function_utils import convert_to_genai_function_dec
|
|
|
18
17
|
import pandas as pd
|
|
19
18
|
from PIL.Image import Image, open as image_open
|
|
20
19
|
|
|
21
|
-
from kfinance.batch_request_handling import add_methods_of_singular_class_to_iterable_class
|
|
22
|
-
from kfinance.fetch import (
|
|
20
|
+
from kfinance.client.batch_request_handling import add_methods_of_singular_class_to_iterable_class
|
|
21
|
+
from kfinance.client.fetch import (
|
|
23
22
|
DEFAULT_API_HOST,
|
|
24
23
|
DEFAULT_API_VERSION,
|
|
25
24
|
DEFAULT_OKTA_AUTH_SERVER,
|
|
26
25
|
DEFAULT_OKTA_HOST,
|
|
27
26
|
KFinanceApiClient,
|
|
28
27
|
)
|
|
29
|
-
from kfinance.
|
|
28
|
+
from kfinance.client.industry_models import IndustryClassification
|
|
29
|
+
from kfinance.client.meta_classes import (
|
|
30
30
|
CompanyFunctionsMetaClass,
|
|
31
31
|
DelegatedCompanyFunctionsMetaClass,
|
|
32
32
|
)
|
|
33
|
-
from kfinance.models.date_and_period_models import
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
from kfinance.
|
|
39
|
-
from kfinance.
|
|
33
|
+
from kfinance.client.models.date_and_period_models import (
|
|
34
|
+
LatestPeriods,
|
|
35
|
+
Periodicity,
|
|
36
|
+
YearAndQuarter,
|
|
37
|
+
)
|
|
38
|
+
from kfinance.client.server_thread import ServerThread
|
|
39
|
+
from kfinance.domains.companies.company_models import IdentificationTriple
|
|
40
|
+
from kfinance.domains.earnings.earning_models import EarningsCall, TranscriptComponent
|
|
41
|
+
from kfinance.domains.prices.price_models import HistoryMetadata, PriceHistory
|
|
40
42
|
|
|
41
43
|
|
|
42
44
|
if TYPE_CHECKING:
|
|
43
|
-
from kfinance.tool_calling.
|
|
45
|
+
from kfinance.integrations.tool_calling.tool_calling_models import KfinanceTool
|
|
44
46
|
|
|
45
47
|
logger = logging.getLogger(__name__)
|
|
46
48
|
|
|
@@ -266,6 +268,19 @@ class Earnings:
|
|
|
266
268
|
self.key_dev_id = key_dev_id
|
|
267
269
|
self._transcript: Transcript | None = None
|
|
268
270
|
|
|
271
|
+
@classmethod
|
|
272
|
+
def from_earnings_call(
|
|
273
|
+
cls, earnings_call: EarningsCall, kfinance_api_client: KFinanceApiClient
|
|
274
|
+
) -> "Earnings":
|
|
275
|
+
"""Generate an Earnings object from an EarningsCall pydantic model."""
|
|
276
|
+
|
|
277
|
+
return Earnings(
|
|
278
|
+
name=earnings_call.name,
|
|
279
|
+
datetime=earnings_call.datetime,
|
|
280
|
+
key_dev_id=earnings_call.key_dev_id,
|
|
281
|
+
kfinance_api_client=kfinance_api_client,
|
|
282
|
+
)
|
|
283
|
+
|
|
269
284
|
def __str__(self) -> str:
|
|
270
285
|
"""String representation for the earnings object"""
|
|
271
286
|
return f"{type(self).__module__}.{type(self).__qualname__} of {self.key_dev_id}"
|
|
@@ -513,24 +528,13 @@ class Company(CompanyFunctionsMetaClass):
|
|
|
513
528
|
return self._all_earnings
|
|
514
529
|
|
|
515
530
|
earnings_data = self.kfinance_api_client.fetch_earnings(self.company_id)
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
earnings["key_dev_id"] = deepcopy(earnings["keydevid"])
|
|
521
|
-
del earnings["keydevid"]
|
|
522
|
-
earnings_datetime = datetime.fromisoformat(
|
|
523
|
-
earnings["datetime"].replace("Z", "+00:00")
|
|
524
|
-
).replace(tzinfo=timezone.utc)
|
|
525
|
-
|
|
526
|
-
self._all_earnings.append(
|
|
527
|
-
Earnings(
|
|
528
|
-
kfinance_api_client=self.kfinance_api_client,
|
|
529
|
-
name=earnings["name"],
|
|
530
|
-
datetime=earnings_datetime,
|
|
531
|
-
key_dev_id=earnings["key_dev_id"],
|
|
532
|
-
)
|
|
531
|
+
|
|
532
|
+
self._all_earnings = [
|
|
533
|
+
Earnings.from_earnings_call(
|
|
534
|
+
earnings_call=earnings_call, kfinance_api_client=self.kfinance_api_client
|
|
533
535
|
)
|
|
536
|
+
for earnings_call in earnings_data.earnings_calls
|
|
537
|
+
]
|
|
534
538
|
|
|
535
539
|
return self._all_earnings
|
|
536
540
|
|
|
@@ -641,83 +645,77 @@ class Company(CompanyFunctionsMetaClass):
|
|
|
641
645
|
return self._mergers_for_company
|
|
642
646
|
|
|
643
647
|
|
|
644
|
-
class
|
|
648
|
+
class ParticipantInMerger:
|
|
645
649
|
"""A Company that has been involved in a transaction is a company that may have been advised."""
|
|
646
650
|
|
|
647
651
|
def __init__(
|
|
648
|
-
self,
|
|
649
|
-
kfinance_api_client: KFinanceApiClient,
|
|
650
|
-
company_id: int,
|
|
651
|
-
transaction_id: int,
|
|
652
|
-
company_name: str | None = None,
|
|
652
|
+
self, kfinance_api_client: KFinanceApiClient, transaction_id: int, company: Company
|
|
653
653
|
):
|
|
654
654
|
"""Initialize the AdvisedCompany object
|
|
655
655
|
|
|
656
656
|
:param kfinance_api_client: The KFinanceApiClient used to fetch data
|
|
657
657
|
:type kfinance_api_client: KFinanceApiClient
|
|
658
|
-
:param company_id: The S&P Global CIQ Company Id
|
|
659
|
-
:type company_id: int
|
|
660
658
|
:param transaction_id: The S&P Global CIP Transaction Id
|
|
661
659
|
:type transaction_id: int
|
|
660
|
+
:param company: The company object
|
|
661
|
+
:type company: Company
|
|
662
662
|
"""
|
|
663
|
-
|
|
664
|
-
super().__init__(
|
|
665
|
-
kfinance_api_client=kfinance_api_client,
|
|
666
|
-
company_id=company_id,
|
|
667
|
-
company_name=company_name,
|
|
668
|
-
)
|
|
663
|
+
self.kfinance_api_client = kfinance_api_client
|
|
669
664
|
self.transaction_id = transaction_id
|
|
665
|
+
self._company = company
|
|
670
666
|
|
|
671
667
|
@property
|
|
672
|
-
def
|
|
668
|
+
def company(self) -> Company:
|
|
669
|
+
"""Get the specific Company object."""
|
|
670
|
+
return self._company
|
|
671
|
+
|
|
672
|
+
@property
|
|
673
|
+
def advisors(self) -> list[Advisor] | None:
|
|
673
674
|
"""Get the companies that advised this company during the current transaction."""
|
|
674
675
|
advisors = self.kfinance_api_client.fetch_advisors_for_company_in_merger(
|
|
675
|
-
transaction_id=self.transaction_id, advised_company_id=self.company_id
|
|
676
|
+
transaction_id=self.transaction_id, advised_company_id=self._company.company_id
|
|
676
677
|
)["advisors"]
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
kfinance_api_client=self.kfinance_api_client,
|
|
680
|
-
company_id=int(advisor["advisor_company_id"]),
|
|
681
|
-
company_name=str(advisor["advisor_company_name"]),
|
|
678
|
+
return [
|
|
679
|
+
Advisor(
|
|
682
680
|
advisor_type_name=str(advisor["advisor_type_name"]),
|
|
681
|
+
company=Company(
|
|
682
|
+
kfinance_api_client=self.kfinance_api_client,
|
|
683
|
+
company_id=int(advisor["advisor_company_id"]),
|
|
684
|
+
company_name=str(advisor["advisor_company_name"]),
|
|
685
|
+
),
|
|
683
686
|
)
|
|
684
687
|
for advisor in advisors
|
|
685
688
|
]
|
|
686
|
-
return Companies(kfinance_api_client=self.kfinance_api_client, companies=companies)
|
|
687
689
|
|
|
688
690
|
|
|
689
|
-
class
|
|
691
|
+
class Advisor:
|
|
690
692
|
"""A company that advised another company during a transaction."""
|
|
691
693
|
|
|
692
694
|
def __init__(
|
|
693
695
|
self,
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
advisor_type_name: str,
|
|
697
|
-
company_name: str | None = None,
|
|
696
|
+
advisor_type_name: str | None,
|
|
697
|
+
company: Company,
|
|
698
698
|
):
|
|
699
699
|
"""Initialize the AdvisorCompany object
|
|
700
700
|
|
|
701
|
-
:param
|
|
702
|
-
:type
|
|
703
|
-
:param company_id: The S&P Global CIQ Company Id
|
|
704
|
-
:type company_id: int
|
|
701
|
+
:param company: The company that advised
|
|
702
|
+
:type company: Company
|
|
705
703
|
:param advisor_type_name: The type of the advisor company
|
|
706
704
|
:type advisor_type_name: str
|
|
707
705
|
"""
|
|
708
|
-
|
|
709
|
-
super().__init__(
|
|
710
|
-
kfinance_api_client=kfinance_api_client,
|
|
711
|
-
company_id=company_id,
|
|
712
|
-
company_name=company_name,
|
|
713
|
-
)
|
|
714
706
|
self._advisor_type_name = advisor_type_name
|
|
707
|
+
self._company = company
|
|
715
708
|
|
|
716
709
|
@property
|
|
717
710
|
def advisor_type_name(self) -> str | None:
|
|
718
711
|
"""When this company advised another during a transaction, get the advisor type name."""
|
|
719
712
|
return self._advisor_type_name
|
|
720
713
|
|
|
714
|
+
@property
|
|
715
|
+
def company(self) -> Company:
|
|
716
|
+
"""Get the Company object."""
|
|
717
|
+
return self._company
|
|
718
|
+
|
|
721
719
|
|
|
722
720
|
class Security:
|
|
723
721
|
"""Security class
|
|
@@ -1253,7 +1251,11 @@ class MergerOrAcquisition:
|
|
|
1253
1251
|
"""An object that represents a merger or an acquisition of a company."""
|
|
1254
1252
|
|
|
1255
1253
|
def __init__(
|
|
1256
|
-
self,
|
|
1254
|
+
self,
|
|
1255
|
+
kfinance_api_client: KFinanceApiClient,
|
|
1256
|
+
transaction_id: int,
|
|
1257
|
+
merger_title: str | None,
|
|
1258
|
+
closed_date: date | None,
|
|
1257
1259
|
) -> None:
|
|
1258
1260
|
"""MergerOrAcqusition initializer.
|
|
1259
1261
|
|
|
@@ -1264,6 +1266,7 @@ class MergerOrAcquisition:
|
|
|
1264
1266
|
self.kfinance_api_client = kfinance_api_client
|
|
1265
1267
|
self.transaction_id = transaction_id
|
|
1266
1268
|
self.merger_title = merger_title
|
|
1269
|
+
self.closed_date = closed_date
|
|
1267
1270
|
self._merger_info: dict | None = None
|
|
1268
1271
|
|
|
1269
1272
|
@property
|
|
@@ -1301,36 +1304,39 @@ class MergerOrAcquisition:
|
|
|
1301
1304
|
Each category is a single Company or a list of Companies.
|
|
1302
1305
|
"""
|
|
1303
1306
|
return {
|
|
1304
|
-
"target":
|
|
1307
|
+
"target": ParticipantInMerger(
|
|
1305
1308
|
kfinance_api_client=self.kfinance_api_client,
|
|
1306
|
-
company_id=self.merger_info["participants"]["target"]["company_id"],
|
|
1307
|
-
company_name=self.merger_info["participants"]["target"]["company_name"],
|
|
1308
1309
|
transaction_id=self.transaction_id,
|
|
1310
|
+
company=Company(
|
|
1311
|
+
kfinance_api_client=self.kfinance_api_client,
|
|
1312
|
+
company_id=self.merger_info["participants"]["target"]["company_id"],
|
|
1313
|
+
company_name=self.merger_info["participants"]["target"]["company_name"],
|
|
1314
|
+
),
|
|
1309
1315
|
),
|
|
1310
|
-
"buyers":
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1316
|
+
"buyers": [
|
|
1317
|
+
ParticipantInMerger(
|
|
1318
|
+
kfinance_api_client=self.kfinance_api_client,
|
|
1319
|
+
transaction_id=self.transaction_id,
|
|
1320
|
+
company=Company(
|
|
1314
1321
|
kfinance_api_client=self.kfinance_api_client,
|
|
1315
1322
|
company_id=company["company_id"],
|
|
1316
1323
|
company_name=company["company_name"],
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1324
|
+
),
|
|
1325
|
+
)
|
|
1326
|
+
for company in self.merger_info["participants"]["buyers"]
|
|
1327
|
+
],
|
|
1328
|
+
"sellers": [
|
|
1329
|
+
ParticipantInMerger(
|
|
1330
|
+
kfinance_api_client=self.kfinance_api_client,
|
|
1331
|
+
transaction_id=self.transaction_id,
|
|
1332
|
+
company=Company(
|
|
1326
1333
|
kfinance_api_client=self.kfinance_api_client,
|
|
1327
1334
|
company_id=company["company_id"],
|
|
1328
1335
|
company_name=company["company_name"],
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
),
|
|
1336
|
+
),
|
|
1337
|
+
)
|
|
1338
|
+
for company in self.merger_info["participants"]["sellers"]
|
|
1339
|
+
],
|
|
1334
1340
|
}
|
|
1335
1341
|
|
|
1336
1342
|
@property
|
|
@@ -1360,7 +1366,6 @@ class Companies(set):
|
|
|
1360
1366
|
self,
|
|
1361
1367
|
kfinance_api_client: KFinanceApiClient,
|
|
1362
1368
|
company_ids: Optional[Iterable[int]] = None,
|
|
1363
|
-
transaction_id: Optional[int] = None,
|
|
1364
1369
|
companies: Optional[Iterable[Company]] = None,
|
|
1365
1370
|
) -> None:
|
|
1366
1371
|
"""Initialize the Companies object
|
|
@@ -1369,8 +1374,6 @@ class Companies(set):
|
|
|
1369
1374
|
:type kfinance_api_client: KFinanceApiClient
|
|
1370
1375
|
:param company_ids: An iterable of S&P CIQ Company ids
|
|
1371
1376
|
:type company_ids: Iterable[int]
|
|
1372
|
-
:param transaction_id: If the companies were party to a transaction, the S&P CIQ Transaction Id
|
|
1373
|
-
:type transaction_id: Optional[int]
|
|
1374
1377
|
:param companies: If there's already an iterable of Company objects
|
|
1375
1378
|
:type companies: Iterable[Company]
|
|
1376
1379
|
"""
|
|
@@ -1378,23 +1381,13 @@ class Companies(set):
|
|
|
1378
1381
|
if companies is not None:
|
|
1379
1382
|
super().__init__(company for company in companies)
|
|
1380
1383
|
elif company_ids is not None:
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
company_id=company_id,
|
|
1386
|
-
transaction_id=transaction_id,
|
|
1387
|
-
)
|
|
1388
|
-
for company_id in company_ids
|
|
1389
|
-
)
|
|
1390
|
-
else:
|
|
1391
|
-
super().__init__(
|
|
1392
|
-
Company(
|
|
1393
|
-
kfinance_api_client=kfinance_api_client,
|
|
1394
|
-
company_id=company_id,
|
|
1395
|
-
)
|
|
1396
|
-
for company_id in company_ids
|
|
1384
|
+
super().__init__(
|
|
1385
|
+
Company(
|
|
1386
|
+
kfinance_api_client=kfinance_api_client,
|
|
1387
|
+
company_id=company_id,
|
|
1397
1388
|
)
|
|
1389
|
+
for company_id in company_ids
|
|
1390
|
+
)
|
|
1398
1391
|
|
|
1399
1392
|
|
|
1400
1393
|
@add_methods_of_singular_class_to_iterable_class(Security)
|
|
@@ -1409,6 +1402,7 @@ class Securities(set):
|
|
|
1409
1402
|
:param security_ids: An iterable of S&P CIQ Security ids
|
|
1410
1403
|
:type security_ids: Iterable[int]
|
|
1411
1404
|
"""
|
|
1405
|
+
self.kfinance_api_client = kfinance_api_client
|
|
1412
1406
|
super().__init__(Security(kfinance_api_client, security_id) for security_id in security_ids)
|
|
1413
1407
|
|
|
1414
1408
|
|
|
@@ -1533,6 +1527,7 @@ class MergersAndAcquisitions(set):
|
|
|
1533
1527
|
kfinance_api_client=kfinance_api_client,
|
|
1534
1528
|
transaction_id=id_and_title["transaction_id"],
|
|
1535
1529
|
merger_title=id_and_title["merger_title"],
|
|
1530
|
+
closed_date=id_and_title["closed_date"],
|
|
1536
1531
|
)
|
|
1537
1532
|
for id_and_title in ids_and_titles
|
|
1538
1533
|
)
|
|
@@ -1551,8 +1546,6 @@ class Client:
|
|
|
1551
1546
|
:type openai_tool_descriptions: list[dict]
|
|
1552
1547
|
"""
|
|
1553
1548
|
|
|
1554
|
-
prompt = PROMPT
|
|
1555
|
-
|
|
1556
1549
|
def __init__(
|
|
1557
1550
|
self,
|
|
1558
1551
|
refresh_token: Optional[str] = None,
|
|
@@ -1632,9 +1625,10 @@ class Client:
|
|
|
1632
1625
|
@property
|
|
1633
1626
|
def langchain_tools(self) -> list["KfinanceTool"]:
|
|
1634
1627
|
"""Return a list of all Kfinance tools for tool calling."""
|
|
1635
|
-
if self._tools is None:
|
|
1636
|
-
from kfinance.tool_calling import ALL_TOOLS
|
|
1637
1628
|
|
|
1629
|
+
from kfinance.integrations.tool_calling.all_tools import ALL_TOOLS
|
|
1630
|
+
|
|
1631
|
+
if self._tools is None:
|
|
1638
1632
|
self._tools = []
|
|
1639
1633
|
# Add tool to _tools if the user has permissions to use it.
|
|
1640
1634
|
for tool_cls in ALL_TOOLS:
|
|
@@ -7,14 +7,15 @@ from cachetools import LRUCache, cached
|
|
|
7
7
|
import numpy as np
|
|
8
8
|
import pandas as pd
|
|
9
9
|
|
|
10
|
-
from .fetch import KFinanceApiClient
|
|
11
|
-
from .models.
|
|
12
|
-
from .
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
from .
|
|
16
|
-
from .
|
|
17
|
-
from .
|
|
10
|
+
from kfinance.client.fetch import KFinanceApiClient
|
|
11
|
+
from kfinance.client.models.date_and_period_models import PeriodType
|
|
12
|
+
from kfinance.domains.business_relationships.business_relationship_models import (
|
|
13
|
+
BusinessRelationshipType,
|
|
14
|
+
)
|
|
15
|
+
from kfinance.domains.capitalizations.capitalization_models import Capitalization
|
|
16
|
+
from kfinance.domains.competitors.competitor_models import CompetitorSource
|
|
17
|
+
from kfinance.domains.line_items.line_item_models import LINE_ITEMS
|
|
18
|
+
from kfinance.domains.segments.segment_models import SegmentType
|
|
18
19
|
|
|
19
20
|
|
|
20
21
|
if TYPE_CHECKING:
|
|
@@ -234,28 +235,16 @@ class CompanyFunctionsMetaClass:
|
|
|
234
235
|
company_id=self.company_id,
|
|
235
236
|
relationship_type=relationship_type,
|
|
236
237
|
)
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
)
|
|
248
|
-
else:
|
|
249
|
-
return BusinessRelationships(
|
|
250
|
-
current=Companies(
|
|
251
|
-
kfinance_api_client=self.kfinance_api_client,
|
|
252
|
-
company_ids=relationship_resp.current,
|
|
253
|
-
),
|
|
254
|
-
previous=Companies(
|
|
255
|
-
kfinance_api_client=self.kfinance_api_client,
|
|
256
|
-
company_ids=relationship_resp.previous,
|
|
257
|
-
),
|
|
258
|
-
)
|
|
238
|
+
return BusinessRelationships(
|
|
239
|
+
current=Companies(
|
|
240
|
+
kfinance_api_client=self.kfinance_api_client,
|
|
241
|
+
company_ids=[c.company_id for c in relationship_resp.current],
|
|
242
|
+
),
|
|
243
|
+
previous=Companies(
|
|
244
|
+
kfinance_api_client=self.kfinance_api_client,
|
|
245
|
+
company_ids=[c.company_id for c in relationship_resp.previous],
|
|
246
|
+
),
|
|
247
|
+
)
|
|
259
248
|
|
|
260
249
|
def market_cap(
|
|
261
250
|
self,
|
|
@@ -329,7 +318,9 @@ class CompanyFunctionsMetaClass:
|
|
|
329
318
|
capitalizations = self.kfinance_api_client.fetch_market_caps_tevs_and_shares_outstanding(
|
|
330
319
|
company_id=self.company_id, start_date=start_date, end_date=end_date
|
|
331
320
|
)
|
|
332
|
-
return capitalizations.
|
|
321
|
+
return capitalizations.model_dump_json_single_metric(
|
|
322
|
+
capitalization_metric=capitalization_to_extract
|
|
323
|
+
)
|
|
333
324
|
|
|
334
325
|
def _segments(
|
|
335
326
|
self,
|
|
@@ -437,16 +428,16 @@ class CompanyFunctionsMetaClass:
|
|
|
437
428
|
|
|
438
429
|
competitors_data = self.kfinance_api_client.fetch_competitors(
|
|
439
430
|
company_id=self.company_id, competitor_source=competitor_source
|
|
440
|
-
)
|
|
431
|
+
)
|
|
441
432
|
return Companies(
|
|
442
433
|
kfinance_api_client=self.kfinance_api_client,
|
|
443
434
|
companies=[
|
|
444
435
|
Company(
|
|
445
436
|
kfinance_api_client=self.kfinance_api_client,
|
|
446
|
-
company_id=company
|
|
447
|
-
company_name=company
|
|
437
|
+
company_id=company.company_id,
|
|
438
|
+
company_name=company.company_name,
|
|
448
439
|
)
|
|
449
|
-
for company in competitors_data
|
|
440
|
+
for company in competitors_data.competitors
|
|
450
441
|
],
|
|
451
442
|
)
|
|
452
443
|
|
|
@@ -5,7 +5,7 @@ from typing import Any
|
|
|
5
5
|
from pydantic import BaseModel, Field, model_validator
|
|
6
6
|
from typing_extensions import Self
|
|
7
7
|
|
|
8
|
-
from kfinance.models.currency_models import ISO_CODE_TO_CURRENCY
|
|
8
|
+
from kfinance.client.models.currency_models import ISO_CODE_TO_CURRENCY
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
class DecimalWithUnit(BaseModel):
|
|
File without changes
|
|
@@ -9,16 +9,18 @@ import pytest
|
|
|
9
9
|
import requests
|
|
10
10
|
import requests_mock
|
|
11
11
|
|
|
12
|
-
from kfinance.batch_request_handling import MAX_WORKERS_CAP
|
|
13
|
-
from kfinance.
|
|
14
|
-
from kfinance.
|
|
15
|
-
from kfinance.
|
|
16
|
-
from kfinance.
|
|
12
|
+
from kfinance.client.batch_request_handling import MAX_WORKERS_CAP
|
|
13
|
+
from kfinance.client.fetch import KFinanceApiClient
|
|
14
|
+
from kfinance.client.kfinance import Companies, Company, Ticker, TradingItem, TradingItems
|
|
15
|
+
from kfinance.client.models.decimal_with_unit import Money, Shares
|
|
16
|
+
from kfinance.domains.prices.price_models import PriceHistory, Prices
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
@pytest.fixture(autouse=True)
|
|
20
20
|
def mock_method():
|
|
21
|
-
with patch(
|
|
21
|
+
with patch(
|
|
22
|
+
"kfinance.client.fetch.KFinanceApiClient.access_token", return_value="fake_access_token"
|
|
23
|
+
):
|
|
22
24
|
yield
|
|
23
25
|
|
|
24
26
|
|
|
@@ -2,18 +2,20 @@ from unittest.mock import Mock
|
|
|
2
2
|
|
|
3
3
|
import pytest
|
|
4
4
|
|
|
5
|
-
from kfinance.kfinance import Client
|
|
6
|
-
from kfinance.
|
|
7
|
-
from kfinance.
|
|
8
|
-
|
|
9
|
-
GetEarnings,
|
|
10
|
-
GetFinancialStatementFromIdentifier,
|
|
11
|
-
GetLatest,
|
|
12
|
-
GetLatestEarnings,
|
|
13
|
-
GetNextEarnings,
|
|
14
|
-
GetTranscript,
|
|
5
|
+
from kfinance.client.kfinance import Client
|
|
6
|
+
from kfinance.client.permission_models import Permission
|
|
7
|
+
from kfinance.domains.business_relationships.business_relationship_tools import (
|
|
8
|
+
GetBusinessRelationshipFromIdentifiers,
|
|
15
9
|
)
|
|
16
|
-
from kfinance.
|
|
10
|
+
from kfinance.domains.earnings.earning_tools import (
|
|
11
|
+
GetEarningsFromIdentifiers,
|
|
12
|
+
GetLatestEarningsFromIdentifiers,
|
|
13
|
+
GetNextEarningsFromIdentifiers,
|
|
14
|
+
GetTranscriptFromKeyDevId,
|
|
15
|
+
)
|
|
16
|
+
from kfinance.domains.statements.statement_tools import GetFinancialStatementFromIdentifiers
|
|
17
|
+
from kfinance.integrations.tool_calling.static_tools.get_latest import GetLatest
|
|
18
|
+
from kfinance.integrations.tool_calling.tool_calling_models import KfinanceTool
|
|
17
19
|
|
|
18
20
|
|
|
19
21
|
class TestLangchainTools:
|
|
@@ -52,19 +54,23 @@ class TestLangchainTools:
|
|
|
52
54
|
mock_client.kfinance_api_client._user_permissions = {Permission.RelationshipPermission} # noqa: SLF001
|
|
53
55
|
tool_classes = [type(t) for t in mock_client.langchain_tools]
|
|
54
56
|
# User should have access to GetBusinessRelationshipFromIdentifier
|
|
55
|
-
assert
|
|
57
|
+
assert GetBusinessRelationshipFromIdentifiers in tool_classes
|
|
56
58
|
# User should have access to functions that don't require permissions
|
|
57
59
|
assert GetLatest in tool_classes
|
|
58
60
|
# User should not have access to functions that require statement permissions
|
|
59
|
-
assert
|
|
61
|
+
assert GetFinancialStatementFromIdentifiers not in tool_classes
|
|
60
62
|
|
|
61
63
|
@pytest.mark.parametrize(
|
|
62
64
|
"user_permission, expected_tool",
|
|
63
65
|
[
|
|
64
66
|
pytest.param(
|
|
65
|
-
Permission.TranscriptsPermission,
|
|
67
|
+
Permission.TranscriptsPermission,
|
|
68
|
+
GetTranscriptFromKeyDevId,
|
|
69
|
+
id="Transcript Permissions",
|
|
70
|
+
),
|
|
71
|
+
pytest.param(
|
|
72
|
+
Permission.EarningsPermission, GetEarningsFromIdentifiers, id="Earnings Permissions"
|
|
66
73
|
),
|
|
67
|
-
pytest.param(Permission.EarningsPermission, GetEarnings, id="Earnings Permissions"),
|
|
68
74
|
],
|
|
69
75
|
)
|
|
70
76
|
def test_permission_set_handling(
|
|
@@ -79,11 +85,11 @@ class TestLangchainTools:
|
|
|
79
85
|
mock_client.kfinance_api_client._user_permissions = {user_permission} # noqa: SLF001
|
|
80
86
|
tool_classes = [type(t) for t in mock_client.langchain_tools]
|
|
81
87
|
# User should have access to GetEarnings, GetNextEarnings, GetLatestEarnings, GetTranscript
|
|
82
|
-
assert
|
|
83
|
-
assert
|
|
84
|
-
assert
|
|
88
|
+
assert GetEarningsFromIdentifiers in tool_classes
|
|
89
|
+
assert GetNextEarningsFromIdentifiers in tool_classes
|
|
90
|
+
assert GetLatestEarningsFromIdentifiers in tool_classes
|
|
85
91
|
assert expected_tool in tool_classes
|
|
86
92
|
# User should have access to functions that don't require permissions
|
|
87
93
|
assert GetLatest in tool_classes
|
|
88
94
|
# User should not have access to functions that require statement permissions
|
|
89
|
-
assert
|
|
95
|
+
assert GetFinancialStatementFromIdentifiers not in tool_classes
|
|
@@ -5,16 +5,15 @@ from pydantic import ValidationError
|
|
|
5
5
|
import pytest
|
|
6
6
|
from requests_mock import Mocker
|
|
7
7
|
|
|
8
|
-
from kfinance.fetch import KFinanceApiClient
|
|
9
|
-
from kfinance.kfinance import Client
|
|
10
|
-
from kfinance.models.
|
|
11
|
-
from kfinance.
|
|
12
|
-
from kfinance.
|
|
13
|
-
|
|
8
|
+
from kfinance.client.fetch import KFinanceApiClient
|
|
9
|
+
from kfinance.client.kfinance import Client
|
|
10
|
+
from kfinance.client.models.date_and_period_models import Periodicity, PeriodType
|
|
11
|
+
from kfinance.conftest import SPGI_COMPANY_ID
|
|
12
|
+
from kfinance.domains.business_relationships.business_relationship_models import (
|
|
13
|
+
BusinessRelationshipType,
|
|
14
14
|
RelationshipResponse,
|
|
15
|
-
RelationshipResponseNoName,
|
|
16
15
|
)
|
|
17
|
-
from kfinance.
|
|
16
|
+
from kfinance.domains.companies.company_models import CompanyIdAndName
|
|
18
17
|
|
|
19
18
|
|
|
20
19
|
def build_mock_api_client() -> KFinanceApiClient:
|
|
@@ -150,7 +149,8 @@ class TestFetchItem(TestCase):
|
|
|
150
149
|
def test_fetch_earnings(self) -> None:
|
|
151
150
|
company_id = 21719
|
|
152
151
|
expected_fetch_url = f"{self.kfinance_api_client.url_base}earnings/{company_id}"
|
|
153
|
-
|
|
152
|
+
with pytest.raises(ValidationError):
|
|
153
|
+
self.kfinance_api_client.fetch_earnings(company_id=company_id)
|
|
154
154
|
self.kfinance_api_client.fetch.assert_called_once_with(expected_fetch_url)
|
|
155
155
|
|
|
156
156
|
def test_fetch_transcript(self) -> None:
|
|
@@ -334,28 +334,10 @@ class TestMarketCap:
|
|
|
334
334
|
|
|
335
335
|
|
|
336
336
|
class TestFetchCompaniesFromBusinessRelationship:
|
|
337
|
-
def
|
|
338
|
-
"""
|
|
339
|
-
GIVEN a business relationship request
|
|
340
|
-
WHEN the api returns a response in the old (no name) format
|
|
341
|
-
THEN the response can successfully be parsed.
|
|
342
|
-
"""
|
|
343
|
-
http_resp = {"current": [883103], "previous": [472898, 8182358]}
|
|
344
|
-
expected_result = RelationshipResponseNoName(current=[883103], previous=[472898, 8182358])
|
|
345
|
-
requests_mock.get(
|
|
346
|
-
url=f"{mock_client.kfinance_api_client.url_base}relationship/{SPGI_COMPANY_ID}/{BusinessRelationshipType.supplier}",
|
|
347
|
-
json=http_resp,
|
|
348
|
-
)
|
|
349
|
-
|
|
350
|
-
resp = mock_client.kfinance_api_client.fetch_companies_from_business_relationship(
|
|
351
|
-
company_id=SPGI_COMPANY_ID, relationship_type=BusinessRelationshipType.supplier
|
|
352
|
-
)
|
|
353
|
-
assert resp == expected_result
|
|
354
|
-
|
|
355
|
-
def test_new_response_format(self, requests_mock: Mocker, mock_client: Client) -> None:
|
|
337
|
+
def test_fetch_business_relationships(self, requests_mock: Mocker, mock_client: Client) -> None:
|
|
356
338
|
"""
|
|
357
339
|
GIVEN a business relationship request
|
|
358
|
-
WHEN the api returns a response
|
|
340
|
+
WHEN the api returns a response
|
|
359
341
|
THEN the response can successfully be parsed.
|
|
360
342
|
"""
|
|
361
343
|
|