--help doesn't work #156

Closed
opened 1 year ago by soheday · 17 comments
soheday commented 1 year ago

In Windows I get no output at all when I try: img2pdf --help or img2pdf -h.

In Windows I get no output at all when I try: `img2pdf --help` or `img2pdf -h`.
josch commented 1 year ago
Owner

I'm unable to reproduce the problem because I do not own a machine that is able to run Microsoft Windows (I'm typing this on the MNT Reform) nor do I own a copy of Windows and I'm not willing to pay Microsoft for a copy of it.

Ultimately, this needs a Windows user who is skilled enough to track down what the problem is.

Until then, you can also read the --help output here:

https://manpages.debian.org/bullseye/img2pdf/img2pdf.1.en.html

I'm unable to reproduce the problem because I do not own a machine that is able to run Microsoft Windows (I'm typing this on the MNT Reform) nor do I own a copy of Windows and I'm not willing to pay Microsoft for a copy of it. Ultimately, this needs a Windows user who is skilled enough to track down what the problem is. Until then, you can also read the `--help` output here: https://manpages.debian.org/bullseye/img2pdf/img2pdf.1.en.html

0.4.4 release binary does not appear to run on windows at all. I believe the problem is not with "--help" not working, but rather it crashes with no output?

Running with --help does not crash, but there is no output to the command line.

Running "img2pdf" with no arguments gives this:

Failed to execute script 'img2pdf' due to unhandled exception:
'NoneType' object has no attribute 'buffer'

Traceback (most recent call last):
  File "img2pdf.py", line 4102, in <module>
  File "img2pdf.py", line 4032, in main
AttributeError: 'NoneType' object has no attribute 'buffer'
0.4.4 release binary does not appear to run on windows at all. I believe the problem is not with "--help" not working, but rather it crashes with no output? Running with --help does not crash, but there is no output to the command line. Running "img2pdf" with no arguments gives this: ``` Failed to execute script 'img2pdf' due to unhandled exception: 'NoneType' object has no attribute 'buffer' Traceback (most recent call last): File "img2pdf.py", line 4102, in <module> File "img2pdf.py", line 4032, in main AttributeError: 'NoneType' object has no attribute 'buffer' ```
josch commented 1 year ago
Owner

Okay, so in version 0.4.4, line 4032 reads:

images = [sys.stdin.buffer.read()]

The error message seems to suggest that sys.stdin is actually None. To solve this, we need somebody who knows about Python on Windows. I have no idea, why or how sys.stdin should ever be None...

Okay, so in version 0.4.4, line 4032 reads: images = [sys.stdin.buffer.read()] The error message seems to suggest that `sys.stdin` is actually `None`. To solve this, we need somebody who knows about Python on Windows. I have no idea, why or how `sys.stdin` should ever be `None`...

Running from IDLE rather than using the exe binary I get this description instead for the same line:

AttributeError: 'StdInputFile' object has no attribute 'buffer'

It seems the specific type of sys.stdin is up to the platform and there is no guarantee that it will have the buffer interface you are using. However, sys.stdin itself does have a read() which I believe you can use in the same way.

I notice at img2pdf.py line 3648 you have an accommodation for stdout:

default=sys.stdout.buffer if hasattr(sys.stdout, "buffer") else sys.stdout

I haven't tried to figure out what img2pdf is doing with the buffer interface specifically, but you can just use sys.stdin.read() directly. So, I'd tentatively suggest doing that. If getting rid of sys.stdin.buffer entirely is unsuitable, perhaps a fallback like stdout would be appropriate?

