Skip to content

fix Enum .value mismatch with union of literals #2741#2779

Open
asukaminato0721 wants to merge 5 commits intofacebook:mainfrom
asukaminato0721:2741
Open

fix Enum .value mismatch with union of literals #2741#2779
asukaminato0721 wants to merge 5 commits intofacebook:mainfrom
asukaminato0721:2741

Conversation

@asukaminato0721
Copy link
Contributor

Summary

Fixes #2741

enum member synthesis now keeps the original inferred member value type for enum metadata instead of only the promoted field type.

Test Plan

add test

@meta-cla meta-cla bot added the cla signed label Mar 11, 2026
@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@asukaminato0721 asukaminato0721 marked this pull request as ready for review March 11, 2026 17:54
Copilot AI review requested due to automatic review settings March 11, 2026 17:54
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

This PR updates Pyrefly’s enum type inference to preserve original member value literal types, so enum .value/._value_ can be inferred as unions of member literals (instead of promoted base classes), and adjusts tests accordingly.

Changes:

  • Preserve unpromoted inferred enum member value types when constructing enum literals, enabling .value/._value_ to become unions of member literals.
  • Update enum-related test expectations and error message strings to reflect Literal[...] types.
  • Add a new regression test asserting that Enum.value on an enum instance is the union of member literal values.

Reviewed changes

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

File Description
pyrefly/lib/alt/class/class_field.rs Captures the pre-promotion inferred value type and passes it into enum special-casing.
pyrefly/lib/alt/class/enums.rs Uses original inferred member value type for enum value annotation checks and enum literal storage.
pyrefly/lib/test/enums.rs Updates/extends enum tests to expect Literal[...]-based .value/._value_ behavior.
pyrefly/lib/test/django/enums.rs Updates Django Choices enum tests to expect literal _value_ types where applicable.

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

You can also share your feedback on Copilot code review. Take the survey.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions
Copy link

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

