Beispiel #1
0
 def __getattr__(self, attr):
     # Assure that we are not just missing some late binding
     # @datasetmethod . We will use interface definitions.
     # The gotcha could be the mismatch between explicit name
     # provided to @datasetmethod and what is defined in interfaces
     meth = None
     if not attr.startswith('_'):  # do not even consider those
         from datalad.interface.base import (
             get_interface_groups, get_api_name, load_interface
         )
         groups = get_interface_groups(True)
         for group, _, interfaces in groups:
             for intfspec in interfaces:
                 # lgr.log(5, "Considering interface %s", intfspec)
                 name = get_api_name(intfspec)
                 if attr == name:
                     meth_ = load_interface(intfspec)
                     if meth_:
                         lgr.debug("Found matching interface %s for %s",
                                   intfspec, name)
                         if meth:
                             lgr.debug(
                                 "New match %s possibly overloaded previous one %s",
                                 meth_, meth
                             )
                         meth = meth_
         if not meth:
             lgr.debug("Found no match among known interfaces for %r", attr)
     return super(Dataset, self).__getattribute__(attr)
Beispiel #2
0
 def __getattr__(self, attr):
     # Assure that we are not just missing some late binding
     # @datasetmethod . We will use interface definitions.
     # The gotcha could be the mismatch between explicit name
     # provided to @datasetmethod and what is defined in interfaces
     meth = None
     if not attr.startswith('_'):  # do not even consider those
         from datalad.interface.base import (
             get_interface_groups, get_api_name, load_interface
         )
         groups = get_interface_groups(True)
         for group, _, interfaces in groups:
             for intfspec in interfaces:
                 # lgr.log(5, "Considering interface %s", intfspec)
                 name = get_api_name(intfspec)
                 if attr == name:
                     meth_ = load_interface(intfspec)
                     if meth_:
                         lgr.debug("Found matching interface %s for %s",
                                   intfspec, name)
                         if meth:
                             lgr.debug(
                                 "New match %s possibly overloaded previous one %s",
                                 meth_, meth
                             )
                         meth = meth_
         if not meth:
             lgr.debug("Found no match among known interfaces for %r", attr)
     return super(Dataset, self).__getattribute__(attr)
Beispiel #3
0
    def _get_long_help(self, parser):
        helpstr = parser.format_help()
        if ' ' in parser.prog:  # subcommand
            # in case of a subcommand there is no need to pull the
            # list of top-level subcommands
            return helpstr
        helpstr = re.sub(
            r'^[uU]sage: .*?\n\s*\n',
            'Usage: datalad [global-opts] command [command-opts]\n\n',
            helpstr,
            flags=re.MULTILINE | re.DOTALL)
        # split into preamble and options
        preamble = []
        options = []
        in_options = False
        for line in helpstr.splitlines():
            if line == 'optional arguments:':
                in_options = True
                continue
            (options if in_options else preamble).append(line)

        intf = self._get_all_interfaces()
        from datalad.interface.base import (
            get_cmd_doc,
            load_interface,
        )
        from .interface import (
            get_cmdline_command_name,
            alter_interface_docs_for_cmdline,
        )
        preamble = get_description_with_cmd_summary(
            # produce a mapping of command groups to
            # [(cmdname, description), ...]
            {
                i[0]: [
                    (
                        get_cmdline_command_name(c),
                        # alter_interface_docs_for_cmdline is only needed, because
                        # some commands use sphinx markup in their summary line
                        # stripping that takes 10-30ms for a typical datalad
                        # installation with some extensions
                        alter_interface_docs_for_cmdline(
                            # we only take the first line
                            get_cmd_doc(
                                # we must import the interface class
                                # this will engage @build_doc -- unavoidable right
                                # now
                                load_interface(c)).split('\n', maxsplit=1)[0]))
                    for c in i[2]
                ]
                for i in intf
            },
            intf,
            '\n'.join(preamble),
        )
        return '{}\n\n*Global options*\n{}\n'.format(
            preamble,
            '\n'.join(options),
        )
