Exemplo n.º 1
0
def _parse_commandline(command=None, style='auto', verbose=None, argv=None):
    # Determine command via sys.argv if not specified
    doctest_example.Config()

    if argv is None:
        argv = sys.argv[1:]

    if command is None:
        if len(argv) >= 1:
            if argv[0] and not argv[0].startswith('-'):
                command = argv[0]

    # Change how docstrs are found
    if '--freeform' in argv:
        style = 'freeform'
    elif '--google' in argv:
        style = 'google'

    # Parse verbosity flag
    if verbose is None:
        if '--verbose' in argv:
            verbose = 3
        elif '--quiet' in argv:
            verbose = 0
        elif '--silent' in argv:
            verbose = -1
        else:
            verbose = 3
    return command, style, verbose
Exemplo n.º 2
0
    def _prepare_internal_config(self):

        class NamespaceLike(object):
            def __init__(self, config):
                self.config = config
            def __getitem__(self, attr):
                return self.config.getvalue('xdoctest_' + attr)
            def __getattr__(self, attr):
                return self.config.getvalue('xdoctest_' + attr)

        ns = NamespaceLike(self.config)

        from xdoctest import doctest_example
        self._examp_conf = doctest_example.Config()._populate_from_cli(ns)
Exemplo n.º 3
0
def pytest_addoption(parser):
    # TODO: make this programatically mirror the argparse in __main__
    from xdoctest import core

    def str_lower(x):
        # python2 fix
        return str.lower(str(x))

    group = parser.getgroup('collect')
    parser.addini('xdoctest_encoding', 'encoding used for xdoctest files', default='utf-8')
    # parser.addini('xdoctest_options', 'default directive flags for doctests',
    #               type="args", default=["+ELLIPSIS"])
    group.addoption('--xdoctest-modules', '--xdoctest', '--xdoc',
                    action='store_true', default=False,
                    help='run doctests in all .py modules using new style parsing',
                    dest='xdoctestmodules')
    group.addoption('--xdoctest-glob', '--xdoc-glob',
                    action='append', default=[], metavar='pat',
                    help='xdoctests file matching pattern, default: test*.txt',
                    dest='xdoctestglob')
    group.addoption('--xdoctest-ignore-syntax-errors',
                    action='store_true', default=False,
                    help='ignore xdoctest SyntaxErrors',
                    dest='xdoctest_ignore_syntax_errors')

    group.addoption('--xdoctest-style', '--xdoc-style',
                    type=str_lower, default='freeform',
                    help='basic style used to write doctests',
                    choices=core.DOCTEST_STYLES,
                    dest='xdoctest_style')

    from xdoctest import doctest_example
    doctest_example.Config()._update_argparse_cli(
        group.addoption, prefix=['xdoctest', 'xdoc'],
        defaults=dict(verbose=0)
    )
Exemplo n.º 4
0
def main(argv=None):
    """
    python -m xdoctest xdoctest all
    python -m xdoctest networkx all --options=+IGNORE_WHITESPACE
    """
    import argparse
    import xdoctest
    from os.path import exists
    from xdoctest import utils

    if argv is None:
        argv = sys.argv

    version_info = {
        'xdoc_version': xdoctest.__version__,
        'sys_version': sys.version,
    }

    if '--version' in argv:
        print(version_info['xdoc_version'])
        return 0

    if '--version-info' in argv:
        for key, value in sorted(version_info.items()):
            print('{} = {}'.format(key, value))
        return 0

    parser = argparse.ArgumentParser(
        prog='xdoctest',
        description=(
            'Xdoctest {xdoc_version} - on Python - {sys_version} - '
            'discover and run doctests within a python package').format(
                **version_info))
    parser.add_argument('arg',
                        nargs='*',
                        help=utils.codeblock('''
            Ignored if optional arguments are specified, otherwise:
            Defaults --modname to arg.pop(0).
            Defaults --command to arg.pop(0).
            '''))
    parser.add_argument('--version',
                        action='store_true',
                        help='display version info and quit')

    # The bulk of the argparse CLI is defined in the doctest example
    from xdoctest import doctest_example
    from xdoctest import runner
    runner._update_argparse_cli(parser.add_argument)
    doctest_example.Config()._update_argparse_cli(parser.add_argument)

    args, unknown = parser.parse_known_args(args=argv[1:])
    ns = args.__dict__.copy()

    __DEBUG__ = '--debug' in sys.argv
    if __DEBUG__:
        print('ns = {!r}'.format(ns))

    if ns['version']:
        print(xdoctest.__version__)
        return 0

    # ... postprocess args
    modname = ns['modname']
    command = ns['command']
    arg = ns['arg']
    style = ns['style']
    durations = ns['durations']
    analysis = ns['analysis']
    if ns['time']:
        durations = 0
    # ---
    # Allow for positional args to specify defaults for unspecified optionals
    errors = []
    if modname is None:
        if len(arg) == 0:
            errors += ['you must specify modname or modpath']
        else:
            modname = arg.pop(0)

    if command is None:
        if len(arg) == 0:
            # errors += ['you must specify a command e.g (list, all)']
            command = 'all'
        else:
            command = arg.pop(0)

    if errors:
        if len(errors) == 1:
            errmsg = errors[0]
        else:
            listed_errors = ', '.join([
                '({}) {}'.format(c, e) for c, e in enumerate(errors, start=1)
            ])
            errmsg = '{} errors: {}'.format(len(errors), listed_errors)
        parser.error(errmsg)
    # ---

    options = ns['options']
    if options is None:
        options = ''
        if exists('pytest.ini'):
            from six.moves import configparser
            parser = configparser.ConfigParser()
            parser.read('pytest.ini')
            try:
                options = parser.get('pytest', 'xdoctest_options')
            except configparser.NoOptionError:
                pass
        ns['options'] = options

    from xdoctest import doctest_example
    config = doctest_example.Config()._populate_from_cli(ns)

    import textwrap
    if config['verbose'] > 2:
        print(
            textwrap.dedent(r'''
            =====================================
            _  _ ___  ____ ____ ___ ____ ____ ___
             \/  |  \ |  | |     |  |___ [__   |
            _/\_ |__/ |__| |___  |  |___ ___]  |

            =====================================
            '''))

    if __DEBUG__:
        try:
            import ubelt as ub
            print('config = {}'.format(ub.repr2(config)))
            print('ns = {}'.format(ub.repr2(ns)))
        except ImportError:
            pass
        print('modname = {!r}'.format(modname))

    run_summary = xdoctest.doctest_module(modname,
                                          argv=[command],
                                          style=style,
                                          verbose=config['verbose'],
                                          config=config,
                                          durations=durations,
                                          analysis=analysis)
    n_failed = run_summary.get('n_failed', 0)
    if n_failed > 0:
        return 1
    else:
        return 0
Exemplo n.º 5
0
def doctest_module(modpath_or_name=None,
                   command=None,
                   argv=None,
                   exclude=[],
                   style='auto',
                   verbose=None,
                   config=None,
                   durations=None,
                   analysis='static'):
    """
    Executes requestsed google-style doctests in a package or module.
    Main entry point into the testing framework.

    Args:
        modname (str): name of or path to the module.

        command (str):
            determines which doctests to run.
            if command is None, this is determined by parsing sys.argv
            Value values are
                'all' - find and run all tests in a module
                'list' - list the tests in a module
                'dump' - dumps tests to stdout

        argv (List[str], default=None):
            if specified, command line flags that might influence beharior.
            if None uses sys.argv.
            SeeAlso :func:_update_argparse_cli
            SeeAlso :func:doctest_example.Config._update_argparse_cli

        verbose (int, default=None):
            Verbosity level.
                0 - disables all text
                1 - minimal printing
                3 - verbose printing

        exclude (List[str]):
            ignores any modname matching any of these glob-like patterns

        config (Dict[str, object]):
            modifies each examples configuration

        durations (int, default=None): if specified report top N slowest tests

        analysis (str): determines if doctests are found using static or
            dynamic analysis.

    Returns:
        Dict: run_summary

    Example:
        >>> modname = 'xdoctest.dynamic_analysis'
        >>> result = doctest_module(modname, 'list', argv=[''])
    """
    _log = partial(log, verbose=DEBUG)
    _log('------+ DEBUG +------')
    _log('CALLED doctest_module')
    _log('exclude = {!r}'.format(exclude))
    _log('argv = {!r}'.format(argv))
    _log('command = {!r}'.format(command))
    _log('modpath_or_name = {!r}'.format(modpath_or_name))
    _log('durations = {!r}'.format(durations))
    _log('config = {!r}'.format(config))
    _log('verbose = {!r}'.format(verbose))
    _log('style = {!r}'.format(style))
    _log('------+ /DEBUG +------')

    # Determine package name via caller if not specified
    if modpath_or_name is None:
        frame_parent = dynamic_analysis.get_parent_frame()
        modpath = frame_parent.f_globals['__file__']
    else:
        if command is None:
            # Allow the modname to contain the name of the test to be run
            if '::' in modpath_or_name:
                modpath_or_name, command = modpath_or_name.split('::')
        modpath = core._rectify_to_modpath(modpath_or_name)

    if config is None:
        config = doctest_example.Config()

    command, style, verbose = _parse_commandline(command, style, verbose, argv)

    _log = partial(log, verbose=verbose)

    _log('Start doctest_module({!r})'.format(modpath_or_name))
    _log('Listing tests')

    if command is None:
        # Display help if command is not specified
        _log('Not testname given. Use `all` to run everything or'
             ' pick from a list of valid choices:')
        command = 'list'

    # TODO: command should not be allowed to be the requested doctest name in
    # case it conflicts with an existing command. This probably requires an API
    # change to this function.
    gather_all = (command == 'all' or command == 'dump')

    tic = time.time()

    # Parse all valid examples
    with warnings.catch_warnings(record=True) as parse_warnlist:
        examples = list(
            core.parse_doctestables(modpath,
                                    exclude=exclude,
                                    style=style,
                                    analysis=analysis))
        # Set each example mode to native to signal that we are using the
        # native xdoctest runner instead of the pytest runner
        for example in examples:
            example.mode = 'native'

    if command == 'list':
        if len(examples) == 0:
            _log('... no docstrings with examples found')
        else:
            _log('    ' + '\n    '.join([
                example.cmdline  # + ' @ ' + str(example.lineno)
                for example in examples
            ]))
        run_summary = {'action': 'list'}
    else:
        _log('gathering tests')
        enabled_examples = []
        for example in examples:
            if gather_all or command in example.valid_testnames:
                if gather_all and example.is_disabled():
                    continue
                enabled_examples.append(example)

        if len(enabled_examples) == 0:
            # Check for zero-arg funcs
            for example in _gather_zero_arg_examples(modpath):
                if command in example.valid_testnames:
                    enabled_examples.append(example)

                elif command in ['zero-all', 'zero', 'zero_all', 'zero-args']:
                    enabled_examples.append(example)

        if config:
            for example in enabled_examples:
                example.config.update(config)

        if command == 'dump':
            # format the doctests as normal unit tests
            _log('dumping tests to stdout')
            module_text = _convert_to_test_module(enabled_examples)
            _log(module_text)

            run_summary = {'action': 'dump'}
        else:
            # Run the gathered doctest examples

            RANDOMIZE_ORDER = False
            if RANDOMIZE_ORDER:
                # randomize the order in which tests are run
                import random
                random.shuffle(enabled_examples)

            run_summary = _run_examples(enabled_examples,
                                        verbose,
                                        config,
                                        _log=_log)

            toc = time.time()
            n_seconds = toc - tic

            # Print final summary info in a style similar to pytest
            if verbose >= 0 and run_summary:
                _print_summary_report(run_summary,
                                      parse_warnlist,
                                      n_seconds,
                                      enabled_examples,
                                      durations,
                                      config=config,
                                      _log=_log)

    return run_summary