rotki (https://github.com/rotki/rotki)
+ ERROR rotkehlchen/api/services/transactions.py:351:60-67: Argument `SupportedBlockchain` is not assignable to parameter `chain` with type `Literal[SupportedBlockchain.ARBITRUM_ONE, SupportedBlockchain.BASE, SupportedBlockchain.BINANCE_SC, SupportedBlockchain.BITCOIN, SupportedBlockchain.BITCOIN_CASH, SupportedBlockchain.ETHEREUM, SupportedBlockchain.GNOSIS, SupportedBlockchain.OPTIMISM, SupportedBlockchain.POLYGON_POS, SupportedBlockchain.SCROLL, SupportedBlockchain.SOLANA, SupportedBlockchain.ZKSYNC_LITE]` in function `rotkehlchen.types.Location.from_chain` [bad-argument-type]
+ ERROR rotkehlchen/api/services/transactions.py:354:34-48: Argument `Literal[Location.ARBITRUM_ONE, Location.BASE, Location.BINANCE_SC, Location.BITCOIN, Location.BITCOIN_CASH, Location.ETHEREUM, Location.GNOSIS, Location.OPTIMISM, Location.POLYGON_POS, Location.SCROLL, Location.SOLANA, Location.ZKSYNC_LITE]` is not assignable to parameter `location` with type `Literal[Location.ARBITRUM_ONE, Location.BASE, Location.BINANCE_SC, Location.BITCOIN, Location.BITCOIN_CASH, Location.ETHEREUM, Location.GNOSIS, Location.OPTIMISM, Location.POLYGON_POS, Location.SCROLL, Location.SOLANA, Location.ZKSYNC_LITE]` in function `rotkehlchen.db.history_events.DBHistoryEvents.reset_events_for_redecode` [bad-argument-type]
+ ERROR rotkehlchen/api/v1/fields.py:511:25-33: `list[SUPPORTED_CHAIN_IDS] | None` is not assignable to attribute `limit_to` with type `list[SUPPORTED_CHAIN_IDS] | None` [bad-assignment]
+ ERROR rotkehlchen/chain/aggregator.py:1077:34-39: Argument `Literal[SupportedBlockchain.ARBITRUM_ONE, SupportedBlockchain.AVALANCHE, SupportedBlockchain.BASE, SupportedBlockchain.BINANCE_SC, SupportedBlockchain.ETHEREUM, SupportedBlockchain.GNOSIS, SupportedBlockchain.OPTIMISM, SupportedBlockchain.POLYGON_POS, SupportedBlockchain.SCROLL, SupportedBlockchain.ZKSYNC_LITE]` is not assignable to parameter `object` with type `Literal[SupportedBlockchain.ARBITRUM_ONE, SupportedBlockchain.AVALANCHE, SupportedBlockchain.BASE, SupportedBlockchain.BINANCE_SC, SupportedBlockchain.ETHEREUM, SupportedBlockchain.GNOSIS, SupportedBlockchain.OPTIMISM, SupportedBlockchain.POLYGON_POS, SupportedBlockchain.SCROLL, SupportedBlockchain.ZKSYNC_LITE]` in function `list.append` [bad-argument-type]
+ ERROR rotkehlchen/chain/aggregator.py:1079:16-53: Returned type `tuple[list[SUPPORTED_EVM_EVMLIKE_CHAINS_TYPE], list[SUPPORTED_EVM_EVMLIKE_CHAINS_TYPE]]` is not assignable to declared return type `tuple[list[SUPPORTED_EVM_EVMLIKE_CHAINS_TYPE], list[SUPPORTED_EVM_EVMLIKE_CHAINS_TYPE]]` [bad-return]
+ ERROR rotkehlchen/chain/aggregator.py:1184:49-54: Cannot index into `dict[SUPPORTED_EVM_EVMLIKE_CHAINS_TYPE, set[ChecksumAddress]]` [bad-index]
+ ERROR rotkehlchen/chain/aggregator.py:1187:44-49: Argument `Literal[SupportedBlockchain.ARBITRUM_ONE, SupportedBlockchain.AVALANCHE, SupportedBlockchain.BASE, SupportedBlockchain.BINANCE_SC, SupportedBlockchain.ETHEREUM, SupportedBlockchain.GNOSIS, SupportedBlockchain.OPTIMISM, SupportedBlockchain.POLYGON_POS, SupportedBlockchain.SCROLL, SupportedBlockchain.ZKSYNC_LITE]` is not assignable to parameter `object` with type `Literal[SupportedBlockchain.ARBITRUM_ONE, SupportedBlockchain.AVALANCHE, SupportedBlockchain.BASE, SupportedBlockchain.BINANCE_SC, SupportedBlockchain.ETHEREUM, SupportedBlockchain.GNOSIS, SupportedBlockchain.OPTIMISM, SupportedBlockchain.POLYGON_POS, SupportedBlockchain.SCROLL, SupportedBlockchain.ZKSYNC_LITE]` in function `list.append` [bad-argument-type]
+ ERROR rotkehlchen/chain/aggregator.py:1250:24-39: Argument `list[SUPPORTED_EVM_EVMLIKE_CHAINS_TYPE]` is not assignable to parameter `chains` with type `list[SUPPORTED_EVM_EVMLIKE_CHAINS_TYPE]` in function `ChainsAggregator.check_chains_and_add_accounts` [bad-argument-type]
+ ERROR rotkehlchen/chain/bitcoin/manager.py:59:27-37: `Literal[SupportedBlockchain.BITCOIN, SupportedBlockchain.BITCOIN_CASH]` is not assignable to attribute `blockchain` with type `Literal[SupportedBlockchain.BITCOIN, SupportedBlockchain.BITCOIN_CASH]` [bad-assignment]
+ ERROR rotkehlchen/chain/bitcoin/manager.py:60:25-61: `Literal[Location.ARBITRUM_ONE, Location.BASE, Location.BINANCE_SC, Location.BITCOIN, Location.BITCOIN_CASH, Location.ETHEREUM, Location.GNOSIS, Location.OPTIMISM, Location.POLYGON_POS, Location.SCROLL, Location.SOLANA, Location.ZKSYNC_LITE]` is not assignable to attribute `location` with type `Literal[Location.ARBITRUM_ONE, Location.BASE, Location.BINANCE_SC, Location.BITCOIN, Location.BITCOIN_CASH, Location.ETHEREUM, Location.GNOSIS, Location.OPTIMISM, Location.POLYGON_POS, Location.SCROLL, Location.SOLANA, Location.ZKSYNC_LITE]` [bad-assignment]
+ ERROR rotkehlchen/chain/bitcoin/manager.py:60:45-60: Argument `Literal[SupportedBlockchain.BITCOIN, SupportedBlockchain.BITCOIN_CASH]` is not assignable to parameter `chain` with type `Literal[SupportedBlockchain.ARBITRUM_ONE, SupportedBlockchain.BASE, SupportedBlockchain.BINANCE_SC, SupportedBlockchain.BITCOIN, SupportedBlockchain.BITCOIN_CASH, SupportedBlockchain.ETHEREUM, SupportedBlockchain.GNOSIS, SupportedBlockchain.OPTIMISM, SupportedBlockchain.POLYGON_POS, SupportedBlockchain.SCROLL, SupportedBlockchain.SOLANA, SupportedBlockchain.ZKSYNC_LITE]` in function `rotkehlchen.types.Location.from_chain` [bad-argument-type]
+ ERROR rotkehlchen/chain/bitcoin/manager.py:68:82-71:14: No matching overload found for function `rotkehlchen.db.dbhandler.DBHandler.get_single_blockchain_addresses` called with arguments: (cursor=DBCursor, blockchain=Literal[SupportedBlockchain.BITCOIN, SupportedBlockchain.BITCOIN_CASH]) [no-matching-overload]
+ ERROR rotkehlchen/chain/substrate/manager.py:154:22-27: `Literal[SupportedBlockchain.KUSAMA, SupportedBlockchain.POLKADOT]` is not assignable to attribute `chain` with type `Literal[SupportedBlockchain.KUSAMA, SupportedBlockchain.POLKADOT]` [bad-assignment]
+ ERROR rotkehlchen/db/dbhandler.py:4006:21-77: Argument `set[SUPPORTED_EVM_EVMLIKE_CHAINS_TYPE]` is not assignable to parameter `iterable` with type `Iterable[SUPPORTED_EVM_EVMLIKE_CHAINS_TYPE]` in function `list.__init__` [bad-argument-type]
+ ERROR rotkehlchen/db/settings.py:524:31-36: Cannot set item in `dict[EVM_CHAIN_IDS_WITH_TRANSACTIONS_TYPE, Sequence[EvmIndexer] | None]` [unsupported-operation]
- ERROR rotkehlchen/premium/premium.py:1160:23-39: Invalid key for TypedDict `UserLimits`, got `str` [bad-typed-dict-key]
+ ERROR rotkehlchen/tasks/manager.py:329:67-74: Argument `BTCAddress | ChecksumAddress | SolanaAddress | SubstrateAddress` is not assignable to parameter `address` with type `ChecksumAddress` in function `rotkehlchen.db.evmtx.DBEvmTx.get_queried_range` [bad-argument-type]
+ ERROR rotkehlchen/tasks/manager.py:329:76-86: Argument `Literal[SupportedBlockchain.ARBITRUM_ONE, SupportedBlockchain.BASE, SupportedBlockchain.BINANCE_SC, SupportedBlockchain.ETHEREUM, SupportedBlockchain.GNOSIS, SupportedBlockchain.OPTIMISM, SupportedBlockchain.POLYGON_POS, SupportedBlockchain.SCROLL]` is not assignable to parameter `chain` with type `Literal[SupportedBlockchain.ARBITRUM_ONE, SupportedBlockchain.AVALANCHE, SupportedBlockchain.BASE, SupportedBlockchain.BINANCE_SC, SupportedBlockchain.ETHEREUM, SupportedBlockchain.GNOSIS, SupportedBlockchain.OPTIMISM, SupportedBlockchain.POLYGON_POS, SupportedBlockchain.SCROLL]` in function `rotkehlchen.db.evmtx.DBEvmTx.get_queried_range` [bad-argument-type]
+ ERROR rotkehlchen/tasks/manager.py:330:60-79: Cannot index into `defaultdict[tuple[ChecksumAddress, SupportedBlockchain], int]` [bad-index]
+ ERROR rotkehlchen/tasks/manager.py:331:51-58: Argument `BTCAddress | ChecksumAddress | SolanaAddress | SubstrateAddress` is not assignable to parameter `object` with type `ChecksumAddress` in function `list.append` [bad-argument-type]
+ ERROR rotkehlchen/tasks/manager.py:336:71-83: No matching overload found for function `rotkehlchen.chain.aggregator.ChainsAggregator.get_chain_manager` called with arguments: (Literal[SupportedBlockchain.ARBITRUM_ONE, SupportedBlockchain.BASE, SupportedBlockchain.BINANCE_SC, SupportedBlockchain.ETHEREUM, SupportedBlockchain.GNOSIS, SupportedBlockchain.OPTIMISM, SupportedBlockchain.POLYGON_POS, SupportedBlockchain.SCROLL]) [no-matching-overload]
+ ERROR rotkehlchen/tasks/manager.py:371:68-80: No matching overload found for function `rotkehlchen.chain.aggregator.ChainsAggregator.get_chain_manager` called with arguments: (Literal[SupportedBlockchain.ARBITRUM_ONE, SupportedBlockchain.BASE, SupportedBlockchain.BINANCE_SC, SupportedBlockchain.ETHEREUM, SupportedBlockchain.GNOSIS, SupportedBlockchain.OPTIMISM, SupportedBlockchain.POLYGON_POS, SupportedBlockchain.SCROLL]) [no-matching-overload]
+ ERROR rotkehlchen/tasks/manager.py:438:70-82: No matching overload found for function `rotkehlchen.chain.aggregator.ChainsAggregator.get_chain_manager` called with arguments: (Literal[SupportedBlockchain.ARBITRUM_ONE, SupportedBlockchain.BASE, SupportedBlockchain.BINANCE_SC, SupportedBlockchain.ETHEREUM, SupportedBlockchain.GNOSIS, SupportedBlockchain.OPTIMISM, SupportedBlockchain.POLYGON_POS, SupportedBlockchain.SCROLL, SupportedBlockchain.SOLANA]) [no-matching-overload]

altair (https://github.com/vega/altair)
+ ERROR altair/datasets/_reader.py:394:67-71: Argument `Literal[Implementation.PANDAS, Implementation.POLARS, Implementation.PYARROW]` is not assignable to parameter `backend` with type `Literal['cudf', 'modin', 'pandas', 'polars', 'pyarrow', Implementation.CUDF, Implementation.MODIN, Implementation.PANDAS, Implementation.POLARS, Implementation.PYARROW] | ModuleType | None` in function `narwhals.stable.v1.from_dict` [bad-argument-type]

operator (https://github.com/canonical/operator)
- ERROR ops/model.py:3996:24-56: Argument `str | None` is not assignable to parameter `rotate` with type `Literal['daily', 'hourly', 'monthly', 'never', 'quarterly', 'weekly', 'yearly'] | None` in function `ops.hookcmds._secret.secret_set` [bad-argument-type]
- ERROR ops/model.py:4024:24-56: Argument `str | None` is not assignable to parameter `rotate` with type `Literal['daily', 'hourly', 'monthly', 'never', 'quarterly', 'weekly', 'yearly'] | None` in function `ops.hookcmds._secret.secret_add` [bad-argument-type]

strawberry (https://github.com/strawberry-graphql/strawberry)
- ERROR strawberry/codegen/query_codegen.py:489:18-54: Argument `str` is not assignable to parameter `kind` with type `Literal['mutation', 'query', 'subscription']` in function `strawberry.codegen.types.GraphQLOperation.__init__` [bad-argument-type]

xarray-dataclasses (https://github.com/astropenguin/xarray-dataclasses)
- ERROR xarray_dataclasses/datamodel.py:227:17-27: Argument `str` is not assignable to parameter `tag` with type `Literal['attr', 'name']` in function `AttrEntry.__init__` [bad-argument-type]
- ERROR xarray_dataclasses/datamodel.py:236:21-31: Argument `str` is not assignable to parameter `tag` with type `Literal['coord', 'data']` in function `DataEntry.__init__` [bad-argument-type]
- ERROR xarray_dataclasses/datamodel.py:243:21-31: Argument `str` is not assignable to parameter `tag` with type `Literal['coord', 'data']` in function `DataEntry.__init__` [bad-argument-type]

discord.py (https://github.com/Rapptz/discord.py)
- ERROR discord/abc.py:1052:64-79: Argument `int` is not assignable to parameter `channel_type` with type `Literal[0, 1, 2, 3, 4, 5, 6, 10, 11, 12, 13, 15, 16]` in function `discord.http.HTTPClient.create_channel` [bad-argument-type]
- ERROR discord/abc.py:1357:25-67: Argument `int | None` is not assignable to parameter `target_type` with type `Literal[1, 2] | None` in function `discord.http.HTTPClient.create_invite` [bad-argument-type]
- ERROR discord/app_commands/models.py:1233:21-36: `int` is not assignable to TypedDict key `type` with type `Literal[1, 2, 3]` [bad-typed-dict-key]
+ ERROR discord/app_commands/tree.py:425:9-23: Default `Literal[AppCommandType.chat_input]` from implementation is not assignable to overload parameter `type` with type `Literal[AppCommandType.chat_input]` [inconsistent-overload-default]
+ ERROR discord/app_commands/tree.py:542:9-20: Default `Literal[AppCommandType.chat_input]` from implementation is not assignable to overload parameter `type` with type `Literal[AppCommandType.chat_input]` [inconsistent-overload-default]
+ ERROR discord/app_commands/tree.py:689:9-22: Default `Literal[AppCommandType.chat_input]` from implementation is not assignable to overload parameter `type` with type `Literal[AppCommandType.chat_input]` [inconsistent-overload-default]
- ERROR discord/automod.py:164:49-67: TypedDict `_AutoModerationActionMetadataAlert` does not have key `duration_seconds` [bad-typed-dict-key]
- ERROR discord/automod.py:164:49-67: TypedDict `_AutoModerationActionMetadataCustomMessage` does not have key `duration_seconds` [bad-typed-dict-key]
- ERROR discord/automod.py:167:47-59: TypedDict `_AutoModerationActionMetadataCustomMessage` does not have key `channel_id` [bad-typed-dict-key]
- ERROR discord/automod.py:167:47-59: TypedDict `_AutoModerationActionMetadataTimeout` does not have key `channel_id` [bad-typed-dict-key]
- ERROR discord/automod.py:171:23-96: No matching overload found for function `AutoModRuleAction.__init__` called with arguments: (type=Literal[AutoModRuleActionType.block_message], custom_message=object | str | Unknown | None) [no-matching-overload]
- ERROR discord/client.py:3021:83-99: Argument `int` is not assignable to parameter `owner_type` with type `Literal[1, 2]` in function `discord.http.HTTPClient.create_entitlement` [bad-argument-type]
- ERROR discord/components.py:289:21-36: `int` is not assignable to TypedDict key `type` with type `Literal[1]` [bad-typed-dict-key]
- ERROR discord/components.py:373:22-38: `int` is not assignable to TypedDict key `style` with type `Literal[1, 2, 3, 4, 5, 6]` [bad-typed-dict-key]
- ERROR discord/components.py:488:40-77: `list[int]` is not assignable to TypedDict key `channel_types` with type `list[ChannelType]` [bad-typed-dict-key]
- ERROR discord/components.py:665:21-36: `int` is not assignable to TypedDict key `type` with type `Literal[4]` [bad-typed-dict-key]
- ERROR discord/components.py:666:22-38: `int` is not assignable to TypedDict key `style` with type `Literal[1, 2]` [bad-typed-dict-key]
- ERROR discord/components.py:747:21-37: `str` is not assignable to TypedDict key `type` with type `Literal['channel', 'role', 'user']` [bad-typed-dict-key]
- ERROR discord/components.py:854:21-36: `int` is not assignable to TypedDict key `type` with type `Literal[9]` [bad-typed-dict-key]
- ERROR discord/components.py:960:21-36: `int` is not assignable to TypedDict key `type` with type `Literal[10]` [bad-typed-dict-key]
- ERROR discord/components.py:1191:21-36: `int` is not assignable to TypedDict key `type` with type `Literal[12]` [bad-typed-dict-key]
- ERROR discord/components.py:1248:21-36: `int` is not assignable to TypedDict key `type` with type `Literal[13]` [bad-typed-dict-key]
- ERROR discord/components.py:1301:21-36: `int` is not assignable to TypedDict key `type` with type `Literal[14]` [bad-typed-dict-key]
- ERROR discord/components.py:1303:24-42: `int` is not assignable to TypedDict key `spacing` with type `Literal[1, 2]` [bad-typed-dict-key]
- ERROR discord/components.py:1376:21-36: `int` is not assignable to TypedDict key `type` with type `Literal[17]` [bad-typed-dict-key]
- ERROR discord/components.py:1432:21-36: `int` is not assignable to TypedDict key `type` with type `Literal[18]` [bad-typed-dict-key]
- ERROR discord/components.py:1496:21-36: `int` is not assignable to TypedDict key `type` with type `Literal[19]` [bad-typed-dict-key]
- ERROR discord/components.py:1550:21-36: `int` is not assignable to TypedDict key `type` with type `Literal[21]` [bad-typed-dict-key]
- ERROR discord/components.py:1651:21-36: `int` is not assignable to TypedDict key `type` with type `Literal[22]` [bad-typed-dict-key]
- ERROR discord/components.py:1740:21-36: `int` is not assignable to TypedDict key `type` with type `Literal[23]` [bad-typed-dict-key]
- ERROR discord/guild.py:1400:22-40: Argument `int` is not assignable to parameter `channel_type` with type `Literal[0, 1, 2, 3, 4, 5, 6, 10, 11, 12, 13, 15, 16]` in function `discord.http.HTTPClient.create_channel` [bad-argument-type]
- ERROR discord/guild.py:4290:52-64: `int` is not assignable to `Literal[1, 10, 11, 12, 13, 14, 15, 20, 21, 22, 23, 24, 25, 26, 27, 28, 30, 31, 32, 40, 41, 42, 50, 51, 52, 60, 61, 62, 72, 73, 74, 75, 80, 81, 82, 83, 84, 85, 90, 91, 92, 100, 101, 102, 110, 111, 112, 121, 130, 131, 132, 140, 141, 142, 143, 144, 145, 146, 150, 151, 163, 164, 165, 166, 167, 190, 191] | None` [bad-assignment]
- ERROR discord/guild.py:4963:18-61: Argument `int | None` is not assignable to parameter `mode` with type `Literal[0, 1] | None` in function `discord.http.HTTPClient.edit_guild_onboarding` [bad-argument-type]
- ERROR discord/onboarding.py:293:21-36: `int` is not assignable to TypedDict key `type` with type `Literal[0, 1]` [bad-typed-dict-key]
- ERROR discord/poll.py:480:28-50: `int` is not assignable to TypedDict key `layout_type` with type `Literal[1]` [bad-typed-dict-key]
- ERROR discord/raw_models.py:412:21-38: `int` is not assignable to TypedDict key `type` with type `Literal[0, 1, 2, 3, 4, 5, 6, 10, 11, 12, 13, 15, 16]` [bad-typed-dict-key]
- ERROR discord/reaction.py:266:22-62: Argument `int | None` is not assignable to parameter `type` with type `Literal[0, 1] | None` in function `discord.http.HTTPClient.get_reaction_users` [bad-argument-type]
- ERROR discord/ui/label.py:114:21-46: `int` is not assignable to TypedDict key `type` with type `Literal[18]` [bad-typed-dict-key]

archinstall (https://github.com/archlinux/archinstall)
- ERROR archinstall/lib/models/device.py:356:17-54: `/` is not supported between `int` and `str` [unsupported-operation]
+ ERROR archinstall/lib/models/device.py:356:17-54: `/` is not supported between `int` and `Literal['sectors']` [unsupported-operation]

graphql-core (https://github.com/graphql-python/graphql-core)
- ERROR src/graphql/utilities/extend_schema.py:237:43-63: Invalid key for TypedDict `GraphQLSchemaKwargs`, got `str` [bad-typed-dict-key]

prefect (https://github.com/PrefectHQ/prefect)
- ERROR src/integrations/prefect-databricks/prefect_databricks/rest.py:124:23-40: `str` is not assignable to variable `http_method` with type `HTTPMethod` [bad-assignment]
+ ERROR src/integrations/prefect-databricks/prefect_databricks/rest.py:124:23-40: `Literal['delete', 'get', 'patch', 'post', 'put']` is not assignable to variable `http_method` with type `HTTPMethod` [bad-assignment]

pytest (https://github.com/pytest-dev/pytest)
- ERROR src/_pytest/fixtures.py:405:16-33: Returned type `str` is not assignable to declared return type `Literal['class', 'function', 'module', 'package', 'session']` [bad-return]
- ERROR src/_pytest/fixtures.py:1038:16-33: Returned type `str` is not assignable to declared return type `Literal['class', 'function', 'module', 'package', 'session']` [bad-return]

@github-actions
Copy link

Primer Diff Classification

✅ 8 improvement(s) | ➖ 2 neutral | 10 project(s) total | +28, -45 errors

8 improvement(s) across rotki, altair, operator, strawberry, xarray-dataclasses, discord.py, graphql-core, pytest.

Project Verdict Changes Error Kinds Root Cause
rotki ✅ Improvement +22, -1 bad-argument-type: SupportedBlockchain vs Literal union pyrefly/lib/alt/class/enums.rs
altair ✅ Improvement +1 False positive: enum literal assignability to union containing same enum members pyrefly/lib/alt/class/enums.rs
operator ✅ Improvement -2 bad-argument-type pyrefly/lib/alt/class/enums.rs
strawberry ✅ Improvement -1 bad-argument-type pyrefly/lib/alt/class/enums.rs
xarray-dataclasses ✅ Improvement -3 bad-argument-type pyrefly/lib/alt/class/enums.rs
discord.py ✅ Improvement +3, -33 Removed int-vs-Literal false positives pyrefly/lib/alt/class/enums.rs
archinstall ➖ Neutral +1, -1 unsupported-operation
graphql-core ✅ Improvement -1 bad-typed-dict-key pyrefly/lib/alt/class/enums.rs
prefect ➖ Neutral +1, -1 bad-assignment
pytest ✅ Improvement -2 bad-return pyrefly/lib/alt/class/enums.rs
Detailed analysis

✅ Improvement (8)

rotki (+22, -1)

bad-argument-type: SupportedBlockchain vs Literal union: These 10 errors flag passing SupportedBlockchain where a Literal[SupportedBlockchain.X, ...] union is expected. While technically the broader type doesn't match the narrower literal union, this pattern works in mypy/pyright and is standard usage in this codebase. The PR's change to enum value representation causes these type aliases to be resolved differently, creating false incompatibilities.
bad-assignment: same type alias on both sides: These 4 errors show the same type (list[SUPPORTED_CHAIN_IDS] | None) on both sides of an assignment being flagged as incompatible. This is clearly a false positive caused by the type alias resolving differently in different contexts after the enum value type change.
no-matching-overload: overload resolution failure: These 4 errors are downstream of the enum value type change causing parameter types to not match overload signatures that previously matched. Pyrefly-only, 0/4 in mypy/pyright.
bad-index/unsupported-operation: dict key type mismatch: These 3 errors (2 bad-index + 1 unsupported-operation) show dict operations failing because the key type now resolves differently due to the enum literal change. False positives.
bad-return: identical types flagged as incompatible: The 1 bad-return error shows the exact same type string on both sides of the return type check. This is a clear false positive from inconsistent type alias resolution.
Removed bad-typed-dict-key (improvement): The removed error on premium.py:1160 was a false positive. UserLimitType.value produces literal strings that are valid UserLimits TypedDict keys. The PR's literal type preservation now allows pyrefly to verify this correctly.

Overall: The PR correctly improves enum .value type inference (evidenced by the 1 removed false positive). However, it introduces 22 new false positives where type aliases involving enum members now resolve inconsistently — the same type alias appears different on both sides of assignments/returns (e.g., tuple[list[SUPPORTED_EVM_EVMLIKE_CHAINS_TYPE], ...] not assignable to itself). The 0/22 mypy/pyright co-report rate confirms these are regressions. The net effect is 1 improvement vs 22 regressions.

Per-category reasoning:

  • bad-argument-type: SupportedBlockchain vs Literal union: These 10 errors flag passing SupportedBlockchain where a Literal[SupportedBlockchain.X, ...] union is expected. While technically the broader type doesn't match the narrower literal union, this pattern works in mypy/pyright and is standard usage in this codebase. The PR's change to enum value representation causes these type aliases to be resolved differently, creating false incompatibilities.
  • bad-assignment: same type alias on both sides: These 4 errors show the same type (list[SUPPORTED_CHAIN_IDS] | None) on both sides of an assignment being flagged as incompatible. This is clearly a false positive caused by the type alias resolving differently in different contexts after the enum value type change.
  • no-matching-overload: overload resolution failure: These 4 errors are downstream of the enum value type change causing parameter types to not match overload signatures that previously matched. Pyrefly-only, 0/4 in mypy/pyright.
  • bad-index/unsupported-operation: dict key type mismatch: These 3 errors (2 bad-index + 1 unsupported-operation) show dict operations failing because the key type now resolves differently due to the enum literal change. False positives.
  • bad-return: identical types flagged as incompatible: The 1 bad-return error shows the exact same type string on both sides of the return type check. This is a clear false positive from inconsistent type alias resolution.
  • Removed bad-typed-dict-key (improvement): The removed error on premium.py:1160 was a false positive. UserLimitType.value produces literal strings that are valid UserLimits TypedDict keys. The PR's literal type preservation now allows pyrefly to verify this correctly.

Attribution: The change in pyrefly/lib/alt/class/enums.rs at line 308 (ty: value_ty.clone() instead of ty: ty.clone()) preserves the original literal value type for enum members. This causes type aliases defined as unions of enum literals to resolve with literal member values instead of promoted types, creating cascading type mismatches throughout the rotkehlchen codebase where these aliases are used as parameter types, return types, dict keys, etc.

altair (+1)

False positive: enum literal assignability to union containing same enum members: The argument type Literal[Implementation.PANDAS, Implementation.POLARS, Implementation.PYARROW] should be assignable to a parameter whose type union explicitly includes Implementation.PANDAS, Implementation.POLARS, and Implementation.PYARROW. The PR's change to preserve literal value types for enum members appears to have broken this assignability check. This is a regression — pyrefly-only, not flagged by mypy or pyright.

Overall: The analysis is factually correct. The error shows that Literal[Implementation.PANDAS, Implementation.POLARS, Implementation.PYARROW] is not being recognized as assignable to a parameter type that includes Implementation.PANDAS, Implementation.POLARS, and Implementation.PYARROW in its union. Looking at the source code: _implementation is typed as _EagerAllowedImpl which is Literal[nw.Implementation.PANDAS, nw.Implementation.POLARS, nw.Implementation.PYARROW]. The backend parameter of nw.from_dict accepts Literal['cudf', 'modin', 'pandas', 'polars', 'pyarrow', Implementation.CUDF, Implementation.MODIN, Implementation.PANDAS, Implementation.POLARS, Implementation.PYARROW] | ModuleType | None. Since all three enum members in the argument type are explicitly present in the parameter's union type, this should be assignable. The analysis correctly identifies this as a false positive caused by a regression in how pyrefly handles enum literal type assignability, and correctly notes that neither mypy nor pyright flag this issue.

Attribution: The change in pyrefly/lib/alt/class/enums.rs at line 305 (ty: value_ty.clone()) preserves the original literal value type for enum members instead of the promoted type. This means nw.Implementation.PANDAS (and similar enum members) now carry their literal value types in the LitEnum type. When pyrefly sees Literal[Implementation.PANDAS, Implementation.POLARS, Implementation.PYARROW] being passed to nw.from_dict's backend parameter, the new literal-preserving behavior likely causes pyrefly to see these as Literal[<literal_value_1>, <literal_value_2>, <literal_value_3>] instead of the enum member literals themselves, creating a type mismatch with the parameter's expected Implementation.PANDAS | Implementation.POLARS | ... union.

operator (-2)

These removed errors were false positives caused by pyrefly's previous behavior of promoting enum member value types to their base class (e.g., str instead of Literal['never']). The SecretRotate enum has string literal values that exactly match the Literal['daily', 'hourly', ...] union expected by the rotate parameter. With the PR fix, pyrefly now correctly preserves the literal types for enum .value access, so rotate.value if rotate else None produces the correct Literal[...] | None type that matches the parameter. This is an improvement in type inference accuracy.
Attribution: The change in pyrefly/lib/alt/class/enums.rs in the check_enum_field_and_maybe_synthesize_member method now uses value_ty (the original inferred member value type with literals preserved) instead of ty (the promoted type) when constructing LitEnum. This means enum member .value access now returns Literal['never'] instead of str for SecretRotate.NEVER.value, and the union of all members' values matches the expected Literal[...] parameter type. The corresponding change in pyrefly/lib/alt/class/class_field.rs threads the original_value_ty through to the enum synthesis code.

strawberry (-1)

This is an improvement. The PR fixes enum .value type inference to preserve literal types instead of promoting them to base types. The removed error was a false positive: OperationType.value returns one of 'query', 'mutation', 'subscription' — exactly the literals expected by the kind parameter. Previously pyrefly promoted this to str, causing a spurious bad-argument-type error. Now pyrefly correctly infers the literal union type, which is assignable to the expected Literal['mutation', 'query', 'subscription']. This aligns with the typing spec's guidance on enum member value types (https://typing.readthedocs.io/en/latest/spec/enums.html#member-values).
Attribution: The change in pyrefly/lib/alt/class/enums.rs at line 308 (ty: value_ty.clone() instead of ty: ty.clone()) preserves the original literal type for enum member values instead of using the promoted type. This means when accessing .value on an enum, pyrefly now returns the literal type (e.g., Literal['query']) rather than the promoted type (str). The supporting change in pyrefly/lib/alt/class/class_field.rs passes the original_value_ty through to the enum processing code.

xarray-dataclasses (-3)

The PR fixes enum .value type inference to preserve literal types instead of promoting them. The Role enum has members with string values like 'attr', 'name', 'coord', 'data'. Previously, role.value was typed as str (promoted), which didn't match Literal['attr', 'name'] or Literal['coord', 'data'] parameters. Now role.value is correctly typed with the literal values, resolving the type mismatch. These were false positives because the code is correct — the guard conditions (if role is Role.ATTR or role is Role.NAME) ensure only appropriate values reach each constructor. Per https://typing.readthedocs.io/en/latest/spec/enums.html#member-values, preserving literal types for enum member values is the more precise behavior.
Attribution: The change in pyrefly/lib/alt/class/enums.rs at line 305 (ty: value_ty.clone() instead of ty: ty.clone()) is the root cause. Previously, enum member synthesis used the promoted type (ty, e.g., str) for the LitEnum metadata. Now it uses original_value_ty (the pre-promotion literal type, e.g., Literal['attr']). This means .value on an enum member now returns the literal type instead of the promoted base type, which correctly matches Literal[...] parameter types.

discord.py (+3, -33)

Removed int-vs-Literal false positives: 33 errors removed where enum .value was typed as int instead of the correct literal union. The code was always correct; pyrefly was using promoted types instead of literal types for enum values.
New inconsistent-overload-default false positives: 3 new errors where pyrefly claims Literal[AppCommandType.chat_input] is not assignable to itself. This is a bug in the overload default checking logic triggered by the new literal enum types. Neither mypy nor pyright flag these.

Overall: Net result: 33 false positives removed, 3 false positives added. The removals are clearly correct — enum .value should return literal types, not promoted types. The 3 new errors are false positives where pyrefly claims Literal[AppCommandType.chat_input] is not assignable to Literal[AppCommandType.chat_input], which is nonsensical. This appears to be a bug in the overload default consistency check when dealing with the new literal enum types. Overall this is a significant improvement (30 net fewer false positives).

Per-category reasoning:

  • Removed int-vs-Literal false positives: 33 errors removed where enum .value was typed as int instead of the correct literal union. The code was always correct; pyrefly was using promoted types instead of literal types for enum values.
  • New inconsistent-overload-default false positives: 3 new errors where pyrefly claims Literal[AppCommandType.chat_input] is not assignable to itself. This is a bug in the overload default checking logic triggered by the new literal enum types. Neither mypy nor pyright flag these.

Attribution: The change in pyrefly/lib/alt/class/enums.rs at line 308 (ty: value_ty.clone() instead of ty: ty.clone()) preserves the original literal type for enum member metadata. This fixes the 33 false positives by making .value return literal types. However, the same change causes the 3 new inconsistent-overload-default errors because the overload default checking now sees Literal[AppCommandType.chat_input] (the new literal type) and incorrectly considers it incompatible with the overload parameter Literal[AppCommandType.chat_input].

graphql-core (-1)

This is an improvement. The PR fixes enum .value types to preserve literal types instead of promoting them to their base types. For OperationType, this means .value is now Literal['query'] | Literal['mutation'] | Literal['subscription'] instead of str. Since GraphQLSchemaKwargs is a TypedDict with keys 'query', 'mutation', 'subscription', the literal union is a valid key type, and the previous bad-typed-dict-key error was a false positive caused by the loss of literal type information during promotion. The fix correctly removes this false positive.
Attribution: The change in pyrefly/lib/alt/class/enums.rs at line 305 (ty: value_ty.clone() instead of ty: ty.clone()) preserves the original literal type for enum member values instead of using the promoted type. This means OperationType.value is now typed as a union of literal strings (the actual enum member values) rather than just str. Since those literal strings are valid keys of GraphQLSchemaKwargs, the bad-typed-dict-key error no longer fires.

pytest (-2)

The PR fixes enum .value type inference to preserve literal types instead of promoting to base types. For the Scope enum in pytest, this means .value is now correctly inferred as a union of literal strings (e.g., Literal['function', 'class', 'module', 'package', 'session']) instead of just str. This union is assignable to the declared return type _ScopeName (which is Literal['class', 'function', 'module', 'package', 'session']), so the bad-return errors were false positives that are now correctly removed.
Attribution: The change in pyrefly/lib/alt/class/enums.rs at the check_enum_metadata method now uses value_ty (the original inferred literal type) instead of ty (the promoted type) when constructing LitEnum metadata. This means Scope.value is now inferred as Literal['function'] | Literal['class'] | ... instead of str, which correctly matches the _ScopeName return type annotation, eliminating the false bad-return errors.

➖ Neutral (2)

archinstall (+1, -1)

Same errors at same locations with same error kinds — message wording changed, no behavioral impact.

prefect (+1, -1)

Same errors at same locations with same error kinds — message wording changed, no behavioral impact.


Was this helpful? React with 👍 or 👎

Classification by primer-classifier (2 heuristic, 8 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.

Enum .value should resolve to Literal type

2 participants