Skip to content

chore(python): cover overloaded-ctor casing on lowercase types#4811

Merged
dbrattli merged 1 commit into
mainfrom
fix/python-type-name-casing-followup
Jul 17, 2026
Merged

chore(python): cover overloaded-ctor casing on lowercase types#4811
dbrattli merged 1 commit into
mainfrom
fix/python-type-name-casing-followup

Conversation

@dbrattli

@dbrattli dbrattli commented Jul 17, 2026

Copy link
Copy Markdown
Collaborator

Follow-up to #4807.

1. Regression test for the overload-suffix casing path

#4807 fixed Python class/member declarations and references disagreeing on casing for lowercase-named types, but its test (type shape with a single constructor) never exercised the overload-suffix path called out in the PR description (shape__ctor_Z524259A4 declared but shape__ctor_z524259a4 imported).

This gives shape a second, overloaded constructor and references both across files. Transpiled output confirms declaration and import agree on the lowercased suffix:

# Misc/util2.py
def shape__ctor_z524259a4(size: int32) -> Shape: ...
def shape__ctor_z721c83c5(label: str) -> Shape: ...
# test_misc.py
from Misc.util2 import (..., shape__ctor_z524259a4, Shape as Shape_1, shape__ctor_z721c83c5, ...)

Before the #4807 fix, the declaration kept ...Z524259A4 while the import used ...z524259a4ImportError.

2. Accurate comments on the composed-name toPythonNaming

While reviewing the double toPythonNaming application in getMemberDeclarationName, I traced (via quicktest) exactly what the unconditional outer call does:

  • It mirrors the re-casing applied at import/reference sites, which is what keeps declarations and references consistent (the whole point of fix(python): make class declarations and references agree on type names #4807).
  • As a side effect, being unconditional it also re-cases [<CompiledName>] members. This is a no-op for class/nested-module members (uppercase entity/module prefix), so their compiled name survives — but a root-level [<CompiledName>] function starting lowercase gets snake_cased ([<CompiledName("rootLevelCompiled")>]root_level_compiled).

This is a pre-existing tension, not something this PR changes: cross-file references to such a function were already broken before #4807 (ImportError), so #4807 traded "compiled name honored but cross-file broken" for "always consistent but not honored verbatim". A fully correct fix would need the import printer to be CompiledName-aware (it only sees a bare string today) — out of scope here. This PR just documents the real behavior instead of the earlier misleading "idempotent, harmless" note.

No compiler behavior change — comments only.

Testing

./build.sh test python — all 2405 tests pass (run against the initial version of this PR; item 2 is comments-only).

🤖 Generated with Claude Code

@github-actions

Copy link
Copy Markdown
Contributor

Python Type Checking Results (Pyright)

Metric Value
Total errors 34
Files with errors 4
Excluded files 4
New errors ✅ No
Excluded files with errors (4 files)

These files have known type errors and are excluded from CI. Remove from pyrightconfig.ci.json as errors are fixed.

File Errors Status
temp/tests/Python/test_hash_set.py 18 Excluded
temp/tests/Python/test_applicative.py 12 Excluded
temp/tests/Python/test_nested_and_recursive_pattern.py 2 Excluded
temp/tests/Python/fable_modules/thoth_json_python/encode.py 2 Excluded

Follow-up to #4807.

Add a regression test for the overload-suffix casing path on a lowercase
type name: an overloaded constructor is emitted as a module-level name
(`shape__ctor_z<hash>`) and imported across files, so the declaration and
the import must agree on the suffix casing, not just the base name. The
existing `type shape` has a single constructor and so never exercised the
suffix path.

Also expand the comments in `getMemberDeclarationName` to describe what the
unconditional `toPythonNaming` on the composed name actually does: it mirrors
the re-casing applied at import/reference sites (keeping declarations and
references consistent), but as a side effect overrides the [<CompiledName>]
skip for root-level compiled names that start lowercase and thus have no
uppercase entity/module prefix.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@dbrattli
dbrattli force-pushed the fix/python-type-name-casing-followup branch from 65304dd to c0b6d06 Compare July 17, 2026 18:26
@dbrattli
dbrattli merged commit 2fc9c14 into main Jul 17, 2026
32 checks passed
@dbrattli
dbrattli deleted the fix/python-type-name-casing-followup branch July 17, 2026 18:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant