Skip to content

Infer every value of a context manager's first yield - #3443

Open
Parsiffall1 wants to merge 3 commits into
pylint-dev:mainfrom
Parsiffall1:fix-contextmanager-first-yield-values
Open

Parsiffall1 wants to merge 3 commits into
pylint-dev:mainfrom
Parsiffall1:fix-contextmanager-first-yield-values

Conversation

@Parsiffall1

Copy link
Copy Markdown

Type of Changes

Type
✓ 🐛 Bug fix

Description

For a contextlib.contextmanager generator, _infer_context_manager did next(inferred.infer_yield_types()), so the as target kept only the first value inferred for the first yield. When that yield can infer to several values, the others were dropped. With the example from the issue, captured inferred only to TextIOWrapper, and pylint reported Instance of 'TextIOWrapper' has no 'getvalue' member.

This change takes the first yield of the generator (same selection as FunctionDef.infer_yield_result) and yields every value inferred for it, using the generator's call context as before. Later yields are still ignored, as test_inferring_with_contextlib_contextmanager expects.

Tests:

  • test_inferring_with_contextlib_contextmanager_all_first_yield_values: yield 1 if flag else "a" now infers to both 1 and "a", and a second yield is still ignored. Fails on main, passes with the fix.
  • test_inferring_with_contextlib_contextmanager_uses_call_arguments: the call arguments are still used to infer the yielded value.
  • pytest tests: all pass, except test_identify_old_namespace_package_protocol, which fails the same way on main in my environment because pkg_resources isn't installed. pre-commit (ruff, black, pylint, mypy, pyright) passes. The new lines have full branch coverage.
  • pylint -E on _pytest and pip/_internal, before and after: the only difference is one less false positive (_pytest/config/__init__.py:507: Instance of 'TextIOWrapper' has no 'mode' member).

Note: #3323 changes how yield from is inferred in infer_yield_result. This path now infers the first yield directly, so whichever PR lands second needs to keep both behaviours. The tests in each PR would catch it.

Closes #3440

_infer_context_manager took only the first value inferred for the first
yield of a contextlib.contextmanager generator, so the target of
"with ... as x" lost the other possible values. Infer all values of that
first yield instead, still ignoring later yields.

Closes pylint-dev#3440

This branch has not been deployed

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Context manager inference keeps only the first inferred yield value

2 participants