Skip to content

Python: SnakeCaseNamespaceNames never executes — CrawlTree inside empty-name guard #7715

@gavinbarron

Description

@gavinbarron

Description

The PythonRefiner.SnakeCaseNamespaceNames method (which was removed in #7714 to avoid a breaking change) was intended to convert namespace segments to snake_case at the CodeDOM level before code generation. However, it never actually executed because CrawlTree was placed inside the if (currentElement is CodeNamespace codeNamespace && !string.IsNullOrEmpty(codeNamespace.Name)) guard.

Since RefineAsync passes the root namespace (which has an empty name), the guard fails at the root and traversal never starts.

Impact

  • CodeNamespace.Name values remain in their original casing (e.g., exportNamespace instead of export_namespace)
  • The path segmenter and import manager apply .ToSnakeCase() downstream, so generated file paths and import statements are already correct
  • The only observable effect is in the public API export surface, which reflects the raw CodeNamespace.Name

Why this wasn't fixed in #7714

Simply moving CrawlTree outside the guard (the obvious fix) causes a breaking change: GetDifferential() in CodeNamespace.cs strips the namespace prefix by character count (Name[prefixLength..]). The clientNamespaceName passed to the writer comes directly from the user's config and is NOT snake_cased. After snake_casing CodeNamespace.Name, the prefix length no longer matches, corrupting import path computation.

Proper fix

To properly fix this, both changes are needed together:

  1. Move CrawlTree outside the guard in SnakeCaseNamespaceNames
  2. Snake_case the clientNamespaceName before passing it to PythonWriter/PythonRelativeImportManager

This ensures prefix stripping in GetDifferential works correctly with the now-snake_cased namespace names.

Related

Split out from #7714 to avoid scope creep and breaking changes.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    Status

    Needs Triage 🔍

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions