コード例 #1
0
ファイル: converter.py プロジェクト: datastark/sos-notebook
 def workflow_from_notebook_cell(self, cell, fh, idx=0):
     # in non-all mode, markdown cells are ignored because they can be mistakenly
     # treated as markdown content of an action or script #806
     if cell.cell_type != "code":
         return
     #
     # Non-sos code cells are also ignored
     if 'kernel' in cell.metadata and cell.metadata['kernel'] not in ('sos',
                                                                      'SoS',
                                                                      None):
         return
     lines = cell.source.split('\n')
     valid_cell = False
     for idx, line in enumerate(lines):
         if valid_cell or (line.startswith('%include')
                           or line.startswith('%from')):
             fh.write(line + '\n')
         elif SOS_SECTION_HEADER.match(line):
             valid_cell = True
             # look retrospectively for comments
             c = idx - 1
             comment = ''
             while c >= 0 and lines[c].startswith('#'):
                 comment = lines[c] + '\n' + comment
                 c -= 1
             fh.write(comment + line + '\n')
         # other content, namely non-%include lines before section header is ignored
     if valid_cell:
         fh.write('\n')
     return idx
コード例 #2
0
 def from_notebook_cell(self, cell, fh, idx=0):
     if self.export_all:
         meta = ' '.join(f'{x}={y}' for x, y in cell.metadata.items())
         if not hasattr(cell,
                        'execution_count') or cell.execution_count is None:
             fh.write(f'%cell {cell.cell_type} {meta}\n')
         else:
             idx += 1
             fh.write(
                 f'%cell {cell.cell_type} {cell.execution_count} {meta}\n')
         if cell.cell_type == 'code':
             fh.write(cell.source.strip() + '\n')
         elif cell.cell_type == "markdown":
             fh.write('\n'.join('#! ' + x
                                for x in cell.source.split('\n')) + '\n')
         fh.write('\n')
     else:
         # in non-all mode, markdown cells are ignored because they can be mistakenly
         # treated as markdown content of an action or script #806
         if cell.cell_type != "code":
             return
         #
         # Non-sos code cells are also ignored
         if 'kernel' in cell.metadata and cell.metadata['kernel'] not in (
                 'sos', 'SoS', None):
             return
         lines = cell.source.split('\n')
         valid_cell = False
         for line in lines:
             if valid_cell or (line.startswith('%include')
                               or line.startswith('%from')):
                 fh.write(line + '\n')
             elif SOS_SECTION_HEADER.match(line):
                 valid_cell = True
                 fh.write(line + '\n')
             # other content, namely non-%include lines before section header is ignored
         if valid_cell:
             fh.write('\n')
     return idx
