pytact.visualisation_webserver
1from dataclasses import asdict 2from pathlib import Path 3import argparse 4import pkg_resources 5import inflection 6from functools import partial 7 8from pytact.data_reader import data_reader 9from pytact.graph_visualize_browse import ( 10 GraphVisualizationData, GraphVisualizator, UrlMaker, Settings, GraphVisualizationOutput) 11 12import capnp 13import pytact.graph_api_capnp as graph_api_capnp 14 15from sanic import Sanic 16from sanic_ext import validate 17from sanic.worker.loader import AppLoader 18 19def post_process(output: GraphVisualizationOutput, settings: Settings): 20 result = asdict(output) 21 result['settings'] = settings 22 result['edge_labels'] = [(v, inflection.camelize(name)) for (name, v) in 23 graph_api_capnp.EdgeClassification.schema.enumerants.items()] 24 result['node_labels'] = [(v, inflection.camelize(name)) for (v, name) in 25 enumerate(list(graph_api_capnp.Graph.Node.Label.schema.union_fields))] 26 return result 27 28def create_app(dataset_path: Path) -> Sanic: 29 app = Sanic("graph-visualizer") 30 app.config.TEMPLATING_PATH_TO_TEMPLATES = pkg_resources.resource_filename('pytact', 'templates/') 31 32 @app.before_server_start 33 async def setup_dataset(app): 34 app.ctx.data_ctx = data_reader(dataset_path) 35 app.ctx.gvd = GraphVisualizationData(app.ctx.data_ctx.__enter__()) 36 @app.after_server_stop 37 async def teardown_dataset(app): 38 del app.ctx.gvd 39 app.ctx.data_ctx.__exit__(None, None, None) 40 del app.ctx.data_ctx 41 42 class SanicUrlMaker(UrlMaker): 43 44 def __init__(self, settings: Settings): 45 self.query = {k: v for k, v in asdict(settings).items() if type(v) != bool or v} 46 47 def definition(self, fname: Path, defid: int) -> str: 48 return app.url_for('definition', path=fname.with_suffix(''), defid=defid, **self.query) 49 50 def proof(self, fname: Path, defid: int) -> str: 51 return app.url_for('proof', path=fname.with_suffix(''), defid=defid, **self.query) 52 53 def outcome(self, fname: Path, defid: int, stepi: int, outcomei: int) -> str: 54 return app.url_for('outcome', path=fname.with_suffix(''), 55 defid=defid, stepi=stepi, outcomei=outcomei, **self.query) 56 57 def global_context(self, fname: Path) -> str: 58 return app.url_for('global_context', path=fname.with_suffix(''), **self.query) 59 60 def folder(self, path: Path) -> str: 61 return app.url_for('folder', path=path, **self.query) 62 63 def root_folder(self) -> str: 64 return app.url_for('root_folder', **self.query) 65 66 @app.get('/<path:path>/definition/<defid:int>/proof/step/<stepi:int>/outcome/<outcomei:int>') 67 @validate(query=Settings) 68 @app.ext.template("visualizer.html") 69 async def outcome(request, path: str, defid: str, stepi: str, outcomei: str, query: Settings): 70 gv = GraphVisualizator(app.ctx.gvd, SanicUrlMaker(query), query) 71 return post_process(gv.outcome(Path(path).with_suffix(".bin"), int(defid), int(stepi), int(outcomei)), query) 72 73 @app.get('/<path:path>/definition/<defid:int>/proof') 74 @validate(query=Settings) 75 @app.ext.template("visualizer.html") 76 async def proof(request, path: str, defid: str, query: Settings): 77 gv = GraphVisualizator(app.ctx.gvd, SanicUrlMaker(query), query) 78 return post_process(gv.proof(Path(path).with_suffix(".bin"), int(defid)), query) 79 80 @app.get('/<path:path>/definition/<defid:int>') 81 @validate(query=Settings) 82 @app.ext.template("visualizer.html") 83 async def definition(request, path: str, defid: str, query: Settings): 84 gv = GraphVisualizator(app.ctx.gvd, SanicUrlMaker(query), query) 85 return post_process(gv.definition(Path(path).with_suffix(".bin"), int(defid)), query) 86 87 @app.get('/<path:path>/context') 88 @validate(query=Settings) 89 @app.ext.template("visualizer.html") 90 async def global_context(request, path: str, query: Settings): 91 gv = GraphVisualizator(app.ctx.gvd, SanicUrlMaker(query), query) 92 return post_process(gv.global_context(Path(path).with_suffix(".bin")), query) 93 94 @app.get('/<path:path>') 95 @validate(query=Settings) 96 @app.ext.template("visualizer.html") 97 async def folder(request, path: str, query: Settings): 98 gv = GraphVisualizator(app.ctx.gvd, SanicUrlMaker(query), query) 99 return post_process(gv.folder(Path(path)), query) 100 101 @app.get('/') 102 @validate(query=Settings) 103 @app.ext.template("visualizer.html") 104 async def root_folder(request, query: Settings): 105 gv = GraphVisualizator(app.ctx.gvd, SanicUrlMaker(query), query) 106 return post_process(gv.folder(Path()), query) 107 108 return app 109 110def main(): 111 112 parser = argparse.ArgumentParser( 113 description = 'Start an interactive server that visualizes a dataset', 114 formatter_class=argparse.ArgumentDefaultsHelpFormatter) 115 116 parser.add_argument('dataset', 117 type=str, 118 help=('The location of the dataset to visualize. ' + 119 'Either a dataset directory, or a SquashFS image, ' + 120 'which will be automatically mounted.')) 121 parser.add_argument('--port', 122 type=int, 123 default=8080, 124 help='the port where the webserver should listen') 125 parser.add_argument('--hostname', 126 type=str, 127 default='0.0.0.0', 128 help='the ip or domain of the hosting machine') 129 parser.add_argument('--dev', 130 action='store_true', 131 help='run the server in development mode') 132 group = parser.add_mutually_exclusive_group() 133 group.add_argument('--fast', action='store_true', default=False, 134 help='Run the server with an optimal number of worker') 135 group.add_argument('--workers', type=int, default=1, 136 help='The number of workers to use') 137 138 args = parser.parse_args() 139 140 dataset_path = Path(args.dataset).resolve() 141 142 loader = AppLoader(factory=partial(create_app, dataset_path)) 143 app = loader.load() 144 app.prepare(host=args.hostname, port=args.port, dev=args.dev, fast=args.fast, workers=args.workers) 145 Sanic.serve(primary=app, app_loader=loader) 146 147if __name__ == '__main__': 148 main()
def
post_process( output: pytact.graph_visualize_browse.GraphVisualizationOutput, settings: pytact.graph_visualize_browse.Settings):
20def post_process(output: GraphVisualizationOutput, settings: Settings): 21 result = asdict(output) 22 result['settings'] = settings 23 result['edge_labels'] = [(v, inflection.camelize(name)) for (name, v) in 24 graph_api_capnp.EdgeClassification.schema.enumerants.items()] 25 result['node_labels'] = [(v, inflection.camelize(name)) for (v, name) in 26 enumerate(list(graph_api_capnp.Graph.Node.Label.schema.union_fields))] 27 return result
def
create_app(dataset_path: pathlib.Path) -> sanic.app.Sanic:
29def create_app(dataset_path: Path) -> Sanic: 30 app = Sanic("graph-visualizer") 31 app.config.TEMPLATING_PATH_TO_TEMPLATES = pkg_resources.resource_filename('pytact', 'templates/') 32 33 @app.before_server_start 34 async def setup_dataset(app): 35 app.ctx.data_ctx = data_reader(dataset_path) 36 app.ctx.gvd = GraphVisualizationData(app.ctx.data_ctx.__enter__()) 37 @app.after_server_stop 38 async def teardown_dataset(app): 39 del app.ctx.gvd 40 app.ctx.data_ctx.__exit__(None, None, None) 41 del app.ctx.data_ctx 42 43 class SanicUrlMaker(UrlMaker): 44 45 def __init__(self, settings: Settings): 46 self.query = {k: v for k, v in asdict(settings).items() if type(v) != bool or v} 47 48 def definition(self, fname: Path, defid: int) -> str: 49 return app.url_for('definition', path=fname.with_suffix(''), defid=defid, **self.query) 50 51 def proof(self, fname: Path, defid: int) -> str: 52 return app.url_for('proof', path=fname.with_suffix(''), defid=defid, **self.query) 53 54 def outcome(self, fname: Path, defid: int, stepi: int, outcomei: int) -> str: 55 return app.url_for('outcome', path=fname.with_suffix(''), 56 defid=defid, stepi=stepi, outcomei=outcomei, **self.query) 57 58 def global_context(self, fname: Path) -> str: 59 return app.url_for('global_context', path=fname.with_suffix(''), **self.query) 60 61 def folder(self, path: Path) -> str: 62 return app.url_for('folder', path=path, **self.query) 63 64 def root_folder(self) -> str: 65 return app.url_for('root_folder', **self.query) 66 67 @app.get('/<path:path>/definition/<defid:int>/proof/step/<stepi:int>/outcome/<outcomei:int>') 68 @validate(query=Settings) 69 @app.ext.template("visualizer.html") 70 async def outcome(request, path: str, defid: str, stepi: str, outcomei: str, query: Settings): 71 gv = GraphVisualizator(app.ctx.gvd, SanicUrlMaker(query), query) 72 return post_process(gv.outcome(Path(path).with_suffix(".bin"), int(defid), int(stepi), int(outcomei)), query) 73 74 @app.get('/<path:path>/definition/<defid:int>/proof') 75 @validate(query=Settings) 76 @app.ext.template("visualizer.html") 77 async def proof(request, path: str, defid: str, query: Settings): 78 gv = GraphVisualizator(app.ctx.gvd, SanicUrlMaker(query), query) 79 return post_process(gv.proof(Path(path).with_suffix(".bin"), int(defid)), query) 80 81 @app.get('/<path:path>/definition/<defid:int>') 82 @validate(query=Settings) 83 @app.ext.template("visualizer.html") 84 async def definition(request, path: str, defid: str, query: Settings): 85 gv = GraphVisualizator(app.ctx.gvd, SanicUrlMaker(query), query) 86 return post_process(gv.definition(Path(path).with_suffix(".bin"), int(defid)), query) 87 88 @app.get('/<path:path>/context') 89 @validate(query=Settings) 90 @app.ext.template("visualizer.html") 91 async def global_context(request, path: str, query: Settings): 92 gv = GraphVisualizator(app.ctx.gvd, SanicUrlMaker(query), query) 93 return post_process(gv.global_context(Path(path).with_suffix(".bin")), query) 94 95 @app.get('/<path:path>') 96 @validate(query=Settings) 97 @app.ext.template("visualizer.html") 98 async def folder(request, path: str, query: Settings): 99 gv = GraphVisualizator(app.ctx.gvd, SanicUrlMaker(query), query) 100 return post_process(gv.folder(Path(path)), query) 101 102 @app.get('/') 103 @validate(query=Settings) 104 @app.ext.template("visualizer.html") 105 async def root_folder(request, query: Settings): 106 gv = GraphVisualizator(app.ctx.gvd, SanicUrlMaker(query), query) 107 return post_process(gv.folder(Path()), query) 108 109 return app
def
main():
111def main(): 112 113 parser = argparse.ArgumentParser( 114 description = 'Start an interactive server that visualizes a dataset', 115 formatter_class=argparse.ArgumentDefaultsHelpFormatter) 116 117 parser.add_argument('dataset', 118 type=str, 119 help=('The location of the dataset to visualize. ' + 120 'Either a dataset directory, or a SquashFS image, ' + 121 'which will be automatically mounted.')) 122 parser.add_argument('--port', 123 type=int, 124 default=8080, 125 help='the port where the webserver should listen') 126 parser.add_argument('--hostname', 127 type=str, 128 default='0.0.0.0', 129 help='the ip or domain of the hosting machine') 130 parser.add_argument('--dev', 131 action='store_true', 132 help='run the server in development mode') 133 group = parser.add_mutually_exclusive_group() 134 group.add_argument('--fast', action='store_true', default=False, 135 help='Run the server with an optimal number of worker') 136 group.add_argument('--workers', type=int, default=1, 137 help='The number of workers to use') 138 139 args = parser.parse_args() 140 141 dataset_path = Path(args.dataset).resolve() 142 143 loader = AppLoader(factory=partial(create_app, dataset_path)) 144 app = loader.load() 145 app.prepare(host=args.hostname, port=args.port, dev=args.dev, fast=args.fast, workers=args.workers) 146 Sanic.serve(primary=app, app_loader=loader)