Repository navigation
Description
Under matplotlib 3.0.0rc1, the return value of matplotlib.get_backend() is a sentinel object:
In [2]: matplotlib.get_backend()
Out[2]: <object at 0x111292d50>
In [3]: backend = matplotlib.get_backend()
In [4]: backend.lower()
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-4-f3c7164fcd07> in <module>()
----> 1 backend.lower()
AttributeError: 'object' object has no attribute 'lower'
Under matplotlib 2.2.3 I get:
In [1]: import matplotlib
In [2]: matplotlib.get_backend()
Out[2]: 'MacOSX'
In [3]: backend = matplotlib.get_backend()
In [4]: backend.lower()
Out[4]: 'macosx'
For backward compatibility purposes it would be really nice if matplotlib 3.0.0 could return an object that at least acted like a string. In particular right now I'd like it to have a lower() method. I'd also like it if it had a nice __repr__ or __str__ implementation instead of printing out as an opaque object of type object.
The former is for backward compatibility, as the change breaks some of the yt plotting code --- in particular here's a failure from the test suite:
======================================================================
ERROR: Failure: AttributeError ('object' object has no attribute 'lower')
----------------------------------------------------------------------
Traceback (most recent call last):
File "/usr/local/lib/python3.7/site-packages/nose/failure.py", line 39, in runTest
raise self.exc_val.with_traceback(self.tb)
File "/usr/local/lib/python3.7/site-packages/nose/loader.py", line 418, in loadTestsFromName
addr.filename, addr.module)
File "/usr/local/lib/python3.7/site-packages/nose/importer.py", line 47, in importFromPath
return self.importFromDir(dir_path, fqname)
File "/usr/local/lib/python3.7/site-packages/nose/importer.py", line 94, in importFromDir
mod = load_module(part_fqname, fh, filename, desc)
File "/usr/local/Cellar/python/3.7.0/Frameworks/Python.framework/Versions/3.7/lib/python3.7/imp.py", line 235, in load_module
return load_source(name, filename, file)
File "/usr/local/Cellar/python/3.7.0/Frameworks/Python.framework/Versions/3.7/lib/python3.7/imp.py", line 172, in load_source
module = _load(spec)
File "<frozen importlib._bootstrap>", line 696, in _load
File "<frozen importlib._bootstrap>", line 677, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 728, in exec_module
File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
File "/Users/goldbaum/Documents/yt-git-fixes/yt/visualization/tests/test_color_maps.py", line 23, in <module>
class TestColorMaps(unittest.TestCase):
File "/Users/goldbaum/Documents/yt-git-fixes/yt/visualization/tests/test_color_maps.py", line 34, in TestColorMaps
@requires_backend('Agg')
File "/Users/goldbaum/Documents/yt-git-fixes/yt/testing.py", line 1143, in requires_backend
if backend.lower() == matplotlib.get_backend().lower():
AttributeError: 'object' object has no attribute 'lower'
This is code that's internal to yt's test suite, but I wouldn't be at all surprised if there's other code out there that assumes matplotlib.get_backend() returns a string. For example:
Activity
anntzer commentedon Aug 13, 2018
The issue is #11600 (comment) and I think (quite strongly) that it makes sense for
get_backend()to, well, perform backend resolution and return an actual backend.Giving the sentinel object a
.lower()method is only going to make things worse IMO.ngoldbaum commentedon Aug 13, 2018
I don't really care too much what type
get_backendreturns. I'd kinda prefer it to return something stringlike just on the principle that it would be better if old code continued working, but I also acknowledge that you're doing a major version number increment so some level of breakage is to be expected.fredrik-1 commentedon Aug 14, 2018
I don't understand this. I am on v3.0.0rc1 on my git version but
matplotlib.get_backend()returns a string for me and the docstring says that it should return the name.anntzer commentedon Aug 14, 2018
That's likely because this should only happen if you don't have a backend set in your matplotlibrc.
fredrik-1 commentedon Aug 14, 2018
That seems like a strange api to me. Why do it return an object when the backend is not set and not for example
''and a string when it is set? (that was the behavior that I got when I tested).Why? The docstring for
matplotlib.get_backendis "Return the name of the current backend."anntzer commentedon Aug 14, 2018
As explained above, it's a bug (IMO) and should be fixed.
tacaswell commentedon Aug 14, 2018
The simplest fix may be to switch the sentinel to the string
'auto'? That way it can go in the.matplotlibrcand returns the expected type fromget_backend()I would prefer that if we keep the non-string sentinel that the backend resolution logic moves up to
__init__rather than adding another buriedpyplotimport.tacaswell commentedon Aug 14, 2018
Closing this in favor of #11844 which is addressing a slightly larger set of issues to keep the discussion from getting too fragmented.