X-Git-Url: http://dolda2000.com/gitweb/?a=blobdiff_plain;f=pdm%2Fsrv.py;h=80f9a260d688a438e0000a248f805c6129e64ef2;hb=HEAD;hp=3ddc6823e1ce33ad3d54a78f7d721cac9e59aaf5;hpb=28203f3fefeaa864b8f14390b7a72d5081a94ce8;p=pdm.git diff --git a/pdm/srv.py b/pdm/srv.py index 3ddc682..2ddb9e7 100644 --- a/pdm/srv.py +++ b/pdm/srv.py @@ -10,6 +10,7 @@ which describes the functioning of the REPL and PERF protocols. import os, sys, socket, threading, grp, select import types, pprint, traceback import pickle, struct +from . import perf as mperf __all__ = ["repl", "perf", "listener", "unixlistener", "tcplistener", "listen"] @@ -19,9 +20,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 @@ -62,8 +63,10 @@ class repl(object): self.echo(eval(ccode, self.mod.__dict__)) self.cl.send(b"+OK\n") except: - for line in traceback.format_exception(*sys.exc_info()): - self.cl.send(b" " + line.encode("utf-8")) + 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): @@ -98,12 +101,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 @@ -117,9 +120,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 @@ -130,7 +133,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 @@ -141,7 +144,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 @@ -151,7 +154,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 @@ -160,12 +163,12 @@ 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 @@ -195,7 +198,7 @@ class perf(object): def bindob(self, id, ob): if not hasattr(ob, "pdm_protocols"): - raise ValueError("Object does not support PDM introspection") + raise mperf.nosuchname("Object does not support PDM introspection") try: proto = ob.pdm_protocols() except Exception as exc: @@ -206,12 +209,12 @@ class perf(object): def bind(self, id, module, obnm): resmod = sys.modules.get(module) if resmod is None: - self.send("-", ImportError("No such module: %s" % module)) + self.send("-", mperf.nosuchname("No such module: %s" % module)) return try: ob = getattr(resmod, obnm) except AttributeError: - self.send("-", AttributeError("No such object: %s" % obnm)) + self.send("-", mperf.nosuchname("No such object: %s" % obnm)) return try: proto = self.bindob(id, ob) @@ -227,7 +230,7 @@ class perf(object): return None ob, protos = ob if proto not in protos: - self.send("-", ValueError("Object does not support that protocol")) + self.send("-", mperf.nosuchproto("Object does not support that protocol: " + proto)) return None return ob @@ -238,7 +241,7 @@ class perf(object): try: ob = src.lookup(obnm) except KeyError as exc: - self.send("-", exc) + self.send("-", mperf.nosuchname(obnm)) return try: proto = self.bindob(tgtid, ob)