18

I recently installed "Anaconda3 for Windows v2.4.0" on my Windows 10 Home (64 bit) machine.

(I downloaded the Windows 64-bit Graphical Installer "Anaconda3-2.4.0-Windows-x86_64.exe" (392 MB) from https://www.continuum.io/downloads.)

In a Command Prompt window, I did the conda "Test Drive", including "conda update conda", etc. In the end, I see the following:

C:\Users\Anshul\Downloads\Python>conda update conda
Fetching package metadata: ....
# All requested packages already installed.
# packages in environment at C:\Anaconda3:
#
conda                     3.18.6                   py35_0    defaults

C:\Users\Anshul\Downloads\Python>conda list matplotlib
# packages in environment at C:\Anaconda3:
#
matplotlib                1.5.0               np110py35_0    defaults

The installation seems to have been successful - for example:

C:\Users\Anshul\Downloads\Python>python
Python 3.5.0 |Anaconda 2.4.0 (64-bit)| (default, Nov  7 2015, 13:15:24) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> print("Hello World")
Hello World
>>> import os
>>> os.getcwd()
'C:\\Users\\Anshul\\Downloads\\Python'
>>> import matplotlib as mpl
>>> print(mpl.__version__)
1.5.0
>>> 

Note that matplotlib was imported fine above. However, I get an error message when I try to import "matplotlib.pyplot" as shown below:

>>> import matplotlib.pyplot as pp
Traceback (most recent call last):
  File "C:\Anaconda3\lib\site-packages\matplotlib\font_manager.py", line 1412, in <module>
    fontManager = pickle_load(_fmcache)
  File "C:\Anaconda3\lib\site-packages\matplotlib\font_manager.py", line 963, in pickle_load
    with open(filename, 'rb') as fh:
FileNotFoundError: [Errno 2] No such file or directory: 'C:\\Users\\Anshul\\.matplotlib\\fontList.py3k.cache'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Anaconda3\lib\site-packages\matplotlib\pyplot.py", line 29, in <module>
    import matplotlib.colorbar
  File "C:\Anaconda3\lib\site-packages\matplotlib\colorbar.py", line 34, in <module>
    import matplotlib.collections as collections
  File "C:\Anaconda3\lib\site-packages\matplotlib\collections.py", line 27, in <module>
    import matplotlib.backend_bases as backend_bases
  File "C:\Anaconda3\lib\site-packages\matplotlib\backend_bases.py", line 62, in <module>
    import matplotlib.textpath as textpath
  File "C:\Anaconda3\lib\site-packages\matplotlib\textpath.py", line 15, in <module>
    import matplotlib.font_manager as font_manager
  File "C:\Anaconda3\lib\site-packages\matplotlib\font_manager.py", line 1420, in <module>
    _rebuild()
  File "C:\Anaconda3\lib\site-packages\matplotlib\font_manager.py", line 1405, in _rebuild
    fontManager = FontManager()
  File "C:\Anaconda3\lib\site-packages\matplotlib\font_manager.py", line 1043, in __init__
    self.ttffiles = findSystemFonts(paths) + findSystemFonts()
  File "C:\Anaconda3\lib\site-packages\matplotlib\font_manager.py", line 312, in findSystemFonts
    for f in win32InstalledFonts(fontdir):
  File "C:\Anaconda3\lib\site-packages\matplotlib\font_manager.py", line 231, in win32InstalledFonts
    direc = os.path.abspath(direc).lower()
  File "C:\Anaconda3\lib\ntpath.py", line 535, in abspath
    path = _getfullpathname(path)
ValueError: _getfullpathname: embedded null character
>>>

I opened "C:\Anaconda3\lib\site-packages\matplotlib\font_manager.py" in a text editor and tried to look for the source of the error. I think this is where things are going wrong:

>>> mpl.get_cachedir()
'C:\\Users\\Anshul\\.matplotlib'
>>> mpl.get_configdir()
'C:\\Users\\Anshul\\.matplotlib'
>>>

In Windows Explorer, I see that the "C:\Users\Anshul.matplotlib" folder is empty, hence the FileNotFoundError for the "fontList.py3k.cache" file (which I don't see anywhere in the "C:\Anaconda3" directory either). It seems to be a problem with the installer (I think), but I don't know how to fix it. I'd appreciate any help or pointers.

(BTW, I've already tried googling this issue. The one that came closest was reported back in 2013: fail to import matplotlib.pyplot #2320. It involved a WinPython-64bit-3.3.2.2 installation on a Windows 7 64-bit machine. The thread was closed with the comment: "Closing. Already fixed in master.", but it appears the issue has resurfaced. I hope there is a simple fix or workaround.)

Thanks,
Anshul

Eryk Sun
  • 33,190
  • 5
  • 92
  • 111
Anshul Agrawal
  • 183
  • 1
  • 2
  • 7
  • 1
    I'm having the same issue on windows 7 and vanilla python 3, I don't think windows version numbers are relevant. – simonzack Nov 30 '15 at 19:42
  • 1
    Just debugged this and I think winreg.EnumValue is buggy, it sometimes outputs strings which are not capped to it's length. – simonzack Nov 30 '15 at 20:38

2 Answers2

21

This is a bug in python, not matplotlib.

The issue is that winreg.EnumValue is not cutting string values at their length properly for some reason, and strings will include null characters which os.path.abspath is not able to process.

The registry entry where this happens is at SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts. Despite this not being matplotlib's fault we can still temporarily patch it so that it ends the string at '\0'. In font_manager.py, patch line 310 in the win32InstalledFonts() function to:

key, direc, any = winreg.EnumValue( local, j)
if not is_string_like(direc):
    continue
if not os.path.dirname(direc):
    direc = os.path.join(directory, direc)
direc = direc.split('\0', 1)[0]
simonzack
  • 19,729
  • 13
  • 73
  • 118
  • 3
    Thank you so much simonzack! Your patch did the trick. One small detail though: in my `C:\Anaconda3\lib\site-packages\matplotlib\font_manager.py` file, the above code appeared starting at line 226 (found it by searching for `winreg.EnumValue`). Only the last line `direc = direc.split('\0', 1)[0]` is different. Hope the python folks make this a permanent fix - this issue appears to have been around for a few years! – Anshul Agrawal Dec 01 '15 at 20:20
  • 1
    @AnshulAgrawal No worries, you could accept my answer if it helps. It is definitely a problem in large projects, no one seems to take on ancient bugs. – simonzack Dec 01 '15 at 21:20
  • 1
    I reported the problem on "Python bug tracker" and their Windows experts are trying to debug it: http://bugs.python.org/issue25778 Just FYI – Anshul Agrawal Dec 04 '15 at 13:20
  • 1
    @AnshulAgrawal Thanks for the report, hope it's going to get fixed soon. – simonzack Dec 05 '15 at 00:05
  • 2
    @simonzack Can you be the change you want to see and put in a PR against mpl with that patch? – tacaswell Dec 05 '15 at 19:44
  • @AnshulAgrawal As you said I found the piece of code you need to change on line 226. But not only the last line is different. This also changes: direc = direc.split('\0', 1)[0] if os.path.splitext(direc)[1][1:] in fontext: items[direc] = 1 – j4n7 Dec 19 '16 at 13:54
  • The patch worked great. I use matplotlib 2.0 on Windows 7 SP1 x64 Ultimate (Python 3.5.2 |Anaconda custom (64-bit)) – Franck Dernoncourt Feb 15 '17 at 22:58
0

I'm using Python 3.5.2. When I tried @simonzack solution, I still got an error. I narrowed down the exception to the <python>/Lib/ntpath.py file. Look for the definition of the abspath() function around line 530.

I added @simonzack's solution to a ValueError exception handler. Insert the following code after line 537:

    530:    def abspath(path):
    531:    """Return the absolute version of a path."""

    533:    if path: # Empty path must return current working directory.
    534:        try:
    535:            path = _getfullpathname(path)
    536:        except OSError:
    537:            pass # Bad path - return unchanged.
    NEW:        except ValueError:
    NEW:            path = path.split('\0', 1)[0]
    NEW:            path = _getfullpathname(path)
    538:    elif isinstance(path, bytes):
    539:        path = os.getcwdb()
    540:    else:
    541:        path = os.getcwd()
    542:    return normpath(path)

That fixed the error for me.

For a little history on the cause of this issue take a look at: Python Issue 25778. It's a bit long but the final conclusion is that the fix didn't make it into 2.7.14, 3.5.3 or 3.6.0. So it appears this hack is going to be our only solution for older versions of Python.

Quantium
  • 1,779
  • 1
  • 14
  • 14