kensho-kfinance 3.2.10__py3-none-any.whl → 3.2.11__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.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kensho-kfinance
3
- Version: 3.2.10
3
+ Version: 3.2.11
4
4
  Summary: Python CLI for kFinance
5
5
  Author-email: Luke Brown <luke.brown@kensho.com>, Michelle Keoy <michelle.keoy@kensho.com>, Keith Page <keith.page@kensho.com>, Matthew Rosen <matthew.rosen@kensho.com>, Nick Roshdieh <nick.roshdieh@kensho.com>
6
6
  Project-URL: source, https://github.com/kensho-technologies/kfinance
@@ -1,14 +1,14 @@
1
- kensho_kfinance-3.2.10.dist-info/licenses/AUTHORS.md,sha256=0h9ClbI0pu1oKj1M28ROUsaxrbZg-6ukQGl6X4y9noI,68
2
- kensho_kfinance-3.2.10.dist-info/licenses/LICENSE,sha256=bsY4blvSgq6o0FMQ3RXa2NCgco--nHCCchLXzxr6kms,83
3
- kfinance/CHANGELOG.md,sha256=3mgDixfg0ojmEr3D36QnfaFd8YZD5zeHkjA3NHBRm08,3388
1
+ kensho_kfinance-3.2.11.dist-info/licenses/AUTHORS.md,sha256=0h9ClbI0pu1oKj1M28ROUsaxrbZg-6ukQGl6X4y9noI,68
2
+ kensho_kfinance-3.2.11.dist-info/licenses/LICENSE,sha256=bsY4blvSgq6o0FMQ3RXa2NCgco--nHCCchLXzxr6kms,83
3
+ kfinance/CHANGELOG.md,sha256=XjHlM5qhd9E4fuTYuhy6Ef2Ol44NM8v7zqtFz1Vujf0,3500
4
4
  kfinance/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
5
- kfinance/conftest.py,sha256=FIZNQyfFbldyVmzaLfWbnMGh6RiC4MZwOVax6815_Ms,3754
5
+ kfinance/conftest.py,sha256=PFflyOx08XgmEA0rdugud7QEA7KqARmd22SH2dLTqrE,4091
6
6
  kfinance/mcp.py,sha256=LTzCIlqsDKRD-0Xcpa_P99-JmJ8duAneO_-GzM43kjw,424
7
7
  kfinance/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
- kfinance/version.py,sha256=0Do_CqGpGkuLSWuqbzGC46drHfwvUEjSDoKQNrc0rss,706
8
+ kfinance/version.py,sha256=MJhMUFQz6_dDcgDJMKAskHXLUlIHM1XXIUEwKPqT7dA,706
9
9
  kfinance/client/README.md,sha256=DA5vg4uz1JmJNiqvYywrj46YNhOr584WO8L83Ysx_Mk,372
10
10
  kfinance/client/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
- kfinance/client/batch_request_handling.py,sha256=opwJJAU2JtqH-s4vt8wRqhH34MiU4tQP6Ng7K6b3upA,6561
11
+ kfinance/client/batch_request_handling.py,sha256=0r9x3-vXdpyKhfsIa6VZ9hovN60t3HB7nE3v5hnrSyI,6617
12
12
  kfinance/client/fetch.py,sha256=CDZA8VMsu-olwmribThQ7MMOy2cgwWqQOYZ7xH3G9jI,29362
13
13
  kfinance/client/industry_models.py,sha256=ydB_cTIsNsfCUeaO7K2qqLUuHdG6WfUCoAzBigKVV8M,243
14
14
  kfinance/client/kfinance.py,sha256=-tyw9-pcP9gag20OTaOO8HpwQRae3iOuFqQ3PqzWagQ,72290
@@ -22,7 +22,7 @@ kfinance/client/models/decimal_with_unit.py,sha256=lfBvOQDk1cdWnqRh7oZoXe3_TbjNs
22
22
  kfinance/client/models/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
23
23
  kfinance/client/models/tests/test_decimal_with_unit.py,sha256=7WlmVXFOFNHFqwsvXQvcgyPfa6noRm3-mLTcXz4GvRs,2202
24
24
  kfinance/client/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
25
- kfinance/client/tests/test_batch_requests.py,sha256=KcE5rNJHBP27xaZOmwg8cVyUMZAAPt6jDiCeq94wUUk,11661
25
+ kfinance/client/tests/test_batch_requests.py,sha256=_V7GS7qbj_sRW49USgfp68TlYToUweruQWtQ8QwaEcg,11740
26
26
  kfinance/client/tests/test_client.py,sha256=GlK89ZOGL9bwrAUFUk8nua2ooKt0JYm7o_rpAfajFXA,4312
27
27
  kfinance/client/tests/test_fetch.py,sha256=QbrvHSpB4DVpx5qAo175Mhr31U0I8riAqT8fS3GGyTA,21715
28
28
  kfinance/client/tests/test_group_objects.py,sha256=wb7MEyGm-Qya3CXWM5Xz3kUhKFWdHT8FF3cQcjt1WxQ,1696
@@ -35,11 +35,11 @@ kfinance/domains/business_relationships/business_relationship_tools.py,sha256=xK
35
35
  kfinance/domains/business_relationships/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
36
36
  kfinance/domains/business_relationships/tests/test_business_relationship_tools.py,sha256=e_EGtM4i5Qw5J1Wi2kXahkyjDA4mhHcT0DFAKA5JQdI,2459
37
37
  kfinance/domains/capitalizations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
38
- kfinance/domains/capitalizations/capitalization_models.py,sha256=SsNsL4NoK4csyOja0Bw1Nw-JcpqaMw1UDeM4sKxVQ7Y,3382
39
- kfinance/domains/capitalizations/capitalization_tools.py,sha256=FJBxotSX-1a7GEKSEkSIuXXIgNyjSnac336rQBePU80,4753
38
+ kfinance/domains/capitalizations/capitalization_models.py,sha256=vTmISvJuagwr8n4yF66M9pty_iIdYKb6okoc2vAyac4,3788
39
+ kfinance/domains/capitalizations/capitalization_tools.py,sha256=3pG174VA-uLrbtk6xlER-xXZfz5PCePT_dE7dTCeNu0,5146
40
40
  kfinance/domains/capitalizations/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
41
41
  kfinance/domains/capitalizations/tests/test_capitalization_models.py,sha256=SSFxEVnSLvuNjOK-gx4I3OCHso80OA37zOLmiHJhsro,3143
42
- kfinance/domains/capitalizations/tests/test_capitalization_tools.py,sha256=H43mlYDq6GCQOw3tm6pFmvZKuJ-WctaqVTRJyYizvY8,4588
42
+ kfinance/domains/capitalizations/tests/test_capitalization_tools.py,sha256=tetZXL6YqC9g5KKcEf0O88FiBei4Bz3UFflleWsMZnk,5384
43
43
  kfinance/domains/companies/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
44
44
  kfinance/domains/companies/company_identifiers.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
45
45
  kfinance/domains/companies/company_models.py,sha256=Ny0o5lB5e1gN3bSj8bVbfqg6ktgJrwn9-58sKO1bmXs,5060
@@ -62,7 +62,7 @@ kfinance/domains/earnings/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm
62
62
  kfinance/domains/earnings/tests/test_earnings_tools.py,sha256=qGhdWI1s4uEjF6XtFC0f1nlAths1H6xfym-iJyBpwBo,6998
63
63
  kfinance/domains/line_items/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
64
64
  kfinance/domains/line_items/line_item_models.py,sha256=6J_9cko9nZ3OAGSC7OMGEMQW8dkXjRLWn4_2BjtHemU,50969
65
- kfinance/domains/line_items/line_item_tools.py,sha256=lxvhYbnZKapIf2nIfdtVqXiDswJoeU5XxMOAGUeb8cI,5192
65
+ kfinance/domains/line_items/line_item_tools.py,sha256=UTLY-_QD6LbHGXHwx1azoqzqbJGdct3R0iwNmvxhIS0,6144
66
66
  kfinance/domains/line_items/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
67
67
  kfinance/domains/line_items/tests/test_line_item_tools.py,sha256=vgxJsPbQG1msXZKTfpyHSzUfhw0GvfxZ041T7J-56hU,5499
68
68
  kfinance/domains/mergers_and_acquisitions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -108,7 +108,7 @@ kfinance/integrations/tool_calling/static_tools/tests/test_get_n_quarters_ago.py
108
108
  kfinance/integrations/tool_calling/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
109
109
  kfinance/integrations/tool_calling/tests/test_tool_calling_models.py,sha256=5L8TpSVJmrjNzGcnERorpfeyrgLND_DL46ld5hVlcNw,2933
110
110
  kfinance/models/permission_models.py,sha256=G0so8ZOsD1YDsCM4he0z5R9M_shUbSRwD3hUDJdqZl0,635
111
- kensho_kfinance-3.2.10.dist-info/METADATA,sha256=u2l7KD1wRwk071OyjYEXqr3N6ZgcvZNRPZQG0OjAqkg,6198
112
- kensho_kfinance-3.2.10.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
113
- kensho_kfinance-3.2.10.dist-info/top_level.txt,sha256=kT_kNwVhfQoOAecY8W7uYah5xaHMoHoAdBIvXh6DaKM,9
114
- kensho_kfinance-3.2.10.dist-info/RECORD,,
111
+ kensho_kfinance-3.2.11.dist-info/METADATA,sha256=qj83T76FViI-obgUPGcYwDmLy6mrpB4ZbWpmPcz1Z3M,6198
112
+ kensho_kfinance-3.2.11.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
113
+ kensho_kfinance-3.2.11.dist-info/top_level.txt,sha256=kT_kNwVhfQoOAecY8W7uYah5xaHMoHoAdBIvXh6DaKM,9
114
+ kensho_kfinance-3.2.11.dist-info/RECORD,,
kfinance/CHANGELOG.md CHANGED
@@ -1,4 +1,7 @@
1
1
  # Changelog
2
+ # 3.2.11
3
+ - Add Handling of status code 400 for Capitalizations, Modify EV/TEV ratio to target quarterly or LTM
4
+
2
5
  # 3.2.10
3
6
  - Add CIQ company_id to GetInfoFromIdentifiersResp
4
7
 
@@ -158,7 +158,9 @@ def resolve_future_with_error_handling(future: Future) -> Any:
158
158
  return future.result()
159
159
  except HTTPError as http_err:
160
160
  error_code = http_err.response.status_code
161
- if error_code == 404:
161
+ if error_code == 400:
162
+ return None
163
+ elif error_code == 404:
162
164
  return None
163
165
  else:
164
166
  raise http_err
@@ -212,11 +212,12 @@ class TestTradingItem(TestCase):
212
212
  )
213
213
  m.get("https://kfinance.kensho.com/api/v1/info/1002", status_code=400)
214
214
 
215
- with self.assertRaises(requests.exceptions.HTTPError) as e:
216
- companies = Companies(self.kfinance_api_client, [1001, 1002])
217
- _ = companies.city
215
+ companies = Companies(self.kfinance_api_client, [1001, 1002])
216
+ result = companies.city
217
+ id_based_result = self.company_object_keys_as_company_id(result)
218
218
 
219
- self.assertEqual(e.exception.response.status_code, 400)
219
+ expected_id_based_result = {1001: "Mock City A", 1002: None}
220
+ self.assertDictEqual(id_based_result, expected_id_based_result)
220
221
 
221
222
  @requests_mock.Mocker()
222
223
  def test_batch_request_500(self, m):
kfinance/conftest.py CHANGED
@@ -64,6 +64,16 @@ def mock_client(requests_mock: Mocker) -> Client:
64
64
  }
65
65
  },
66
66
  )
67
+ # Fetch a fake company
68
+ requests_mock.post(
69
+ url="https://kfinance.kensho.com/api/v1/ids",
70
+ additional_matcher=lambda req: req.json().get("identifiers") == ["C_1"],
71
+ json={
72
+ "data": {
73
+ "C_1": {"company_id": 1, "security_id": 1, "trading_item_id": 1},
74
+ },
75
+ },
76
+ )
67
77
  # Fetch SPGI and a non-existent company (which will include an error)
68
78
  requests_mock.post(
69
79
  url="https://kfinance.kensho.com/api/v1/ids",
@@ -30,6 +30,16 @@ class Capitalizations(BaseModel):
30
30
 
31
31
  capitalizations: list[DailyCapitalization] = Field(validation_alias="market_caps")
32
32
 
33
+ @model_validator(mode="before")
34
+ @classmethod
35
+ def handle_field_alias(cls, data: Any) -> Any:
36
+ """Handle both 'capitalizations' and 'market_caps' field names"""
37
+ if isinstance(data, dict):
38
+ if "capitalizations" in data and "market_caps" not in data:
39
+ data = deepcopy(data)
40
+ data["market_caps"] = data["capitalizations"]
41
+ return data
42
+
33
43
  @model_validator(mode="before")
34
44
  @classmethod
35
45
  def inject_currency_into_data(cls, data: Any) -> Any:
@@ -84,7 +84,11 @@ class GetCapitalizationFromIdentifiers(KfinanceTool):
84
84
  api_client=api_client, tasks=tasks
85
85
  )
86
86
 
87
- for capitalization_response in capitalization_responses.values():
87
+ for identifier, capitalization_response in capitalization_responses.items():
88
+ # If we get an empty response for a company, assign an empty object
89
+ if not capitalization_response:
90
+ capitalization_responses[identifier] = Capitalizations(capitalizations=list())
91
+ capitalization_response = capitalization_responses[identifier]
88
92
  # If we return results for more than one company and the start and end dates are unset,
89
93
  # truncate data to only return the most recent datapoint.
90
94
  if len(capitalization_responses) > 1 and start_date is None and end_date is None:
@@ -93,13 +97,14 @@ class GetCapitalizationFromIdentifiers(KfinanceTool):
93
97
  ]
94
98
  # Set capitalizations that were not requested to None.
95
99
  # That way, they can be skipped for serialization via `exclude_none=True`
96
- for daily_capitalization in capitalization_response.capitalizations:
97
- if capitalization is not Capitalization.market_cap:
98
- daily_capitalization.market_cap = None
99
- if capitalization is not Capitalization.tev:
100
- daily_capitalization.tev = None
101
- if capitalization is not Capitalization.shares_outstanding:
102
- daily_capitalization.shares_outstanding = None
100
+ if capitalization_response.capitalizations:
101
+ for daily_capitalization in capitalization_response.capitalizations:
102
+ if capitalization is not Capitalization.market_cap:
103
+ daily_capitalization.market_cap = None
104
+ if capitalization is not Capitalization.tev:
105
+ daily_capitalization.tev = None
106
+ if capitalization is not Capitalization.shares_outstanding:
107
+ daily_capitalization.shares_outstanding = None
103
108
 
104
109
  return GetCapitalizationFromIdentifiersResp(
105
110
  capitalization=capitalization,
@@ -67,7 +67,7 @@ class TestGetCapitalizationFromCompanyIds:
67
67
  shares_outstanding=None,
68
68
  ),
69
69
  ]
70
- )
70
+ ),
71
71
  },
72
72
  errors=[
73
73
  "No identification triple found for the provided identifier: NON-EXISTENT of type: ticker"
@@ -81,6 +81,26 @@ class TestGetCapitalizationFromCompanyIds:
81
81
  response = tool.run(args.model_dump(mode="json"))
82
82
  assert response == expected_response
83
83
 
84
+ def test_get_capitalization_from_identifiers_property_400(
85
+ self, requests_mock: Mocker, mock_client: Client
86
+ ) -> None:
87
+ requests_mock.get(
88
+ url=f"https://kfinance.kensho.com/api/v1/market_cap/1/none/none",
89
+ status_code=400,
90
+ )
91
+
92
+ expected_response = GetCapitalizationFromIdentifiersResp(
93
+ capitalization=Capitalization.market_cap,
94
+ results={"C_1": Capitalizations(market_caps=list())},
95
+ )
96
+
97
+ tool = GetCapitalizationFromIdentifiers(kfinance_client=mock_client)
98
+ args = GetCapitalizationFromIdentifiersArgs(
99
+ identifiers=["C_1"], capitalization=Capitalization.market_cap
100
+ )
101
+ response = tool.run(args.model_dump(mode="json"))
102
+ assert response == expected_response
103
+
84
104
  def test_most_recent_request(self, requests_mock: Mocker, mock_client: Client) -> None:
85
105
  """
86
106
  GIVEN the GetCapitalizationFromIdentifiers tool
@@ -44,6 +44,13 @@ class GetFinancialLineItemFromIdentifiers(KfinanceTool):
44
44
  - When possible, pass multiple identifiers in a single call rather than making multiple calls.
45
45
  - To fetch the most recent value for the line item, leave start_year, start_quarter, end_year, and end_quarter as None.
46
46
  - The tool accepts arguments in calendar years, and all outputs will be presented in terms of calendar years. Please note that these calendar years may not align with the company's fiscal year.
47
+ - All aliases for a line item return identical data (e.g., "revenue", "normal_revenue", and "regular_revenue" all return the same financial data).
48
+ - For the following Enterprise Value (EV) ratio line items, always specify period_type as either "quarterly" or "ltm" (Last Twelve Months) - do not rely on the default annual period:
49
+ - last_close_tev_to_ebit (and its aliases: ev_to_ebit, enterprise_value_to_ebit, tev_to_ebit, etc.)
50
+ - last_close_tev_to_ebitda (and its aliases: ev_to_ebitda, enterprise_value_to_ebitda, tev_to_ebitda, etc.)
51
+ - ev_to_employees (and its aliases: ev_to_employee_count, tev_to_employees, enterprise_value_to_employees, etc.)
52
+ - ev_to_total_revenue (and its aliases: tev_to_total_revenue, enterprise_value_to_total_revenue, etc.)
53
+ - When requesting these EV ratios, explicitly set period_type="quarterly" or period_type="ltm" for optimal data availability.
47
54
 
48
55
  Example:
49
56
  Query: "What are the revenues of Lowe's and Home Depot?"
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.10'
32
- __version_tuple__ = version_tuple = (3, 2, 10)
31
+ __version__ = version = '3.2.11'
32
+ __version_tuple__ = version_tuple = (3, 2, 11)
33
33
 
34
34
  __commit_id__ = commit_id = None