diff --git a/cwlkernel/CWLKernel.py b/cwlkernel/CWLKernel.py index c14fe94..333e7d9 100644 --- a/cwlkernel/CWLKernel.py +++ b/cwlkernel/CWLKernel.py @@ -211,6 +211,9 @@ def do_complete(self, code: str, cursor_pos: int): self.log.debug(f'suggestions: {suggestions["matches"]}') return {**suggestions, 'status': 'ok'} + def send_text_to_stdout(self, text: str): + self.send_response(self.iopub_socket, 'stream', {'name': 'stdout', 'text': text}) + if __name__ == '__main__': from ipykernel.kernelapp import IPKernelApp diff --git a/cwlkernel/kernel_magics.py b/cwlkernel/kernel_magics.py index 8abcb83..dc93650 100644 --- a/cwlkernel/kernel_magics.py +++ b/cwlkernel/kernel_magics.py @@ -1,3 +1,4 @@ +import argparse import json import os import random @@ -104,7 +105,15 @@ def execute(kernel: CWLKernel, execute_argument_string: str): @CWLKernel.register_magic -def display_data(kernel: CWLKernel, data_name: str): +def display_data(kernel: CWLKernel, data_name: str) -> None: + """ + Display the data generated by workflow. + Usage % display_data [data id] + + @param kernel: the kernel instance + @param data_name: the data id + @return None + """ if not isinstance(data_name, str) or len(data_name.split()) == 0: kernel._send_error_response( 'ERROR: you must select an output to display. Correct format:\n % display_data [output name]' @@ -245,6 +254,9 @@ def logs(kernel: CWLKernel, limit=None): @CWLKernel.register_magic def data(kernel: CWLKernel, *args): + """ + Display all the data which are registered in the kernel session. + """ data = "" kernel.send_response( @@ -286,8 +298,35 @@ def viewTool(kernel: CWLKernel, workflow_id: str): @CWLKernel.register_magic -def magics(kernel: CWLKernel, *args): - kernel._send_json_response(list(kernel._magic_commands.keys())) +def magics(kernel: CWLKernel, arg: str): + arg = arg.split() + parser = argparse.ArgumentParser() + parser.add_argument('magic', default=None, nargs='?') + arg = parser.parse_args(arg) + if arg.magic is None: + commands = ['\t- ' + cmd for cmd in kernel._magic_commands.keys()] + commands.sort() + commands = os.linesep.join(commands) + kernel.send_text_to_stdout( + f'List of Available Magic commands\n{commands}' + ) + else: + try: + full_doc: str = globals()[arg.magic].__doc__.splitlines() + doc = [] + for line_number, line in enumerate(full_doc): + line = line.strip() + if line.startswith('@'): + break + elif len(line) > 0: + doc.append(line) + doc = os.linesep.join(doc) + + kernel.send_text_to_stdout(doc) + except Exception: + kernel.send_text_to_stdout( + 'The function does not provide documentation' + ) # import user's magic commands diff --git a/examples/introduction.ipynb b/examples/introduction.ipynb index d51e84f..7bb587c 100644 --- a/examples/introduction.ipynb +++ b/examples/introduction.ipynb @@ -52,7 +52,7 @@ "source": [ "#!/usr/bin/env cwl-runner\n", "\n", - "cwlVersion: v1.0\n", + "cwlVersion: v1.1\n", "class: CommandLineTool\n", "baseCommand: echo\n", "id: echo\n", @@ -89,19 +89,20 @@ "data": { "application/json": { "example_output": { - "basename": "f811c63eed22dec4eec6f02280820eabf16fa779", + "basename": "2e0a23bee9af60260156f18c56053610387aefc3", "checksum": "sha1$47a013e660d408619d894b20806b1d5086aab03b", "class": "File", "http://commonwl.org/cwltool#generation": 0, "id": "example_output", - "location": "file:///private/tmp/CWLKERNEL_DATA/runtime_data/f811c63eed22dec4eec6f02280820eabf16fa779", + "location": "file:///private/tmp/CWLKERNEL_DATA/fde9200f-dffd-4493-9ff5-03ea5f0cd4dd/runtime_data/2e0a23bee9af60260156f18c56053610387aefc3", "nameext": "", - "nameroot": "f811c63eed22dec4eec6f02280820eabf16fa779", + "nameroot": "2e0a23bee9af60260156f18c56053610387aefc3", + "result_counter": 0, "size": 13 } }, "text/plain": [ - "" + "{\"example_output\": {\"location\": \"file:///private/tmp/CWLKERNEL_DATA/fde9200f-dffd-4493-9ff5-03ea5f0cd4dd/runtime_data/2e0a23bee9af60260156f18c56053610387aefc3\", \"basename\": \"2e0a23bee9af60260156f18c56053610387aefc3\", \"nameroot\": \"2e0a23bee9af60260156f18c56053610387aefc3\", \"nameext\": \"\", \"class\": \"File\", \"checksum\": \"sha1$47a013e660d408619d894b20806b1d5086aab03b\", \"size\": 13, \"http://commonwl.org/cwltool#generation\": 0, \"id\": \"example_output\", \"result_counter\": 0}}" ] }, "metadata": { @@ -122,6 +123,58 @@ "cell_type": "code", "execution_count": 3, "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "List of Available Magic commands\n", + "\t- data\n", + "\t- display_data\n", + "\t- display_data_csv\n", + "\t- display_data_image\n", + "\t- execute\n", + "\t- githubImport\n", + "\t- logs\n", + "\t- magics\n", + "\t- newWorkflow\n", + "\t- newWorkflowAddInput\n", + "\t- newWorkflowAddOutputSource\n", + "\t- newWorkflowAddStep\n", + "\t- newWorkflowAddStepIn\n", + "\t- newWorkflowBuild\n", + "\t- sample_csv\n", + "\t- snippet\n", + "\t- viewTool" + ] + } + ], + "source": [ + "% magics" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Display the data generated by workflow.\n", + "Usage % display_data [data id]" + ] + } + ], + "source": [ + "% magics display_data" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, "outputs": [ { "name": "stdout", diff --git a/tests/test_CWLKernel.py b/tests/test_CWLKernel.py index 8365d23..be62798 100644 --- a/tests/test_CWLKernel.py +++ b/tests/test_CWLKernel.py @@ -835,6 +835,38 @@ def test_import_users_magic_commands(self): ) os.environ.pop('CWLKERNEL_MAGIC_COMMANDS_DIRECTORY') + def test_magics_magic_command(self): + kernel = CWLKernel() + # cancel send_response + responses = [] + kernel.send_response = lambda *args, **kwargs: responses.append((args, kwargs)) + + commands = [f'\t- {cmd}' for cmd in kernel._magic_commands.keys()] + commands.sort() + + + self.assertDictEqual( + {'status': 'ok', 'execution_count': 0, 'payload': [], 'user_expressions': {}}, + kernel.do_execute(f"""% magics""") + ) + self.assertEqual( + 'List of Available Magic commands\n' + os.linesep.join(commands), + responses[-1][0][2]['text'] + ) + + self.assertDictEqual( + {'status': 'ok', 'execution_count': 0, 'payload': [], 'user_expressions': {}}, + kernel.do_execute(f"""% magics data""") + ) + from cwlkernel.kernel_magics import data as data_magic_command + import inspect + self.assertEqual( + inspect.getdoc(data_magic_command), + responses[-1][0][2]['text'] + ) + self.assertIn(' '.join('Display all the data which are registered in the kernel session.'.split()), + ' '.join(responses[-1][0][2]['text'].split())) + if __name__ == '__main__': unittest.main()