<commit_before>import ctk_cli
import itertools
import os

from girder.models.model_base import ValidationException
from girder.plugins.worker import constants

_SLICER_TO_GIRDER_WORKER_INPUT_TYPE_MAP = {
    'boolean': 'boolean',
    'integer': 'integer',
    'float': 'number',
    'double': 'number',
    'string': 'string',
    'integer-vector': 'integer_list',
    'float-vector': 'number_list',
    'double-vector': 'number_list',
    'string-vector': 'string_list',
    'integer-enumeration': 'integer',
    'float-enumeration': 'number',
    'double-enumeration': 'number',
    'string-enumeration': 'string',
    'file': 'file',
    'directory': 'folder',
    'image': 'file',
    'pointfile': 'file'
}

_SLICER_TO_GIRDER_WORKER_OUTPUT_TYPE_MAP = {
    'file': 'new-file',
    'image': 'new-file',
    'pointfile': 'new-file'
}

_SLICER_TYPE_TO_GIRDER_MODEL_MAP = {
    'image': 'file',
    'file': 'file',
    'directory': 'folder'
}


def _validateParam(param):
    if param.channel == 'input' and param.typ not in _SLICER_TO_GIRDER_WORKER_INPUT_TYPE_MAP:
        raise ValidationException(
            'Input parameter type %s is currently not supported.' % param.typ)

    if param.channel == 'output' and param.typ not in _SLICER_TO_GIRDER_WORKER_OUTPUT_TYPE_MAP:
        raise ValidationException(
            'Output parameter type %s is currently not supported.' % param.typ)


def parseSlicerCliXml(fd):
    """
    Parse a slicer CLI XML document into a form suitable for use
    in the worker.

    :param fd: A file descriptor representing the XML document to parse.
    :type fd: file-like
    :returns: A dict of information about the CLI.
    """
    cliSpec = ctk_cli.CLIModule(stream=fd)

    description = '\n\n'.join((
        '**Description**: %s' % cliSpec.description,
        '**Author(s)**: %s' % cliSpec.contributor,
        '**Version**: %s' % cliSpec.version,
        '**License**: %s' % cliSpec.license,
        '**Acknowledgements**: %s' % (cliSpec.acknowledgements or '*none*'),
        '*This description was auto-generated from the Slicer CLI XML specification.*'
    ))

    info = {
        'title': cliSpec.title,
        'description': description,
        'args': [],
        'inputs': [],
        'outputs': []
    }

    args, opts, outputs = cliSpec.classifyParameters()

    for param in itertools.chain(args, opts):
        _validateParam(param)

    args.sort(key=lambda p: p.index)
    opts.sort(key=lambda p: p.flag or p.longflag)

    inputArgs = [a for a in args if a.channel == 'input']
    inputOpts = [o for o in opts if o.channel == 'input']
    outputArgs = [a for a in args if a.channel == 'output']
    outputOpts = [o for o in opts if o.channel == 'output']

    def ioSpec(name, param, addDefault=False):
        if param.channel == 'output':
            typ = _SLICER_TO_GIRDER_WORKER_OUTPUT_TYPE_MAP[param.typ]
        else:
            typ = _SLICER_TO_GIRDER_WORKER_INPUT_TYPE_MAP[param.typ]

        spec = {
            'id': name.strip('-'),
            'name': param.label,
            'description': param.description,
            'type': typ,
            'format': typ
        }

        if param.isExternalType():
            spec['target'] = 'filepath'

        if addDefault and param.default is not None:
            spec['default'] = param.default

        return spec

    for param in inputOpts:
        name = param.flag or param.longflag
        info['inputs'].append(ioSpec(name, param, True))
        info['args'] += [name, '$input{%s}' % name.strip('-')]

    for param in outputOpts:
        name = param.flag or param.longflag
        info['outputs'].append(ioSpec(name, param))
        info['args'] += [
            param.flag or param.longflag,
            os.path.join(constants.DOCKER_DATA_VOLUME, name.strip('-'))
        ]

    for param in inputArgs:
        info['inputs'].append(ioSpec(param.name, param, True))
        info['args'].append('$input{%s}' % param.name)

    for param in outputArgs:
        info['outputs'].append(ioSpec(param.name, param))
        info['args'].append(os.path.join(constants.DOCKER_DATA_VOLUME, param.name))

    return info<commit_msg>Support Slicer CLI boolean flag arguments<commit_after>import ctk_cli
import itertools
import os

from girder.models.model_base import ValidationException
from girder.plugins.worker import constants

