예제 #1
0
파일: dataset.py 프로젝트: shots47s/datalad
 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)
예제 #2
0
파일: dataset.py 프로젝트: datalad/datalad
 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)
예제 #3
0
파일: helpers.py 프로젝트: datalad/datalad
 def _get_all_interfaces(self):
     # load all extensions and command specs
     # this does not fully tune all the command docs
     from datalad.interface.base import get_interface_groups
     interface_groups = get_interface_groups()
     add_entrypoints_to_interface_groups(interface_groups)
     return interface_groups
예제 #4
0
파일: test_api.py 프로젝트: ypid/datalad
def test_consistent_order_of_args():
    from datalad.interface.base import get_interface_groups

    from importlib import import_module

    for grp_name, grp_descr, interfaces in get_interface_groups():
        for intfspec in interfaces:
            # turn the interface spec into an instance
            mod = import_module(intfspec[0], package='datalad')
            intf = getattr(mod, intfspec[1])
            spec = getattr(intf, '_params_', dict())

            # figure out which of the specs are "positional"
            spec_posargs = {
                name
                for name, param in spec.items()
                if param.cmd_args and not param.cmd_args[0].startswith('-')
            }
            # we have information about positional args
            yield _test_consistent_order_of_args, intf, spec_posargs
예제 #5
0
def test_consistent_order_of_args():
    from datalad.interface.base import get_interface_groups

    from importlib import import_module

    for grp_name, grp_descr, interfaces in get_interface_groups():
        for intfspec in interfaces:
            # turn the interface spec into an instance
            mod = import_module(intfspec[0], package='datalad')
            intf = getattr(mod, intfspec[1])
            spec = getattr(intf, '_params_', dict())

            # figure out which of the specs are "positional"
            spec_posargs = {
                name
                for name, param in spec.items()
                if param.cmd_args and not param.cmd_args[0].startswith('-')
            }
            # we have information about positional args
            yield _test_consistent_order_of_args, intf, spec_posargs
예제 #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()
    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))
예제 #7
0
파일: api.py 프로젝트: datalad/datalad
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))
예제 #8
0
파일: parser.py 프로젝트: datalad/datalad
def setup_parser(cmdlineargs,
                 formatter_class=argparse.RawDescriptionHelpFormatter,
                 return_subparsers=False,
                 completing=False,
                 help_ignore_extensions=False):
    """
    The holy grail of establishing CLI for DataLad's Interfaces

    Parameters
    ----------
    cmdlineargs: sys.argv
      Used to make some shortcuts when construction of a full parser can be
      avoided.
    formatter_class:
      Passed to argparse
    return_subparsers: bool, optional
      is used ATM only by BuildManPage in _datalad_build_support
    completing: bool, optional
      Flag to indicate whether the process was invoked by argcomplete
    help_ignore_extensions: bool, optional
      Prevent loading of extension entrypoints when --help is requested.
      This is enabled when building docs to avoid pollution of generated
      manpages with extensions commands (that should appear in their own
      docs, but not in the core datalad package docs)
    """
    lgr.log(5, "Starting to setup_parser")

    # main parser
    parser = ArgumentParserDisableAbbrev(
        fromfile_prefix_chars=None,
        prog='datalad',
        # usage="%(prog)s ...",
        description=help_gist,
        epilog='"Be happy!"',
        formatter_class=formatter_class,
        add_help=False,
        # TODO: when dropping support for Python 3.8: uncomment below
        # and use parse_known_args instead of _parse_known_args:
        # # set to False so parse_known_args does not add its error handling
        # # Added while RFing from using _parse_known_args to parse_known_args.
        # exit_on_error=False,
    )

    # common options
    parser_add_common_options(parser)

    # get all interface definitions from datalad-core
    interface_groups = get_interface_groups()

    # try to figure out whether the parser construction can be limited to
    # a single (sub)command -- don't even try to do this, when we are in
    # any of the doc-building capacities -- timing is not relevant there
    status, parseinfo = single_subparser_possible(
        cmdlineargs,
        parser,
        completing,
    ) if not return_subparsers else ('allparsers', None)

    command_provider = 'core'

    if status == 'allparsers' and not help_ignore_extensions:
        from .helpers import add_entrypoints_to_interface_groups
        add_entrypoints_to_interface_groups(interface_groups)

    # when completing and we have no incomplete option or parameter
    # we still need to offer all commands for completion
    if (completing and status == 'allknown') or (
            status == 'subcommand'
            and parseinfo not in get_commands_from_groups(interface_groups)):
        # we know the command is not in the core package
        # still a chance it could be in an extension
        command_provider = 'extension'
        # we need the full help, or we have a potential command that
        # lives in an extension, must load all extension, expensive
        from .helpers import add_entrypoints_to_interface_groups
        # need to load all the extensions and try again
        # TODO load extensions one-by-one and stop when a command was found
        add_entrypoints_to_interface_groups(interface_groups)

        if status == 'subcommand':
            known_commands = get_commands_from_groups(interface_groups)
            if parseinfo not in known_commands:
                # certainly not possible to identify a single parser that
                # could be constructed, but we can be helpful
                # will sys.exit() unless we are completing
                try_suggest_extension_with_command(parser, parseinfo,
                                                   completing, known_commands)
                # in completion mode we can get here, even for a command
                # that does not exist at all!
                command_provider = None

    # TODO check if not needed elsewhere
    if status == 'help' or completing and status in ('allknown', 'unknownopt'):
        # --help specification was delayed since it causes immediate
        # printout of
        # --help output before we setup --help for each command
        parser_add_common_opt(parser, 'help')

    all_parsers = {}  # name: (sub)parser

    if (completing and status == 'allknown') or status \
            in ('allparsers', 'subcommand'):
        # parseinfo could be None here, when we could not identify
        # a subcommand, but need to locate matching ones for
        # completion
        # create subparser, use module suffix as cmd name
        subparsers = parser.add_subparsers()
        for _, _, _interfaces \
                in sorted(interface_groups, key=lambda x: x[1]):
            for _intfspec in _interfaces:
                cmd_name = get_cmdline_command_name(_intfspec)
                if status == 'subcommand':
                    # in case only a subcommand is desired, we could
                    # skip some processing
                    if command_provider and cmd_name != parseinfo:
                        # a known command, but know what we are looking for
                        continue
                    if command_provider is None and not cmd_name.startswith(
                            parseinfo):
                        # an unknown command, and has no common prefix with
                        # the current command candidate, not even good
                        # for completion
                        continue
                subparser = add_subparser(
                    _intfspec,
                    subparsers,
                    cmd_name,
                    formatter_class,
                    completing=completing,
                )
                if subparser:  # interface can fail to load
                    all_parsers[cmd_name] = subparser

    # "main" parser is under "datalad" name
    all_parsers['datalad'] = parser
    lgr.log(5, "Finished setup_parser")
    if return_subparsers:
        # TODO why not pull the subparsers from the main parser?
        return all_parsers
    else:
        return parser
예제 #9
0
def get_all_commands() -> list:
    return list(get_commands_from_groups(get_interface_groups()))