FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

gh-99749: Add closest choice if exists in Argparser if wrong choice picked by abdulrafey38 · Pull Request #99773 · python/cpython · GitHub

/ cpython Public

gh-99749: Add closest choice if exists in Argparser if wrong choice picked - #99773

Closed
abdulrafey38 wants to merge 24 commits into
python:mainfrom
abdulrafey38:fix-issue-99749
Closed

gh-99749: Add closest choice if exists in Argparser if wrong choice picked#99773
abdulrafey38 wants to merge 24 commits into
python:mainfrom
abdulrafey38:fix-issue-99749

Conversation

abdulrafey38 commented Nov 25, 2022
edited
Loading

Copy link
Copy Markdown

Description

Add closet choice if exists in Argparser if wrong choice picked

Copy link
Copy Markdown

Most changes to Python require a NEWS entry.

Please add it using the blurb_it web app or the blurb command-line tool.

ghost commented Nov 25, 2022
edited by ghost
Loading

Copy link
Copy Markdown

All commit authors signed the Contributor License Agreement.

AlexWaygood changed the title gh-99749: Add closet choice if exists in Argparser if wrong choice picked gh-99749: Add closest choice if exists in Argparser if wrong choice picked Nov 25, 2022
abdulrafey38 marked this pull request as draft November 25, 2022 18:12

noamcohen97 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Great feature!
Maybe a way to opt out of this feature should be added?

Comment thread Lib/argparse.py Outdated
Comment on lines +2551 to +2552
if closest_choice := closest_choice and closest_choice[0] or None:
args['closest'] = closest_choice

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality
Suggested change
if closest_choice := closest_choice and closest_choice[0] or None:
args['closest'] = closest_choice
if closest_choice:
args['closest'] = closest_choice[0]

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

why not the above one liner?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

the one liner is less readable - at least to me

Comment thread Lib/argparse.py Outdated
args = {'value': value,
'choices': ', '.join(map(repr, action.choices))}
msg = _('invalid choice: %(value)r (choose from %(choices)s)')
closest_choice = _difflib.get_close_matches(value, action.choices)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

this might fail if action.choices are not strings

abdulrafey38 Nov 26, 2022
edited
Loading

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

argparser does not accept choices other than string, it will throw error even before reaching at this line
reference ==> https://stackoverflow.com/questions/49578928/typeerror-int-object-is-not-subscriptable-when-i-try-to-pass-three-arguments

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

The second example for the documentation (https://docs.python.org/3/library/argparse.html#choices)

parser = argparse.ArgumentParser(prog='doors.py')
parser.add_argument('door', type=int, choices=range(1, 4))
print(parser.parse_args(['3']))

Also - I would use

Suggested change
closest_choice = _difflib.get_close_matches(value, action.choices)
closest_choice = _difflib.get_close_matches(value, action.choices, 1)

ndenissov left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Please, instead of just this

closet_choice = _difflib.get_close_matches(value, action.choices)

Add

if isinstance(value, Iterable) and all(isinstance(option, Sized) for option in action.choices)):
    closet_choice = _difflib.get_close_matches(value, action.choices, 1)  # also n=1 (default 3)
else:
    closet_choice = []

or this (better in my opinion)

try:
    closet_choice = _difflib.get_close_matches(value, action.choices, 1)
except TypeError:
    closet_choice = []

abdulrafey38 marked this pull request as ready for review November 26, 2022 13:25
abdulrafey38 requested review from sobolevn and removed request for ndenissov November 26, 2022 13:25

abdulrafey38 commented Nov 28, 2022
edited
Loading

Copy link
Copy Markdown
Author

Closing this pull request & opening a new one as this PR contains unwanted commits...

Copy link
Copy Markdown
Member

Please, don't create new PRs.
This PR contains history and reviews. New one is empty. It is better to force push commits in case you have some conflicts than creating a new PR.

Copy link
Copy Markdown
Author

Ok @sobolevn i will open this PR again... and close the new one

abdulrafey38 reopened this Nov 28, 2022

