Skip to content

Commit

Permalink
Merge branch 'Python3_update' into python3_usage_documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
loechel committed Feb 2, 2017
2 parents 77365bf + 64546c7 commit 4d6d21c
Show file tree
Hide file tree
Showing 8 changed files with 324 additions and 195 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Expand Up @@ -5,7 +5,7 @@ python:
- 3.4
- 3.5
- 3.6
- pypy
- pypy-5.4
env:
- ENVIRON=py
- ENVIRON=isort
Expand Down
1 change: 0 additions & 1 deletion setup.py
Expand Up @@ -49,7 +49,6 @@ def read(*rnames):
package_dir={'': 'src'},
install_requires=[
'setuptools',
'six',
],
extras_require={
'docs': [
Expand Down
38 changes: 0 additions & 38 deletions src/RestrictedPython/tests/security_in_syntax.py
Expand Up @@ -3,44 +3,6 @@
# Each function in this module is compiled using compile_restricted().


def overrideGuardWithLambda():
lambda o, _getattr=None: o


def overrideGuardWithArgument():
def f(_getattr=None):
pass


def bad_name(): # ported
__ = 12


def bad_attr(): # ported
some_ob._some_attr = 15


def no_exec(): # ported
exec 'q = 1'


def no_yield(): # ported
yield 42


def check_getattr_in_lambda(arg=lambda _getattr=(lambda ob, name: name):
_getattr):
42


def import_as_bad_name():
import os as _leading_underscore


def from_import_as_bad_name():
from x import y as _leading_underscore


def except_using_bad_name():
try:
foo
Expand Down
35 changes: 15 additions & 20 deletions src/RestrictedPython/transformer.py
Expand Up @@ -86,11 +86,11 @@ def new_print_scope(self):

class RestrictingNodeTransformer(ast.NodeTransformer):

def __init__(self, errors=[], warnings=[], used_names=[]):
def __init__(self, errors=None, warnings=None, used_names=None):
super(RestrictingNodeTransformer, self).__init__()
self.errors = errors
self.warnings = warnings
self.used_names = used_names
self.errors = [] if errors is None else errors
self.warnings = [] if warnings is None else warnings
self.used_names = [] if used_names is None else used_names

# Global counter to construct temporary variable names.
self._tmp_idx = 0
Expand Down Expand Up @@ -1161,6 +1161,13 @@ def visit_alias(self, node):
"""
return self.node_contents_visit(node)

def visit_Exec(self, node):
"""Deny the usage of the exec statement.
Exists only in Python 2.
"""
self.not_allowed(node)

# Control flow

def visit_If(self, node):
Expand Down Expand Up @@ -1197,30 +1204,19 @@ def visit_Try(self, node):
"""Allow Try without restrictions.
This is Python 3 only, Python 2 uses TryExcept.
XXX This was forbidden in RestrictedPython 3.x maybe we have to revisit
this change in RestrictedPython 4.x.
"""
return self.node_contents_visit(node)

def visit_TryFinally(self, node):
"""Allow Try-Finally without restrictions.
XXX This was forbidden in RestrictedPython 3.x maybe we have to revisit
this change in RestrictedPython 4.x.
"""
"""Allow Try-Finally without restrictions."""
return self.node_contents_visit(node)

def visit_TryExcept(self, node):
"""Allow Try-Except without restrictions.
XXX This was forbidden in RestrictedPython 3.x maybe we have to revisit
this change in RestrictedPython 4.x.
"""
"""Allow Try-Except without restrictions."""
return self.node_contents_visit(node)

def visit_ExceptHandler(self, node):
"""Protects tuple unpacking on exception handlers.
"""Protect tuple unpacking on exception handlers.
try:
.....
Expand All @@ -1237,7 +1233,6 @@ def visit_ExceptHandler(self, node):
finally:
del tmp
"""

node = self.node_contents_visit(node)

if IS_PY3:
Expand Down Expand Up @@ -1318,7 +1313,7 @@ def visit_FunctionDef(self, node):
return node

def visit_Lambda(self, node):
"""Checks a lambda definition."""
"""Check a lambda definition."""
self.check_function_argument_names(node)

node = self.node_contents_visit(node)
Expand Down
26 changes: 26 additions & 0 deletions tests/__init__.py
@@ -0,0 +1,26 @@
from RestrictedPython._compat import IS_PY2

import RestrictedPython


def _execute(compile_func):
"""Factory to create an execute function."""
def _execute(source):
code, errors = compile_func(source)[:2]
assert errors == (), errors
assert code is not None
glb = {}
exec(code, glb)
return glb
return _execute


# Define the arguments for @pytest.mark.parametrize to be able to test both the
# old and the new implementation to be equal:
compile = ('compile', [RestrictedPython.compile.compile_restricted_exec])
execute = ('execute',
[_execute(RestrictedPython.compile.compile_restricted_exec)])
if IS_PY2:
from RestrictedPython import RCompile
compile[1].append(RCompile.compile_restricted_exec)
execute[1].append(_execute(RCompile.compile_restricted_exec))
22 changes: 22 additions & 0 deletions tests/test_compile.py
@@ -0,0 +1,22 @@
from . import compile
from RestrictedPython._compat import IS_PY2

import pytest


EXEC_STATEMENT = """\
def no_exec():
exec 'q = 1'
"""


@pytest.mark.skipif(
IS_PY2,
reason="exec statement in Python 2 is handled by RestrictedPython ")
@pytest.mark.parametrize(*compile)
def test_compile__compile_restricted_exec__10(compile):
"""It is a SyntaxError to use the `exec` statement. (Python 3 only)"""
code, errors, warnings, used_names = compile(EXEC_STATEMENT)
assert (
"Line 2: SyntaxError: Missing parentheses in call to 'exec' in on "
"statement: exec 'q = 1'",) == errors

0 comments on commit 4d6d21c

Please sign in to comment.