Skip to content

fix Do not enforce name alignment for namedtuple and enum functional syntax #2874#2892

Open
asukaminato0721 wants to merge 1 commit intofacebook:mainfrom
asukaminato0721:2874
Open

fix Do not enforce name alignment for namedtuple and enum functional syntax #2874#2892
asukaminato0721 wants to merge 1 commit intofacebook:mainfrom
asukaminato0721:2874

Conversation

@asukaminato0721
Copy link
Contributor

Summary

Fixes #2874

no longer enforces assignment-name alignment for functional Enum and functional NamedTuple definitions.

Test Plan

update && add test

Copilot AI review requested due to automatic review settings March 25, 2026 03:37
@meta-cla meta-cla bot added the cla signed label Mar 25, 2026
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes issue #2874 by removing the diagnostic that enforced assignment-name alignment for functional Enum(...) and NamedTuple(...)/namedtuple(...) definitions, matching the behavior of other modern type checkers.

Changes:

  • Stop emitting “Expected string literal <varname>” errors for functional Enum definitions whose first string argument doesn’t match the assignment target name.
  • Stop emitting the same alignment error for functional typing.NamedTuple(...) and collections.namedtuple(...) assignments (while still binding/type-checking the passed name expression).
  • Add regression tests covering name-mismatch cases for both functional namedtuple and functional Enum.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.

File Description
pyrefly/lib/binding/stmt.rs Removes name-alignment enforcement for functional namedtuple assignments; still type-checks the name expression via ensure_expr.
pyrefly/lib/binding/class.rs Removes name-alignment enforcement for functional Enum synthesis.
pyrefly/lib/test/named_tuple.rs Adds regression test ensuring mismatched functional namedtuple names don’t error and types are still inferred as expected.
pyrefly/lib/test/enums.rs Adds regression test ensuring mismatched functional Enum names don’t error and member literals are still inferred.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@github-actions
Copy link

Diff from mypy_primer, showing the effect of this PR on open source code:

