Repository: janluke/cloup

Issue:
Constraints do not work with options that specify more than 2 argument names
Given an option group like

```python
@cloup.option_group(
    option("--name", "-n", "--username", type=str, required=True)
    option("--something", type=str, required=True)
    constraint=cloup.constraints.all_or_none
)
```

We get a
```python
ValueError: too many values to unpack (expected 2) from: 
https://github.com/janluke/cloup/blob/master/cloup/constraints/common.py#L74-L81
```

Probably it should sort the list and set `short, long = sorted_args[0], sorted_args[-1]`

Hints from issue comments:
@tylerduffin: PR here https://github.com/janluke/cloup/pull/188@janluke: Lol, I didn't even know you could assign multiple --names to an option! I'll have a look at your PR soon. Thanks!@janluke: Releasing fix in v3.0.7.

Solution patch:
diff --git a/cloup/constraints/common.py b/cloup/constraints/common.py
index e3fcffc..abec22d 100644
--- a/cloup/constraints/common.py
+++ b/cloup/constraints/common.py
@@ -74,11 +74,18 @@ def join_with_and(strings: Sequence[str], sep: str = ', ') -> str:
 def format_param(param: Parameter) -> str:
     if isinstance(param, Argument):
         return param.human_readable_name
-    # return ' | '.join(param.opts)
-    if len(param.opts) == 1:
-        return param.opts[0]
-    short, long = sorted(param.opts, key=len)
-    return f'{long} ({short})'
+
+    opts = param.opts
+    if len(opts) == 1:
+        return opts[0]
+
+    # Use the first long opt as the main/canonical one, put all others
+    # opts between parenthesis as aliases, long opts first, then short ones
+    long_opts = [opt for opt in opts if opt.startswith("--")]
+    short_opts = [opt for opt in opts if not opt.startswith("--")]
+    main_opt = long_opts[0]
+    aliases = ", ".join(long_opts[1:] + short_opts)
+    return f'{main_opt} ({aliases})'
 
 
 def format_param_list(param_list: Iterable[Parameter], indent: int = 2) -> str:


Test patch:
diff --git a/tests/constraints/test_common.py b/tests/constraints/test_common.py
index c14b794..5e7ae44 100644
--- a/tests/constraints/test_common.py
+++ b/tests/constraints/test_common.py
@@ -43,6 +43,18 @@ def test_format_param():
     assert format_param(Option(['--opt', '-o'])) == '--opt (-o)'
     assert format_param(Option(['-o', '--opt'])) == '--opt (-o)'
     assert format_param(Option(['-o/-O', '--opt/--no-opt', 'blah'])) == '--opt (-o)'
+    # Multiple long opts
+    assert format_param(Option(['--name', '--username'])) == (
+        '--name (--username)'
+    )
+    # Multiple short opts
+    assert format_param(Option(['--name', '-n', '-u'])) == (
+        '--name (-n, -u)'
+    )
+    # Multiple short and long opts
+    assert format_param(Option(['-n', '-u', '--name', '--username'])) == (
+        '--name (--username, -n, -u)'
+    )
 
 
 def test_format_param_list():