Running from IDLE rather than using the exe binary I get this description instead for the same line: ``` AttributeError: 'StdInputFile' object has no attribute 'buffer' ``` It seems the specific type of sys.stdin is up to the platform and there is no guarantee that it will have the buffer interface you are using. However, sys.stdin itself does have a read() which I believe you can use in the same way. I notice at [img2pdf.py line 3648](https://gitlab.mister-muffin.de/josch/img2pdf/src/commit/f454ebc6a65abf555dcdba51fbec8c906ababc95/src/img2pdf.py#L3648) you have an accommodation for stdout: ``` default=sys.stdout.buffer if hasattr(sys.stdout, "buffer") else sys.stdout ``` I haven't tried to figure out what img2pdf is doing with the buffer interface specifically, but you can just use sys.stdin.read() directly. So, I'd tentatively suggest doing that. If getting rid of sys.stdin.buffer entirely is unsuitable, perhaps a fallback like stdout would be appropriate?
josch commented 1 year ago
Owner

The difference between sys.stdin and sys.stdin.buffer is, that the latter is raw binary data while the former is a python string decoded according to the current locale. Using sys.stdin makes sense for application reading in text data that should be handled according to the current locale. But this doesn't make sense for img2pdf because we are not reading text but binary data in the form of raw images. That's why img2pdf is using sys.stdin.buffer. Now we could of course also use this:

images = [sys.stdin.buffer.read() if hasattr(sys.stdin, "buffer") else sys.stdin.read()]

But according to the error message, sys.stdin itself is None so the code above would also fail with an error message like:

AttributeError: 'NoneType' object has no attribute 'read'

I've been reading https://docs.python.org/3/library/sys.html but it doesn't mention that sys.stdin could ever become None. I do not understand what is going on here.

The difference between `sys.stdin` and `sys.stdin.buffer` is, that the latter is raw binary data while the former is a python string decoded according to the current locale. Using `sys.stdin` makes sense for application reading in text data that should be handled according to the current locale. But this doesn't make sense for img2pdf because we are not reading text but binary data in the form of raw images. That's why img2pdf is using `sys.stdin.buffer`. Now we could of course also use this: images = [sys.stdin.buffer.read() if hasattr(sys.stdin, "buffer") else sys.stdin.read()] But according to the error message, `sys.stdin` itself is `None` so the code above would also fail with an error message like: AttributeError: 'NoneType' object has no attribute 'read' I've been reading https://docs.python.org/3/library/sys.html but it doesn't mention that `sys.stdin` could ever become `None`. I do not understand what is going on here.
josch commented 1 year ago
Owner

There is some hint about what is going on here:

Under some conditions stdin, stdout and stderr as well as the original values stdin, stdout and stderr can be None. It is usually the case for Windows GUI apps that aren’t connected to a console and Python apps started with pythonw.

This would also explain why running img2pdf --help does not produce any output. If Windows does not provide a connection to a console to img2pdf, then obviously it cannot print its --help output.

So how can this be fixed?

There is some hint about what is going on [here](https://docs.python.org/3/library/sys.html#sys.__stdin__): > Under some conditions stdin, stdout and stderr as well as the original values __stdin__, __stdout__ and __stderr__ can be None. It is usually the case for Windows GUI apps that aren’t connected to a console and Python apps started with pythonw. This would also explain why running `img2pdf --help` does not produce any output. If Windows does not provide a connection to a console to img2pdf, then obviously it cannot print its `--help` output. So how can this be fixed?

So, it seems like you are using PyInstaller to make the EXE? I haven't used that before, but a quick guess would be that you removed the console with "--noconsole". A windows command line application will require the console.

So, it seems like you are using PyInstaller to make the EXE? I haven't used that before, but a quick guess would be that you [removed the console](https://gitlab.mister-muffin.de/josch/img2pdf/src/commit/be8369373fbe1d75f40ada7f9f995d37ea57184c/appveyor.yml#L29) with "--noconsole". A windows command line application will require the console.
josch commented 1 year ago
Owner

But if this is true, then this means that the appveyor windows builds never worked. I'm really upset about the Windows situations as people keep asking for it but then do not test it: #125

But if this never worked in the past I wonder where the other issues from Windows users come from who reported bugs to me. Are those then not using the img2pdf.exe from appveyor but use pypi and python.exe manually? No idea.

In any case, I tried out your suggestion and removed --noconsoleproducing the img2pdf_console.exe artifact here:

https://ci.appveyor.com/project/josch/img2pdf/build/artifacts

Could you give those a try and report back what happens? Thanks!

But if this is true, then this means that the appveyor windows builds **never** worked. I'm really upset about the Windows situations as people keep asking for it but then do not test it: https://gitlab.mister-muffin.de/josch/img2pdf/issues/125 But if this never worked in the past I wonder where the other issues from Windows users come from who reported bugs to me. Are those then not using the img2pdf.exe from appveyor but use pypi and python.exe manually? No idea. In any case, I tried out your suggestion and removed `--noconsole`producing the `img2pdf_console.exe` artifact here: https://ci.appveyor.com/project/josch/img2pdf/build/artifacts Could you give those a try and report back what happens? Thanks!

Yes, img2pdf.exe is still broken in the same way as before. img2pdf_console.exe --help now gives the help text to the console as expected.

--console is the default and --nowindowed is just an alias for the same option, so you don't actually need both on your command. Actually because it's already the default you don't need either of them, you just needed to remove --noconsole, but perhaps it is nice to explicitly ask for --console.

.

To explain: Windows applications are either for the command line (attached to the console), or they are GUI only and do not have the console system for user text input/output.

Either type can be run from a command line console, or by double clicking the executable in the file explorer. A console application will attach itself to the console it is run from, but if double-clicked it will instead open its own new console window for its duration.

A GUI application will not open a new console if double clicked, and if run from the command line console, it does not attach itself to that console. Instead that console returns immediately to its own command line, ready for more user input, and the GUI application will run independently on its own.

Either type of application can open one or more additional GUI windows, but only the console application can have user text I/O through the standard command line console (GUI application cannot normally open its own, or attach to an existing one). Additionally the console application must have its console window open for its entire life time, closing that console will close the console application.

.

So, to report what happens:

img2pdf
  GUI: crashes with a pop-up window with the message that I gave above.
  Console: no output, waits for user input on the command line.

img2pdf --help
  GUI: exits with no message.
  Console: displays help text to the console.

img2pdf test.jpg -o test.pdf
  Works on both, no text output.

img2pdf filenotfound.jpg -o test.pdf
  GUI: does not display usage, crashes with pop-up window containing technical
     information and stack trace. Includes the exception text, but in the middle
     of much other information:
       FileNotFoundError: [WinError 2] The system cannot find the file specified:
       'filenotfound.jpg'
  Console: displays usage followed by:
     error: argument infile: "filenotfound.jpg" does not exist

img2pdf < test.jpg > test.pdf
  Works on both, no text output.

img2pdf < test.jpg
  GUI: no output file, no output text.
  Console: outputs garbage to the command line console.

For the sake of users, I would suggest that running the application with no parameters should print usage. Having the console wait for input in this case is confusing and not useful. The user simply has an empty console window with a blinking cursor, and no indication of what to do. Indeed, the only thing I can do here is press Ctrl-C to cancel the program, or close the console itself.

I could not see any mention in your README about piping an image file directly to stdin. I only guessed that I could do this because of the confusing way it was waiting for input if given no parameters. I don't feel that most Windows users would be able to guess this.

Yes, ```img2pdf.exe``` is still broken in the same way as before. ```img2pdf_console.exe --help``` now gives the help text to the console as expected. ```--console``` is the default and ```--nowindowed``` is just an alias for the same option, so you don't actually need both on your command. Actually because it's already the default you don't need either of them, you just needed to remove ```--noconsole```, but perhaps it is nice to explicitly ask for ``--console``. . To explain: Windows applications are either for the command line (attached to the console), or they are GUI only and do not have the console system for user text input/output. Either type can be run from a command line console, or by double clicking the executable in the file explorer. A console application will attach itself to the console it is run from, but if double-clicked it will instead open its own new console window for its duration. A GUI application will not open a new console if double clicked, and if run from the command line console, it does not attach itself to that console. Instead that console returns immediately to its own command line, ready for more user input, and the GUI application will run independently on its own. Either type of application can open one or more additional GUI windows, but only the console application can have user text I/O through the standard command line console (GUI application cannot normally open its own, or attach to an existing one). Additionally the console application must have its console window open for its entire life time, closing that console will close the console application. . So, to report what happens: ``` img2pdf GUI: crashes with a pop-up window with the message that I gave above. Console: no output, waits for user input on the command line. img2pdf --help GUI: exits with no message. Console: displays help text to the console. img2pdf test.jpg -o test.pdf Works on both, no text output. img2pdf filenotfound.jpg -o test.pdf GUI: does not display usage, crashes with pop-up window containing technical information and stack trace. Includes the exception text, but in the middle of much other information: FileNotFoundError: [WinError 2] The system cannot find the file specified: 'filenotfound.jpg' Console: displays usage followed by: error: argument infile: "filenotfound.jpg" does not exist img2pdf < test.jpg > test.pdf Works on both, no text output. img2pdf < test.jpg GUI: no output file, no output text. Console: outputs garbage to the command line console. ``` For the sake of users, I would suggest that running the application with no parameters should print usage. Having the console wait for input in this case is confusing and not useful. The user simply has an empty console window with a blinking cursor, and no indication of what to do. Indeed, the only thing I can do here is press Ctrl-C to cancel the program, or close the console itself. I could not see any mention in your README about piping an image file directly to stdin. I only guessed that I could do this because of the confusing way it was waiting for input if given no parameters. I don't feel that most Windows users would be able to guess this.

But if this is true, then this means that the appveyor windows builds never worked. I'm really upset about the Windows situations as people keep asking for it but then do not test it: #125

It seems that it did work if given the right command line, but could not produce --help, and any error conditions were unfortunately only diagnosed with a pop-up GUI crash window, which I think is PyInstaller's exception handler for --noconsole apps.

What I would say is that a new Windows user looking to try this would probably run it with no arguments, see it crash, and move on rather than saying anything. Some users will try --help but only if they are more persistent. (This is also why I strongly suggest printing usage if no arguments are given, rather than locking the user into an unusable text input mode.)

Finally, even for the users who are more persistent, they have to be especially persistent to want to create a new user account on your private mister-muffin gitlab to be able to report an issue. I almost gave up instead of creating this account.

Truthfully, my own motivation was partly that I mistakenly thought the old tool I had was an earlier working version (#163), and because I found it useful I was sad to see that it no longer works. After going through all the steps to be able to report an issue, I have stayed because you are responsive and seem generally interested in improving the situation, so I am happy to help test it.

Anyway, these are my 2 suggestions:

  • --console will make --help functional, and allow useful error messages.
  • No-arguments printing usage instead of waiting forever for user input.
> But if this is true, then this means that the appveyor windows builds **never** worked. I'm really upset about the Windows situations as people keep asking for it but then do not test it: https://gitlab.mister-muffin.de/josch/img2pdf/issues/125 It seems that it did work if given the right command line, but could not produce --help, and any error conditions were unfortunately only diagnosed with a pop-up GUI crash window, which I think is PyInstaller's exception handler for ```--noconsole``` apps. What I would say is that a new Windows user looking to try this would probably run it with no arguments, see it crash, and move on rather than saying anything. Some users will try --help but only if they are more persistent. (This is also why I strongly suggest printing usage if no arguments are given, rather than locking the user into an unusable text input mode.) Finally, even for the users who are more persistent, they have to be especially persistent to want to create a new user account on your private mister-muffin gitlab to be able to report an issue. I almost gave up instead of creating this account. Truthfully, my own motivation was partly that I mistakenly thought the old tool I had was an earlier working version (#163), and because I found it useful I was sad to see that it no longer works. After going through all the steps to be able to report an issue, I have stayed because you are responsive and seem generally interested in improving the situation, so I am happy to help test it. Anyway, these are my 2 suggestions: * ``--console`` will make --help functional, and allow useful error messages. * No-arguments printing usage instead of waiting forever for user input.

Two more thoughts on the default behaviour with no arguments:

Printing usage would be good, since --help is very verbose with multiple pages, but I think it would be helpful if it also had a more direct statement to use "--help" for more information. The concise usage lists [-h] as the first possible option, but I think more novice users might not guess that this is for help.

.

As a secondary idea, I notice that the --gui option does work on windows, though obviously it's experimental. It's at least enough to open some files and save a PDF. After opening files, the panel on the left will say "PyMuPDF not available. Install the Python fitz module for preview functionality."

If the GUI was completed and no longer experimental, it could be appropriate to just open the GUI if no other arguments were given. That would mean a Windows user with no command-line experience could double click on the EXE, and have a good chance of being able to use it.

Two more thoughts on the default behaviour with no arguments: Printing usage would be good, since --help is very verbose with multiple pages, but I think it would be helpful if it also had a more direct statement to use "--help" for more information. The concise usage lists ```[-h]``` as the first possible option, but I think more novice users might not guess that this is for help. . As a secondary idea, I notice that the --gui option *does* work on windows, though obviously it's experimental. It's at least enough to open some files and save a PDF. After opening files, the panel on the left will say "PyMuPDF not available. Install the Python fitz module for preview functionality." If the GUI was completed and no longer experimental, it could be appropriate to just open the GUI if no other arguments were given. That would mean a Windows user with no command-line experience could double click on the EXE, and have a good chance of being able to use it.
Poster

nor do I own a copy of Windows and I'm not willing to pay Microsoft for a copy of it.

You can download legal free Windows images that run in virtual machines. They have some restrictions, but are more than good enough for testing.

In any case, I tried out your suggestion and removed --noconsoleproducing the img2pdf_console.exe artifact here:

https://ci.appveyor.com/project/josch/img2pdf/build/artifacts

Could you give those a try and report back what happens? Thanks!

It now works as expected. Thank you!

I absolutely agree with @bbbradsmith on these points:

  • For the sake of users, I would suggest that running the application with no parameters should print usage.
  • What I would say is that a new Windows user looking to try this would probably run it with no arguments, see it crash, and move on rather than saying anything. (Personally, I was more persistent user and looked for an example how to use img2pdf, then tried to modify it to my needs, failed many many times until I got the result I was looking for. Working stdout would have helped a lot).
> nor do I own a copy of Windows and I'm not willing to pay Microsoft for a copy of it. You can download legal free Windows images that run in virtual machines. They have some restrictions, but are more than good enough for testing. > In any case, I tried out your suggestion and removed `--noconsole`producing the `img2pdf_console.exe` artifact here: > > https://ci.appveyor.com/project/josch/img2pdf/build/artifacts > > Could you give those a try and report back what happens? Thanks! It now works as expected. Thank you! I absolutely agree with @bbbradsmith on these points: * For the sake of users, I would suggest that running the application with no parameters should print usage. * What I would say is that a new Windows user looking to try this would probably run it with no arguments, see it crash, and move on rather than saying anything. (Personally, I was more persistent user and looked for an example how to use img2pdf, then tried to modify it to my needs, failed many many times until I got the result I was looking for. Working *stdout* would have helped a lot).
Owner

You can download legal free Windows images that run in virtual machines. They have some restrictions, but are more than good enough for testing.

This is my computer: https://shop.mntre.com/products/mnt-reform

It has an ARM Cortex-A53 A53 at 1.5 GHz and 4 GB of RAM. Loading youtube.com (the front page) in my browser takes 38 seconds (so that you get an idea about its performance). But I doubt my 4 GB of RAM alone would be enough to run Windows and even less so the RAM a virtual machine would have. Or do you know of another way?

For the sake of users, I would suggest that running the application with no parameters should print usage.

On Linux and UNIX-like systems it is a common pattern that positional arguments are optional and if they are missing, the content is read from standard input. I'd like to retain this feature as I'm using it a lot in my own scripts.

What I want to do to make this less confusing for users who are not familiar with this principle and who do not try typing the same command with --help is to add a message like this to stderr if img2pdf is run with no arguments:

Reading image from standard input... Re-run with `--help` to get usage information

What I would say is that a new Windows user looking to try this would probably run it with no arguments, see it crash, and move on rather than saying anything. (Personally, I was more persistent user and looked for an example how to use img2pdf, then tried to modify it to my needs, failed many many times until I got the result I was looking for. Working stdout would have helped a lot).

Thank you for sticking around and writing here! I'll definitely move the windows build to --console as long as the GUI is of little value (and probably provide two executables for Windows once it is).

But also remember that I have no problem with you moving on because I'm only writing this software in my free time as a hobby, so if you like my software and use it that's great! But I'm not loosing anything if you do not like it and move on.

Thanks!

> You can download legal free Windows images that run in virtual machines. They have some restrictions, but are more than good enough for testing. This is my computer: https://shop.mntre.com/products/mnt-reform It has an ARM Cortex-A53 A53 at 1.5 GHz and 4 GB of RAM. Loading youtube.com (the front page) in my browser takes 38 seconds (so that you get an idea about its performance). But I doubt my 4 GB of RAM alone would be enough to run Windows and even less so the RAM a virtual machine would have. Or do you know of another way? > For the sake of users, I would suggest that running the application with no parameters should print usage. On Linux and UNIX-like systems it is a common pattern that positional arguments are optional and if they are missing, the content is read from standard input. I'd like to retain this feature as I'm using it a lot in my own scripts. What I want to do to make this less confusing for users who are not familiar with this principle and who do not try typing the same command with `--help` is to add a message like this to stderr if img2pdf is run with no arguments: Reading image from standard input... Re-run with `--help` to get usage information > What I would say is that a new Windows user looking to try this would probably run it with no arguments, see it crash, and move on rather than saying anything. (Personally, I was more persistent user and looked for an example how to use img2pdf, then tried to modify it to my needs, failed many many times until I got the result I was looking for. Working stdout would have helped a lot). Thank you for sticking around and writing here! I'll definitely move the windows build to `--console` as long as the GUI is of little value (and probably provide two executables for Windows once it is). But also remember that I have no problem with you moving on because I'm only writing this software in my free time as a hobby, so if you like my software and use it that's great! But I'm not loosing anything if you do not like it and move on. Thanks!

Using --console does not prevent the Windows application from opening GUI windows, it only makes sure there is console open for standard output. The --noconsole option is for GUI-only programs that don't want a console. So, there's probably no need to build it both of these ways, the --console version can still open the GUI.

Using `--console` does not prevent the Windows application from opening GUI windows, it only makes sure there is console open for standard output. The `--noconsole` option is for GUI-only programs that don't want a console. So, there's probably no need to build it both of these ways, the `--console` version can still open the GUI.
Owner

Using --console does not prevent the Windows application from opening GUI windows, it only makes sure there is console open for standard output. The --noconsole option is for GUI-only programs that don't want a console. So, there's probably no need to build it both of these ways, the --console version can still open the GUI.

But would that not be very bothersome for people who only want the GUI in the future and would then click on an icon somewhere and have both the console and the GUI opened?

> Using --console does not prevent the Windows application from opening GUI windows, it only makes sure there is console open for standard output. The --noconsole option is for GUI-only programs that don't want a console. So, there's probably no need to build it both of these ways, the --console version can still open the GUI. But would that not be very bothersome for people who only want the GUI in the future and would then click on an icon somewhere and have both the console *and* the GUI opened?

If you want a GUI-only app, yes it's the norm to build it without console.

It's not common for GUI windows apps to open a console, though there are some programs that do it anyway. Doesn't really cause much problem, just an extra window that might not have much purpose. If you want to eliminate this extra window, then yes that does require the separate build.

If you want a GUI-only app, yes it's the norm to build it without console. It's not common for GUI windows apps to open a console, though there are some programs that do it anyway. Doesn't really cause much problem, just an extra window that might not have much purpose. If you want to eliminate this extra window, then yes that does require the separate build.
josch closed this issue 11 months ago
Owner

I think the problem is now solved. Thank you very much @bbbradsmith for your very helpful input which finally fixes this problem on Windows! 💙

I think the problem is now solved. Thank you very much @bbbradsmith for your very helpful input which finally fixes this problem on Windows! 💙
Sign in to join this conversation.
No Milestone
No project
No Assignees
3 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: josch/img2pdf#156
Loading…
There is no content yet.