Skip to content

Commit

Permalink
Finished the install-and-run topic and added docs for ZODB.config
Browse files Browse the repository at this point in the history
  • Loading branch information
Jim Fulton committed Sep 7, 2016
1 parent 86b0452 commit 86ed6e9
Show file tree
Hide file tree
Showing 6 changed files with 169 additions and 9 deletions.
4 changes: 4 additions & 0 deletions documentation/guide/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ If you haven't yet, you should read the :ref:`Tutorial <tutorial-label>`.
.. toctree::
:maxdepth: 2

install-and-run
writing-persistent-objects.rst

.. todo:
transaction.rst
storages.rst
configuration.rst
Expand Down
154 changes: 147 additions & 7 deletions documentation/guide/install-and-run.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ For more complex configurations, you'll probably find ZODB's
configuration language easier to use.

To understand database setup, it's important to understand ZODB's
architecture. In particular, ZODB separates database functionality
from low-level storage concerns. When you create a database object,
architecture. ZODB separates database functionality
from storage concerns. When you create a database object,
you specify a storage object for it to use, as in::

import ZODB, ZODB.FileStorage
Expand All @@ -45,7 +45,7 @@ a database.

Sometimes, storages are created through composition. For example, if
we want to save space, we could layer a ``ZlibStorage``
[#zlibstorage_]_ over the file storage::
[#zlibstoragefn]_ over the file storage::

import ZODB, ZODB.FileStorage, zc.zlibstorage

Expand All @@ -61,19 +61,159 @@ Python configuration
--------------------

To set up a database with Python, you'll construct a storage using the
ref:`storage APIs <included-storages-label>`, and then pass the
storage to the class:`~ZODB.DB` class to create a database, as shown
:ref:`storage APIs <included-storages-label>`, and then pass the
storage to the :class:`~ZODB.DB` class to create a database, as shown
in the examples in the previous section.

The class:`~ZODB.DB` class also accepts a string path name as it's
The :class:`~ZODB.DB` class also accepts a string path name as it's
storage argument to automatically create a file storage. You can also
pass ``None`` as the storage to automatically use a
:class:`~ZODB.MappingStorage.MappingStorage`, which is convenient when
exploring ZODB::

db = ZODB.DB(None) # Create an in-memory database.

Text configuration
------------------

.. [#zlibstorage_] `zc.zlibstorage
ZODB supports a text-based configuration language. It uses a syntax
similar to Apache configuration files. The syntax was chosen to be
familiar to site administrators.

ZODB's text configuration uses `ZConfig
<https://pypi.python.org/pypi/ZConfig/3.1.0>`_. You can use ZConfig to
create your application's configuration, but it's more common to
include ZODB configuration strings in their own files or embedded in
simpler configuration files, such as `configarser
<https://docs.python.org/3/library/configparser.html#module-configparser>`_
files.

A database configuration string has a ``zodb`` section wrapping a
storage section, as in::

<zodb>
cache-size-bytes 100MB
<mappingstorage>
</mappingstorage>
</zodb>

.. -> snippet
In the example above, the :ref:`mappingstorage
<mappingstorage-text-configuration>` section defines the storage used
by the database.

To create a database from a string, use
:func:`ZODB.config.databaseFromString`::

>>> import ZODB.config
>>> db = ZODB.config.databaseFromString(snippet)

To load databases from file names or URLs, use
:func:`ZODB.config.databaseFromURL`.

Using databases: connections
============================

Once you have a database, you need to get a database connection to to
much of anything. Connections take care of loading and saving objects
and manage object caches. Each connection has it's own cache
[#caches-are-expensive]_.

Getting connections
-------------------

Amongst [#amongst]_ the common ways of getting a connection:

db.open()
The database :meth:`~ZODB.DB.open` method opens a
connection, returning a connection object::

>>> conn = db.open()

It's up to the application to call
:meth:`~ZODB.Connection.Connection.close` when the application is
done using the connection.

If changes are made, the application :ref:`commits transactions
<commit-transactions>` to make them permanent.

db.transaction() The database :meth:`~ZODB.DB.transaction` method
returns a context manager that can be used with the `python with
statement
<https://docs.python.org/3/reference/compound_stmts.html#grammar-token-with_stmt>`_
to execute a block of code in a transaction::

with db.transaction() as connection:
connection.root.foo = 1

.. -> src
>>> exec(src)
>>> with db.transaction() as connection:
... print connection.root.foo
1
>>> _ = conn.transaction_manager.begin() # get updates on conn
In the example above, we used ``as connection`` to get the database
connection used in the variable ``connection``.

some_object._p_jar
For code that's already running in the context of an open
connection, you can get the current connection as the ``_p_jar``
attribute of some persistent object that was accessed via the
connection.

Getting objects
---------------

Once you have a connection, you access objects by traversing the
object graph form the root object.

The database root object is a mapping object that holds the top level
objects in the database. There should only be a small number of
top-level (often only one). You can get the root object by calling a
connection's ``root`` attribute::

>>> root = conn.root()
>>> root
{'foo': 1}
>>> root['foo']
1

For convenience [#root-convenience]_, you can also get top-level
objects by accessing attributes of the connection root object:

>>> conn.root.foo
1

Once you have a top-level object, you use it's methods, attributes, or
operations to access other objects and so on to get the objects you
need. Often indexing data structures like BTrees_ are used to
make it possible to search objects in large collections.

.. [#zlibstoragefn] `zc.zlibstorage
<https://pypi.python.org/pypi/zc.zlibstorage>`_ is an optional
package that you need to install separately.
.. [#caches-are-expensive] ZODB can be very efficient at caching data
in memory, especially if your `working set
<https://en.wikipedia.org/wiki/Working_set>`_, because the cache is
simply an object tree and accessing a cached object typically
requires no database interaction. Because each connection has it's
own cache, connections can be expensive, depending on their cache
sizes. For this reason, you'll generally want to limit the number
of open connections you have at any one time. Connections are
pooled, so opening a connection is inexpensive.
.. [#amongst] https://www.youtube.com/watch?v=7WJXHY2OXGE
.. [#root-convenience] The ability to access top-level objects of the
database as root attributes is a recent convenience. Originally,
the ``root()`` method was used to access the root object which was
then accessed as a mapping. It's still potentially useful to
access top-level objects using the mapping interface if their names
aren't valid attribute names.
.. _BTrees: https://pythonhosted.org/BTrees/
4 changes: 3 additions & 1 deletion documentation/guide/writing-persistent-objects.rst
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ record from the book record and is managed by ZODB independent of the
management of the book.

In addition to ``PersistentList`` and ``PersistentMapping``, general
persistent data structures are provided by the ``BTrees`` package,
persistent data structures are provided by the BTrees_ package,
most notably ``BTree`` and ``TreeSet`` objects. Unlike
``PersistentList`` and ``PersistentMapping``, ``BTree`` and
``TreeSet`` objects are scalable and can easily hold millions of
Expand Down Expand Up @@ -566,3 +566,5 @@ framework for managing schema-migration scripts.
<https://pypi.python.org/pypi/zope.cachedescriptors>`_ package
provides some descriptors that help implement attributes that cache
data.
.. _BTrees: https://pythonhosted.org/BTrees/
2 changes: 2 additions & 0 deletions documentation/reference/storages.rst
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ MappingStorage
.. autoclass:: ZODB.MappingStorage.MappingStorage
:members: __init__

.. _mappingstorage-text-configuration:

MappingStorage text configuration
---------------------------------

Expand Down
13 changes: 12 additions & 1 deletion documentation/reference/zodb.rst
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,16 @@ Databases
supportsUndo, undoLog, undoInfo, undoMultiple, undo,
transaction, storage

.. _database-text-configuration:

Database text configuration
---------------------------

Databases are configured with ``zodb`` sections::

<zodb>
cache-size-bytes 100MB
<mappingstorage
<mappingstorage>
</mappingstorage>
</zodb>

Expand All @@ -47,6 +49,8 @@ storage and any of the following options:

.. zconfigsectionkeys:: ZODB component.xml zodb

.. _multidatabase-text-configuration:

For a multi-database configuration, use multiple ``zodb`` sections and
give the sections names::

Expand Down Expand Up @@ -136,3 +140,10 @@ TimeStamp (transaction ids)
.. method:: year()

Return the time stamp's year.

Loading configuration
=====================

.. automodule:: ZODB.config
:members: databaseFromString, databaseFromFile, databaseFromURL,
storageFromString, storageFromFile, storageFromURL
1 change: 1 addition & 0 deletions zodbdocumentationtests/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ def test_suite():
manuel.testing.TestSuite(
manuel.doctest.Manuel() + manuel.capture.Manuel(),
join(guide, 'writing-persistent-objects.rst'),
join(guide, 'install-and-run.rst'),
join(reference, 'zodb.rst'),
join(reference, 'storages.rst'),
setUp=setUp, tearDown=tearDown,
Expand Down

0 comments on commit 86ed6e9

Please sign in to comment.