Skip to content

sync dev -> main - #2828

Merged
ValueRaider merged 56 commits into
mainfrom
dev
May 23, 2026
Merged

ValueRaider merged 56 commits into
mainfrom
dev

Conversation

ValueRaider and others added 30 commits April 23, 2026 20:47
- calendars.py: "prividing" -> "providing" (3 user-visible UserWarning messages)
- data.py: "Reponse" -> "Response" (docstring)
…n different years as the same interval

The "1mo" branch compared only `dt1.month == dt2.month`, so e.g.
(2024-12-15, 2025-12-15) returned True. The "3mo" branch already
handles year differences via `year_diff`; mirror that by also
requiring `dt1.year == dt2.year`.

Added a test (`test_same_month_different_year`) that fails on the
old logic and passes on the fix. All existing tests still pass.
Adding try block for added protection to "meta" data
…viding-response

chore: fix typos (prividing -> providing, Reponse -> Response)
…al-1mo-year

Fix: _dts_in_same_interval("1mo") ignored year
Add Auth class for Logging In
Guard both chart-error and chart-result checks against data['chart']
being None, which previously raised TypeError instead of the expected
YFPricesMissingError.

- history.py L270: add 'data["chart"]' truthiness check before accessing ['error']
- history.py L274: add 'not data["chart"]' short-circuit before accessing ['result']
- Add regression test covering chart=None, result=None, missing key, and error payload
Use yf.Ticker().history() convention consistent with the rest of test_prices.py.
Remove standalone test_chart_none_guard.py file.
Fix TypeError when data['chart'] is None in history.py (#2670)
…rror

Fix dividends error on unlisted tickers
Yahoo's markettime endpoint silently ignores the `market` parameter and
always returns U.S. data, so `Market("EUROPE").status` previously returned
U.S. status while pretending to be European. The summary endpoint does
honor the parameter and is unaffected.

- Introduce `MarketRegion(str, Enum)` as the single source of truth for
  the supported region values, exposed as `yfinance.MarketRegion`.
- Validate `Market(...)` input against the enum and raise `ValueError`
  on unknown regions.
- Detect the markettime mismatch: when a non-`US` region is requested
  but the response id is `us`, set `status` to `None` and log a warning
  rather than returning misleading data.
- Document the markettime limitation and add tests covering validation
  and the EUROPE/US fetch behavior.

Closes #2784
Fix #2784: validate Market region and stop returning misleading status
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
`download()` used module-level dicts in `yfinance.shared` (`_DFS`,
`_ERRORS`, `_TRACEBACKS`, `_ISINS`) as scratch space. Concurrent calls
trampled each other; the previous fix wrapped the whole call in
`shared._LOCK`, which silently serialized parallel downloads — hiding
the race instead of removing it, and defeating the parallelism users
reach for `download()` to get.

- Introduce `_DownloadCtx` per call holding `dfs/errors/tracebacks/isins`
  plus a fine-grained lock for thread workers.
- `_download_one`, `_download_one_threaded`, `_realign_dfs` take the ctx
  explicitly and write into it.
- Drop the call-wide `shared._LOCK.acquire()`; concurrent `download()`
  calls now actually run in parallel. The polling loop on the threaded
  path reads `len(ctx.dfs)` under the ctx lock.
- `PriceHistory` records soft errors (delisted, missing tz, repair
  failure) in `self._last_error` instead of `shared._ERRORS`; the
  download loop reads it after `Ticker.history()` returns.
- `yfinance.shared` is left in place for import-compat with code that
  may still import it, but yfinance no longer reads or writes it.
- Update existing test_multi to the new `_download_one(ctx, ...)`
  signature and add regression tests covering result separation,
  no-raise on concurrent calls, and a sentinel proving `shared._DFS`
  is no longer used as scratch space.
Allow region scoping for Sector and Industry (closes #2601)
Make yf.download() reentrant by removing shared module globals
Yahoo's v7 (`/v7/quote`) and v10 (`/quoteSummary`) endpoints accept
`lang` and `region` parameters and return localized fields (`longName`,
`shortName`, ...) when the ticker has been translated for that locale —
e.g. 1810.HK returns '小米集團-W' under `lang=zh-Hant-HK`, GAZP.ME
returns 'Публичное акционерное общество Газпром' under `lang=ru-RU`.
Previously these params were not exposed and `Ticker.info["longName"]`
always came back in U.S. English.

Surfaced as global config (`YfConfig.locale.lang` / `YfConfig.locale.region`)
rather than per-Ticker constructor params: a typical user wants the
same locale for every call in their session, and the config approach
also covers the v10 calendar/earnings endpoint in `_fetch_history_metadata`
without threading kwargs through three layers.

- Add `YfConfig.locale.lang` (default `"en-US"`) and `YfConfig.locale.region`
  (default `"US"`).
- `Quote._fetch` (v10/quoteSummary) and `Quote._fetch_additional_info`
  (v7/quote) read the locale from `YfConfig` on every call.
- `_fetch_history_metadata` (v1 calendar) reads the same locale, replacing
  a hardcoded `lang=en-US, region=US`.
- The `v8/chart` endpoint ignores `lang` server-side, so we don't forward
  there — would only generate noise.
- Verified live for Latin/diacritics (it-IT), CJK (zh-Hant-HK, ja-JP),
  Cyrillic (ru-RU); Apple under ja-JP correctly stays "Apple Inc." since
  it's a U.S. listing.

Closes #2582
- history.py: drop the hardcoded ['KAP.IL', 'SAND'] ticker whitelist
  from the phantom-dividend approval in _fix_bad_div_adjust. Per
  maintainer feedback on the original PR, the whitelist was leakage
  from a custom debug build and was never meant to be in main; phantom
  detections are safe to approve unconditionally in this branch.
- history.py: split a semicolon-joined statement that was failing
  ruff E702 in CI.
- domain/industry.py: fix `compnaies` → `companies` typo (8
  occurrences, local-variable rename only, no behavioural impact).
Simplify phantom-dividend repair branch + drive-by typo/lint fixes
Allow lang and region scoping for Ticker (closes #2582)
Some platforms (e.g. older macOS, exotic Linux distros) cannot build the
curl-impersonate binary that backs curl_cffi, leaving yfinance unusable.
This change keeps curl_cffi as the preferred and default backend but no
longer hard-requires it at runtime.

- New `yfinance/_http.py` abstracts the HTTP backend. If `curl_cffi` is
  importable it is used as before; otherwise yfinance falls back to plain
  `requests` with a realistic Chrome User-Agent and logs a warning so the
  downgrade is explicit.
- `data.py`, `base.py`, `multi.py`, `scrapers/history.py` build sessions
  via `_http.new_session()`.
- Scrapers and screener catch `_http.HTTPError` instead of importing
  `curl_cffi.requests.exceptions.HTTPError` directly.
- `is_supported_session()` accepts either backend; `cookie_jar()` papers
  over the small API difference between curl_cffi (`cookies.jar`) and
  requests (`cookies` is itself the jar).
- New Advanced > Installation page documents the curl_cffi-free install
  recipe; README links to it just under the install instruction.

Empirically verified that plain `requests` with a Chrome UA does not hit
the 401-after-~10-requests issue that the earlier `curl_adapter` approach
ran into; 15/15 quoteSummary calls succeed without rate limiting.

`setup.py` is unchanged -- `curl_cffi>=0.15` remains the default install
requirement (CVE-pinned). The fallback only activates when the import
fails at runtime; moving curl_cffi to extras_require can be a follow-up
decision for the maintainer.
@ValueRaider
ValueRaider marked this pull request as ready for review May 21, 2026 19:19
@ValueRaider
ValueRaider marked this pull request as draft May 21, 2026 19:20
@ValueRaider
ValueRaider marked this pull request as ready for review May 23, 2026 13:47
@dokson

dokson commented May 23, 2026

Copy link
Copy Markdown
Contributor

Let's go 🚀🚀🚀

@ValueRaider
ValueRaider merged commit ff36bd7 into main May 23, 2026
4 checks passed
@Deepak-Chaturvedi

Deepak-Chaturvedi commented May 25, 2026 •

Copy link
Copy Markdown

Something broke in my code with this new release. Same things happened with release version 1.2.0 in Feb 2026. Now again the same thing with 1.4.0

data = yf.download(tickers, start=start, end=end, threads=True, interval=interval)

df = ( data.stack() .reset_index() .rename(columns={"level_1": "Ticker"}) .sort_values(["Ticker", "Date"]) )
---> your DataFrame df does not contain a column named "Date".
:(

@ValueRaider

Copy link
Copy Markdown
Collaborator Author

@Deepak-Chaturvedi wrong place

@dokson

dokson commented May 25, 2026

Copy link
Copy Markdown
Contributor

@Deepak-Chaturvedi @ValueRaider tracked down the regression — reindex_dfs() was dropping the Date/Datetime index name, so data.stack().reset_index() produced a level_0 column instead. Fix in #2832.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants