From 1aa3e308d3dfaff38d09620018c63d60cb61b992 Mon Sep 17 00:00:00 2001 From: Alexander Loechel Date: Tue, 21 Feb 2017 13:00:03 +0100 Subject: [PATCH] apply requested changes on docs --- README.rst | 2 +- docs/conf.py | 1 + docs/contributing/index.rst | 6 ----- docs/roadmap/index.rst | 4 --- docs/usage/basic_usage.rst | 47 +++++++++++++++++++++++++++------- docs/usage/framework_usage.rst | 37 +++++++++++++++++++------- docs/usage/policy.rst | 32 +++++++++++++++++++---- setup.py | 2 -- tox.ini | 3 ++- 9 files changed, 97 insertions(+), 37 deletions(-) diff --git a/README.rst b/README.rst index 7894bcc..14e9451 100644 --- a/README.rst +++ b/README.rst @@ -4,4 +4,4 @@ RestrictedPython RestrictedPython is a defined subset of the Python language which allows to provide a program input into a trusted environment. -For full documentation please see docs/index. +For full documentation please see http://restrictedpython.readthedocs.io/en/python3_update/ or local docs/index. diff --git a/docs/conf.py b/docs/conf.py index da3ffea..39cf1bb 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -31,6 +31,7 @@ extensions = [ 'sphinx.ext.intersphinx', 'sphinx.ext.todo', + 'sphinx.ext.doctest', ] # Add any paths that contain templates here, relative to this directory. diff --git a/docs/contributing/index.rst b/docs/contributing/index.rst index 2d1d759..2b62e40 100644 --- a/docs/contributing/index.rst +++ b/docs/contributing/index.rst @@ -2,9 +2,3 @@ Contributing ============ Contributing to RestrictedPython 4+ - - -* `Trello Board`_ - - -.. _`Trello Board`: https://trello.com/b/pKaXJIlT/restrictedpython diff --git a/docs/roadmap/index.rst b/docs/roadmap/index.rst index 7aa003e..1333295 100644 --- a/docs/roadmap/index.rst +++ b/docs/roadmap/index.rst @@ -1,10 +1,6 @@ Roadmap for RestrictedPython ============================ -A few of the action items currently worked on is on our `Trello Board`_. - -.. _`Trello Board`: https://trello.com/b/pKaXJIlT/restrictedpython - RestrictedPython 4.0 -------------------- diff --git a/docs/usage/basic_usage.rst b/docs/usage/basic_usage.rst index 522c23f..6aad2e5 100644 --- a/docs/usage/basic_usage.rst +++ b/docs/usage/basic_usage.rst @@ -14,28 +14,53 @@ The general workflow to execute Python code that is loaded within a Python progr exec(byte_code) do_something() +.. doctest:: + :hide: + + >>> source_code = """ + ... def do_something(): + ... pass + ... """ + >>> byte_code = compile(source_code, filename='', mode='exec') + >>> exec(byte_code) + >>> do_something() + + With RestrictedPython that workflow should be as straight forward as possible: .. code:: Python - from RestrictedPython import compile_restricted as compile + from RestrictedPython import compile_restricted source_code = """ def do_something(): pass """ - byte_code = compile(source_code, filename='', mode='exec') + byte_code = compile_restricted(source_code, filename='', mode='exec') exec(byte_code) do_something() -With that simple addition: + +.. doctest:: + :hide: + + >>> from RestrictedPython import compile_restricted + >>> source_code = """ + ... def do_something(): + ... pass + ... """ + >>> byte_code = compile_restricted(source_code, filename='', mode='exec') + >>> exec(byte_code) + >>> do_something() + +You might also use the replacement import: .. code:: Python from RestrictedPython import compile_restricted as compile -it uses a predefined policy that checks and modify the source code and checks against a restricted subset of the Python language. +``compile_restricted`` uses a predefined policy that checks and modify the source code and checks against a restricted subset of the Python language. The compiled source code is still executed against the full available set of library modules and methods. The Python :py:func:`exec` takes three parameters: @@ -55,7 +80,7 @@ Providing defined dictionaries for ``exec()`` should be used in context of Restr exec(byte_code, { ... }, { ... }) Typically there is a defined set of allowed modules, methods and constants used in that context. -RestrictedPython provides three predefined built-ins for that: +RestrictedPython provides three predefined built-ins for that (see :ref:`predefined_builtins` for details): * ``safe_builtins`` * ``limited_builtins`` @@ -65,15 +90,19 @@ So you normally end up using: .. code:: Python - from RestrictedPython import ..._builtins - from RestrictedPython import compile_restricted as compile + #from RestrictedPython import ..._builtins + from RestrictedPython import safe_builtins + from RestrictedPython import limited_builtins + from RestrictedPython import utilities_builtins + from RestrictedPython import compile_restricted source_code = """""" try: - byte_code = compile(source_code, filename='', mode='exec') + byte_code = compile_restricted(source_code, filename='', mode='exec') - used_builtins = ..._builtins + { } + #used_builtins = ..._builtins + { } # Whitelisting additional elements + used_builtins = safe_builtins exec(byte_code, used_buildins, None) except SyntaxError as e: ... diff --git a/docs/usage/framework_usage.rst b/docs/usage/framework_usage.rst index 5d5e1ed..7c31172 100644 --- a/docs/usage/framework_usage.rst +++ b/docs/usage/framework_usage.rst @@ -11,9 +11,9 @@ RestrictedPython provides four specialized compile_restricted methods: * ``compile_restricted_single`` * ``compile_restricted_function`` -Those four methods return a tuple with four elements: +Those four methods return a named tuple (``CompileResult``) with four elements: -* ``byte_code`` object or ``None`` if ``errors`` is not empty +* ``code`` ```` object or ``None`` if ``errors`` is not empty * ``errors`` a tuple with error messages * ``warnings`` a list with warnings * ``used_names`` a set / dictionary with collected used names of library calls @@ -31,15 +31,18 @@ Modifying the builtins is straight forward, it is just a dictionary containing a Modification is normally removing elements from existing builtins or adding allowed elements by copying from globals. For frameworks it could possibly also be useful to change handling of specific Python language elements. -For that use case RestrictedPython provide the possibility to pass an own policy. -A policy is basically a special ``NodeTransformer`` that could be instantiated with three params for ``errors``, ``warnings`` and ``used_names``, it should be a subclass of RestrictingNodeTransformer (that subclassing will maybe later be enforced). +For that use case RestrictedPython provides the possibility to pass an own policy. + +A policy is basically a special ``NodeTransformer`` that could be instantiated with three params for ``errors``, ``warnings`` and ``used_names``, it should be a subclass of RestrictedPython.RestrictingNodeTransformer. + +.. todo:: + + write doctests for following code .. code:: Python OwnRestrictingNodeTransformer(errors=[], warnings=[], used_names=[]) -One special case (defined to unblock ports of Zope Packages to Python 3) is to actually use RestrictedPython in an unrestricted mode, by providing a Null-Policy (aka ``None``). - All ``compile_restricted*`` methods do have a optional parameter ``policy``, where a specific policy could be provided. .. code:: Python @@ -48,14 +51,30 @@ All ``compile_restricted*`` methods do have a optional parameter ``policy``, whe policy = OwnRestrictingNodeTransformer - byte_code = compile(source_code, filename='', mode='exec', policy=policy) + byte_code = compile_restricted(source_code, filename='', mode='exec', policy=policy) exec(byte_code, { ... }, { ... }) -The Special case "unrestricted RestrictedPython" would be: +One special case "unrestricted RestrictedPython" (defined to unblock ports of Zope Packages to Python 3) is to actually use RestrictedPython in an unrestricted mode, by providing a Null-Policy (aka ``None``). +That special case would be written as: .. code:: Python source_code = """""" - byte_code = compile(source_code, filename='', mode='exec', policy=None) + byte_code = compile_restricted(source_code, filename='', mode='exec', policy=None) exec(byte_code, globals(), None) + +.. doctest:: + :hide: + + >>> from RestrictedPython import compile_restricted + >>> + >>> source_code = """ + ... def do_something(): + ... pass + ... + ... do_something() + ... """ + >>> + >>> byte_code = compile_restricted(source_code, filename='', mode='exec', policy=None) + >>> exec(byte_code, globals(), None) diff --git a/docs/usage/policy.rst b/docs/usage/policy.rst index 7884829..bce3413 100644 --- a/docs/usage/policy.rst +++ b/docs/usage/policy.rst @@ -1,13 +1,35 @@ +.. _policy_builtins: + Policies & builtins ------------------- +.. todo:: + + Should be described in detail. + Especially the difference between builtins and a policy which is a NodeTransformer. + + +RestrictedPython provides a way to define Policies, by redefining restricted versions of ``print``, ``getattr``, ``setattr``, ``import``, etc.. +As shortcuts it offers three stripped down versions of Pythons ``__builtins__``: + +.. _predefined_builtins: + +Predefined builtins +................... + +.. todo:: + + Describe more in details + +* ``safe_builtins`` a safe set of builtin modules and functions, +* ``limited_builtins`` which provides restricted sequence types, +* ``utilities_builtins`` which provides access for standard modules math, random, string and for sets. +Guards +...... -Also RestrictedPython provides a way to define Policies, by redefining restricted versions of ``print``, ``getattr``, ``setattr``, ``import``, etc.. -As shortcutes it offers three stripped down versions of Pythons ``__builtins__``: +.. todo:: -* ``safe_builtins`` (by Guards.py) -* ``limited_builtins`` (by Limits.py), which provides restriced sequence types -* ``utilities_builtins`` (by Utilities.py), which provides access for standard modules math, random, string and for sets. + Describe Guards and predefined guard methods in details There is also a guard function for making attributes immutable --> ``full_write_guard`` (write and delete protected) diff --git a/setup.py b/setup.py index 99c9d0b..503918d 100644 --- a/setup.py +++ b/setup.py @@ -30,8 +30,6 @@ def read(*rnames): description='RestrictedPython provides a restricted execution ' 'environment for Python, e.g. for running untrusted code.', long_description=(read('README.rst') + '\n' + - read('docs', 'install', 'index.rst') + '\n' + - read('docs', 'usage', 'basic_usage.rst') + '\n' + read('docs', 'CHANGES.rst')), classifiers=[ 'License :: OSI Approved :: Zope Public License', diff --git a/tox.ini b/tox.ini index e72abc8..9079330 100644 --- a/tox.ini +++ b/tox.ini @@ -8,9 +8,9 @@ envlist = py35, py36, pypy, + docs, coverage-report, isort, - docs, skip_missing_interpreters = False [testenv] @@ -74,6 +74,7 @@ commands = flake8 --doctests src tests setup.py basepython = python2.7 commands = sphinx-build -b html -d build/docs/doctrees docs build/docs/html + sphinx-build -b doctest docs build/docs/doctrees deps = .[docs] Sphinx