Skip to content

Commit

Permalink
more docs
Browse files Browse the repository at this point in the history
  • Loading branch information
loechel committed Feb 4, 2017
1 parent 7e5ca7a commit a06f0dd
Show file tree
Hide file tree
Showing 12 changed files with 201 additions and 169 deletions.
7 changes: 7 additions & 0 deletions README.rst
@@ -0,0 +1,7 @@
================
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.
1 change: 0 additions & 1 deletion README.txt

This file was deleted.

File renamed without changes.
4 changes: 4 additions & 0 deletions docs/contributing/index.rst
@@ -0,0 +1,4 @@
Contributing
============

https://trello.com/b/pKaXJIlT/restrictedpython
5 changes: 5 additions & 0 deletions docs/index.rst
Expand Up @@ -25,6 +25,11 @@ Contents
upgrade/index
upgrade_dependencies/index

roadmap/index
contributing/index

CHANGES

Indices and tables
==================

Expand Down
10 changes: 10 additions & 0 deletions docs/install/index.rst
@@ -0,0 +1,10 @@
Install / Depend on RestrictedPython
====================================

RestrictedPython is usually not used stand alone, if you use it in context of your package add it to ``install_requires`` in your ``setup.py`` or a ``requirement.txt`` used by ``pip``.

For a standalone usage:

.. code:: bash
pip install RestrictedPython
4 changes: 4 additions & 0 deletions docs/roadmap/index.rst
@@ -0,0 +1,4 @@
Roadmap for RestrictedPython
============================

https://trello.com/b/pKaXJIlT/restrictedpython
22 changes: 22 additions & 0 deletions docs/usage/api.rst
@@ -0,0 +1,22 @@
API overview
------------

RestrictedPython has tree major scopes:

1. ``compile_restricted`` methods:

* ``compile_restricted``
* ``compile_restricted_exec``
* ``compile_restricted_eval``
* ``compile_restricted_single``
* ``compile_restricted_function``

2. restricted builtins

* ``safe_builtins``
* ``limited_builtins``
* ``utility_builtins``

3. helper modules

* ``PrintCollector``
81 changes: 81 additions & 0 deletions docs/usage/basic_usage.rst
@@ -0,0 +1,81 @@
Basic usage
-----------

The general workflow to execute Python code that is loaded within a Python program is:

.. code:: Python
source_code = """
def do_something():
pass
"""
byte_code = compile(source_code, filename='<inline code>', 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
source_code = """
def do_something():
pass
"""
byte_code = compile(source_code, filename='<inline code>', mode='exec')
exec(byte_code)
do_something()
With that simple addition:

.. 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.
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:

* ``code`` which is the compiled byte code
* ``globals`` which is global dictionary
* ``locals`` which is the local dictionary

By limiting the entries in the ``globals`` and ``locals`` dictionaries you
restrict the access to the available library modules and methods.

Providing defined dictionaries for ``exec()`` should be used in context of RestrictedPython.

.. code:: Python
byte_code = <code>
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:

* ``safe_builtins``
* ``limited_builtins``
* ``utilities_builtins``

So you normally end up using:

.. code:: Python
from RestrictedPython import ..._builtins
from RestrictedPython import compile_restricted as compile
source_code = """<demo code>"""
try:
byte_code = compile(source_code, filename='<name>', mode='exec')
used_builtins = ..._builtins + { <additionl elems> }
exec(byte_code, used_buildins, None)
except SyntaxError as e:
...
One common advanced usage would be to define an own restricted builtin dictionary.
61 changes: 61 additions & 0 deletions docs/usage/framework_usage.rst
@@ -0,0 +1,61 @@
.. _sec_usage_frameworks:

Usage in frameworks and Zope
----------------------------

One major issue with using ``compile_restricted`` directly in a framework is, that you have to use try-except statements to handle problems and it might be a bit harder to provide useful information to the user.
RestrictedPython provides four specialized compile_restricted methods:

* ``compile_restricted_exec``
* ``compile_restricted_eval``
* ``compile_restricted_single``
* ``compile_restricted_function``

Those four methods return a tuple with four elements:

* ``byte_code`` <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

Those three information "lists" could be used to provide the user with informations about the compiled source code.

Typical uses cases for the four specialized methods:

* ``compile_restricted_exec`` --> Python Modules or Scripts that should be used or called by the framework itself or from user calls
* ``compile_restricted_eval`` --> Templates
* ``compile_restricted_single``
* ``compile_restricted_function``

Modifying the builtins is straight forward, it is just a dictionary containing access pointers to available library elements.
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).

.. 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
source_code = """<demo code>"""
policy = OwnRestrictingNodeTransformer
byte_code = compile(source_code, filename='<inline code>', mode='exec', policy=policy)
exec(byte_code, { ... }, { ... })
The Special case "unrestricted RestrictedPython" would be:

.. code:: Python
source_code = """<demo code>"""
byte_code = compile(source_code, filename='<inline code>', mode='exec', policy=None)
exec(byte_code, globals(), None)
169 changes: 3 additions & 166 deletions docs/usage/index.rst
@@ -1,169 +1,6 @@
Usage of RestrictedPython
=========================

API overview
------------

RestrictedPython has tree major scopes:

1. ``compile_restricted`` methods:

* ``compile_restricted``
* ``compile_restricted_exec``
* ``compile_restricted_eval``
* ``compile_restricted_single``
* ``compile_restricted_function``

2. restricted builtins

* ``safe_builtins``
* ``limited_builtins``
* ``utility_builtins``

3. helper modules

* ``PrintCollector``

Basic usage
-----------

The general workflow to execute Python code that is loaded within a Python program is:

.. code:: Python
source_code = """
def do_something():
pass
"""
byte_code = compile(source_code, filename='<inline code>', 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
source_code = """
def do_something():
pass
"""
byte_code = compile(source_code, filename='<inline code>', mode='exec')
exec(byte_code)
do_something()
With that simple addition:

.. 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.
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:

* ``code`` which is the compiled byte code
* ``globals`` which is global dictionary
* ``locals`` which is the local dictionary

By limiting the entries in the ``globals`` and ``locals`` dictionaries you
restrict the access to the available library modules and methods.

Providing defined dictionaries for ``exec()`` should be used in context of RestrictedPython.

.. code:: Python
byte_code = <code>
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:

* ``safe_builtins``
* ``limited_builtins``
* ``utilities_builtins``

So you normally end up using:

.. code:: Python
from RestrictedPython import ..._builtins
from RestrictedPython import compile_restricted as compile
source_code = """<demo code>"""
try:
byte_code = compile(source_code, filename='<name>', mode='exec')
used_builtins = ..._builtins + { <additionl elems> }
exec(byte_code, used_buildins, None)
except SyntaxError as e:
...
One common advanced usage would be to define an own restricted builtin dictionary.

.. _sec_usage_frameworks:

Usage in frameworks and Zope
----------------------------

One major issue with using ``compile_restricted`` directly in a framework is, that you have to use try-except statements to handle problems and it might be a bit harder to provide useful information to the user.
RestrictedPython provides four specialized compile_restricted methods:

* ``compile_restricted_exec``
* ``compile_restricted_eval``
* ``compile_restricted_single``
* ``compile_restricted_function``

Those four methods return a tuple with four elements:

* ``byte_code`` <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

Those three information "lists" could be used to provide the user with informations about the compiled source code.

Typical uses cases for the four specialized methods:

* ``compile_restricted_exec`` --> Python Modules or Scripts that should be used or called by the framework itself or from user calls
* ``compile_restricted_eval`` --> Templates
* ``compile_restricted_single``
* ``compile_restricted_function``

Modifying the builtins is straight forward, it is just a dictionary containing access pointers to available library elements.
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).

.. 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
source_code = """<demo code>"""
policy = OwnRestrictingNodeTransformer
byte_code = compile(source_code, filename='<inline code>', mode='exec', policy=policy)
exec(byte_code, { ... }, { ... })
The Special case "unrestricted RestrictedPython" would be:

.. code:: Python
source_code = """<demo code>"""
byte_code = compile(source_code, filename='<inline code>', mode='exec', policy=None)
exec(byte_code, globals(), None)
.. include:: api.rst
.. include:: basic_usage.rst
.. include:: framework_usage.rst
6 changes: 4 additions & 2 deletions setup.py
Expand Up @@ -29,8 +29,10 @@ def read(*rnames):
license='ZPL 2.1',
description='RestrictedPython provides a restricted execution '
'environment for Python, e.g. for running untrusted code.',
long_description=(read('src', 'RestrictedPython', 'README.rst') + '\n' +
read('CHANGES.rst')),
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',
'Programming Language :: Python',
Expand Down

0 comments on commit a06f0dd

Please sign in to comment.