@@ -380,6 +380,48 @@ def save(self):
380380 )
381381 )
382382
383+ @property
384+ def server_url (self ):
385+ """
386+ The server URL to use for an external orca server, or None if orca
387+ should be managed locally
388+
389+ Overrides executable, port, timeout, mathjax, topojson,
390+ and mapbox_access_token
391+
392+ Returns
393+ -------
394+ str or None
395+ """
396+ return self ._props .get ("server_url" , None )
397+
398+ @server_url .setter
399+ def server_url (self , val ):
400+
401+ if val is None :
402+ self ._props .pop ("server_url" , None )
403+ return
404+ if not isinstance (val , str ):
405+ raise ValueError (
406+ """
407+ The server_url property must be a string, but received value of type {typ}.
408+ Received value: {val}""" .format (
409+ typ = type (val ), val = val
410+ )
411+ )
412+
413+ if not val .startswith ("http://" ) and not val .startswith ("https://" ):
414+ val = "http://" + val
415+
416+ shutdown_server ()
417+ self .executable = None
418+ self .port = None
419+ self .timeout = None
420+ self .mathjax = None
421+ self .topojson = None
422+ self .mapbox_access_token = None
423+ self ._props ["server_url" ] = val
424+
383425 @property
384426 def port (self ):
385427 """
@@ -777,6 +819,7 @@ def __repr__(self):
777819 return """\
778820 orca configuration
779821------------------
822+ server_url: {server_url}
780823 executable: {executable}
781824 port: {port}
782825 timeout: {timeout}
@@ -795,6 +838,7 @@ def __repr__(self):
795838 config_file: {config_file}
796839
797840""" .format (
841+ server_url = self .server_url ,
798842 port = self .port ,
799843 executable = self .executable ,
800844 timeout = self .timeout ,
@@ -1344,62 +1388,65 @@ def ensure_server():
13441388 if status .state == "unvalidated" :
13451389 validate_executable ()
13461390
1347- # Acquire lock to make sure that we keep the properties of orca_state
1348- # consistent across threads
1349- with orca_lock :
1350- # Cancel the current shutdown timer, if any
1351- if orca_state ["shutdown_timer" ] is not None :
1352- orca_state ["shutdown_timer" ].cancel ()
1391+ if not config .server_url :
1392+ # Acquire lock to make sure that we keep the properties of orca_state
1393+ # consistent across threads
1394+ with orca_lock :
1395+ # Cancel the current shutdown timer, if any
1396+ if orca_state ["shutdown_timer" ] is not None :
1397+ orca_state ["shutdown_timer" ].cancel ()
1398+
1399+ # Start a new server process if none is active
1400+ if orca_state ["proc" ] is None :
1401+
1402+ # Determine server port
1403+ if config .port is None :
1404+ orca_state ["port" ] = find_open_port ()
1405+ else :
1406+ orca_state ["port" ] = config .port
1407+
1408+ # Build orca command list
1409+ cmd_list = status ._props ["executable_list" ] + [
1410+ "serve" ,
1411+ "-p" ,
1412+ str (orca_state ["port" ]),
1413+ "--plotly" ,
1414+ config .plotlyjs ,
1415+ "--graph-only" ,
1416+ ]
13531417
1354- # Start a new server process if none is active
1355- if orca_state [ "proc" ] is None :
1418+ if config . topojson :
1419+ cmd_list . extend ([ "--topojson" , config . topojson ])
13561420
1357- # Determine server port
1358- if config .port is None :
1359- orca_state ["port" ] = find_open_port ()
1360- else :
1361- orca_state ["port" ] = config .port
1362-
1363- # Build orca command list
1364- cmd_list = status ._props ["executable_list" ] + [
1365- "serve" ,
1366- "-p" ,
1367- str (orca_state ["port" ]),
1368- "--plotly" ,
1369- config .plotlyjs ,
1370- "--graph-only" ,
1371- ]
1372-
1373- if config .topojson :
1374- cmd_list .extend (["--topojson" , config .topojson ])
1375-
1376- if config .mathjax :
1377- cmd_list .extend (["--mathjax" , config .mathjax ])
1378-
1379- if config .mapbox_access_token :
1380- cmd_list .extend (["--mapbox-access-token" , config .mapbox_access_token ])
1381-
1382- # Create subprocess that launches the orca server on the
1383- # specified port.
1384- DEVNULL = open (os .devnull , "wb" )
1385- with orca_env ():
1386- orca_state ["proc" ] = subprocess .Popen (cmd_list , stdout = DEVNULL )
1387-
1388- # Update orca.status so the user has an accurate view
1389- # of the state of the orca server
1390- status ._props ["state" ] = "running"
1391- status ._props ["pid" ] = orca_state ["proc" ].pid
1392- status ._props ["port" ] = orca_state ["port" ]
1393- status ._props ["command" ] = cmd_list
1394-
1395- # Create new shutdown timer if a timeout was specified
1396- if config .timeout is not None :
1397- t = threading .Timer (config .timeout , shutdown_server )
1398- # Make it a daemon thread so that exit won't wait for timer to
1399- # complete
1400- t .daemon = True
1401- t .start ()
1402- orca_state ["shutdown_timer" ] = t
1421+ if config .mathjax :
1422+ cmd_list .extend (["--mathjax" , config .mathjax ])
1423+
1424+ if config .mapbox_access_token :
1425+ cmd_list .extend (
1426+ ["--mapbox-access-token" , config .mapbox_access_token ]
1427+ )
1428+
1429+ # Create subprocess that launches the orca server on the
1430+ # specified port.
1431+ DEVNULL = open (os .devnull , "wb" )
1432+ with orca_env ():
1433+ orca_state ["proc" ] = subprocess .Popen (cmd_list , stdout = DEVNULL )
1434+
1435+ # Update orca.status so the user has an accurate view
1436+ # of the state of the orca server
1437+ status ._props ["state" ] = "running"
1438+ status ._props ["pid" ] = orca_state ["proc" ].pid
1439+ status ._props ["port" ] = orca_state ["port" ]
1440+ status ._props ["command" ] = cmd_list
1441+
1442+ # Create new shutdown timer if a timeout was specified
1443+ if config .timeout is not None :
1444+ t = threading .Timer (config .timeout , shutdown_server )
1445+ # Make it a daemon thread so that exit won't wait for timer to
1446+ # complete
1447+ t .daemon = True
1448+ t .start ()
1449+ orca_state ["shutdown_timer" ] = t
14031450
14041451
14051452@retrying .retry (wait_random_min = 5 , wait_random_max = 10 , stop_max_delay = 60000 )
@@ -1410,9 +1457,12 @@ def request_image_with_retrying(**kwargs):
14101457 """
14111458 from requests import post
14121459
1413- server_url = "http://{hostname}:{port}" .format (
1414- hostname = "localhost" , port = orca_state ["port" ]
1415- )
1460+ if config .server_url :
1461+ server_url = config .server_url
1462+ else :
1463+ server_url = "http://{hostname}:{port}" .format (
1464+ hostname = "localhost" , port = orca_state ["port" ]
1465+ )
14161466
14171467 request_params = {k : v for k , v , in kwargs .items () if v is not None }
14181468 json_str = json .dumps (request_params , cls = _plotly_utils .utils .PlotlyJSONEncoder )
@@ -1513,29 +1563,41 @@ def to_image(fig, format=None, width=None, height=None, scale=None, validate=Tru
15131563 # Get current status string
15141564 status_str = repr (status )
15151565
1516- # Check if the orca server process exists
1517- pid_exists = psutil .pid_exists (status .pid )
1518-
1519- # Raise error message based on whether the server process existed
1520- if pid_exists :
1566+ if config .server_url :
15211567 raise ValueError (
15221568 """
1569+ Plotly.py was unable to communicate with the orca server at {server_url}
1570+
1571+ Please check that the server is running and accessible.
1572+ """ .format (
1573+ server_url = config .server_url
1574+ )
1575+ )
1576+
1577+ else :
1578+ # Check if the orca server process exists
1579+ pid_exists = psutil .pid_exists (status .pid )
1580+
1581+ # Raise error message based on whether the server process existed
1582+ if pid_exists :
1583+ raise ValueError (
1584+ """
15231585For some reason plotly.py was unable to communicate with the
15241586local orca server process, even though the server process seems to be running.
15251587
15261588Please review the process and connection information below:
15271589
15281590{info}
15291591""" .format (
1530- info = status_str
1592+ info = status_str
1593+ )
15311594 )
1532- )
1533- else :
1534- # Reset the status so that if the user tries again, we'll try to
1535- # start the server again
1536- reset_status ()
1537- raise ValueError (
1538- """
1595+ else :
1596+ # Reset the status so that if the user tries again, we'll try to
1597+ # start the server again
1598+ reset_status ()
1599+ raise ValueError (
1600+ """
15391601For some reason the orca server process is no longer running.
15401602
15411603Please review the process and connection information below:
@@ -1544,9 +1606,9 @@ def to_image(fig, format=None, width=None, height=None, scale=None, validate=Tru
15441606plotly.py will attempt to start the local server process again the next time
15451607an image export operation is performed.
15461608""" .format (
1547- info = status_str
1609+ info = status_str
1610+ )
15481611 )
1549- )
15501612
15511613 # Check response
15521614 # --------------
0 commit comments