PyInstaller batch application works fine in console mode, crashing in window mode

I am creating a fairly complex application using Python and PySide. Finally, the release day is close, so I want to create this application as exe.

However, I have a strange problem on my hands. I used PyInstaller (using version 2 by the way) in the past and it never happened to me.

Basically, when I create an application with the --console flag, it works fine, but it opens a console window. When I create an application with a window flag ( -w ), it does not work fine. It starts and everything, but there are all these strange glitches. For example, when loading a text file, a BadFileDescriptor error often occurs (which does not occur in console mode), and the application crashes after performing a certain task. Worse, the task is a cycle, and it works great for the first time, but when it starts working again, it crashes.

When I looked at the minidump file, there were some errors in violation of access to QtGui4.dll files. Again, this does not happen in console mode.

Does anyone have any ideas?

+4
source share
1 answer

BadFileDescriptor error and, consequently, memory access violation caused by the fact that stdout applications in windowed mode is a buffer of a fixed size. So, if you write to stdout , either using print or sys.stdout directly, after a while you will see these errors.

You can fix this:

  • Removing / commenting on stdout entries
  • Using logging instead of printing in stdout
  • Redirecting stdout at the start of your application. This is a solution that requires less code to modify, although I think that choosing logging debug statements would be a better choice.

To redirect stdout , you can use code like this:

 import sys import tempfile sys.stdout = tempfile.TemporaryFile() sys.stderr = tempfile.TemporaryFile() 

Before executing your program. You can also use some kind of custom object to put the output in "log" files or something else, the important thing is that the output should not fill a fixed size buffer.

For example, you can do something similar to be able to use the logging module without changing too much code:

 import sys import logging debug_logger = logging.getLogger('debug') debug_logger.write = debug_logger.debug #consider all prints as debug information debug_logger.flush = lambda: None # this may be called when printing #debug_logger.setLevel(logging.DEBUG) #activate debug logger output sys.stdout = debug_logger 

The disadvantage of this approach is that print makes more stdout.write calls for each line:

 >>> print 'test' DEBUG:debug:test DEBUG:debug: 

If you want, you can probably avoid this behavior by creating a real write function that calls the_logger.debug with "full lines" only.

In any case, I think that such a solution should only be temporary and should only be used before transferring print to logging.debug calls.

(Obviously, registrars should write to a file, not to stdout , to avoid errors.)

+5
source

Source: https://habr.com/ru/post/1446625/


All Articles