diff --git a/pydantic/alias_generators.py b/pydantic/alias_generators.py index bbdaaaf121..155e66e0c4 100644 --- a/pydantic/alias_generators.py +++ b/pydantic/alias_generators.py @@ -39,6 +39,12 @@ def to_snake(camel: str) -> str: Returns: The converted string in snake_case. """ - snake = re.sub(r'([a-zA-Z])([0-9])', lambda m: f'{m.group(1)}_{m.group(2)}', camel) - snake = re.sub(r'([a-z0-9])([A-Z])', lambda m: f'{m.group(1)}_{m.group(2)}', snake) + # Handle the sequence of uppercase letters followed by a lowercase letter + snake = re.sub(r'([A-Z]+)([A-Z][a-z])', lambda m: f'{m.group(1)}_{m.group(2)}', camel) + # Insert an underscore between a lowercase letter and an uppercase letter + snake = re.sub(r'([a-z])([A-Z])', lambda m: f'{m.group(1)}_{m.group(2)}', snake) + # Insert an underscore between a digit and an uppercase letter + snake = re.sub(r'([0-9])([A-Z])', lambda m: f'{m.group(1)}_{m.group(2)}', snake) + # Insert an underscore between a lowercase letter and a digit + snake = re.sub(r'([a-z])([0-9])', lambda m: f'{m.group(1)}_{m.group(2)}', snake) return snake.lower() diff --git a/tests/test_utils.py b/tests/test_utils.py index ccbc956a00..dff54caac0 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -529,6 +529,7 @@ def test_snake2camel(value: str, result: str) -> None: ('Camel2Snake', 'camel_2_snake'), ('_CamelToSnake', '_camel_to_snake'), ('CamelToSnake_', 'camel_to_snake_'), + ('CAMELToSnake', 'camel_to_snake'), ('__CamelToSnake__', '__camel_to_snake__'), ('Camel2', 'camel_2'), ('Camel2_', 'camel_2_'),