Throw more informative error classes from perf.
[pdm.git] / pdm / cli.py
index 1d83920..df04883 100644 (file)
@@ -23,7 +23,7 @@ def resolve(spec):
             p = spec.rindex(":")
             first, second = spec[:p], spec[p + 1:]
             if "/" in second:
             p = spec.rindex(":")
             first, second = spec[:p], spec[p + 1:]
             if "/" in second:
-                import sshsock
+                from . import sshsock
                 sk = sshsock.sshsocket(first, second)
             else:
                 sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                 sk = sshsock.sshsocket(first, second)
             else:
                 sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
@@ -64,41 +64,49 @@ class client(object):
         the select() method).
         """
         self.sk = resolve(sk)
         the select() method).
         """
         self.sk = resolve(sk)
-        self.buf = ""
+        self.buf = b""
         line = self.readline()
         line = self.readline()
-        if line != "+PDM1":
+        if line != b"+PDM1":
             raise protoerr("Illegal protocol signature")
         if proto is not None:
             self.select(proto)
 
             raise protoerr("Illegal protocol signature")
         if proto is not None:
             self.select(proto)
 
+    @property
+    def closed(self):
+        return self.sk is None
+
     def close(self):
         """Close this connection"""
     def close(self):
         """Close this connection"""
-        self.sk.close()
+        if self.sk is not None:
+            self.sk.close()
+            self.sk = None
 
     def fileno(self):
         """Return the file descriptor of the underlying socket."""
 
     def fileno(self):
         """Return the file descriptor of the underlying socket."""
-        return self.sk.fileno()
+        return self.sk.fileno() if self.sk else None
 
     def readline(self):
         """Read a single NL-terminated line and return it."""
         while True:
 
     def readline(self):
         """Read a single NL-terminated line and return it."""
         while True:
-            p = self.buf.find("\n")
+            p = self.buf.find(b"\n")
             if p >= 0:
                 ret = self.buf[:p]
                 self.buf = self.buf[p + 1:]
                 return ret
             ret = self.sk.recv(1024)
             if p >= 0:
                 ret = self.buf[:p]
                 self.buf = self.buf[p + 1:]
                 return ret
             ret = self.sk.recv(1024)
-            if ret == "":
+            if ret == b"":
                 return None
             self.buf += ret
 
     def select(self, proto):
         """Negotiate the given subprotocol with the server"""
                 return None
             self.buf += ret
 
     def select(self, proto):
         """Negotiate the given subprotocol with the server"""
-        if "\n" in proto:
+        if isinstance(proto, str):
+            proto = proto.encode("ascii")
+        if b"\n" in proto:
             raise Exception("Illegal protocol specified: %r" % proto)
             raise Exception("Illegal protocol specified: %r" % proto)
-        self.sk.send(proto + "\n")
+        self.sk.send(proto + b"\n")
         rep = self.readline()
         rep = self.readline()
-        if len(rep) < 1 or rep[0] != "+":
+        if len(rep) < 1 or rep[0] != b"+"[0]:
             raise protoerr("Error reply when selecting protocol %s: %s" % (proto, rep[1:]))
 
     def __enter__(self):
             raise protoerr("Error reply when selecting protocol %s: %s" % (proto, rep[1:]))
 
     def __enter__(self):
@@ -116,7 +124,7 @@ class replclient(client):
     """
     def __init__(self, sk):
         """Create a connected client as documented in the `client' class."""
     """
     def __init__(self, sk):
         """Create a connected client as documented in the `client' class."""
-        super(replclient, self).__init__(sk, "repl")
+        super().__init__(sk, "repl")
 
     def run(self, code):
         """Run a single block of Python code on the server. Returns
 
     def run(self, code):
         """Run a single block of Python code on the server. Returns
@@ -129,16 +137,16 @@ class replclient(client):
             code = ncode
         while len(code) > 0 and code[-1] == "\n":
             code = code[:-1]
             code = ncode
         while len(code) > 0 and code[-1] == "\n":
             code = code[:-1]
-        self.sk.send(code + "\n\n")
-        buf = ""
+        self.sk.send((code + "\n\n").encode("utf-8"))
+        buf = b""
         while True:
             ln = self.readline()
         while True:
             ln = self.readline()
-            if ln[0] == " ":
-                buf += ln[1:] + "\n"
-            elif ln[0] == "+":
-                return buf
-            elif ln[0] == "-":
-                raise protoerr("Error reply: %s" % ln[1:])
+            if ln[0] == b" "[0]:
+                buf += ln[1:] + b"\n"
+            elif ln[0] == b"+"[0]:
+                return buf.decode("utf-8")
+            elif ln[0] == b"-"[0]:
+                raise protoerr("Error reply: %s" % ln[1:].decode("utf-8"))
             else:
                 raise protoerr("Illegal reply: %s" % ln)
 
             else:
                 raise protoerr("Illegal reply: %s" % ln)
 
@@ -195,7 +203,8 @@ class perfproxy(object):
 
     def close(self):
         if self.id is not None:
 
     def close(self):
         if self.id is not None:
-            self.cl.run("unbind", self.id)
+            if not self.cl.closed:
+                self.cl.run("unbind", self.id)
             del self.cl.proxies[self.id]
             self.id = None
 
             del self.cl.proxies[self.id]
             self.id = None
 
@@ -228,7 +237,7 @@ class perfclient(client):
     """
     def __init__(self, sk):
         """Create a connected client as documented in the `client' class."""
     """
     def __init__(self, sk):
         """Create a connected client as documented in the `client' class."""
-        super(perfclient, self).__init__(sk, "perf")
+        super().__init__(sk, "perf")
         self.nextid = 0
         self.lock = threading.Lock()
         self.proxies = {}
         self.nextid = 0
         self.lock = threading.Lock()
         self.proxies = {}
@@ -240,10 +249,10 @@ class perfclient(client):
         self.sk.send(buf)
 
     def recvb(self, num):
         self.sk.send(buf)
 
     def recvb(self, num):
-        buf = ""
+        buf = b""
         while len(buf) < num:
             data = self.sk.recv(num - len(buf))
         while len(buf) < num:
             data = self.sk.recv(num - len(buf))
-            if data == "":
+            if data == b"":
                 raise EOFError()
             buf += data
         return buf
                 raise EOFError()
             buf += data
         return buf
@@ -322,7 +331,7 @@ class perfclient(client):
         used by the server process.
 
         The proxy objects returned by this function are cached and the
         used by the server process.
 
         The proxy objects returned by this function are cached and the
-        same object are returned the next time the same name is
+        same object is returned the next time the same name is
         requested, which means that they are kept live until the
         client connection is closed.
         """
         requested, which means that they are kept live until the
         client connection is closed.
         """