Skip to content

ENH: Gracefully handle python-build-standalone ImportError with Tk #30394

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 30 additions & 2 deletions lib/matplotlib/backends/_backend_tk.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,36 @@
TimerBase, ToolContainerBase, cursors, _Mode, MouseButton,
CloseEvent, KeyEvent, LocationEvent, MouseEvent, ResizeEvent)
from matplotlib._pylab_helpers import Gcf
from . import _tkagg
from ._tkagg import TK_PHOTO_COMPOSITE_OVERLAY, TK_PHOTO_COMPOSITE_SET

try:
from . import _tkagg
from ._tkagg import TK_PHOTO_COMPOSITE_OVERLAY, TK_PHOTO_COMPOSITE_SET
except ImportError as e:
# catch incompatibility of python-build-standalone with Tk
cause1 = getattr(e, '__cause__', None)
cause2 = getattr(cause1, '__cause__', None)
if (isinstance(cause1, ImportError) and
isinstance(cause2, AttributeError) and
"'_tkinter' has no attribute '__file__'" in str(cause2)):

is_uv_python = "/uv/python" in (os.path.realpath(sys.executable))
Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Member Author

Choose a reason for hiding this comment

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

Is that more helpful?

I think we should catch the error, not exclude python-build-standalone per-se. If they'd fix the tk issue, our versions would directly work. On is_uv_python - I've explicitly tested for uv and tailored the error message, because I anticipate that'll by far the most route to trigger this, and I project that most uv users will not know what python-build-standalone is. So let's give them a uv-targeted error message.

Copy link
Member

Choose a reason for hiding this comment

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

I didn't suggest excluding python-build-standalone, just detecting it differently.

Copy link
Member Author

Choose a reason for hiding this comment

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

My point is I do not really care about python-build-standalone. The criterion is 1. does it raise the known error? And if so, is it a uv-install that I can point users to as the practical cause.

Copy link
Member

Choose a reason for hiding this comment

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

If that's the case that you only care about uv, then the PR/commit title should be adjusted.

Copy link
Member Author

Choose a reason for hiding this comment

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

Possibly my wording was not exactly precise.

The issue originates from the current way python-build-standalone is implmented. - So the PR title is justified.

Then there are two aspects to handling:

  1. Detection: I want to detect the specific error and respond to that. - It's not helpful to detect python-build-standalone. They may improve to fix the error in the future. So issuing a warning/error purely on the fact that python-build-standalone is used would be presumptuous.

  2. Error message: In the simplest case, we could just have the second error message

    Failed to import tkagg backend. This is likely caused by using a Python executable based on python-build-standalone, which is not compatible with Tk. Please use another Python interpreter or select another backend.

    (or if you want to be more affirmative explicitly test for python-build-standalone and remove the "likely"). However, the by-far most common way to obtain a python-build-standalone python is via uv. But it's a technical detail of uv and users are most likely not aware of it. So telling them, they have python-build-standalone is not helpful for fixing the issue. Therefore, I added the uv detection to tell them that uv-provided python is not compatible.

Copy link
Member

Choose a reason for hiding this comment

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

I am 👍 on doing the work to detect if it is uv.

if is_uv_python:
raise ImportError(
"Failed to import tkagg backend. You appear to be using an outdated "
"version of uv's managed Python distribution which is not compatible "
"with Tk. Please upgrade to the latest uv version, then update "
"Python with: `uv python upgrade --reinstall`"
) from e
else:
raise ImportError(
"Failed to import tkagg backend. This is likely caused by using a "
"Python executable based on python-build-standalone, which is not "
"compatible with Tk. Recent versions of python-build-standalone "
"should be compatible with Tk. Please update your python version "
"or select another backend."
) from e
else:
raise


_log = logging.getLogger(__name__)
Expand Down
Loading