eric6/Sessions/SessionFile.py

branch
jsonfiles
changeset 8009
29818ac4853c
child 8012
ecf45f723038
equal deleted inserted replaced
8006:c4110b8b5931 8009:29818ac4853c
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2021 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing a class representing the project debugger properties
8 JSON file.
9 """
10
11 import json
12 import os
13 import time
14
15 from PyQt5.QtCore import QObject
16
17 from E5Gui import E5MessageBox
18 from E5Gui.E5OverrideCursor import E5OverridenCursor
19 from E5Gui.E5Application import e5App
20
21 import Preferences
22
23
24 class SessionFile(QObject):
25 """
26 Class representing the project debugger properties JSON file.
27 """
28 def __init__(self, isGlobal: bool, parent: QObject = None):
29 """
30 Constructor
31
32 @param project reference to the project object
33 @type Project
34 @param parent reference to the parent object
35 @type QObject (optional)
36 """
37 super(SessionFile, self).__init__(parent)
38
39 self.__isGlobal = isGlobal
40
41 def writeFile(self, filename: str) -> bool:
42 """
43 Public method to write the project debugger properties data to a
44 project debugger properties JSON file.
45
46 @param filename name of the user project file
47 @type str
48 @return flag indicating a successful write
49 @rtype bool
50 """
51 # get references to objects we need
52 project = e5App().getObject("Project")
53 projectBrowser = e5App().getObject("ProjectBrowser")
54 multiProject = e5App().getObject("MultiProject")
55 vm = e5App().getObject("ViewManager")
56 dbg = e5App().getObject("DebugUI")
57 dbs = e5App().getObject("DebugServer")
58
59 name = os.path.splitext(os.path.basename(filename))[0]
60
61 # prepare the session data dictionary
62 # step 0: header
63 sessionDict = {}
64 sessionDict["header"] = {}
65 if not self.__isGlobal:
66 sessionDict["header"]["comment"] = (
67 f"eric session file for project {name}"
68 )
69 sessionDict["header"]["warning"] = (
70 "This file was generated automatically, do not edit."
71 )
72
73 # TODO: replace 'XMLTimestamp' by 'Timestamp'
74 if Preferences.getProject("XMLTimestamp") or self.__isGlobal:
75 sessionDict["header"]["saved"] = (
76 time.strftime('%Y-%m-%d, %H:%M:%S')
77 )
78
79 # step 1: open multi project and project for global session
80 sessionDict["MultiProject"] = ""
81 sessionDict["Project"] = ""
82 if self.__isGlobal:
83 if multiProject.isOpen():
84 sessionDict["MultiProject"] = (
85 multiProject.getMultiProjectFile()
86 )
87 if project.isOpen():
88 sessionDict["Project"] = project.getProjectFile()
89
90 # step 2: all open (project) filenames and the active editor
91 if vm.canSplit():
92 sessionDict["ViewManagerSplits"] = {
93 "Count": vm.splitCount(),
94 "Orientation": vm.getSplitOrientation(),
95 }
96 else:
97 sessionDict["ViewManagerSplits"] = {
98 "Count": 0,
99 "Orientation": 1,
100 }
101
102 editorsDict = {} # remember editors by file name to detect clones
103 sessionDict["Editors"] = []
104 allOpenEditorLists = vm.getOpenEditorsForSession()
105 for splitIndex, openEditorList in enumerate(allOpenEditorLists):
106 for editorIndex, editor in enumerate(openEditorList):
107 fileName = editor.getFileName()
108 if self.__isGlobal or project.isProjectFile(fileName):
109 if fileName in editorsDict:
110 isClone = editorsDict[fileName].isClone(editor)
111 else:
112 isClone = False
113 editorsDict[fileName] = editor
114 editorDict = {
115 "Filename": fileName,
116 "Cursor": editor.getCursorPosition(),
117 "Folds": editor.contractedFolds(),
118 "Zoom": editor.getZoom(),
119 "Clone": isClone,
120 "Splitindex": splitIndex,
121 "Editorindex": editorIndex,
122 }
123 sessionDict["Editors"].append(editorDict)
124
125 aw = vm.getActiveName()
126 sessionDict["ActiveWindow"] = {}
127 if aw and (self.__isGlobal or project.isProjectFile(aw)):
128 ed = vm.getOpenEditor(aw)
129 sessionDict["ActiveWindow"] = {
130 "Filename": aw,
131 "Cursor": ed.getCursorPosition(),
132 }
133
134 # step 3: breakpoints
135 allBreaks = Preferences.getProject("SessionAllBreakpoints")
136 projectFiles = project.getSources(True)
137 bpModel = dbs.getBreakPointModel()
138 if self.__isGlobal or allBreaks:
139 sessionDict["Breakpoints"] = bpModel.getAllBreakpoints()
140 else:
141 sessionDict["Breakpoints"] = [
142 bp
143 for bp in bpModel.getAllBreakpoints()
144 if bp[0] in projectFiles
145 ]
146
147 # step 4: watch expressions
148 wpModel = dbs.getWatchPointModel()
149 sessionDict["Watchpoints"] = wpModel.getAllWatchpoints()
150
151 # step 5: debug info
152 if self.__isGlobal:
153 if len(dbg.argvHistory):
154 dbgCmdline = dbg.argvHistory[0]
155 else:
156 dbgCmdline = ""
157 if len(dbg.wdHistory):
158 dbgWd = dbg.wdHistory[0]
159 else:
160 dbgWd = ""
161 if len(dbg.envHistory):
162 dbgEnv = dbg.envHistory[0]
163 else:
164 dbgEnv = ""
165 if len(dbg.multiprocessNoDebugHistory):
166 dbgMultiprocessNoDebug = (
167 dbg.multiprocessNoDebugHistory[0]
168 )
169 else:
170 dbgMultiprocessNoDebug = ""
171 sessionDict["DebugInfo"] = {
172 "VirtualEnv": dbg.lastUsedVenvName,
173 "CommandLine": dbgCmdline,
174 "WorkingDirectory": dbgWd,
175 "Environment": dbgEnv,
176 "ReportExceptions": dbg.exceptions,
177 "Exceptions": dbg.excList,
178 "IgnoredExceptions": dbg.excIgnoreList,
179 "AutoClearShell": dbg.autoClearShell,
180 "TracePython": dbg.tracePython,
181 "AutoContinue": dbg.autoContinue,
182 "EnableMultiprocess": dbg.enableMultiprocess,
183 "MultiprocessNoDebug": dbgMultiprocessNoDebug
184 }
185 else:
186 sessionDict["DebugInfo"] = {
187 "VirtualEnv": project.dbgVirtualEnv,
188 "CommandLine": project.dbgCmdline,
189 "WorkingDirectory": project.dbgWd,
190 "Environment": project.dbgEnv,
191 "ReportExceptions": project.dbgReportExceptions,
192 "Exceptions": project.dbgExcList,
193 "IgnoredExceptions": project.dbgExcIgnoreList,
194 "AutoClearShell": project.dbgAutoClearShell,
195 "TracePython": project.dbgTracePython,
196 "AutoContinue": project.dbgAutoContinue,
197 "EnableMultiprocess": project.dbgEnableMultiprocess,
198 "MultiprocessNoDebug": project.dbgMultiprocessNoDebug,
199 }
200
201 # step 6: bookmarks
202 bookmarksList = []
203 for fileName in editorsDict:
204 if self.__isGlobal or project.isProjectFile(fileName):
205 editor = editorsDict[fileName]
206 bookmarks = editor.getBookmarks()
207 if bookmarks:
208 bookmarksList.append({
209 "Filename": fileName,
210 "Lines": bookmarks,
211 })
212 sessionDict["Bookmarks"] = bookmarksList
213
214 # step 7: state of the various project browsers
215 browsersList = []
216 for browserName in projectBrowser.getProjectBrowserNames():
217 expandedItems = (
218 projectBrowser.getProjectBrowser(browserName)
219 .getExpandedItemNames()
220 )
221 if expandedItems:
222 browsersList.append({
223 "Name": browserName,
224 "ExpandedItems": expandedItems,
225 })
226 sessionDict["ProjectBrowserStates"] = browsersList
227
228 try:
229 jsonString = json.dumps(sessionDict, indent=2)
230 with open(filename, "w") as f:
231 f.write(jsonString)
232 except (TypeError, EnvironmentError) as err:
233 with E5OverridenCursor():
234 E5MessageBox.critical(
235 None,
236 self.tr("Save Session"),
237 self.tr(
238 "<p>The session file <b>{0}</b> could not be"
239 " written.</p><p>Reason: {1}</p>"
240 ).format(filename, str(err))
241 )
242 return False
243
244 return True
245
246 def readFile(self, filename: str) -> bool:
247 """
248 Public method to read the session data from a session JSON file.
249
250 @param filename name of the project file
251 @type str
252 @return flag indicating a successful read
253 @rtype bool
254 """
255 try:
256 with open(filename, "r") as f:
257 jsonString = f.read()
258 sessionDict = json.loads(jsonString)
259 except (EnvironmentError, json.JSONDecodeError) as err:
260 E5MessageBox.critical(
261 None,
262 self.tr("Read Debugger Properties"),
263 self.tr(
264 "<p>The project debugger properties file <b>{0}</b>"
265 " could not be read.</p><p>Reason: {1}</p>"
266 ).format(filename, str(err))
267 )
268 return False
269
270 # get references to objects we need
271 project = e5App().getObject("Project")
272 projectBrowser = e5App().getObject("ProjectBrowser")
273 multiProject = e5App().getObject("MultiProject")
274 vm = e5App().getObject("ViewManager")
275 dbg = e5App().getObject("DebugUI")
276 dbs = e5App().getObject("DebugServer")
277
278 # step 1: multi project and project
279 if sessionDict["MultiProject"]:
280 multiProject.openMultiProject(sessionDict["MultiProject"], False)
281 if sessionDict["Project"]:
282 project.openProject(sessionDict["Project"], False)
283
284 # step 2: (project) filenames and the active editor
285 vm.setSplitOrientation(sessionDict["ViewManagerSplits"]["Orientation"])
286 vm.setSplitCount(sessionDict["ViewManagerSplits"]["Count"])
287
288 editorsDict = {}
289 for editorDict in sessionDict["Editors"]:
290 if editorDict["Clone"] and editorDict["Filename"] in editorsDict:
291 editor = editorsDict[editorDict["Filename"]]
292 ed = vm.newEditorView(
293 editorDict["Filename"], editor, editor.getFileType(),
294 indexes=(editorDict["Splitindex"],
295 editorDict["Editorindex"])
296 )
297 else:
298 ed = vm.openSourceFile(
299 editorDict["Filename"],
300 indexes=(editorDict["Splitindex"],
301 editorDict["Editorindex"])
302 )
303 editorsDict[editorDict["Filename"]] = ed
304 if ed is not None:
305 ed.zoomTo(editorDict["Zoom"])
306 if editorDict["Folds"]:
307 ed.recolor()
308 ed.setContractedFolds(editorDict["Folds"])
309 ed.setCursorPosition(*editorDict["Cursor"])
310
311 # step 3: breakpoints
312 bpModel = dbs.getBreakPointModel()
313 bpModel.addBreakPoints(sessionDict["Breakpoints"])
314
315 # step 4: watch expressions
316 wpModel = dbs.getWatchPointModel()
317 wpModel.addWatchPoints(sessionDict["Watchpoints"])
318
319 # step 5: debug info
320 debugInfoDict = sessionDict["DebugInfo"]
321 dbg.lastUsedVenvName = debugInfoDict["VirtualEnv"]
322 dbg.setArgvHistory(debugInfoDict["CommandLine"])
323 dbg.setWdHistory(debugInfoDict["WorkingDirectory"])
324 dbg.setEnvHistory(debugInfoDict["Environment"])
325 dbg.setExceptionReporting(debugInfoDict["ReportExceptions"])
326 dbg.setExcList(debugInfoDict["Exceptions"])
327 dbg.setExcIgnoreList(debugInfoDict["IgnoredExceptions"])
328 dbg.setAutoClearShell(debugInfoDict["AutoClearShell"])
329 dbg.setTracePython(debugInfoDict["TracePython"])
330 dbg.setAutoContinue(debugInfoDict["AutoContinue"])
331 dbg.setEnableMultiprocess(debugInfoDict["EnableMultiprocess"])
332 dbg.setMultiprocessNoDebugHistory(debugInfoDict["MultiprocessNoDebug"])
333 if not self.__isGlobal:
334 project.setDbgInfo(
335 debugInfoDict["VirtualEnv"],
336 debugInfoDict["CommandLine"],
337 debugInfoDict["WorkingDirectory"],
338 debugInfoDict["Environment"],
339 debugInfoDict["ReportExceptions"],
340 debugInfoDict["Exceptions"],
341 debugInfoDict["IgnoredExceptions"],
342 debugInfoDict["AutoClearShell"],
343 debugInfoDict["TracePython"],
344 debugInfoDict["AutoContinue"],
345 debugInfoDict["EnableMultiprocess"],
346 debugInfoDict["MultiprocessNoDebug"]
347 )
348
349 # step 6: bookmarks
350 for bookmark in sessionDict["Bookmarks"]:
351 editor = vm.getOpenEditor(bookmark["Filename"])
352 if editor is not None:
353 for lineno in bookmark["Lines"]:
354 editor.toggleBookmark(lineno)
355
356 # step 7: state of the various project browsers
357 for browserState in sessionDict["ProjectBrowserStates"]:
358 browser = projectBrowser.getProjectBrowser(browserState["Name"])
359 if browser is not None:
360 browser.expandItemsByName(browserState["ExpandedItems"])
361
362 # step 8: active window
363 vm.openFiles(sessionDict["ActiveWindow"]["Filename"])
364 ed = vm.getOpenEditor(sessionDict["ActiveWindow"]["Filename"])
365 if ed is not None:
366 ed.setCursorPosition(*sessionDict["ActiveWindow"]["Cursor"])
367 ed.ensureCursorVisible()
368
369 return True

eric ide

mercurial