Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #111041 > unrolled thread

Re: Spot the bug: getoptquestion.py

Started byChris Angelico <rosuav@gmail.com>
First post2016-07-04 21:36 +1000
Last post2016-07-26 11:12 +1000
Articles 9 — 4 participants

Back to article view | Back to comp.lang.python

This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by below is the oldest one visible, not the original post.


Contents

  Re: Spot the bug: getoptquestion.py Chris Angelico <rosuav@gmail.com> - 2016-07-04 21:36 +1000
    Re: Spot the bug: getoptquestion.py jornws0718@xs4all.nl (Oscar) - 2016-07-04 12:38 +0000
      Re: Spot the bug: getoptquestion.py Chris Angelico <rosuav@gmail.com> - 2016-07-04 23:42 +1000
        Re: Spot the bug: getoptquestion.py Lawrence D’Oliveiro <lawrencedo99@gmail.com> - 2016-07-05 21:04 -0700
          Re: Spot the bug: getoptquestion.py Chris Angelico <rosuav@gmail.com> - 2016-07-06 14:14 +1000
            Re: Spot the bug: getoptquestion.py jornws0718@xs4all.nl (Oscar) - 2016-07-07 11:30 +0000
              Re: Spot the bug: getoptquestion.py Chris Angelico <rosuav@gmail.com> - 2016-07-07 22:12 +1000
                Re: Spot the bug: getoptquestion.py jornws0718@xs4all.nl (Oscar) - 2016-07-07 12:29 +0000
              Re: Spot the bug: getoptquestion.py Steven D'Aprano <steve@pearwood.info> - 2016-07-26 11:12 +1000

#111041 — Re: Spot the bug: getoptquestion.py

FromChris Angelico <rosuav@gmail.com>
Date2016-07-04 21:36 +1000
SubjectRe: Spot the bug: getoptquestion.py
Message-ID<mailman.66.1467632176.2295.python-list@python.org>
On Mon, Jul 4, 2016 at 9:24 PM, Oscar <jornws0718@xs4all.nl> wrote:
> Is this:
>
> a) a bug in getopt.getopt
> b) a bug in my code
> c) a great way to keep me busy for a while
> d) all of the above?
>
>
> #!/usr/bin/python
>
> from __future__ import print_function
> from getopt import getopt, GetoptError
> import sys
>
> try:
>     opts, args = getopt(sys.argv[1:], 'b', ['bug '])
>
> except GetoptError as err:
>     print('Caught:', repr(err))
>
> else:
>     if opts:
>         for opt, arg in opts:
>
>             if opt in ('-b', '--bug'):
>                 print ("Ceci n'est pas un bug!")
>             else:
>                 #print ('Missed option: "{0}"'.format(opt))
>                 print ('Missed option:', opt)
>     else:
>         print('Usage:', sys.argv[0],'-b|--bug')

Well, first thing I'd do is wipe out your try/except. It's not really
achieving much (you effectively catch an exception to print it to the
console and terminate).

But then what I'm seeing is that you have 'bug ' (with a trailing
space) in your list of long options, so getopt returns '--bug ' as a
long option. Is that a bug? I dunno. Why do you have the trailing
space? In any case, it's pretty easy to see if you change one line of
your code to:

print('Missed option: %r' % opt)

ChrisA

[toc] | [next] | [standalone]


#111047

Fromjornws0718@xs4all.nl (Oscar)
Date2016-07-04 12:38 +0000
Message-ID<577a58b9$0$5902$e4fe514c@news.xs4all.nl>
In reply to#111041
In article <mailman.66.1467632176.2295.python-list@python.org>,
Chris Angelico  <rosuav@gmail.com> wrote:
>On Mon, Jul 4, 2016 at 9:24 PM, Oscar <jornws0718@xs4all.nl> wrote:
>> Is this:
>>
>> a) a bug in getopt.getopt
>> b) a bug in my code
>> c) a great way to keep me busy for a while
>> d) all of the above?
>>
>>
>> #!/usr/bin/python
>>
>> from __future__ import print_function
>> from getopt import getopt, GetoptError
>> import sys
>>
>> try:
>>     opts, args = getopt(sys.argv[1:], 'b', ['bug '])
>>
>> except GetoptError as err:
>>     print('Caught:', repr(err))
>>
>> else:
>>     if opts:
>>         for opt, arg in opts:
>>
>>             if opt in ('-b', '--bug'):
>>                 print ("Ceci n'est pas un bug!")
>>             else:
>>                 #print ('Missed option: "{0}"'.format(opt))
>>                 print ('Missed option:', opt)
>>     else:
>>         print('Usage:', sys.argv[0],'-b|--bug')
>
>Well, first thing I'd do is wipe out your try/except. It's not really
>achieving much (you effectively catch an exception to print it to the
>console and terminate).

