From 8083f251297adb06045677d3429414521de739d0 Mon Sep 17 00:00:00 2001 From: Matt Giuca Date: Wed, 6 Mar 2013 11:13:15 +1100 Subject: [PATCH 01/17] shutil.move: Guard against IOError and print warnings instead of crashing. --- lib/matplotlib/__init__.py | 10 ++++++++-- lib/matplotlib/texmanager.py | 5 ++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/lib/matplotlib/__init__.py b/lib/matplotlib/__init__.py index 997e86f40c93..0be7dc09a99b 100644 --- a/lib/matplotlib/__init__.py +++ b/lib/matplotlib/__init__.py @@ -642,7 +642,10 @@ def matplotlib_fname(): WARNING: Old rc filename ".matplotlibrc" found in working dir and and renamed to new default rc file name "matplotlibrc" (no leading"dot"). """, file=sys.stderr) - shutil.move('.matplotlibrc', 'matplotlibrc') + try: + shutil.move('.matplotlibrc', 'matplotlibrc') + except IOError as e: + print("WARNING: File could not be renamed: %s" % e, file=sys.stderr) home = get_home() oldname = os.path.join( home, '.matplotlibrc') @@ -653,7 +656,10 @@ def matplotlib_fname(): WARNING: Old rc filename "%s" found and renamed to new default rc file name "%s"."""%(oldname, newname), file=sys.stderr) - shutil.move(oldname, newname) + try: + shutil.move(oldname, newname) + except IOError as e: + print("WARNING: File could not be renamed: %s" % e, file=sys.stderr) fname = os.path.join( os.getcwd(), 'matplotlibrc') diff --git a/lib/matplotlib/texmanager.py b/lib/matplotlib/texmanager.py index da666b1a138e..a90082c44968 100644 --- a/lib/matplotlib/texmanager.py +++ b/lib/matplotlib/texmanager.py @@ -102,7 +102,10 @@ class TexManager: WARNING: found a TeX cache dir in the deprecated location "%s". Moving it to the new default location "%s".""" % (oldcache, texcache), file=sys.stderr) - shutil.move(oldcache, texcache) + try: + shutil.move(oldcache, texcache) + except IOError as e: + print("WARNING: File could not be renamed: %s" % e, file=sys.stderr) mkdirs(texcache) _dvipng_hack_alpha = None From a697a26b2bbaa5768981fd7f67753fb858eba727 Mon Sep 17 00:00:00 2001 From: Matt Giuca Date: Wed, 6 Mar 2013 11:27:11 +1100 Subject: [PATCH 02/17] matplotlib: _is_writable_dir uses os.access instead of TemporaryFile. This is a more direct approach and avoids strange behaviour on systems that provide a fake implementation of TemporaryFile. In particular, on Google App Engine, TemporaryFile is equivalent to StringIO, so this would have always succeeded, despite the fact that the directory is not actually writable. It is also not particularly nice to go creating and deleting random files in the user's home directory. --- lib/matplotlib/__init__.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/lib/matplotlib/__init__.py b/lib/matplotlib/__init__.py index 0be7dc09a99b..d9f13faef0ba 100644 --- a/lib/matplotlib/__init__.py +++ b/lib/matplotlib/__init__.py @@ -216,13 +216,8 @@ def _is_writable_dir(p): try: p + '' # test is string like except TypeError: return False try: - t = tempfile.TemporaryFile(dir=p) - try: - t.write(ascii('1')) - finally: - t.close() + return os.access(p, os.W_OK) except OSError: return False - else: return True class Verbose: """ From 4d654004c6b0eca84c6ed1a0353d51c2220f8213 Mon Sep 17 00:00:00 2001 From: Matt Giuca Date: Wed, 6 Mar 2013 13:52:51 +1100 Subject: [PATCH 03/17] Matplotlib now works when the user has no home directory. matplotlib.get_home now returns None if there is no home directory, instead of raising RuntimeError. Updated code in several places to handle this gracefully. matplotlib.get_configdir now returns a temporary directory if there is no home directory, instead of raising RuntimeError. --- lib/matplotlib/__init__.py | 84 ++++++++++++++++++++------------------ 1 file changed, 45 insertions(+), 39 deletions(-) diff --git a/lib/matplotlib/__init__.py b/lib/matplotlib/__init__.py index d9f13faef0ba..bfedb8c2e9fc 100644 --- a/lib/matplotlib/__init__.py +++ b/lib/matplotlib/__init__.py @@ -470,26 +470,25 @@ def checkdep_usetex(s): def _get_home(): """Find user's home directory if possible. - Otherwise raise error. + Otherwise, returns None. - :see: http://mail.python.org/pipermail/python-list/2005-February/263921.html + :see: http://mail.python.org/pipermail/python-list/2005-February/325395.html """ - path='' try: - path=os.path.expanduser("~") + path = os.path.expanduser("~") except: pass - if not os.path.isdir(path): - for evar in ('HOME', 'USERPROFILE', 'TMP'): - try: - path = os.environ[evar] - if os.path.isdir(path): - break - except: pass - if path: - return path else: - raise RuntimeError('please define environment variable $HOME') + if os.path.isdir(path): + return path + for evar in ('HOME', 'USERPROFILE', 'TMP'): + try: + path = os.environ[evar] + if os.path.isdir(path): + return path + except: + pass + return None def _create_tmp_config_dir(): @@ -513,12 +512,14 @@ def _get_configdir(): """ Return the string representing the configuration directory. - Default is HOME/.matplotlib. You can override this with the - MPLCONFIGDIR environment variable. If the default is not - writable, and MPLCONFIGDIR is not set, then - tempfile.gettempdir() is used to provide a directory in - which a matplotlib subdirectory is created as the configuration - directory. + The directory is chosen as follows: + + 1. If the MPLCONFIGDIR environment variable is supplied, choose that. Else, + choose the '.matplotlib' subdirectory of the user's home directory (and + create it if necessary). + 2. If the chosen directory exists and is writable, use that as the + configuration directory. + 3. Create a temporary directory, and use it as the configuration directory. """ configdir = os.environ.get('MPLCONFIGDIR') @@ -530,18 +531,21 @@ def _get_configdir(): return configdir h = get_home() - p = os.path.join(get_home(), '.matplotlib') + if h is not None: + p = os.path.join(h, '.matplotlib') - if os.path.exists(p): - if not _is_writable_dir(p): - return _create_tmp_config_dir() - else: - if not _is_writable_dir(h): - return _create_tmp_config_dir() - from matplotlib.cbook import mkdirs - mkdirs(p) + if os.path.exists(p): + if not _is_writable_dir(p): + return _create_tmp_config_dir() + else: + if not _is_writable_dir(h): + return _create_tmp_config_dir() + from matplotlib.cbook import mkdirs + mkdirs(p) + + return p - return p + return _create_tmp_config_dir() get_configdir = verbose.wrap('CONFIGDIR=%s', _get_configdir, always=False) @@ -643,18 +647,20 @@ def matplotlib_fname(): print("WARNING: File could not be renamed: %s" % e, file=sys.stderr) home = get_home() - oldname = os.path.join( home, '.matplotlibrc') - if os.path.exists(oldname): - configdir = get_configdir() - newname = os.path.join(configdir, 'matplotlibrc') - print("""\ + if home: + oldname = os.path.join( home, '.matplotlibrc') + if os.path.exists(oldname): + configdir = get_configdir() + newname = os.path.join(configdir, 'matplotlibrc') + print("""\ WARNING: Old rc filename "%s" found and renamed to new default rc file name "%s"."""%(oldname, newname), file=sys.stderr) - try: - shutil.move(oldname, newname) - except IOError as e: - print("WARNING: File could not be renamed: %s" % e, file=sys.stderr) + try: + shutil.move(oldname, newname) + except IOError as e: + print("WARNING: File could not be renamed: %s" % e, + file=sys.stderr) fname = os.path.join( os.getcwd(), 'matplotlibrc') From 21921a3e77b07b666bd35bd365853d3c6d4fe9da Mon Sep 17 00:00:00 2001 From: Matt Giuca Date: Wed, 6 Mar 2013 14:12:25 +1100 Subject: [PATCH 04/17] get_configdir returns None if tempfile.gettempdir() is not available. Previously, it would raise NotImplementedError. This is necessary on restricted platforms such as Google App Engine that do not provide gettempdir. --- lib/matplotlib/__init__.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/lib/matplotlib/__init__.py b/lib/matplotlib/__init__.py index bfedb8c2e9fc..df23c093fc17 100644 --- a/lib/matplotlib/__init__.py +++ b/lib/matplotlib/__init__.py @@ -495,12 +495,19 @@ def _create_tmp_config_dir(): """ If the config directory can not be created, create a temporary directory. + + Returns None if a writable temporary directory could not be created. """ import getpass import tempfile - tempdir = os.path.join( - tempfile.gettempdir(), 'matplotlib-%s' % getpass.getuser()) + try: + tempdir = tempfile.gettempdir() + except NotImplementedError: + # Some restricted platforms (such as Google App Engine) do not provide + # gettempdir. + return None + tempdir = os.path.join(tempdir, 'matplotlib-%s' % getpass.getuser()) os.environ['MPLCONFIGDIR'] = tempdir return tempdir @@ -519,7 +526,9 @@ def _get_configdir(): create it if necessary). 2. If the chosen directory exists and is writable, use that as the configuration directory. - 3. Create a temporary directory, and use it as the configuration directory. + 3. If possible, create a temporary directory, and use it as the + configuration directory. + 4. A writable directory could not be found or created; return None. """ configdir = os.environ.get('MPLCONFIGDIR') From 4987dcd9bc014dcef358cc509ba5c8780c0c5a63 Mon Sep 17 00:00:00 2001 From: Matt Giuca Date: Wed, 6 Mar 2013 14:25:36 +1100 Subject: [PATCH 05/17] Deal with all cases where get_configdir might return None. Each case is either handled gracefully, or raises a RuntimeError. --- lib/matplotlib/__init__.py | 26 ++++++++++++++++---------- lib/matplotlib/finance.py | 2 ++ lib/matplotlib/font_manager.py | 7 +++++-- lib/matplotlib/testing/compare.py | 5 ++++- lib/matplotlib/texmanager.py | 2 ++ 5 files changed, 29 insertions(+), 13 deletions(-) diff --git a/lib/matplotlib/__init__.py b/lib/matplotlib/__init__.py index df23c093fc17..556e5e15faad 100644 --- a/lib/matplotlib/__init__.py +++ b/lib/matplotlib/__init__.py @@ -656,20 +656,25 @@ def matplotlib_fname(): print("WARNING: File could not be renamed: %s" % e, file=sys.stderr) home = get_home() + configdir = get_configdir() if home: oldname = os.path.join( home, '.matplotlibrc') if os.path.exists(oldname): - configdir = get_configdir() - newname = os.path.join(configdir, 'matplotlibrc') - print("""\ + if configdir is not None: + newname = os.path.join(configdir, 'matplotlibrc') + print("""\ WARNING: Old rc filename "%s" found and renamed to new default rc file name "%s"."""%(oldname, newname), file=sys.stderr) - try: - shutil.move(oldname, newname) - except IOError as e: - print("WARNING: File could not be renamed: %s" % e, - file=sys.stderr) + try: + shutil.move(oldname, newname) + except IOError as e: + print("WARNING: File could not be renamed: %s" % e, + file=sys.stderr) + else: + print("""\ +WARNING: Could not rename old rc file "%s": a suitable configuration directory + could not be found.""" % oldname, file=sys.stderr) fname = os.path.join( os.getcwd(), 'matplotlibrc') @@ -682,8 +687,9 @@ def matplotlib_fname(): if os.path.exists(fname): return fname - fname = os.path.join(get_configdir(), 'matplotlibrc') - if os.path.exists(fname): return fname + if configdir is not None: + fname = os.path.join(configdir, 'matplotlibrc') + if os.path.exists(fname): return fname path = get_data_path() # guaranteed to exist or raise diff --git a/lib/matplotlib/finance.py b/lib/matplotlib/finance.py index faa3175be3f5..eb26121b5fb6 100644 --- a/lib/matplotlib/finance.py +++ b/lib/matplotlib/finance.py @@ -28,6 +28,8 @@ configdir = get_configdir() +if configdir is None: + raise RuntimeError('Could not find a suitable configuration directory') cachedir = os.path.join(configdir, 'finance.cache') diff --git a/lib/matplotlib/font_manager.py b/lib/matplotlib/font_manager.py index 28ac73453e26..3d3316b1beea 100644 --- a/lib/matplotlib/font_manager.py +++ b/lib/matplotlib/font_manager.py @@ -1311,10 +1311,13 @@ def findfont(prop, fontext='ttf'): return result else: + configdir = get_configdir() + if configdir is None: + raise RuntimeError('Could not find a suitable configuration directory') if sys.version_info[0] >= 3: - _fmcache = os.path.join(get_configdir(), 'fontList.py3k.cache') + _fmcache = os.path.join(configdir, 'fontList.py3k.cache') else: - _fmcache = os.path.join(get_configdir(), 'fontList.cache') + _fmcache = os.path.join(configdir, 'fontList.cache') fontManager = None diff --git a/lib/matplotlib/testing/compare.py b/lib/matplotlib/testing/compare.py index 17d247746bf7..7f649e58befd 100644 --- a/lib/matplotlib/testing/compare.py +++ b/lib/matplotlib/testing/compare.py @@ -99,7 +99,10 @@ def compare_float( expected, actual, relTol = None, absTol = None ): # parameters old and new to a list that can be passed to Popen to # convert files with that extension to png format. def get_cache_dir(): - cache_dir = os.path.join(_get_configdir(), 'test_cache') + configdir = _get_configdir() + if configdir is None: + raise RuntimeError('Could not find a suitable configuration directory') + cache_dir = os.path.join(configdir, 'test_cache') if not os.path.exists(cache_dir): try: os.makedirs(cache_dir) diff --git a/lib/matplotlib/texmanager.py b/lib/matplotlib/texmanager.py index a90082c44968..7a36e26c03c2 100644 --- a/lib/matplotlib/texmanager.py +++ b/lib/matplotlib/texmanager.py @@ -94,6 +94,8 @@ class TexManager: oldcache = os.path.join(oldpath, '.tex.cache') configdir = mpl.get_configdir() + if configdir is None: + raise RuntimeError('Could not find a suitable configuration directory') texcache = os.path.join(configdir, 'tex.cache') if os.path.exists(oldcache): From 64c797b3cd69afb2387ad888426f334a8b95f484 Mon Sep 17 00:00:00 2001 From: Matt Giuca Date: Wed, 6 Mar 2013 14:38:02 +1100 Subject: [PATCH 06/17] font_manager: Gracefully handle the case of there being no config dir. Instead of raising RuntimeError, now avoids reading and writing the font cache. --- lib/matplotlib/font_manager.py | 35 ++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/lib/matplotlib/font_manager.py b/lib/matplotlib/font_manager.py index 3d3316b1beea..5684fc6263f8 100644 --- a/lib/matplotlib/font_manager.py +++ b/lib/matplotlib/font_manager.py @@ -1312,30 +1312,37 @@ def findfont(prop, fontext='ttf'): else: configdir = get_configdir() - if configdir is None: - raise RuntimeError('Could not find a suitable configuration directory') - if sys.version_info[0] >= 3: - _fmcache = os.path.join(configdir, 'fontList.py3k.cache') + if configdir is not None: + if sys.version_info[0] >= 3: + _fmcache = os.path.join(configdir, 'fontList.py3k.cache') + else: + _fmcache = os.path.join(configdir, 'fontList.cache') else: - _fmcache = os.path.join(configdir, 'fontList.cache') + # Should only happen in a restricted environment (such as Google App + # Engine). Deal with this gracefully by not caching fonts. + _fmcache = None fontManager = None def _rebuild(): global fontManager fontManager = FontManager() - pickle_dump(fontManager, _fmcache) + if _fmcache: + pickle_dump(fontManager, _fmcache) verbose.report("generated new fontManager") - try: - fontManager = pickle_load(_fmcache) - if (not hasattr(fontManager, '_version') or - fontManager._version != FontManager.__version__): + if _fmcache: + try: + fontManager = pickle_load(_fmcache) + if (not hasattr(fontManager, '_version') or + fontManager._version != FontManager.__version__): + _rebuild() + else: + fontManager.default_size = None + verbose.report("Using fontManager instance from %s" % _fmcache) + except: _rebuild() - else: - fontManager.default_size = None - verbose.report("Using fontManager instance from %s" % _fmcache) - except: + else: _rebuild() def findfont(prop, **kw): From 1dbd6def075678ed16bf7c830bf0537123fa31bd Mon Sep 17 00:00:00 2001 From: Matt Giuca Date: Wed, 6 Mar 2013 15:26:58 +1100 Subject: [PATCH 07/17] texmanager: Gracefully handle the case of there being no config dir upon import. Instead of raising RuntimeError, now avoids creating the cache dir. This permits texmanager to be imported in a restricted environment such as Google App Engine. Actually constructing a TexManager object will fail, but it can be imported. --- lib/matplotlib/texmanager.py | 38 +++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/lib/matplotlib/texmanager.py b/lib/matplotlib/texmanager.py index 7a36e26c03c2..7b212ace961c 100644 --- a/lib/matplotlib/texmanager.py +++ b/lib/matplotlib/texmanager.py @@ -94,21 +94,32 @@ class TexManager: oldcache = os.path.join(oldpath, '.tex.cache') configdir = mpl.get_configdir() - if configdir is None: - raise RuntimeError('Could not find a suitable configuration directory') - texcache = os.path.join(configdir, 'tex.cache') + if configdir is not None: + texcache = os.path.join(configdir, 'tex.cache') + else: + # Should only happen in a restricted environment (such as Google App + # Engine). Deal with this gracefully by not creating a cache directory. + texcache = None if os.path.exists(oldcache): - # FIXME raise proper warning - print("""\ + if texcache is not None: + # FIXME raise proper warning + print("""\ WARNING: found a TeX cache dir in the deprecated location "%s". Moving it to the new default location "%s".""" % (oldcache, texcache), - file=sys.stderr) - try: - shutil.move(oldcache, texcache) - except IOError as e: - print("WARNING: File could not be renamed: %s" % e, file=sys.stderr) - mkdirs(texcache) + file=sys.stderr) + try: + shutil.move(oldcache, texcache) + except IOError as e: + print("WARNING: File could not be renamed: %s" % e, + file=sys.stderr) + else: + print("""\ +WARNING: Could not rename old TeX cache dir "%s": a suitable configuration + directory could not be found.""" % oldcache, file=sys.stderr) + + if texcache is not None: + mkdirs(texcache) _dvipng_hack_alpha = None #_dvipng_hack_alpha = dvipng_hack_alpha() @@ -150,6 +161,11 @@ class TexManager: def __init__(self): + if not self.texcache: + raise RuntimeError( + ('Cannot create TexManager, as there is no cache directory ' + 'available')) + mkdirs(self.texcache) ff = rcParams['font.family'].lower() if ff in self.font_families: From 1adfc851f5a3713341c8bc0ab70b1be422396779 Mon Sep 17 00:00:00 2001 From: Matt Giuca Date: Fri, 8 Mar 2013 11:29:56 +1100 Subject: [PATCH 08/17] finance: Gracefully handle the case of there being no config dir. Instead of raising RuntimeError, now avoids reading and writing the cache. --- lib/matplotlib/finance.py | 40 +++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/lib/matplotlib/finance.py b/lib/matplotlib/finance.py index eb26121b5fb6..adc5e7cb4332 100644 --- a/lib/matplotlib/finance.py +++ b/lib/matplotlib/finance.py @@ -28,9 +28,13 @@ configdir = get_configdir() -if configdir is None: - raise RuntimeError('Could not find a suitable configuration directory') -cachedir = os.path.join(configdir, 'finance.cache') +# cachedir will be None if there is no writable directory. +if configdir is not None: + cachedir = os.path.join(configdir, 'finance.cache') +else: + # Should only happen in a restricted environment (such as Google App + # Engine). Deal with this gracefully by not caching finance data. + cachedir = None stock_dt = np.dtype([('date', object), @@ -180,20 +184,24 @@ def fetch_historical_yahoo(ticker, date1, date2, cachename=None,dividends=False) d2[0], d2[1], d2[2], ticker, g) - if cachename is None: - cachename = os.path.join(cachedir, md5(url).hexdigest()) - if os.path.exists(cachename): - fh = open(cachename) - verbose.report('Using cachefile %s for %s'%(cachename, ticker)) + # Cache the finance data if there is a writable cache directory. + if cachedir is not None: + if cachename is None: + cachename = os.path.join(cachedir, md5(url).hexdigest()) + if os.path.exists(cachename): + fh = open(cachename) + verbose.report('Using cachefile %s for %s'%(cachename, ticker)) + else: + mkdirs(os.path.abspath(os.path.dirname(cachename))) + with contextlib.closing(urlopen(url)) as urlfh: + with open(cachename, 'wb') as fh: + fh.write(urlfh.read()) + verbose.report('Saved %s data to cache file %s'%(ticker, cachename)) + fh = open(cachename, 'r') + + return fh else: - mkdirs(os.path.abspath(os.path.dirname(cachename))) - with contextlib.closing(urlopen(url)) as urlfh: - with open(cachename, 'wb') as fh: - fh.write(urlfh.read()) - verbose.report('Saved %s data to cache file %s'%(ticker, cachename)) - fh = open(cachename, 'r') - - return fh + return urlopen(url) def quotes_historical_yahoo(ticker, date1, date2, asobject=False, From 941efd435b51da1c05056b72ddd033063d1ea509 Mon Sep 17 00:00:00 2001 From: Matt Giuca Date: Mon, 18 Mar 2013 10:30:11 +1100 Subject: [PATCH 09/17] Fix formatting and other misc code tweaks. --- lib/matplotlib/__init__.py | 20 +++++++++++--------- lib/matplotlib/texmanager.py | 2 +- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/lib/matplotlib/__init__.py b/lib/matplotlib/__init__.py index 556e5e15faad..691e090bfe5d 100644 --- a/lib/matplotlib/__init__.py +++ b/lib/matplotlib/__init__.py @@ -213,11 +213,14 @@ def _is_writable_dir(p): p is a string pointing to a putative writable dir -- return True p is such a string, else False """ - try: p + '' # test is string like - except TypeError: return False + try: + p + '' # test is string like + except TypeError: + return False try: return os.access(p, os.W_OK) - except OSError: return False + except OSError: + return False class Verbose: """ @@ -644,7 +647,7 @@ def matplotlib_fname(): """ - oldname = os.path.join( os.getcwd(), '.matplotlibrc') + oldname = os.path.join(os.getcwd(), '.matplotlibrc') if os.path.exists(oldname): print("""\ WARNING: Old rc filename ".matplotlibrc" found in working dir @@ -658,7 +661,7 @@ def matplotlib_fname(): home = get_home() configdir = get_configdir() if home: - oldname = os.path.join( home, '.matplotlibrc') + oldname = os.path.join(home, '.matplotlibrc') if os.path.exists(oldname): if configdir is not None: newname = os.path.join(configdir, 'matplotlibrc') @@ -676,8 +679,7 @@ def matplotlib_fname(): WARNING: Could not rename old rc file "%s": a suitable configuration directory could not be found.""" % oldname, file=sys.stderr) - - fname = os.path.join( os.getcwd(), 'matplotlibrc') + fname = os.path.join(os.getcwd(), 'matplotlibrc') if os.path.exists(fname): return fname if 'MATPLOTLIBRC' in os.environ: @@ -689,8 +691,8 @@ def matplotlib_fname(): if configdir is not None: fname = os.path.join(configdir, 'matplotlibrc') - if os.path.exists(fname): return fname - + if os.path.exists(fname): + return fname path = get_data_path() # guaranteed to exist or raise fname = os.path.join(path, 'matplotlibrc') diff --git a/lib/matplotlib/texmanager.py b/lib/matplotlib/texmanager.py index 7b212ace961c..b913c8e883be 100644 --- a/lib/matplotlib/texmanager.py +++ b/lib/matplotlib/texmanager.py @@ -161,7 +161,7 @@ class TexManager: def __init__(self): - if not self.texcache: + if self.texcache is None: raise RuntimeError( ('Cannot create TexManager, as there is no cache directory ' 'available')) From ca6cd190995b0ca744b9163a66a715011d06146d Mon Sep 17 00:00:00 2001 From: Matt Giuca Date: Mon, 18 Mar 2013 11:44:30 +1100 Subject: [PATCH 10/17] matplotlib.get_home: Removing catch-all except blocks. --- lib/matplotlib/__init__.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/lib/matplotlib/__init__.py b/lib/matplotlib/__init__.py index 691e090bfe5d..afbee2f6165e 100644 --- a/lib/matplotlib/__init__.py +++ b/lib/matplotlib/__init__.py @@ -479,18 +479,16 @@ def _get_home(): """ try: path = os.path.expanduser("~") - except: + except ImportError: + # This happens on Google App Engine (pwd module is not present). pass else: if os.path.isdir(path): return path for evar in ('HOME', 'USERPROFILE', 'TMP'): - try: - path = os.environ[evar] - if os.path.isdir(path): - return path - except: - pass + path = os.environ.get(evar) + if path is not None and os.path.isdir(path): + return path return None From cc8cd1b0c58cc4ff6a681ce089ddbdb2c60be6f0 Mon Sep 17 00:00:00 2001 From: Matt Giuca Date: Mon, 18 Mar 2013 11:59:14 +1100 Subject: [PATCH 11/17] matplotlib, texmanager: Change WARNING prints into real warnings. --- lib/matplotlib/__init__.py | 24 +++++++++++------------- lib/matplotlib/texmanager.py | 18 ++++++++---------- 2 files changed, 19 insertions(+), 23 deletions(-) diff --git a/lib/matplotlib/__init__.py b/lib/matplotlib/__init__.py index afbee2f6165e..0ff3a80244d7 100644 --- a/lib/matplotlib/__init__.py +++ b/lib/matplotlib/__init__.py @@ -647,14 +647,13 @@ def matplotlib_fname(): oldname = os.path.join(os.getcwd(), '.matplotlibrc') if os.path.exists(oldname): - print("""\ -WARNING: Old rc filename ".matplotlibrc" found in working dir - and and renamed to new default rc file name "matplotlibrc" - (no leading"dot"). """, file=sys.stderr) + warnings.warn("""\ +Old rc filename ".matplotlibrc" found in working dir and and renamed to new + default rc file name "matplotlibrc" (no leading ".").""") try: shutil.move('.matplotlibrc', 'matplotlibrc') except IOError as e: - print("WARNING: File could not be renamed: %s" % e, file=sys.stderr) + warnings.warn('File could not be renamed: %s' % e) home = get_home() configdir = get_configdir() @@ -663,19 +662,18 @@ def matplotlib_fname(): if os.path.exists(oldname): if configdir is not None: newname = os.path.join(configdir, 'matplotlibrc') - print("""\ -WARNING: Old rc filename "%s" found and renamed to - new default rc file name "%s"."""%(oldname, newname), file=sys.stderr) + warnings.warn("""\ +Old rc filename "%s" found and renamed to new default rc file name "%s".""" + % (oldname, newname)) try: shutil.move(oldname, newname) except IOError as e: - print("WARNING: File could not be renamed: %s" % e, - file=sys.stderr) + warnings.warn('File could not be renamed: %s' % e) else: - print("""\ -WARNING: Could not rename old rc file "%s": a suitable configuration directory - could not be found.""" % oldname, file=sys.stderr) + warnings.warn("""\ +Could not rename old rc file "%s": a suitable configuration directory could not + be found.""" % oldname) fname = os.path.join(os.getcwd(), 'matplotlibrc') if os.path.exists(fname): return fname diff --git a/lib/matplotlib/texmanager.py b/lib/matplotlib/texmanager.py index b913c8e883be..86c9873849cb 100644 --- a/lib/matplotlib/texmanager.py +++ b/lib/matplotlib/texmanager.py @@ -41,6 +41,7 @@ import os import shutil import sys +import warnings from hashlib import md5 @@ -103,20 +104,17 @@ class TexManager: if os.path.exists(oldcache): if texcache is not None: - # FIXME raise proper warning - print("""\ -WARNING: found a TeX cache dir in the deprecated location "%s". - Moving it to the new default location "%s".""" % (oldcache, texcache), - file=sys.stderr) + warnings.warn("""\ +Found a TeX cache dir in the deprecated location "%s". + Moving it to the new default location "%s".""" % (oldcache, texcache)) try: shutil.move(oldcache, texcache) except IOError as e: - print("WARNING: File could not be renamed: %s" % e, - file=sys.stderr) + warnings.warn('File could not be renamed: %s' % e) else: - print("""\ -WARNING: Could not rename old TeX cache dir "%s": a suitable configuration - directory could not be found.""" % oldcache, file=sys.stderr) + warnings.warn("""\ +Could not rename old TeX cache dir "%s": a suitable configuration + directory could not be found.""" % oldcache) if texcache is not None: mkdirs(texcache) From f01ebe18d36f5945e96ed3174d41fd7b979488d1 Mon Sep 17 00:00:00 2001 From: Matt Giuca Date: Mon, 18 Mar 2013 11:59:52 +1100 Subject: [PATCH 12/17] matplotlib, texmanager: Only print the rename message if it actually succeeded. --- lib/matplotlib/__init__.py | 14 ++++++++------ lib/matplotlib/texmanager.py | 7 ++++--- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/lib/matplotlib/__init__.py b/lib/matplotlib/__init__.py index 0ff3a80244d7..28c58a733e5c 100644 --- a/lib/matplotlib/__init__.py +++ b/lib/matplotlib/__init__.py @@ -647,13 +647,14 @@ def matplotlib_fname(): oldname = os.path.join(os.getcwd(), '.matplotlibrc') if os.path.exists(oldname): - warnings.warn("""\ -Old rc filename ".matplotlibrc" found in working dir and and renamed to new - default rc file name "matplotlibrc" (no leading ".").""") try: shutil.move('.matplotlibrc', 'matplotlibrc') except IOError as e: warnings.warn('File could not be renamed: %s' % e) + else: + warnings.warn("""\ +Old rc filename ".matplotlibrc" found in working dir and and renamed to new + default rc file name "matplotlibrc" (no leading ".").""") home = get_home() configdir = get_configdir() @@ -662,14 +663,15 @@ def matplotlib_fname(): if os.path.exists(oldname): if configdir is not None: newname = os.path.join(configdir, 'matplotlibrc') - warnings.warn("""\ -Old rc filename "%s" found and renamed to new default rc file name "%s".""" - % (oldname, newname)) try: shutil.move(oldname, newname) except IOError as e: warnings.warn('File could not be renamed: %s' % e) + else: + warnings.warn("""\ +Old rc filename "%s" found and renamed to new default rc file name "%s".""" + % (oldname, newname)) else: warnings.warn("""\ Could not rename old rc file "%s": a suitable configuration directory could not diff --git a/lib/matplotlib/texmanager.py b/lib/matplotlib/texmanager.py index 86c9873849cb..b3fcc8df0247 100644 --- a/lib/matplotlib/texmanager.py +++ b/lib/matplotlib/texmanager.py @@ -104,13 +104,14 @@ class TexManager: if os.path.exists(oldcache): if texcache is not None: - warnings.warn("""\ -Found a TeX cache dir in the deprecated location "%s". - Moving it to the new default location "%s".""" % (oldcache, texcache)) try: shutil.move(oldcache, texcache) except IOError as e: warnings.warn('File could not be renamed: %s' % e) + else: + warnings.warn("""\ +Found a TeX cache dir in the deprecated location "%s". + Moving it to the new default location "%s".""" % (oldcache, texcache)) else: warnings.warn("""\ Could not rename old TeX cache dir "%s": a suitable configuration From 018ce266414175e050bddcfc597b1ceeedc364bc Mon Sep 17 00:00:00 2001 From: Matt Giuca Date: Mon, 18 Mar 2013 15:30:39 +1100 Subject: [PATCH 13/17] finance: Fixed caching when cachename is supplied. Previously, it would not cache if there was no cachedir, even if cachename was supplied. --- lib/matplotlib/finance.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/matplotlib/finance.py b/lib/matplotlib/finance.py index adc5e7cb4332..c456acbf43f0 100644 --- a/lib/matplotlib/finance.py +++ b/lib/matplotlib/finance.py @@ -184,10 +184,11 @@ def fetch_historical_yahoo(ticker, date1, date2, cachename=None,dividends=False) d2[0], d2[1], d2[2], ticker, g) - # Cache the finance data if there is a writable cache directory. - if cachedir is not None: - if cachename is None: - cachename = os.path.join(cachedir, md5(url).hexdigest()) + # Cache the finance data if cachename is supplied, or there is a writable + # cache directory. + if cachename is None and cachedir is not None: + cachename = os.path.join(cachedir, md5(url).hexdigest()) + if cachename is not None: if os.path.exists(cachename): fh = open(cachename) verbose.report('Using cachefile %s for %s'%(cachename, ticker)) From 6a4f1e77878e843503990d59e57780009bf277f3 Mon Sep 17 00:00:00 2001 From: Matt Giuca Date: Tue, 19 Mar 2013 10:22:39 +1100 Subject: [PATCH 14/17] matplotlib: Use cbook.mkdirs instead of os.makedirs. --- lib/matplotlib/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/__init__.py b/lib/matplotlib/__init__.py index 28c58a733e5c..fa18bd44d5c1 100644 --- a/lib/matplotlib/__init__.py +++ b/lib/matplotlib/__init__.py @@ -535,7 +535,7 @@ def _get_configdir(): configdir = os.environ.get('MPLCONFIGDIR') if configdir is not None: if not os.path.exists(configdir): - os.makedirs(configdir) + mkdirs(configdir) if not _is_writable_dir(configdir): return _create_tmp_config_dir() return configdir From 4f55a278dd283f7542e4bc503c2f944c7cadb587 Mon Sep 17 00:00:00 2001 From: Matt Giuca Date: Tue, 19 Mar 2013 10:30:05 +1100 Subject: [PATCH 15/17] matplotlib: Remove catch for OSError. os.access does not raise this exception. --- lib/matplotlib/__init__.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/matplotlib/__init__.py b/lib/matplotlib/__init__.py index fa18bd44d5c1..efdbeec6a7a6 100644 --- a/lib/matplotlib/__init__.py +++ b/lib/matplotlib/__init__.py @@ -217,10 +217,7 @@ def _is_writable_dir(p): p + '' # test is string like except TypeError: return False - try: - return os.access(p, os.W_OK) - except OSError: - return False + return os.access(p, os.W_OK) class Verbose: """ From 81639a19d86c1514b3946716aa574459ec6a4008 Mon Sep 17 00:00:00 2001 From: Matt Giuca Date: Tue, 19 Mar 2013 10:38:44 +1100 Subject: [PATCH 16/17] matplotlib: _is_writable_dir checks that it is a directory. --- lib/matplotlib/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/__init__.py b/lib/matplotlib/__init__.py index efdbeec6a7a6..9629eb7f09c1 100644 --- a/lib/matplotlib/__init__.py +++ b/lib/matplotlib/__init__.py @@ -217,7 +217,7 @@ def _is_writable_dir(p): p + '' # test is string like except TypeError: return False - return os.access(p, os.W_OK) + return os.access(p, os.W_OK) and os.path.isdir(p) class Verbose: """ From 83357738300983e6b31bedff7fa9bf4f3205e81a Mon Sep 17 00:00:00 2001 From: Matt Giuca Date: Tue, 19 Mar 2013 10:33:16 +1100 Subject: [PATCH 17/17] matplotlib: _is_writable_dir tests with os.access and TemporaryFile. This fails either if the OS tells us it isn't writable, or if a file cannot be created there. --- lib/matplotlib/__init__.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/lib/matplotlib/__init__.py b/lib/matplotlib/__init__.py index 9629eb7f09c1..fdc351e59cd1 100644 --- a/lib/matplotlib/__init__.py +++ b/lib/matplotlib/__init__.py @@ -217,7 +217,24 @@ def _is_writable_dir(p): p + '' # test is string like except TypeError: return False - return os.access(p, os.W_OK) and os.path.isdir(p) + + # Test whether the operating system thinks it's a writable directory. + # Note that this check is necessary on Google App Engine, because the + # subsequent check will succeed even though p may not be writable. + if not os.access(p, os.W_OK) or not os.path.isdir(p): + return False + + # Also test that it is actually possible to write to a file here. + try: + t = tempfile.TemporaryFile(dir=p) + try: + t.write(ascii('1')) + finally: + t.close() + except OSError: + return False + + return True class Verbose: """