Repository: huggingface/transformers (Python)

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.
If you want to have a look at the PR mentioned above and check it does give the expected behavior, that would be great!
Ok, I'll check it tomorrow against our internal use case to make sure it fixes that too.



Patch:
diff --git a/src/transformers/hf_argparser.py b/src/transformers/hf_argparser.py
index 176362250499..b6f23ec4e2aa 100644
--- 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
index 787990b86659..44a52035ddee 100644
--- 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)