Repository: pallets/click (python)

Issue:
Duplicate Boolean flag options "--foo/--foo" are not detected (defaults to False)
I ran into an issue where I had the code:

    @click.option( "--print-verbose-info/--print-verbose-info", help="...", default=False )

...and running `cli.py --print-verbose-info` was apparently defaulting over to the `False` value.  Totally my mistake (it should have been `--no-print-verbose-info`), but it'd be nice to get a warning/error for boolean values which match exactly (ie: cannot be set to true).

It was kindof tricky to diagnose b/c I assumed that the `--print-verbose-info` that I was passing on the CLI was triggering the `True` path, not the `False` path, and usually Click option parsing is pretty bulletproof so it took a while to find that copy/paste problem.

This would be a `good-first-issue`, I'm submitting it now more as a reminder to maybe follow-up on it and figure out the appropriate P.R.

Pull request description:
raise ValueError for duplicate flags
Specifying the same flag name twice will raise a `RuntimeError`.

```python
@click.option( "--foo/--foo", default=False)
```

fixes #1465 

Patch:
diff --git a/CHANGES.rst b/CHANGES.rst
index 6eb180e..bcfa72d 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -20,6 +20,8 @@ Unreleased
     is not shown in the error message. :issue:`1460`
 -   An ``IntRange`` option shows the accepted range in its help text.
     :issue:`1525`
+-   An option defined with duplicate flag names (``"--foo/--foo"``)
+    raises a ``ValueError``. :issue:`1465`
 
 
 Version 7.1.2
diff --git a/src/click/core.py b/src/click/core.py
index 87415bd..2b05d3f 100644
--- a/src/click/core.py
+++ b/src/click/core.py
@@ -1840,6 +1840,11 @@ class Option(Parameter):
                     second = second.lstrip()
                     if second:
                         secondary_opts.append(second.lstrip())
+                    if first == second:
+                        raise ValueError(
+                            f"Boolean option {decl!r} cannot use the"
+                            " same flag for true/false."
+                        )
                 else:
                     possible_names.append(split_opt(decl))
                     opts.append(decl)


Test patch:
diff --git a/tests/test_options.py b/tests/test_options.py
index 28990c3..bd66bd2 100644
--- a/tests/test_options.py
+++ b/tests/test_options.py
@@ -565,3 +565,8 @@ def test_option_names(runner, option_args, expected):
         if form.startswith("-"):
             result = runner.invoke(cmd, [form])
             assert result.output == "True\n"
+
+
+def test_flag_duplicate_names(runner):
+    with pytest.raises(ValueError, match="cannot use the same flag for true/false"):
+        click.Option(["--foo/--foo"], default=False)