Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 91b1d9f

Browse filesBrowse files
committed
Merge pull request #1824 from mgiuca-google/no-home-dir
Support environments without a home dir or writable file system
2 parents 9e477b3 + 8335773 commit 91b1d9f
Copy full SHA for 91b1d9f

File tree

Expand file treeCollapse file tree

5 files changed

+172
-92
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

5 files changed

+172
-92
lines changed
Open diff view settings
Collapse file

‎lib/matplotlib/__init__.py‎

Copy file name to clipboardExpand all lines: lib/matplotlib/__init__.py
+94-58Lines changed: 94 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -213,16 +213,28 @@ def _is_writable_dir(p):
213213
p is a string pointing to a putative writable dir -- return True p
214214
is such a string, else False
215215
"""
216-
try: p + '' # test is string like
217-
except TypeError: return False
216+
try:
217+
p + '' # test is string like
218+
except TypeError:
219+
return False
220+
221+
# Test whether the operating system thinks it's a writable directory.
222+
# Note that this check is necessary on Google App Engine, because the
223+
# subsequent check will succeed even though p may not be writable.
224+
if not os.access(p, os.W_OK) or not os.path.isdir(p):
225+
return False
226+
227+
# Also test that it is actually possible to write to a file here.
218228
try:
219229
t = tempfile.TemporaryFile(dir=p)
220230
try:
221231
t.write(ascii('1'))
222232
finally:
223233
t.close()
224-
except OSError: return False
225-
else: return True
234+
except OSError:
235+
return False
236+
237+
return True
226238

227239
class Verbose:
228240
"""
@@ -475,38 +487,42 @@ def checkdep_usetex(s):
475487

476488
def _get_home():
477489
"""Find user's home directory if possible.
478-
Otherwise raise error.
490+
Otherwise, returns None.
479491
480-
:see: http://mail.python.org/pipermail/python-list/2005-February/263921.html
492+
:see: http://mail.python.org/pipermail/python-list/2005-February/325395.html
481493
"""
482-
path=''
483494
try:
484-
path=os.path.expanduser("~")
485-
except:
495+
path = os.path.expanduser("~")
496+
except ImportError:
497+
# This happens on Google App Engine (pwd module is not present).
486498
pass
487-
if not os.path.isdir(path):
488-
for evar in ('HOME', 'USERPROFILE', 'TMP'):
489-
try:
490-
path = os.environ[evar]
491-
if os.path.isdir(path):
492-
break
493-
except: pass
494-
if path:
495-
return path
496499
else:
497-
raise RuntimeError('please define environment variable $HOME')
500+
if os.path.isdir(path):
501+
return path
502+
for evar in ('HOME', 'USERPROFILE', 'TMP'):
503+
path = os.environ.get(evar)
504+
if path is not None and os.path.isdir(path):
505+
return path
506+
return None
498507

499508

500509
def _create_tmp_config_dir():
501510
"""
502511
If the config directory can not be created, create a temporary
503512
directory.
513+
514+
Returns None if a writable temporary directory could not be created.
504515
"""
505516
import getpass
506517
import tempfile
507518

508-
tempdir = os.path.join(
509-
tempfile.gettempdir(), 'matplotlib-%s' % getpass.getuser())
519+
try:
520+
tempdir = tempfile.gettempdir()
521+
except NotImplementedError:
522+
# Some restricted platforms (such as Google App Engine) do not provide
523+
# gettempdir.
524+
return None
525+
tempdir = os.path.join(tempdir, 'matplotlib-%s' % getpass.getuser())
510526
os.environ['MPLCONFIGDIR'] = tempdir
511527

512528
return tempdir
@@ -518,35 +534,42 @@ def _get_configdir():
518534
"""
519535
Return the string representing the configuration directory.
520536
521-
Default is HOME/.matplotlib. You can override this with the
522-
MPLCONFIGDIR environment variable. If the default is not
523-
writable, and MPLCONFIGDIR is not set, then
524-
tempfile.gettempdir() is used to provide a directory in
525-
which a matplotlib subdirectory is created as the configuration
526-
directory.
537+
The directory is chosen as follows:
538+
539+
1. If the MPLCONFIGDIR environment variable is supplied, choose that. Else,
540+
choose the '.matplotlib' subdirectory of the user's home directory (and
541+
create it if necessary).
542+
2. If the chosen directory exists and is writable, use that as the
543+
configuration directory.
544+
3. If possible, create a temporary directory, and use it as the
545+
configuration directory.
546+
4. A writable directory could not be found or created; return None.
527547
"""
528548

