{
    "file_diffs": [
        {
            "old_file_content": "# emacs: -*- mode: python; py-indent-offset: 4; tab-width: 4; indent-tabs-mode: nil -*-\n# ex: set sts=4 ts=4 sw=4 noet:\n# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##\n#\n#   See COPYING file distributed along with the datalad package for the\n#   copyright and license terms.\n#\n# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##\n\"\"\"High-level interface generation\n\n\"\"\"\n\n__docformat__ = 'restructuredtext'\n\nimport sys\nimport re\n\nfrom ..ui import ui\n\n\ndef get_api_name(intfspec):\n    \"\"\"Given an interface specification return an API name for it\"\"\"\n    if len(intfspec) > 3:\n        name = intfspec[3]\n    else:\n        name = intfspec[0].split('.')[-1]\n    return name\n\n\ndef get_cmdline_command_name(intfspec):\n    \"\"\"Given an interface specification return a cmdline command name\"\"\"\n    if len(intfspec) > 2:\n        name = intfspec[2]\n    else:\n        name = intfspec[0].split('.')[-1].replace('_', '-')\n    return name\n\n\ndef get_interface_groups():\n    from .. import interface as _interfaces\n\n    grps = []\n    # auto detect all available interfaces and generate a function-based\n    # API from them\n    for _item in _interfaces.__dict__:\n        if not _item.startswith('_group_'):\n            continue\n        grp_name = _item[7:]\n        grp = getattr(_interfaces, _item)\n        grps.append((grp_name,) + grp)\n    return grps\n\n\ndef dedent_docstring(text):\n    import textwrap\n    \"\"\"Remove uniform indentation from a multiline docstring\"\"\"\n    # Problem is that first line might often have no offset, so might\n    # need to be ignored from dedent call\n    if text is None:\n        return None\n    if not text.startswith(' '):\n        lines = text.split('\\n')\n        if len(lines) == 1:\n            # single line, no indentation, nothing to do\n            return text\n        text2 = '\\n'.join(lines[1:])\n        return lines[0] + \"\\n\" + textwrap.dedent(text2)\n    else:\n        return textwrap.dedent(text)\n\n\ndef alter_interface_docs_for_api(docs):\n    \"\"\"Apply modifications to interface docstrings for Python API use.\"\"\"\n    # central place to alter the impression of docstrings,\n    # like removing cmdline specific sections\n    if not docs:\n        return docs\n    docs = dedent_docstring(docs)\n    # clean cmdline sections\n    docs = re.sub(\n        '\\|\\| Command line use only \\>\\>.*\\<\\< Command line use only \\|\\|',\n        '',\n        docs,\n        flags=re.MULTILINE | re.DOTALL)\n    # clean cmdline in-line bits\n    docs = re.sub(\n        '\\[CMD:\\s.*CMD\\]',\n        '',\n        docs,\n        flags=re.MULTILINE | re.DOTALL)\n    return docs\n\n\ndef alter_interface_docs_for_cmdline(docs):\n    \"\"\"Apply modifications to interface docstrings for cmdline doc use.\"\"\"\n    # central place to alter the impression of docstrings,\n    # like removing Python API specific sections, and argument markup\n    if not docs:\n        return docs\n    docs = dedent_docstring(docs)\n    # clean cmdline sections\n    docs = re.sub(\n        '\\|\\| Python use only \\>\\>.*\\<\\< Python use only \\|\\|',\n        '',\n        docs,\n        flags=re.MULTILINE | re.DOTALL)\n    # clean cmdline in-line bits\n    docs = re.sub(\n        '\\[PY:\\s.*PY\\]',\n        '',\n        docs,\n        flags=re.MULTILINE | re.DOTALL)\n    # remove :role:`...` RST markup for cmdline docs\n    docs = re.sub(\n        r':\\S+:`[^`]*`[\\\\]*',\n        lambda match: ':'.join(match.group(0).split(':')[2:]).strip('`\\\\'),\n        docs,\n        flags=re.MULTILINE | re.DOTALL)\n    # remove None constraint. In general, `None` on the cmdline means don't\n    # give option at all, but specifying `None` explicitly is practically\n    # impossible\n    docs = re.sub(\n        ',\\sor\\svalue\\smust\\sbe\\s`None`',\n        '',\n        docs,\n        flags=re.MULTILINE | re.DOTALL)\n    # capitalize variables and remove backticks to uniformize with\n    # argparse output\n    docs = re.sub(\n        '`\\S*`',\n        lambda match: match.group(0).strip('`').upper(),\n        docs)\n    return docs\n\n\ndef update_docstring_with_parameters(func, params, prefix=None, suffix=None):\n    \"\"\"Generate a useful docstring from a parameter spec\n\n    Amends any existing docstring of a callable with a textual\n    description of its parameters. The Parameter spec needs to match\n    the number and names of the callables arguments.\n    \"\"\"\n    from inspect import getargspec\n    # get the signature\n    ndefaults = 0\n    args, varargs, varkw, defaults = getargspec(func)\n    if not defaults is None:\n        ndefaults = len(defaults)\n    # start documentation with what the callable brings with it\n    doc = prefix if prefix else u''\n    if len(args) > 1:\n        if len(doc):\n            doc += '\\n'\n        doc += \"Parameters\\n----------\\n\"\n        for i, arg in enumerate(args):\n            if arg == 'self':\n                continue\n            # we need a parameter spec for each argument\n            if not arg in params:\n                raise ValueError(\"function has argument '%s' not described as a parameter\" % arg)\n            param = params[arg]\n            # validate the default -- to make sure that the parameter description is\n            # somewhat OK\n            defaults_idx = ndefaults - len(args) + i\n            if defaults_idx >= 0:\n                if not param.constraints is None:\n                    param.constraints(defaults[defaults_idx])\n            doc += param.get_autodoc(\n                arg,\n                default=defaults[defaults_idx] if defaults_idx >= 0 else None,\n                has_default=defaults_idx >= 0)\n            doc += '\\n'\n    doc += suffix if suffix else u\"\"\n    # assign the amended docs\n    func.__doc__ = doc\n    return func\n\n\nclass Interface(object):\n    \"\"\"Base class for interface implementations\"\"\"\n\n    @classmethod\n    def setup_parser(cls, parser):\n        # XXX needs safety check for name collisions\n        # XXX allow for parser kwargs customization\n        parser_kwargs = {}\n        from inspect import getargspec\n        # get the signature\n        ndefaults = 0\n        args, varargs, varkw, defaults = getargspec(cls.__call__)\n        if not defaults is None:\n            ndefaults = len(defaults)\n        for i, arg in enumerate(args):\n            if arg == 'self':\n                continue\n            param = cls._params_[arg]\n            defaults_idx = ndefaults - len(args) + i\n            cmd_args = param.cmd_args\n            if cmd_args is None:\n                cmd_args = []\n            if not len(cmd_args):\n                if defaults_idx >= 0:\n                    # dealing with a kwarg\n                    template = '--%s'\n                else:\n                    # positional arg\n                    template = '%s'\n                # use parameter name as default argument name\n                parser_args = (template % arg.replace('_', '-'),)\n            else:\n                parser_args = [c.replace('_', '-') for c in cmd_args]\n            parser_kwargs = param.cmd_kwargs\n            if defaults_idx >= 0:\n                parser_kwargs['default'] = defaults[defaults_idx]\n            help = alter_interface_docs_for_cmdline(param._doc)\n            if help and help[-1] != '.':\n                help += '.'\n            if param.constraints is not None:\n                parser_kwargs['type'] = param.constraints\n                # include value contraint description and default\n                # into the help string\n                cdoc = alter_interface_docs_for_cmdline(\n                    param.constraints.long_description())\n                if cdoc[0] == '(' and cdoc[-1] == ')':\n                    cdoc = cdoc[1:-1]\n                help += '  Constraints: %s' % cdoc\n            if defaults_idx >= 0:\n                help += \" [Default: %r]\" % (defaults[defaults_idx],)\n            # create the parameter, using the constraint instance for type\n            # conversion\n            parser.add_argument(*parser_args, help=help,\n                                **parser_kwargs)\n\n    @classmethod\n    def call_from_parser(cls, args):\n        # XXX needs safety check for name collisions\n        from inspect import getargspec\n        argnames = getargspec(cls.__call__)[0]\n        kwargs = {k: getattr(args, k) for k in argnames if k != 'self'}\n        try:\n            return cls.__call__(**kwargs)\n        except KeyboardInterrupt:\n            ui.error(\"\\nInterrupted by user while doing magic\")\n            sys.exit(1)\n",
            "new_file_content": "# emacs: -*- mode: python; py-indent-offset: 4; tab-width: 4; indent-tabs-mode: nil -*-\n# ex: set sts=4 ts=4 sw=4 noet:\n# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##\n#\n#   See COPYING file distributed along with the datalad package for the\n#   copyright and license terms.\n#\n# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##\n\"\"\"High-level interface generation\n\n\"\"\"\n\n__docformat__ = 'restructuredtext'\n\nimport sys\nimport re\n\nfrom ..ui import ui\n\n\ndef get_api_name(intfspec):\n    \"\"\"Given an interface specification return an API name for it\"\"\"\n    if len(intfspec) > 3:\n        name = intfspec[3]\n    else:\n        name = intfspec[0].split('.')[-1]\n    return name\n\n\ndef get_cmdline_command_name(intfspec):\n    \"\"\"Given an interface specification return a cmdline command name\"\"\"\n    if len(intfspec) > 2:\n        name = intfspec[2]\n    else:\n        name = intfspec[0].split('.')[-1].replace('_', '-')\n    return name\n\n\ndef get_interface_groups():\n    from .. import interface as _interfaces\n\n    grps = []\n    # auto detect all available interfaces and generate a function-based\n    # API from them\n    for _item in _interfaces.__dict__:\n        if not _item.startswith('_group_'):\n            continue\n        grp_name = _item[7:]\n        grp = getattr(_interfaces, _item)\n        grps.append((grp_name,) + grp)\n    return grps\n\n\ndef dedent_docstring(text):\n    import textwrap\n    \"\"\"Remove uniform indentation from a multiline docstring\"\"\"\n    # Problem is that first line might often have no offset, so might\n    # need to be ignored from dedent call\n    if text is None:\n        return None\n    if not text.startswith(' '):\n        lines = text.split('\\n')\n        if len(lines) == 1:\n            # single line, no indentation, nothing to do\n            return text\n        text2 = '\\n'.join(lines[1:])\n        return lines[0] + \"\\n\" + textwrap.dedent(text2)\n    else:\n        return textwrap.dedent(text)\n\n\ndef alter_interface_docs_for_api(docs):\n    \"\"\"Apply modifications to interface docstrings for Python API use.\"\"\"\n    # central place to alter the impression of docstrings,\n    # like removing cmdline specific sections\n    if not docs:\n        return docs\n    docs = dedent_docstring(docs)\n    # clean cmdline sections\n    docs = re.sub(\n        '\\|\\| CMDLINE \\>\\>.*\\<\\< CMDLINE \\|\\|',\n        '',\n        docs,\n        flags=re.MULTILINE | re.DOTALL)\n    # clean cmdline in-line bits\n    docs = re.sub(\n        '\\[CMD:\\s.*\\sCMD\\]',\n        '',\n        docs,\n        flags=re.MULTILINE | re.DOTALL)\n    docs = re.sub(\n        '\\[PY:\\s(.*)\\sPY\\]',\n        lambda match: match.group(1),\n        docs,\n        flags=re.MULTILINE)\n    docs = re.sub(\n        '\\|\\| PYTHON \\>\\>(.*)\\<\\< PYTHON \\|\\|',\n        lambda match: match.group(1),\n        docs,\n        flags=re.MULTILINE | re.DOTALL)\n    return docs\n\n\ndef alter_interface_docs_for_cmdline(docs):\n    \"\"\"Apply modifications to interface docstrings for cmdline doc use.\"\"\"\n    # central place to alter the impression of docstrings,\n    # like removing Python API specific sections, and argument markup\n    if not docs:\n        return docs\n    docs = dedent_docstring(docs)\n    # clean cmdline sections\n    docs = re.sub(\n        '\\|\\| PYTHON \\>\\>.*\\<\\< PYTHON \\|\\|',\n        '',\n        docs,\n        flags=re.MULTILINE | re.DOTALL)\n    # clean cmdline in-line bits\n    docs = re.sub(\n        '\\[PY:\\s.*\\sPY\\]',\n        '',\n        docs,\n        flags=re.MULTILINE | re.DOTALL)\n    docs = re.sub(\n        '\\[CMD:\\s(.*)\\sCMD\\]',\n        lambda match: match.group(1),\n        docs,\n        flags=re.MULTILINE)\n    docs = re.sub(\n        '\\|\\| CMDLINE \\>\\>(.*)\\<\\< CMDLINE \\|\\|',\n        lambda match: match.group(1),\n        docs,\n        flags=re.MULTILINE | re.DOTALL)\n    # remove :role:`...` RST markup for cmdline docs\n    docs = re.sub(\n        r':\\S+:`[^`]*`[\\\\]*',\n        lambda match: ':'.join(match.group(0).split(':')[2:]).strip('`\\\\'),\n        docs,\n        flags=re.MULTILINE | re.DOTALL)\n    # remove None constraint. In general, `None` on the cmdline means don't\n    # give option at all, but specifying `None` explicitly is practically\n    # impossible\n    docs = re.sub(\n        ',\\sor\\svalue\\smust\\sbe\\s`None`',\n        '',\n        docs,\n        flags=re.MULTILINE | re.DOTALL)\n    # capitalize variables and remove backticks to uniformize with\n    # argparse output\n    docs = re.sub(\n        '`\\S*`',\n        lambda match: match.group(0).strip('`').upper(),\n        docs)\n    return docs\n\n\ndef update_docstring_with_parameters(func, params, prefix=None, suffix=None):\n    \"\"\"Generate a useful docstring from a parameter spec\n\n    Amends any existing docstring of a callable with a textual\n    description of its parameters. The Parameter spec needs to match\n    the number and names of the callables arguments.\n    \"\"\"\n    from inspect import getargspec\n    # get the signature\n    ndefaults = 0\n    args, varargs, varkw, defaults = getargspec(func)\n    if not defaults is None:\n        ndefaults = len(defaults)\n    # start documentation with what the callable brings with it\n    doc = prefix if prefix else u''\n    if len(args) > 1:\n        if len(doc):\n            doc += '\\n'\n        doc += \"Parameters\\n----------\\n\"\n        for i, arg in enumerate(args):\n            if arg == 'self':\n                continue\n            # we need a parameter spec for each argument\n            if not arg in params:\n                raise ValueError(\"function has argument '%s' not described as a parameter\" % arg)\n            param = params[arg]\n            # validate the default -- to make sure that the parameter description is\n            # somewhat OK\n            defaults_idx = ndefaults - len(args) + i\n            if defaults_idx >= 0:\n                if not param.constraints is None:\n                    param.constraints(defaults[defaults_idx])\n            doc += param.get_autodoc(\n                arg,\n                default=defaults[defaults_idx] if defaults_idx >= 0 else None,\n                has_default=defaults_idx >= 0)\n            doc += '\\n'\n    doc += suffix if suffix else u\"\"\n    # assign the amended docs\n    func.__doc__ = doc\n    return func\n\n\nclass Interface(object):\n    \"\"\"Base class for interface implementations\"\"\"\n\n    @classmethod\n    def setup_parser(cls, parser):\n        # XXX needs safety check for name collisions\n        # XXX allow for parser kwargs customization\n        parser_kwargs = {}\n        from inspect import getargspec\n        # get the signature\n        ndefaults = 0\n        args, varargs, varkw, defaults = getargspec(cls.__call__)\n        if not defaults is None:\n            ndefaults = len(defaults)\n        for i, arg in enumerate(args):\n            if arg == 'self':\n                continue\n            param = cls._params_[arg]\n            defaults_idx = ndefaults - len(args) + i\n            cmd_args = param.cmd_args\n            if cmd_args is None:\n                cmd_args = []\n            if not len(cmd_args):\n                if defaults_idx >= 0:\n                    # dealing with a kwarg\n                    template = '--%s'\n                else:\n                    # positional arg\n                    template = '%s'\n                # use parameter name as default argument name\n                parser_args = (template % arg.replace('_', '-'),)\n            else:\n                parser_args = [c.replace('_', '-') for c in cmd_args]\n            parser_kwargs = param.cmd_kwargs\n            if defaults_idx >= 0:\n                parser_kwargs['default'] = defaults[defaults_idx]\n            help = alter_interface_docs_for_cmdline(param._doc)\n            if help and help[-1] != '.':\n                help += '.'\n            if param.constraints is not None:\n                parser_kwargs['type'] = param.constraints\n                # include value contraint description and default\n                # into the help string\n                cdoc = alter_interface_docs_for_cmdline(\n                    param.constraints.long_description())\n                if cdoc[0] == '(' and cdoc[-1] == ')':\n                    cdoc = cdoc[1:-1]\n                help += '  Constraints: %s' % cdoc\n            if defaults_idx >= 0:\n                help += \" [Default: %r]\" % (defaults[defaults_idx],)\n            # create the parameter, using the constraint instance for type\n            # conversion\n            parser.add_argument(*parser_args, help=help,\n                                **parser_kwargs)\n\n    @classmethod\n    def call_from_parser(cls, args):\n        # XXX needs safety check for name collisions\n        from inspect import getargspec\n        argnames = getargspec(cls.__call__)[0]\n        kwargs = {k: getattr(args, k) for k in argnames if k != 'self'}\n        try:\n            return cls.__call__(**kwargs)\n        except KeyboardInterrupt:\n            ui.error(\"\\nInterrupted by user while doing magic\")\n            sys.exit(1)\n",
            "header": {
                "file": {
                    "path": "datalad/interface/base.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "35aba6bed",
                "new_commit_hash": "37dbd595c",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/datalad/interface/base.py"
            },
            "plus_file": {
                "path": "b/datalad/interface/base.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 78,
                            "length": 16
                        },
                        "new_range": {
                            "start": 78,
                            "length": 26
                        },
                        "section": "def alter_interface_docs_for_api(docs):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "    docs = dedent_docstring(docs)",
                                "type": "context"
                            },
                            {
                                "content": "    # clean cmdline sections",
                                "type": "context"
                            },
                            {
                                "content": "    docs = re.sub(",
                                "type": "context"
                            },
                            {
                                "content": "        '\\|\\| Command line use only \\>\\>.*\\<\\< Command line use only \\|\\|',",
                                "type": "deleted"
                            },
                            {
                                "content": "        '\\|\\| CMDLINE \\>\\>.*\\<\\< CMDLINE \\|\\|',",
                                "type": "added"
                            },
                            {
                                "content": "        '',",
                                "type": "context"
                            },
                            {
                                "content": "        docs,",
                                "type": "context"
                            },
                            {
                                "content": "        flags=re.MULTILINE | re.DOTALL)",
                                "type": "context"
                            },
                            {
                                "content": "    # clean cmdline in-line bits",
                                "type": "context"
                            },
                            {
                                "content": "    docs = re.sub(",
                                "type": "context"
                            },
                            {
                                "content": "        '\\[CMD:\\s.*CMD\\]',",
                                "type": "deleted"
                            },
                            {
                                "content": "        '\\[CMD:\\s.*\\sCMD\\]',",
                                "type": "added"
                            },
                            {
                                "content": "        '',",
                                "type": "context"
                            },
                            {
                                "content": "        docs,",
                                "type": "context"
                            },
                            {
                                "content": "        flags=re.MULTILINE | re.DOTALL)",
                                "type": "context"
                            },
                            {
                                "content": "    docs = re.sub(",
                                "type": "added"
                            },
                            {
                                "content": "        '\\[PY:\\s(.*)\\sPY\\]',",
                                "type": "added"
                            },
                            {
                                "content": "        lambda match: match.group(1),",
                                "type": "added"
                            },
                            {
                                "content": "        docs,",
                                "type": "added"
                            },
                            {
                                "content": "        flags=re.MULTILINE)",
                                "type": "added"
                            },
                            {
                                "content": "    docs = re.sub(",
                                "type": "added"
                            },
                            {
                                "content": "        '\\|\\| PYTHON \\>\\>(.*)\\<\\< PYTHON \\|\\|',",
                                "type": "added"
                            },
                            {
                                "content": "        lambda match: match.group(1),",
                                "type": "added"
                            },
                            {
                                "content": "        docs,",
                                "type": "added"
                            },
                            {
                                "content": "        flags=re.MULTILINE | re.DOTALL)",
                                "type": "added"
                            },
                            {
                                "content": "    return docs",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "datalad/interface/base.py",
                            "type": "function",
                            "name": "alter_interface_docs_for_api",
                            "content": "def alter_interface_docs_for_api(docs):\n    \"\"\"Apply modifications to interface docstrings for Python API use.\"\"\"\n    # central place to alter the impression of docstrings,\n    # like removing cmdline specific sections\n    if not docs:\n        return docs\n    docs = dedent_docstring(docs)\n    # clean cmdline sections\n    docs = re.sub(\n        '\\|\\| Command line use only \\>\\>.*\\<\\< Command line use only \\|\\|',\n        '',\n        docs,\n        flags=re.MULTILINE | re.DOTALL)\n    # clean cmdline in-line bits\n    docs = re.sub(\n        '\\[CMD:\\s.*CMD\\]',\n        '',\n        docs,\n        flags=re.MULTILINE | re.DOTALL)\n    return docs",
                            "ast_type_str": "FunctionDef",
                            "start_lineno": 72,
                            "end_lineno": 91,
                            "parent": null
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                },
                {
                    "descriptor": {
                        "old_range": {
                            "start": 100,
                            "length": 16
                        },
                        "new_range": {
                            "start": 110,
                            "length": 26
                        },
                        "section": "def alter_interface_docs_for_cmdline(docs):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "    docs = dedent_docstring(docs)",
                                "type": "context"
                            },
                            {
                                "content": "    # clean cmdline sections",
                                "type": "context"
                            },
                            {
                                "content": "    docs = re.sub(",
                                "type": "context"
                            },
                            {
                                "content": "        '\\|\\| Python use only \\>\\>.*\\<\\< Python use only \\|\\|',",
                                "type": "deleted"
                            },
                            {
                                "content": "        '\\|\\| PYTHON \\>\\>.*\\<\\< PYTHON \\|\\|',",
                                "type": "added"
                            },
                            {
                                "content": "        '',",
                                "type": "context"
                            },
                            {
                                "content": "        docs,",
                                "type": "context"
                            },
                            {
                                "content": "        flags=re.MULTILINE | re.DOTALL)",
                                "type": "context"
                            },
                            {
                                "content": "    # clean cmdline in-line bits",
                                "type": "context"
                            },
                            {
                                "content": "    docs = re.sub(",
                                "type": "context"
                            },
                            {
                                "content": "        '\\[PY:\\s.*PY\\]',",
                                "type": "deleted"
                            },
                            {
                                "content": "        '\\[PY:\\s.*\\sPY\\]',",
                                "type": "added"
                            },
                            {
                                "content": "        '',",
                                "type": "context"
                            },
                            {
                                "content": "        docs,",
                                "type": "context"
                            },
                            {
                                "content": "        flags=re.MULTILINE | re.DOTALL)",
                                "type": "context"
                            },
                            {
                                "content": "    docs = re.sub(",
                                "type": "added"
                            },
                            {
                                "content": "        '\\[CMD:\\s(.*)\\sCMD\\]',",
                                "type": "added"
                            },
                            {
                                "content": "        lambda match: match.group(1),",
                                "type": "added"
                            },
                            {
                                "content": "        docs,",
                                "type": "added"
                            },
                            {
                                "content": "        flags=re.MULTILINE)",
                                "type": "added"
                            },
                            {
                                "content": "    docs = re.sub(",
                                "type": "added"
                            },
                            {
                                "content": "        '\\|\\| CMDLINE \\>\\>(.*)\\<\\< CMDLINE \\|\\|',",
                                "type": "added"
                            },
                            {
                                "content": "        lambda match: match.group(1),",
                                "type": "added"
                            },
                            {
                                "content": "        docs,",
                                "type": "added"
                            },
                            {
                                "content": "        flags=re.MULTILINE | re.DOTALL)",
                                "type": "added"
                            },
                            {
                                "content": "    # remove :role:`...` RST markup for cmdline docs",
                                "type": "context"
                            },
                            {
                                "content": "    docs = re.sub(",
                                "type": "context"
                            },
                            {
                                "content": "        r':\\S+:`[^`]*`[\\\\]*',",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "datalad/interface/base.py",
                            "type": "function",
                            "name": "alter_interface_docs_for_cmdline",
                            "content": "def alter_interface_docs_for_cmdline(docs):\n    \"\"\"Apply modifications to interface docstrings for cmdline doc use.\"\"\"\n    # central place to alter the impression of docstrings,\n    # like removing Python API specific sections, and argument markup\n    if not docs:\n        return docs\n    docs = dedent_docstring(docs)\n    # clean cmdline sections\n    docs = re.sub(\n        '\\|\\| Python use only \\>\\>.*\\<\\< Python use only \\|\\|',\n        '',\n        docs,\n        flags=re.MULTILINE | re.DOTALL)\n    # clean cmdline in-line bits\n    docs = re.sub(\n        '\\[PY:\\s.*PY\\]',\n        '',\n        docs,\n        flags=re.MULTILINE | re.DOTALL)\n    # remove :role:`...` RST markup for cmdline docs\n    docs = re.sub(\n        r':\\S+:`[^`]*`[\\\\]*',\n        lambda match: ':'.join(match.group(0).split(':')[2:]).strip('`\\\\'),\n        docs,\n        flags=re.MULTILINE | re.DOTALL)\n    # remove None constraint. In general, `None` on the cmdline means don't\n    # give option at all, but specifying `None` explicitly is practically\n    # impossible\n    docs = re.sub(\n        ',\\sor\\svalue\\smust\\sbe\\s`None`',\n        '',\n        docs,\n        flags=re.MULTILINE | re.DOTALL)\n    # capitalize variables and remove backticks to uniformize with\n    # argparse output\n    docs = re.sub(\n        '`\\S*`',\n        lambda match: match.group(0).strip('`').upper(),\n        docs)\n    return docs",
                            "ast_type_str": "FunctionDef",
                            "start_lineno": 94,
                            "end_lineno": 133,
                            "parent": null
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                }
            ]
        },
        {
            "old_file_content": "# emacs: -*- mode: python; py-indent-offset: 4; tab-width: 4; indent-tabs-mode: nil -*-\n# ex: set sts=4 ts=4 sw=4 noet:\n# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##\n#\n#   See COPYING file distributed along with the datalad package for the\n#   copyright and license terms.\n#\n# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##\n\"\"\"Tests for interface doc wranglers.\n\n\"\"\"\n\n__docformat__ = 'restructuredtext'\n\nfrom datalad.interface.base import dedent_docstring\nfrom datalad.interface.base import alter_interface_docs_for_api\nfrom datalad.interface.base import alter_interface_docs_for_cmdline\nfrom datalad.tests.utils import assert_true, assert_false, assert_in, \\\n    assert_not_in, eq_\n\n\ndemo_doc = \"\"\"\\\n    Bla bla summary\n\n    Generic intro blurb. Ping pong ping pong ping pong ping pong.  Ping pong ping\n    pong ping pong ping pong. Ping pong ping pong ping pong ping pong. Ping pong\n    ping pong ping pong ping pong. Ping pong ping pong ping pong ping pong. Ping\n    pong ping pong ping pong ping pong.\n\n    || Command line use only >>\n    Something for the cmdline only CMDONLY\n    Multiline!\n    << Command line use only ||\n\n    || Python use only >>\n\n    Some Python-only bits PYONLY\n    Multiline!\n\n    << Python use only ||\n\n    And an example for in-line markup: [PY: just for Python PY] and\n    the other one [CMD: just for the command line CMD]. End of demo.\n\n    Generic appendix. Ding dong ding dong ding dong.  Ding dong ding dong ding\n    dong.  Ding dong ding dong ding dong.  Ding dong ding dong ding dong.  Ding\n    dong ding dong ding dong.\n\n\"\"\"\n\ndemo_paramdoc = \"\"\"\\\n\n    Parameters\n    ----------\n    dataset : Dataset or None, optional\n      specify the dataset to perform the install operation on. If no\n      dataset is given, an attempt is made to identify the dataset based\n      on the current working directory and/or the `path` given.\n      Constraints: Value must be a Dataset or a valid identifier of a\n      Dataset (e.g. a path), or value must be `None`. [Default: None]\n\"\"\"\n\ndemo_argdoc = \"\"\"\\\n    specify the dataset to perform the install operation\n    on. If no dataset is given, an attempt is made to\n    identify the dataset based on the current working\n    directory and/or the `path` given. Constraints: Value\n    must be a Dataset or a valid identifier of a Dataset\n    (e.g. a path), or value must be `None`. [Default:\n    None]\n\"\"\"\n\n\ndef test_dedent():\n    assert_false(dedent_docstring(\"one liner\").endswith(\"\\n\"))\n\n\ndef test_alter_interface_docs_for_api():\n    alt = alter_interface_docs_for_api(demo_doc)\n    alt_l = alt.split('\\n')\n    # dedented\n    assert_false(alt_l[0].startswith(' '))\n    assert_false(alt_l[-1].startswith(' '))\n    assert_not_in('CMD', alt)\n    assert_not_in('Command line', alt)\n\n\ndef test_alter_interface_docs_for_cmdline():\n    alt = alter_interface_docs_for_cmdline(demo_doc)\n    alt_l = alt.split('\\n')\n    # dedented\n    assert_false(alt_l[0].startswith(' '))\n    assert_false(alt_l[-1].startswith(' '))\n    assert_not_in('PY', alt)\n    assert_not_in('Python', alt)\n    # args\n    altarg = alter_interface_docs_for_cmdline(demo_argdoc)\n    # RST role markup\n    eq_(alter_interface_docs_for_cmdline(':murks:`me and my buddies`'),\n        'me and my buddies')\n    # spread across lines\n    eq_(alter_interface_docs_for_cmdline(':term:`Barbara\\nStreisand`'),\n        'Barbara\\nStreisand')\n    # multiple on one line\n    eq_(alter_interface_docs_for_cmdline(\n        ':term:`one` bla bla :term:`two` bla'),\n        'one bla bla two bla')\n",
            "new_file_content": "# emacs: -*- mode: python; py-indent-offset: 4; tab-width: 4; indent-tabs-mode: nil -*-\n# ex: set sts=4 ts=4 sw=4 noet:\n# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##\n#\n#   See COPYING file distributed along with the datalad package for the\n#   copyright and license terms.\n#\n# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##\n\"\"\"Tests for interface doc wranglers.\n\n\"\"\"\n\n__docformat__ = 'restructuredtext'\n\nfrom datalad.interface.base import dedent_docstring\nfrom datalad.interface.base import alter_interface_docs_for_api\nfrom datalad.interface.base import alter_interface_docs_for_cmdline\nfrom datalad.tests.utils import assert_true, assert_false, assert_in, \\\n    assert_not_in, eq_\n\n\ndemo_doc = \"\"\"\\\n    Bla bla summary\n\n    Generic intro blurb. Ping pong ping pong ping pong ping pong.  Ping pong ping\n    pong ping pong ping pong. Ping pong ping pong ping pong ping pong. Ping pong\n    ping pong ping pong ping pong. Ping pong ping pong ping pong ping pong. Ping\n    pong ping pong ping pong ping pong.\n\n    || CMDLINE >>\n    Something for the cmdline only\n    Multiline!\n    << CMDLINE ||\n\n    || PYTHON >>\n\n    Some Python-only bits\n    Multiline!\n\n    << PYTHON ||\n\n    And an example for in-line markup: [PY: just for Python PY] and\n    the other one [CMD: just for the command line CMD]. End of demo.\n\n    Generic appendix. Ding dong ding dong ding dong.  Ding dong ding dong ding\n    dong.  Ding dong ding dong ding dong.  Ding dong ding dong ding dong.  Ding\n    dong ding dong ding dong.\n\n\"\"\"\n\ndemo_paramdoc = \"\"\"\\\n\n    Parameters\n    ----------\n    dataset : Dataset or None, optional\n      specify the dataset to perform the install operation on. If no\n      dataset is given, an attempt is made to identify the dataset based\n      on the current working directory and/or the `path` given.\n      Constraints: Value must be a Dataset or a valid identifier of a\n      Dataset (e.g. a path), or value must be `None`. [Default: None]\n\"\"\"\n\ndemo_argdoc = \"\"\"\\\n    specify the dataset to perform the install operation\n    on. If no dataset is given, an attempt is made to\n    identify the dataset based on the current working\n    directory and/or the `path` given. Constraints: Value\n    must be a Dataset or a valid identifier of a Dataset\n    (e.g. a path), or value must be `None`. [Default:\n    None]\n\"\"\"\n\n\ndef test_dedent():\n    assert_false(dedent_docstring(\"one liner\").endswith(\"\\n\"))\n\n\ndef test_alter_interface_docs_for_api():\n    alt = alter_interface_docs_for_api(demo_doc)\n    alt_l = alt.split('\\n')\n    # dedented\n    assert_false(alt_l[0].startswith(' '))\n    assert_false(alt_l[-1].startswith(' '))\n    assert_not_in('CMD', alt)\n    assert_not_in('PY', alt)\n\n\ndef test_alter_interface_docs_for_cmdline():\n    alt = alter_interface_docs_for_cmdline(demo_doc)\n    alt_l = alt.split('\\n')\n    # dedented\n    assert_false(alt_l[0].startswith(' '))\n    assert_false(alt_l[-1].startswith(' '))\n    assert_not_in('PY', alt)\n    assert_not_in('CMD', alt)\n    # args\n    altarg = alter_interface_docs_for_cmdline(demo_argdoc)\n    # RST role markup\n    eq_(alter_interface_docs_for_cmdline(':murks:`me and my buddies`'),\n        'me and my buddies')\n    # spread across lines\n    eq_(alter_interface_docs_for_cmdline(':term:`Barbara\\nStreisand`'),\n        'Barbara\\nStreisand')\n    # multiple on one line\n    eq_(alter_interface_docs_for_cmdline(\n        ':term:`one` bla bla :term:`two` bla'),\n        'one bla bla two bla')\n",
            "header": {
                "file": {
                    "path": "datalad/interface/tests/test_docs.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "0c8b10b16",
                "new_commit_hash": "e078f606c",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/datalad/interface/tests/test_docs.py"
            },
            "plus_file": {
                "path": "b/datalad/interface/tests/test_docs.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 27,
                            "length": 17
                        },
                        "new_range": {
                            "start": 27,
                            "length": 17
                        },
                        "section": "demo_doc = \"\"\"\\"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "    ping pong ping pong ping pong. Ping pong ping pong ping pong ping pong. Ping",
                                "type": "context"
                            },
                            {
                                "content": "    pong ping pong ping pong ping pong.",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "    || Command line use only >>",
                                "type": "deleted"
                            },
                            {
                                "content": "    Something for the cmdline only CMDONLY",
                                "type": "deleted"
                            },
                            {
                                "content": "    || CMDLINE >>",
                                "type": "added"
                            },
                            {
                                "content": "    Something for the cmdline only",
                                "type": "added"
                            },
                            {
                                "content": "    Multiline!",
                                "type": "context"
                            },
                            {
                                "content": "    << Command line use only ||",
                                "type": "deleted"
                            },
                            {
                                "content": "    << CMDLINE ||",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "    || Python use only >>",
                                "type": "deleted"
                            },
                            {
                                "content": "    || PYTHON >>",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "    Some Python-only bits PYONLY",
                                "type": "deleted"
                            },
                            {
                                "content": "    Some Python-only bits",
                                "type": "added"
                            },
                            {
                                "content": "    Multiline!",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "    << Python use only ||",
                                "type": "deleted"
                            },
                            {
                                "content": "    << PYTHON ||",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "    And an example for in-line markup: [PY: just for Python PY] and",
                                "type": "context"
                            },
                            {
                                "content": "    the other one [CMD: just for the command line CMD]. End of demo.",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [],
                    "added_entities": [
                        {
                            "file_name": "datalad/interface/tests/test_docs.py",
                            "type": "statement",
                            "name": "",
                            "content": "demo_doc = \"\"\"\\\n    Bla bla summary\n\n    Generic intro blurb. Ping pong ping pong ping pong ping pong.  Ping pong ping\n    pong ping pong ping pong. Ping pong ping pong ping pong ping pong. Ping pong\n    ping pong ping pong ping pong. Ping pong ping pong ping pong ping pong. Ping\n    pong ping pong ping pong ping pong.\n\n    || CMDLINE >>\n    Something for the cmdline only\n    Multiline!\n    << CMDLINE ||\n\n    || PYTHON >>\n\n    Some Python-only bits\n    Multiline!\n\n    << PYTHON ||\n\n    And an example for in-line markup: [PY: just for Python PY] and\n    the other one [CMD: just for the command line CMD]. End of demo.\n\n    Generic appendix. Ding dong ding dong ding dong.  Ding dong ding dong ding\n    dong.  Ding dong ding dong ding dong.  Ding dong ding dong ding dong.  Ding\n    dong ding dong ding dong.\n\n\"\"\"",
                            "ast_type_str": "Assign",
                            "start_lineno": 22,
                            "end_lineno": 49,
                            "parent": null
                        }
                    ],
                    "deleted_entities": [
                        {
                            "file_name": "datalad/interface/tests/test_docs.py",
                            "type": "statement",
                            "name": "",
                            "content": "demo_doc = \"\"\"\\\n    Bla bla summary\n\n    Generic intro blurb. Ping pong ping pong ping pong ping pong.  Ping pong ping\n    pong ping pong ping pong. Ping pong ping pong ping pong ping pong. Ping pong\n    ping pong ping pong ping pong. Ping pong ping pong ping pong ping pong. Ping\n    pong ping pong ping pong ping pong.\n\n    || Command line use only >>\n    Something for the cmdline only CMDONLY\n    Multiline!\n    << Command line use only ||\n\n    || Python use only >>\n\n    Some Python-only bits PYONLY\n    Multiline!\n\n    << Python use only ||\n\n    And an example for in-line markup: [PY: just for Python PY] and\n    the other one [CMD: just for the command line CMD]. End of demo.\n\n    Generic appendix. Ding dong ding dong ding dong.  Ding dong ding dong ding\n    dong.  Ding dong ding dong ding dong.  Ding dong ding dong ding dong.  Ding\n    dong ding dong ding dong.\n\n\"\"\"",
                            "ast_type_str": "Assign",
                            "start_lineno": 22,
                            "end_lineno": 49,
                            "parent": null
                        }
                    ]
                },
                {
                    "descriptor": {
                        "old_range": {
                            "start": 82,
                            "length": 7
                        },
                        "new_range": {
                            "start": 82,
                            "length": 7
                        },
                        "section": "def test_alter_interface_docs_for_api():"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "    assert_false(alt_l[0].startswith(' '))",
                                "type": "context"
                            },
                            {
                                "content": "    assert_false(alt_l[-1].startswith(' '))",
                                "type": "context"
                            },
                            {
                                "content": "    assert_not_in('CMD', alt)",
                                "type": "context"
                            },
                            {
                                "content": "    assert_not_in('Command line', alt)",
                                "type": "deleted"
                            },
                            {
                                "content": "    assert_not_in('PY', alt)",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "def test_alter_interface_docs_for_cmdline():",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "datalad/interface/tests/test_docs.py",
                            "type": "function",
                            "name": "test_alter_interface_docs_for_api",
                            "content": "def test_alter_interface_docs_for_api():\n    alt = alter_interface_docs_for_api(demo_doc)\n    alt_l = alt.split('\\n')\n    # dedented\n    assert_false(alt_l[0].startswith(' '))\n    assert_false(alt_l[-1].startswith(' '))\n    assert_not_in('CMD', alt)\n    assert_not_in('Command line', alt)",
                            "ast_type_str": "FunctionDef",
                            "start_lineno": 78,
                            "end_lineno": 85,
                            "parent": null
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                },
                {
                    "descriptor": {
                        "old_range": {
                            "start": 92,
                            "length": 7
                        },
                        "new_range": {
                            "start": 92,
                            "length": 7
                        },
                        "section": "def test_alter_interface_docs_for_cmdline():"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "    assert_false(alt_l[0].startswith(' '))",
                                "type": "context"
                            },
                            {
                                "content": "    assert_false(alt_l[-1].startswith(' '))",
                                "type": "context"
                            },
                            {
                                "content": "    assert_not_in('PY', alt)",
                                "type": "context"
                            },
                            {
                                "content": "    assert_not_in('Python', alt)",
                                "type": "deleted"
                            },
                            {
                                "content": "    assert_not_in('CMD', alt)",
                                "type": "added"
                            },
                            {
                                "content": "    # args",
                                "type": "context"
                            },
                            {
                                "content": "    altarg = alter_interface_docs_for_cmdline(demo_argdoc)",
                                "type": "context"
                            },
                            {
                                "content": "    # RST role markup",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "datalad/interface/tests/test_docs.py",
                            "type": "function",
                            "name": "test_alter_interface_docs_for_cmdline",
                            "content": "def test_alter_interface_docs_for_cmdline():\n    alt = alter_interface_docs_for_cmdline(demo_doc)\n    alt_l = alt.split('\\n')\n    # dedented\n    assert_false(alt_l[0].startswith(' '))\n    assert_false(alt_l[-1].startswith(' '))\n    assert_not_in('PY', alt)\n    assert_not_in('Python', alt)\n    # args\n    altarg = alter_interface_docs_for_cmdline(demo_argdoc)\n    # RST role markup\n    eq_(alter_interface_docs_for_cmdline(':murks:`me and my buddies`'),\n        'me and my buddies')\n    # spread across lines\n    eq_(alter_interface_docs_for_cmdline(':term:`Barbara\\nStreisand`'),\n        'Barbara\\nStreisand')\n    # multiple on one line\n    eq_(alter_interface_docs_for_cmdline(\n        ':term:`one` bla bla :term:`two` bla'),\n        'one bla bla two bla')",
                            "ast_type_str": "FunctionDef",
                            "start_lineno": 88,
                            "end_lineno": 107,
                            "parent": null
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                }
            ]
        },
        {
            "old_file_content": "# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*-\n# vi: set ft=python sts=4 ts=4 sw=4 et:\n### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##\n#\n#   See COPYING file distributed along with the datalad package for the\n#   copyright and license terms.\n#\n### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##g\n\"\"\"Parameter representation\"\"\"\n\n__docformat__ = 'restructuredtext'\n\nimport re\nimport textwrap\nfrom .constraints import expand_contraint_spec\n\n_whitespace_re = re.compile('\\n\\s+|^\\s+')\n\n\nclass Parameter(object):\n    \"\"\"This class shall serve as a representation of a parameter.\n    \"\"\"\n\n    def __init__(self, constraints=None, doc=None, args=None, **kwargs):\n        \"\"\"Add contraints (validator) specifications and a docstring for\n        a parameter.\n\n        Parameters\n        ----------\n        constraints : callable\n          A functor that takes any input value, performs checks or type\n          conversions and finally returns a value that is appropriate for a\n          parameter or raises an exception. This will also be used to set up\n          the ``type`` functionality of argparse.add_argument.\n        doc : str\n          Documentation about the purpose of this parameter.\n        args : tuple or None\n          Any additional positional args for argparser.add_argument. This is\n          most useful for assigned multiple alternative argument names or\n          create positional arguments.\n        **kwargs :\n          Any additional keyword args for argparser.add_argument.\n\n        Examples\n        --------\n        Ensure a parameter is a float\n        >>> from datalad.support.param import Parameter\n        >>> from datalad.support.constraints import (EnsureFloat, EnsureRange,\n        ...                              AltConstraints, Constraints)\n        >>> C = Parameter(constraints=EnsureFloat())\n\n        Ensure a parameter is of type float or None:\n        >>> C = Parameter(constraints=AltConstraints(EnsureFloat(), None))\n\n        Ensure a parameter is None or of type float and lies in the inclusive\n        range (7.0,44.0):\n        >>> C = Parameter(\n        ...         AltConstraints(\n        ...             Constraints(EnsureFloat(),\n        ...                         EnsureRange(min=7.0,max=44.0)),\n        ...             None))\n        \"\"\"\n        self.constraints = expand_contraint_spec(constraints)\n        self._doc = doc\n        self.cmd_args = args\n        self.cmd_kwargs = kwargs\n\n    def get_autodoc(self, name, indent=\"  \", width=70, default=None, has_default=False):\n        \"\"\"Docstring for the parameter to be used in lists of parameters\n\n        Returns\n        -------\n        string or list of strings (if indent is None)\n        \"\"\"\n        paramsdoc = '%s' % name\n        if not self.constraints is None:\n            sdoc = self.constraints.short_description()\n            if not sdoc is None:\n                if sdoc[0] == '(' and sdoc[-1] == ')':\n                    sdoc = sdoc[1:-1]\n                paramsdoc += \" : %s\" % sdoc\n                if has_default:\n                    paramsdoc += \", optional\"\n        paramsdoc = [paramsdoc]\n\n        doc = self._doc\n        if doc is None:\n            doc = ''\n        doc.strip()\n        if len(doc) and not doc.endswith('.'):\n            doc += '.'\n        if self.constraints is not None:\n            cdoc = self.constraints.long_description()\n            if cdoc[0] == '(' and cdoc[-1] == ')':\n                cdoc = cdoc[1:-1]\n            doc += ' Constraints: %s.' % cdoc\n        if has_default:\n            doc += \" [Default: %r]\" % (default,)\n        # Explicitly deal with multiple spaces, for some reason\n        # replace_whitespace is non-effective\n        doc = _whitespace_re.sub(' ', doc)\n        paramsdoc += [indent + x\n                      for x in textwrap.wrap(doc, width=width - len(indent),\n                                             replace_whitespace=True)]\n        return '\\n'.join(paramsdoc)\n",
            "new_file_content": "# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*-\n# vi: set ft=python sts=4 ts=4 sw=4 et:\n### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##\n#\n#   See COPYING file distributed along with the datalad package for the\n#   copyright and license terms.\n#\n### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##g\n\"\"\"Parameter representation\"\"\"\n\n__docformat__ = 'restructuredtext'\n\nimport re\nimport textwrap\nfrom .constraints import expand_contraint_spec\n\n_whitespace_re = re.compile('\\n\\s+|^\\s+')\n\n\nclass Parameter(object):\n    \"\"\"This class shall serve as a representation of a parameter.\n    \"\"\"\n\n    def __init__(self, constraints=None, doc=None, args=None, **kwargs):\n        \"\"\"Add contraints (validator) specifications and a docstring for\n        a parameter.\n\n        Parameters\n        ----------\n        constraints : callable\n          A functor that takes any input value, performs checks or type\n          conversions and finally returns a value that is appropriate for a\n          parameter or raises an exception. This will also be used to set up\n          the ``type`` functionality of argparse.add_argument.\n        doc : str\n          Documentation about the purpose of this parameter.\n        args : tuple or None\n          Any additional positional args for argparser.add_argument. This is\n          most useful for assigned multiple alternative argument names or\n          create positional arguments.\n        **kwargs :\n          Any additional keyword args for argparser.add_argument.\n\n        Examples\n        --------\n        Ensure a parameter is a float\n        >>> from datalad.support.param import Parameter\n        >>> from datalad.support.constraints import (EnsureFloat, EnsureRange,\n        ...                              AltConstraints, Constraints)\n        >>> C = Parameter(constraints=EnsureFloat())\n\n        Ensure a parameter is of type float or None:\n        >>> C = Parameter(constraints=AltConstraints(EnsureFloat(), None))\n\n        Ensure a parameter is None or of type float and lies in the inclusive\n        range (7.0,44.0):\n        >>> C = Parameter(\n        ...         AltConstraints(\n        ...             Constraints(EnsureFloat(),\n        ...                         EnsureRange(min=7.0,max=44.0)),\n        ...             None))\n        \"\"\"\n        self.constraints = expand_contraint_spec(constraints)\n        self._doc = doc\n        self.cmd_args = args\n        self.cmd_kwargs = kwargs\n\n    def get_autodoc(self, name, indent=\"  \", width=70, default=None, has_default=False):\n        \"\"\"Docstring for the parameter to be used in lists of parameters\n\n        Returns\n        -------\n        string or list of strings (if indent is None)\n        \"\"\"\n        paramsdoc = '%s' % name\n        sdoc = None\n        if self.constraints is not None:\n            sdoc = self.constraints.short_description()\n        elif 'action' in self.cmd_kwargs \\\n                and self.cmd_kwargs['action'] in (\"store_true\", \"store_false\"):\n            sdoc = 'bool'\n        if not sdoc is None:\n            if sdoc[0] == '(' and sdoc[-1] == ')':\n                sdoc = sdoc[1:-1]\n            paramsdoc += \" : %s\" % sdoc\n            if has_default:\n                paramsdoc += \", optional\"\n        paramsdoc = [paramsdoc]\n\n        doc = self._doc\n        if doc is None:\n            doc = ''\n        doc.strip()\n        if len(doc) and not doc.endswith('.'):\n            doc += '.'\n        if self.constraints is not None:\n            cdoc = self.constraints.long_description()\n            if cdoc[0] == '(' and cdoc[-1] == ')':\n                cdoc = cdoc[1:-1]\n            addinfo = ''\n            if 'nargs' in self.cmd_kwargs \\\n                    and not self.cmd_kwargs['nargs'] == '?':\n                addinfo = 'list expected, each '\n            doc += ' Constraints: %s%s.' % (addinfo, cdoc)\n        if has_default:\n            doc += \" [Default: %r]\" % (default,)\n        # Explicitly deal with multiple spaces, for some reason\n        # replace_whitespace is non-effective\n        doc = _whitespace_re.sub(' ', doc)\n        paramsdoc += [indent + x\n                      for x in textwrap.wrap(doc, width=width - len(indent),\n                                             replace_whitespace=True)]\n        return '\\n'.join(paramsdoc)\n",
            "header": {
                "file": {
                    "path": "datalad/support/param.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "a22ea83e3",
                "new_commit_hash": "da0080533",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/datalad/support/param.py"
            },
            "plus_file": {
                "path": "b/datalad/support/param.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 73,
                            "length": 14
                        },
                        "new_range": {
                            "start": 73,
                            "length": 18
                        },
                        "section": "class Parameter(object):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "        string or list of strings (if indent is None)",
                                "type": "context"
                            },
                            {
                                "content": "        \"\"\"",
                                "type": "context"
                            },
                            {
                                "content": "        paramsdoc = '%s' % name",
                                "type": "context"
                            },
                            {
                                "content": "        if not self.constraints is None:",
                                "type": "deleted"
                            },
                            {
                                "content": "        sdoc = None",
                                "type": "added"
                            },
                            {
                                "content": "        if self.constraints is not None:",
                                "type": "added"
                            },
                            {
                                "content": "            sdoc = self.constraints.short_description()",
                                "type": "context"
                            },
                            {
                                "content": "            if not sdoc is None:",
                                "type": "deleted"
                            },
                            {
                                "content": "                if sdoc[0] == '(' and sdoc[-1] == ')':",
                                "type": "deleted"
                            },
                            {
                                "content": "                    sdoc = sdoc[1:-1]",
                                "type": "deleted"
                            },
                            {
                                "content": "                paramsdoc += \" : %s\" % sdoc",
                                "type": "deleted"
                            },
                            {
                                "content": "                if has_default:",
                                "type": "deleted"
                            },
                            {
                                "content": "                    paramsdoc += \", optional\"",
                                "type": "deleted"
                            },
                            {
                                "content": "        elif 'action' in self.cmd_kwargs \\",
                                "type": "added"
                            },
                            {
                                "content": "                and self.cmd_kwargs['action'] in (\"store_true\", \"store_false\"):",
                                "type": "added"
                            },
                            {
                                "content": "            sdoc = 'bool'",
                                "type": "added"
                            },
                            {
                                "content": "        if not sdoc is None:",
                                "type": "added"
                            },
                            {
                                "content": "            if sdoc[0] == '(' and sdoc[-1] == ')':",
                                "type": "added"
                            },
                            {
                                "content": "                sdoc = sdoc[1:-1]",
                                "type": "added"
                            },
                            {
                                "content": "            paramsdoc += \" : %s\" % sdoc",
                                "type": "added"
                            },
                            {
                                "content": "            if has_default:",
                                "type": "added"
                            },
                            {
                                "content": "                paramsdoc += \", optional\"",
                                "type": "added"
                            },
                            {
                                "content": "        paramsdoc = [paramsdoc]",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "        doc = self._doc",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "datalad/support/param.py",
                            "type": "class",
                            "name": "Parameter",
                            "content": "class Parameter(object):\n    \"\"\"This class shall serve as a representation of a parameter.\n    \"\"\"\n\n    def __init__(self, constraints=None, doc=None, args=None, **kwargs):\n        \"\"\"Add contraints (validator) specifications and a docstring for\n        a parameter.\n\n        Parameters\n        ----------\n        constraints : callable\n          A functor that takes any input value, performs checks or type\n          conversions and finally returns a value that is appropriate for a\n          parameter or raises an exception. This will also be used to set up\n          the ``type`` functionality of argparse.add_argument.\n        doc : str\n          Documentation about the purpose of this parameter.\n        args : tuple or None\n          Any additional positional args for argparser.add_argument. This is\n          most useful for assigned multiple alternative argument names or\n          create positional arguments.\n        **kwargs :\n          Any additional keyword args for argparser.add_argument.\n\n        Examples\n        --------\n        Ensure a parameter is a float\n        >>> from datalad.support.param import Parameter\n        >>> from datalad.support.constraints import (EnsureFloat, EnsureRange,\n        ...                              AltConstraints, Constraints)\n        >>> C = Parameter(constraints=EnsureFloat())\n\n        Ensure a parameter is of type float or None:\n        >>> C = Parameter(constraints=AltConstraints(EnsureFloat(), None))\n\n        Ensure a parameter is None or of type float and lies in the inclusive\n        range (7.0,44.0):\n        >>> C = Parameter(\n        ...         AltConstraints(\n        ...             Constraints(EnsureFloat(),\n        ...                         EnsureRange(min=7.0,max=44.0)),\n        ...             None))\n        \"\"\"\n        self.constraints = expand_contraint_spec(constraints)\n        self._doc = doc\n        self.cmd_args = args\n        self.cmd_kwargs = kwargs\n\n    def get_autodoc(self, name, indent=\"  \", width=70, default=None, has_default=False):\n        \"\"\"Docstring for the parameter to be used in lists of parameters\n\n        Returns\n        -------\n        string or list of strings (if indent is None)\n        \"\"\"\n        paramsdoc = '%s' % name\n        if not self.constraints is None:\n            sdoc = self.constraints.short_description()\n            if not sdoc is None:\n                if sdoc[0] == '(' and sdoc[-1] == ')':\n                    sdoc = sdoc[1:-1]\n                paramsdoc += \" : %s\" % sdoc\n                if has_default:\n                    paramsdoc += \", optional\"\n        paramsdoc = [paramsdoc]\n\n        doc = self._doc\n        if doc is None:\n            doc = ''\n        doc.strip()\n        if len(doc) and not doc.endswith('.'):\n            doc += '.'\n        if self.constraints is not None:\n            cdoc = self.constraints.long_description()\n            if cdoc[0] == '(' and cdoc[-1] == ')':\n                cdoc = cdoc[1:-1]\n            doc += ' Constraints: %s.' % cdoc\n        if has_default:\n            doc += \" [Default: %r]\" % (default,)\n        # Explicitly deal with multiple spaces, for some reason\n        # replace_whitespace is non-effective\n        doc = _whitespace_re.sub(' ', doc)\n        paramsdoc += [indent + x\n                      for x in textwrap.wrap(doc, width=width - len(indent),\n                                             replace_whitespace=True)]\n        return '\\n'.join(paramsdoc)",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 20,
                            "end_lineno": 105,
                            "parent": null
                        },
                        {
                            "file_name": "datalad/support/param.py",
                            "type": "method",
                            "name": "Parameter.get_autodoc",
                            "content": "class Parameter(object):\n    \"\"\"This class shall serve as a representation of a parameter.\n    \"\"\"\n\n    def __init__(self, constraints=None, doc=None, args=None, **kwargs):\n        \"\"\"Add contraints (validator) specifications and a docstring for\n        a parameter.\n\n        Parameters\n        ----------\n        constraints : callable\n          A functor that takes any input value, performs checks or type\n          conversions and finally returns a value that is appropriate for a\n          parameter or raises an exception. This will also be used to set up\n          the ``type`` functionality of argparse.add_argument.\n        doc : str\n          Documentation about the purpose of this parameter.\n        args : tuple or None\n          Any additional positional args for argparser.add_argument. This is\n          most useful for assigned multiple alternative argument names or\n          create positional arguments.\n        **kwargs :\n          Any additional keyword args for argparser.add_argument.\n\n        Examples\n        --------\n        Ensure a parameter is a float\n        >>> from datalad.support.param import Parameter\n        >>> from datalad.support.constraints import (EnsureFloat, EnsureRange,\n        ...                              AltConstraints, Constraints)\n        >>> C = Parameter(constraints=EnsureFloat())\n\n        Ensure a parameter is of type float or None:\n        >>> C = Parameter(constraints=AltConstraints(EnsureFloat(), None))\n\n        Ensure a parameter is None or of type float and lies in the inclusive\n        range (7.0,44.0):\n        >>> C = Parameter(\n        ...         AltConstraints(\n        ...             Constraints(EnsureFloat(),\n        ...                         EnsureRange(min=7.0,max=44.0)),\n        ...             None))\n        \"\"\"\n        self.constraints = expand_contraint_spec(constraints)\n        self._doc = doc\n        self.cmd_args = args\n        self.cmd_kwargs = kwargs\n\n    def get_autodoc(self, name, indent=\"  \", width=70, default=None, has_default=False):\n        \"\"\"Docstring for the parameter to be used in lists of parameters\n\n        Returns\n        -------\n        string or list of strings (if indent is None)\n        \"\"\"\n        paramsdoc = '%s' % name\n        if not self.constraints is None:\n            sdoc = self.constraints.short_description()\n            if not sdoc is None:\n                if sdoc[0] == '(' and sdoc[-1] == ')':\n                    sdoc = sdoc[1:-1]\n                paramsdoc += \" : %s\" % sdoc\n                if has_default:\n                    paramsdoc += \", optional\"\n        paramsdoc = [paramsdoc]\n\n        doc = self._doc\n        if doc is None:\n            doc = ''\n        doc.strip()\n        if len(doc) and not doc.endswith('.'):\n            doc += '.'\n        if self.constraints is not None:\n            cdoc = self.constraints.long_description()\n            if cdoc[0] == '(' and cdoc[-1] == ')':\n                cdoc = cdoc[1:-1]\n            doc += ' Constraints: %s.' % cdoc\n        if has_default:\n            doc += \" [Default: %r]\" % (default,)\n        # Explicitly deal with multiple spaces, for some reason\n        # replace_whitespace is non-effective\n        doc = _whitespace_re.sub(' ', doc)\n        paramsdoc += [indent + x\n                      for x in textwrap.wrap(doc, width=width - len(indent),\n                                             replace_whitespace=True)]\n        return '\\n'.join(paramsdoc)",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 68,
                            "end_lineno": 105,
                            "parent": {
                                "file_name": "datalad/support/param.py",
                                "type": "class",
                                "name": "Parameter",
                                "content": "class Parameter(object):\n    \"\"\"This class shall serve as a representation of a parameter.\n    \"\"\"\n\n    def __init__(self, constraints=None, doc=None, args=None, **kwargs):\n        \"\"\"Add contraints (validator) specifications and a docstring for\n        a parameter.\n\n        Parameters\n        ----------\n        constraints : callable\n          A functor that takes any input value, performs checks or type\n          conversions and finally returns a value that is appropriate for a\n          parameter or raises an exception. This will also be used to set up\n          the ``type`` functionality of argparse.add_argument.\n        doc : str\n          Documentation about the purpose of this parameter.\n        args : tuple or None\n          Any additional positional args for argparser.add_argument. This is\n          most useful for assigned multiple alternative argument names or\n          create positional arguments.\n        **kwargs :\n          Any additional keyword args for argparser.add_argument.\n\n        Examples\n        --------\n        Ensure a parameter is a float\n        >>> from datalad.support.param import Parameter\n        >>> from datalad.support.constraints import (EnsureFloat, EnsureRange,\n        ...                              AltConstraints, Constraints)\n        >>> C = Parameter(constraints=EnsureFloat())\n\n        Ensure a parameter is of type float or None:\n        >>> C = Parameter(constraints=AltConstraints(EnsureFloat(), None))\n\n        Ensure a parameter is None or of type float and lies in the inclusive\n        range (7.0,44.0):\n        >>> C = Parameter(\n        ...         AltConstraints(\n        ...             Constraints(EnsureFloat(),\n        ...                         EnsureRange(min=7.0,max=44.0)),\n        ...             None))\n        \"\"\"\n        self.constraints = expand_contraint_spec(constraints)\n        self._doc = doc\n        self.cmd_args = args\n        self.cmd_kwargs = kwargs\n\n    def get_autodoc(self, name, indent=\"  \", width=70, default=None, has_default=False):\n        \"\"\"Docstring for the parameter to be used in lists of parameters\n\n        Returns\n        -------\n        string or list of strings (if indent is None)\n        \"\"\"\n        paramsdoc = '%s' % name\n        if not self.constraints is None:\n            sdoc = self.constraints.short_description()\n            if not sdoc is None:\n                if sdoc[0] == '(' and sdoc[-1] == ')':\n                    sdoc = sdoc[1:-1]\n                paramsdoc += \" : %s\" % sdoc\n                if has_default:\n                    paramsdoc += \", optional\"\n        paramsdoc = [paramsdoc]\n\n        doc = self._doc\n        if doc is None:\n            doc = ''\n        doc.strip()\n        if len(doc) and not doc.endswith('.'):\n            doc += '.'\n        if self.constraints is not None:\n            cdoc = self.constraints.long_description()\n            if cdoc[0] == '(' and cdoc[-1] == ')':\n                cdoc = cdoc[1:-1]\n            doc += ' Constraints: %s.' % cdoc\n        if has_default:\n            doc += \" [Default: %r]\" % (default,)\n        # Explicitly deal with multiple spaces, for some reason\n        # replace_whitespace is non-effective\n        doc = _whitespace_re.sub(' ', doc)\n        paramsdoc += [indent + x\n                      for x in textwrap.wrap(doc, width=width - len(indent),\n                                             replace_whitespace=True)]\n        return '\\n'.join(paramsdoc)",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 20,
                                "end_lineno": 105,
                                "parent": null
                            }
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                },
                {
                    "descriptor": {
                        "old_range": {
                            "start": 93,
                            "length": 7
                        },
                        "new_range": {
                            "start": 97,
                            "length": 11
                        },
                        "section": "class Parameter(object):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "            cdoc = self.constraints.long_description()",
                                "type": "context"
                            },
                            {
                                "content": "            if cdoc[0] == '(' and cdoc[-1] == ')':",
                                "type": "context"
                            },
                            {
                                "content": "                cdoc = cdoc[1:-1]",
                                "type": "context"
                            },
                            {
                                "content": "            doc += ' Constraints: %s.' % cdoc",
                                "type": "deleted"
                            },
                            {
                                "content": "            addinfo = ''",
                                "type": "added"
                            },
                            {
                                "content": "            if 'nargs' in self.cmd_kwargs \\",
                                "type": "added"
                            },
                            {
                                "content": "                    and not self.cmd_kwargs['nargs'] == '?':",
                                "type": "added"
                            },
                            {
                                "content": "                addinfo = 'list expected, each '",
                                "type": "added"
                            },
                            {
                                "content": "            doc += ' Constraints: %s%s.' % (addinfo, cdoc)",
                                "type": "added"
                            },
                            {
                                "content": "        if has_default:",
                                "type": "context"
                            },
                            {
                                "content": "            doc += \" [Default: %r]\" % (default,)",
                                "type": "context"
                            },
                            {
                                "content": "        # Explicitly deal with multiple spaces, for some reason",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "datalad/support/param.py",
                            "type": "class",
                            "name": "Parameter",
                            "content": "class Parameter(object):\n    \"\"\"This class shall serve as a representation of a parameter.\n    \"\"\"\n\n    def __init__(self, constraints=None, doc=None, args=None, **kwargs):\n        \"\"\"Add contraints (validator) specifications and a docstring for\n        a parameter.\n\n        Parameters\n        ----------\n        constraints : callable\n          A functor that takes any input value, performs checks or type\n          conversions and finally returns a value that is appropriate for a\n          parameter or raises an exception. This will also be used to set up\n          the ``type`` functionality of argparse.add_argument.\n        doc : str\n          Documentation about the purpose of this parameter.\n        args : tuple or None\n          Any additional positional args for argparser.add_argument. This is\n          most useful for assigned multiple alternative argument names or\n          create positional arguments.\n        **kwargs :\n          Any additional keyword args for argparser.add_argument.\n\n        Examples\n        --------\n        Ensure a parameter is a float\n        >>> from datalad.support.param import Parameter\n        >>> from datalad.support.constraints import (EnsureFloat, EnsureRange,\n        ...                              AltConstraints, Constraints)\n        >>> C = Parameter(constraints=EnsureFloat())\n\n        Ensure a parameter is of type float or None:\n        >>> C = Parameter(constraints=AltConstraints(EnsureFloat(), None))\n\n        Ensure a parameter is None or of type float and lies in the inclusive\n        range (7.0,44.0):\n        >>> C = Parameter(\n        ...         AltConstraints(\n        ...             Constraints(EnsureFloat(),\n        ...                         EnsureRange(min=7.0,max=44.0)),\n        ...             None))\n        \"\"\"\n        self.constraints = expand_contraint_spec(constraints)\n        self._doc = doc\n        self.cmd_args = args\n        self.cmd_kwargs = kwargs\n\n    def get_autodoc(self, name, indent=\"  \", width=70, default=None, has_default=False):\n        \"\"\"Docstring for the parameter to be used in lists of parameters\n\n        Returns\n        -------\n        string or list of strings (if indent is None)\n        \"\"\"\n        paramsdoc = '%s' % name\n        if not self.constraints is None:\n            sdoc = self.constraints.short_description()\n            if not sdoc is None:\n                if sdoc[0] == '(' and sdoc[-1] == ')':\n                    sdoc = sdoc[1:-1]\n                paramsdoc += \" : %s\" % sdoc\n                if has_default:\n                    paramsdoc += \", optional\"\n        paramsdoc = [paramsdoc]\n\n        doc = self._doc\n        if doc is None:\n            doc = ''\n        doc.strip()\n        if len(doc) and not doc.endswith('.'):\n            doc += '.'\n        if self.constraints is not None:\n            cdoc = self.constraints.long_description()\n            if cdoc[0] == '(' and cdoc[-1] == ')':\n                cdoc = cdoc[1:-1]\n            doc += ' Constraints: %s.' % cdoc\n        if has_default:\n            doc += \" [Default: %r]\" % (default,)\n        # Explicitly deal with multiple spaces, for some reason\n        # replace_whitespace is non-effective\n        doc = _whitespace_re.sub(' ', doc)\n        paramsdoc += [indent + x\n                      for x in textwrap.wrap(doc, width=width - len(indent),\n                                             replace_whitespace=True)]\n        return '\\n'.join(paramsdoc)",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 20,
                            "end_lineno": 105,
                            "parent": null
                        },
                        {
                            "file_name": "datalad/support/param.py",
                            "type": "method",
                            "name": "Parameter.get_autodoc",
                            "content": "class Parameter(object):\n    \"\"\"This class shall serve as a representation of a parameter.\n    \"\"\"\n\n    def __init__(self, constraints=None, doc=None, args=None, **kwargs):\n        \"\"\"Add contraints (validator) specifications and a docstring for\n        a parameter.\n\n        Parameters\n        ----------\n        constraints : callable\n          A functor that takes any input value, performs checks or type\n          conversions and finally returns a value that is appropriate for a\n          parameter or raises an exception. This will also be used to set up\n          the ``type`` functionality of argparse.add_argument.\n        doc : str\n          Documentation about the purpose of this parameter.\n        args : tuple or None\n          Any additional positional args for argparser.add_argument. This is\n          most useful for assigned multiple alternative argument names or\n          create positional arguments.\n        **kwargs :\n          Any additional keyword args for argparser.add_argument.\n\n        Examples\n        --------\n        Ensure a parameter is a float\n        >>> from datalad.support.param import Parameter\n        >>> from datalad.support.constraints import (EnsureFloat, EnsureRange,\n        ...                              AltConstraints, Constraints)\n        >>> C = Parameter(constraints=EnsureFloat())\n\n        Ensure a parameter is of type float or None:\n        >>> C = Parameter(constraints=AltConstraints(EnsureFloat(), None))\n\n        Ensure a parameter is None or of type float and lies in the inclusive\n        range (7.0,44.0):\n        >>> C = Parameter(\n        ...         AltConstraints(\n        ...             Constraints(EnsureFloat(),\n        ...                         EnsureRange(min=7.0,max=44.0)),\n        ...             None))\n        \"\"\"\n        self.constraints = expand_contraint_spec(constraints)\n        self._doc = doc\n        self.cmd_args = args\n        self.cmd_kwargs = kwargs\n\n    def get_autodoc(self, name, indent=\"  \", width=70, default=None, has_default=False):\n        \"\"\"Docstring for the parameter to be used in lists of parameters\n\n        Returns\n        -------\n        string or list of strings (if indent is None)\n        \"\"\"\n        paramsdoc = '%s' % name\n        if not self.constraints is None:\n            sdoc = self.constraints.short_description()\n            if not sdoc is None:\n                if sdoc[0] == '(' and sdoc[-1] == ')':\n                    sdoc = sdoc[1:-1]\n                paramsdoc += \" : %s\" % sdoc\n                if has_default:\n                    paramsdoc += \", optional\"\n        paramsdoc = [paramsdoc]\n\n        doc = self._doc\n        if doc is None:\n            doc = ''\n        doc.strip()\n        if len(doc) and not doc.endswith('.'):\n            doc += '.'\n        if self.constraints is not None:\n            cdoc = self.constraints.long_description()\n            if cdoc[0] == '(' and cdoc[-1] == ')':\n                cdoc = cdoc[1:-1]\n            doc += ' Constraints: %s.' % cdoc\n        if has_default:\n            doc += \" [Default: %r]\" % (default,)\n        # Explicitly deal with multiple spaces, for some reason\n        # replace_whitespace is non-effective\n        doc = _whitespace_re.sub(' ', doc)\n        paramsdoc += [indent + x\n                      for x in textwrap.wrap(doc, width=width - len(indent),\n                                             replace_whitespace=True)]\n        return '\\n'.join(paramsdoc)",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 68,
                            "end_lineno": 105,
                            "parent": {
                                "file_name": "datalad/support/param.py",
                                "type": "class",
                                "name": "Parameter",
                                "content": "class Parameter(object):\n    \"\"\"This class shall serve as a representation of a parameter.\n    \"\"\"\n\n    def __init__(self, constraints=None, doc=None, args=None, **kwargs):\n        \"\"\"Add contraints (validator) specifications and a docstring for\n        a parameter.\n\n        Parameters\n        ----------\n        constraints : callable\n          A functor that takes any input value, performs checks or type\n          conversions and finally returns a value that is appropriate for a\n          parameter or raises an exception. This will also be used to set up\n          the ``type`` functionality of argparse.add_argument.\n        doc : str\n          Documentation about the purpose of this parameter.\n        args : tuple or None\n          Any additional positional args for argparser.add_argument. This is\n          most useful for assigned multiple alternative argument names or\n          create positional arguments.\n        **kwargs :\n          Any additional keyword args for argparser.add_argument.\n\n        Examples\n        --------\n        Ensure a parameter is a float\n        >>> from datalad.support.param import Parameter\n        >>> from datalad.support.constraints import (EnsureFloat, EnsureRange,\n        ...                              AltConstraints, Constraints)\n        >>> C = Parameter(constraints=EnsureFloat())\n\n        Ensure a parameter is of type float or None:\n        >>> C = Parameter(constraints=AltConstraints(EnsureFloat(), None))\n\n        Ensure a parameter is None or of type float and lies in the inclusive\n        range (7.0,44.0):\n        >>> C = Parameter(\n        ...         AltConstraints(\n        ...             Constraints(EnsureFloat(),\n        ...                         EnsureRange(min=7.0,max=44.0)),\n        ...             None))\n        \"\"\"\n        self.constraints = expand_contraint_spec(constraints)\n        self._doc = doc\n        self.cmd_args = args\n        self.cmd_kwargs = kwargs\n\n    def get_autodoc(self, name, indent=\"  \", width=70, default=None, has_default=False):\n        \"\"\"Docstring for the parameter to be used in lists of parameters\n\n        Returns\n        -------\n        string or list of strings (if indent is None)\n        \"\"\"\n        paramsdoc = '%s' % name\n        if not self.constraints is None:\n            sdoc = self.constraints.short_description()\n            if not sdoc is None:\n                if sdoc[0] == '(' and sdoc[-1] == ')':\n                    sdoc = sdoc[1:-1]\n                paramsdoc += \" : %s\" % sdoc\n                if has_default:\n                    paramsdoc += \", optional\"\n        paramsdoc = [paramsdoc]\n\n        doc = self._doc\n        if doc is None:\n            doc = ''\n        doc.strip()\n        if len(doc) and not doc.endswith('.'):\n            doc += '.'\n        if self.constraints is not None:\n            cdoc = self.constraints.long_description()\n            if cdoc[0] == '(' and cdoc[-1] == ')':\n                cdoc = cdoc[1:-1]\n            doc += ' Constraints: %s.' % cdoc\n        if has_default:\n            doc += \" [Default: %r]\" % (default,)\n        # Explicitly deal with multiple spaces, for some reason\n        # replace_whitespace is non-effective\n        doc = _whitespace_re.sub(' ', doc)\n        paramsdoc += [indent + x\n                      for x in textwrap.wrap(doc, width=width - len(indent),\n                                             replace_whitespace=True)]\n        return '\\n'.join(paramsdoc)",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 20,
                                "end_lineno": 105,
                                "parent": null
                            }
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                }
            ]
        }
    ],
    "old_commit_hash": "c68ffad60e75fee8d2f1cc448353f16b3f159983^",
    "new_commit_hash": "c68ffad60e75fee8d2f1cc448353f16b3f159983",
    "commit_message": "Merge pull request #608 from hanke/bf-conditional-docs\n\nDocumentation-related code bugfixes from #598",
    "commit_date": "2016-07-06T09:52:44-04:00",
    "metadata": {}
}
{
    "repo_name": "datalad",
    "new_commit_hash": "c68ffad60e75fee8d2f1cc448353f16b3f159983",
    "test_file_codes": [
        "# emacs: -*- mode: python; py-indent-offset: 4; tab-width: 4; indent-tabs-mode: nil -*-\n# ex: set sts=4 ts=4 sw=4 noet:\n# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##\n#\n#   See COPYING file distributed along with the datalad package for the\n#   copyright and license terms.\n#\n# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##\n\"\"\"Tests for interface doc wranglers.\n\n\"\"\"\n\n__docformat__ = 'restructuredtext'\n\nfrom datalad.interface.base import dedent_docstring\nfrom datalad.interface.base import alter_interface_docs_for_api\nfrom datalad.interface.base import alter_interface_docs_for_cmdline\nfrom datalad.tests.utils import assert_true, assert_false, assert_in, \\\n    assert_not_in, eq_\n\n\ndemo_doc = \"\"\"\\\n    Bla bla summary\n\n    Generic intro blurb. Ping pong ping pong ping pong ping pong.  Ping pong ping\n    pong ping pong ping pong. Ping pong ping pong ping pong ping pong. Ping pong\n    ping pong ping pong ping pong. Ping pong ping pong ping pong ping pong. Ping\n    pong ping pong ping pong ping pong.\n\n    || CMDLINE >>\n    Something for the cmdline only\n    Multiline!\n    << CMDLINE ||\n\n    || PYTHON >>\n\n    Some Python-only bits\n    Multiline!\n\n    << PYTHON ||\n\n    And an example for in-line markup: [PY: just for Python PY] and\n    the other one [CMD: just for the command line CMD]. End of demo.\n\n    Generic appendix. Ding dong ding dong ding dong.  Ding dong ding dong ding\n    dong.  Ding dong ding dong ding dong.  Ding dong ding dong ding dong.  Ding\n    dong ding dong ding dong.\n\n\"\"\"\n\ndemo_paramdoc = \"\"\"\\\n\n    Parameters\n    ----------\n    dataset : Dataset or None, optional\n      specify the dataset to perform the install operation on. If no\n      dataset is given, an attempt is made to identify the dataset based\n      on the current working directory and/or the `path` given.\n      Constraints: Value must be a Dataset or a valid identifier of a\n      Dataset (e.g. a path), or value must be `None`. [Default: None]\n\"\"\"\n\ndemo_argdoc = \"\"\"\\\n    specify the dataset to perform the install operation\n    on. If no dataset is given, an attempt is made to\n    identify the dataset based on the current working\n    directory and/or the `path` given. Constraints: Value\n    must be a Dataset or a valid identifier of a Dataset\n    (e.g. a path), or value must be `None`. [Default:\n    None]\n\"\"\"\n\n\ndef test_dedent():\n    assert_false(dedent_docstring(\"one liner\").endswith(\"\\n\"))\n\n\ndef test_alter_interface_docs_for_api():\n    alt = alter_interface_docs_for_api(demo_doc)\n    alt_l = alt.split('\\n')\n    # dedented\n    assert_false(alt_l[0].startswith(' '))\n    assert_false(alt_l[-1].startswith(' '))\n    assert_not_in('CMD', alt)\n    assert_not_in('PY', alt)\n\n\ndef test_alter_interface_docs_for_cmdline():\n    alt = alter_interface_docs_for_cmdline(demo_doc)\n    alt_l = alt.split('\\n')\n    # dedented\n    assert_false(alt_l[0].startswith(' '))\n    assert_false(alt_l[-1].startswith(' '))\n    assert_not_in('PY', alt)\n    assert_not_in('CMD', alt)\n    # args\n    altarg = alter_interface_docs_for_cmdline(demo_argdoc)\n    # RST role markup\n    eq_(alter_interface_docs_for_cmdline(':murks:`me and my buddies`'),\n        'me and my buddies')\n    # spread across lines\n    eq_(alter_interface_docs_for_cmdline(':term:`Barbara\\nStreisand`'),\n        'Barbara\\nStreisand')\n    # multiple on one line\n    eq_(alter_interface_docs_for_cmdline(\n        ':term:`one` bla bla :term:`two` bla'),\n        'one bla bla two bla')\n",
        "import pytest\nimport tempfile\nimport os\n\n\n@pytest.fixture\ndef path():\n    with tempfile.TemporaryDirectory() as tmpdir:\n        yield tmpdir\n\n\n@pytest.fixture(autouse=True)\ndef setup_git_config():\n    with tempfile.TemporaryDirectory() as home:\n        old_home = os.environ.get(\"HOME\")\n        os.environ[\"HOME\"] = home\n        os.system('git config --global user.name \"DataLad Tester\"')\n        os.system('git config --global user.email \"test@example.com\"')\n        yield\n        if old_home:\n            os.environ[\"HOME\"] = old_home\n"
    ],
    "test_file_names": [
        "test_1.py",
        "conftest.py"
    ],
    "setup_res_code": 0,
    "setup_res_stdout": "Starting Datalad installation attempts...\nVerifying installation...\n❌ Verification failed\nPython 3.9 installation failed, trying Python 3.7...\nVerifying installation...\nDatalad version: 0.2.3.dev26\n✅ Installation successful!\nSuccessfully installed Datalad using Python 3.7\n",
    "setup_res_stderr": "Using CPython 3.9.21\nCreating virtual environment at: .venv\nActivate with: source .venv/bin/activate\nResolved 25 packages in 140ms\nInstalled 25 packages in 5.16s\n + coverage==7.6.10\n + docopt==0.6.2\n + exceptiongroup==1.2.2\n + grabbit==0.2.6\n + importlib-resources==6.4.5\n + iniconfig==2.0.0\n + nibabel==5.3.2\n + num2words==0.5.14\n + numpy==2.0.2\n + packaging==24.2\n + pandas==2.2.3\n + patsy==1.0.1\n + pluggy==1.5.0\n + pybids==0.6.5\n + pytest==8.3.4\n + pytest-cov==6.0.0\n + python-dateutil==2.9.0.post0\n + pytz==2024.2\n + scipy==1.13.1\n + setuptools==75.6.0\n + six==1.17.0\n + tomli==2.2.1\n + typing-extensions==4.12.2\n + tzdata==2024.2\n + zipp==3.21.0\nerror: The build backend returned an error\n  Caused by: Call to `setuptools.build_meta:__legacy__.build_editable` failed (exit status: 1)\n\n[stderr]\nTraceback (most recent call last):\n  File \"<string>\", line 14, in <module>\n  File \"/home/gcpuser/.cache/uv/builds-v0/.tmpkEe8wT/lib/python3.9/site-packages/setuptools/build_meta.py\", line 483, in get_requires_for_build_editable\n    return self.get_requires_for_build_wheel(config_settings)\n  File \"/home/gcpuser/.cache/uv/builds-v0/.tmpkEe8wT/lib/python3.9/site-packages/setuptools/build_meta.py\", line 334, in get_requires_for_build_wheel\n    return self._get_build_requires(config_settings, requirements=[])\n  File \"/home/gcpuser/.cache/uv/builds-v0/.tmpkEe8wT/lib/python3.9/site-packages/setuptools/build_meta.py\", line 304, in _get_build_requires\n    self.run_setup()\n  File \"/home/gcpuser/.cache/uv/builds-v0/.tmpkEe8wT/lib/python3.9/site-packages/setuptools/build_meta.py\", line 522, in run_setup\n    super().run_setup(setup_script=setup_script)\n  File \"/home/gcpuser/.cache/uv/builds-v0/.tmpkEe8wT/lib/python3.9/site-packages/setuptools/build_meta.py\", line 320, in run_setup\n    exec(code, locals())\n  File \"<string>\", line 39, in <module>\nAttributeError: module 'platform' has no attribute 'dist'\n\nhint: This usually indicates a problem with the package or the build environment.\nerror: The build backend returned an error\n  Caused by: Call to `setuptools.build_meta:__legacy__.build_editable` failed (exit status: 1)\n\n[stderr]\nTraceback (most recent call last):\n  File \"<string>\", line 14, in <module>\n  File \"/home/gcpuser/.cache/uv/builds-v0/.tmpsAKcve/lib/python3.9/site-packages/setuptools/build_meta.py\", line 483, in get_requires_for_build_editable\n    return self.get_requires_for_build_wheel(config_settings)\n  File \"/home/gcpuser/.cache/uv/builds-v0/.tmpsAKcve/lib/python3.9/site-packages/setuptools/build_meta.py\", line 334, in get_requires_for_build_wheel\n    return self._get_build_requires(config_settings, requirements=[])\n  File \"/home/gcpuser/.cache/uv/builds-v0/.tmpsAKcve/lib/python3.9/site-packages/setuptools/build_meta.py\", line 304, in _get_build_requires\n    self.run_setup()\n  File \"/home/gcpuser/.cache/uv/builds-v0/.tmpsAKcve/lib/python3.9/site-packages/setuptools/build_meta.py\", line 522, in run_setup\n    super().run_setup(setup_script=setup_script)\n  File \"/home/gcpuser/.cache/uv/builds-v0/.tmpsAKcve/lib/python3.9/site-packages/setuptools/build_meta.py\", line 320, in run_setup\n    exec(code, locals())\n  File \"<string>\", line 39, in <module>\nAttributeError: module 'platform' has no attribute 'dist'\n\nhint: This usually indicates a problem with the package or the build environment.\nTraceback (most recent call last):\n  File \"<string>\", line 1, in <module>\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/datalad_c68ffad60e75fee8d2f1cc448353f16b3f159983/datalad/__init__.py\", line 20, in <module>\n    from .config import ConfigManager\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/datalad_c68ffad60e75fee8d2f1cc448353f16b3f159983/datalad/config.py\", line 17, in <module>\n    from appdirs import AppDirs\nModuleNotFoundError: No module named 'appdirs'\nUsing CPython 3.7.9\nCreating virtual environment at: .venv\nActivate with: source .venv/bin/activate\nResolved 26 packages in 349ms\nInstalled 26 packages in 4.50s\n + bids==0.0\n + coverage==7.2.7\n + docopt==0.6.2\n + exceptiongroup==1.2.2\n + fasteners==0.19\n + grabbit==0.2.6\n + importlib-metadata==6.7.0\n + iniconfig==2.0.0\n + nibabel==4.0.2\n + num2words==0.5.14\n + numpy==1.21.6\n + packaging==24.0\n + pandas==1.3.5\n + patsy==1.0.1\n + pluggy==1.2.0\n + pybids==0.6.5\n + pytest==7.4.4\n + pytest-cov==4.1.0\n + python-dateutil==2.9.0.post0\n + pytz==2024.2\n + scipy==1.7.3\n + setuptools==68.0.0\n + six==1.17.0\n + tomli==2.0.1\n + typing-extensions==4.7.1\n + zipp==3.15.0\nResolved 67 packages in 3.56s\nPrepared 1 package in 1.37s\nInstalled 61 packages in 114ms\n + appdirs==1.4.4\n + attrs==24.2.0\n + automat==22.10.0\n + beautifulsoup4==4.12.3\n + boto==2.49.0\n + certifi==2024.12.14\n + cffi==1.15.1\n + charset-normalizer==3.4.1\n + constantly==15.1.0\n + cryptography==44.0.0\n + cssselect==1.2.0\n + datalad==0.2.3 (from file:///home/gcpuser/buckets/local_repoeval_bucket/repos/datalad_c68ffad60e75fee8d2f1cc448353f16b3f159983)\n + filelock==3.12.2\n + gitdb==4.0.12\n + gitpython==3.1.44\n + httpretty==1.1.4\n + humanize==4.6.0\n + hyperlink==21.0.0\n + idna==3.10\n + importlib-resources==5.12.0\n + incremental==22.10.0\n + itemadapter==0.8.0\n + itemloaders==1.1.0\n + jaraco-classes==3.2.3\n + jeepney==0.8.0\n + jmespath==1.0.1\n + keyring==24.1.1\n + keyrings-alt==4.2.0\n + lxml==5.3.0\n + mock==5.1.0\n + more-itertools==9.1.0\n + msgpack-python==0.5.6\n + multidict==6.0.5\n + nose==1.3.7\n + parsel==1.8.1\n + patool==1.12\n + protego==0.3.0\n + pyasn1==0.5.1\n + pyasn1-modules==0.3.0\n + pycparser==2.21\n + pydispatcher==2.0.7\n + pyopenssl==24.3.0\n + pyyaml==6.0.1\n + queuelib==1.6.2\n + requests==2.31.0\n + requests-file==2.1.0\n + scrapy==2.9.0\n + secretstorage==3.3.3\n + service-identity==21.1.0\n + smmap==5.0.2\n + soupsieve==2.4.1\n + testtools==2.7.1\n + tldextract==4.0.0\n + tqdm==4.67.1\n + twisted==23.8.0\n + urllib3==2.0.7\n + vcrpy==4.3.0\n + w3lib==2.1.2\n + wrapt==1.16.0\n + yarl==1.9.4\n + zope-interface==6.4.post2\nAudited 1 package in 25ms\n/home/gcpuser/buckets/local_repoeval_bucket/repos/datalad_c68ffad60e75fee8d2f1cc448353f16b3f159983/.venv/lib/python3.7/site-packages/urllib3/__init__.py:38: NotOpenSSLWarning: urllib3 v2.0 only supports OpenSSL 1.1.1+, currently the 'ssl' module is compiled with 'LibreSSL 3.1.4'. See: https://github.com/urllib3/urllib3/issues/3020\n  exceptions.NotOpenSSLWarning,\n",
    "new_commit_res_code": 0,
    "new_commit_res_stdout": "============================= test session starts ==============================\nplatform linux -- Python 3.7.9, pytest-7.4.4, pluggy-1.2.0\nrootdir: /home/gcpuser/buckets/local_repoeval_bucket/repos/datalad_c68ffad60e75fee8d2f1cc448353f16b3f159983\nplugins: cov-4.1.0\ncollected 3 items\n\nr2e_tests/test_1.py ...                                                  [100%]\n\n==================================== PASSES ====================================\n=========================== short test summary info ============================\nPASSED r2e_tests/test_1.py::test_dedent\nPASSED r2e_tests/test_1.py::test_alter_interface_docs_for_api\nPASSED r2e_tests/test_1.py::test_alter_interface_docs_for_cmdline\n============================== 3 passed in 0.94s ===============================\n",
    "new_commit_res_stderr": "",
    "old_commit_res_code": 1,
    "old_commit_res_stdout": "============================= test session starts ==============================\nplatform linux -- Python 3.7.9, pytest-7.4.4, pluggy-1.2.0\nrootdir: /home/gcpuser/buckets/local_repoeval_bucket/repos/datalad_c68ffad60e75fee8d2f1cc448353f16b3f159983\nplugins: cov-4.1.0\ncollected 3 items\n\nr2e_tests/test_1.py .FF                                                  [100%]\n\n=================================== FAILURES ===================================\n______________________ test_alter_interface_docs_for_api _______________________\n\n    def test_alter_interface_docs_for_api():\n        alt = alter_interface_docs_for_api(demo_doc)\n        alt_l = alt.split('\\n')\n        # dedented\n        assert_false(alt_l[0].startswith(' '))\n        assert_false(alt_l[-1].startswith(' '))\n>       assert_not_in('CMD', alt)\n\nr2e_tests/test_1.py:84: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n../../../../.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/lib/python3.7/unittest/case.py:1126: in assertNotIn\n    self.fail(self._formatMessage(msg, standardMsg))\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <nose.tools.trivial.Dummy testMethod=nop>\nmsg = \"'CMD' unexpectedly found in 'Bla bla summary\\\\n\\\\nGeneric intro blurb. Ping pong ping pong ping pong ping pong.  Ping... ding\\\\ndong.  Ding dong ding dong ding dong.  Ding dong ding dong ding dong.  Ding\\\\ndong ding dong ding dong.\\\\n\\\\n'\"\n\n    def fail(self, msg=None):\n        \"\"\"Fail immediately, with the given message.\"\"\"\n>       raise self.failureException(msg)\nE       AssertionError: 'CMD' unexpectedly found in 'Bla bla summary\\n\\nGeneric intro blurb. Ping pong ping pong ping pong ping pong.  Ping pong ping\\npong ping pong ping pong. Ping pong ping pong ping pong ping pong. Ping pong\\nping pong ping pong ping pong. Ping pong ping pong ping pong ping pong. Ping\\npong ping pong ping pong ping pong.\\n\\n|| CMDLINE >>\\nSomething for the cmdline only\\nMultiline!\\n<< CMDLINE ||\\n\\n|| PYTHON >>\\n\\nSome Python-only bits\\nMultiline!\\n\\n<< PYTHON ||\\n\\nAnd an example for in-line markup: [PY: just for Python PY] and\\nthe other one . End of demo.\\n\\nGeneric appendix. Ding dong ding dong ding dong.  Ding dong ding dong ding\\ndong.  Ding dong ding dong ding dong.  Ding dong ding dong ding dong.  Ding\\ndong ding dong ding dong.\\n\\n'\n\n../../../../.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/lib/python3.7/unittest/case.py:693: AssertionError\n____________________ test_alter_interface_docs_for_cmdline _____________________\n\n    def test_alter_interface_docs_for_cmdline():\n        alt = alter_interface_docs_for_cmdline(demo_doc)\n        alt_l = alt.split('\\n')\n        # dedented\n        assert_false(alt_l[0].startswith(' '))\n        assert_false(alt_l[-1].startswith(' '))\n>       assert_not_in('PY', alt)\n\nr2e_tests/test_1.py:94: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n../../../../.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/lib/python3.7/unittest/case.py:1126: in assertNotIn\n    self.fail(self._formatMessage(msg, standardMsg))\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <nose.tools.trivial.Dummy testMethod=nop>\nmsg = \"'PY' unexpectedly found in 'Bla bla summary\\\\n\\\\nGeneric intro blurb. Ping pong ping pong ping pong ping pong.  Ping ... ding\\\\ndong.  Ding dong ding dong ding dong.  Ding dong ding dong ding dong.  Ding\\\\ndong ding dong ding dong.\\\\n\\\\n'\"\n\n    def fail(self, msg=None):\n        \"\"\"Fail immediately, with the given message.\"\"\"\n>       raise self.failureException(msg)\nE       AssertionError: 'PY' unexpectedly found in 'Bla bla summary\\n\\nGeneric intro blurb. Ping pong ping pong ping pong ping pong.  Ping pong ping\\npong ping pong ping pong. Ping pong ping pong ping pong ping pong. Ping pong\\nping pong ping pong ping pong. Ping pong ping pong ping pong ping pong. Ping\\npong ping pong ping pong ping pong.\\n\\n|| CMDLINE >>\\nSomething for the cmdline only\\nMultiline!\\n<< CMDLINE ||\\n\\n|| PYTHON >>\\n\\nSome Python-only bits\\nMultiline!\\n\\n<< PYTHON ||\\n\\nAnd an example for in-line markup:  and\\nthe other one [CMD: just for the command line CMD]. End of demo.\\n\\nGeneric appendix. Ding dong ding dong ding dong.  Ding dong ding dong ding\\ndong.  Ding dong ding dong ding dong.  Ding dong ding dong ding dong.  Ding\\ndong ding dong ding dong.\\n\\n'\n\n../../../../.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/lib/python3.7/unittest/case.py:693: AssertionError\n==================================== PASSES ====================================\n=========================== short test summary info ============================\nPASSED r2e_tests/test_1.py::test_dedent\nFAILED r2e_tests/test_1.py::test_alter_interface_docs_for_api - AssertionErro...\nFAILED r2e_tests/test_1.py::test_alter_interface_docs_for_cmdline - Assertion...\n========================= 2 failed, 1 passed in 0.63s ==========================\n",
    "old_commit_res_stderr": ""
}
datalad/interface/base.py datalad/interface/tests/test_docs.py datalad/support/param.py
We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
**Analysis:**

- **Key Parts of Commit Details and Test Results:**
  - **Commit Message:** Merge pull request #608 from hanke/bf-conditional-docs
  - **Commit Patch:** Updates regex patterns in `alter_interface_docs_for_api` and `alter_interface_docs_for_cmdline` functions to correctly remove specific documentation markers (`CMDLINE`, `PYTHON`).
  - **Test Results:**
    - **Old Commit:**
      - `test_alter_interface_docs_for_api` failed because `'CMD'` was unexpectedly found in the altered documentation.
      - `test_alter_interface_docs_for_cmdline` failed because `'PY'` was unexpectedly found in the altered documentation.
    - **New Commit:** Both tests pass, indicating that the markers are correctly removed.

- **Main Problem Highlighted by Test Results:**
  The documentation alteration functions were not properly removing the `CMD` and `PY` markers, causing them to remain in the processed documentation and leading to test failures.

- **Expected Behavior:**
  The `alter_interface_docs_for_api` and `alter_interface_docs_for_cmdline` functions should completely remove any `CMD` and `PY` markers from the documentation, ensuring clean and accurate documentation without residual placeholders.

- **Actual Behavior:**
  The markers `CMD` and `PY` remained in the altered documentation, resulting in failed tests that detect these unexpected strings.

- **Issue Description:**
  The documentation processing functions are failing to remove specific markers (`CMD` and `PY`), leading to residual placeholders in the documentation. This causes tests to fail as they detect these unintended strings, indicating incomplete or incorrect documentation cleanup.

**Drafted GitHub Issue:**

[ISSUE]
**Title:** Documentation Processor Fails to Remove CMD and PY Markers, Causing Test Failures

**Description:**
The functions responsible for altering interface documentation are not correctly removing the `CMD` and `PY` markers. This oversight leaves unwanted placeholders in the documentation, which leads to test failures when these markers are detected unexpectedly.

**Example Buggy Code:**
```python
def alter_interface_docs_for_api(docs):
    # Existing regex patterns intended to remove CMD markers
    docs = re.sub(
        '\|\| Command line use only \>\>.*\<\< Command line use only \|\|',
        '',
        docs,
        flags=re.MULTILINE | re.DOTALL)
    docs = re.sub(
        '\[CMD:\s.*CMD\]',
        '',
        docs,
        flags=re.MULTILINE | re.DOTALL)
    return docs
```
In this example, the regex intended to remove `[CMD: ... CMD]` patterns does not fully eliminate the `CMD` marker, leaving residual text that should have been removed.

**Expected Behavior:**
The `alter_interface_docs_for_api` and `alter_interface_docs_for_cmdline` functions should completely remove all instances of `CMD` and `PY` markers from the documentation. This ensures that the processed documentation is clean and free of any unintended placeholders.

**Actual Behavior:**
Residual `CMD` and `PY` markers remain in the altered documentation despite the regex substitutions. As a result, tests that check for the absence of these markers fail because they are unexpectedly present in the documentation output.
[/ISSUE]
--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.

--- BEGIN FILE ---
```
### datalad/interface/base.py
# emacs: -*- mode: python; py-indent-offset: 4; tab-width: 4; indent-tabs-mode: nil -*-
# ex: set sts=4 ts=4 sw=4 noet:
# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##
#
#   See COPYING file distributed along with the datalad package for the
#   copyright and license terms.
#
# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##
"""High-level interface generation

"""

__docformat__ = 'restructuredtext'

import sys
import re

from ..ui import ui


def get_api_name(intfspec):
    """Given an interface specification return an API name for it"""
    if len(intfspec) > 3:
        name = intfspec[3]
    else:
        name = intfspec[0].split('.')[-1]
    return name


def get_cmdline_command_name(intfspec):
    """Given an interface specification return a cmdline command name"""
    if len(intfspec) > 2:
        name = intfspec[2]
    else:
        name = intfspec[0].split('.')[-1].replace('_', '-')
    return name


def get_interface_groups():
    from .. import interface as _interfaces

    grps = []
    # auto detect all available interfaces and generate a function-based
    # API from them
    for _item in _interfaces.__dict__:
        if not _item.startswith('_group_'):
            continue
        grp_name = _item[7:]
        grp = getattr(_interfaces, _item)
        grps.append((grp_name,) + grp)
    return grps


def dedent_docstring(text):
    import textwrap
    """Remove uniform indentation from a multiline docstring"""
    # Problem is that first line might often have no offset, so might
    # need to be ignored from dedent call
    if text is None:
        return None
    if not text.startswith(' '):
        lines = text.split('\n')
        if len(lines) == 1:
            # single line, no indentation, nothing to do
            return text
        text2 = '\n'.join(lines[1:])
        return lines[0] + "\n" + textwrap.dedent(text2)
    else:
        return textwrap.dedent(text)


def alter_interface_docs_for_api(docs):
    """Apply modifications to interface docstrings for Python API use."""
    # central place to alter the impression of docstrings,
    # like removing cmdline specific sections
    if not docs:
        return docs
    docs = dedent_docstring(docs)
    # clean cmdline sections
    docs = re.sub(
        '\|\| Command line use only \>\>.*\<\< Command line use only \|\|',
        '',
        docs,
        flags=re.MULTILINE | re.DOTALL)
    # clean cmdline in-line bits
    docs = re.sub(
        '\[CMD:\s.*CMD\]',
        '',
        docs,
        flags=re.MULTILINE | re.DOTALL)
    return docs


def alter_interface_docs_for_cmdline(docs):
    """Apply modifications to interface docstrings for cmdline doc use."""
    # central place to alter the impression of docstrings,
    # like removing Python API specific sections, and argument markup
    if not docs:
        return docs
    docs = dedent_docstring(docs)
    # clean cmdline sections
    docs = re.sub(
        '\|\| Python use only \>\>.*\<\< Python use only \|\|',
        '',
        docs,
        flags=re.MULTILINE | re.DOTALL)
    # clean cmdline in-line bits
    docs = re.sub(
        '\[PY:\s.*PY\]',
        '',
        docs,
        flags=re.MULTILINE | re.DOTALL)
    # remove :role:`...` RST markup for cmdline docs
    docs = re.sub(
        r':\S+:`[^`]*`[\\]*',
        lambda match: ':'.join(match.group(0).split(':')[2:]).strip('`\\'),
        docs,
        flags=re.MULTILINE | re.DOTALL)
    # remove None constraint. In general, `None` on the cmdline means don't
    # give option at all, but specifying `None` explicitly is practically
    # impossible
    docs = re.sub(
        ',\sor\svalue\smust\sbe\s`None`',
        '',
        docs,
        flags=re.MULTILINE | re.DOTALL)
    # capitalize variables and remove backticks to uniformize with
    # argparse output
    docs = re.sub(
        '`\S*`',
        lambda match: match.group(0).strip('`').upper(),
        docs)
    return docs


def update_docstring_with_parameters(func, params, prefix=None, suffix=None):
    """Generate a useful docstring from a parameter spec

    Amends any existing docstring of a callable with a textual
    description of its parameters. The Parameter spec needs to match
    the number and names of the callables arguments.
    """
    from inspect import getargspec
    # get the signature
    ndefaults = 0
    args, varargs, varkw, defaults = getargspec(func)
    if not defaults is None:
        ndefaults = len(defaults)
    # start documentation with what the callable brings with it
    doc = prefix if prefix else u''
    if len(args) > 1:
        if len(doc):
            doc += '\n'
        doc += "Parameters\n----------\n"
        for i, arg in enumerate(args):
            if arg == 'self':
                continue
            # we need a parameter spec for each argument
            if not arg in params:
                raise ValueError("function has argument '%s' not described as a parameter" % arg)
            param = params[arg]
            # validate the default -- to make sure that the parameter description is
            # somewhat OK
            defaults_idx = ndefaults - len(args) + i
            if defaults_idx >= 0:
                if not param.constraints is None:
                    param.constraints(defaults[defaults_idx])
            doc += param.get_autodoc(
                arg,
                default=defaults[defaults_idx] if defaults_idx >= 0 else None,
                has_default=defaults_idx >= 0)
            doc += '\n'
    doc += suffix if suffix else u""
    # assign the amended docs
    func.__doc__ = doc
    return func


class Interface(object):
    """Base class for interface implementations"""

    @classmethod
    def setup_parser(cls, parser):
        # XXX needs safety check for name collisions
        # XXX allow for parser kwargs customization
        parser_kwargs = {}
        from inspect import getargspec
        # get the signature
        ndefaults = 0
        args, varargs, varkw, defaults = getargspec(cls.__call__)
        if not defaults is None:
            ndefaults = len(defaults)
        for i, arg in enumerate(args):
            if arg == 'self':
                continue
            param = cls._params_[arg]
            defaults_idx = ndefaults - len(args) + i
            cmd_args = param.cmd_args
            if cmd_args is None:
                cmd_args = []
            if not len(cmd_args):
                if defaults_idx >= 0:
                    # dealing with a kwarg
                    template = '--%s'
                else:
                    # positional arg
                    template = '%s'
                # use parameter name as default argument name
                parser_args = (template % arg.replace('_', '-'),)
            else:
                parser_args = [c.replace('_', '-') for c in cmd_args]
            parser_kwargs = param.cmd_kwargs
            if defaults_idx >= 0:
                parser_kwargs['default'] = defaults[defaults_idx]
            help = alter_interface_docs_for_cmdline(param._doc)
            if help and help[-1] != '.':
                help += '.'
            if param.constraints is not None:
                parser_kwargs['type'] = param.constraints
                # include value contraint description and default
                # into the help string
                cdoc = alter_interface_docs_for_cmdline(
                    param.constraints.long_description())
                if cdoc[0] == '(' and cdoc[-1] == ')':
                    cdoc = cdoc[1:-1]
                help += '  Constraints: %s' % cdoc
            if defaults_idx >= 0:
                help += " [Default: %r]" % (defaults[defaults_idx],)
            # create the parameter, using the constraint instance for type
            # conversion
            parser.add_argument(*parser_args, help=help,
                                **parser_kwargs)

    @classmethod
    def call_from_parser(cls, args):
        # XXX needs safety check for name collisions
        from inspect import getargspec
        argnames = getargspec(cls.__call__)[0]
        kwargs = {k: getattr(args, k) for k in argnames if k != 'self'}
        try:
            return cls.__call__(**kwargs)
        except KeyboardInterrupt:
            ui.error("\nInterrupted by user while doing magic")
            sys.exit(1)

```
--- END FILE ---

Please first localize the bug based on the issue statement, and then generate *SEARCH/REPLACE* edits to fix the issue.

Every *SEARCH/REPLACE* edit must use this format:
1. The file path
2. The start of search block: <<<<<<< SEARCH
3. A contiguous chunk of lines to search for in the existing source code
4. The dividing line: =======
5. The lines to replace into the source code
6. The end of the replace block: >>>>>>> REPLACE

Here is an example:

```python
### mathweb/flask/app.py
<<<<<<< SEARCH
from flask import Flask
=======
import math
from flask import Flask
>>>>>>> REPLACE
```
</solution>

Please note that the *SEARCH/REPLACE* edit REQUIRES PROPER INDENTATION. If you would like to add the line '        print(x)', you must fully write that out, with all those spaces before the code!
Wrap each *SEARCH/REPLACE* edit in a code block as shown in the example above. If you have multiple *SEARCH/REPLACE* edits, use a separate code block for each one.
**Analysis:**

- **Key Parts of Commit Details and Test Results:**
  - **Commit Message:** Merge pull request #608 from hanke/bf-conditional-docs
  - **Commit Patch:** Updates regex patterns in `alter_interface_docs_for_api` and `alter_interface_docs_for_cmdline` functions to correctly remove specific documentation markers (`CMDLINE`, `PYTHON`).
  - **Test Results:**
    - **Old Commit:**
      - `test_alter_interface_docs_for_api` failed because `'CMD'` was unexpectedly found in the altered documentation.
      - `test_alter_interface_docs_for_cmdline` failed because `'PY'` was unexpectedly found in the altered documentation.
    - **New Commit:** Both tests pass, indicating that the markers are correctly removed.

- **Main Problem Highlighted by Test Results:**
  The documentation alteration functions were not properly removing the `CMD` and `PY` markers, causing them to remain in the processed documentation and leading to test failures.

- **Expected Behavior:**
  The `alter_interface_docs_for_api` and `alter_interface_docs_for_cmdline` functions should completely remove any `CMD` and `PY` markers from the documentation, ensuring clean and accurate documentation without residual placeholders.

- **Actual Behavior:**
  The markers `CMD` and `PY` remained in the altered documentation, resulting in failed tests that detect these unexpected strings.

- **Issue Description:**
  The documentation processing functions are failing to remove specific markers (`CMD` and `PY`), leading to residual placeholders in the documentation. This causes tests to fail as they detect these unintended strings, indicating incomplete or incorrect documentation cleanup.

**Drafted GitHub Issue:**

[ISSUE]
**Title:** Documentation Processor Fails to Remove CMD and PY Markers, Causing Test Failures

**Description:**
The functions responsible for altering interface documentation are not correctly removing the `CMD` and `PY` markers. This oversight leaves unwanted placeholders in the documentation, which leads to test failures when these markers are detected unexpectedly.

**Example Buggy Code:**
```python
def alter_interface_docs_for_api(docs):
    # Existing regex patterns intended to remove CMD markers
    docs = re.sub(
        '\|\| Command line use only \>\>.*\<\< Command line use only \|\|',
        '',
        docs,
        flags=re.MULTILINE | re.DOTALL)
    docs = re.sub(
        '\[CMD:\s.*CMD\]',
        '',
        docs,
        flags=re.MULTILINE | re.DOTALL)
    return docs
```
In this example, the regex intended to remove `[CMD: ... CMD]` patterns does not fully eliminate the `CMD` marker, leaving residual text that should have been removed.

**Expected Behavior:**
The `alter_interface_docs_for_api` and `alter_interface_docs_for_cmdline` functions should completely remove all instances of `CMD` and `PY` markers from the documentation. This ensures that the processed documentation is clean and free of any unintended placeholders.

**Actual Behavior:**
Residual `CMD` and `PY` markers remain in the altered documentation despite the regex substitutions. As a result, tests that check for the absence of these markers fail because they are unexpectedly present in the documentation output.
[/ISSUE]
{
    "test_dedent": "PASSED",
    "test_alter_interface_docs_for_api": "PASSED",
    "test_alter_interface_docs_for_cmdline": "PASSED"
}
diff --git a/datalad/interface/base.py b/datalad/interface/base.py
index 35aba6bed..37dbd595c 100644
--- a/datalad/interface/base.py
+++ b/datalad/interface/base.py
@@ -78,16 +78,26 @@ def alter_interface_docs_for_api(docs):
     docs = dedent_docstring(docs)
     # clean cmdline sections
     docs = re.sub(
-        '\|\| Command line use only \>\>.*\<\< Command line use only \|\|',
+        '\|\| CMDLINE \>\>.*\<\< CMDLINE \|\|',
         '',
         docs,
         flags=re.MULTILINE | re.DOTALL)
     # clean cmdline in-line bits
     docs = re.sub(
-        '\[CMD:\s.*CMD\]',
+        '\[CMD:\s.*\sCMD\]',
         '',
         docs,
         flags=re.MULTILINE | re.DOTALL)
+    docs = re.sub(
+        '\[PY:\s(.*)\sPY\]',
+        lambda match: match.group(1),
+        docs,
+        flags=re.MULTILINE)
+    docs = re.sub(
+        '\|\| PYTHON \>\>(.*)\<\< PYTHON \|\|',
+        lambda match: match.group(1),
+        docs,
+        flags=re.MULTILINE | re.DOTALL)
     return docs
 
 
@@ -100,16 +110,26 @@ def alter_interface_docs_for_cmdline(docs):
     docs = dedent_docstring(docs)
     # clean cmdline sections
     docs = re.sub(
-        '\|\| Python use only \>\>.*\<\< Python use only \|\|',
+        '\|\| PYTHON \>\>.*\<\< PYTHON \|\|',
         '',
         docs,
         flags=re.MULTILINE | re.DOTALL)
     # clean cmdline in-line bits
     docs = re.sub(
-        '\[PY:\s.*PY\]',
+        '\[PY:\s.*\sPY\]',
         '',
         docs,
         flags=re.MULTILINE | re.DOTALL)
+    docs = re.sub(
+        '\[CMD:\s(.*)\sCMD\]',
+        lambda match: match.group(1),
+        docs,
+        flags=re.MULTILINE)
+    docs = re.sub(
+        '\|\| CMDLINE \>\>(.*)\<\< CMDLINE \|\|',
+        lambda match: match.group(1),
+        docs,
+        flags=re.MULTILINE | re.DOTALL)
     # remove :role:`...` RST markup for cmdline docs
     docs = re.sub(
         r':\S+:`[^`]*`[\\]*',
diff --git a/datalad/support/param.py b/datalad/support/param.py
index a22ea83e3..da0080533 100644
--- a/datalad/support/param.py
+++ b/datalad/support/param.py
@@ -73,14 +73,18 @@ class Parameter(object):
         string or list of strings (if indent is None)
         """
         paramsdoc = '%s' % name
-        if not self.constraints is None:
+        sdoc = None
+        if self.constraints is not None:
             sdoc = self.constraints.short_description()
-            if not sdoc is None:
-                if sdoc[0] == '(' and sdoc[-1] == ')':
-                    sdoc = sdoc[1:-1]
-                paramsdoc += " : %s" % sdoc
-                if has_default:
-                    paramsdoc += ", optional"
+        elif 'action' in self.cmd_kwargs \
+                and self.cmd_kwargs['action'] in ("store_true", "store_false"):
+            sdoc = 'bool'
+        if not sdoc is None:
+            if sdoc[0] == '(' and sdoc[-1] == ')':
+                sdoc = sdoc[1:-1]
+            paramsdoc += " : %s" % sdoc
+            if has_default:
+                paramsdoc += ", optional"
         paramsdoc = [paramsdoc]
 
         doc = self._doc
@@ -93,7 +97,11 @@ class Parameter(object):
             cdoc = self.constraints.long_description()
             if cdoc[0] == '(' and cdoc[-1] == ')':
                 cdoc = cdoc[1:-1]
-            doc += ' Constraints: %s.' % cdoc
+            addinfo = ''
+            if 'nargs' in self.cmd_kwargs \
+                    and not self.cmd_kwargs['nargs'] == '?':
+                addinfo = 'list expected, each '
+            doc += ' Constraints: %s%s.' % (addinfo, cdoc)
         if has_default:
             doc += " [Default: %r]" % (default,)
         # Explicitly deal with multiple spaces, for some reason
 

{"datalad/interface/base.py": "# emacs: -*- mode: python; py-indent-offset: 4; tab-width: 4; indent-tabs-mode: nil -*-\n# ex: set sts=4 ts=4 sw=4 noet:\n# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##\n#\n#   See COPYING file distributed along with the datalad package for the\n#   copyright and license terms.\n#\n# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##\n\"\"\"High-level interface generation\n\n\"\"\"\n\n__docformat__ = 'restructuredtext'\n\nimport sys\nimport re\n\nfrom ..ui import ui\n\n\ndef get_api_name(intfspec):\n    \"\"\"Given an interface specification return an API name for it\"\"\"\n    if len(intfspec) > 3:\n        name = intfspec[3]\n    else:\n        name = intfspec[0].split('.')[-1]\n    return name\n\n\ndef get_cmdline_command_name(intfspec):\n    \"\"\"Given an interface specification return a cmdline command name\"\"\"\n    if len(intfspec) > 2:\n        name = intfspec[2]\n    else:\n        name = intfspec[0].split('.')[-1].replace('_', '-')\n    return name\n\n\ndef get_interface_groups():\n    from .. import interface as _interfaces\n\n    grps = []\n    # auto detect all available interfaces and generate a function-based\n    # API from them\n    for _item in _interfaces.__dict__:\n        if not _item.startswith('_group_'):\n            continue\n        grp_name = _item[7:]\n        grp = getattr(_interfaces, _item)\n        grps.append((grp_name,) + grp)\n    return grps\n\n\ndef dedent_docstring(text):\n    import textwrap\n    \"\"\"Remove uniform indentation from a multiline docstring\"\"\"\n    # Problem is that first line might often have no offset, so might\n    # need to be ignored from dedent call\n    if text is None:\n        return None\n    if not text.startswith(' '):\n        lines = text.split('\\n')\n        if len(lines) == 1:\n            # single line, no indentation, nothing to do\n            return text\n        text2 = '\\n'.join(lines[1:])\n        return lines[0] + \"\\n\" + textwrap.dedent(text2)\n    else:\n        return textwrap.dedent(text)\n\n\ndef alter_interface_docs_for_api(docs):\n    \"\"\"Apply modifications to interface docstrings for Python API use.\"\"\"\n    # central place to alter the impression of docstrings,\n    # like removing cmdline specific sections\n    if not docs:\n        return docs\n    docs = dedent_docstring(docs)\n    # clean cmdline sections\n    docs = re.sub(\n        '\\|\\| Command line use only \\>\\>.*\\<\\< Command line use only \\|\\|',\n        '',\n        docs,\n        flags=re.MULTILINE | re.DOTALL)\n    # clean cmdline in-line bits\n    docs = re.sub(\n        '\\[CMD:\\s.*CMD\\]',\n        '',\n        docs,\n        flags=re.MULTILINE | re.DOTALL)\n    return docs\n\n\ndef alter_interface_docs_for_cmdline(docs):\n    \"\"\"Apply modifications to interface docstrings for cmdline doc use.\"\"\"\n    # central place to alter the impression of docstrings,\n    # like removing Python API specific sections, and argument markup\n    if not docs:\n        return docs\n    docs = dedent_docstring(docs)\n    # clean cmdline sections\n    docs = re.sub(\n        '\\|\\| Python use only \\>\\>.*\\<\\< Python use only \\|\\|',\n        '',\n        docs,\n        flags=re.MULTILINE | re.DOTALL)\n    # clean cmdline in-line bits\n    docs = re.sub(\n        '\\[PY:\\s.*PY\\]',\n        '',\n        docs,\n        flags=re.MULTILINE | re.DOTALL)\n    # remove :role:`...` RST markup for cmdline docs\n    docs = re.sub(\n        r':\\S+:`[^`]*`[\\\\]*',\n        lambda match: ':'.join(match.group(0).split(':')[2:]).strip('`\\\\'),\n        docs,\n        flags=re.MULTILINE | re.DOTALL)\n    # remove None constraint. In general, `None` on the cmdline means don't\n    # give option at all, but specifying `None` explicitly is practically\n    # impossible\n    docs = re.sub(\n        ',\\sor\\svalue\\smust\\sbe\\s`None`',\n        '',\n        docs,\n        flags=re.MULTILINE | re.DOTALL)\n    # capitalize variables and remove backticks to uniformize with\n    # argparse output\n    docs = re.sub(\n        '`\\S*`',\n        lambda match: match.group(0).strip('`').upper(),\n        docs)\n    return docs\n\n\ndef update_docstring_with_parameters(func, params, prefix=None, suffix=None):\n    \"\"\"Generate a useful docstring from a parameter spec\n\n    Amends any existing docstring of a callable with a textual\n    description of its parameters. The Parameter spec needs to match\n    the number and names of the callables arguments.\n    \"\"\"\n    from inspect import getargspec\n    # get the signature\n    ndefaults = 0\n    args, varargs, varkw, defaults = getargspec(func)\n    if not defaults is None:\n        ndefaults = len(defaults)\n    # start documentation with what the callable brings with it\n    doc = prefix if prefix else u''\n    if len(args) > 1:\n        if len(doc):\n            doc += '\\n'\n        doc += \"Parameters\\n----------\\n\"\n        for i, arg in enumerate(args):\n            if arg == 'self':\n                continue\n            # we need a parameter spec for each argument\n            if not arg in params:\n                raise ValueError(\"function has argument '%s' not described as a parameter\" % arg)\n            param = params[arg]\n            # validate the default -- to make sure that the parameter description is\n            # somewhat OK\n            defaults_idx = ndefaults - len(args) + i\n            if defaults_idx >= 0:\n                if not param.constraints is None:\n                    param.constraints(defaults[defaults_idx])\n            doc += param.get_autodoc(\n                arg,\n                default=defaults[defaults_idx] if defaults_idx >= 0 else None,\n                has_default=defaults_idx >= 0)\n            doc += '\\n'\n    doc += suffix if suffix else u\"\"\n    # assign the amended docs\n    func.__doc__ = doc\n    return func\n\n\nclass Interface(object):\n    \"\"\"Base class for interface implementations\"\"\"\n\n    @classmethod\n    def setup_parser(cls, parser):\n        # XXX needs safety check for name collisions\n        # XXX allow for parser kwargs customization\n        parser_kwargs = {}\n        from inspect import getargspec\n        # get the signature\n        ndefaults = 0\n        args, varargs, varkw, defaults = getargspec(cls.__call__)\n        if not defaults is None:\n            ndefaults = len(defaults)\n        for i, arg in enumerate(args):\n            if arg == 'self':\n                continue\n            param = cls._params_[arg]\n            defaults_idx = ndefaults - len(args) + i\n            cmd_args = param.cmd_args\n            if cmd_args is None:\n                cmd_args = []\n            if not len(cmd_args):\n                if defaults_idx >= 0:\n                    # dealing with a kwarg\n                    template = '--%s'\n                else:\n                    # positional arg\n                    template = '%s'\n                # use parameter name as default argument name\n                parser_args = (template % arg.replace('_', '-'),)\n            else:\n                parser_args = [c.replace('_', '-') for c in cmd_args]\n            parser_kwargs = param.cmd_kwargs\n            if defaults_idx >= 0:\n                parser_kwargs['default'] = defaults[defaults_idx]\n            help = alter_interface_docs_for_cmdline(param._doc)\n            if help and help[-1] != '.':\n                help += '.'\n            if param.constraints is not None:\n                parser_kwargs['type'] = param.constraints\n                # include value contraint description and default\n                # into the help string\n                cdoc = alter_interface_docs_for_cmdline(\n                    param.constraints.long_description())\n                if cdoc[0] == '(' and cdoc[-1] == ')':\n                    cdoc = cdoc[1:-1]\n                help += '  Constraints: %s' % cdoc\n            if defaults_idx >= 0:\n                help += \" [Default: %r]\" % (defaults[defaults_idx],)\n            # create the parameter, using the constraint instance for type\n            # conversion\n            parser.add_argument(*parser_args, help=help,\n                                **parser_kwargs)\n\n    @classmethod\n    def call_from_parser(cls, args):\n        # XXX needs safety check for name collisions\n        from inspect import getargspec\n        argnames = getargspec(cls.__call__)[0]\n        kwargs = {k: getattr(args, k) for k in argnames if k != 'self'}\n        try:\n            return cls.__call__(**kwargs)\n        except KeyboardInterrupt:\n            ui.error(\"\\nInterrupted by user while doing magic\")\n            sys.exit(1)\n"}
A user will ask you to solve a task. You should first draft your thinking process (inner monologue). Then, generate the solution.

Your response format must follow the template below:
<think>
Your thoughts or/and draft, like working through an exercise on scratch paper. Be as casual and as long as you want until you are confident to generate a correct solution.
</think>
<solution>
Final solution presented to the user.
</solution>
system
We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
**Analysis:**

- **Key Parts of Commit Details and Test Results:**
  - **Commit Message:** Merge pull request #608 from hanke/bf-conditional-docs
  - **Commit Patch:** Updates regex patterns in `alter_interface_docs_for_api` and `alter_interface_docs_for_cmdline` functions to correctly remove specific documentation markers (`CMDLINE`, `PYTHON`).
  - **Test Results:**
    - **Old Commit:**
      - `test_alter_interface_docs_for_api` failed because `'CMD'` was unexpectedly found in the altered documentation.
      - `test_alter_interface_docs_for_cmdline` failed because `'PY'` was unexpectedly found in the altered documentation.
    - **New Commit:** Both tests pass, indicating that the markers are correctly removed.

- **Main Problem Highlighted by Test Results:**
  The documentation alteration functions were not properly removing the `CMD` and `PY` markers, causing them to remain in the processed documentation and leading to test failures.

- **Expected Behavior:**
  The `alter_interface_docs_for_api` and `alter_interface_docs_for_cmdline` functions should completely remove any `CMD` and `PY` markers from the documentation, ensuring clean and accurate documentation without residual placeholders.

- **Actual Behavior:**
  The markers `CMD` and `PY` remained in the altered documentation, resulting in failed tests that detect these unexpected strings.

- **Issue Description:**
  The documentation processing functions are failing to remove specific markers (`CMD` and `PY`), leading to residual placeholders in the documentation. This causes tests to fail as they detect these unintended strings, indicating incomplete or incorrect documentation cleanup.

**Drafted GitHub Issue:**

[ISSUE]
**Title:** Documentation Processor Fails to Remove CMD and PY Markers, Causing Test Failures

**Description:**
The functions responsible for altering interface documentation are not correctly removing the `CMD` and `PY` markers. This oversight leaves unwanted placeholders in the documentation, which leads to test failures when these markers are detected unexpectedly.

**Example Buggy Code:**
```python
def alter_interface_docs_for_api(docs):
    # Existing regex patterns intended to remove CMD markers
    docs = re.sub(
        '\|\| Command line use only \>\>.*\<\< Command line use only \|\|',
        '',
        docs,
        flags=re.MULTILINE | re.DOTALL)
    docs = re.sub(
        '\[CMD:\s.*CMD\]',
        '',
        docs,
        flags=re.MULTILINE | re.DOTALL)
    return docs
```
In this example, the regex intended to remove `[CMD: ... CMD]` patterns does not fully eliminate the `CMD` marker, leaving residual text that should have been removed.

**Expected Behavior:**
The `alter_interface_docs_for_api` and `alter_interface_docs_for_cmdline` functions should completely remove all instances of `CMD` and `PY` markers from the documentation. This ensures that the processed documentation is clean and free of any unintended placeholders.

**Actual Behavior:**
Residual `CMD` and `PY` markers remain in the altered documentation despite the regex substitutions. As a result, tests that check for the absence of these markers fail because they are unexpectedly present in the documentation output.
[/ISSUE]
--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.

--- BEGIN FILE ---
```
### datalad/interface/base.py
# emacs: -*- mode: python; py-indent-offset: 4; tab-width: 4; indent-tabs-mode: nil -*-
# ex: set sts=4 ts=4 sw=4 noet:
# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##
#
#   See COPYING file distributed along with the datalad package for the
#   copyright and license terms.
#
# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##
"""High-level interface generation

"""

__docformat__ = 'restructuredtext'

import sys
import re

from ..ui import ui


def get_api_name(intfspec):
    """Given an interface specification return an API name for it"""
    if len(intfspec) > 3:
        name = intfspec[3]
    else:
        name = intfspec[0].split('.')[-1]
    return name


def get_cmdline_command_name(intfspec):
    """Given an interface specification return a cmdline command name"""
    if len(intfspec) > 2:
        name = intfspec[2]
    else:
        name = intfspec[0].split('.')[-1].replace('_', '-')
    return name


def get_interface_groups():
    from .. import interface as _interfaces

    grps = []
    # auto detect all available interfaces and generate a function-based
    # API from them
    for _item in _interfaces.__dict__:
        if not _item.startswith('_group_'):
            continue
        grp_name = _item[7:]
        grp = getattr(_interfaces, _item)
        grps.append((grp_name,) + grp)
    return grps


def dedent_docstring(text):
    import textwrap
    """Remove uniform indentation from a multiline docstring"""
    # Problem is that first line might often have no offset, so might
    # need to be ignored from dedent call
    if text is None:
        return None
    if not text.startswith(' '):
        lines = text.split('\n')
        if len(lines) == 1:
            # single line, no indentation, nothing to do
            return text
        text2 = '\n'.join(lines[1:])
        return lines[0] + "\n" + textwrap.dedent(text2)
    else:
        return textwrap.dedent(text)


def alter_interface_docs_for_api(docs):
    """Apply modifications to interface docstrings for Python API use."""
    # central place to alter the impression of docstrings,
    # like removing cmdline specific sections
    if not docs:
        return docs
    docs = dedent_docstring(docs)
    # clean cmdline sections
    docs = re.sub(
        '\|\| Command line use only \>\>.*\<\< Command line use only \|\|',
        '',
        docs,
        flags=re.MULTILINE | re.DOTALL)
    # clean cmdline in-line bits
    docs = re.sub(
        '\[CMD:\s.*CMD\]',
        '',
        docs,
        flags=re.MULTILINE | re.DOTALL)
    return docs


def alter_interface_docs_for_cmdline(docs):
    """Apply modifications to interface docstrings for cmdline doc use."""
    # central place to alter the impression of docstrings,
    # like removing Python API specific sections, and argument markup
    if not docs:
        return docs
    docs = dedent_docstring(docs)
    # clean cmdline sections
    docs = re.sub(
        '\|\| Python use only \>\>.*\<\< Python use only \|\|',
        '',
        docs,
        flags=re.MULTILINE | re.DOTALL)
    # clean cmdline in-line bits
    docs = re.sub(
        '\[PY:\s.*PY\]',
        '',
        docs,
        flags=re.MULTILINE | re.DOTALL)
    # remove :role:`...` RST markup for cmdline docs
    docs = re.sub(
        r':\S+:`[^`]*`[\\]*',
        lambda match: ':'.join(match.group(0).split(':')[2:]).strip('`\\'),
        docs,
        flags=re.MULTILINE | re.DOTALL)
    # remove None constraint. In general, `None` on the cmdline means don't
    # give option at all, but specifying `None` explicitly is practically
    # impossible
    docs = re.sub(
        ',\sor\svalue\smust\sbe\s`None`',
        '',
        docs,
        flags=re.MULTILINE | re.DOTALL)
    # capitalize variables and remove backticks to uniformize with
    # argparse output
    docs = re.sub(
        '`\S*`',
        lambda match: match.group(0).strip('`').upper(),
        docs)
    return docs


def update_docstring_with_parameters(func, params, prefix=None, suffix=None):
    """Generate a useful docstring from a parameter spec

    Amends any existing docstring of a callable with a textual
    description of its parameters. The Parameter spec needs to match
    the number and names of the callables arguments.
    """
    from inspect import getargspec
    # get the signature
    ndefaults = 0
    args, varargs, varkw, defaults = getargspec(func)
    if not defaults is None:
        ndefaults = len(defaults)
    # start documentation with what the callable brings with it
    doc = prefix if prefix else u''
    if len(args) > 1:
        if len(doc):
            doc += '\n'
        doc += "Parameters\n----------\n"
        for i, arg in enumerate(args):
            if arg == 'self':
                continue
            # we need a parameter spec for each argument
            if not arg in params:
                raise ValueError("function has argument '%s' not described as a parameter" % arg)
            param = params[arg]
            # validate the default -- to make sure that the parameter description is
            # somewhat OK
            defaults_idx = ndefaults - len(args) + i
            if defaults_idx >= 0:
                if not param.constraints is None:
                    param.constraints(defaults[defaults_idx])
            doc += param.get_autodoc(
                arg,
                default=defaults[defaults_idx] if defaults_idx >= 0 else None,
                has_default=defaults_idx >= 0)
            doc += '\n'
    doc += suffix if suffix else u""
    # assign the amended docs
    func.__doc__ = doc
    return func


class Interface(object):
    """Base class for interface implementations"""

    @classmethod
    def setup_parser(cls, parser):
        # XXX needs safety check for name collisions
        # XXX allow for parser kwargs customization
        parser_kwargs = {}
        from inspect import getargspec
        # get the signature
        ndefaults = 0
        args, varargs, varkw, defaults = getargspec(cls.__call__)
        if not defaults is None:
            ndefaults = len(defaults)
        for i, arg in enumerate(args):
            if arg == 'self':
                continue
            param = cls._params_[arg]
            defaults_idx = ndefaults - len(args) + i
            cmd_args = param.cmd_args
            if cmd_args is None:
                cmd_args = []
            if not len(cmd_args):
                if defaults_idx >= 0:
                    # dealing with a kwarg
                    template = '--%s'
                else:
                    # positional arg
                    template = '%s'
                # use parameter name as default argument name
                parser_args = (template % arg.replace('_', '-'),)
            else:
                parser_args = [c.replace('_', '-') for c in cmd_args]
            parser_kwargs = param.cmd_kwargs
            if defaults_idx >= 0:
                parser_kwargs['default'] = defaults[defaults_idx]
            help = alter_interface_docs_for_cmdline(param._doc)
            if help and help[-1] != '.':
                help += '.'
            if param.constraints is not None:
                parser_kwargs['type'] = param.constraints
                # include value contraint description and default
                # into the help string
                cdoc = alter_interface_docs_for_cmdline(
                    param.constraints.long_description())
                if cdoc[0] == '(' and cdoc[-1] == ')':
                    cdoc = cdoc[1:-1]
                help += '  Constraints: %s' % cdoc
            if defaults_idx >= 0:
                help += " [Default: %r]" % (defaults[defaults_idx],)
            # create the parameter, using the constraint instance for type
            # conversion
            parser.add_argument(*parser_args, help=help,
                                **parser_kwargs)

    @classmethod
    def call_from_parser(cls, args):
        # XXX needs safety check for name collisions
        from inspect import getargspec
        argnames = getargspec(cls.__call__)[0]
        kwargs = {k: getattr(args, k) for k in argnames if k != 'self'}
        try:
            return cls.__call__(**kwargs)
        except KeyboardInterrupt:
            ui.error("\nInterrupted by user while doing magic")
            sys.exit(1)

```
--- END FILE ---

Please first localize the bug based on the issue statement, and then generate *SEARCH/REPLACE* edits to fix the issue.

Every *SEARCH/REPLACE* edit must use this format:
1. The file path
2. The start of search block: <<<<<<< SEARCH
3. A contiguous chunk of lines to search for in the existing source code
4. The dividing line: =======
5. The lines to replace into the source code
6. The end of the replace block: >>>>>>> REPLACE

Here is an example:

```python
### mathweb/flask/app.py
<<<<<<< SEARCH
from flask import Flask
=======
import math
from flask import Flask
>>>>>>> REPLACE
```
</solution>

Please note that the *SEARCH/REPLACE* edit REQUIRES PROPER INDENTATION. If you would like to add the line '        print(x)', you must fully write that out, with all those spaces before the code!
Wrap each *SEARCH/REPLACE* edit in a code block as shown in the example above. If you have multiple *SEARCH/REPLACE* edits, use a separate code block for each one.
user