It does something: it shows that --bug on my commandline did not throw
an GetoptError. I could post the whole 400 line script, but decided to
cut it down to a demonstration of a subtle bug that i introduced in my
script. So far, answers b) and c) certainly do apply.


>But then what I'm seeing is that you have 'bug ' (with a trailing
>space) in your list of long options, so getopt returns '--bug ' as a
>long option.

You found it much faster than I did! ;-)

As i learned now, --b and --bu will also match '--bug ', as they are not
ambigous. So, of course '--bug' also returns '--bug ' in opts.

But it took me quite a while before I found my logic wasn't working
further down the script, just because I somehow introduced a space
character somewhere where it shouldn't have been.


> Is that a bug? I dunno. Why do you have the trailing
>space?

Because I'm stupid. It should not have been there at all. I've been
readjusting and reformatting my long 'getopt' line all day long and
somewhere my thumb must have hit my spacebar when I wasn't paying
attention. So a hard-to-find bug (for me at least) was introduced.

Now I also did not spot the trailing space in the loop where I was
evaluating the options when I added some debug statements. This sure 
got me scratching my head. The option is there, why doesn't my code do
what it's supposed to do? I sure was looking in the wrong place. I
better use repr() for debugging purposes next time. Thanks for the tip.

But is this not at least a bit unexpected behaviour from getopt? On one
hand, if I want to have trailing spaces in my longoptions, why not just
play along and allow them? On the other hand, a space is a delimiter on
the commandline. Does it make sense to allow it as a parameter to
getopt()? And if getopt would silently strip it, would that be a bug?

I agree that it's hard to debate wheter it is a bug, but I wanted to
share this experience anyway... ;-)


> In any case, it's pretty easy to see if you change one line of
>your code to:
>print('Missed option: %r' % opt)

Or uncomment my hint in the OP. But repr() is even better indeed.
-- 
[J|O|R] <- .signature.gz

[toc] | [prev] | [next] | [standalone]


#111073

FromChris Angelico <rosuav@gmail.com>
Date2016-07-04 23:42 +1000
Message-ID<mailman.68.1467639747.2295.python-list@python.org>
In reply to#111047
On Mon, Jul 4, 2016 at 10:38 PM, Oscar <jornws0718@xs4all.nl> wrote:
> But is this not at least a bit unexpected behaviour from getopt? On one
> hand, if I want to have trailing spaces in my longoptions, why not just
> play along and allow them? On the other hand, a space is a delimiter on
> the commandline. Does it make sense to allow it as a parameter to
> getopt()? And if getopt would silently strip it, would that be a bug?
>

This is really the crux of the matter. Honestly, I've no idea. The
getopt module is designed to match the C getopt function, which I've
never used; for my command-line parsing, I use argparse instead
(usually via some wrapper that cuts down the duplication, like clize).

ChrisA

[toc] | [prev] | [next] | [standalone]


#111167

FromLawrence D’Oliveiro <lawrencedo99@gmail.com>
Date2016-07-05 21:04 -0700
Message-ID<a588eed6-bfac-4cc9-be4a-f6ce188247b0@googlegroups.com>
In reply to#111073
On Tuesday, July 5, 2016 at 1:42:42 AM UTC+12, Chris Angelico wrote:

> The getopt module is designed to match the C getopt function, which I've
> never used; for my command-line parsing, I use argparse instead
> (usually via some wrapper that cuts down the duplication, like clize).

getopt seems so much simpler.

[toc] | [prev] | [next] | [standalone]


#111168

FromChris Angelico <rosuav@gmail.com>
Date2016-07-06 14:14 +1000
Message-ID<mailman.118.1467778498.2295.python-list@python.org>
In reply to#111167
On Wed, Jul 6, 2016 at 2:04 PM, Lawrence D’Oliveiro
<lawrencedo99@gmail.com> wrote:
> On Tuesday, July 5, 2016 at 1:42:42 AM UTC+12, Chris Angelico wrote:
>
>> The getopt module is designed to match the C getopt function, which I've
>> never used; for my command-line parsing, I use argparse instead
>> (usually via some wrapper that cuts down the duplication, like clize).
>
> getopt seems so much simpler.

Look at clize:

https://github.com/Rosuav/LetMeKnow/blob/master/letmeknow.py

I just put docstrings on my functions, slap "@command" above them, and
with minimal boilerplate, I have a fully-working command line
interface. It's a wrapper around argparse.

ChrisA

