def test_in_decorator(capsys): seq = [_exception_in_decorator] try: with catcher.handler(): spy.chain(seq).run_to_exhaustion([None]) except catcher.CaughtException as e: e.print_traceback() out, err = capsys.readouterr() assert any(s.startswith(' Fragment 1, in decorator spy.decorators.callable') for s in err.splitlines())
def test_forced_exception(capsys): seq = [_forced_error] try: with catcher.handler(): spy.chain(seq).run_to_exhaustion([None]) except catcher.CaughtException as e: e.print_traceback() out, err = capsys.readouterr() err = err.strip().split('\n') # in other words, not the internal error assert 'input to fragment' in err[-2]
def test_forced_exception(capsys): seq = [_forced_error] try: with catcher.handler(): spy.chain(seq).run_to_exhaustion([None]) except catcher.CaughtException as e: e.print_traceback() out, err = capsys.readouterr() err = err.strip().split('\n') # in other words, not the internal error assert 'input to fragment' in err[-2] assert err[-1].startswith('AttributeError:')
def test_multiple_collect(): @spy.fragment def collect_twice(v, context): return [*islice(spy.collect(context), 2), *spy.collect(context)] chain = spy.chain([collect_twice]) assert next(chain.apply([0, 1, 2, 3, 4, 5])) == [0, 1, 2, 3, 4, 5] @spy.fragment def collect_nothing_then_something(v, context): return [*islice(spy.collect(context), 0), *spy.collect(context)] chain = spy.chain([collect_nothing_then_something]) assert next(chain.apply([0, 1, 2, 3, 4, 5])) == [0, 1, 2, 3, 4, 5]
def test_focus(): @spy.fragment @decorators.focus(1) def test(v): return v * 3 l = list(spy.chain([test]).apply([[1,2,3], [4,5,6]])) assert l == [[1,6,3], [4,15,6]]
def test_chain(): seq = [noop, upper, noop, reverse, noop] chain = spy.chain(seq) assert list(chain.apply(['FOO', 'BAR'])) == ['OOF', 'RAB'] output = [] @spy.fragment def capture(v): output.append(v) seq.append(capture) chain = spy.chain(seq) chain.run_to_exhaustion(['FOO', 'BAR']) assert output == ['OOF', 'RAB']
def test_accumulate(capsys): calls = 0 @spy.fragment @decorators.accumulate def test(v): nonlocal calls calls += 1 return v try: spy.chain([test]).run_to_exhaustion(['x']) except KeyboardInterrupt: assert capsys.readouterr() == '' assert calls == 1
def test_chain(): seq = [noop, upper, noop, reverse, noop] chain = spy.chain(seq) assert list(chain.apply(["FOO", "BAR"])) == ["OOF", "RAB"] output = [] @spy.fragment def capture(v): output.append(v) seq.append(capture) chain = spy.chain(seq) chain.run_to_exhaustion(["FOO", "BAR"]) assert output == ["OOF", "RAB"]
def test_try_except(): # make sure the testcase is correct @spy.fragment def test(v): return v[1] with pytest.raises(IndexError): list(spy.chain([test]).apply(["a", "bc", "de"])) @spy.fragment @decorators.try_except def test(v): return v[1] l = list(spy.chain([test]).apply(["a", "bc", "de"])) assert l == ["c", "e"]
def test_magnify_lens(): @spy.fragment @decorators.magnify(lenses.lens[2]) def test(v): return v * 3 l = list(spy.chain([test]).apply([[1,2,3], [4,5,6]])) assert l == [9, 18]
def test_magnify(): @spy.fragment @decorators.magnify(1) def test(v): return v * 3 l = list(spy.chain([test]).apply([[1,2,3], [4,5,6]])) assert l == [6, 15]
def test_focus_lens(): @spy.fragment @decorators.focus(lenses.lens[1::2].Each()) def test(v): return v * 3 l = list(spy.chain([test]).apply([[1,2,3,4,5,6]])) assert l == [[1,6,3,12,5,18]]
def test_many(): @spy.fragment @decorators.many def test(v): return [1, 2, 3, 4, 5] l = spy.chain([test]).apply([None]) assert list(l) == [1, 2, 3, 4, 5]
def test_format(): @spy.fragment @decorators.format def test(v): return {'test': 1}, '{test}23' l = spy.chain([test]).apply([None]) assert list(l) == ['123']
def test_format(): seq = [noop, upper, "spaghetti"] chain = spy.chain(seq, index_offset=-1) lines = chain.format().splitlines() assert lines[0].strip().startswith("|") assert "test_core.noop" in lines[0] assert lines[1].strip().startswith("1 |") assert "test_core.upper" in lines[1] assert "UNKNOWN" in lines[2]
def test_format(): seq = [noop, upper, 'spaghetti'] chain = spy.chain(seq, index_offset=-1) lines = chain.format().splitlines() assert lines[0].strip().startswith('|') assert 'test_core.noop' in lines[0] assert lines[1].strip().startswith('1 |') assert 'test_core.upper' in lines[1] assert 'UNKNOWN' in lines[2]
def test_regex(): @spy.fragment @decorators.regex def test(v): return {}, '1(2)3' l = list(spy.chain([test]).apply(['123'])) assert len(l) == 1 assert l[0].group(1) == '2'
def test_keywords(): # keywords only works with base functions that have _spy_setenv, so pure # python API won't work with pytest.raises(ValueError): @spy.fragment @decorators.keywords def test(v): pass def build(): env = {} def test(v): return env['a'] def setenv(env_): nonlocal env env = env_ test._spy_setenv = setenv return test test = spy.fragment(decorators.keywords(build())) l = list(spy.chain([test]).apply([{'a': 'xyz'}])) assert l[0] == 'xyz'
def test_many(): seq = [many, upper] chain = spy.chain(seq) assert list(chain.apply(["foo", "bar"])) == list("FOOBAR")
def test_index_offset(): with pytest.raises(TypeError): c = spy.chain([noop], "fubar")
def _main( *steps: (use_mixin(StepList), Parameter.REQUIRED), each_line: 'l' = False, # noqa: F821 raw: 'r' = False, # noqa: F821 start: (int, 's') = 0, # noqa: F821 end: (int, 'e') = None, # noqa: F821 prelude: (multi(), 'p') = 'pass', # noqa: F821 pipe_name: Parameter.UNDOCUMENTED = PIPE_NAME, no_default_fragments: Parameter.UNDOCUMENTED = False, no_exception_handling: Parameter.UNDOCUMENTED = False, show_fragments: Parameter.UNDOCUMENTED = False, break_: Parameter.UNDOCUMENTED = False): """Feed data through a sequence of Python expressions. :param steps: At least one Python expression (or suite) to execute :param each_line: Process lines as strings rather than all of stdin as a file :param start: Don't print before this result (zero-based) :param end: Stop after getting this result (zero-based) :param prelude: Execute a statement before running any steps. Can be specified more than once. :param raw: Don't add helper functionality to stdin """ pipe_name = sys.intern(pipe_name) spy.context = context = make_context() for stmt in prelude: exec(stmt, context, context.view()) step_src = steps steps = [] for i, code in enumerate(step_src): fragment_name = 'Fragment {}'.format(i + 1) source = code literal = False if isinstance(code, _Decorated): source = '{} {!r}'.format(code.name, code.value) literal = code.LITERAL code, funcseq = code.value, code.funcseq else: funcseq = () debuginfo = (fragment_name, source) if literal: ca = make_literal(code, context, pipe_name, debuginfo) else: try: co, is_expr = compile_(code, filename=fragment_name) except SyntaxError as e: pretty_syntax_error(code, e) if break_: # pragma: no cover debugger() sys.exit(1) ca = make_callable(co, is_expr, context, pipe_name, debuginfo) for fn in funcseq: ca = fn(ca) steps.append(spy.fragment(ca)) index_offset = 0 if not no_default_fragments: steps.append(fragments.make_limit(start=start, end=end)) steps.append(fragments.print) if each_line: steps.insert(0, fragments.foreach) index_offset -= 1 chain = spy.chain(steps, index_offset=index_offset) if raw: data = [sys.stdin] else: data = [SpyFile(sys.stdin)] if show_fragments: print(chain.format()) return with ExitStack() as stack: if not no_exception_handling: stack.enter_context(catcher.handler(delete_all=True)) if break_: # pragma: no cover stack.enter_context(DebuggerContext()) chain.run_to_exhaustion(data)
def _main(*steps, each_line: 'l' = False, start: (int, 's') = 0, end: (int, 'e') = None, pipe_name: Parameter.UNDOCUMENTED = PIPE_NAME, no_default_fragments: Parameter.UNDOCUMENTED = False, no_exception_handling: Parameter.UNDOCUMENTED = False, show_fragments: Parameter.UNDOCUMENTED = False): """Run Python code. steps: At least one Python expression (or suite) to execute each_line: If specified, process lines as strings rather than all of stdin as a file start: Don't print before this result (zero-based) end: Stop after getting this result (zero-based) """ sys.setcheckinterval(10000) pipe_name = sys.intern(pipe_name) spy.context = context = make_context() step_src = steps steps = [] for i, code in enumerate(step_src): fragment_name = 'Fragment {}'.format(i + 1) source = code if isinstance(code, _Decorated): source = '{} {!r}'.format(code.name, code.value) code, funcseq = code.value, code.funcseq else: funcseq = () co, is_expr = compile_(code, filename=fragment_name) debuginfo = (fragment_name, source) ca = make_callable(co, is_expr, context, pipe_name, debuginfo) for fn in funcseq: try: ca = fn(ca, debuginfo=debuginfo) except TypeError: ca = fn(ca) steps.append(spy.fragment(ca)) index_offset = 0 if not no_default_fragments: steps.append(fragments.make_limit(start=start, end=end)) steps.append(fragments.print) if each_line: steps.insert(0, fragments.many) index_offset -= 1 chain = spy.chain(steps, index_offset=index_offset) data = [SpyFile(sys.stdin)] if show_fragments: print(chain.format()) return if no_exception_handling: context = NullContext() else: context = catcher.handler(delete_all=True) with context: chain.run_to_exhaustion(data)
def test_drop(): seq = [drop_foo] chain = spy.chain(seq) for item in chain.apply(["foo", "bar", "foo", "test"]): assert item.lower() != "foo"
def test_collect(): seq = [collect] chain = spy.chain(seq) assert list(next(chain.apply(["foo", "bar"]))) == ["foo", "bar"]
def test_many(): seq = [many, upper] chain = spy.chain(seq) assert list(chain.apply(['foo', 'bar'])) == list('FOOBAR')
def test_index_offset(): with pytest.raises(TypeError): c = spy.chain([noop], 'fubar')
def test_drop(): seq = [drop_foo] chain = spy.chain(seq) for item in chain.apply(['foo', 'bar', 'foo', 'test']): assert item.lower() != 'foo'
def _use_decorator(d): @spy.fragment @d def fragment(x): return x * 7 return list(spy.chain([fragment]).apply([1, 2, 3, 4, 5, 6]))
def test_collect(): seq = [collect] chain = spy.chain(seq) assert list(next(chain.apply(['foo', 'bar']))) == ['foo', 'bar']
def _main(*steps: use_mixin(StepList), each_line: 'l' = False, # noqa: F821 raw: 'r' = False, # noqa: F821 start: (int, 's') = 0, end: (int, 'e') = None, prelude: (multi(), 'p') = 'pass', pipe_name: Parameter.UNDOCUMENTED = PIPE_NAME, no_default_fragments: Parameter.UNDOCUMENTED = False, no_exception_handling: Parameter.UNDOCUMENTED = False, show_fragments: Parameter.UNDOCUMENTED = False, break_: Parameter.UNDOCUMENTED = False): """Run Python code. :param steps: At least one Python expression (or suite) to execute :param each_line: If specified, process lines as strings rather than all of stdin as a file :param start: Don't print before this result (zero-based) :param end: Stop after getting this result (zero-based) :param prelude: Execute this statement before running any steps. Can be specified more than once. :param raw: Don't add helper functionality to stdin """ pipe_name = sys.intern(pipe_name) spy.context = context = make_context() for stmt in prelude: exec(stmt, context, context.view()) step_src = steps steps = [] for i, code in enumerate(step_src): fragment_name = 'Fragment {}'.format(i + 1) source = code if isinstance(code, _Decorated): source = '{} {!r}'.format(code.name, code.value) code, funcseq = code.value, code.funcseq else: funcseq = () try: co, is_expr = compile_(code, filename=fragment_name) except SyntaxError as e: pretty_syntax_error(code, e) if break_: # pragma: no cover debugger() sys.exit(1) debuginfo = (fragment_name, source) ca = make_callable(co, is_expr, context, pipe_name, debuginfo) for fn in funcseq: try: ca = fn(ca, debuginfo=debuginfo) except TypeError: ca = fn(ca) steps.append(spy.fragment(ca)) index_offset = 0 if not no_default_fragments: steps.append(fragments.make_limit(start=start, end=end)) steps.append(fragments.print) if each_line: steps.insert(0, fragments.foreach) index_offset -= 1 if raw: steps.insert(0, fragments.raw_stdin) else: steps.insert(0, fragments.stdin) index_offset -= 1 chain = spy.chain(steps, index_offset=index_offset) data = [None] if show_fragments: print(chain.format()) return with ExitStack() as stack: if not no_exception_handling: stack.enter_context(catcher.handler(delete_all=True)) if break_: # pragma: no cover stack.enter_context(DebuggerContext()) chain.run_to_exhaustion(data)