Copy link
Copy Markdown
Author

@sobolevn reopened this PR again, please have a review

Copy link
Copy Markdown
Member

Quoting myself:

Isn't invalid choice: %(value)r (choose from %(choices)s) enough?

Copy link
Copy Markdown
Author

Quoting myself:

Isn't invalid choice: %(value)r (choose from %(choices)s) enough?

@sobolevn no this is not enough now, as we change argparser logic here ==> when we pass a choice which is not in choices array it now throws an exception with a different error message (this error message now includes closest suggestions too if available) & in the test case we are passing ['foo','bar'] in choices array and adding 'baz' in argparser. so instead of showing previous message which is (Isn't invalid choice: %(value)r (choose from %(choices)s)) it now throws msg including closest_choice which is (Isn't invalid choice: %(value)r, may be you meant %(closest_choice)r (choose from %(choices)s).

Copy link
Copy Markdown
Author

@sobolevn do we have any update here?

rhettinger self-assigned this Dec 3, 2022

Copy link
Copy Markdown
Contributor

I'm still evaluating whether this should be done or not. Here are a few thoughts:

  • We've tried hard to not add dependencies to argparse because startup time is important in command line applications. The import of difflib loads a slew of other modules.

  • The current choices error message is self-explanatory and we have no evidence that it is insufficient. AFAICT, no end-user has ever asked for this.

  • If this were added, it would need to be opt-in. There are thousands of deployed command line tools and the publishers of those tools may not want this new behavior.

encukou commented Mar 19, 2024

Copy link
Copy Markdown
Member

How's the evaluation going?
Some counterpoints:

  • difflib could be imported on error only
  • We don't really have a way for end-users to ask; “did you mean” notes for things like AttributeError were generally received positively.
  • IMO, opt-out would be fine; I don't think the wording of this message is API. But that's a personal opinion.

Copy link
Copy Markdown
Author

@encukou i can work on it further like importing on errors only, what u say?

encukou commented Mar 20, 2024

Copy link
Copy Markdown
Member

That work might not be merged, so it's better to wait for the decision on whether this is a good idea.

savannahostrowski left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Hey there - thanks for the PR! I'm in the process of triaging existing PRs for argparse and noticed this was still open.

A couple of comments but, this still works as intended.

(If you haven't got the bandwidth, let me know and I'd also be happy to carry the PR forward (with credit to you, of course!))

Comment thread Lib/argparse.py
]


import difflib as _difflib

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

I think we'd probably want to move the import down into the case where the error is thrown, since this is probably not going to be used very often.

Comment thread Lib/test/test_argparse.py
with self.assertRaises(ArgumentParserError) as excinfo:
parser.parse_args(('baz',))
self.assertRegex(
self.assertIn(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

We probably also want some additional test cases here.

Comment thread Lib/test/test_argparse.py
parser.parse_args(('baz',))
self.assertRegex(
self.assertIn(
"error: argument {foo,bar}: invalid choice: 'baz', maybe you meant 'bar'? (choose from 'foo', 'bar')",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

I'd be interested in others' opinions around the verbiage here. It seems like we are using both "Maybe you meant" and "Did you mean" verbiage in the codebase. Not sure if we have any principle around this.

Copy link
Copy Markdown
Author

Hi @savannahostrowski ,

Yes you can pick it and if you need any help do let me know.

Thanks

Copy link
Copy Markdown
Member

Carrying this forward in #124456 with @abdulrafey38's blessing. Thank you!

savannahostrowski added a commit to savannahostrowski/cpython that referenced this pull request Sep 24, 2024
savannahostrowski added a commit to savannahostrowski/cpython that referenced this pull request Sep 24, 2024
savannahostrowski added a commit to savannahostrowski/cpython that referenced this pull request Oct 12, 2024
serhiy-storchaka added a commit to savannahostrowski/cpython that referenced this pull request Oct 14, 2024
savannahostrowski added a commit to savannahostrowski/cpython that referenced this pull request Oct 17, 2024
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants


Back | FazBrowse Home | New Git URL