Skip to content

Remove stringcase #3239

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Mar 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@
All notable changes to `dash` will be documented in this file.
This project adheres to [Semantic Versioning](https://semver.org/).

## [UNRELEASED]

## Fixed

- [#3239](https://github.com/plotly/dash/pull/3239) Remove stringcase dependency, fix [#3238](https://github.com/plotly/dash/issues/3238)

## [3.0.0] - 2025-03-17

## Added
Expand Down
13 changes: 13 additions & 0 deletions dash/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
import secrets
import string
import inspect
import re

from html import escape
from functools import wraps
from typing import Union
Expand Down Expand Up @@ -302,3 +304,14 @@ def get_caller_name():
return s.frame.f_locals.get("__name__", "__main__")

return "__main__"


def pascal_case(name: Union[str, None]):
s = re.sub(r"\s", "_", str(name))
# Replace leading `_`
s = re.sub("^[_]+", "", s)
if not s:
return s
return s[0].upper() + re.sub(
r"[\-_\.]+([a-z])", lambda match: match.group(1).upper(), s[1:]
)
4 changes: 2 additions & 2 deletions dash/development/_py_prop_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import textwrap
import importlib

import stringcase
from .._utils import pascal_case


shapes = {}
Expand Down Expand Up @@ -54,7 +54,7 @@ def generate_any(*_):

def generate_shape(type_info, component_name: str, prop_name: str):
Copy link
Contributor

Choose a reason for hiding this comment

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

@T4rk1n Is this function covered by tests? Will anything break in a very deep way if this function returns a slightly different output following this change? (The regex looks solid but just in case)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It would just be the name of the generated type, I don't think it would break. It's also almost the same as what stringcase was doing.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@emilykl I added a unit test for the pascal_case

props = []
name = stringcase.pascalcase(prop_name)
name = pascal_case(prop_name)

for prop_key, prop_type in type_info["value"].items():
typed = get_prop_typing(
Expand Down
1 change: 1 addition & 0 deletions dash/py.typed
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
partial
1 change: 0 additions & 1 deletion requirements/install.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,3 @@ requests
retrying
nest-asyncio
setuptools
stringcase>=1.2.0
16 changes: 16 additions & 0 deletions tests/unit/library/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,19 @@ def test_ddut001_attribute_dict():
a.x = 4
assert err.value.args == ("Object is final: No new keys may be added.", "x")
assert "x" not in a


@pytest.mark.parametrize(
"value,expected",
[
("foo_bar", "FooBar"),
("", ""),
("fooBarFoo", "FooBarFoo"),
("foo bar", "FooBar"),
("foo-bar", "FooBar"),
("__private_prop", "PrivateProp"),
("double__middle___triple", "DoubleMiddleTriple"),
],
)
def test_ddut002_pascal_case(value, expected):
assert utils.pascal_case(value) == expected