X-Git-Url: http://dolda2000.com/gitweb/?a=blobdiff_plain;f=pdm%2Fsrv.py;h=80f9a260d688a438e0000a248f805c6129e64ef2;hb=HEAD;hp=128c6d9b017479885bd8b157de083e4e338d3a29;hpb=6fde0e19d966a3d83f837a035d05e2afbc20e010;p=pdm.git diff --git a/pdm/srv.py b/pdm/srv.py index 128c6d9..80f9a26 100644 --- a/pdm/srv.py +++ b/pdm/srv.py @@ -19,9 +19,9 @@ class repl(object): """REPL protocol handler Provides a read-eval-print loop. The primary client-side interface - is the pdm.cli.replclient class. Clients can send arbitrary code, - which is compiled and run on its own thread in the server process, - and output responses that are echoed back to the client. + is the L{pdm.cli.replclient} class. Clients can send arbitrary + code, which is compiled and run on its own thread in the server + process, and output responses that are echoed back to the client. Each client is provided with its own module, in which the code runs. The module is prepared with a function named `echo', which @@ -40,33 +40,36 @@ class repl(object): self.mod = types.ModuleType("repl") self.mod.echo = self.echo self.printer = pprint.PrettyPrinter(indent = 4, depth = 6) - cl.send("+REPL\n") + cl.send(b"+REPL\n") def sendlines(self, text): for line in text.split("\n"): - self.cl.send(" " + line + "\n") + self.cl.send(b" " + line.encode("utf-8") + b"\n") def echo(self, ob): self.sendlines(self.printer.pformat(ob)) def command(self, cmd): + cmd = cmd.decode("utf-8") try: try: ccode = compile(cmd, "PDM Input", "eval") except SyntaxError: ccode = compile(cmd, "PDM Input", "exec") - exec ccode in self.mod.__dict__ - self.cl.send("+OK\n") + exec(ccode, self.mod.__dict__) + self.cl.send(b"+OK\n") else: self.echo(eval(ccode, self.mod.__dict__)) - self.cl.send("+OK\n") + self.cl.send(b"+OK\n") except: - for line in traceback.format_exception(*sys.exc_info()): - self.cl.send(" " + line) - self.cl.send("+EXC\n") + lines = ("".join(traceback.format_exception(*sys.exc_info()))).split("\n") + while len(lines) > 0 and lines[-1] == "": lines = lines[:-1] + for line in lines: + self.cl.send(b" " + line.encode("utf-8") + b"\n") + self.cl.send(b"+EXC\n") def handle(self, buf): - p = buf.find("\n\n") + p = buf.find(b"\n\n") if p < 0: return buf cmd = buf[:p + 1] @@ -97,12 +100,12 @@ class perf(object): already be imported. PDM will not import new modules for clients; rather, the daemon process needs to import all modules that clients should be able to interact with. PDM itself always imports - the pdm.perf module, which contains a few basic PERF objects. See - its documentation for details. + the L{pdm.perf} module, which contains a few basic PERF + objects. See its documentation for details. The following interfaces are currently known to PERF. - * attr: + - attr: An object that implements the `attr' interface models an attribute that can be read by clients. The attribute can be anything, as long as its representation can be @@ -116,9 +119,9 @@ class perf(object): description of the attribute. Both should be idempotent. `readattr' can return any pickleable object, and `attrinfo' should return either None to indicate that it has no - description, or an instance of the pdm.perf.attrinfo class. + description, or an instance of the L{pdm.perf.attrinfo} class. - * dir: + - dir: The `dir' interface models a directory of other PERF objects. An object implementing it must implement methods called `lookup' and `listdir'. `lookup' is called with a single @@ -129,7 +132,7 @@ class perf(object): used as argument to `lookup', but the list is not required to be exhaustive and may also be empty. - * invoke: + - invoke: The `invoke' interface allows a more arbitrary form of method calls to objects implementing it. Such objects must implement a method called `invoke', which is called with one positional @@ -140,7 +143,7 @@ class perf(object): the client. In case the method name is not recognized, `invoke' should raise an AttributeError. - * event: + - event: The `event' interface allows PERF objects to notify clients of events asynchronously. Objects implementing it must implement methods called `subscribe' and `unsubscribe'. `subscribe' will @@ -150,7 +153,7 @@ class perf(object): `event' object should then call all such registered callables with a single argument describing the event. The argument could be any object that can be pickled, but should be an instance of - a subclass of the pdm.perf.event class. If `subscribe' is + a subclass of the L{pdm.perf.event} class. If `subscribe' is called with a callback object that it has already registered, it should raise a ValueError. `unsubscribe' is called with a single argument, which is a previously registered callback @@ -159,23 +162,23 @@ class perf(object): object is not, in fact, registered, a ValueError should be raised. - The pdm.perf module contains a few convenience classes which + The L{pdm.perf} module contains a few convenience classes which implements the interfaces, but PERF objects are not required to be instances of them. Any object can implement a PERF interface, as long as it does so as described above. - The pdm.cli.perfclient class is the client-side implementation. + The L{pdm.cli.perfclient} class is the client-side implementation. """ def __init__(self, cl): self.cl = cl self.odtab = {} - cl.send("+PERF1\n") + cl.send(b"+PERF1\n") self.buf = "" self.lock = threading.Lock() self.subscribed = {} def closed(self): - for id, recv in self.subscribed.iteritems(): + for id, recv in self.subscribed.items(): ob = self.odtab[id] if ob is None: continue ob, protos = ob @@ -197,7 +200,7 @@ class perf(object): raise ValueError("Object does not support PDM introspection") try: proto = ob.pdm_protocols() - except Exception, exc: + except Exception as exc: raise ValueError("PDM introspection failed", exc) self.odtab[id] = ob, proto return proto @@ -214,7 +217,7 @@ class perf(object): return try: proto = self.bindob(id, ob) - except Exception, exc: + except Exception as exc: self.send("-", exc) return self.send("+", proto) @@ -236,12 +239,12 @@ class perf(object): return try: ob = src.lookup(obnm) - except KeyError, exc: + except KeyError as exc: self.send("-", exc) return try: proto = self.bindob(tgtid, ob) - except Exception, exc: + except Exception as exc: self.send("-", exc) return self.send("+", proto) @@ -271,7 +274,7 @@ class perf(object): return try: ret = ob.readattr() - except Exception, exc: + except Exception as exc: self.send("-", Exception("Could not read attribute")) return self.send("+", ret) @@ -288,7 +291,7 @@ class perf(object): return try: self.send("+", ob.invoke(method, *args, **kwargs)) - except Exception, exc: + except Exception as exc: self.send("-", exc) def event(self, id, ob, ev): @@ -354,7 +357,7 @@ protocols["perf"] = perf class client(threading.Thread): def __init__(self, sk): - super(client, self).__init__(name = "Management client") + super().__init__(name = "Management client") self.setDaemon(True) self.sk = sk self.handler = self @@ -363,6 +366,10 @@ class client(threading.Thread): return self.sk.send(data) def choose(self, proto): + try: + proto = proto.decode("ascii") + except UnicodeError: + proto = None if proto in protocols: self.handler = protocols[proto](self) else: @@ -370,7 +377,7 @@ class client(threading.Thread): raise Exception() def handle(self, buf): - p = buf.find("\n") + p = buf.find(b"\n") if p >= 0: proto = buf[:p] buf = buf[p + 1:] @@ -379,24 +386,24 @@ class client(threading.Thread): def run(self): try: - buf = "" - self.send("+PDM1\n") + buf = b"" + self.send(b"+PDM1\n") while True: ret = self.sk.recv(1024) - if ret == "": + if ret == b"": return buf += ret while True: try: nbuf = self.handler.handle(buf) except: + #for line in traceback.format_exception(*sys.exc_info()): + # print(line) return if nbuf == buf: break buf = nbuf finally: - #for line in traceback.format_exception(*sys.exc_info()): - # print line try: self.sk.close() finally: @@ -413,7 +420,7 @@ class listener(threading.Thread): tcplistener. """ def __init__(self): - super(listener, self).__init__(name = "Management listener") + super().__init__(name = "Management listener") self.setDaemon(True) def listen(self, sk): @@ -441,14 +448,14 @@ class listener(threading.Thread): class unixlistener(listener): """Unix socket listener""" - def __init__(self, name, mode = 0600, group = None): + def __init__(self, name, mode = 0o600, group = None): """Create a listener that will bind to the Unix socket named by `name'. The socket will not actually be bound until the listener is started. The socket will be chmodded to `mode', and if `group' is given, the named group will be set as the owner of the socket. """ - super(unixlistener, self).__init__() + super().__init__() self.name = name self.mode = mode self.group = group @@ -478,7 +485,7 @@ class tcplistener(listener): the given local interface. The socket will not actually be bound until the listener is started. """ - super(tcplistener, self).__init__() + super().__init__() self.port = port self.bindaddr = bindaddr @@ -516,7 +523,7 @@ def listen(spec): last = spec if "/" in first: parts = spec.split(":") - mode = 0600 + mode = 0o600 group = None if len(parts) > 1: mode = int(parts[1], 8)