• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

zopefoundation / RestrictedPython / 11248712278

09 Oct 2024 05:18AM UTC coverage: 98.768% (-0.1%) from 98.863%
11248712278

Pull #289

github

dataflake
- remove Python3.7 declaration
Pull Request #289: Support Python 3.13 and remove Python 3.7 support.

371 of 391 branches covered (94.88%)

16 of 17 new or added lines in 3 files covered. (94.12%)

27 existing lines in 4 files now uncovered.

2486 of 2517 relevant lines covered (98.77%)

0.99 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.41
/tests/test_compile.py
1
import platform
1✔
2
import types
1✔
3

4
import pytest
1✔
5

6
from RestrictedPython import CompileResult
1✔
7
from RestrictedPython import compile_restricted
1✔
8
from RestrictedPython import compile_restricted_eval
1✔
9
from RestrictedPython import compile_restricted_exec
1✔
10
from RestrictedPython import compile_restricted_single
1✔
11
from RestrictedPython._compat import IS_PY310_OR_GREATER
1✔
12
from RestrictedPython._compat import IS_PY311_OR_GREATER
1✔
13
from tests.helper import restricted_eval
1✔
14

15

16
def test_compile__compile_restricted_invalid_code_input():
1✔
17
    with pytest.raises(TypeError):
1✔
18
        compile_restricted(object(), '<string>', 'exec')
1✔
19
    with pytest.raises(TypeError):
1✔
20
        compile_restricted(object(), '<string>', 'eval')
1✔
21
    with pytest.raises(TypeError):
1✔
22
        compile_restricted(object(), '<string>', 'single')
1✔
23

24

25
def test_compile__compile_restricted_invalid_policy_input():
1✔
26
    with pytest.raises(TypeError):
1✔
27
        compile_restricted("pass", '<string>', 'exec', policy=object)
1✔
28

29

30
def test_compile__compile_restricted_invalid_mode_input():
1✔
31
    with pytest.raises(TypeError):
1✔
32
        compile_restricted("pass", '<string>', 'invalid')
1✔
33

34

35
INVALID_ASSINGMENT = """
1✔
36
1 = 2
37
"""
38

39

40
def test_compile__invalid_syntax():
1✔
41
    with pytest.raises(SyntaxError) as err:
1✔
42
        compile_restricted(INVALID_ASSINGMENT, '<string>', 'exec')
1✔
43
    if IS_PY310_OR_GREATER:
1!
44
        assert "SyntaxError: cannot assign to literal here." in str(err.value)
1✔
45
    else:
NEW
46
        assert "cannot assign to literal at statement:" in str(err.value)
×
47

48

49
def test_compile__compile_restricted_exec__1():
1✔
50
    """It returns a CompileResult on success."""
51
    result = compile_restricted_exec('a = 42')
1✔
52
    assert result.__class__ == CompileResult
1✔
53
    assert result.errors == ()
1✔
54
    assert result.warnings == []
1✔
55
    assert result.used_names == {}
1✔
56
    glob = {}
1✔
57
    exec(result.code, glob)
1✔
58
    assert glob['a'] == 42
1✔
59

60

61
def test_compile__compile_restricted_exec__2():
1✔
62
    """It compiles without restrictions if there is no policy."""
63
    result = compile_restricted_exec('_a = 42', policy=None)
1✔
64
    assert result.errors == ()
1✔
65
    assert result.warnings == []
1✔
66
    assert result.used_names == {}
1✔
67
    glob = {}
1✔
68
    exec(result.code, glob)
1✔
69
    assert glob['_a'] == 42
1✔
70

71

72
def test_compile__compile_restricted_exec__3():
1✔
73
    """It returns a tuple of errors if the code is not allowed.
74

75
    There is no code in this case.
76
    """
77
    result = compile_restricted_exec('_a = 42\n_b = 43')
1✔
78
    errors = (
1✔
79
        'Line 1: "_a" is an invalid variable name because it starts with "_"',
80
        'Line 2: "_b" is an invalid variable name because it starts with "_"')
81
    assert result.errors == errors
1✔
82
    assert result.warnings == []
1✔
83
    assert result.used_names == {}
1✔
84
    assert result.code is None
1✔
85

86

87
def test_compile__compile_restricted_exec__4():
1✔
88
    """It does not return code on a SyntaxError."""
89
    result = compile_restricted_exec('asdf|')
1✔
90
    assert result.code is None
1✔
91
    assert result.warnings == []
1✔
92
    assert result.used_names == {}
1✔
93
    assert result.errors == (
1✔
94
        "Line 1: SyntaxError: invalid syntax at statement: 'asdf|'",)
95

96

97
def test_compile__compile_restricted_exec__5():
1✔
98
    """It does not return code if the code contains a NULL byte."""
99
    result = compile_restricted_exec('a = 5\x00')
1✔
100
    assert result.code is None
1✔
101
    assert result.warnings == []
1✔
102
    assert result.used_names == {}
1✔
103
    if IS_PY311_OR_GREATER:
1!
104
        assert result.errors == (
1✔
105
            'Line None: SyntaxError: source code string cannot contain null'
106
            ' bytes at statement: None',)
107
    else:
UNCOV
108
        assert result.errors == (
×
109
            'source code string cannot contain null bytes',)
110

111

112
EXEC_STATEMENT = """\
1✔
113
def no_exec():
114
    exec 'q = 1'
115
"""
116

117

118
def test_compile__compile_restricted_exec__10():
1✔
119
    """It is a SyntaxError to use the `exec` statement."""
120
    result = compile_restricted_exec(EXEC_STATEMENT)
1✔
121
    if IS_PY310_OR_GREATER:
1!
122
        assert (
1✔
123
            'Line 2: SyntaxError: Missing parentheses in call to \'exec\'. Did'
124
            ' you mean exec(...)? at statement: "exec \'q = 1\'"',
125
        ) == result.errors
126
    else:
UNCOV
127
        assert (
×
128
            'Line 2: SyntaxError: Missing parentheses in call to \'exec\' at'
129
            ' statement: "exec \'q = 1\'"',) == result.errors
130

131

132
FUNCTION_DEF = """\
1✔
133
def a():
134
    pass
135
"""
136

137

138
def test_compile__compile_restricted_eval__1():
1✔
139
    """It compiles code as an Expression.
140

141
    Function definitions are not allowed in Expressions.
142
    """
143
    result = compile_restricted_eval(FUNCTION_DEF)
1✔
144
    assert result.errors == (
1✔
145
        "Line 1: SyntaxError: invalid syntax at statement: 'def a():'",)
146

147

148
def test_compile__compile_restricted_eval__2():
1✔
149
    """It compiles code as an Expression."""
150
    assert restricted_eval('4 * 6') == 24
1✔
151

152

153
def test_compile__compile_restricted_eval__used_names():
1✔
154
    result = compile_restricted_eval("a + b + func(x)")
1✔
155
    assert result.errors == ()
1✔
156
    assert result.warnings == []
1✔
157
    assert result.used_names == {'a': True, 'b': True, 'x': True, 'func': True}
1✔
158

159

160
def test_compile__compile_restricted_single__1():
1✔
161
    """It compiles code as an Interactive."""
162
    result = compile_restricted_single('x = 4 * 6')
1✔
163

164
    assert result.errors == ()
1✔
165
    assert result.warnings == []
1✔
166
    assert result.code is not None
1✔
167
    locals = {}
1✔
168
    exec(result.code, {}, locals)
1✔
169
    assert locals["x"] == 24
1✔
170

171

172
def test_compile__compile_restricted__2():
1✔
173
    """It compiles code as an Interactive."""
174
    code = compile_restricted('x = 4 * 6', filename="<string>", mode="single")
1✔
175
    locals = {}
1✔
176
    exec(code, {}, locals)
1✔
177
    assert locals["x"] == 24
1✔
178

179

180
PRINT_EXAMPLE = """
1✔
181
def a():
182
    print('Hello World!')
183
"""
184

185

186
def test_compile_restricted():
1✔
187
    """It emits Python warnings.
188

189
    For actual tests for print statement see: test_print_stmt.py
190
    """
191
    with pytest.warns(SyntaxWarning) as record:
1✔
192
        result = compile_restricted(PRINT_EXAMPLE, '<string>', 'exec')
1✔
193
        assert isinstance(result, types.CodeType)
1✔
194
        assert len(record) == 1
1✔
195
        assert record[0].message.args[0] == \
1✔
196
            "Line 2: Prints, but never reads 'printed' variable."
197

198

199
EVAL_EXAMPLE = """
1✔
200
def a():
201
    eval('2 + 2')
202
"""
203

204

205
def test_compile_restricted_eval():
1✔
206
    """This test checks compile_restricted itself if that raise Python errors.
207
    """
208
    with pytest.raises(SyntaxError,
1✔
209
                       match="Line 3: Eval calls are not allowed."):
210
        compile_restricted(EVAL_EXAMPLE, '<string>', 'exec')
1✔
211

212

213
def test_compile___compile_restricted_mode__1(recwarn, mocker):
1✔
214
    """It warns when using another Python implementation than CPython."""
215
    if platform.python_implementation() == 'CPython':  # pragma: no cover
216
        # Using CPython we have to fake the check:
217
        mocker.patch('RestrictedPython.compile.IS_CPYTHON', new=False)
218
    compile_restricted('42')
1✔
219
    assert len(recwarn) == 1
1✔
220
    w = recwarn.pop()
1✔
221
    assert w.category == RuntimeWarning
1✔
222
    assert str(w.message) == str(
1✔
223
        'RestrictedPython is only supported on CPython: use on other Python '
224
        'implementations may create security issues.'
225
    )
226

227

228
@pytest.mark.skipif(
229
    platform.python_implementation() == 'CPython',
230
    reason='Warning only present if not CPython.')
231
def test_compile_CPython_warning(recwarn, mocker):  # pragma: no cover
232
    """It warns when using another Python implementation than CPython."""
233
    assert platform.python_implementation() != 'CPython'
234
    with pytest.warns(RuntimeWarning) as record:
235
        compile_restricted('42')
236
    assert len(record) == 1
237
    assert str(record[0].message) == str(
238
        'RestrictedPython is only supported on CPython: use on other Python '
239
        'implementations may create security issues.'
240
    )
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc