# HG changeset patch # User Sylvain Thénault # Date 1270573687 -7200 # Node ID 2543cfa5d54a98756a4cb1a95c8fd92195922e8a # Parent 5e9055b8c10a8d69f3a50afdc5f4b539710729c9# Parent 834269261ae406f175eff30ff89196d34918877a backport stable diff -r 5e9055b8c10a -r 2543cfa5d54a appobject.py --- a/appobject.py Tue Apr 06 18:51:17 2010 +0200 +++ b/appobject.py Tue Apr 06 19:08:07 2010 +0200 @@ -1,11 +1,18 @@ -"""Base class for dynamically loaded objects accessible through the vregistry. - -You'll also find some convenience classes to build selectors. +# :organization: Logilab +# :copyright: 2001-2010 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2. +# :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr +# :license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses +""" +The `AppObject` class +--------------------- -:organization: Logilab -:copyright: 2001-2010 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2. -:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr -:license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses +The AppObject class is the base class for all dynamically loaded objects +(application objects) accessible through the vregistry. + +We can find a certain number of attributes and methods defined in this class and +common to all the application objects. + +.. autoclass:: AppObject """ __docformat__ = "restructuredtext en" @@ -21,13 +28,17 @@ # selector base classes and operations ######################################## def objectify_selector(selector_func): - """convenience decorator for simple selectors where a class definition - would be overkill:: + """Most of the time, a simple score function is enough to build a selector. + The :func:`objectify_selector` decorator turn it into a proper selector + class:: @objectify_selector def one(cls, *args, **kwargs): return 1 + class MyView(View): + __select__ = View.__select__ & one() + """ return type(selector_func.__name__, (Selector,), {'__doc__': selector_func.__doc__, @@ -49,7 +60,7 @@ class Selector(object): """base class for selector classes providing implementation - for operators ``&`` and ``|`` + for operators ``&``, ``|`` and ``~`` This class is only here to give access to binary operators, the selector logic itself should be implemented in the __call__ method @@ -205,42 +216,77 @@ selected according to a context (usually at least a request and a result set). - Concrete application objects classes are designed to be loaded by the - vregistry and should be accessed through it, not by direct instantiation. + The following attributes should be set on concret appobject classes: - The following attributes should be set on concret appobject classes: - :__registry__: + :attr:`__registry__` name of the registry for this object (string like 'views', 'templates'...) - :__regid__: + + :attr:`__regid__` object's identifier in the registry (string like 'main', 'primary', 'folder_box') - :__select__: + + :attr:`__select__` class'selector - Moreover, the `__abstract__` attribute may be set to True to indicate - that a appobject is abstract and should not be registered. + Moreover, the `__abstract__` attribute may be set to True to indicate that a + class is abstract and should not be registered. At selection time, the following attributes are set on the instance: - :_cw: + :attr:`_cw` current request - :cw_extra_kwargs: + :attr:`cw_extra_kwargs` other received arguments - only if rset is found in arguments (in which case rset/row/col will be - removed from cwextra_kwargs): + And also the following, only if `rset` is found in arguments (in which case + rset/row/col will be removed from `cwextra_kwargs`): - :cw_rset: + :attr:`cw_rset` context result set or None - :cw_row: + + :attr:`cw_row` if a result set is set and the context is about a particular cell in the result set, and not the result set as a whole, specify the row number we are interested in, else None - :cw_col: + + :attr:`cw_col` if a result set is set and the context is about a particular cell in the result set, and not the result set as a whole, specify the col number we are interested in, else None + + + .. Note:: + + * do not inherit directly from this class but from a more specific class + such as `AnyEntity`, `EntityView`, `AnyRsetView`, `Action`... + + * to be recordable, a subclass has to define its registry (attribute + `__registry__`) and its identifier (attribute `__regid__`). Usually + you don't have to take care of the registry since it's set by the base + class, only the identifier `id` + + * application objects are designed to be loaded by the vregistry and + should be accessed through it, not by direct instantiation, besides + to use it as base classe. + + + * When we inherit from `AppObject` (even not directly), you *always* have + to use **super()** to get the methods and attributes of the superclasses, + and not use the class identifier. + + For example, instead of writting:: + + class Truc(PrimaryView): + def f(self, arg1): + PrimaryView.f(self, arg1) + + You must write:: + + class Truc(PrimaryView): + def f(self, arg1): + super(Truc, self).f(arg1) + """ __registry__ = None __regid__ = None diff -r 5e9055b8c10a -r 2543cfa5d54a cwconfig.py --- a/cwconfig.py Tue Apr 06 18:51:17 2010 +0200 +++ b/cwconfig.py Tue Apr 06 19:08:07 2010 +0200 @@ -1,45 +1,42 @@ # -*- coding: utf-8 -*- -"""common configuration utilities for cubicweb +#:organization: Logilab +#:copyright: 2001-2010 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2. +#:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr +#:license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses + +# docstring included in doc/book/en/admin/setup.rst +""" +.. _ResourceMode: + +Resource mode +------------- -:organization: Logilab -:copyright: 2001-2010 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2. -:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr +A resource *mode* is a predifined set of settings for various resources +directories, such as cubes, instances, etc. to ease development with the +framework. There are two running modes with |cubicweb|: + +* 'user', resources are searched / created in the user home directory: + + - instances are stored in :file:`~/etc/cubicweb.d` + - temporary files (such as pid file) in :file:`/tmp` + +* 'system', resources are searched / created in the system directories (eg + usually requiring root access): + + - instances are stored in :file:`/etc/cubicweb.d` + - temporary files (such as pid file) in :file:`/var/run/cubicweb` + + where `` is the detected installation prefix ('/usr/local' for + instance). -If cubicweb is a mercurial checkout (eg `CWDEV` is true), located in -`CW_SOFTWARE_ROOT`: - - * main cubes directory is `/../cubes`. You can specify - another one with `CW_INSTANCES_DIR` environment variable or simply add some - other directories by using `CW_CUBES_PATH`. - - * cubicweb migration files are by default searched in - `/misc/migration` instead of - `/share/cubicweb/migration/` - - * Cubicweb will start in 'user' mode (see below) - - -On startup, Cubicweb is using a specific *mode*. A mode corresponds to some -default setting for various resource directories. There are currently 2 main -modes : 'system', for system wide installation, and 'user', fur user local -installation (e.g. no root privileges). - -'user' mode is activated automatically when cubicweb is a mercurial checkout -(e.g. has a .hg directory). You can also force mode by using the `CW_MODE` -environment variable, to: - -* use system wide installation but user specific instances and all, without root - privileges on the system (`export CW_MODE=user`) - -* use local checkout of cubicweb on system wide instances (requires root - privileges on the system (`export CW_MODE=system`) - - Here is the default resource directories settings according to mode: +Notice that each resource path may be explicitly set using an environment +variable if the default doesn't suit your needs. Here are the default resource +directories that are affected according to mode: * 'system': :: - CW_INSTANCES_DIR = /etc/cubicweb.d/ + CW_INSTANCES_DIR = /etc/cubicweb.d/ CW_INSTANCES_DATA_DIR = /var/lib/cubicweb/instances/ CW_RUNTIME_DIR = /var/run/cubicweb/ @@ -49,24 +46,79 @@ CW_INSTANCES_DATA_DIR = ~/etc/cubicweb.d/ CW_RUNTIME_DIR = /tmp +Cubes search path is also affected, see the :ref:Cube section. + +By default, the mode automatically set to 'user' if a :file:`.hg` directory is found +in the cubicweb package, else it's set to 'system'. You can force this by setting +the :envvar:`CW_MODE` environment variable to either 'user' or 'system' so you can +easily: + +* use system wide installation but user specific instances and all, without root + privileges on the system (`export CW_MODE=user`) + +* use local checkout of cubicweb on system wide instances (requires root + privileges on the system (`export CW_MODE=system`) + +If you've a doubt about the mode you're currently running, check the first line +outputed by the :command:`cubicweb-ctl list` command. + +Also, if cubicweb is a mercurial checkout located in ``: + +* main cubes directory is `/../cubes`. You can specify + another one with :envvar:`CW_INSTANCES_DIR` environment variable or simply + add some other directories by using :envvar:`CW_CUBES_PATH` + +* cubicweb migration files are searched in `/misc/migration` + instead of `/share/cubicweb/migration/`. + + +.. _ConfigurationEnv: + +Environment configuration +------------------------- + +Python +`````` + +If you installed |cubicweb| by cloning the Mercurial forest or from source +distribution, then you will need to update the environment variable PYTHONPATH by +adding the path to the forest `cubicweb`: + +Add the following lines to either :file:`.bashrc` or :file:`.bash_profile` to +configure your development environment :: + + export PYTHONPATH=/full/path/to/cubicweb-forest + +If you installed |cubicweb| with packages, no configuration is required and your +new cubes will be placed in `/usr/share/cubicweb/cubes` and your instances will +be placed in `/etc/cubicweb.d`. + + +CubicWeb +```````` + +Here are all environment variables that may be used to configure |cubicweb|: .. envvar:: CW_MODE - Resource mode: user or system + + Resource mode: user or system, as explained in :ref:ResourceMode. .. envvar:: CW_CUBES_PATH - Augments the default search path for cubes + + Augments the default search path for cubes. You may specify several + directories using ':' as separator (';' under windows environment). .. envvar:: CW_INSTANCES_DIR - Directory where cubicweb instances will be found + + Directory where cubicweb instances will be found. .. envvar:: CW_INSTANCES_DATA_DIR - Directory where cubicweb instances data will be written + + Directory where cubicweb instances data will be written (backup file...) .. envvar:: CW_RUNTIME_DIR + Directory where pid files will be written - - -:license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses """ __docformat__ = "restructuredtext en" _ = unicode diff -r 5e9055b8c10a -r 2543cfa5d54a cwvreg.py --- a/cwvreg.py Tue Apr 06 18:51:17 2010 +0200 +++ b/cwvreg.py Tue Apr 06 19:08:07 2010 +0200 @@ -1,9 +1,178 @@ -"""extend the generic VRegistry with some cubicweb specific stuff +# :organization: Logilab +# :copyright: 2001-2010 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2. +# :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr +# :license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses +""".. VRegistry: + +The `VRegistry` +--------------- + +The `VRegistry` can be seen as a two level dictionary. It contains all objects +loaded dynamically to build a |cubicweb| application. Basically: + +* first level key return a *registry*. This key corresponds to the `__registry__` + attribute of application object classes + +* second level key return a list of application objects which share the same + identifier. This key corresponds to the `__regid__` attribute of application + object classes. + +A *registry* hold a specific kind of application objects. You've for instance +a registry for entity classes, another for views, etc... + +The `VRegistry` has two main responsibilities: + +- being the access point to all registries + +- handling the registration process at startup time, and during automatic + reloading in debug mode. + + +.. _AppObjectRecording: + +Details of the recording process +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. index:: + vregistry: registration_callback + +On startup, |cubicweb| have to load application objects defined in its library +and in cubes used by the instance. Application objects from the library are +loaded first, then those provided by cubes are loaded in an ordered way (e.g. if +your cube depends on an other, objects from the dependancy will be loaded +first). Cube's modules or packages where appobject are looked at is explained in +:ref:`cubelayout`. + +For each module: + +* by default all objects are registered automatically + +* if some objects have to replace other objects, or be included only if some + condition is true, you'll have to define a `registration_callback(vreg)` + function in your module and explicitly register **all objects** in this module, + using the api defined below. + +.. Note:: + Once the function `registration_callback(vreg)` is implemented in a module, + all the objects from this module have to be explicitly registered as it + disables the automatic objects registration. + + +API for objects registration +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Here are the registration methods that you can use in the `registration_callback` +to register your objects to the `VRegistry` instance given as argument (usually +named `vreg`): + +.. automethod:: cubicweb.cwvreg.CubicWebVRegistry.register_all +.. automethod:: cubicweb.cwvreg.CubicWebVRegistry.register_and_replace +.. automethod:: cubicweb.cwvreg.CubicWebVRegistry.register +.. automethod:: cubicweb.cwvreg.CubicWebVRegistry.register_if_interface_found +.. automethod:: cubicweb.cwvreg.CubicWebVRegistry.unregister + + +Examples: + +.. sourcecode:: python + + # web/views/basecomponents.py + def registration_callback(vreg): + # register everything in the module except SeeAlsoComponent + vreg.register_all(globals().values(), __name__, (SeeAlsoVComponent,)) + # conditionally register SeeAlsoVComponent + if 'see_also' in vreg.schema: + vreg.register(SeeAlsoVComponent) -:organization: Logilab -:copyright: 2001-2010 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2. -:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr -:license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses +In this example, we register all application object classes defined in the module +except `SeeAlsoVComponent`. This class is then registered only if the 'see_also' +relation type is defined in the instance'schema. + +.. sourcecode:: python + + # goa/appobjects/sessions.py + def registration_callback(vreg): + vreg.register(SessionsCleaner) + # replace AuthenticationManager by GAEAuthenticationManager + vreg.register_and_replace(GAEAuthenticationManager, AuthenticationManager) + # replace PersistentSessionManager by GAEPersistentSessionManager + vreg.register_and_replace(GAEPersistentSessionManager, PersistentSessionManager) + +In this example, we explicitly register classes one by one: + +* the `SessionCleaner` class +* the `GAEAuthenticationManager` to replace the `AuthenticationManager` +* the `GAEPersistentSessionManager` to replace the `PersistentSessionManager` + +If at some point we register a new appobject class in this module, it won't be +registered at all without modification to the `registration_callback` +implementation. The previous example will register it though, thanks to the call +to the `register_all` method. + + +.. _Selection: + +Runtime objects selection +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Now that we've all application objects loaded, the question is : when I want some +specific object, for instance the primary view for a given entity, how do I get +the proper object ? This is what we call the **selection mechanism**. + +As explained in the :ref:`Concepts` section: + +* each application object has a **selector**, defined by its `__select__` class attribute + +* this selector is responsible to return a **score** for a given context + + - 0 score means the object doesn't apply to this context + + - else, the higher the score, the better the object suits the context + +* the object with the higher score is selected. + +.. Note:: + + When no score is higher than the others, an exception is raised in development + mode to let you know that the engine was not able to identify the view to + apply. This error is silenced in production mode and one of the objects with + the higher score is picked. + + In such cases you would need to review your design and make sure your selectors + or appobjects are properly defined. + +For instance, if you are selecting the primary (eg `__regid__ = 'primary'`) view (eg +`__registry__ = 'views'`) for a result set containing a `Card` entity, 2 objects +will probably be selectable: + +* the default primary view (`__select__ = implements('Any')`), meaning + that the object is selectable for any kind of entity type + +* the specific `Card` primary view (`__select__ = implements('Card')`, + meaning that the object is selectable for Card entities + +Other primary views specific to other entity types won't be selectable in this +case. Among selectable objects, the implements selector will return a higher +score than the second view since it's more specific, so it will be selected as +expected. + +.. _SelectionAPI: + +API for objects selections +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Here is the selection API you'll get on every registry. Some of them, as the +'etypes' registry, containing entity classes, extend it. In those methods, +`*args, **kwargs` is what we call the **context**. Those arguments are given to +selectors that will inspect there content and return a score accordingly. + +.. automethod:: cubicweb.vregistry.Registry.select + +.. automethod:: cubicweb.vregistry.Registry.select_or_none + +.. automethod:: cubicweb.vregistry.Registry.possible_objects + +.. automethod:: cubicweb.vregistry.Registry.object_by_id """ __docformat__ = "restructuredtext en" _ = unicode @@ -347,8 +516,11 @@ obj.schema = schema def register_if_interface_found(self, obj, ifaces, **kwargs): - """register an object but remove it if no entity class implements one of - the given interfaces at the end of the registration process + """register `obj` but remove it if no entity class implements one of + the given `ifaces` interfaces at the end of the registration process. + + Extra keyword arguments are given to the + :meth:`~cubicweb.cwvreg.CubicWebVRegistry.register` function. """ self.register(obj, **kwargs) if not isinstance(ifaces, (tuple, list)): @@ -357,6 +529,13 @@ self._needs_iface[obj] = ifaces def register(self, obj, *args, **kwargs): + """register `obj` application object into `registryname` or + `obj.__registry__` if not specified, with identifier `oid` or + `obj.__regid__` if not specified. + + If `clear` is true, all objects with the same identifier will be + previously unregistered. + """ super(CubicWebVRegistry, self).register(obj, *args, **kwargs) # XXX bw compat ifaces = use_interfaces(obj) diff -r 5e9055b8c10a -r 2543cfa5d54a devtools/testlib.py --- a/devtools/testlib.py Tue Apr 06 18:51:17 2010 +0200 +++ b/devtools/testlib.py Tue Apr 06 19:08:07 2010 +0200 @@ -363,9 +363,11 @@ self.vreg._loadedmods.setdefault(self.__module__, {}) for obj in appobjects: self.vreg.register(obj) - yield - for obj in appobjects: - self.vreg.unregister(obj) + try: + yield + finally: + for obj in appobjects: + self.vreg.unregister(obj) # vregistry inspection utilities ########################################### diff -r 5e9055b8c10a -r 2543cfa5d54a doc/book/en/admin/setup.rst --- a/doc/book/en/admin/setup.rst Tue Apr 06 18:51:17 2010 +0200 +++ b/doc/book/en/admin/setup.rst Tue Apr 06 19:08:07 2010 +0200 @@ -8,16 +8,17 @@ Installation of `Cubicweb` and its dependencies ----------------------------------------------- -*CubicWeb* is packaged for Debian and Ubuntu, but can be installed from source +|cubicweb| is packaged for Debian and Ubuntu, but can be installed from source using a tarball or the Mercurial version control system. + .. _DebianInstallation: Debian and Ubuntu packages ``````````````````````````` -Depending on the distribution you are using, add the appropriate line to your list -of sources (for example by editing ``/etc/apt/sources.list``). +Depending on the distribution you are using, add the appropriate line to your +list of sources (for example by editing ``/etc/apt/sources.list``). For Debian Lenny:: @@ -37,21 +38,26 @@ apt-get update apt-get install cubicweb cubicweb-dev -`cubicweb` installs the framework itself, allowing you to create -new instances. + +`cubicweb` installs the framework itself, allowing you to create new instances. + +`cubicweb-dev` installs the development environment allowing you to develop new +cubes. -`cubicweb-dev` installs the development environment allowing you to -develop new cubes. +There is also a wide variety of cubes listed on the `CubicWeb.org Forge`_ +available as debian packages and tarball. -There is also a wide variety of cubes listed on http://www.cubicweb.org/Project available as debian packages and tarball. +The repositories are signed with `Logilab's gnupg key`_. To avoid warning on +"apt-get update": -The repositories are signed with `Logilab's gnupg key`_. To avoid warning on "apt-get update": 1. become root using sudo 2. download http://ftp.logilab.org/dists/logilab-dists-key.asc using e.g. wget 3. run "apt-key add logilab-dists-key.asc" 4. re-run apt-get update (manually or through the package manager, whichever you prefer) .. _`Logilab's gnupg key`: http://ftp.logilab.org/dists/logilab-dists-key.asc +.. _`CubicWeb.org Forge`: http://www.cubicweb.org/project/ + .. _SourceInstallation: @@ -66,6 +72,11 @@ Make sure you have installed the dependencies (see appendixes for the list). +|cubicweb| should soon be pip_ installable, stay tuned (expected in 3.8). + +.. _pip: http://pypi.python.org/pypi/pip + + Install from version control system ``````````````````````````````````` @@ -85,32 +96,31 @@ Make sure you have installed the dependencies (see appendixes for the list). + .. _WindowsInstallation: Windows installation ```````````````````` Base elements -_____________ +~~~~~~~~~~~~~ -Setting up a windows development environment is not too complicated -but requires a series of small steps. What is proposed there is only -an example of what can be done. We assume everything goes into C:\ in -this document. Adjusting the installation drive should be -straightforward. +Setting up a windows development environment is not too complicated but requires +a series of small steps. What is proposed there is only an example of what can be +done. We assume everything goes into `C:\\` in this document. Adjusting the +installation drive should be straightforward. -You should start by downloading and installing the Python(x,y) -distribution. It contains python 2.5 plus numerous useful third-party -modules and applications:: +You should start by downloading and installing the Python(x,y) distribution. It +contains python 2.5 plus numerous useful third-party modules and applications:: http://www.pythonxy.com/download_fr.php -At the time of this writting, one gets version 2.1.15. Among the many -things provided, one finds Eclipse + pydev (an arguably good IDE for -python under windows). +At the time of this writting, one gets version 2.1.15. Among the many things +provided, one finds Eclipse + pydev (an arguably good IDE for python under +windows). -Then you must grab Twisted. There is a windows installer directly -available from this page:: +Then you must grab Twisted. There is a windows installer directly available from +this page:: http://twistedmatrix.com/trac/ @@ -129,11 +139,9 @@ http://www.stickpeople.com/projects/python/win-psycopg/#Version2 -Please be careful to select the right python (2.5) and postgres (8.4) -versions. +Please be careful to select the right python (2.5) and postgres (8.4) versions. -Pyro enables remote access to cubicweb repository instances. Get it -there:: +Pyro enables remote access to cubicweb repository instances. Get it there:: http://sourceforge.net/projects/pyro/files/ @@ -144,26 +152,26 @@ Check out the latest release. -Having graphviz will allow schema drawings, which is quite recommended -(albeit not mandatory). You should get an msi installer there:: +Having graphviz will allow schema drawings, which is quite recommended (albeit +not mandatory). You should get an msi installer there:: http://www.graphviz.org/Download_windows.php -Simplejson will be provided within the forest, but a win32 compiled -version will run much faster:: +Simplejson will be provided within the forest, but a win32 compiled version will +run much faster:: http://www.osuch.org/python-simplejson%3Awin32 Tools -_____ +~~~~~ -Get mercurial + its standard windows GUI (TortoiseHG) there (the -latest is the greatest):: +Get mercurial + its standard windows GUI (TortoiseHG) there (the latest is the +greatest):: http://bitbucket.org/tortoisehg/stable/wiki/download -If you need to peruse mercurial over ssh, it can be helpful to get an -ssh client like Putty:: +If you need to peruse mercurial over ssh, it can be helpful to get an ssh client +like Putty:: http://www.putty.org/ @@ -173,10 +181,9 @@ http://www.vectrace.com/mercurialeclipse/ Setting up the sources -______________________ +~~~~~~~~~~~~~~~~~~~~~~ -You need to enable the mercurial forest extension. To do this, edit -the file:: +You need to enable the mercurial forest extension. To do this, edit the file:: C:\Program Files\TortoiseHg\Mercurial.ini @@ -185,8 +192,8 @@ forest=C:\Program Files\TortoiseHg\ext\forest\forest.py Now, you need to clone the cubicweb repository. We assume that you use -Eclipse. From the IDE, choose File -> Import. In the box, select -`Mercurial/Clone repository using MercurialEclipse`. +Eclipse. From the IDE, choose File -> Import. In the box, select `Mercurial/Clone +repository using MercurialEclipse`. In the import main panel you just have to: @@ -194,28 +201,26 @@ * check the 'Repository is a forest' box. -Then, click on 'Finish'. It might take some time to get it all. Note -that the `cubicwin32` forest contains additional python packages such -as yapps, vobject, simplejson and twisted-web2 which are not provided -with Python(x,y). This is provided for convenience, as we do not -ensure the up-to-dateness of these packages, especially with respect -to security fixes. +Then, click on 'Finish'. It might take some time to get it all. Note that the +`cubicwin32` forest contains additional python packages such as yapps, vobject, +simplejson and twisted-web2 which are not provided with Python(x,y). This is +provided for convenience, as we do not ensure the up-to-dateness of these +packages, especially with respect to security fixes. Environment variables -_____________________ +~~~~~~~~~~~~~~~~~~~~~ -You will need some convenience environment variables once all is set -up. These variables are settable through the GUI by getting at the -'System properties' window (by righ-clicking on 'My Computer' -> -properties). +You will need some convenience environment variables once all is set up. These +variables are settable through the GUI by getting at the 'System properties' +window (by righ-clicking on 'My Computer' -> properties). -In the 'advanced' tab, there is an 'Environment variables' -button. Click on it. That opens a small window allowing edition of -user-related and system-wide variables. +In the 'advanced' tab, there is an 'Environment variables' button. Click on +it. That opens a small window allowing edition of user-related and system-wide +variables. -We will consider only user variables. First, the PATH variable. You -should ensure it contains, separated by semi-colons, and assuming you -are logged in as user Jane:: +We will consider only user variables. First, the PATH variable. You should ensure +it contains, separated by semi-colons, and assuming you are logged in as user +Jane:: C:\Documents and Settings\Jane\My Documents\Python\cubicweb\cubicweb\bin C:\Program Files\Graphviz2.24\bin @@ -231,13 +236,13 @@ ... and get a meaningful output. Running an instance as a service --------------------------------- +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -This currently assumes that the instances configurations is located -at C:\\etc\\cubicweb.d. +This currently assumes that the instances configurations is located at +C:\\etc\\cubicweb.d. -For a cube 'my_cube', you will then find C:\\etc\\cubicweb.d\\my_cube\\win32svc.py -that has to be used thusly:: +For a cube 'my_cube', you will then find +C:\\etc\\cubicweb.d\\my_cube\\win32svc.py that has to be used thusly:: win32svc install @@ -248,17 +253,6 @@ should start the service. -PostgreSQL installation -``````````````````````` - -Please refer to the `PostgreSQL project online documentation`_. - -.. _`PostgreSQL project online documentation`: http://www.postgresql.org/ - -You need to install the three following packages: `postgresql-8.3`, -`postgresql-contrib-8.3` and `postgresql-plpython-8.3`. - - Other dependencies `````````````````` @@ -271,103 +265,115 @@ * `python-ldap` if you plan to use a LDAP source on the server -.. _ConfigurationEnv: -Environment configuration -------------------------- - -If you installed *CubicWeb* by cloning the Mercurial forest, then you -will need to update the environment variable PYTHONPATH by adding -the path to the forest ``cubicweb``: - -Add the following lines to either `.bashrc` or `.bash_profile` to configure -your development environment :: - - export PYTHONPATH=/full/path/to/cubicweb-forest - -If you installed *CubicWeb* with packages, no configuration is required and your -new cubes will be placed in `/usr/share/cubicweb/cubes` and your instances -will be placed in `/etc/cubicweb.d`. - -You may run a system-wide install of *CubicWeb* in "user mode" and use it for -development by setting the following environment variable:: - - export CW_MODE=user - export CW_CUBES_PATH=~/lib/cubes - export CW_INSTANCES_DIR=~/etc/cubicweb.d/ - export CW_INSTANCES_DATA_DIR=$CW_INSTANCES_DIR - export CW_RUNTIME_DIR=/tmp - -.. note:: - The values given above are our suggestions but of course - can be different. - +.. _DatabaseInstallation: Databases configuration ----------------------- -.. _ConfigurationPostgresql: +Whatever the backend used, database connection information are stored in the +instance's :file:`sources` file. Currently cubicweb has been tested using +Postgresql (recommanded), MySQL, SQLServer and SQLite. + +.. _PostgresqlConfiguration: PostgreSQL configuration ```````````````````````` -.. note:: - If you already have an existing cluster and PostgreSQL server - running, you do not need to execute the initilization step - of your PostgreSQL database. +For installation, please refer to the `PostgreSQL project online documentation`_. + +.. _`PostgreSQL project online documentation`: http://www.postgresql.org/ + +You need to install the three following packages: `postgresql-8.X`, +`postgresql-client-8.X`, and `postgresql-plpython-8.X`. If you run postgres +version prior to 8.3, you'll also need the `postgresql-contrib-8.X` package for +full-text search extension. -* First, initialize the database PostgreSQL with the command ``initdb``. +If you run postgres on another host than the |cubicweb| repository, you should +install the `postgresql-client` package on the |cubicweb| host, and others on the +database host. + +.. Note:: + + If you already have an existing cluster and PostgreSQL server running, you do + not need to execute the initilization step of your PostgreSQL database unless + you want a specific cluster for |cubicweb| databases or if your existing + cluster doesn't use the UTF8 encoding (see note below). + +* First, initialize a PostgreSQL cluster with the command ``initdb``. :: - $ initdb -D /path/to/pgsql + $ initdb -E UTF8 -D /path/to/pgsql + + Notice the encoding specification. This is necessary since |cubicweb| usually + want UTF8 encoded database. If you use a cluster with the wrong encoding, you'll + get error like:: - Once initialized, start the database server PostgreSQL - with the command:: + new encoding (UTF8) is incompatible with the encoding of the template database (SQL_ASCII) + HINT: Use the same encoding as in the template database, or use template0 as template. + + + Once initialized, start the database server PostgreSQL with the command:: $ postgres -D /path/to/psql - If you cannot execute this command due to permission issues, please - make sure that your username has write access on the database. - :: + If you cannot execute this command due to permission issues, please make sure + that your username has write access on the database. :: $ chown username /path/to/pgsql -* The database authentication can be either set to `ident sameuser` - or `md5`. - If set to `md5`, make sure to use an existing user - of your database. - If set to `ident sameuser`, make sure that your - client's operating system user name has a matching user in - the database. If not, please do as follow to create a user:: +* The database authentication can be either set to `ident sameuser` or `md5`. If + set to `md5`, make sure to use an existing user of your database. If set to + `ident sameuser`, make sure that your client's operating system user name has a + matching user in the database. If not, please do as follow to create a user:: $ su $ su - postgres $ createuser -s -P username - The option `-P` (for password prompt), will encrypt the password with - the method set in the configuration file ``pg_hba.conf``. - If you do not use this option `-P`, then the default value will be null - and you will need to set it with:: + The option `-P` (for password prompt), will encrypt the password with the + method set in the configuration file :file:`pg_hba.conf`. If you do not use this + option `-P`, then the default value will be null and you will need to set it + with:: $ su postgres -c "echo ALTER USER username WITH PASSWORD 'userpasswd' | psql" - This login/password will be requested when you will create an - instance with `cubicweb-ctl create` to initialize the database of - your instance. - -.. note:: - The authentication method can be configured in ``pg_hba.conf``. +.. Note:: + The authentication method can be configured in file:`pg_hba.conf`. -.. FIXME Are these steps really necessary? It seemed to work without. +The above login/password will be requested when you will create an instance with +`cubicweb-ctl create` to initialize the database of your instance. -* Installation of plain-text index extension :: +Notice that the `cubicweb-ctl db-create` does database initialization that +may requires a postgres superuser. That's why a login/password is explicitly asked +at this step, so you can use there a superuser without using this user when running +the instance. Things that require special privileges at this step: + +* database creation, require the 'create database' permission +* install the plpython extension language (require superuser) +* install the tsearch extension for postgres version prior to 8.3 (require superuser) - cat /usr/share/postgresql/8.3/contrib/tsearch2.sql | psql -U username template1 +To avoid using a super user each time you create an install, a nice trick is to +install plpython (and tsearch when needed) on the special `template1` database, +so they will be installed automatically when cubicweb databases are created +without even with needs for special access rights. To do so, run :: + + # Installation of plpythonu language by default :: + $ createlang -U pgadmin plpythonu template1 + $ psql -U pgadmin template1 + template1=# update pg_language set lanpltrusted=TRUE where lanname='plpythonu'; -* Installation of plpythonu language by default :: +Where `pgadmin` is a postgres superuser. The last command is necessary since by +default plpython is an 'untrusted' language and as such can't be used by non +superuser. This update fix that problem by making it trusted. - createlang -U pgadmin plpythonu template1 +To install the tsearch plain-text index extension on postgres prior to 8.3, run:: + + cat /usr/share/postgresql/8.X/contrib/tsearch2.sql | psql -U username template1 + + +.. _MySqlConfiguration: MySql configuration ``````````````````` @@ -378,19 +384,22 @@ default-character-set=utf8 max_allowed_packet = 128M -.. note:: +.. Note:: It is unclear whether mysql supports indexed string of arbitrary lenght or not. + +.. _SQLServerConfiguration: + SQLServer configuration ------------------------ +``````````````````````` -As of this writing, sqlserver support is in progress. You should be -able to connect, create a database and go quite far, but some of the -generated SQL is still currently not accepted by the backend. +As of this writing, sqlserver support is in progress. You should be able to +connect, create a database and go quite far, but some of the generated SQL is +still currently not accepted by the backend. -The `source` configuration file may look like this (specific parts -only are shown):: +The `source` configuration file may look like this (specific parts only are +shown):: [system] db-driver=sqlserver2005 @@ -402,17 +411,43 @@ db-encoding=utf8 + +.. _SQLiteConfiguration: + +SQLite configuration +```````````````````` +SQLite has the great advantage of requiring almost no configuration. Simply +use 'sqlite' as db-driver, and set path to the dabase as db-name. Don't specify +anything for db-user and db-password, they will be ignore anyway. + +.. Note:: + SQLite is great for testing and to play with cubicweb but is not suited for + production environments. + + +.. _PyroConfiguration: + Pyro configuration ------------------ -If you use Pyro, it is required to have a name server Pyro running on your -network (by default it is detected by a broadcast request). +If you want to use Pyro to access your instance remotly, or to have multi-source +or distributed configuration, it is required to have a name server Pyro running +on your network. By by default it is detected by a broadcast request, but you can +specify a location in the instance's configuration file. To do so, you need to : -* launch the server manually before starting cubicweb as a server with - `pyro-nsd start` +* launch the server manually before starting cubicweb as a server with `pyro-nsd + start` + +* under debian, edit the file :file:`/etc/default/pyro-nsd` so that the name + server pyro will be launched automatically when the machine fire up + -* edit the file ``/etc/default/pyro-nsd`` so that the name server pyro - will be launched automatically when the machine fire up +Cubicweb resources configuration +-------------------------------- +.. autodocstring:: cubicweb.cwconfig + + +.. |cubicweb| replace:: *CubicWeb* diff -r 5e9055b8c10a -r 2543cfa5d54a doc/book/en/conf.py --- a/doc/book/en/conf.py Tue Apr 06 18:51:17 2010 +0200 +++ b/doc/book/en/conf.py Tue Apr 06 19:08:07 2010 +0200 @@ -19,6 +19,7 @@ # serve to show the default value. import sys, os + from cubicweb import __pkginfo__ as cw # If your extensions are in another directory, add it here. If the directory @@ -31,7 +32,7 @@ # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['sphinx.ext.autodoc'] +extensions = ['sphinx.ext.autodoc', 'logilab.common.sphinx_ext'] autoclass_content = 'both' # Add any paths that contain templates here, relative to this directory. templates_path = ['.templates'] diff -r 5e9055b8c10a -r 2543cfa5d54a doc/book/en/development/datamodel/definition.rst --- a/doc/book/en/development/datamodel/definition.rst Tue Apr 06 18:51:17 2010 +0200 +++ b/doc/book/en/development/datamodel/definition.rst Tue Apr 06 19:08:07 2010 +0200 @@ -11,21 +11,20 @@ At this point, it is important to make clear the difference between *relation type* and *relation definition*: a *relation type* is only a relation -name with potentially other additionnal properties (see below), whereas a +name with potentially other additional properties (see below), whereas a *relation definition* is a complete triplet " ". -A relation type could have been implied if none is related to a -relation definition of the schema. -Also, it should be clear that to properly handle data migration, an instance'schema -is stored in the database, so the python schema file used to defined it are only readen +Also, it should be clear that to properly handle data migration, an +instance's schema +is stored in the database, so the python schema file used to defined it is only read when the instance is created or upgraded. -The following built-in types are available : `String`, `Int`, `Float`, +The following built-in types are available: `String`, `Int`, `Float`, `Decimal`, `Boolean`, `Date`, `Datetime`, `Time`, `Interval`, `Byte` and `Password`. -You'll also have access to :ref:`base cubicweb entity types `. +You'll also have access to :ref:`base CubicWeb entity types `. The instance schema is accessible through the .schema attribute of the `vregistry`. It's an instance of :class:`cubicweb.schema.Schema`, which @@ -33,117 +32,127 @@ :note: In previous yams versions, almost all classes where available without - any import, but the should now be explicitely imported. + any import, but the should now be explicitly imported. Entity type ~~~~~~~~~~~ -It's an instance of :class:`yams.schema.EntitySchema`. Each entity types has -a set of attributes and relation and some permissions, defining who can add, read, +An entity type is an instance of :class:`yams.schema.EntitySchema`. Each entity type has +a set of attributes and relations, and some permissions which define who can add, read, update or delete entities of this type. XXX yams inheritance Relation type ~~~~~~~~~~~~~ -It's an instance of :class:`yams.schema.RelationSchema`. A relation type is simply -a semantic definition of a kind of relationship that may occurs in your application. +A relation type is an instance of :class:`yams.schema.RelationSchema`. A relation type is simply +a semantic definition of a kind of relationship that may occur in an application. -It's important to choose a good name, at least to avoid conflicts with some semantically -different relation defined in other cubes (since we've no namespace yet). +It is important to choose a good name, at least to avoid conflicts with some semantically +different relation defined in other cubes (since we've no name space yet). -A relation type hold the following properties (which are hence shared between all +A relation type holds the following properties (which are hence shared between all relation definitions of that type): -* `inlined` : boolean handling the physical optimization for archiving +* `inlined`: boolean handling the physical optimization for archiving the relation in the subject entity table, instead of creating a specific table for the relation. This applies to relations where cardinality of subject->relation->object is 0..1 (`?`) or 1..1 (`1`) for *all* its relation definitions. -* `symmetric` : boolean indicating that the relation is symmetrical, which +* `symmetric`: boolean indicating that the relation is symmetrical, which means that `X relation Y` implies `Y relation X`. Relation definition ~~~~~~~~~~~~~~~~~~~ -It's an instance of :class:`yams.schema.RelationDefinition`. It is a complete triplet +A relation definition is an instance of :class:`yams.schema.RelationDefinition`. It is a complete triplet " ". +When creating a new instance of that class, the corresponding +:class:`RelationType` instance is created on the fly if necessary. + + Properties `````````` -* Optional properties for attributes and relations : +* Optional properties for attributes and relations: - - `description` : a string describing an attribute or a relation. By default + - `description`: a string describing an attribute or a relation. By default this string will be used in the editing form of the entity, which means that it is supposed to help the end-user and should be flagged by the function `_` to be properly internationalized. - - `constraints` : a list of conditions/constraints that the relation has to + - `constraints`: a list of conditions/constraints that the relation has to satisfy (c.f. `Constraints`_) - - `cardinality` : a two character string which specify the cardinality of the + - `cardinality`: a two character string specifying the cardinality of the relation. The first character defines the cardinality of the relation on the subject, and the second on the object. When a relation can have multiple subjects or objects, the cardinality applies to all, not on a one-to-one basis (so it must be consistent...). The possible - values are inspired from regular expression syntax : + values are inspired from regular expression syntax: * `1`: 1..1 * `?`: 0..1 * `+`: 1..n * `*`: 0..n -* optional properties for attributes : +* optional properties for attributes: - - `unique` : boolean indicating if the value of the attribute has to be unique + - `unique`: boolean indicating if the value of the attribute has to be unique or not within all entities of the same type (false by default) - - `indexed` : boolean indicating if an index needs to be created for this + - `indexed`: boolean indicating if an index needs to be created for this attribute in the database (false by default). This is useful only if you know that you will have to run numerous searches on the value of this attribute. - - `default` : default value of the attribute. In case of date types, the values + - `default`: default value of the attribute. In case of date types, the values which could be used correspond to the RQL keywords `TODAY` and `NOW`. -* optional properties of type `String` : +* optional properties for type `String` attributes: - - `fulltextindexed` : boolean indicating if the attribute is part of + - `fulltextindexed`: boolean indicating if the attribute is part of the full text index (false by default) (*applicable on the type `Byte` as well*) - - `internationalizable` : boolean indicating if the value of the attribute + - `internationalizable`: boolean indicating if the value of the attribute is internationalizable (false by default) -* optional properties for relations : +* optional properties for relations: - - `composite` : string indicating that the subject (composite == 'subject') + - `composite`: string indicating that the subject (composite == 'subject') is composed of the objects of the relations. For the opposite case (when the object is composed of the subjects of the relation), we just set 'object' as value. The composition implies that when the relation is deleted (so when the composite is deleted, at least), the composed are also deleted. - - `fti_container`: XXX feed me + - `fulltext_container`: string indicating if the value if the full text + indexation of the entity on one end of the relation should be used + to find the entity on the other end. The possible values are + 'subject' or 'object'. For instance the use_email relation has + that property set to 'subject', since when performing a full text + search people want to find the entity using an email address, and not + the entity representing the email address. Constraints ``````````` -By default, the available constraint types are : +By default, the available constraint types are: General Constraints ...................... -* `SizeConstraint` : allows to specify a minimum and/or maximum size on +* `SizeConstraint`: allows to specify a minimum and/or maximum size on string (generic case of `maxsize`) -* `BoundConstraint` : allows to specify a minimum and/or maximum value on +* `BoundConstraint`: allows to specify a minimum and/or maximum value on numeric types -* `UniqueConstraint` : identical to "unique=True" +* `UniqueConstraint`: identical to "unique=True" -* `StaticVocabularyConstraint` : identical to "vocabulary=(...)" +* `StaticVocabularyConstraint`: identical to "vocabulary=(...)" XXX Attribute, TODAY, NOW @@ -159,39 +168,19 @@ displayed when the constraint fails. As RQLVocabularyConstraint never fails the third argument is not available. -* `RQLConstraint` : allows to specify a RQL query that has to be satisfied +* `RQLConstraint`: allows to specify a RQL query that has to be satisfied by the subject and/or the object of relation. In this query the variables - `S` and `O` are reserved for the entities subject and object of the - relation. + `S` and `O` are reserved for the relation subject and object entities. -* `RQLVocabularyConstraint` : similar to the previous type of constraint except +* `RQLVocabularyConstraint`: similar to the previous type of constraint except that it does not express a "strong" constraint, which means it is only used to restrict the values listed in the drop-down menu of editing form, but it does not prevent another entity to be selected. -* `RQLUniqueConstraint` : allows to the specify a RQL query that ensure that an +* `RQLUniqueConstraint`: allows to the specify a RQL query that ensure that an attribute is unique in a specific context. The Query must **never** return more than a single result to be satisfied. In this query the variables `S` is - reserved for the entity subject of the relation. The other variable should be - specified with the second constructor argument (mainvars). This constraints - should be used when UniqueConstraint doesn't fit. Here is a simple example :: - - # Check that in the same Workflow each state's name is unique. Using - # UniqueConstraint (or unique=True) here would prevent states in different - # workflows to have the same name. - - # With: State S, Workflow W, String N ; S state_of W, S name N - - RQLUniqueConstraint('S name N, S state_of WF, Y state_of WF, Y name N', - mainvars='Y', - msg=_('workflow already have a state of that name')) - - - -* `RQLUniqueConstraint` : allows to the specify a RQL query that ensure that an - attribute is unique in a specific context. The Query must **never** return more - than a single result to be satisfied. In this query the variables `S` is - reserved for the entity subject of the relation. The other variable should be + reserved for the relation subject entity. The other variables should be specified with the second constructor argument (mainvars). This constraints should be used when UniqueConstraint doesn't fit. Here is a simple example :: @@ -215,7 +204,7 @@ The security model ~~~~~~~~~~~~~~~~~~ -The security model of `cubicWeb` is based on `Access Control List`. +The security model of `CubicWeb` is based on `Access Control List`. The main principles are: * users and groups of users @@ -225,24 +214,25 @@ For *CubicWeb* in particular: -* we associate rights at the enttities/relations schema level -* for each entity, we distinguish four kind of permissions: read, - add, update and delete -* for each relation, we distinguish three kinds of permissions: read, - add and delete (we can not modify a relation) -* the basic groups are: Administrators, Users and Guests -* by default, users belong to the group Users -* there is a virtual group called `Owners` to which we - can associate only deletion and update permissions -* we can not add users to the `Owners` group, they are - implicitly added to it according to the context of the objects - they own -* the permissions of this group are only checked on update/deletion - actions if all the other groups the user belongs to does not provide - those permissions +* we associate rights at the entities/relations schema level +* for each entity, we distinguish four kinds of permissions: `read`, + `add`, `update` and `delete` +* for each relation, we distinguish three kinds of permissions: `read`, + `add` and `delete` (it is not possible to `modify` a relation) +* the default groups are: `administrators`, `users` and `guests` +* by default, users belong to the `users` group +* there is a virtual group called `owners` to which we + can associate only `delete` and `update` permissions + + * we can not add users to the `Owners` group, they are + implicitly added to it according to the context of the objects + they own + * the permissions of this group are only checked on `update`/`delete` + actions if all the other groups the user belongs to do not provide + those permissions Setting permissions is done with the attribute `__permissions__` of entities and -relation types. It defines a dictionary where the keys are the access types +relation types. The value of this attribute is a dictionary where the keys are the access types (action), and the values are the authorized groups or expressions. For an entity type, the possible actions are `read`, `add`, `update` and @@ -252,7 +242,7 @@ For each access type, a tuple indicates the name of the authorized groups and/or one or multiple RQL expressions to satisfy to grant access. The access is -provided if the user is in one of the listed groups or one of if the RQL condition +provided if the user is in one of the listed groups or if one of the RQL condition is satisfied. The standard user groups @@ -264,14 +254,14 @@ * `managers` -* `owners` : virtual group corresponding to the entity's owner. +* `owners`: virtual group corresponding to the entity's owner. This can only be used for the actions `update` and `delete` of an entity type. It is also possible to use specific groups if they are defined in the -precreate of the cube (``migration/precreate.py``). Defining groups in -postcreate or even later makes them NOT available for security -purposes (in this case, an `sync_schema_props_perms` command have to +precreate script of the cube (``migration/precreate.py``). Defining groups in +postcreate script or later makes them unavailable for security +purposes (in this case, an `sync_schema_props_perms` command has to be issued in a CubicWeb shell). @@ -280,13 +270,13 @@ It is possible to define RQL expression to provide update permission (`add`, `delete` and `update`) on relation and entity types. -RQL expression for entity type permission : +RQL expression for entity type permission: * you have to use the class `ERQLExpression` * the used expression corresponds to the WHERE statement of an RQL query -* in this expression, the variables X and U are pre-defined references +* in this expression, the variables `X` and `U` are pre-defined references respectively on the current entity (on which the action is verified) and on the user who send the request @@ -297,19 +287,19 @@ to this variable For RQL expressions on a relation type, the principles are the same except -for the following : +for the following: * you have to use the class `RRQLExpression` in the case of a non-final relation -* in the expression, the variables S, O and U are pre-defined references +* in the expression, the variables `S`, `O` and `U` are pre-defined references to respectively the subject and the object of the current relation (on which the action is being verified) and the user who executed the query * we can also define rights over attributes of an entity (non-final relation), - knowing that : + knowing that: - to define RQL expression, we have to use the class `ERQLExpression` - in which X represents the entity the attribute belongs to + in which `X` represents the entity the attribute belongs to - the permissions `add` and `delete` are equivalent. Only `add`/`read` are actually taken in consideration. @@ -333,7 +323,7 @@ Use of RQL expression for reading rights ```````````````````````````````````````` -The principles are the same but with the following restrictions : +The principles are the same but with the following restrictions: * we can not use `RRQLExpression` on relation types for reading @@ -348,19 +338,28 @@ Entity type definition ~~~~~~~~~~~~~~~~~~~~~~ -An entity type is defined by a Python class which inherits from `EntityType`. -The class definition contains the description of attributes and relations -for the defined entity type. -The class name corresponds to the entity type name. It is exepected to be -defined in the module ``mycube.schema``. +An entity type is defined by a Python class which inherits from +:class:`yams.buildobjs.EntityType`. The class definition contains the +description of attributes and relations for the defined entity type. +The class name corresponds to the entity type name. It is expected to +be defined in the module ``mycube.schema``. + +:Note on schema definition: + + The code in ``mycube.schema`` is not meant to be executed. The class + EntityType mentioned above is different from the EntitySchema class + described in the previous chapter. EntityType is a helper class to + make Entity definition easier. Yams will process EntityType classes + and create EntitySchema instances from these class definitions. Similar + manipulation happen for relations. When defining a schema using python files, you may use the following shortcuts: -- `required` : boolean indicating if the attribute is required, eg subject cardinality is '1' +- `required`: boolean indicating if the attribute is required, ed subject cardinality is '1' -- `vocabulary` : specify static possible values of an attribute +- `vocabulary`: specify static possible values of an attribute -- `maxsize` : integer providing the maximum size of a string (no limit by default) +- `maxsize`: integer providing the maximum size of a string (no limit by default) For example: @@ -382,6 +381,20 @@ birth and a relation that connects a `Person` to another entity of type `Company` through the semantic `works_for`. +:Naming convention: + + Entity class names must start with an uppercase letter. The common + usage is to use ``CamelCase`` names. + + Attribute and relation names must start with a lowercase letter. The + common usage is to use ``underscore_separated_words``. Attribute and + relation names starting with a single underscore are permitted, to + denote a somewhat "protected" or "private" attribute. + + In any case, identifiers starting with "CW" or "cw" are reserved for + internal use by the framework. + + The name of the Python attribute corresponds to the name of the attribute or the relation in *CubicWeb* application. @@ -390,29 +403,16 @@ attr_name = attr_type(properties) where `attr_type` is one of the type listed above and `properties` is -a list of the attribute needs to statisfy (see `Properties`_ +a list of the attribute needs to satisfy (see `Properties`_ for more details). - -* relations can be defined by using `ObjectRelation` or `SubjectRelation`. - The first argument of `SubjectRelation` or `ObjectRelation` gives respectively - the object/subject entity type of the relation. This could be : - - * a string corresponding to an entity type - - * a tuple of string corresponding to multiple entity types - - * special string such as follows : - - - "**" : all types of entities - - "*" : all types of non-meta entities - - "@" : all types of meta entities but not system entities (e.g. used for - the basic schema description) - * it is possible to use the attribute `meta` to flag an entity type as a `meta` (e.g. used to describe/categorize other entities) -*Note* : if you end up with an `if` in the definition of your entity, this probably +.. XXX the paragraph below needs clarification and / or moving out in +.. another place + +*Note*: if you end up with an `if` in the definition of your entity, this probably means that you need two separate entities that implement the `ITree` interface and get the result from `.children()` which ever entity is concerned. @@ -440,20 +440,49 @@ subject = '*' object = 'CWUser' -In the case of simultaneous relations definitions, `subject` and `object` -can both be equal to the value of the first argument of `SubjectRelation` -and `ObjectRelation`. +If provided, the `subject` and `object` attributes denote the subject +and object of the various relation definitions related to the relation +type. Allowed values for these attributes are: + +* a string corresponding to an entity type +* a tuple of string corresponding to multiple entity types +* special string such as follows: + + - "**": all types of entities + - "*": all types of non-meta entities + - "@": all types of meta entities but not system entities (e.g. used for + the basic schema description) When a relation is not inlined and not symmetrical, and it does not require -specific permissions, its definition (by using `SubjectRelation` and -`ObjectRelation`) is all we need. +specific permissions, it can be defined using a `SubjectRelation` +attribute in the EntityType class. The first argument of `SubjectRelation` gives +the entity type for the object of the relation. + +:Naming convention: + + Although this way of defining relations uses a Python class, the + naming convention defined earlier prevails over the PEP8 conventions + used in the framework: relation type class names use + ``underscore_separated_words``. +:Historical note: + + It has been historically possible to use `ObjectRelation` which + defines a relation in the opposite direction. This feature is soon to be + deprecated and therefore should not be used in newly written code. + +:Future deprecation note: + + In an even more remote future, it is quite possible that the + SubjectRelation shortcut will become deprecated, in favor of the + RelationType declaration which offers some advantages in the context + of reusable cubes. Definition of permissions ~~~~~~~~~~~~~~~~~~~~~~~~~~ The entity type `CWPermission` from the standard library allows to build very complex and dynamic security architectures. The schema of -this entity type is as follow : +this entity type is as follow: .. sourcecode:: python @@ -461,12 +490,12 @@ """entity type that may be used to construct some advanced security configuration """ name = String(required=True, indexed=True, internationalizable=True, maxsize=100) - require_group = SubjectRelation('CWGroup', cardinality='+*', + require_group = SubjectRelation('CWGroup', cardinality='+*', description=_('groups to which the permission is granted')) - require_state = SubjectRelation('State', + require_state = SubjectRelation('State', description=_("entity's state in which the permission is applicable")) # can be used on any entity - require_permission = ObjectRelation('**', cardinality='*1', composite='subject', + require_permission = ObjectRelation('**', cardinality='*1', composite='subject', description=_("link a permission to the entity. This " "permission should be used in the security " "definition of the entity's type to be useful.")) @@ -502,7 +531,7 @@ This configuration indicates that an entity `CWPermission` named "add_version" can be associated to a project and provides rights to create -new versions on this project to specific groups. It is important to notice that : +new versions on this project to specific groups. It is important to notice that: * in such case, we have to protect both the entity type "Version" and the relation associating a version to a project ("version_of") diff -r 5e9055b8c10a -r 2543cfa5d54a doc/book/en/development/devcore/appobject.rst --- a/doc/book/en/development/devcore/appobject.rst Tue Apr 06 18:51:17 2010 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +0,0 @@ - - -The `AppObject` class -~~~~~~~~~~~~~~~~~~~~~ - -In general: - -* we do not inherit directly from this class but from a more specific - class such as `AnyEntity`, `EntityView`, `AnyRsetView`, - `Action`... - -* to be recordable, a subclass has to define its own register (attribute - `__registry__`) and its identifier (attribute `id`). Usually we do not have - to take care of the register, only the identifier `id`. - -We can find a certain number of attributes and methods defined in this class -and common to all the application objects. - -At recording time, the following attributes are dynamically added to -the *subclasses*: - -* `vreg`, the `vregistry` of the instance -* `schema`, the instance schema -* `config`, the instance configuration - -We also find on instances, the following attributes: - -* ._cw`, `Request` instance -* `rset`, the *result set* associated to the object if necessary - -:URL handling: - * `build_url(*args, **kwargs)`, returns an absolute URL based on the - given arguments. The *controller* supposed to handle the response, - can be specified through the first positional parameter (the - connection is theoretically done automatically :). - -:Data manipulation: - - * `entity(row, col=0)`, returns the entity corresponding to the data position - in the *result set* associated to the object - - * `complete_entity(row, col=0, skip_bytes=True)`, is equivalent to `entity` but - also call the method `complete()` on the entity before returning it - -:Data formatting: - * `format_date(date, date_format=None, time=False)` returns a string for a - date time according to instance's configuration - * `format_time(time)` returns a string for a date time according to - instance's configuration - -:And more...: - - * `tal_render(template, variables)`, renders a precompiled page template with - variables in the given dictionary as context - -.. note:: - When we inherit from `AppObject` (even not directly), you *always* have to use - **super()** to get the methods and attributes of the superclasses, and not - use the class identifier. - - For example, instead of writting: :: - - class Truc(PrimaryView): - def f(self, arg1): - PrimaryView.f(self, arg1) - - You must write: :: - - class Truc(PrimaryView): - def f(self, arg1): - super(Truc, self).f(arg1) diff -r 5e9055b8c10a -r 2543cfa5d54a doc/book/en/development/devcore/cwconfig.rst --- a/doc/book/en/development/devcore/cwconfig.rst Tue Apr 06 18:51:17 2010 +0200 +++ b/doc/book/en/development/devcore/cwconfig.rst Tue Apr 06 19:08:07 2010 +0200 @@ -1,5 +1,5 @@ :mod:`Configuration ` ---------------------------------------- -.. automodule:: cubicweb.cwconfig - :members: +.. .. automodule:: cubicweb.cwconfig +.. :members: diff -r 5e9055b8c10a -r 2543cfa5d54a doc/book/en/development/devcore/index.rst --- a/doc/book/en/development/devcore/index.rst Tue Apr 06 18:51:17 2010 +0200 +++ b/doc/book/en/development/devcore/index.rst Tue Apr 06 19:08:07 2010 +0200 @@ -4,9 +4,7 @@ .. toctree:: :maxdepth: 1 - vreg.rst - appobject.rst - selectors.rst dbapi.rst + reqbase.rst cwconfig.rst diff -r 5e9055b8c10a -r 2543cfa5d54a doc/book/en/development/devcore/reqbase.rst --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/book/en/development/devcore/reqbase.rst Tue Apr 06 19:08:07 2010 +0200 @@ -0,0 +1,30 @@ + +Those are methods you'll find on both request objects and on repository session: + +:URL handling: + * `build_url(*args, **kwargs)`, returns an absolute URL based on the + given arguments. The *controller* supposed to handle the response, + can be specified through the first positional parameter (the + connection is theoretically done automatically :). +:Data formatting: + * `format_date(date, date_format=None, time=False)` returns a string for a + date time according to instance's configuration + + * `format_time(time)` returns a string for a date time according to + instance's configuration + +:And more...: + + * `tal_render(template, variables)`, renders a precompiled page template with + variables in the given dictionary as context + + +Result set methods: + + * `get_entity(row, col)`, returns the entity corresponding to the data position + in the *result set* + + * `complete_entity(row, col, skip_bytes=True)`, is equivalent to `get_entity` but + also call the method `complete()` on the entity before returning it + + diff -r 5e9055b8c10a -r 2543cfa5d54a doc/book/en/development/devcore/selectors.rst --- a/doc/book/en/development/devcore/selectors.rst Tue Apr 06 18:51:17 2010 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,89 +0,0 @@ -Base selectors --------------- - -Selectors are scoring functions that are called by the registry to tell whenever -an appobject can be selected in a given context. Selector sets are for instance -the glue that tie views to the data model. Using them appropriately is an -essential part of the construction of well behaved cubes. - -Of course you may have to write your own set of selectors as your needs grows and -you get familiar with the framework (see :ref:`CustomSelectors`). - -Here is a description of generic selectors provided by CubicWeb that should suit -most of your needs. - -Bare selectors -~~~~~~~~~~~~~~ -Those selectors are somewhat dumb, which doesn't mean they're not (very) useful. - -.. autoclass:: cubicweb.appobject.yes -.. autoclass:: cubicweb.selectors.match_kwargs -.. autoclass:: cubicweb.selectors.appobject_selectable - - -Result set selectors -~~~~~~~~~~~~~~~~~~~~~ -Those selectors are looking for a result set in the context ('rset' argument or -the input context) and match or not according to its shape. Some of these -selectors have different behaviour if a particular cell of the result set is -specified using 'row' and 'col' arguments of the input context or not. - -.. autoclass:: cubicweb.selectors.none_rset -.. autoclass:: cubicweb.selectors.any_rset -.. autoclass:: cubicweb.selectors.nonempty_rset -.. autoclass:: cubicweb.selectors.empty_rset -.. autoclass:: cubicweb.selectors.one_line_rset -.. autoclass:: cubicweb.selectors.multi_lines_rset -.. autoclass:: cubicweb.selectors.multi_columns_rset -.. autoclass:: cubicweb.selectors.paginated_rset -.. autoclass:: cubicweb.selectors.sorted_rset -.. autoclass:: cubicweb.selectors.one_etype_rset -.. autoclass:: cubicweb.selectors.multi_etypes_rset - - -Entity selectors -~~~~~~~~~~~~~~~~ -Those selectors are looking for either an `entity` argument in the input context, -or entity found in the result set ('rset' argument or the input context) and -match or not according to entity's (instance or class) properties. - -.. autoclass:: cubicweb.selectors.non_final_entity -.. autoclass:: cubicweb.selectors.implements -.. autoclass:: cubicweb.selectors.score_entity -.. autoclass:: cubicweb.selectors.rql_condition -.. autoclass:: cubicweb.selectors.relation_possible -.. autoclass:: cubicweb.selectors.partial_relation_possible -.. autoclass:: cubicweb.selectors.has_related_entities -.. autoclass:: cubicweb.selectors.partial_has_related_entities -.. autoclass:: cubicweb.selectors.has_permission -.. autoclass:: cubicweb.selectors.has_add_permission - - -Logged user selectors -~~~~~~~~~~~~~~~~~~~~~ -Those selectors are looking for properties of the user issuing the request. - -.. autoclass:: cubicweb.selectors.anonymous_user -.. autoclass:: cubicweb.selectors.authenticated_user -.. autoclass:: cubicweb.selectors.match_user_groups - - -Web request selectors -~~~~~~~~~~~~~~~~~~~~~ -Those selectors are looking for properties of *web* request, they can not be -used on the data repository side. - -.. autoclass:: cubicweb.selectors.match_form_params -.. autoclass:: cubicweb.selectors.match_search_state -.. autoclass:: cubicweb.selectors.match_context_prop -.. autoclass:: cubicweb.selectors.match_view -.. autoclass:: cubicweb.selectors.primary_view -.. autoclass:: cubicweb.selectors.specified_etype_implements - - -Other selectors -~~~~~~~~~~~~~~~ -.. autoclass:: cubicweb.selectors.match_transition - -You'll also find some other (very) specific selectors hidden in other modules -than :mod:`cubicweb.selectors`. diff -r 5e9055b8c10a -r 2543cfa5d54a doc/book/en/development/devcore/vreg.rst --- a/doc/book/en/development/devcore/vreg.rst Tue Apr 06 18:51:17 2010 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,220 +0,0 @@ -The VRegistry --------------- - -The recording process on startup -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Details of the recording process -```````````````````````````````` - -.. index:: - vregistry: registration_callback - -On startup, |cubicweb| have to fill the vregistry with appobjects defined -in its library and in cubes used by the instance. Appobjects from the library -are loaded first, then appobjects provided by cubes are loaded in an ordered -way (e.g. if your cube depends on an other, appobjects from the dependancy will -be loaded first). Cube's modules or packages where appobject are looked at is explained -in :ref:`cubelayout`. - -For each module: - -* by default all objects are registered automatically - -* if some objects have to replace other objects or be included only if a - condition is true, you'll have to define a `registration_callback(vreg)` - function in your module and explicitly register *all objects* in this - module, using the vregistry api defined below. - -.. note:: - Once the function `registration_callback(vreg)` is implemented, all the objects - have to be explicitly registered as it disables the automatic object registering. - - -API d'enregistrement des objets -``````````````````````````````` -.. automethod:: cubicweb.cwvreg.CubicWebVRegistry.register_all -.. automethod:: cubicweb.cwvreg.CubicWebVRegistry.register_and_replace -.. automethod:: cubicweb.cwvreg.CubicWebVRegistry.register -.. automethod:: cubicweb.cwvreg.CubicWebVRegistry.register_if_interface_found -.. automethod:: cubicweb.cwvreg.CubicWebVRegistry.unregister - - -Examples -```````` -.. sourcecode:: python - - # web/views/basecomponents.py - def registration_callback(vreg): - # register everything in the module except SeeAlsoComponent - vreg.register_all(globals().values(), __name__, (SeeAlsoVComponent,)) - # conditionally register SeeAlsoVComponent - if 'see_also' in vreg.schema: - vreg.register(SeeAlsoVComponent) - - # goa/appobjects/sessions.py - def registration_callback(vreg): - vreg.register(SessionsCleaner) - # replace AuthenticationManager by GAEAuthenticationManager - vreg.register_and_replace(GAEAuthenticationManager, AuthenticationManager) - # replace PersistentSessionManager by GAEPersistentSessionManager - vreg.register_and_replace(GAEPersistentSessionManager, PersistentSessionManager) - - -Runtime objects selection -~~~~~~~~~~~~~~~~~~~~~~~~~ - -Using and combining existant selectors -`````````````````````````````````````` - -The object's selector is defined by its `__select__` class attribute. - -When two selectors are combined using the `&` operator (formerly `chainall`), it -means that both should return a positive score. On success, the sum of scores is returned. - -When two selectors are combined using the `|` operator (former `chainfirst`), it -means that one of them should return a positive score. On success, the first -positive score is returned. - -You can also "negate" a selector by precedeing it by the `~` operator. - -Of course you can use paren to balance expressions. - - -For instance, if you are selecting the primary (eg `__regid__ = 'primary'`) view (eg -`__registry__ = 'view'`) for a result set containing a `Card` entity, 2 objects -will probably be selectable: - -* the default primary view (`__select__ = implements('Any')`), meaning - that the object is selectable for any kind of entity type - -* the specific `Card` primary view (`__select__ = implements('Card')`, - meaning that the object is selectable for Card entities - -Other primary views specific to other entity types won't be selectable -in this case. Among selectable objects, the implements selector will -return a higher score than the second view since it's more specific, -so it will be selected as expected. - - -Example -```````` - -The goal: when on a Blog, one wants the RSS link to refer to blog -entries, not to the blog entity itself. - -To do that, one defines a method on entity classes that returns the -RSS stream url for a given entity. The default implementation on -AnyEntity and a specific implementation on Blog will do what we want. - -But when we have a result set containing several Blog entities (or -different entities), we don't know on which entity to call the -aforementioned method. In this case, we keep the current behaviour -(e.g : call to limited_rql). - -Hence we have two cases here, one for a single-entity rsets, the other -for multi-entities rsets. - -In web/views/boxes.py lies the RSSIconBox class. Look at its selector :: - - class RSSIconBox(ExtResourcesBoxTemplate): - """just display the RSS icon on uniform result set""" - __select__ = ExtResourcesBoxTemplate.__select__ & non_final_entity() - -It takes into account: - -* the inherited selection criteria (one has to look them up in the - class hierarchy to know the details) - -* non_final_entity, which filters on rsets containing non final - entities (a 'final entity' being synonym for entity attribute) - -This matches our second case. Hence we have to provide a specific -component for the first case:: - - class EntityRSSIconBox(RSSIconBox): - """just display the RSS icon on uniform result set for a single entity""" - __select__ = RSSIconBox.__select__ & one_line_rset() - -Here, one adds the one_line_rset selector, which filters result sets -of size 1. When one chains selectors, the final score is the sum of -the score of each individual selector (unless one of them returns 0, -in which case the object is non selectable). Thus, on a multiple -entities selector, one_line_rset makes the EntityRSSIconBox class non -selectable. For an rset with one entity, the EntityRSSIconBox class -will have a higher score then RSSIconBox, which is what we wanted. - -Of course, once this is done, you have to: - -* fill in the call method of EntityRSSIconBox - -* provide the default implementation of the method returning the RSS - stream url on AnyEntity - -* redefine this method on Blog. - -When to use selectors? -`````````````````````` - -Selectors are to be used whenever arises the need of dispatching on the shape or -content of a result set or whatever else context (value in request form params, -authenticated user groups, etc...). That is, almost all the time. - -XXX add and example of a single view w/ big "if" inside splitted into two views -with appropriate selectors. - - -.. CustomSelectors_ - -Defining your own selectors -``````````````````````````` -.. autoclass:: cubicweb.appobject.Selector - :members: __call__ - -.. autofunction:: cubicweb.appobject.objectify_selector -.. autofunction:: cubicweb.selectors.lltrace - -Selectors __call__ should *always* return a positive integer, and shall never -return `None`. - -Useful abstract base classes for 'entity' selectors: - -.. autoclass:: cubicweb.selectors.EClassSelector -.. autoclass:: cubicweb.selectors.EntitySelector - - -Debugging -````````` - -Once in a while, one needs to understand why a view (or any AppObject) -is, or is not selected appropriately. Looking at which selectors fired -(or did not) is the way. There exists a traced_selection context -manager to help with that, *if you're running your instance in debug mode*. - -Here is an example: - -.. sourcecode:: python - - from cubicweb.selectors import traced_selection - with traced_selection(): - mycomp = self._cw.vreg['views'].select('wfhistory', self._cw, rset=rset) - -Don't forget the 'from __future__ import with_statement' at the module -top-level if you're using python 2.5. - -This will yield additional WARNINGs in the logs, like this:: - - 2009-01-09 16:43:52 - (cubicweb.selectors) WARNING: selector one_line_rset returned 0 for - -You can also give to traced_selection the registry ids of objects on which to debug -you want to debug selection ('wfhistory' in the example above). - -Also, if you're using python 2.4, which as no 'with' yet, you'll have to to it -the following way: - -.. sourcecode:: python - - from cubicweb import selectors - selectors.TRACED_OIDS = ('wfhistory',) - mycomp = self._cw.vreg['views'].select('wfhistory', self._cw, rset=rset) - selectors.TRACED_OIDS = () diff -r 5e9055b8c10a -r 2543cfa5d54a doc/book/en/development/devweb/index.rst --- a/doc/book/en/development/devweb/index.rst Tue Apr 06 18:51:17 2010 +0200 +++ b/doc/book/en/development/devweb/index.rst Tue Apr 06 19:08:07 2010 +0200 @@ -12,7 +12,6 @@ property rtags views - gettingdata form facets httpcaching diff -r 5e9055b8c10a -r 2543cfa5d54a doc/book/en/development/devweb/internationalization.rst --- a/doc/book/en/development/devweb/internationalization.rst Tue Apr 06 18:51:17 2010 +0200 +++ b/doc/book/en/development/devweb/internationalization.rst Tue Apr 06 19:08:07 2010 +0200 @@ -15,7 +15,7 @@ * in your Python code and cubicweb-tal templates : mark translatable strings -* in your instance : handle the translation catalog +* in your instance : handle the translation catalog, edit translations String internationalization ~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -50,8 +50,9 @@ itself, but not its translation (it's actually another name for the `unicode` builtin). -In the other hand the request's method `self._cw._` is meant to retrieve the -proper translation of translation strings in the requested language. +In the other hand the request's method `self._cw._` is also meant to +retrieve the proper translation of translation strings in the +requested language. Finally you can also use the `__` attribute of request object to get a translation for a string *which should not itself added to the catalog*, @@ -62,14 +63,15 @@ In this example ._cw.__` is used instead of ._cw._` so we don't have 'This %s' in messages catalogs. - Translations in cubicweb-tal template can also be done with TAL tags `i18n:content` and `i18n:replace`. - If you need to add messages on top of those that can be found in the source, you can create a file named `i18n/static-messages.pot`. +You could put there messages not found in the python sources or +overrides for some messages of used cubes. + Generated string ```````````````` @@ -80,20 +82,20 @@ For exemple the following schema :: Class EntityA(EntityType): - relationa2b = SubjectRelation('EntityB') + relation_a2b = SubjectRelation('EntityB') class EntityB(EntityType): pass May generate the following message :: - add Execution has_export File subject + add EntityA relation_a2b EntityB subject This message will be used in views of ``EntityA`` for creation of a new ``EntityB`` with a preset relation ``relation_a2b`` between the current ``EntityA`` and the new ``EntityB``. The opposite message :: - add Execution has_export File object + add EntityA relation_a2b EntityB object Is used for similar creation of an ``EntityA`` from a view of ``EntityB``. The title of they respective creation form will be :: @@ -105,8 +107,8 @@ In the translated string you can use ``%(linkto)s`` for reference to the source ``entity``. -Handle the translation catalog -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Handling the translation catalog +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Once the internationalization is done in your code, you need to populate and update the translation catalog. Cubicweb provides the following commands for this @@ -117,11 +119,11 @@ catalogs. Unless you actually work on the framework itself, you don't need to use this command. -* `i18ncube` updates the translation catalogs of *one particular - cube* (or of all cubes). After this command is - executed you must update the translation files *.po* in the "i18n" - directory of your template. This command will of course not remove - existing translations still in use. +* `i18ncube` updates the translation catalogs of *one particular cube* + (or of all cubes). After this command is executed you must update + the translation files *.po* in the "i18n" directory of your + cube. This command will of course not remove existing translations + still in use. It will mark unused translation but not remove them. * `i18ninstance` recompiles the translation catalogs of *one particular instance* (or of all instances) after the translation catalogs of @@ -134,6 +136,7 @@ Example ``````` + You have added and/or modified some translation strings in your cube (after creating a new view or modifying the cube's schema for exemple). To update the translation catalogs you need to do: @@ -143,3 +146,77 @@ 3. `hg ci -m "updated i18n catalogs"` 4. `cubicweb-ctl i18ninstance ` +Editing po files +~~~~~~~~~~~~~~~~ + +Using a PO aware editor +```````````````````````` + +Many tools exist to help maintain .po (PO) files. Common editors or +development environment provides modes for these. One can also find +dedicated PO files editor, such as `poedit`_. + +.. _`poedit`: http://www.poedit.net/ + +While usage of such a tool is commendable, PO files are perfectly +editable with a (unicode aware) plain text editor. It is also useful +to know their structure for troubleshooting purposes. + +Structure of a PO file +`````````````````````` + +In this section, we selectively quote passages of the `GNU gettext`_ +manual chapter on PO files, available there:: + + http://www.gnu.org/software/hello/manual/gettext/PO-Files.html + +One PO file entry has the following schematic structure:: + + white-space + # translator-comments + #. extracted-comments + #: reference... + #, flag... + #| msgid previous-untranslated-string + msgid untranslated-string + msgstr translated-string + + +A simple entry can look like this:: + + #: lib/error.c:116 + msgid "Unknown system error" + msgstr "Error desconegut del sistema" + +It is also possible to have entries with a context specifier. They +look like this:: + + white-space + # translator-comments + #. extracted-comments + #: reference... + #, flag... + #| msgctxt previous-context + #| msgid previous-untranslated-string + msgctxt context + msgid untranslated-string + msgstr translated-string + + +The context serves to disambiguate messages with the same +untranslated-string. It is possible to have several entries with the +same untranslated-string in a PO file, provided that they each have a +different context. Note that an empty context string and an absent +msgctxt line do not mean the same thing. + +Contexts and CubicWeb +````````````````````` + +CubicWeb PO files have both non-contextual and contextual msgids. + +Contextual entries are automatically used in some cases. For instance, +entity.dc_type(), eschema.display_name(req) or display_name(etype, +req, form, context) methods/function calls will use them. + +It is also possible to explicitly use the with _cw.pgettext(context, +msgid). diff -r 5e9055b8c10a -r 2543cfa5d54a doc/book/en/development/devweb/js.rst --- a/doc/book/en/development/devweb/js.rst Tue Apr 06 18:51:17 2010 +0200 +++ b/doc/book/en/development/devweb/js.rst Tue Apr 06 19:08:07 2010 +0200 @@ -54,12 +54,224 @@ ajax request, otherwise the document itself for standard HTTP requests. +Important AJAX APIS +~~~~~~~~~~~~~~~~~~~ -Overview of what's available +* `jQuery.fn.loadxhtml` is an important extension to jQuery which + allow proper loading and in-place DOM update of xhtml views. It is + suitably augmented to trigger necessary events, and process CubicWeb + specific elements such as the facet system, fckeditor, etc. + +* `asyncRemoteExec` and `remoteExec` are the base building blocks for + doing arbitrary async (resp. sync) communications with the server + +A simple example with asyncRemoteExec +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In the python side, we have to extend the BaseController class. The +@jsonize decorator ensures that the `return value` of the method is +encoded as JSON data. By construction, the JSonController inputs +everything in JSON format. + +.. sourcecode: python + + from cubicweb.web.views.basecontrollers import JSonController, jsonize + + @monkeypatch(JSonController) + @jsonize + def js_say_hello(self, name): + return u'hello %s' % name + +In the javascript side, we do the asynchronous call. Notice how it +creates a `deferred` object. Proper treatment of the return value or +error handling has to be done through the addCallback and addErrback +methods. + +.. sourcecode: javascript + + function async_hello(name) { + var deferred = asyncRemoteExec('say_hello', name); + deferred.addCallback(function (response) { + alert(response); + }); + deferred.addErrback(function () { + alert('something fishy happened'); + }); + } + + function sync_hello(name) { + alert( remoteExec('say_hello', name) ); + } + +A simple example with loadxhtml +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Here we are concerned with the retrieval of a specific view to be +injected in the live DOM. The view will be of course selected +server-side using an entity eid provided by the client side. + +.. sourcecode: python + + from cubicweb import typed_eid + from cubicweb.web.views.basecontrollers import JSonController, xhtmlize + + @monkeypatch(JSonController) + @xhtmlize + def js_frob_status(self, eid, frobname): + entity = self._cw.entity_from_eid(typed_eid(eid)) + return entity.view('frob', name=frobname) + +.. sourcecode: javascript + + function update_some_div(divid, eid, frobname) { + var params = {fname:'frob_status', eid: eid, frobname:frobname}; + jQuery('#'+divid).loadxhtml(JSON_BASE_URL, params, 'post'); + } + +In this example, the url argument is the base json url of a cube +instance (it should contain something like +`http://myinstance/json?`). The actual JSonController method name is +encoded in the `params` dictionnary using the `fname` key. + +A more real-life example from CubicWeb +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A frequent use case of Web 2 applications is the delayed (or +on-demand) loading of pieces of the DOM. This is typically achieved +using some preparation of the initial DOM nodes, jQuery event handling +and proper use of loadxhtml. + +We present here a skeletal version of the mecanism used in CubicWeb +and available in web/views/tabs.py, in the `LazyViewMixin` class. + +.. sourcecode: python + + def lazyview(self, vid, rql=None): + """ a lazy version of wview """ + w = self.w + self._cw.add_js('cubicweb.lazy.js') + urlparams = {'vid' : vid, 'fname' : 'view'} + if rql is not None: + urlparams['rql'] = rql + w(u'
' % ( + vid, xml_escape(self._cw.build_url('json', **urlparams)))) + w(u'
') + self._cw.add_onload(u""" + jQuery('#lazy-%(vid)s').bind('%(event)s', function() { + load_now('#lazy-%(vid)s');});""" + % {'event': 'load_%s' % vid, 'vid': vid}) + +This creates a `div` with an specific event associated to it. + +The full version deals with: + +* optional parameters such as an entity eid, an rset + +* the ability to further reload the fragment + +* the ability to display a spinning wheel while the fragment is still + not loaded + +* handling of browsers that do not support ajax (search engines, + text-based browsers such as lynx, etc.) + +The javascript side is quite simple, due to loadxhtml awesomeness. + +.. sourcecode: javascript + + function load_now(eltsel) { + var lazydiv = jQuery(eltsel); + lazydiv.loadxhtml(lazydiv.attr('cubicweb:loadurl')); + } + +This is all significantly different of the previous `simple example` +(albeit this example actually comes from real-life code). + +Notice how the `cubicweb:loadurl` is used to convey the url +information. The base of this url is similar to the global javascript +JSON_BASE_URL. According to the pattern described earlier, +the `fname` parameter refers to the standard `js_view` method of the +JSonController. This method renders an arbitrary view provided a view +id (or `vid`) is provided, and most likely an rql expression yielding +a result set against which a proper view instance will be selected. + +The `cubicweb:loadurl` is one of the 29 attributes extensions to XHTML +in a specific cubicweb namespace. It is a means to pass information +without breaking HTML nor XHTML compliance and without resorting to +ungodly hacks. + +Given all this, it is easy to add a small nevertheless useful feature +to force the loading of a lazy view (for instance, a very +computation-intensive web page could be scinded into one fast-loading +part and a delayed part). + +In the server side, a simple call to a javascript function is +sufficient. + +.. sourcecode: python + + def forceview(self, vid): + """trigger an event that will force immediate loading of the view + on dom readyness + """ + self._cw.add_onload("trigger_load('%s');" % vid) + +The browser-side definition follows. + +.. sourcecode: javascript + + function trigger_load(divid) { + jQuery('#lazy-' + divd).trigger('load_' + divid); + } + + +Anatomy of a lodxhtml call +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The loadxhtml extension to jQuery accept many parameters with rich +semantics. Let us detail these. + +* `url` (mandatory) should be a complete url, typically based on the + JSonController, but this is not strictly mandatory + +* `data` (optional) is a dictionnary of values given to the + controller specified through an `url` argument; some keys may have a + special meaning depending on the choosen controller (such as `fname` + for the JSonController); the `callback` key, if present, must refer + to a function to be called at the end of loadxhtml (more on this + below) + +* `reqtype` (optional) specifies the request method to be used (get or + post); if the argument is 'post', then the post method is used, + otherwise the get method is used + +* `mode` (optional) is one of `replace` (the default) which means the + loaded node will replace the current node content, `swap` to replace + the current node with the loaded node, and `append` which will + append the loaded node to the current node content + + +About the `callback` option: + +* it is called with two parameters: the current node, and a list + containing the loaded (and post-processed node) + +* whenever is returns another function, this function is called in + turn with the same parameters as above + +This mecanism allows callback chaining. + + +Javascript library: overview ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * jquery.* : jquery and jquery UI library +* cubicweb.ajax.js : concentrates all ajax related facilities (it + extends jQuery with the loahxhtml function, provides a handfull of + high-level ajaxy operations like asyncRemoteExec, reloadComponent, + replacePageChunk, getDomFromResponse) + * cubicweb.python.js : adds a number of practical extension to stdanrd javascript objects (on Date, Array, String, some list and dictionary operations), and a pythonesque way to build classes. Defines a @@ -69,11 +281,6 @@ in various other cubicweb javascript resources (baseuri, progress cursor handling, popup login box, html2dom function, etc.) -* cubicweb.ajax.js : concentrates all ajax related facilities (it - extends jQuery with the loahxhtml function, provides a handfull of - high-level ajaxy operations like asyncRemoteExec, reloadComponent, - replacePageChunk, getDomFromResponse) - * cubicweb.widgets.js : provides a widget namespace and constructors and helpers for various widgets (mainly facets and timeline) @@ -83,5 +290,6 @@ * cubicweb.facets.js : used by the facets mechanism -xxx massmailing, gmap, fckcwconfig, timeline-bundle, timeline-ext, -calendar, goa, flotn tazy, tabs, bookmarks +There is also javascript support for massmailing, gmap (google maps), +fckcwconfig (fck editor), timeline, calendar, goa (CubicWeb over +AppEngine), flot (charts drawing), tabs and bookmarks. diff -r 5e9055b8c10a -r 2543cfa5d54a doc/book/en/development/entityclasses/application-logic.rst --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/book/en/development/entityclasses/application-logic.rst Tue Apr 06 19:08:07 2010 +0200 @@ -0,0 +1,166 @@ +How to use entities objects +--------------------------- + +The previous chapters detailed the classes and methods available to +the developper at the so-called `ORM`_ level. However they say little +about the common patterns of usage of these objects. + +.. _`ORM`: http://en.wikipedia.org/wiki/Object-relational_mapping + +Entities objects are used in the repository and web sides of +CubicWeb. In the repository side of things, one should manipulate them +in Hooks and Operations. + +Hooks and Operations provide support for the implementation of rules +such as computed attributes, coherency invariants, etc (they play the +same role as database triggers, but in a way that is independant of +the actual data sources). + +So a lot of an application's business rules will be written in Hooks +(or Operations). + +In the web side, views also typically operate using entity +objects. Obvious entity methods for use in views are the dublin code +method like dc_title, etc. For separation of concerns reasons, one +should ensure no ui logic pervades the entities level, and also no +business logic should creep into the views. + +In the duration of a transaction, entities objects can be instantiated +many times, in views and hooks, even for the same database entity. For +instance, in a classic CubicWeb deployment setup, the repository and +the web frontend are separated process communicating over the +wire. There is no way state can be shared between these processes +(there is a specific API for that). Hence, it is not possible to use +entity objects as messengers between these components of an +application. It means that an attribute set as in `obj.x = 42`, +whether or not x is actually an entity schema attribute, has a short +life span, limited to the hook, operation or view within which the +object was built. + +Setting an attribute or relation value can be done in the context of a +Hook/Operation, using the obj.set_attributes(x=42) notation or a plain +RQL SET expression. + +In views, it would be preferable to encapsulate the necessary logic in +a method of the concerned entity class(es). But of course, this advice +is also reasonnable for Hooks/Operations, though the separation of +concerns here is less stringent than in the case of views. + +This leads to the practical role of entity objects: it's where an +important part of the application logic lie (the other part being +located in the Hook/Operations). + +Anatomy of an entity class +-------------------------- + +We can look now at a real life example coming from the `tracker`_ +cube. Let us begin to study the entities/project.py content. + +.. sourcecode:: python + + class Project(TreeMixIn, AnyEntity): + __regid__ = 'Project' + __implements__ = AnyEntity.__implements__ + (ITree,) + fetch_attrs, fetch_order = fetch_config(('name', 'description', + 'description_format', 'summary')) + + TICKET_DEFAULT_STATE_RESTR = 'S name IN ("created","identified","released","scheduled")' + + tree_attribute = 'subproject_of' + parent_target = 'subject' + children_target = 'object' + + def dc_title(self): + return self.name + +First we see that it uses an ITree interface and the TreeMixIn default +implementation. The attributes `tree_attribute`, `parent_target` and +`children_target` are used by the TreeMixIn code. This is typically +used in views concerned with the representation of tree-like +structures (CubicWeb provides several such views). + +It is important that the views themselves try not to implement this +logic, not only because such views would be hardly applyable to other +tree-like relations, but also because it is perfectly fine and useful +to use such an interface in Hooks. + +In fact, Tree nature is a property of the data model that cannot be +fully and portably expressed at the level of database entities (think +about the transitive closure of the child relation). This is a further +argument to implement it at entity class level. + +The `dc_title` method provides a (unicode string) value likely to be +consummed by views, but note that here we do not care about output +encodings. We care about providing data in the most universal format +possible, because the data could be used by a web view (which would be +responsible of ensuring XHTML compliance), or a console or file +oriented output (which would have the necessary context about the +needed byte stream encoding). + +The fetch_attrs, fetch_order class attributes are parameters of the +`ORM`_ layer. They tell which attributes should be loaded at once on +entity object instantiation (by default, only the eid is known, other +attributes are loaded on demand), and which attribute is to be used to +order the .related() and .unrelated() methods output. + +Finally, we can observe the big TICKET_DEFAULT_STATE_RESTR is a pure +application domain piece of data. There is, of course, no limitation +to the amount of class attributes of this kind. + +Let us now dig into more substantial pieces of code. + +.. sourcecode:: python + + def latest_version(self, states=('published',), reverse=None): + """returns the latest version(s) for the project in one of the given + states. + + when no states specified, returns the latest published version. + """ + order = 'DESC' + if reverse is not None: + warn('reverse argument is deprecated', + DeprecationWarning, stacklevel=1) + if reverse: + order = 'ASC' + rset = self.versions_in_state(states, order, True) + if rset: + return rset.get_entity(0, 0) + return None + + def versions_in_state(self, states, order='ASC', limit=False): + """returns version(s) for the project in one of the given states, sorted + by version number. + + If limit is true, limit result to one version. + If reverse, versions are returned from the smallest to the greatest. + """ + if limit: + order += ' LIMIT 1' + rql = 'Any V,N ORDERBY version_sort_value(N) %s ' \ + 'WHERE V num N, V in_state S, S name IN (%s), ' \ + 'V version_of P, P eid %%(p)s' % (order, ','.join(repr(s) for s in states)) + return self._cw.execute(rql, {'p': self.eid}) + +.. _`tracker`: http://www.cubicweb.org/project/cubicweb-tracker/ + +These few lines exhibit the important properties we want to outline: + +* entity code is concerned with the application domain + +* it is NOT concerned with database coherency (this is the realm of + Hooks/Operations); in other words, it assumes a coherent world + +* it is NOT concerned with end-user interfaces + +* however it can be used in both contexts + +* it does not create or manipulate the internal object's state + +* it plays freely with RQL expression as needed + +* it is not concerned with internationalization + +* it does not raise exceptions + + diff -r 5e9055b8c10a -r 2543cfa5d54a doc/book/en/development/entityclasses/data-as-objects.rst --- a/doc/book/en/development/entityclasses/data-as-objects.rst Tue Apr 06 18:51:17 2010 +0200 +++ b/doc/book/en/development/entityclasses/data-as-objects.rst Tue Apr 06 19:08:07 2010 +0200 @@ -17,6 +17,7 @@ :Formatting and output generation: * `view(vid, **kwargs)`, applies the given view to the entity + (and returns an unicode string) * `absolute_url(**kwargs)`, returns an absolute URL to access the primary view of an entity @@ -32,22 +33,30 @@ * `as_rset()`, converts the entity into an equivalent result set simulating the request `Any X WHERE X eid _eid_` - * `complete(skip_bytes=True)`, executes a request that recovers all at once - all the missing attributes of an entity + * `complete(skip_bytes=True)`, executes a request that recovers at + once all the missing attributes of an entity * `get_value(name)`, returns the value associated to the attribute name given in parameter - * `related(rtype, x='subject', limit=None, entities=False)`, returns a list - of entities related to the current entity by the relation given in parameter + * `related(rtype, role='subject', limit=None, entities=False)`, + returns a list of entities related to the current entity by the + relation given in parameter - * `unrelated(rtype, targettype, x='subject', limit=None)`, returns a result set - corresponding to the entities not related to the current entity by the - relation given in parameter and satisfying its constraints + * `unrelated(rtype, targettype, role='subject', limit=None)`, + returns a result set corresponding to the entities not (yet) + related to the current entity by the relation given in parameter + and satisfying its constraints * `set_attributes(**kwargs)`, updates the attributes list with the corresponding values given named parameters + * `set_relations(**kwargs)`, add relations to the given object. To + set a relation where this entity is the object of the relation, + use 'reverse_' as argument name. Values may be an + entity, a list of entities, or None (meaning that all relations of + the given type from or to this object should be deleted). + * `copy_relations(ceid)`, copies the relations of the entities having the eid given in the parameters on the current entity @@ -66,8 +75,10 @@ and helps specializing (by further subclassing) the handling of a given entity type. -The methods defined for `AnyEntity`, in addition to `Entity`, are the -following ones: +Most methods defined for `AnyEntity`, in addition to `Entity`, add +support for the `Dublin Core`_ metadata. + +.. _`Dublin Core`: http://dublincore.org/ :Standard meta-data (Dublin Core): @@ -85,12 +96,26 @@ * `dc_authors()`, returns a unicode string corresponding to the meta-data `Authors` (owners by default) + * `dc_creator()`, returns a unicode string corresponding to the + creator of the entity + * `dc_date(date_format=None)`, returns a unicode string corresponding to the meta-data `Date` (update date by default) * `dc_type(form='')`, returns a string to display the entity type by specifying the preferred form (`plural` for a plural form) + * `dc_language()`, returns the language used by the entity + + +:Misc methods: + + * `after_deletion_path`, return (path, parameters) which should be + used as redirect information when this entity is being deleted + + * `pre_web_edit`, callback called by the web editcontroller when an + entity will be created/modified, to let a chance to do some entity + specific stuff (does nothing by default) Inheritance ----------- diff -r 5e9055b8c10a -r 2543cfa5d54a doc/book/en/development/entityclasses/index.rst --- a/doc/book/en/development/entityclasses/index.rst Tue Apr 06 18:51:17 2010 +0200 +++ b/doc/book/en/development/entityclasses/index.rst Tue Apr 06 19:08:07 2010 +0200 @@ -10,4 +10,4 @@ data-as-objects load-sort interfaces - more + application-logic diff -r 5e9055b8c10a -r 2543cfa5d54a doc/book/en/development/entityclasses/interfaces.rst --- a/doc/book/en/development/entityclasses/interfaces.rst Tue Apr 06 18:51:17 2010 +0200 +++ b/doc/book/en/development/entityclasses/interfaces.rst Tue Apr 06 19:08:07 2010 +0200 @@ -1,7 +1,9 @@ Interfaces ---------- -Same thing as object-oriented programming interfaces. +This is the same thing as object-oriented programming `interfaces`_. + +.. _`interfaces`: http://java.sun.com/docs/books/tutorial/java/concepts/interface.html Definition of an interface is quite trivial. An example from cubicweb itself (found in cubicweb/interfaces.py): @@ -17,7 +19,7 @@ """returns the item's children""" def children_rql(self): - """XXX returns RQL to get children""" + """returns RQL to get children""" def iterchildren(self): """iterates over the item's children""" diff -r 5e9055b8c10a -r 2543cfa5d54a doc/book/en/development/entityclasses/more.rst --- a/doc/book/en/development/entityclasses/more.rst Tue Apr 06 18:51:17 2010 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,14 +0,0 @@ -Navigation on deletion ----------------------- - -XXX after_deletion_path, pre_web_edit - -Controlling output url ------------------------ - -XXX write me - -Controling notification references ----------------------------------- - -XXX write me diff -r 5e9055b8c10a -r 2543cfa5d54a doc/book/en/development/index.rst --- a/doc/book/en/development/index.rst Tue Apr 06 18:51:17 2010 +0200 +++ b/doc/book/en/development/index.rst Tue Apr 06 19:08:07 2010 +0200 @@ -11,12 +11,13 @@ :numbered: cubes/index + vreg.rst datamodel/index entityclasses/index devcore/index devweb/index devrepo/index - testing/index - migration/index + testing.rst + migration.rst webstdlib/index - profiling/index + profiling.rst diff -r 5e9055b8c10a -r 2543cfa5d54a doc/book/en/development/migration.rst --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/book/en/development/migration.rst Tue Apr 06 19:08:07 2010 +0200 @@ -0,0 +1,198 @@ +.. -*- coding: utf-8 -*- + +.. _migration: + +Migration +========= + +One of the main design goals of *CubicWeb* was to support iterative and agile +development. For this purpose, multiple actions are provided to facilitate the +improvement of an instance, and in particular to handle the changes to be +applied to the data model, without loosing existing data. + +The current version of a cube (and of cubicweb itself) is provided in the file +`__pkginfo__.py` as a tuple of 3 integers. + +Migration scripts management +---------------------------- + +Migration scripts has to be located in the directory `migration` of your +cube and named accordingly: + +:: + + [_]_.py + +in which : + +* X.Y.Z is the model version number to which the script enables to migrate. + +* *mode* (between the last "_" and the extension ".py") is used for + distributed installation. It indicates to which part + of the application (RQL server, web server) the script applies. + Its value could be : + + * `common`, applies to the RQL server as well as the web server and updates + files on the hard drive (configuration files migration for example). + + * `web`, applies only to the web server and updates files on the hard drive. + + * `repository`, applies only to the RQL server and updates files on the + hard drive. + + * `Any`, applies only to the RQL server and updates data in the database + (schema and data migration for example). + +Again in the directory `migration`, the file `depends.map` allows to indicate +that for the migration to a particular model version, you always have to first +migrate to a particular *CubicWeb* version. This file can contain comments (lines +starting by `#`) and a dependancy is listed as follows: :: + + : + +For example: :: + + 0.12.0: 2.26.0 + 0.13.0: 2.27.0 + # 0.14 works with 2.27 <= cubicweb <= 2.28 at least + 0.15.0: 2.28.0 + +Base context +------------ + +The following identifiers are pre-defined in migration scripts: + +* `config`, instance configuration + +* `interactive_mode`, boolean indicating that the script is executed in + an interactive mode or not + +* `versions_map`, dictionary of migrated versions (key are cubes + names, including 'cubicweb', values are (from version, to version) + +* `confirm(question)`, function asking the user and returning true + if the user answers yes, false otherwise (always returns true in + non-interactive mode) + +* the function `_`, it is equivalent to `unicode` allowing to flag the strings + to internationalize in the migration scripts. + +In the `repository` scripts, the following identifiers are also defined: + +* `checkpoint`, request confirming and executing a "commit" at checking point + +* `schema`, instance schema (readen from the database) + +* `fsschema`, installed schema on the file system (e.g. schema of + the updated model and cubicweb) + +* `repo`, repository object + +* `session`, repository session object + + +Schema migration +---------------- +The following functions for schema migration are available in `repository` +scripts: + +* `add_attribute(etype, attrname, attrtype=None, commit=True)`, adds a new + attribute to an existing entity type. If the attribute type is not specified, + then it is extracted from the updated schema. + +* `drop_attribute(etype, attrname, commit=True)`, removes an attribute from an + existing entity type. + +* `rename_attribute(etype, oldname, newname, commit=True)`, renames an attribute + +* `add_entity_type(etype, auto=True, commit=True)`, adds a new entity type. + If `auto` is True, all the relations using this entity type and having a known + entity type on the other hand will automatically be added. + +* `drop_entity_type(etype, commit=True)`, removes an entity type and all the + relations using it. + +* `rename_entity_type(oldname, newname, commit=True)`, renames an entity type + +* `add_relation_type(rtype, addrdef=True, commit=True)`, adds a new relation + type. If `addrdef` is True, all the relations definitions of this type will + be added. + +* `drop_relation_type(rtype, commit=True)`, removes a relation type and all the + definitions of this type. + +* `rename_relation(oldname, newname, commit=True)`, renames a relation. + +* `add_relation_definition(subjtype, rtype, objtype, commit=True)`, adds a new + relation definition. + +* `drop_relation_definition(subjtype, rtype, objtype, commit=True)`, removes + a relation definition. + +* `sync_schema_props_perms(ertype=None, syncperms=True, syncprops=True, syncrdefs=True, commit=True)`, + synchronizes properties and/or permissions on: + - the whole schema if ertype is None + - an entity or relation type schema if ertype is a string + - a relation definition if ertype is a 3-uple (subject, relation, object) + +* `change_relation_props(subjtype, rtype, objtype, commit=True, **kwargs)`, changes + properties of a relation definition by using the named parameters of the properties + to change. + +* `set_widget(etype, rtype, widget, commit=True)`, changes the widget used for the + relation of entity type . + +* `set_size_constraint(etype, rtype, size, commit=True)`, changes the size constraints + for the relation of entity type . + +Data migration +-------------- +The following functions for data migration are available in `repository` scripts: + +* `rql(rql, kwargs=None, cachekey=None, ask_confirm=True)`, executes an arbitrary RQL + query, either to interrogate or update. A result set object is returned. + +* `add_entity(etype, *args, **kwargs)`, adds a nes entity type of the given + type. The attribute and relation values are specified using the named and + positionned parameters. + +Workflow creation +----------------- + +The following functions for workflow creation are available in `repository` +scripts: + +* `add_workflow(label, workflowof, initial=False, commit=False, **kwargs)`, adds a new workflow + for a given type(s) + +You can find more details about workflows in the chapter :ref:`Workflow` . + +Configuration migration +----------------------- + +The following functions for configuration migration are available in all +scripts: + +* `option_renamed(oldname, newname)`, indicates that an option has been renamed + +* `option_group_change(option, oldgroup, newgroup)`, indicates that an option does not + belong anymore to the same group. + +* `option_added(oldname, newname)`, indicates that an option has been added. + +* `option_removed(oldname, newname)`, indicates that an option has been deleted. + + +Others migration functions +-------------------------- +Those functions are only used for low level operations that could not be +accomplished otherwise or to repair damaged databases during interactive +session. They are available in `repository` scripts: + +* `sql(sql, args=None, ask_confirm=True)`, executes an arbitrary SQL query on the system source +* `add_entity_type_table(etype, commit=True)` +* `add_relation_type_table(rtype, commit=True)` +* `uninline_relation(rtype, commit=True)` + + +[FIXME] Add explanation on how to use cubicweb-ctl shell diff -r 5e9055b8c10a -r 2543cfa5d54a doc/book/en/development/migration/index.rst --- a/doc/book/en/development/migration/index.rst Tue Apr 06 18:51:17 2010 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,198 +0,0 @@ -.. -*- coding: utf-8 -*- - -.. _migration: - -Migration -========= - -One of the main design goals of *CubicWeb* was to support iterative and agile -development. For this purpose, multiple actions are provided to facilitate the -improvement of an instance, and in particular to handle the changes to be -applied to the data model, without loosing existing data. - -The current version of a cube (and of cubicweb itself) is provided in the file -`__pkginfo__.py` as a tuple of 3 integers. - -Migration scripts management ----------------------------- - -Migration scripts has to be located in the directory `migration` of your -cube and named accordingly: - -:: - - [_]_.py - -in which : - -* X.Y.Z is the model version number to which the script enables to migrate. - -* *mode* (between the last "_" and the extension ".py") is used for - distributed installation. It indicates to which part - of the application (RQL server, web server) the script applies. - Its value could be : - - * `common`, applies to the RQL server as well as the web server and updates - files on the hard drive (configuration files migration for example). - - * `web`, applies only to the web server and updates files on the hard drive. - - * `repository`, applies only to the RQL server and updates files on the - hard drive. - - * `Any`, applies only to the RQL server and updates data in the database - (schema and data migration for example). - -Again in the directory `migration`, the file `depends.map` allows to indicate -that for the migration to a particular model version, you always have to first -migrate to a particular *CubicWeb* version. This file can contain comments (lines -starting by `#`) and a dependancy is listed as follows: :: - - : - -For example: :: - - 0.12.0: 2.26.0 - 0.13.0: 2.27.0 - # 0.14 works with 2.27 <= cubicweb <= 2.28 at least - 0.15.0: 2.28.0 - -Base context ------------- - -The following identifiers are pre-defined in migration scripts: - -* `config`, instance configuration - -* `interactive_mode`, boolean indicating that the script is executed in - an interactive mode or not - -* `versions_map`, dictionary of migrated versions (key are cubes - names, including 'cubicweb', values are (from version, to version) - -* `confirm(question)`, function asking the user and returning true - if the user answers yes, false otherwise (always returns true in - non-interactive mode) - -* the function `_`, it is equivalent to `unicode` allowing to flag the strings - to internationalize in the migration scripts. - -In the `repository` scripts, the following identifiers are also defined: - -* `checkpoint`, request confirming and executing a "commit" at checking point - -* `schema`, instance schema (readen from the database) - -* `fsschema`, installed schema on the file system (e.g. schema of - the updated model and cubicweb) - -* `repo`, repository object - -* `session`, repository session object - - -Schema migration ----------------- -The following functions for schema migration are available in `repository` -scripts: - -* `add_attribute(etype, attrname, attrtype=None, commit=True)`, adds a new - attribute to an existing entity type. If the attribute type is not specified, - then it is extracted from the updated schema. - -* `drop_attribute(etype, attrname, commit=True)`, removes an attribute from an - existing entity type. - -* `rename_attribute(etype, oldname, newname, commit=True)`, renames an attribute - -* `add_entity_type(etype, auto=True, commit=True)`, adds a new entity type. - If `auto` is True, all the relations using this entity type and having a known - entity type on the other hand will automatically be added. - -* `drop_entity_type(etype, commit=True)`, removes an entity type and all the - relations using it. - -* `rename_entity_type(oldname, newname, commit=True)`, renames an entity type - -* `add_relation_type(rtype, addrdef=True, commit=True)`, adds a new relation - type. If `addrdef` is True, all the relations definitions of this type will - be added. - -* `drop_relation_type(rtype, commit=True)`, removes a relation type and all the - definitions of this type. - -* `rename_relation(oldname, newname, commit=True)`, renames a relation. - -* `add_relation_definition(subjtype, rtype, objtype, commit=True)`, adds a new - relation definition. - -* `drop_relation_definition(subjtype, rtype, objtype, commit=True)`, removes - a relation definition. - -* `sync_schema_props_perms(ertype=None, syncperms=True, syncprops=True, syncrdefs=True, commit=True)`, - synchronizes properties and/or permissions on: - - the whole schema if ertype is None - - an entity or relation type schema if ertype is a string - - a relation definition if ertype is a 3-uple (subject, relation, object) - -* `change_relation_props(subjtype, rtype, objtype, commit=True, **kwargs)`, changes - properties of a relation definition by using the named parameters of the properties - to change. - -* `set_widget(etype, rtype, widget, commit=True)`, changes the widget used for the - relation of entity type . - -* `set_size_constraint(etype, rtype, size, commit=True)`, changes the size constraints - for the relation of entity type . - -Data migration --------------- -The following functions for data migration are available in `repository` scripts: - -* `rql(rql, kwargs=None, cachekey=None, ask_confirm=True)`, executes an arbitrary RQL - query, either to interrogate or update. A result set object is returned. - -* `add_entity(etype, *args, **kwargs)`, adds a nes entity type of the given - type. The attribute and relation values are specified using the named and - positionned parameters. - -Workflow creation ------------------ - -The following functions for workflow creation are available in `repository` -scripts: - -* `add_workflow(label, workflowof, initial=False, commit=False, **kwargs)`, adds a new workflow - for a given type(s) - -You can find more details about workflows in the chapter :ref:`Workflow` . - -Configuration migration ------------------------ - -The following functions for configuration migration are available in all -scripts: - -* `option_renamed(oldname, newname)`, indicates that an option has been renamed - -* `option_group_change(option, oldgroup, newgroup)`, indicates that an option does not - belong anymore to the same group. - -* `option_added(oldname, newname)`, indicates that an option has been added. - -* `option_removed(oldname, newname)`, indicates that an option has been deleted. - - -Others migration functions --------------------------- -Those functions are only used for low level operations that could not be -accomplished otherwise or to repair damaged databases during interactive -session. They are available in `repository` scripts: - -* `sql(sql, args=None, ask_confirm=True)`, executes an arbitrary SQL query on the system source -* `add_entity_type_table(etype, commit=True)` -* `add_relation_type_table(rtype, commit=True)` -* `uninline_relation(rtype, commit=True)` - - -[FIXME] Add explanation on how to use cubicweb-ctl shell diff -r 5e9055b8c10a -r 2543cfa5d54a doc/book/en/development/profiling.rst --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/book/en/development/profiling.rst Tue Apr 06 19:08:07 2010 +0200 @@ -0,0 +1,55 @@ +Profiling and performance +========================= + +If you feel that one of your pages takes more time than it should to be +generated, chances are that you're making too many RQL queries. Obviously, +there are other reasons but experience tends to show this is the first thing to +track down. Luckily, CubicWeb provides a configuration option to log RQL +queries. In your ``all-in-one.conf`` file, set the **query-log-file** option:: + + # web application query log file + query-log-file=~/myapp-rql.log + +Then restart your application, reload your page and stop your application. +The file ``myapp-rql.log`` now contains the list of RQL queries that were +executed during your test. It's a simple text file containing lines such as:: + + Any A WHERE X eid %(x)s, X lastname A {'x': 448} -- (0.002 sec, 0.010 CPU sec) + Any A WHERE X eid %(x)s, X firstname A {'x': 447} -- (0.002 sec, 0.000 CPU sec) + +The structure of each line is:: + + --