Allow region scoping for Sector and Industry

Yahoo's `/v1/finance/sectors/{key}` and `/industries/{key}` endpoints accept
an ISO 3166-1 alpha-2 `region` query parameter and return regional top
companies/ETFs/funds accordingly. The Domain base class hard-coded `region=US`,
so `Sector("technology").top_companies` always returned U.S. names regardless
of the user's interest.

- Add `region: str = "US"` to `Domain.__init__` and propagate through
  `Sector` and `Industry`.
- Normalize input via `.strip().upper()` so "us", " GB ", and "Fr" all work.
- Use `self._region` in the request params.
- Document and test the behavior.

Closes #2601
This commit is contained in:
Alessandro Colace
2026-05-09 17:55:05 +02:00
parent 570e02f7b0
commit ac1a7f65ca
5 changed files with 60 additions and 9 deletions
@@ -30,3 +30,13 @@ The modules can be chained with Ticker as below.
.. literalinclude:: examples/sector_industry_ticker.py
:language: python
Region scoping
--------------
By default ``Sector`` and ``Industry`` return U.S. data. Pass a Yahoo region
(ISO 3166-1 alpha-2 country code, case-insensitive) to scope ``top_companies``,
``top_etfs``, ``top_mutual_funds`` and the industry top performing/growth lists::
yf.Sector("technology", region="GB").top_companies # UK
yf.Sector("technology", region="DE").top_companies # Germany
yf.Industry("software-infrastructure", region="JP") # Japan
+31
View File
@@ -0,0 +1,31 @@
import unittest
from tests.context import yfinance as yf
class TestSectorRegion(unittest.TestCase):
def test_default_region_is_us(self):
s = yf.Sector("technology")
self.assertEqual(s._region, "US")
def test_region_is_normalized(self):
for raw, expected in [("us", "US"), (" GB ", "GB"), ("Fr", "FR")]:
s = yf.Sector("technology", region=raw)
self.assertEqual(s._region, expected)
def test_us_and_gb_top_companies_differ(self):
us = yf.Sector("technology").top_companies
gb = yf.Sector("technology", region="GB").top_companies
self.assertIsNotNone(us)
self.assertIsNotNone(gb)
# UK-listed symbols carry the .L suffix, U.S. symbols do not.
self.assertTrue(any(sym.endswith(".L") for sym in gb.index))
self.assertFalse(any(sym.endswith(".L") for sym in us.index))
def test_industry_region_propagates(self):
ind = yf.Industry("software-infrastructure", region="DE")
self.assertEqual(ind._region, "DE")
if __name__ == "__main__":
unittest.main()
+7 -3
View File
@@ -14,16 +14,20 @@ class Domain(ABC):
and methods for fetching and parsing data. Derived classes must implement the `_fetch_and_parse()` method.
"""
def __init__(self, key: str, session=None):
def __init__(self, key: str, session=None, region: str = "US"):
"""
Initializes the Domain object with a key, session.
Initializes the Domain object with a key, session, and region.
Args:
key (str): Unique key identifying the domain entity.
session (Optional[requests.Session]): Session object for HTTP requests. Defaults to None.
region (str): Yahoo region (ISO 3166-1 alpha-2 country code, e.g.
"US", "GB", "FR", "DE", "JP"). Determines the regional scope
of returned data such as ``top_companies``. Defaults to "US".
"""
self._key: str = key
self.session = session
self._region: str = region.strip().upper()
self._data: YfData = YfData(session=session)
self._name: Optional[str] = None
@@ -118,7 +122,7 @@ class Domain(ABC):
Returns:
Dict: The JSON response data from the request.
"""
params_dict = {"formatted": "true", "withReturns": "true", "lang": "en-US", "region": "US"}
params_dict = {"formatted": "true", "withReturns": "true", "lang": "en-US", "region": self._region}
result = self._data.get_raw_json(query_url, params=params_dict)
return result
+5 -2
View File
@@ -14,14 +14,17 @@ class Industry(Domain):
Represents an industry within a sector.
"""
def __init__(self, key, session=None):
def __init__(self, key, session=None, region: str = "US"):
"""
Args:
key (str): The key identifier for the industry.
session (optional): The session to use for requests.
region (str): Yahoo region (ISO 3166-1 alpha-2 country code, e.g.
"US", "GB", "FR", "DE", "JP"). Scopes top performing/growth
company listings. Defaults to "US".
"""
YfData(session=session)
super(Industry, self).__init__(key, session)
super(Industry, self).__init__(key, session, region)
self._query_url = f'{_QUERY_URL_}/industries/{self._key}'
self._sector_key = None
+7 -4
View File
@@ -15,18 +15,21 @@ class Sector(Domain):
such as top ETFs, top mutual funds, and industry data.
"""
def __init__(self, key, session=None):
def __init__(self, key, session=None, region: str = "US"):
"""
Args:
key (str): The key representing the sector.
session (requests.Session, optional): A session for making requests. Defaults to None.
region (str): Yahoo region (ISO 3166-1 alpha-2 country code, e.g.
"US", "GB", "FR", "DE", "JP"). Scopes ``top_companies``,
``top_etfs`` and ``top_mutual_funds``. Defaults to "US".
.. seealso::
:attr:`Sector.industries <yfinance.Sector.industries>`
Map of sector and industry
"""
super(Sector, self).__init__(key, session)
super(Sector, self).__init__(key, session, region)
self._query_url: str = f'{_QUERY_URL_}/sectors/{self._key}'
self._top_etfs: Optional[Dict] = None
self._top_mutual_funds: Optional[Dict] = None