Skip to content

fix option to treat ALL_CAPS variables as Final #3678#3693

Open
asukaminato0721 wants to merge 2 commits into
facebook:mainfrom
asukaminato0721:3678
Open

fix option to treat ALL_CAPS variables as Final #3678#3693
asukaminato0721 wants to merge 2 commits into
facebook:mainfrom
asukaminato0721:3678

Conversation

@asukaminato0721

@asukaminato0721 asukaminato0721 commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #3678

Added treat-all-caps-as-final / --treat-all-caps-as-final, wired it through config and state, and added the bind-time reassignment check.

Test Plan

add test

@meta-cla meta-cla Bot added the cla signed label Jun 5, 2026
@github-actions github-actions Bot added the size/m label Jun 5, 2026
@asukaminato0721 asukaminato0721 changed the title fix fix option to treat ALL_CAPS variables as Final #3678 Jun 5, 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 June 5, 2026 04:55
@yangdanny97

Copy link
Copy Markdown
Contributor

This change seems reasonable; I'd be curious to see how many errors mypy primer reports if this is on-by-default.

It might help us catch more edge cases that we wouldn't see from unit tests

@github-actions github-actions Bot added size/m and removed size/m labels Jun 9, 2026
@github-actions

github-actions Bot commented Jun 9, 2026

Copy link
Copy Markdown

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

