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

zopefoundation / RestrictedPython / 16550884845

20 Mar 2025 07:39AM UTC coverage: 98.772%. Remained the same
16550884845

push

github

icemac
Back to development: 8.1

213 of 231 branches covered (92.21%)

2493 of 2524 relevant lines covered (98.77%)

0.99 hits per line

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

100.0
/src/RestrictedPython/Eval.py
1
##############################################################################
2
#
3
# Copyright (c) 2002 Zope Foundation and Contributors.
4
#
5
# This software is subject to the provisions of the Zope Public License,
6
# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
7
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
8
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
9
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
10
# FOR A PARTICULAR PURPOSE
11
#
12
##############################################################################
13
"""Restricted Python Expressions."""
14

15
import ast
1✔
16

17
from .compile import compile_restricted_eval
1✔
18

19

20
nltosp = str.maketrans('\r\n', '  ')
1✔
21

22
# No restrictions.
23
default_guarded_getattr = getattr
1✔
24

25

26
def default_guarded_getitem(ob, index):
1✔
27
    # No restrictions.
28
    return ob[index]
1✔
29

30

31
def default_guarded_getiter(ob):
1✔
32
    # No restrictions.
33
    return ob
1✔
34

35

36
class RestrictionCapableEval:
1✔
37
    """A base class for restricted code."""
38

39
    globals = {'__builtins__': None}
1✔
40
    # restricted
41
    rcode = None
1✔
42

43
    # unrestricted
44
    ucode = None
1✔
45

46
    # Names used by the expression
47
    used = None
1✔
48

49
    def __init__(self, expr):
1✔
50
        """Create a restricted expression
51

52
        where:
53

54
          expr -- a string containing the expression to be evaluated.
55
        """
56
        expr = expr.strip()
1✔
57
        self.__name__ = expr
1✔
58
        expr = expr.translate(nltosp)
1✔
59
        self.expr = expr
1✔
60
        # Catch syntax errors.
61
        self.prepUnrestrictedCode()
1✔
62

63
    def prepRestrictedCode(self):
1✔
64
        if self.rcode is None:
1✔
65
            result = compile_restricted_eval(self.expr, '<string>')
1✔
66
            if result.errors:
1✔
67
                raise SyntaxError(result.errors[0])
1✔
68
            self.used = tuple(result.used_names)
1✔
69
            self.rcode = result.code
1✔
70

71
    def prepUnrestrictedCode(self):
1✔
72
        if self.ucode is None:
1✔
73
            exp_node = compile(
1✔
74
                self.expr,
75
                '<string>',
76
                'eval',
77
                ast.PyCF_ONLY_AST)
78

79
            co = compile(exp_node, '<string>', 'eval')
1✔
80

81
            # Examine the ast to discover which names the expression needs.
82
            if self.used is None:
1✔
83
                used = set()
1✔
84
                for node in ast.walk(exp_node):
1✔
85
                    if isinstance(node, ast.Name):
1✔
86
                        if isinstance(node.ctx, ast.Load):
1✔
87
                            used.add(node.id)
1✔
88

89
                self.used = tuple(used)
1✔
90

91
            self.ucode = co
1✔
92

93
    def eval(self, mapping):
1✔
94
        # This default implementation is probably not very useful. :-(
95
        # This is meant to be overridden.
96
        self.prepRestrictedCode()
1✔
97

98
        global_scope = {
1✔
99
            '_getattr_': default_guarded_getattr,
100
            '_getitem_': default_guarded_getitem,
101
            '_getiter_': default_guarded_getiter,
102
        }
103

104
        global_scope.update(self.globals)
1✔
105

106
        for name in self.used:
1✔
107
            if (name not in global_scope) and (name in mapping):
1✔
108
                global_scope[name] = mapping[name]
1✔
109

110
        return eval(self.rcode, global_scope)
1✔
111

112
    def __call__(self, **kw):
1✔
113
        return self.eval(kw)
1✔
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