Skip to content

fix(python): make class declarations and references agree on type names#4807

Merged
dbrattli merged 2 commits into
fable-compiler:mainfrom
caroott:fix/python-type-name-casing
Jul 17, 2026
Merged

fix(python): make class declarations and references agree on type names#4807
dbrattli merged 2 commits into
fable-compiler:mainfrom
caroott:fix/python-type-name-casing

Conversation

@caroott

@caroott caroott commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Fixes #4806

Class declarations are PascalCased on the Python target, but references to them are not, so a type with a lowercase name gets declared as class Shape while other modules import shape:

from lib import (shape__ctor, shape, shape__get_size)
ImportError: cannot import name 'shape' from 'lib'. Did you mean: 'Shape'?

First commit: all entity names funnel through getEntityDeclarationName, so the PascalCasing is applied there (Python branch only) and declarations and references agree by construction. The same commit fixes the equivalent mismatch for member names: reference sites re-case the full composed name, so a lowercase member with an overload suffix was declared as shape__ctor_Z524259A4 but imported as shape__ctor_z524259a4. The composed declaration name now gets the same casing convention.

Second commit: when an imported union's name collides with a local declaration, the import is correctly aliased (Direction as Direction_1) but makeEntityTypeAnnotation discarded the returned local identifier and emitted the original name, which fails with a NameError inside StaticProperty[...] annotations. Annotations now use the actual (possibly aliased) import identifier.

Only types whose names aren't already PascalCase produce different output than before, and references to those were broken one way or another.
Note that toPascalCase only upper-cases the first character, which is why types nested in modules (mangled to Module_name) never hit this.

@dbrattli dbrattli left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks for fixing!

@dbrattli
dbrattli merged commit ae4b910 into fable-compiler:main Jul 17, 2026
32 checks passed
dbrattli added a commit that referenced this pull request Jul 17, 2026
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>
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.

[Python] Generated class names don't match their references (lowercase type names, name collisions)

2 participants