def test_comment(): docsrc = utils.codeblock(''' >>> # foobar ''') self = doctest_example.DocTest(docsrc=docsrc) self._parse() assert len(self._parts) == 1 self.run(verbose=0) docsrc = utils.codeblock(''' >>> # foobar >>> # bazbiz ''') self = doctest_example.DocTest(docsrc=docsrc) self._parse() assert len(self._parts) == 1 self.run(verbose=0) docsrc = utils.codeblock(''' >>> # foobar >>> x = 0 >>> x / 0 >>> # bazbiz ''') self = doctest_example.DocTest(docsrc=docsrc, lineno=1) self._parse() assert len(self._parts) == 1 result = self.run(on_error='return', verbose=0) assert not result['passed'] assert self.failed_lineno() == 3
def test_multi_requires_directive(): """ Test semi-complex case with multiple requirements in a single line xdoctest ~/code/xdoctest/testing/test_directive.py test_multi_requires_directive """ string = utils.codeblock(''' >>> x = 0 >>> print('not-skipped') >>> # doctest: +REQUIRES(env:NOT_EXIST, --show, module:xdoctest) >>> print('is-skipped') >>> assert False, 'should be skipped' >>> # doctest: -REQUIRES(env:NOT_EXIST, module:xdoctest) >>> print('is-skipped') >>> assert False, 'should be skipped' >>> # doctest: +REQUIRES(env:NOT_EXIST, --show, module:xdoctest) >>> print('is-skipped') >>> assert False, 'should be skipped' >>> # doctest: -REQUIRES(env:NOT_EXIST) >>> print('is-skipped') >>> assert False, 'should be skipped' >>> # doctest: -REQUIRES(--show) >>> print('not-skipped') >>> x = 'this will not be skipped' >>> # doctest: -REQUIRES(env:NOT_EXIST, --show, module:xdoctest) >>> print('not-skipped') >>> assert x == 'this will not be skipped' ''') self = doctest_example.DocTest(docsrc=string) result = self.run(on_error='raise') stdout = ''.join(list(self.logged_stdout.values())) assert result['passed'] assert stdout.count('not-skipped') == 3 assert stdout.count('is-skipped') == 0
def test_eval_expr_capture(): """ pytest testing/test_doctest_example.py::test_eval_expr_capture -s """ docsrc = utils.codeblock(''' >>> x = 3 >>> y = x + 2 >>> y + 2 2 ''') self = doctest_example.DocTest(docsrc=docsrc) self._parse() p1, p2 = self._parts # test_globals = {} # code1 = compile(p1.source, '<string>', 'exec') # exec(code1, test_globals) # code2 = compile(p2.source, '<string>', 'eval') # result = eval(code2, test_globals) try: self.run() except Exception as ex: assert hasattr(ex, 'output_difference') msg = ex.output_difference(colored=False) assert msg == utils.codeblock(''' Expected: 2 Got: 7 ''')
def test_format_src(): """ python testing/test_doctest_example.py test_format_src pytest testing/test_doctest_example.py::test_format_src -s -v """ string = utils.codeblock( ''' >>> i = 0 >>> 0 / i 2 ''') string_with_lineno = utils.codeblock( ''' 1 >>> i = 0 2 >>> 0 / i 2 ''').replace('!', ' ') self = doctest_example.DocTest(docsrc=string) self._parse() assert self.format_src(colored=0, linenos=1) == string_with_lineno assert self.format_src(colored=0, linenos=0) == string assert utils.strip_ansi(self.format_src(colored=1, linenos=1)) == string_with_lineno assert utils.strip_ansi(self.format_src(colored=1, linenos=0)) == string
def test_block_skip_directive(): """ pytest testing/test_directive.py::test_block_skip_directive """ string = utils.codeblock(''' >>> x = 0 >>> # doctest: +SKIP >>> assert False, 'should be skipped' ''') self = doctest_example.DocTest(docsrc=string) result = self.run(on_error='raise') assert result['passed']
def test_inline_skip_directive(): """ pytest testing/test_directive.py::test_inline_skip_directive """ string = utils.codeblock(''' >>> x = 0 >>> assert False, 'should be skipped' # doctest: +SKIP >>> y = 0 ''') self = doctest_example.DocTest(docsrc=string) result = self.run(on_error='raise') # TODO: ensure that lines after the inline are run assert result['passed']
def test_failed_assign_want(): """ pytest testing/test_doctest_example.py::test_exit_test_exception """ string = utils.codeblock(''' >>> name = 'foo' 'anything' ''') self = doctest_example.DocTest(docsrc=string) result = self.run(on_error='return', verbose=0) assert result['failed'] fail_text = '\n'.join(self.repr_failure()) assert 'Got nothing' in fail_text
def test_multiline_list(): """ pytest testing/test_doctest_example.py::test_multiline_list """ string = utils.codeblock(''' >>> x = [1, 2, 3, >>> 4, 5, 6] >>> print(len(x)) 6 ''') self = doctest_example.DocTest(docsrc=string) result = self.run(on_error='raise') assert result['passed']
def test_want_error_msg(): """ python testing/test_doctest_example.py test_want_error_msg pytest testing/test_doctest_example.py::test_want_error_msg """ string = utils.codeblock(''' >>> raise Exception('everything is fine') Traceback (most recent call last): Exception: everything is fine ''') self = doctest_example.DocTest(docsrc=string) result = self.run(on_error='raise') assert result['passed']
def test_exit_test_exception(): """ pytest testing/test_doctest_example.py::test_exit_test_exception """ string = utils.codeblock(''' >>> from xdoctest import ExitTestException >>> raise ExitTestException() >>> 0 / 0 # should never reach this 2 ''') self = doctest_example.DocTest(docsrc=string) result = self.run(on_error='raise') assert result['passed']
def test_want_error_msg_failure(): """ python testing/test_doctest_example.py test_want_error_msg_failure pytest testing/test_doctest_example.py::test_want_error_msg_failure """ string = utils.codeblock(''' >>> raise Exception('everything is NOT fine') Traceback (most recent call last): Exception: everything is fine ''') self = doctest_example.DocTest(docsrc=string) import pytest with pytest.raises(checker.GotWantException): self.run(on_error='raise')
def test_contination_want_ambiguity(): """ xdoctest ~/code/xdoctest/testing/test_doctest_example.py test_contination_want_ambiguity """ string = utils.codeblock(''' >>> class Lowerer(object): ... def __init__(self): ... self.cache = LRI() ... ... def lower(self, text): ... return text.lower() ... ''') self = doctest_example.DocTest(docsrc=string) result = self.run(on_error='return', verbose=3) assert result['passed']
def test_failure(): string = utils.codeblock(''' >>> i = 0 >>> 0 / i 2 ''') self = doctest_example.DocTest(docsrc=string, lineno=1000) self._parse() try: self.run(on_error='raise') except ZeroDivisionError as ex: pass else: raise AssertionError('should have gotten zero division') result = self.run(on_error='return') assert not result['passed']
def parse_google_docstr_examples(docstr, callname=None, modpath=None, lineno=1, fpath=None, eager_parse=True): """ Parses Google-style doctests from a docstr and generates example objects Args: lineno (int): the line number (starting from 1) of the docstring. (i.e. if you were to go to this line number in the source file the starting quotes of the docstr would be on this line). Raises: .exceptions.MalformedDocstr: if an error occurs in finding google blocks .exceptions.DoctestParseError: if an error occurs in parsing """ blocks = docscrape_google.split_google_docblocks(docstr) example_blocks = [] for type, block in blocks: if type.startswith('Example'): example_blocks.append((type, block)) if type.startswith('Doctest'): example_blocks.append((type, block)) if type.startswith('Script'): example_blocks.append((type, block)) if type.startswith('Benchmark'): example_blocks.append((type, block)) for num, (type, (docsrc, offset)) in enumerate(example_blocks): # Add one because offset indicates the position of the block-label # and the body of the block always starts on the next line. label_lineno = lineno + offset body_lineno = label_lineno + 1 example = doctest_example.DocTest(docsrc, modpath, callname, num, lineno=body_lineno, fpath=fpath, block_type=type) if eager_parse: # parse on the fly to be consistent with freeform? example._parse() yield example
def _gather_zero_arg_examples(modpath): """ Find functions in `modpath` args with no args (so we can automatically make a dummy docstring). """ for calldefs, _modpath in core.package_calldefs(modpath): for callname, calldef in calldefs.items(): if calldef.args is not None: # The only existing args should have defaults n_args = len(calldef.args.args) - len(calldef.args.defaults) if n_args == 0: # Create a dummy doctest example for a zero-arg function docsrc = '>>> {}()'.format(callname) example = doctest_example.DocTest(docsrc=docsrc, modpath=_modpath, callname=callname, block_type='zero-arg') example.mode = 'native' yield example
def test_run_multi_want(): docsrc = utils.codeblock( ''' >>> x = 2 >>> x 2 >>> 'string' 'string' >>> print('string') string ''') self = doctest_example.DocTest(docsrc=docsrc) self.run() result = self.run() assert result['passed'] assert list(self.logged_stdout.values()) == ['', '', '', 'string\n'] assert list(self.logged_evals.values()) == [constants.NOT_EVALED, 2, 'string', None]
def doctest_from_parts(parts, num, curr_offset): # FIXME: this will cause line numbers to become misaligned nested = [ p.orig_lines if p.want is None else p.orig_lines + p.want.splitlines() for p in parts ] docsrc = '\n'.join(list(it.chain.from_iterable(nested))) docsrc = textwrap.dedent(docsrc) example = doctest_example.DocTest(docsrc, modpath=modpath, callname=callname, num=num, lineno=lineno + curr_offset, fpath=fpath) # rebase the offsets relative to the test lineno (ie start at 0) unoffset = parts[0].line_offset for p in parts: p.line_offset -= unoffset # We've already parsed the parts, so we dont need to do it again example._parts = parts return example
def parse_google_docstr_examples(docstr, callname=None, modpath=None, lineno=1, fpath=None, eager_parse=True): """ Parses Google-style doctests from a docstr and generates example objects Args: docstr (str): an extracted docstring callname (str, default=None): the name of the callable (e.g. function, class, or method) that this docstring belongs to. modpath (str | PathLike, default=None): original module the docstring is from lineno (int, default=1): the line number (starting from 1) of the docstring. i.e. if you were to go to this line number in the source file the starting quotes of the docstr would be on this line. fpath (str | PathLike, default=None): the file that the docstring is from (if the file was not a module, needed for backwards compatibility) eager_parse (bool, default=True): if True eagerly evaluate the parser inside the google example blocks Yields: xdoctest.doctest_example.DocTest : doctest object Raises: xdoctest.exceptions.MalformedDocstr: if an error occurs in finding google blocks xdoctest.exceptions.DoctestParseError: if an error occurs in parsing """ try: blocks = docscrape_google.split_google_docblocks(docstr) except exceptions.MalformedDocstr: print('ERROR PARSING {} GOOGLE BLOCKS IN {} ON line {}'.format( callname, modpath, lineno)) print('Did you forget to make a docstr with newlines raw?') raise example_blocks = [] example_tags = ('Example', 'Doctest', 'Script', 'Benchmark') for type, block in blocks: if type.startswith(example_tags): example_blocks.append((type, block)) for num, (type, (docsrc, offset)) in enumerate(example_blocks): # Add one because offset indicates the position of the block-label # and the body of the block always starts on the next line. label_lineno = lineno + offset body_lineno = label_lineno + 1 example = doctest_example.DocTest(docsrc, modpath, callname, num, lineno=body_lineno, fpath=fpath, block_type=type) if eager_parse: # parse on the fly to be consistent with freeform? example._parse() yield example