Linuxbrew-core: Python: not configured with Tk and break matplotlib

Created on 16 Jan 2019  路  12Comments  路  Source: Homebrew/linuxbrew-core

Please note we will close your issue without comment if you delete, do not read or do not fill out the issue checklist below and provide ALL the requested information. If you repeatedly fail to use the issue template, we will block you from ever submitting issues to Homebrew again.

  • [x] have a problem with brew install (or upgrade, reinstall) a single formula? If it's a general brew problem please file this issue at Linuxbrew/brew: https://github.com/Linuxbrew/brew/issues/new/choose. If it's a tap (e.g. Brewsci/homebrew-bio) problem please file this issue at the tap.
  • [x] ran brew update and can still reproduce the problem?
  • [x] ran brew doctor, fixed all issues and can still reproduce the problem?
  • [ ] ran brew gist-logs <formula> (where <formula> is the name of the formula that failed) and included the output link?
  • [ ] if brew gist-logs didn't work: ran brew config and brew doctor and included their output with your issue?

To help us debug your issue please explain:

  • What you were trying to do (and why)
    Install and use matplotlib in python3
  • What happened (include command output)
    After pip3 install matplotlib, I can't use the TkAgg backend because of python3 is not configured with Tk:
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/linuxbrew/.linuxbrew/Cellar/python/3.7.2_1/lib/python3.7/site-packages/matplotlib/pyplot.py", line 2374, in <module>
    switch_backend(rcParams["backend"])
  File "/home/linuxbrew/.linuxbrew/Cellar/python/3.7.2_1/lib/python3.7/site-packages/matplotlib/pyplot.py", line 207, in switch_backend
    backend_mod = importlib.import_module(backend_name)
  File "/home/linuxbrew/.linuxbrew/bin/../Cellar/python/3.7.2_1/lib/python3.7/importlib/__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "/home/linuxbrew/.linuxbrew/Cellar/python/3.7.2_1/lib/python3.7/site-packages/matplotlib/backends/backend_tkagg.py", line 1, in <module>
    from . import _backend_tk
  File "/home/linuxbrew/.linuxbrew/Cellar/python/3.7.2_1/lib/python3.7/site-packages/matplotlib/backends/_backend_tk.py", line 5, in <module>
    import tkinter as Tk
  File "/home/linuxbrew/.linuxbrew/Cellar/python/3.7.2_1/lib/python3.7/tkinter/__init__.py", line 36, in <module>
    import _tkinter # If this fails your Python may not be configured for Tk
ModuleNotFoundError: No module named '_tkinter'
brew install python3
pip3 install matplotlib
python3 -c "import matplotlib.pyplot as plt"
python3 -c "import _tkinter"
outdated

Most helpful comment

That's exactly the reason why that option is not enabled. I already tried to enable it and it only brought problems.

The only way out in my opinion is the following: we need a minimal python formula (called python-minimal for example), that just installs a python binary. The formula should not install anything else, and should not conflict with other python formulae. The binary could maybe even be called something else (instead of calling python, we could call python-minimal). We could then use that binary to break the dependency cycle and build either python or tcl-tk.

This is just a hypothesis, not sure it will work. Having the separate build-time only python binary would also help fix other dependency cycles (I think there was another one involving libxml2).

All 12 comments

I can fix the issue by adding the config option when building python from source:

diff --git a/Formula/python.rb b/Formula/python.rb
index c6afd1c300..3b51fe512c 100644
--- a/Formula/python.rb
+++ b/Formula/python.rb
@@ -92,6 +92,8 @@ class Python < Formula
       --enable-loadable-sqlite-extensions
       --without-ensurepip
       --with-openssl=#{Formula["openssl"].opt_prefix}
+      --with-tcltk-includes="-I#{Formula["tcl-tk"].opt_include}"
+      --with-tcltk-libs="-L#{Formula["tcl-tk"].opt_lib}"
     ]
     args << "--with-dtrace" unless OS.linux?

I can see that there would be a cyclic dependency issue if python depends on tcl-tk. However, a lot of python applications depends on matplotlib and python would lose an arm and a leg without it. Is there a workaround for this?

That's exactly the reason why that option is not enabled. I already tried to enable it and it only brought problems.

The only way out in my opinion is the following: we need a minimal python formula (called python-minimal for example), that just installs a python binary. The formula should not install anything else, and should not conflict with other python formulae. The binary could maybe even be called something else (instead of calling python, we could call python-minimal). We could then use that binary to break the dependency cycle and build either python or tcl-tk.

This is just a hypothesis, not sure it will work. Having the separate build-time only python binary would also help fix other dependency cycles (I think there was another one involving libxml2).

Well, I think it's easier if we don't explicit specify the dependency of python3 on tcl-tk but use the config option anyway. Python will ignore that option if no tcl-tk is found. As a result, when the user doesn't have tcl-tk installed, we have the crippled python as the current version (no tkinter module); when the user does install tcl-tk, we have the working python. We document this in the caveat and let the user know