Exemplo n.º 6
0
def doctest_module(modpath_or_name=None,
                   command=None,
                   argv=None,
                   exclude=[],
                   style='auto',
                   verbose=None,
                   config=None,
                   durations=None):
    """
    Executes requestsed google-style doctests in a package or module.
    Main entry point into the testing framework.

    Args:
        modname (str): name of or path to the module.
        command (str): determines which doctests to run.
            if command is None, this is determined by parsing sys.argv
        argv (list): if None uses sys.argv
        verbose (bool):  verbosity flag
        exclude (list): ignores any modname matching any of these
            glob-like patterns
        config (dict): modifies each examples configuration

    Returns:
        Dict: run_summary

    Example:
        >>> modname = 'xdoctest.dynamic_analysis'
        >>> result = doctest_module(modname, 'list', argv=[''])
    """
    print('Start doctest_module({!r})'.format(modpath_or_name))

    # Determine package name via caller if not specified
    if modpath_or_name is None:
        frame_parent = dynamic.get_parent_frame()
        modpath = frame_parent.f_globals['__file__']
    else:
        modpath = core._rectify_to_modpath(modpath_or_name)

    if config is None:
        config = doctest_example.Config()

    command, style, verbose = _parse_commandline(command, style, verbose, argv)

    if command == 'list':
        print('Listing tests')

    if command is None:
        # Display help if command is not specified
        print('Not testname given. Use `all` to run everything or'
              ' pick from a list of valid choices:')
        command = 'list'

    # TODO: command should not be allowed to be the requested doctest name in
    # case it conflicts with an existing command. This probably requires an API
    # change to this function.
    gather_all = (command == 'all' or command == 'dump')

    tic = time.time()

    # Parse all valid examples
    with warnings.catch_warnings(record=True) as parse_warnlist:
        examples = list(
            core.parse_doctestables(modpath, exclude=exclude, style=style))
        # Set each example mode to native to signal that we are using the
        # native xdoctest runner instead of the pytest runner
        for example in examples:
            example.mode = 'native'

    if command == 'list':
        if len(examples) == 0:
            print('... no docstrings with examples found')
        else:
            print('    ' + '\n    '.join([
                example.cmdline  # + ' @ ' + str(example.lineno)
                for example in examples
            ]))
        run_summary = {'action': 'list'}
    else:
        print('gathering tests')
        enabled_examples = []
        for example in examples:
            if gather_all or command in example.valid_testnames:
                if gather_all and example.is_disabled():
                    continue
                enabled_examples.append(example)

        if len(enabled_examples) == 0:
            # Check for zero-arg funcs
            for example in _gather_zero_arg_examples(modpath):
                if command in example.valid_testnames:
                    enabled_examples.append(example)

                elif command in ['zero-all', 'zero', 'zero_all', 'zero-args']:
                    enabled_examples.append(example)

        if config:
            for example in enabled_examples:
                example.config.update(config)

        if command == 'dump':
            # format the doctests as normal unit tests
            print('dumping tests to stdout')
            _convert_to_test_module(enabled_examples)
            run_summary = {'action': 'dump'}
        else:
            # Run the gathered doctest examples

            RANDOMIZE_ORDER = False
            if RANDOMIZE_ORDER:
                # randomize the order in which tests are run
                import random
                random.shuffle(enabled_examples)

            run_summary = _run_examples(enabled_examples, verbose, config)

            toc = time.time()
            n_seconds = toc - tic

            # Print final summary info in a style similar to pytest
            if verbose >= 0 and run_summary:
                _print_summary_report(run_summary,
                                      parse_warnlist,
                                      n_seconds,
                                      enabled_examples,
                                      durations,
                                      config=config)

    return run_summary
