{
    "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\"\"\"\"\"\"\n\n__docformat__ = 'restructuredtext'\n\nimport logging\nlgr = logging.getLogger('datalad.cmdline')\n\nlgr.log(5, \"Importing cmdline.main\")\n\nimport argparse\nimport sys\nimport textwrap\nimport shutil\nfrom importlib import import_module\nimport os\n\nfrom six import text_type\n\nimport datalad\n\nfrom datalad.cmdline import helpers\nfrom datalad.support.exceptions import InsufficientArgumentsError\nfrom datalad.support.exceptions import IncompleteResultsError\nfrom datalad.support.exceptions import CommandError\nfrom .helpers import strip_arg_from_argv\nfrom ..utils import setup_exceptionhook, chpwd\nfrom ..utils import assure_unicode\nfrom ..dochelpers import exc_str\n\n\ndef _license_info():\n    return \"\"\"\\\nCopyright (c) 2013-2017 DataLad developers\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n\"\"\"\n\n\n# TODO:  OPT look into making setup_parser smarter to become faster\n# Now it seems to take up to 200ms to do all the parser setup\n# even though it might not be necessary to know about all the commands etc.\n# I wondered if it could somehow decide on what commands to worry about etc\n# by going through sys.args first\ndef setup_parser(\n        formatter_class=argparse.RawDescriptionHelpFormatter,\n        return_subparsers=False):\n\n    lgr.log(5, \"Starting to setup_parser\")\n    # delay since it can be a heavy import\n    from ..interface.base import dedent_docstring, get_interface_groups, \\\n        get_cmdline_command_name, alter_interface_docs_for_cmdline\n    # setup cmdline args parser\n    parts = {}\n    # main parser\n    parser = argparse.ArgumentParser(\n        # cannot use '@' because we need to input JSON-LD properties (which might come wit @ prefix)\n        # MH: question, do we need this at all?\n        fromfile_prefix_chars=':',\n        # usage=\"%(prog)s ...\",\n        description=dedent_docstring(\"\"\"\\\n            DataLad provides a unified data distribution with the convenience of git-annex\n            repositories as a backend.  DataLad command line tools allow to manipulate\n            (obtain, create, update, publish, etc.) datasets and their collections.\"\"\"),\n        epilog='\"Control Your Data\"',\n        formatter_class=formatter_class,\n        add_help=False)\n    # common options\n    helpers.parser_add_common_opt(parser, 'help')\n    helpers.parser_add_common_opt(parser, 'log_level')\n    helpers.parser_add_common_opt(parser, 'pbs_runner')\n    helpers.parser_add_common_opt(parser, 'change_path')\n    helpers.parser_add_common_opt(\n        parser,\n        'version',\n        version='datalad %s\\n\\n%s' % (datalad.__version__, _license_info()))\n    if __debug__:\n        parser.add_argument(\n            '--dbg', action='store_true', dest='common_debug',\n            help=\"enter Python debugger when uncaught exception happens\")\n        parser.add_argument(\n            '--idbg', action='store_true', dest='common_idebug',\n            help=\"enter IPython debugger when uncaught exception happens\")\n    parser.add_argument(\n        '-c', action='append', dest='cfg_overrides', metavar='KEY=VALUE',\n        help=\"\"\"configuration variable setting. Overrides any configuration\n        read from a file, but is potentially overridden itself by configuration\n        variables in the process environment.\"\"\")\n    parser.add_argument(\n        '-f', '--output-format', dest='common_output_format',\n        default='default',\n        type=assure_unicode,\n        metavar=\"{default,json,json_pp,tailored,'<template>'\",\n        help=\"\"\"select format for returned command results. 'default' give one line\n        per result reporting action, status, path and an optional message;\n        'json' renders a JSON object with all properties for each result (one per\n        line); 'json_pp' pretty-prints JSON spanning multiple lines; 'tailored'\n        enables a command-specific rendering style that is typically\n        tailored to human consumption (no result output otherwise),\n        '<template>' reports any value(s) of any result properties in any format\n        indicated by the template (e.g. '{path}'; compare with JSON\n        output for all key-value choices). The template syntax follows the Python\n        \"format() language\". It is possible to report individual\n        dictionary values, e.g. '{metadata[name]}'. If a 2nd-level key contains\n        a colon, e.g. 'music:Genre', ':' must be substituted by '#' in the template,\n        like so: '{metadata[music#Genre]}'.\"\"\")\n    parser.add_argument(\n        '--report-status', dest='common_report_status',\n        choices=['success', 'failure', 'ok', 'notneeded', 'impossible', 'error'],\n        help=\"\"\"constrain command result report to records matching the given\n        status. 'success' is a synonym for 'ok' OR 'notneeded', 'failure' stands\n        for 'impossible' OR 'error'.\"\"\")\n    parser.add_argument(\n        '--report-type', dest='common_report_type',\n        choices=['dataset', 'file'],\n        action='append',\n        help=\"\"\"constrain command result report to records matching the given\n        type. Can be given more than once to match multiple types.\"\"\")\n    parser.add_argument(\n        '--on-failure', dest='common_on_failure',\n        choices=['ignore', 'continue', 'stop'],\n        # no default: better be configure per-command\n        help=\"\"\"when an operation fails: 'ignore' and continue with remaining\n        operations, the error is logged but does not lead to a non-zero exit code\n        of the command; 'continue' works like 'ignore', but an error causes a\n        non-zero exit code; 'stop' halts on first failure and yields non-zero exit\n        code. A failure is any result with status 'impossible' or 'error'.\"\"\")\n    parser.add_argument(\n        '--run-before', dest='common_run_before',\n        nargs='+',\n        action='append',\n        metavar='PLUGINSPEC',\n        help=\"\"\"DataLad plugin to run after the command. PLUGINSPEC is a list\n        comprised of a plugin name plus optional `key=value` pairs with arguments\n        for the plugin call (see `plugin` command documentation for details).\n        This option can be given more than once to run multiple plugins\n        in the order in which they were given.\n        For running plugins that require a --dataset argument it is important\n        to provide the respective dataset as the --dataset argument of the main\n        command, if it is not in the list of plugin arguments.\"\"\"),\n    parser.add_argument(\n        '--run-after', dest='common_run_after',\n        nargs='+',\n        action='append',\n        metavar='PLUGINSPEC',\n        help=\"\"\"Like --run-before, but plugins are executed after the main command\n        has finished.\"\"\"),\n    parser.add_argument(\n        '--cmd', dest='_', action='store_true',\n        help=\"\"\"syntactical helper that can be used to end the list of global\n        command line options before the subcommand label. Options like\n        --run-before can take an arbitray number of arguments and may require\n        to be followed by a single --cmd in order to enable identification\n        of the subcommand.\"\"\")\n\n    # yoh: atm we only dump to console.  Might adopt the same separation later on\n    #      and for consistency will call it --verbose-level as well for now\n    # log-level is set via common_opts ATM\n    # parser.add_argument('--log-level',\n    #                     choices=('critical', 'error', 'warning', 'info', 'debug'),\n    #                     dest='common_log_level',\n    #                     help=\"\"\"level of verbosity in log files. By default\n    #                          everything, including debug messages is logged.\"\"\")\n    #parser.add_argument('-l', '--verbose-level',\n    #                    choices=('critical', 'error', 'warning', 'info', 'debug'),\n    #                    dest='common_verbose_level',\n    #                    help=\"\"\"level of verbosity of console output. By default\n    #                         only warnings and errors are printed.\"\"\")\n\n    # subparsers\n    subparsers = parser.add_subparsers()\n\n    # auto detect all available interfaces and generate a function-based\n    # API from them\n    grp_short_descriptions = []\n    interface_groups = get_interface_groups()\n    for grp_name, grp_descr, _interfaces \\\n                in sorted(interface_groups, key=lambda x: x[1]):\n        # for all subcommand modules it can find\n        cmd_short_descriptions = []\n\n        for _intfspec in _interfaces:\n            # turn the interface spec into an instance\n            lgr.log(5, \"Importing module %s \" % _intfspec[0])\n            try:\n                _mod = import_module(_intfspec[0], package='datalad')\n            except Exception as e:\n                lgr.error(\"Internal error, cannot import interface '%s': %s\",\n                          _intfspec[0], exc_str(e))\n                continue\n            _intf = getattr(_mod, _intfspec[1])\n            cmd_name = get_cmdline_command_name(_intfspec)\n            # deal with optional parser args\n            if hasattr(_intf, 'parser_args'):\n                parser_args = _intf.parser_args\n            else:\n                parser_args = dict(formatter_class=formatter_class)\n            # use class description, if no explicit description is available\n                intf_doc = _intf.__doc__.strip()\n                if hasattr(_intf, '_docs_'):\n                    # expand docs\n                    intf_doc = intf_doc.format(**_intf._docs_)\n                parser_args['description'] = alter_interface_docs_for_cmdline(\n                    intf_doc)\n            # create subparser, use module suffix as cmd name\n            subparser = subparsers.add_parser(cmd_name, add_help=False, **parser_args)\n            # our own custom help for all commands\n            helpers.parser_add_common_opt(subparser, 'help')\n            # let module configure the parser\n            _intf.setup_parser(subparser)\n            # logger for command\n\n            # configure 'run' function for this command\n            plumbing_args = dict(\n                func=_intf.call_from_parser,\n                logger=logging.getLogger(_intf.__module__),\n                subparser=subparser)\n            if hasattr(_intf, 'result_renderer_cmdline'):\n                plumbing_args['result_renderer'] = _intf.result_renderer_cmdline\n            subparser.set_defaults(**plumbing_args)\n            # store short description for later\n            sdescr = getattr(_intf, 'short_description',\n                             parser_args['description'].split('\\n')[0])\n            cmd_short_descriptions.append((cmd_name, sdescr))\n            parts[cmd_name] = subparser\n        grp_short_descriptions.append(cmd_short_descriptions)\n\n    # create command summary\n    cmd_summary = []\n    console_width = shutil.get_terminal_size()[0] \\\n        if hasattr(shutil, 'get_terminal_size') else 80\n\n    for i, grp in enumerate(\n            sorted(interface_groups, key=lambda x: x[1])):\n        grp_descr = grp[1]\n        grp_cmds = grp_short_descriptions[i]\n\n        cmd_summary.append('\\n*%s*\\n' % (grp_descr,))\n        for cd in grp_cmds:\n            cmd_summary.append('  %s\\n%s'\n                               % ((cd[0],\n                                  textwrap.fill(\n                                      cd[1].rstrip(' .'),\n                                      console_width - 5,\n                                      initial_indent=' ' * 6,\n                                      subsequent_indent=' ' * 6))))\n    # we need one last formal section to not have the trailed be\n    # confused with the last command group\n    cmd_summary.append('\\n*General information*\\n')\n    parser.description = '%s\\n%s\\n\\n%s' \\\n        % (parser.description,\n           '\\n'.join(cmd_summary),\n           textwrap.fill(dedent_docstring(\"\"\"\\\n    Detailed usage information for individual commands is\n    available via command-specific --help, i.e.:\n    datalad <command> --help\"\"\"),\n                         console_width - 5, initial_indent='', subsequent_indent=''))\n    parts['datalad'] = parser\n    lgr.log(5, \"Finished setup_parser\")\n    if return_subparsers:\n        return parts\n    else:\n        return parser\n\n\n# yoh: arn't used\n# def generate_api_call(cmdlineargs=None):\n#     parser = setup_parser()\n#     # parse cmd args\n#     cmdlineargs = parser.parse_args(cmdlineargs)\n#     # convert cmdline args into API call spec\n#     functor, args, kwargs = cmdlineargs.func(cmdlineargs)\n#     return cmdlineargs, functor, args, kwargs\n\n\ndef main(args=None):\n    lgr.log(5, \"Starting main(%r)\", args)\n    # PYTHON_ARGCOMPLETE_OK\n    parser = setup_parser()\n    try:\n        import argcomplete\n        argcomplete.autocomplete(parser)\n    except ImportError:\n        pass\n\n    # parse cmd args\n    cmdlineargs, unparsed_args = parser.parse_known_args(args)\n    has_func = hasattr(cmdlineargs, 'func') and cmdlineargs.func is not None\n    if unparsed_args:\n        if has_func and cmdlineargs.func.__self__.__name__ != 'Export':\n            lgr.error('unknown argument{}: {}'.format(\n                's' if len(unparsed_args) > 1 else '',\n                unparsed_args if len(unparsed_args) > 1 else unparsed_args[0]))\n            cmdlineargs.subparser.print_usage()\n            sys.exit(1)\n        else:\n            # store all unparsed arguments\n            cmdlineargs.datalad_unparsed_args = unparsed_args\n\n    # to possibly be passed into PBS scheduled call\n    args_ = args or sys.argv\n\n    if cmdlineargs.cfg_overrides is not None:\n        overrides = dict([\n            (o.split('=')[0], '='.join(o.split('=')[1:]))\n            for o in cmdlineargs.cfg_overrides])\n        datalad.cfg.overrides.update(overrides)\n\n    # enable overrides\n    datalad.cfg.reload(force=True)\n\n    if cmdlineargs.change_path is not None:\n        from .common_args import change_path as change_path_opt\n        for path in cmdlineargs.change_path:\n            chpwd(path)\n            args_ = strip_arg_from_argv(args_, path, change_path_opt[1])\n\n    ret = None\n    if cmdlineargs.pbs_runner:\n        from .helpers import run_via_pbs\n        from .common_args import pbs_runner as pbs_runner_opt\n        args_ = strip_arg_from_argv(args_, cmdlineargs.pbs_runner, pbs_runner_opt[1])\n        # run the function associated with the selected command\n        run_via_pbs(args_, cmdlineargs.pbs_runner)\n    elif has_func:\n        if cmdlineargs.common_debug or cmdlineargs.common_idebug:\n            # so we could see/stop clearly at the point of failure\n            setup_exceptionhook(ipython=cmdlineargs.common_idebug)\n            from datalad.interface.base import Interface\n            Interface._interrupted_exit_code = None\n            ret = cmdlineargs.func(cmdlineargs)\n        else:\n            # otherwise - guard and only log the summary. Postmortem is not\n            # as convenient if being caught in this ultimate except\n            try:\n                ret = cmdlineargs.func(cmdlineargs)\n            except InsufficientArgumentsError as exc:\n                # if the func reports inappropriate usage, give help output\n                lgr.error('%s (%s)' % (exc_str(exc), exc.__class__.__name__))\n                cmdlineargs.subparser.print_usage(sys.stderr)\n                sys.exit(2)\n            except IncompleteResultsError as exc:\n                # rendering for almost all commands now happens 'online'\n                # hence we are no longer attempting to render the actual\n                # results in an IncompleteResultsError, ubt rather trust that\n                # this happened before\n\n                # in general we do not want to see the error again, but\n                # present in debug output\n                lgr.debug('could not perform all requested actions: %s',\n                          exc_str(exc))\n                sys.exit(1)\n            except CommandError as exc:\n                # behave as if the command ran directly, importantly pass\n                # exit code as is\n                if exc.msg:\n                    os.write(2, exc.msg.encode() if isinstance(exc.msg, text_type) else exc.msg)\n                if exc.stdout:\n                    os.write(1, exc.stdout.encode() if isinstance(exc.stdout, text_type) else exc.stdout)\n                if exc.stderr:\n                    os.write(2, exc.stderr.encode() if isinstance(exc.stderr, text_type) else exc.stderr)\n                # We must not exit with 0 code if any exception got here but\n                # had no code defined\n                sys.exit(exc.code if exc.code is not None else 1)\n            except Exception as exc:\n                lgr.error('%s (%s)' % (exc_str(exc), exc.__class__.__name__))\n                sys.exit(1)\n    else:\n        # just let argparser spit out its error, since there is smth wrong\n        parser.parse_args(args)\n        # if that one didn't puke -- we should\n        parser.print_usage()\n        lgr.error(\"Please specify the command\")\n        sys.exit(2)\n\n    try:\n        if hasattr(cmdlineargs, 'result_renderer'):\n            cmdlineargs.result_renderer(ret, cmdlineargs)\n    except Exception as exc:\n        lgr.error(\"Failed to render results due to %s\", exc_str(exc))\n        sys.exit(1)\n\nlgr.log(5, \"Done importing cmdline.main\")\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\"\"\"\"\"\"\n\n__docformat__ = 'restructuredtext'\n\nimport logging\nlgr = logging.getLogger('datalad.cmdline')\n\nlgr.log(5, \"Importing cmdline.main\")\n\nimport argparse\nimport sys\nimport textwrap\nimport shutil\nfrom importlib import import_module\nimport os\n\nfrom six import text_type\n\nimport datalad\n\nfrom datalad.cmdline import helpers\nfrom datalad.support.exceptions import InsufficientArgumentsError\nfrom datalad.support.exceptions import IncompleteResultsError\nfrom datalad.support.exceptions import CommandError\nfrom .helpers import strip_arg_from_argv\nfrom ..utils import setup_exceptionhook, chpwd\nfrom ..utils import assure_unicode\nfrom ..dochelpers import exc_str\n\n\ndef _license_info():\n    return \"\"\"\\\nCopyright (c) 2013-2017 DataLad developers\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n\"\"\"\n\n\n# TODO:  OPT look into making setup_parser smarter to become faster\n# Now it seems to take up to 200ms to do all the parser setup\n# even though it might not be necessary to know about all the commands etc.\n# I wondered if it could somehow decide on what commands to worry about etc\n# by going through sys.args first\ndef setup_parser(\n        formatter_class=argparse.RawDescriptionHelpFormatter,\n        return_subparsers=False):\n\n    lgr.log(5, \"Starting to setup_parser\")\n    # delay since it can be a heavy import\n    from ..interface.base import dedent_docstring, get_interface_groups, \\\n        get_cmdline_command_name, alter_interface_docs_for_cmdline\n    # setup cmdline args parser\n    parts = {}\n    # main parser\n    parser = argparse.ArgumentParser(\n        # cannot use '@' because we need to input JSON-LD properties (which might come wit @ prefix)\n        # MH: question, do we need this at all?\n        fromfile_prefix_chars=':',\n        # usage=\"%(prog)s ...\",\n        description=dedent_docstring(\"\"\"\\\n            DataLad provides a unified data distribution with the convenience of git-annex\n            repositories as a backend.  DataLad command line tools allow to manipulate\n            (obtain, create, update, publish, etc.) datasets and their collections.\"\"\"),\n        epilog='\"Control Your Data\"',\n        formatter_class=formatter_class,\n        add_help=False)\n    # common options\n    helpers.parser_add_common_opt(parser, 'help')\n    helpers.parser_add_common_opt(parser, 'log_level')\n    helpers.parser_add_common_opt(parser, 'pbs_runner')\n    helpers.parser_add_common_opt(parser, 'change_path')\n    helpers.parser_add_common_opt(\n        parser,\n        'version',\n        version='datalad %s\\n\\n%s' % (datalad.__version__, _license_info()))\n    if __debug__:\n        parser.add_argument(\n            '--dbg', action='store_true', dest='common_debug',\n            help=\"enter Python debugger when uncaught exception happens\")\n        parser.add_argument(\n            '--idbg', action='store_true', dest='common_idebug',\n            help=\"enter IPython debugger when uncaught exception happens\")\n    parser.add_argument(\n        '-c', action='append', dest='cfg_overrides', metavar='KEY=VALUE',\n        help=\"\"\"configuration variable setting. Overrides any configuration\n        read from a file, but is potentially overridden itself by configuration\n        variables in the process environment.\"\"\")\n    parser.add_argument(\n        '-f', '--output-format', dest='common_output_format',\n        default='default',\n        type=assure_unicode,\n        metavar=\"{default,json,json_pp,tailored,'<template>'}\",\n        help=\"\"\"select format for returned command results. 'default' give one line\n        per result reporting action, status, path and an optional message;\n        'json' renders a JSON object with all properties for each result (one per\n        line); 'json_pp' pretty-prints JSON spanning multiple lines; 'tailored'\n        enables a command-specific rendering style that is typically\n        tailored to human consumption (no result output otherwise),\n        '<template>' reports any value(s) of any result properties in any format\n        indicated by the template (e.g. '{path}'; compare with JSON\n        output for all key-value choices). The template syntax follows the Python\n        \"format() language\". It is possible to report individual\n        dictionary values, e.g. '{metadata[name]}'. If a 2nd-level key contains\n        a colon, e.g. 'music:Genre', ':' must be substituted by '#' in the template,\n        like so: '{metadata[music#Genre]}'.\"\"\")\n    parser.add_argument(\n        '--report-status', dest='common_report_status',\n        choices=['success', 'failure', 'ok', 'notneeded', 'impossible', 'error'],\n        help=\"\"\"constrain command result report to records matching the given\n        status. 'success' is a synonym for 'ok' OR 'notneeded', 'failure' stands\n        for 'impossible' OR 'error'.\"\"\")\n    parser.add_argument(\n        '--report-type', dest='common_report_type',\n        choices=['dataset', 'file'],\n        action='append',\n        help=\"\"\"constrain command result report to records matching the given\n        type. Can be given more than once to match multiple types.\"\"\")\n    parser.add_argument(\n        '--on-failure', dest='common_on_failure',\n        choices=['ignore', 'continue', 'stop'],\n        # no default: better be configure per-command\n        help=\"\"\"when an operation fails: 'ignore' and continue with remaining\n        operations, the error is logged but does not lead to a non-zero exit code\n        of the command; 'continue' works like 'ignore', but an error causes a\n        non-zero exit code; 'stop' halts on first failure and yields non-zero exit\n        code. A failure is any result with status 'impossible' or 'error'.\"\"\")\n    parser.add_argument(\n        '--run-before', dest='common_run_before',\n        nargs='+',\n        action='append',\n        metavar='PLUGINSPEC',\n        help=\"\"\"DataLad plugin to run after the command. PLUGINSPEC is a list\n        comprised of a plugin name plus optional `key=value` pairs with arguments\n        for the plugin call (see `plugin` command documentation for details).\n        This option can be given more than once to run multiple plugins\n        in the order in which they were given.\n        For running plugins that require a --dataset argument it is important\n        to provide the respective dataset as the --dataset argument of the main\n        command, if it is not in the list of plugin arguments.\"\"\"),\n    parser.add_argument(\n        '--run-after', dest='common_run_after',\n        nargs='+',\n        action='append',\n        metavar='PLUGINSPEC',\n        help=\"\"\"Like --run-before, but plugins are executed after the main command\n        has finished.\"\"\"),\n    parser.add_argument(\n        '--cmd', dest='_', action='store_true',\n        help=\"\"\"syntactical helper that can be used to end the list of global\n        command line options before the subcommand label. Options like\n        --run-before can take an arbitray number of arguments and may require\n        to be followed by a single --cmd in order to enable identification\n        of the subcommand.\"\"\")\n\n    # yoh: atm we only dump to console.  Might adopt the same separation later on\n    #      and for consistency will call it --verbose-level as well for now\n    # log-level is set via common_opts ATM\n    # parser.add_argument('--log-level',\n    #                     choices=('critical', 'error', 'warning', 'info', 'debug'),\n    #                     dest='common_log_level',\n    #                     help=\"\"\"level of verbosity in log files. By default\n    #                          everything, including debug messages is logged.\"\"\")\n    #parser.add_argument('-l', '--verbose-level',\n    #                    choices=('critical', 'error', 'warning', 'info', 'debug'),\n    #                    dest='common_verbose_level',\n    #                    help=\"\"\"level of verbosity of console output. By default\n    #                         only warnings and errors are printed.\"\"\")\n\n    # subparsers\n    subparsers = parser.add_subparsers()\n\n    # auto detect all available interfaces and generate a function-based\n    # API from them\n    grp_short_descriptions = []\n    interface_groups = get_interface_groups()\n    for grp_name, grp_descr, _interfaces \\\n                in sorted(interface_groups, key=lambda x: x[1]):\n        # for all subcommand modules it can find\n        cmd_short_descriptions = []\n\n        for _intfspec in _interfaces:\n            # turn the interface spec into an instance\n            lgr.log(5, \"Importing module %s \" % _intfspec[0])\n            try:\n                _mod = import_module(_intfspec[0], package='datalad')\n            except Exception as e:\n                lgr.error(\"Internal error, cannot import interface '%s': %s\",\n                          _intfspec[0], exc_str(e))\n                continue\n            _intf = getattr(_mod, _intfspec[1])\n            cmd_name = get_cmdline_command_name(_intfspec)\n            # deal with optional parser args\n            if hasattr(_intf, 'parser_args'):\n                parser_args = _intf.parser_args\n            else:\n                parser_args = dict(formatter_class=formatter_class)\n            # use class description, if no explicit description is available\n                intf_doc = _intf.__doc__.strip()\n                if hasattr(_intf, '_docs_'):\n                    # expand docs\n                    intf_doc = intf_doc.format(**_intf._docs_)\n                parser_args['description'] = alter_interface_docs_for_cmdline(\n                    intf_doc)\n            # create subparser, use module suffix as cmd name\n            subparser = subparsers.add_parser(cmd_name, add_help=False, **parser_args)\n            # our own custom help for all commands\n            helpers.parser_add_common_opt(subparser, 'help')\n            # let module configure the parser\n            _intf.setup_parser(subparser)\n            # logger for command\n\n            # configure 'run' function for this command\n            plumbing_args = dict(\n                func=_intf.call_from_parser,\n                logger=logging.getLogger(_intf.__module__),\n                subparser=subparser)\n            if hasattr(_intf, 'result_renderer_cmdline'):\n                plumbing_args['result_renderer'] = _intf.result_renderer_cmdline\n            subparser.set_defaults(**plumbing_args)\n            # store short description for later\n            sdescr = getattr(_intf, 'short_description',\n                             parser_args['description'].split('\\n')[0])\n            cmd_short_descriptions.append((cmd_name, sdescr))\n            parts[cmd_name] = subparser\n        grp_short_descriptions.append(cmd_short_descriptions)\n\n    # create command summary\n    cmd_summary = []\n    console_width = shutil.get_terminal_size()[0] \\\n        if hasattr(shutil, 'get_terminal_size') else 80\n\n    for i, grp in enumerate(\n            sorted(interface_groups, key=lambda x: x[1])):\n        grp_descr = grp[1]\n        grp_cmds = grp_short_descriptions[i]\n\n        cmd_summary.append('\\n*%s*\\n' % (grp_descr,))\n        for cd in grp_cmds:\n            cmd_summary.append('  %s\\n%s'\n                               % ((cd[0],\n                                  textwrap.fill(\n                                      cd[1].rstrip(' .'),\n                                      console_width - 5,\n                                      initial_indent=' ' * 6,\n                                      subsequent_indent=' ' * 6))))\n    # we need one last formal section to not have the trailed be\n    # confused with the last command group\n    cmd_summary.append('\\n*General information*\\n')\n    parser.description = '%s\\n%s\\n\\n%s' \\\n        % (parser.description,\n           '\\n'.join(cmd_summary),\n           textwrap.fill(dedent_docstring(\"\"\"\\\n    Detailed usage information for individual commands is\n    available via command-specific --help, i.e.:\n    datalad <command> --help\"\"\"),\n                         console_width - 5, initial_indent='', subsequent_indent=''))\n    parts['datalad'] = parser\n    lgr.log(5, \"Finished setup_parser\")\n    if return_subparsers:\n        return parts\n    else:\n        return parser\n\n\n# yoh: arn't used\n# def generate_api_call(cmdlineargs=None):\n#     parser = setup_parser()\n#     # parse cmd args\n#     cmdlineargs = parser.parse_args(cmdlineargs)\n#     # convert cmdline args into API call spec\n#     functor, args, kwargs = cmdlineargs.func(cmdlineargs)\n#     return cmdlineargs, functor, args, kwargs\n\n\ndef main(args=None):\n    lgr.log(5, \"Starting main(%r)\", args)\n    # PYTHON_ARGCOMPLETE_OK\n    parser = setup_parser()\n    try:\n        import argcomplete\n        argcomplete.autocomplete(parser)\n    except ImportError:\n        pass\n\n    # parse cmd args\n    cmdlineargs, unparsed_args = parser.parse_known_args(args)\n    has_func = hasattr(cmdlineargs, 'func') and cmdlineargs.func is not None\n    if unparsed_args:\n        if has_func and cmdlineargs.func.__self__.__name__ != 'Export':\n            lgr.error('unknown argument{}: {}'.format(\n                's' if len(unparsed_args) > 1 else '',\n                unparsed_args if len(unparsed_args) > 1 else unparsed_args[0]))\n            cmdlineargs.subparser.print_usage()\n            sys.exit(1)\n        else:\n            # store all unparsed arguments\n            cmdlineargs.datalad_unparsed_args = unparsed_args\n\n    # to possibly be passed into PBS scheduled call\n    args_ = args or sys.argv\n\n    if cmdlineargs.cfg_overrides is not None:\n        overrides = dict([\n            (o.split('=')[0], '='.join(o.split('=')[1:]))\n            for o in cmdlineargs.cfg_overrides])\n        datalad.cfg.overrides.update(overrides)\n\n    # enable overrides\n    datalad.cfg.reload(force=True)\n\n    if cmdlineargs.change_path is not None:\n        from .common_args import change_path as change_path_opt\n        for path in cmdlineargs.change_path:\n            chpwd(path)\n            args_ = strip_arg_from_argv(args_, path, change_path_opt[1])\n\n    ret = None\n    if cmdlineargs.pbs_runner:\n        from .helpers import run_via_pbs\n        from .common_args import pbs_runner as pbs_runner_opt\n        args_ = strip_arg_from_argv(args_, cmdlineargs.pbs_runner, pbs_runner_opt[1])\n        # run the function associated with the selected command\n        run_via_pbs(args_, cmdlineargs.pbs_runner)\n    elif has_func:\n        if cmdlineargs.common_debug or cmdlineargs.common_idebug:\n            # so we could see/stop clearly at the point of failure\n            setup_exceptionhook(ipython=cmdlineargs.common_idebug)\n            from datalad.interface.base import Interface\n            Interface._interrupted_exit_code = None\n            ret = cmdlineargs.func(cmdlineargs)\n        else:\n            # otherwise - guard and only log the summary. Postmortem is not\n            # as convenient if being caught in this ultimate except\n            try:\n                ret = cmdlineargs.func(cmdlineargs)\n            except InsufficientArgumentsError as exc:\n                # if the func reports inappropriate usage, give help output\n                lgr.error('%s (%s)' % (exc_str(exc), exc.__class__.__name__))\n                cmdlineargs.subparser.print_usage(sys.stderr)\n                sys.exit(2)\n            except IncompleteResultsError as exc:\n                # rendering for almost all commands now happens 'online'\n                # hence we are no longer attempting to render the actual\n                # results in an IncompleteResultsError, ubt rather trust that\n                # this happened before\n\n                # in general we do not want to see the error again, but\n                # present in debug output\n                lgr.debug('could not perform all requested actions: %s',\n                          exc_str(exc))\n                sys.exit(1)\n            except CommandError as exc:\n                # behave as if the command ran directly, importantly pass\n                # exit code as is\n                if exc.msg:\n                    os.write(2, exc.msg.encode() if isinstance(exc.msg, text_type) else exc.msg)\n                if exc.stdout:\n                    os.write(1, exc.stdout.encode() if isinstance(exc.stdout, text_type) else exc.stdout)\n                if exc.stderr:\n                    os.write(2, exc.stderr.encode() if isinstance(exc.stderr, text_type) else exc.stderr)\n                # We must not exit with 0 code if any exception got here but\n                # had no code defined\n                sys.exit(exc.code if exc.code is not None else 1)\n            except Exception as exc:\n                lgr.error('%s (%s)' % (exc_str(exc), exc.__class__.__name__))\n                sys.exit(1)\n    else:\n        # just let argparser spit out its error, since there is smth wrong\n        parser.parse_args(args)\n        # if that one didn't puke -- we should\n        parser.print_usage()\n        lgr.error(\"Please specify the command\")\n        sys.exit(2)\n\n    try:\n        if hasattr(cmdlineargs, 'result_renderer'):\n            cmdlineargs.result_renderer(ret, cmdlineargs)\n    except Exception as exc:\n        lgr.error(\"Failed to render results due to %s\", exc_str(exc))\n        sys.exit(1)\n\nlgr.log(5, \"Done importing cmdline.main\")\n",
            "header": {
                "file": {
                    "path": "datalad/cmdline/main.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "aed381f96",
                "new_commit_hash": "20313fc41",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/datalad/cmdline/main.py"
            },
            "plus_file": {
                "path": "b/datalad/cmdline/main.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 113,
                            "length": 7
                        },
                        "new_range": {
                            "start": 113,
                            "length": 7
                        },
                        "section": "def setup_parser("
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "        '-f', '--output-format', dest='common_output_format',",
                                "type": "context"
                            },
                            {
                                "content": "        default='default',",
                                "type": "context"
                            },
                            {
                                "content": "        type=assure_unicode,",
                                "type": "context"
                            },
                            {
                                "content": "        metavar=\"{default,json,json_pp,tailored,'<template>'\",",
                                "type": "deleted"
                            },
                            {
                                "content": "        metavar=\"{default,json,json_pp,tailored,'<template>'}\",",
                                "type": "added"
                            },
                            {
                                "content": "        help=\"\"\"select format for returned command results. 'default' give one line",
                                "type": "context"
                            },
                            {
                                "content": "        per result reporting action, status, path and an optional message;",
                                "type": "context"
                            },
                            {
                                "content": "        'json' renders a JSON object with all properties for each result (one per",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "datalad/cmdline/main.py",
                            "type": "function",
                            "name": "setup_parser",
                            "content": "def setup_parser(\n        formatter_class=argparse.RawDescriptionHelpFormatter,\n        return_subparsers=False):\n\n    lgr.log(5, \"Starting to setup_parser\")\n    # delay since it can be a heavy import\n    from ..interface.base import dedent_docstring, get_interface_groups, \\\n        get_cmdline_command_name, alter_interface_docs_for_cmdline\n    # setup cmdline args parser\n    parts = {}\n    # main parser\n    parser = argparse.ArgumentParser(\n        # cannot use '@' because we need to input JSON-LD properties (which might come wit @ prefix)\n        # MH: question, do we need this at all?\n        fromfile_prefix_chars=':',\n        # usage=\"%(prog)s ...\",\n        description=dedent_docstring(\"\"\"\\\n            DataLad provides a unified data distribution with the convenience of git-annex\n            repositories as a backend.  DataLad command line tools allow to manipulate\n            (obtain, create, update, publish, etc.) datasets and their collections.\"\"\"),\n        epilog='\"Control Your Data\"',\n        formatter_class=formatter_class,\n        add_help=False)\n    # common options\n    helpers.parser_add_common_opt(parser, 'help')\n    helpers.parser_add_common_opt(parser, 'log_level')\n    helpers.parser_add_common_opt(parser, 'pbs_runner')\n    helpers.parser_add_common_opt(parser, 'change_path')\n    helpers.parser_add_common_opt(\n        parser,\n        'version',\n        version='datalad %s\\n\\n%s' % (datalad.__version__, _license_info()))\n    if __debug__:\n        parser.add_argument(\n            '--dbg', action='store_true', dest='common_debug',\n            help=\"enter Python debugger when uncaught exception happens\")\n        parser.add_argument(\n            '--idbg', action='store_true', dest='common_idebug',\n            help=\"enter IPython debugger when uncaught exception happens\")\n    parser.add_argument(\n        '-c', action='append', dest='cfg_overrides', metavar='KEY=VALUE',\n        help=\"\"\"configuration variable setting. Overrides any configuration\n        read from a file, but is potentially overridden itself by configuration\n        variables in the process environment.\"\"\")\n    parser.add_argument(\n        '-f', '--output-format', dest='common_output_format',\n        default='default',\n        type=assure_unicode,\n        metavar=\"{default,json,json_pp,tailored,'<template>'\",\n        help=\"\"\"select format for returned command results. 'default' give one line\n        per result reporting action, status, path and an optional message;\n        'json' renders a JSON object with all properties for each result (one per\n        line); 'json_pp' pretty-prints JSON spanning multiple lines; 'tailored'\n        enables a command-specific rendering style that is typically\n        tailored to human consumption (no result output otherwise),\n        '<template>' reports any value(s) of any result properties in any format\n        indicated by the template (e.g. '{path}'; compare with JSON\n        output for all key-value choices). The template syntax follows the Python\n        \"format() language\". It is possible to report individual\n        dictionary values, e.g. '{metadata[name]}'. If a 2nd-level key contains\n        a colon, e.g. 'music:Genre', ':' must be substituted by '#' in the template,\n        like so: '{metadata[music#Genre]}'.\"\"\")\n    parser.add_argument(\n        '--report-status', dest='common_report_status',\n        choices=['success', 'failure', 'ok', 'notneeded', 'impossible', 'error'],\n        help=\"\"\"constrain command result report to records matching the given\n        status. 'success' is a synonym for 'ok' OR 'notneeded', 'failure' stands\n        for 'impossible' OR 'error'.\"\"\")\n    parser.add_argument(\n        '--report-type', dest='common_report_type',\n        choices=['dataset', 'file'],\n        action='append',\n        help=\"\"\"constrain command result report to records matching the given\n        type. Can be given more than once to match multiple types.\"\"\")\n    parser.add_argument(\n        '--on-failure', dest='common_on_failure',\n        choices=['ignore', 'continue', 'stop'],\n        # no default: better be configure per-command\n        help=\"\"\"when an operation fails: 'ignore' and continue with remaining\n        operations, the error is logged but does not lead to a non-zero exit code\n        of the command; 'continue' works like 'ignore', but an error causes a\n        non-zero exit code; 'stop' halts on first failure and yields non-zero exit\n        code. A failure is any result with status 'impossible' or 'error'.\"\"\")\n    parser.add_argument(\n        '--run-before', dest='common_run_before',\n        nargs='+',\n        action='append',\n        metavar='PLUGINSPEC',\n        help=\"\"\"DataLad plugin to run after the command. PLUGINSPEC is a list\n        comprised of a plugin name plus optional `key=value` pairs with arguments\n        for the plugin call (see `plugin` command documentation for details).\n        This option can be given more than once to run multiple plugins\n        in the order in which they were given.\n        For running plugins that require a --dataset argument it is important\n        to provide the respective dataset as the --dataset argument of the main\n        command, if it is not in the list of plugin arguments.\"\"\"),\n    parser.add_argument(\n        '--run-after', dest='common_run_after',\n        nargs='+',\n        action='append',\n        metavar='PLUGINSPEC',\n        help=\"\"\"Like --run-before, but plugins are executed after the main command\n        has finished.\"\"\"),\n    parser.add_argument(\n        '--cmd', dest='_', action='store_true',\n        help=\"\"\"syntactical helper that can be used to end the list of global\n        command line options before the subcommand label. Options like\n        --run-before can take an arbitray number of arguments and may require\n        to be followed by a single --cmd in order to enable identification\n        of the subcommand.\"\"\")\n\n    # yoh: atm we only dump to console.  Might adopt the same separation later on\n    #      and for consistency will call it --verbose-level as well for now\n    # log-level is set via common_opts ATM\n    # parser.add_argument('--log-level',\n    #                     choices=('critical', 'error', 'warning', 'info', 'debug'),\n    #                     dest='common_log_level',\n    #                     help=\"\"\"level of verbosity in log files. By default\n    #                          everything, including debug messages is logged.\"\"\")\n    #parser.add_argument('-l', '--verbose-level',\n    #                    choices=('critical', 'error', 'warning', 'info', 'debug'),\n    #                    dest='common_verbose_level',\n    #                    help=\"\"\"level of verbosity of console output. By default\n    #                         only warnings and errors are printed.\"\"\")\n\n    # subparsers\n    subparsers = parser.add_subparsers()\n\n    # auto detect all available interfaces and generate a function-based\n    # API from them\n    grp_short_descriptions = []\n    interface_groups = get_interface_groups()\n    for grp_name, grp_descr, _interfaces \\\n                in sorted(interface_groups, key=lambda x: x[1]):\n        # for all subcommand modules it can find\n        cmd_short_descriptions = []\n\n        for _intfspec in _interfaces:\n            # turn the interface spec into an instance\n            lgr.log(5, \"Importing module %s \" % _intfspec[0])\n            try:\n                _mod = import_module(_intfspec[0], package='datalad')\n            except Exception as e:\n                lgr.error(\"Internal error, cannot import interface '%s': %s\",\n                          _intfspec[0], exc_str(e))\n                continue\n            _intf = getattr(_mod, _intfspec[1])\n            cmd_name = get_cmdline_command_name(_intfspec)\n            # deal with optional parser args\n            if hasattr(_intf, 'parser_args'):\n                parser_args = _intf.parser_args\n            else:\n                parser_args = dict(formatter_class=formatter_class)\n            # use class description, if no explicit description is available\n                intf_doc = _intf.__doc__.strip()\n                if hasattr(_intf, '_docs_'):\n                    # expand docs\n                    intf_doc = intf_doc.format(**_intf._docs_)\n                parser_args['description'] = alter_interface_docs_for_cmdline(\n                    intf_doc)\n            # create subparser, use module suffix as cmd name\n            subparser = subparsers.add_parser(cmd_name, add_help=False, **parser_args)\n            # our own custom help for all commands\n            helpers.parser_add_common_opt(subparser, 'help')\n            # let module configure the parser\n            _intf.setup_parser(subparser)\n            # logger for command\n\n            # configure 'run' function for this command\n            plumbing_args = dict(\n                func=_intf.call_from_parser,\n                logger=logging.getLogger(_intf.__module__),\n                subparser=subparser)\n            if hasattr(_intf, 'result_renderer_cmdline'):\n                plumbing_args['result_renderer'] = _intf.result_renderer_cmdline\n            subparser.set_defaults(**plumbing_args)\n            # store short description for later\n            sdescr = getattr(_intf, 'short_description',\n                             parser_args['description'].split('\\n')[0])\n            cmd_short_descriptions.append((cmd_name, sdescr))\n            parts[cmd_name] = subparser\n        grp_short_descriptions.append(cmd_short_descriptions)\n\n    # create command summary\n    cmd_summary = []\n    console_width = shutil.get_terminal_size()[0] \\\n        if hasattr(shutil, 'get_terminal_size') else 80\n\n    for i, grp in enumerate(\n            sorted(interface_groups, key=lambda x: x[1])):\n        grp_descr = grp[1]\n        grp_cmds = grp_short_descriptions[i]\n\n        cmd_summary.append('\\n*%s*\\n' % (grp_descr,))\n        for cd in grp_cmds:\n            cmd_summary.append('  %s\\n%s'\n                               % ((cd[0],\n                                  textwrap.fill(\n                                      cd[1].rstrip(' .'),\n                                      console_width - 5,\n                                      initial_indent=' ' * 6,\n                                      subsequent_indent=' ' * 6))))\n    # we need one last formal section to not have the trailed be\n    # confused with the last command group\n    cmd_summary.append('\\n*General information*\\n')\n    parser.description = '%s\\n%s\\n\\n%s' \\\n        % (parser.description,\n           '\\n'.join(cmd_summary),\n           textwrap.fill(dedent_docstring(\"\"\"\\\n    Detailed usage information for individual commands is\n    available via command-specific --help, i.e.:\n    datalad <command> --help\"\"\"),\n                         console_width - 5, initial_indent='', subsequent_indent=''))\n    parts['datalad'] = parser\n    lgr.log(5, \"Finished setup_parser\")\n    if return_subparsers:\n        return parts\n    else:\n        return parser",
                            "ast_type_str": "FunctionDef",
                            "start_lineno": 68,
                            "end_lineno": 286,
                            "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\"\"\"High-level interface generation\n\n\"\"\"\n\n__docformat__ = 'restructuredtext'\n\nimport logging\nlgr = logging.getLogger('datalad.interface.base')\n\nimport sys\nimport re\nimport textwrap\nimport inspect\nfrom collections import OrderedDict\n\nfrom ..ui import ui\nfrom ..dochelpers import exc_str\n\nfrom datalad.interface.common_opts import eval_params\nfrom datalad.interface.common_opts import eval_defaults\nfrom datalad.support.exceptions import InsufficientArgumentsError\nfrom datalad.utils import with_pathsep as _with_sep\nfrom datalad.support.constraints import EnsureKeyChoice\nfrom datalad.distribution.dataset import Dataset\nfrom datalad.distribution.dataset import resolve_path\n\n\ndefault_logchannels = {\n    '': 'debug',\n    'ok': 'debug',\n    'notneeded': 'debug',\n    'impossible': 'warning',\n    'error': 'error',\n}\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    \"\"\"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    docs = re.sub(\n        '\\|\\| REFLOW \\>\\>\\n(.*)\\<\\< REFLOW \\|\\|',\n        lambda match: textwrap.fill(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    # clean up sphinx API refs\n    docs = re.sub(\n        '\\~datalad\\.api\\.\\S*',\n        lambda match: \"`{0}`\".format(match.group(0)[13:]),\n        docs)\n    # Remove RST paragraph markup\n    docs = re.sub(\n        r'^.. \\S+::',\n        lambda match: match.group(0)[3:-2].upper(),\n        docs,\n        flags=re.MULTILINE)\n    docs = re.sub(\n        '\\|\\| REFLOW \\>\\>\\n(.*)\\<\\< REFLOW \\|\\|',\n        lambda match: textwrap.fill(match.group(1)),\n        docs,\n        flags=re.MULTILINE | re.DOTALL)\n    return docs\n\n\ndef is_api_arg(arg):\n    \"\"\"Return True if argument is our API argument or self or used for internal\n    purposes\n    \"\"\"\n    return arg != 'self' and not arg.startswith('_')\n\n\ndef update_docstring_with_parameters(func, params, prefix=None, suffix=None,\n                                     add_args=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 add_args:\n        add_argnames = sorted(add_args.keys())\n        args.extend(add_argnames)\n        defaults = defaults + tuple(add_args[k] for k in add_argnames)\n    if defaults is not 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 not is_api_arg(arg):\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 param.constraints is not None:\n                    param.constraints(defaults[defaults_idx])\n            orig_docs = param._doc\n            param._doc = alter_interface_docs_for_api(param._doc)\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            param._doc = orig_docs\n            doc += '\\n'\n    doc += suffix if suffix else u\"\"\n    # assign the amended docs\n    func.__doc__ = doc\n    return func\n\n\ndef build_doc(cls, **kwargs):\n    \"\"\"Decorator to build docstrings for datalad commands\n\n    It's intended to decorate the class, the __call__-method of which is the\n    actual command. It expects that __call__-method to be decorated by\n    eval_results.\n\n    Parameters\n    ----------\n    cls: Interface\n      class defining a datalad command\n    \"\"\"\n\n    # Note, that this is a class decorator, which is executed only once when the\n    # class is imported. It builds the docstring for the class' __call__ method\n    # and returns the original class.\n    #\n    # This is because a decorator for the actual function would not be able to\n    # behave like this. To build the docstring we need to access the attribute\n    # _params of the class. From within a function decorator we cannot do this\n    # during import time, since the class is being built in this very moment and\n    # is not yet available in the module. And if we do it from within the part\n    # of a function decorator, that is executed when the function is called, we\n    # would need to actually call the command once in order to build this\n    # docstring.\n\n    lgr.debug(\"Building doc for {}\".format(cls))\n\n    cls_doc = cls.__doc__\n    if hasattr(cls, '_docs_'):\n        # expand docs\n        cls_doc = cls_doc.format(**cls._docs_)\n\n    call_doc = None\n    # suffix for update_docstring_with_parameters:\n    if cls.__call__.__doc__:\n        call_doc = cls.__call__.__doc__\n\n    # build standard doc and insert eval_doc\n    spec = getattr(cls, '_params_', dict())\n    # get docs for eval_results parameters:\n    spec.update(eval_params)\n\n    update_docstring_with_parameters(\n        cls.__call__, spec,\n        prefix=alter_interface_docs_for_api(cls_doc),\n        suffix=alter_interface_docs_for_api(call_doc),\n        add_args=eval_defaults if not hasattr(cls, '_no_eval_results') else None\n    )\n\n    # return original\n    return cls\n\n\nclass Interface(object):\n    \"\"\"Base class for interface implementations\"\"\"\n\n    # exit code to return if user-interrupted\n    # if None, would just reraise the Exception, so if in --dbg\n    # mode would fall into the debugger\n    _interrupted_exit_code = 1\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 not is_api_arg(arg):\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 constraint 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        from datalad import cfg\n        # XXX needs safety check for name collisions\n        from inspect import getargspec\n        argspec = getargspec(cls.__call__)\n        if argspec[2] is None:\n            # no **kwargs in the call receiver, pull argnames from signature\n            argnames = getargspec(cls.__call__)[0]\n        else:\n            # common options\n            # XXX define or better get from elsewhere\n            common_opts = ('change_path', 'common_debug', 'common_idebug', 'func',\n                           'help', 'log_level', 'logger', 'pbs_runner',\n                           'result_renderer', 'subparser')\n            argnames = [name for name in dir(args)\n                        if not (name.startswith('_') or name in common_opts)]\n        kwargs = {k: getattr(args, k) for k in argnames if is_api_arg(k)}\n        # we are coming from the entry point, this is the toplevel command,\n        # let it run like generator so we can act on partial results quicker\n        # TODO remove following condition test when transition is complete and\n        # run indented code unconditionally\n        if cls.__name__ not in (\n                'AddArchiveContent',\n                'CrawlInit', 'Crawl', 'CreateSiblingGithub',\n                'CreateTestDataset', 'DownloadURL', 'Export', 'Ls', 'Move',\n                'SSHRun', 'Test'):\n            # set all common args explicitly  to override class defaults\n            # that are tailored towards the the Python API\n            kwargs['return_type'] = 'generator'\n            kwargs['result_xfm'] = None\n            # allow commands to override the default, unless something other than\n            # default is requested\n            kwargs['result_renderer'] = \\\n                args.common_output_format if args.common_output_format != 'default' \\\n                else getattr(cls, 'result_renderer', args.common_output_format)\n            if '{' in args.common_output_format:\n                # stupid hack, could and should become more powerful\n                kwargs['result_renderer'] = \\\n                    lambda x, **kwargs: ui.message(args.common_output_format.format(\n                        **{k: {k_.replace(':', '#'): v_ for k_, v_ in v.items()}\n                           if isinstance(v, dict) else v\n                           for k, v in x.items()}))\n            if args.common_on_failure:\n                kwargs['on_failure'] = args.common_on_failure\n            # compose filter function from to be invented cmdline options\n            result_filter = None\n            if args.common_report_status or 'datalad.runtime.report-status' in cfg:\n                report_status = args.common_report_status or \\\n                    cfg.obtain('datalad.runtime.report-status')\n                if report_status == 'success':\n                    result_filter = EnsureKeyChoice('status', ('ok', 'notneeded'))\n                elif report_status == 'failure':\n                    result_filter = EnsureKeyChoice('status', ('impossible', 'error'))\n                else:\n                    result_filter = EnsureKeyChoice('status', (report_status,))\n            if args.common_report_type:\n                tfilt = EnsureKeyChoice('type', tuple(args.common_report_type))\n                result_filter = result_filter & tfilt if result_filter else tfilt\n            kwargs['result_filter'] = result_filter\n        try:\n            ret = cls.__call__(**kwargs)\n            if inspect.isgenerator(ret):\n                ret = list(ret)\n            if args.common_output_format == 'tailored' and \\\n                    hasattr(cls, 'custom_result_summary_renderer'):\n                cls.custom_result_summary_renderer(ret)\n            return ret\n        except KeyboardInterrupt as exc:\n            ui.error(\"\\nInterrupted by user while doing magic: %s\" % exc_str(exc))\n            if cls._interrupted_exit_code is not None:\n                sys.exit(cls._interrupted_exit_code)\n            else:\n                raise\n\n    @classmethod\n    def get_refds_path(cls, dataset):\n        \"\"\"Return a resolved reference dataset path from a `dataset` argument\"\"\"\n        # theoretically a dataset could come in as a relative path -> resolve\n        if dataset is None:\n            return dataset\n        refds_path = dataset.path if isinstance(dataset, Dataset) \\\n            else Dataset(dataset).path\n        if refds_path:\n            refds_path = resolve_path(refds_path)\n        return refds_path\n\n\ndef get_allargs_as_kwargs(call, args, kwargs):\n    \"\"\"Generate a kwargs dict from a call signature and *args, **kwargs\n\n    Basically resolving the argnames for all positional arguments, and\n    resolvin the defaults for all kwargs that are not given in a kwargs\n    dict\n    \"\"\"\n    from inspect import getargspec\n    argspec = getargspec(call)\n    defaults = argspec.defaults\n    nargs = len(argspec.args)\n    assert (nargs >= len(defaults))\n    # map any args to their name\n    argmap = list(zip(argspec.args[:len(args)], args))\n    kwargs_ = OrderedDict(argmap)\n    # map defaults of kwargs to their names (update below)\n    for k, v in zip(argspec.args[-len(defaults):], defaults):\n        if k not in kwargs_:\n            kwargs_[k] = v\n    # update with provided kwarg args\n    kwargs_.update(kwargs)\n    # XXX we cannot assert the following, because our own highlevel\n    # API commands support more kwargs than what is discoverable\n    # from their signature...\n    #assert (nargs == len(kwargs_))\n    return kwargs_\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 logging\nlgr = logging.getLogger('datalad.interface.base')\n\nimport sys\nimport re\nimport textwrap\nimport inspect\nfrom collections import OrderedDict\n\nfrom ..ui import ui\nfrom ..dochelpers import exc_str\n\nfrom datalad.interface.common_opts import eval_params\nfrom datalad.interface.common_opts import eval_defaults\nfrom datalad.support.exceptions import InsufficientArgumentsError\nfrom datalad.utils import with_pathsep as _with_sep\nfrom datalad.support.constraints import EnsureKeyChoice\nfrom datalad.distribution.dataset import Dataset\nfrom datalad.distribution.dataset import resolve_path\n\n\ndefault_logchannels = {\n    '': 'debug',\n    'ok': 'debug',\n    'notneeded': 'debug',\n    'impossible': 'warning',\n    'error': 'error',\n}\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    \"\"\"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    docs = re.sub(\n        '\\|\\| REFLOW \\>\\>\\n(.*)\\<\\< REFLOW \\|\\|',\n        lambda match: textwrap.fill(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    # clean up sphinx API refs\n    docs = re.sub(\n        '\\~datalad\\.api\\.\\S*',\n        lambda match: \"`{0}`\".format(match.group(0)[13:]),\n        docs)\n    # Remove RST paragraph markup\n    docs = re.sub(\n        r'^.. \\S+::',\n        lambda match: match.group(0)[3:-2].upper(),\n        docs,\n        flags=re.MULTILINE)\n    docs = re.sub(\n        '\\|\\| REFLOW \\>\\>\\n(.*)\\<\\< REFLOW \\|\\|',\n        lambda match: textwrap.fill(match.group(1)),\n        docs,\n        flags=re.MULTILINE | re.DOTALL)\n    return docs\n\n\ndef is_api_arg(arg):\n    \"\"\"Return True if argument is our API argument or self or used for internal\n    purposes\n    \"\"\"\n    return arg != 'self' and not arg.startswith('_')\n\n\ndef update_docstring_with_parameters(func, params, prefix=None, suffix=None,\n                                     add_args=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 add_args:\n        add_argnames = sorted(add_args.keys())\n        args.extend(add_argnames)\n        defaults = defaults + tuple(add_args[k] for k in add_argnames)\n    if defaults is not 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 not is_api_arg(arg):\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 param.constraints is not None:\n                    param.constraints(defaults[defaults_idx])\n            orig_docs = param._doc\n            param._doc = alter_interface_docs_for_api(param._doc)\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            param._doc = orig_docs\n            doc += '\\n'\n    doc += suffix if suffix else u\"\"\n    # assign the amended docs\n    func.__doc__ = doc\n    return func\n\n\ndef build_doc(cls, **kwargs):\n    \"\"\"Decorator to build docstrings for datalad commands\n\n    It's intended to decorate the class, the __call__-method of which is the\n    actual command. It expects that __call__-method to be decorated by\n    eval_results.\n\n    Parameters\n    ----------\n    cls: Interface\n      class defining a datalad command\n    \"\"\"\n\n    # Note, that this is a class decorator, which is executed only once when the\n    # class is imported. It builds the docstring for the class' __call__ method\n    # and returns the original class.\n    #\n    # This is because a decorator for the actual function would not be able to\n    # behave like this. To build the docstring we need to access the attribute\n    # _params of the class. From within a function decorator we cannot do this\n    # during import time, since the class is being built in this very moment and\n    # is not yet available in the module. And if we do it from within the part\n    # of a function decorator, that is executed when the function is called, we\n    # would need to actually call the command once in order to build this\n    # docstring.\n\n    lgr.debug(\"Building doc for {}\".format(cls))\n\n    cls_doc = cls.__doc__\n    if hasattr(cls, '_docs_'):\n        # expand docs\n        cls_doc = cls_doc.format(**cls._docs_)\n\n    call_doc = None\n    # suffix for update_docstring_with_parameters:\n    if cls.__call__.__doc__:\n        call_doc = cls.__call__.__doc__\n\n    # build standard doc and insert eval_doc\n    spec = getattr(cls, '_params_', dict())\n    # get docs for eval_results parameters:\n    spec.update(eval_params)\n\n    update_docstring_with_parameters(\n        cls.__call__, spec,\n        prefix=alter_interface_docs_for_api(cls_doc),\n        suffix=alter_interface_docs_for_api(call_doc),\n        add_args=eval_defaults if not hasattr(cls, '_no_eval_results') else None\n    )\n\n    # return original\n    return cls\n\n\nclass Interface(object):\n    \"\"\"Base class for interface implementations\"\"\"\n\n    # exit code to return if user-interrupted\n    # if None, would just reraise the Exception, so if in --dbg\n    # mode would fall into the debugger\n    _interrupted_exit_code = 1\n\n    _OLDSTYLE_COMMANDS = (\n        'AddArchiveContent', 'CrawlInit', 'Crawl', 'CreateSiblingGithub',\n        'CreateTestDataset', 'DownloadURL', 'Export', 'Ls', 'Move', 'SSHRun',\n        'Test')\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 not is_api_arg(arg):\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 constraint 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        argspec = getargspec(cls.__call__)\n        if argspec[2] is None:\n            # no **kwargs in the call receiver, pull argnames from signature\n            argnames = getargspec(cls.__call__)[0]\n        else:\n            # common options\n            # XXX define or better get from elsewhere\n            common_opts = ('change_path', 'common_debug', 'common_idebug', 'func',\n                           'help', 'log_level', 'logger', 'pbs_runner',\n                           'result_renderer', 'subparser')\n            argnames = [name for name in dir(args)\n                        if not (name.startswith('_') or name in common_opts)]\n        kwargs = {k: getattr(args, k) for k in argnames if is_api_arg(k)}\n        # we are coming from the entry point, this is the toplevel command,\n        # let it run like generator so we can act on partial results quicker\n        # TODO remove following condition test when transition is complete and\n        # run indented code unconditionally\n        if cls.__name__ not in Interface._OLDSTYLE_COMMANDS:\n            # set all common args explicitly  to override class defaults\n            # that are tailored towards the the Python API\n            kwargs['return_type'] = 'generator'\n            kwargs['result_xfm'] = None\n            # allow commands to override the default, unless something other than\n            # default is requested\n            kwargs['result_renderer'] = \\\n                args.common_output_format if args.common_output_format != 'default' \\\n                else getattr(cls, 'result_renderer', args.common_output_format)\n            if '{' in args.common_output_format:\n                # stupid hack, could and should become more powerful\n                kwargs['result_renderer'] = \\\n                    lambda x, **kwargs: ui.message(args.common_output_format.format(\n                        **{k: {k_.replace(':', '#'): v_ for k_, v_ in v.items()}\n                           if isinstance(v, dict) else v\n                           for k, v in x.items()}))\n            if args.common_on_failure:\n                kwargs['on_failure'] = args.common_on_failure\n            # compose filter function from to be invented cmdline options\n            kwargs['result_filter'] = cls._get_result_filter(args)\n        try:\n            ret = cls.__call__(**kwargs)\n            if inspect.isgenerator(ret):\n                ret = list(ret)\n            if args.common_output_format == 'tailored' and \\\n                    hasattr(cls, 'custom_result_summary_renderer'):\n                cls.custom_result_summary_renderer(ret)\n            return ret\n        except KeyboardInterrupt as exc:\n            ui.error(\"\\nInterrupted by user while doing magic: %s\" % exc_str(exc))\n            if cls._interrupted_exit_code is not None:\n                sys.exit(cls._interrupted_exit_code)\n            else:\n                raise\n\n    @classmethod\n    def _get_result_filter(cls, args):\n        from datalad import cfg\n        result_filter = None\n        if args.common_report_status or 'datalad.runtime.report-status' in cfg:\n            report_status = args.common_report_status or \\\n                            cfg.obtain('datalad.runtime.report-status')\n            if report_status == 'success':\n                result_filter = EnsureKeyChoice('status', ('ok', 'notneeded'))\n            elif report_status == 'failure':\n                result_filter = EnsureKeyChoice('status',\n                                                ('impossible', 'error'))\n            else:\n                result_filter = EnsureKeyChoice('status', (report_status,))\n        if args.common_report_type:\n            tfilt = EnsureKeyChoice('type', tuple(args.common_report_type))\n            result_filter = result_filter & tfilt if result_filter else tfilt\n        return result_filter\n\n    @classmethod\n    def get_refds_path(cls, dataset):\n        \"\"\"Return a resolved reference dataset path from a `dataset` argument\"\"\"\n        # theoretically a dataset could come in as a relative path -> resolve\n        if dataset is None:\n            return dataset\n        refds_path = dataset.path if isinstance(dataset, Dataset) \\\n            else Dataset(dataset).path\n        if refds_path:\n            refds_path = resolve_path(refds_path)\n        return refds_path\n\n\ndef get_allargs_as_kwargs(call, args, kwargs):\n    \"\"\"Generate a kwargs dict from a call signature and *args, **kwargs\n\n    Basically resolving the argnames for all positional arguments, and\n    resolvin the defaults for all kwargs that are not given in a kwargs\n    dict\n    \"\"\"\n    from inspect import getargspec\n    argspec = getargspec(call)\n    defaults = argspec.defaults\n    nargs = len(argspec.args)\n    assert (nargs >= len(defaults))\n    # map any args to their name\n    argmap = list(zip(argspec.args[:len(args)], args))\n    kwargs_ = OrderedDict(argmap)\n    # map defaults of kwargs to their names (update below)\n    for k, v in zip(argspec.args[-len(defaults):], defaults):\n        if k not in kwargs_:\n            kwargs_[k] = v\n    # update with provided kwarg args\n    kwargs_.update(kwargs)\n    # XXX we cannot assert the following, because our own highlevel\n    # API commands support more kwargs than what is discoverable\n    # from their signature...\n    #assert (nargs == len(kwargs_))\n    return kwargs_\n",
            "header": {
                "file": {
                    "path": "datalad/interface/base.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "31ff267e8",
                "new_commit_hash": "631e7a30d",
                "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": 317,
                            "length": 6
                        },
                        "new_range": {
                            "start": 317,
                            "length": 11
                        },
                        "section": "class Interface(object):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "    # mode would fall into the debugger",
                                "type": "context"
                            },
                            {
                                "content": "    _interrupted_exit_code = 1",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "    _OLDSTYLE_COMMANDS = (",
                                "type": "added"
                            },
                            {
                                "content": "        'AddArchiveContent', 'CrawlInit', 'Crawl', 'CreateSiblingGithub',",
                                "type": "added"
                            },
                            {
                                "content": "        'CreateTestDataset', 'DownloadURL', 'Export', 'Ls', 'Move', 'SSHRun',",
                                "type": "added"
                            },
                            {
                                "content": "        'Test')",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "    @classmethod",
                                "type": "context"
                            },
                            {
                                "content": "    def setup_parser(cls, parser):",
                                "type": "context"
                            },
                            {
                                "content": "        # XXX needs safety check for name collisions",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "datalad/interface/base.py",
                            "type": "class",
                            "name": "Interface",
                            "content": "class Interface(object):\n    \"\"\"Base class for interface implementations\"\"\"\n\n    # exit code to return if user-interrupted\n    # if None, would just reraise the Exception, so if in --dbg\n    # mode would fall into the debugger\n    _interrupted_exit_code = 1\n\n    _OLDSTYLE_COMMANDS = (\n        'AddArchiveContent', 'CrawlInit', 'Crawl', 'CreateSiblingGithub',\n        'CreateTestDataset', 'DownloadURL', 'Export', 'Ls', 'Move', 'SSHRun',\n        'Test')\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 not is_api_arg(arg):\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 constraint 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        argspec = getargspec(cls.__call__)\n        if argspec[2] is None:\n            # no **kwargs in the call receiver, pull argnames from signature\n            argnames = getargspec(cls.__call__)[0]\n        else:\n            # common options\n            # XXX define or better get from elsewhere\n            common_opts = ('change_path', 'common_debug', 'common_idebug', 'func',\n                           'help', 'log_level', 'logger', 'pbs_runner',\n                           'result_renderer', 'subparser')\n            argnames = [name for name in dir(args)\n                        if not (name.startswith('_') or name in common_opts)]\n        kwargs = {k: getattr(args, k) for k in argnames if is_api_arg(k)}\n        # we are coming from the entry point, this is the toplevel command,\n        # let it run like generator so we can act on partial results quicker\n        # TODO remove following condition test when transition is complete and\n        # run indented code unconditionally\n        if cls.__name__ not in Interface._OLDSTYLE_COMMANDS:\n            # set all common args explicitly  to override class defaults\n            # that are tailored towards the the Python API\n            kwargs['return_type'] = 'generator'\n            kwargs['result_xfm'] = None\n            # allow commands to override the default, unless something other than\n            # default is requested\n            kwargs['result_renderer'] = \\\n                args.common_output_format if args.common_output_format != 'default' \\\n                else getattr(cls, 'result_renderer', args.common_output_format)\n            if '{' in args.common_output_format:\n                # stupid hack, could and should become more powerful\n                kwargs['result_renderer'] = \\\n                    lambda x, **kwargs: ui.message(args.common_output_format.format(\n                        **{k: {k_.replace(':', '#'): v_ for k_, v_ in v.items()}\n                           if isinstance(v, dict) else v\n                           for k, v in x.items()}))\n            if args.common_on_failure:\n                kwargs['on_failure'] = args.common_on_failure\n            # compose filter function from to be invented cmdline options\n            kwargs['result_filter'] = cls._get_result_filter(args)\n        try:\n            ret = cls.__call__(**kwargs)\n            if inspect.isgenerator(ret):\n                ret = list(ret)\n            if args.common_output_format == 'tailored' and \\\n                    hasattr(cls, 'custom_result_summary_renderer'):\n                cls.custom_result_summary_renderer(ret)\n            return ret\n        except KeyboardInterrupt as exc:\n            ui.error(\"\\nInterrupted by user while doing magic: %s\" % exc_str(exc))\n            if cls._interrupted_exit_code is not None:\n                sys.exit(cls._interrupted_exit_code)\n            else:\n                raise\n\n    @classmethod\n    def _get_result_filter(cls, args):\n        from datalad import cfg\n        result_filter = None\n        if args.common_report_status or 'datalad.runtime.report-status' in cfg:\n            report_status = args.common_report_status or \\\n                            cfg.obtain('datalad.runtime.report-status')\n            if report_status == 'success':\n                result_filter = EnsureKeyChoice('status', ('ok', 'notneeded'))\n            elif report_status == 'failure':\n                result_filter = EnsureKeyChoice('status',\n                                                ('impossible', 'error'))\n            else:\n                result_filter = EnsureKeyChoice('status', (report_status,))\n        if args.common_report_type:\n            tfilt = EnsureKeyChoice('type', tuple(args.common_report_type))\n            result_filter = result_filter & tfilt if result_filter else tfilt\n        return result_filter\n\n    @classmethod\n    def get_refds_path(cls, dataset):\n        \"\"\"Return a resolved reference dataset path from a `dataset` argument\"\"\"\n        # theoretically a dataset could come in as a relative path -> resolve\n        if dataset is None:\n            return dataset\n        refds_path = dataset.path if isinstance(dataset, Dataset) \\\n            else Dataset(dataset).path\n        if refds_path:\n            refds_path = resolve_path(refds_path)\n        return refds_path",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 312,
                            "end_lineno": 463,
                            "parent": null
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                },
                {
                    "descriptor": {
                        "old_range": {
                            "start": 371,
                            "length": 7
                        },
                        "new_range": {
                            "start": 376,
                            "length": 6
                        },
                        "section": "class Interface(object):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "    @classmethod",
                                "type": "context"
                            },
                            {
                                "content": "    def call_from_parser(cls, args):",
                                "type": "context"
                            },
                            {
                                "content": "        from datalad import cfg",
                                "type": "deleted"
                            },
                            {
                                "content": "        # XXX needs safety check for name collisions",
                                "type": "context"
                            },
                            {
                                "content": "        from inspect import getargspec",
                                "type": "context"
                            },
                            {
                                "content": "        argspec = getargspec(cls.__call__)",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "datalad/interface/base.py",
                            "type": "class",
                            "name": "Interface",
                            "content": "class Interface(object):\n    \"\"\"Base class for interface implementations\"\"\"\n\n    # exit code to return if user-interrupted\n    # if None, would just reraise the Exception, so if in --dbg\n    # mode would fall into the debugger\n    _interrupted_exit_code = 1\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 not is_api_arg(arg):\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 constraint 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        from datalad import cfg\n        # XXX needs safety check for name collisions\n        from inspect import getargspec\n        argspec = getargspec(cls.__call__)\n        if argspec[2] is None:\n            # no **kwargs in the call receiver, pull argnames from signature\n            argnames = getargspec(cls.__call__)[0]\n        else:\n            # common options\n            # XXX define or better get from elsewhere\n            common_opts = ('change_path', 'common_debug', 'common_idebug', 'func',\n                           'help', 'log_level', 'logger', 'pbs_runner',\n                           'result_renderer', 'subparser')\n            argnames = [name for name in dir(args)\n                        if not (name.startswith('_') or name in common_opts)]\n        kwargs = {k: getattr(args, k) for k in argnames if is_api_arg(k)}\n        # we are coming from the entry point, this is the toplevel command,\n        # let it run like generator so we can act on partial results quicker\n        # TODO remove following condition test when transition is complete and\n        # run indented code unconditionally\n        if cls.__name__ not in (\n                'AddArchiveContent',\n                'CrawlInit', 'Crawl', 'CreateSiblingGithub',\n                'CreateTestDataset', 'DownloadURL', 'Export', 'Ls', 'Move',\n                'SSHRun', 'Test'):\n            # set all common args explicitly  to override class defaults\n            # that are tailored towards the the Python API\n            kwargs['return_type'] = 'generator'\n            kwargs['result_xfm'] = None\n            # allow commands to override the default, unless something other than\n            # default is requested\n            kwargs['result_renderer'] = \\\n                args.common_output_format if args.common_output_format != 'default' \\\n                else getattr(cls, 'result_renderer', args.common_output_format)\n            if '{' in args.common_output_format:\n                # stupid hack, could and should become more powerful\n                kwargs['result_renderer'] = \\\n                    lambda x, **kwargs: ui.message(args.common_output_format.format(\n                        **{k: {k_.replace(':', '#'): v_ for k_, v_ in v.items()}\n                           if isinstance(v, dict) else v\n                           for k, v in x.items()}))\n            if args.common_on_failure:\n                kwargs['on_failure'] = args.common_on_failure\n            # compose filter function from to be invented cmdline options\n            result_filter = None\n            if args.common_report_status or 'datalad.runtime.report-status' in cfg:\n                report_status = args.common_report_status or \\\n                    cfg.obtain('datalad.runtime.report-status')\n                if report_status == 'success':\n                    result_filter = EnsureKeyChoice('status', ('ok', 'notneeded'))\n                elif report_status == 'failure':\n                    result_filter = EnsureKeyChoice('status', ('impossible', 'error'))\n                else:\n                    result_filter = EnsureKeyChoice('status', (report_status,))\n            if args.common_report_type:\n                tfilt = EnsureKeyChoice('type', tuple(args.common_report_type))\n                result_filter = result_filter & tfilt if result_filter else tfilt\n            kwargs['result_filter'] = result_filter\n        try:\n            ret = cls.__call__(**kwargs)\n            if inspect.isgenerator(ret):\n                ret = list(ret)\n            if args.common_output_format == 'tailored' and \\\n                    hasattr(cls, 'custom_result_summary_renderer'):\n                cls.custom_result_summary_renderer(ret)\n            return ret\n        except KeyboardInterrupt as exc:\n            ui.error(\"\\nInterrupted by user while doing magic: %s\" % exc_str(exc))\n            if cls._interrupted_exit_code is not None:\n                sys.exit(cls._interrupted_exit_code)\n            else:\n                raise\n\n    @classmethod\n    def get_refds_path(cls, dataset):\n        \"\"\"Return a resolved reference dataset path from a `dataset` argument\"\"\"\n        # theoretically a dataset could come in as a relative path -> resolve\n        if dataset is None:\n            return dataset\n        refds_path = dataset.path if isinstance(dataset, Dataset) \\\n            else Dataset(dataset).path\n        if refds_path:\n            refds_path = resolve_path(refds_path)\n        return refds_path",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 312,
                            "end_lineno": 457,
                            "parent": null
                        },
                        {
                            "file_name": "datalad/interface/base.py",
                            "type": "method",
                            "name": "Interface.call_from_parser",
                            "content": "class Interface(object):\n    \"\"\"Base class for interface implementations\"\"\"\n\n    # exit code to return if user-interrupted\n    # if None, would just reraise the Exception, so if in --dbg\n    # mode would fall into the debugger\n    _interrupted_exit_code = 1\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 not is_api_arg(arg):\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 constraint 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        from datalad import cfg\n        # XXX needs safety check for name collisions\n        from inspect import getargspec\n        argspec = getargspec(cls.__call__)\n        if argspec[2] is None:\n            # no **kwargs in the call receiver, pull argnames from signature\n            argnames = getargspec(cls.__call__)[0]\n        else:\n            # common options\n            # XXX define or better get from elsewhere\n            common_opts = ('change_path', 'common_debug', 'common_idebug', 'func',\n                           'help', 'log_level', 'logger', 'pbs_runner',\n                           'result_renderer', 'subparser')\n            argnames = [name for name in dir(args)\n                        if not (name.startswith('_') or name in common_opts)]\n        kwargs = {k: getattr(args, k) for k in argnames if is_api_arg(k)}\n        # we are coming from the entry point, this is the toplevel command,\n        # let it run like generator so we can act on partial results quicker\n        # TODO remove following condition test when transition is complete and\n        # run indented code unconditionally\n        if cls.__name__ not in (\n                'AddArchiveContent',\n                'CrawlInit', 'Crawl', 'CreateSiblingGithub',\n                'CreateTestDataset', 'DownloadURL', 'Export', 'Ls', 'Move',\n                'SSHRun', 'Test'):\n            # set all common args explicitly  to override class defaults\n            # that are tailored towards the the Python API\n            kwargs['return_type'] = 'generator'\n            kwargs['result_xfm'] = None\n            # allow commands to override the default, unless something other than\n            # default is requested\n            kwargs['result_renderer'] = \\\n                args.common_output_format if args.common_output_format != 'default' \\\n                else getattr(cls, 'result_renderer', args.common_output_format)\n            if '{' in args.common_output_format:\n                # stupid hack, could and should become more powerful\n                kwargs['result_renderer'] = \\\n                    lambda x, **kwargs: ui.message(args.common_output_format.format(\n                        **{k: {k_.replace(':', '#'): v_ for k_, v_ in v.items()}\n                           if isinstance(v, dict) else v\n                           for k, v in x.items()}))\n            if args.common_on_failure:\n                kwargs['on_failure'] = args.common_on_failure\n            # compose filter function from to be invented cmdline options\n            result_filter = None\n            if args.common_report_status or 'datalad.runtime.report-status' in cfg:\n                report_status = args.common_report_status or \\\n                    cfg.obtain('datalad.runtime.report-status')\n                if report_status == 'success':\n                    result_filter = EnsureKeyChoice('status', ('ok', 'notneeded'))\n                elif report_status == 'failure':\n                    result_filter = EnsureKeyChoice('status', ('impossible', 'error'))\n                else:\n                    result_filter = EnsureKeyChoice('status', (report_status,))\n            if args.common_report_type:\n                tfilt = EnsureKeyChoice('type', tuple(args.common_report_type))\n                result_filter = result_filter & tfilt if result_filter else tfilt\n            kwargs['result_filter'] = result_filter\n        try:\n            ret = cls.__call__(**kwargs)\n            if inspect.isgenerator(ret):\n                ret = list(ret)\n            if args.common_output_format == 'tailored' and \\\n                    hasattr(cls, 'custom_result_summary_renderer'):\n                cls.custom_result_summary_renderer(ret)\n            return ret\n        except KeyboardInterrupt as exc:\n            ui.error(\"\\nInterrupted by user while doing magic: %s\" % exc_str(exc))\n            if cls._interrupted_exit_code is not None:\n                sys.exit(cls._interrupted_exit_code)\n            else:\n                raise\n\n    @classmethod\n    def get_refds_path(cls, dataset):\n        \"\"\"Return a resolved reference dataset path from a `dataset` argument\"\"\"\n        # theoretically a dataset could come in as a relative path -> resolve\n        if dataset is None:\n            return dataset\n        refds_path = dataset.path if isinstance(dataset, Dataset) \\\n            else Dataset(dataset).path\n        if refds_path:\n            refds_path = resolve_path(refds_path)\n        return refds_path",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 373,
                            "end_lineno": 445,
                            "parent": {
                                "file_name": "datalad/interface/base.py",
                                "type": "class",
                                "name": "Interface",
                                "content": "class Interface(object):\n    \"\"\"Base class for interface implementations\"\"\"\n\n    # exit code to return if user-interrupted\n    # if None, would just reraise the Exception, so if in --dbg\n    # mode would fall into the debugger\n    _interrupted_exit_code = 1\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 not is_api_arg(arg):\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 constraint 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        from datalad import cfg\n        # XXX needs safety check for name collisions\n        from inspect import getargspec\n        argspec = getargspec(cls.__call__)\n        if argspec[2] is None:\n            # no **kwargs in the call receiver, pull argnames from signature\n            argnames = getargspec(cls.__call__)[0]\n        else:\n            # common options\n            # XXX define or better get from elsewhere\n            common_opts = ('change_path', 'common_debug', 'common_idebug', 'func',\n                           'help', 'log_level', 'logger', 'pbs_runner',\n                           'result_renderer', 'subparser')\n            argnames = [name for name in dir(args)\n                        if not (name.startswith('_') or name in common_opts)]\n        kwargs = {k: getattr(args, k) for k in argnames if is_api_arg(k)}\n        # we are coming from the entry point, this is the toplevel command,\n        # let it run like generator so we can act on partial results quicker\n        # TODO remove following condition test when transition is complete and\n        # run indented code unconditionally\n        if cls.__name__ not in (\n                'AddArchiveContent',\n                'CrawlInit', 'Crawl', 'CreateSiblingGithub',\n                'CreateTestDataset', 'DownloadURL', 'Export', 'Ls', 'Move',\n                'SSHRun', 'Test'):\n            # set all common args explicitly  to override class defaults\n            # that are tailored towards the the Python API\n            kwargs['return_type'] = 'generator'\n            kwargs['result_xfm'] = None\n            # allow commands to override the default, unless something other than\n            # default is requested\n            kwargs['result_renderer'] = \\\n                args.common_output_format if args.common_output_format != 'default' \\\n                else getattr(cls, 'result_renderer', args.common_output_format)\n            if '{' in args.common_output_format:\n                # stupid hack, could and should become more powerful\n                kwargs['result_renderer'] = \\\n                    lambda x, **kwargs: ui.message(args.common_output_format.format(\n                        **{k: {k_.replace(':', '#'): v_ for k_, v_ in v.items()}\n                           if isinstance(v, dict) else v\n                           for k, v in x.items()}))\n            if args.common_on_failure:\n                kwargs['on_failure'] = args.common_on_failure\n            # compose filter function from to be invented cmdline options\n            result_filter = None\n            if args.common_report_status or 'datalad.runtime.report-status' in cfg:\n                report_status = args.common_report_status or \\\n                    cfg.obtain('datalad.runtime.report-status')\n                if report_status == 'success':\n                    result_filter = EnsureKeyChoice('status', ('ok', 'notneeded'))\n                elif report_status == 'failure':\n                    result_filter = EnsureKeyChoice('status', ('impossible', 'error'))\n                else:\n                    result_filter = EnsureKeyChoice('status', (report_status,))\n            if args.common_report_type:\n                tfilt = EnsureKeyChoice('type', tuple(args.common_report_type))\n                result_filter = result_filter & tfilt if result_filter else tfilt\n            kwargs['result_filter'] = result_filter\n        try:\n            ret = cls.__call__(**kwargs)\n            if inspect.isgenerator(ret):\n                ret = list(ret)\n            if args.common_output_format == 'tailored' and \\\n                    hasattr(cls, 'custom_result_summary_renderer'):\n                cls.custom_result_summary_renderer(ret)\n            return ret\n        except KeyboardInterrupt as exc:\n            ui.error(\"\\nInterrupted by user while doing magic: %s\" % exc_str(exc))\n            if cls._interrupted_exit_code is not None:\n                sys.exit(cls._interrupted_exit_code)\n            else:\n                raise\n\n    @classmethod\n    def get_refds_path(cls, dataset):\n        \"\"\"Return a resolved reference dataset path from a `dataset` argument\"\"\"\n        # theoretically a dataset could come in as a relative path -> resolve\n        if dataset is None:\n            return dataset\n        refds_path = dataset.path if isinstance(dataset, Dataset) \\\n            else Dataset(dataset).path\n        if refds_path:\n            refds_path = resolve_path(refds_path)\n        return refds_path",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 312,
                                "end_lineno": 457,
                                "parent": null
                            }
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                },
                {
                    "descriptor": {
                        "old_range": {
                            "start": 391,
                            "length": 11
                        },
                        "new_range": {
                            "start": 395,
                            "length": 7
                        },
                        "section": "class Interface(object):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "        # let it run like generator so we can act on partial results quicker",
                                "type": "context"
                            },
                            {
                                "content": "        # TODO remove following condition test when transition is complete and",
                                "type": "context"
                            },
                            {
                                "content": "        # run indented code unconditionally",
                                "type": "context"
                            },
                            {
                                "content": "        if cls.__name__ not in (",
                                "type": "deleted"
                            },
                            {
                                "content": "                'AddArchiveContent',",
                                "type": "deleted"
                            },
                            {
                                "content": "                'CrawlInit', 'Crawl', 'CreateSiblingGithub',",
                                "type": "deleted"
                            },
                            {
                                "content": "                'CreateTestDataset', 'DownloadURL', 'Export', 'Ls', 'Move',",
                                "type": "deleted"
                            },
                            {
                                "content": "                'SSHRun', 'Test'):",
                                "type": "deleted"
                            },
                            {
                                "content": "        if cls.__name__ not in Interface._OLDSTYLE_COMMANDS:",
                                "type": "added"
                            },
                            {
                                "content": "            # set all common args explicitly  to override class defaults",
                                "type": "context"
                            },
                            {
                                "content": "            # that are tailored towards the the Python API",
                                "type": "context"
                            },
                            {
                                "content": "            kwargs['return_type'] = 'generator'",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "datalad/interface/base.py",
                            "type": "class",
                            "name": "Interface",
                            "content": "class Interface(object):\n    \"\"\"Base class for interface implementations\"\"\"\n\n    # exit code to return if user-interrupted\n    # if None, would just reraise the Exception, so if in --dbg\n    # mode would fall into the debugger\n    _interrupted_exit_code = 1\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 not is_api_arg(arg):\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 constraint 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        from datalad import cfg\n        # XXX needs safety check for name collisions\n        from inspect import getargspec\n        argspec = getargspec(cls.__call__)\n        if argspec[2] is None:\n            # no **kwargs in the call receiver, pull argnames from signature\n            argnames = getargspec(cls.__call__)[0]\n        else:\n            # common options\n            # XXX define or better get from elsewhere\n            common_opts = ('change_path', 'common_debug', 'common_idebug', 'func',\n                           'help', 'log_level', 'logger', 'pbs_runner',\n                           'result_renderer', 'subparser')\n            argnames = [name for name in dir(args)\n                        if not (name.startswith('_') or name in common_opts)]\n        kwargs = {k: getattr(args, k) for k in argnames if is_api_arg(k)}\n        # we are coming from the entry point, this is the toplevel command,\n        # let it run like generator so we can act on partial results quicker\n        # TODO remove following condition test when transition is complete and\n        # run indented code unconditionally\n        if cls.__name__ not in (\n                'AddArchiveContent',\n                'CrawlInit', 'Crawl', 'CreateSiblingGithub',\n                'CreateTestDataset', 'DownloadURL', 'Export', 'Ls', 'Move',\n                'SSHRun', 'Test'):\n            # set all common args explicitly  to override class defaults\n            # that are tailored towards the the Python API\n            kwargs['return_type'] = 'generator'\n            kwargs['result_xfm'] = None\n            # allow commands to override the default, unless something other than\n            # default is requested\n            kwargs['result_renderer'] = \\\n                args.common_output_format if args.common_output_format != 'default' \\\n                else getattr(cls, 'result_renderer', args.common_output_format)\n            if '{' in args.common_output_format:\n                # stupid hack, could and should become more powerful\n                kwargs['result_renderer'] = \\\n                    lambda x, **kwargs: ui.message(args.common_output_format.format(\n                        **{k: {k_.replace(':', '#'): v_ for k_, v_ in v.items()}\n                           if isinstance(v, dict) else v\n                           for k, v in x.items()}))\n            if args.common_on_failure:\n                kwargs['on_failure'] = args.common_on_failure\n            # compose filter function from to be invented cmdline options\n            result_filter = None\n            if args.common_report_status or 'datalad.runtime.report-status' in cfg:\n                report_status = args.common_report_status or \\\n                    cfg.obtain('datalad.runtime.report-status')\n                if report_status == 'success':\n                    result_filter = EnsureKeyChoice('status', ('ok', 'notneeded'))\n                elif report_status == 'failure':\n                    result_filter = EnsureKeyChoice('status', ('impossible', 'error'))\n                else:\n                    result_filter = EnsureKeyChoice('status', (report_status,))\n            if args.common_report_type:\n                tfilt = EnsureKeyChoice('type', tuple(args.common_report_type))\n                result_filter = result_filter & tfilt if result_filter else tfilt\n            kwargs['result_filter'] = result_filter\n        try:\n            ret = cls.__call__(**kwargs)\n            if inspect.isgenerator(ret):\n                ret = list(ret)\n            if args.common_output_format == 'tailored' and \\\n                    hasattr(cls, 'custom_result_summary_renderer'):\n                cls.custom_result_summary_renderer(ret)\n            return ret\n        except KeyboardInterrupt as exc:\n            ui.error(\"\\nInterrupted by user while doing magic: %s\" % exc_str(exc))\n            if cls._interrupted_exit_code is not None:\n                sys.exit(cls._interrupted_exit_code)\n            else:\n                raise\n\n    @classmethod\n    def get_refds_path(cls, dataset):\n        \"\"\"Return a resolved reference dataset path from a `dataset` argument\"\"\"\n        # theoretically a dataset could come in as a relative path -> resolve\n        if dataset is None:\n            return dataset\n        refds_path = dataset.path if isinstance(dataset, Dataset) \\\n            else Dataset(dataset).path\n        if refds_path:\n            refds_path = resolve_path(refds_path)\n        return refds_path",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 312,
                            "end_lineno": 457,
                            "parent": null
                        },
                        {
                            "file_name": "datalad/interface/base.py",
                            "type": "method",
                            "name": "Interface.call_from_parser",
                            "content": "class Interface(object):\n    \"\"\"Base class for interface implementations\"\"\"\n\n    # exit code to return if user-interrupted\n    # if None, would just reraise the Exception, so if in --dbg\n    # mode would fall into the debugger\n    _interrupted_exit_code = 1\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 not is_api_arg(arg):\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 constraint 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        from datalad import cfg\n        # XXX needs safety check for name collisions\n        from inspect import getargspec\n        argspec = getargspec(cls.__call__)\n        if argspec[2] is None:\n            # no **kwargs in the call receiver, pull argnames from signature\n            argnames = getargspec(cls.__call__)[0]\n        else:\n            # common options\n            # XXX define or better get from elsewhere\n            common_opts = ('change_path', 'common_debug', 'common_idebug', 'func',\n                           'help', 'log_level', 'logger', 'pbs_runner',\n                           'result_renderer', 'subparser')\n            argnames = [name for name in dir(args)\n                        if not (name.startswith('_') or name in common_opts)]\n        kwargs = {k: getattr(args, k) for k in argnames if is_api_arg(k)}\n        # we are coming from the entry point, this is the toplevel command,\n        # let it run like generator so we can act on partial results quicker\n        # TODO remove following condition test when transition is complete and\n        # run indented code unconditionally\n        if cls.__name__ not in (\n                'AddArchiveContent',\n                'CrawlInit', 'Crawl', 'CreateSiblingGithub',\n                'CreateTestDataset', 'DownloadURL', 'Export', 'Ls', 'Move',\n                'SSHRun', 'Test'):\n            # set all common args explicitly  to override class defaults\n            # that are tailored towards the the Python API\n            kwargs['return_type'] = 'generator'\n            kwargs['result_xfm'] = None\n            # allow commands to override the default, unless something other than\n            # default is requested\n            kwargs['result_renderer'] = \\\n                args.common_output_format if args.common_output_format != 'default' \\\n                else getattr(cls, 'result_renderer', args.common_output_format)\n            if '{' in args.common_output_format:\n                # stupid hack, could and should become more powerful\n                kwargs['result_renderer'] = \\\n                    lambda x, **kwargs: ui.message(args.common_output_format.format(\n                        **{k: {k_.replace(':', '#'): v_ for k_, v_ in v.items()}\n                           if isinstance(v, dict) else v\n                           for k, v in x.items()}))\n            if args.common_on_failure:\n                kwargs['on_failure'] = args.common_on_failure\n            # compose filter function from to be invented cmdline options\n            result_filter = None\n            if args.common_report_status or 'datalad.runtime.report-status' in cfg:\n                report_status = args.common_report_status or \\\n                    cfg.obtain('datalad.runtime.report-status')\n                if report_status == 'success':\n                    result_filter = EnsureKeyChoice('status', ('ok', 'notneeded'))\n                elif report_status == 'failure':\n                    result_filter = EnsureKeyChoice('status', ('impossible', 'error'))\n                else:\n                    result_filter = EnsureKeyChoice('status', (report_status,))\n            if args.common_report_type:\n                tfilt = EnsureKeyChoice('type', tuple(args.common_report_type))\n                result_filter = result_filter & tfilt if result_filter else tfilt\n            kwargs['result_filter'] = result_filter\n        try:\n            ret = cls.__call__(**kwargs)\n            if inspect.isgenerator(ret):\n                ret = list(ret)\n            if args.common_output_format == 'tailored' and \\\n                    hasattr(cls, 'custom_result_summary_renderer'):\n                cls.custom_result_summary_renderer(ret)\n            return ret\n        except KeyboardInterrupt as exc:\n            ui.error(\"\\nInterrupted by user while doing magic: %s\" % exc_str(exc))\n            if cls._interrupted_exit_code is not None:\n                sys.exit(cls._interrupted_exit_code)\n            else:\n                raise\n\n    @classmethod\n    def get_refds_path(cls, dataset):\n        \"\"\"Return a resolved reference dataset path from a `dataset` argument\"\"\"\n        # theoretically a dataset could come in as a relative path -> resolve\n        if dataset is None:\n            return dataset\n        refds_path = dataset.path if isinstance(dataset, Dataset) \\\n            else Dataset(dataset).path\n        if refds_path:\n            refds_path = resolve_path(refds_path)\n        return refds_path",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 373,
                            "end_lineno": 445,
                            "parent": {
                                "file_name": "datalad/interface/base.py",
                                "type": "class",
                                "name": "Interface",
                                "content": "class Interface(object):\n    \"\"\"Base class for interface implementations\"\"\"\n\n    # exit code to return if user-interrupted\n    # if None, would just reraise the Exception, so if in --dbg\n    # mode would fall into the debugger\n    _interrupted_exit_code = 1\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 not is_api_arg(arg):\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 constraint 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        from datalad import cfg\n        # XXX needs safety check for name collisions\n        from inspect import getargspec\n        argspec = getargspec(cls.__call__)\n        if argspec[2] is None:\n            # no **kwargs in the call receiver, pull argnames from signature\n            argnames = getargspec(cls.__call__)[0]\n        else:\n            # common options\n            # XXX define or better get from elsewhere\n            common_opts = ('change_path', 'common_debug', 'common_idebug', 'func',\n                           'help', 'log_level', 'logger', 'pbs_runner',\n                           'result_renderer', 'subparser')\n            argnames = [name for name in dir(args)\n                        if not (name.startswith('_') or name in common_opts)]\n        kwargs = {k: getattr(args, k) for k in argnames if is_api_arg(k)}\n        # we are coming from the entry point, this is the toplevel command,\n        # let it run like generator so we can act on partial results quicker\n        # TODO remove following condition test when transition is complete and\n        # run indented code unconditionally\n        if cls.__name__ not in (\n                'AddArchiveContent',\n                'CrawlInit', 'Crawl', 'CreateSiblingGithub',\n                'CreateTestDataset', 'DownloadURL', 'Export', 'Ls', 'Move',\n                'SSHRun', 'Test'):\n            # set all common args explicitly  to override class defaults\n            # that are tailored towards the the Python API\n            kwargs['return_type'] = 'generator'\n            kwargs['result_xfm'] = None\n            # allow commands to override the default, unless something other than\n            # default is requested\n            kwargs['result_renderer'] = \\\n                args.common_output_format if args.common_output_format != 'default' \\\n                else getattr(cls, 'result_renderer', args.common_output_format)\n            if '{' in args.common_output_format:\n                # stupid hack, could and should become more powerful\n                kwargs['result_renderer'] = \\\n                    lambda x, **kwargs: ui.message(args.common_output_format.format(\n                        **{k: {k_.replace(':', '#'): v_ for k_, v_ in v.items()}\n                           if isinstance(v, dict) else v\n                           for k, v in x.items()}))\n            if args.common_on_failure:\n                kwargs['on_failure'] = args.common_on_failure\n            # compose filter function from to be invented cmdline options\n            result_filter = None\n            if args.common_report_status or 'datalad.runtime.report-status' in cfg:\n                report_status = args.common_report_status or \\\n                    cfg.obtain('datalad.runtime.report-status')\n                if report_status == 'success':\n                    result_filter = EnsureKeyChoice('status', ('ok', 'notneeded'))\n                elif report_status == 'failure':\n                    result_filter = EnsureKeyChoice('status', ('impossible', 'error'))\n                else:\n                    result_filter = EnsureKeyChoice('status', (report_status,))\n            if args.common_report_type:\n                tfilt = EnsureKeyChoice('type', tuple(args.common_report_type))\n                result_filter = result_filter & tfilt if result_filter else tfilt\n            kwargs['result_filter'] = result_filter\n        try:\n            ret = cls.__call__(**kwargs)\n            if inspect.isgenerator(ret):\n                ret = list(ret)\n            if args.common_output_format == 'tailored' and \\\n                    hasattr(cls, 'custom_result_summary_renderer'):\n                cls.custom_result_summary_renderer(ret)\n            return ret\n        except KeyboardInterrupt as exc:\n            ui.error(\"\\nInterrupted by user while doing magic: %s\" % exc_str(exc))\n            if cls._interrupted_exit_code is not None:\n                sys.exit(cls._interrupted_exit_code)\n            else:\n                raise\n\n    @classmethod\n    def get_refds_path(cls, dataset):\n        \"\"\"Return a resolved reference dataset path from a `dataset` argument\"\"\"\n        # theoretically a dataset could come in as a relative path -> resolve\n        if dataset is None:\n            return dataset\n        refds_path = dataset.path if isinstance(dataset, Dataset) \\\n            else Dataset(dataset).path\n        if refds_path:\n            refds_path = resolve_path(refds_path)\n        return refds_path",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 312,
                                "end_lineno": 457,
                                "parent": null
                            }
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                },
                {
                    "descriptor": {
                        "old_range": {
                            "start": 415,
                            "length": 20
                        },
                        "new_range": {
                            "start": 415,
                            "length": 7
                        },
                        "section": "class Interface(object):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "            if args.common_on_failure:",
                                "type": "context"
                            },
                            {
                                "content": "                kwargs['on_failure'] = args.common_on_failure",
                                "type": "context"
                            },
                            {
                                "content": "            # compose filter function from to be invented cmdline options",
                                "type": "context"
                            },
                            {
                                "content": "            result_filter = None",
                                "type": "deleted"
                            },
                            {
                                "content": "            if args.common_report_status or 'datalad.runtime.report-status' in cfg:",
                                "type": "deleted"
                            },
                            {
                                "content": "                report_status = args.common_report_status or \\",
                                "type": "deleted"
                            },
                            {
                                "content": "                    cfg.obtain('datalad.runtime.report-status')",
                                "type": "deleted"
                            },
                            {
                                "content": "                if report_status == 'success':",
                                "type": "deleted"
                            },
                            {
                                "content": "                    result_filter = EnsureKeyChoice('status', ('ok', 'notneeded'))",
                                "type": "deleted"
                            },
                            {
                                "content": "                elif report_status == 'failure':",
                                "type": "deleted"
                            },
                            {
                                "content": "                    result_filter = EnsureKeyChoice('status', ('impossible', 'error'))",
                                "type": "deleted"
                            },
                            {
                                "content": "                else:",
                                "type": "deleted"
                            },
                            {
                                "content": "                    result_filter = EnsureKeyChoice('status', (report_status,))",
                                "type": "deleted"
                            },
                            {
                                "content": "            if args.common_report_type:",
                                "type": "deleted"
                            },
                            {
                                "content": "                tfilt = EnsureKeyChoice('type', tuple(args.common_report_type))",
                                "type": "deleted"
                            },
                            {
                                "content": "                result_filter = result_filter & tfilt if result_filter else tfilt",
                                "type": "deleted"
                            },
                            {
                                "content": "            kwargs['result_filter'] = result_filter",
                                "type": "deleted"
                            },
                            {
                                "content": "            kwargs['result_filter'] = cls._get_result_filter(args)",
                                "type": "added"
                            },
                            {
                                "content": "        try:",
                                "type": "context"
                            },
                            {
                                "content": "            ret = cls.__call__(**kwargs)",
                                "type": "context"
                            },
                            {
                                "content": "            if inspect.isgenerator(ret):",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "datalad/interface/base.py",
                            "type": "class",
                            "name": "Interface",
                            "content": "class Interface(object):\n    \"\"\"Base class for interface implementations\"\"\"\n\n    # exit code to return if user-interrupted\n    # if None, would just reraise the Exception, so if in --dbg\n    # mode would fall into the debugger\n    _interrupted_exit_code = 1\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 not is_api_arg(arg):\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 constraint 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        from datalad import cfg\n        # XXX needs safety check for name collisions\n        from inspect import getargspec\n        argspec = getargspec(cls.__call__)\n        if argspec[2] is None:\n            # no **kwargs in the call receiver, pull argnames from signature\n            argnames = getargspec(cls.__call__)[0]\n        else:\n            # common options\n            # XXX define or better get from elsewhere\n            common_opts = ('change_path', 'common_debug', 'common_idebug', 'func',\n                           'help', 'log_level', 'logger', 'pbs_runner',\n                           'result_renderer', 'subparser')\n            argnames = [name for name in dir(args)\n                        if not (name.startswith('_') or name in common_opts)]\n        kwargs = {k: getattr(args, k) for k in argnames if is_api_arg(k)}\n        # we are coming from the entry point, this is the toplevel command,\n        # let it run like generator so we can act on partial results quicker\n        # TODO remove following condition test when transition is complete and\n        # run indented code unconditionally\n        if cls.__name__ not in (\n                'AddArchiveContent',\n                'CrawlInit', 'Crawl', 'CreateSiblingGithub',\n                'CreateTestDataset', 'DownloadURL', 'Export', 'Ls', 'Move',\n                'SSHRun', 'Test'):\n            # set all common args explicitly  to override class defaults\n            # that are tailored towards the the Python API\n            kwargs['return_type'] = 'generator'\n            kwargs['result_xfm'] = None\n            # allow commands to override the default, unless something other than\n            # default is requested\n            kwargs['result_renderer'] = \\\n                args.common_output_format if args.common_output_format != 'default' \\\n                else getattr(cls, 'result_renderer', args.common_output_format)\n            if '{' in args.common_output_format:\n                # stupid hack, could and should become more powerful\n                kwargs['result_renderer'] = \\\n                    lambda x, **kwargs: ui.message(args.common_output_format.format(\n                        **{k: {k_.replace(':', '#'): v_ for k_, v_ in v.items()}\n                           if isinstance(v, dict) else v\n                           for k, v in x.items()}))\n            if args.common_on_failure:\n                kwargs['on_failure'] = args.common_on_failure\n            # compose filter function from to be invented cmdline options\n            result_filter = None\n            if args.common_report_status or 'datalad.runtime.report-status' in cfg:\n                report_status = args.common_report_status or \\\n                    cfg.obtain('datalad.runtime.report-status')\n                if report_status == 'success':\n                    result_filter = EnsureKeyChoice('status', ('ok', 'notneeded'))\n                elif report_status == 'failure':\n                    result_filter = EnsureKeyChoice('status', ('impossible', 'error'))\n                else:\n                    result_filter = EnsureKeyChoice('status', (report_status,))\n            if args.common_report_type:\n                tfilt = EnsureKeyChoice('type', tuple(args.common_report_type))\n                result_filter = result_filter & tfilt if result_filter else tfilt\n            kwargs['result_filter'] = result_filter\n        try:\n            ret = cls.__call__(**kwargs)\n            if inspect.isgenerator(ret):\n                ret = list(ret)\n            if args.common_output_format == 'tailored' and \\\n                    hasattr(cls, 'custom_result_summary_renderer'):\n                cls.custom_result_summary_renderer(ret)\n            return ret\n        except KeyboardInterrupt as exc:\n            ui.error(\"\\nInterrupted by user while doing magic: %s\" % exc_str(exc))\n            if cls._interrupted_exit_code is not None:\n                sys.exit(cls._interrupted_exit_code)\n            else:\n                raise\n\n    @classmethod\n    def get_refds_path(cls, dataset):\n        \"\"\"Return a resolved reference dataset path from a `dataset` argument\"\"\"\n        # theoretically a dataset could come in as a relative path -> resolve\n        if dataset is None:\n            return dataset\n        refds_path = dataset.path if isinstance(dataset, Dataset) \\\n            else Dataset(dataset).path\n        if refds_path:\n            refds_path = resolve_path(refds_path)\n        return refds_path",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 312,
                            "end_lineno": 457,
                            "parent": null
                        },
                        {
                            "file_name": "datalad/interface/base.py",
                            "type": "method",
                            "name": "Interface.call_from_parser",
                            "content": "class Interface(object):\n    \"\"\"Base class for interface implementations\"\"\"\n\n    # exit code to return if user-interrupted\n    # if None, would just reraise the Exception, so if in --dbg\n    # mode would fall into the debugger\n    _interrupted_exit_code = 1\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 not is_api_arg(arg):\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 constraint 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        from datalad import cfg\n        # XXX needs safety check for name collisions\n        from inspect import getargspec\n        argspec = getargspec(cls.__call__)\n        if argspec[2] is None:\n            # no **kwargs in the call receiver, pull argnames from signature\n            argnames = getargspec(cls.__call__)[0]\n        else:\n            # common options\n            # XXX define or better get from elsewhere\n            common_opts = ('change_path', 'common_debug', 'common_idebug', 'func',\n                           'help', 'log_level', 'logger', 'pbs_runner',\n                           'result_renderer', 'subparser')\n            argnames = [name for name in dir(args)\n                        if not (name.startswith('_') or name in common_opts)]\n        kwargs = {k: getattr(args, k) for k in argnames if is_api_arg(k)}\n        # we are coming from the entry point, this is the toplevel command,\n        # let it run like generator so we can act on partial results quicker\n        # TODO remove following condition test when transition is complete and\n        # run indented code unconditionally\n        if cls.__name__ not in (\n                'AddArchiveContent',\n                'CrawlInit', 'Crawl', 'CreateSiblingGithub',\n                'CreateTestDataset', 'DownloadURL', 'Export', 'Ls', 'Move',\n                'SSHRun', 'Test'):\n            # set all common args explicitly  to override class defaults\n            # that are tailored towards the the Python API\n            kwargs['return_type'] = 'generator'\n            kwargs['result_xfm'] = None\n            # allow commands to override the default, unless something other than\n            # default is requested\n            kwargs['result_renderer'] = \\\n                args.common_output_format if args.common_output_format != 'default' \\\n                else getattr(cls, 'result_renderer', args.common_output_format)\n            if '{' in args.common_output_format:\n                # stupid hack, could and should become more powerful\n                kwargs['result_renderer'] = \\\n                    lambda x, **kwargs: ui.message(args.common_output_format.format(\n                        **{k: {k_.replace(':', '#'): v_ for k_, v_ in v.items()}\n                           if isinstance(v, dict) else v\n                           for k, v in x.items()}))\n            if args.common_on_failure:\n                kwargs['on_failure'] = args.common_on_failure\n            # compose filter function from to be invented cmdline options\n            result_filter = None\n            if args.common_report_status or 'datalad.runtime.report-status' in cfg:\n                report_status = args.common_report_status or \\\n                    cfg.obtain('datalad.runtime.report-status')\n                if report_status == 'success':\n                    result_filter = EnsureKeyChoice('status', ('ok', 'notneeded'))\n                elif report_status == 'failure':\n                    result_filter = EnsureKeyChoice('status', ('impossible', 'error'))\n                else:\n                    result_filter = EnsureKeyChoice('status', (report_status,))\n            if args.common_report_type:\n                tfilt = EnsureKeyChoice('type', tuple(args.common_report_type))\n                result_filter = result_filter & tfilt if result_filter else tfilt\n            kwargs['result_filter'] = result_filter\n        try:\n            ret = cls.__call__(**kwargs)\n            if inspect.isgenerator(ret):\n                ret = list(ret)\n            if args.common_output_format == 'tailored' and \\\n                    hasattr(cls, 'custom_result_summary_renderer'):\n                cls.custom_result_summary_renderer(ret)\n            return ret\n        except KeyboardInterrupt as exc:\n            ui.error(\"\\nInterrupted by user while doing magic: %s\" % exc_str(exc))\n            if cls._interrupted_exit_code is not None:\n                sys.exit(cls._interrupted_exit_code)\n            else:\n                raise\n\n    @classmethod\n    def get_refds_path(cls, dataset):\n        \"\"\"Return a resolved reference dataset path from a `dataset` argument\"\"\"\n        # theoretically a dataset could come in as a relative path -> resolve\n        if dataset is None:\n            return dataset\n        refds_path = dataset.path if isinstance(dataset, Dataset) \\\n            else Dataset(dataset).path\n        if refds_path:\n            refds_path = resolve_path(refds_path)\n        return refds_path",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 373,
                            "end_lineno": 445,
                            "parent": {
                                "file_name": "datalad/interface/base.py",
                                "type": "class",
                                "name": "Interface",
                                "content": "class Interface(object):\n    \"\"\"Base class for interface implementations\"\"\"\n\n    # exit code to return if user-interrupted\n    # if None, would just reraise the Exception, so if in --dbg\n    # mode would fall into the debugger\n    _interrupted_exit_code = 1\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 not is_api_arg(arg):\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 constraint 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        from datalad import cfg\n        # XXX needs safety check for name collisions\n        from inspect import getargspec\n        argspec = getargspec(cls.__call__)\n        if argspec[2] is None:\n            # no **kwargs in the call receiver, pull argnames from signature\n            argnames = getargspec(cls.__call__)[0]\n        else:\n            # common options\n            # XXX define or better get from elsewhere\n            common_opts = ('change_path', 'common_debug', 'common_idebug', 'func',\n                           'help', 'log_level', 'logger', 'pbs_runner',\n                           'result_renderer', 'subparser')\n            argnames = [name for name in dir(args)\n                        if not (name.startswith('_') or name in common_opts)]\n        kwargs = {k: getattr(args, k) for k in argnames if is_api_arg(k)}\n        # we are coming from the entry point, this is the toplevel command,\n        # let it run like generator so we can act on partial results quicker\n        # TODO remove following condition test when transition is complete and\n        # run indented code unconditionally\n        if cls.__name__ not in (\n                'AddArchiveContent',\n                'CrawlInit', 'Crawl', 'CreateSiblingGithub',\n                'CreateTestDataset', 'DownloadURL', 'Export', 'Ls', 'Move',\n                'SSHRun', 'Test'):\n            # set all common args explicitly  to override class defaults\n            # that are tailored towards the the Python API\n            kwargs['return_type'] = 'generator'\n            kwargs['result_xfm'] = None\n            # allow commands to override the default, unless something other than\n            # default is requested\n            kwargs['result_renderer'] = \\\n                args.common_output_format if args.common_output_format != 'default' \\\n                else getattr(cls, 'result_renderer', args.common_output_format)\n            if '{' in args.common_output_format:\n                # stupid hack, could and should become more powerful\n                kwargs['result_renderer'] = \\\n                    lambda x, **kwargs: ui.message(args.common_output_format.format(\n                        **{k: {k_.replace(':', '#'): v_ for k_, v_ in v.items()}\n                           if isinstance(v, dict) else v\n                           for k, v in x.items()}))\n            if args.common_on_failure:\n                kwargs['on_failure'] = args.common_on_failure\n            # compose filter function from to be invented cmdline options\n            result_filter = None\n            if args.common_report_status or 'datalad.runtime.report-status' in cfg:\n                report_status = args.common_report_status or \\\n                    cfg.obtain('datalad.runtime.report-status')\n                if report_status == 'success':\n                    result_filter = EnsureKeyChoice('status', ('ok', 'notneeded'))\n                elif report_status == 'failure':\n                    result_filter = EnsureKeyChoice('status', ('impossible', 'error'))\n                else:\n                    result_filter = EnsureKeyChoice('status', (report_status,))\n            if args.common_report_type:\n                tfilt = EnsureKeyChoice('type', tuple(args.common_report_type))\n                result_filter = result_filter & tfilt if result_filter else tfilt\n            kwargs['result_filter'] = result_filter\n        try:\n            ret = cls.__call__(**kwargs)\n            if inspect.isgenerator(ret):\n                ret = list(ret)\n            if args.common_output_format == 'tailored' and \\\n                    hasattr(cls, 'custom_result_summary_renderer'):\n                cls.custom_result_summary_renderer(ret)\n            return ret\n        except KeyboardInterrupt as exc:\n            ui.error(\"\\nInterrupted by user while doing magic: %s\" % exc_str(exc))\n            if cls._interrupted_exit_code is not None:\n                sys.exit(cls._interrupted_exit_code)\n            else:\n                raise\n\n    @classmethod\n    def get_refds_path(cls, dataset):\n        \"\"\"Return a resolved reference dataset path from a `dataset` argument\"\"\"\n        # theoretically a dataset could come in as a relative path -> resolve\n        if dataset is None:\n            return dataset\n        refds_path = dataset.path if isinstance(dataset, Dataset) \\\n            else Dataset(dataset).path\n        if refds_path:\n            refds_path = resolve_path(refds_path)\n        return refds_path",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 312,
                                "end_lineno": 457,
                                "parent": null
                            }
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                },
                {
                    "descriptor": {
                        "old_range": {
                            "start": 444,
                            "length": 6
                        },
                        "new_range": {
                            "start": 431,
                            "length": 25
                        },
                        "section": "class Interface(object):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "            else:",
                                "type": "context"
                            },
                            {
                                "content": "                raise",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "    @classmethod",
                                "type": "added"
                            },
                            {
                                "content": "    def _get_result_filter(cls, args):",
                                "type": "added"
                            },
                            {
                                "content": "        from datalad import cfg",
                                "type": "added"
                            },
                            {
                                "content": "        result_filter = None",
                                "type": "added"
                            },
                            {
                                "content": "        if args.common_report_status or 'datalad.runtime.report-status' in cfg:",
                                "type": "added"
                            },
                            {
                                "content": "            report_status = args.common_report_status or \\",
                                "type": "added"
                            },
                            {
                                "content": "                            cfg.obtain('datalad.runtime.report-status')",
                                "type": "added"
                            },
                            {
                                "content": "            if report_status == 'success':",
                                "type": "added"
                            },
                            {
                                "content": "                result_filter = EnsureKeyChoice('status', ('ok', 'notneeded'))",
                                "type": "added"
                            },
                            {
                                "content": "            elif report_status == 'failure':",
                                "type": "added"
                            },
                            {
                                "content": "                result_filter = EnsureKeyChoice('status',",
                                "type": "added"
                            },
                            {
                                "content": "                                                ('impossible', 'error'))",
                                "type": "added"
                            },
                            {
                                "content": "            else:",
                                "type": "added"
                            },
                            {
                                "content": "                result_filter = EnsureKeyChoice('status', (report_status,))",
                                "type": "added"
                            },
                            {
                                "content": "        if args.common_report_type:",
                                "type": "added"
                            },
                            {
                                "content": "            tfilt = EnsureKeyChoice('type', tuple(args.common_report_type))",
                                "type": "added"
                            },
                            {
                                "content": "            result_filter = result_filter & tfilt if result_filter else tfilt",
                                "type": "added"
                            },
                            {
                                "content": "        return result_filter",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "    @classmethod",
                                "type": "context"
                            },
                            {
                                "content": "    def get_refds_path(cls, dataset):",
                                "type": "context"
                            },
                            {
                                "content": "        \"\"\"Return a resolved reference dataset path from a `dataset` argument\"\"\"",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "datalad/interface/base.py",
                            "type": "class",
                            "name": "Interface",
                            "content": "class Interface(object):\n    \"\"\"Base class for interface implementations\"\"\"\n\n    # exit code to return if user-interrupted\n    # if None, would just reraise the Exception, so if in --dbg\n    # mode would fall into the debugger\n    _interrupted_exit_code = 1\n\n    _OLDSTYLE_COMMANDS = (\n        'AddArchiveContent', 'CrawlInit', 'Crawl', 'CreateSiblingGithub',\n        'CreateTestDataset', 'DownloadURL', 'Export', 'Ls', 'Move', 'SSHRun',\n        'Test')\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 not is_api_arg(arg):\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 constraint 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        argspec = getargspec(cls.__call__)\n        if argspec[2] is None:\n            # no **kwargs in the call receiver, pull argnames from signature\n            argnames = getargspec(cls.__call__)[0]\n        else:\n            # common options\n            # XXX define or better get from elsewhere\n            common_opts = ('change_path', 'common_debug', 'common_idebug', 'func',\n                           'help', 'log_level', 'logger', 'pbs_runner',\n                           'result_renderer', 'subparser')\n            argnames = [name for name in dir(args)\n                        if not (name.startswith('_') or name in common_opts)]\n        kwargs = {k: getattr(args, k) for k in argnames if is_api_arg(k)}\n        # we are coming from the entry point, this is the toplevel command,\n        # let it run like generator so we can act on partial results quicker\n        # TODO remove following condition test when transition is complete and\n        # run indented code unconditionally\n        if cls.__name__ not in Interface._OLDSTYLE_COMMANDS:\n            # set all common args explicitly  to override class defaults\n            # that are tailored towards the the Python API\n            kwargs['return_type'] = 'generator'\n            kwargs['result_xfm'] = None\n            # allow commands to override the default, unless something other than\n            # default is requested\n            kwargs['result_renderer'] = \\\n                args.common_output_format if args.common_output_format != 'default' \\\n                else getattr(cls, 'result_renderer', args.common_output_format)\n            if '{' in args.common_output_format:\n                # stupid hack, could and should become more powerful\n                kwargs['result_renderer'] = \\\n                    lambda x, **kwargs: ui.message(args.common_output_format.format(\n                        **{k: {k_.replace(':', '#'): v_ for k_, v_ in v.items()}\n                           if isinstance(v, dict) else v\n                           for k, v in x.items()}))\n            if args.common_on_failure:\n                kwargs['on_failure'] = args.common_on_failure\n            # compose filter function from to be invented cmdline options\n            kwargs['result_filter'] = cls._get_result_filter(args)\n        try:\n            ret = cls.__call__(**kwargs)\n            if inspect.isgenerator(ret):\n                ret = list(ret)\n            if args.common_output_format == 'tailored' and \\\n                    hasattr(cls, 'custom_result_summary_renderer'):\n                cls.custom_result_summary_renderer(ret)\n            return ret\n        except KeyboardInterrupt as exc:\n            ui.error(\"\\nInterrupted by user while doing magic: %s\" % exc_str(exc))\n            if cls._interrupted_exit_code is not None:\n                sys.exit(cls._interrupted_exit_code)\n            else:\n                raise\n\n    @classmethod\n    def _get_result_filter(cls, args):\n        from datalad import cfg\n        result_filter = None\n        if args.common_report_status or 'datalad.runtime.report-status' in cfg:\n            report_status = args.common_report_status or \\\n                            cfg.obtain('datalad.runtime.report-status')\n            if report_status == 'success':\n                result_filter = EnsureKeyChoice('status', ('ok', 'notneeded'))\n            elif report_status == 'failure':\n                result_filter = EnsureKeyChoice('status',\n                                                ('impossible', 'error'))\n            else:\n                result_filter = EnsureKeyChoice('status', (report_status,))\n        if args.common_report_type:\n            tfilt = EnsureKeyChoice('type', tuple(args.common_report_type))\n            result_filter = result_filter & tfilt if result_filter else tfilt\n        return result_filter\n\n    @classmethod\n    def get_refds_path(cls, dataset):\n        \"\"\"Return a resolved reference dataset path from a `dataset` argument\"\"\"\n        # theoretically a dataset could come in as a relative path -> resolve\n        if dataset is None:\n            return dataset\n        refds_path = dataset.path if isinstance(dataset, Dataset) \\\n            else Dataset(dataset).path\n        if refds_path:\n            refds_path = resolve_path(refds_path)\n        return refds_path",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 312,
                            "end_lineno": 463,
                            "parent": null
                        }
                    ],
                    "added_entities": [
                        {
                            "file_name": "datalad/interface/base.py",
                            "type": "method",
                            "name": "Interface._get_result_filter",
                            "content": "class Interface(object):\n    \"\"\"Base class for interface implementations\"\"\"\n\n    # exit code to return if user-interrupted\n    # if None, would just reraise the Exception, so if in --dbg\n    # mode would fall into the debugger\n    _interrupted_exit_code = 1\n\n    _OLDSTYLE_COMMANDS = (\n        'AddArchiveContent', 'CrawlInit', 'Crawl', 'CreateSiblingGithub',\n        'CreateTestDataset', 'DownloadURL', 'Export', 'Ls', 'Move', 'SSHRun',\n        'Test')\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 not is_api_arg(arg):\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 constraint 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        argspec = getargspec(cls.__call__)\n        if argspec[2] is None:\n            # no **kwargs in the call receiver, pull argnames from signature\n            argnames = getargspec(cls.__call__)[0]\n        else:\n            # common options\n            # XXX define or better get from elsewhere\n            common_opts = ('change_path', 'common_debug', 'common_idebug', 'func',\n                           'help', 'log_level', 'logger', 'pbs_runner',\n                           'result_renderer', 'subparser')\n            argnames = [name for name in dir(args)\n                        if not (name.startswith('_') or name in common_opts)]\n        kwargs = {k: getattr(args, k) for k in argnames if is_api_arg(k)}\n        # we are coming from the entry point, this is the toplevel command,\n        # let it run like generator so we can act on partial results quicker\n        # TODO remove following condition test when transition is complete and\n        # run indented code unconditionally\n        if cls.__name__ not in Interface._OLDSTYLE_COMMANDS:\n            # set all common args explicitly  to override class defaults\n            # that are tailored towards the the Python API\n            kwargs['return_type'] = 'generator'\n            kwargs['result_xfm'] = None\n            # allow commands to override the default, unless something other than\n            # default is requested\n            kwargs['result_renderer'] = \\\n                args.common_output_format if args.common_output_format != 'default' \\\n                else getattr(cls, 'result_renderer', args.common_output_format)\n            if '{' in args.common_output_format:\n                # stupid hack, could and should become more powerful\n                kwargs['result_renderer'] = \\\n                    lambda x, **kwargs: ui.message(args.common_output_format.format(\n                        **{k: {k_.replace(':', '#'): v_ for k_, v_ in v.items()}\n                           if isinstance(v, dict) else v\n                           for k, v in x.items()}))\n            if args.common_on_failure:\n                kwargs['on_failure'] = args.common_on_failure\n            # compose filter function from to be invented cmdline options\n            kwargs['result_filter'] = cls._get_result_filter(args)\n        try:\n            ret = cls.__call__(**kwargs)\n            if inspect.isgenerator(ret):\n                ret = list(ret)\n            if args.common_output_format == 'tailored' and \\\n                    hasattr(cls, 'custom_result_summary_renderer'):\n                cls.custom_result_summary_renderer(ret)\n            return ret\n        except KeyboardInterrupt as exc:\n            ui.error(\"\\nInterrupted by user while doing magic: %s\" % exc_str(exc))\n            if cls._interrupted_exit_code is not None:\n                sys.exit(cls._interrupted_exit_code)\n            else:\n                raise\n\n    @classmethod\n    def _get_result_filter(cls, args):\n        from datalad import cfg\n        result_filter = None\n        if args.common_report_status or 'datalad.runtime.report-status' in cfg:\n            report_status = args.common_report_status or \\\n                            cfg.obtain('datalad.runtime.report-status')\n            if report_status == 'success':\n                result_filter = EnsureKeyChoice('status', ('ok', 'notneeded'))\n            elif report_status == 'failure':\n                result_filter = EnsureKeyChoice('status',\n                                                ('impossible', 'error'))\n            else:\n                result_filter = EnsureKeyChoice('status', (report_status,))\n        if args.common_report_type:\n            tfilt = EnsureKeyChoice('type', tuple(args.common_report_type))\n            result_filter = result_filter & tfilt if result_filter else tfilt\n        return result_filter\n\n    @classmethod\n    def get_refds_path(cls, dataset):\n        \"\"\"Return a resolved reference dataset path from a `dataset` argument\"\"\"\n        # theoretically a dataset could come in as a relative path -> resolve\n        if dataset is None:\n            return dataset\n        refds_path = dataset.path if isinstance(dataset, Dataset) \\\n            else Dataset(dataset).path\n        if refds_path:\n            refds_path = resolve_path(refds_path)\n        return refds_path",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 435,
                            "end_lineno": 451,
                            "parent": {
                                "file_name": "datalad/interface/base.py",
                                "type": "class",
                                "name": "Interface",
                                "content": "class Interface(object):\n    \"\"\"Base class for interface implementations\"\"\"\n\n    # exit code to return if user-interrupted\n    # if None, would just reraise the Exception, so if in --dbg\n    # mode would fall into the debugger\n    _interrupted_exit_code = 1\n\n    _OLDSTYLE_COMMANDS = (\n        'AddArchiveContent', 'CrawlInit', 'Crawl', 'CreateSiblingGithub',\n        'CreateTestDataset', 'DownloadURL', 'Export', 'Ls', 'Move', 'SSHRun',\n        'Test')\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 not is_api_arg(arg):\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 constraint 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        argspec = getargspec(cls.__call__)\n        if argspec[2] is None:\n            # no **kwargs in the call receiver, pull argnames from signature\n            argnames = getargspec(cls.__call__)[0]\n        else:\n            # common options\n            # XXX define or better get from elsewhere\n            common_opts = ('change_path', 'common_debug', 'common_idebug', 'func',\n                           'help', 'log_level', 'logger', 'pbs_runner',\n                           'result_renderer', 'subparser')\n            argnames = [name for name in dir(args)\n                        if not (name.startswith('_') or name in common_opts)]\n        kwargs = {k: getattr(args, k) for k in argnames if is_api_arg(k)}\n        # we are coming from the entry point, this is the toplevel command,\n        # let it run like generator so we can act on partial results quicker\n        # TODO remove following condition test when transition is complete and\n        # run indented code unconditionally\n        if cls.__name__ not in Interface._OLDSTYLE_COMMANDS:\n            # set all common args explicitly  to override class defaults\n            # that are tailored towards the the Python API\n            kwargs['return_type'] = 'generator'\n            kwargs['result_xfm'] = None\n            # allow commands to override the default, unless something other than\n            # default is requested\n            kwargs['result_renderer'] = \\\n                args.common_output_format if args.common_output_format != 'default' \\\n                else getattr(cls, 'result_renderer', args.common_output_format)\n            if '{' in args.common_output_format:\n                # stupid hack, could and should become more powerful\n                kwargs['result_renderer'] = \\\n                    lambda x, **kwargs: ui.message(args.common_output_format.format(\n                        **{k: {k_.replace(':', '#'): v_ for k_, v_ in v.items()}\n                           if isinstance(v, dict) else v\n                           for k, v in x.items()}))\n            if args.common_on_failure:\n                kwargs['on_failure'] = args.common_on_failure\n            # compose filter function from to be invented cmdline options\n            kwargs['result_filter'] = cls._get_result_filter(args)\n        try:\n            ret = cls.__call__(**kwargs)\n            if inspect.isgenerator(ret):\n                ret = list(ret)\n            if args.common_output_format == 'tailored' and \\\n                    hasattr(cls, 'custom_result_summary_renderer'):\n                cls.custom_result_summary_renderer(ret)\n            return ret\n        except KeyboardInterrupt as exc:\n            ui.error(\"\\nInterrupted by user while doing magic: %s\" % exc_str(exc))\n            if cls._interrupted_exit_code is not None:\n                sys.exit(cls._interrupted_exit_code)\n            else:\n                raise\n\n    @classmethod\n    def _get_result_filter(cls, args):\n        from datalad import cfg\n        result_filter = None\n        if args.common_report_status or 'datalad.runtime.report-status' in cfg:\n            report_status = args.common_report_status or \\\n                            cfg.obtain('datalad.runtime.report-status')\n            if report_status == 'success':\n                result_filter = EnsureKeyChoice('status', ('ok', 'notneeded'))\n            elif report_status == 'failure':\n                result_filter = EnsureKeyChoice('status',\n                                                ('impossible', 'error'))\n            else:\n                result_filter = EnsureKeyChoice('status', (report_status,))\n        if args.common_report_type:\n            tfilt = EnsureKeyChoice('type', tuple(args.common_report_type))\n            result_filter = result_filter & tfilt if result_filter else tfilt\n        return result_filter\n\n    @classmethod\n    def get_refds_path(cls, dataset):\n        \"\"\"Return a resolved reference dataset path from a `dataset` argument\"\"\"\n        # theoretically a dataset could come in as a relative path -> resolve\n        if dataset is None:\n            return dataset\n        refds_path = dataset.path if isinstance(dataset, Dataset) \\\n            else Dataset(dataset).path\n        if refds_path:\n            refds_path = resolve_path(refds_path)\n        return refds_path",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 312,
                                "end_lineno": 463,
                                "parent": null
                            }
                        }
                    ],
                    "deleted_entities": []
                }
            ]
        },
        {
            "old_file_content": "",
            "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\"\"\"test the holy grail of interfaces\n\n\"\"\"\n\nimport mock\nfrom datalad.tests.utils import *\nfrom datalad.utils import updated\nfrom ..base import Interface\nfrom argparse import Namespace\n\n\ndef _args(**kwargs):\n    return Namespace(\n        # ATM duplicates definitions done by cmdline.main and\n        # required by code logic to be defined. (should they?)\n        **updated(\n            dict(\n                common_output_format=\"default\"\n            ),\n            kwargs\n        )\n    )\n\n\ndef _new_args(**kwargs):\n    # A few more must be specified\n    return _args(\n        **updated(\n            dict(\n                common_on_failure=None,  # ['ignore', 'continue', 'stop']\n                common_report_status=None,  # ['success', 'failure', 'ok', 'notneeded', 'impossible', 'error']\n                common_report_type=None,  # ['dataset', 'file']\n            ),\n            kwargs\n        )\n    )\n\n\ndef test_call_from_parser_old_style():\n    # test that old style commands are invoked without any additional arguments\n    class DummyOne(Interface):\n        @staticmethod\n        def __call__(arg=None):\n            eq_(arg, \"nothing\")\n            return \"magical\"\n    with mock.patch.object(Interface, '_OLDSTYLE_COMMANDS', ('DummyOne',)):\n        val = DummyOne.call_from_parser(_args(arg=\"nothing\"))\n        eq_(val, \"magical\")\n\n\ndef test_call_from_parser_old_style_generator():\n    # test that old style commands are invoked without any additional arguments\n    class DummyOne(Interface):\n        @staticmethod\n        def __call__(arg=None):\n            eq_(arg, \"nothing\")\n            yield \"nothing is\"\n            yield \"magical\"\n    with mock.patch.object(Interface, '_OLDSTYLE_COMMANDS', ('DummyOne',)):\n        val = DummyOne.call_from_parser(_args(arg=\"nothing\"))\n        eq_(val, [\"nothing is\", \"magical\"])\n\n\ndef test_call_from_parser_default_args():\n    class DummyOne(Interface):\n        # explicitly without @eval_results\n        @staticmethod\n        def __call__(arg=None, **kwargs):\n            eq_(kwargs['common_on_failure'], None)\n            eq_(kwargs['common_report_status'], None)\n            eq_(kwargs['common_report_type'], None)\n            # and even those we didn't pass\n            eq_(kwargs['common_output_format'], \"default\")\n            eq_(kwargs['return_type'], \"generator\")\n            eq_(arg, \"nothing\")\n            yield \"nothing is\"\n            yield \"magical\"\n\n    # just to be sure no evil spirits chase away our Dummy\n    with mock.patch.object(Interface, '_OLDSTYLE_COMMANDS', tuple()):\n        val = DummyOne.call_from_parser(_new_args(arg=\"nothing\"))\n        eq_(val, [\"nothing is\", \"magical\"])\n\n\ndef test_get_result_filter_arg_vs_config():\n    # just tests that we would be obtaining the same constraints via\n    # cmdline argument or via config variable.  With cmdline overloading\n    # config\n    f = Interface._get_result_filter\n    eq_(f(_new_args()), None)  # by default, no filter\n\n    for v in \"success\", \"failure\", \"ok\", \"notneeded\", \"error\":\n        cargs = f(_new_args(common_report_status=v))\n        assert cargs is not None\n        with patch_config({\"datalad.runtime.report-status\": v}):\n            ccfg = f(_new_args())\n        # cannot compare directly but at least could verify based on repr\n        print(\"%s -> %s\" % (v, repr(cargs)))\n        eq_(repr(cargs), repr(ccfg))\n\n        # and we overload the \"error\" in config\n        with patch_config({\"datalad.runtime.report-status\": \"error\"}):\n            cargs_overload = f(_new_args(common_report_status=v))\n        eq_(repr(cargs), repr(cargs_overload))",
            "header": {
                "file": {
                    "path": "datalad/interface/tests/test_base.py"
                },
                "misc_line": "new file mode 100644"
            },
            "index_line": {
                "old_commit_hash": "000000000",
                "new_commit_hash": "4d91392f4",
                "mode": ""
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "/dev/null"
            },
            "plus_file": {
                "path": "b/datalad/interface/tests/test_base.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 0,
                            "length": 0
                        },
                        "new_range": {
                            "start": 1,
                            "length": 112
                        },
                        "section": ""
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "# emacs: -*- mode: python; py-indent-offset: 4; tab-width: 4; indent-tabs-mode: nil -*-",
                                "type": "added"
                            },
                            {
                                "content": "# ex: set sts=4 ts=4 sw=4 noet:",
                                "type": "added"
                            },
                            {
                                "content": "# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##",
                                "type": "added"
                            },
                            {
                                "content": "#",
                                "type": "added"
                            },
                            {
                                "content": "#   See COPYING file distributed along with the datalad package for the",
                                "type": "added"
                            },
                            {
                                "content": "#   copyright and license terms.",
                                "type": "added"
                            },
                            {
                                "content": "#",
                                "type": "added"
                            },
                            {
                                "content": "# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##",
                                "type": "added"
                            },
                            {
                                "content": "\"\"\"test the holy grail of interfaces",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "\"\"\"",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "import mock",
                                "type": "added"
                            },
                            {
                                "content": "from datalad.tests.utils import *",
                                "type": "added"
                            },
                            {
                                "content": "from datalad.utils import updated",
                                "type": "added"
                            },
                            {
                                "content": "from ..base import Interface",
                                "type": "added"
                            },
                            {
                                "content": "from argparse import Namespace",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "def _args(**kwargs):",
                                "type": "added"
                            },
                            {
                                "content": "    return Namespace(",
                                "type": "added"
                            },
                            {
                                "content": "        # ATM duplicates definitions done by cmdline.main and",
                                "type": "added"
                            },
                            {
                                "content": "        # required by code logic to be defined. (should they?)",
                                "type": "added"
                            },
                            {
                                "content": "        **updated(",
                                "type": "added"
                            },
                            {
                                "content": "            dict(",
                                "type": "added"
                            },
                            {
                                "content": "                common_output_format=\"default\"",
                                "type": "added"
                            },
                            {
                                "content": "            ),",
                                "type": "added"
                            },
                            {
                                "content": "            kwargs",
                                "type": "added"
                            },
                            {
                                "content": "        )",
                                "type": "added"
                            },
                            {
                                "content": "    )",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "def _new_args(**kwargs):",
                                "type": "added"
                            },
                            {
                                "content": "    # A few more must be specified",
                                "type": "added"
                            },
                            {
                                "content": "    return _args(",
                                "type": "added"
                            },
                            {
                                "content": "        **updated(",
                                "type": "added"
                            },
                            {
                                "content": "            dict(",
                                "type": "added"
                            },
                            {
                                "content": "                common_on_failure=None,  # ['ignore', 'continue', 'stop']",
                                "type": "added"
                            },
                            {
                                "content": "                common_report_status=None,  # ['success', 'failure', 'ok', 'notneeded', 'impossible', 'error']",
                                "type": "added"
                            },
                            {
                                "content": "                common_report_type=None,  # ['dataset', 'file']",
                                "type": "added"
                            },
                            {
                                "content": "            ),",
                                "type": "added"
                            },
                            {
                                "content": "            kwargs",
                                "type": "added"
                            },
                            {
                                "content": "        )",
                                "type": "added"
                            },
                            {
                                "content": "    )",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "def test_call_from_parser_old_style():",
                                "type": "added"
                            },
                            {
                                "content": "    # test that old style commands are invoked without any additional arguments",
                                "type": "added"
                            },
                            {
                                "content": "    class DummyOne(Interface):",
                                "type": "added"
                            },
                            {
                                "content": "        @staticmethod",
                                "type": "added"
                            },
                            {
                                "content": "        def __call__(arg=None):",
                                "type": "added"
                            },
                            {
                                "content": "            eq_(arg, \"nothing\")",
                                "type": "added"
                            },
                            {
                                "content": "            return \"magical\"",
                                "type": "added"
                            },
                            {
                                "content": "    with mock.patch.object(Interface, '_OLDSTYLE_COMMANDS', ('DummyOne',)):",
                                "type": "added"
                            },
                            {
                                "content": "        val = DummyOne.call_from_parser(_args(arg=\"nothing\"))",
                                "type": "added"
                            },
                            {
                                "content": "        eq_(val, \"magical\")",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "def test_call_from_parser_old_style_generator():",
                                "type": "added"
                            },
                            {
                                "content": "    # test that old style commands are invoked without any additional arguments",
                                "type": "added"
                            },
                            {
                                "content": "    class DummyOne(Interface):",
                                "type": "added"
                            },
                            {
                                "content": "        @staticmethod",
                                "type": "added"
                            },
                            {
                                "content": "        def __call__(arg=None):",
                                "type": "added"
                            },
                            {
                                "content": "            eq_(arg, \"nothing\")",
                                "type": "added"
                            },
                            {
                                "content": "            yield \"nothing is\"",
                                "type": "added"
                            },
                            {
                                "content": "            yield \"magical\"",
                                "type": "added"
                            },
                            {
                                "content": "    with mock.patch.object(Interface, '_OLDSTYLE_COMMANDS', ('DummyOne',)):",
                                "type": "added"
                            },
                            {
                                "content": "        val = DummyOne.call_from_parser(_args(arg=\"nothing\"))",
                                "type": "added"
                            },
                            {
                                "content": "        eq_(val, [\"nothing is\", \"magical\"])",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "def test_call_from_parser_default_args():",
                                "type": "added"
                            },
                            {
                                "content": "    class DummyOne(Interface):",
                                "type": "added"
                            },
                            {
                                "content": "        # explicitly without @eval_results",
                                "type": "added"
                            },
                            {
                                "content": "        @staticmethod",
                                "type": "added"
                            },
                            {
                                "content": "        def __call__(arg=None, **kwargs):",
                                "type": "added"
                            },
                            {
                                "content": "            eq_(kwargs['common_on_failure'], None)",
                                "type": "added"
                            },
                            {
                                "content": "            eq_(kwargs['common_report_status'], None)",
                                "type": "added"
                            },
                            {
                                "content": "            eq_(kwargs['common_report_type'], None)",
                                "type": "added"
                            },
                            {
                                "content": "            # and even those we didn't pass",
                                "type": "added"
                            },
                            {
                                "content": "            eq_(kwargs['common_output_format'], \"default\")",
                                "type": "added"
                            },
                            {
                                "content": "            eq_(kwargs['return_type'], \"generator\")",
                                "type": "added"
                            },
                            {
                                "content": "            eq_(arg, \"nothing\")",
                                "type": "added"
                            },
                            {
                                "content": "            yield \"nothing is\"",
                                "type": "added"
                            },
                            {
                                "content": "            yield \"magical\"",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "    # just to be sure no evil spirits chase away our Dummy",
                                "type": "added"
                            },
                            {
                                "content": "    with mock.patch.object(Interface, '_OLDSTYLE_COMMANDS', tuple()):",
                                "type": "added"
                            },
                            {
                                "content": "        val = DummyOne.call_from_parser(_new_args(arg=\"nothing\"))",
                                "type": "added"
                            },
                            {
                                "content": "        eq_(val, [\"nothing is\", \"magical\"])",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "def test_get_result_filter_arg_vs_config():",
                                "type": "added"
                            },
                            {
                                "content": "    # just tests that we would be obtaining the same constraints via",
                                "type": "added"
                            },
                            {
                                "content": "    # cmdline argument or via config variable.  With cmdline overloading",
                                "type": "added"
                            },
                            {
                                "content": "    # config",
                                "type": "added"
                            },
                            {
                                "content": "    f = Interface._get_result_filter",
                                "type": "added"
                            },
                            {
                                "content": "    eq_(f(_new_args()), None)  # by default, no filter",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "    for v in \"success\", \"failure\", \"ok\", \"notneeded\", \"error\":",
                                "type": "added"
                            },
                            {
                                "content": "        cargs = f(_new_args(common_report_status=v))",
                                "type": "added"
                            },
                            {
                                "content": "        assert cargs is not None",
                                "type": "added"
                            },
                            {
                                "content": "        with patch_config({\"datalad.runtime.report-status\": v}):",
                                "type": "added"
                            },
                            {
                                "content": "            ccfg = f(_new_args())",
                                "type": "added"
                            },
                            {
                                "content": "        # cannot compare directly but at least could verify based on repr",
                                "type": "added"
                            },
                            {
                                "content": "        print(\"%s -> %s\" % (v, repr(cargs)))",
                                "type": "added"
                            },
                            {
                                "content": "        eq_(repr(cargs), repr(ccfg))",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "        # and we overload the \"error\" in config",
                                "type": "added"
                            },
                            {
                                "content": "        with patch_config({\"datalad.runtime.report-status\": \"error\"}):",
                                "type": "added"
                            },
                            {
                                "content": "            cargs_overload = f(_new_args(common_report_status=v))",
                                "type": "added"
                            },
                            {
                                "content": "        eq_(repr(cargs), repr(cargs_overload))",
                                "type": "added"
                            },
                            {
                                "content": "No newline at end of file",
                                "type": "note"
                            },
                            {
                                "content": "",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [],
                    "added_entities": [
                        {
                            "file_name": "datalad/interface/tests/test_base.py",
                            "type": "statement",
                            "name": "",
                            "content": "from argparse import Namespace",
                            "ast_type_str": "ImportFrom",
                            "start_lineno": 17,
                            "end_lineno": 17,
                            "parent": null
                        },
                        {
                            "file_name": "datalad/interface/tests/test_base.py",
                            "type": "function",
                            "name": "_args",
                            "content": "def _args(**kwargs):\n    return Namespace(\n        # ATM duplicates definitions done by cmdline.main and\n        # required by code logic to be defined. (should they?)\n        **updated(\n            dict(\n                common_output_format=\"default\"\n            ),\n            kwargs\n        )\n    )",
                            "ast_type_str": "FunctionDef",
                            "start_lineno": 20,
                            "end_lineno": 30,
                            "parent": null
                        },
                        {
                            "file_name": "datalad/interface/tests/test_base.py",
                            "type": "function",
                            "name": "test_call_from_parser_old_style",
                            "content": "def test_call_from_parser_old_style():\n    # test that old style commands are invoked without any additional arguments\n    class DummyOne(Interface):\n        @staticmethod\n        def __call__(arg=None):\n            eq_(arg, \"nothing\")\n            return \"magical\"\n    with mock.patch.object(Interface, '_OLDSTYLE_COMMANDS', ('DummyOne',)):\n        val = DummyOne.call_from_parser(_args(arg=\"nothing\"))\n        eq_(val, \"magical\")",
                            "ast_type_str": "FunctionDef",
                            "start_lineno": 47,
                            "end_lineno": 56,
                            "parent": null
                        },
                        {
                            "file_name": "datalad/interface/tests/test_base.py",
                            "type": "function",
                            "name": "test_get_result_filter_arg_vs_config",
                            "content": "def test_get_result_filter_arg_vs_config():\n    # just tests that we would be obtaining the same constraints via\n    # cmdline argument or via config variable.  With cmdline overloading\n    # config\n    f = Interface._get_result_filter\n    eq_(f(_new_args()), None)  # by default, no filter\n\n    for v in \"success\", \"failure\", \"ok\", \"notneeded\", \"error\":\n        cargs = f(_new_args(common_report_status=v))\n        assert cargs is not None\n        with patch_config({\"datalad.runtime.report-status\": v}):\n            ccfg = f(_new_args())\n        # cannot compare directly but at least could verify based on repr\n        print(\"%s -> %s\" % (v, repr(cargs)))\n        eq_(repr(cargs), repr(ccfg))\n\n        # and we overload the \"error\" in config\n        with patch_config({\"datalad.runtime.report-status\": \"error\"}):\n            cargs_overload = f(_new_args(common_report_status=v))\n        eq_(repr(cargs), repr(cargs_overload))",
                            "ast_type_str": "FunctionDef",
                            "start_lineno": 93,
                            "end_lineno": 112,
                            "parent": null
                        },
                        {
                            "file_name": "datalad/interface/tests/test_base.py",
                            "type": "function",
                            "name": "test_call_from_parser_old_style_generator",
                            "content": "def test_call_from_parser_old_style_generator():\n    # test that old style commands are invoked without any additional arguments\n    class DummyOne(Interface):\n        @staticmethod\n        def __call__(arg=None):\n            eq_(arg, \"nothing\")\n            yield \"nothing is\"\n            yield \"magical\"\n    with mock.patch.object(Interface, '_OLDSTYLE_COMMANDS', ('DummyOne',)):\n        val = DummyOne.call_from_parser(_args(arg=\"nothing\"))\n        eq_(val, [\"nothing is\", \"magical\"])",
                            "ast_type_str": "FunctionDef",
                            "start_lineno": 59,
                            "end_lineno": 69,
                            "parent": null
                        },
                        {
                            "file_name": "datalad/interface/tests/test_base.py",
                            "type": "import",
                            "name": "mock",
                            "content": "import mock",
                            "ast_type_str": "Import",
                            "start_lineno": 13,
                            "end_lineno": 13,
                            "parent": null
                        },
                        {
                            "file_name": "datalad/interface/tests/test_base.py",
                            "type": "function",
                            "name": "test_call_from_parser_default_args",
                            "content": "def test_call_from_parser_default_args():\n    class DummyOne(Interface):\n        # explicitly without @eval_results\n        @staticmethod\n        def __call__(arg=None, **kwargs):\n            eq_(kwargs['common_on_failure'], None)\n            eq_(kwargs['common_report_status'], None)\n            eq_(kwargs['common_report_type'], None)\n            # and even those we didn't pass\n            eq_(kwargs['common_output_format'], \"default\")\n            eq_(kwargs['return_type'], \"generator\")\n            eq_(arg, \"nothing\")\n            yield \"nothing is\"\n            yield \"magical\"\n\n    # just to be sure no evil spirits chase away our Dummy\n    with mock.patch.object(Interface, '_OLDSTYLE_COMMANDS', tuple()):\n        val = DummyOne.call_from_parser(_new_args(arg=\"nothing\"))\n        eq_(val, [\"nothing is\", \"magical\"])",
                            "ast_type_str": "FunctionDef",
                            "start_lineno": 72,
                            "end_lineno": 90,
                            "parent": null
                        },
                        {
                            "file_name": "datalad/interface/tests/test_base.py",
                            "type": "statement",
                            "name": "",
                            "content": "from ..base import Interface",
                            "ast_type_str": "ImportFrom",
                            "start_lineno": 16,
                            "end_lineno": 16,
                            "parent": null
                        },
                        {
                            "file_name": "datalad/interface/tests/test_base.py",
                            "type": "statement",
                            "name": "",
                            "content": "from datalad.tests.utils import *",
                            "ast_type_str": "ImportFrom",
                            "start_lineno": 14,
                            "end_lineno": 14,
                            "parent": null
                        },
                        {
                            "file_name": "datalad/interface/tests/test_base.py",
                            "type": "function",
                            "name": "_new_args",
                            "content": "def _new_args(**kwargs):\n    # A few more must be specified\n    return _args(\n        **updated(\n            dict(\n                common_on_failure=None,  # ['ignore', 'continue', 'stop']\n                common_report_status=None,  # ['success', 'failure', 'ok', 'notneeded', 'impossible', 'error']\n                common_report_type=None,  # ['dataset', 'file']\n            ),\n            kwargs\n        )\n    )",
                            "ast_type_str": "FunctionDef",
                            "start_lineno": 33,
                            "end_lineno": 44,
                            "parent": null
                        },
                        {
                            "file_name": "datalad/interface/tests/test_base.py",
                            "type": "statement",
                            "name": "",
                            "content": "from datalad.utils import updated",
                            "ast_type_str": "ImportFrom",
                            "start_lineno": 15,
                            "end_lineno": 15,
                            "parent": null
                        },
                        {
                            "file_name": "datalad/interface/tests/test_base.py",
                            "type": "statement",
                            "name": "",
                            "content": "\"\"\"test the holy grail of interfaces\n\n\"\"\"",
                            "ast_type_str": "Expr",
                            "start_lineno": 9,
                            "end_lineno": 11,
                            "parent": null
                        }
                    ],
                    "deleted_entities": []
                }
            ]
        }
    ],
    "old_commit_hash": "c30dd60ec134dbf7142f263cd885ea97003ebfea^",
    "new_commit_hash": "c30dd60ec134dbf7142f263cd885ea97003ebfea",
    "commit_message": "Merge pull request #24 from yarikoptic/bf-2183\n\nA humble attempt to add basic unittests for call_from_parser",
    "commit_date": "2018-02-23T07:22:42+01:00",
    "metadata": {}
}
{
    "repo_name": "datalad",
    "new_commit_hash": "c30dd60ec134dbf7142f263cd885ea97003ebfea",
    "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\"\"\"test the holy grail of interfaces\n\n\"\"\"\n\nimport mock\nfrom datalad.tests.utils import *\nfrom datalad.utils import updated\nfrom datalad.interface.base import Interface\nfrom argparse import Namespace\n\n\ndef _args(**kwargs):\n    return Namespace(\n        # ATM duplicates definitions done by cmdline.main and\n        # required by code logic to be defined. (should they?)\n        **updated(\n            dict(\n                common_output_format=\"default\"\n            ),\n            kwargs\n        )\n    )\n\n\ndef _new_args(**kwargs):\n    # A few more must be specified\n    return _args(\n        **updated(\n            dict(\n                common_on_failure=None,  # ['ignore', 'continue', 'stop']\n                common_report_status=None,  # ['success', 'failure', 'ok', 'notneeded', 'impossible', 'error']\n                common_report_type=None,  # ['dataset', 'file']\n            ),\n            kwargs\n        )\n    )\n\n\ndef test_call_from_parser_old_style():\n    # test that old style commands are invoked without any additional arguments\n    class DummyOne(Interface):\n        @staticmethod\n        def __call__(arg=None):\n            eq_(arg, \"nothing\")\n            return \"magical\"\n    with mock.patch.object(Interface, '_OLDSTYLE_COMMANDS', ('DummyOne',)):\n        val = DummyOne.call_from_parser(_args(arg=\"nothing\"))\n        eq_(val, \"magical\")\n\n\ndef test_call_from_parser_old_style_generator():\n    # test that old style commands are invoked without any additional arguments\n    class DummyOne(Interface):\n        @staticmethod\n        def __call__(arg=None):\n            eq_(arg, \"nothing\")\n            yield \"nothing is\"\n            yield \"magical\"\n    with mock.patch.object(Interface, '_OLDSTYLE_COMMANDS', ('DummyOne',)):\n        val = DummyOne.call_from_parser(_args(arg=\"nothing\"))\n        eq_(val, [\"nothing is\", \"magical\"])\n\n\ndef test_call_from_parser_default_args():\n    class DummyOne(Interface):\n        # explicitly without @eval_results\n        @staticmethod\n        def __call__(arg=None, **kwargs):\n            eq_(kwargs['common_on_failure'], None)\n            eq_(kwargs['common_report_status'], None)\n            eq_(kwargs['common_report_type'], None)\n            # and even those we didn't pass\n            eq_(kwargs['common_output_format'], \"default\")\n            eq_(kwargs['return_type'], \"generator\")\n            eq_(arg, \"nothing\")\n            yield \"nothing is\"\n            yield \"magical\"\n\n    # just to be sure no evil spirits chase away our Dummy\n    with mock.patch.object(Interface, '_OLDSTYLE_COMMANDS', tuple()):\n        val = DummyOne.call_from_parser(_new_args(arg=\"nothing\"))\n        eq_(val, [\"nothing is\", \"magical\"])\n\n\ndef test_get_result_filter_arg_vs_config():\n    # just tests that we would be obtaining the same constraints via\n    # cmdline argument or via config variable.  With cmdline overloading\n    # config\n    f = Interface._get_result_filter\n    eq_(f(_new_args()), None)  # by default, no filter\n\n    for v in \"success\", \"failure\", \"ok\", \"notneeded\", \"error\":\n        cargs = f(_new_args(common_report_status=v))\n        assert cargs is not None\n        with patch_config({\"datalad.runtime.report-status\": v}):\n            ccfg = f(_new_args())\n        # cannot compare directly but at least could verify based on repr\n        print(\"%s -> %s\" % (v, repr(cargs)))\n        eq_(repr(cargs), repr(ccfg))\n\n        # and we overload the \"error\" in config\n        with patch_config({\"datalad.runtime.report-status\": \"error\"}):\n            cargs_overload = f(_new_args(common_report_status=v))\n        eq_(repr(cargs), repr(cargs_overload))",
        "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.9.1.dev865\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 53ms\nInstalled 25 packages in 5.79s\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/.tmp7ego1y/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/.tmp7ego1y/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/.tmp7ego1y/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/.tmp7ego1y/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/.tmp7ego1y/lib/python3.9/site-packages/setuptools/build_meta.py\", line 320, in run_setup\n    exec(code, locals())\n  File \"<string>\", line 50, 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/.tmpB4ylOX/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/.tmpB4ylOX/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/.tmpB4ylOX/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/.tmpB4ylOX/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/.tmpB4ylOX/lib/python3.9/site-packages/setuptools/build_meta.py\", line 320, in run_setup\n    exec(code, locals())\n  File \"<string>\", line 50, 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_c30dd60ec134dbf7142f263cd885ea97003ebfea/datalad/__init__.py\", line 17, in <module>\n    from datalad.cmd import GitRunner\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/datalad_c30dd60ec134dbf7142f263cd885ea97003ebfea/datalad/cmd.py\", line 35, in <module>\n    from .utils import on_windows, get_tempfile_kwargs, assure_unicode\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/datalad_c30dd60ec134dbf7142f263cd885ea97003ebfea/datalad/utils.py\", line 24, in <module>\n    import wrapt\nModuleNotFoundError: No module named 'wrapt'\nUsing CPython 3.7.9\nCreating virtual environment at: .venv\nActivate with: source .venv/bin/activate\nResolved 26 packages in 161ms\nInstalled 26 packages in 3.11s\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 88 packages in 1.39s\nPrepared 1 package in 1.07s\nInstalled 77 packages in 94ms\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 + chardet==5.2.0\n + charset-normalizer==3.4.1\n + citeproc-py==0.6.0\n + constantly==15.1.0\n + cryptography==44.0.0\n + cssselect==1.2.0\n + datalad==0.9.1.dev1 (from file:///home/gcpuser/buckets/local_repoeval_bucket/repos/datalad_c30dd60ec134dbf7142f263cd885ea97003ebfea)\n + deprecated==1.2.15\n + duecredit==0.9.3\n + exifread==3.0.0\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 + iso8601==2.1.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 + jsmin==3.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 + mutagen==1.47.0\n + nose==1.3.7\n + parsel==1.8.1\n + patool==1.12\n + pillow==9.5.0\n + protego==0.3.0\n + pyasn1==0.5.1\n + pyasn1-modules==0.3.0\n + pycparser==2.21\n + pydicom==2.4.4\n + pydispatcher==2.0.7\n + pygithub==2.3.0\n + pyjwt==2.8.0\n + pynacl==1.5.0\n + pyopenssl==24.3.0\n + python-xmp-toolkit==2.0.2\n + pyyaml==6.0.1\n + queuelib==1.6.2\n + requests==2.31.0\n + requests-file==2.1.0\n + requests-ftp==0.3.1\n + scrapy==2.9.0\n + secretstorage==3.3.3\n + service-identity==21.1.0\n + simplejson==3.19.3\n + smmap==5.0.2\n + soupsieve==2.4.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 + whoosh==2.7.4\n + wrapt==1.16.0\n + yarl==1.9.4\n + zope-interface==6.4.post2\nResolved 107 packages in 162ms\nInstalled 19 packages in 157ms\n + alabaster==0.7.13\n + babel==2.14.0\n + docutils==0.19\n + imagesize==1.4.1\n + jinja2==3.1.5\n + markupsafe==2.1.5\n + nose-timer==1.0.1\n + pygments==2.17.2\n + pypandoc==1.14\n + snowballstemmer==2.2.0\n + sphinx==5.3.0\n + sphinx-rtd-theme==2.0.0\n + sphinxcontrib-applehelp==1.0.2\n + sphinxcontrib-devhelp==1.0.2\n + sphinxcontrib-htmlhelp==2.0.0\n + sphinxcontrib-jquery==4.1\n + sphinxcontrib-jsmath==1.0.1\n + sphinxcontrib-qthelp==1.0.3\n + sphinxcontrib-serializinghtml==1.1.5\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_c30dd60ec134dbf7142f263cd885ea97003ebfea\nplugins: cov-4.1.0\ncollected 4 items\n\nr2e_tests/test_1.py ....                                                 [100%]\n\n==================================== PASSES ====================================\n_____________________ test_get_result_filter_arg_vs_config _____________________\n----------------------------- Captured stdout call -----------------------------\nsuccess -> constraint:status:{ok, notneeded}\nfailure -> constraint:status:{impossible, error}\nok -> constraint:status:{ok}\nnotneeded -> constraint:status:{notneeded}\nerror -> constraint:status:{error}\n=========================== short test summary info ============================\nPASSED r2e_tests/test_1.py::test_call_from_parser_old_style\nPASSED r2e_tests/test_1.py::test_call_from_parser_old_style_generator\nPASSED r2e_tests/test_1.py::test_call_from_parser_default_args\nPASSED r2e_tests/test_1.py::test_get_result_filter_arg_vs_config\n============================== 4 passed in 0.61s ===============================\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_c30dd60ec134dbf7142f263cd885ea97003ebfea\nplugins: cov-4.1.0\ncollected 4 items\n\nr2e_tests/test_1.py FFFF                                                 [100%]\n\n=================================== FAILURES ===================================\n_______________________ test_call_from_parser_old_style ________________________\n\n    def test_call_from_parser_old_style():\n        # test that old style commands are invoked without any additional arguments\n        class DummyOne(Interface):\n            @staticmethod\n            def __call__(arg=None):\n                eq_(arg, \"nothing\")\n                return \"magical\"\n>       with mock.patch.object(Interface, '_OLDSTYLE_COMMANDS', ('DummyOne',)):\n\nr2e_tests/test_1.py:54: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n.venv/lib/python3.7/site-packages/mock/mock.py:1520: in __enter__\n    original, local = self.get_original()\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <mock.mock._patch object at 0x76263efc9290>\n\n    def get_original(self):\n        target = self.getter()\n        name = self.attribute\n    \n        original = DEFAULT\n        local = False\n    \n        try:\n            original = target.__dict__[name]\n        except (AttributeError, KeyError):\n            original = getattr(target, name, DEFAULT)\n        else:\n            local = True\n    \n        if name in _builtins and isinstance(target, ModuleType):\n            self.create = True\n    \n        if not self.create and original is DEFAULT:\n            raise AttributeError(\n>               \"%s does not have the attribute %r\" % (target, name)\n            )\nE           AttributeError: <class 'datalad.interface.base.Interface'> does not have the attribute '_OLDSTYLE_COMMANDS'\n\n.venv/lib/python3.7/site-packages/mock/mock.py:1494: AttributeError\n__________________ test_call_from_parser_old_style_generator ___________________\n\n    def test_call_from_parser_old_style_generator():\n        # test that old style commands are invoked without any additional arguments\n        class DummyOne(Interface):\n            @staticmethod\n            def __call__(arg=None):\n                eq_(arg, \"nothing\")\n                yield \"nothing is\"\n                yield \"magical\"\n>       with mock.patch.object(Interface, '_OLDSTYLE_COMMANDS', ('DummyOne',)):\n\nr2e_tests/test_1.py:67: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n.venv/lib/python3.7/site-packages/mock/mock.py:1520: in __enter__\n    original, local = self.get_original()\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <mock.mock._patch object at 0x76263ef98a10>\n\n    def get_original(self):\n        target = self.getter()\n        name = self.attribute\n    \n        original = DEFAULT\n        local = False\n    \n        try:\n            original = target.__dict__[name]\n        except (AttributeError, KeyError):\n            original = getattr(target, name, DEFAULT)\n        else:\n            local = True\n    \n        if name in _builtins and isinstance(target, ModuleType):\n            self.create = True\n    \n        if not self.create and original is DEFAULT:\n            raise AttributeError(\n>               \"%s does not have the attribute %r\" % (target, name)\n            )\nE           AttributeError: <class 'datalad.interface.base.Interface'> does not have the attribute '_OLDSTYLE_COMMANDS'\n\n.venv/lib/python3.7/site-packages/mock/mock.py:1494: AttributeError\n______________________ test_call_from_parser_default_args ______________________\n\n    def test_call_from_parser_default_args():\n        class DummyOne(Interface):\n            # explicitly without @eval_results\n            @staticmethod\n            def __call__(arg=None, **kwargs):\n                eq_(kwargs['common_on_failure'], None)\n                eq_(kwargs['common_report_status'], None)\n                eq_(kwargs['common_report_type'], None)\n                # and even those we didn't pass\n                eq_(kwargs['common_output_format'], \"default\")\n                eq_(kwargs['return_type'], \"generator\")\n                eq_(arg, \"nothing\")\n                yield \"nothing is\"\n                yield \"magical\"\n    \n        # just to be sure no evil spirits chase away our Dummy\n>       with mock.patch.object(Interface, '_OLDSTYLE_COMMANDS', tuple()):\n\nr2e_tests/test_1.py:88: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n.venv/lib/python3.7/site-packages/mock/mock.py:1520: in __enter__\n    original, local = self.get_original()\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <mock.mock._patch object at 0x76263edc8750>\n\n    def get_original(self):\n        target = self.getter()\n        name = self.attribute\n    \n        original = DEFAULT\n        local = False\n    \n        try:\n            original = target.__dict__[name]\n        except (AttributeError, KeyError):\n            original = getattr(target, name, DEFAULT)\n        else:\n            local = True\n    \n        if name in _builtins and isinstance(target, ModuleType):\n            self.create = True\n    \n        if not self.create and original is DEFAULT:\n            raise AttributeError(\n>               \"%s does not have the attribute %r\" % (target, name)\n            )\nE           AttributeError: <class 'datalad.interface.base.Interface'> does not have the attribute '_OLDSTYLE_COMMANDS'\n\n.venv/lib/python3.7/site-packages/mock/mock.py:1494: AttributeError\n_____________________ test_get_result_filter_arg_vs_config _____________________\n\n    def test_get_result_filter_arg_vs_config():\n        # just tests that we would be obtaining the same constraints via\n        # cmdline argument or via config variable.  With cmdline overloading\n        # config\n>       f = Interface._get_result_filter\nE       AttributeError: type object 'Interface' has no attribute '_get_result_filter'\n\nr2e_tests/test_1.py:97: AttributeError\n=========================== short test summary info ============================\nFAILED r2e_tests/test_1.py::test_call_from_parser_old_style - AttributeError:...\nFAILED r2e_tests/test_1.py::test_call_from_parser_old_style_generator - Attri...\nFAILED r2e_tests/test_1.py::test_call_from_parser_default_args - AttributeErr...\nFAILED r2e_tests/test_1.py::test_get_result_filter_arg_vs_config - AttributeE...\n============================== 4 failed in 0.62s ===============================\n",
    "old_commit_res_stderr": ""
}
datalad/cmdline/main.py datalad/interface/base.py datalad/interface/tests/test_base.py
We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[ISSUE]

**Title:** AttributeError when invoking `call_from_parser`: Missing `_get_result_filter` Method

**Description:**
When using the `call_from_parser` method from the `Interface` class, an `AttributeError` is encountered because the `_get_result_filter` method does not exist. This prevents the method from processing arguments correctly and executing as expected.

**Example Code:**
```python
from datalad.interface.base import Interface
from argparse import Namespace

args = Namespace(common_output_format='default')

result = Interface.call_from_parser(args)
```

**Expected Behavior:**
The `call_from_parser` method should process the provided arguments and return the appropriate results without any errors.

**Actual Behavior:**
An `AttributeError` is raised indicating that the `Interface` class lacks the `_get_result_filter` method.

**Error Message:**
```
AttributeError: type object 'Interface' has no attribute '_get_result_filter'
```

[/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 logging
lgr = logging.getLogger('datalad.interface.base')

import sys
import re
import textwrap
import inspect
from collections import OrderedDict

from ..ui import ui
from ..dochelpers import exc_str

from datalad.interface.common_opts import eval_params
from datalad.interface.common_opts import eval_defaults
from datalad.support.exceptions import InsufficientArgumentsError
from datalad.utils import with_pathsep as _with_sep
from datalad.support.constraints import EnsureKeyChoice
from datalad.distribution.dataset import Dataset
from datalad.distribution.dataset import resolve_path


default_logchannels = {
    '': 'debug',
    'ok': 'debug',
    'notneeded': 'debug',
    'impossible': 'warning',
    'error': 'error',
}


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):
    """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(
        '\|\| CMDLINE \>\>.*\<\< CMDLINE \|\|',
        '',
        docs,
        flags=re.MULTILINE | re.DOTALL)
    # clean cmdline in-line bits
    docs = re.sub(
        '\[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)
    docs = re.sub(
        '\|\| REFLOW \>\>\n(.*)\<\< REFLOW \|\|',
        lambda match: textwrap.fill(match.group(1)),
        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 \>\>.*\<\< PYTHON \|\|',
        '',
        docs,
        flags=re.MULTILINE | re.DOTALL)
    # clean cmdline in-line bits
    docs = re.sub(
        '\[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+:`[^`]*`[\\]*',
        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)
    # clean up sphinx API refs
    docs = re.sub(
        '\~datalad\.api\.\S*',
        lambda match: "`{0}`".format(match.group(0)[13:]),
        docs)
    # Remove RST paragraph markup
    docs = re.sub(
        r'^.. \S+::',
        lambda match: match.group(0)[3:-2].upper(),
        docs,
        flags=re.MULTILINE)
    docs = re.sub(
        '\|\| REFLOW \>\>\n(.*)\<\< REFLOW \|\|',
        lambda match: textwrap.fill(match.group(1)),
        docs,
        flags=re.MULTILINE | re.DOTALL)
    return docs


def is_api_arg(arg):
    """Return True if argument is our API argument or self or used for internal
    purposes
    """
    return arg != 'self' and not arg.startswith('_')


def update_docstring_with_parameters(func, params, prefix=None, suffix=None,
                                     add_args=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 add_args:
        add_argnames = sorted(add_args.keys())
        args.extend(add_argnames)
        defaults = defaults + tuple(add_args[k] for k in add_argnames)
    if defaults is not 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 not is_api_arg(arg):
                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 param.constraints is not None:
                    param.constraints(defaults[defaults_idx])
            orig_docs = param._doc
            param._doc = alter_interface_docs_for_api(param._doc)
            doc += param.get_autodoc(
                arg,
                default=defaults[defaults_idx] if defaults_idx >= 0 else None,
                has_default=defaults_idx >= 0)
            param._doc = orig_docs
            doc += '\n'
    doc += suffix if suffix else u""
    # assign the amended docs
    func.__doc__ = doc
    return func


def build_doc(cls, **kwargs):
    """Decorator to build docstrings for datalad commands

    It's intended to decorate the class, the __call__-method of which is the
    actual command. It expects that __call__-method to be decorated by
    eval_results.

    Parameters
    ----------
    cls: Interface
      class defining a datalad command
    """

    # Note, that this is a class decorator, which is executed only once when the
    # class is imported. It builds the docstring for the class' __call__ method
    # and returns the original class.
    #
    # This is because a decorator for the actual function would not be able to
    # behave like this. To build the docstring we need to access the attribute
    # _params of the class. From within a function decorator we cannot do this
    # during import time, since the class is being built in this very moment and
    # is not yet available in the module. And if we do it from within the part
    # of a function decorator, that is executed when the function is called, we
    # would need to actually call the command once in order to build this
    # docstring.

    lgr.debug("Building doc for {}".format(cls))

    cls_doc = cls.__doc__
    if hasattr(cls, '_docs_'):
        # expand docs
        cls_doc = cls_doc.format(**cls._docs_)

    call_doc = None
    # suffix for update_docstring_with_parameters:
    if cls.__call__.__doc__:
        call_doc = cls.__call__.__doc__

    # build standard doc and insert eval_doc
    spec = getattr(cls, '_params_', dict())
    # get docs for eval_results parameters:
    spec.update(eval_params)

    update_docstring_with_parameters(
        cls.__call__, spec,
        prefix=alter_interface_docs_for_api(cls_doc),
        suffix=alter_interface_docs_for_api(call_doc),
        add_args=eval_defaults if not hasattr(cls, '_no_eval_results') else None
    )

    # return original
    return cls


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

    # exit code to return if user-interrupted
    # if None, would just reraise the Exception, so if in --dbg
    # mode would fall into the debugger
    _interrupted_exit_code = 1

    @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 not is_api_arg(arg):
                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 constraint 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):
        from datalad import cfg
        # XXX needs safety check for name collisions
        from inspect import getargspec
        argspec = getargspec(cls.__call__)
        if argspec[2] is None:
            # no **kwargs in the call receiver, pull argnames from signature
            argnames = getargspec(cls.__call__)[0]
        else:
            # common options
            # XXX define or better get from elsewhere
            common_opts = ('change_path', 'common_debug', 'common_idebug', 'func',
                           'help', 'log_level', 'logger', 'pbs_runner',
                           'result_renderer', 'subparser')
            argnames = [name for name in dir(args)
                        if not (name.startswith('_') or name in common_opts)]
        kwargs = {k: getattr(args, k) for k in argnames if is_api_arg(k)}
        # we are coming from the entry point, this is the toplevel command,
        # let it run like generator so we can act on partial results quicker
        # TODO remove following condition test when transition is complete and
        # run indented code unconditionally
        if cls.__name__ not in (
                'AddArchiveContent',
                'CrawlInit', 'Crawl', 'CreateSiblingGithub',
                'CreateTestDataset', 'DownloadURL', 'Export', 'Ls', 'Move',
                'SSHRun', 'Test'):
            # set all common args explicitly  to override class defaults
            # that are tailored towards the the Python API
            kwargs['return_type'] = 'generator'
            kwargs['result_xfm'] = None
            # allow commands to override the default, unless something other than
            # default is requested
            kwargs['result_renderer'] = \
                args.common_output_format if args.common_output_format != 'default' \
                else getattr(cls, 'result_renderer', args.common_output_format)
            if '{' in args.common_output_format:
                # stupid hack, could and should become more powerful
                kwargs['result_renderer'] = \
                    lambda x, **kwargs: ui.message(args.common_output_format.format(
                        **{k: {k_.replace(':', '#'): v_ for k_, v_ in v.items()}
                           if isinstance(v, dict) else v
                           for k, v in x.items()}))
            if args.common_on_failure:
                kwargs['on_failure'] = args.common_on_failure
            # compose filter function from to be invented cmdline options
            result_filter = None
            if args.common_report_status or 'datalad.runtime.report-status' in cfg:
                report_status = args.common_report_status or \
                    cfg.obtain('datalad.runtime.report-status')
                if report_status == 'success':
                    result_filter = EnsureKeyChoice('status', ('ok', 'notneeded'))
                elif report_status == 'failure':
                    result_filter = EnsureKeyChoice('status', ('impossible', 'error'))
                else:
                    result_filter = EnsureKeyChoice('status', (report_status,))
            if args.common_report_type:
                tfilt = EnsureKeyChoice('type', tuple(args.common_report_type))
                result_filter = result_filter & tfilt if result_filter else tfilt
            kwargs['result_filter'] = result_filter
        try:
            ret = cls.__call__(**kwargs)
            if inspect.isgenerator(ret):
                ret = list(ret)
            if args.common_output_format == 'tailored' and \
                    hasattr(cls, 'custom_result_summary_renderer'):
                cls.custom_result_summary_renderer(ret)
            return ret
        except KeyboardInterrupt as exc:
            ui.error("\nInterrupted by user while doing magic: %s" % exc_str(exc))
            if cls._interrupted_exit_code is not None:
                sys.exit(cls._interrupted_exit_code)
            else:
                raise

    @classmethod
    def get_refds_path(cls, dataset):
        """Return a resolved reference dataset path from a `dataset` argument"""
        # theoretically a dataset could come in as a relative path -> resolve
        if dataset is None:
            return dataset
        refds_path = dataset.path if isinstance(dataset, Dataset) \
            else Dataset(dataset).path
        if refds_path:
            refds_path = resolve_path(refds_path)
        return refds_path


def get_allargs_as_kwargs(call, args, kwargs):
    """Generate a kwargs dict from a call signature and *args, **kwargs

    Basically resolving the argnames for all positional arguments, and
    resolvin the defaults for all kwargs that are not given in a kwargs
    dict
    """
    from inspect import getargspec
    argspec = getargspec(call)
    defaults = argspec.defaults
    nargs = len(argspec.args)
    assert (nargs >= len(defaults))
    # map any args to their name
    argmap = list(zip(argspec.args[:len(args)], args))
    kwargs_ = OrderedDict(argmap)
    # map defaults of kwargs to their names (update below)
    for k, v in zip(argspec.args[-len(defaults):], defaults):
        if k not in kwargs_:
            kwargs_[k] = v
    # update with provided kwarg args
    kwargs_.update(kwargs)
    # XXX we cannot assert the following, because our own highlevel
    # API commands support more kwargs than what is discoverable
    # from their signature...
    #assert (nargs == len(kwargs_))
    return kwargs_

```
--- 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.
[ISSUE]

**Title:** AttributeError when invoking `call_from_parser`: Missing `_get_result_filter` Method

**Description:**
When using the `call_from_parser` method from the `Interface` class, an `AttributeError` is encountered because the `_get_result_filter` method does not exist. This prevents the method from processing arguments correctly and executing as expected.

**Example Code:**
```python
from datalad.interface.base import Interface
from argparse import Namespace

args = Namespace(common_output_format='default')

result = Interface.call_from_parser(args)
```

**Expected Behavior:**
The `call_from_parser` method should process the provided arguments and return the appropriate results without any errors.

**Actual Behavior:**
An `AttributeError` is raised indicating that the `Interface` class lacks the `_get_result_filter` method.

**Error Message:**
```
AttributeError: type object 'Interface' has no attribute '_get_result_filter'
```

[/ISSUE]
{
    "test_call_from_parser_old_style": "PASSED",
    "test_call_from_parser_old_style_generator": "PASSED",
    "test_call_from_parser_default_args": "PASSED",
    "test_get_result_filter_arg_vs_config": "PASSED"
}
diff --git a/datalad/cmdline/main.py b/datalad/cmdline/main.py
index aed381f96..20313fc41 100644
--- a/datalad/cmdline/main.py
+++ b/datalad/cmdline/main.py
@@ -113,7 +113,7 @@ def setup_parser(
         '-f', '--output-format', dest='common_output_format',
         default='default',
         type=assure_unicode,
-        metavar="{default,json,json_pp,tailored,'<template>'",
+        metavar="{default,json,json_pp,tailored,'<template>'}",
         help="""select format for returned command results. 'default' give one line
         per result reporting action, status, path and an optional message;
         'json' renders a JSON object with all properties for each result (one per
diff --git a/datalad/interface/base.py b/datalad/interface/base.py
index 31ff267e8..631e7a30d 100644
--- a/datalad/interface/base.py
+++ b/datalad/interface/base.py
@@ -317,6 +317,11 @@ class Interface(object):
     # mode would fall into the debugger
     _interrupted_exit_code = 1
 
+    _OLDSTYLE_COMMANDS = (
+        'AddArchiveContent', 'CrawlInit', 'Crawl', 'CreateSiblingGithub',
+        'CreateTestDataset', 'DownloadURL', 'Export', 'Ls', 'Move', 'SSHRun',
+        'Test')
+
     @classmethod
     def setup_parser(cls, parser):
         # XXX needs safety check for name collisions
@@ -371,7 +376,6 @@ class Interface(object):
 
     @classmethod
     def call_from_parser(cls, args):
-        from datalad import cfg
         # XXX needs safety check for name collisions
         from inspect import getargspec
         argspec = getargspec(cls.__call__)
@@ -391,11 +395,7 @@ class Interface(object):
         # let it run like generator so we can act on partial results quicker
         # TODO remove following condition test when transition is complete and
         # run indented code unconditionally
-        if cls.__name__ not in (
-                'AddArchiveContent',
-                'CrawlInit', 'Crawl', 'CreateSiblingGithub',
-                'CreateTestDataset', 'DownloadURL', 'Export', 'Ls', 'Move',
-                'SSHRun', 'Test'):
+        if cls.__name__ not in Interface._OLDSTYLE_COMMANDS:
             # set all common args explicitly  to override class defaults
             # that are tailored towards the the Python API
             kwargs['return_type'] = 'generator'
@@ -415,20 +415,7 @@ class Interface(object):
             if args.common_on_failure:
                 kwargs['on_failure'] = args.common_on_failure
             # compose filter function from to be invented cmdline options
-            result_filter = None
-            if args.common_report_status or 'datalad.runtime.report-status' in cfg:
-                report_status = args.common_report_status or \
-                    cfg.obtain('datalad.runtime.report-status')
-                if report_status == 'success':
-                    result_filter = EnsureKeyChoice('status', ('ok', 'notneeded'))
-                elif report_status == 'failure':
-                    result_filter = EnsureKeyChoice('status', ('impossible', 'error'))
-                else:
-                    result_filter = EnsureKeyChoice('status', (report_status,))
-            if args.common_report_type:
-                tfilt = EnsureKeyChoice('type', tuple(args.common_report_type))
-                result_filter = result_filter & tfilt if result_filter else tfilt
-            kwargs['result_filter'] = result_filter
+            kwargs['result_filter'] = cls._get_result_filter(args)
         try:
             ret = cls.__call__(**kwargs)
             if inspect.isgenerator(ret):
@@ -444,6 +431,25 @@ class Interface(object):
             else:
                 raise
 
+    @classmethod
+    def _get_result_filter(cls, args):
+        from datalad import cfg
+        result_filter = None
+        if args.common_report_status or 'datalad.runtime.report-status' in cfg:
+            report_status = args.common_report_status or \
+                            cfg.obtain('datalad.runtime.report-status')
+            if report_status == 'success':
+                result_filter = EnsureKeyChoice('status', ('ok', 'notneeded'))
+            elif report_status == 'failure':
+                result_filter = EnsureKeyChoice('status',
+                                                ('impossible', 'error'))
+            else:
+                result_filter = EnsureKeyChoice('status', (report_status,))
+        if args.common_report_type:
+            tfilt = EnsureKeyChoice('type', tuple(args.common_report_type))
+            result_filter = result_filter & tfilt if result_filter else tfilt
+        return result_filter
+
     @classmethod
     def get_refds_path(cls, dataset):
         """Return a resolved reference dataset path from a `dataset` argument"""

{"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 logging\nlgr = logging.getLogger('datalad.interface.base')\n\nimport sys\nimport re\nimport textwrap\nimport inspect\nfrom collections import OrderedDict\n\nfrom ..ui import ui\nfrom ..dochelpers import exc_str\n\nfrom datalad.interface.common_opts import eval_params\nfrom datalad.interface.common_opts import eval_defaults\nfrom datalad.support.exceptions import InsufficientArgumentsError\nfrom datalad.utils import with_pathsep as _with_sep\nfrom datalad.support.constraints import EnsureKeyChoice\nfrom datalad.distribution.dataset import Dataset\nfrom datalad.distribution.dataset import resolve_path\n\n\ndefault_logchannels = {\n    '': 'debug',\n    'ok': 'debug',\n    'notneeded': 'debug',\n    'impossible': 'warning',\n    'error': 'error',\n}\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    \"\"\"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    docs = re.sub(\n        '\\|\\| REFLOW \\>\\>\\n(.*)\\<\\< REFLOW \\|\\|',\n        lambda match: textwrap.fill(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    # clean up sphinx API refs\n    docs = re.sub(\n        '\\~datalad\\.api\\.\\S*',\n        lambda match: \"`{0}`\".format(match.group(0)[13:]),\n        docs)\n    # Remove RST paragraph markup\n    docs = re.sub(\n        r'^.. \\S+::',\n        lambda match: match.group(0)[3:-2].upper(),\n        docs,\n        flags=re.MULTILINE)\n    docs = re.sub(\n        '\\|\\| REFLOW \\>\\>\\n(.*)\\<\\< REFLOW \\|\\|',\n        lambda match: textwrap.fill(match.group(1)),\n        docs,\n        flags=re.MULTILINE | re.DOTALL)\n    return docs\n\n\ndef is_api_arg(arg):\n    \"\"\"Return True if argument is our API argument or self or used for internal\n    purposes\n    \"\"\"\n    return arg != 'self' and not arg.startswith('_')\n\n\ndef update_docstring_with_parameters(func, params, prefix=None, suffix=None,\n                                     add_args=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 add_args:\n        add_argnames = sorted(add_args.keys())\n        args.extend(add_argnames)\n        defaults = defaults + tuple(add_args[k] for k in add_argnames)\n    if defaults is not 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 not is_api_arg(arg):\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 param.constraints is not None:\n                    param.constraints(defaults[defaults_idx])\n            orig_docs = param._doc\n            param._doc = alter_interface_docs_for_api(param._doc)\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            param._doc = orig_docs\n            doc += '\\n'\n    doc += suffix if suffix else u\"\"\n    # assign the amended docs\n    func.__doc__ = doc\n    return func\n\n\ndef build_doc(cls, **kwargs):\n    \"\"\"Decorator to build docstrings for datalad commands\n\n    It's intended to decorate the class, the __call__-method of which is the\n    actual command. It expects that __call__-method to be decorated by\n    eval_results.\n\n    Parameters\n    ----------\n    cls: Interface\n      class defining a datalad command\n    \"\"\"\n\n    # Note, that this is a class decorator, which is executed only once when the\n    # class is imported. It builds the docstring for the class' __call__ method\n    # and returns the original class.\n    #\n    # This is because a decorator for the actual function would not be able to\n    # behave like this. To build the docstring we need to access the attribute\n    # _params of the class. From within a function decorator we cannot do this\n    # during import time, since the class is being built in this very moment and\n    # is not yet available in the module. And if we do it from within the part\n    # of a function decorator, that is executed when the function is called, we\n    # would need to actually call the command once in order to build this\n    # docstring.\n\n    lgr.debug(\"Building doc for {}\".format(cls))\n\n    cls_doc = cls.__doc__\n    if hasattr(cls, '_docs_'):\n        # expand docs\n        cls_doc = cls_doc.format(**cls._docs_)\n\n    call_doc = None\n    # suffix for update_docstring_with_parameters:\n    if cls.__call__.__doc__:\n        call_doc = cls.__call__.__doc__\n\n    # build standard doc and insert eval_doc\n    spec = getattr(cls, '_params_', dict())\n    # get docs for eval_results parameters:\n    spec.update(eval_params)\n\n    update_docstring_with_parameters(\n        cls.__call__, spec,\n        prefix=alter_interface_docs_for_api(cls_doc),\n        suffix=alter_interface_docs_for_api(call_doc),\n        add_args=eval_defaults if not hasattr(cls, '_no_eval_results') else None\n    )\n\n    # return original\n    return cls\n\n\nclass Interface(object):\n    \"\"\"Base class for interface implementations\"\"\"\n\n    # exit code to return if user-interrupted\n    # if None, would just reraise the Exception, so if in --dbg\n    # mode would fall into the debugger\n    _interrupted_exit_code = 1\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 not is_api_arg(arg):\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 constraint 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        from datalad import cfg\n        # XXX needs safety check for name collisions\n        from inspect import getargspec\n        argspec = getargspec(cls.__call__)\n        if argspec[2] is None:\n            # no **kwargs in the call receiver, pull argnames from signature\n            argnames = getargspec(cls.__call__)[0]\n        else:\n            # common options\n            # XXX define or better get from elsewhere\n            common_opts = ('change_path', 'common_debug', 'common_idebug', 'func',\n                           'help', 'log_level', 'logger', 'pbs_runner',\n                           'result_renderer', 'subparser')\n            argnames = [name for name in dir(args)\n                        if not (name.startswith('_') or name in common_opts)]\n        kwargs = {k: getattr(args, k) for k in argnames if is_api_arg(k)}\n        # we are coming from the entry point, this is the toplevel command,\n        # let it run like generator so we can act on partial results quicker\n        # TODO remove following condition test when transition is complete and\n        # run indented code unconditionally\n        if cls.__name__ not in (\n                'AddArchiveContent',\n                'CrawlInit', 'Crawl', 'CreateSiblingGithub',\n                'CreateTestDataset', 'DownloadURL', 'Export', 'Ls', 'Move',\n                'SSHRun', 'Test'):\n            # set all common args explicitly  to override class defaults\n            # that are tailored towards the the Python API\n            kwargs['return_type'] = 'generator'\n            kwargs['result_xfm'] = None\n            # allow commands to override the default, unless something other than\n            # default is requested\n            kwargs['result_renderer'] = \\\n                args.common_output_format if args.common_output_format != 'default' \\\n                else getattr(cls, 'result_renderer', args.common_output_format)\n            if '{' in args.common_output_format:\n                # stupid hack, could and should become more powerful\n                kwargs['result_renderer'] = \\\n                    lambda x, **kwargs: ui.message(args.common_output_format.format(\n                        **{k: {k_.replace(':', '#'): v_ for k_, v_ in v.items()}\n                           if isinstance(v, dict) else v\n                           for k, v in x.items()}))\n            if args.common_on_failure:\n                kwargs['on_failure'] = args.common_on_failure\n            # compose filter function from to be invented cmdline options\n            result_filter = None\n            if args.common_report_status or 'datalad.runtime.report-status' in cfg:\n                report_status = args.common_report_status or \\\n                    cfg.obtain('datalad.runtime.report-status')\n                if report_status == 'success':\n                    result_filter = EnsureKeyChoice('status', ('ok', 'notneeded'))\n                elif report_status == 'failure':\n                    result_filter = EnsureKeyChoice('status', ('impossible', 'error'))\n                else:\n                    result_filter = EnsureKeyChoice('status', (report_status,))\n            if args.common_report_type:\n                tfilt = EnsureKeyChoice('type', tuple(args.common_report_type))\n                result_filter = result_filter & tfilt if result_filter else tfilt\n            kwargs['result_filter'] = result_filter\n        try:\n            ret = cls.__call__(**kwargs)\n            if inspect.isgenerator(ret):\n                ret = list(ret)\n            if args.common_output_format == 'tailored' and \\\n                    hasattr(cls, 'custom_result_summary_renderer'):\n                cls.custom_result_summary_renderer(ret)\n            return ret\n        except KeyboardInterrupt as exc:\n            ui.error(\"\\nInterrupted by user while doing magic: %s\" % exc_str(exc))\n            if cls._interrupted_exit_code is not None:\n                sys.exit(cls._interrupted_exit_code)\n            else:\n                raise\n\n    @classmethod\n    def get_refds_path(cls, dataset):\n        \"\"\"Return a resolved reference dataset path from a `dataset` argument\"\"\"\n        # theoretically a dataset could come in as a relative path -> resolve\n        if dataset is None:\n            return dataset\n        refds_path = dataset.path if isinstance(dataset, Dataset) \\\n            else Dataset(dataset).path\n        if refds_path:\n            refds_path = resolve_path(refds_path)\n        return refds_path\n\n\ndef get_allargs_as_kwargs(call, args, kwargs):\n    \"\"\"Generate a kwargs dict from a call signature and *args, **kwargs\n\n    Basically resolving the argnames for all positional arguments, and\n    resolvin the defaults for all kwargs that are not given in a kwargs\n    dict\n    \"\"\"\n    from inspect import getargspec\n    argspec = getargspec(call)\n    defaults = argspec.defaults\n    nargs = len(argspec.args)\n    assert (nargs >= len(defaults))\n    # map any args to their name\n    argmap = list(zip(argspec.args[:len(args)], args))\n    kwargs_ = OrderedDict(argmap)\n    # map defaults of kwargs to their names (update below)\n    for k, v in zip(argspec.args[-len(defaults):], defaults):\n        if k not in kwargs_:\n            kwargs_[k] = v\n    # update with provided kwarg args\n    kwargs_.update(kwargs)\n    # XXX we cannot assert the following, because our own highlevel\n    # API commands support more kwargs than what is discoverable\n    # from their signature...\n    #assert (nargs == len(kwargs_))\n    return kwargs_\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 ---
[ISSUE]

**Title:** AttributeError when invoking `call_from_parser`: Missing `_get_result_filter` Method

**Description:**
When using the `call_from_parser` method from the `Interface` class, an `AttributeError` is encountered because the `_get_result_filter` method does not exist. This prevents the method from processing arguments correctly and executing as expected.

**Example Code:**
```python
from datalad.interface.base import Interface
from argparse import Namespace

args = Namespace(common_output_format='default')

result = Interface.call_from_parser(args)
```

**Expected Behavior:**
The `call_from_parser` method should process the provided arguments and return the appropriate results without any errors.

**Actual Behavior:**
An `AttributeError` is raised indicating that the `Interface` class lacks the `_get_result_filter` method.

**Error Message:**
```
AttributeError: type object 'Interface' has no attribute '_get_result_filter'
```

[/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 logging
lgr = logging.getLogger('datalad.interface.base')

import sys
import re
import textwrap
import inspect
from collections import OrderedDict

from ..ui import ui
from ..dochelpers import exc_str

from datalad.interface.common_opts import eval_params
from datalad.interface.common_opts import eval_defaults
from datalad.support.exceptions import InsufficientArgumentsError
from datalad.utils import with_pathsep as _with_sep
from datalad.support.constraints import EnsureKeyChoice
from datalad.distribution.dataset import Dataset
from datalad.distribution.dataset import resolve_path


default_logchannels = {
    '': 'debug',
    'ok': 'debug',
    'notneeded': 'debug',
    'impossible': 'warning',
    'error': 'error',
}


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):
    """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(
        '\|\| CMDLINE \>\>.*\<\< CMDLINE \|\|',
        '',
        docs,
        flags=re.MULTILINE | re.DOTALL)
    # clean cmdline in-line bits
    docs = re.sub(
        '\[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)
    docs = re.sub(
        '\|\| REFLOW \>\>\n(.*)\<\< REFLOW \|\|',
        lambda match: textwrap.fill(match.group(1)),
        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 \>\>.*\<\< PYTHON \|\|',
        '',
        docs,
        flags=re.MULTILINE | re.DOTALL)
    # clean cmdline in-line bits
    docs = re.sub(
        '\[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+:`[^`]*`[\\]*',
        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)
    # clean up sphinx API refs
    docs = re.sub(
        '\~datalad\.api\.\S*',
        lambda match: "`{0}`".format(match.group(0)[13:]),
        docs)
    # Remove RST paragraph markup
    docs = re.sub(
        r'^.. \S+::',
        lambda match: match.group(0)[3:-2].upper(),
        docs,
        flags=re.MULTILINE)
    docs = re.sub(
        '\|\| REFLOW \>\>\n(.*)\<\< REFLOW \|\|',
        lambda match: textwrap.fill(match.group(1)),
        docs,
        flags=re.MULTILINE | re.DOTALL)
    return docs


def is_api_arg(arg):
    """Return True if argument is our API argument or self or used for internal
    purposes
    """
    return arg != 'self' and not arg.startswith('_')


def update_docstring_with_parameters(func, params, prefix=None, suffix=None,
                                     add_args=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 add_args:
        add_argnames = sorted(add_args.keys())
        args.extend(add_argnames)
        defaults = defaults + tuple(add_args[k] for k in add_argnames)
    if defaults is not 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 not is_api_arg(arg):
                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 param.constraints is not None:
                    param.constraints(defaults[defaults_idx])
            orig_docs = param._doc
            param._doc = alter_interface_docs_for_api(param._doc)
            doc += param.get_autodoc(
                arg,
                default=defaults[defaults_idx] if defaults_idx >= 0 else None,
                has_default=defaults_idx >= 0)
            param._doc = orig_docs
            doc += '\n'
    doc += suffix if suffix else u""
    # assign the amended docs
    func.__doc__ = doc
    return func


def build_doc(cls, **kwargs):
    """Decorator to build docstrings for datalad commands

    It's intended to decorate the class, the __call__-method of which is the
    actual command. It expects that __call__-method to be decorated by
    eval_results.

    Parameters
    ----------
    cls: Interface
      class defining a datalad command
    """

    # Note, that this is a class decorator, which is executed only once when the
    # class is imported. It builds the docstring for the class' __call__ method
    # and returns the original class.
    #
    # This is because a decorator for the actual function would not be able to
    # behave like this. To build the docstring we need to access the attribute
    # _params of the class. From within a function decorator we cannot do this
    # during import time, since the class is being built in this very moment and
    # is not yet available in the module. And if we do it from within the part
    # of a function decorator, that is executed when the function is called, we
    # would need to actually call the command once in order to build this
    # docstring.

    lgr.debug("Building doc for {}".format(cls))

    cls_doc = cls.__doc__
    if hasattr(cls, '_docs_'):
        # expand docs
        cls_doc = cls_doc.format(**cls._docs_)

    call_doc = None
    # suffix for update_docstring_with_parameters:
    if cls.__call__.__doc__:
        call_doc = cls.__call__.__doc__

    # build standard doc and insert eval_doc
    spec = getattr(cls, '_params_', dict())
    # get docs for eval_results parameters:
    spec.update(eval_params)

    update_docstring_with_parameters(
        cls.__call__, spec,
        prefix=alter_interface_docs_for_api(cls_doc),
        suffix=alter_interface_docs_for_api(call_doc),
        add_args=eval_defaults if not hasattr(cls, '_no_eval_results') else None
    )

    # return original
    return cls


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

    # exit code to return if user-interrupted
    # if None, would just reraise the Exception, so if in --dbg
    # mode would fall into the debugger
    _interrupted_exit_code = 1

    @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 not is_api_arg(arg):
                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 constraint 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):
        from datalad import cfg
        # XXX needs safety check for name collisions
        from inspect import getargspec
        argspec = getargspec(cls.__call__)
        if argspec[2] is None:
            # no **kwargs in the call receiver, pull argnames from signature
            argnames = getargspec(cls.__call__)[0]
        else:
            # common options
            # XXX define or better get from elsewhere
            common_opts = ('change_path', 'common_debug', 'common_idebug', 'func',
                           'help', 'log_level', 'logger', 'pbs_runner',
                           'result_renderer', 'subparser')
            argnames = [name for name in dir(args)
                        if not (name.startswith('_') or name in common_opts)]
        kwargs = {k: getattr(args, k) for k in argnames if is_api_arg(k)}
        # we are coming from the entry point, this is the toplevel command,
        # let it run like generator so we can act on partial results quicker
        # TODO remove following condition test when transition is complete and
        # run indented code unconditionally
        if cls.__name__ not in (
                'AddArchiveContent',
                'CrawlInit', 'Crawl', 'CreateSiblingGithub',
                'CreateTestDataset', 'DownloadURL', 'Export', 'Ls', 'Move',
                'SSHRun', 'Test'):
            # set all common args explicitly  to override class defaults
            # that are tailored towards the the Python API
            kwargs['return_type'] = 'generator'
            kwargs['result_xfm'] = None
            # allow commands to override the default, unless something other than
            # default is requested
            kwargs['result_renderer'] = \
                args.common_output_format if args.common_output_format != 'default' \
                else getattr(cls, 'result_renderer', args.common_output_format)
            if '{' in args.common_output_format:
                # stupid hack, could and should become more powerful
                kwargs['result_renderer'] = \
                    lambda x, **kwargs: ui.message(args.common_output_format.format(
                        **{k: {k_.replace(':', '#'): v_ for k_, v_ in v.items()}
                           if isinstance(v, dict) else v
                           for k, v in x.items()}))
            if args.common_on_failure:
                kwargs['on_failure'] = args.common_on_failure
            # compose filter function from to be invented cmdline options
            result_filter = None
            if args.common_report_status or 'datalad.runtime.report-status' in cfg:
                report_status = args.common_report_status or \
                    cfg.obtain('datalad.runtime.report-status')
                if report_status == 'success':
                    result_filter = EnsureKeyChoice('status', ('ok', 'notneeded'))
                elif report_status == 'failure':
                    result_filter = EnsureKeyChoice('status', ('impossible', 'error'))
                else:
                    result_filter = EnsureKeyChoice('status', (report_status,))
            if args.common_report_type:
                tfilt = EnsureKeyChoice('type', tuple(args.common_report_type))
                result_filter = result_filter & tfilt if result_filter else tfilt
            kwargs['result_filter'] = result_filter
        try:
            ret = cls.__call__(**kwargs)
            if inspect.isgenerator(ret):
                ret = list(ret)
            if args.common_output_format == 'tailored' and \
                    hasattr(cls, 'custom_result_summary_renderer'):
                cls.custom_result_summary_renderer(ret)
            return ret
        except KeyboardInterrupt as exc:
            ui.error("\nInterrupted by user while doing magic: %s" % exc_str(exc))
            if cls._interrupted_exit_code is not None:
                sys.exit(cls._interrupted_exit_code)
            else:
                raise

    @classmethod
    def get_refds_path(cls, dataset):
        """Return a resolved reference dataset path from a `dataset` argument"""
        # theoretically a dataset could come in as a relative path -> resolve
        if dataset is None:
            return dataset
        refds_path = dataset.path if isinstance(dataset, Dataset) \
            else Dataset(dataset).path
        if refds_path:
            refds_path = resolve_path(refds_path)
        return refds_path


def get_allargs_as_kwargs(call, args, kwargs):
    """Generate a kwargs dict from a call signature and *args, **kwargs

    Basically resolving the argnames for all positional arguments, and
    resolvin the defaults for all kwargs that are not given in a kwargs
    dict
    """
    from inspect import getargspec
    argspec = getargspec(call)
    defaults = argspec.defaults
    nargs = len(argspec.args)
    assert (nargs >= len(defaults))
    # map any args to their name
    argmap = list(zip(argspec.args[:len(args)], args))
    kwargs_ = OrderedDict(argmap)
    # map defaults of kwargs to their names (update below)
    for k, v in zip(argspec.args[-len(defaults):], defaults):
        if k not in kwargs_:
            kwargs_[k] = v
    # update with provided kwarg args
    kwargs_.update(kwargs)
    # XXX we cannot assert the following, because our own highlevel
    # API commands support more kwargs than what is discoverable
    # from their signature...
    #assert (nargs == len(kwargs_))
    return kwargs_

```
--- 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