def test_assigning_to_any_special_variable_is_disallowed(self): for var in ('p', 'ff', 'files'): with self.assertRaises(AssertionError) as cm: print("testing var " + var) run(var + ' = 1', [0]) self.assertEqual(cm.exception.message, "can't assign to `%s` (expression: %s)" % (var,var + ' = 1'))
def test_sortby_error_checking(self): self.assertRaises(AssertionError, lambda: run('pp.sortby(len, key=0)', [])) self.assertRaises(AssertionError, lambda: run('pp.sortby(len, attr=0)', [])) self.assertRaises(AssertionError, lambda: run('pp.sortby(len, method=0)', []))
def test_lists_are_not_downgraded_to_streams(self): self.assertEqual( run('pp[0], pp[0]', ['1','2']), ['1','2']) self.assertEqual( run('list(pp) | pp[0], pp[0]', ['1','2']), ['1','1'])
def test_sort(self): self.assertEqual( run('pp.sort()', [3,2,1,1]), ['1', '1','2','3']) self.assertEqual( run('pp.sort(uniq=True)', [3,2,1,1]), ['1','2','3'])
def test_assigning_to_any_special_variable_is_disallowed(self): for var in ('i', 'ff', 'files'): with self.assertRaises(AssertionError) as cm: print("testing var " + var) run(var + ' = 1', [0]) self.assertEqual( cm.exception.message, "can't assign to `%s` (expression: %s)" % (var, var + ' = 1'))
def test_file_usage_causes_file_wise_mode(self): with tempfile.NamedTemporaryFile() as f: f.write('a\nb\nc\n') f.seek(0) self.assertEqual( run('--file=' + f.name, 'len(ff)', [1, 2, 3, 4, 5, 6]), ['3']) with tempfile.NamedTemporaryFile() as f2: f2.write('a\nb\nc\nd\n') f2.seek(0) self.assertEqual( run('--file=' + f.name, '--file=' + f2.name, 'map(len, files)', [1, 2, 3, 4, 5, 6]), ['3', '4'])
def test_modules_are_not_importable_from_cwd_by_default(self): # for the same reason $PATH does not include # "." - it could be an attack vector with temp_cwd(): with open("mymod.py", 'w') as f: f.write("def up(s): return s.upper()") self.assertRaises(ImportError, lambda: run('-m', 'mymod', 'mymod.up(p)', ['a']))
def test_complex_parsing(self): self.assertEqual( run('("%s) %s || %s" % ((i + 1) | 0x00, p, p.upper())) | p', ['a', 'b', 'c']), [ '1) a || A', '2) b || B', '3) c || C', ])
def test_a_pair_of_files(self): with tempfile.NamedTemporaryFile() as f: f.write('a\nb\nc\n') f.seek(0) self.assertEqual( run('--join=-', '--file=' + f.name, 'pp.zip(files[0]) | p[0] or "", p[1].upper()', ['1']), ['1-A', '-B', '-C'])
def test_a_pair_of_files(self): with tempfile.NamedTemporaryFile() as f: f.write('a\nb\nc\n') f.seek(0) self.assertEqual( run('--join=-', '--file=' + f.name, 'pp.zip(files[0]) | p[0] or "", p[1].upper()', ['1']), ['1-A','-B','-C'])
def test_file_alias_when_one_file_used(self): with tempfile.NamedTemporaryFile() as f: f.write('a\nb\nc\n') f.seek(0) self.assertEqual( run('--join=-', '--file=' + f.name, 'pp.zip(ff) | p[0] or "", p[1].upper()', ['1']), ['1-A','-B','-C'])
def test_zip_shortest(self): with tempfile.NamedTemporaryFile() as f: f.write('a\nb\nc\n') f.seek(0) self.assertEqual( run('--join=-', '--file=' + f.name, 'pp.zip_shortest(files[0]) | p[0], p[1].upper()', ['1']), ['1-A'])
def test_file_alias_when_one_file_used(self): with tempfile.NamedTemporaryFile() as f: f.write('a\nb\nc\n') f.seek(0) self.assertEqual( run('--join=-', '--file=' + f.name, 'pp.zip(ff) | p[0] or "", p[1].upper()', ['1']), ['1-A', '-B', '-C'])
def test_file_usage_causes_file_wise_mode(self): with tempfile.NamedTemporaryFile() as f: f.write('a\nb\nc\n') f.seek(0) self.assertEqual( run( '--file=' + f.name, 'len(ff)', [1,2,3,4,5,6]), ['3']) with tempfile.NamedTemporaryFile() as f2: f2.write('a\nb\nc\nd\n') f2.seek(0) self.assertEqual( run( '--file=' + f.name, '--file=' + f2.name, 'map(len, files)', [1,2,3,4,5,6]), ['3', '4'])
def test_shell_coercion_to_string(self): self.assertEqual(run('sh("echo", p) | "oo" in p', ['foo', 'bar', 'boo']), ['foo', 'boo']) self.assertEqual(run('sh("echo", p) | p > "doo"', ['foo', 'bar', 'boo']), ['foo']) self.assertEqual(run('sh("echo", p) | p[1] == "o"', ['foo', 'bar', 'boo']), ['foo', 'boo']) self.assertEqual(run('sh("echo", p) | p + "o"', ['foo', 'bar', 'boo']), ['fooo', 'baro', 'booo']) self.assertEqual(run('sh("echo", "%s", p) | p % "1"', ['foo', 'bar', 'boo']), ['1 foo', '1 bar', '1 boo']) self.assertEqual(run('sh("echo", p) | p * 2', ['foo', 'bar', 'boo']), ['foofoo', 'barbar', 'booboo'])
def test_regex_functions(self): self.assertEqual(run('p.splitre(" +")' , ['a b c']) , ['a b c']) self.assertEqual(run('p.match("b..")' , ['a beef c']) , ['bee']) self.assertEqual(run('p.match("b(..)",1)' , ['a beef c']) , ['ee']) self.assertEqual(run('p.match("b(?P<m>..)?","m")' , ['a beef c']) , ['ee']) self.assertEqual(run('p.match("b(?P<m>..)?","m")' , ['a b']) , []) self.assertEqual(run('p.matches("b..")' , ['a bee c', 'nope']) , ['a bee c'])
def test_chunk_returns_enhanced_list(self): self.assertEqual( run('pp.divide(lambda l: "---" in l, keep_header=False) | p.len()', [ 'leading', '----', 'chunk 1 line 1', 'chunk 1 line 2', '----', 'chunk 2 line 1', 'chunk 2 line 2', '---', ]), ['1', '2', '2'])
def test_chunk_on_predicate(self): self.assertEqual( run('pp.divide(lambda l: "---" in l) | ".".join(p)', [ 'leading', '----', 'chunk 1 line 1', 'chunk 1 line 2', '----', 'chunk 2 line 1', 'chunk 2 line 2', '---', ]), [ 'leading', '----.chunk 1 line 1.chunk 1 line 2', '----.chunk 2 line 1.chunk 2 line 2', '---' ])
def test_chunk_on_predicate(self): self.assertEqual( run('pp.divide(lambda l: "---" in l) | ".".join(p)', [ 'leading', '----', 'chunk 1 line 1', 'chunk 1 line 2', '----', 'chunk 2 line 1', 'chunk 2 line 2', '---', ]), ['leading', '----.chunk 1 line 1.chunk 1 line 2', '----.chunk 2 line 1.chunk 2 line 2', '---'] )
def test_shell_coercion_to_string(self): self.assertEqual( run('sh("echo", p) | "oo" in p', ['foo', 'bar', 'boo']), ['foo', 'boo']) self.assertEqual( run('sh("echo", p) | p > "doo"', ['foo', 'bar', 'boo']), ['foo']) self.assertEqual( run('sh("echo", p) | p[1] == "o"', ['foo', 'bar', 'boo']), ['foo', 'boo']) self.assertEqual(run('sh("echo", p) | p + "o"', ['foo', 'bar', 'boo']), ['fooo', 'baro', 'booo']) self.assertEqual( run('sh("echo", "%s", p) | p % "1"', ['foo', 'bar', 'boo']), ['1 foo', '1 bar', '1 boo']) self.assertEqual(run('sh("echo", p) | p * 2', ['foo', 'bar', 'boo']), ['foofoo', 'barbar', 'booboo'])
def test_reversed(self): self.assertEqual( run('pp.reverse()', ['1', '2']), ['2','1'])
def test_len(self): self.assertEqual(run('len(pp)', [1, 2, 3]), ['3'])
def test_int(self): self.assertEqual( run('pp.len()', ['1','2','3']), ['3'])
def test_multi_head_and_tail(self): self.assertEqual( run('pp[:5] | "hello", p | pp[-2:]', [1, 2, 3, 4, 5, 6, 7, 8, 9. ,10]), ['hello 4', 'hello 5'])
def test_simple_shell_commands(self): self.assertEqual( run('sh(*shellsplit(p))', ['echo "1 2 3"', 'echo 1 2 3']), ['1 2 3', '1 2 3'])
def test_shell_in_pipes(self): self.assertEqual(run('sh("echo", p) | "%s) %s" % (i, p)', ['a']), ['0) a'])
def test_shell_attributes_that_dont_exist_cause_coercion_to_str(self): self.assertEqual(run('sh("echo", p).upper()', ['a']), ['A'])
def test_str(self): self.assertEqual( run('str(pp)', ['a','b','c']), ['a\nb\nc'])
def test_shell_combination(self): self.assertEqual(run('sh("false") or sh("echo", "true")', ['1']), ['true'])
def test_suppress_failures_explicitly(self): self.assertEqual(run('sh("false", check=False) | "ok"', ['a']), ['ok'])
def test_sortby_key(self): self.assertEqual( run('p.split() | pp.sortby(key=0) | p[1]', ["0 zero", "3 three", "2 two"]), ["zero", "two", "three"])
def test_sortby(self): self.assertEqual( run('p.split() | pp.sortby(lambda x: x[0]) | p[1]', ["0 zero", "3 three", "2 two", "0 zero"]), ["zero", "zero", "two", "three"])
def test_spawn(self): self.assertEqual(run('spawn("echo", "hello")', ['a']), ['a'])
def test_shadowing_a_special_variable_is_ok(self): self.assertEqual(run('pp.map(lambda p: 1)', [0]), ['1'])
def test_shell_boolean_is_respected(self): self.assertEqual(run('sh("true") and "ok"', ['1']), ['ok'])
def test_shell_failures_are_suppressed(self): self.assertEqual(run('sh("false") or "failed"', ['1']), ['failed'])
def test_head_works_lazily(self): self.assertEqual( run('pp[:4]', itertools.cycle('abc')), ['a','b','c', 'a'])
def test_spawn_failures_are_tracked(self): self.assertRaises(subprocess.CalledProcessError, lambda: run('spawn("false")', ['1']))
def test_strings_are_split_on_lines(self): self.assertEqual( run('pp[0].split().join("\\n") | p', ['1 2 3']), ['1','2','3'])
def test_modules_can_be_imported_from_cwd(self): with temp_cwd(): with open("mymod.py", 'w') as f: f.write("def up(s): return s.upper()") self.assertEqual( run('-p', '.', '-m', 'mymod', 'mymod.up(p)', ['a']), ['A'])
def test_shell_short_circuiting(self): self.assertEqual(run('sh("echo", p) or str(sh("false"))', ['1']), ['1'])
def test_assigning_naked_functions(self): self.assertEqual(run('p=repr', ['abc']), [str(repr)])
def test_shell_failures_are_not_suppressed_when_explicitly_checked(self): self.assertRaises( subprocess.CalledProcessError, lambda: run('sh("false", check=True) or "ok"', ['1']))
def test_non_list_objects_are_left_to_their_own_devices_which_may_or_may_not_succeed(self): self.assertEqual( run('int(pp[0]) | pp + 1', ['1', '2', '3']), ['2']) self.assertRaises((TypeError, AttributeError), lambda: run('int(pp[0]) | p + 1', ['1', '2', '3']))
def test_reprocess_multi_line_elements(self): self.assertEqual( run('p + "\\n" + p | pp.flatten()', ['a','b','c']), ['a','a','b','b','c','c'])
def test_single_string(self): self.assertEqual( run('pp.join(".")', ['1','2','3']), ['1.2.3'])
def test_reprocess_sequence_elements(self): self.assertEqual( run('[p,p] | pp.merge()', ['a','b','c']), ['a','a','b','b','c','c'])
def test_merge(self): self.assertEqual( run('p.split(".") | pp.merge() | p + "!"', ['1.2.3', '4.5.6']), ['1!', '2!', '3!', '4!', '5!', '6!'])
def test_shell_failures_are_not_suppressed_with_and(self): self.skipTest("not implementable?") self.assertRaises(subprocess.CalledProcessError, lambda: run('sh("false") and "ok"', ['1']))
def test_concat(self): self.assertEqual(run('sh("echo", p) + p', ['a']), ['aa'])
def test_explicitly_setting_pp_is_ok(self): self.assertEqual(run('pp = [1,2,3] | p', [1]), ['1','2','3'])
def test_head(self): self.assertEqual( run('pp[:2]', ['a','b','c', 'd']), ['a','b'])
def test_shell_failure_in_pipes(self): self.assertRaises( subprocess.CalledProcessError, lambda: run('sh("false") | "%s) %s" % (i, p)', ['a']))
def test_sortby_attr(self): self.assertEqual( run('int(p) | pp.sortby(attr="real")', [3,2,1,1]), ['1','1','2','3'])
def test_shell_failure_when_result_is_not_used(self): self.assertRaises(subprocess.CalledProcessError, lambda: run('sh("false") | "ok"', ['a']))