コード例 #3
0
def runfile(script=None,
            raw_args='',
            wdir='.',
            code=None,
            kernel=None,
            **kwargs):
    # this has something to do with Prefix matching rule of parse_known_args
    #
    # That is to say
    #
    #   --rep 3
    #
    # would be parsed as
    #
    #   args.workflow=3, unknown --rep
    #
    # instead of
    #
    #   args.workflow=None, unknown --rep 3
    #
    # we then have to change the parse to disable args.workflow when
    # there is no workflow option.
    raw_args = shlex.split(raw_args) if isinstance(raw_args, str) else raw_args
    if (script is None and code is None) or '-h' in raw_args:
        parser = get_run_parser(interactive=True, with_workflow=True)
        parser.print_help()
        return
    if raw_args and raw_args[0].lstrip().startswith('-'):
        parser = get_run_parser(interactive=True, with_workflow=False)
        parser.error = _parse_error
        args, workflow_args = parser.parse_known_args(raw_args)
        args.workflow = None
    else:
        parser = get_run_parser(interactive=True, with_workflow=True)
        parser.error = _parse_error
        args, workflow_args = parser.parse_known_args(raw_args)

    # for reporting purpose
    sys.argv = ['%run'] + raw_args

    env.verbosity = args.verbosity
    if kernel and not isinstance(env.logger.handlers[0],
                                 NotebookLoggingHandler):
        env.logger.handlers = []
        levels = {
            0: logging.ERROR,
            1: logging.WARNING,
            2: logging.INFO,
            3: logging.DEBUG,
            4: logging.TRACE,
            None: logging.INFO
        }
        env.logger.addHandler(
            NotebookLoggingHandler(levels[env.verbosity],
                                   kernel,
                                   title=' '.join(sys.argv)))
    else:
        env.logger.handers[0].setTitle(' '.join(sys.argv))

    dt = datetime.datetime.now().strftime('%m%d%y_%H%M')
    if args.__dag__ is None:
        args.__dag__ = f'workflow_{dt}.dot'
    elif args.__dag__ == '':
        args.__dag__ = None

    if args.__report__ is None:
        args.__report__ = f'workflow_{dt}.html'
    elif args.__report__ == '':
        args.__report__ = None

    if args.__remote__:
        from sos.utils import load_config_files
        cfg = load_config_files(args.__config__)
        env.sos_dict.set('CONFIG', cfg)

        # if executing on a remote host...
        from sos.hosts import Host
        host = Host(args.__remote__)
        #
        if script is None:
            if not code.strip():
                return
            script = os.path.join('.sos', '__interactive__.sos')
            with open(script, 'w') as s:
                s.write(code)

        # copy script to remote host...
        host.send_to_host(script)
        from sos.utils import remove_arg
        argv = shlex.split(raw_args) if isinstance(raw_args, str) else raw_args
        argv = remove_arg(argv, '-r')
        argv = remove_arg(argv, '-c')
        # execute the command on remote host
        try:
            with kernel.redirect_sos_io():
                ret = host._host_agent.run_command(['sos', 'run', script] +
                                                   argv,
                                                   wait_for_task=True,
                                                   realtime=True)
            if ret:
                kernel.send_response(
                    kernel.iopub_socket, 'stream',
                    dict(name='stderr',
                         text=
                         f'remote execution of workflow exited with code {ret}'
                         ))
        except Exception as e:
            if kernel:
                kernel.send_response(kernel.iopub_socket, 'stream', {
                    'name': 'stdout',
                    'text': str(e)
                })
        return

    if args.__bin_dirs__:
        for d in args.__bin_dirs__:
            if d == '~/.sos/bin' and not os.path.isdir(os.path.expanduser(d)):
                os.makedirs(os.path.expanduser(d), exist_ok=True)
        os.environ['PATH'] = os.pathsep.join(
            [os.path.expanduser(x)
             for x in args.__bin_dirs__]) + os.pathsep + os.environ['PATH']

    # clear __step_input__, __step_output__ etc because there is
    # no concept of passing input/outputs across cells.
    env.sos_dict.set('__step_output__', sos_targets([]))
    for k in [
            '__step_input__', '__default_output__', 'step_input',
            'step_output', 'step_depends', '_input', '_output', '_depends'
    ]:
        env.sos_dict.pop(k, None)

    try:
        if script is None:
            if not code.strip():
                return
            if kernel is None:
                script = SoS_Script(content=code)
            else:
                if kernel._workflow_mode:
                    # in workflow mode, the content is sent by magics %run and %sosrun
                    script = SoS_Script(content=code)
                else:
                    # this is a scratch step...
                    # if there is no section header, add a header so that the block
                    # appears to be a SoS script with one section
                    if not any([
                            SOS_SECTION_HEADER.match(line)
                            or line.startswith('%from')
                            or line.startswith('%include')
                            for line in code.splitlines()
                    ]):
                        code = '[scratch_0]\n' + code
                        script = SoS_Script(content=code)
                    else:
                        #kernel.send_frontend_msg('stream',
                        #                         {'name': 'stdout', 'text': 'Workflow cell can only be executed with magic %run or %sosrun.'},
                        #                         title='# SoS warning')
                        return
        else:
            script = SoS_Script(filename=script)
        workflow = script.workflow(args.workflow,
                                   use_default=not args.__targets__)
        env.config: DefaultDict[str, Union[None, bool, str]] = defaultdict(str)
        executor = Interactive_Executor(
            workflow,
            args=workflow_args,
            config={
                'config_file':
                args.__config__,
                'output_dag':
                args.__dag__,
                'output_report':
                args.__report__,
                'sig_mode':
                'ignore' if args.dryrun else args.__sig_mode__,
                'default_queue':
                '' if args.__queue__ is None else args.__queue__,
                'wait_for_task':
                True if args.__wait__ is True or args.dryrun else
                (False if args.__no_wait__ else None),
                'resume_mode':
                kernel is not None and kernel._resume_execution,
                'run_mode':
                'dryrun' if args.dryrun else 'interactive',
                'verbosity':
                args.verbosity,

                # wait if -w or in dryrun mode, not wait if -W, otherwise use queue default
                'max_procs':
                args.__max_procs__,
                'max_running_jobs':
                args.__max_running_jobs__,
                # for infomration and resume only
                'workdir':
                os.getcwd(),
                'script':
                "interactive",
                'workflow':
                args.workflow,
                'targets':
                args.__targets__,
                'bin_dirs':
                args.__bin_dirs__,
                'workflow_args':
                workflow_args
            })
        return executor.run(args.__targets__)['__last_res__']
    except PendingTasks:
        raise
    except SystemExit:
        # this happens because the executor is in resume mode but nothing
        # needs to be resumed, we simply pass
        return
    except Exception:
        if args.verbosity and args.verbosity > 2:
            sys.stderr.write(get_traceback())
        raise
    finally:
        env.config['sig_mode'] = 'ignore'
        env.verbosity = 2
コード例 #4
0
def execute_scratch_cell(code, raw_args, kernel):
    # we then have to change the parse to disable args.workflow when
    # there is no workflow option.
    raw_args = shlex.split(raw_args) if isinstance(raw_args, str) else raw_args
    if code is None or '-h' in raw_args:
        parser = get_run_parser(interactive=True, with_workflow=True)
        parser.print_help()
        return
    if raw_args and raw_args[0].lstrip().startswith('-'):
        parser = get_run_parser(interactive=True, with_workflow=False)
        parser.error = _parse_error
        args, workflow_args = parser.parse_known_args(raw_args)
        args.workflow = None
    else:
        parser = get_run_parser(interactive=True, with_workflow=True)
        parser.error = _parse_error
        args, workflow_args = parser.parse_known_args(raw_args)

    if not code.strip():
        return

    # for reporting purpose
    sys.argv = ['%run'] + raw_args
    env.verbosity = args.verbosity

    if not any(
            isinstance(x, NotebookLoggingHandler)
            for x in env.logger.handlers):
        env.logger.handlers = [
            x for x in env.logger.handlers
            if type(x) is not logging.StreamHandler
        ]
        levels = {
            0: logging.ERROR,
            1: logging.WARNING,
            2: logging.INFO,
            3: logging.DEBUG,
            4: logging.DEBUG,
            None: logging.INFO
        }
        env.logger.addHandler(
            NotebookLoggingHandler(levels[env.verbosity],
                                   kernel,
                                   title=' '.join(sys.argv)))
    else:
        env.logger.handers[0].setTitle(' '.join(sys.argv))

    global last_cell_id
    # we retain step_input etc only when we step through a cell  #256
    if kernel and kernel.cell_id != last_cell_id:
        # clear __step_input__, __step_output__ etc because there is
        # no concept of passing input/outputs across cells.
        env.sos_dict.set('__step_output__', sos_targets([]))
        for k in [
                '__step_input__', '__default_output__', 'step_input',
                'step_output', 'step_depends', '_input', '_output', '_depends'
        ]:
            env.sos_dict.pop(k, None)

    last_cell_id = kernel.cell_id

    config = {
        'config_file':
        args.__config__,
        'default_queue':
        args.__queue__,
        'run_mode':
        'dryrun' if args.dryrun else 'interactive',
        # issue 230, ignore sig mode in interactive mode
        'sig_mode':
        'ignore',
        'verbosity':
        args.verbosity,
        # for backward compatibility, we try both args.__worker_procs__ and args.__max_procs__
        'worker_procs':
        args.__worker_procs__
        if hasattr(args, '__worker_procs__') else args.__max_procs__,
        'max_running_jobs':
        args.__max_running_jobs__,
        # for infomration and resume only
        'workdir':
        os.getcwd(),
        'workflow':
        args.workflow,
        'targets':
        args.__targets__,
        'workflow_args':
        workflow_args,
        'workflow_id':
        textMD5(code),

        # interactive work is also a slave of the controller
        'slave_id':
        kernel.cell_id,
    }

    env.sos_dict.set('workflow_id', config['workflow_id'])
    env.config.update(config)

    try:
        if not any([
                SOS_SECTION_HEADER.match(line) or line.startswith('%from')
                or line.startswith('%include') for line in code.splitlines()
        ]):
            code = f'[cell_{str(kernel.cell_id)[:8] if kernel and kernel.cell_id else "0"}]\n' + code
            script = SoS_Script(content=code)
        else:
            return
        workflow = script.workflow(args.workflow)
        section = workflow.sections[0]
        res = analyze_section(section)
        env.sos_dict.quick_update({
            '__signature_vars__': res['signature_vars'],
            '__environ_vars__': res['environ_vars'],
            '__changed_vars__': res['changed_vars']
        })
        executor = Interactive_Step_Executor(section, mode='interactive')
        ret = executor.run()
        try:
            return ret['__last_res__']
        except Exception as e:
            raise RuntimeError(
                f'Unknown result returned from executor {ret}: {e}')
    except (UnknownTarget, RemovedTarget) as e:
        raise RuntimeError(f'Unavailable target {e.target}')
    except TerminateExecution as e:
        return
    except SystemExit:
        # this happens because the executor is in resume mode but nothing
        # needs to be resumed, we simply pass
        return
    except Exception:
        env.log_to_file('PROCESS', get_traceback())
        raise