_SLICER_TO_GIRDER_WORKER_INPUT_TYPE_MAP = {
    'boolean': 'boolean',
    'integer': 'integer',
    'float': 'number',
    'double': 'number',
    'string': 'string',
    'integer-vector': 'integer_list',
    'float-vector': 'number_list',
    'double-vector': 'number_list',
    'string-vector': 'string_list',
    'integer-enumeration': 'integer',
    'float-enumeration': 'number',
    'double-enumeration': 'number',
    'string-enumeration': 'string',
    'file': 'file',
    'directory': 'folder',
    'image': 'file',
    'pointfile': 'file'
}

_SLICER_TO_GIRDER_WORKER_OUTPUT_TYPE_MAP = {
    'file': 'new-file',
    'image': 'new-file',
    'pointfile': 'new-file'
}

_SLICER_TYPE_TO_GIRDER_MODEL_MAP = {
    'image': 'file',
    'file': 'file',
    'directory': 'folder'
}


def _validateParam(param):
    if param.channel == 'input' and param.typ not in _SLICER_TO_GIRDER_WORKER_INPUT_TYPE_MAP:
        raise ValidationException(
            'Input parameter type %s is currently not supported.' % param.typ)

    if param.channel == 'output' and param.typ not in _SLICER_TO_GIRDER_WORKER_OUTPUT_TYPE_MAP:
        raise ValidationException(
            'Output parameter type %s is currently not supported.' % param.typ)


def parseSlicerCliXml(fd):
    """
    Parse a slicer CLI XML document into a form suitable for use
    in the worker.

    :param fd: A file descriptor representing the XML document to parse.
    :type fd: file-like
    :returns: A dict of information about the CLI.
    """
    cliSpec = ctk_cli.CLIModule(stream=fd)

    description = '\n\n'.join((
        '**Description**: %s' % cliSpec.description,
        '**Author(s)**: %s' % cliSpec.contributor,
        '**Version**: %s' % cliSpec.version,
        '**License**: %s' % cliSpec.license,
        '**Acknowledgements**: %s' % (cliSpec.acknowledgements or '*none*'),
        '*This description was auto-generated from the Slicer CLI XML specification.*'
    ))

    info = {
        'title': cliSpec.title,
        'description': description,
        'args': [],
        'inputs': [],
        'outputs': []
    }

    args, opts, outputs = cliSpec.classifyParameters()

    for param in itertools.chain(args, opts):
        _validateParam(param)

    args.sort(key=lambda p: p.index)
    opts.sort(key=lambda p: p.flag or p.longflag)

    inputArgs = [a for a in args if a.channel == 'input']
    inputOpts = [o for o in opts if o.channel == 'input']
    outputArgs = [a for a in args if a.channel == 'output']
    outputOpts = [o for o in opts if o.channel == 'output']

    def ioSpec(name, param, addDefault=False):
        if param.channel == 'output':
            typ = _SLICER_TO_GIRDER_WORKER_OUTPUT_TYPE_MAP[param.typ]
        else:
            typ = _SLICER_TO_GIRDER_WORKER_INPUT_TYPE_MAP[param.typ]

        spec = {
            'id': name,
            'name': param.label,
            'description': param.description,
            'type': typ,
            'format': typ
        }

        if param.isExternalType():
            spec['target'] = 'filepath'

        if addDefault and param.default is not None:
            spec['default'] = param.default

        return spec

    for param in inputOpts:
        name = param.flag or param.longflag
        info['inputs'].append(ioSpec(name, param, True))

        if param.typ == 'boolean':
            info['args'].append('$flag{%s}' % name)
        else:
            info['args'] += [name, '$input{%s}' % name]

    for param in outputOpts:
        name = param.flag or param.longflag
        info['outputs'].append(ioSpec(name, param))
        info['args'] += [
            param.flag or param.longflag,
            os.path.join(constants.DOCKER_DATA_VOLUME, name)
        ]

    for param in inputArgs:
        info['inputs'].append(ioSpec(param.name, param, True))
        info['args'].append('$input{%s}' % param.name)

    for param in outputArgs:
        info['outputs'].append(ioSpec(param.name, param))
        info['args'].append(os.path.join(constants.DOCKER_DATA_VOLUME, param.name))

    return info
{'fraction_non_alphanumeric': 0.13868786332898328, 'fraction_numerical': 0.0, 'mean_word_length': 2.7450022212350067, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1069080', 'n_tokens_mistral': 2728, 'n_tokens_neox': 2664, 'n_words': 656}