pip (https://github.com/pypa/pip)
+ ERROR src/pip/_internal/utils/entrypoints.py:18:5-22: Cannot assign to variable `_EXECUTABLE_NAMES` because it is marked final [bad-assignment]
+ ERROR src/pip/_internal/utils/unpacking.py:32:5-25: Cannot assign to variable `SUPPORTED_EXTENSIONS` because it is marked final [bad-assignment]
+ ERROR src/pip/_internal/utils/unpacking.py:40:5-25: Cannot assign to variable `SUPPORTED_EXTENSIONS` because it is marked final [bad-assignment]
+ ERROR src/pip/_vendor/rich/panel.py:305:30-37: Cannot assign to variable `ROUNDED` because it is marked final [bad-assignment]
+ ERROR src/pip/_vendor/urllib3/util/request.py:32:5-20: Cannot assign to variable `ACCEPT_ENCODING` because it is marked final [bad-assignment]
+ ERROR src/pip/_vendor/urllib3/util/ssl_.py:59:9-36: Cannot assign to variable `HAS_NEVER_CHECK_COMMON_NAME` because it is marked final [bad-assignment]
+ ERROR src/pip/_vendor/urllib3/util/ssl_.py:80:9-36: Cannot assign to variable `HAS_NEVER_CHECK_COMMON_NAME` because it is marked final [bad-assignment]

openlibrary (https://github.com/internetarchive/openlibrary)
+ ERROR openlibrary/accounts/__init__.py:11:20-21: Cannot assign to variable `TYPE_CHECKING` because it is marked final [bad-assignment]

aioredis (https://github.com/aio-libs/aioredis)
+ ERROR aioredis/connection.py:75:9-26: Cannot assign to variable `HIREDIS_AVAILABLE` because it is marked final [bad-assignment]

cloud-init (https://github.com/canonical/cloud-init)
+ ERROR cloudinit/sources/DataSourceAzure.py:283:5-15: Cannot assign to variable `DEFAULT_FS` because it is marked final [bad-assignment]
+ ERROR cloudinit/sources/DataSourceAzure.py:287:9-27: Cannot assign to variable `RESOURCE_DISK_PATH` because it is marked final [bad-assignment]
+ ERROR cloudinit/sources/DataSourceAzure.py:291:5-28: Cannot assign to variable `PLATFORM_ENTROPY_SOURCE` because it is marked final [bad-assignment]
+ ERROR cloudinit/sources/DataSourceOpenStack.py:36:1-21: Cannot assign to variable `VALID_DMI_ASSET_TAGS` because it is marked final [bad-assignment]
+ ERROR cloudinit/sources/helpers/cloudsigma.py:31:5-16: Cannot assign to variable `SERIAL_PORT` because it is marked final [bad-assignment]
+ ERROR tests/unittests/config/test_apt_source_v3.py:1454:1-29: Cannot assign to variable `DEB822_DISABLED_SINGLE_SUITE` because it is marked final [bad-assignment]
+ ERROR tests/unittests/distros/test_hostname.py:10:1-14: Cannot assign to variable `BASE_HOSTNAME` because it is marked final [bad-assignment]
+ ERROR tests/unittests/distros/test_hosts.py:13:1-9: Cannot assign to variable `BASE_ETC` because it is marked final [bad-assignment]
+ ERROR tests/unittests/distros/test_resolv.py:15:1-13: Cannot assign to variable `BASE_RESOLVE` because it is marked final [bad-assignment]

egglog-python (https://github.com/egraphs-good/egglog-python)
+ ERROR python/egglog/examples/matrix.py:143:1-2: Cannot assign to variable `A` because it is marked final [bad-assignment]
+ ERROR python/egglog/examples/matrix.py:144:1-2: Cannot assign to variable `B` because it is marked final [bad-assignment]
+ ERROR python/egglog/examples/matrix.py:145:1-2: Cannot assign to variable `C` because it is marked final [bad-assignment]

rotki (https://github.com/rotki/rotki)
+ ERROR rotkehlchen/tests/conftest.py:64:40-41: Cannot assign to variable `TYPE_CHECKING` because it is marked final [bad-assignment]
+ ERROR rotkehlchen/tests/fixtures/__init__.py:5:43-44: Cannot assign to variable `USERSDIR_NAME` because it is marked final [bad-assignment]
+ ERROR rotkehlchen/tests/fixtures/__init__.py:12:48-49: Cannot assign to variable `TYPE_CHECKING` because it is marked final [bad-assignment]
+ ERROR rotkehlchen/tests/fixtures/__init__.py:17:52-53: Cannot assign to variable `TYPE_CHECKING` because it is marked final [bad-assignment]
+ ERROR rotkehlchen/tests/fixtures/__init__.py:19:49-50: Cannot assign to variable `TYPE_CHECKING` because it is marked final [bad-assignment]
+ ERROR rotkehlchen/tests/utils/ethereum.py:153:5-29: Cannot assign to variable `ETHEREUM_TEST_PARAMETERS` because it is marked final [bad-assignment]
+ ERROR rotkehlchen/tests/utils/ethereum.py:159:5-29: Cannot assign to variable `ETHEREUM_TEST_PARAMETERS` because it is marked final [bad-assignment]

steam.py (https://github.com/Gobot1234/steam.py)
+ ERROR steam/__init__.py:45:24-25: Cannot assign to variable `TYPE_CHECKING` because it is marked final [bad-assignment]
+ ERROR steam/__init__.py:45:24-25: Cannot assign to variable `ID` because it is marked final [bad-assignment]

pytest (https://github.com/pytest-dev/pytest)
+ ERROR src/_pytest/_code/code.py:1590:5-16: Cannot assign to variable `_PLUGGY_DIR` because it is marked final [bad-assignment]

jax (https://github.com/google/jax)
+ ERROR jax/_src/pallas/mosaic_gpu/interpret/gpu_callbacks.py:42:1-24: Cannot assign to variable `IDX_BY_GPU_MEMORY_SPACE` because it is marked final [bad-assignment]
+ ERROR jax/_src/pallas/mosaic_gpu/interpret/gpu_callbacks.py:48:1-24: Cannot assign to variable `GPU_MEMORY_SPACE_BY_IDX` because it is marked final [bad-assignment]
+ ERROR jax/experimental/mosaic/gpu/core.py:94:3-15: Cannot assign to variable `RUNTIME_PATH` because it is marked final [bad-assignment]

cwltool (https://github.com/common-workflow-language/cwltool)
+ ERROR setup.py:63:5-14: Cannot assign to variable `USE_MYPYC` because it is marked final [bad-assignment]
+ ERROR setup.py:65:5-14: Cannot assign to variable `USE_MYPYC` because it is marked final [bad-assignment]

DateType (https://github.com/glyph/DateType)
+ ERROR src/datetype/test/test_datetype.py:20:5-14: Cannot assign to variable `TEST_DATA` because it is marked final [bad-assignment]
+ ERROR src/datetype/test/test_datetype.py:21:1-10: Cannot assign to variable `TEST_DATA` because it is marked final [bad-assignment]

prefect (https://github.com/PrefectHQ/prefect)
+ ERROR src/integrations/prefect-aws/prefect_aws/workers/ecs_worker.py:97:22-26: Cannot assign to variable `UUID` because it is marked final [bad-assignment]

scipy (https://github.com/scipy/scipy)
+ ERROR scipy/_lib/_testutils.py:46:5-12: Cannot assign to variable `IS_MUSL` because it is marked final [bad-assignment]
+ ERROR scipy/optimize/_tstutils.py:967:1-20: Cannot assign to variable `_CHANDRUPATLA_TESTS` because it is marked final [bad-assignment]

colour (https://github.com/colour-science/colour)
+ ERROR colour/constants/cie.py:31:5-17: Cannot assign to variable `CONSTANT_K_M` because it is marked final [bad-assignment]
+ ERROR colour/constants/cie.py:48:5-18: Cannot assign to variable `CONSTANT_KP_M` because it is marked final [bad-assignment]
+ ERROR colour/constants/codata.py:27:5-22: Cannot assign to variable `CONSTANT_AVOGADRO` because it is marked final [bad-assignment]
+ ERROR colour/constants/codata.py:34:5-23: Cannot assign to variable `CONSTANT_BOLTZMANN` because it is marked final [bad-assignment]
+ ERROR colour/constants/codata.py:41:5-25: Cannot assign to variable `CONSTANT_LIGHT_SPEED` because it is marked final [bad-assignment]
+ ERROR colour/constants/codata.py:48:5-20: Cannot assign to variable `CONSTANT_PLANCK` because it is marked final [bad-assignment]
+ ERROR colour/constants/common.py:43:5-22: Cannot assign to variable `THRESHOLD_INTEGER` because it is marked final [bad-assignment]
+ ERROR colour/corresponding/datasets/breneman1987.py:1434:5-49: Cannot assign to variable `BRENEMAN_EXPERIMENT_PRIMARIES_CHROMATICITIES` because it is marked final [bad-assignment]
+ ERROR colour/corresponding/datasets/breneman1987.py:1462:5-25: Cannot assign to variable `BRENEMAN_EXPERIMENTS` because it is marked final [bad-assignment]
+ ERROR colour/difference/delta_e.py:98:5-16: Cannot assign to variable `JND_CIE1976` because it is marked final [bad-assignment]
+ ERROR colour/examples/colorimetry/examples_luminance.py:32:1-2: Cannot assign to variable `L` because it is marked final [bad-assignment]
+ ERROR colour/examples/colorimetry/examples_luminance.py:42:1-2: Cannot assign to variable `L` because it is marked final [bad-assignment]
+ ERROR colour/examples/colorimetry/examples_whiteness.py:72:1-2: Cannot assign to variable `Y` because it is marked final [bad-assignment]
+ ERROR colour/examples/examples_colour.py:112:1-4: Cannot assign to variable `XYZ` because it is marked final [bad-assignment]
+ ERROR colour/examples/examples_colour.py:119:1-4: Cannot assign to variable `XYZ` because it is marked final [bad-assignment]
+ ERROR colour/examples/examples_colour.py:126:1-4: Cannot assign to variable `XYZ` because it is marked final [bad-assignment]
+ ERROR colour/examples/examples_colour.py:177:1-6: Cannot assign to variable `XYZ_1` because it is marked final [bad-assignment]
+ ERROR colour/examples/examples_colour.py:213:1-6: Cannot assign to variable `XYZ_1` because it is marked final [bad-assignment]
+ ERROR colour/examples/examples_colour.py:250:1-6: Cannot assign to variable `XYZ_1` because it is marked final [bad-assignment]
+ ERROR colour/examples/io/examples_luts.py:89:1-4: Cannot assign to variable `LUT` because it is marked final [bad-assignment]
+ ERROR colour/examples/io/examples_luts.py:96:1-4: Cannot assign to variable `LUT` because it is marked final [bad-assignment]
+ ERROR colour/examples/io/examples_luts.py:101:1-4: Cannot assign to variable `LUT` because it is marked final [bad-assignment]
+ ERROR colour/examples/models/examples_models.py:240:1-4: Cannot assign to variable `XYZ` because it is marked final [bad-assignment]
+ ERROR colour/examples/models/examples_models.py:275:1-4: Cannot assign to variable `XYZ` because it is marked final [bad-assignment]
+ ERROR colour/examples/models/examples_models.py:331:1-4: Cannot assign to variable `IPT` because it is marked final [bad-assignment]
+ ERROR colour/examples/models/examples_models.py:427:1-4: Cannot assign to variable `XYZ` because it is marked final [bad-assignment]
+ ERROR colour/examples/models/examples_models.py:447:1-4: Cannot assign to variable `XYZ` because it is marked final [bad-assignment]
+ ERROR colour/examples/models/examples_models.py:467:1-4: Cannot assign to variable `XYZ` because it is marked final [bad-assignment]
+ ERROR colour/examples/models/examples_transfer_functions.py:40:1-2: Cannot assign to variable `N` because it is marked final [bad-assignment]
+ ERROR colour/examples/models/examples_transfer_functions.py:53:1-2: Cannot assign to variable `N` because it is marked final [bad-assignment]
+ ERROR colour/examples/models/examples_transfer_functions.py:68:1-2: Cannot assign to variable `N` because it is marked final [bad-assignment]
+ ERROR colour/examples/models/examples_ycbcr.py:46:1-4: Cannot assign to variable `RGB` because it is marked final [bad-assignment]
+ ERROR colour/examples/recovery/examples_otsu2018.py:32:1-4: Cannot assign to variable `XYZ` because it is marked final [bad-assignment]
+ ERROR colour/examples/temperature/examples_cct.py:99:1-4: Cannot assign to variable `CCT` because it is marked final [bad-assignment]
+ ERROR colour/models/common.py:107:5-23: Cannot assign to variable `COLOURSPACE_MODELS` because it is marked final [bad-assignment]
+ ERROR colour/models/hdr_cie_lab.py:78:5-23: Cannot assign to variable `HDR_CIELAB_METHODS` because it is marked final [bad-assignment]
+ ERROR colour/models/hdr_ipt.py:81:5-20: Cannot assign to variable `HDR_IPT_METHODS` because it is marked final [bad-assignment]
+ ERROR colour/models/jzazbz.py:158:5-19: Cannot assign to variable `IZAZBZ_METHODS` because it is marked final [bad-assignment]
+ ERROR colour/models/rgb/itut_h_273.py:327:5-30: Cannot assign to variable `COLOUR_PRIMARIES_ITUTH273` because it is marked final [bad-assignment]
+ ERROR colour/models/rgb/itut_h_273.py:490:5-38: Cannot assign to variable `TRANSFER_CHARACTERISTICS_ITUTH273` because it is marked final [bad-assignment]
+ ERROR colour/models/rgb/itut_h_273.py:647:5-33: Cannot assign to variable `MATRIX_COEFFICIENTS_ITUTH273` because it is marked final [bad-assignment]
+ ERROR colour/models/rgb/itut_h_273.py:740:5-29: Cannot assign to variable `CCS_WHITEPOINTS_ITUTH273` because it is marked final [bad-assignment]
+ ERROR colour/models/rgb/itut_h_273.py:782:5-30: Cannot assign to variable `WHITEPOINT_NAMES_ITUTH273` because it is marked final [bad-assignment]
+ ERROR colour/models/rgb/itut_h_273.py:815:5-33: Cannot assign to variable `MATRICES_ITUTH273_RGB_TO_XYZ` because it is marked final [bad-assignment]
+ ERROR colour/models/rgb/itut_h_273.py:848:5-33: Cannot assign to variable `MATRICES_XYZ_TO_ITUTH273_RGB` because it is marked final [bad-assignment]
+ ERROR colour/quality/cqs.py:199:5-33: Cannot assign to variable `COLOUR_QUALITY_SCALE_METHODS` because it is marked final [bad-assignment]
+ ERROR colour/quality/cri.py:151:5-35: Cannot assign to variable `COLOUR_RENDERING_INDEX_METHODS` because it is marked final [bad-assignment]

urllib3 (https://github.com/urllib3/urllib3)
+ ERROR test/__init__.py:77:5-17: Cannot assign to variable `LONG_TIMEOUT` because it is marked final [bad-assignment]
+ ERROR src/urllib3/util/request.py:31:5-20: Cannot assign to variable `ACCEPT_ENCODING` because it is marked final [bad-assignment]
+ ERROR src/urllib3/util/request.py:41:5-20: Cannot assign to variable `ACCEPT_ENCODING` because it is marked final [bad-assignment]
+ ERROR src/urllib3/util/ssl_.py:59:9-36: Cannot assign to variable `HAS_NEVER_CHECK_COMMON_NAME` because it is marked final [bad-assignment]
+ ERROR src/urllib3/util/ssl_.py:80:9-36: Cannot assign to variable `HAS_NEVER_CHECK_COMMON_NAME` because it is marked final [bad-assignment]

scikit-learn (https://github.com/scikit-learn/scikit-learn)
+ ERROR sklearn/_loss/tests/test_loss.py:56:1-15: Cannot assign to variable `LOSS_INSTANCES` because it is marked final [bad-assignment]
+ ERROR sklearn/cluster/tests/test_hdbscan.py:28:1-2: Cannot assign to variable `X` because it is marked final [bad-assignment]
+ ERROR sklearn/cluster/tests/test_hdbscan.py:29:1-2: Cannot assign to variable `X` because it is marked final [bad-assignment]
+ ERROR sklearn/datasets/_covtype.py:61:1-14: Cannot assign to variable `FEATURE_NAMES` because it is marked final [bad-assignment]
+ ERROR sklearn/datasets/_covtype.py:62:1-14: Cannot assign to variable `FEATURE_NAMES` because it is marked final [bad-assignment]
+ ERROR sklearn/ensemble/_gb.py:64:1-8: Cannot assign to variable `_LOSSES` because it is marked final [bad-assignment]
+ ERROR sklearn/ensemble/_hist_gradient_boosting/gradient_boosting.py:58:1-8: Cannot assign to variable `_LOSSES` because it is marked final [bad-assignment]
+ ERROR sklearn/linear_model/tests/test_omp.py:32:4-5: Cannot assign to variable `X` because it is marked final [bad-assignment]
+ ERROR sklearn/linear_model/tests/test_omp.py:34:1-2: Cannot assign to variable `X` because it is marked final [bad-assignment]
+ ERROR sklearn/linear_model/tests/test_ransac.py:28:1-2: Cannot assign to variable `X` because it is marked final [bad-assignment]
+ ERROR sklearn/metrics/pairwise.py:687:5-19: Cannot assign to variable `_VALID_METRICS` because it is marked final [bad-assignment]
+ ERROR sklearn/metrics/pairwise.py:690:5-19: Cannot assign to variable `_VALID_METRICS` because it is marked final [bad-assignment]
+ ERROR sklearn/metrics/pairwise.py:693:5-19: Cannot assign to variable `_VALID_METRICS` because it is marked final [bad-assignment]
+ ERROR sklearn/metrics/pairwise.py:2502:5-31: Cannot assign to variable `PAIRWISE_BOOLEAN_FUNCTIONS` because it is marked final [bad-assignment]
+ ERROR sklearn/metrics/pairwise.py:2505:5-31: Cannot assign to variable `PAIRWISE_BOOLEAN_FUNCTIONS` because it is marked final [bad-assignment]
+ ERROR sklearn/metrics/pairwise.py:2508:5-31: Cannot assign to variable `PAIRWISE_BOOLEAN_FUNCTIONS` because it is marked final [bad-assignment]
+ ERROR sklearn/neighbors/_base.py:51:5-18: Cannot assign to variable `SCIPY_METRICS` because it is marked final [bad-assignment]
+ ERROR sklearn/neighbors/_base.py:54:5-18: Cannot assign to variable `SCIPY_METRICS` because it is marked final [bad-assignment]
+ ERROR sklearn/neighbors/_base.py:57:5-18: Cannot assign to variable `SCIPY_METRICS` because it is marked final [bad-assignment]
+ ERROR sklearn/tests/test_kernel_approximation.py:42:1-2: Cannot assign to variable `X` because it is marked final [bad-assignment]
+ ERROR sklearn/tests/test_kernel_approximation.py:43:1-2: Cannot assign to variable `Y` because it is marked final [bad-assignment]
+ ERROR sklearn/utils/tests/test_response.py:23:1-2: Cannot assign to variable `X` because it is marked final [bad-assignment]

materialize (https://github.com/MaterializeInc/materialize)
+ ERROR test/data-ingest/mzcompose.py:24:46-55: Cannot assign to variable `WORKLOADS` because it is marked final [bad-assignment]

setuptools (https://github.com/pypa/setuptools)
+ ERROR setuptools/_vendor/jaraco/functools/__init__.py:677:1-3: Cannot assign to variable `_T` because it is marked final [bad-assignment]

scikit-build-core (https://github.com/scikit-build/scikit-build-core)
+ ERROR noxfile.py:214:1-9: Cannot assign to variable `EXAMPLES` because it is marked final [bad-assignment]
+ ERROR noxfile.py:215:1-9: Cannot assign to variable `EXAMPLES` because it is marked final [bad-assignment]

yarl (https://github.com/aio-libs/yarl)
+ ERROR yarl/_quoting.py:10:5-18: Cannot assign to variable `NO_EXTENSIONS` because it is marked final [bad-assignment]

apprise (https://github.com/caronc/apprise)
+ ERROR apprise/cli.py:173:5-25: Cannot assign to variable `DEFAULT_CONFIG_PATHS` because it is marked final [bad-assignment]
+ ERROR apprise/cli.py:203:5-25: Cannot assign to variable `DEFAULT_PLUGIN_PATHS` because it is marked final [bad-assignment]
+ ERROR apprise/cli.py:220:5-25: Cannot assign to variable `DEFAULT_STORAGE_PATH` because it is marked final [bad-assignment]
+ ERROR apprise/cli.py:245:5-25: Cannot assign to variable `DEFAULT_STORAGE_PATH` because it is marked final [bad-assignment]
+ ERROR apprise/locale.py:46:5-19: Cannot assign to variable `GETTEXT_LOADED` because it is marked final [bad-assignment]
+ ERROR apprise/plugins/blink1.py:45:5-26: Cannot assign to variable `NOTIFY_BLINK1_ENABLED` because it is marked final [bad-assignment]
+ ERROR apprise/plugins/dbus.py:58:9-18: Cannot assign to variable `LOOP_GLIB` because it is marked final [bad-assignment]
+ ERROR apprise/plugins/dbus.py:68:9-16: Cannot assign to variable `LOOP_QT` because it is marked final [bad-assignment]
+ ERROR apprise/plugins/dbus.py:75:5-32: Cannot assign to variable `NOTIFY_DBUS_SUPPORT_ENABLED` because it is marked final [bad-assignment]
+ ERROR apprise/plugins/dbus.py:91:9-34: Cannot assign to variable `NOTIFY_DBUS_IMAGE_SUPPORT` because it is marked final [bad-assignment]
+ ERROR apprise/plugins/fcm/__init__.py:71:5-31: Cannot assign to variable `NOTIFY_FCM_SUPPORT_ENABLED` because it is marked final [bad-assignment]
+ ERROR apprise/plugins/glib.py:51:5-32: Cannot assign to variable `NOTIFY_GLIB_SUPPORT_ENABLED` because it is marked final [bad-assignment]
+ ERROR apprise/plugins/glib.py:65:9-34: Cannot assign to variable `NOTIFY_GLIB_IMAGE_SUPPORT` because it is marked final [bad-assignment]
+ ERROR apprise/plugins/gnome.py:48:5-33: Cannot assign to variable `NOTIFY_GNOME_SUPPORT_ENABLED` because it is marked final [bad-assignment]
+ ERROR apprise/plugins/growl.py:41:5-33: Cannot assign to variable `NOTIFY_GROWL_SUPPORT_ENABLED` because it is marked final [bad-assignment]
+ ERROR apprise/plugins/macosx.py:48:5-34: Cannot assign to variable `NOTIFY_MACOSX_SUPPORT_ENABLED` because it is marked final [bad-assignment]
+ ERROR apprise/plugins/mqtt.py:56:5-32: Cannot assign to variable `NOTIFY_MQTT_SUPPORT_ENABLED` because it is marked final [bad-assignment]
+ ERROR apprise/plugins/windows.py:46:5-35: Cannot assign to variable `NOTIFY_WINDOWS_SUPPORT_ENABLED` because it is marked final [bad-assignment]
+ ERROR apprise/plugins/xmpp/adapter.py:57:5-30: Cannot assign to variable `SLIXMPP_SUPPORT_AVAILABLE` because it is marked final [bad-assignment]

pycryptodome (https://github.com/Legrandin/pycryptodome)
+ ERROR lib/Crypto/SelfTest/Cipher/test_EAX.py:746:32-36: Cannot assign to variable `DES3` because it is marked final [bad-assignment]

manticore (https://github.com/trailofbits/manticore)
+ ERROR manticore/platforms/evm.py:118:1-13: Cannot assign to variable `DEFAULT_FORK` because it is marked final [bad-assignment]
+ ERROR tests/auto_generators/make_dump.py:426:9-15: Cannot assign to variable `EFLAGS` because it is marked final [bad-assignment]

schemathesis (https://github.com/schemathesis/schemathesis)
+ ERROR src/schemathesis/specs/openapi/patterns.py:330:5-12: Cannot assign to variable `REPEATS` because it is marked final [bad-assignment]
+ ERROR src/schemathesis/specs/openapi/patterns.py:332:5-12: Cannot assign to variable `REPEATS` because it is marked final [bad-assignment]
+ ERROR src/schemathesis/specs/openapi/patterns.py:663:5-18: Cannot assign to variable `_FLAG_LETTERS` because it is marked final [bad-assignment]

mongo-python-driver (https://github.com/mongodb/mongo-python-driver)
+ ERROR pymongo/asynchronous/auth.py:61:9-23: Cannot assign to variable `_USE_PRINCIPAL` because it is marked final [bad-assignment]
+ ERROR pymongo/asynchronous/auth.py:66:9-22: Cannot assign to variable `HAVE_KERBEROS` because it is marked final [bad-assignment]
+ ERROR pymongo/auth_oidc.py:19:43-44: Cannot assign to variable `CALLBACK_VERSION` because it is marked final [bad-assignment]
+ ERROR pymongo/auth_oidc.py:19:43-44: Cannot assign to variable `HUMAN_CALLBACK_TIMEOUT_SECONDS` because it is marked final [bad-assignment]
+ ERROR pymongo/auth_oidc.py:19:43-44: Cannot assign to variable `MACHINE_CALLBACK_TIMEOUT_SECONDS` because it is marked final [bad-assignment]
+ ERROR pymongo/auth_oidc.py:19:43-44: Cannot assign to variable `TIME_BETWEEN_CALLS_SECONDS` because it is marked final [bad-assignment]
+ ERROR pymongo/ssl_support.py:30:5-15: Cannot assign to variable `HAVE_PYSSL` because it is marked final [bad-assignment]
+ ERROR pymongo/ssl_support.py:44:5-13: Cannot assign to variable `HAVE_SSL` because it is marked final [bad-assignment]
+ ERROR pymongo/synchronous/auth.py:60:9-23: Cannot assign to variable `_USE_PRINCIPAL` because it is marked final [bad-assignment]
+ ERROR pymongo/synchronous/auth.py:65:9-22: Cannot assign to variable `HAVE_KERBEROS` because it is marked final [bad-assignment]
+ ERROR pymongo/uri_parser.py:24:39-40: Cannot assign to variable `SCHEME` because it is marked final [bad-assignment]
+ ERROR pymongo/uri_parser.py:24:39-40: Cannot assign to variable `SCHEME_LEN` because it is marked final [bad-assignment]
+ ERROR pymongo/uri_parser.py:24:39-40: Cannot assign to variable `SRV_SCHEME_LEN` because it is marked final [bad-assignment]
+ ERROR pymongo/uri_parser.py:24:39-40: Cannot assign to variable `DEFAULT_PORT` because it is marked final [bad-assignment]

asynq (https://github.com/quora/asynq)
+ ERROR asynq/debug.pyi:22:5-13: Cannot assign to variable `DUMP_ALL` because it is marked final [bad-assignment]

pandera (https://github.com/pandera-dev/pandera)
+ ERROR pandera/backends/pyspark/register.py:18:9-34: Cannot assign to variable `PYSPARK_CONNECT_AVAILABLE` because it is marked final [bad-assignment]
+ ERROR tests/modin/conftest.py:13:5-12: Cannot assign to variable `ENGINES` because it is marked final [bad-assignment]
+ ERROR tests/modin/test_schemas_on_modin.py:30:1-31: Cannot assign to variable `UNSUPPORTED_STRATEGY_DTYPE_CLS` because it is marked final [bad-assignment]
+ ERROR tests/pandas/test_pydantic.py:24:5-16: Cannot assign to variable `PYDANTIC_V2` because it is marked final [bad-assignment]
+ ERROR tests/polars/test_polars_pydantic.py:20:5-16: Cannot assign to variable `PYDANTIC_V2` because it is marked final [bad-assignment]
+ ERROR tests/pyspark/test_schemas_on_pyspark_pandas.py:42:1-31: Cannot assign to variable `UNSUPPORTED_STRATEGY_DTYPE_CLS` because it is marked final [bad-assignment]

pytest-autoprofile (https://gitlab.com/TTsangSC/pytest-autoprofile)
+ ERROR tests/test_doctest.py:47:17-41: Cannot assign to variable `HAS_XDOCTEST_ENV_EFFECTS` because it is marked final [bad-assignment]

ibis (https://github.com/ibis-project/ibis)
+ ERROR ibis/expr/datatypes/__init__.py:4:38-39: Cannot assign to variable `TYPE_CHECKING` because it is marked final [bad-assignment]
+ ERROR ibis/expr/operations/__init__.py:6:42-43: Cannot assign to variable `T` because it is marked final [bad-assignment]
+ ERROR ibis/expr/operations/__init__.py:14:44-45: Cannot assign to variable `T` because it is marked final [bad-assignment]
+ ERROR ibis/expr/operations/__init__.py:21:38-39: Cannot assign to variable `S` because it is marked final [bad-assignment]
+ ERROR ibis/expr/operations/__init__.py:23:41-42: Cannot assign to variable `T` because it is marked final [bad-assignment]
+ ERROR ibis/expr/operations/__init__.py:23:41-42: Cannot assign to variable `S` because it is marked final [bad-assignment]
+ ERROR ibis/expr/types/__init__.py:6:36-37: Cannot assign to variable `TYPE_CHECKING` because it is marked final [bad-assignment]
+ ERROR ibis/expr/types/__init__.py:8:34-35: Cannot assign to variable `TYPE_CHECKING` because it is marked final [bad-assignment]
+ ERROR ibis/expr/types/__init__.py:9:37-38: Cannot assign to variable `TYPE_CHECKING` because it is marked final [bad-assignment]
+ ERROR ibis/expr/types/__init__.py:10:40-41: Cannot assign to variable `TYPE_CHECKING` because it is marked final [bad-assignment]
+ ERROR ibis/expr/types/__init__.py:12:34-35: Cannot assign to variable `TYPE_CHECKING` because it is marked final [bad-assignment]
+ ERROR ibis/expr/types/__init__.py:13:37-38: Cannot assign to variable `TYPE_CHECKING` because it is marked final [bad-assignment]
+ ERROR ibis/expr/types/__init__.py:14:34-35: Cannot assign to variable `TYPE_CHECKING` because it is marked final [bad-assignment]
+ ERROR ibis/expr/types/__init__.py:15:37-38: Cannot assign to variable `TYPE_CHECKING` because it is marked final [bad-assignment]
+ ERROR ibis/expr/types/__init__.py:16:39-40: Cannot assign to variable `TYPE_CHECKING` because it is marked final [bad-assignment]
+ ERROR ibis/expr/types/__init__.py:17:35-36: Cannot assign to variable `TYPE_CHECKING` because it is marked final [bad-assignment]
+ ERROR ibis/expr/types/__init__.py:18:37-38: Cannot assign to variable `TYPE_CHECKING` because it is marked final [bad-assignment]
+ ERROR ibis/expr/types/__init__.py:19:37-38: Cannot assign to variable `TYPE_CHECKING` because it is marked final [bad-assignment]
+ ERROR ibis/expr/types/__init__.py:20:38-39: Cannot assign to variable `TYPE_CHECKING` because it is marked final [bad-assignment]
+ ERROR ibis/tests/benchmarks/benchfuncs.py:31:1-9: Cannot assign to variable `NAN_LIKE` because it is marked final [bad-assignment]

aiohttp (https://github.com/aio-libs/aiohttp)
+ ERROR aiohttp/client_reqrep.py:167:1-29: Cannot assign to variable `_CONNECTION_CLOSED_EXCEPTION` because it is marked final [bad-assignment]
+ ERROR aiohttp/resolver.py:24:5-19: Cannot assign to variable `_AI_ADDRCONFIG` because it is marked final [bad-assignment]

zulip (https://github.com/zulip/zulip)
+ ERROR tools/lib/provision.py:162:5-31: Cannot assign to variable `BUILD_PGROONGA_FROM_SOURCE` because it is marked final [bad-assignment]
+ ERROR tools/lib/provision.py:219:5-31: Cannot assign to variable `BUILD_PGROONGA_FROM_SOURCE` because it is marked final [bad-assignment]
+ ERROR version.py:14:1-14: Cannot assign to variable `ZULIP_VERSION` because it is marked final [bad-assignment]
+ ERROR zproject/backends.py:4464:1-22: Cannot assign to variable `EXTERNAL_AUTH_METHODS` because it is marked final [bad-assignment]
+ ERROR zproject/computed_settings.py:107:5-38: Cannot assign to variable `PUSH_REGISTRATION_ENCRYPTION_KEYS` because it is marked final [bad-assignment]
+ ERROR zproject/computed_settings.py:132:9-46: Cannot assign to variable `ZULIP_SERVICE_SUBMIT_USAGE_STATISTICS` because it is marked final [bad-assignment]
+ ERROR zproject/computed_settings.py:151:5-37: Cannot assign to variable `ZULIP_SERVICE_PUSH_NOTIFICATIONS` because it is marked final [bad-assignment]
+ ERROR zproject/computed_settings.py:153:5-23: Cannot assign to variable `ZULIP_SERVICES_URL` because it is marked final [bad-assignment]
+ ERROR zproject/computed_settings.py:155:9-46: Cannot assign to variable `ZULIP_SERVICE_SUBMIT_USAGE_STATISTICS` because it is marked final [bad-assignment]
+ ERROR zproject/computed_settings.py:233:1-14: Cannot assign to variable `ALLOWED_HOSTS` because it is marked final [bad-assignment]
+ ERROR zproject/computed_settings.py:235:1-14: Cannot assign to variable `ALLOWED_HOSTS` because it is marked final [bad-assignment]
+ ERROR zproject/computed_settings.py:237:1-14: Cannot assign to variable `ALLOWED_HOSTS` because it is marked final [bad-assignment]
+ ERROR zproject/computed_settings.py:290:5-19: Cannot assign to variable `INSTALLED_APPS` because it is marked final [bad-assignment]
+ ERROR zproject/computed_settings.py:291:1-15: Cannot assign to variable `INSTALLED_APPS` because it is marked final [bad-assignment]
+ ERROR zproject/computed_settings.py:297:5-18: Cannot assign to variable `TORNADO_PORTS` because it is marked final [bad-assignment]
+ ERROR zproject/computed_settings.py:305:5-17: Cannot assign to variable `ROOT_URLCONF` because it is marked final [bad-assignment]
+ ERROR zproject/computed_settings.py:447:1-20: Cannot assign to variable `RATE_LIMITING_RULES` because it is marked final [bad-assignment]
+ ERROR zproject/computed_settings.py:526:5-14: Cannot assign to variable `S3_REGION` because it is marked final [bad-assignment]
+ ERROR zproject/computed_settings.py:580:5-18: Cannot assign to variable `INTERNAL_BOTS` because it is marked final [bad-assignment]
+ ERROR zproject/computed_settings.py:608:9-19: Cannot assign to variable `STATIC_URL` because it is marked final [bad-assignment]
+ ERROR zproject/computed_settings.py:610:9-19: Cannot assign to variable `STATIC_URL` because it is marked final [bad-assignment]
+ ERROR zproject/computed_settings.py:658:5-12: Cannot assign to variable `LOADERS` because it is marked final [bad-assignment]
+ ERROR zproject/computed_settings.py:1092:1-24: Cannot assign to variable `AUTHENTICATION_BACKENDS` because it is marked final [bad-assignment]
+ ERROR zproject/computed_settings.py:1097:5-28: Cannot assign to variable `AUTHENTICATION_BACKENDS` because it is marked final [bad-assignment]
+ ERROR zproject/computed_settings.py:1099:5-30: Cannot assign to variable `POPULATE_PROFILE_VIA_LDAP` because it is marked final [bad-assignment]
+ ERROR zproject/computed_settings.py:1120:5-27: Cannot assign to variable `REGISTER_LINK_DISABLED` because it is marked final [bad-assignment]
+ ERROR zproject/computed_settings.py:1173:1-23: Cannot assign to variable `SOCIAL_AUTH_GOOGLE_KEY` because it is marked final [bad-assignment]
+ ERROR zproject/computed_settings.py:1174:1-26: Cannot assign to variable `SOCIAL_AUTH_GOOGLE_SECRET` because it is marked final [bad-assignment]
+ ERROR zproject/computed_settings.py:1234:5-18: Cannot assign to variable `EMAIL_BACKEND` because it is marked final [bad-assignment]
+ ERROR zproject/computed_settings.py:1238:5-18: Cannot assign to variable `EMAIL_BACKEND` because it is marked final [bad-assignment]
+ ERROR zproject/computed_settings.py:1242:9-22: Cannot assign to variable `EMAIL_BACKEND` because it is marked final [bad-assignment]
+ ERROR zproject/computed_settings.py:1244:9-22: Cannot assign to variable `EMAIL_BACKEND` because it is marked final [bad-assignment]
+ ERROR zproject/computed_settings.py:1248:5-15: Cannot assign to variable `EMAIL_HOST` because it is marked final [bad-assignment]
+ ERROR zproject/computed_settings.py:1282:1-11: Cannot assign to variable `SENTRY_DSN` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:14:21-31: Cannot assign to variable `PRODUCTION` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:20:32-33: Cannot assign to variable `ZULIP_ADMINISTRATOR` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:20:32-33: Cannot assign to variable `EXTERNAL_HOST` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:20:32-33: Cannot assign to variable `EMAIL_GATEWAY_PATTERN` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:20:32-33: Cannot assign to variable `EMAIL_GATEWAY_LOGIN` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:20:32-33: Cannot assign to variable `EMAIL_GATEWAY_IMAP_SERVER` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:20:32-33: Cannot assign to variable `EMAIL_GATEWAY_IMAP_PORT` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:20:32-33: Cannot assign to variable `EMAIL_GATEWAY_IMAP_FOLDER` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:20:32-33: Cannot assign to variable `AUTH_LDAP_USER_SEARCH` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:20:32-33: Cannot assign to variable `AUTH_LDAP_USER_ATTR_MAP` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:20:32-33: Cannot assign to variable `SOCIAL_AUTH_OIDC_ENABLED_IDPS` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:20:32-33: Cannot assign to variable `SOCIAL_AUTH_SAML_ORG_INFO` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:20:32-33: Cannot assign to variable `SOCIAL_AUTH_SAML_ENABLED_IDPS` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:20:32-33: Cannot assign to variable `SOCIAL_AUTH_SAML_SECURITY_CONFIG` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:20:32-33: Cannot assign to variable `SOCIAL_AUTH_SAML_SP_ENTITY_ID` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:20:32-33: Cannot assign to variable `SOCIAL_AUTH_SAML_TECHNICAL_CONTACT` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:20:32-33: Cannot assign to variable `SOCIAL_AUTH_SAML_SUPPORT_CONTACT` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:20:32-33: Cannot assign to variable `LOCAL_UPLOADS_DIR` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:20:32-33: Cannot assign to variable `CAMO_URI` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:24:41-42: Cannot assign to variable `ZULIP_ADMINISTRATOR` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:24:41-42: Cannot assign to variable `EXTERNAL_HOST` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:24:41-42: Cannot assign to variable `EMAIL_GATEWAY_PATTERN` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:24:41-42: Cannot assign to variable `EMAIL_GATEWAY_LOGIN` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:24:41-42: Cannot assign to variable `EMAIL_GATEWAY_IMAP_SERVER` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:24:41-42: Cannot assign to variable `EMAIL_GATEWAY_IMAP_PORT` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:24:41-42: Cannot assign to variable `EMAIL_GATEWAY_IMAP_FOLDER` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:24:41-42: Cannot assign to variable `AUTH_LDAP_USER_SEARCH` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:24:41-42: Cannot assign to variable `AUTH_LDAP_USER_ATTR_MAP` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:24:41-42: Cannot assign to variable `SOCIAL_AUTH_OIDC_ENABLED_IDPS` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:24:41-42: Cannot assign to variable `SOCIAL_AUTH_SAML_ORG_INFO` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:24:41-42: Cannot assign to variable `SOCIAL_AUTH_SAML_ENABLED_IDPS` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:24:41-42: Cannot assign to variable `SOCIAL_AUTH_SAML_SECURITY_CONFIG` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:24:41-42: Cannot assign to variable `SOCIAL_AUTH_SAML_SP_ENTITY_ID` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:24:41-42: Cannot assign to variable `SOCIAL_AUTH_SAML_TECHNICAL_CONTACT` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:24:41-42: Cannot assign to variable `SOCIAL_AUTH_SAML_SUPPORT_CONTACT` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:24:41-42: Cannot assign to variable `LOCAL_UPLOADS_DIR` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:24:41-42: Cannot assign to variable `CAMO_URI` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `ZULIP_ADMINISTRATOR` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `TEST_SUITE` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `LOCAL_UPLOADS_DIR` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `IS_DEV_DROPLET` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `EXTERNAL_HOST` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `REALM_HOSTS` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `EXTERNAL_HOST_WITHOUT_PORT` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `FAKE_EMAIL_DOMAIN` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `ALLOWED_HOSTS` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `AUTHENTICATION_BACKENDS` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `EXTERNAL_URI_SCHEME` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `EMAIL_GATEWAY_PATTERN` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `NOTIFICATION_BOT` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `EMAIL_GATEWAY_BOT` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `PHYSICAL_ADDRESS` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `EXTRA_INSTALLED_APPS` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `CAMO_URI` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `KATEX_SERVER` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `TORNADO_PORTS` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `OPEN_REALM_CREATION` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `WEB_PUBLIC_STREAMS_ENABLED` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `INVITES_MIN_USER_AGE_DAYS` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `CUSTOM_HOME_NOT_LOGGED_IN` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `POLICIES_DIRECTORY` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `TERMS_OF_SERVICE_VERSION` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `TERMS_OF_SERVICE_MESSAGE` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `EMBEDDED_BOTS_ENABLED` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `SYSTEM_ONLY_REALMS` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `USING_PGROONGA` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `POST_MIGRATION_CACHE_FLUSHING` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `APNS_TOKEN_KEY_FILE` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `APNS_CERT_FILE` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `PASSWORD_MIN_LENGTH` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `PASSWORD_MAX_LENGTH` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `PASSWORD_MIN_GUESSES` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `FAKE_LDAP_MODE` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `LDAP_APPEND_DOMAIN` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `AUTH_LDAP_USER_SEARCH` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `AUTH_LDAP_REVERSE_EMAIL_SEARCH` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `AUTH_LDAP_USERNAME_ATTR` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `AUTH_LDAP_USER_ATTR_MAP` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `LDAP_EMAIL_ATTR` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `BILLING_ENABLED` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `LANDING_PAGE_NAVBAR_MESSAGE` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `SOCIAL_AUTH_SAML_SP_ENTITY_ID` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `SOCIAL_AUTH_SUBDOMAIN` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `MEMCACHED_USERNAME` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `SCIM_CONFIG` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `SELF_HOSTING_MANAGEMENT_SUBDOMAIN` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `DEVELOPMENT_DISABLE_PUSH_BOUNCER_DOMAIN_CHECK` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `ZULIP_SERVICES_URL` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `ZULIP_SERVICE_PUSH_NOTIFICATIONS` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `ZULIP_SERVICE_SUBMIT_USAGE_STATISTICS` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `RESOLVE_TOPIC_UNDO_GRACE_PERIOD_SECONDS` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `ROOT_DOMAIN_LANDING_PAGE` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `DEMO_ORG_DEADLINE_DAYS` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `USING_CAPTCHA` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `TOPIC_SUMMARIZATION_MODEL` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `TOPIC_SUMMARIZATION_API_BASE` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `OUTPUT_COST_PER_GIGATOKEN` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `INPUT_COST_PER_GIGATOKEN` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `MAX_PER_USER_MONTHLY_AI_COST` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `MAX_WEB_DATA_IMPORT_SIZE_MB` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:25:31-32: Cannot assign to variable `RATE_LIMITING_RULES` because it is marked final [bad-assignment]
+ ERROR zproject/configured_settings.py:38:13-40: Cannot assign to variable `CUSTOM_DEVELOPMENT_SETTINGS` because it is marked final [bad-assignment]
+ ERROR zproject/dev_settings.py:71:5-24: Cannot assign to variable `EXTERNAL_URI_SCHEME` because it is marked final [bad-assignment]
+ ERROR zproject/dev_settings.py:156:9-39: Cannot assign to variable `AUTH_LDAP_REVERSE_EMAIL_SEARCH` because it is marked final [bad-assignment]
+ ERROR zproject/dev_settings.py:169:9-27: Cannot assign to variable `LDAP_APPEND_DOMAIN` because it is marked final [bad-assignment]
+ ERROR zproject/dev_settings.py:182:5-28: Cannot assign to variable `AUTHENTICATION_BACKENDS` because it is marked final [bad-assignment]
+ ERROR zproject/dev_settings.py:197:5-34: Cannot assign to variable `SOCIAL_AUTH_SAML_SP_ENTITY_ID` because it is marked final [bad-assignment]
+ ERROR zproject/settings.py:41:34-35: Cannot assign to variable `TYPE_CHECKING` because it is marked final [bad-assignment]
+ ERROR zproject/settings.py:42:32-33: Cannot assign to variable `DEPLOY_ROOT` because it is marked final [bad-assignment]
+ ERROR zproject/settings.py:42:32-33: Cannot assign to variable `DEVELOPMENT` because it is marked final [bad-assignment]
+ ERROR zproject/settings.py:42:32-33: Cannot assign to variable `PRODUCTION` because it is marked final [bad-assignment]
+ ERROR zproject/settings.py:42:32-33: Cannot assign to variable `ADMINS` because it is marked final [bad-assignment]
+ ERROR zproject/settings.py:42:32-33: Cannot assign to variable `ALLOWED_HOSTS` because it is marked final [bad-assignment]
+ ERROR zproject/settings.py:42:32-33: Cannot assign to variable `AUTH_LDAP_BIND_DN` because it is marked final [bad-assignment]
+ ERROR zproject/settings.py:42:32-33: Cannot assign to variable `AUTH_LDAP_CONNECTION_OPTIONS` because it is marked final [bad-assignment]
+ ERROR zproject/settings.py:42:32-33: Cannot assign to variable `AUTH_LDAP_SERVER_URI` because it is marked final [bad-assignment]
+ ERROR zproject/settings.py:42:32-33: Cannot assign to variable `AUTHENTICATION_BACKENDS` because it is marked final [bad-assignment]
+ ERROR zproject/settings.py:42:32-33: Cannot assign to variable `CAMO_URI` because it is marked final [bad-assignment]
+ ERROR zproject/settings.py:42:32-33: Cannot assign to variable `CUSTOM_HOME_NOT_LOGGED_IN` because it is marked final [bad-assignment]
+ ERROR zproject/settings.py:42:32-33: Cannot assign to variable `DEBUG` because it is marked final [bad-assignment]
+ ERROR zproject/settings.py:42:32-33: Cannot assign to variable `DEBUG_ERROR_REPORTING` because it is marked final [bad-assignment]
+ ERROR zproject/settings.py:42:32-33: Cannot assign to variable `DEFAULT_RATE_LIMITING_RULES` because it is marked final [bad-assignment]
+ ERROR zproject/settings.py:42:32-33: Cannot assign to variable `EMAIL_BACKEND` because it is marked final [bad-assignment]
+ ERROR zproject/settings.py:42:32-33: Cannot assign to variable `EMAIL_HOST` because it is marked final [bad-assignment]
+ ERROR zproject/settings.py:42:32-33: Cannot assign to variable `EMAIL_MAX_CONNECTION_LIFETIME_IN_MINUTES` because it is marked final [bad-assignment]
+ ERROR zproject/settings.py:42:32-33: Cannot assign to variable `ERROR_REPORTING` because it is marked final [bad-assignment]
+ ERROR zproject/settings.py:42:32-33: Cannot assign to variable `EXTERNAL_HOST` because it is marked final [bad-assignment]
+ ERROR zproject/settings.py:42:32-33: Cannot assign to variable `EXTERNAL_HOST_WITHOUT_PORT` because it is marked final [bad-assignment]
+ ERROR zproject/settings.py:42:32-33: Cannot assign to variable `EXTERNAL_URI_SCHEME` because it is marked final [bad-assignment]
+ ERROR zproject/settings.py:42:32-33: Cannot assign to variable `EXTRA_INSTALLED_APPS` because it is marked final [bad-assignment]
+ ERROR zproject/settings.py:42:32-33: Cannot assign to variable `GOOGLE_OAUTH2_CLIENT_ID` because it is marked final [bad-assignment]
+ ERROR zproject/settings.py:42:32-33: Cannot assign to variable `IS_DEV_DROPLET` because it is marked final [bad-assignment]
+ ERROR zproject/settings.py:42:32-33: Cannot assign to variable `LOCAL_UPLOADS_DIR` because it is marked final [bad-assignment]
+ ERROR zproject/settings.py:42:32-33: Cannot assign to variable `MEMCACHED_LOCATION` because it is marked final [bad-assignment]
+ ERROR zproject/settings.py:42:32-33: Cannot assign to variable `MEMCACHED_USERNAME` because it is marked final [bad-assignment]
+ ERROR zproject/settings.py:42:32-33: Cannot assign to variable `PUSH_NOTIFICATION_BOUNCER_URL` because it is marked final [bad-assignment]
+ ERROR zproject/settings.py:42:32-33: Cannot assign to variable `RATE_LIMITING_RULES` because it is marked final [bad-assignment]
+ ERROR zproject/settings.py:42:32-33: Cannot assign to variable `REALM_HOSTS` because it is marked final [bad-assignment]
+ ERROR zproject/settings.py:42:32-33: Cannot assign to variable `REGISTER_LINK_DISABLED` because it is marked final [bad-assignment]
+ ERROR zproject/settings.py:42:32-33: Cannot assign to variable `REMOTE_POSTGRES_HOST` because it is marked final [bad-assignment]
+ ERROR zproject/settings.py:42:32-33: Cannot assign to variable `REMOTE_POSTGRES_PORT` because it is marked final [bad-assignment]
+ ERROR zproject/settings.py:42:32-33: Cannot assign to variable `REMOTE_POSTGRES_SSLMODE` because it is marked final [bad-assignment]
+ ERROR zproject/settings.py:42:32-33: Cannot assign to variable `ROOT_SUBDOMAIN_ALIASES` because it is marked final [bad-assignment]

... (truncated 133 lines) ...

ignite (https://github.com/pytorch/ignite)
+ ERROR ignite/contrib/handlers/neptune_logger.py:41:1-25: Cannot assign to variable `_INTEGRATION_VERSION_KEY` because it is marked final [bad-assignment]
+ ERROR ignite/contrib/metrics/roc_auc.py:21:1-8: Cannot assign to variable `ROC_AUC` because it is marked final [bad-assignment]

dragonchain (https://github.com/dragonchain/dragonchain)
+ ERROR dragonchain/broadcast_processor/broadcast_processor.py:47:5-30: Cannot assign to variable `VERIFICATION_NOTIFICATION` because it is marked final [bad-assignment]
+ ERROR dragonchain/lib/error_reporter.py:33:5-18: Cannot assign to variable `REPORT_ERRORS` because it is marked final [bad-assignment]
+ ERROR dragonchain/lib/error_reporter.py:36:5-18: Cannot assign to variable `REPORT_ERRORS` because it is marked final [bad-assignment]

pywin32 (https://github.com/mhammond/pywin32)
+ ERROR adodbapi/setup.py:35:9-16: Cannot assign to variable `VERSION` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PID_DICTIONARY` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PID_CODEPAGE` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PID_FIRST_USABLE` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PID_FIRST_NAME_DEFAULT` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PID_LOCALE` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PID_MODIFY_TIME` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PID_SECURITY` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PID_BEHAVIOR` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PID_ILLEGAL` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PID_MIN_READONLY` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PID_MAX_READONLY` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PIDDI_THUMBNAIL` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PIDSI_TITLE` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PIDSI_SUBJECT` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PIDSI_AUTHOR` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PIDSI_KEYWORDS` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PIDSI_COMMENTS` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PIDSI_TEMPLATE` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PIDSI_LASTAUTHOR` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PIDSI_REVNUMBER` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PIDSI_EDITTIME` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PIDSI_LASTPRINTED` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PIDSI_CREATE_DTM` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PIDSI_LASTSAVE_DTM` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PIDSI_PAGECOUNT` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PIDSI_WORDCOUNT` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PIDSI_CHARCOUNT` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PIDSI_THUMBNAIL` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PIDSI_APPNAME` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PIDSI_DOC_SECURITY` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PIDDSI_CATEGORY` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PIDDSI_PRESFORMAT` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PIDDSI_BYTECOUNT` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PIDDSI_LINECOUNT` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PIDDSI_PARCOUNT` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PIDDSI_SLIDECOUNT` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PIDDSI_NOTECOUNT` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PIDDSI_HIDDENCOUNT` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PIDDSI_MMCLIPCOUNT` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PIDDSI_SCALE` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PIDDSI_HEADINGPAIR` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PIDDSI_DOCPARTS` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PIDDSI_MANAGER` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PIDDSI_COMPANY` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PIDDSI_LINKSDIRTY` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PIDMSI_EDITOR` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PIDMSI_SUPPLIER` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PIDMSI_SOURCE` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PIDMSI_SEQUENCE_NO` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PIDMSI_PROJECT` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PIDMSI_STATUS` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PIDMSI_OWNER` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PIDMSI_RATING` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PIDMSI_PRODUCTION` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PIDMSI_COPYRIGHT` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PROPSETFLAG_DEFAULT` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PROPSETFLAG_NONSIMPLE` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PROPSETFLAG_ANSI` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PROPSETFLAG_UNBUFFERED` because it is marked final [bad-assignment]
+ ERROR com/win32com/test/testShell.py:13:33-34: Cannot assign to variable `PROPSETFLAG_CASE_SENSITIVE` because it is marked final [bad-assignment]
+ ERROR win32/Demos/service/pipeTestService.py:29:24-25: Cannot assign to variable `SYNCHRONIZE` because it is marked final [bad-assignment]
+ ERROR win32/Demos/service/pipeTestService.py:30:23-24: Cannot assign to variable `FILE_ALL_ACCESS` because it is marked final [bad-assignment]
+ ERROR win32/Demos/service/pipeTestService.py:30:23-24: Cannot assign to variable `FILE_GENERIC_READ` because it is marked final [bad-assignment]
+ ERROR win32/Demos/service/pipeTestService.py:30:23-24: Cannot assign to variable `FILE_GENERIC_WRITE` because it is marked final [bad-assignment]
+ ERROR win32/Demos/service/pipeTestService.py:30:23-24: Cannot assign to variable `GENERIC_EXECUTE` because it is marked final [bad-assignment]
+ ERROR win32/Demos/service/pipeTestService.py:30:23-24: Cannot assign to variable `GENERIC_READ` because it is marked final [bad-assignment]
+ ERROR win32/Demos/service/pipeTestService.py:30:23-24: Cannot assign to variable `GENERIC_WRITE` because it is marked final [bad-assignment]
+ ERROR win32/Demos/service/pipeTestService.py:30:23-24: Cannot assign to variable `UNICODE` because it is marked final [bad-assignment]
+ ERROR win32/Demos/service/pipeTestService.py:31:23-24: Cannot assign to variable `UNICODE` because it is marked final [bad-assignment]
+ ERROR win32/Demos/service/pipeTestServiceClient.py:20:23-24: Cannot assign to variable `UNICODE` because it is marked final [bad-assignment]
+ ERROR win32/Demos/service/pipeTestServiceClient.py:21:23-24: Cannot assign to variable `UNICODE` because it is marked final [bad-assignment]

hydpy (https://github.com/hydpy-dev/hydpy)
+ ERROR hydpy/models/wland/__init__.py:35:48-49: Cannot assign to variable `SAND` because it is marked final [bad-assignment]
+ ERROR hydpy/models/wland/__init__.py:35:48-49: Cannot assign to variable `LOAMY_SAND` because it is marked final [bad-assignment]
+ ERROR hydpy/models/wland/__init__.py:35:48-49: Cannot assign to variable `SANDY_LOAM` because it is marked final [bad-assignment]
+ ERROR hydpy/models/wland/__init__.py:35:48-49: Cannot assign to variable `SILT_LOAM` because it is marked final [bad-assignment]
+ ERROR hydpy/models/wland/__init__.py:35:48-49: Cannot assign to variable `LOAM` because it is marked final [bad-assignment]
+ ERROR hydpy/models/wland/__init__.py:35:48-49: Cannot assign to variable `SANDY_CLAY_LOAM` because it is marked final [bad-assignment]
+ ERROR hydpy/models/wland/__init__.py:35:48-49: Cannot assign to variable `SILT_CLAY_LOAM` because it is marked final [bad-assignment]
+ ERROR hydpy/models/wland/__init__.py:35:48-49: Cannot assign to variable `CLAY_LOAM` because it is marked final [bad-assignment]
+ ERROR hydpy/models/wland/__init__.py:35:48-49: Cannot assign to variable `SANDY_CLAY` because it is marked final [bad-assignment]
+ ERROR hydpy/models/wland/__init__.py:35:48-49: Cannot assign to variable `SILTY_CLAY` because it is marked final [bad-assignment]
+ ERROR hydpy/models/wland/__init__.py:35:48-49: Cannot assign to variable `CLAY` because it is marked final [bad-assignment]
+ ERROR hydpy/models/wland/__init__.py:35:48-49: Cannot assign to variable `SEALED` because it is marked final [bad-assignment]
+ ERROR hydpy/models/wland/__init__.py:35:48-49: Cannot assign to variable `FIELD` because it is marked final [bad-assignment]
+ ERROR hydpy/models/wland/__init__.py:35:48-49: Cannot assign to variable `WINE` because it is marked final [bad-assignment]
+ ERROR hydpy/models/wland/__init__.py:35:48-49: Cannot assign to variable `ORCHARD` because it is marked final [bad-assignment]
+ ERROR hydpy/models/wland/__init__.py:35:48-49: Cannot assign to variable `SOIL` because it is marked final [bad-assignment]
+ ERROR hydpy/models/wland/__init__.py:35:48-49: Cannot assign to variable `PASTURE` because it is marked final [bad-assignment]
+ ERROR hydpy/models/wland/__init__.py:35:48-49: Cannot assign to variable `WETLAND` because it is marked final [bad-assignment]
+ ERROR hydpy/models/wland/__init__.py:35:48-49: Cannot assign to variable `TREES` because it is marked final [bad-assignment]
+ ERROR hydpy/models/wland/__init__.py:35:48-49: Cannot assign to variable `CONIFER` because it is marked final [bad-assignment]
+ ERROR hydpy/models/wland/__init__.py:35:48-49: Cannot assign to variable `DECIDIOUS` because it is marked final [bad-assignment]
+ ERROR hydpy/models/wland/__init__.py:35:48-49: Cannot assign to variable `MIXED` because it is marked final [bad-assignment]
+ ERROR hydpy/mypy_plugin.py:124:5-14: Cannot assign to variable `MODEL_MAP` because it is marked final [bad-assignment]
+ ERROR hydpy/mypy_plugin.py:124:16-25: Cannot assign to variable `VAR_MAP_1` because it is marked final [bad-assignment]
+ ERROR hydpy/mypy_plugin.py:124:27-36: Cannot assign to variable `VAR_MAP_2` because it is marked final [bad-assignment]
+ ERROR hydpy/mypy_plugin.py:124:38-46: Cannot assign to variable `VAR_INFO` because it is marked final [bad-assignment]
+ ERROR hydpy/mypy_plugin.py:124:48-57: Cannot assign to variable `VAR_SHAPE` because it is marked final [bad-assignment]

dd-trace-py (https://github.com/DataDog/dd-trace-py)
+ ERROR ddtrace/contrib/internal/aws_durable_execution_sdk_python/patch.py:60:1-22: Cannot assign to variable `_RETRYABLE_OPERATIONS` because it is marked final [bad-assignment]
+ ERROR ddtrace/ext/db.py:6:1-7: Cannot assign to variable `SYSTEM` because it is marked final [bad-assignment]
+ ERROR ddtrace/internal/process_tags/__init__.py:27:18-32: Cannot assign to variable `_ALLOWED_CHARS` because it is marked final [bad-assignment]
+ ERROR ddtrace/internal/settings/endpoint_config.py:24:9-16: Cannot assign to variable `RETRIES` because it is marked final [bad-assignment]
+ ERROR ddtrace/internal/settings/endpoint_config.py:36:9-16: Cannot assign to variable `TIMEOUT` because it is marked final [bad-assignment]
+ ERROR ddtrace/internal/wrapping/asyncs.py:42:5-24: Cannot assign to variable `ASYNC_HEAD_ASSEMBLY` because it is marked final [bad-assignment]
+ ERROR ddtrace/internal/wrapping/asyncs.py:167:5-24: Cannot assign to variable `ASYNC_HEAD_ASSEMBLY` because it is marked final [bad-assignment]
+ ERROR ddtrace/internal/wrapping/asyncs.py:291:5-24: Cannot assign to variable `ASYNC_HEAD_ASSEMBLY` because it is marked final [bad-assignment]
+ ERROR ddtrace/internal/wrapping/asyncs.py:415:5-24: Cannot assign to variable `ASYNC_HEAD_ASSEMBLY` because it is marked final [bad-assignment]
+ ERROR ddtrace/internal/wrapping/generators.py:40:5-28: Cannot assign to variable `GENERATOR_HEAD_ASSEMBLY` because it is marked final [bad-assignment]
+ ERROR ddtrace/internal/wrapping/generators.py:118:5-28: Cannot assign to variable `GENERATOR_HEAD_ASSEMBLY` because it is marked final [bad-assignment]
+ ERROR ddtrace/internal/wrapping/generators.py:195:5-28: Cannot assign to variable `GENERATOR_HEAD_ASSEMBLY` because it is marked final [bad-assignment]
+ ERROR ddtrace/internal/wrapping/generators.py:272:5-28: Cannot assign to variable `GENERATOR_HEAD_ASSEMBLY` because it is marked final [bad-assignment]
+ ERROR ddtrace/openfeature/__init__.py:21:9-25: Cannot assign to variable `_HAS_OPENFEATURE` because it is marked final [bad-assignment]

meson (https://github.com/mesonbuild/meson)
+ ERROR mesonbuild/compilers/c.py:53:1-9: Cannot assign to variable `ALL_STDS` because it is marked final [bad-assignment]
+ ERROR mesonbuild/compilers/c.py:54:1-9: Cannot assign to variable `ALL_STDS` because it is marked final [bad-assignment]
+ ERROR mesonbuild/compilers/cpp.py:49:1-9: Cannot assign to variable `ALL_STDS` because it is marked final [bad-assignment]
+ ERROR mesonbuild/compilers/cpp.py:50:1-9: Cannot assign to variable `ALL_STDS` because it is marked final [bad-assignment]
+ ERROR mesonbuild/compilers/cpp.py:51:1-9: Cannot assign to variable `ALL_STDS` because it is marked final [bad-assignment]
+ ERROR run_tests.py:52:5-24: Cannot assign to variable `NINJA_1_12_OR_NEWER` because it is marked final [bad-assignment]
+ ERROR run_tests.py:53:5-14: Cannot assign to variable `NINJA_CMD` because it is marked final [bad-assignment]
+ ERROR run_tests.py:56:5-14: Cannot assign to variable `NINJA_CMD` because it is marked final [bad-assignment]
+ ERROR run_tests.py:58:9-28: Cannot assign to variable `NINJA_1_12_OR_NEWER` because it is marked final [bad-assignment]
+ ERROR run_tests.py:60:9-18: Cannot assign to variable `NINJA_CMD` because it is marked final [bad-assignment]
+ ERROR unittests/allplatformstests.py:68:22-23: Cannot assign to variable `T` because it is marked final [bad-assignment]
+ ERROR unittests/failuretests.py:28:22-23: Cannot assign to variable `T` because it is marked final [bad-assignment]
+ ERROR unittests/internaltests.py:53:22-23: Cannot assign to variable `T` because it is marked final [bad-assignment]
+ ERROR unittests/linuxliketests.py:50:22-23: Cannot assign to variable `T` because it is marked final [bad-assignment]
+ ERROR unittests/machinefiletests.py:44:22-23: Cannot assign to variable `T` because it is marked final [bad-assignment]
+ ERROR unittests/subprojectscommandtests.py:18:22-23: Cannot assign to variable `T` because it is marked final [bad-assignment]

mypy (https://github.com/python/mypy)
+ ERROR mypy/defaults.py:25:1-18: Cannot assign to variable `USER_CONFIG_FILES` because it is marked final [bad-assignment]
+ ERROR mypy/typeshed/stdlib/_ctypes.pyi:144:9-16: Cannot assign to variable `POINTER` because it is marked final [bad-assignment]

speedrun.com_global_scoreboard_webapp (https://github.com/Avasam/speedrun.com_global_scoreboard_webapp)
+ ERROR backend/services/cached_requests.py:80:5-12: Cannot assign to variable `__REDIS` because it is marked final [bad-assignment]

core (https://github.com/home-assistant/core)
+ ERROR homeassistant/components/habitica/const.py:32:1-14: Cannot assign to variable `ATTR_PRIORITY` because it is marked final [bad-assignment]
+ ERROR homeassistant/components/insteon/const.py:110:1-25: Cannot assign to variable `SIGNAL_ADD_DEFAULT_LINKS` because it is marked final [bad-assignment]
+ ERROR homeassistant/components/linux_battery/sensor.py:44:1-12: Cannot assign to variable `ATTR_STATUS` because it is marked final [bad-assignment]
+ ERROR homeassistant/components/music_assistant/const.py:70:1-18: Cannot assign to variable `ATTR_STREAM_TITLE` because it is marked final [bad-assignment]
+ ERROR homeassistant/components/roomba/vacuum.py:52:1-22: Cannot assign to variable `ATTR_SOFTWARE_VERSION` because it is marked final [bad-assignment]
+ ERROR homeassistant/components/simplisafe/__init__.py:95:1-21: Cannot assign to variable `ATTR_LAST_EVENT_TYPE` because it is marked final [bad-assignment]
+ ERROR homeassistant/components/unifi/sensor.py:690:1-20: Cannot assign to variable `ENTITY_DESCRIPTIONS` because it is marked final [bad-assignment]
+ ERROR homeassistant/components/zwave_js/api.py:134:1-8: Cannot assign to variable `ENABLED` because it is marked final [bad-assignment]
+ ERROR homeassistant/components/zwave_js/api.py:178:1-7: Cannot assign to variable `STATUS` because it is marked final [bad-assignment]
+ ERROR homeassistant/components/zwave_js/const.py:173:1-16: Cannot assign to variable `ATTR_PARAMETERS` because it is marked final [bad-assignment]

trio (https://github.com/python-trio/trio)
+ ERROR src/trio/_socket.py:171:1-14: Cannot assign to variable `_NUMERIC_ONLY` because it is marked final [bad-assignment]
+ ERROR src/trio/_tests/test_highlevel_socket.py:11:33-34: Cannot assign to variable `TYPE_CHECKING` because it is marked final [bad-assignment]
+ ERROR src/trio/_tests/test_subprocess.py:56:24-31: Cannot assign to variable `SIGKILL` because it is marked final [bad-assignment]
+ ERROR src/trio/_tests/test_subprocess.py:56:33-40: Cannot assign to variable `SIGTERM` because it is marked final [bad-assignment]
+ ERROR src/trio/_tests/test_subprocess.py:56:42-49: Cannot assign to variable `SIGUSR1` because it is marked final [bad-assignment]
+ ERROR src/trio/_tools/windows_ffi_build.py:205:1-4: Cannot assign to variable `LIB` because it is marked final [bad-assignment]
+ ERROR src/trio/_tools/windows_ffi_build.py:209:1-4: Cannot assign to variable `LIB` because it is marked final [bad-assignment]
+ ERROR src/trio/_tools/windows_ffi_build.py:212:1-4: Cannot assign to variable `LIB` because it is marked final [bad-assignment]

xarray (https://github.com/pydata/xarray)
+ ERROR xarray/coding/cftimeindex.py:76:5-35: Cannot assign to variable `OUT_OF_BOUNDS_TIMEDELTA_ERRORS` because it is marked final [bad-assignment]
+ ERROR xarray/coding/cftimeindex.py:78:5-35: Cannot assign to variable `OUT_OF_BOUNDS_TIMEDELTA_ERRORS` because it is marked final [bad-assignment]

spack (https://github.com/spack/spack)
+ ERROR lib/spack/spack/package.py:197:1-12: Cannot assign to variable `LC_ID_DYLIB` because it is marked final [bad-assignment]

parso (https://github.com/davidhalter/parso)
+ ERROR parso/python/pep8.py:24:1-13: Cannot assign to variable `_NEEDS_SPACE` because it is marked final [bad-assignment]

rich (https://github.com/Textualize/rich)
+ ERROR rich/panel.py:305:30-37: Cannot assign to variable `ROUNDED` because it is marked final [bad-assignment]

scrapy (https://github.com/scrapy/scrapy)
+ ERROR scrapy/core/downloader/handlers/_httpx.py:56:9-18: Cannot assign to variable `HAS_HTTP2` because it is marked final [bad-assignment]
+ ERROR scrapy/core/downloader/handlers/_httpx.py:57:9-35: Cannot assign to variable `DOWNLOAD_FAILED_EXCEPTIONS` because it is marked final [bad-assignment]
+ ERROR scrapy/core/downloader/handlers/_httpx.py:64:9-18: Cannot assign to variable `HAS_SOCKS` because it is marked final [bad-assignment]
+ ERROR scrapy/core/downloader/handlers/_httpx.py:65:9-35: Cannot assign to variable `DOWNLOAD_FAILED_EXCEPTIONS` because it is marked final [bad-assignment]
+ ERROR tests/AsyncCrawlerProcess/asyncio_deferred_signal.py:37:9-27: Cannot assign to variable `ASYNCIO_EVENT_LOOP` because it is marked final [bad-assignment]
+ ERROR tests/AsyncCrawlerProcess/asyncio_deferred_signal.py:39:9-27: Cannot assign to variable `ASYNCIO_EVENT_LOOP` because it is marked final [bad-assignment]
+ ERROR tests/CrawlerProcess/asyncio_deferred_signal.py:37:9-27: Cannot assign to variable `ASYNCIO_EVENT_LOOP` because it is marked final [bad-assignment]
+ ERROR tests/CrawlerProcess/asyncio_deferred_signal.py:39:9-27: Cannot assign to variable `ASYNCIO_EVENT_LOOP` because it is marked final [bad-assignment]

optuna (https://github.com/optuna/optuna)
+ ERROR tutorial/20_recipes/009_ask_and_tell.py:77:5-6: Cannot assign to variable `C` because it is marked final [bad-assignment]
+ ERROR tutorial/20_recipes/009_ask_and_tell.py:180:5-6: Cannot assign to variable `C` because it is marked final [bad-assignment]

discord.py (https://github.com/Rapptz/discord.py)
+ ERROR discord/player.py:70:5-21: Cannot assign to variable `CREATE_NO_WINDOW` because it is marked final [bad-assignment]
+ ERROR discord/utils.py:92:5-17: Cannot assign to variable `_ZSTD_SOURCE` because it is marked final [bad-assignment]
+ ERROR discord/utils.py:97:9-21: Cannot assign to variable `_ZSTD_SOURCE` because it is marked final [bad-assignment]

schema_salad (https://github.com/common-workflow-language/schema_salad)
+ ERROR setup.py:18:5-14: Cannot assign to variable `USE_MYPYC` because it is marked final [bad-assignment]
+ ERROR setup.py:20:5-14: Cannot assign to variable `USE_MYPYC` because it is marked final [bad-assignment]

@github-actions

github-actions Bot commented Jun 9, 2026

Copy link
Copy Markdown

Primer Diff Classification

❌ 49 regression(s) | 49 project(s) total | +320 errors

49 regression(s) across pip, openlibrary, aioredis, cloud-init, egglog-python, rotki, steam.py, pytest, jax, cwltool, DateType, prefect, scipy, colour, urllib3, scikit-learn, materialize, setuptools, scikit-build-core, yarl, apprise, pycryptodome, manticore, schemathesis, mongo-python-driver, asynq, pandera, pytest-autoprofile, ibis, aiohttp, zulip, ignite, dragonchain, pywin32, hydpy, dd-trace-py, meson, mypy, speedrun.com_global_scoreboard_webapp, core, trio, xarray, spack, parso, rich, scrapy, optuna, discord.py, schema_salad. error kinds: bad-assignment, ALL_CAPS treated as Final false positives, ALL_CAPS treated as Final (false positives). caused by check_for_all_caps_final_reassignment().

Project Verdict Changes Error Kinds Root Cause
pip ❌ Regression +7 ALL_CAPS treated as Final — conditional/feature-detection reassignment check_for_all_caps_final_reassignment()
openlibrary ❌ Regression +1 bad-assignment check_for_all_caps_final_reassignment()
aioredis ❌ Regression +1 bad-assignment check_for_all_caps_final_reassignment()
cloud-init ❌ Regression +9 ALL_CAPS conditional reassignment flagged as Final violation check_for_all_caps_final_reassignment()
egglog-python ❌ Regression +3 bad-assignment check_for_all_caps_final_reassignment()
rotki ❌ Regression +7 bad-assignment check_for_all_caps_final_reassignment()
steam.py ❌ Regression +1 bad-assignment check_for_all_caps_final_reassignment()
pytest ❌ Regression +1 bad-assignment check_for_all_caps_final_reassignment()
jax ❌ Regression +3 bad-assignment check_for_all_caps_final_reassignment()
cwltool ❌ Regression +2 bad-assignment pyrefly/lib/binding/bindings.rs
DateType ❌ Regression +2 ALL_CAPS treated as Final false positives check_for_all_caps_final_reassignment()
prefect ❌ Regression +1 bad-assignment check_for_all_caps_final_reassignment()
scipy ❌ Regression +2 ALL_CAPS treated as Final (IS_MUSL) check_for_all_caps_final_reassignment()
colour ❌ Regression +47 ALL_CAPS treated as Final — false positives from new default-on heuristic check_for_all_caps_final_reassignment()
urllib3 ❌ Regression +5 bad-assignment check_for_all_caps_final_reassignment()
scikit-learn ❌ Regression +22 ALL_CAPS treated as Final false positives check_for_all_caps_final_reassignment()
materialize ❌ Regression +1 False positive: re-import treated as reassignment of ALL_CAPS Final check_for_all_caps_final_reassignment()
setuptools ❌ Regression +1 bad-assignment check_for_all_caps_final_reassignment()
scikit-build-core ❌ Regression +2 ALL_CAPS treated as Final false positives check_for_all_caps_final_reassignment()
yarl ❌ Regression +1 bad-assignment pyrefly/lib/binding/bindings.rs
apprise ❌ Regression +19 ALL_CAPS treated as Final — platform-conditional reassignment check_for_all_caps_final_reassignment()
pycryptodome ❌ Regression +1 bad-assignment check_for_all_caps_final_reassignment()
manticore ❌ Regression +2 ALL_CAPS treated as Final (false positives) check_for_all_caps_final_reassignment()
schemathesis ❌ Regression +3 ALL_CAPS conditional assignment treated as Final violation check_for_all_caps_final_reassignment()
mongo-python-driver ❌ Regression +8 ALL_CAPS reassignment in try/except feature detection check_for_all_caps_final_reassignment()
asynq ❌ Regression +1 bad-assignment check_for_all_caps_final_reassignment()
pandera ❌ Regression +6 ALL_CAPS treated as Final (false positives) check_for_all_caps_final_reassignment()
pytest-autoprofile ❌ Regression +1 ALL_CAPS treated as Final (new feature default) check_for_all_caps_final_reassignment()
ibis ❌ Regression +19 bad-assignment check_for_all_caps_final_reassignment()
aiohttp ❌ Regression +2 bad-assignment check_for_all_caps_final_reassignment()
zulip ❌ Regression +50 ALL_CAPS treated as Final false positives check_for_all_caps_final_reassignment()
ignite ❌ Regression +2 bad-assignment check_for_all_caps_final_reassignment()
dragonchain ❌ Regression +3 ALL_CAPS conditional reassignment flagged as bad-assignment check_for_all_caps_final_reassignment()
pywin32 ❌ Regression +7 ALL_CAPS treated as Final — reassignment check_for_all_caps_final_reassignment()
hydpy ❌ Regression +6 bad-assignment check_for_all_caps_final_reassignment()
dd-trace-py ❌ Regression +14 ALL_CAPS treated as Final check_for_all_caps_final_reassignment()
meson ❌ Regression +16 ALL_CAPS treated as Final false positives check_for_all_caps_final_reassignment()
mypy ❌ Regression +2 bad-assignment check_for_all_caps_final_reassignment()
speedrun.com_global_scoreboard_webapp ❌ Regression +1 bad-assignment pyrefly/lib/binding/bindings.rs
core ❌ Regression +10 ALL_CAPS treated as Final (duplicate definitions) check_for_all_caps_final_reassignment()
trio ❌ Regression +8 bad-assignment check_for_all_caps_final_reassignment()
xarray ❌ Regression +2 bad-assignment check_for_all_caps_final_reassignment()
spack ❌ Regression +1 bad-assignment check_for_all_caps_final_reassignment()
parso ❌ Regression +1 bad-assignment check_for_all_caps_final_reassignment()
rich ❌ Regression +1 bad-assignment check_for_all_caps_final_reassignment()
scrapy ❌ Regression +8 bad-assignment check_for_all_caps_final_reassignment()
optuna ❌ Regression +2 bad-assignment check_for_all_caps_final_reassignment()
discord.py ❌ Regression +3 ALL_CAPS bare annotation treated as assignment (CREATE_NO_WINDOW) check_for_all_caps_final_reassignment()
schema_salad ❌ Regression +2 bad-assignment check_for_all_caps_final_reassignment()
Detailed analysis

❌ Regression (49)

pip (+7)

ALL_CAPS treated as Final — conditional/feature-detection reassignment: All 7 errors flag legitimate Python patterns: conditional reassignment (if WINDOWS: _EXECUTABLE_NAMES = ...) and feature-detection augmented assignment in try/except blocks (SUPPORTED_EXTENSIONS += BZ2_EXTENSIONS). These are not bugs — they are standard Python idioms for platform-specific and optional-dependency handling. The new treat_all_caps_as_final feature (defaulting to true) doesn't account for control flow context, causing false positives on well-established patterns. 6/7 are pyrefly-only, confirming these are too strict.

Overall: This PR introduces a new feature that treats ALL_CAPS module-level variables as implicitly Final. While this is a useful convention-based check (similar to pyright's reportConstantRedefinition), the default of true causes false positives on legitimate Python patterns:

  1. _EXECUTABLE_NAMES in entrypoints.py (line 18): This is a conditional reassignment — the variable is first set to a list, then conditionally reassigned inside if WINDOWS: to extend it with .exe variants. This is a standard pattern, not a bug. The leading underscore _ also suggests it's a private mutable variable, not a true constant.

  2. SUPPORTED_EXTENSIONS in unpacking.py (lines 32, 40): These are += augmented assignments inside try/except blocks for feature detection (checking if bz2 and lzma modules are available). This is a textbook Python pattern for optional dependency handling. The variable is intentionally mutable — it accumulates supported extensions based on available modules.

The key issue is that the check doesn't distinguish between:

  • True constant redefinition (e.g., FOO = 1; FOO = 2 at module level with no control flow)
  • Conditional/incremental assignment patterns (if/try blocks)

Per rule #9 (WELL-KNOWN EXEMPT PATTERNS): Re-assigning module-level constants in feature detection blocks (try/except) is a common pattern in projects like urllib3, pip, etc. These are false positives. The fact that 6/7 are pyrefly-only confirms this.

Per-category reasoning:

  • ALL_CAPS treated as Final — conditional/feature-detection reassignment: All 7 errors flag legitimate Python patterns: conditional reassignment (if WINDOWS: _EXECUTABLE_NAMES = ...) and feature-detection augmented assignment in try/except blocks (SUPPORTED_EXTENSIONS += BZ2_EXTENSIONS). These are not bugs — they are standard Python idioms for platform-specific and optional-dependency handling. The new treat_all_caps_as_final feature (defaulting to true) doesn't account for control flow context, causing false positives on well-established patterns. 6/7 are pyrefly-only, confirming these are too strict.

Attribution: The PR adds a new treat_all_caps_as_final config option (default true) in crates/pyrefly_config/src/config.rs line 1366. The check itself is in pyrefly/lib/binding/bindings.rs in the new method check_for_all_caps_final_reassignment(). This method fires whenever a module-level ALL_CAPS name has a prior assignment in the current flow, treating it as implicitly Final. The default of true means all existing projects get this new check applied without opt-in, causing these 7 new errors on pip.

openlibrary (+1)

This is a regression. The new treat_all_caps_as_final feature (defaulting to true) incorrectly flags a star import (from .model import *) as reassigning TYPE_CHECKING.

What's happening: TYPE_CHECKING is imported on line 2 from typing. Because it's an ALL_CAPS name, the treat_all_caps_as_final feature treats it as implicitly Final. Then on line 11, from .model import * imports everything from .model, which likely includes or re-exports TYPE_CHECKING (since .model probably also imports it from typing). Pyrefly treats this star import as a reassignment to the already-Final TYPE_CHECKING binding.

This is a false positive because:

  1. Star imports should not be treated as intentional constant reassignments — they import a set of names that may overlap with existing bindings, and this is normal Python practice.
  2. TYPE_CHECKING is a well-known constant from the typing module that is commonly imported in multiple modules. Even if .model re-exports it, the value would be the same bool constant.
  3. Neither mypy nor pyright flag this pattern (pyrefly-only error).

The root cause is in pyrefly's binding analysis, which doesn't distinguish star imports from explicit assignments when checking for reassignment of ALL_CAPS (implicitly Final) variables.

Attribution: The PR adds a new treat_all_caps_as_final feature (default true) in pyrefly/lib/binding/bindings.rs via check_for_all_caps_final_reassignment(). This function checks if a module-level ALL_CAPS name already has a flow entry and flags any subsequent assignment as bad-assignment. The problem is that TYPE_CHECKING is ALL_CAPS, was imported on line 2, and the star import on line 11 (from .model import *) is being treated as a reassignment. The star import may or may not actually export TYPE_CHECKING, but pyrefly is treating it as if it does. This is a false positive because: (1) TYPE_CHECKING is already Final in typeshed, so the new ALL_CAPS heuristic shouldn't be needed for it, (2) star imports are not intentional reassignments, and (3) per rule 9, re-assigning TYPE_CHECKING is a well-known exempt pattern that mypy/pyright explicitly allow.

aioredis (+1)

This is a regression. The code at lines 61-75 of aioredis/connection.py uses a standard Python pattern for feature detection: HIREDIS_AVAILABLE is set in both branches of a try/except/else block, and then conditionally overwritten inside the else block if the version is too old. This is idiomatic Python — reassigning a module-level constant based on runtime conditions is extremely common (see rule #9 about well-known exempt patterns for feature detection blocks). Neither mypy nor pyright would flag this by default. The PR enables treat_all_caps_as_final with a default of true, which is overly aggressive — it treats ALL_CAPS names as implicitly Final even though the typing spec requires an explicit Final annotation for finality. This creates false positives on legitimate feature-detection patterns that are ubiquitous in the Python ecosystem.
Attribution: The PR adds a new treat_all_caps_as_final config option (defaulting to true) and implements check_for_all_caps_final_reassignment() in pyrefly/lib/binding/bindings.rs. This function checks if a module-level ALL_CAPS name is being reassigned and emits a bad-assignment error. The default of true in pyrefly/lib/state/steps.rs and crates/pyrefly_config/src/config.rs (line self.root.treat_all_caps_as_final = Some(true)) means this check is ON by default for all projects, causing the new error on aioredis.

cloud-init (+9)

ALL_CAPS conditional reassignment flagged as Final violation: All 9 errors are module-level ALL_CAPS variables being conditionally reassigned (e.g., DEFAULT_FS, RESOURCE_DISK_PATH, PLATFORM_ENTROPY_SOURCE in DataSourceAzure.py reassigned inside if util.is_FreeBSD():). This is a standard Python pattern for platform-specific configuration. The new treat-all-caps-as-final feature (defaulting to true) incorrectly treats these as Final violations. No typing spec requires this, and neither mypy nor pyright flag these. These are false positives.

Overall: The PR introduces a new feature treat-all-caps-as-final that defaults to true, causing ALL_CAPS module-level variables to be treated as implicitly Final. This is a pyrefly-specific convention not required by the typing spec. The affected code in cloud-init uses a very common Python pattern: defining platform-specific defaults at module level with conditional reassignment (e.g., DEFAULT_FS = 'ext4' then DEFAULT_FS = 'freebsd-ufs' inside if util.is_FreeBSD()). This is intentional, correct code. Neither mypy nor pyright flag any of these 9 errors. While Pyright has a similar option (reportConstantRedefinition), it defaults to disabled ('none'). Defaulting this to true creates false positives on legitimate Python patterns across real-world projects. The feature itself may be useful as an opt-in, but defaulting to true causes regressions.

Attribution: The change in pyrefly/lib/binding/bindings.rs adding check_for_all_caps_final_reassignment() is the direct cause. This function checks if a name matches is_constant_name() (ALL_CAPS), is at module scope, is not explicitly Final, and has a prior assignment — then emits bad-assignment. The default of true for treat_all_caps_as_final in pyrefly/lib/state/steps.rs and crates/pyrefly_config/src/config.rs means this fires on all projects by default.

egglog-python (+3)

These are false positives. The egglog DSL uses a common pattern where symbolic variables (A, B, C) are first created for defining rewrite rules (line 87), then reassigned to concrete matrix instances (lines 143-145). This is intentional and correct code. The new treat_all_caps_as_final feature defaults to true, which is overly aggressive — it treats ALL_CAPS names as implicitly Final even though the user never annotated them as such. Neither mypy nor pyright flags these by default. The typing spec (https://typing.readthedocs.io/en/latest/spec/qualifiers.html#final) only makes variables Final when explicitly annotated with Final. Inferring finality from naming convention and then erroring on reassignment is a heuristic that produces false positives on legitimate code patterns like this one. The default should arguably be false to avoid breaking existing projects.
Attribution: The PR adds a new treat_all_caps_as_final config option (default: true) in crates/pyrefly_config/src/config.rs line 1366. The check itself is in pyrefly/lib/binding/bindings.rs in the new method check_for_all_caps_final_reassignment(). When a module-level ALL_CAPS name already has a flow binding, any subsequent assignment is flagged as bad-assignment. The variables A, B, C are first bound on line 87 via tuple unpacking (A, B, C, D = vars_(...)) and then reassigned on lines 143-145, triggering the new check.

rotki (+7)

All 7 errors flag star imports (from ... import *) as reassignments of Final variables. The error message specifically says 'Cannot assign to variable TYPE_CHECKING because it is marked final' — typing.TYPE_CHECKING is declared as TYPE_CHECKING: Final = False in the typing module. When multiple star imports bring in the same Final variable (e.g., TYPE_CHECKING is re-exported through fixture modules that themselves import from typing), the checker treats each subsequent star import as a reassignment of that Final variable. Star imports are not intentional reassignments — they're a standard Python import pattern for re-exporting names, especially common in test fixture __init__.py files. Neither mypy nor pyright (0/7 cross-check for both) flag star imports as Final variable reassignments, because the semantics of from x import * are to bind names in the current namespace, not to mutate the original variable. These are false positives caused by the checker's overly broad treatment of star imports as assignments to Final-annotated names.
Attribution: The change to check_for_all_caps_final_reassignment() in pyrefly/lib/binding/bindings.rs introduces the ALL_CAPS-as-final check. The check fires on star imports because star imports that bring in an ALL_CAPS name (like TYPE_CHECKING) are treated as reassignments when the name was already bound. The default of true in pyrefly/lib/state/steps.rs and pyrefly/lib/test/util.rs means this fires for all projects by default. The check should exclude star imports or at minimum not treat them as reassignments.

steam.py (+1)

This is a regression. The new treat-all-caps-as-final feature (enabled by default) incorrectly flags TYPE_CHECKING as being reassigned via a star import (from .user_news import *). TYPE_CHECKING is an ALL_CAPS name from typing that gets imported through multiple star imports in this __init__.py. The feature treats ALL_CAPS names as implicitly Final, and when TYPE_CHECKING is brought into scope by an earlier star import (e.g., from one of the modules like .user or .client that re-exports it) and then again by from .user_news import *, pyrefly treats this as a reassignment of a Final variable. This is a false positive for two reasons: (1) Star imports re-exporting the same name from different submodules is not a true 'reassignment' — it's the same value being imported from a different path, which is extremely common in __init__.py files that aggregate submodule exports. (2) TYPE_CHECKING is a standard library constant from typing that many modules import and thus re-export via *; treating it as Final and then flagging star-import collisions is overly aggressive. Neither mypy nor pyright flag this pattern (pyrefly-only). The feature's default of true is too aggressive for real-world codebases that use star imports in __init__.py files.
Attribution: The PR adds a new treat_all_caps_as_final feature (default: true) in pyrefly/lib/binding/bindings.rs via check_for_all_caps_final_reassignment(). This function checks if a module-level ALL_CAPS name is being reassigned and emits a bad-assignment error. The default is set to true in crates/pyrefly_config/src/config.rs line 1366. The TYPE_CHECKING variable from typing is ALL_CAPS and is being brought into scope via star imports — when from .user_news import * re-imports it, pyrefly treats this as a reassignment of a Final variable. This is a false positive because: (1) TYPE_CHECKING is not explicitly annotated as Final by the user, (2) star imports commonly re-export the same name, and (3) this is a well-known exempt pattern per rule 9.

pytest (+1)

This is a false positive. The _PLUGGY_DIR variable is being conditionally initialized — first set to a Path, then adjusted if pluggy is a package. This is a standard Python pattern for module-level constants that need runtime detection. The new treat-all-caps-as-final feature is too aggressive: it flags any second assignment without considering that conditional initialization (where the variable's final value depends on a runtime check) is a legitimate and common pattern. Pyright's equivalent reportConstantRedefinition handles this more carefully.
Attribution: The new check_for_all_caps_final_reassignment() function in pyrefly/lib/binding/bindings.rs treats any second assignment to an ALL_CAPS module-level name as a bad-assignment error. It doesn't distinguish between true redefinition (FOO = 1; FOO = 2) and conditional initialization (FOO = x; if cond: FOO = y), causing this false positive on pytest's _PLUGGY_DIR.

jax (+3)

These are false positives from the new treat_all_caps_as_final feature (defaulting to true). The feature treats ALL_CAPS module-level names as implicitly Final, but the flagged code uses two legitimate patterns that should not be errors:

  1. Type annotation followed by assignment (gpu_callbacks.py): Lines 41 and 47 have bare type annotations (IDX_BY_GPU_MEMORY_SPACE: Mapping[...]) which are NOT assignments — they only declare the type. The actual assignment on lines 42 and 48 is the first and only real assignment. Pyrefly incorrectly counts the annotation as a prior binding.

  2. Try/except feature detection (core.py): Line 90 sets RUNTIME_PATH = None as a default, then line 94 inside a try block sets it to the real value. This is a universally accepted Python pattern for conditional initialization. Per rule 9, re-assigning module-level constants in try/except blocks is a well-known exempt pattern.

Neither mypy nor pyright flags any of these (0/3 co-reported). The typing spec does not require treating ALL_CAPS as Final — this is purely a pyrefly heuristic that produces false positives on common, correct code patterns.

Attribution: The PR adds a treat_all_caps_as_final config option (defaulting to true) in pyrefly/lib/binding/bindings.rs via check_for_all_caps_final_reassignment(). This function fires when: (1) the name is ALL_CAPS, (2) we're at module scope, (3) the name is NOT explicitly Final, and (4) there's already a prior binding in the current flow. The three errors are direct consequences of this new check firing on legitimate code patterns:

  1. gpu_callbacks.py lines 41-42 and 47-48: The pattern IDX_BY_GPU_MEMORY_SPACE: Mapping[...] (type annotation only, no assignment) followed by IDX_BY_GPU_MEMORY_SPACE = types.MappingProxyType(...) (actual assignment). Pyrefly treats the bare annotation as a 'first assignment' and then flags the real assignment as a reassignment. This is a false positive — the annotation-only line doesn't assign a value.

  2. core.py lines 90-94: RUNTIME_PATH = None followed by RUNTIME_PATH = pathlib.Path(...) inside a try block. This is a standard feature-detection pattern (set default, try to compute real value). Pyrefly flags the second assignment as a reassignment of a 'final' variable. This falls under the 'well-known exempt pattern' of re-assigning module-level constants in try/except blocks (rule 9).

cwltool (+2)

This is a regression. The PR introduces a new treat-all-caps-as-final feature that defaults to true, which means it fires on all existing projects without any opt-in. The pattern of reassigning an ALL_CAPS variable conditionally (e.g., USE_MYPYC = False then USE_MYPYC = True inside an if block) is extremely common in Python — it's a standard configuration/feature-detection pattern. Neither mypy nor pyright treat ALL_CAPS names as implicitly Final by default. The typing spec at https://typing.readthedocs.io/en/latest/spec/qualifiers.html#uppercase-names says type checkers MAY infer Final for uppercase names but does not require it. Defaulting this to true and applying it to all projects is too strict — it falls under the 'well-known exempt patterns' rule (rule 9) where module-level constants are commonly reassigned in conditional/feature-detection blocks.
Attribution: The PR adds a new treat_all_caps_as_final config option that defaults to true (see config.rs line: self.root.treat_all_caps_as_final = Some(true)). The check_for_all_caps_final_reassignment function in pyrefly/lib/binding/bindings.rs fires for any module-level ALL_CAPS name that has a prior assignment in the current flow. Since USE_MYPYC = False is the first assignment (line 59), the reassignments on lines 63 and 65 trigger the new error. The feature is enabled by default, causing these errors on existing projects that never opted in.

DateType (+2)

ALL_CAPS treated as Final false positives: The TEST_DATA variable is intentionally reassigned in a while loop and after it. This is valid Python code. The new heuristic incorrectly treats it as Final because it's ALL_CAPS, but there is no Final annotation. Neither mypy nor pyright flags this. The default-on behavior creates false positives.

Overall: The analysis is factually correct. The treat_all_caps_as_final feature defaults to true in pyrefly, causing ALL_CAPS module-level variables like TEST_DATA to be treated as Final. The code clearly shows TEST_DATA being intentionally reassigned: first initialized on line 18, then reassigned in a while loop on line 20, and again on line 21. This is a legitimate and common Python pattern for path traversal. The variable has no Final annotation. The analysis correctly notes that neither mypy nor pyright would flag this code as erroneous. The claim about pyright's reportConstantRedefinition defaulting to off/warning rather than error is also accurate. The errors are false positives caused by the convention-based heuristic being too aggressive when enabled by default.

Attribution: The PR adds a new treat_all_caps_as_final config option (defaulting to true in config.rs line 1366: self.root.treat_all_caps_as_final = Some(true)). The check is implemented in check_for_all_caps_final_reassignment() in pyrefly/lib/binding/bindings.rs. This function fires when a module-level ALL_CAPS name is reassigned after its first binding. The default of true means this check is active for all projects unless explicitly disabled, causing these new errors on the datetype project.

prefect (+1)

This is a false positive. UUID is a class name (an acronym), not a constant. The ALL_CAPS heuristic incorrectly treats it as a constant. Furthermore, re-importing the same symbol inside a TYPE_CHECKING block is a standard Python pattern that should never be flagged. Pyright's equivalent reportConstantRedefinition handles these cases correctly. The feature as implemented is too aggressive in its default-on state.
Attribution: The new check_for_all_caps_final_reassignment() function in pyrefly/lib/binding/bindings.rs uses is_constant_name() to detect ALL_CAPS names and flags any reassignment at module scope. The default is true (set in pyrefly/lib/state/steps.rs and crates/pyrefly_config/src/config.rs). The check is too broad — it catches UUID (a class name that's an acronym) and doesn't exempt TYPE_CHECKING re-imports of the same symbol.

scipy (+2)

ALL_CAPS treated as Final (IS_MUSL): IS_MUSL is initialized to False on line 39 and conditionally reassigned to True on line 46 based on sysconfig detection. This is a standard feature-detection pattern. No type checker treats this as an error by default. False positive.
ALL_CAPS treated as Final (_CHANDRUPATLA_TESTS): _CHANDRUPATLA_TESTS is defined on line 920 as raw test data, then reassigned on line 967 to a transformed version with added ID strings. This is a data-building pattern, not a constant redefinition. The leading underscore signals it's private. False positive.

Overall: Both errors are false positives caused by the new treat_all_caps_as_final feature defaulting to true. The code patterns being flagged are completely legitimate:

  1. IS_MUSL (line 39→46): Initialized to False, then conditionally set to True based on sysconfig.get_config_var('HOST_GNU_TYPE'). This is a standard feature-detection pattern used throughout the Python ecosystem. See KEY RULE Documentation: Pyrefly Errors #9 — re-assigning module-level constants in feature detection blocks is a well-known exempt pattern.

  2. _CHANDRUPATLA_TESTS (line 920→967): First defined as a list of test data, then reassigned to a transformed version that adds ID strings. The underscore prefix _ indicates it's a private implementation detail, not a public constant. The reassignment is a data transformation, not a redefinition.

Neither mypy nor pyright flags these. The typing spec does not require ALL_CAPS names to be treated as Final — that's an explicit annotation per https://typing.readthedocs.io/en/latest/spec/qualifiers.html#final. Defaulting this heuristic to true creates noise on real-world projects. Even Pyright's equivalent reportConstantRedefinition defaults to none severity.

Per-category reasoning:

  • ALL_CAPS treated as Final (IS_MUSL): IS_MUSL is initialized to False on line 39 and conditionally reassigned to True on line 46 based on sysconfig detection. This is a standard feature-detection pattern. No type checker treats this as an error by default. False positive.
  • ALL_CAPS treated as Final (_CHANDRUPATLA_TESTS): _CHANDRUPATLA_TESTS is defined on line 920 as raw test data, then reassigned on line 967 to a transformed version with added ID strings. This is a data-building pattern, not a constant redefinition. The leading underscore signals it's private. False positive.

Attribution: The PR adds a new treat_all_caps_as_final config option in crates/pyrefly_config/src/config.rs with a default of true (line self.root.treat_all_caps_as_final = Some(true)). The check itself is in pyrefly/lib/binding/bindings.rs in the new method check_for_all_caps_final_reassignment(), which fires when a module-level ALL_CAPS name is assigned more than once. The default-true setting causes these errors to appear on scipy without any explicit opt-in.

colour (+47)

ALL_CAPS treated as Final — false positives from new default-on heuristic: All 47 errors come from the new treat_all_caps_as_final feature defaulting to true. The affected code in colour intentionally reassigns ALL_CAPS module-level variables (e.g., CONSTANT_K_M = DocstringFloat(CONSTANT_K_M) inside if is_documentation_building() blocks). This is a legitimate, common Python pattern. The typing spec does not treat ALL_CAPS as implicitly Final — only explicit Final annotations create finality. Pyright has a related but softer diagnostic (reportConstantRedefinition) that defaults to 'none' in basic mode, and importantly does not treat ALL_CAPS as Final. 0/47 errors are co-reported by mypy or pyright. These are all false positives.

Overall: This is a regression. The PR introduces a new heuristic feature (treat_all_caps_as_final) that is enabled by default (true). This feature has no basis in the typing spec — Final requires explicit annotation per https://typing.readthedocs.io/en/latest/spec/qualifiers.html#final. The ALL_CAPS convention is just that — a convention, not a type system rule. Pyright has a related diagnostic (reportConstantRedefinition) that treats ALL_CAPS module-level variables as implicitly constant, but this is a softer check (it reports redefinition of constants, not assignment to Final variables) and defaults to 'none' in basic mode (though it becomes 'warning' in strict mode). Critically, pyright does not treat ALL_CAPS as Final — it uses a separate, less restrictive concept of constant. The colour project demonstrates exactly this: variables like CONSTANT_K_M are first assigned a numeric value, then conditionally reassigned to DocstringFloat(...) inside if is_documentation_building() blocks. This is intentional, correct code. All 47 errors are pyrefly-only (neither mypy nor pyright flags them), confirming these are false positives introduced by an overly aggressive default. The default should be false to avoid breaking well-established Python patterns.

Attribution: The PR adds a new treat_all_caps_as_final config option (in pyrefly/lib/binding/bindings.rs, function check_for_all_caps_final_reassignment()) that treats module-level ALL_CAPS names as implicitly Final. The default is set to true in crates/pyrefly_config/src/config.rs (line: self.root.treat_all_caps_as_final = Some(true)). This causes all 47 new errors on the colour project, which extensively uses the pattern of declaring ALL_CAPS constants and then conditionally reassigning them for documentation purposes.

urllib3 (+5)

This is a regression. Pyrefly's implicit Final inference for ALL_CAPS module-level variables fires on ALL module-level ALL_CAPS reassignments without distinguishing between intentional patterns (try/except feature detection, conditional updates) and actual mistakes.

Specifically:

  1. LONG_TIMEOUT (test/init.py:77) — initially set to 0.1 at line 75, then conditionally updated to 0.5 based on CI environment variables. This is a standard configuration pattern.
  2. ACCEPT_ENCODING (request.py:31,41) — initially set to "gzip,deflate" at line 22, then incrementally built up via += in try/except else blocks based on available compression libraries (brotli, zstd). This is the canonical feature-detection pattern.
  3. HAS_NEVER_CHECK_COMMON_NAME (ssl_.py:59,80) — set in try/except blocks for SSL feature detection.

All of these are well-known Python patterns for conditional initialization and feature detection. Re-assigning module-level constants in feature detection blocks (try/except) and conditional blocks (if/else) is common in projects like urllib3. Mypy does not flag any of these. Pyright only flags 1 of the 5 (ssl_.py:80, as shown by the [mypy: no, pyright: yes] annotation). The implicit Final inference for ALL_CAPS variables is too aggressive for real-world Python code, producing false positives on legitimate patterns that many Python projects use.

Attribution: The PR adds a new treat_all_caps_as_final config option in crates/pyrefly_config/src/config.rs with a default of true (line self.root.treat_all_caps_as_final = Some(true)). The check itself is in pyrefly/lib/binding/bindings.rs in the new method check_for_all_caps_final_reassignment(), which fires whenever a module-level ALL_CAPS name has a prior flow assignment. The problem is that this check doesn't account for common Python patterns like try/except feature detection or conditional reassignment (if/else blocks), which are the exact patterns urllib3 uses.

scikit-learn (+22)

ALL_CAPS treated as Final false positives: All 22 errors flag valid reassignments of ALL_CAPS module-level variables (like LOSS_INSTANCES += [...], X = StandardScaler().fit_transform(X), etc.). These are standard Python patterns, not bugs. The typing spec does not require ALL_CAPS names to be treated as Final. Neither mypy nor pyright flags any of these. The new treat_all_caps_as_final feature defaults to true, which is too strict for real-world code.

Overall: All 22 new errors are false positives caused by pyrefly's new treat_all_caps_as_final feature defaulting to true. The affected code patterns are completely valid Python:

  1. LOSS_INSTANCES += [...] (test_loss.py:56): A list is created on line 54 and extended on line 56 using +=. This is standard list augmentation, not a redefinition of a constant.

  2. X, y = shuffle(X, y, ...) (test_hdbscan.py:28): X and y are first assigned from make_blobs() on line 27, then reassigned from shuffle() on line 28. This is a standard data preprocessing pipeline.

  3. X = StandardScaler().fit_transform(X) (test_hdbscan.py:29): X is transformed in-place, another standard sklearn pattern.

These are not bugs — they are intentional reassignments. The typing spec (https://typing.readthedocs.io/en/latest/spec/qualifiers.html#final) only treats variables as final when explicitly annotated with Final. The ALL_CAPS convention is just that — a convention, not a type system rule. Neither mypy nor pyright flag any of these 22 cases. The default of true for this feature is too aggressive for real-world codebases.

Per-category reasoning:

  • ALL_CAPS treated as Final false positives: All 22 errors flag valid reassignments of ALL_CAPS module-level variables (like LOSS_INSTANCES += [...], X = StandardScaler().fit_transform(X), etc.). These are standard Python patterns, not bugs. The typing spec does not require ALL_CAPS names to be treated as Final. Neither mypy nor pyright flags any of these. The new treat_all_caps_as_final feature defaults to true, which is too strict for real-world code.

Attribution: The PR adds a new treat_all_caps_as_final config option (defaulting to true) in pyrefly/lib/binding/bindings.rs via check_for_all_caps_final_reassignment(). This function checks if a module-level ALL_CAPS name is being reassigned and emits a bad-assignment error. The default of true is set in crates/pyrefly_config/src/config.rs line 1366. This causes all 22 new errors across sklearn, as the project extensively uses patterns like LOSS_INSTANCES += [...], X, y = shuffle(X, y, ...), and X = StandardScaler().fit_transform(X) at module level with ALL_CAPS names.

materialize (+1)

False positive: re-import treated as reassignment of ALL_CAPS Final: The error fires on from materialize.data_ingest.workload import WORKLOADS (line 24) because WORKLOADS was already brought into scope by the star import on line 23 from the same module. Re-importing the same name from the same module is not a reassignment — it's a standard Python idiom. The new check_for_all_caps_final_reassignment check doesn't distinguish between actual value reassignment and harmless re-imports. This is a regression — a false positive that would affect many real-world codebases that use star imports followed by explicit imports.

Overall: This is a false positive. The code on line 23 does from materialize.data_ingest.workload import * and line 24 does from materialize.data_ingest.workload import WORKLOADS, execute_workload. This is a very common Python pattern: star-import for convenience, then explicit import for the names you actually need (often for IDE support, linting, or documentation). The WORKLOADS name is being imported from the exact same module both times — this is not a reassignment to a different value. Pyrefly's new treat_all_caps_as_final feature incorrectly treats a re-import as a reassignment. Neither mypy nor pyright would flag this. The feature's implementation in check_for_all_caps_final_reassignment() only checks whether the name already exists in the current flow, without distinguishing between actual value reassignment and re-importing the same binding.

Attribution: The change to check_for_all_caps_final_reassignment() in pyrefly/lib/binding/bindings.rs introduces the new check. The issue is that the check fires when a name was previously brought into scope via import * (line 23) and then explicitly imported again (line 24). The check sees that WORKLOADS already exists in the current flow (self.scopes.current_flow_idx(name).[is_some()](https://github.com/facebook/pyrefly/blob/main/pyrefly/lib/binding/bindings.rs)) and treats the second import as a reassignment. But re-importing the same name from the same module is not a reassignment — it's a standard Python pattern for making star-imported names explicitly visible. The default value of treat_all_caps_as_final is set to true in pyrefly/lib/state/steps.rs and crates/pyrefly_config/src/config.rs, meaning this fires by default for all projects.

setuptools (+1)

This is a false positive. _T is a TypeVar name following standard Python typing conventions, not a constant. The duplicate _T = TypeVar('_T') on line 677 is identical to the one on line 293 — it's redundant but not a bug. The new treat_all_caps_as_final feature incorrectly treats TypeVar names as constants. Pyright's equivalent reportConstantRedefinition excludes TypeVar assignments. The feature defaulting to true means it creates noise on common, correct patterns across the ecosystem.
Attribution: The check_for_all_caps_final_reassignment() function added in pyrefly/lib/binding/bindings.rs fires on _T because is_constant_name() matches the ALL_CAPS pattern. The feature defaults to true in pyrefly/lib/state/steps.rs and crates/pyrefly_config/src/config.rs (line self.root.treat_all_caps_as_final = Some(true)), causing it to fire on all projects by default. The check doesn't exclude TypeVar definitions, which is why it produces this false positive.

scikit-build-core (+2)

ALL_CAPS treated as Final false positives: The new treat_all_caps_as_final feature defaults to true and flags the common pattern of incrementally building a module-level ALL_CAPS list (EXAMPLES = [comprehension] and EXAMPLES += [more]). Neither mypy nor pyright flags this. The code is correct and idiomatic Python. These are false positives introduced by an overly aggressive default.

Overall: This is a regression. The code pattern in noxfile.py is extremely common in Python:

EXAMPLES = ["c", "abi3", ...]
if condition:
    EXAMPLES.append("fortran")
EXAMPLES = [f"getting_started/{n}" for n in EXAMPLES]  # transform
EXAMPLES += ["downstream/pybind11_example", ...]  # extend

This is a deliberate, incremental construction of a module-level constant. The variable IS effectively constant after the module finishes loading — it's just built up in stages. Treating ALL_CAPS as Final is not required by the typing spec. It's an optional heuristic that both mypy and pyright either don't implement or keep off by default. The PR defaults treat_all_caps_as_final to true, which is more aggressive than any other major type checker. This creates false positives on common, idiomatic Python patterns like the one seen here. The += augmented assignment on line 215 is particularly egregious to flag — it's extending the list, not redefining the variable's meaning.

Per rule 9 (well-known exempt patterns), reassigning module-level constants during module initialization is a standard Python pattern. Flagging it when neither mypy nor pyright would is a regression.

Per-category reasoning:

  • ALL_CAPS treated as Final false positives: The new treat_all_caps_as_final feature defaults to true and flags the common pattern of incrementally building a module-level ALL_CAPS list (EXAMPLES = [comprehension] and EXAMPLES += [more]). Neither mypy nor pyright flags this. The code is correct and idiomatic Python. These are false positives introduced by an overly aggressive default.

Attribution: The PR adds a treat_all_caps_as_final config option in crates/pyrefly_config/src/config.rs with a default of true (line self.root.treat_all_caps_as_final = Some(true)). The check itself is in check_for_all_caps_final_reassignment() in pyrefly/lib/binding/bindings.rs, which fires when a module-level ALL_CAPS name is assigned more than once. This causes the two new bad-assignment errors on EXAMPLES at lines 214 and 215 of noxfile.py.

yarl (+1)

This is a regression. The yarl code uses a completely standard Python pattern: set a default value for NO_EXTENSIONS on line 8, then conditionally override it on line 10 based on sys.implementation.name. This is not a bug — it's intentional feature detection. The PR introduces a new heuristic that treats ALL_CAPS names as implicitly Final, but this heuristic is too aggressive. The typing spec (https://typing.readthedocs.io/en/latest/spec/qualifiers.html#final) only makes variables Final when explicitly annotated as such. Neither mypy nor pyright flag this code. Pyright's reportConstantRedefinition diagnostic only applies to variables explicitly declared as Final, not to ALL_CAPS variables inferred as Final. The variable NO_EXTENSIONS is not annotated with Final — it has a # type: bool comment annotation, which explicitly marks it as bool, not Final[bool]. Reassigning module-level variables in feature detection blocks (like checking sys.implementation.name) is a common, accepted Python pattern. Making this ALL_CAPS-implies-Final heuristic active by default creates false positives on real-world projects.
Attribution: The PR adds a new treat_all_caps_as_final config option that defaults to true (see config.rs line: self.root.treat_all_caps_as_final = Some(true)). The check_for_all_caps_final_reassignment function in pyrefly/lib/binding/bindings.rs fires when a module-level ALL_CAPS name is reassigned. This is what causes the error on NO_EXTENSIONS = True in yarl. The default being true means this fires on all projects unless they opt out.

apprise (+19)

ALL_CAPS treated as Final — platform-conditional reassignment: Variables like DEFAULT_CONFIG_PATHS, DEFAULT_PLUGIN_PATHS, and DEFAULT_STORAGE_PATH are defined with Unix defaults then reassigned inside if platform.system() == 'Windows': blocks. This is a standard Python pattern for cross-platform configuration. The typing spec does not make ALL_CAPS variables Final — only explicit typing.Final annotations do. Flagging these is a false positive.
ALL_CAPS treated as Final — environment variable override: Variables like DEFAULT_STORAGE_PATH are reassigned based on environment variables (e.g., if os.environ.get('APPRISE_STORAGE_PATH', '').strip(): DEFAULT_STORAGE_PATH = ...). This is intentional configuration override behavior, not a bug. Other type checkers (mypy, pyright) do not flag this by default.

Overall: This is a regression. The PR introduces a new feature (treat-all-caps-as-final) that is enabled by default, but it flags a very common and correct Python pattern: reassigning module-level ALL_CAPS variables for platform-specific or environment-specific configuration. In apprise/cli.py, DEFAULT_CONFIG_PATHS is defined on line 97 with Unix paths, then reassigned on line 173 inside if platform.system() == 'Windows': — this is standard cross-platform Python. Similarly, DEFAULT_PLUGIN_PATHS (line 127 → 203) and DEFAULT_STORAGE_PATH (line 158 → 220, and again on line 245 for env var override). These are not bugs — they are intentional, correct reassignments.

The typing spec (https://typing.readthedocs.io/en/latest/spec/qualifiers.html#final) only treats variables as Final when explicitly annotated with typing.Final. ALL_CAPS naming is a convention, not a type system rule. Even pyright, which has reportConstantRedefinition, does NOT enable it by default. Making this default-true creates 19 false positives on just this one project, and the pattern (platform-conditional reassignment of constants) is ubiquitous across the Python ecosystem. The 16/19 pyrefly-only rate confirms these are false positives that other type checkers correctly avoid.

Attribution: The PR adds a new treat_all_caps_as_final config option in crates/pyrefly_config/src/config.rs with a default of true (line self.root.treat_all_caps_as_final = Some(true)). The check itself is in pyrefly/lib/binding/bindings.rs in the new method check_for_all_caps_final_reassignment(), which fires when a module-level ALL_CAPS name is assigned more than once. This is called from bind_name() on every name binding. The default-true setting causes all 19 errors on the apprise project, which uses the common pattern of defining platform-specific defaults by reassigning ALL_CAPS variables inside if platform.system() == 'Windows': blocks and if os.environ.get(...) blocks.

pycryptodome (+1)

The error flags line 746 where DES3 is re-imported via from Crypto.Cipher import DES, DES3, ARC2, CAST, Blowfish. DES3 was already imported on line 37 (from Crypto.Cipher import AES, DES3). This is a module-level re-import of a module object whose name happens to match the ALL_CAPS pattern. This is not a constant being redefined — it's a module being re-imported (with the same value). The new treat_all_caps_as_final feature with its default of true is too aggressive: it treats ALL_CAPS module names (like DES3, which is a cipher module, not a constant) as final and flags re-imports as errors. Neither mypy nor pyright flag this. The feature is convention-based, not spec-mandated, and the default of true causes false positives on legitimate code patterns.
Attribution: The PR adds a new treat_all_caps_as_final config option (defaulting to true) and implements check_for_all_caps_final_reassignment() in pyrefly/lib/binding/bindings.rs. This function checks if a module-level ALL_CAPS name is being reassigned and emits a bad-assignment error. The default of true (set in config.rs line self.root.treat_all_caps_as_final = Some(true)) means this check is active for all projects by default, causing the false positive on the DES3 re-import.

manticore (+2)

ALL_CAPS treated as Final (false positives): Both errors stem from the new treat_all_caps_as_final feature defaulting to true. The DEFAULT_FORK reassignment in evm.py (line 118) is the same value "istanbul" being set again at module level — not a bug, likely an intentional grouping of constants after config setup. The EFLAGS reassignment in make_dump.py (line 426) is inside a while True loop body. It was conditionally assigned on line 359 (inside an if block) and then unconditionally reassigned on line 426 later in the same iteration as part of post-step processing. This is a standard Python pattern of reassigning a variable within a loop. Neither mypy nor pyright flags these. The typing spec does not require ALL_CAPS names to be treated as Final without an explicit Final annotation.

Overall: These are false positives from pyrefly's treat_all_caps_as_final feature. The DEFAULT_FORK variable in evm.py is assigned on line 57 and then reassigned on line 118 with the identical value "istanbul" — this is a common pattern (possibly a copy-paste artifact or intentional grouping of constants) but not a bug. The EFLAGS variable in make_dump.py is a local variable within a while True loop body. It is conditionally assigned on line 359 (inside if instruction.mnemonic.upper() in flags.keys()) and then unconditionally reassigned on line 426 later in the same loop iteration as part of the post-step processing. This is standard Python — reassigning a variable within a loop body is completely normal. Neither mypy nor pyright would flag these. The typing spec does not require ALL_CAPS names to be treated as Final without an explicit Final annotation. The treat_all_caps_as_final feature creates noise on legitimate code patterns when defaulting to true for primer runs on existing projects.

Attribution: The PR adds a new treat_all_caps_as_final config option (defaulting to true) in crates/pyrefly_config/src/config.rs line 1366. The check is implemented in check_for_all_caps_final_reassignment() in pyrefly/lib/binding/bindings.rs. This function fires when a module-level ALL_CAPS name is reassigned. The default of true means all existing projects get this new check applied, causing these two new errors.

schemathesis (+3)

ALL_CAPS conditional assignment treated as Final violation: All 3 errors flag legitimate conditional assignments to ALL_CAPS module-level variables (REPEATS in if/else branches, _FLAG_LETTERS with conditional +=). These are standard Python feature-detection patterns, not Final violations. The new treat_all_caps_as_final heuristic (default true) doesn't distinguish between true reassignment and conditional initialization. Neither mypy nor pyright flags these.

Overall: These are false positives. The code uses a standard Python pattern for version-dependent feature detection:

  1. REPEATS (lines 328-332): Declared with a type annotation REPEATS: tuple[int, ...], then assigned in an if hasattr(sre, 'POSSESSIVE_REPEAT') / else block. Only one branch executes at runtime. This is not a reassignment — it's a conditional initialization.

  2. _FLAG_LETTERS (lines 654-663): Initially assigned a base tuple, then conditionally augmented with += inside if hasattr(sre, 'SRE_FLAG_ASCII'). This is a common pattern for building up configuration based on available features.

The new treat_all_caps_as_final heuristic (defaulting to true) incorrectly treats these conditional assignments as Final violations. Neither mypy nor pyright flags these. The typing spec does not require ALL_CAPS names to be treated as Final — only explicit typing.Final annotations create that constraint (https://typing.readthedocs.io/en/latest/spec/qualifiers.html#final). This falls under rule 9 (well-known exempt patterns): conditional reassignment in feature detection blocks is universally accepted by the Python ecosystem.

Attribution: The PR adds a new treat_all_caps_as_final config option (default true) in pyrefly/lib/binding/bindings.rs via check_for_all_caps_final_reassignment(). This function checks if a module-level ALL_CAPS name already has a flow binding and, if so, emits a bad-assignment error. The default of true (set in config.rs line 1366) means this applies to all projects by default. The check in bindings.rs at line 1822 (self.scopes.current_flow_idx(name).[is_some()](https://github.com/facebook/pyrefly/blob/main/pyrefly/lib/binding/bindings.rs)) triggers on the second assignment to REPEATS and _FLAG_LETTERS, even though these are conditional assignments in if/else branches — the checker doesn't account for the fact that only one branch executes.

mongo-python-driver (+8)

ALL_CAPS reassignment in try/except feature detection: Variables like HAVE_KERBEROS and _USE_PRINCIPAL are set at module level then conditionally reassigned in try/except blocks for feature detection. This is a standard Python idiom. Flagging these as final-variable violations is a false positive. Neither mypy nor pyright flag these.
ALL_CAPS reassignment via star import: The pymongo/auth_oidc.py error comes from star imports that may re-export ALL_CAPS names. This is another false positive from the overly aggressive default.

Overall: This is a regression. The new treat-all-caps-as-final feature defaults to true, causing false positives on a very common Python pattern: feature detection via try/except blocks. Looking at the actual code:

  1. pymongo/asynchronous/auth.py:61_USE_PRINCIPAL = False at line 56, then _USE_PRINCIPAL = True at line 61 inside a conditional within a try block. This is standard feature detection.
  2. pymongo/asynchronous/auth.py:66HAVE_KERBEROS = True at line 55, then HAVE_KERBEROS = False at line 66 inside except ImportError. This is the canonical Python pattern for optional dependency detection.
  3. pymongo/auth_oidc.py:19 — A star import from pymongo.synchronous.auth_oidc import * that apparently re-exports some ALL_CAPS names already imported from pymongo.auth_oidc_shared.

These are all well-established Python patterns. Neither mypy nor pyright flag them. The feature itself is reasonable as an opt-in, but defaulting to true creates noise on real-world codebases. Per rule 9 (well-known exempt patterns), re-assigning module-level constants in try/except feature detection blocks is a common pattern that mypy/pyright would NOT flag.

Per-category reasoning:

  • ALL_CAPS reassignment in try/except feature detection: Variables like HAVE_KERBEROS and _USE_PRINCIPAL are set at module level then conditionally reassigned in try/except blocks for feature detection. This is a standard Python idiom. Flagging these as final-variable violations is a false positive. Neither mypy nor pyright flag these.
  • ALL_CAPS reassignment via star import: The pymongo/auth_oidc.py error comes from star imports that may re-export ALL_CAPS names. This is another false positive from the overly aggressive default.

Attribution: The PR adds a new treat-all-caps-as-final config option (in crates/pyrefly_config/src/config.rs) that defaults to true (line self.root.treat_all_caps_as_final = Some(true)). The check itself is in pyrefly/lib/binding/bindings.rs in the new method check_for_all_caps_final_reassignment(), which fires when a module-level ALL_CAPS name is reassigned. This is called from bind_key() on every assignment. The default of true means all existing projects get this new check without opting in.

asynq (+1)

This is a false positive. In asynq/debug.pyi, DUMP_ALL is defined as an overloaded function with two @overload signatures (lines 19-22). The second @overload definition at line 22 is NOT a reassignment — it's the standard Python pattern for declaring overloaded functions, which requires multiple def statements with the same name. The new treat_all_caps_as_final feature incorrectly treats the second overload definition as a reassignment of a final variable. Neither mypy nor pyright flag this. The feature needs to exclude overload definitions from the reassignment check.
Attribution: The new treat_all_caps_as_final feature (default true) in pyrefly/lib/binding/bindings.rs added the check_for_all_caps_final_reassignment() method. This method fires when it sees a second binding for an ALL_CAPS name at module scope. The problem is that it doesn't account for @overload decorated functions — the second @overload definition of DUMP_ALL at line 22 is being treated as a reassignment of a 'final' variable, when it's actually part of a valid overload group. The check in check_for_all_caps_final_reassignment() calls self.scopes.current_flow_idx(name).[is_some()](https://github.com/facebook/pyrefly/blob/main/pyrefly/lib/binding/bindings.rs) to detect a prior binding, but doesn't check whether the current and prior bindings are both @overload decorated functions.

pandera (+6)

ALL_CAPS treated as Final (false positives): All 6 errors are from the new treat-all-caps-as-final feature defaulting to true. The affected code uses standard Python patterns (feature detection, default overrides, re-binding imports) that are not type errors. Neither mypy nor pyright flags any of these. The typing spec does not require ALL_CAPS names to be treated as Final without an explicit Final annotation.

Overall: This is a regression. The new treat-all-caps-as-final feature defaults to true, which causes false positives on common, correct Python patterns:

  1. Feature detection (PYSPARK_CONNECT_AVAILABLE = False in an except block) — this is a universally accepted pattern for conditional feature availability.
  2. Default value override (ENGINES = ["dask"] when env var is empty) — standard configuration pattern.
  3. Re-binding imported names (UNSUPPORTED_STRATEGY_DTYPE_CLS = set(...)) — converting an imported collection to a mutable copy.

These patterns are explicitly NOT violations of the typing spec. The spec requires an explicit Final annotation to mark something as final (https://typing.readthedocs.io/en/latest/spec/qualifiers.html#final). ALL_CAPS naming is a convention, not a type constraint. Even Pyright's equivalent reportConstantRedefinition defaults to disabled ('none' severity). The fact that 0/6 errors are co-reported by mypy or pyright confirms these are false positives.

The default should be false, not true, to avoid breaking real-world codebases that use these standard patterns. See Rule 9 (well-known exempt patterns) — re-assigning module-level constants in feature detection blocks is a common pattern that mypy/pyright do not flag.

Per-category reasoning:

  • ALL_CAPS treated as Final (false positives): All 6 errors are from the new treat-all-caps-as-final feature defaulting to true. The affected code uses standard Python patterns (feature detection, default overrides, re-binding imports) that are not type errors. Neither mypy nor pyright flags any of these. The typing spec does not require ALL_CAPS names to be treated as Final without an explicit Final annotation.

Attribution: The PR adds a new treat_all_caps_as_final config option in crates/pyrefly_config/src/config.rs with a default of true (line self.root.treat_all_caps_as_final = Some(true)). The check itself is in pyrefly/lib/binding/bindings.rs in the new method check_for_all_caps_final_reassignment(), which fires during bind_definition(). This default-on behavior causes all 6 new errors on the pandera project, which reassigns ALL_CAPS variables as part of standard feature-detection and data-preparation patterns.

pytest-autoprofile (+1)

ALL_CAPS treated as Final (new feature default): The new treat_all_caps_as_final feature defaults to true, causing a false positive on HAS_XDOCTEST_ENV_EFFECTS reassignment in a test file. This is a convention-based check not required by the typing spec, and neither mypy nor pyright flag it by default. The variable is being intentionally reassigned, which is valid Python. This is a regression — the default should be false to avoid breaking existing projects, or at minimum the primer projects should be tested with the new default before shipping.

Overall: This is a new opt-in-by-default feature that treats ALL_CAPS module-level variables as Final. The error on HAS_XDOCTEST_ENV_EFFECTS in tests/test_doctest.py is a false positive — the code is intentionally reassigning this variable (likely in a test context to override behavior). This pattern is common in Python: ALL_CAPS variables are conventionally constants but are frequently reassigned in tests, configuration, and feature-detection blocks. The fact that neither mypy nor pyright flags this (even pyright's similar feature is off by default) confirms this is too strict as a default. The PR's default of true causes noise on real-world projects. While the feature itself is reasonable as an opt-in, defaulting it to true creates regressions on existing codebases.

Attribution: The PR adds a new treat_all_caps_as_final config option (defaulting to true in config.rs line self.root.treat_all_caps_as_final = Some(true)) and the check in check_for_all_caps_final_reassignment() in pyrefly/lib/binding/bindings.rs. This new feature treats any module-level ALL_CAPS variable as implicitly Final, causing the bad-assignment error when the variable HAS_XDOCTEST_ENV_EFFECTS is reassigned in the test file.

ibis (+19)

These are false positives. The errors occur because multiple star imports each bring in TYPE_CHECKING (a Final[bool] from typing), and pyrefly treats the second star import as reassigning a final variable. This is not a meaningful reassignment - it's the same constant value being imported multiple times through different modules. The 0/19 pyright cross-check confirms pyright does not flag this pattern. The TYPE_CHECKING re-import via star imports is a common and harmless pattern that pyrefly's bad-assignment check handles too aggressively. The feature should either not flag re-imports of the same final value through star imports, or handle TYPE_CHECKING as a known special case.
Attribution: The change to check_for_all_caps_final_reassignment() in pyrefly/lib/binding/bindings.rs introduces the new check. The default of true set in pyrefly/lib/state/steps.rs and crates/pyrefly_config/src/config.rs (line self.root.treat_all_caps_as_final = Some(true)) causes it to fire on all projects by default. The check fires on star imports because star imports are treated as assignments, and the check sees a second 'assignment' to the same ALL_CAPS name.

aiohttp (+2)

These are false positives introduced by a new feature (treat-all-caps-as-final) that defaults to true. The feature treats ALL_CAPS module-level names as implicitly Final, but this convention is NOT part of the typing spec — Final requires explicit annotation per https://typing.readthedocs.io/en/latest/spec/qualifiers.html#final. Both flagged patterns are legitimate Python code:

  1. _CONNECTION_CLOSED_EXCEPTION (client_reqrep.py): First assigned on line 80, then reassigned on line 167. Looking at the code, line 80 assigns _CONNECTION_CLOSED_EXCEPTION = ClientConnectionError("Connection closed") and line 167 does the exact same assignment. This is a deliberate pattern — the variable is defined early (before class definitions) and then redefined after the classes it's used with are fully defined.

  2. _AI_ADDRCONFIG (resolver.py): Assigned on line 22 as _AI_ADDRCONFIG = socket.AI_ADDRCONFIG, then on line 24 _AI_ADDRCONFIG &= socket.AI_MASK inside a hasattr guard. This is a standard bit-masking pattern for platform compatibility — it's not a reassignment bug, it's intentional value modification.

Neither mypy nor pyright flags these. The default-on behavior of this feature causes noise on real-world projects that use common Python patterns. Even pyright's similar reportConstantRedefinition is off by default and handles augmented assignments differently.

Attribution: The PR adds a new treat_all_caps_as_final config option (in pyrefly/lib/binding/bindings.rs, function check_for_all_caps_final_reassignment()) that treats any module-level ALL_CAPS name as implicitly Final after its first assignment. The default is true (set in crates/pyrefly_config/src/config.rs line 1366). This causes the two new errors because: (1) _CONNECTION_CLOSED_EXCEPTION is assigned on line 80 and reassigned on line 167, and (2) _AI_ADDRCONFIG is assigned on line 22 and then modified with &= on line 24. The feature is enabled by default for all projects, causing false positives on common Python patterns.

zulip (+50)

ALL_CAPS treated as Final false positives: All 50 errors flag legitimate reassignment of module-level ALL_CAPS variables that use the common 'set default, conditionally override' pattern. These are not bugs — they are idiomatic Python. Neither mypy nor pyright flags any of them. The feature defaults to true but should default to false (like Pyright's equivalent).

Overall: The analysis is factually correct. The 50 errors are all bad-assignment errors caused by the new treat-all-caps-as-final feature treating ALL_CAPS module-level variables as implicitly Final. The source code clearly shows the pattern described: variables like BUILD_PGROONGA_FROM_SOURCE are set to a default value (False on line 158) and then conditionally reassigned (True on lines 162 and 219), and ZULIP_VERSION is set on line 3 and then reassigned on line 14. These are standard, idiomatic Python patterns. The claim that neither mypy nor pyright flags these (0/50 cross-check) is supported by the error data. The claim that no typing spec requires ALL_CAPS to be Final is correct — PEP 591 defines Final as an explicit annotation, not an implicit convention. The comparison to Pyright's reportConstantRedefinition defaulting to disabled (it defaults to "none" severity) is also accurate. All 50 errors are false positives from this new feature's default-on behavior.

Attribution: The change to pyrefly/lib/binding/bindings.rs adding check_for_all_caps_final_reassignment() introduces the new check. The default of true is set in crates/pyrefly_config/src/config.rs line self.root.treat_all_caps_as_final = Some(true). This default causes all 50 errors on the Zulip project, which uses the common pattern of setting ALL_CAPS defaults and conditionally overriding them.

ignite (+2)

The PR introduces a feature (likely treat_all_caps_as_final or similar) that implicitly treats ALL_CAPS variables as Final. This causes false positives on common Python patterns like re-export shims. In ignite/contrib/handlers/neptune_logger.py:41, the code does _INTEGRATION_VERSION_KEY = _INTEGRATION_VERSION_KEY — this is a reassignment of an imported name to ensure it's available in the module's namespace for re-export. Similarly, ROC_AUC = ROC_AUC in ignite/contrib/metrics/roc_auc.py:21. These are standard deprecation shim patterns where a module re-exports names from a new location while maintaining backward compatibility. The typing spec (https://typing.readthedocs.io/en/latest/spec/qualifiers.html#final) states that Final only applies to explicitly annotated variables — inferring finality from naming convention alone is not spec-required behavior. Pyright has an analogous diagnostic (reportConstantRedefinition) but it defaults to off in basic mode, recognizing that such inference can produce false positives. The fact that neither mypy nor pyright flags these patterns by default confirms they are false positives introduced by pyrefly's implicit Final inference for ALL_CAPS names.
Attribution: The PR adds a new treat_all_caps_as_final config option in pyrefly/lib/binding/bindings.rs (function check_for_all_caps_final_reassignment()), defaulting to true in crates/pyrefly_config/src/config.rs (line self.root.treat_all_caps_as_final = Some(true)). This new feature treats ALL_CAPS module-level names as implicitly Final after first assignment. The check fires in check_for_all_caps_final_reassignment() when: the name is ALL_CAPS, not in function scope, not in class body, not already explicitly Final, and has a prior flow assignment. This causes the two new errors on ignite's deprecation shim modules.

dragonchain (+3)

ALL_CAPS conditional reassignment flagged as bad-assignment: All 3 errors flag the standard Python pattern of initializing an ALL_CAPS variable with a default then conditionally reassigning it (e.g., REPORT_ERRORS = False then REPORT_ERRORS = True inside an if-branch, or VERIFICATION_NOTIFICATION = {} then reassigned from env var). This is not a bug — it's intentional conditional initialization. The new treat-all-caps-as-final feature with default true creates false positives on this extremely common pattern. Pyright's equivalent feature defaults to disabled for exactly this reason.

Overall: These are false positives caused by a new feature (treat-all-caps-as-final) that defaults to true. The code uses a completely standard Python pattern: initialize a module-level ALL_CAPS variable with a default value, then conditionally reassign it based on environment variables or configuration. This pattern is ubiquitous in Python codebases. Neither mypy nor pyright flags these. Even pyright's equivalent reportConstantRedefinition defaults to disabled ('none' severity) because this pattern is so common. The typing spec does not require ALL_CAPS names to be treated as Final — only explicitly Final-annotated variables have that restriction. Defaulting this feature to true introduces noise on real-world projects.

Attribution: The change to check_for_all_caps_final_reassignment() in pyrefly/lib/binding/bindings.rs introduces the new check. The default value of true for treat_all_caps_as_final is set in pyrefly/lib/test/util.rs (line treat_all_caps_as_final: true) and crates/pyrefly_config/src/config.rs (line self.root.treat_all_caps_as_final = Some(true)). The default being true causes these errors to appear on existing projects that use the common Python pattern of conditional ALL_CAPS reassignment.

pywin32 (+7)

ALL_CAPS treated as Final — reassignment: VERSION = None followed by VERSION = line.split(...) is an intentional fallback pattern, not a bug. The code has a pyright ignore comment for this exact check.
ALL_CAPS treated as Final — star import overlap: Star imports from win32event, win32api, win32file, win32pipe, shellcon, storagecon may export overlapping ALL_CAPS names. Flagging these as Final reassignment is a false positive — star imports commonly share names.

Overall: The analysis is factually accurate. Let me verify each claim:

  1. VERSION reassignment pattern: The code at adodbapi/setup.py clearly shows VERSION = None at line 31 followed by VERSION = line.split("'")[1] at line 35. This is indeed an intentional fallback pattern, not a bug. The # pyright: ignore[reportConstantRedefinition] comment at line 35 confirms the author is aware of and deliberately suppresses this kind of check.

  2. Star import overlap: In com/win32com/test/testShell.py, lines 12-13 show from win32com.shell.shellcon import * followed by from win32com.storagecon import *. These Windows COM constant modules could indeed export overlapping ALL_CAPS constant names. Similarly, in win32/Demos/service/pipeTestService.py, lines 27-31 show multiple star imports from ntsecuritycon, win32api, win32event, win32file, and win32pipe — these Windows API modules commonly share constant names (e.g., WAIT_OBJECT_0, INFINITE, FILE_FLAG_OVERLAPPED, etc.).

  3. No typing spec requirement: The analysis correctly states there is no typing spec rule requiring ALL_CAPS variables to be treated as Final. PEP 591 introduced Final as an explicit annotation; treating ALL_CAPS as implicitly Final is a heuristic/convention, not a spec requirement.

  4. Pyright's default: The analysis correctly states that Pyright's reportConstantRedefinition defaults to "none" (disabled), which is accurate per Pyright's documentation.

  5. Cross-check data: The error summary confirms 0/7 errors appear in mypy and 0/7 in pyright, supporting the claim that this is a pyrefly-specific heuristic causing false positives.

All factual claims in the analysis are correct.

Attribution: The change to check_for_all_caps_final_reassignment() in pyrefly/lib/binding/bindings.rs introduces the new check. The default of true set in pyrefly/lib/state/steps.rs and crates/pyrefly_config/src/config.rs (line self.root.treat_all_caps_as_final = Some(true)) causes it to fire on all projects by default, producing these false positives on legitimate code patterns like intentional reassignment and star import overlaps.

hydpy (+6)

The treat-all-caps-as-final feature defaults to true and produces false positives in two common patterns: (1) explicit imports followed by star imports from the same module (line 35 of __init__.py), where names like SAND are first imported explicitly and then re-imported via *, and (2) bare type annotations of ALL_CAPS names (lines 118-122 of mypy_plugin.py) followed by their first actual assignment via tuple unpacking on line 124. In pattern (1), star re-imports of the same names from the same module are idiomatic and not true reassignments. In pattern (2), bare annotations (e.g., MODEL_MAP: dict[str, dict[str, tuple[str, str]]]) without = are not assignments per Python semantics — they declare the type but do not bind a value. Pyrefly's treat-all-caps-as-final feature apparently treats these bare annotations as Final declarations, then flags the subsequent first actual assignment (MODEL_MAP, VAR_MAP_1, VAR_MAP_2, VAR_INFO, VAR_SHAPE = load(file_)) as reassignment of a Final variable. This is a false positive because the annotation-only line never assigned a value. Neither mypy nor pyright flags these patterns, consistent with the cross-check showing 0/6 overlap.
Attribution: The new treat-all-caps-as-final feature added in pyrefly/lib/binding/bindings.rs (specifically check_for_all_caps_final_reassignment()) with default true (set in crates/pyrefly_config/src/config.rs line 1366) causes all 6 errors. The check at line 1826 fires when current_flow_idx(name).[is_some()](https://github.com/facebook/pyrefly/blob/main/pyrefly/lib/binding/bindings.rs) — meaning the name was previously seen. For the star import case, the explicit imports on lines 10-32 count as the first binding, making the star import on line 35 look like a reassignment. For the pickle case, the bare annotations on lines 118-122 apparently count as a first binding, making the actual assignment on line 124 look like a reassignment.

dd-trace-py (+14)

ALL_CAPS treated as Final: All 14 errors stem from the treat_all_caps_as_final feature defaulting to true. The typing spec explicitly permits (but does not require) type checkers to treat ALL_CAPS module-level variables as implicitly Final. Some flagged cases (db.py duplicate SYSTEM, patch.py duplicate _RETRYABLE_OPERATIONS) appear to be genuine bugs. Others are intentional reassignment patterns common in Python. 0/14 are co-reported by mypy or pyright. While the feature is spec-permitted, enabling it by default produces false positives on real-world code that intentionally reassigns ALL_CAPS variables.

Overall: This is a new feature that treats ALL_CAPS module-level variables as implicitly Final, which is permitted (but not required) by the typing spec. The typing spec at https://typing.readthedocs.io/en/latest/spec/qualifiers.html explicitly states that 'Type checkers may support treating uppercase module-level variables as implicitly Final,' so this behavior does not contradict the spec — it is a spec-sanctioned optional feature.

However, enabling it by default does produce false positives on real-world code. Looking at the specific cases:

  1. db.py line 6: SYSTEM = "db.system" is defined identically on line 4 — this is a genuine duplicate/bug.
  2. patch.py line 60: _RETRYABLE_OPERATIONS is redefined with hardcoded strings instead of the constants used on line 57 — this also appears to be a genuine bug (the second definition shadows the first with equivalent but hardcoded values).
  3. process_tags/init.py line 27: _ALLOWED_CHARS = _ALLOWED_CHARS = frozenset(...) uses a double-assignment pattern that is syntactically valid Python but triggers the checker.

Some of the flagged cases appear to be genuine bugs, while others are intentional patterns. The feature is spec-permitted but defaulting to true without opt-in does produce noise on projects with intentional ALL_CAPS reassignments. Note that Pyright's reportConstantRedefinition actually defaults to warning in basic mode, not off.

0/14 are co-reported by mypy or pyright, though this is partly because mypy does not implement this optional spec feature and pyright may handle it differently.

Attribution: The change in pyrefly/lib/binding/bindings.rs adding check_for_all_caps_final_reassignment() introduces the new check. The default of true is set in crates/pyrefly_config/src/config.rs at line self.root.treat_all_caps_as_final = Some(true). This default-on behavior causes all 14 new errors across the ddtrace project.

meson (+16)

ALL_CAPS treated as Final false positives: All 16 errors are from the new treat_all_caps_as_final feature defaulting to true. The affected code uses += to incrementally build module-level lists (e.g., ALL_STDS += [...] in c.py and cpp.py) or reassigns constants in test files. This is standard Python — not a bug. The typing spec does not mandate treating ALL_CAPS as Final. Neither mypy nor pyright flag any of these. These are false positives introduced by an overly aggressive default.

Overall: This PR introduces a new feature that treats ALL_CAPS module-level variables as implicitly Final. The feature defaults to true, which means it fires on existing projects that use the extremely common Python pattern of building up a list incrementally:

ALL_STDS = ['c89', 'c9x', ...]
ALL_STDS += [f'gnu{std[1:]}' for std in ALL_STDS]
ALL_STDS += ['iso9899:1990', ...]

This is not a real bug — it's an intentional, idiomatic pattern for constructing a module-level constant in multiple steps. The typing spec (https://typing.readthedocs.io/en/latest/spec/qualifiers.html#final) only treats variables as Final when explicitly annotated with Final. Neither mypy nor pyright flag any of these 16 locations. The feature is opt-in in Pyright (reportConstantRedefinition) and is off by default there. Making it default-on in pyrefly introduces 16 false positives on this project alone. These are regressions — correct code is being flagged incorrectly.

Per-category reasoning:

  • ALL_CAPS treated as Final false positives: All 16 errors are from the new treat_all_caps_as_final feature defaulting to true. The affected code uses += to incrementally build module-level lists (e.g., ALL_STDS += [...] in c.py and cpp.py) or reassigns constants in test files. This is standard Python — not a bug. The typing spec does not mandate treating ALL_CAPS as Final. Neither mypy nor pyright flag any of these. These are false positives introduced by an overly aggressive default.

Attribution: The PR adds a new treat_all_caps_as_final config option (in crates/pyrefly_config/src/config.rs, pyrefly/lib/binding/bindings.rs, etc.) that defaults to true. The check_for_all_caps_final_reassignment() method in pyrefly/lib/binding/bindings.rs fires a bad-assignment error whenever a module-level ALL_CAPS name is assigned more than once. The default of true (set in config.rs line self.root.treat_all_caps_as_final = Some(true)) means this fires on all projects without opt-in, causing these 16 new errors on the meson project.

mypy (+2)

This PR introduces a new feature that treats ALL_CAPS module-level names as implicitly Final, defaulting to true. This causes two false positives:

  1. mypy/defaults.py:25: USER_CONFIG_FILES is declared as list[str] on line 22 (no Final annotation), then intentionally reassigned on line 25 to expand user paths via os.path.expanduser. This is a deliberate, correct pattern — the variable is mutable by design.

  2. _ctypes.pyi:144: POINTER is defined using @overload decorators (lines 141-144). The second @overload definition of POINTER is being flagged as a reassignment, but overload definitions are not reassignments — they're part of the standard typing pattern for declaring multiple signatures.

The default of true is too aggressive. Neither mypy nor pyright flag these. Pyright's equivalent (reportConstantRedefinition) defaults to none severity. The typing spec at https://typing.readthedocs.io/en/latest/spec/qualifiers.html#uppercase-names says type checkers MAY treat uppercase names as Final but this is optional, and the implementation here has bugs (treating overloads as reassignments) and is too strict by default for real-world code.

Attribution: The PR adds a new treat_all_caps_as_final config option that defaults to true (see config.rs line: self.root.treat_all_caps_as_final = Some(true)). The check_for_all_caps_final_reassignment() method in pyrefly/lib/binding/bindings.rs fires on any module-level ALL_CAPS name that has a prior assignment in the current flow. This causes two false positives: (1) USER_CONFIG_FILES in mypy/defaults.py is intentionally reassigned (it's a mutable list, not annotated as Final), and (2) POINTER in _ctypes.pyi is an overloaded function definition, not a reassignment.

speedrun.com_global_scoreboard_webapp (+1)

This is a regression. The PR introduces a new heuristic (treat-all-caps-as-final) that is enabled by default (true). This heuristic treats module-level ALL_CAPS names as implicitly Final, which is NOT required by the typing spec — the spec only treats explicitly annotated Final variables as final (https://typing.readthedocs.io/en/latest/spec/qualifiers.html#final). The pattern in this code — initializing __REDIS = None and then conditionally reassigning it — is extremely common in Python. Neither mypy nor pyright flag this by default. Pyright's equivalent (reportConstantRedefinition) defaults to off. Defaulting this to true causes false positives on legitimate code patterns across the ecosystem. The variable __REDIS is set to None on line 76 as a default, then conditionally reassigned to a redislite.Redis instance on line 80 inside an if block — this is standard Python for platform-conditional initialization.
Attribution: The PR adds a new treat_all_caps_as_final config option that defaults to true (see config.rs line: self.root.treat_all_caps_as_final = Some(true)). The check_for_all_caps_final_reassignment function in pyrefly/lib/binding/bindings.rs fires when a module-level ALL_CAPS name is reassigned. Since __REDIS matches the ALL_CAPS pattern (the is_constant_name check considers names with all uppercase letters and underscores as constants, and __REDIS qualifies), the reassignment on line 80 triggers the error. The default being true means this fires on all projects in the primer without opt-in.

core (+10)

ALL_CAPS treated as Final (duplicate definitions): All 10 errors flag duplicate ALL_CAPS constant definitions at module level. The specific cases are genuine duplicates (same value assigned twice) representing copy-paste bugs. However, the feature is enabled by default in pyrefly while neither mypy nor pyright implements equivalent behavior. Per the typing spec, treating ALL_CAPS as implicitly Final is optional ('MAY'), not required. While these 10 catches are true positives, enabling this by default is stricter than the ecosystem norm and risks false positives for intentional ALL_CAPS reassignments in other codebases.

Overall: The 10 errors all flag duplicate ALL_CAPS constant definitions at module level where the same variable name is assigned twice with the same value (copy-paste errors). Looking at the source code: ATTR_PRIORITY is defined on line 27 and again on line 32 in habitica/const.py; SIGNAL_ADD_DEFAULT_LINKS is defined on line 102 and again on line 110 in insteon/const.py; ATTR_STATUS is defined on line 39 and again on line 44 in linux_battery/sensor.py. These are genuine duplicate definitions that represent copy-paste bugs.

The errors arise because pyrefly treats ALL_CAPS module-level variables as implicitly Final, per the typing spec's allowance that type checkers MAY do so. The cross-check shows 0/10 errors appear in mypy and 0/10 in pyright, confirming neither of those tools treats ALL_CAPS as implicitly Final.

The typing spec (PEP 591 and the typing spec documentation) states that type checkers MAY treat ALL_CAPS variables as implicitly Final - this is optional behavior, not required. Neither mypy nor pyright implements this inference. Pyrefly enabling this by default creates a stricter baseline than the ecosystem norm.

While the specific cases caught here are genuine bugs (true duplicate definitions that should be cleaned up), the underlying feature - treating all ALL_CAPS variables as Final - will also flag intentional reassignments of ALL_CAPS variables that are legitimate patterns in Python (e.g., conditional platform-specific constant definitions, configuration overrides, or test fixtures). The feature catches real bugs in these 10 cases, but enabling it by default without an opt-in mechanism risks false positives across the broader ecosystem of Python projects.

Attribution: The change in pyrefly/lib/binding/bindings.rs adding check_for_all_caps_final_reassignment() implements the check. The default of true is set in crates/pyrefly_config/src/config.rs line self.root.treat_all_caps_as_final = Some(true). This default-on behavior causes all 10 new errors.

trio (+8)

The new treat-all-caps-as-final feature defaults to true, causing false positives on legitimate Python patterns: multi-line constant initialization (_NUMERIC_ONLY = X; _NUMERIC_ONLY |= Y), conditional platform imports (SIGKILL: SignalType then from signal import SIGKILL), and star imports. While the typing spec (PEP 591) does mention that type checkers MAY treat module-level all-caps variables as implicitly Final, this is an optional behavior, not a required one. The cross-check data shows 7/8 errors also appear in pyright, indicating pyright does flag these by default (pyright's reportConstantRedefinition is enabled in basic type checking mode). However, these patterns represent legitimate, well-structured Python code: platform-conditional imports with type annotations, incremental constant construction, and star imports. Defaulting this feature to enabled creates noise on real-world codebases that use these common patterns.
Attribution: The change in pyrefly/lib/binding/bindings.rs adding check_for_all_caps_final_reassignment() introduces the new check. The default of true set in crates/pyrefly_config/src/config.rs (self.root.treat_all_caps_as_final = Some(true)) causes all projects to get this behavior without opt-in. The is_constant_name() check combined with current_flow_idx().[is_some()](https://github.com/facebook/pyrefly/blob/main/pyrefly/lib/binding/bindings.rs) treats any second assignment to an ALL_CAPS module-level name as a Final violation.

xarray (+2)

These are false positives. The code uses a standard Python pattern: declare a type annotation without assignment (line 74), then conditionally initialize in a try/except block (lines 75-78). Neither branch is a reassignment — both are the first actual assignment. The new treat_all_caps_as_final feature (defaulting to true) incorrectly treats the bare annotation as an assignment, causing both try and except branches to be flagged. Pyright's equivalent reportConstantRedefinition handles this pattern correctly and would not flag it. Neither mypy nor pyright reports these errors.
Attribution: The PR adds a new treat_all_caps_as_final config option (default true) in pyrefly/lib/binding/bindings.rs. The method check_for_all_caps_final_reassignment() checks if a module-level ALL_CAPS name already has a flow entry (current_flow_idx(name).[is_some()](https://github.com/facebook/pyrefly/blob/main/pyrefly/lib/binding/bindings.rs)) and flags reassignment. The bug is that in a try/except pattern like this, the type annotation on line 74 (OUT_OF_BOUNDS_TIMEDELTA_ERRORS: tuple[type[Exception], ...]) creates a flow entry without an actual assignment, so both the try branch (line 76) and except branch (line 78) are incorrectly treated as reassignments. The check in check_for_all_caps_final_reassignment() doesn't account for the fact that a bare type annotation without = is not an assignment — it's a declaration. Both branches are the first assignment, not reassignments.

spack (+1)

This is a false positive. The pattern LC_ID_DYLIB = LC_ID_DYLIB is a standard Python re-export idiom — the module imports the name and re-exports it as part of its own API. The value doesn't change. The new treat_all_caps_as_final heuristic (enabled by default) incorrectly flags this as a reassignment of a final variable. The typing spec does not treat ALL_CAPS names as implicitly Final — that requires an explicit Final annotation. This is a regression because pyrefly is introducing a false positive on valid, idiomatic code that neither mypy nor pyright would flag.
Attribution: The new check_for_all_caps_final_reassignment() function in pyrefly/lib/binding/bindings.rs fires on line 197 because LC_ID_DYLIB was first bound by the import on line 12 and then re-assigned on line 197. The feature defaults to true (set in pyrefly/lib/state/steps.rs and crates/pyrefly_config/src/config.rs), causing this false positive on a standard re-export pattern.

parso (+1)

This is a regression. The pattern _NEEDS_SPACE: Tuple[str, ...] = (...); _NEEDS_SPACE += _BITWISE_OPERATOR is a completely standard Python idiom for building up module-level constants incrementally. The variable is not annotated with Final, and the typing spec does not require ALL_CAPS names to be treated as final — it only says type checkers MAY do so optionally. The PR defaults treat_all_caps_as_final to true, which means this new check fires on existing codebases that never opted into this behavior. Neither mypy nor pyright would flag this by default. Pyright's equivalent (reportConstantRedefinition) defaults to none severity. This is a false positive — the code is correct and intentional. The feature itself may be useful as an opt-in, but defaulting to true causes regressions on real-world code.
Attribution: The PR adds a new treat_all_caps_as_final config option (defaulting to true in pyrefly/lib/state/steps.rs and crates/pyrefly_config/src/config.rs line 1366). The check_for_all_caps_final_reassignment() method in pyrefly/lib/binding/bindings.rs checks if a module-level ALL_CAPS name is being reassigned and emits ErrorKind::BadAssignment. Since _NEEDS_SPACE matches the ALL_CAPS pattern (checked by is_constant_name()), and it's assigned on line 19 then reassigned with += on line 24, the new check fires. The critical issue is that the default is true, causing this to fire on all existing projects without opt-in.

rich (+1)

This is a false positive. The code at line 305 (from .box import DOUBLE, ROUNDED) is a re-import inside a if __name__ == '__main__' block. The name ROUNDED was already imported at module level on line 4. This is a standard Python pattern — re-importing names in a guarded block for use in a script section. It's not a reassignment of a constant value. Neither mypy nor pyright flag this. Even Pyright's reportConstantRedefinition (which pyrefly's docs cite as equivalent) does not flag re-imports. The feature defaults to true, causing false positives on legitimate code patterns in well-known projects like rich. The implementation in check_for_all_caps_final_reassignment() needs to exclude re-imports of the same name from the same module, or at minimum exclude re-imports entirely.
Attribution: The PR adds a new treat_all_caps_as_final config option (default true) and implements check_for_all_caps_final_reassignment() in pyrefly/lib/binding/bindings.rs. This function checks if a name matches is_constant_name() (ALL_CAPS), is at module scope, and has a previous flow entry — if so, it emits a bad-assignment error. The problem is that this check fires on re-imports (line 305 of rich/panel.py re-imports ROUNDED which was already imported at line 4), treating a re-import as a reassignment of a final variable. The check in check_for_all_caps_final_reassignment() doesn't distinguish between actual value reassignment and re-importing the same name.

scrapy (+8)

This is a regression. The PR introduces a new feature (treat-all-caps-as-final) that defaults to true, which causes false positives on the extremely common Python pattern of feature-detection flags:

HAS_SOCKS = HAS_HTTP2 = False
try:
    import h2.exceptions
    HAS_HTTP2 = True  # flagged as bad-assignment
except ImportError:
    pass

This pattern (initialize a flag to False, then set it to True inside a try/except import block) is ubiquitous in Python projects. The variables HAS_HTTP2, HAS_SOCKS, and DOWNLOAD_FAILED_EXCEPTIONS are intentionally reassigned — they are mutable configuration flags, not constants.

The typing spec (https://typing.readthedocs.io/en/latest/spec/qualifiers.html#final) only treats variables as final when explicitly annotated with Final. Inferring finality from naming convention is a heuristic, and applying it by default to all ALL_CAPS variables is too aggressive. Neither mypy nor pyright flag any of these 8 locations. Even pyright's equivalent reportConstantRedefinition defaults to none severity.

This falls squarely under rule 9 (WELL-KNOWN EXEMPT PATTERNS): re-assigning module-level constants in feature detection blocks (try/except) is a standard pattern that mypy/pyright do not flag. The default should be false, not true, to avoid flooding users with false positives on legitimate code.

Attribution: The PR adds a new treat_all_caps_as_final config option (defaulting to true) in crates/pyrefly_config/src/config.rs line 1366. The check is implemented in pyrefly/lib/binding/bindings.rs in the new method check_for_all_caps_final_reassignment(). This method fires for any module-level ALL_CAPS variable that is assigned more than once, treating the first assignment as implicitly Final. The default of true causes these errors to appear on projects like scrapy that use the common HAS_X = False; try: import x; HAS_X = True pattern.

optuna (+2)

These are false positives. The variable C in this Optuna tutorial is a regular hyperparameter variable, not a constant. It is first assigned C = 0.01 at module level (line 35) and then intentionally reassigned inside for loops (lines 77 and 180) as part of hyperparameter optimization. The user never declared C as Final. The new treat-all-caps-as-final feature defaults to true, which causes it to flag legitimate reassignments of single-letter ALL_CAPS variables like C, X, N, etc. that are commonly used as regular variables in scientific/ML code. Neither mypy nor pyright would flag this by default. While the feature itself may be useful as an opt-in, defaulting it to true creates false positives on real-world code that uses ALL_CAPS variable names without intending them to be final.
Attribution: The PR adds a new treat_all_caps_as_final config option (in crates/pyrefly_config/src/config.rs) that defaults to true (line self.root.treat_all_caps_as_final = Some(true)). The check is implemented in pyrefly/lib/binding/bindings.rs in the new method check_for_all_caps_final_reassignment(), which fires when a module-level ALL_CAPS name is reassigned. The variable C matches the ALL_CAPS pattern, so both reassignments at lines 77 and 180 are flagged.

discord.py (+3)

ALL_CAPS bare annotation treated as assignment (CREATE_NO_WINDOW): Line 67 CREATE_NO_WINDOW: int is a bare type annotation, not an assignment. Lines 70/72 are the first actual assignments in an if/else platform check. The heuristic incorrectly treats the annotation as creating a 'first assignment' flow entry.
ALL_CAPS try/except feature detection reassignment (_ZSTD_SOURCE): Line 87 initializes _ZSTD_SOURCE = None, then lines 92 and 97 reassign it inside nested try/except blocks for optional dependency detection. This is a universally accepted Python pattern (Rule 9). Neither mypy nor pyright flags this. The variable even starts with _ (private), making the 'constant' inference even less appropriate.

Overall: The analysis is factually correct.

  1. CREATE_NO_WINDOW in player.py: Line 67 CREATE_NO_WINDOW: int is indeed a bare type annotation with no assignment (no = sign). Lines 70 and 72 are the first actual assignments within an if/else block (if sys.platform != 'win32'). The pyrefly heuristic treating the bare annotation as establishing finality and then flagging line 70 as a reassignment is correctly identified as a false positive.

  2. _ZSTD_SOURCE in utils.py: Line 87 _ZSTD_SOURCE: Literal['zstandard', 'compression.zstd'] | None = None is the initial assignment. Lines 92 and 97 reassign it inside nested try/except blocks for optional dependency detection (zstandard vs compression.zstd). This is correctly identified as a standard Python feature detection pattern using try/except. The variable does start with an underscore, indicating it's private. The analysis correctly notes that neither mypy nor pyright would flag these reassignments as errors.

All claims about line numbers, code behavior, and the nature of the patterns are verified against the source code.

Attribution: The PR adds a treat_all_caps_as_final config option (defaulting to true) and implements check_for_all_caps_final_reassignment() in pyrefly/lib/binding/bindings.rs. This function fires when: (1) the name is ALL_CAPS, (2) we're at module scope, (3) the name is not explicitly Final, and (4) there's already a flow entry for the name. The problem is that this heuristic doesn't account for common Python patterns: bare type annotations without assignment (the CREATE_NO_WINDOW: int case — the annotation creates a flow entry but isn't a real assignment), and try/except feature detection blocks (the _ZSTD_SOURCE case). The default of true in pyrefly/lib/state/steps.rs and pyrefly/lib/test/util.rs means all projects get this behavior.

schema_salad (+2)

The PR introduces a new feature (treat_all_caps_as_final) that defaults to true, causing pyrefly to treat ALL_CAPS module-level variables as Final and flag reassignments. However, this is a convention-based heuristic, not a typing spec requirement. The code in setup.py uses a completely standard pattern: initialize USE_MYPYC = False, then conditionally set it to True based on CLI args or environment variables. This is not a bug — it's intentional control flow. Neither mypy nor pyright flags this. Even Pyright's equivalent (reportConstantRedefinition) defaults to disabled ('none'). By defaulting this to true, pyrefly introduces false positives on legitimate, widely-used Python patterns. The feature itself may be useful as an opt-in check, but defaulting it to true causes regressions on real-world code.
Attribution: The PR adds a new treat_all_caps_as_final config option (in crates/pyrefly_config/src/config.rs) that defaults to true (line self.root.treat_all_caps_as_final = Some(true)). The check itself is in pyrefly/lib/binding/bindings.rs in the new method check_for_all_caps_final_reassignment(), which fires when a module-level ALL_CAPS name is reassigned. This is called from bind_key() on every assignment. Because the default is true, all projects without explicit configuration get this behavior, causing false positives on legitimate reassignment patterns like USE_MYPYC = False followed by USE_MYPYC = True.

Suggested fixes

Summary: The new treat_all_caps_as_final feature defaults to true, causing 300+ false positive bad-assignment errors across 49 projects on legitimate Python patterns (try/except feature detection, conditional reassignment, star imports, bare annotations, overloads, re-imports).

1. In configure() in crates/pyrefly_config/src/config.rs, change the default value of treat_all_caps_as_final from Some(true) to Some(false). The line self.root.treat_all_caps_as_final = Some(true); should become self.root.treat_all_caps_as_final = Some(false);. This makes the feature opt-in rather than opt-out, matching pyright's reportConstantRedefinition which defaults to none severity. The typing spec says type checkers MAY treat ALL_CAPS as Final — it's optional, not required. Defaulting to true causes ~300+ false positives across 49 projects on legitimate patterns (try/except feature detection, conditional platform reassignment, star imports, bare annotations, overloads, re-exports). Changing the default to false eliminates all 49 project regressions while preserving the feature for users who explicitly opt in.

Files: crates/pyrefly_config/src/config.rs
Confidence: high
Affected projects: pip, openlibrary, aioredis, cloud-init, egglog-python, rotki, steam.py, pytest, jax, cwltool, DateType, prefect, scipy, colour, urllib3, scikit-learn, materialize, setuptools, scikit-build-core, yarl, apprise, pycryptodome, manticore, schemathesis, mongo-python-driver, asynq, pandera, pytest-autoprofile, ibis, aiohttp, zulip, ignite, dragonchain, pywin32, hydpy, dd-trace-py, meson, mypy, speedrun.com_global_scoreboard_webapp, core, trio, xarray, spack, parso, rich, scrapy, optuna, discord.py, schema_salad
Fixes: bad-assignment
Every single one of the 49 regressions is caused by this feature defaulting to true. The vast majority of errors (280+/300+) are pyrefly-only — neither mypy nor pyright reports them. The patterns being flagged (try/except feature detection, conditional reassignment, star imports, bare type annotations followed by assignment, overload definitions, re-imports) are all well-established, idiomatic Python. Changing the default to false is the minimal, safe fix that eliminates all regressions.

2. If the team wants to keep the default as true, then check_for_all_caps_final_reassignment() in pyrefly/lib/binding/bindings.rs needs multiple guard conditions to avoid false positives on common patterns. Specifically: (1) Skip star imports — when the current binding comes from a from X import * statement, do not flag it as reassignment. (2) Skip bare type annotations — if the prior flow entry is an annotation-only binding (no = assignment), don't treat it as establishing finality. (3) Skip overload definitions — if both the prior and current bindings are @overload-decorated functions, don't flag. (4) Skip re-imports — if both the prior and current bindings are imports of the same name (possibly from the same module), don't flag. (5) Skip try/except and if/else branches — if the reassignment is in a different control flow branch (try vs except, if vs else), don't flag since only one branch executes. Add these guards before the self.error() call in check_for_all_caps_final_reassignment(), e.g.: if self.is_star_import(idx) || self.is_annotation_only(prior_idx) || self.is_overload_def(idx) || self.is_reimport_of_same_name(prior_idx, idx) || self.is_in_different_branch(prior_idx, idx) { return; }

Files: pyrefly/lib/binding/bindings.rs
Confidence: medium
Affected projects: pip, openlibrary, aioredis, cloud-init, egglog-python, rotki, steam.py, pytest, jax, cwltool, DateType, prefect, scipy, colour, urllib3, scikit-learn, materialize, setuptools, scikit-build-core, yarl, apprise, pycryptodome, manticore, schemathesis, mongo-python-driver, asynq, pandera, pytest-autoprofile, ibis, aiohttp, zulip, ignite, dragonchain, pywin32, hydpy, dd-trace-py, meson, mypy, speedrun.com_global_scoreboard_webapp, core, trio, xarray, spack, parso, rich, scrapy, optuna, discord.py, schema_salad
Fixes: bad-assignment
This is the alternative fix if the team insists on keeping default=true. The current implementation is too simplistic — it only checks current_flow_idx(name).is_some() without considering the nature of the prior or current binding. The false positives break down into clear categories: star imports (rotki, ibis, steam.py, openlibrary, materialize, mongo-python-driver, pywin32 — ~30 errors), bare annotations (jax, discord.py, xarray, hydpy — ~10 errors), try/except feature detection (pip, urllib3, scrapy, aioredis, mongo-python-driver — ~25 errors), conditional if/else (cloud-init, apprise, schemathesis, zulip — ~70 errors), overloads (asynq, mypy — ~3 errors), and re-imports (rich, pycryptodome, ignite — ~5 errors). However, implementing all these guards correctly is complex and error-prone, so changing the default to false (suggestion 1) is strongly preferred.


Was this helpful? React with 👍 or 👎

Classification by primer-classifier (49 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.

option to treat ALL_CAPS variables as Final

2 participants