529549
configdir = os.environ.get('MPLCONFIGDIR')
530550
if configdir is not None:
531551
if not os.path.exists(configdir):
532-
os.makedirs(configdir)
552+
mkdirs(configdir)
533553
if not _is_writable_dir(configdir):
534554
return _create_tmp_config_dir()
535555
return configdir
536556

537557
h = get_home()
538-
p = os.path.join(get_home(), '.matplotlib')
558+
if h is not None:
559+
p = os.path.join(h, '.matplotlib')
539560

540-
if os.path.exists(p):
541-
if not _is_writable_dir(p):
542-
return _create_tmp_config_dir()
543-
else:
544-
if not _is_writable_dir(h):
545-
return _create_tmp_config_dir()
546-
from matplotlib.cbook import mkdirs
547-
mkdirs(p)
561+
if os.path.exists(p):
562+
if not _is_writable_dir(p):
563+
return _create_tmp_config_dir()
564+
else:
565+
if not _is_writable_dir(h):
566+
return _create_tmp_config_dir()
567+
from matplotlib.cbook import mkdirs
568+
mkdirs(p)
548569

549-
return p
570+
return p
571+
572+
return _create_tmp_config_dir()
550573
get_configdir = verbose.wrap('CONFIGDIR=%s', _get_configdir, always=False)
551574

552575

