p3lib 1.1.108__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
p3lib/netplotly.py ADDED
@@ -0,0 +1,223 @@
1
+ #!/usr/bin/env python3
2
+
3
+ import os
4
+ import plotly
5
+ import tarfile
6
+ import tempfile
7
+ import shutil
8
+
9
+ from pathlib import Path
10
+ try:
11
+ from .ssh import SSH
12
+ from .helper import getHomePath
13
+ except:
14
+ #We get here if running netplotly_demo.py as it sits in the same folder
15
+ #as netplotly.py
16
+ from ssh import SSH
17
+ from helper import getHomePath
18
+
19
+ class NetPlotly(object):
20
+ """@brief Manage plotly graphs on a webserver and allow them to be transferred over a network via ssh.
21
+ Plots are saved to a local folder. The local folder maybe served via a web server.
22
+ The contents of the local folder maybe transferred to a remote machine via ssh.
23
+ The contents of the remote folder maybe served via a web server.
24
+
25
+ The local and remote folders will contain an index.html file. This displays a table of
26
+ all the available plots. Each plot name in the table maybe clicked which will display
27
+ the plotly plot."""
28
+ INDEX_HTML_FILE = "netplotly_index.html"
29
+ DEFAULT_LOCAL_ROOT = "~/.netplotly"
30
+ ASSETS_FOLDER = "assets"
31
+ PLOT_LIST_FILE = "plot_list.txt"
32
+
33
+ @staticmethod
34
+ def GetTarBallFile():
35
+ """@brief Get the tarball file path
36
+ @return The abs file path"""
37
+ return os.path.join( tempfile.gettempdir(), "netplotly.tgz" )
38
+
39
+ def __init__(self, localRoot=DEFAULT_LOCAL_ROOT, serverRoot=DEFAULT_LOCAL_ROOT, host=None, username=None, password=None, port=22, uio=None):
40
+ """@brief Constructor
41
+ @param localRoot The local folder to store the plots in.
42
+ A web server may serve files directly from here or they maybe
43
+ uploaded (via ssh) to a webserver using the API's provided
44
+ by this class.
45
+ @param serverRoot The folder to store html files in on the server.
46
+ @param host The address of the ssh server to upload files to.
47
+ @param username The SSH server username
48
+ @param password The SSH server password. Not required if auto login via public
49
+ key is enabled for the ssh server.
50
+ @param port The ssh server port (default=22).
51
+ @param uio A UIO instance for displaying messages to the user."""
52
+ self._localRoot = localRoot
53
+ self._serverRoot = serverRoot
54
+ self._host = host
55
+ self._username = username
56
+ self._password = password
57
+ self._port = port
58
+ self._uio = uio
59
+ self._ssh = None
60
+
61
+ self._updateLocalRoot()
62
+
63
+ def _updateLocalRoot(self):
64
+ """@brief Set the local _rootp attr"""
65
+ if self._localRoot.startswith("~"):
66
+ self._localRoot = getHomePath() + self._localRoot.replace("~", "")
67
+
68
+ def info(self, msg):
69
+ """@brief Display an info level message if we have been provided with a uio object"""
70
+ if self._uio:
71
+ self._uio.info(msg)
72
+
73
+ def _getPlotListFile(self):
74
+ """@return The plot list file"""
75
+ return os.path.join(self._localRoot, NetPlotly.PLOT_LIST_FILE)
76
+
77
+ def _updatePlotList(self, plotTitle):
78
+ """@brief Update the plot title log file. This file is read by the javascript to
79
+ present a table of available plots to the user. The PLOT_LIST_FILE
80
+ simply contains a number of lines each lines text is the name of the plot.
81
+ @param plotTitle The plot title
82
+ @return None"""
83
+ alreadyAdded = False
84
+ plotListFile = self._getPlotListFile()
85
+ if os.path.isfile(plotListFile):
86
+ fd = open(plotListFile, 'r')
87
+ lines = fd.readlines()
88
+ fd.close()
89
+ for line in lines:
90
+ line=line.rstrip("\n")
91
+ if line == plotTitle:
92
+ alreadyAdded=True
93
+ if not alreadyAdded:
94
+ fd = open(plotListFile, 'a')
95
+ fd.write("{}\n".format(plotTitle))
96
+ fd.close()
97
+
98
+ def _removePlotList(self, plotTitle):
99
+ """@brief Remove a file from the plot list.
100
+ @param plotTitle The plot title
101
+ @return None"""
102
+ plotListFile = self._getPlotListFile()
103
+ newLines = []
104
+ if os.path.isfile(plotListFile):
105
+ fd = open(plotListFile, 'r')
106
+ lines = fd.readlines()
107
+ fd.close()
108
+
109
+ for line in lines:
110
+ if not line.startswith(plotTitle):
111
+ newLines.append(line)
112
+
113
+ fd = open(plotListFile, 'w')
114
+ for l in newLines:
115
+ fd.write(l)
116
+
117
+ fd.close()
118
+
119
+ def save(self, fig, htmlFile=None, autoOpen=False):
120
+ """@brief Save a plotly figure to an html file in the local home folder.
121
+ @param fig The plotly figure
122
+ @param htmlFile The name of the htmlfile to save. If not provided the name of the plot
123
+ with the .html suffix is used as the filename.
124
+ @param autoOpen If True then a browser window is launched to show the plot"""
125
+ #don't allow index.html as this is usd for the table of plots
126
+ if htmlFile == NetPlotly.INDEX_HTML_FILE:
127
+ raise Exception("save(): {} is a reserved html file name.".format(NetPlotly.INDEX_HTML_FILE))
128
+
129
+ #If no html file provided then use the name of the plot
130
+ if not htmlFile:
131
+ htmlFile = "{}.html".format( fig["layout"]["title"]["text"] )
132
+
133
+ if not os.path.isdir(self._localRoot):
134
+ os.makedirs(self._localRoot)
135
+ self.info("Created {}".format(self._localRoot))
136
+
137
+ plotName = htmlFile.replace(".html", "")
138
+ self._updatePlotList(plotName)
139
+
140
+ fileToSave = os.path.join(self._localRoot, htmlFile)
141
+ plotly.offline.plot(fig, filename=fileToSave, auto_open = autoOpen)
142
+ self.info("Saved {}".format(fileToSave))
143
+
144
+ def _createTarBall(self, opFile, srcFolder):
145
+ self.info("Creating {} from {}".format(opFile, srcFolder))
146
+ with tarfile.open(opFile, "w:gz") as tar:
147
+ tar.add(srcFolder, arcname=os.path.basename(srcFolder))
148
+
149
+ def connect(self):
150
+ """@brief connect to the server vis ssh"""
151
+ if not self._host:
152
+ raise Exception("No SSH server defined to connect to")
153
+
154
+ if not self._ssh:
155
+ self.info("Connecting to {}:{} as {}".format(self._host, self._port, self._username))
156
+ self._ssh = SSH(self._host, username=self._username, password=self._password, port=self._port)
157
+ self._ssh.connect(connectSFTPSession=True)
158
+ self.info("Connected")
159
+
160
+ def disconnect(self):
161
+ """@brief Close the connection to the server."""
162
+ if self._ssh:
163
+ self._ssh.close()
164
+ self._ssh = None
165
+ self.info("Closed server connection")
166
+
167
+ def upload(self, purge=False):
168
+ """@brief Upload the plot to the server.
169
+ @param purge If True (default is False) then all html files are removed from the server before uploading
170
+ from the local path. If True the caller must be careful to set serverRoot (in Constructor)
171
+ as all files in this location are purged before files are uploaded."""
172
+ if self._host and self._username:
173
+ tarBallFile = NetPlotly.GetTarBallFile()
174
+ self._createTarBall(tarBallFile, self._localRoot)
175
+ self.connect()
176
+
177
+ if purge:
178
+ #Remove all the files in the server folder
179
+ cmd = "rm -f {}/*".format(self._serverRoot)
180
+ self._ssh.runCmd(cmd)
181
+
182
+ self.info("Uploading {} to {}:{}".format(tarBallFile, self._host, self._port))
183
+ self._ssh.putFile(tarBallFile, tarBallFile)
184
+
185
+ self.info("Decompressing {} into {} on the server.".format(tarBallFile, self._serverRoot))
186
+ rPath = Path(self._serverRoot)
187
+ cmd = "tar zxvf {} -C {}".format(tarBallFile, rPath.parent)
188
+ self._ssh.runCmd(cmd)
189
+
190
+ self.disconnect()
191
+
192
+ def getPlotNameList(self):
193
+ """@brief Get a list of the names of all the plots currently stored in the local root folder.
194
+ @return a list of plot names."""
195
+ plotList = []
196
+ plotListFile = self._getPlotListFile()
197
+ if os.path.isfile(plotListFile):
198
+ fd = open(plotListFile, 'r')
199
+ plotList = fd.read().splitlines()
200
+ fd.close()
201
+
202
+ return plotList
203
+
204
+ def getPlotFileList(self):
205
+ """@brief Get a list of the plot file names of all the plots currently stored in the local root folder.
206
+ @return a list of plot file names."""
207
+ plotList = self.getPlotNameList()
208
+ plotFileList = ["{}.html".format(plotName) for plotName in plotList]
209
+ return plotFileList
210
+
211
+ def remove(self, plotName):
212
+ """@brief Remove a plot by it's name from the plot list.
213
+ @return None"""
214
+ fileToRemove = os.path.join(self._localRoot, "{}.html".format(plotName))
215
+ if os.path.isfile(fileToRemove):
216
+ os.remove(fileToRemove)
217
+ self._removePlotList(plotName)
218
+
219
+ def removeLocalRoot(self):
220
+ """@brief Remove all plots from the list of plots. Be sure you have _localRoot set
221
+ correctly before calling this method.
222
+ @return None"""
223
+ shutil.rmtree(self._localRoot)