Repository: huggingface/transformers

Issue:
HfArgumentParser defaults booleans to on
## Environment info
- `transformers` version: 4.9.0.dev0 (initially discovered on 4.8.1)
- Platform: macOS-11.4-x86_64-i386-64bit
- Python version: 3.9.5
- PyTorch version (GPU?): not installed (NA)
- Tensorflow version (GPU?): not installed (NA)
- Flax version (CPU?/GPU?/TPU?): not installed (NA)
- Jax version: not installed
- JaxLib version: not installed

### Who can help
@sgugger

## Information

HfArgumentParser when used on a dataclass with a bool field with no default turns the bool on unless it's supplied with `--<field_name> False` or similar "false-y" value. I would expect that as the field has no default it should be false unless `--<field_name>` or `--<field_name> True` is supplied.  This is a behaviour change from `v3.0.0` where the booleans are parsed correctly as we're looking at upgrading and this issue hit us.

## To reproduce

Steps to reproduce the behavior:

1. Define a dataclass with a boolean field
2. Supply a list of arguments which does not include that field name
3. The field is turned on.

Appending this snippet to the bottom of [`test_basic` at line 110](https://github.com/huggingface/transformers/blob/master/tests/test_hf_argparser.py#L110) in `test_hf_argparser.py` fails the test.

```python

        args = ["--foo", "1", "--baz", "quux", "--bar", "0.5"]

        example, = parser.parse_args_into_dataclasses(args, look_for_args_file=False)

        self.assertFalse(example.flag)
```

Extending `args` with `["--flag","False"]` recovers the expected behaviour.

## Expected behavior

The boolean should be set to false if the argument is not passed in.


Discussion:
If you agree this is a bug in the parsing logic then we'd be happy to fix it and send a PR.
Yes, it does look like a bug. Fix is quite simple, I can make a PR.
Ok thanks. That saves me a job later this week.

Resolving patch:
diff --git a/src/transformers/hf_argparser.py b/src/transformers/hf_argparser.py
--- a/src/transformers/hf_argparser.py
+++ b/src/transformers/hf_argparser.py
@@ -112,8 +112,8 @@ def _add_dataclass_arguments(self, dtype: DataClassType):
                 # Hack because type=bool in argparse does not behave as we want.
                 kwargs["type"] = string_to_bool
                 if field.type is bool or (field.default is not None and field.default is not dataclasses.MISSING):
-                    # Default value is True if we have no default when of type bool.
-                    default = True if field.default is dataclasses.MISSING else field.default
+                    # Default value is False if we have no default when of type bool.
+                    default = False if field.default is dataclasses.MISSING else field.default
                     # This is the value that will get picked if we don't include --field_name in any way
                     kwargs["default"] = default
                     # This tells argparse we accept 0 or 1 value after --field_name


Test patch:
diff --git a/tests/test_hf_argparser.py b/tests/test_hf_argparser.py
--- a/tests/test_hf_argparser.py
+++ b/tests/test_hf_argparser.py
@@ -106,9 +106,13 @@ def test_basic(self):
         expected.add_argument("--foo", type=int, required=True)
         expected.add_argument("--bar", type=float, required=True)
         expected.add_argument("--baz", type=str, required=True)
-        expected.add_argument("--flag", type=string_to_bool, default=True, const=True, nargs="?")
+        expected.add_argument("--flag", type=string_to_bool, default=False, const=True, nargs="?")
         self.argparsersEqual(parser, expected)
 
+        args = ["--foo", "1", "--baz", "quux", "--bar", "0.5"]
+        (example,) = parser.parse_args_into_dataclasses(args, look_for_args_file=False)
+        self.assertFalse(example.flag)
+
     def test_with_default(self):
         parser = HfArgumentParser(WithDefaultExample)