[ty] Infer constant membership in inline list and set literals - #28676
Conversation
Typing conformance resultsNo changes detected ✅Current numbersThe percentage of diagnostics emitted that were expected errors held steady at 98.15%. The percentage of expected errors that received a diagnostic held steady at 98.07%. The number of fully passing files held steady at 133/146. |
Memory usage reportSummary
Significant changesClick to expand detailed breakdownsphinx
prefect
flake8
trio
|
|
| Lint rule | Added | Removed | Changed |
|---|---|---|---|
redundant-condition-strict |
4 | 0 | 0 |
| Total | 4 | 0 | 0 |
Flaky changes detected. This PR summary excludes flaky changes; see the HTML report for details.
Raw diff:
dd-trace-py (https://github.com/DataDog/dd-trace-py)
+ ddtrace/internal/settings/errortracking.py:43:48 warning[redundant-condition-strict] Condition `config._report_handled_errors in ["all", "user", "third_party"]` is always false
paasta (https://github.com/yelp/paasta)
+ paasta_tools/paastaapi/api_client.py:211:12 warning[redundant-condition-strict] Condition `response_type not in ["file", "bytes"]` is always true
scipy (https://github.com/scipy/scipy)
+ scipy/optimize/tests/test__root.py:25:16 warning[redundant-condition-strict] Condition `method in ('linearmixing', 'excitingmixing')` is always false
scrapy (https://github.com/scrapy/scrapy)
+ scrapy/core/engine.py:267:12 warning[redundant-condition-strict] Condition `self._state in (_EngineState.STOPPING, _EngineState.STOPPED)` is always false
Ecosystem reportPR #28676 ecosystem summaryThe comparison for head Affected projects1. dd-trace-py: dynamically replaced configuration attributesReport entry: ddtrace/internal/settings/errortracking.py:43 The PR adds Existing ty issue: ty#2016 discusses the underlying limitation in modeling dynamic class Config:
value = 0
config = Config()
setattr(config, 'value', 'all')
# Merge base: no diagnostic
# PR: warning[redundant-condition-strict] Condition `config.value in ['all']` is always false
if config.value in ['all']:
passThe condition is true at runtime; ty retains the declared attribute type after 2. paasta: a tuple parameter checked against stringsReport entry: paasta_tools/paastaapi/api_client.py:211 The parameter is annotated as # Merge base: no diagnostic
# PR: warning[redundant-condition-strict] Condition `() not in ['']` is always true
if () not in ['']:
pass3. SciPy: a literal union excludes both tested method namesReport entry: scipy/optimize/tests/test__root.py:25 The loop iterates over seven literal method names, including neither for method in ['hybr', 'lm']:
# Merge base: no diagnostic
# PR: warning[redundant-condition-strict] Condition `method in ('linearmixing',)` is always false
if method in ('linearmixing',):
pass4. Scrapy: attribute narrowing survives state changesReport entry: scrapy/core/engine.py:267 The PR adds The PR does not change the narrowing. Its union handling for reflexive equality lets existing tuple membership establish that the inferred union is disjoint from the tested states. Replacing only the final membership condition with the equivalent two Existing ty issues: ty#2792 tracks attribute narrowing across mutating method calls; ty#885 discusses narrowing in unsound contexts, including class Engine:
_state: bool | None = False
def stop(self):
self._state = True
def start(self):
if self._state not in (False, None):
return
self.stop()
# Merge base: no diagnostic
# PR: warning[redundant-condition-strict] Condition `self._state in (True,)` is always false
if self._state in (True,):
return TrueReproduction
|
AlexWaygood
left a comment
There was a problem hiding this comment.
Thanks! Some of this feels a bit overcomplicated right now
Inline list and set membership tests now preserve the values of their individual elements, allowing ty to determine when a condition is always true or false. With the target platform set to Linux, both
sys.platform in ["linux", "windows"]andsys.platform in {"linux", "windows"}select only the matching branch, so an assignment there is inferred asLiteral[1].Reuse the precise element extraction used for iteration and membership narrowing without changing the inferred container type. Lists and sets use the existing tuple membership equality evaluator, including its identity-or-equality behavior. For sets, assume equality is an equivalence relation and equal objects have equal hashes. Checking reflexive equality across union alternatives also improves existing tuple membership inference.
Context is that in python/typing#2173 people are wanting to specify that
sys.platform in ["linux", "windows"]should work. This makes it work in ty so that we can be fine with any outcome of that specification change.Test plan
Mdtests cover platform-dependent branch reachability; positive and negative membership in inline lists and sets; inferred literal values and unions; fixed-length unpacking; stored mutable containers; custom equality and identity; comparison chains; and preservation of enum-set narrowing.
Ecosystem report
The comparison for head
90111f10da9359722abb903351b89aaae0f9bcbaadds fourredundant-condition-strictwarnings. The paasta and SciPy warnings correctly identify disjoint membership checks. The dd-trace-py warning exposes existing limitations in modeling dynamicsetattr; the Scrapy warning exposes existing attribute narrowing across method calls andawait. Equivalent equality checks already exhibit both limitations on the base revision. These existing limitations are accepted for this change. See the full ecosystem report for minimized examples and exact comparison details.