Beispiel #4
0
def add_subparser(_intfspec,
                  subparsers,
                  cmd_name,
                  formatter_class,
                  completing=False):
    """Given an interface spec, add a subparser to subparsers under cmd_name
    """
    _intf = load_interface(_intfspec)
    if _intf is None:
        # failed to load, error was already logged
        return

    # compose argparse.add_parser() arguments, focused on docs
    parser_args = dict(formatter_class=formatter_class)
    # use class description, if no explicit description is available
    intf_doc = get_cmd_doc(_intf)
    if not completing:
        parser_args['description'] = alter_interface_docs_for_cmdline(intf_doc)
        if hasattr(_intf, '_examples_'):
            intf_ex = alter_interface_docs_for_cmdline(get_cmd_ex(_intf))
            parser_args['description'] += intf_ex

    # create the sub-parser
    subparser = subparsers.add_parser(cmd_name, add_help=False, **parser_args)
    # our own custom help for all commands, we must do it here
    # (not in setup_parser_for_interface()) because the top-level parser must
    # not unconditionally have it available initially
    parser_add_common_opt(subparser, 'help')
    # let module configure the parser
    setup_parser_for_interface(subparser, _intf, completing=completing)
    # and we would add custom handler for --version
    parser_add_version_opt(subparser,
                           _intf.__module__.split('.', 1)[0],
                           include_name=True)
    # logger for command
    # configure 'run' function for this command
    plumbing_args = dict(
        # this is the key execution handler
        func=partial(call_from_parser, _intf),
        # use the logger of the module that defined the interface
        logger=logging.getLogger(_intf.__module__),
        subparser=subparser)
    if hasattr(_intf, 'result_renderer_cmdline'):
        plumbing_args['result_renderer'] = _intf.result_renderer_cmdline
    subparser.set_defaults(**plumbing_args)
    return subparser
Beispiel #5
0
def _command_summary():
    # Import here to avoid polluting the datalad.api namespace.
    from collections import defaultdict
    from datalad.interface.base import alter_interface_docs_for_api
    from datalad.interface.base import get_api_name
    from datalad.interface.base import get_cmd_doc
    from datalad.interface.base import get_cmd_summaries
    from datalad.interface.base import get_interface_groups
    from datalad.interface.base import load_interface

    groups = get_interface_groups()
    grp_short_descriptions = defaultdict(list)
    for group, _, specs in sorted(groups, key=lambda x: x[1]):
        for spec in specs:
            intf = load_interface(spec)
            if intf is None:
                continue
            sdescr = getattr(intf, "short_description", None) or \
                alter_interface_docs_for_api(get_cmd_doc(intf)).split("\n")[0]
            grp_short_descriptions[group].append((get_api_name(spec), sdescr))
    return "\n".join(get_cmd_summaries(grp_short_descriptions, groups))
Beispiel #6
0
def _command_summary():
    # Import here to avoid polluting the datalad.api namespace.
    from collections import defaultdict
    from datalad.interface.base import alter_interface_docs_for_api
    from datalad.interface.base import get_api_name
    from datalad.interface.base import get_cmd_doc
    from datalad.interface.base import get_cmd_summaries
    from datalad.interface.base import get_interface_groups
    from datalad.interface.base import load_interface

    groups = get_interface_groups(include_plugins=True)
    grp_short_descriptions = defaultdict(list)
    for group, _, specs in sorted(groups, key=lambda x: x[1]):
        for spec in specs:
            intf = load_interface(spec)
            if intf is None:
                continue
            sdescr = getattr(intf, "short_description", None) or \
                alter_interface_docs_for_api(get_cmd_doc(intf)).split("\n")[0]
            grp_short_descriptions[group].append(
                (get_api_name(spec), sdescr))
    return "\n".join(get_cmd_summaries(grp_short_descriptions, groups))
Beispiel #7
0
def _generate_extension_api():
    """Auto detect all available extensions and generate an API from them
    """
    from datalad.support.entrypoints import iter_entrypoints
    from datalad.interface.base import (
        get_api_name,
        load_interface,
    )

    import logging
    lgr = logging.getLogger('datalad.api')

    for ename, _, (grp_descr,
                   interfaces) in iter_entrypoints('datalad.extensions',
                                                   load=True):
        for intfspec in interfaces:
            # turn the interface spec into an instance
            intf = load_interface(intfspec[:2])
            api_name = get_api_name(intfspec)
            if api_name in globals():
                lgr.debug(
                    'Command %s from extension %s is replacing a previously loaded implementation',
                    api_name, ename)
            globals()[api_name] = intf.__call__