Skip to content

Add invalid name checker uppercase and pascal case suggested fixes#1341

Open
a1-su wants to merge 4 commits into
pyta-uoft:masterfrom
a1-su:invalid-name-checker-uppercase-pascal-suggested-fixes
Open

Add invalid name checker uppercase and pascal case suggested fixes#1341
a1-su wants to merge 4 commits into
pyta-uoft:masterfrom
a1-su:invalid-name-checker-uppercase-pascal-suggested-fixes

Conversation

@a1-su
Copy link
Copy Markdown
Contributor

@a1-su a1-su commented May 19, 2026

Proposed Changes

Adds suggested naming fixes for the UPPER_CASE_WITH_UNDERSCORES and PascalCase variable names in the invalid_name_checker.py. Added the _to_upper_case_with_underscores and _to_pascal_case helper functions and corresponding tests.

Type of Change

(Write an X or a brief description next to the type or types that best describe your changes.)

Type Applies?
🚨 Breaking change (fix or feature that would cause existing functionality to change)
New feature (non-breaking change that adds functionality) X
🐛 Bug fix (non-breaking change that fixes an issue)
♻️ Refactoring (internal change to codebase, without changing functionality)
🚦 Test update (change that only adds or modifies tests)
📚 Documentation update (change that only updates documentation)
📦 Dependency update (change that updates a dependency)
🔧 Internal (change that only affects developers or continuous integration)

Checklist

(Complete each of the following items for your pull request. Indicate that you have completed an item by changing the [ ] into a [x] in the raw text, or by clicking on the checkbox in the rendered description on GitHub.)

Before opening your pull request:

  • I have performed a self-review of my changes.
    • Check that all changed files included in this pull request are intentional changes.
    • Check that all changes are relevant to the purpose of this pull request, as described above.
  • I have added tests for my changes, if applicable.
    • This is required for all bug fixes and new features.
  • I have updated the project documentation, if applicable.
    • This is required for new features.
  • I have updated the project Changelog (this is required for all changes).
  • If this is my first contribution, I have added myself to the list of contributors.

After opening your pull request:

  • I have verified that the CI tests have passed.
  • I have reviewed the test coverage changes reported by Coveralls.
  • I have requested a review from a project maintainer.

Questions and Comments

(Include any questions or comments you have regarding your changes.)

  • The CHANGELOG.md wasn't updated as it should have been updated in Rachel's PR

  • While I know a single trailing underscore is sometimes used by libraries to denote different things, such as that a method is in-place, in the conversion to UPPERCASE_WITH_UNDERSCORES, I've allowed multiple trailing underscores because the regex in the function _is_in_upper_case_with_underscores unconventionally allows it. If this is something that should should be flagged, feel free to let me know and I can change both functions.

    def _is_in_upper_case_with_underscores(name: str) -> bool:
    """Returns whether `name` is in UPPER_CASE_WITH_UNDERSCORES.
    `name` is in `UPPER_CASE_WITH_UNDERSCORES if:
    - each word is in uppercase, and
    - words are separated by an underscore.
    """
    pattern = "(_?[A-Z][A-Z0-9_]*)$"
    return re.match(pattern, name) is not None

  • This is less related to this specific PR, but I noticed that the _check_method_and_attr_name function accepts names that start with three underscores (not just two or three)

    def _check_method_and_attr_name(node_type: str, name: str) -> list[str]:
    """Returns a list of strings, each detailing how `name` violates Python naming conventions for
    method and instance or class attribute names.
    Returns an empty list if `name` is a valid method, instance, or attribute name."""
    error_msgs = []
    # Also consider the case of invoking Python's name mangling rules with leading dunderscores.
    if not (_is_in_snake_case(name) or (name.startswith("__") and _is_in_snake_case(name[2:]))):

    Due to the fact after the "__" is spliced, _is_in_snake_case still accepts a leading underscore

    def _is_in_snake_case(name: str) -> bool:
    """Returns whether `name` is in snake_case.
    `name` is in snake_case if:
    - `name` starts with a lowercase letter or an underscore (to denote private fields) followed
    by a lowercase letter,
    - each word is separated by an underscore, and
    - each word is in lowercase.
    """
    pattern = "(_?[a-z][a-z0-9_]*)$"
    return re.match(pattern, name) is not None

    I'm not sure if this is intentional or not, but triple underscore-prefixed variables in Python seem uncommon to me.

@a1-su a1-su changed the title Invalid name checker uppercase pascal suggested fixes Add invalid name checker uppercase and pascal case suggested fixes May 19, 2026
@coveralls
Copy link
Copy Markdown
Collaborator

coveralls commented May 19, 2026

Coverage Report for CI Build 26200273900

Warning

Build has drifted: This PR's base is out of sync with its target branch, so coverage data may include unrelated changes.
Quick fix: rebase this PR. Learn more →

Coverage decreased (-0.006%) to 90.533%

Details

  • Coverage decreased (-0.006%) from the base build.
  • Patch coverage: 4 uncovered changes across 1 file (40 of 44 lines covered, 90.91%).
  • No coverage regressions found.

Uncovered Changes

File Changed Covered %
packages/python-ta/src/python_ta/checkers/invalid_name_checker.py 44 40 90.91%

Coverage Regressions

No coverage regressions found.


Coverage Stats

Coverage Status
Relevant Lines: 3919
Covered Lines: 3548
Line Coverage: 90.53%
Coverage Strength: 17.57 hits per line

💛 - Coveralls

@a1-su a1-su requested a review from david-yz-liu May 19, 2026 01:21
Copy link
Copy Markdown
Contributor

@david-yz-liu david-yz-liu left a comment

Choose a reason for hiding this comment

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

@a1-su nice work. In addition to the inline comment I left, (1) see the comments I left on https://github.com/pyta-uoft/pyta/pull/1340/changes (they also apply here), and (2) make sure to update the changelog.

"""Returns a PascalCase version of `name`."""
prefix, words, _ = _parse_name(name)

return prefix + "".join(word.capitalize() for word in words)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

With pascal case we will allow allcaps words, e.g. JSONParser. So I wouldn't use str.capitalize directly but instead manually ensure the first letter is capitalized.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

No problem 👍. As a side note, one unintended consequence may be that even though it works for a name like parseJSONText to ParseJSONText, for a name like UPPER_CASE_NAME, this gets converted to UPPERCASENAME instead of UpperCaseName.

def test_to_pascal_case(self) -> None:
"""Test that names are correctly converted to PascalCase."""
self.assertEqual(_to_pascal_case("snake_case"), "SnakeCase")
self.assertEqual(_to_pascal_case("PascalCase"), "PascalCase")
self.assertEqual(_to_pascal_case("_UPPER_CASE_NAME"), "_UPPERCASENAME")
self.assertEqual(_to_pascal_case("__varName_here_"), "_VarNameHere")
self.assertEqual(_to_pascal_case("parseJSONText"), "ParseJSONText")

@a1-su a1-su requested a review from david-yz-liu May 21, 2026 01:46
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.

3 participants