Skip to content

Commit d6afeeb

Browse files
authored
Merge pull request #2757 from ranaroussi/dev
sync dev -> main
2 parents b1ed233 + b23433f commit d6afeeb

12 files changed

Lines changed: 565 additions & 24 deletions

File tree

‎doc/source/reference/index.rst‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ The following are the publicly available classes, and functions exposed by the `
2626
- :attr:`Industry <yfinance.Industry>`: Domain class for accessing industry information.
2727
- :attr:`EquityQuery <yfinance.EquityQuery>`: Class to build equity query filters.
2828
- :attr:`FundQuery <yfinance.FundQuery>`: Class to build fund query filters.
29+
- :attr:`ETFQuery <yfinance.ETFQuery>`: Class to build ETF query filters.
2930
- :attr:`screen <yfinance.screen>`: Run equity/fund queries.
3031
- :attr:`config.debug.logging <yfinance.config>`: Enable verbose debug logging (``yf.config.debug.logging = True``).
3132
- :attr:`set_tz_cache_location <yfinance.set_tz_cache_location>`: Function to set the timezone cache location.

‎doc/source/reference/yfinance.screener.rst‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ The `Sector` and `Industry` modules allow you to access the sector and industry
1313

1414
EquityQuery
1515
FundQuery
16+
ETFQuery
1617
screen
1718

1819
.. seealso::
@@ -24,4 +25,8 @@ The `Sector` and `Industry` modules allow you to access the sector and industry
2425
supported operand values for query
2526
:attr:`FundQuery.valid_values <yfinance.FundQuery.valid_values>`
2627
supported `EQ query operand parameters`
28+
:attr:`ETFQuery.valid_fields <yfinance.ETFQuery.valid_fields>`
29+
supported operand values for query
30+
:attr:`ETFQuery.valid_values <yfinance.ETFQuery.valid_values>`
31+
supported `EQ query operand parameters`
2732

‎tests/test_ticker.py‎

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
import unittest
2121
# import requests_cache
22+
from unittest.mock import patch, MagicMock
2223
from typing import Union, Any, get_args, _GenericAlias
2324
# from urllib.parse import urlparse, parse_qs, urlencode, urlunparse
2425

@@ -1235,6 +1236,54 @@ def test_sector_weightings(self):
12351236
sector_weightings = ticker.funds_data.sector_weightings
12361237
self.assertIsInstance(sector_weightings, dict)
12371238

1239+
class TestTickerValuationMeasures(unittest.TestCase):
1240+
1241+
_MOCK_HTML = """<html><body>
1242+
<table>
1243+
<tr><td></td><td>Current</td><td>12/31/2025</td><td>9/30/2025</td></tr>
1244+
<tr><td>Market Cap</td><td>3.76T</td><td>4.00T</td><td>3.76T</td></tr>
1245+
<tr><td>Enterprise Value</td><td>3.78T</td><td>4.04T</td><td>3.81T</td></tr>
1246+
<tr><td>Trailing P/E</td><td>32.39</td><td>36.44</td><td>38.64</td></tr>
1247+
<tr><td>Forward P/E</td><td>29.76</td><td>32.79</td><td>31.65</td></tr>
1248+
<tr><td>PEG Ratio (5yr expected)</td><td>2.27</td><td>2.75</td><td>2.44</td></tr>
1249+
<tr><td>Price/Sales</td><td>8.77</td><td>9.80</td><td>9.41</td></tr>
1250+
<tr><td>Price/Book</td><td>42.60</td><td>54.21</td><td>57.14</td></tr>
1251+
<tr><td>Enterprise Value/Revenue</td><td>8.68</td><td>9.71</td><td>9.32</td></tr>
1252+
<tr><td>Enterprise Value/EBITDA</td><td>24.73</td><td>27.92</td><td>26.87</td></tr>
1253+
</table>
1254+
</body></html>"""
1255+
1256+
def _make_ticker_with_mock(self, html):
1257+
mock_response = MagicMock()
1258+
mock_response.text = html
1259+
with patch("yfinance.data.YfData.cache_get", return_value=mock_response):
1260+
dat = yf.Ticker("AAPL")
1261+
data = dat.valuation_measures
1262+
return data
1263+
1264+
def test_valuation_measures(self):
1265+
data = self._make_ticker_with_mock(self._MOCK_HTML)
1266+
self.assertEqual(data.shape, (9, 3), "unexpected shape")
1267+
self.assertListEqual(list(data.columns), ["Current", "12/31/2025", "9/30/2025"])
1268+
self.assertIn("Market Cap", data.index)
1269+
self.assertIn("Trailing P/E", data.index)
1270+
self.assertIn("Enterprise Value/EBITDA", data.index)
1271+
self.assertIsNone(data.index.name)
1272+
self.assertEqual(data.loc["Market Cap", "Current"], "3.76T")
1273+
self.assertEqual(data.loc["Forward P/E", "12/31/2025"], "32.79")
1274+
1275+
def test_valuation_measures_no_table(self):
1276+
data = self._make_ticker_with_mock("<html><body><p>No tables here</p></body></html>")
1277+
self.assertIsInstance(data, pd.DataFrame)
1278+
self.assertTrue(data.empty)
1279+
1280+
def test_valuation_measures_fetch_error(self):
1281+
with patch("yfinance.data.YfData.cache_get", side_effect=Exception("network error")):
1282+
dat = yf.Ticker("AAPL")
1283+
data = dat.valuation_measures
1284+
self.assertIsInstance(data, pd.DataFrame)
1285+
self.assertTrue(data.empty)
1286+
12381287
def suite():
12391288
suite = unittest.TestSuite()
12401289
suite.addTest(TestTicker('Test ticker'))
@@ -1244,6 +1293,7 @@ def suite():
12441293
suite.addTest(TestTickerMiscFinancials('Test misc financials'))
12451294
suite.addTest(TestTickerInfo('Test info & fast_info'))
12461295
suite.addTest(TestTickerFundsData('Test Funds Data'))
1296+
suite.addTest(TestTickerValuationMeasures('Test valuation measures'))
12471297
return suite
12481298

12491299

‎yfinance/__init__.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
from .domain.market import Market
3535
from .config import YfConfig as config
3636

37-
from .screener.query import EquityQuery, FundQuery
37+
from .screener.query import EquityQuery, FundQuery, ETFQuery
3838
from .screener.screener import screen, PREDEFINED_SCREENER_QUERIES
3939

4040
__version__ = version.version
@@ -45,7 +45,7 @@
4545

4646
__all__ = ['download', 'Market', 'Search', 'Lookup', 'Ticker', 'Tickers', 'enable_debug_mode', 'set_tz_cache_location', 'Sector', 'Industry', 'WebSocket', 'AsyncWebSocket', 'Calendars']
4747
# screener stuff:
48-
__all__ += ['EquityQuery', 'FundQuery', 'screen', 'PREDEFINED_SCREENER_QUERIES']
48+
__all__ += ['EquityQuery', 'FundQuery', 'ETFQuery', 'screen', 'PREDEFINED_SCREENER_QUERIES']
4949

5050
# Config stuff:
5151
_NOTSET=object()

‎yfinance/base.py‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,10 @@ def get_fast_info(self):
287287
self._fast_info = FastInfo(self)
288288
return self._fast_info
289289

290+
def get_valuation_measures(self):
291+
data = self._quote.valuation_measures
292+
return data
293+
290294
def get_sustainability(self, as_dict=False):
291295
data = self._quote.sustainability
292296
if as_dict:

0 commit comments

Comments
 (0)