# HG changeset patch # User sylvain.thenault@logilab.fr # Date 1239089423 -7200 # Node ID 01152fffd593b08fe2886997644827836b59a23d # Parent 76b3cd5d4f3138d08364abaf74fa16b1791a1ffe# Parent abaadb570626bcffad7f3f339323f6f051b4fa98 backport default branch diff -r 76b3cd5d4f31 -r 01152fffd593 .hgtags --- a/.hgtags Mon Apr 06 12:37:45 2009 +0200 +++ b/.hgtags Tue Apr 07 09:30:23 2009 +0200 @@ -18,3 +18,11 @@ a8e9e53b245d53838a07aa8c76d1bed352692a9f cubicweb-debian-version-3_0_9-1 a711c7c185d15a1bd22b7eaab46a26b98b74fbf3 cubicweb-version-3_1_0 dd3efdf58d281286d6f52f7416db349b75b7789c cubicweb-debian-version-3_1_0-1 +ce8094084165419ff1717bdb2f426574bcaaad93 cubicweb-version-3_1_1 +dfaedb0bba88e3a4e931948bb0c6a9587269303f cubicweb-debian-version-3_1_1-1 +a9ba200ab15098704a6255387c558c02488551c6 cubicweb-version-3_1_2 +a823124b812f4fa494bfceb773f3ca1cd00407e8 cubicweb-debian-version-3_1_2-1 +a5dc91adb7c133f83f5ad9cceb07bc246d21ed01 cubicweb-version-3_1_3 +9e98dec0768b87363a7826a04636dc161ed0ec7d cubicweb-debian-version-3_1_3-1 +e0e0a1c3d80f4fbf4bbd55066278e467b75df8a4 cubicweb-version-3_1_4 +0e132fbae9cc5e004f4b79a8b842addad43519a7 cubicweb-debian-version-3_1_4-1 diff -r 76b3cd5d4f31 -r 01152fffd593 MANIFEST.in --- a/MANIFEST.in Mon Apr 06 12:37:45 2009 +0200 +++ b/MANIFEST.in Tue Apr 07 09:30:23 2009 +0200 @@ -25,6 +25,6 @@ recursive-include web/test/data *.js *.css *.png *.gif *.jpg *.ico external_resources recursive-include devtools/test/data * -recursive-include skeleton *.py*.css *.js *.po compat *.in *.tmpl +recursive-include skeleton *.py *.css *.js *.po compat *.in *.tmpl prune misc/cwfs diff -r 76b3cd5d4f31 -r 01152fffd593 __init__.py --- a/__init__.py Mon Apr 06 12:37:45 2009 +0200 +++ b/__init__.py Tue Apr 07 09:30:23 2009 +0200 @@ -4,7 +4,7 @@ :organization: Logilab :copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved. :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr -:license: General Public License version 2 - http://www.gnu.org/licenses +:license: Library General Public License version 2 - http://www.gnu.org/licenses """ __docformat__ = "restructuredtext en" from cubicweb.__pkginfo__ import version as __version__ diff -r 76b3cd5d4f31 -r 01152fffd593 __pkginfo__.py --- a/__pkginfo__.py Mon Apr 06 12:37:45 2009 +0200 +++ b/__pkginfo__.py Tue Apr 07 09:30:23 2009 +0200 @@ -6,10 +6,10 @@ distname = "cubicweb" modname = "cubicweb" -numversion = (3, 1, 0) +numversion = (3, 1, 4) version = '.'.join(str(num) for num in numversion) -license = 'GPL' +license = 'LGPL v2' copyright = '''Copyright (c) 2003-2009 LOGILAB S.A. (Paris, FRANCE). http://www.logilab.fr/ -- mailto:contact@logilab.fr''' diff -r 76b3cd5d4f31 -r 01152fffd593 _exceptions.py --- a/_exceptions.py Mon Apr 06 12:37:45 2009 +0200 +++ b/_exceptions.py Tue Apr 07 09:30:23 2009 +0200 @@ -2,7 +2,7 @@ :organization: Logilab -:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved. :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr """ __docformat__ = "restructuredtext en" diff -r 76b3cd5d4f31 -r 01152fffd593 common/mixins.py --- a/common/mixins.py Mon Apr 06 12:37:45 2009 +0200 +++ b/common/mixins.py Tue Apr 07 09:30:23 2009 +0200 @@ -193,6 +193,7 @@ """change the entity's state according to a state defined in given parameters """ + assert not isinstance(stateeid, basestring), 'change_state wants a state eid' if trcomment: self.req.set_shared_data('trcomment', trcomment) if trcommentformat: diff -r 76b3cd5d4f31 -r 01152fffd593 common/registerers.py --- a/common/registerers.py Mon Apr 06 12:37:45 2009 +0200 +++ b/common/registerers.py Tue Apr 07 09:30:23 2009 +0200 @@ -70,6 +70,8 @@ def equivalent(self, other): if use_interfaces(self.vobject) != use_interfaces(other): return False + if getattr(self.vobject, 'require_groups', ()) != getattr(other, 'require_groups', ()): + return False try: newaccepts = list(other.accepts) for etype in self.vobject.accepts: diff -r 76b3cd5d4f31 -r 01152fffd593 common/selectors.py diff -r 76b3cd5d4f31 -r 01152fffd593 common/uilib.py --- a/common/uilib.py Mon Apr 06 12:37:45 2009 +0200 +++ b/common/uilib.py Tue Apr 07 09:30:23 2009 +0200 @@ -165,21 +165,27 @@ if add_ellipsis: return text + u'...' return text - -def text_cut(text, nbwords=30): + +def text_cut(text, nbwords=30, gotoperiod=True): """from the given plain text, return a text with at least words, trying to go to the end of the current sentence. + :param nbwords: the minimum number of words required + :param gotoperiod: specifies if the function should try to go to + the first period after the cut (i.e. finish + the sentence if possible) + Note that spaces are normalized. """ if text is None: return u'' words = text.split() text = u' '.join(words) # normalize spaces - minlength = len(' '.join(words[:nbwords])) - textlength = text.find('.', minlength) + 1 - if textlength == 0: # no point found - textlength = minlength + textlength = minlength = len(' '.join(words[:nbwords])) + if gotoperiod: + textlength = text.find('.', minlength) + 1 + if textlength == 0: # no period found + textlength = minlength return text[:textlength] def cut(text, length): diff -r 76b3cd5d4f31 -r 01152fffd593 cwconfig.py --- a/cwconfig.py Mon Apr 06 12:37:45 2009 +0200 +++ b/cwconfig.py Tue Apr 07 09:30:23 2009 +0200 @@ -2,7 +2,7 @@ """common configuration utilities for cubicweb :organization: Logilab -:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved. :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr """ __docformat__ = "restructuredtext en" @@ -10,7 +10,7 @@ import sys import os import logging -from os.path import exists, join, expanduser, abspath, basename +from os.path import exists, join, expanduser, abspath, normpath, basename, isdir from logilab.common.decorators import cached from logilab.common.logging_ext import set_log_methods, init_log @@ -141,7 +141,7 @@ file(join(CUBES_DIR, '__init__.py'), 'w').close() elif exists(join(CW_SOFTWARE_ROOT, '.hg')): mode = 'dev' - CUBES_DIR = join(CW_SOFTWARE_ROOT, '../cubes') + CUBES_DIR = abspath(normpath(join(CW_SOFTWARE_ROOT, '../cubes'))) else: mode = 'installed' CUBES_DIR = '/usr/share/cubicweb/cubes/' @@ -219,7 +219,7 @@ """ if cls.mode in ('dev', 'test') and not os.environ.get('APYCOT_ROOT'): return join(CW_SOFTWARE_ROOT, 'web') - return join(cls.cubes_dir(), 'shared') + return cls.cube_dir('shared') @classmethod def i18n_lib_dir(cls): @@ -230,26 +230,38 @@ @classmethod def available_cubes(cls): - cubes_dir = cls.cubes_dir() - return sorted(cube for cube in os.listdir(cubes_dir) - if os.path.isdir(os.path.join(cubes_dir, cube)) - and not cube in ('CVS', '.svn', 'shared', '.hg')) + cubes = set() + for directory in cls.cubes_search_path(): + for cube in os.listdir(directory): + if isdir(join(directory, cube)) and not cube in ('CVS', '.svn', 'shared', '.hg'): + cubes.add(cube) + return sorted(cubes) @classmethod - def cubes_dir(cls): - """return the application cubes directory""" - return env_path('CW_CUBES', cls.CUBES_DIR, 'cubes') + def cubes_search_path(cls): + """return the path of directories where cubes should be searched""" + path = [] + try: + for directory in os.environ['CW_CUBES_PATH'].split(os.pathsep): + directory = abspath(normpath(directory)) + if exists(directory) and not directory in path: + path.append(directory) + except KeyError: + pass + if not cls.CUBES_DIR in path: + path.append(cls.CUBES_DIR) + return path @classmethod def cube_dir(cls, cube): """return the cube directory for the given cube id, raise ConfigurationError if it doesn't exists """ - cube_dir = join(cls.cubes_dir(), cube) - if not exists(cube_dir): - raise ConfigurationError('no cube %s in %s' % ( - cube, cls.cubes_dir())) - return cube_dir + for directory in cls.cubes_search_path(): + cubedir = join(directory, cube) + if exists(cubedir): + return cubedir + raise ConfigurationError('no cube %s in %s' % (cube, cls.cubes_search_path())) @classmethod def cube_migration_scripts_dir(cls, cube): @@ -335,12 +347,14 @@ @classmethod def cls_adjust_sys_path(cls): """update python path if necessary""" + cubes_parent_dir = normpath(join(cls.CUBES_DIR, '..')) + if not cubes_parent_dir in sys.path: + sys.path.insert(0, cubes_parent_dir) try: - templdir = abspath(join(cls.cubes_dir(), '..')) - if not templdir in sys.path: - sys.path.insert(0, templdir) - except ConfigurationError: - return # cube dir doesn't exists + import cubes + cubes.__path__ = cls.cubes_search_path() + except ImportError: + return # cubes dir doesn't exists @classmethod def load_cwctl_plugins(cls): @@ -352,10 +366,9 @@ if exists(join(CW_SOFTWARE_ROOT, ctlfile)): load_module_from_file(join(CW_SOFTWARE_ROOT, ctlfile)) cls.info('loaded cubicweb-ctl plugin %s', ctlfile) - templdir = cls.cubes_dir() for cube in cls.available_cubes(): - pluginfile = join(templdir, cube, 'ecplugin.py') - initfile = join(templdir, cube, '__init__.py') + pluginfile = join(cls.cube_dir(cube), 'ecplugin.py') + initfile = join(cls.cube_dir(cube), '__init__.py') if exists(pluginfile): try: __import__('cubes.%s.ecplugin' % cube) @@ -482,17 +495,16 @@ class CubicWebConfiguration(CubicWebNoAppConfiguration): """base class for cubicweb server and web configurations""" + INSTANCE_DATA_DIR = None if CubicWebNoAppConfiguration.mode == 'test': root = os.environ['APYCOT_ROOT'] REGISTRY_DIR = '%s/etc/cubicweb.d/' % root - INSTANCE_DATA_DIR = REGISTRY_DIR RUNTIME_DIR = '/tmp/' MIGRATION_DIR = '%s/local/share/cubicweb/migration/' % root if not exists(REGISTRY_DIR): os.makedirs(REGISTRY_DIR) elif CubicWebNoAppConfiguration.mode == 'dev': REGISTRY_DIR = expanduser('~/etc/cubicweb.d/') - INSTANCE_DATA_DIR = REGISTRY_DIR RUNTIME_DIR = '/tmp/' MIGRATION_DIR = join(CW_SOFTWARE_ROOT, 'misc', 'migration') else: #mode = 'installed' @@ -555,7 +567,8 @@ @classmethod def instance_data_dir(cls): """return the instance data directory""" - return env_path('CW_INSTANCE_DATA', cls.INSTANCE_DATA_DIR, + return env_path('CW_INSTANCE_DATA', + cls.INSTANCE_DATA_DIR or cls.REGISTRY_DIR, 'additional data') @classmethod diff -r 76b3cd5d4f31 -r 01152fffd593 cwctl.py --- a/cwctl.py Mon Apr 06 12:37:45 2009 +0200 +++ b/cwctl.py Tue Apr 07 09:30:23 2009 +0200 @@ -187,7 +187,6 @@ for cube in cwcfg.available_cubes(): if cube in ('CVS', '.svn', 'shared', '.hg'): continue - templdir = join(cubesdir, cube) try: tinfo = cwcfg.cube_pkginfo(cube) tversion = tinfo.version @@ -200,7 +199,7 @@ or tinfo.__doc__) if shortdesc: print ' '+ ' \n'.join(shortdesc.splitlines()) - modes = detect_available_modes(templdir) + modes = detect_available_modes(CubicWebConfiguration.cube_dir(cube)) print ' available modes: %s' % ', '.join(modes) print try: @@ -622,7 +621,11 @@ config = cwcfg.config_for(appid) config.creating = True # notice we're not starting the server config.verbosity = self.config.verbosity - config.set_sources_mode(self.config.ext_sources or ('migration',)) + try: + config.set_sources_mode(self.config.ext_sources or ('migration',)) + except AttributeError: + # not a server config + pass # get application and installed versions for the server and the componants print 'getting versions configuration from the repository...' mih = config.migration_handler() diff -r 76b3cd5d4f31 -r 01152fffd593 cwvreg.py --- a/cwvreg.py Mon Apr 06 12:37:45 2009 +0200 +++ b/cwvreg.py Tue Apr 07 09:30:23 2009 +0200 @@ -11,7 +11,7 @@ from rql import RQLHelper -from cubicweb import Binary, UnknownProperty +from cubicweb import Binary, UnknownProperty, UnknownEid from cubicweb.vregistry import VRegistry, ObjectNotFound, NoSelectableObject _ = unicode @@ -352,9 +352,9 @@ if vocab is not None: if callable(vocab): # list() just in case its a generator function - vocabfunc = lambda e: list(vocab(propkey, req)) + vocabfunc = lambda **kwargs: list(vocab(propkey, req)) else: - vocabfunc = lambda e: vocab + vocabfunc = lambda **kwargs: vocab w = StaticComboBoxWidget(self, 'EProperty', self.schema['value'], 'String', vocabfunc=vocabfunc, description=tr(pdef['help']), **attrs) @@ -367,7 +367,11 @@ rqlst = self.rqlhelper.parse(rql) def type_from_eid(eid, session=session): return session.describe(eid)[0] - self.rqlhelper.compute_solutions(rqlst, {'eid': type_from_eid}, args) + try: + self.rqlhelper.compute_solutions(rqlst, {'eid': type_from_eid}, args) + except UnknownEid: + for select in rqlst.children: + select.solutions = [] return rqlst @property diff -r 76b3cd5d4f31 -r 01152fffd593 debian/changelog --- a/debian/changelog Mon Apr 06 12:37:45 2009 +0200 +++ b/debian/changelog Tue Apr 07 09:30:23 2009 +0200 @@ -1,3 +1,27 @@ +cubicweb (3.1.4-1) unstable; urgency=low + + * new upstream release + + -- Aurélien Campéas Mon, 06 Apr 2009 14:30:00 +0200 + +cubicweb (3.1.3-1) unstable; urgency=low + + * new upstream release + + -- Sylvain Thénault Mon, 06 Apr 2009 08:52:27 +0200 + +cubicweb (3.1.2-1) unstable; urgency=low + + * new upstream release + + -- Aurélien Campéas Wed, 10 Mar 2009 12:30:00 +0100 + +cubicweb (3.1.1-1) unstable; urgency=low + + * new upstream release + + -- Aurélien Campéas Wed, 9 Mar 2009 18:32:00 +0100 + cubicweb (3.1.0-1) unstable; urgency=low * new upstream release diff -r 76b3cd5d4f31 -r 01152fffd593 debian/control --- a/debian/control Mon Apr 06 12:37:45 2009 +0200 +++ b/debian/control Tue Apr 07 09:30:23 2009 +0200 @@ -1,9 +1,10 @@ Source: cubicweb Section: web Priority: optional -Maintainer: Logilab Packaging Team +Maintainer: Logilab S.A. Uploaders: Sylvain Thenault , - Julien Jehannet + Julien Jehannet , + Aurélien Campéas Build-Depends: debhelper (>= 7), python-dev (>=2.4), python-central (>= 0.5) Standards-Version: 3.8.0 Homepage: http://www.cubicweb.org @@ -53,7 +54,7 @@ This package provides a twisted based HTTP server to serve the adaptative web interface (see cubicweb-web package). . - This package provides only the twisted server part of the library. + This package provides only the twisted server part of the library. Package: cubicweb-web @@ -104,7 +105,7 @@ Description: RQL command line client for the CubicWeb framework CubicWeb is a semantic web application framework. . - This package provides a RQL (Relation Query Language) command line client using + This package provides a RQL (Relation Query Language) command line client using pyro to connect to a repository server. diff -r 76b3cd5d4f31 -r 01152fffd593 debian/rules --- a/debian/rules Mon Apr 06 12:37:45 2009 +0200 +++ b/debian/rules Tue Apr 07 09:30:23 2009 +0200 @@ -48,7 +48,6 @@ rm -rf debian/cubicweb-common/usr/lib/${PY_VERSION}/site-packages/cubicweb/common/test # cubes directory must be managed as a valid python module - ls -l debian/cubicweb-common/usr/share/cubicweb/cubes touch debian/cubicweb-common/usr/share/cubicweb/cubes/__init__.py %: %.in diff -r 76b3cd5d4f31 -r 01152fffd593 devtools/apptest.py --- a/devtools/apptest.py Mon Apr 06 12:37:45 2009 +0200 +++ b/devtools/apptest.py Tue Apr 07 09:30:23 2009 +0200 @@ -493,13 +493,10 @@ self._prepare() self.session.set_pool() self.maxeid = self.session.system_sql('SELECT MAX(eid) FROM entities').fetchone()[0] - #self.maxeid = self.execute('Any MAX(X)') - def tearDown(self, close=True): + def tearDown(self): self.close_connections() self.rollback() self.session.unsafe_execute('DELETE Any X WHERE X eid > %(x)s', {'x': self.maxeid}) self.commit() -# if close: -# self.close() diff -r 76b3cd5d4f31 -r 01152fffd593 devtools/devctl.py --- a/devtools/devctl.py Mon Apr 06 12:37:45 2009 +0200 +++ b/devtools/devctl.py Tue Apr 07 09:30:23 2009 +0200 @@ -284,12 +284,11 @@ def run(self, args): """run the command with its specific arguments""" - CUBEDIR = DevCubeConfiguration.cubes_dir() if args: - cubes = [join(CUBEDIR, app) for app in args] + cubes = [DevCubeConfiguration.cube_dir(cube) for cube in args] else: - cubes = [join(CUBEDIR, app) for app in listdir(CUBEDIR) - if exists(join(CUBEDIR, app, 'i18n'))] + cubes = [DevCubeConfiguration.cube_dir(cube) for cube in DevCubeConfiguration.available_cubes()] + cubes = [cubepath for cubepath in cubes if exists(join(cubepath, 'i18n'))] update_cubes_catalogs(cubes) def update_cubes_catalogs(cubes): @@ -385,6 +384,11 @@ arguments = '' options = ( + ("directory", + {'short': 'd', 'type' : 'string', 'metavar': '', + 'help': 'directory where the new cube should be created', + } + ), ("verbose", {'short': 'v', 'type' : 'yn', 'metavar': '', 'default': 'n', @@ -419,14 +423,20 @@ #if ServerConfiguration.mode != "dev": # self.fail("you can only create new cubes in development mode") verbose = self.get('verbose') - cubedir = ServerConfiguration.CUBES_DIR - if not isdir(cubedir): - print "creating apps directory", cubedir + cubesdir = self.get('directory') + if not cubesdir: + cubespath = ServerConfiguration.cubes_search_path() + if len(cubespath) > 1: + raise BadCommandUsage("can't guess directory where to put the new cube." + " Please specify it using the --directory option") + cubesdir = cubespath[0] + if not isdir(cubesdir): + print "creating cubes directory", cubesdir try: - mkdir(cubedir) + mkdir(cubesdir) except OSError, err: - self.fail("failed to create directory %r\n(%s)" % (cubedir, err)) - cubedir = join(cubedir, cubename) + self.fail("failed to create directory %r\n(%s)" % (cubesdir, err)) + cubedir = join(cubesdir, cubename) if exists(cubedir): self.fail("%s already exists !" % (cubedir)) skeldir = join(BASEDIR, 'skeleton') @@ -502,17 +512,22 @@ raise BadCommandUsage("no argument expected") import re requests = {} - for line in sys.stdin: + for lineno, line in enumerate(sys.stdin): if not ' WHERE ' in line: continue #sys.stderr.write( line ) - rql, time = line.split('--') - rql = re.sub("(\'\w+': \d*)", '', rql) - req = requests.setdefault(rql, []) - time.strip() - chunks = time.split() - cputime = float(chunks[-3]) - req.append( cputime ) + try: + rql, time = line.split('--') + rql = re.sub("(\'\w+': \d*)", '', rql) + if '{' in rql: + rql = rql[:rql.index('{')] + req = requests.setdefault(rql, []) + time.strip() + chunks = time.split() + cputime = float(chunks[-3]) + req.append( cputime ) + except Exception, exc: + sys.stderr.write('Line %s: %s (%s)\n' % (lineno, exc, line)) stat = [] for rql, times in requests.items(): @@ -520,8 +535,11 @@ stat.sort() stat.reverse() + + total_time = sum(time for time, occ, rql in stat)*0.01 + print 'Percentage;Cumulative Time;Occurences;Query' for time, occ, rql in stat: - print time, occ, rql + print '%.2f;%.2f;%s;%s' % (time/total_time, time, occ, rql) register_commands((UpdateCubicWebCatalogCommand, UpdateTemplateCatalogCommand, diff -r 76b3cd5d4f31 -r 01152fffd593 devtools/repotest.py --- a/devtools/repotest.py Mon Apr 06 12:37:45 2009 +0200 +++ b/devtools/repotest.py Tue Apr 07 09:30:23 2009 +0200 @@ -72,7 +72,7 @@ def __contains__(self, key): return key in self.iterkeys() def __getitem__(self, key): - for key_, value in self.iteritems(): + for key_, value in list.__iter__(self): if key == key_: return value raise KeyError(key) @@ -80,6 +80,17 @@ return (x for x, y in list.__iter__(self)) def iteritems(self): return (x for x in list.__iter__(self)) + def items(self): + return [x for x in list.__iter__(self)] + +class DumbOrderedDict2(object): + def __init__(self, origdict, sortkey): + self.origdict = origdict + self.sortkey = sortkey + def __getattr__(self, attr): + return getattr(self.origdict, attr) + def __iter__(self): + return iter(sorted(self.origdict, key=self.sortkey)) from logilab.common.testlib import TestCase @@ -258,15 +269,15 @@ class PartPlanInformation(object): def merge_input_maps(self, *args): pass - def _choose_var(self, sourcevars): + def _choose_term(self, sourceterms): pass _orig_merge_input_maps = PartPlanInformation.merge_input_maps -_orig_choose_var = PartPlanInformation._choose_var +_orig_choose_term = PartPlanInformation._choose_term def _merge_input_maps(*args): return sorted(_orig_merge_input_maps(*args)) -def _choose_var(self, sourcevars): +def _choose_term(self, sourceterms): # predictable order for test purpose def get_key(x): try: @@ -279,17 +290,7 @@ except AttributeError: # const return x.value - varsinorder = sorted(sourcevars, key=get_key) - if len(self._sourcesvars) > 1: - for var in varsinorder: - if not var.scope is self.rqlst: - return var, sourcevars.pop(var) - else: - for var in varsinorder: - if var.scope is self.rqlst: - return var, sourcevars.pop(var) - var = varsinorder[0] - return var, sourcevars.pop(var) + return _orig_choose_term(self, DumbOrderedDict2(sourceterms, get_key)) def do_monkey_patch(): @@ -299,7 +300,7 @@ ExecutionPlan.tablesinorder = None ExecutionPlan.init_temp_table = _init_temp_table PartPlanInformation.merge_input_maps = _merge_input_maps - PartPlanInformation._choose_var = _choose_var + PartPlanInformation._choose_term = _choose_term def undo_monkey_patch(): RQLRewriter.insert_snippets = _orig_insert_snippets @@ -307,5 +308,5 @@ ExecutionPlan._check_permissions = _orig_check_permissions ExecutionPlan.init_temp_table = _orig_init_temp_table PartPlanInformation.merge_input_maps = _orig_merge_input_maps - PartPlanInformation._choose_var = _orig_choose_var + PartPlanInformation._choose_term = _orig_choose_term diff -r 76b3cd5d4f31 -r 01152fffd593 doc/book/en/A000-introduction.en.txt --- a/doc/book/en/A000-introduction.en.txt Mon Apr 06 12:37:45 2009 +0200 +++ b/doc/book/en/A000-introduction.en.txt Tue Apr 07 09:30:23 2009 +0200 @@ -1,5 +1,6 @@ .. -*- coding: utf-8 -*- +.. _Part1: =================================== Part I - Introduction to `CubicWeb` diff -r 76b3cd5d4f31 -r 01152fffd593 doc/book/en/A020-tutorial.en.txt --- a/doc/book/en/A020-tutorial.en.txt Mon Apr 06 12:37:45 2009 +0200 +++ b/doc/book/en/A020-tutorial.en.txt Tue Apr 07 09:30:23 2009 +0200 @@ -20,6 +20,7 @@ This tutorial will show how to create a `cube` and how to use it as an application to run an `instance`. +.. include:: Z013-blog-less-ten-minutes.en.txt .. include:: A02a-create-cube.en.txt .. include:: A02b-components.en.txt .. include:: A02c-maintemplate.en.txt diff -r 76b3cd5d4f31 -r 01152fffd593 doc/book/en/A02a-create-cube.en.txt --- a/doc/book/en/A02a-create-cube.en.txt Mon Apr 06 12:37:45 2009 +0200 +++ b/doc/book/en/A02a-create-cube.en.txt Tue Apr 07 09:30:23 2009 +0200 @@ -169,47 +169,45 @@ .. _DefineViews: -Define your entities views --------------------------- +Define your entity views +------------------------ -Each entity defined in a model inherits defaults views allowing +Each entity defined in a model inherits default views allowing different rendering of the data. You can redefine each of them -according to your needs and preferences. If you feel like it then -you have to know how a view is defined. +according to your needs and preferences. So let's see how the +views are defined. -The views selection principle -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The view selection principle +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A view is defined by a Python class which includes: - an identifier (all objects in `CubicWeb` are entered in a registry and this identifier will be used as a key) - - a filter to select the resulsets it can be applied to + - a filter to select the result sets it can be applied to A view has a set of methods complying with the `View` class interface (`cubicweb.common.view`). -`CubicWeb` provides a lot of standard views for the type -`EntityView`, for a complete list, you -will have to read the code in directory ``cubicweb/web/views/`` +`CubicWeb` provides a lot of standard views for the type `EntityView`; +for a complete list, read the code in directory ``cubicweb/web/views/``. A view is applied on a `result set` which contains a set of entities we are trying to display. `CubicWeb` uses a selector -mechanism which computes a score used to identify which view -is the best to apply for the `result set` we are trying to -display. The standard library of selectors is in +mechanism which computes for each available view a score: +the view with the highest score is then used to display the given `result set`. +The standard library of selectors is in ``cubicweb.common.selector`` and a library of methods used to compute scores is available in ``cubicweb.vregistry.vreq``. It is possible to define multiple views for the same identifier and to associate selectors and filters to allow the application -to find the best way to render the data. We will see more details -on this in :ref:`DefinitionVues`. +to find the best way to render the data. For example, the view named ``primary`` is the one used to display -a single entity. We will now show you hos to customize this view. +a single entity. We will now show you how to customize this view. View customization @@ -219,8 +217,8 @@ overwrite the `primary` view defined in the module ``views`` of the cube ``cubes/blog/views.py``. -We can for example add in front of the pulication date a prefix specifying -the date we see is the publication date. +We can for example add in front of the publication date a prefix specifying +that the date we see is the publication date. To do so, please apply the following changes: @@ -263,12 +261,13 @@ :alt: modified primary view -The above source code defines a new primary view for -``BlogEntry``. +The above source code defines a new primary view for ``BlogEntry``. -Since views are applied to resultsets and resulsets can be tables of -data, it is needed to recover the entity from its (row,col) -coordinates. We will get to this in more detail later. +Since views are applied to result sets and result sets can be tables of +data, we have to recover the entity from its (row,col)-coordinates. +The view has a ``self.w()`` method that is used to output data, in our +example HTML output. -The view has a ``self.w()`` method that is used to output data. In our -example we use it to output HTML tags and values of the entity's attributes. +You can find more details about views and selectors in :ref:`ViewDefinition`. + + diff -r 76b3cd5d4f31 -r 01152fffd593 doc/book/en/A03a-concepts.en.txt --- a/doc/book/en/A03a-concepts.en.txt Mon Apr 06 12:37:45 2009 +0200 +++ b/doc/book/en/A03a-concepts.en.txt Tue Apr 07 09:30:23 2009 +0200 @@ -12,18 +12,18 @@ `CubicWeb` framework is a server/client application framework. Those two -parties communicates through RQL (`CubicWeb` query language implementation) +parts communicate through RQL (`CubicWeb` query language implementation) and ResultSet (which will be explained in :ref:`TermsVocabulary`). The server manages all interactions with sources. .. note:: - For real, the client and server sides are integrated in the same - process and interact directly, without the needs for distants - calls using Pyro. It is important to note down that those two + Usually, the client and server sides are integrated in the same + process and interact directly, without the need for distant + calls using Pyro. But, it is important to note that those two sides, client/server, are disjointed and it is possible to execute - a couple of calls in distincts processes to balance the load of + a couple of calls in distinct processes to balance the load of your web site on one or more machines. .. _TermsVocabulary: @@ -42,8 +42,8 @@ classes based on `yams`_ library. This is the core piece of an application. It is initially defined in the file system and is stored in the database at the time an instance is created. `CubicWeb` - provides a certain number of system entities included automatically as - it is necessary for the core of `CubicWeb` and a library of + provides a certain number of system entities included automatically + (necessary for the core of `CubicWeb`) and a library of cubes (which defined application entities) that can be explicitely included if necessary. @@ -57,7 +57,7 @@ a relation the `subject` and the second the `object`. *final entity type* - Final types corresponds to the basic types such as string of characters, + Final types correspond to the basic types such as string of characters, integers... Those types have a main property which is that they can only be used as `object` of a relation. The attributes of an entity (non final) are entities (finals). @@ -78,11 +78,11 @@ A data source is a container of data (SGBD, LDAP directory, `Google App Engine`'s datastore ...) integrated in the `CubicWeb` repository. This repository has at least one source, `system` which - contains the schema of the application, plain-text index and others + contains the schema of the application, plain-text index and other vital informations for the system. *configuration* - It is possible to create differents configurations for an instance: + It is possible to create different configurations for an instance: - ``repository`` : repository only, accessible for clients using Pyro - ``twisted`` : web interface only, access the repository using Pyro @@ -91,15 +91,15 @@ *cube* A cube is a model grouping one or multiple data types and/or views - to provide a specific functionnality or a complete `CubicWeb` application + to provide a specific functionality or a complete `CubicWeb` application potentially using other cubes. The available cubes are located in the file - system at `/path/to/forest/cubicweb/cubes` for a Mercurial forest installation, - for a debian packages installation they will be located in + system at `/path/to/forest/cubicweb/cubes` for a Mercurial forest installation. + For a debian packages installation they will be located in `/usr/share/cubicweb/cubes`. - Larger applications can be built faster by importing cubes, - adding entities and relationships and overriding the - views that need to display or edit informations not provided by - cubes. + Larger applications can be built quite fast by importing cubes, + adding entities and relationships, overriding the + *views* that display the cubes or by editing informations not provided by + the cubes. *instance* An instance is a specific installation of one or multiple cubes. All the required @@ -107,11 +107,11 @@ are grouped in an instance. This will refer to the cube(s) your application is based on. For example logilab.org and our intranet are two instances of a single - cube jpl, developped internally. + cube "jpl", developped internally. The instances are defined in the directory `/etc/cubicweb.d`. *application* - The term application is sometime used to talk about an instance + The term application is sometimes used to talk about an instance and sometimes to talk of a cube depending on the context. So we would like to avoid using this term and try to use *cube* and *instance* instead. @@ -143,9 +143,9 @@ the same identifier. *rql* - Relation Query Language in order to empasize the way of browsing relations. - This query language is inspired by SQL but is highest level, its implementation - generates SQL. + Relation Query Language in order to emphasize the way of browsing relations. + This query language is inspired by SQL but is on a higher level; + its implementation generates SQL. .. _`Python Remote Object`: http://pyro.sourceforge.net/ @@ -156,9 +156,9 @@ ~~~~~~~~~~~~~~~~~ The engine in `CubicWeb` is a set of classes managing a set of objects loaded -dynamically at the startup of `CubicWeb` (*appobjects*). Those dynamics objects, +dynamically at the startup of `CubicWeb` (*appobjects*). Those dynamic objects, based on the schema or the library, are building the final application. -The differents dymanic components are for example: +The different dynamic components are for example: * client and server side @@ -200,11 +200,11 @@ `execute(rqlstring, args=None, eid_key=None, build_descr=True)` :rqlstring: the RQL query to execute (unicode) -:args: if the query contains substitutions, a dictionnary containing the values to use +:args: if the query contains substitutions, a dictionary containing the values to use :eid_key: - an implementation detail of the RQL queries cache implies that if a substitution + an implementation detail of the RQL cache implies that if a substitution is used to introduce an eid *susceptible to raise the ambiguities in the query - type resolution*, then we have to specify the correponding key in the dictionnary + type resolution*, then we have to specify the corresponding key in the dictionary through this argument @@ -214,7 +214,7 @@ on the query execution success. .. note:: - While executing updates queries (SET, INSERT, DELETE), if a query generates + While executing update queries (SET, INSERT, DELETE), if a query generates an error related to security, a rollback is automatically done on the current transaction. @@ -223,7 +223,7 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A request instance is created when an HTTP request is sent to the web server. -It contains informations such as forms parameters, user authenticated, etc. +It contains informations such as form parameters, user authenticated, etc. **Globally, a request represents a user query, either through HTTP or not (we also talk about RQL queries on the server side for example).** @@ -232,13 +232,13 @@ * `user`, instance of `cubicweb.common.utils.User` corresponding to the authenticated user -* `form`, dictionnary containing the values of a web form -* `encoding`, characters encoding to use in the response +* `form`, dictionary containing the values of a web form +* `encoding`, character encoding to use in the response But also: :Session data handling: - * `session_data()`, returns a dictionnary containing all the session data + * `session_data()`, returns a dictionary containing all the session data * `get_session_data(key, default=None)`, returns a value associated to the given key or the value `default` if the key is not defined * `set_session_data(key, value)`, assign a value to a key @@ -246,7 +246,7 @@ :Cookies handling: - * `get_cookie()`, returns a dictionnary containing the value of the header + * `get_cookie()`, returns a dictionary containing the value of the header HTTP 'Cookie' * `set_cookie(cookie, key, maxage=300)`, adds a header HTTP `Set-Cookie`, with a minimal 5 minutes length of duration by default (`maxage` = None @@ -268,7 +268,7 @@ * `cursor()` returns a RQL cursor on the session * `execute(*args, **kwargs)`, shortcut to ``.cursor().execute()`` * `property_value(key)`, properties management (`EProperty`) - * dictionnary `data` to store data to share informations between components + * dictionary `data` to store data to share informations between components *while a request is executed* Please note that this class is abstract and that a concrete implementation @@ -372,7 +372,7 @@ A cube is a model grouping one or more entity types and/or views associated in order to provide a specific feature or even a complete application using -others cubes. +other cubes. You can decide to write your own set of cubes if you wish to re-use the entity types you develop. Lots of cubes are available from the `CubicWeb @@ -460,7 +460,7 @@ * ``sobjects`` contains hooks and/or views notifications (server side only) * ``views`` contains the web interface components (web interface only) * ``test`` contains tests related to the application (not installed) -* ``i18n`` contains messages catalogs for supported languages (server side and +* ``i18n`` contains message catalogs for supported languages (server side and web interface) * ``data`` contains data files for static content (images, css, javascripts) ...(web interface only) @@ -479,7 +479,7 @@ * the file ``__pkginfo__.py`` * the schema definition XXX false, we may want to have cubes which are only adding a service, - no persistent data (eg embeding for instance) + no persistent data (eg embedding for instance) Standard library diff -r 76b3cd5d4f31 -r 01152fffd593 doc/book/en/B000-development.en.txt --- a/doc/book/en/B000-development.en.txt Mon Apr 06 12:37:45 2009 +0200 +++ b/doc/book/en/B000-development.en.txt Tue Apr 07 09:30:23 2009 +0200 @@ -1,5 +1,6 @@ .. -*- coding: utf-8 -*- +.. _Part2: ===================== Part II - Development diff -r 76b3cd5d4f31 -r 01152fffd593 doc/book/en/B0010-define-schema.en.txt --- a/doc/book/en/B0010-define-schema.en.txt Mon Apr 06 12:37:45 2009 +0200 +++ b/doc/book/en/B0010-define-schema.en.txt Tue Apr 07 09:30:23 2009 +0200 @@ -1,17 +1,18 @@ .. -*- coding: utf-8 -*- -Data model definition (*schema*) -================================ +Data model definition: the *schema* +=================================== -The schema is the core piece of a `CubicWeb` application as it defines -the data model handled. It is based on entities types already defined -in the `CubicWeb` standard library and others, more specific, we would -expect to find in one or more Python files under the `schema` directory. +The **schema** is the core piece of a `CubicWeb` application as it defines +the handled data model. It is based on entity types that are either already +defined in the `CubicWeb` standard library; or more specific types, that +`CubicWeb` expects to find in one or more Python files under the directory +`schema`. At this point, it is important to make clear the difference between -relation type and relation definition: a relation type is only a relation +*relation type* and *relation definition*: a *relation type* is only a relation name with potentially other additionnal properties (see XXXX), whereas a -relation definition is a complete triplet +*relation definition* is a complete triplet " ". A relation type could have been implied if none is related to a relation definition of the schema. diff -r 76b3cd5d4f31 -r 01152fffd593 doc/book/en/B0011-schema-stdlib.en.txt --- a/doc/book/en/B0011-schema-stdlib.en.txt Mon Apr 06 12:37:45 2009 +0200 +++ b/doc/book/en/B0011-schema-stdlib.en.txt Tue Apr 07 09:30:23 2009 +0200 @@ -3,14 +3,14 @@ Pre-defined schemas in the library ---------------------------------- -The library defines a set of entities schemas that are required by the system +The library defines a set of entity schemas that are required by the system or commonly used in `CubicWeb` applications. Of course, you can extend those schemas if necessary. System schemas `````````````` -The system entities available are : +The available system entities are: * `EUser`, system users * `EGroup`, users groups @@ -31,7 +31,10 @@ * `Bookmark`, an entity type used to allow a user to customize his links within the application -Cubes available +(The first 'E' in some of the names is the first letter of 'Erudi', +`CubicWeb`'s old name; it might be changed/removed some day.) + +Available cubes ``````````````` An application is based on several basic cubes. In the set of available diff -r 76b3cd5d4f31 -r 01152fffd593 doc/book/en/B0012-schema-definition.en.txt --- a/doc/book/en/B0012-schema-definition.en.txt Mon Apr 06 12:37:45 2009 +0200 +++ b/doc/book/en/B0012-schema-definition.en.txt Tue Apr 07 09:30:23 2009 +0200 @@ -3,26 +3,30 @@ Entity type definition ---------------------- -An entity type is defined by a Python class which inherits `EntityType`. The -class name correponds to the type name. Then the content of the class contains -the description of attributes and relations for the defined entity type, -for example :: +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. - class Personne(EntityType): +For example :: + + class Person(EntityType): """A person with the properties and the relations necessary for my application""" last_name = String(required=True, fulltextindexed=True) first_name = String(required=True, fulltextindexed=True) - title = String(vocabulary=('M', 'Mme', 'Mlle')) + title = String(vocabulary=('Mr', 'Mrs', 'Miss')) date_of_birth = Date() works_for = SubjectRelation('Company', cardinality='?*') + * the name of the Python attribute corresponds to the name of the attribute or the relation in `CubicWeb` application. -* all built-in types are available : `String`, `Int`, `Float`, - `Boolean`, `Date`, `Datetime`, `Time`, `Byte`. +* all `CubicWeb` built-in types are available : `String`, `Int`, `Float`, + `Boolean`, `Date`, `Datetime`, `Time`, `Byte`; they are and implicitely + imported (as well as the special the function "_"). * each entity type has at least the following meta-relations : @@ -34,21 +38,19 @@ - `created_by` (`EUser`) (which user created the entity) - - `owned_by` (`EUser`) (who does the entity belongs to, by default the - creator but not necessary and it could have multiple owners) + - `owned_by` (`EUser`) (to whom the entity belongs; by default the + creator but not necessary, and it could have multiple owners) - `is` (`EEType`) - -* it is also possible to define relations of type object by using `ObjectRelation` - instead of `SubjectRelation` -* the first argument of `SubjectRelation` and `ObjectRelation` gives respectively +* 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 correponding to multiple entities types + * a tuple of string corresponding to multiple entity types * special string such as follows : @@ -62,20 +64,20 @@ * optional properties for attributes and relations : - - `description` : 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` : list of conditions/constraints that the relation needs to + - `constraints` : a list of conditions/constraints that the relation has to satisfy (c.f. `Contraints`_) - - `cardinality` : two characters string which specify the cardinality of the + - `cardinality` : a two character string which specify the cardinality of the relation. The first character defines the cardinality of the relation on - the subject, the second on the object of the relation. When a relation - has multiple possible subjects or objects, the cardinality applies to all - and not on a one to one basis (so it must be consistent...). The possible - values are inspired from regular expressions syntax : + 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 : * `1`: 1..1 * `?`: 0..1 @@ -85,7 +87,7 @@ - `meta` : boolean indicating that the relation is a meta-relation (false by default) -* optionnal properties for attributes : +* optional properties for attributes : - `required` : boolean indicating if the attribute is required (false by default) @@ -98,11 +100,11 @@ attribute. - `default` : default value of the attribute. In case of date types, the values - which could be used correpond to the RQL keywords `TODAY` and `NOW`. + which could be used correspond to the RQL keywords `TODAY` and `NOW`. - `vocabulary` : specify static possible values of an attribute -* optionnal properties of type `String` : +* optional properties of type `String` : - `fulltextindexed` : boolean indicating if the attribute is part of the full text index (false by default) (*applicable on the type `Byte` @@ -113,17 +115,17 @@ - `maxsize` : integer providing the maximum size of the string (no limit by default) -* optionnal properties for relations : +* optional properties for relations : - `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 need - to set 'object' as the value. The composition implies that when the relation + 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), the composed are also deleted. Contraints `````````` -By default, the available constraints types are : +By default, the available constraint types are : * `SizeConstraint` : allows to specify a minimum and/or maximum size on string (generic case of `maxsize`) @@ -135,7 +137,7 @@ * `StaticVocabularyConstraint` : identical to "vocabulary=(...)" -* `RQLConstraint` : allows to specify a RQL query that needs to be satisfied +* `RQLConstraint` : allows to specify a RQL query that has to be satisfied by the subject and/or the object of the relation. In this query the variables `S` and `O` are reserved for the entities subject and object of the relation. @@ -143,18 +145,18 @@ * `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 + not prevent another entity to be selected. -Relation definition -------------------- +Definition of relations +----------------------- XXX add note about defining relation type / definition A relation is defined by a Python class heriting `RelationType`. The name of the class corresponds to the name of the type. The class then contains a description of the properties of this type of relation, and could as well -contains a string for the subject and a string for the object. This allows to create +contain a string for the subject and a string for the object. This allows to create new definition of associated relations, (so that the class can have the definition properties from the relation) for example :: @@ -174,14 +176,14 @@ table for the relation. This applies to the relation when the cardinality of subject->relation->object is 0..1 (`?`) or 1..1 (`1`) -* `symetric` : boolean indication that the relation is symetrical, which +* `symmetric` : boolean indicating that the relation is symmetrical, which means `X relation Y` implies `Y relation X` 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`. -When a relation is not inlined and not symetrical, and it does not require +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. @@ -219,8 +221,8 @@ Permissions definition `````````````````````` -Define permissions is set through to the attribute `permissions` of entities and -relations types. It defines a dictionnary where the keys are the access types +Setting permissions is done with the attribute `permissions` of entities and +relation types. It defines 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 @@ -375,12 +377,16 @@ Updating your application with your new schema `````````````````````````````````````````````` -You have to get a shell on your application :: +If you modified your schema, the update is not automatic; indeed, this is +in general not a good idea. +Instead, you call a shell on your application, which is a +an interactive python shell, with an appropriate +cubicweb environment :: - cubicweb-ctl shell moninstance + cubicweb-ctl shell myinstance and type :: - add_entity_type('Personne') + add_entity_type('Person') And restart your application! diff -r 76b3cd5d4f31 -r 01152fffd593 doc/book/en/B0020-define-workflows.en.txt --- a/doc/book/en/B0020-define-workflows.en.txt Mon Apr 06 12:37:45 2009 +0200 +++ b/doc/book/en/B0020-define-workflows.en.txt Tue Apr 07 09:30:23 2009 +0200 @@ -2,78 +2,43 @@ .. _Workflow: -Workflow definition -=================== +An Example: Workflow definition +=============================== General ------- -A workflow can be defined in a `CubicWeb` application thanks to the system -entities ``State`` and ``Transition``. Those are defined within all -`CubicWeb` application and can be set-up through the main administrator interface. - -Once your schema is defined, you can start creating the set of states and -the required transitions for your applications entities. - -You first need to define the states and then the transitions between those -to complete your workflow. - -A ``State`` defines the status of an entity. While creating a new state, -you will be first given the option to select the entity type the state -can be applied to. By choosing ``Apply``, a new section will be displayed -in the editing screen to enable you to add relation to the state you are -creating. +A workflow describes how certain entities have to evolve between +different states. Hence we have a set of states, and a "transition graph", +i.e. a list of possible transitions from one state to another state. -A ``Transition`` is also based on an entity type it can be applied to. -By choosing ``Apply``, a new section will be displayed in the editing -screen to enable you to add relation to the transition you are -creating. - -At the transition level you will also define the group of user which can -aplly this transition to an object. - - -Example of a simple workflow ----------------------------- - -Please see the tutorial to view and example of a simple workflow. - - -[Create a simple workflow for BlogDemo, to have a moderator approve new blog -entry to be published. This implies, specify a dedicated group of blog -moderator as well as hide the view of a blog entry to the user until -it reaches the state published] +We will define a simple workflow for a blog, with only the following +two states: `submitted` and `published`. So first, we create a simple +`CubicWeb` in ten minutes (see :ref:`BlogTenMinutes`). Set-up a workflow ----------------- We want to create a workflow to control the quality of the BlogEntry submitted on your application. When a BlogEntry is created by a user -its state should be `submitted`. To be visible to all, it needs to -be in the state `published`. To move from `submitted` to `published` -we need a transition that we can name `approve_blogentry`. - -We do not want every user to be allowed to change the state of a -BlogEntry. We need to define a group of user, `moderators`, and -this group will have appropriate permissions to approve BlogEntry -to be published and visible to all. +its state should be `submitted`. To be visible to all, it has to +be in the state `published`. To move it from `submitted` to `published`, +we need a transition that we can call `approve_blogentry`. -There are two ways to create a workflow, form the user interface, -and also by defining it in ``migration/postcreate.py``. +A BlogEntry state should not be modifiable by every user. +So we have to define a group of users, `moderators`, and +this group will have appropriate permissions to publish a BlogEntry. + +There are two ways to create a workflow: from the user interface, +or by defining it in ``migration/postcreate.py``. This script is executed each time a new ``cubicweb-ctl db-init`` is done. -If you create the states and transitions through the user interface -this means that next time you will need to initialize the database -you will have to re-create all the entities. -We strongly recommand you create the workflow in ``migration\postcreate.py`` -and we will now show you how. -The user interface would only be a reference for you to view the states -and transitions but is not the appropriate interface to define your -application workflow. +We strongly recommand to create the workflow in ``migration/postcreate.py`` +and we will now show you how. Read `Under the hood`_ to understand why. Update the schema ~~~~~~~~~~~~~~~~~ -To enable a BlogEntry to have a State, we have to define a relation -``in_state`` in the schema of BlogEntry. Please do as follows, add +If we want a State for our BlogEntry, we have to define a relation +``in_state`` in the schema of BlogEntry. So we add the line ``in_state (...)``:: class BlogEntry(EntityType): @@ -86,59 +51,64 @@ entry_of = SubjectRelation('Blog', cardinality='?*') in_state = SubjectRelation('State', cardinality='1*') -As you updated the schema, you will have re-execute ``cubicweb-ctl db-init`` +As you updated the schema, you have to re-execute ``cubicweb-ctl db-init`` to initialize the database and migrate your existing entities. + [WRITE ABOUT MIGRATION] Create states, transitions and group permissions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -At the time the ``postcreate.py`` script is executed, several methods -can be used. They are all defined in the ``class ServerMigrationHelper``. -We will only discuss the method we use to create a wrokflow here. +The ``postcreate.py`` script is executed in a special environment, adding +several `CubicWeb` primitives that can be used. +They are all defined in the ``class ServerMigrationHelper``. +We will only discuss the methods we use to create a workflow in this example. To define our workflow for BlogDemo, please add the following lines to ``migration/postcreate.py``:: _ = unicode - moderators = add_entity('EGroup', name=u"moderators") + moderators = add_entity('EGroup', name=u"moderators") + +This adds the `moderators` user group. + +:: submitted = add_state(_('submitted'), 'BlogEntry', initial=True) published = add_state(_('published'), 'BlogEntry') +``add_state`` expects as first argument the name of the state you want +to create, then the entity type on which the state can be applied, +and an optional argument to say if it is supposed to be the initial state +of the entity type. + +:: + add_transition(_('approve_blogentry'), 'BlogEntry', (submitted,), published, ('moderators', 'managers'),) + +``add_transition`` expects + + * as the first argument the name of the + transition, then the entity type on which the transition can be applied, + * then the list of states on which the transition can be trigged, + * the target state of the transition, + * and the permissions + (e.g. a list of user groups who can apply the transition; the user + has to belong to at least one of the listed group to perform the action). + +:: + checkpoint() .. note:: Do not forget to add the `_()` in front of all states and transitions names while creating a workflow so that they will be identified by the i18n catalog scripts. -``add_entity`` is used here to define the new group of users that we -need to define the transitions, `moderators`. -If this group required by the transition is not defined before the -transition is created, it will not create the relation `transition -require the group moderator`. - -``add_state`` expects as the first argument the name of the state you are -willing to create, then the entity type on which the state can be applied, -and an optionnal argument to set if the state is the initial state -of the entity type or not. - -``add_transition`` expects as the first argument the name of the -transition, then the entity type on which we can apply the transition, -then the list of possible initial states from which the transition -can be applied, the target state of the transition, and the permissions -(e.g. list of the groups of users who can apply the transition, the user -needs to belong to at least one of the listed group). - - -We could have also added a RQL condition in addition to a group to -which the user should belong to. - -If we use both RQL condition and group, the two must be satisfied -for the user to be allowed to apply the transition. +In addition to the user group condition, we could have added a RQL condition. +In this case, the user can only perform the action if +the two conditions are satisfied. If we use a RQL condition on a transition, we can use the following variables: @@ -150,8 +120,40 @@ .. image:: images/lax-book.03-transitions-view.en.png -You can now notice that in the actions box of a BlogEntry, the state -is now listed as well as the possible transitions from this state -defined by the workflow. This transition, as defined in the workflow, -will only being displayed for the users belonging to the group -moderators of managers. +You can notice that in the action box of a BlogEntry, the state +is now listed as well as the possible transitions defined by the workflow. +The transitions will only be displayed for users having the right permissions. +In our example, the transition `approve_blogentry` will only be displayed +for the users belonging to the group `moderators` or `managers`. + + +Under the hood +~~~~~~~~~~~~~~ + +A workflow is a collection of entities of type ``State`` and of type ``Transition`` +which are standard `CubicWeb` entity types. +For instance, the following lines:: + + submitted = add_state(_('submitted'), 'BlogEntry', initial=True) + published = add_state(_('published'), 'BlogEntry') + +will create two entities of type ``State``, one with name 'submitted', and the other +with name 'published'. Whereas:: + + add_transition(_('approve_blogentry'), 'BlogEntry', (submitted,), published, ('moderators', 'managers'),) + +will create an entity of type ``Transition`` with name 'approve_blogentry' which will +be linked to the ``State`` entities created before. +As a consequence, we could use the administration interface to do these operations. +But it is not recommanded because it will be uselessly complicated +and will be only local to your instance. + + +Indeed, if you create the states and transitions through the user interface, +next time you initialize the database +you will have to re-create all the entities. +The user interface should only be a reference for you to view the states +and transitions, but is not the appropriate interface to define your +application workflow. + + diff -r 76b3cd5d4f31 -r 01152fffd593 doc/book/en/B0030-data-as-objects.en.txt --- a/doc/book/en/B0030-data-as-objects.en.txt Mon Apr 06 12:37:45 2009 +0200 +++ b/doc/book/en/B0030-data-as-objects.en.txt Tue Apr 07 09:30:23 2009 +0200 @@ -4,15 +4,15 @@ Data as objects =============== -We will in this chapter introduce the objects that are used to handle +In this chapter, we will introduce the objects that are used to handle the data stored in the database. Classes `Entity` and `AnyEntity` -------------------------------- -To provide a specific behavior for each entity, we just need to define -a class inheriting from `cubicweb.entities.AnyEntity`. In general, we have -to defined those classes in a module of `entities` package of an application +To provide a specific behavior for each entity, we have to define +a class inheriting from `cubicweb.entities.AnyEntity`. In general, we +define this class in a module of `entities` package of an application so that it will be available on both server and client side. The class `AnyEntity` is loaded dynamically from the class `Entity` @@ -22,7 +22,7 @@ Descriptors are added when classes are registered in order to initialize the class according to its schema: -* we can access the defined attributes in the schema thanks the attributes of +* we can access the defined attributes in the schema thanks to the attributes of the same name on instances (typed value) * we can access the defined relations in the schema thanks to the relations of @@ -33,12 +33,12 @@ * `has_eid()`, returns true is the entity has an definitive eid (e.g. not in the creation process) -* `check_perm(action)`, checks if the user has the permission to execcute the +* `check_perm(action)`, checks if the user has the permission to execute the requested action on the entity :Formatting and output generation: - * `view(vid, **kwargs)`, apply the given view to the entity + * `view(vid, **kwargs)`, applies the given view to the entity * `absolute_url(**kwargs)`, returns an absolute URL to access the primary view of an entity @@ -118,30 +118,31 @@ *rtags* ------- -*rtags* allows to specify certain behaviors of relations relative to a given +*rtags* allow to specify certain behaviors of relations relative to a given entity type (see later). They are defined on the entity class by the attribute -`rtags` which is a dictionnary with as its keys the triplet :: +`rtags` which is a dictionary with as keys the triplets :: , , -and as the values a `set` or a tuple of markers defining the properties that +and as values a `set` or a tuple of markers defining the properties that apply to this relation. -It is possible to simplify this dictionnary: +It is possible to simplify this dictionary: * if we want to specifiy a single marker, it is not necessary to - use a tuple as the value, the marker by itself (characters string) + use a tuple as value, the marker by itself (character string) is enough * if we only care about a single type of relation and not about the target and the context position (or when this one is not ambigous), we can simply - use the name of the relation type as the key + use the name of the relation type as key * if we want a marker to apply independently from the target entity type, - we have to use the string `*` as the target entity type + we have to use the string `*` as target entity type -Please note that this dictionnary is *treated at the time the class is created*. +Please note that this dictionary is *treated at the time the class is created*. It is automatically merged with the parent class(es) (no need to copy the -dictionnary from the parent class to modify it). Also, modify it after the +dictionary from the parent class to modify it). Also, modifying it after the class is created will not have any effect... .. include:: B0031-define-entities.en.txt + diff -r 76b3cd5d4f31 -r 01152fffd593 doc/book/en/B0031-define-entities.en.txt --- a/doc/book/en/B0031-define-entities.en.txt Mon Apr 06 12:37:45 2009 +0200 +++ b/doc/book/en/B0031-define-entities.en.txt Tue Apr 07 09:30:23 2009 +0200 @@ -5,8 +5,8 @@ Dynamic default values `````````````````````` -It is possible to define in the schema *static* default values. -It is also possible to define in the schema *dynamic* default values +It is possible to define *static* default values in the schema. +It is also possible to define *dynamic* default values by defining in the entity class a method `default_` for a given attribute. @@ -118,20 +118,22 @@ 1. we consider that the first column contains the entities to constraint 2. we collect the first entity of the table (row 0) to represent all the others -3. for all the others variables defined in the original request: +3. for all the other variables defined in the original request: - 1. if the varaible is related to the main variable by at least one relation + 1. if the variable is related to the main variable by at least one relation 2. we call the method ``filterform_vocabulary(rtype, x)`` on the entity, if nothing is returned (meaning a tuple `Non`, see below), we go to the next variable, otherwise a form filtering element is created based on the vocabulary values returned -4. there is no others limitations to the `RQL`, it can include sorting, grouping - conditions... Javascripts functions are used to regenerate a request based on the +4. there are no other limitations to the `RQL`, it can include sorting, grouping + conditions... JavaScript functions are used to regenerate a request based on the initial request and on the selected values from the filtering form. The method ``filterform_vocabulary(rtype, x, var, rqlst, args, cachekey)`` takes -the name of a relation and the target as parameters, which indicates of the +the name of a relation and the target as parameters, +[XXX what does it mean ?] + which indicates of the entity on which we apply the method is subject or object of the relation. It has to return: @@ -157,18 +159,18 @@ class Ticket(AnyEntity): - ... + ... - def filterform_vocabulary(self, rtype, x, var, rqlst, args, cachekey): - _ = self.req._ - if rtype == 'type': - return 'string', [(x, _(x)) for x in ('bug', 'story')] - if rtype == 'priority': - return 'string', [(x, _(x)) for x in ('minor', 'normal', 'important')] - if rtype == 'done_in': - rql = insert_attr_select_relation(rqlst, var, rtype, 'num') - return 'eid', self.req.execute(rql, args, cachekey) - return super(Ticket, self).filterform_vocabulary(rtype, x, var, rqlst, + def filterform_vocabulary(self, rtype, x, var, rqlst, args, cachekey): + _ = self.req._ + if rtype == 'type': + return 'string', [(x, _(x)) for x in ('bug', 'story')] + if rtype == 'priority': + return 'string', [(x, _(x)) for x in ('minor', 'normal', 'important')] + if rtype == 'done_in': + rql = insert_attr_select_relation(rqlst, var, rtype, 'num') + return 'eid', self.req.execute(rql, args, cachekey) + return super(Ticket, self).filterform_vocabulary(rtype, x, var, rqlst, args, cachekey) .. note:: diff -r 76b3cd5d4f31 -r 01152fffd593 doc/book/en/B0040-migration.en.txt --- a/doc/book/en/B0040-migration.en.txt Mon Apr 06 12:37:45 2009 +0200 +++ b/doc/book/en/B0040-migration.en.txt Tue Apr 07 09:30:23 2009 +0200 @@ -5,10 +5,10 @@ Migration ========= -One of the main concept in `CubicWeb` is to create incremental applications -and for this purpose multiple actions are provided to facilitate the improvement -of an application and in particular changes applied to the data model -without loosing existing data. +One of the main concept in `CubicWeb` is to create incremental applications. +For this purpose, multiple actions are provided to facilitate the improvement +of an application, and in particular to handle the changes to be applied +to the data model, without loosing existing data. The current version of an application model is provided in the file `__pkginfo__.py` as a tuple of 3 integers. @@ -16,8 +16,8 @@ Migration scripts management ---------------------------- -Migration scripts needs to be located in the directory `migration` of your -application and nammed accordingly: +Migration scripts has to be located in the directory `migration` of your +application and named accordingly: :: @@ -25,26 +25,27 @@ in which : -* X.Y.Z is the model version number to which the script enable to migrate +* X.Y.Z is the model version number to which the script enables to migrate. -* *mode* (between the last "_" and the extension ".py") indicates which part - of the application (RQL server, web server) the script applies to in case - of distributed installation. Its value could be : +* *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 + * `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 + hard drive. * `Any`, applies only to the RQL server and updates data in the database - (schema and data migration for example) + (schema and data migration for example). Again in the directory `migration`, the file `depends.map` allows to indicate -that to migrate to a particular model version, you always have to first migrate -to a particular `CubicWeb` version. This file can contains comments (lines +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: :: : @@ -53,33 +54,31 @@ 0.12.0: 2.26.0 0.13.0: 2.27.0 - # 0.14 works with 2.27 <= erudi <= 2.28 at least + # 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 the migration scripts: +The following identifiers are pre-defined in migration scripts: * `config`, instance configuration * `interactive_mode`, boolean indicating that the script is executed in - an intercative mode or not + an interactive mode or not * `appltemplversion`, application model version of the instance -* `applerudiversion`, cubicweb instance version - * `templversion`, installed application model version -* `erudiversion`, installed cubicweb version +* `cubicwebversion`, installed cubicweb version -* `confirm(question)`, function interrogating the user and returning true - if the user answers yes, false otherwise (always returns true when in a +* `confirm(question)`, function asking the user and returning true + if the user answers yes, false otherwise (always returns true in non-interactive mode) -* `_`, function fonction equivalent to `unicode` allowing to flag the strings - to internationalize in the migration scripts +* 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: @@ -89,7 +88,7 @@ current migration) * `newschema`, installed schema on the file system (e.g. schema of - the updated model and erudi) + the updated model and cubicweb) * `sqlcursor`, SQL cursor for very rare cases where it is really necessary or beneficial to go through the sql @@ -99,7 +98,7 @@ Schema migration ---------------- -The following functions for schema migration are available in the `repository` +The following functions for schema migration are available in `repository` scripts: * `add_attribute(etype, attrname, attrtype=None, commit=True)`, adds a new @@ -109,7 +108,7 @@ * `drop_attribute(etype, attrname, commit=True)`, removes an attribute from an existing entity type. -* `rename_attribute(etype, oldname, newname, commit=True)`, rename an attribute +* `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 @@ -149,7 +148,7 @@ or even relations definitions). * `change_relation_props(subjtype, rtype, objtype, commit=True, **kwargs)`, changes - properties of a relation definition by using the nammed parameters of the properties + 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 @@ -160,19 +159,19 @@ Data migration -------------- -The following functions for data migration are available in the `repository` scripts: +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 attributes and relations values are specified using the nammed and + 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 the `repository` +The following functions for workflow creation are available in `repository` scripts: * `add_state(name, stateof, initial=False, commit=False, **kwargs)`, adds a new state @@ -186,10 +185,10 @@ Configuration migration ----------------------- -The following functions for configuration migration are available in all the +The following functions for configuration migration are available in all scripts: -* `option_renamed(oldname, newname)`, indicates that an option has been renammed +* `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. @@ -203,7 +202,7 @@ -------------------------- 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 the `repository` scripts: +session. They are available in `repository` scripts: * `sqlexec(sql, args=None, ask_confirm=True)`, executes an arbitrary SQL query * `add_entity_type_table(etype, commit=True)` diff -r 76b3cd5d4f31 -r 01152fffd593 doc/book/en/B1020-define-views.en.txt --- a/doc/book/en/B1020-define-views.en.txt Mon Apr 06 12:37:45 2009 +0200 +++ b/doc/book/en/B1020-define-views.en.txt Tue Apr 07 09:30:23 2009 +0200 @@ -1,6 +1,6 @@ .. -*- coding: utf-8 -*- -.. _DefinitionVues: +.. _ViewDefinition: Views definition ================ @@ -61,13 +61,11 @@ * `page_title()`, returns the title to use in the HTML header `title` -* `creator(eid)`, returns the eid and the login of the entity creator of the entity - having the eid given in the parameter -Other basic views classes -````````````````````````` +Other basic view classes +```````````````````````` Here are some of the subclasses of `View` defined in `cubicweb.common.view` -that are more concrete as they relates to data rendering within the application: +that are more concrete as they relate to data rendering within the application: * `EntityView`, view applying to lines or cell containing an entity (e.g. an eid) * `StartupView`, start view that does not require a result set to apply to @@ -83,14 +81,14 @@ and this identifier will be used as a key). This is defined in the class attribute ``id``. -- a filter to select the resulsets it can be applied to. This is defined in +- a filter to select the result sets it can be applied to. This is defined in the class attribute ``__selectors__``, which expects a tuple of selectors as its value. For a given identifier, multiple views can be defined. `CubicWeb` uses -a selector which computes scores so that it can identify and select the -best view to apply in context. The selectors library is in +a selector which computes scores to identify and select the +best view to apply in the given context. The selectors library is in ``cubicweb.common.selector`` and a library of the methods used to compute scores is in ``cubicweb.vregistry.vreq``. @@ -107,8 +105,8 @@ object that is equivalent to an already registered object, which could happen when we define two `primary` views for an entity type. -The purpose of a `registerer` is to control objects registry -at the application startup whereas `selectors` controls objects +The purpose of a `registerer` is to control object registry +at the application startup whereas `selectors` control objects when they are selected for display. @@ -163,7 +161,7 @@ If you want to change the way a ``BlogEntry`` is displayed, just override the method ``cell_call()`` of the view ``primary`` in ``BlogDemo/views.py`` :: - 01. from ginco.web.views import baseviews + 01. from cubicweb.web.views import baseviews 02. 03. class BlogEntryPrimaryView(baseviews.PrimaryView): 04. @@ -179,15 +177,15 @@ The above source code defines a new primary view (`line 03`) for ``BlogEntry`` (`line 05`). -Since views are applied to resultsets and resulsets can be tables of -data, it is needed to recover the entity from its (row,col) -coordinates (`line 08`). We will get to this in more detail later. +Since views are applied to result sets which can be tables of +data, we have to recover the entity from its (row,col)-coordinates (`line 08`). +We will get to this in more detail later. -The view has a ``self.w()`` method that is used to output data. Here `lines +The view method ``self.w()`` is used to output data. Here `lines 09-12` output HTML tags and values of the entity's attributes. -When displaying same blog entry as before, you will notice that the -page is now looking much nicer. +When displaying the same blog entry as before, you will notice that the +page is now looking much nicer. [FIXME: it is not clear to what this refers.] .. image:: images/lax-book.09-new-view-blogentry.en.png :alt: blog entries now look much nicer @@ -206,22 +204,22 @@ 10. self.wview('primary', rset) In the above source code, `lines 01-08` are similar to the previous -view we defined. +view we defined. [FIXME: defined where ?] -At `line 09`, a simple request in made to build a resultset with all +At `line 09`, a simple request is made to build a result set with all the entities linked to the current ``Blog`` entity by the relationship ``entry_of``. The part of the framework handling the request knows about the schema and infer that such entities have to be of the ``BlogEntry`` kind and retrieves them. -The request returns a selection of data called a resultset. At -`line 10` the view 'primary' is applied to this resultset to output +The request returns a selection of data called a result set. At +`line 10` the view 'primary' is applied to this result set to output HTML. **This is to be compared to interfaces and protocols in object-oriented -languages. Applying a given view to all the entities of a resultset only -requires the availability, for each entity of this resultset, of a -view with that name that can accepts the entity.** +languages. Applying a given view called 'a_view' to all the entities +of a result set only requires to have for each entity of this result set, +an available view called 'a_view' which accepts the entity.** Assuming we added entries to the blog titled `MyLife`, displaying it now allows to read its description and all its entries. @@ -232,7 +230,7 @@ **Before we move forward, remember that the selection/view principle is at the core of `CubicWeb`. Everywhere in the engine, data is requested using the RQL language, then HTML/XML/text/PNG is output by applying a -view to the resultset returned by the query. That is where most of the +view to the result set returned by the query. That is where most of the flexibility comes from.** [WRITE ME] @@ -242,7 +240,7 @@ We will implement the `cubicweb.interfaces.ICalendarable` interfaces on entities.BlogEntry and apply the OneMonthCalendar and iCalendar views -to resultsets like "Any E WHERE E is BlogEntry" +to result sets like "Any E WHERE E is BlogEntry" * create view "blogentry table" with title, publish_date, category @@ -262,7 +260,7 @@ Templates --------- -*Templates* are specific view that does not depend on a result set. The basic +*Templates* are specific views that do not depend on a result set. The basic class `Template` (`cubicweb.common.view`) is derived from the class `View`. To build a HTML page, a *main template* is used. In general, the template of @@ -280,16 +278,16 @@ XML views, binaries... ---------------------- -For the views generating other formats that HTML (an image generated dynamically -for example), and which can not usually be included in the HTML page generated +For views generating other formats than HTML (an image generated dynamically +for example), and which can not simply be included in the HTML page generated by the main template (see above), you have to: -* set the atribute `templatable` of the class to `False` +* set the attribute `templatable` of the class to `False` * set, through the attribute `content_type` of the class, the MIME type generated by the view to `application/octet-stream` -For the views dedicated to binary content creation (an image dynamically generated -for example), we have to set the attribute `binary` of the class to `True` (which +For views dedicated to binary content creation (like dynamically generated +images), we have to set the attribute `binary` of the class to `True` (which implies that `templatable == False`, so that the attribute `w` of the view could be replaced by a binary flow instead of unicode). diff -r 76b3cd5d4f31 -r 01152fffd593 doc/book/en/B1021-views-selectors.en.txt --- a/doc/book/en/B1021-views-selectors.en.txt Mon Apr 06 12:37:45 2009 +0200 +++ b/doc/book/en/B1021-views-selectors.en.txt Tue Apr 07 09:30:23 2009 +0200 @@ -5,7 +5,7 @@ Selectors are scoring functions that are called by the view dispatcher to tell whenever a view can be applied to a given result -set and request. Selector sets are the glue that tie views to the data +set of a request. Selector sets are the glue that tie views to the data model. Using them appropriately is an essential part of the construction of well behaved cubes. diff -r 76b3cd5d4f31 -r 01152fffd593 doc/book/en/B1060-templates.en.txt --- a/doc/book/en/B1060-templates.en.txt Mon Apr 06 12:37:45 2009 +0200 +++ b/doc/book/en/B1060-templates.en.txt Tue Apr 07 09:30:23 2009 +0200 @@ -84,7 +84,7 @@ :: - from ginco.web.views.basetemplates import HTMLPageHeader + from cubicweb.web.views.basetemplates import HTMLPageHeader class MyHTMLPageHeader(HTMLPageHeader): def main_header(self, view): """build the top menu with authentification info and the rql box""" @@ -143,7 +143,7 @@ for HTMLPageFooter and override it in your views file as in : :: - form ginco.web.views.basetemplates import HTMLPageFooter + form cubicweb.web.views.basetemplates import HTMLPageFooter class MyHTMLPageFooter(HTMLPageFooter): def call(self, **kwargs): self.w(u'