Skip to content

Commit 79cdc1e

Browse files
authored
Support configurable settings directory with lazy initialization (#1195)
This PR makes 2 changes to our handling of the .plotly settings directory. 1. The default location of this directory is still ~/.plotly, but it can now be overridden by setting the PLOTLY_DIR environment variable before Python starts. 2. Previously this settings directory was created and initialized during the initial import of the plotly library. Now, the creation of the directory and the initialization of the configuration files is delayed until an operation is performed that needs to write to the directory. Defaults are now returned when settings are accessed and the config directory does not exist. Change 1 provides a way to customize the location of plotly.py's settings, and makes it possible for users to create and maintain multiple profiles. Change 2 removes the concurrency issues associated with launching many plotly processes simultaneously.
1 parent e197f57 commit 79cdc1e

File tree

6 files changed

+43
-35
lines changed

6 files changed

+43
-35
lines changed

plotly/files.py

+9-6
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import os
22

33
# file structure
4-
PLOTLY_DIR = os.path.join(os.path.expanduser("~"), ".plotly")
4+
PLOTLY_DIR = os.environ.get("PLOTLY_DIR",
5+
os.path.join(os.path.expanduser("~"), ".plotly"))
6+
57
CREDENTIALS_FILE = os.path.join(PLOTLY_DIR, ".credentials")
68
CONFIG_FILE = os.path.join(PLOTLY_DIR, ".config")
7-
TEST_DIR = os.path.join(os.path.expanduser("~"), ".test")
89
TEST_FILE = os.path.join(PLOTLY_DIR, ".permission_test")
910

1011
# this sets both the DEFAULTS and the TYPES for these files
@@ -25,8 +26,6 @@
2526

2627
def _permissions():
2728
try:
28-
os.mkdir(TEST_DIR)
29-
os.rmdir(TEST_DIR)
3029
if not os.path.exists(PLOTLY_DIR):
3130
os.mkdir(PLOTLY_DIR)
3231
with open(TEST_FILE, 'w') as f:
@@ -37,8 +36,12 @@ def _permissions():
3736
return False
3837

3938

40-
_file_permissions = _permissions()
39+
_file_permissions = None
4140

4241

43-
def check_file_permissions():
42+
def ensure_writable_plotly_dir():
43+
# Cache permissions status
44+
global _file_permissions
45+
if _file_permissions is None:
46+
_file_permissions = _permissions()
4447
return _file_permissions

plotly/io/_orca.py

+8-3
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from six import string_types
1414

1515
import plotly
16-
from plotly.files import PLOTLY_DIR
16+
from plotly.files import PLOTLY_DIR, ensure_writable_plotly_dir
1717
from plotly.io._utils import validate_coerce_fig_to_dict
1818
from plotly.optional_imports import get_module
1919

@@ -354,8 +354,13 @@ def save(self):
354354
-------
355355
None
356356
"""
357-
with open(self.config_file, 'w') as f:
358-
json.dump(self._props, f, indent=4)
357+
if ensure_writable_plotly_dir():
358+
with open(self.config_file, 'w') as f:
359+
json.dump(self._props, f, indent=4)
360+
else:
361+
warnings.warn("""\
362+
Failed to write orca configuration file at '{path}'""".format(
363+
path=self.config_file))
359364

360365
@property
361366
def port(self):

plotly/plotly/plotly.py

-3
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,6 @@
5757
"'secret'."
5858
)
5959

60-
# test file permissions and make sure nothing is corrupted
61-
tools.ensure_local_plotly_files()
62-
6360

6461
# don't break backwards compatibility
6562
def sign_in(username, api_key, **kwargs):

plotly/tests/test_plot_ly/test_get_figure/test_get_figure.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ def test_get_figure_raw(self):
9898
py.get_figure('PlotlyImageTest', str(file_id), raw=True)
9999

100100

101-
class TestBytesVStrings(TestCase):
101+
class TestBytesVStrings(PlotlyTestCase):
102102

103103
@skipIf(not six.PY3, 'Decoding and missing escapes only seen in PY3')
104104
def test_proper_escaping(self):

plotly/tests/utils.py

+6-8
Original file line numberDiff line numberDiff line change
@@ -36,16 +36,14 @@ def tearDown(self):
3636
self.restore_session()
3737

3838
def stash_files(self):
39-
if files.check_file_permissions():
40-
self._credentials = utils.load_json_dict(files.CREDENTIALS_FILE)
41-
self._config = utils.load_json_dict(files.CONFIG_FILE)
39+
self._credentials = utils.load_json_dict(files.CREDENTIALS_FILE)
40+
self._config = utils.load_json_dict(files.CONFIG_FILE)
4241

4342
def restore_files(self):
44-
if files.check_file_permissions():
45-
if self._credentials is not None:
46-
utils.save_json_dict(files.CREDENTIALS_FILE, self._credentials)
47-
if self._config is not None:
48-
utils.save_json_dict(files.CONFIG_FILE, self._config)
43+
if self._credentials and files.ensure_writable_plotly_dir():
44+
utils.save_json_dict(files.CREDENTIALS_FILE, self._credentials)
45+
if self._config and files.ensure_writable_plotly_dir():
46+
utils.save_json_dict(files.CONFIG_FILE, self._config)
4947

5048
def stash_session(self):
5149
self._session = copy.deepcopy(session._session)

plotly/tools.py

+19-14
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,11 @@
1212
import warnings
1313

1414
import six
15+
import copy
1516

1617
from plotly import exceptions, optional_imports, session, utils
1718
from plotly.files import (CONFIG_FILE, CREDENTIALS_FILE, FILE_CONTENT,
18-
check_file_permissions)
19+
ensure_writable_plotly_dir)
1920

2021
DEFAULT_PLOTLY_COLORS = ['rgb(31, 119, 180)', 'rgb(255, 127, 14)',
2122
'rgb(44, 160, 44)', 'rgb(214, 39, 40)',
@@ -78,7 +79,7 @@ def ensure_local_plotly_files():
7879
If the config or credential files aren't filled out, then write them
7980
to the disk.
8081
"""
81-
if check_file_permissions():
82+
if ensure_writable_plotly_dir():
8283
for fn in [CREDENTIALS_FILE, CONFIG_FILE]:
8384
utils.ensure_file_exists(fn)
8485
contents = utils.load_json_dict(fn)
@@ -124,7 +125,7 @@ def set_credentials_file(username=None,
124125
:param (str) proxy_password: The pw associated with your Proxy un
125126
126127
"""
127-
if not check_file_permissions():
128+
if not ensure_writable_plotly_dir():
128129
raise exceptions.PlotlyError("You don't have proper file permissions "
129130
"to run this function.")
130131
ensure_local_plotly_files() # make sure what's there is OK
@@ -152,11 +153,13 @@ def get_credentials_file(*args):
152153
get_credentials_file('username')
153154
154155
"""
155-
if check_file_permissions():
156-
ensure_local_plotly_files() # make sure what's there is OK
157-
return utils.load_json_dict(CREDENTIALS_FILE, *args)
158-
else:
159-
return FILE_CONTENT[CREDENTIALS_FILE]
156+
# Read credentials from file if possible
157+
credentials = utils.load_json_dict(CREDENTIALS_FILE, *args)
158+
if not credentials:
159+
# Credentials could not be read, use defaults
160+
credentials = copy.copy(FILE_CONTENT[CREDENTIALS_FILE])
161+
162+
return credentials
160163

161164

162165
def reset_credentials_file():
@@ -185,7 +188,7 @@ def set_config_file(plotly_domain=None,
185188
:param (bool) world_readable: True = public, False = private
186189
187190
"""
188-
if not check_file_permissions():
191+
if not ensure_writable_plotly_dir():
189192
raise exceptions.PlotlyError("You don't have proper file permissions "
190193
"to run this function.")
191194
ensure_local_plotly_files() # make sure what's there is OK
@@ -247,11 +250,13 @@ def get_config_file(*args):
247250
get_config_file('plotly_domain')
248251
249252
"""
250-
if check_file_permissions():
251-
ensure_local_plotly_files() # make sure what's there is OK
252-
return utils.load_json_dict(CONFIG_FILE, *args)
253-
else:
254-
return FILE_CONTENT[CONFIG_FILE]
253+
# Read config from file if possible
254+
config = utils.load_json_dict(CONFIG_FILE, *args)
255+
if not config:
256+
# Config could not be read, use defaults
257+
config = copy.copy(FILE_CONTENT[CONFIG_FILE])
258+
259+
return config
255260

256261

257262
def reset_config_file():

0 commit comments

Comments
 (0)