serve

fastdaemon server
import time
from fastcore.parallel import threaded
from pathlib import Path
from socketserver import UnixStreamServer

CmdHandler

 CmdHandler (request, client_address, server)

Run self.server.cmd with request’s argv and stdin; return stdout and stderr

CmdHandler’s primary use-case is together with a server inheriting CmdMixin, however it supports any socketserver.BaseServer that has a cmd attribute. If the server also has a pool it’s used to execute cmd.

Here’s an example of how to use CmdHandler. First, define the command. It should have no arguments itself but rather parse its arguments from sys.argv. Its return value isn’t used, instead it should write to stdout.

def _cmd():
    sys.stdout.write(sys.stdin.read()+sys.argv[1])
    sys.stderr.write('Error!')

Then define a server with a cmd attribute:

class _CmdServer(UnixStreamServer): cmd = lambda x: _cmd()

Start the server. We start it with handle_request in a separate thread:

p = Path('fdaemon.sock')
if p.exists(): p.unlink()

@threaded
def _f():
    with _CmdServer(str(p), CmdHandler) as srv: srv.handle_request()
_f()
time.sleep(0.2) # wait for server to start

…so that we can send a request and print its response:

transfer(['Hello, ', 'world!'], str(p))
len(stdin)=7 argv=['<lambda>', 'world!']
['Hello, world!', 'Error!']

CmdMixin

 CmdMixin (server_address, cmd, pool=None,
           RequestHandlerClass=<class'__main__.CmdHandler'>, timeout=None,
           **kwargs)

Socket server with a cmd and optional pool

class CmdUnixServer(CmdMixin, ThreadingUnixStreamServer): pass
p = Path('fdaemon.sock')
if p.exists(): p.unlink()

@threaded
def _f():
    with ProcessPoolExecutor() as pool, CmdUnixServer(str(p), _cmd, pool) as srv: srv.handle_request()
_f()
time.sleep(0.2) # wait for server to start
transfer(['Hello, ', 'world!'], str(p))
len(stdin)=7 argv=['_cmd', 'world!']
['Hello, world!', 'Error!']

CmdTCPServer

 CmdTCPServer (server_address, cmd, pool=None,
               RequestHandlerClass=<class'__main__.CmdHandler'>,
               timeout=None, **kwargs)

Socket server with a cmd and optional pool

A convenient wrapper to instantiate and start a CmdTCPServer that handles requests until it’s interrupted or times out. Here’s the previous example using _fastdaemon_serve. We’ve also set a timeout to avoid running forever:

host,port = 'localhost',9999

@threaded
def _f(): _fastdaemon_serve(_cmd, port, host, timeout=1)
_f()
time.sleep(0.4) # wait for server to start
transfer(['Hello, ', 'world!'], port, host)
len(stdin)=7 argv=['_cmd', 'world!']
['Hello, world!', 'Error!']
_import_cmd('nbdev.clean:nbdev_clean')
<function nbdev.clean.nbdev_clean(fname: str = None, clear_all: bool = False, disp: bool = False, stdin: bool = False)>

fastdaemon_serve

 fastdaemon_serve (cmd:str, port:int, host:str='localhost',
                   timeout:int=None)

Serve cmd on port, with optional host and timeout

Type Default Details
cmd str Module path to callable command (example: pkg.mod:obj)
port int Server port
host str localhost Server host
timeout int None Shutdown after timeout seconds without requests
!fastdaemon_serve -h
usage: fastdaemon_serve [-h] [--host HOST] [--timeout TIMEOUT] cmd port

Serve `cmd` on `port`, with optional `host` and `timeout`

positional arguments:
  cmd                Module path to callable command (example: pkg.mod:obj)
  port               Server port

optional arguments:
  -h, --help         show this help message and exit
  --host HOST        Server host (default: localhost)
  --timeout TIMEOUT  Shutdown after `timeout` seconds without requests