Path: blob/master/contrib/sagecell-client/sagecell-client.py
447 views
#!/usr/bin/env python31"""2A small client illustrating how to interact with the Sage Cell Server, version 234Requires the websocket-client package: http://pypi.python.org/pypi/websocket-client5"""67import websocket8import json9import requests101112class SageCell(object):1314def __init__(self, url, timeout=10):15if not url.endswith('/'):16url += '/'17# POST or GET <url>/kernel18# if there is a terms of service agreement, you need to19# indicate acceptance in the data parameter below (see the API docs)20response = requests.post(21url + 'kernel',22data={'accepted_tos': 'true'},23headers={'Accept': 'application/json'}).json()24# RESPONSE: {"id": "ce20fada-f757-45e5-92fa-05e952dd9c87", "ws_url": "ws://localhost:8888/"}25# construct the websocket channel url from that26self.kernel_url = '{ws_url}kernel/{id}/'.format(**response)27print(self.kernel_url)28websocket.setdefaulttimeout(timeout)29self._ws = websocket.create_connection(30self.kernel_url + 'channels',31header={'Jupyter-Kernel-ID': response['id']})32# initialize our list of messages33self.shell_messages = []34self.iopub_messages = []3536def execute_request(self, code):37# zero out our list of messages, in case this is not the first request38self.shell_messages = []39self.iopub_messages = []4041# Send the JSON execute_request message string down the shell channel42msg = self._make_execute_request(code)43self._ws.send(msg)4445# Wait until we get both a kernel status idle message and an execute_reply message46got_execute_reply = False47got_idle_status = False48while not (got_execute_reply and got_idle_status):49msg = json.loads(self._ws.recv())50if msg['channel'] == 'shell':51self.shell_messages.append(msg)52# an execute_reply message signifies the computation is done53if msg['header']['msg_type'] == 'execute_reply':54got_execute_reply = True55elif msg['channel'] == 'iopub':56self.iopub_messages.append(msg)57# the kernel status idle message signifies the kernel is done58if (msg['header']['msg_type'] == 'status' and59msg['content']['execution_state'] == 'idle'):60got_idle_status = True6162return {'shell': self.shell_messages, 'iopub': self.iopub_messages}6364def _make_execute_request(self, code):65from uuid import uuid466session = str(uuid4())6768# Here is the general form for an execute_request message69execute_request = {70'channel': 'shell',71'header': {72'msg_type': 'execute_request',73'msg_id': str(uuid4()),74'username': '', 'session': session,75},76'parent_header':{},77'metadata': {},78'content': {79'code': code,80'silent': False,81'user_expressions': {82'_sagecell_files': 'sys._sage_.new_files()',83},84'allow_stdin': False,85}86}87return json.dumps(execute_request)8889def close(self):90# If we define this, we can use the closing() context manager to automatically close the channels91self._ws.close()9293if __name__ == "__main__":94import sys95if len(sys.argv) >= 2:96# argv[1] is the web address97url = sys.argv[1]98else:99url = 'https://sagecell.sagemath.org'100a = SageCell(url)101import pprint102pprint.pprint(a.execute_request('factorial(2020)'))103104105