@iMichka In any case, we need to document that the current python is without tkinter module -- which I think no one wants to use

diff --git a/Formula/python.rb b/Formula/python.rb
index c6afd1c300..3b51fe512c 100644
--- a/Formula/python.rb
+++ b/Formula/python.rb
@@ -92,6 +92,8 @@ class Python < Formula
       --enable-loadable-sqlite-extensions
       --without-ensurepip
       --with-openssl=#{Formula["openssl"].opt_prefix}
+      --with-tcltk-includes="-I#{Formula["tcl-tk"].opt_include}"
+      --with-tcltk-libs="-L#{Formula["tcl-tk"].opt_lib}"
     ]
     args << "--with-dtrace" unless OS.linux?

@iMichka Is it OK for me to the submit this as a PR? This is a temporary solution -- it will default to the current bottled version if no tcl-tk found or build with tcl-tk if found.

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.

I have 3 pull requests open to clean up a little bit the dependency tree:
util-linux should not depend on Python2: #12232
libxcb and xcb-proto can be simplified and will not depend on Python anymore (only on minimal-python): https://github.com/Linuxbrew/homebrew-xorg/pull/455
libxt should not depend on glib, as this is only needed for the tests: https://github.com/Linuxbrew/homebrew-xorg/pull/483

With all this I was able to get a xorg formula which does not depend on Python/Python2

I have the same problem as OP: Trying to get some pandas examples to run, which in turn use matplotlib. However matplotlib complains about _tkinter not being available:

>>> import pandas as pd
>>> california_housing_dataframe = pd.read_csv("https://download.mlcc.google.com/mledu-datasets/california_housing_train.csv", sep=",")
>>> california_housing_dataframe.hist('housing_median_age')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/linuxbrew/.linuxbrew/Cellar/python/3.7.2_2/lib/python3.7/site-packages/pandas/plotting/_core.py", line 2405, in hist_frame
    layout=layout)
  File "/home/linuxbrew/.linuxbrew/Cellar/python/3.7.2_2/lib/python3.7/site-packages/pandas/plotting/_tools.py", line 191, in _subplots
    import matplotlib.pyplot as plt
  File "/home/linuxbrew/.linuxbrew/Cellar/python/3.7.2_2/lib/python3.7/site-packages/matplotlib/pyplot.py", line 2372, in <module>
    switch_backend(rcParams["backend"])
  File "/home/linuxbrew/.linuxbrew/Cellar/python/3.7.2_2/lib/python3.7/site-packages/matplotlib/pyplot.py", line 207, in switch_backend
    backend_mod = importlib.import_module(backend_name)
  File "/home/linuxbrew/.linuxbrew/Cellar/python/3.7.2_2/lib/python3.7/importlib/__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "/home/linuxbrew/.linuxbrew/Cellar/python/3.7.2_2/lib/python3.7/site-packages/matplotlib/backends/backend_tkagg.py", line 1, in <module>
    from . import _backend_tk
  File "/home/linuxbrew/.linuxbrew/Cellar/python/3.7.2_2/lib/python3.7/site-packages/matplotlib/backends/_backend_tk.py", line 5, in <module>
    import tkinter as Tk
  File "/home/linuxbrew/.linuxbrew/Cellar/python/3.7.2_2/lib/python3.7/tkinter/__init__.py", line 36, in <module>
    import _tkinter # If this fails your Python may not be configured for Tk
ModuleNotFoundError: No module named '_tkinter'

I have this problem too. Reproduces with this dockerfile:

FROM ubuntu:18.04                                                                  

RUN apt clean && apt update && apt upgrade -y                                      
RUN apt update && apt install -y build-essential cargo curl make file wget openvpn easy-rsa exuberant-ctags git

RUN groupadd -r mistler && useradd --no-log-init -r -g mistler mistler             
RUN usermod -aG sudo mistler                                                       
WORKDIR /home/mistler                                                              
RUN chown mistler:mistler /home/mistler                                            
USER mistler                                                                       

RUN mkdir ~/.linuxbrew && (cd ~/.linuxbrew && mkdir -p etc include bin lib opt sbin share var/homebrew/linked Cellar)                                                                                                                         
RUN git clone https://github.com/Homebrew/brew ~/.linuxbrew/Homebrew && ln -s ../Homebrew/bin/brew ~/.linuxbrew/bin && eval $(~/.linuxbrew/bin/brew shellenv)

ENV PATH="/home/mistler/.linuxbrew/bin:$PATH"                                      

RUN brew update && brew install pyenv git

@iMichka , the gentlest of bumps on this.
You had time to progress in sorting out this python-tcl/tk intertwined dependency tree?
Thanks and sorry for the noise

The discussions has stalled on this PR: https://github.com/Linuxbrew/homebrew-xorg/pull/455

We did not agree on a strategy right now. So this is on hold.

@iMichka Should we revive https://github.com/Homebrew/linuxbrew-core/pull/11417 as a temporary solution because it doesn't seem a more systematic solution would happen soon.

Was this page helpful?
0 / 5 - 0 ratings