Skip to content

Guard get_shares_full against empty/missing share-count timeseries - #2898

Open
joaopedroassad wants to merge 1 commit into
ranaroussi:devfrom
joaopedroassad:guard-shares-full-empty-timeseries
Open

Guard get_shares_full against empty/missing share-count timeseries#2898
joaopedroassad wants to merge 1 commit into
ranaroussi:devfrom
joaopedroassad:guard-shares-full-empty-timeseries

Conversation

@joaopedroassad

Copy link
Copy Markdown
Contributor

Summary

  • TickerBase.get_shares_full reads json_data["timeseries"]["result"] and then indexes shares_data[0] with no guard. When Yahoo returns a 200 whose share-count timeseries envelope has an empty result ([]), a null result, or omits timeseries entirely (the finance error envelope), this raises a raw IndexError / TypeError / KeyError that leaks straight to the caller and ignores hide_exceptions.
  • Empty result is the common case: symbols with no share-count history (a lot of non-US tickers, ETFs, indices) come back as {"timeseries": {"error": null, "result": []}}, so shares_data[0] hits IndexError: list index out of range.
  • The break isn't limited to the public get_shares_full() call. Quote.shares calls get_shares_full internally to populate the shares complementary field, so the same exception can take down .info for the whole ticker.
  • Fix is minimal and matches how the rest of the function already degrades: pull result defensively and return None when it's empty, exactly like the existing if "shares_out" not in shares_data[0]: return None exit right below it. Every other failure path in this function already returns None.
shares_data = (json_data.get("timeseries") or {}).get("result") or []
if not shares_data or "shares_out" not in shares_data[0]:
    return None

This is the same class of empty/malformed-timeseries guard as #2877 (Complementary info: guard against empty or missing timeseries result), which fixed the identical json_result["result"][0] pattern in quote.py. This is the next-door site in base.py that reads the same share-count timeseries shape and was still unguarded.

Testing

Ran in a fresh venv with an editable install:

python -m venv .venv && . .venv/bin/activate
pip install -e . pytest ruff

Red -> green on the new test:

# stock dev (fix reverted): FAILS with IndexError: list index out of range at base.py:541
python -m pytest tests/test_ticker.py::TestTickerInfo::test_shares_full_empty_result_timeseries -v
# with the fix: PASSES
python -m pytest tests/test_ticker.py::TestTickerInfo::test_shares_full_empty_result_timeseries -v

Adjacent complementary-info guard tests still pass:

python -m pytest tests/test_ticker.py::TestTickerInfo::test_complementary_info_sparse_timeseries tests/test_ticker.py::TestTickerInfo::test_complementary_info_empty_result_timeseries -v

Lint / compile clean on changed files:

ruff check yfinance/base.py tests/test_ticker.py    # All checks passed!
python -m py_compile yfinance/base.py tests/test_ticker.py
git diff --check

The new test is fully mock-based (patches _data.cache_get, sets _tz to skip the network tz lookup), so it needs no network. It covers the four failing shapes (empty list, missing result, null result, missing timeseries) plus a happy path that still returns a populated Series.

@ValueRaider

Copy link
Copy Markdown
Collaborator

When Yahoo returns a 200 whose share-count timeseries envelope has an empty result

Example?

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.

2 participants