Skip to content

Commit 3264340

Browse files
committed
fix(cli): fix parsing CLI objects to classnames
1 parent 9d6c188 commit 3264340

File tree

3 files changed

+47
-20
lines changed

3 files changed

+47
-20
lines changed

gitlab/cli.py

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,14 @@
2323
import re
2424
import sys
2525

26+
from requests.structures import CaseInsensitiveDict
27+
2628
import gitlab.config
2729

28-
camel_re = re.compile("(.)([A-Z])")
30+
# Full credit for this regex goes to:
31+
# https://github.com/jpvanhal/inflection/blob/master/inflection/__init__.py
32+
camel_upperlower_regex = re.compile(r"([A-Z]+)([A-Z][a-z])")
33+
camel_lowerupper_regex = re.compile(r"([a-z\d])([A-Z])")
2934

3035
# custom_actions = {
3136
# cls: {
@@ -70,12 +75,20 @@ def die(msg, e=None):
7075
sys.exit(1)
7176

7277

73-
def what_to_cls(what):
74-
return "".join([s.capitalize() for s in what.split("-")])
78+
def what_to_cls(object, what):
79+
"""Convert a kebab-case argument to the corresponding attribute of an object
80+
with a case-insensitive lookup."""
81+
attributes = CaseInsensitiveDict(object.__dict__)
82+
lowercase_attribute = what.replace("-", "")
83+
84+
return attributes[lowercase_attribute]
7585

7686

7787
def cls_to_what(cls):
78-
return camel_re.sub(r"\1-\2", cls.__name__).lower()
88+
"""Convert CamelCase class names to kebab-case in two steps, to ensure names
89+
with whole upper-case words are correctly dash-separated as well."""
90+
dash_upper = camel_upperlower_regex.sub(r"\1-\2", cls.__name__)
91+
return camel_lowerupper_regex.sub(r"\1-\2", dash_upper).lower()
7992

8093

8194
def _get_base_parser(add_help=True):

gitlab/tests/test_cli.py

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -29,20 +29,34 @@
2929
import gitlab.v4.cli
3030

3131

32-
def test_what_to_cls():
33-
assert "Foo" == cli.what_to_cls("foo")
34-
assert "FooBar" == cli.what_to_cls("foo-bar")
35-
36-
37-
def test_cls_to_what():
38-
class Class(object):
39-
pass
40-
41-
class TestClass(object):
42-
pass
43-
44-
assert "test-class" == cli.cls_to_what(TestClass)
45-
assert "class" == cli.cls_to_what(Class)
32+
@pytest.mark.parametrize(
33+
"what,attribute_class",
34+
[
35+
("class", "Class"),
36+
("test-class", "TestClass"),
37+
("test-longer-class", "TestLongerClass"),
38+
],
39+
)
40+
def test_what_to_cls(what, attribute_class):
41+
AttributeClass = type(attribute_class, (), {})
42+
GitlabCLI = type("GitlabCLI", (), {attribute_class: AttributeClass})
43+
44+
assert cli.what_to_cls(GitlabCLI, what) == AttributeClass
45+
46+
47+
@pytest.mark.parametrize(
48+
"class_name,expected_what",
49+
[
50+
("Class", "class"),
51+
("TestClass", "test-class"),
52+
("TestUPPERCASEClass", "test-uppercase-class"),
53+
("UPPERCASETestClass", "uppercase-test-class"),
54+
],
55+
)
56+
def test_cls_to_what(class_name, expected_what):
57+
TestClass = type(class_name, (), {})
58+
59+
assert cli.cls_to_what(TestClass) == expected_what
4660

4761

4862
def test_die():

gitlab/v4/cli.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@
2828

2929
class GitlabCLI(object):
3030
def __init__(self, gl, what, action, args):
31-
self.cls_name = cli.what_to_cls(what)
32-
self.cls = gitlab.v4.objects.__dict__[self.cls_name]
31+
self.cls = cli.what_to_cls(self, what)
32+
self.cls_name = self.cls.__name__
3333
self.what = what.replace("-", "_")
3434
self.action = action.lower()
3535
self.gl = gl

0 commit comments

Comments
 (0)