Exemplo n.º 7
0
def main():
    """
    python -m xdoctest xdoctest all
    python -m xdoctest networkx all --options=+IGNORE_WHITESPACE
    """
    import sys
    import argparse
    from os.path import exists
    from xdoctest import utils

    parser = argparse.ArgumentParser(prog='xdoctest',
                                     description=utils.codeblock('''
            discover and run doctests within a python package
            '''))
    parser.add_argument('arg',
                        nargs='*',
                        help=utils.codeblock('''
            Ignored if optional arguments are specified, otherwise:
            Defaults --modname to arg.pop(0).
            Defaults --command to arg.pop(0).
            '''))
    parser.add_argument('--version',
                        action='store_true',
                        help='display version info and quit')

    # The bulk of the argparse CLI is defined in the doctest example
    from xdoctest import doctest_example
    from xdoctest import runner
    runner._update_argparse_cli(parser.add_argument)
    doctest_example.Config()._update_argparse_cli(parser.add_argument)

    args, unknown = parser.parse_known_args()
    ns = args.__dict__.copy()

    if ns['version']:
        import xdoctest
        print(xdoctest.__version__)
        sys.exit(0)

    # ... postprocess args
    modname = ns['modname']
    command = ns['command']
    arg = ns['arg']
    style = ns['style']
    durations = ns['durations']
    if ns['time']:
        durations = 0
    # ---
    # Allow for positional args to specify defaults for unspecified optionals
    errors = []
    if modname is None:
        if len(arg) == 0:
            errors += ['you must specify modname or modpath']
        else:
            modname = arg.pop(0)

    if command is None:
        if len(arg) == 0:
            # errors += ['you must specify a command e.g (list, all)']
            command = 'all'
        else:
            command = arg.pop(0)

    if errors:
        if len(errors) == 1:
            errmsg = errors[0]
        else:
            listed_errors = ', '.join([
                '({}) {}'.format(c, e) for c, e in enumerate(errors, start=1)
            ])
            errmsg = '{} errors: {}'.format(len(errors), listed_errors)
        parser.error(errmsg)
    # ---

    import xdoctest

    if ns['version']:
        print(xdoctest.__version__)
        sys.exit(0)

    options = ns['options']
    if options is None:
        options = ''
        if exists('pytest.ini'):
            from six.moves import configparser
            parser = configparser.ConfigParser()
            parser.read('pytest.ini')
            try:
                options = parser.get('pytest', 'xdoctest_options')
            except configparser.NoOptionError:
                pass
        ns['options'] = options

    from xdoctest import doctest_example
    config = doctest_example.Config()._populate_from_cli(ns)

    run_summary = xdoctest.doctest_module(modname,
                                          argv=[command],
                                          style=style,
                                          verbose=config['verbose'],
                                          config=config,
                                          durations=durations)
    n_failed = run_summary.get('n_failed', 0)
    if n_failed > 0:
        sys.exit(1)
    else:
        sys.exit(0)
Exemplo n.º 8
0
def pytest_addoption(parser):
    # TODO: make this programatically mirror the argparse in __main__
    from xdoctest import core

    def str_lower(x):
        # python2 fix
        return str.lower(str(x))

    group = parser.getgroup('collect')
    parser.addini('xdoctest_encoding',
                  'encoding used for xdoctest files',
                  default='utf-8')
    # parser.addini('xdoctest_options', 'default directive flags for doctests',
    #               type="args", default=["+ELLIPSIS"])
    group.addoption(
        '--xdoctest-modules',
        '--xdoctest',
        '--xdoc',
        action='store_true',
        default=False,
        help='run doctests in all .py modules using new style parsing',
        dest='xdoctestmodules')
    group.addoption(
        '--xdoctest-glob',
        '--xdoc-glob',
        action='append',
        default=[],
        metavar='pat',
        help=('text files matching this pattern will be checked '
              'for doctests. This option may be specified multiple '
              'times. XDoctest does not check any text files by '
              'default. For compatibility with doctest set this to '
              'test*.txt'),
        dest='xdoctestglob')
    group.addoption('--xdoctest-ignore-syntax-errors',
                    action='store_true',
                    default=False,
                    help='ignore xdoctest SyntaxErrors',
                    dest='xdoctest_ignore_syntax_errors')

    group.addoption('--xdoctest-style',
                    '--xdoc-style',
                    type=str_lower,
                    default='freeform',
                    help='basic style used to write doctests',
                    choices=core.DOCTEST_STYLES,
                    dest='xdoctest_style')

    group.addoption('--xdoctest-analysis',
                    '--xdoc-analysis',
                    type=str_lower,
                    default='auto',
                    help=('How doctests are collected. '
                          'Can either be static, dynamic, or auto'),
                    choices=['static', 'dynamic', 'auto'],
                    dest='xdoctest_analysis')

    from xdoctest import doctest_example
    doctest_example.Config()._update_argparse_cli(group.addoption,
                                                  prefix=['xdoctest', 'xdoc'],
                                                  defaults=dict(verbose=0))