コード例 #5
0
ファイル: converter.py プロジェクト: datastark/sos-notebook
    def convert(self,
                script_file,
                notebook_file,
                args=None,
                unknown_args=None):
        '''
        Convert a sos script to iPython notebook (.ipynb) so that it can be opened
        by Jupyter notebook.
        '''
        if unknown_args:
            raise ValueError(f'Unrecognized parameter {unknown_args}')
        cells = []
        cell_count = 1
        cell_type = 'code'
        metainfo = {}
        content = []

        def add_cell(cells, content, cell_type, cell_count, metainfo):
            # if a section consist of all report, report it as a markdown cell
            if not content:
                return
            if cell_type not in ('code', 'markdown'):
                env.logger.warning(
                    f'Unrecognized cell type {cell_type}, code assumed.')
            if cell_type == 'markdown' and any(
                    x.strip() and not x.startswith('#! ') for x in content):
                env.logger.warning(
                    'Markdown lines not starting with #!, code cell assumed.')
                cell_type = 'code'
            #
            if cell_type == 'markdown':
                cells.append(
                    new_markdown_cell(source=''.join([x[3:] for x in content
                                                      ]).strip(),
                                      metadata=metainfo))
            else:
                cells.append(
                    new_code_cell(
                        # remove any trailing blank lines...
                        source=''.join(content).strip(),
                        execution_count=cell_count,
                        metadata=metainfo))

        with open(script_file) as script:
            first_block = True
            for line in script:
                if line.startswith('#') and first_block:
                    if line.startswith('#!'):
                        continue
                    if line.startswith('#fileformat='):
                        if not line[12:].startswith('SOS'):
                            raise RuntimeError(
                                f'{script_file} is not a SoS script according to #fileformat line.'
                            )
                        continue

                first_block = False

                mo = SOS_SECTION_HEADER.match(line)
                if mo:
                    # get rid of empty content
                    if not any(x.strip() for x in content):
                        content = []

                    if content:
                        # the comment should be absorbed into the next section
                        i = len(content) - 1
                        while i >= 0 and content[i].startswith('#'):
                            i -= 1
                        # i point to the last non comment line
                        if i >= 0:
                            add_cell(cells, content[:i + 1], cell_type,
                                     cell_count, metainfo)
                        content = content[i + 1:]

                    cell_type = 'code'
                    cell_count += 1
                    metainfo = {'kernel': 'SoS'}
                    content += [line]
                    continue

                if line.startswith('#!'):
                    if cell_type == 'markdown':
                        content.append(line)
                        continue
                    else:
                        # get ride of empty content
                        if not any(x.strip() for x in content):
                            content = []

                        if content:
                            add_cell(cells, content, cell_type, cell_count,
                                     metainfo)

                        cell_type = 'markdown'
                        cell_count += 1
                        content = [line]
                        continue

                # other cases
                content.append(line)
        #
        if content and any(x.strip() for x in content):
            add_cell(cells, content, cell_type, cell_count, metainfo)
        #
        nb = new_notebook(cells=cells,
                          metadata={
                              'kernelspec': {
                                  "display_name": "SoS",
                                  "language": "sos",
                                  "name": "sos"
                              },
                              "language_info": {
                                  'codemirror_mode':
                                  'sos',
                                  "file_extension":
                                  ".sos",
                                  "mimetype":
                                  "text/x-sos",
                                  "name":
                                  "sos",
                                  "pygments_lexer":
                                  "python",
                                  'nbconvert_exporter':
                                  'sos_notebook.converter.SoS_Exporter',
                              },
                              'sos': {
                                  'kernels': [['SoS', 'sos', '', '']]
                              }
                          })
        if not notebook_file:
            nbformat.write(nb, sys.stdout, 4)
        else:
            with open(notebook_file, 'w') as notebook:
                nbformat.write(nb, notebook, 4)
            env.logger.info(f'Jupyter notebook saved to {notebook_file}')
コード例 #6
0
def script_to_notebook(script_file,
                       notebook_file,
                       args=None,
                       unknown_args=None):
    '''
    Convert a sos script to iPython notebook (.ipynb) so that it can be opened
    by Jupyter notebook.
    '''
    if unknown_args:
        raise ValueError(f'Unrecognized parameter {unknown_args}')
    cells = []
    cell_count = 1
    cell_type = 'code'
    metainfo = {}
    content = []

    with open(script_file) as script:
        split_step = '%cell ' not in script.read()

    with open(script_file) as script:
        first_block = True
        for line in script:
            if line.startswith('#') and first_block:
                if line.startswith('#!'):
                    continue
                if line.startswith('#fileformat='):
                    if not line[12:].startswith('SOS'):
                        raise RuntimeError(
                            f'{script_file} is not a SoS script according to #fileformat line.'
                        )
                    continue

            first_block = False

            mo = SOS_CELL_LINE.match(line)
            if mo:
                # get ride of empty content
                if not any(x.strip() for x in content):
                    content = []

                if content:
                    add_cell(cells, content, cell_type, cell_count, metainfo)

                cell_type = mo.group('cell_type')
                if not cell_type:
                    cell_type = 'code'
                cc = mo.group('cell_count')
                if cc:
                    cell_count = int(cc)
                else:
                    cell_count += 1
                metainfo = mo.group('metainfo')
                if metainfo:
                    pieces = [
                        piece.split('=', 1) for piece in metainfo.split()
                    ]
                    for idx, piece in enumerate(pieces):
                        if len(piece) == 1:
                            env.logger.warning(f'Incorrect metadata {piece}')
                            pieces[idx].append('')
                        if piece[1] == 'True':
                            pieces[idx][1] = True
                        elif piece[1] == 'False':
                            pieces[idx][1] = False
                    metainfo = {x: y for x, y in pieces}
                else:
                    metainfo = {}
                content = []
                continue

            if split_step:
                mo = SOS_SECTION_HEADER.match(line)
                if mo:
                    # get ride of empty content
                    if not any(x.strip() for x in content):
                        content = []

                    if content:
                        add_cell(cells, content, cell_type, cell_count,
                                 metainfo)

                    cell_type = 'code'
                    cell_count += 1
                    metainfo = {'kernel': 'SoS'}
                    content = [line]
                    continue

                if line.startswith('#!'):
                    if cell_type == 'markdown':
                        content.append(line)
                        continue
                    else:
                        # get ride of empty content
                        if not any(x.strip() for x in content):
                            content = []

                        if content:
                            add_cell(cells, content, cell_type, cell_count,
                                     metainfo)

                        cell_type = 'markdown'
                        cell_count += 1
                        content = [line]
                        continue

            # other cases
            content.append(line)
    #
    if content and any(x.strip() for x in content):
        add_cell(cells, content, cell_type, cell_count, metainfo)
    #
    nb = new_notebook(cells=cells,
                      metadata={
                          'kernelspec': {
                              "display_name": "SoS",
                              "language": "sos",
                              "name": "sos"
                          },
                          "language_info": {
                              'codemirror_mode':
                              'sos',
                              "file_extension":
                              ".sos",
                              "mimetype":
                              "text/x-sos",
                              "name":
                              "sos",
                              "pygments_lexer":
                              "python",
                              'nbconvert_exporter':
                              'sos_notebook.converter.SoS_Exporter',
                          },
                          'sos': {
                              'kernels': [['SoS', 'sos', '', '']]
                          }
                      })
    #err = None
    # if args and args.execute:
    #    ep = SoS_ExecutePreprocessor(timeout=600, kernel_name='sos')
    #    try:
    #        ep.preprocess(nb, {'metadata': {'path': '.'}})
    #    except CellExecutionError as e:
    #        err = e
    #
    if not notebook_file:
        nbformat.write(nb, sys.stdout, 4)
    else:
        with open(notebook_file, 'w') as notebook:
            nbformat.write(nb, notebook, 4)
        env.logger.info(f'Jupyter notebook saved to {notebook_file}')
コード例 #7
0
def script_to_notebook(script_file,
                       notebook_file,
                       args=None,
                       unknown_args=None):
    '''
    Convert a sos script to iPython notebook (.ipynb) so that it can be opened
    by Jupyter notebook.
    '''
    if unknown_args:
        raise ValueError(f'Unrecognized parameter {unknown_args}')
    cells = []
    cell_count = 1
    cell_type = 'code'
    metainfo = {}
    content = []

    with open(script_file) as script:
        first_block = True
        for line in script:
            if line.startswith('#') and first_block:
                if line.startswith('#!'):
                    continue
                if line.startswith('#fileformat='):
                    if not line[12:].startswith('SOS'):
                        raise RuntimeError(
                            f'{script_file} is not a SoS script according to #fileformat line.'
                        )
                    continue

            first_block = False

            mo = SOS_SECTION_HEADER.match(line)
            if mo:
                # get ride of empty content
                if not any(x.strip() for x in content):
                    content = []

                if content:
                    add_cell(cells, content, cell_type, cell_count, metainfo)

                cell_type = 'code'
                cell_count += 1
                metainfo = {'kernel': 'SoS'}
                content = [line]
                continue

            if line.startswith('#!'):
                if cell_type == 'markdown':
                    content.append(line)
                    continue
                else:
                    # get ride of empty content
                    if not any(x.strip() for x in content):
                        content = []

                    if content:
                        add_cell(cells, content, cell_type, cell_count,
                                 metainfo)

                    cell_type = 'markdown'
                    cell_count += 1
                    content = [line]
                    continue

            # other cases
            content.append(line)
    #
    if content and any(x.strip() for x in content):
        add_cell(cells, content, cell_type, cell_count, metainfo)
    #
    nb = new_notebook(cells=cells,
                      metadata={
                          'kernelspec': {
                              "display_name": "SoS",
                              "language": "sos",
                              "name": "sos"
                          },
                          "language_info": {
                              'codemirror_mode':
                              'sos',
                              "file_extension":
                              ".sos",
                              "mimetype":
                              "text/x-sos",
                              "name":
                              "sos",
                              "pygments_lexer":
                              "python",
                              'nbconvert_exporter':
                              'sos_notebook.converter.SoS_Exporter',
                          },
                          'sos': {
                              'kernels': [['SoS', 'sos', '', '']]
                          }
                      })
    if not notebook_file:
        nbformat.write(nb, sys.stdout, 4)
    else:
        with open(notebook_file, 'w') as notebook:
            nbformat.write(nb, notebook, 4)
        env.logger.info(f'Jupyter notebook saved to {notebook_file}')
