Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@tdyas
Copy link

@tdyas tdyas commented Mar 16, 2016

Add two command-line arguments for BoolParameter's instead of one, specifically one to set it to True (e.g, --foo) and another (--no-foo) to set it to False. This is necessary because BoolParameter currently uses argparse's "store_true" action, which does not take a parameter. This change allows BoolParameter's to have a default of True and still be settable to False.

For cases where an inverted argument does not make sense, the caller should set omit_inverted_argument=True on the BoolParameter. (For example, this has been done for the --help and --help-all options, as --no-help is of no help at all.)

@tdyas tdyas force-pushed the inverted_arguments_for_boolparameter branch 2 times, most recently from a60aa88 to 4e19297 Compare March 16, 2016 18:13
@Tarrasch
Copy link
Contributor

This implementation looks nice and clean. Just some minor inline comments:

return bool(value) if value is not None else None

@staticmethod
def _parser_action():
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this be deleted now? Is _parser_action() still used anywhere?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like it can be since the only place it is overridden is in BoolParameter which does not even call _parser_action any more in _parser_add_arguments.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok. Please delete the dead code then :)

@Tarrasch
Copy link
Contributor

The reason I like this patch is that I've by now repeatedly told other PR senders that "No, you're not allowed to have True as a default for your BoolParameter". But with this patch we could allow it from now on.

@Tarrasch
Copy link
Contributor

This is a reasonably big change (not in code size), but in what we communicate are good practices to the luigi users. I remember @erikbern saying some time that BoolParameters should always be false by default. But I don't know if he meant that as a "that's good design in general" or "due to current luigi limitations that's the only implementation that works out".

@tdyas
Copy link
Author

tdyas commented Mar 24, 2016

Understood. I agree that existing community usages may have a part to play in whether this PR should be accepted or not.

As an anecdotal data point, at my employer, we use Luigi and I have seen our developers confused on multiple occasions by not really being able to set default=True on BoolParameter. (The confusion stemming from the BoolParameter behaving differently from other Parameter subclasses with respect to setting its value.)

@tdyas
Copy link
Author

tdyas commented Mar 24, 2016

And this PR is an attempt to improve the API to remove that source of confusion.

@a1k0n
Copy link
Contributor

a1k0n commented Mar 24, 2016

I agree with @tdyas on this, as someone who used Luigi heavily while working with @erikbern . It doesn't break the existing semantics, and it does exactly what I had assumed it would have done when I first started using Luigi: adds a --no-xyz argument, which is a de-facto standard for GNU tools and elsewhere.

The only reason default=True was a bad practice is because it lacked this implementation, and we had to do dumb hacks like create argument variables named no_this and disable_that.

@Tarrasch
Copy link
Contributor

Thank you both @tdyas and @a1k0n for sharing your design thoughts, they sound sane to me. I'll just give @erikbern until tomorrow to chime in. Otherwise I'll merge this tomorrow once you fix the build.

@erikbern
Copy link
Contributor

i'm fine with this

@tdyas
Copy link
Author

tdyas commented Mar 24, 2016

Adding the --no-xyz arguments seems to confuse argparse's parse_known_args method. I'll have to dig into why argparse is confused.

runtests.py: error: ambiguous option: --n could match --no-scheduler-record-task-history, --no-lock, --no-worker-no-install-shutdown-handler, --no-no-lock, --no-RangeBase-reverse, --no-worker-count-uniques, --no-scheduler-prune-on-get-work, --no-RangeDaily-reverse, --no-local-scheduler, --no-worker-retry-external-tasks, --no-RangeHourlyBase-reverse, --no-take-lock, --no-RangeDailyBase-reverse, --no-scheduler-prune-done-tasks, --no-RangeHourly-reverse, --no-parallel-scheduling, --no-TestNotificationsTask-raise-in-complete, --no-worker-keep-alive, --no-assistant

@erikbern
Copy link
Contributor

i'm guessing no argument can be a prefix of another

@tdyas
Copy link
Author

tdyas commented Mar 24, 2016

