def test_print_stmt__simple_prints(c_exec): glb = {'_print_': PrintCollector, '_getattr_': None} code, errors = c_exec(ALLOWED_PRINT_STATEMENT)[:2] assert code is not None assert errors == () exec(code, glb) assert glb['_print']() == 'Hello World!\n' code, errors = c_exec(ALLOWED_PRINT_STATEMENT_WITH_NO_NL)[:2] assert code is not None assert errors == () exec(code, glb) assert glb['_print']() == 'Hello World!' code, errors = c_exec(ALLOWED_MULTI_PRINT_STATEMENT)[:2] assert code is not None assert errors == () exec(code, glb) assert glb['_print']() == 'Hello World! Hello Earth!\n' code, errors = c_exec(ALLOWED_PRINT_TUPLE)[:2] assert code is not None assert errors == () exec(code, glb) assert glb['_print']() == "Hello World!\n" code, errors = c_exec(ALLOWED_PRINT_MULTI_TUPLE)[:2] assert code is not None assert errors == () exec(code, glb) assert glb['_print']() == "('Hello World!', 'Hello Earth!')\n"
def test_RestrictingNodeTransformer__visit_Import_star__1(c_exec): """Importing `*` is a SyntaxError in Python itself.""" result = c_exec('import *') assert result.errors == ( 'Line 1: SyntaxError: invalid syntax in on statement: import *', ) # NOQA: E501 assert result.code is None
def test_call_py2_builtins(c_exec): """It should not be allowed to access global __builtins__ in Python2.""" result = c_exec('__builtins__["getattr"]') assert result.code is None assert result.errors == ( 'Line 1: "__builtins__" is an invalid variable name because it starts with "_"', ) # NOQA: E501
def test_RestrictingNodeTransformer__visit_FunctionDef__6(c_exec): """It prevents function arguments starting with `_` in tuples.""" result = c_exec("def foo(a, (c, (_bad, c))): pass") # RestrictedPython.compile.compile_restricted_exec on Python 2 renders # the error message twice. This is necessary as otherwise *_bad and # **_bad would be allowed. assert functiondef_err_msg in result.errors
def test_RestrictingNodeTransformer__visit_Lambda__2(c_exec): """It prevents keyword arguments starting with `_`.""" result = c_exec("lambda _bad=1: None") # RestrictedPython.compile.compile_restricted_exec on Python 2 renders # the error message twice. This is necessary as otherwise *_bad and **_bad # would be allowed. assert lambda_err_msg in result.errors
def test_with_stmt_multi_ctx_unpack_sequence(c_exec, mocker): result = c_exec(WITH_STMT_MULTI_CTX_WITH_UNPACK_SEQUENCE) assert result.errors == () @contextlib.contextmanager def ctx1(): yield (1, (2, 3)) @contextlib.contextmanager def ctx2(): yield (4, 5), (6, 7) _getiter_ = mocker.stub() _getiter_.side_effect = lambda ob: ob glb = { '_getiter_': _getiter_, '_unpack_sequence_': guarded_unpack_sequence } exec(result.code, glb) ret = glb['call'](ctx1, ctx2) assert ret == (1, 2, 3, 4, 5, 6, 7) _getiter_.assert_has_calls([ mocker.call((1, (2, 3))), mocker.call((2, 3)), mocker.call(((4, 5), (6, 7))), mocker.call((4, 5)), mocker.call((6, 7)) ])
def test_RestrictingNodeTransformer__visit_Lambda__6(c_exec): """It prevents arguments starting with `_` in nested tuple unpacking.""" result = c_exec("lambda (a, (c, (_bad, c))): None") # RestrictedPython.compile.compile_restricted_exec on Python 2 renders # the error message twice. This is necessary as otherwise *_bad and # **_bad would be allowed. assert lambda_err_msg in result.errors
def test_print_stmt_conditional_print(c_exec): code, errors = c_exec(CONDITIONAL_PRINT)[:2] glb = {'_print_': PrintCollector, '_getattr_': None} exec(code, glb) assert glb['func'](True) == '1\n' assert glb['func'](False) == ''
def test_print_stmt_no_new_scope(c_exec): code, errors = c_exec(NO_PRINT_SCOPES)[:2] glb = {'_print_': PrintCollector, '_getattr_': None} exec(code, glb) ret = glb['class_scope']() assert ret == 'a\n'
def test_call_breakpoint(c_exec): """The Python3.7+ builtin function breakpoint should not be used and is forbidden in RestrictedPython. """ result = c_exec('breakpoint()') assert result.errors == ('Line 1: "breakpoint" is a reserved name.', ) assert result.code is None
def test_compile__compile_restricted_exec__4(c_exec): """It does not return code on a SyntaxError.""" result = c_exec('asdf|') assert result.code is None assert result.warnings == [] assert result.used_names == {} assert result.errors == ( 'Line 1: SyntaxError: invalid syntax in on statement: asdf|', )
def test_print_stmt__nested_print_collector(c_exec, mocker): code, errors = c_exec(INJECT_PRINT_COLLECTOR_NESTED)[:2] glb = {"_print_": PrintCollector, '_getattr_': None} exec(code, glb) ret = glb['main']() assert ret == 'inner\nf1\nf2main\n'
def test_import_py2_as_builtins(c_exec): """It should not be allowed to access global __builtins__ in Python2.""" result = c_exec(__BUILTINS_EXAMPLE) assert result.code is None assert result.errors == ( 'Line 2: "__builtins__" is an invalid variable name because it starts with "_"', # NOQA: E501 'Line 4: "__builtins__" is an invalid variable name because it starts with "_"' # NOQA: E501 )
def test_RestrictingNodeTransformer__visit_Call__1(c_exec): """It compiles a function call successfully and returns the used name.""" result = c_exec('a = max([1, 2, 3])') assert result.errors == () loc = {} exec(result.code, {}, loc) assert loc['a'] == 3 assert result.used_names == {'max': True}
def test_iterate_over_dict_items_plain(c_exec): glb = {} result = c_exec(ITERATE_OVER_DICT_ITEMS) assert result.code is not None assert result.errors == () with pytest.raises(NameError) as excinfo: exec(result.code, glb, None) assert "name '_iter_unpack_sequence_' is not defined" in str(excinfo.value)
def test_iterate_over_dict_items_safe(c_exec): glb = safe_globals.copy() glb['_getiter_'] = default_guarded_getiter glb['_iter_unpack_sequence_'] = guarded_iter_unpack_sequence result = c_exec(ITERATE_OVER_DICT_ITEMS) assert result.code is not None assert result.errors == () exec(result.code, glb, None)
def test_RestrictingNodeTransformer__visit_ClassDef__4(c_exec): """It does not allow to pass a metaclass to class definitions.""" result = c_exec(EXPLICIT_METACLASS) assert result.errors == ( 'Line 2: The keyword argument "metaclass" is not allowed.', ) assert result.code is None
def test_compile__compile_restricted_exec__2(c_exec): """It compiles without restrictions if there is no policy.""" result = c_exec('_a = 42', policy=None) assert result.errors == () assert result.warnings == [] assert result.used_names == {} glob = {} exec(result.code, glob) assert glob['_a'] == 42
def test_print_stmt__with_print_no_printed(c_exec): code, errors, warnings = c_exec(WARN_PRINT_NO_PRINTED)[:3] assert code is not None assert errors == () assert warnings == [ "Line 3: Print statement is deprecated and not avaliable anymore in Python 3.", # NOQA: E501 "Line 2: Prints, but never reads 'printed' variable." ]
def test_yield(c_exec): """`yield` statement should be allowed.""" result = c_exec(YIELD_EXAMPLE) assert result.errors == () assert result.code is not None local = {} exec(result.code, {}, local) test_generator = local['test_generator'] exec_result = list(test_generator()) assert exec_result == [42]
def test_compile__compile_restricted_exec__1(c_exec): """It returns a CompileResult on success.""" result = c_exec('a = 42') assert result.__class__ == CompileResult assert result.errors == () assert result.warnings == [] assert result.used_names == {} glob = {} exec(result.code, glob) assert glob['a'] == 42
def test_RestrictingNodeTransformer__module_func_def_name_call(c_exec): """It forbids definition and usage of magic methods as functions ... ... at module level. """ result = c_exec(BLACKLISTED_FUNC_NAMES_CALL_TEST) # assert result.errors == ('Line 1: ') assert result.errors == ( 'Line 2: "__init__" is an invalid variable name because it starts with "_"', # NOQA: E501 'Line 5: "__init__" is an invalid variable name because it starts with "_"', # NOQA: E501 )
def test_print_stmt__fail_with_none_target(c_exec, mocker): code, errors = c_exec('print >> None, "test"')[:2] assert code is not None assert errors == () glb = {'_getattr_': getattr, '_print_': PrintCollector} with pytest.raises(AttributeError) as excinfo: exec(code, glb) assert "'NoneType' object has no attribute 'write'" in str(excinfo.value)
def test_safer_getattr__underscore_name(c_exec): """It prevents accessing an attribute which starts with an underscore.""" result = c_exec(GETATTR_UNDERSCORE_NAME) assert result.errors == () assert result.warnings == [] glb = safe_globals.copy() glb['getattr'] = safer_getattr with pytest.raises(AttributeError) as err: exec(result.code, glb, {}) assert ( '"__class__" is an invalid attribute name because it starts with "_"' == str(err.value))
def test_compile__compile_restricted_exec__5(c_exec): """It does not return code if the code contains a NULL byte.""" result = c_exec('a = 5\x00') assert result.code is None assert result.warnings == [] assert result.used_names == {} if IS_PY2: assert result.errors == ( 'compile() expected string without null bytes', ) else: assert result.errors == ( 'source code string cannot contain null bytes', )
def test_compile__compile_restricted_exec__3(c_exec): """It returns a tuple of errors if the code is not allowed. There is no code in this case. """ result = c_exec('_a = 42\n_b = 43') errors = ( 'Line 1: "_a" is an invalid variable name because it starts with "_"', 'Line 2: "_b" is an invalid variable name because it starts with "_"') assert result.errors == errors assert result.warnings == [] assert result.used_names == {} assert result.code is None
def test_yield_from(c_exec): """`yield from` statement should be allowed.""" result = c_exec(YIELD_FORM_EXAMPLE) assert result.errors == () assert result.code is not None def my_external_generator(): my_list = [1, 2, 3, 4, 5] for elem in my_list: yield (elem) local = {} exec(result.code, {}, local) reader_wapper = local['reader_wapper'] exec_result = list(reader_wapper(my_external_generator())) assert exec_result == [1, 2, 3, 4, 5]
def test_print_stmt__protect_chevron_print(c_exec, mocker): code, errors = c_exec(PROTECT_PRINT_STATEMENT_WITH_CHEVRON)[:2] _getattr_ = mocker.stub() _getattr_.side_effect = getattr glb = {'_getattr_': _getattr_, '_print_': PrintCollector} exec(code, glb) stream = mocker.stub() stream.write = mocker.stub() glb['print_into_stream'](stream) stream.write.assert_has_calls( [mocker.call('Hello World!'), mocker.call('\n')]) _getattr_.assert_called_once_with(stream, 'write')
def test_async_yield_from(c_exec): """`yield from` statement should be allowed.""" result = c_exec(ASYNC_YIELD_FORM_EXAMPLE) assert result.errors == ( 'Line 4: AsyncFunctionDef statements are not allowed.', ) assert result.code is None
def test_asyncio_yield_from(c_exec): """`yield from` statement should be allowed.""" result = c_exec(ASYNCIO_YIELD_FORM_EXAMPLE) assert result.errors == () assert result.code is not None