コード例 #8
0
def runfile(script=None,
            raw_args='',
            wdir='.',
            code=None,
            kernel=None,
            **kwargs):
    # this has something to do with Prefix matching rule of parse_known_args
    #
    # That is to say
    #
    #   --rep 3
    #
    # would be parsed as
    #
    #   args.workflow=3, unknown --rep
    #
    # instead of
    #
    #   args.workflow=None, unknown --rep 3
    #
    # we then have to change the parse to disable args.workflow when
    # there is no workflow option.
    args = shlex.split(raw_args) if isinstance(raw_args, str) else raw_args
    if (script is None and code is None) or '-h' in args:
        parser = get_run_parser(interactive=True, with_workflow=True)
        parser.print_help()
        return
    if args and args[0].lstrip().startswith('-'):
        parser = get_run_parser(interactive=True, with_workflow=False)
        parser.error = _parse_error
        args, workflow_args = parser.parse_known_args(args)
        args.workflow = None
    else:
        parser = get_run_parser(interactive=True, with_workflow=True)
        parser.error = _parse_error
        args, workflow_args = parser.parse_known_args(args)

    # no multi-processing in interactive mode
    env.max_jobs = 1
    env.verbosity = args.verbosity

    if args.__queue__ == '':
        from sos.hosts import list_queues
        list_queues(args.__config__, args.verbosity)
        return

    if args.__remote__:
        from sos.utils import load_config_files
        cfg = load_config_files(args.__config__)
        env.sos_dict.set('CONFIG', cfg)
        if args.__remote__ == '':
            from .hosts import list_queues
            list_queues(cfg, args.verbosity)
            return

        # if executing on a remote host...
        from sos.hosts import Host
        host = Host(args.__remote__)
        #
        if script is None:
            if not code.strip():
                return
            script = os.path.join('.sos', '__interactive__.sos')
            with open(script, 'w') as s:
                s.write(code)

        # copy script to remote host...
        host.send_to_host(script)
        from sos.utils import remove_arg
        argv = shlex.split(raw_args) if isinstance(raw_args, str) else raw_args
        argv = remove_arg(argv, '-r')
        argv = remove_arg(argv, '-c')
        # execute the command on remote host
        try:
            with kernel.redirect_sos_io():
                ret = host._host_agent.run_command(['sos', 'run', script] +
                                                   argv,
                                                   wait_for_task=True,
                                                   realtime=True)
            if ret:
                kernel.send_response(
                    kernel.iopub_socket, 'stream',
                    dict(name='stderr',
                         text=
                         f'remote execution of workflow exited with code {ret}'
                         ))
        except Exception as e:
            if kernel:
                kernel.send_response(kernel.iopub_socket, 'stream', {
                    'name': 'stdout',
                    'text': str(e)
                })
        return

    if args.__bin_dirs__:
        import fasteners
        for d in args.__bin_dirs__:
            if d == '~/.sos/bin' and not os.path.isdir(os.path.expanduser(d)):
                with fasteners.InterProcessLock(
                        os.path.join(tempfile.gettempdir(), 'sos_lock_bin')):
                    os.makedirs(os.path.expanduser(d))
            elif not os.path.isdir(os.path.expanduser(d)):
                raise ValueError(f'directory does not exist: {d}')
        os.environ['PATH'] = os.pathsep.join(
            [os.path.expanduser(x)
             for x in args.__bin_dirs__]) + os.pathsep + os.environ['PATH']

    # clear __step_input__, __step_output__ etc because there is
    # no concept of passing input/outputs across cells.
    env.sos_dict.set('__step_output__', [])
    for k in ['__step_input__', '__default_output__', 'input', 'output', \
        'depends', '_input', '_output', '_depends']:
        env.sos_dict.pop(k, None)

    try:
        if script is None:
            if not code.strip():
                return
            if kernel is None:
                script = SoS_Script(content=code)
            else:
                if kernel._workflow_mode:
                    # in workflow mode, the content is sent by magics %run and %sosrun
                    script = SoS_Script(content=code)
                else:
                    # this is a scratch step...
                    # if there is no section header, add a header so that the block
                    # appears to be a SoS script with one section
                    if not any([
                            SOS_SECTION_HEADER.match(line)
                            or line.startswith('%from')
                            or line.startswith('%include')
                            for line in code.splitlines()
                    ]):
                        code = '[scratch_0]\n' + code
                        script = SoS_Script(content=code)
                    else:
                        if kernel.cell_idx == -1:
                            kernel.send_frontend_msg(
                                'stream', {
                                    'name':
                                    'stdout',
                                    'text':
                                    'Workflow can only be executed with magic %run or %sosrun.'
                                })
                        return
        else:
            script = SoS_Script(filename=script)
        workflow = script.workflow(args.workflow)
        executor = Interactive_Executor(
            workflow,
            args=workflow_args,
            config={
                'config_file':
                args.__config__,
                'output_dag':
                args.__dag__,
                'sig_mode':
                args.__sig_mode__,
                'default_queue':
                '' if args.__queue__ is None else args.__queue__,
                'wait_for_task':
                True if args.__wait__ is True or args.dryrun else
                (False if args.__no_wait__ else None),
                'resume_mode':
                kernel is not None and kernel._resume_execution,
                'run_mode':
                'dryrun' if args.dryrun else 'interactive',
                'verbosity':
                args.verbosity,

                # wait if -w or in dryrun mode, not wait if -W, otherwise use queue default
                'max_procs':
                1,
                'max_running_jobs':
                args.__max_running_jobs__,
                # for infomration and resume only
                'workdir':
                os.getcwd(),
                'script':
                "interactive",
                'workflow':
                args.workflow,
                'targets':
                args.__targets__,
                'bin_dirs':
                args.__bin_dirs__,
                'workflow_args':
                workflow_args
            })
        return executor.run(args.__targets__)
    except PendingTasks:
        raise
    except SystemExit:
        # this happens because the executor is in resume mode but nothing
        # needs to be resumed, we simply pass
        return
    except Exception:
        if args.verbosity and args.verbosity > 2:
            sys.stderr.write(get_traceback())
        raise
    finally:
        env.config['sig_mode'] = 'ignore'
        env.verbosity = 2