[book] Update documentation for new repoapi
Quite a few things change in 3.19:
- repoapi instead of dbapi
- ClientConnection / Connection / Session rework
- web authentication process
- test APIs
Closes #3638793
--- a/devtools/testlib.py Fri Mar 14 11:18:15 2014 +0100
+++ b/devtools/testlib.py Tue Mar 11 15:56:05 2014 +0100
@@ -39,8 +39,9 @@
from logilab.common.deprecation import deprecated, class_deprecated
from logilab.common.shellutils import getlogin
-from cubicweb import ValidationError, NoSelectableObject, AuthenticationError
-from cubicweb import cwconfig, dbapi, devtools, web, server, repoapi
+from cubicweb import (ValidationError, NoSelectableObject, AuthenticationError,
+ ProgrammingError)
+from cubicweb import cwconfig, devtools, web, server, repoapi
from cubicweb.utils import json
from cubicweb.sobjects import notification
from cubicweb.web import Redirect, application
@@ -156,7 +157,7 @@
class TestCaseConnectionProxy(object):
- """thin wrapper around `cubicweb.dbapi.Connection` context-manager
+ """thin wrapper around `cubicweb.repoapi.ClientConnection` context-manager
used in CubicWebTC (cf. `cubicweb.devtools.testlib.CubicWebTC.login` method)
It just proxies to the default connection context manager but
@@ -260,7 +261,7 @@
* `vreg`, the vregistry
* `schema`, self.vreg.schema
* `config`, cubicweb configuration
- * `cnx`, dbapi connection to the repository using an admin user
+ * `cnx`, repoapi connection to the repository using an admin user
* `session`, server side session associated to `cnx`
* `app`, the cubicweb publisher (for web testing)
* `repo`, the repository object
@@ -436,7 +437,7 @@
def rollback(self):
try:
self.cnx.rollback()
- except dbapi.ProgrammingError:
+ except ProgrammingError:
pass # connection closed
finally:
self.session.set_cnxset() # ensure cnxset still set after commit
@@ -667,14 +668,13 @@
.. sourcecode:: python
- rdef = self.schema['CWUser'].rdef('login')
with self.temporary_permissions(CWUser={'read': ()}):
...
- Usually the former will be prefered to override permissions on a
+ Usually the former will be preferred to override permissions on a
relation definition, while the latter is well suited for entity types.
- The allowed keys in the permission dictionary depends on the schema type
+ The allowed keys in the permission dictionary depend on the schema type
(entity type / relation definition). Resulting permissions will be
similar to `orig_permissions.update(partial_perms)`.
"""
--- a/doc/book/en/devrepo/repo/sessions.rst Fri Mar 14 11:18:15 2014 +0100
+++ b/doc/book/en/devrepo/repo/sessions.rst Tue Mar 11 15:56:05 2014 +0100
@@ -3,50 +3,47 @@
Sessions
========
-Sessions are object carrying the `.execute` method to query the data
-sources.
+Sessions are objects linked to an authenticated user. The `Session.new_cnx`
+method returns a new Connection linked to that session.
+
+Connections
+===========
-Kinds of sessions
------------------
+Connections provide the `.execute` method to query the data sources.
-There are two kinds of sessions.
+Kinds of connections
+--------------------
-* `normal sessions` are the most common: they are related to users and
+There are two kinds of connections.
+
+* `normal connections` are the most common: they are related to users and
carry security checks coming with user credentials
-* `internal sessions` have all the powers; they are also used in only a
+* `internal connections` have all the powers; they are also used in only a
few situations where you don't already have an adequate session at
hand, like: user authentication, data synchronisation in
multi-source contexts
-.. note::
- Do not confuse the session type with their connection mode, for
- instance : `in memory` or `pyro`.
-
-Normal sessions are typically named `_cw` in most appobjects or
+Normal connections are typically named `_cw` in most appobjects or
sometimes just `session`.
-Internal sessions are available from the `Repository` object and are
+Internal connections are available from the `Repository` object and are
to be used like this:
.. sourcecode:: python
- session = self.repo.internal_session()
- try:
- do_stuff_with(session)
- finally:
- session.close()
+ with self.repo.internal_cnx() as cnx:
+ do_stuff_with(cnx)
+ cnx.commit()
-.. warning::
- Do not forget to close such a session after use for a session leak
- will quickly lead to an application crash.
+Connections should always be used as context managers, to avoid leaks.
Authentication and management of sessions
-----------------------------------------
The authentication process is a ballet involving a few dancers:
-* through its `connect` method the top-level application object (the
+* through its `get_session` method the top-level application object (the
`CubicWebPublisher`) will open a session whenever a web request
comes in; it asks the `session manager` to open a session (giving
the web request object as context) using `open_session`
@@ -88,7 +85,7 @@
------------------------------
Sometimes CubicWeb's out-of-the-box authentication schemes (cookie and
-http) are not sufficient. Nowadays there is a plethore of such schemes
+http) are not sufficient. Nowadays there is a plethora of such schemes
and the framework cannot provide them all, but as the sequence above
shows, it is extensible.
@@ -154,7 +151,7 @@
.. sourcecode:: python
- class XFooUserRetriever(authentication.LoginPasswordRetreiver):
+ class XFooUserRetriever(authentication.LoginPasswordRetriever):
""" authenticate by the x-foo-user http header
or just do normal login/password authentication
"""
@@ -200,7 +197,8 @@
return 1
return 0
-Full API Session
-~~~~~~~~~~~~~~~~~~~~~~~~~~
+Full Session and Connection API
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. autoclass:: cubicweb.server.session.Session
+.. autoclass:: cubicweb.server.session.Connection
--- a/doc/book/en/devrepo/testing.rst Fri Mar 14 11:18:15 2014 +0100
+++ b/doc/book/en/devrepo/testing.rst Tue Mar 11 15:56:05 2014 +0100
@@ -466,29 +466,26 @@
First, remember to think that some code run on a client side, some
other on the repository side. More precisely:
-* client side: web interface, raw db-api connection (cubicweb-ctl shell for
+* client side: web interface, raw repoapi connection (cubicweb-ctl shell for
instance);
* repository side: RQL query execution, that may trigger hooks and operation.
-The client interact with the repository through a db-api connection.
+The client interacts with the repository through a repoapi connection.
-A db-api connection is tied to a session in the repository. The connection and
+A repoapi connection is tied to a session in the repository. The connection and
request objects are unaccessible from repository code / the session object is
-unaccessible from client code (theorically at least).
+unaccessible from client code (theoretically at least).
-The :mod:`cubicweb.dbapi` module provides a base request class. The web interface
-provides an extended request class.
-
-
-The `request` object provides access to all cubicweb resources, eg:
+The web interface provides a request class. That `request` object provides
+access to all cubicweb resources, eg:
* the registry (which itself provides access to the schema and the
configuration);
-* an underlying db-api connection (when using req.execute, you actually call the
- db-api);
+* an underlying repoapi connection (when using req.execute, you actually call the
+ repoapi);
* other specific resources depending on the client type (url generation according
to base url, form parameters, etc.).
@@ -510,37 +507,32 @@
The `_cw` attribute
```````````````````
The `_cw` attribute available on every application object provides access to all
-cubicweb resources, eg:
+cubicweb resources, i.e.:
-For code running on the client side (eg web interface view), `_cw` is a request
-instance.
+- For code running on the client side (eg web interface view), `_cw` is a request
+ instance.
-For code running on the repository side (hooks and operation), `_cw` is a session
-instance.
+- For code running on the repository side (hooks and operation), `_cw` is a
+ Connection or Session instance.
-Beware some views may be called with a session (eg notifications) or with a
-DB-API request. In the later case, see :meth:`use_web_compatible_requests` on
-:class:`Connection` instances.
+Beware some views may be called with a session (e.g. notifications) or with a
+request.
Request, session and transaction
````````````````````````````````
-In the web interface, an HTTP request is handle by a single request, which will
-be thrown way once the response send.
+In the web interface, an HTTP request is handled by a single request, which will
+be thrown away once the response is sent.
-The web publisher handle the transaction:
+The web publisher handles the transaction:
* commit / rollback is done automatically
* you should not commit / rollback explicitly
-When using a raw db-api, you're on your own regarding transaction.
-
-On the other hand, db-api connection and session live from a user login to its logout.
-
-Because session lives for a long time, and database connections is a limited
-resource, we can't bound a session to its own database connection for all its
+Because a session lives for a long time, and database connections are a limited
+resource, we can't bind a session to its own database connection for all its
lifetime. The repository handles a pool of connections (4 by default), and it's
responsible to attribute them as needed.
@@ -550,13 +542,13 @@
2. the repository attributes a database connection to the session
-3. the repository's querier execute the query
+3. the repository's querier executes the query
4. this query may trigger hooks. Hooks and operation may execute some rql queries
through `_cw.execute`. Those queries go directly to the querier, hence don't
touch the database connection, they use the one attributed in 2.
-5. the repository's get the result of the query in 1. If it was a RQL read query,
+5. the repository gets the result of the query in 1. If it was a RQL read query,
the database connection is released. If it was a write query, the connection
is then tied to the session until the transaction is commited or rollbacked.
@@ -567,11 +559,11 @@
* when using a request, or code executed in hooks, this database connection
handling is totally transparent
-* however, take care when writing test: you are usually faking / testing both the
- server and the client side, so you have to decide when to use self.request() /
- self.session. Ask yourself "where the code I want to test will be running,
- client or repository side ?". The response is usually : use a request :)
- However, if you really need using a session:
+* however, take care when writing tests: you are usually faking / testing both the
+ server and the client side, so you have to decide when to use RepoAccess.client_cnx /
+ RepoAccess.repo_cnx. Ask yourself "where the code I want to test will be running,
+ client or repository side ?". The response is usually : use a client connection :)
+ However, if you really need using a server-side object:
- commit / rollback will free the database connection (unless explicitly told
not to do so).
--- a/doc/book/en/devweb/request.rst Fri Mar 14 11:18:15 2014 +0100
+++ b/doc/book/en/devweb/request.rst Tue Mar 11 15:56:05 2014 +0100
@@ -20,8 +20,6 @@
* `ie_browser`: tells if the browser belong to the Internet Explorer
family
- * `xhtml_browser`: tells if the browser is able to properly handle
- XHTML (at the HTTP content_type level)
* `User and identification`:
@@ -30,7 +28,8 @@
* `Session data handling`
- * `session.data` is the dictionnary of the session data; it can be manipulated like an ordinary Python dictionnary
+ * `session.data` is the dictionary of the session data; it can be
+ manipulated like an ordinary Python dictionary
* `Edition` (utilities for edition control):
@@ -104,8 +103,7 @@
* `get_header(header)`, returns the value associated to an arbitrary header
of the HTTP request
* `set_header(header, value)`, adds an arbitrary header in the response
- * `cursor()` returns a RQL cursor on the session
- * `execute(*args, **kwargs)`, shortcut to ``.cursor().execute()``
+ * `execute(*args, **kwargs)`, executes an RQL query and return the result set
* `property_value(key)`, properties management (`CWProperty`)
* dictionary `data` to store data to share informations between components
*while a request is executed*
@@ -120,14 +118,14 @@
```
The elements we gave in overview for above are built in three layers,
-from ``cubicweb.req.RequestSessionBase``, ``cubicweb.dbapi.DBAPIRequest`` and
-``cubicweb.web.CubicWebRequestBase``.
+from ``cubicweb.req.RequestSessionBase``, ``cubicweb.repoapi.ClientConnection`` and
+``cubicweb.web.ConnectionCubicWebRequestBase``.
.. autoclass:: cubicweb.req.RequestSessionBase
:members:
-.. autoclass:: cubicweb.dbapi.DBAPIRequest
+.. autoclass:: cubicweb.repoapi.ClientConnection
:members:
-.. autoclass:: cubicweb.web.request.CubicWebRequestBase
+.. autoclass:: cubicweb.web.request.ConnectionCubicWebRequestBase
:members:
Binary file doc/book/en/images/request_session.png has changed
--- a/doc/book/en/images/request_session.svg Fri Mar 14 11:18:15 2014 +0100
+++ b/doc/book/en/images/request_session.svg Tue Mar 11 15:56:05 2014 +0100
@@ -13,7 +13,7 @@
height="12.382812"
id="svg2"
version="1.1"
- inkscape:version="0.48.1 r9760"
+ inkscape:version="0.48.3.1 r9886"
sodipodi:docname="request_session.svg">
<defs
id="defs4">
@@ -48,10 +48,10 @@
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
- inkscape:window-width="766"
- inkscape:window-height="1151"
- inkscape:window-x="1152"
- inkscape:window-y="24"
+ inkscape:window-width="958"
+ inkscape:window-height="1160"
+ inkscape:window-x="0"
+ inkscape:window-y="38"
inkscape:window-maximized="0"
inkscape:snap-global="true" />
<metadata
@@ -62,7 +62,7 @@
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
- <dc:title></dc:title>
+ <dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
@@ -113,7 +113,7 @@
sodipodi:role="line"
id="tspan3763"
x="262.63968"
- y="470.51431">DB API</tspan></text>
+ y="470.51431">REPOAPI</tspan></text>
<text
xml:space="preserve"
style="font-size:16px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"