[toc] | [prev] | [next] | [standalone]


#111184

Fromjornws0718@xs4all.nl (Oscar)
Date2016-07-07 11:30 +0000
Message-ID<577e3d66$0$5816$e4fe514c@news.xs4all.nl>
In reply to#111168
In article <mailman.118.1467778498.2295.python-list@python.org>,
Chris Angelico  <rosuav@gmail.com> wrote:
>On Wed, Jul 6, 2016 at 2:04 PM, Lawrence D’Oliveiro
><lawrencedo99@gmail.com> wrote:
>> On Tuesday, July 5, 2016 at 1:42:42 AM UTC+12, Chris Angelico wrote:
>>
>>> The getopt module is designed to match the C getopt function, which I've
>>> never used; for my command-line parsing, I use argparse instead
>>> (usually via some wrapper that cuts down the duplication, like clize).
>>
>> getopt seems so much simpler.
>
>Look at clize:

Okay:

| >>> import clize
| Traceback (most recent call last):
|  File "<stdin>", line 1, in <module>
| ImportError: No module named clize

Mmm... nope. I'm not going to learn a new tool and introduce an extra
dependency just to do something as basic as getopt. But then again,
coming from a C background, getopt feels kind of familiar. ;-)

Thanks all for the input. I think it all boils down to: "If you don't
want a space in your long_option, don't put a space in there".


>I just put docstrings on my functions, slap "@command" above them, and
>with minimal boilerplate, I have a fully-working command line
>interface. It's a wrapper around argparse.

Looks neat though! 
-- 
[J|O|R] <- .signature.gz

[toc] | [prev] | [next] | [standalone]


#111185

FromChris Angelico <rosuav@gmail.com>
Date2016-07-07 22:12 +1000
Message-ID<mailman.128.1467893565.2295.python-list@python.org>
In reply to#111184
On Thu, Jul 7, 2016 at 9:30 PM, Oscar <jornws0718@xs4all.nl> wrote:
> Thanks all for the input. I think it all boils down to: "If you don't
> want a space in your long_option, don't put a space in there".

Yeah, I guess, pretty much!

> Mmm... nope. I'm not going to learn a new tool and introduce an extra
> dependency just to do something as basic as getopt. But then again,
> coming from a C background, getopt feels kind of familiar. ;-)

>>I just put docstrings on my functions, slap "@command" above them, and
>>with minimal boilerplate, I have a fully-working command line
>>interface. It's a wrapper around argparse.
>
> Looks neat though!

Yes, it's a third-party dependency. (Sorry, should have mentioned
that.) You're welcome to consider that to be too much risk and/or
hassle to be worth improving on getopt, but personally, I *really*
like the simplicity of just writing docstrings that still read
perfectly well as docstrings, and having them create my argparse
configs for me. Different strokes for different horses, or something
like that.

ChrisA

[toc] | [prev] | [next] | [standalone]


#111186

Fromjornws0718@xs4all.nl (Oscar)
Date2016-07-07 12:29 +0000
Message-ID<577e4b2b$0$5819$e4fe514c@news.xs4all.nl>
In reply to#111185
In article <mailman.128.1467893565.2295.python-list@python.org>,
Chris Angelico  <rosuav@gmail.com> wrote:
>Yes, it's a third-party dependency. (Sorry, should have mentioned
>that.) You're welcome to consider that to be too much risk and/or
>hassle to be worth improving on getopt, but personally, I *really*
>like the simplicity of just writing docstrings that still read
>perfectly well as docstrings, and having them create my argparse
>configs for me. Different strokes for different horses, or something
>like that.

Well, parsing the arguments was not really the problem in my case. But
after parsing I had to look at valid combinations and show helpfull
messages if required information is missing or conflicting options were
given. I doubt if an extra abstraction layer would have helped me.

It did make my typo a bit hard to catch, though...
-- 
[J|O|R] <- .signature.gz

[toc] | [prev] | [next] | [standalone]


#111875

FromSteven D'Aprano <steve@pearwood.info>
Date2016-07-26 11:12 +1000
Message-ID<5796b8ec$0$1603$c3e8da3$5496439d@news.astraweb.com>
In reply to#111184
On Thu, 7 Jul 2016 09:30 pm, Oscar wrote:

> Thanks all for the input. I think it all boils down to: "If you don't
> want a space in your long_option, don't put a space in there".


No, I don't think so. I think we can do better than that:

http://bugs.python.org/issue27619


What decided it for me was that the shell getopt on my system ignores
leading and trailing spaces.




-- 
Steven
“Cheer up,” they said, “things could be worse.” So I cheered up, and sure
enough, things got worse.

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web