diff --git a/skillbridge/client/translator.py b/skillbridge/client/translator.py index f857fef..ecdbe4b 100644 --- a/skillbridge/client/translator.py +++ b/skillbridge/client/translator.py @@ -1,5 +1,5 @@ -from typing import NoReturn, Any, List, Iterable, cast -from re import sub +from typing import NoReturn, Any, List, Iterable, cast, Match +from re import sub, findall from json import dumps, loads from warnings import warn_explicit @@ -28,17 +28,21 @@ def _skill_value_to_python(string: str, replicate: Replicator) -> Skill: ) +def _upper_without_first(match: Match[str]) -> str: + return match.group()[1:].upper() + + def snake_to_camel(snake: str) -> str: if snake.startswith('_') or '_' not in snake: return snake - return snake[0] + snake.replace('_', ' ').title().replace(' ', '')[1:] + return sub(r'_[a-zA-Z]', _upper_without_first, snake) def camel_to_snake(camel: str) -> str: if camel[0].isupper(): return camel - - return sub(r'(?<=[a-z])([A-Z])|([A-Z][a-z])', r'_\1\2', camel).lower() + parts = findall("[a-z]+|[A-Z][a-z]+|[A-Z]+(?=[A-Z][a-z]|$)", camel) + return '_'.join(part.lower() if part[-1].islower() else part for part in parts) def _python_value_to_skill(value: Skill) -> SkillCode: diff --git a/tests/test_channel.py b/tests/test_channel.py index b669f7d..6dc6d07 100644 --- a/tests/test_channel.py +++ b/tests/test_channel.py @@ -8,7 +8,6 @@ from skillbridge.client.channel import Channel, create_channel_class from skillbridge import Workspace, current_workspace -from skillbridge import FunctionCollection WORKSPACE_ID = '__test__' channel_class = create_channel_class() diff --git a/tests/test_translator.py b/tests/test_translator.py index 7f62330..4fbd8d7 100644 --- a/tests/test_translator.py +++ b/tests/test_translator.py @@ -38,6 +38,16 @@ def decode_simple(simple_translator: Translator) -> Callable[[str], Any]: return simple_translator.decode +def test_snake_to_wrong_camel_case(): + assert snake_to_camel('load_XML_from_string') == 'loadXMLFromString' + assert snake_to_camel('load_xml_from_string') == 'loadXmlFromString' + + +def test_wrong_camel_to_snake_case(): + assert camel_to_snake('loadXMLConfigFromString') == 'load_XML_config_from_string' + assert camel_to_snake('loadXmlConfigFromString') == 'load_xml_config_from_string' + + def test_snake_to_camel_simple_does_not_change(): assert snake_to_camel('x') == 'x' assert snake_to_camel('simple') == 'simple' @@ -64,7 +74,7 @@ def test_camel_to_snake_simple_does_not_change(): def test_camel_to_snake_input_camel(): assert camel_to_snake('camelCase') == 'camel_case' assert camel_to_snake('thisIsCamelCase') == 'this_is_camel_case' - assert camel_to_snake('thisIsHTML') == 'this_is_html' + assert camel_to_snake('thisIsHTML') == 'this_is_HTML' def test_named_parameters_are_optionally_converted(simple_translator: Translator):