beeware / briefcase-windows-VisualStudio-template

A template for generating Visual Studio projects for building Windows apps with Briefcase
MIT License
4 stars 9 forks source link

Stub application doesn't have stderr when running without console. #17

Closed gerasimovich-a closed 1 year ago

gerasimovich-a commented 1 year ago

Describe the bug

I'm trying to deploy my ML model with briefcase. It works with briefcase run but i have an error when launch an .exe

CatBoostError: Expected callable object or stream-like object \windows\app\src\app_packages\catboost\core.py", line 120, in _get_stream_like_object

https://github.com/catboost/catboost/blob/master/catboost/python-package/catboost/core.py

i found out that sys.stderr is None in case of running exe file

How can i fix it? I really appreciate any help you can provide

Expected behavior

sys.stderr is not None

Environment

freakboy3742 commented 1 year ago

Thanks for the report.

I've been able to reproduce your problem; for others, the critical piece is that briefcase dev and briefcase run won't trigger the problem. You need to start the app from the icon - either by installing, or activating the app from the file manager.

The thing is - I'm not 100% clear if this is a bug in Briefcase, or a bug in Catboost.

The problem is caused by this line in the Briefcase bootstrap app. This code exists because GUI apps can generate console output; but on Windows, that console output is lost when the app is run from the icon. This can make it exceedingly difficult to debug errors, because an app will just "not start", and the logs telling you what went wrong will be lost. The dialog that you've seen on the crash is part of this handling - we capture exception crashes and display the stack trace; we also write all stdout/stderr output to a log file in the user's AppData folder (keeping the last 9 runs, and deleting old log files as they age out).

This code is only executed when the app doesn't have a console attached. So, if you use briefcase run, the console is attached, and you get both stdout and stderr. However, when you run from the icon, there's no console, stderr is set to None, and as a result, stderr output redirects to stdout. We have to do this because we can only open a single pipe to write a log file, and IIRC stderr can't be dup'd on Windows to point to the same file handle as stdout. And - if you print("hello", file=sys.stderr), it works fine - the output is directed to stdout, which is logged to the output file.

However, catboost is doing something different - it's assuming that stderr exists, and is looking specifically for a write method on sys.stderr. That then raises the error you're seeing. I think this is a bug in catboost, because it's assuming that stderr must exist - which I think is a false assumption. However, I can't find any canonical documentation that confirms this. It's certainly true that processes usually have both stdout and stderr - but I don't know if they're required, or if Python guarantees that they're open pipes. Regardless, patching catboost to return stdout when stderr is None would fix the problem; whether you can convince catboost this is a required fix in their library is left as an exercise to the reader :-)

I can think of 2 immediate workarounds:

Firstly - based on the code you've referenced, catboost appears to have the ability to set a custom logger; if you install a custom logger that directs stderr output to stdout, that should work.

Secondly - you can do the same thing, but at the base Python level: if you put

import sys
sys.stderr = sys.stdout

into your code before catboost is initialised, you should get the same effect.

I'm going to transfer this issue to the briefcase visual studio template, since the problem isn't with Briefcase itself, but with the stub app used on Windows.

rmartin16 commented 1 year ago

Mild defense for catboost implementing a change.

Note 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.

freakboy3742 commented 1 year ago

🤦 I was looking for a Unix stdout/err reference, and forgot that Python's docs might have something to say on the matter.

I'd call that a little more than "mild"... that's pretty much canonical defence of what the stub app is doing, IMHO :-)

On the basis that Briefcase has a documented defence of it's implementation, and workarounds exist, I'm going to close this issue and call it a bug in catboost.