So I dug in further, and it seems like a bug in argparse. The error occurs during the call to parse_known_args in CmdlineParser.__init__. That method is trying to determine the root_task to use. argparse should really not throw an error about an ambiguous option when invoked via parse_known_args. It should just mark the option in question as unknown.

I can get the failing test to pass by renaming the n option in SomeTask in cmdline_test.py to something else (e.g., z).

This still brings up an issue about whether this will break Luigi for anybody who has a task with a "n" parameter.

@tdyas
Copy link
Author

tdyas commented Mar 24, 2016

And this issue is known to the Python developers: https://bugs.python.org/issue19814

And apparently only warrants a warning in the documentation.

@Tarrasch
Copy link
Contributor

Please let me know if you need any help. Otherwise I'm patiently waiting for something that builds. :)

Tom Dyas added 2 commits March 29, 2016 18:34
Refactor the add_argument call for adding Parameter's to a ArgumentParser
into the Parameter class. This lays the foundation for overriding the
default behavior in BoolParameter.
Add two command-line arguments for BoolParameter's instead of one,
specifically one to set it to True (e.g, --foo) and another (--no-foo)
to set it to False.

For cases where an inverted argument does not make sense, the caller
should set omit_inverted_argument=True on the BoolParameter. For example,
this has been done for --help and --help-all options, as --no-help does
not make any sense.

This allows BoolParameter's to have a default of True and still be settable
to False.

Other notes:
* Removes Parameter._parser_action as moot.
* Merges Parameter._parse_or_no_value into the sole call site
  and changes the logic to account for None in the value check.
* Several tests initially failed with this change because argparse considered
  --n ambiguous with the --no-FOO style options. This is a known issue with
  argparse. These options have been renamed to allow the tests to pass.
  See https://bugs.python.org/issue19814 for details.
@tdyas tdyas force-pushed the inverted_arguments_for_boolparameter branch from e60f5c3 to 2aa25be Compare March 30, 2016 22:58
@tdyas
Copy link
Author

tdyas commented Mar 30, 2016

As it turns out, the test I added wasn't actually testing whether a BoolParameter with default=True could be set to False by option. This uncovered some places where checks for truthy values had to actually check for None.

I also merged all of the other commits (other than the commit refactoring the add_argument call) into the commit adding the inverted argument support.

@tdyas
Copy link
Author

tdyas commented Mar 30, 2016

There was also a test failure locally for me with test/file_test.py which seems unrelated to my change since the tests in that file don't deal with parameters. It could be an issue with my local setup so will wait for the Travis build to see if that is the case.

@tdyas
Copy link
Author

tdyas commented Mar 31, 2016

CI tests passed.

@Tarrasch
Copy link
Contributor

I'm still a bit worried about we suddenly dropping support for parameters with names like n and I'm not fond of you renaming a local variable to an all caps name (n --> N). Would it not just be much easier if you only had the --no-boolparam option only if default=True? Alternatively you could another option add_negative_cli_flag with a value False as default.

@Tarrasch
Copy link
Contributor

Yea I understand this is entirely the fault of some stupid bug in the argparse module (I've also felt the pain). But I'm afraid people are going to start to say their stuff broke and this would need to be reverted in haste if we break compatibility.

@erikbern
Copy link
Contributor

apparently python 3.5 added a flag to argparse allow_abbrev=False that turns off the prefix matching. too bad it wasn't earlier

the correct way would probably be to first change luigi's behavior so that prefix flags throw a deprecation warning for a few months and then an exception

btw reminds me – maybe it's time to publish a new version of luigi to pypi?

@tdyas
Copy link
Author

tdyas commented Apr 5, 2016

So the solution for now it seems is to just add a --no-FOO option for BoolParameter's with default=True?

@Tarrasch
Copy link
Contributor

Tarrasch commented Apr 5, 2016

Yea. I would be more comfortable that way actually @tdyas

@stale
Copy link

stale bot commented Jul 31, 2018

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. If closed, you may revisit when your time allows and reopen! Thank you for your contributions.

@stale stale bot added the wontfix label Jul 31, 2018
@dlstadther
Copy link
Collaborator

Resolved by #2427

@dlstadther dlstadther closed this Jul 31, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants