Corrected some issues and improved some existing code with respect to eric-ide server use. server

Fri, 08 Mar 2024 15:30:23 +0100

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Fri, 08 Mar 2024 15:30:23 +0100
branch
server
changeset 10630
552a790fd9bc
parent 10629
b0d14cba79b1
child 10631
00f5aae565a3

Corrected some issues and improved some existing code with respect to eric-ide server use.

src/eric7/DataViews/PyCoverageDialog.py file | annotate | diff | comparison | revisions
src/eric7/Debugger/DebugUI.py file | annotate | diff | comparison | revisions
src/eric7/Debugger/DebuggerInterfaceNone.py file | annotate | diff | comparison | revisions
src/eric7/Debugger/DebuggerInterfacePython.py file | annotate | diff | comparison | revisions
src/eric7/Debugger/StartDialog.py file | annotate | diff | comparison | revisions
src/eric7/EricWidgets/EricPathPickerDialog.py file | annotate | diff | comparison | revisions
src/eric7/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleCheckerDialog.py file | annotate | diff | comparison | revisions
src/eric7/Plugins/CheckerPlugins/SyntaxChecker/SyntaxCheckerDialog.py file | annotate | diff | comparison | revisions
src/eric7/Plugins/PluginCodeStyleChecker.py file | annotate | diff | comparison | revisions
src/eric7/QScintilla/Shell.py file | annotate | diff | comparison | revisions
src/eric7/RemoteServer/EricServer.py file | annotate | diff | comparison | revisions
src/eric7/RemoteServer/EricServerCoverageRequestHandler.py file | annotate | diff | comparison | revisions
src/eric7/RemoteServer/EricServerDebuggerRequestHandler.py file | annotate | diff | comparison | revisions
src/eric7/RemoteServer/EricServerFileSystemRequestHandler.py file | annotate | diff | comparison | revisions
src/eric7/RemoteServerInterface/EricServerFileDialog.py file | annotate | diff | comparison | revisions
src/eric7/RemoteServerInterface/EricServerInterface.py file | annotate | diff | comparison | revisions
src/eric7/UI/UserInterface.py file | annotate | diff | comparison | revisions
src/eric7/ViewManager/ViewManager.py file | annotate | diff | comparison | revisions
--- a/src/eric7/DataViews/PyCoverageDialog.py	Tue Feb 27 15:05:53 2024 +0100
+++ b/src/eric7/DataViews/PyCoverageDialog.py	Fri Mar 08 15:30:23 2024 +0100
@@ -80,10 +80,13 @@
         self.resultList.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
         self.resultList.customContextMenuRequested.connect(self.__showContextMenu)
 
-        # eric-ide server interface
+        # eric-ide server interfaces
         self.__serverCoverageInterface = (
             ericApp().getObject("EricServer").getServiceInterface("Coverage")
         )
+        self.__remotefsInterface = (
+            ericApp().getObject("EricServer").getServiceInterface("FileSystem")
+        )
 
     def __format_lines(self, lines):
         """
--- a/src/eric7/Debugger/DebugUI.py	Tue Feb 27 15:05:53 2024 +0100
+++ b/src/eric7/Debugger/DebugUI.py	Fri Mar 08 15:30:23 2024 +0100
@@ -2565,6 +2565,14 @@
             scriptName = self.lastDebuggedFile
         else:
             scriptName = ""
+        if (
+            scriptName
+            and FileSystemUtilities.isRemoteFileName(scriptName)
+            and not self.ui.isEricServerConnected()
+        ):
+            self.__showNotConnectedWarning(title=cap, name=scriptName)
+            return
+
         dlg = StartDialog(
             cap,
             self.lastUsedVenvName,
@@ -2661,7 +2669,7 @@
                 FileSystemUtilities.isRemoteFileName(fn)
                 and not self.ui.isEricServerConnected()
             ):
-                self.__showNotConnectedWarning(title=cap)
+                self.__showNotConnectedWarning(title=cap, name=fn)
                 return
 
             # save the filename for use by the restart method
@@ -3205,18 +3213,20 @@
         """
         return self.debugServer.getProjectEnvironmentString()
 
-    def __showNotConnectedWarning(self, title):
+    def __showNotConnectedWarning(self, title, name=""):
         """
         Private method to show a warning about a not connected eric-ide server.
 
         @param title title for the dialog
         @type str
+        @param name name of the file (defaults to "")
+        @type str (optional)
         """
         EricMessageBox.warning(
             None,
             title,
             self.tr(
-                "<p>The selected file is located on an eric-ide server but no such"
-                " server is connected. Aborting...</p>"
-            ),
+                "<p>The selected file <b>{0}</b> is located on an eric-ide server but"
+                " no such server is connected. Aborting...</p>"
+            ).format(name),
         )
--- a/src/eric7/Debugger/DebuggerInterfaceNone.py	Tue Feb 27 15:05:53 2024 +0100
+++ b/src/eric7/Debugger/DebuggerInterfaceNone.py	Fri Mar 08 15:30:23 2024 +0100
@@ -46,6 +46,7 @@
         originalPathString,
         workingDir=None,
         configOverride=None,
+        startRemote=False,
     ):
         """
         Public method to start a remote Python interpreter.
@@ -64,6 +65,9 @@
         @param configOverride dictionary containing the global config override
             data
         @type dict
+        @param startRemote flag indicating to start the client via an eric-ide server
+            (defaults to False)
+        @type bool (optional)
         @return client process object, a flag to indicate a network connection
             and the name of the interpreter in case of a local execution
         @rtype tuple of (QProcess, bool, str)
@@ -78,6 +82,7 @@
         originalPathString,
         workingDir=None,
         configOverride=None,
+        startRemote=False,
     ):
         """
         Public method to start a remote Python interpreter for a project.
@@ -96,6 +101,9 @@
         @param configOverride dictionary containing the global config override
             data
         @type dict
+        @param startRemote flag indicating to start the client via an eric-ide server
+            (defaults to False)
+        @type bool (optional)
         @return client process object, a flag to indicate a network connection
             and the name of the interpreter in case of a local execution
         @rtype tuple of (QProcess, bool, str)
--- a/src/eric7/Debugger/DebuggerInterfacePython.py	Tue Feb 27 15:05:53 2024 +0100
+++ b/src/eric7/Debugger/DebuggerInterfacePython.py	Fri Mar 08 15:30:23 2024 +0100
@@ -231,7 +231,7 @@
             # TODO change this once server environment definitions are supported
             startRemote = True
             venvName = self.debugServer.getEricServerEnvironmentString()
-            interpreter = ""
+            interpreter = ""  # use the interpreter of the server
         else:
             if not venvName:
                 venvName = Preferences.getDebugger("Python3VirtualEnv")
@@ -501,8 +501,6 @@
             and the name of the interpreter in case of a local execution
         @rtype tuple of (QProcess, bool, str)
         """
-        # TODO: 'startRemoteForProject()' - implement the 'startRemote' logic like
-        #       for 'startRemote'.
         global origPathEnv
 
         project = ericApp().getObject("Project")
@@ -525,21 +523,36 @@
             else ""
         )
 
-        if venvName and venvName != self.debugServer.getProjectEnvironmentString():
-            venvManager = ericApp().getObject("VirtualEnvManager")
-            interpreter = venvManager.getVirtualenvInterpreter(venvName)
-            execPath = venvManager.getVirtualenvExecPath(venvName)
+        if (
+            startRemote is True
+            or (
+                startRemote is None
+                and (
+                    venvName == self.debugServer.getEricServerEnvironmentString()
+                    or self.__ericServerDebugging
+                )
+            )
+        ) and ericApp().getObject("EricServer").isServerConnected():
+            # TODO change this once server environment definitions are supported
+            startRemote = True
+            venvName = self.debugServer.getEricServerEnvironmentString()
+            interpreter = ""  # use the interpreter of the server
         else:
-            venvName = project.getProjectVenv()
-            execPath = project.getProjectExecPath()
-            interpreter = project.getProjectInterpreter()
-        if interpreter == "":
-            EricMessageBox.critical(
-                None,
-                self.tr("Start Debugger"),
-                self.tr("""<p>No suitable Python3 environment configured.</p>"""),
-            )
-            return None, self.__isNetworked, ""
+            if venvName and venvName != self.debugServer.getProjectEnvironmentString():
+                venvManager = ericApp().getObject("VirtualEnvManager")
+                interpreter = venvManager.getVirtualenvInterpreter(venvName)
+                execPath = venvManager.getVirtualenvExecPath(venvName)
+            else:
+                venvName = project.getProjectVenv()
+                execPath = project.getProjectExecPath()
+                interpreter = project.getProjectInterpreter()
+            if interpreter == "":
+                EricMessageBox.critical(
+                    None,
+                    self.tr("Start Debugger"),
+                    self.tr("""<p>No suitable Python3 environment configured.</p>"""),
+                )
+                return None, self.__isNetworked, ""
 
         self.__inShutdown = False
 
@@ -603,6 +616,27 @@
                 return None, self.__isNetworked, ""
 
         # TODO: add server debugging for projects
+        elif startRemote and self.__ericServerDebuggerInterface is not None:
+            # debugging via an eric-ide server
+            self.translate = self.__ericServerTranslation
+            self.__ericServerDebugging = True
+
+            args = []
+            if noencoding:
+                args.append(noencoding)
+            if multiprocessEnabled:
+                args.append(multiprocessEnabled)
+            if callTraceOptimization:
+                args.append(callTraceOptimization)
+            self.__ericServerDebuggerInterface.startClient(
+                interpreter,
+                originalPathString,
+                args,
+                workingDir=workingDir,
+            )
+            self.__startedVenv = venvName
+
+            return None, self.__isNetworked, ""
 
         else:
             # local debugging code below
--- a/src/eric7/Debugger/StartDialog.py	Tue Feb 27 15:05:53 2024 +0100
+++ b/src/eric7/Debugger/StartDialog.py	Fri Mar 08 15:30:23 2024 +0100
@@ -16,6 +16,7 @@
 from eric7 import Preferences
 from eric7.EricWidgets.EricApplication import ericApp
 from eric7.EricWidgets.EricPathPicker import EricPathPickerModes
+from eric7.SystemUtilities import FileSystemUtilities
 
 from .Ui_StartDialog import Ui_StartDialog
 
@@ -203,6 +204,13 @@
         self.scriptnamePicker.addItems(scriptsList)
         self.scriptnamePicker.setText(scriptName)
 
+        self.scriptnamePicker.setRemote(
+            FileSystemUtilities.isRemoteFileName(scriptName)
+        )
+        self.workdirPicker.setRemote(
+            FileSystemUtilities.isRemoteFileName(scriptName)
+        )
+
         if dialogMode == StartDialogMode.Debug:
             enableMultiprocessGlobal = Preferences.getDebugger("MultiProcessEnabled")
             self.tracePythonCheckBox.setChecked(tracePython)
--- a/src/eric7/EricWidgets/EricPathPickerDialog.py	Tue Feb 27 15:05:53 2024 +0100
+++ b/src/eric7/EricWidgets/EricPathPickerDialog.py	Fri Mar 08 15:30:23 2024 +0100
@@ -78,6 +78,15 @@
         """
         self.__pathPicker.setMode(mode)
 
+    def setPickerRemote(self, remote):
+        """
+        Public method to set the remote mode of the path picker.
+
+        @param remote flag indicating the remote mode
+        @type bool
+        """
+        self.__pathPicker.setRemote(remote)
+
     def setPickerFilters(self, filters):
         """
         Public method to set the filters of the path picker.
@@ -134,6 +143,7 @@
     strPath=None,
     defaultDirectory=None,
     filters=None,
+    remote=False,
 ):
     """
     Function to get a file or directory path from the user.
@@ -153,6 +163,8 @@
     @type str (optional)
     @param filters list of file filters (defaults to None)
     @type list of str (optional)
+    @param remote flag indicating the remote mode (defaults to False)
+    @type bool (optional)
     @return tuple containing the entered path and a flag indicating that the
         user pressed the OK button
     @rtype tuple of (str, bool)
@@ -164,6 +176,7 @@
     if label:
         dlg.setLabelText(label)
     dlg.setPickerMode(mode)
+    dlg.setPickerRemote(remote)
     if strPath:
         dlg.setPickerPath(strPath)
     if defaultDirectory:
--- a/src/eric7/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleCheckerDialog.py	Tue Feb 27 15:05:53 2024 +0100
+++ b/src/eric7/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleCheckerDialog.py	Fri Mar 08 15:30:23 2024 +0100
@@ -1579,7 +1579,7 @@
             return
 
         if item.parent():
-            fn = os.path.abspath(item.data(0, self.filenameRole))
+            fn = item.data(0, self.filenameRole)
             lineno = item.data(0, self.lineRole)
             position = item.data(0, self.positionRole)
             message = item.data(0, self.messageRole)
@@ -1621,7 +1621,7 @@
         for index in selectedIndexes:
             itm = self.resultList.topLevelItem(index)
             if itm.data(0, self.filenameRole) is not None:
-                fn = os.path.abspath(itm.data(0, self.filenameRole))
+                fn = itm.data(0, self.filenameRole)
                 vm.openSourceFile(fn, 1)
                 editor = vm.getOpenEditor(fn)
                 editor.clearStyleWarnings()
@@ -1639,7 +1639,7 @@
         errorFiles = []
         for index in range(self.resultList.topLevelItemCount()):
             itm = self.resultList.topLevelItem(index)
-            errorFiles.append(os.path.abspath(itm.data(0, self.filenameRole)))
+            errorFiles.append(itm.data(0, self.filenameRole))
         for file in openFiles:
             if file not in errorFiles:
                 editor = vm.getOpenEditor(file)
--- a/src/eric7/Plugins/CheckerPlugins/SyntaxChecker/SyntaxCheckerDialog.py	Tue Feb 27 15:05:53 2024 +0100
+++ b/src/eric7/Plugins/CheckerPlugins/SyntaxChecker/SyntaxCheckerDialog.py	Fri Mar 08 15:30:23 2024 +0100
@@ -298,18 +298,35 @@
         @param fn file or list of files or directory to be checked
         @type str or list of str
         """
+        isdir = isinstance(fn, str) and (
+            self.__remotefsInterface.isdir(fn)
+            if FileSystemUtilities.isRemoteFileName(fn)
+            else os.path.isdir(fn)
+        )
+
         if isinstance(fn, list):
             files = fn
-        elif os.path.isdir(fn):
-            files = FileSystemUtilities.direntries(
-                fn,
-                filesonly=True,
-                pattern=[
-                    "*{0}".format(ext)
-                    for ext in self.syntaxCheckService.getExtensions()
-                ],
-                followsymlinks=False,
-            )
+        elif isdir:
+            if FileSystemUtilities.isRemoteFileName(fn):
+                files = self.__remotefsInterface.direntries(
+                    fn,
+                    filesonly=True,
+                    pattern=[
+                        "*{0}".format(ext)
+                        for ext in self.syntaxCheckService.getExtensions()
+                    ],
+                    followsymlinks=False,
+                )
+            else:
+                files = FileSystemUtilities.direntries(
+                    fn,
+                    filesonly=True,
+                    pattern=[
+                        "*{0}".format(ext)
+                        for ext in self.syntaxCheckService.getExtensions()
+                    ],
+                    followsymlinks=False,
+                )
         else:
             files = [fn]
 
@@ -364,13 +381,25 @@
             self.checkProgress.setVisible(True)
             QApplication.processEvents()
 
+            isdir = isinstance(fn, str) and (
+                self.__remotefsInterface.isdir(fn)
+                if FileSystemUtilities.isRemoteFileName(fn)
+                else os.path.isdir(fn)
+            )
+
             if isinstance(fn, list):
                 self.files = fn
-            elif os.path.isdir(fn):
+            elif isdir:
                 self.files = []
                 for ext in self.syntaxCheckService.getExtensions():
                     self.files.extend(
-                        FileSystemUtilities.direntries(fn, True, "*{0}".format(ext), 0)
+                        self.__remotefsInterface.direntries(
+                            fn, True, "*{0}".format(ext), False
+                        )
+                        if FileSystemUtilities.isRemoteFileName(fn)
+                        else FileSystemUtilities.direntries(
+                            fn, True, "*{0}".format(ext), False
+                        )
                     )
             else:
                 self.files = [fn]
@@ -468,8 +497,8 @@
 
             try:
                 source = (
-                    self.__remotefsInterface.readEncodedFile(self.filename)[0]
-                    if FileSystemUtilities.isRemoteFileName(self.filename)
+                    self.__remotefsInterface.readEncodedFile(filename)[0]
+                    if FileSystemUtilities.isRemoteFileName(filename)
                     else Utilities.readEncodedFile(filename)[0]
                 )
                 source = Utilities.normalizeCode(source)
@@ -699,7 +728,7 @@
         vm = ericApp().getObject("ViewManager")
 
         if itm.parent():
-            fn = os.path.abspath(itm.data(0, self.filenameRole))
+            fn = itm.data(0, self.filenameRole)
             lineno = itm.data(0, self.lineRole)
             index = itm.data(0, self.indexRole)
             error = itm.data(0, self.errorRole)
@@ -712,7 +741,7 @@
             else:
                 editor.toggleSyntaxError(lineno, index, True, error, show=True)
         else:
-            fn = os.path.abspath(itm.data(0, self.filenameRole))
+            fn = itm.data(0, self.filenameRole)
             vm.openSourceFile(fn)
             editor = vm.getOpenEditor(fn)
             for index in range(itm.childCount()):
@@ -744,7 +773,7 @@
         for index in selectedIndexes:
             itm = self.resultList.topLevelItem(index)
             if itm.data(0, self.filenameRole) is not None:
-                fn = os.path.abspath(itm.data(0, self.filenameRole))
+                fn = itm.data(0, self.filenameRole)
                 vm.openSourceFile(fn, 1)
                 editor = vm.getOpenEditor(fn)
                 editor.clearSyntaxError()
@@ -764,7 +793,7 @@
         errorFiles = []
         for index in range(self.resultList.topLevelItemCount()):
             itm = self.resultList.topLevelItem(index)
-            errorFiles.append(os.path.abspath(itm.data(0, self.filenameRole)))
+            errorFiles.append(itm.data(0, self.filenameRole))
         for fn in vm.getOpenFilenames():
             if fn not in errorFiles:
                 editor = vm.getOpenEditor(fn)
--- a/src/eric7/Plugins/PluginCodeStyleChecker.py	Tue Feb 27 15:05:53 2024 +0100
+++ b/src/eric7/Plugins/PluginCodeStyleChecker.py	Fri Mar 08 15:30:23 2024 +0100
@@ -476,7 +476,6 @@
         if menuName == "Checks":
             if self.__editorAct not in menu.actions():
                 menu.addAction(self.__editorAct)
-            # TODO: disable the action for eric-ide server files
             self.__editorAct.setEnabled(editor.isPyFile())
 
     def __editorCodeStyleCheck(self):
--- a/src/eric7/QScintilla/Shell.py	Tue Feb 27 15:05:53 2024 +0100
+++ b/src/eric7/QScintilla/Shell.py	Fri Mar 08 15:30:23 2024 +0100
@@ -34,6 +34,7 @@
 from eric7.EricWidgets import EricFileDialog, EricMessageBox
 from eric7.EricWidgets.EricApplication import ericApp
 from eric7.EricWidgets.EricSimpleHelpDialog import EricSimpleHelpDialog
+from eric7.SystemUtilities import FileSystemUtilities
 from eric7.UI.SearchWidget import SearchWidget
 
 from . import Lexers
@@ -2628,8 +2629,12 @@
         Private slot to start the shell for the opened project.
         """
         if Preferences.getProject("RestartShellForProject"):
+            ppath = self.__project.getProjectPath()
             self.dbs.startClient(
-                False, forProject=True, workingDir=self.__project.getProjectPath()
+                False,
+                forProject=True,
+                workingDir=ppath,
+                startRemote=FileSystemUtilities.isRemoteFileName(ppath)
             )
             self.__currentWorkingDirectory = self.__project.getProjectPath()
             self.__getBanner()
--- a/src/eric7/RemoteServer/EricServer.py	Tue Feb 27 15:05:53 2024 +0100
+++ b/src/eric7/RemoteServer/EricServer.py	Fri Mar 08 15:30:23 2024 +0100
@@ -73,7 +73,6 @@
             self.__coverageRequestHandler.handleRequest,
         )
 
-        # TODO: 'Project' handler not implemented yet
         # TODO: implement an 'EditorConfig' handler (?)
 
         self.__address = ("", port)
@@ -203,7 +202,7 @@
             return {}
 
         jsonStr = data.decode("utf8", "backslashreplace")
-        # - print("Eric Server Receive:", jsonStr)  # for debugging
+        print("Eric Server Receive:", jsonStr)  # for debugging
         try:
             return json.loads(jsonStr.strip())
         except (TypeError, ValueError) as err:
@@ -281,8 +280,10 @@
 
         self.__socket.listen(0)
         self.__socket.setblocking(False)
-        print(f"Listening for 'eric-ide' connections on {self.__socket.getsockname()}")
-        # noqa: M801
+        address = self.__socket.getsockname()
+        print(  # noqa: M801
+            f"Listening for 'eric-ide' connections on {address[0]}, port {address[1]}"
+        )
         data = types.SimpleNamespace(
             name="server", acceptHandler=self.__acceptIdeConnection
         )
@@ -320,10 +321,10 @@
         """
         connection, address = sock.accept()  # Should be ready to read
         if self.__connection is None:
-            print(f"'eric-ide' connection from {address[0]},  port {address[1]}")
+            print(f"'eric-ide' connection from {address[0]}, port {address[1]}")
             # noqa: M801
             self.__connection = connection
-            self.__connection.setblocking(False)
+            ##self.__connection.setblocking(False)
             data = types.SimpleNamespace(
                 name="eric-ide", address=address, handler=self.__serviceIdeConnection
             )
@@ -333,7 +334,7 @@
             self.__unregisterIdeSocket()
         else:
             print(  # noqa: M801
-                f"'eric-ide' connection from {address[0]},  port {address[1]} rejected"
+                f"'eric-ide' connection from {address[0]}, port {address[1]} rejected"
             )
             connection.close()
 
@@ -347,9 +348,9 @@
         if self.__connection is not None:
             self.__selector.unregister(self.__connection)
             try:
+                address = self.__connection.getpeername()
                 print(  # noqa: M801
-                    f"Closing 'eric-ide' connection to"
-                    f" {self.__connection.getpeername()}."
+                    f"Closing 'eric-ide' connection to {address[0]}, port {address[1]}."
                 )
                 self.__connection.shutdown(socket.SHUT_RDWR)
                 self.__connection.close()
--- a/src/eric7/RemoteServer/EricServerCoverageRequestHandler.py	Tue Feb 27 15:05:53 2024 +0100
+++ b/src/eric7/RemoteServer/EricServerCoverageRequestHandler.py	Fri Mar 08 15:30:23 2024 +0100
@@ -125,7 +125,6 @@
         @return dictionary containing the reply data
         @rtype dict
         """
-        # TODO: not implemented yet
         if self.__cover is None:
             return {
                 "ok": False,
@@ -152,7 +151,6 @@
         @return dictionary containing the reply data
         @rtype dict
         """
-        # TODO: not implemented yet
         if self.__cover is None:
             return {
                 "ok": False,
--- a/src/eric7/RemoteServer/EricServerDebuggerRequestHandler.py	Tue Feb 27 15:05:53 2024 +0100
+++ b/src/eric7/RemoteServer/EricServerDebuggerRequestHandler.py	Fri Mar 08 15:30:23 2024 +0100
@@ -47,6 +47,9 @@
         address = ("127.0.0.1", 0)
         self.__socket = socket.create_server(address, family=socket.AF_INET)
 
+        self.__originalPathString = os.getenv("PATH")
+
+
     def initServerSocket(self):
         """
         Public method to initialize the server socket listening for debug client
@@ -55,9 +58,10 @@
         # listen on the debug server socket
         self.__socket.listen()
         self.__socket.setblocking(False)
+        address = self.__socket.getsockname()
         print(  # noqa: M801
-            f"Listening for 'debug client' connections on"
-            f" {self.__socket.getsockname()}"
+            f"Listening for 'Debug Client' connections on"
+            f" {address[0]}, port {address[1]}"
         )
         data = types.SimpleNamespace(
             name="server", acceptHandler=self.__acceptDbgClientConnection
@@ -106,7 +110,7 @@
         @type socket.socket
         """
         connection, address = sock.accept()  # Should be ready to read
-        print(f"'Debug client' connection from {address[0]},  port {address[1]}")
+        print(f"'Debug Client' connection from {address[0]}, port {address[1]}")
         # noqa: M801
         connection.setblocking(False)
         self.__pendingConnections.append(connection)
@@ -173,6 +177,11 @@
         """
         self.__server.getSelector().unregister(sock)
 
+        address = sock.getpeername()
+        print(
+            f"'Debug Client' connection from {address[0]}, port {address[1]} closed."
+        )
+        # noqa: M801
         for debuggerId in list(self.__connections):
             if self.__connections[debuggerId] is sock:
                 del self.__connections[debuggerId]
@@ -291,8 +300,18 @@
         args.extend(params["arguments"])
         args.extend([str(port), "True", ipaddr])
 
+        workingDir = params["working_dir"] if params["working_dir"] else None
+
+        clientEnv = os.environ.copy()
+        if self.__originalPathString:
+            clientEnv["PATH"] = self.__originalPathString
+
         self.__client = subprocess.Popen(
-            args, stdout=subprocess.PIPE, stderr=subprocess.PIPE
+            args,
+            stdout=subprocess.PIPE,
+            stderr=subprocess.PIPE,
+            cwd=workingDir,
+            env=clientEnv,
         )
 
     def __stopClient(self, params):  # noqa: U100
@@ -327,9 +346,9 @@
             for sock in self.__connections.values():
                 self.__server.sendJsonCommand(jsonStr, sock)
         else:
-            try:
+            try:  # noqa: Y105
                 sock = self.__connections[debuggerId]
                 self.__server.sendJsonCommand(jsonStr, sock)
             except KeyError:
-                print(f"Command for unknown debugger ID '{debuggerId}' received.")
-                # noqa: M801
+                pass
+                # - print(f"Command for unknown debugger ID '{debuggerId}' received.")
--- a/src/eric7/RemoteServer/EricServerFileSystemRequestHandler.py	Tue Feb 27 15:05:53 2024 +0100
+++ b/src/eric7/RemoteServer/EricServerFileSystemRequestHandler.py	Fri Mar 08 15:30:23 2024 +0100
@@ -140,23 +140,7 @@
             directory = os.getcwd()
 
         try:
-            listing = []
-            for dirEntry in os.scandir(directory):
-                filestat = dirEntry.stat()
-                entry = {
-                    "name": dirEntry.name,
-                    "path": dirEntry.path,
-                    "is_dir": dirEntry.is_dir(),
-                    "is_file": dirEntry.is_file(),
-                    "is_link": dirEntry.is_symlink(),
-                    "mode": filestat.st_mode,
-                    "mode_str": stat.filemode(filestat.st_mode),
-                    "size": filestat.st_size,
-                    "mtime": time.strftime(
-                        "%Y-%m-%d %H:%M:%S", time.localtime(filestat.st_mtime)
-                    ),
-                }
-                listing.append(entry)
+            listing = self.__scanDirectory(directory, params["recursive"])
 
             return {
                 "ok": True,
@@ -170,6 +154,43 @@
                 "error": str(err),
             }
 
+    def __scanDirectory(self, directory, recursive, withHidden=False):
+        """
+        Private method to scan a given directory.
+
+        @param directory path of the directory to be scanned
+        @type str
+        @param recursive flag indicating a recursive scan
+        @type bool
+        @param withHidden flag indicating to list hidden files and directories
+            as well (defaults to False)
+        @type bool (optional)
+        """
+        listing = []
+        for dirEntry in os.scandir(directory):
+            filestat = dirEntry.stat()
+            if withHidden or not dirEntry.name.startswith("."):
+                entry = {
+                    "name": dirEntry.name,
+                    "path": dirEntry.path,
+                    "is_dir": dirEntry.is_dir(),
+                    "is_file": dirEntry.is_file(),
+                    "is_link": dirEntry.is_symlink(),
+                    "mode": filestat.st_mode,
+                    "mode_str": stat.filemode(filestat.st_mode),
+                    "size": filestat.st_size,
+                    "mtime": filestat.st_mtime,
+                    "mtime_str": time.strftime(
+                        "%Y-%m-%d %H:%M:%S", time.localtime(filestat.st_mtime)
+                    ),
+                }
+                listing.append(entry)
+                
+                if entry["is_dir"] and recursive:
+                    listing += self.__scanDirectory(dirEntry.path, recursive)
+
+        return listing
+
     def __stat(self, params):
         """
         Private method to get the status of a file.
@@ -327,8 +348,9 @@
             with open(filename, "wb"):
                 pass
 
+        newline = None if params["newline"] == "<<none>>" else params["newline"]
         try:
-            with open(filename, "rb") as f:
+            with open(filename, "rb", newline=newline) as f:
                 data = f.read()
             return {
                 "ok": True,
@@ -369,8 +391,9 @@
                 os.rename(filename, backupFilename)
 
         # 2. write the data to the file and reset the permissions
+        newline = None if params["newline"] == "<<none>>" else params["newline"]
         try:
-            with open(filename, "wb") as f:
+            with open(filename, "wb", newline=newline) as f:
                 f.write(data)
             if params["with_backup"] and perms_valid:
                 os.chmod(filename, permissions)
--- a/src/eric7/RemoteServerInterface/EricServerFileDialog.py	Tue Feb 27 15:05:53 2024 +0100
+++ b/src/eric7/RemoteServerInterface/EricServerFileDialog.py	Fri Mar 08 15:30:23 2024 +0100
@@ -122,9 +122,7 @@
 
         self.treeCombo.currentTextChanged.connect(self.setDirectory)
 
-        if self.__fsInterface.isfile(directory):
-            directory = self.__fsInterface.dirname(directory)
-        self.setDirectory(FileSystemUtilities.plainFileName(directory))
+        self.setDirectory(directory)
 
     def acceptMode(self):
         """
@@ -488,6 +486,11 @@
         self.__filenameCache.clear()
         self.__directoryCache.clear()
 
+        if self.__fsInterface.isfile(directory):
+            directory, basename = self.__fsInterface.split(directory)
+        else:
+            basename = ""
+
         try:
             directory, sep, dirListing = self.__fsInterface.listdir(directory)
 
@@ -528,7 +531,9 @@
                     sizeStr = dataString(dirEntry["size"], QLocale.system())
                     self.__filenameCache.append(dirEntry["name"])
                 itm = QTreeWidgetItem(
-                    self.listing, [dirEntry["name"], sizeStr, type_, dirEntry["mtime"]]
+                    self.listing, [
+                        dirEntry["name"], sizeStr, type_, dirEntry["mtime_str"]
+                    ]
                 )
                 itm.setIcon(0, EricPixmapCache.getIcon(iconName))
                 itm.setTextAlignment(1, Qt.AlignmentFlag.AlignRight)
@@ -555,7 +560,10 @@
             )
 
         # 4. update some dependent states
-        self.nameEdit.clear()
+        if basename:
+            self.nameEdit.setText(basename)
+        else:
+            self.nameEdit.clear()
         self.__updateUpButton()
 
     @pyqtSlot(QPoint)
--- a/src/eric7/RemoteServerInterface/EricServerInterface.py	Tue Feb 27 15:05:53 2024 +0100
+++ b/src/eric7/RemoteServerInterface/EricServerInterface.py	Fri Mar 08 15:30:23 2024 +0100
@@ -111,7 +111,7 @@
         try:
             return self.__serviceInterfaces[lname]
         except KeyError:
-            if lname not in ("coverage", "debugger", "filesystem", "project"):
+            if lname not in ("coverage", "debugger", "filesystem"):
                 raise ValueError(f"no such service supported ({name})")
             else:
                 # instantiate the service interface
@@ -135,9 +135,6 @@
                     )
 
                     self.__serviceInterfaces[lname] = EricServerCoverageInterface(self)
-                elif lname == "project":
-                    # TODO: 'Project Interface' not implemented yet
-                    pass
 
             return self.__serviceInterfaces[lname]
 
--- a/src/eric7/UI/UserInterface.py	Tue Feb 27 15:05:53 2024 +0100
+++ b/src/eric7/UI/UserInterface.py	Fri Mar 08 15:30:23 2024 +0100
@@ -592,13 +592,17 @@
             )
 
         self.__ericServerInterface.connectionStateChanged.connect(
+            self.project.remoteConnectionChanged
+        )
+        self.__ericServerInterface.connectionStateChanged.connect(
             self.viewmanager.remoteConnectionChanged
         )
         self.__ericServerInterface.connectionStateChanged.connect(
             self.shell.remoteConnectionChanged
         )
-        self.__ericServerInterface.connectionStateChanged.connect(
-            self.project.remoteConnectionChanged
+
+        self.__ericServerInterface.aboutToDisconnect.connect(
+            self.project.closeProject
         )
         self.__ericServerInterface.aboutToDisconnect.connect(
             self.viewmanager.closeRemoteEditors
--- a/src/eric7/ViewManager/ViewManager.py	Tue Feb 27 15:05:53 2024 +0100
+++ b/src/eric7/ViewManager/ViewManager.py	Fri Mar 08 15:30:23 2024 +0100
@@ -6122,7 +6122,7 @@
             if fn is not None and fn not in filenames:
                 # only return names of existing files
                 exists = (
-                    self.__remotefsInterface.exists(fn)
+                    True
                     if FileSystemUtilities.isRemoteFileName(fn)
                     else os.path.exists(fn)
                 )

eric ide

mercurial