diff options
author | Nejc Habjan <hab.nejc@gmail.com> | 2021-02-10 00:32:48 +0100 |
---|---|---|
committer | Nejc Habjan <hab.nejc@gmail.com> | 2021-03-07 11:58:53 +0100 |
commit | f335435f8e2c4a6136388cfdcbc21795071b5810 (patch) | |
tree | 0fd38d2f67a72847f327f063311397fe6f7c00a7 | |
parent | 48fc907403b630f069dfd63fada73f96a8c6e983 (diff) | |
download | gitlab-f335435f8e2c4a6136388cfdcbc21795071b5810.tar.gz |
fix(cli): fix parsing CLI objects to classnames
-rw-r--r-- | gitlab/cli.py | 26 | ||||
-rw-r--r-- | gitlab/tests/test_cli.py | 37 | ||||
-rw-r--r-- | gitlab/v4/cli.py | 4 |
3 files changed, 49 insertions, 18 deletions
diff --git a/gitlab/cli.py b/gitlab/cli.py index bd2c13d..6db8d61 100644 --- a/gitlab/cli.py +++ b/gitlab/cli.py @@ -21,11 +21,17 @@ import argparse import functools import re import sys -from typing import Any, Callable, Dict, Optional, Tuple, Union +from typing import Callable, Dict, Optional, Tuple, Type, Union +from requests.structures import CaseInsensitiveDict + +from gitlab.base import RESTObject import gitlab.config -camel_re = re.compile("(.)([A-Z])") +# Full credit for this regex goes to: +# https://github.com/jpvanhal/inflection/blob/master/inflection/__init__.py +camel_upperlower_regex = re.compile(r"([A-Z]+)([A-Z][a-z])") +camel_lowerupper_regex = re.compile(r"([a-z\d])([A-Z])") # custom_actions = { # cls: { @@ -75,12 +81,20 @@ def die(msg: str, e: Optional[Exception] = None) -> None: sys.exit(1) -def what_to_cls(what: str) -> str: - return "".join([s.capitalize() for s in what.split("-")]) +def what_to_cls(what: str, namespace: Type) -> RESTObject: + """Given a kebab-case string from a CLI argument, return a corresponding + (CamelCase) class in a given namespace with a case-insensitive lookup.""" + classes = CaseInsensitiveDict(namespace.__dict__) + lowercase_class = what.replace("-", "") + + return classes[lowercase_class] -def cls_to_what(cls: Any) -> str: - return camel_re.sub(r"\1-\2", cls.__name__).lower() +def cls_to_what(cls: RESTObject) -> str: + """Convert CamelCase class names to kebab-case in two steps, to ensure names + with whole upper-case words are correctly dash-separated as well.""" + dash_upper = camel_upperlower_regex.sub(r"\1-\2", cls.__name__) + return camel_lowerupper_regex.sub(r"\1-\2", dash_upper).lower() def _get_base_parser(add_help: bool = True) -> argparse.ArgumentParser: diff --git a/gitlab/tests/test_cli.py b/gitlab/tests/test_cli.py index 2246369..12e3e42 100644 --- a/gitlab/tests/test_cli.py +++ b/gitlab/tests/test_cli.py @@ -29,20 +29,37 @@ from gitlab import cli import gitlab.v4.cli -def test_what_to_cls(): - assert "Foo" == cli.what_to_cls("foo") - assert "FooBar" == cli.what_to_cls("foo-bar") +@pytest.mark.parametrize( + "what,expected_class", + [ + ("class", "Class"), + ("test-class", "TestClass"), + ("test-longer-class", "TestLongerClass"), + ], +) +def test_what_to_cls(what, expected_class): + def _namespace(): + pass + ExpectedClass = type(expected_class, (), {}) + _namespace.__dict__[expected_class] = ExpectedClass -def test_cls_to_what(): - class Class(object): - pass + assert cli.what_to_cls(what, _namespace) == ExpectedClass - class TestClass(object): - pass - assert "test-class" == cli.cls_to_what(TestClass) - assert "class" == cli.cls_to_what(Class) +@pytest.mark.parametrize( + "class_name,expected_what", + [ + ("Class", "class"), + ("TestClass", "test-class"), + ("TestUPPERCASEClass", "test-uppercase-class"), + ("UPPERCASETestClass", "uppercase-test-class"), + ], +) +def test_cls_to_what(class_name, expected_what): + TestClass = type(class_name, (), {}) + + assert cli.cls_to_what(TestClass) == expected_what def test_die(): diff --git a/gitlab/v4/cli.py b/gitlab/v4/cli.py index 6172f93..20b3907 100644 --- a/gitlab/v4/cli.py +++ b/gitlab/v4/cli.py @@ -28,8 +28,8 @@ import gitlab.v4.objects class GitlabCLI(object): def __init__(self, gl, what, action, args): - self.cls_name = cli.what_to_cls(what) - self.cls = gitlab.v4.objects.__dict__[self.cls_name] + self.cls = cli.what_to_cls(what, namespace=gitlab.v4.objects) + self.cls_name = self.cls.__name__ self.what = what.replace("-", "_") self.action = action.lower() self.gl = gl |