dd-trace-py (https://github.com/DataDog/dd-trace-py)
- ERROR ddtrace/vendor/psutil/_psbsd.py:868:9-15: Expected string literal "nt_mmap_grouped" [invalid-argument]
- ERROR ddtrace/vendor/psutil/_psbsd.py:871:9-15: Expected string literal "nt_mmap_ext" [invalid-argument]
- ERROR ddtrace/vendor/psutil/_pssunos.py:670:34-40: Expected string literal "nt_mmap_grouped" [invalid-argument]
- ERROR ddtrace/vendor/psutil/_pssunos.py:671:30-36: Expected string literal "nt_mmap_ext" [invalid-argument]

pycryptodome (https://github.com/Legrandin/pycryptodome)
- ERROR lib/Crypto/Cipher/_mode_gcm.py:70:28-40: Expected string literal "GHASH_Imp" [invalid-argument]

scikit-learn (https://github.com/scikit-learn/scikit-learn)
- ERROR sklearn/utils/_testing.py:840:23-29: Expected string literal "Args" [invalid-argument]

psycopg (https://github.com/psycopg/psycopg)
- ERROR tests/types/test_enum.py:351:9-18: Expected string literal "enum" [invalid-argument]

mongo-python-driver (https://github.com/mongodb/mongo-python-driver)
- ERROR pymongo/ocsp_cache.py:50:9-31: Expected string literal "CACHE_KEY_TYPE" [invalid-argument]

cloud-init (https://github.com/canonical/cloud-init)
- ERROR tests/unittests/sources/test_smartos.py:793:9-17: Expected string literal "res" [invalid-argument]
- ERROR tests/unittests/test_net_activators.py:48:24-31: Expected string literal "mocks" [invalid-argument]
- ERROR tests/unittests/test_net_activators.py:67:24-31: Expected string literal "mocks" [invalid-argument]

pandas (https://github.com/pandas-dev/pandas)
- ERROR pandas/core/frame.py:1437:17-21: Expected string literal "itertuple" [invalid-argument]
- ERROR pandas/tests/frame/indexing/test_indexing.py:1407:36-45: Expected string literal "indexer_tuple" [invalid-argument]
- ERROR pandas/tests/frame/test_constructors.py:1613:34-42: Expected string literal "named_tuple" [invalid-argument]

discord.py (https://github.com/Rapptz/discord.py)
- ERROR discord/enums.py:96:22-42: Expected string literal "cls" [invalid-argument]

spack (https://github.com/spack/spack)
- ERROR lib/spack/spack/test/test_suite.py:265:40-51: Expected string literal "MockSuite" [invalid-argument]

spark (https://github.com/apache/spark)
- ERROR python/pyspark/serializers.py:356:42-46: Expected string literal "cls" [invalid-argument]

@github-actions
Copy link

Primer Diff Classification

✅ 10 improvement(s) | 10 project(s) total | -17 errors

10 improvement(s) across dd-trace-py, pycryptodome, scikit-learn, psycopg, mongo-python-driver, cloud-init, pandas, discord.py, spack, spark.

Project Verdict Changes Error Kinds Root Cause
dd-trace-py ✅ Improvement -4 invalid-argument pyrefly/lib/binding/class.rs
pycryptodome ✅ Improvement -1 invalid-argument pyrefly/lib/binding/class.rs
scikit-learn ✅ Improvement -1 invalid-argument pyrefly/lib/binding/class.rs
psycopg ✅ Improvement -1 invalid-argument pyrefly/lib/binding/class.rs
mongo-python-driver ✅ Improvement -1 invalid-argument pyrefly/lib/binding/class.rs
cloud-init ✅ Improvement -3 invalid-argument pyrefly/lib/binding/class.rs
pandas ✅ Improvement -3 invalid-argument pyrefly/lib/binding/class.rs
discord.py ✅ Improvement -1 invalid-argument pyrefly/lib/binding/class.rs
spack ✅ Improvement -1 invalid-argument pyrefly/lib/binding/class.rs
spark ✅ Improvement -1 invalid-argument pyrefly/lib/binding/class.rs
Detailed analysis

✅ Improvement (10)

dd-trace-py (-4)

These were false positives. Pyrefly was enforcing that the first string argument to namedtuple() must match the variable name it's assigned to (e.g., nt_mmap_grouped = namedtuple('mmap', ...) was flagged because 'mmap' != 'nt_mmap_grouped'). Neither the typing spec nor mypy/pyright enforce this constraint. The PR correctly removes this overly strict check, as documented in the test cases and issue #2874.
Attribution: The changes in pyrefly/lib/binding/class.rs (removing self.check_functional_definition_name(&name.id, arg_name) at line 990) and pyrefly/lib/binding/stmt.rs (replacing check_functional_definition_name with self.ensure_expr(arg_name, &mut Usage::StaticTypeInformation) at lines 609 and 624) removed the enforcement of name alignment for functional namedtuple and Enum definitions. This directly eliminated the invalid-argument errors on _psbsd.py and _pssunos.py where the variable names (nt_mmap_grouped, nt_mmap_ext) didn't match the string literals ('mmap', 'nt_mmap_grouped', 'nt_mmap_ext').

pycryptodome (-1)

The PR explicitly fixes issue #2874, which reported that pyrefly was incorrectly enforcing name alignment between the assignment target and the string argument in functional namedtuple() and Enum() calls. The code GHASH_Imp = namedtuple('_GHash_Imp', funcs) on line 70 is perfectly valid Python — the variable name GHASH_Imp and the internal namedtuple name _GHash_Imp are intentionally different. Neither the typing spec (https://typing.readthedocs.io/en/latest/spec/namedtuples.html) nor mypy/pyright require these names to match. The removed error was a false positive.
Attribution: The change in pyrefly/lib/binding/class.rs at line 990 removed the call to self.check_functional_definition_name(&name.id, arg_name) for collections.namedtuple functional definitions. Similarly, changes in pyrefly/lib/binding/stmt.rs at lines 609 and 624 replaced self.check_functional_definition_name(&name.id, arg_name) with self.ensure_expr(arg_name, &mut Usage::StaticTypeInformation) for typing.NamedTuple and collections.namedtuple functional definitions. This removed the enforcement that the assignment variable name must match the string literal argument, which was the source of the invalid-argument error.

scikit-learn (-1)

This is a clear improvement. The removed error was a false positive — pyrefly was enforcing a convention (namedtuple string name must match variable name) as if it were a type error. The code Args = namedtuple('args', ['include', 'exclude', 'arg_name']) is perfectly valid Python. The PR explicitly fixes this by removing the check_functional_definition_name check for functional NamedTuple and Enum definitions, as documented in issue #2874. Neither mypy nor pyright enforce this constraint.
Attribution: The PR removed the check_functional_definition_name call from three locations: (1) pyrefly/lib/binding/class.rs line 990 (for Enum functional syntax), (2) pyrefly/lib/binding/stmt.rs line 609 (for typing.NamedTuple functional syntax), and (3) pyrefly/lib/binding/stmt.rs line 624 (for collections.namedtuple functional syntax). The sklearn error was specifically from the namedtuple case at line 624, where self.check_functional_definition_name(&name.id, arg_name) was replaced with self.ensure_expr(arg_name, &mut Usage::StaticTypeInformation). This stopped enforcing that the string argument matches the assignment target name.

psycopg (-1)

This is a clear improvement. Pyrefly was enforcing that the string name in functional Enum definitions must match the assignment target variable name. The error at line 351 flags the string literal "ByValue" because the assignment target is enum, and pyrefly expected Expected string literal "enum". However, Python's enum.Enum() functional API does not require the first argument (the enum class name) to match the variable it's assigned to — this is a perfectly valid pattern. Neither mypy nor pyright enforce such a restriction. The code enum = Enum("ByValue", ...) is valid Python that creates an enum class named ByValue and assigns it to a local variable enum. This pattern is especially common in test code where a local variable holds a dynamically-created enum. The PR explicitly fixes this as a known issue (#2874), removing the overly strict name-matching check.
Attribution: The change in pyrefly/lib/binding/class.rs at line 990 removed the call to self.check_functional_definition_name(&name.id, arg_name) for Enum functional definitions. This directly removed the enforcement that the assignment variable name must match the string literal argument in Enum("Name", ...). The same change was made in pyrefly/lib/binding/stmt.rs for NamedTuple functional definitions (lines 609 and 624), replacing check_functional_definition_name with ensure_expr. The test case test_enum_functional_name_mismatch in pyrefly/lib/test/enums.rs confirms this was an intentional fix, and the old test that expected # E: Expected string literal "Color" was removed.

mongo-python-driver (-1)

The PR fixes issue #2874 by no longer enforcing that the string literal argument to namedtuple() or Enum() must match the variable name. In pymongo's ocsp_cache.py, CACHE_KEY_TYPE = namedtuple('OcspResponseCacheKey', ...) is perfectly valid Python — the string names the namedtuple class while the variable is just a binding. Neither mypy nor pyright enforce this alignment. The removed error was a false positive, making this an improvement.
Attribution: The PR removed the check_functional_definition_name call from pyrefly/lib/binding/class.rs (line 990, for collections.namedtuple) and from pyrefly/lib/binding/stmt.rs (lines 609 and 624, for typing.NamedTuple and Enum functional syntax). This directly eliminated the name-alignment enforcement that was producing the false positive invalid-argument error on pymongo's CACHE_KEY_TYPE = namedtuple('OcspResponseCacheKey', ...) pattern.

cloud-init (-3)

The PR fixes issue #2874 by no longer enforcing that the string name in functional namedtuple() and Enum() definitions must match the variable name. All three removed errors were false positives — the code is valid Python and the name mismatch is intentional and common in real-world code (e.g., res = namedtuple('joyent', ...) in test_smartos.py, mocks = namedtuple('Mocks', ...) in test_net_activators.py). Per the typing spec on namedtuples, there is no requirement for name alignment.
Attribution: The PR removed the self.check_functional_definition_name(&name.id, arg_name) call in three places: (1) in pyrefly/lib/binding/class.rs for Enum functional syntax, (2) twice in pyrefly/lib/binding/stmt.rs for both typing.NamedTuple and collections.namedtuple functional syntax. These calls were replaced with self.ensure_expr(arg_name, &mut Usage::StaticTypeInformation) (for the namedtuple cases) or simply removed (for the Enum case). This directly eliminates the invalid-argument errors that were enforcing name alignment between the assignment target and the string literal argument.

pandas (-3)

The PR removes a check that required the first argument to collections.namedtuple() (and similar functional forms) to be a string literal. This check was too strict — Python's collections.namedtuple() accepts any string expression as its first argument, not just string literals. In the pandas code at line 1437, collections.namedtuple(name, fields, rename=True) uses the runtime parameter name (which has type str | None), which is perfectly valid Python but was rejected by pyrefly because it expected a string literal. Similarly, the test files pass variables rather than string literals as the first argument. The removed errors were all false positives where pyrefly incorrectly demanded a string literal where a string-typed variable was used.
Attribution: The PR removed the check_functional_definition_name call in three places:

  1. In pyrefly/lib/binding/class.rs (line 990) — for Enum functional syntax
  2. In pyrefly/lib/binding/stmt.rs (lines 609 and 624) — for both typing.NamedTuple and collections.namedtuple functional syntax
    These calls were replaced with self.ensure_expr(arg_name, &mut Usage::StaticTypeInformation) which processes the argument without enforcing name alignment. This directly fixes the false positive invalid-argument errors on pandas.

discord.py (-1)

The removed error was a false positive. Pyrefly was enforcing that the first argument to namedtuple() must match the variable name (cls), but the code cls = namedtuple('_EnumValue_' + name, 'name value') intentionally uses a dynamically constructed name. Neither the typing spec nor mypy/pyright require this alignment. The PR explicitly fixes this (issue #2874) by removing the check_functional_definition_name call, which is the correct fix.
Attribution: The change in pyrefly/lib/binding/class.rs at line 990 removed the call to self.check_functional_definition_name(&name.id, arg_name) for enum functional definitions. Similarly, changes in pyrefly/lib/binding/stmt.rs at lines 609 and 624 replaced self.check_functional_definition_name(&name.id, arg_name) with self.ensure_expr(arg_name, &mut Usage::StaticTypeInformation) for both typing.NamedTuple and collections.namedtuple functional definitions. This removed the enforcement of name alignment between the assignment target and the first string argument in functional syntax for enums and namedtuples.

spack (-1)

This is a clear improvement. The PR explicitly fixes issue #2874 by no longer enforcing that the string argument to functional namedtuple() or Enum() calls must match the assignment variable name. The removed error was a false positive — MockSuite = collections.namedtuple('TestSuite', ['specs']) is valid Python where the developer intentionally chose different names. Neither mypy nor pyright enforce this alignment requirement, and the typing spec does not mandate it.
Attribution: The change in pyrefly/lib/binding/class.rs removed the call to self.check_functional_definition_name(&name.id, arg_name) for collections.namedtuple functional definitions. Similarly, pyrefly/lib/binding/stmt.rs replaced self.check_functional_definition_name(&name.id, arg_name) with self.ensure_expr(arg_name, &mut Usage::StaticTypeInformation) for both typing.NamedTuple and collections.namedtuple functional syntax. This intentionally removes the name-alignment enforcement, which was the source of the invalid-argument error on line 265.

spark (-1)

This is an improvement. The removed error was a false positive — pyrefly was enforcing an unnecessary constraint that the first string argument to collections.namedtuple() must match the variable name it's assigned to. In this case, the code cls = collections.namedtuple(name, fields) uses a dynamic variable name (not a string literal at all), and cls is just a local variable in a helper function. Neither mypy nor pyright enforce this constraint, and the typing spec does not require it. The PR explicitly fixes this by removing the check_functional_definition_name check for functional NamedTuple and Enum definitions.
Attribution: The PR removed the check_functional_definition_name call from pyrefly/lib/binding/class.rs (line 990) and replaced it with ensure_expr calls in pyrefly/lib/binding/stmt.rs (lines 609 and 624). This change stops pyrefly from enforcing that the string argument to functional NamedTuple/Enum definitions must match the assignment target variable name, which directly removes the false positive invalid-argument error on collections.namedtuple(name, fields) in pyspark's serializers.py.


Was this helpful? React with 👍 or 👎

Classification by primer-classifier (10 LLM)

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.

Do not enforce name alignment for namedtuple and enum functional syntax

2 participants