Skip to content

Commit

Permalink
bugfixes
Browse files Browse the repository at this point in the history
  • Loading branch information
Aran-Fey committed Mar 10, 2024
1 parent 281ddec commit 4943609
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 54 deletions.
2 changes: 1 addition & 1 deletion introspection/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
New and improved introspection functions
"""

__version__ = "1.7.11"
__version__ = "1.7.12"

from .parameter import *
from .signature_ import *
Expand Down
91 changes: 55 additions & 36 deletions introspection/misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import inspect
import sys
import types
import warnings

from collections import defaultdict, deque
from typing import *
Expand Down Expand Up @@ -573,7 +574,14 @@ def camel_to_snake(camel: str) -> str:
'http_adapter'
.. versionadded:: 1.5
.. deprecated:: 1.7.12
Use :func:`convert_case` instead.
"""
warnings.warn(
"The `camel_to_snake` function is deprecated in favor of `convert_case`",
DeprecationWarning,
)

chars: List[str] = []
last_char_was_upper = True

Expand Down Expand Up @@ -607,7 +615,14 @@ def snake_to_camel(snake: str) -> str:
'HttpAdapter'
.. versionadded:: 1.5
.. deprecated:: 1.7.12
Use :func:`convert_case` instead.
"""
warnings.warn(
"The `snake_to_camel` function is deprecated in favor of `convert_case`",
DeprecationWarning,
)

chars: List[str] = []
last_char_was_underscore = True

Expand All @@ -625,47 +640,60 @@ def snake_to_camel(snake: str) -> str:
return "".join(chars)


def detect_case(name: str) -> Case:
def detect_case(name: str) -> Union[Case, Literal["mixed"]]:
"""
Detects the case of a name, for example::
>>> detect_case('foo_bar')
'snake'
>>> detect_case('FooBar')
'pascal'
"""
if name[0].islower():
if "-" in name:
return "kebab"
elif name.islower():
return "snake"
else:
return "camel"

if "-" in name:
return "upper kebab"
elif "_" in name:
return "upper snake"
>>> detect_case('foo_bar-qux')
'mixed'
"""
has_upper = has_lower = False
has_dash = has_underscore = has_whitespace = False

for char in name:
if char == "-":
has_dash = True
elif char == "_":
has_underscore = True
elif char.isspace():
has_whitespace = True
elif char.isupper():
has_upper = True
elif char.islower():
has_lower = True

if has_upper and has_lower:
return "mixed"

if has_dash + has_underscore + has_whitespace != 1:
return "mixed"

if has_dash:
return "upper kebab" if has_upper else "kebab"
elif has_underscore:
return "upper snake" if has_upper else "snake"
else:
return "pascal"


def _split_snake(name: str) -> List[str]:
return name.split("_")
return "pascal" if name[0].isupper() else "camel"


def _split_kebab(name: str) -> List[str]:
return name.split("-")


def _split_camel_and_pascal(name: str) -> List[str]:
def _split_name(name: str) -> List[str]:
words: List[str] = []
word: List[str] = []
last_char_was_upper = True

for i, char in enumerate(name):
is_upper = char.isupper()

if char in "-_" or char.isspace():
words.append("".join(word))
word.clear()
last_char_was_upper = False
continue

if (
word
and is_upper
Expand Down Expand Up @@ -716,20 +744,11 @@ def convert_case(name: str, to: Case) -> str:
"""
Converts a name to a different case, for example::
>>> convert_case('FooBar', 'snake')
'foo_bar'
>>> convert_case('HTMLParser', 'snake')
'html_parser'
"""
case_ = detect_case(name)

split_func = {
"snake": _split_snake,
"upper snake": _split_snake,
"kebab": _split_kebab,
"upper kebab": _split_kebab,
"camel": _split_camel_and_pascal,
"pascal": _split_camel_and_pascal,
}[case_]
words = split_func(name)
words = _split_name(name)

# Special case conversions between pascal and camel so that capitalization is preserved. For
# example, `FancyHTML` should become `fancyHTML`, not `fancyHtml`.
Expand Down
2 changes: 1 addition & 1 deletion introspection/typing/misc2.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,6 @@ def get_type_annotations(cls: type) -> Dict[str, TypeInfo]:

for attr_name, annotation in annotations.items():
if attr_name not in result:
result[attr_name] = TypeInfo(annotation)
result[attr_name] = TypeInfo(annotation, forward_ref_context=class_)

return result
24 changes: 8 additions & 16 deletions tests/test_misc_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -505,22 +505,14 @@ def test_is_sub_qualname(sub_name, super_name, expected):


@pytest.mark.parametrize(
"camel, expected",
"original, case, expected",
[
("FooBar", "foo_bar"),
("HTTPAdapter", "http_adapter"),
("FooBar", "upper snake", "FOO_BAR"),
("HTTPAdapter", "snake", "http_adapter"),
("foo_bar", "pascal", "FooBar"),
("http_adapter", "camel", "httpAdapter"),
("remoteCode_execution", "kebab", "remote-code-execution"),
],
)
def test_camel_to_snake(camel, expected):
assert camel_to_snake(camel) == expected


@pytest.mark.parametrize(
"snake, expected",
[
("foo_bar", "FooBar"),
("http_adapter", "HttpAdapter"),
],
)
def test_snake_to_camel(snake, expected):
assert snake_to_camel(snake) == expected
def test_convert_case(original, case, expected):
assert convert_case(original, case) == expected

0 comments on commit 4943609

Please sign in to comment.