@@ -636,27 +659,39 @@ def matplotlib_fname():
636659
637660
"""
638661

639-
oldname = os.path.join( os.getcwd(), '.matplotlibrc')
662+
oldname = os.path.join(os.getcwd(), '.matplotlibrc')
640663
if os.path.exists(oldname):
641-
print("""\
642-
WARNING: Old rc filename ".matplotlibrc" found in working dir
643-
and and renamed to new default rc file name "matplotlibrc"
644-
(no leading"dot"). """, file=sys.stderr)
645-
shutil.move('.matplotlibrc', 'matplotlibrc')
664+
try:
665+
shutil.move('.matplotlibrc', 'matplotlibrc')
666+
except IOError as e:
667+
warnings.warn('File could not be renamed: %s' % e)
668+
else:
669+
warnings.warn("""\
670+
Old rc filename ".matplotlibrc" found in working dir and and renamed to new
671+
default rc file name "matplotlibrc" (no leading ".").""")
646672

647673
home = get_home()
648-
oldname = os.path.join( home, '.matplotlibrc')
649-
if os.path.exists(oldname):
650-
configdir = get_configdir()
651-
newname = os.path.join(configdir, 'matplotlibrc')
652-
print("""\
653-
WARNING: Old rc filename "%s" found and renamed to
654-
new default rc file name "%s"."""%(oldname, newname), file=sys.stderr)
655-
656-
shutil.move(oldname, newname)
657-
674+
configdir = get_configdir()
675+
if home:
676+
oldname = os.path.join(home, '.matplotlibrc')
677+
if os.path.exists(oldname):
678+
if configdir is not None:
679+
newname = os.path.join(configdir, 'matplotlibrc')
680+
681+
try:
682+
shutil.move(oldname, newname)
683+
except IOError as e:
684+
warnings.warn('File could not be renamed: %s' % e)
685+
else:
686+
warnings.warn("""\
687+
Old rc filename "%s" found and renamed to new default rc file name "%s"."""
688+
% (oldname, newname))
689+
else:
690+
warnings.warn("""\
691+
Could not rename old rc file "%s": a suitable configuration directory could not
692+
be found.""" % oldname)
658693

659-
fname = os.path.join( os.getcwd(), 'matplotlibrc')
694+
fname = os.path.join(os.getcwd(), 'matplotlibrc')
660695
if os.path.exists(fname): return fname
661696

662697
if 'MATPLOTLIBRC' in os.environ:
@@ -666,9 +701,10 @@ def matplotlib_fname():
666701
if os.path.exists(fname):
667702
return fname
668703

669-
fname = os.path.join(get_configdir(), 'matplotlibrc')
670-
if os.path.exists(fname): return fname
671-
704+
if configdir is not None:
705+
fname = os.path.join(configdir, 'matplotlibrc')
706+
if os.path.exists(fname):
707+
return fname
672708

673709
path = get_data_path() # guaranteed to exist or raise
674710
fname = os.path.join(path, 'matplotlibrc')
Collapse file

‎lib/matplotlib/finance.py‎

Copy file name to clipboardExpand all lines: lib/matplotlib/finance.py
+24-13Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,13 @@
2828

2929

3030
configdir = get_configdir()
31-
cachedir = os.path.join(configdir, 'finance.cache')
31+
# cachedir will be None if there is no writable directory.
32+
if configdir is not None:
33+
cachedir = os.path.join(configdir, 'finance.cache')
34+
else:
35+
# Should only happen in a restricted environment (such as Google App
36+
# Engine). Deal with this gracefully by not caching finance data.
37+
cachedir = None
3238

3339

3440
stock_dt = np.dtype([('date', object),
@@ -178,20 +184,25 @@ def fetch_historical_yahoo(ticker, date1, date2, cachename=None,dividends=False)
178184
d2[0], d2[1], d2[2], ticker, g)
179185

180186

181-
if cachename is None:
187+
# Cache the finance data if cachename is supplied, or there is a writable
188+
# cache directory.
189+
if cachename is None and cachedir is not None:
182190
cachename = os.path.join(cachedir, md5(url).hexdigest())
183-
if os.path.exists(cachename):
184-
fh = open(cachename)
185-
verbose.report('Using cachefile %s for %s'%(cachename, ticker))
191+
if cachename is not None:
192+
if os.path.exists(cachename):
193+
fh = open(cachename)
194+
verbose.report('Using cachefile %s for %s'%(cachename, ticker))
195+
else:
196+
mkdirs(os.path.abspath(os.path.dirname(cachename)))
197+
with contextlib.closing(urlopen(url)) as urlfh:
198+
with open(cachename, 'wb') as fh:
199+
fh.write(urlfh.read())
200+
verbose.report('Saved %s data to cache file %s'%(ticker, cachename))
201+
fh = open(cachename, 'r')
202+
203+
return fh
186204
else:
187-
mkdirs(os.path.abspath(os.path.dirname(cachename)))
188-
with contextlib.closing(urlopen(url)) as urlfh:
189-
with open(cachename, 'wb') as fh:
190-
fh.write(urlfh.read())
191-
verbose.report('Saved %s data to cache file %s'%(ticker, cachename))
192-
fh = open(cachename, 'r')
193-
194-
return fh
205+
return urlopen(url)
195206

196207

197208
def quotes_historical_yahoo(ticker, date1, date2, asobject=False,
Collapse file

‎lib/matplotlib/font_manager.py‎

Copy file name to clipboardExpand all lines: lib/matplotlib/font_manager.py
+22-12Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1311,28 +1311,38 @@ def findfont(prop, fontext='ttf'):
13111311
return result
13121312

13131313
else:
1314-
if sys.version_info[0] >= 3:
1315-
_fmcache = os.path.join(get_configdir(), 'fontList.py3k.cache')
1314+
configdir = get_configdir()
1315+
if configdir is not None:
1316+
if sys.version_info[0] >= 3:
1317+
_fmcache = os.path.join(configdir, 'fontList.py3k.cache')
1318+
else:
1319+
_fmcache = os.path.join(configdir, 'fontList.cache')
13161320
else:
1317-
_fmcache = os.path.join(get_configdir(), 'fontList.cache')
1321+
# Should only happen in a restricted environment (such as Google App
1322+
# Engine). Deal with this gracefully by not caching fonts.
1323+
_fmcache = None
13181324

13191325
fontManager = None
13201326

13211327
def _rebuild():
13221328
global fontManager
13231329
fontManager = FontManager()
1324-
pickle_dump(fontManager, _fmcache)
1330+
if _fmcache:
1331+
pickle_dump(fontManager, _fmcache)
13251332
verbose.report("generated new fontManager")
13261333

1327-
try:
1328-
fontManager = pickle_load(_fmcache)
1329-
if (not hasattr(fontManager, '_version') or
1330-
fontManager._version != FontManager.__version__):
1334+
if _fmcache:
1335+
try:
1336+
fontManager = pickle_load(_fmcache)
1337+
if (not hasattr(fontManager, '_version') or
1338+
fontManager._version != FontManager.__version__):
1339+
_rebuild()
1340+
else:
1341+
fontManager.default_size = None
1342+
verbose.report("Using fontManager instance from %s" % _fmcache)
1343+
except:
13311344
_rebuild()
1332-
else:
1333-
fontManager.default_size = None
1334-
verbose.report("Using fontManager instance from %s" % _fmcache)
1335-
except:
1345+
else:
13361346
_rebuild()
13371347

13381348
def findfont(prop, **kw):
Collapse file

‎lib/matplotlib/testing/compare.py‎

Copy file name to clipboardExpand all lines: lib/matplotlib/testing/compare.py
+4-1Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,10 @@ def compare_float( expected, actual, relTol = None, absTol = None ):
9999
# parameters old and new to a list that can be passed to Popen to
100100
# convert files with that extension to png format.
101101
def get_cache_dir():
102-
cache_dir = os.path.join(_get_configdir(), 'test_cache')
102+
configdir = _get_configdir()
103+
if configdir is None:
104+
raise RuntimeError('Could not find a suitable configuration directory')
105+
cache_dir = os.path.join(configdir, 'test_cache')
103106
if not os.path.exists(cache_dir):
104107
try:
105108
os.makedirs(cache_dir)
Collapse file

‎lib/matplotlib/texmanager.py‎

Copy file name to clipboardExpand all lines: lib/matplotlib/texmanager.py
+28-8Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import os
4242
import shutil
4343
import sys
44+
import warnings
4445

4546
from hashlib import md5
4647

@@ -94,16 +95,30 @@ class TexManager:
9495
oldcache = os.path.join(oldpath, '.tex.cache')
9596

9697
configdir = mpl.get_configdir()
97-
texcache = os.path.join(configdir, 'tex.cache')
98+
if configdir is not None:
99+
texcache = os.path.join(configdir, 'tex.cache')
100+
else:
101+
# Should only happen in a restricted environment (such as Google App
102+
# Engine). Deal with this gracefully by not creating a cache directory.
103+
texcache = None
98104

99105
if os.path.exists(oldcache):
100-
# FIXME raise proper warning
101-
print("""\
102-
WARNING: found a TeX cache dir in the deprecated location "%s".
103-
Moving it to the new default location "%s".""" % (oldcache, texcache),
104-
file=sys.stderr)
105-
shutil.move(oldcache, texcache)
106-
mkdirs(texcache)
106+
if texcache is not None:
107+
try:
108+
shutil.move(oldcache, texcache)
109+
except IOError as e:
110+
warnings.warn('File could not be renamed: %s' % e)
111+
else:
112+
warnings.warn("""\
113+
Found a TeX cache dir in the deprecated location "%s".
114+
Moving it to the new default location "%s".""" % (oldcache, texcache))
115+
else:
116+
warnings.warn("""\
117+
Could not rename old TeX cache dir "%s": a suitable configuration
118+
directory could not be found.""" % oldcache)
119+
120+
if texcache is not None:
121+
mkdirs(texcache)
107122

108123
_dvipng_hack_alpha = None
109124
#_dvipng_hack_alpha = dvipng_hack_alpha()
@@ -145,6 +160,11 @@ class TexManager:
145160

146161
def __init__(self):
147162

163+
if self.texcache is None:
164+
raise RuntimeError(
165+
('Cannot create TexManager, as there is no cache directory '
166+
'available'))
167+
148168
mkdirs(self.texcache)
149169
ff = rcParams['font.family'].lower()
150170
if ff in self.font_families:

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.