# HG changeset patch # User sylvain.thenault@logilab.fr # Date 1239809769 -7200 # Node ID 9d61b146f5059394e2b4122b796caf24c5bbbf16 # Parent 8a3102fb47605a4c297b64b2a84b07efd570ad30# Parent a81d3babb5825e9ddd96f326ceadc9f65adb5485 backport 3.1 branch to default (duh...) diff -r a81d3babb582 -r 9d61b146f505 .hgtags --- a/.hgtags Thu Jan 15 10:13:25 2009 +0100 +++ b/.hgtags Wed Apr 15 17:36:09 2009 +0200 @@ -12,3 +12,17 @@ 18d3e56c1de4a6597ab36536964bc66b5550cf98 cubicweb-debian-version-3_0_2-1 0cb027c056f939ec3580ea1cc0aeda9f9884f0fa cubicweb-version-3_0_3 a736bae56d4a703a26933fb9875fb9caab216c6b cubicweb-debian-version-3_0_3-1 +2e400b8dfc25ae30db602f64601e30e210b3fade cubicweb-version-3_0_4 +fc222bc99929d395c1c2235c40d3bb6f247b4ba9 cubicweb-debian-version-3_0_4-1 +7ad527099393ef56f27af313392022bb8ed73082 cubicweb-version-3_0_9 +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 a81d3babb582 -r 9d61b146f505 MANIFEST.in --- a/MANIFEST.in Thu Jan 15 10:13:25 2009 +0100 +++ b/MANIFEST.in Wed Apr 15 17:36:09 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 a81d3babb582 -r 9d61b146f505 __init__.py --- a/__init__.py Thu Jan 15 10:13:25 2009 +0100 +++ b/__init__.py Wed Apr 15 17:36:09 2009 +0200 @@ -2,9 +2,9 @@ relations between entitites. :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 -: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 a81d3babb582 -r 9d61b146f505 __pkginfo__.py --- a/__pkginfo__.py Thu Jan 15 10:13:25 2009 +0100 +++ b/__pkginfo__.py Wed Apr 15 17:36:09 2009 +0200 @@ -6,11 +6,11 @@ distname = "cubicweb" modname = "cubicweb" -numversion = (3, 0, 3) +numversion = (3, 1, 5) version = '.'.join(str(num) for num in numversion) -license = 'LCL' -copyright = '''Copyright (c) 2003-2008 LOGILAB S.A. (Paris, FRANCE). +license = 'LGPL v2' +copyright = '''Copyright (c) 2003-2009 LOGILAB S.A. (Paris, FRANCE). http://www.logilab.fr/ -- mailto:contact@logilab.fr''' author = "Logilab" @@ -27,11 +27,12 @@ * a bunch of other management tools """ -web = '' -ftp = '' -pyversions = ['2.4'] +web = 'http://www.cubicweb.org' +ftp = 'ftp://ftp.logilab.org/pub/cubicweb' +pyversions = ['2.4', '2.5'] +import sys from os import listdir, environ from os.path import join, isdir import glob @@ -60,7 +61,8 @@ # --home install pydir = 'python' else: - pydir = join('python2.4', 'site-packages') + python_version = '.'.join(str(num) for num in sys.version_info[0:2]) + pydir = join('python' + python_version, 'site-packages') try: data_files = [ @@ -90,7 +92,6 @@ [join('share', 'cubicweb', 'cubes', 'shared', 'i18n'), [join(i18n_dir, fname) for fname in listdir(i18n_dir)]], # skeleton - ] except OSError: # we are in an installed directory, don't care about this diff -r a81d3babb582 -r 9d61b146f505 _exceptions.py --- a/_exceptions.py Thu Jan 15 10:13:25 2009 +0100 +++ b/_exceptions.py Wed Apr 15 17:36:09 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 a81d3babb582 -r 9d61b146f505 common/appobject.py --- a/common/appobject.py Thu Jan 15 10:13:25 2009 +0100 +++ b/common/appobject.py Wed Apr 15 17:36:09 2009 +0200 @@ -1,7 +1,7 @@ """Base class for dynamically loaded objects manipulated in the web interface :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" @@ -12,6 +12,8 @@ from simplejson import dumps from logilab.common.deprecation import obsolete + +from rql.nodes import VariableRef, SubQuery from rql.stmts import Union, Select from cubicweb import Unauthorized diff -r a81d3babb582 -r 9d61b146f505 common/entity.py --- a/common/entity.py Thu Jan 15 10:13:25 2009 +0100 +++ b/common/entity.py Wed Apr 15 17:36:09 2009 +0200 @@ -1,7 +1,7 @@ """Base class for entity objects manipulated in clients :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" @@ -41,6 +41,8 @@ 'inlineview')) def __init__(self, eclass, tagdefs): + # XXX if a rtag is redefined in a subclass, + # the rtag of the base class overwrite the rtag of the subclass self.eclass = eclass self._tagdefs = {} for relation, tags in tagdefs.iteritems(): @@ -391,6 +393,10 @@ res['source'] = self.req.source_defs()[res['source']] return res + def clear_local_perm_cache(self, action): + for rqlexpr in self.e_schema.get_rqlexprs(action): + self.req.local_perm_cache.pop((rqlexpr.eid, (('x', self.eid),)), None) + def check_perm(self, action): self.e_schema.check_perm(self.req, action, self.eid) @@ -998,6 +1004,7 @@ _done.add(self.eid) containers = tuple(self.e_schema.fulltext_containers()) if containers: + yielded = False for rschema, target in containers: if target == 'object': targets = getattr(self, rschema.type) @@ -1008,6 +1015,9 @@ continue for container in entity.fti_containers(_done): yield container + yielded = True + if not yielded: + yield self else: yield self diff -r a81d3babb582 -r 9d61b146f505 common/migration.py --- a/common/migration.py Thu Jan 15 10:13:25 2009 +0100 +++ b/common/migration.py Wed Apr 15 17:36:09 2009 +0200 @@ -312,12 +312,18 @@ """a configuration option's type has changed""" self._option_changes.append(('typechanged', optname, oldtype, newvalue)) - def cmd_add_cube(self, cube): + def cmd_add_cubes(self, cubes): + """modify the list of used cubes in the in-memory config + returns newly inserted cubes, including dependencies + """ + if isinstance(cubes, basestring): + cubes = (cubes,) origcubes = self.config.cubes() - newcubes = [p for p in self.config.expand_cubes([cube]) + newcubes = [p for p in self.config.expand_cubes(cubes) if not p in origcubes] if newcubes: - assert cube in newcubes + for cube in cubes: + assert cube in newcubes self.config.add_cubes(newcubes) return newcubes @@ -346,7 +352,7 @@ if optdescr[0] == 'added': optdict = self.config.get_option_def(optdescr[1]) if optdict.get('default') is REQUIRED: - self.config.input_option(option, optdict) + self.config.input_option(optdescr[1], optdict) self.config.generate_config(open(newconfig, 'w')) show_diffs(configfile, newconfig) if exists(newconfig): diff -r a81d3babb582 -r 9d61b146f505 common/mixins.py --- a/common/mixins.py Thu Jan 15 10:13:25 2009 +0100 +++ b/common/mixins.py Wed Apr 15 17:36:09 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" @@ -145,7 +145,6 @@ return self.iterchildren() def is_leaf(self): - print '*' * 80 return len(self.children()) == 0 def is_root(self): @@ -165,21 +164,25 @@ @property def state(self): - return self.in_state[0].name + try: + return self.in_state[0].name + except IndexError: + self.warning('entity %s has no state', self) + return None @property def displayable_state(self): return self.req._(self.state) def wf_state(self, statename): - rset = self.req.execute('Any S, SN WHERE S name %(n)s, S state_of E, E name %(e)s', + rset = self.req.execute('Any S, SN WHERE S name SN, S name %(n)s, S state_of E, E name %(e)s', {'n': statename, 'e': str(self.e_schema)}) if rset: return rset.get_entity(0, 0) return None def wf_transition(self, trname): - rset = self.req.execute('Any T, TN WHERE T name %(n)s, T transition_of E, E name %(e)s', + rset = self.req.execute('Any T, TN WHERE T name TN, T name %(n)s, T transition_of E, E name %(e)s', {'n': trname, 'e': str(self.e_schema)}) if rset: return rset.get_entity(0, 0) @@ -189,6 +192,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: @@ -366,22 +370,18 @@ """provide default implementations for IProgress interface methods""" @property - @cached def cost(self): return self.progress_info()['estimated'] @property - @cached def revised_cost(self): return self.progress_info().get('estimatedcorrected', self.cost) @property - @cached def done(self): return self.progress_info()['done'] @property - @cached def todo(self): return self.progress_info()['todo'] @@ -400,6 +400,6 @@ return 100. * self.done / self.revised_cost except ZeroDivisionError: # total cost is 0 : if everything was estimated, task is completed - if self.progress_info().get('notestmiated'): + if self.progress_info().get('notestimated'): return 0. return 100 diff -r a81d3babb582 -r 9d61b146f505 common/registerers.py --- a/common/registerers.py Thu Jan 15 10:13:25 2009 +0100 +++ b/common/registerers.py Wed Apr 15 17:36:09 2009 +0200 @@ -101,6 +101,8 @@ def equivalent(self, other): if _accepts_interfaces(self.vobject) != _accepts_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 a81d3babb582 -r 9d61b146f505 common/rest.py --- a/common/rest.py Thu Jan 15 10:13:25 2009 +0100 +++ b/common/rest.py Wed Apr 15 17:36:09 2009 +0200 @@ -1,9 +1,19 @@ """rest publishing functions -contains some functions and setup of docutils for cubicweb +contains some functions and setup of docutils for cubicweb. Provides the +following ReST directives: + +* `eid`, create link to entity in the repository by their eid + +* `card`, create link to card entity in the repository by their wikiid + (proposing to create it when the refered card doesn't exist yet) + +* `winclude`, reference to a web documentation file (in wdoc/ directories) + +* `sourcecode` (if pygments is installed), source code colorization :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" @@ -156,6 +166,36 @@ 'encoding': directives.encoding} directives.register_directive('winclude', winclude_directive) +try: + from pygments import highlight + from pygments.lexers import get_lexer_by_name, LEXERS + from pygments.formatters import HtmlFormatter +except ImportError: + pass +else: + _PYGMENTS_FORMATTER = HtmlFormatter() + + def pygments_directive(name, arguments, options, content, lineno, + content_offset, block_text, state, state_machine): + try: + lexer = get_lexer_by_name(arguments[0]) + except ValueError: + import traceback + traceback.print_exc() + print sorted(aliases for module_name, name, aliases, _, _ in LEXERS.itervalues()) + # no lexer found + lexer = get_lexer_by_name('text') + print 'LEXER', lexer + parsed = highlight(u'\n'.join(content), lexer, _PYGMENTS_FORMATTER) + context = state.document.settings.context + context.req.add_css('pygments.css') + return [nodes.raw('', parsed, format='html')] + + pygments_directive.arguments = (1, 0, 1) + pygments_directive.content = 1 + directives.register_directive('sourcecode', pygments_directive) + + class CubicWebReSTParser(Parser): """The (customized) reStructuredText parser.""" diff -r a81d3babb582 -r 9d61b146f505 common/selectors.py --- a/common/selectors.py Thu Jan 15 10:13:25 2009 +0100 +++ b/common/selectors.py Wed Apr 15 17:36:09 2009 +0200 @@ -20,12 +20,12 @@ above by:: # in Python2.5 - from cubicweb.selectors import traced_selection + from cubicweb.common.selectors import traced_selection with traced_selection(): self.view('calendar', myrset) # in Python2.4 - from cubicweb import selectors + from cubicweb.common import selectors selectors.TRACED_OIDS = ('calendar',) self.view('calendar', myrset) selectors.TRACED_OIDS = () @@ -50,7 +50,6 @@ from cubicweb.cwconfig import CubicWebConfiguration from cubicweb.schema import split_expression - # helpers for debugging selectors SELECTOR_LOGGER = logging.getLogger('cubicweb.selectors') TRACED_OIDS = () @@ -62,8 +61,9 @@ def traced(cls, *args, **kwargs): ret = selector(cls, *args, **kwargs) if TRACED_OIDS == 'all' or cls.id in TRACED_OIDS: - SELECTOR_LOGGER.warning('selector %s returned %s for %s', selector.__name__, ret, cls) + SELECTOR_LOGGER.critical('selector %s returned %s for %s', selector.__name__, ret, cls) return ret + traced.__name__ = selector.__name__ return traced class traced_selection(object): @@ -110,12 +110,12 @@ norset_selector = deprecated_function(none_rset) @lltrace -def rset(cls, req, rset, *args, **kwargs): +def any_rset(cls, req, rset, *args, **kwargs): """accept result set, whatever the number of result""" if rset is not None: return 1 return 0 -rset_selector = deprecated_function(rset) +rset_selector = deprecated_function(any_rset) @lltrace def nonempty_rset(cls, req, rset, *args, **kwargs): @@ -161,13 +161,20 @@ def paginated_rset(cls, req, rset, *args, **kwargs): """accept result sets with more rows than the page size """ - if rset is None or len(rset) <= req.property_value('navigation.page-size'): + page_size = kwargs.get('page_size') + if page_size is None: + page_size = req.form.get('page_size') + if page_size is None: + page_size = req.property_value('navigation.page-size') + else: + page_size = int(page_size) + if rset is None or len(rset) <= page_size: return 0 return 1 largerset_selector = deprecated_function(paginated_rset) @lltrace -def sorted_rset(cls, req, rset, row=None, col=None): +def sorted_rset(cls, req, rset, row=None, col=None, **kwargs): """accept sorted result set""" rqlst = rset.syntax_tree() if len(rqlst.children) > 1 or not rqlst.children[0].orderby: @@ -222,7 +229,7 @@ @lltrace def authenticated_user(cls, req, *args, **kwargs): """accept if user is authenticated""" - return not anonymous_selector(cls, req, *args, **kwargs) + return not anonymous_user(cls, req, *args, **kwargs) not_anonymous_selector = deprecated_function(authenticated_user) @lltrace @@ -499,7 +506,7 @@ propval = req.property_value('%s.%s.context' % (cls.__registry__, cls.id)) if not propval: propval = cls.context - if context is not None and propval is not None and context != propval: + if context is not None and propval and context != propval: return 0 return 1 contextprop_selector = deprecated_function(match_context_prop) @@ -529,28 +536,36 @@ # compound selectors ########################################################## non_final_entity = chainall(nonempty_rset, _non_final_entity) +non_final_entity.__name__ = 'non_final_entity' nfentity_selector = deprecated_function(non_final_entity) implement_interface = chainall(non_final_entity, _implement_interface) +implement_interface.__name__ = 'implement_interface' interface_selector = deprecated_function(implement_interface) accept = chainall(non_final_entity, accept_rset) +accept.__name__ = 'accept' accept_selector = deprecated_function(accept) -accept_one = chainall(one_line_rset, accept_selector) +accept_one = chainall(one_line_rset, accept) +accept_one.__name__ = 'accept_one' accept_one_selector = deprecated_function(accept_one) rql_condition = chainall(non_final_entity, one_line_rset, _rql_condition) +rql_condition.__name__ = 'rql_condition' rqlcondition_selector = deprecated_function(rql_condition) searchstate_accept = chainall(nonempty_rset, match_search_state, accept) +searchstate_accept.__name__ = 'searchstate_accept' searchstate_accept_selector = deprecated_function(searchstate_accept) searchstate_accept_one = chainall(one_line_rset, match_search_state, accept, _rql_condition) +searchstate_accept_one.__name__ = 'searchstate_accept_one' searchstate_accept_one_selector = deprecated_function(searchstate_accept_one) searchstate_accept_one_but_etype = chainall(searchstate_accept_one, but_etype) +searchstate_accept_one_but_etype.__name__ = 'searchstate_accept_one_but_etype' searchstate_accept_one_but_etype_selector = deprecated_function( searchstate_accept_one_but_etype) diff -r a81d3babb582 -r 9d61b146f505 common/test/unittest_entity.py --- a/common/test/unittest_entity.py Thu Jan 15 10:13:25 2009 +0100 +++ b/common/test/unittest_entity.py Wed Apr 15 17:36:09 2009 +0200 @@ -250,8 +250,7 @@ self.assertListEquals(rbc(e.relations_by_category('generic')), [('primary_email', 'subject'), ('evaluee', 'subject'), - ('for_user', 'object'), - ('bookmarked_by', 'object')]) + ('for_user', 'object')]) # owned_by is defined both as subject and object relations on EUser self.assertListEquals(rbc(e.relations_by_category('generated')), [('last_login_time', 'subject'), @@ -263,7 +262,8 @@ ('owned_by', 'subject'), ('created_by', 'object'), ('wf_info_for', 'object'), - ('owned_by', 'object')]) + ('owned_by', 'object'), + ('bookmarked_by', 'object')]) e = self.etype_instance('Personne') self.assertListEquals(rbc(e.relations_by_category('primary')), [('nom', 'subject'), ('eid', 'subject')]) diff -r a81d3babb582 -r 9d61b146f505 common/test/unittest_mixins.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/test/unittest_mixins.py Wed Apr 15 17:36:09 2009 +0200 @@ -0,0 +1,25 @@ +from logilab.common.testlib import unittest_main +from cubicweb.devtools.apptest import EnvBasedTC + +class WorkfloableMixInTC(EnvBasedTC): + def test_wf_state(self): + s = self.add_entity('State', name=u'activated') + self.execute('SET X state_of ET WHERE ET name "Bookmark", X eid %(x)s', + {'x': s.eid}) + es = self.user().wf_state('activated') + self.assertEquals(es.state_of[0].name, 'EUser') + + def test_wf_transition(self): + t = self.add_entity('Transition', name=u'deactivate') + self.execute('SET X transition_of ET WHERE ET name "Bookmark", X eid %(x)s', + {'x': t.eid}) + et = self.user().wf_transition('deactivate') + self.assertEquals(et.transition_of[0].name, 'EUser') + + def test_change_state(self): + user = self.user() + user.change_state(user.wf_state('deactivated').eid) + self.assertEquals(user.state, 'deactivated') + +if __name__ == '__main__': + unittest_main() diff -r a81d3babb582 -r 9d61b146f505 common/uilib.py --- a/common/uilib.py Thu Jan 15 10:13:25 2009 +0100 +++ b/common/uilib.py Wed Apr 15 17:36:09 2009 +0200 @@ -4,7 +4,7 @@ contains some functions designed to help implementation of cubicweb user interface :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" @@ -180,21 +180,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 = ' '.join(words) # normalize spaces - minlength = len(' '.join(words[:nbwords])) - textlength = text.find('.', minlength) + 1 - if textlength == 0: # no point found - textlength = minlength + text = u' '.join(words) # normalize spaces + 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): @@ -213,6 +219,21 @@ # HTML generation helper functions ############################################ +def simple_sgml_tag(tag, content=None, **attrs): + """generation of a simple sgml tag (eg without children tags) easier + + content and attributes will be escaped + """ + value = u'<%s' % tag + if attrs: + value += u' ' + u' '.join(u'%s="%s"' % (attr, html_escape(unicode(value))) + for attr, value in attrs.items()) + if content: + value += u'>%s' % (html_escape(unicode(content)), tag) + else: + value += u'/>' + return value + def tooltipize(text, tooltip, url=None): """make an HTML tooltip""" url = url or '#' diff -r a81d3babb582 -r 9d61b146f505 common/view.py --- a/common/view.py Thu Jan 15 10:13:25 2009 +0100 +++ b/common/view.py Wed Apr 15 17:36:09 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" @@ -28,9 +28,9 @@ ] ''' TRANSITIONAL_DOCTYPE = u'\n' @@ -71,7 +73,7 @@ A view is instantiated to render a [part of a] result set. View subclasses may be parametred using the following class attributes: - + * `templatable` indicates if the view may be embeded in a main template or if it has to be rendered standalone (i.e. XML for instance) @@ -85,14 +87,14 @@ time to a write function to use. """ __registry__ = 'views' - + templatable = True need_navigation = True # content_type = 'application/xhtml+xml' # text/xhtml' binary = False add_to_breadcrumbs = True category = 'view' - + def __init__(self, req, rset): super(View, self).__init__(req, rset) self.w = None @@ -102,7 +104,7 @@ if self.req.xhtml_browser(): return 'application/xhtml+xml' return 'text/html' - + def set_stream(self, w=None): if self.w is not None: return @@ -118,14 +120,14 @@ return stream # main view interface ##################################################### - + def dispatch(self, w=None, **context): """called to render a view object for a result set. This method is a dispatched to an actual method selected according to optional row and col parameters, which are locating a particular row or cell in the result set: - + * if row [and col] are specified, `cell_call` is called * if none of them is supplied, the view is considered to apply on the whole result set (which may be None in this case), `call` is @@ -147,7 +149,7 @@ # should default .call() method add a
around each # rset item add_div_section = True - + def call(self, **kwargs): """the view is called for an entire result set, by default loop other rows of the result set and call the same view on the @@ -169,10 +171,10 @@ def cell_call(self, row, col, **kwargs): """the view is called for a particular result set cell""" raise NotImplementedError, self - + def linkable(self): """return True if the view may be linked in a menu - + by default views without title are not meant to be displayed """ if not getattr(self, 'title', None): @@ -181,7 +183,7 @@ def is_primary(self): return self.id == 'primary' - + def url(self): """return the url associated with this view. Should not be necessary for non linkable views, but a default implementation @@ -197,7 +199,7 @@ self.req.set_content_type(self.content_type) # view utilities ########################################################## - + def view(self, __vid, rset, __fallback_vid=None, **kwargs): """shortcut to self.vreg.render method avoiding to pass self.req""" try: @@ -207,7 +209,7 @@ raise view = self.vreg.select_view(__fallback_vid, self.req, rset, **kwargs) return view.dispatch(**kwargs) - + def wview(self, __vid, rset, __fallback_vid=None, **kwargs): """shortcut to self.view method automatically passing self.w as argument """ @@ -234,7 +236,7 @@ label = label or self.req._(action.title) return u'%s' % (html_escape(action.url()), label) return u'' - + def html_headers(self): """return a list of html headers (eg something to be inserted between and of the returned page @@ -242,7 +244,7 @@ by default return a meta tag to disable robot indexation of the page """ return [NOINDEX] - + def page_title(self): """returns a title according to the result set - used for the title in the HTML header @@ -292,7 +294,7 @@ """ return the url of the entity creation form for a given entity type""" return self.req.build_url('add/%s'%etype, **kwargs) - + # concrete views base classes ################################################# class EntityView(View): @@ -300,8 +302,9 @@ """ __registerer__ = accepts_registerer __selectors__ = (accept,) + accepts = ('Any',) category = 'entityview' - + def field(self, label, value, row=True, show_label=True, w=None, tr=True): """ read-only field """ if w is None: @@ -316,7 +319,7 @@ if row: w(u'
') - + class StartupView(View): """base class for views which doesn't need a particular result set to be displayed (so they can always be displayed !) @@ -325,7 +328,7 @@ __selectors__ = (match_user_group, none_rset) require_groups = () category = 'startupview' - + def url(self): """return the url associated with this view. We can omit rql here""" return self.build_url('view', vid=self.id) @@ -345,9 +348,9 @@ """ __registerer__ = accepts_registerer __selectors__ = (chainfirst(none_rset, accept),) - + default_rql = None - + def __init__(self, req, rset): super(EntityStartupView, self).__init__(req, rset) if rset is None: @@ -357,7 +360,7 @@ def startup_rql(self): """return some rql to be executedif the result set is None""" return self.default_rql - + def call(self, **kwargs): """override call to execute rql returned by the .startup_rql method if necessary @@ -376,14 +379,14 @@ return self.build_url(vid=self.id) return super(EntityStartupView, self).url() - + class AnyRsetView(View): """base class for views applying on any non empty result sets""" __registerer__ = priority_registerer __selectors__ = (nonempty_rset,) - + category = 'anyrsetview' - + def columns_labels(self, tr=True): if tr: translate = display_name @@ -400,7 +403,7 @@ label = translate(self.req, attr) labels.append(label) return labels - + class EmptyRsetView(View): """base class for views applying on any empty result sets""" @@ -419,7 +422,7 @@ __selectors__ = (match_user_group,) require_groups = () - + def template(self, oid, **kwargs): """shortcut to self.registry.render method on the templates registry""" w = kwargs.pop('w', self.w) diff -r a81d3babb582 -r 9d61b146f505 cwconfig.py --- a/cwconfig.py Thu Jan 15 10:13:25 2009 +0100 +++ b/cwconfig.py Wed Apr 15 17:36:09 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 @@ -148,9 +148,11 @@ if os.environ.get('APYCOT_ROOT'): mode = 'test' CUBES_DIR = '%(APYCOT_ROOT)s/local/share/cubicweb/cubes/' % os.environ + # create __init__ file + 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/' @@ -223,7 +225,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): @@ -234,26 +236,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): @@ -339,12 +353,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): @@ -356,10 +372,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) @@ -486,17 +501,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' @@ -559,7 +573,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 a81d3babb582 -r 9d61b146f505 cwctl.py --- a/cwctl.py Thu Jan 15 10:13:25 2009 +0100 +++ b/cwctl.py Wed Apr 15 17:36:09 2009 +0200 @@ -173,19 +173,18 @@ continue print ' ', line print + cubesdirs = ', '.join(CubicWebConfiguration.cubes_search_path()) try: - cubesdir = CubicWebConfiguration.cubes_dir() namesize = max(len(x) for x in CubicWebConfiguration.available_cubes()) except ConfigurationError, ex: print 'No cubes available:', ex except ValueError: - print 'No cubes available in %s' % cubesdir + print 'No cubes available in %s' % cubesdirs else: - print 'Available cubes (%s):' % cubesdir + print 'Available cubes (%s):' % cubesdirs for cube in CubicWebConfiguration.available_cubes(): if cube in ('CVS', '.svn', 'shared', '.hg'): continue - templdir = join(cubesdir, cube) try: tinfo = CubicWebConfiguration.cube_pkginfo(cube) tversion = tinfo.version @@ -198,7 +197,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: @@ -620,7 +619,11 @@ config = CubicWebConfiguration.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 a81d3babb582 -r 9d61b146f505 cwvreg.py --- a/cwvreg.py Thu Jan 15 10:13:25 2009 +0100 +++ b/cwvreg.py Wed Apr 15 17:36:09 2009 +0200 @@ -1,7 +1,7 @@ """extend the generic VRegistry with some cubicweb specific stuff :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" @@ -12,7 +12,7 @@ from rql import RQLHelper -from cubicweb import Binary, UnknownProperty +from cubicweb import Binary, UnknownProperty, UnknownEid from cubicweb.vregistry import VRegistry, ObjectNotFound, NoSelectableObject _ = unicode @@ -322,9 +322,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) @@ -337,7 +337,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 a81d3babb582 -r 9d61b146f505 debian.hardy/compat --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debian.hardy/compat Wed Apr 15 17:36:09 2009 +0200 @@ -0,0 +1,1 @@ +5 diff -r a81d3babb582 -r 9d61b146f505 debian.hardy/control --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debian.hardy/control Wed Apr 15 17:36:09 2009 +0200 @@ -0,0 +1,131 @@ +Source: cubicweb +Section: web +Priority: optional +Maintainer: Logilab S.A. +Uploaders: Sylvain Thenault , + Julien Jehannet , + Aurélien Campéas +Build-Depends: debhelper (>= 5), python-dev (>=2.4), python-central (>= 0.5) +Standards-Version: 3.8.0 +Homepage: http://www.cubicweb.org +XS-Python-Version: >= 2.4, << 2.6 + + +Package: cubicweb +Architecture: all +XB-Python-Version: ${python:Versions} +Depends: ${python:Depends}, cubicweb-server (= ${source:Version}), cubicweb-twisted (= ${source:Version}), cubicweb-client (= ${source:Version}) +XB-Recommends: (postgresql, postgresql-plpython, postgresql-contrib) | mysql | sqlite3 +Recommends: postgresql | mysql | sqlite3 +Description: the complete CubicWeb framework + CubicWeb is a semantic web application framework. + . + This package will install all the components you need to run cubicweb on + a single machine. You can also deploy cubicweb by running the different + process on different computers, in which case you need to install the + corresponding packages on the different hosts. + + +Package: cubicweb-server +Architecture: all +XB-Python-Version: ${python:Versions} +Conflicts: cubicweb-multisources +Replaces: cubicweb-multisources +Provides: cubicweb-multisources +Depends: ${python:Depends}, cubicweb-common (= ${source:Version}), cubicweb-ctl (= ${source:Version}), python-indexer (>= 0.6.1), python-psycopg2 | python-mysqldb | python-pysqlite2 +Recommends: pyro, cubicweb-documentation (= ${source:Version}) +Description: server part of the CubicWeb framework + CubicWeb is a semantic web application framework. + . + This package provides the repository server part of the system. + . + This package provides the repository server part of the library and + necessary shared data files such as the schema library. + + +Package: cubicweb-twisted +Architecture: all +XB-Python-Version: ${python:Versions} +Provides: cubicweb-web-frontend +Depends: ${python:Depends}, cubicweb-web (= ${source:Version}), cubicweb-ctl (= ${source:Version}), python-twisted-web2 +Recommends: pyro, cubicweb-documentation (= ${source:Version}) +Description: twisted-based web interface for the CubicWeb framework + CubicWeb is a semantic web application framework. + . + 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. + + +Package: cubicweb-web +Architecture: all +XB-Python-Version: ${python:Versions} +Depends: ${python:Depends}, cubicweb-common (= ${source:Version}), python-docutils, python-vobject, python-elementtree +Recommends: fckeditor +Description: web interface library for the CubicWeb framework + CubicWeb is a semantic web application framework. + . + This package provides an adaptative web interface to the CubicWeb server. + Install the cubicweb-twisted package to serve this interface via HTTP. + . + This package provides the web interface part of the library and + necessary shared data files such as defaut views, images... + + +Package: cubicweb-common +Architecture: all +XB-Python-Version: ${python:Versions} +Depends: ${python:Depends}, python-logilab-mtconverter (>= 0.6.0), python-simpletal (>= 4.0), graphviz, gettext, python-lxml, python-logilab-common (>= 0.38.1), python-yams (>= 0.20.2), python-rql (>= 0.20.2), python-simplejson (>= 1.3) +Recommends: python-psyco +Conflicts: cubicweb-core +Replaces: cubicweb-core +Description: common library for the CubicWeb framework + CubicWeb is a semantic web application framework. + . + This package provides the common parts of the library used by both server + code and web application code. + + +Package: cubicweb-ctl +Architecture: all +XB-Python-Version: ${python:Versions} +Depends: ${python:Depends}, cubicweb-common (= ${source:Version}) +Description: tool to manage the CubicWeb framework + CubicWeb is a semantic web application framework. + . + This package provides a control script to manage (create, upgrade, start, + stop, etc) CubicWeb applications. It also include the init.d script + to automatically start and stop CubicWeb applications on boot or shutdown. + + +Package: cubicweb-client +Architecture: all +XB-Python-Version: ${python:Versions} +Depends: ${python:Depends}, cubicweb-ctl (= ${source:Version}), pyro +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 + pyro to connect to a repository server. + + +Package: cubicweb-dev +Architecture: all +XB-Python-Version: ${python:Versions} +Depends: ${python:Depends}, cubicweb-server (= ${source:Version}), cubicweb-web (= ${source:Version}), python-pysqlite2 +Suggests: w3c-dtd-xhtml +Description: tests suite and development tools for the CubicWeb framework + CubicWeb is a semantic web application framework. + . + This package provides the CubicWeb tests suite and some development tools + helping in the creation of application. + + +Package: cubicweb-documentation +Architecture: all +Recommends: doc-base +Description: documentation for the CubicWeb framework + CubicWeb is a semantic web application framework. + . + This package provides the system's documentation. diff -r a81d3babb582 -r 9d61b146f505 debian.hardy/rules --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debian.hardy/rules Wed Apr 15 17:36:09 2009 +0200 @@ -0,0 +1,78 @@ +#!/usr/bin/make -f +# Sample debian/rules that uses debhelper. +# GNU copyright 1997 to 1999 by Joey Hess. + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + +PY_VERSION:=$(shell pyversions -d) + +build: build-stamp +build-stamp: + dh_testdir + # XXX doesn't work if logilab-doctools, logilab-xml are not in build depends + # and I can't get pbuilder find them in its chroot :( + # cd doc && make + # FIXME cleanup and use sphinx-build as build-depends ? + python setup.py build + touch build-stamp + +clean: + dh_testdir + dh_testroot + rm -f build-stamp configure-stamp + rm -rf build + #rm -rf debian/cubicweb-*/ + find . -name "*.pyc" -delete + rm -f $(basename $(wildcard debian/*.in)) + dh_clean + +install: build $(basename $(wildcard debian/*.in)) + dh_testdir + dh_testroot + dh_clean + dh_installdirs + + #python setup.py install_lib --no-compile --install-dir=debian/cubicweb-common/usr/lib/python2.4/site-packages/ + python setup.py -q install --no-compile --prefix=debian/tmp/usr + + # Put all the python library and data in cubicweb-common + # and scripts in cubicweb-server + dh_install -vi + #dh_lintian XXX not before debhelper 7 + + # Remove unittests directory (should be available in cubicweb-dev only) + rm -rf debian/cubicweb-server/usr/lib/${PY_VERSION}/site-packages/cubicweb/server/test + rm -rf debian/cubicweb-server/usr/lib/${PY_VERSION}/site-packages/cubicweb/sobjects/test + rm -rf debian/cubicweb-web/usr/lib/${PY_VERSION}/site-packages/cubicweb/web/test + rm -rf debian/cubicweb-common/usr/lib/${PY_VERSION}/site-packages/cubicweb/common/test + + # cubes directory must be managed as a valid python module + touch debian/cubicweb-common/usr/share/cubicweb/cubes/__init__.py + +%: %.in + sed "s/PY_VERSION/${PY_VERSION}/g" < $< > $@ + +# Build architecture-independent files here. +binary-indep: build install + dh_testdir + dh_testroot -i + dh_pycentral -i + dh_installinit -i -n --name cubicweb -u"defaults 99" + dh_installlogrotate -i + dh_installdocs -i -A README + dh_installman -i + dh_installchangelogs -i + dh_link -i + dh_compress -i -X.py -X.ini -X.xml + dh_fixperms -i + dh_installdeb -i + dh_gencontrol -i + dh_md5sums -i + dh_builddeb -i + +binary-arch: + +binary: binary-indep +.PHONY: build clean binary binary-indep binary-arch + diff -r a81d3babb582 -r 9d61b146f505 debian/changelog --- a/debian/changelog Thu Jan 15 10:13:25 2009 +0100 +++ b/debian/changelog Wed Apr 15 17:36:09 2009 +0200 @@ -1,3 +1,52 @@ +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 + + -- Sylvain Thénault Wed, 25 Feb 2009 18:41:47 +0100 + +cubicweb (3.0.10-1) unstable; urgency=low + + * merge cubicweb-core package into cubicweb-common + * simplify debian/rules + + -- Julien Jehannet Thu, 19 Feb 2009 16:24:09 +0100 + +cubicweb (3.0.9-1) unstable; urgency=low + + * new upstream (interim) release + + -- Aurélien Campéas Tue, 10 Feb 2009 14:05:12 +0100 + +cubicweb (3.0.4-1) unstable; urgency=low + + * new upstream release + + -- Sylvain Thénault Tue, 27 Jan 2009 16:05:12 +0100 + cubicweb (3.0.3-1) DISTRIBUTION; urgency=low * new upstream release diff -r a81d3babb582 -r 9d61b146f505 debian/compat --- a/debian/compat Thu Jan 15 10:13:25 2009 +0100 +++ b/debian/compat Wed Apr 15 17:36:09 2009 +0200 @@ -1,1 +1,1 @@ -5 +7 diff -r a81d3babb582 -r 9d61b146f505 debian/control --- a/debian/control Thu Jan 15 10:13:25 2009 +0100 +++ b/debian/control Wed Apr 15 17:36:09 2009 +0200 @@ -1,17 +1,21 @@ Source: cubicweb Section: web Priority: optional -Maintainer: Logilab Packaging Team -Uploaders: Sylvain Thenault -Build-Depends: debhelper (>= 5.0.37.1), python (>=2.4), python-dev (>=2.4), python-central (>= 0.5) +Maintainer: Logilab S.A. +Uploaders: Sylvain Thenault , + 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 XS-Python-Version: >= 2.4, << 2.6 + Package: cubicweb Architecture: all XB-Python-Version: ${python:Versions} Depends: ${python:Depends}, cubicweb-server (= ${source:Version}), cubicweb-twisted (= ${source:Version}), cubicweb-client (= ${source:Version}) -XBS-Recommends: (postgresql, postgresql-plpython, postgresql-contrib) | mysql | sqlite3 +XB-Recommends: (postgresql, postgresql-plpython, postgresql-contrib) | mysql | sqlite3 Recommends: postgresql | mysql | sqlite3 Description: the complete CubicWeb framework CubicWeb is a semantic web application framework. @@ -51,13 +55,13 @@ 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 Architecture: all XB-Python-Version: ${python:Versions} -Depends: ${python:Depends}, cubicweb-common (= ${source:Version}), python-simplejson (>= 1.3), python-docutils, python-vobject, python-elementtree +Depends: ${python:Depends}, cubicweb-common (= ${source:Version}), python-docutils, python-vobject, python-elementtree Recommends: fckeditor Description: web interface library for the CubicWeb framework CubicWeb is a semantic web application framework. @@ -72,8 +76,10 @@ Package: cubicweb-common Architecture: all XB-Python-Version: ${python:Versions} -Depends: ${python:Depends}, cubicweb-core (= ${source:Version}), python-logilab-mtconverter (>= 0.4.0), python-simpletal (>= 4.0), graphviz, gettext, python-lxml +Depends: ${python:Depends}, python-logilab-mtconverter (>= 0.6.0), python-simpletal (>= 4.0), graphviz, gettext, python-lxml, python-logilab-common (>= 0.38.1), python-yams (>= 0.20.2), python-rql (>= 0.20.2), python-simplejson (>= 1.3) Recommends: python-psyco +Conflicts: cubicweb-core +Replaces: cubicweb-core Description: common library for the CubicWeb framework CubicWeb is a semantic web application framework. . @@ -84,7 +90,7 @@ Package: cubicweb-ctl Architecture: all XB-Python-Version: ${python:Versions} -Depends: ${python:Depends}, cubicweb-core (= ${source:Version}) +Depends: ${python:Depends}, cubicweb-common (= ${source:Version}) Description: tool to manage the CubicWeb framework CubicWeb is a semantic web application framework. . @@ -100,21 +106,10 @@ 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. -Package: cubicweb-core -Architecture: all -XB-Python-Version: ${python:Versions} -Depends: ${python:Depends}, python-logilab-common (>= 0.37.2), python-yams (>= 0.20.2), python-rql (>= 0.20.2) -Description: core library for the CubicWeb framework - CubicWeb is a semantic web application framework. - . - This package provides the core part of the library used by anyone having - to do some cubicweb programming in Python. - - Package: cubicweb-dev Architecture: all XB-Python-Version: ${python:Versions} diff -r a81d3babb582 -r 9d61b146f505 debian/cubicweb-client.dirs --- a/debian/cubicweb-client.dirs Thu Jan 15 10:13:25 2009 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -usr/lib/python2.4/site-packages/cubicweb/ diff -r a81d3babb582 -r 9d61b146f505 debian/cubicweb-client.install.in --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debian/cubicweb-client.install.in Wed Apr 15 17:36:09 2009 +0200 @@ -0,0 +1,1 @@ +debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/hercule.py usr/lib/PY_VERSION/site-packages/cubicweb diff -r a81d3babb582 -r 9d61b146f505 debian/cubicweb-common.dirs --- a/debian/cubicweb-common.dirs Thu Jan 15 10:13:25 2009 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -usr/lib/python2.4/site-packages/cubicweb -usr/lib/python2.4/site-packages/cubicweb/common -usr/share/cubicweb/cubes/shared -usr/share/doc/cubicweb-common diff -r a81d3babb582 -r 9d61b146f505 debian/cubicweb-common.install.in --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debian/cubicweb-common.install.in Wed Apr 15 17:36:09 2009 +0200 @@ -0,0 +1,17 @@ +debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/common/ usr/lib/PY_VERSION/site-packages/cubicweb +debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/entities/ usr/lib/PY_VERSION/site-packages/cubicweb +debian/tmp/usr/share/cubicweb/cubes/shared/i18n usr/share/cubicweb/cubes/shared/ +debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/rset.py usr/share/pyshared/cubicweb +debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/gettext.py usr/share/pyshared/cubicweb +debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/toolsutils.py usr/share/pyshared/cubicweb +debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/cwvreg.py usr/share/pyshared/cubicweb +debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/_exceptions.py usr/share/pyshared/cubicweb +debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/schemaviewer.py usr/share/pyshared/cubicweb +debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/dbapi.py usr/share/pyshared/cubicweb +debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/cwconfig.py usr/share/pyshared/cubicweb +debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/__init__.py usr/share/pyshared/cubicweb +debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/md5crypt.py usr/share/pyshared/cubicweb +debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/schema.py usr/share/pyshared/cubicweb +debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/interfaces.py usr/share/pyshared/cubicweb +debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/vregistry.py usr/share/pyshared/cubicweb +debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/__pkginfo__.py usr/share/pyshared/cubicweb diff -r a81d3babb582 -r 9d61b146f505 debian/cubicweb-core.dirs --- a/debian/cubicweb-core.dirs Thu Jan 15 10:13:25 2009 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ -usr/lib/python2.4/site-packages/cubicweb -usr/share/doc/cubicweb-core diff -r a81d3babb582 -r 9d61b146f505 debian/cubicweb-ctl.cubicweb.init --- a/debian/cubicweb-ctl.cubicweb.init Thu Jan 15 10:13:25 2009 +0100 +++ b/debian/cubicweb-ctl.cubicweb.init Wed Apr 15 17:36:09 2009 +0200 @@ -11,5 +11,22 @@ # Short-Description: Start cubicweb application at boot time ### END INIT INFO +# FIXME Seems to be inadequate here +# FIXME If related to pyro, try instead: +# export PYRO_STORAGE="/tmp" cd /tmp -/usr/bin/cubicweb-ctl $1 --force + +# FIXME Work-around about the following lintian error +# E: cubicweb-ctl: init.d-script-does-not-implement-required-option /etc/init.d/cubicweb start +# +# Check if we are sure to not want the start-stop-daemon machinery here +# Refer to Debian Policy Manual section 9.3.2 (Writing the scripts) for details. + +case "$1" in + "force-reload") + /usr/bin/cubicweb-ctl reload --force + ;; + "*|restart") + /usr/bin/cubicweb-ctl $1 --force + ;; +esac diff -r a81d3babb582 -r 9d61b146f505 debian/cubicweb-ctl.install.in --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debian/cubicweb-ctl.install.in Wed Apr 15 17:36:09 2009 +0200 @@ -0,0 +1,3 @@ +debian/tmp/usr/bin/cubicweb-ctl usr/bin/ +debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/cwctl.py usr/lib/PY_VERSION/site-packages/cubicweb +debian/cubicweb-ctl.bash_completion etc/bash_completion.d/cubicweb-ctl diff -r a81d3babb582 -r 9d61b146f505 debian/cubicweb-ctl.postinst --- a/debian/cubicweb-ctl.postinst Thu Jan 15 10:13:25 2009 +0100 +++ b/debian/cubicweb-ctl.postinst Wed Apr 15 17:36:09 2009 +0200 @@ -2,7 +2,7 @@ case "$1" in configure|abort-upgrade|abort-remove|abort-deconfigure) - update-rc.d cubicweb defaults >/dev/null + update-rc.d cubicweb defaults 99 >/dev/null ;; *) echo "postinst called with unknown argument \`$1'" >&2 diff -r a81d3babb582 -r 9d61b146f505 debian/cubicweb-dev.dirs --- a/debian/cubicweb-dev.dirs Thu Jan 15 10:13:25 2009 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,7 +0,0 @@ -usr/lib/python2.4/site-packages/cubicweb -usr/lib/python2.4/site-packages/cubicweb/common -usr/lib/python2.4/site-packages/cubicweb/web -usr/lib/python2.4/site-packages/cubicweb/server -usr/lib/python2.4/site-packages/cubicweb/sobjects -usr/lib/python2.4/site-packages/cubicweb/entities -usr/share/doc/cubicweb-dev diff -r a81d3babb582 -r 9d61b146f505 debian/cubicweb-dev.install.in --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debian/cubicweb-dev.install.in Wed Apr 15 17:36:09 2009 +0200 @@ -0,0 +1,7 @@ +debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/devtools/ usr/lib/PY_VERSION/site-packages/cubicweb/ +debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/skeleton/ usr/lib/PY_VERSION/site-packages/cubicweb/ +debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/test usr/lib/PY_VERSION/site-packages/cubicweb/ +debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/common/test usr/lib/PY_VERSION/site-packages/cubicweb/common/ +debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/server/test usr/lib/PY_VERSION/site-packages/cubicweb/server/ +debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/sobjects/test usr/lib/PY_VERSION/site-packages/cubicweb/sobjects/ +debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/web/test usr/lib/PY_VERSION/site-packages/cubicweb/web/ diff -r a81d3babb582 -r 9d61b146f505 debian/cubicweb-documentation.dirs --- a/debian/cubicweb-documentation.dirs Thu Jan 15 10:13:25 2009 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -usr/share/doc/cubicweb-documentation/ -usr/share/doc/cubicweb-documentation/devmanual_fr -usr/share/doc-base/ diff -r a81d3babb582 -r 9d61b146f505 debian/cubicweb-documentation.install --- a/debian/cubicweb-documentation.install Thu Jan 15 10:13:25 2009 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -debian/cubicweb-doc usr/share/doc-base/ diff -r a81d3babb582 -r 9d61b146f505 debian/cubicweb-documentation.install.in --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debian/cubicweb-documentation.install.in Wed Apr 15 17:36:09 2009 +0200 @@ -0,0 +1,2 @@ +doc/book usr/share/doc/cubicweb-documentation +debian/cubicweb-doc usr/share/doc-base/cubicweb-doc diff -r a81d3babb582 -r 9d61b146f505 debian/cubicweb-server.dirs --- a/debian/cubicweb-server.dirs Thu Jan 15 10:13:25 2009 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -usr/lib/python2.4/site-packages/cubicweb/ -usr/share/cubicweb -usr/share/doc/cubicweb-server diff -r a81d3babb582 -r 9d61b146f505 debian/cubicweb-server.install.in --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debian/cubicweb-server.install.in Wed Apr 15 17:36:09 2009 +0200 @@ -0,0 +1,4 @@ +debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/server/ usr/lib/PY_VERSION/site-packages/cubicweb +debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/sobjects/ usr/lib/PY_VERSION/site-packages/cubicweb +debian/tmp/usr/share/cubicweb/schemas/ usr/share/cubicweb/ +debian/tmp/usr/share/cubicweb/migration/ usr/share/cubicweb/ diff -r a81d3babb582 -r 9d61b146f505 debian/cubicweb-twisted.dirs --- a/debian/cubicweb-twisted.dirs Thu Jan 15 10:13:25 2009 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -usr/lib/python2.4/site-packages -usr/lib/python2.4/site-packages/cubicweb -usr/share/doc/cubicweb-twisted diff -r a81d3babb582 -r 9d61b146f505 debian/cubicweb-twisted.install.in --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debian/cubicweb-twisted.install.in Wed Apr 15 17:36:09 2009 +0200 @@ -0,0 +1,1 @@ +debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/etwist/ usr/lib/PY_VERSION/site-packages/cubicweb/ diff -r a81d3babb582 -r 9d61b146f505 debian/cubicweb-web.dirs --- a/debian/cubicweb-web.dirs Thu Jan 15 10:13:25 2009 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -usr/lib/python2.4/site-packages/ -usr/lib/python2.4/site-packages/cubicweb -usr/share/cubicweb/cubes/shared -usr/share/doc/cubicweb-web diff -r a81d3babb582 -r 9d61b146f505 debian/cubicweb-web.install.in --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debian/cubicweb-web.install.in Wed Apr 15 17:36:09 2009 +0200 @@ -0,0 +1,3 @@ +debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/web usr/lib/PY_VERSION/site-packages/cubicweb +debian/tmp/usr/share/cubicweb/cubes/shared/data usr/share/cubicweb/cubes/shared +debian/tmp/usr/share/cubicweb/cubes/shared/wdoc usr/share/cubicweb/cubes/shared diff -r a81d3babb582 -r 9d61b146f505 debian/cubicweb-web.lintian-overrides --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debian/cubicweb-web.lintian-overrides Wed Apr 15 17:36:09 2009 +0200 @@ -0,0 +1,1 @@ +cubicweb-web: embedded-javascript-library usr/share/cubicweb/cubes/shared/data/jquery.js diff -r a81d3babb582 -r 9d61b146f505 debian/rules --- a/debian/rules Thu Jan 15 10:13:25 2009 +0100 +++ b/debian/rules Wed Apr 15 17:36:09 2009 +0200 @@ -4,12 +4,16 @@ # Uncomment this to turn on verbose mode. #export DH_VERBOSE=1 + +PY_VERSION:=$(shell pyversions -d) + build: build-stamp build-stamp: dh_testdir # XXX doesn't work if logilab-doctools, logilab-xml are not in build depends # and I can't get pbuilder find them in its chroot :( - #cd doc && make + # cd doc && make + # FIXME cleanup and use sphinx-build as build-depends ? python setup.py build touch build-stamp @@ -18,78 +22,41 @@ dh_testroot rm -f build-stamp configure-stamp rm -rf build - rm -rf debian/cubicweb-*/ - find . -name "*.pyc" | xargs rm -f + #rm -rf debian/cubicweb-*/ + find . -name "*.pyc" -delete + rm -f $(basename $(wildcard debian/*.in)) dh_clean -install: build +install: build $(basename $(wildcard debian/*.in)) dh_testdir dh_testroot - dh_clean -k + dh_clean dh_installdirs - ########## core package ############################################# - # put : - # * all the python library and data in cubicweb-core - # * scripts in cubicweb-server - # - # pick from each latter to construct each package - python setup.py -q install_lib --no-compile --install-dir=debian/cubicweb-core/usr/lib/python2.4/site-packages/ - python setup.py -q install_data --install-dir=debian/cubicweb-core/usr/ - python setup.py -q install_scripts --install-dir=debian/cubicweb-server/usr/bin/ - ########## common package ############################################# - mv debian/cubicweb-core/usr/lib/python2.4/site-packages/cubicweb/common/ debian/cubicweb-common/usr/lib/python2.4/site-packages/cubicweb - mv debian/cubicweb-core/usr/lib/python2.4/site-packages/cubicweb/entities/ debian/cubicweb-common/usr/lib/python2.4/site-packages/cubicweb - # data - mv debian/cubicweb-core/usr/share/cubicweb/cubes/shared/i18n debian/cubicweb-common/usr/share/cubicweb/cubes/shared/ + + #python setup.py install_lib --no-compile --install-dir=debian/cubicweb-common/usr/lib/python2.4/site-packages/ + python setup.py -q install --no-compile --prefix=debian/tmp/usr + + # Put all the python library and data in cubicweb-common + # and scripts in cubicweb-server + dh_install -vi + dh_lintian + + # Remove unittests directory (should be available in cubicweb-dev only) + rm -rf debian/cubicweb-server/usr/lib/${PY_VERSION}/site-packages/cubicweb/server/test + rm -rf debian/cubicweb-server/usr/lib/${PY_VERSION}/site-packages/cubicweb/sobjects/test + rm -rf debian/cubicweb-web/usr/lib/${PY_VERSION}/site-packages/cubicweb/web/test + rm -rf debian/cubicweb-common/usr/lib/${PY_VERSION}/site-packages/cubicweb/common/test + + # cubes directory must be managed as a valid python module touch debian/cubicweb-common/usr/share/cubicweb/cubes/__init__.py - ########## server package ############################################# - # library - mv debian/cubicweb-core/usr/lib/python2.4/site-packages/cubicweb/server/ debian/cubicweb-server/usr/lib/python2.4/site-packages/cubicweb - mv debian/cubicweb-core/usr/lib/python2.4/site-packages/cubicweb/sobjects/ debian/cubicweb-server/usr/lib/python2.4/site-packages/cubicweb - # data - mv debian/cubicweb-core/usr/share/cubicweb/schemas/ debian/cubicweb-server/usr/share/cubicweb/ - mv debian/cubicweb-core/usr/share/cubicweb/migration/ debian/cubicweb-server/usr/share/cubicweb/ - ########## twisted package ############################################ - # library - mv debian/cubicweb-core/usr/lib/python2.4/site-packages/cubicweb/etwist/ debian/cubicweb-twisted/usr/lib/python2.4/site-packages/cubicweb/ - ########## web package ################################################ - # library - mv debian/cubicweb-core/usr/lib/python2.4/site-packages/cubicweb/web/ debian/cubicweb-web/usr/lib/python2.4/site-packages/cubicweb/ - # data / web documentation - mv debian/cubicweb-core/usr/share/cubicweb/cubes/shared/data debian/cubicweb-web/usr/share/cubicweb/cubes/shared/ - mv debian/cubicweb-core/usr/share/cubicweb/cubes/shared/wdoc debian/cubicweb-web/usr/share/cubicweb/cubes/shared/ - ########## ctl package ################################################ - # scripts - mv debian/cubicweb-server/usr/bin/cubicweb-ctl debian/cubicweb-ctl/usr/bin/ - mv debian/cubicweb-core/usr/lib/python2.4/site-packages/cubicweb/cwctl.py debian/cubicweb-ctl/usr/lib/python2.4/site-packages/cubicweb - mv debian/cubicweb-ctl.bash_completion debian/cubicweb-ctl/etc/bash_completion.d/cubicweb-ctl - ########## client package ############################################# - # library - mv debian/cubicweb-core/usr/lib/python2.4/site-packages/cubicweb/hercule.py debian/cubicweb-client/usr/lib/python2.4/site-packages/cubicweb - ########## dev package ################################################ - # devtools package - mv debian/cubicweb-core/usr/lib/python2.4/site-packages/cubicweb/devtools/ debian/cubicweb-dev/usr/lib/python2.4/site-packages/cubicweb/ - mv debian/cubicweb-core/usr/lib/python2.4/site-packages/cubicweb/skeleton/ debian/cubicweb-dev/usr/lib/python2.4/site-packages/cubicweb/ - # tests directories - mv debian/cubicweb-core/usr/lib/python2.4/site-packages/cubicweb/test debian/cubicweb-dev/usr/lib/python2.4/site-packages/cubicweb/ - mv debian/cubicweb-common/usr/lib/python2.4/site-packages/cubicweb/common/test debian/cubicweb-dev/usr/lib/python2.4/site-packages/cubicweb/common/ - mv debian/cubicweb-server/usr/lib/python2.4/site-packages/cubicweb/server/test debian/cubicweb-dev/usr/lib/python2.4/site-packages/cubicweb/server/ - mv debian/cubicweb-server/usr/lib/python2.4/site-packages/cubicweb/sobjects/test debian/cubicweb-dev/usr/lib/python2.4/site-packages/cubicweb/sobjects/ - mv debian/cubicweb-web/usr/lib/python2.4/site-packages/cubicweb/web/test debian/cubicweb-dev/usr/lib/python2.4/site-packages/cubicweb/web/ - ########## documentation package ###################################### - cp -r doc/book debian/cubicweb-documentation/usr/share/doc/cubicweb-documentation/ - ########## core package ############################################### - # small cleanup - rm -rf debian/cubicweb-core/usr/share/cubicweb/ - # undistributed for now - rm -rf debian/cubicweb-core/usr/lib/python2.4/site-packages/cubicweb/goa - rm -rf debian/cubicweb-core/usr/lib/python2.4/site-packages/cubicweb/wsgi + +%: %.in + sed "s/PY_VERSION/${PY_VERSION}/g" < $< > $@ # Build architecture-independent files here. binary-indep: build install dh_testdir dh_testroot -i - dh_install -i dh_pycentral -i dh_installinit -i -n --name cubicweb -u"defaults 99" dh_installlogrotate -i diff -r a81d3babb582 -r 9d61b146f505 devtools/__init__.py --- a/devtools/__init__.py Thu Jan 15 10:13:25 2009 +0100 +++ b/devtools/__init__.py Wed Apr 15 17:36:09 2009 +0200 @@ -260,6 +260,8 @@ - http://www.sqlite.org/cvstrac/tktview?tn=1327,33 (some dates are returned as strings rather thant date objects) """ + if hasattr(querier.__class__, '_devtools_sqlite_patched'): + return # already monkey patched def wrap_execute(base_execute): def new_execute(*args, **kwargs): rset = base_execute(*args, **kwargs) @@ -288,7 +290,7 @@ return rset return new_execute querier.__class__.execute = wrap_execute(querier.__class__.execute) - + querier.__class__._devtools_sqlite_patched = True def init_test_database(driver='sqlite', configdir='data', config=None, vreg=None): diff -r a81d3babb582 -r 9d61b146f505 devtools/apptest.py --- a/devtools/apptest.py Thu Jan 15 10:13:25 2009 +0100 +++ b/devtools/apptest.py Wed Apr 15 17:36:09 2009 +0200 @@ -407,6 +407,7 @@ self.__close(self.cnxid) # other utilities ######################################################### + def set_debug(self, debugmode): from cubicweb.server import set_debug set_debug(debugmode) @@ -452,7 +453,7 @@ self.__commit = repo.commit self.__rollback = repo.rollback self.__close = repo.close - self.cnxid = repo.connect(*self.default_user_password()) + self.cnxid = self.cnx.sessionid self.session = repo._sessions[self.cnxid] # XXX copy schema since hooks may alter it and it may be not fully # cleaned (missing some schema synchronization support) @@ -499,6 +500,6 @@ self.rollback() self.session.unsafe_execute('DELETE Any X WHERE X eid > %(x)s', {'x': self.maxeid}) self.commit() - if close: - self.close() + #if close: + # self.close() diff -r a81d3babb582 -r 9d61b146f505 devtools/devctl.py --- a/devtools/devctl.py Thu Jan 15 10:13:25 2009 +0100 +++ b/devtools/devctl.py Wed Apr 15 17:36:09 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') @@ -503,17 +513,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(): @@ -521,8 +536,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 a81d3babb582 -r 9d61b146f505 devtools/fill.py --- a/devtools/fill.py Thu Jan 15 10:13:25 2009 +0100 +++ b/devtools/fill.py Wed Apr 15 17:36:09 2009 +0200 @@ -136,6 +136,9 @@ def generate_integer(self, attrname, index): """generates a consistent value for 'attrname' if it's an integer""" + choosed = self.generate_choice(attrname, index) + if choosed is not None: + return choosed minvalue, maxvalue = get_bounds(self.e_schema, attrname) if maxvalue is not None and maxvalue <= 0 and minvalue is None: minvalue = maxvalue - index # i.e. randint(-index, 0) diff -r a81d3babb582 -r 9d61b146f505 devtools/repotest.py --- a/devtools/repotest.py Thu Jan 15 10:13:25 2009 +0100 +++ b/devtools/repotest.py Wed Apr 15 17:36:09 2009 +0200 @@ -3,7 +3,7 @@ This module contains functions to initialize a new repository. :organization: Logilab -:copyright: 2003-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +:copyright: 2003-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved. :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr """ __docformat__ = "restructuredtext en" @@ -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 @@ -249,7 +260,8 @@ _orig_select_principal = rqlannotation._select_principal def _select_principal(scope, relations): - return _orig_select_principal(scope, sorted(relations, key=lambda x: x.r_type)) + return _orig_select_principal(scope, relations, + _sort=lambda rels: sorted(rels, key=lambda x: x.r_type)) try: from cubicweb.server.msplanner import PartPlanInformation @@ -257,15 +269,15 @@ class PartPlanInformation(object): def merge_input_maps(*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: @@ -278,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(): @@ -298,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 @@ -306,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 a81d3babb582 -r 9d61b146f505 devtools/test/data/bootstrap_cubes --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/devtools/test/data/bootstrap_cubes Wed Apr 15 17:36:09 2009 +0200 @@ -0,0 +1,1 @@ +person, comment diff -r a81d3babb582 -r 9d61b146f505 devtools/test/data/bootstrap_packages --- a/devtools/test/data/bootstrap_packages Thu Jan 15 10:13:25 2009 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -eperson, ecomment diff -r a81d3babb582 -r 9d61b146f505 devtools/testlib.py --- a/devtools/testlib.py Thu Jan 15 10:13:25 2009 +0100 +++ b/devtools/testlib.py Wed Apr 15 17:36:09 2009 +0200 @@ -78,6 +78,8 @@ return center - before <= line_no <= center + after ## base webtest class ######################################################### +VALMAP = {None: None, 'dtd': DTDValidator, 'xml': SaxOnlyValidator} + class WebTest(EnvBasedTC): """base class for web tests""" __abstract__ = True @@ -93,35 +95,28 @@ # SaxOnlyValidator : guarantees XML is well formed # None : do not try to validate anything # validators used must be imported from from.devtools.htmlparser - validators = { - # maps vid : validator name - 'hcal' : SaxOnlyValidator, - 'rss' : SaxOnlyValidator, - 'rssitem' : None, - 'xml' : SaxOnlyValidator, - 'xmlitem' : None, - 'xbel' : SaxOnlyValidator, - 'xbelitem' : None, - 'vcard' : None, - 'fulltext': None, - 'fullthreadtext': None, - 'fullthreadtext_descending': None, - 'text' : None, - 'treeitemview': None, - 'textincontext' : None, - 'textoutofcontext' : None, - 'combobox' : None, - 'csvexport' : None, - 'ecsvexport' : None, + content_type_validators = { + # maps MIME type : validator name + # + # do not set html validators here, we need HTMLValidator for html + # snippets + #'text/html': DTDValidator, + #'application/xhtml+xml': DTDValidator, + 'application/xml': SaxOnlyValidator, + 'text/xml': SaxOnlyValidator, + 'text/plain': None, + 'text/comma-separated-values': None, + 'text/x-vcard': None, + 'text/calendar': None, + 'application/json': None, + 'image/png': None, } - valmap = {None: None, 'dtd': DTDValidator, 'xml': SaxOnlyValidator} - no_auto_populate = () - ignored_relations = () + # maps vid : validator name (override content_type_validators) + vid_validators = dict((vid, VALMAP[valkey]) + for vid, valkey in VIEW_VALIDATORS.iteritems()) - def __init__(self, *args, **kwargs): - EnvBasedTC.__init__(self, *args, **kwargs) - for view, valkey in VIEW_VALIDATORS.iteritems(): - self.validators[view] = self.valmap[valkey] + no_auto_populate = () + ignored_relations = () def custom_populate(self, how_many, cursor): pass @@ -163,21 +158,24 @@ self.commit() @nocoverage - def _check_html(self, output, vid, template='main'): + def _check_html(self, output, view, template='main'): """raises an exception if the HTML is invalid""" - if template is None: - default_validator = HTMLValidator - else: - default_validator = DTDValidator - validatorclass = self.validators.get(vid, default_validator) + try: + validatorclass = self.vid_validators[view.id] + except KeyError: + if template is None: + default_validator = HTMLValidator + else: + default_validator = DTDValidator + validatorclass = self.content_type_validators.get(view.content_type, + default_validator) if validatorclass is None: return None validator = validatorclass() - output = output.strip() - return validator.parse_string(output) + return validator.parse_string(output.strip()) - def view(self, vid, rset, req=None, template='main', htmlcheck=True, **kwargs): + def view(self, vid, rset, req=None, template='main', **kwargs): """This method tests the view `vid` on `rset` using `template` If no error occured while rendering the view, the HTML is analyzed @@ -194,8 +192,6 @@ # print req.form['vid'] = vid view = self.vreg.select_view(vid, req, rset, **kwargs) - if view.content_type not in ('application/xml', 'application/xhtml+xml', 'text/html'): - htmlcheck = False # set explicit test description if rset is not None: self.set_description("testing %s, mod=%s (%s)" % (vid, view.__module__, rset.printable_rql())) @@ -207,15 +203,18 @@ elif template == 'main': _select_view_and_rset = TheMainTemplate._select_view_and_rset # patch TheMainTemplate.process_rql to avoid recomputing resultset - TheMainTemplate._select_view_and_rset = lambda *a, **k: (view, rset) + def __select_view_and_rset(self, view=view, rset=rset): + self.rset = rset + return view, rset + TheMainTemplate._select_view_and_rset = __select_view_and_rset try: - return self._test_view(viewfunc, vid, htmlcheck, template, **kwargs) + return self._test_view(viewfunc, view, template, **kwargs) finally: if template == 'main': TheMainTemplate._select_view_and_rset = _select_view_and_rset - def _test_view(self, viewfunc, vid, htmlcheck=True, template='main', **kwargs): + def _test_view(self, viewfunc, view, template='main', **kwargs): """this method does the actual call to the view If no error occured while rendering the view, the HTML is analyzed @@ -227,10 +226,7 @@ output = None try: output = viewfunc(**kwargs) - if htmlcheck: - return self._check_html(output, vid, template) - else: - return output + return self._check_html(output, view, template) except (SystemExit, KeyboardInterrupt): raise except: @@ -238,19 +234,16 @@ # is not an AssertionError klass, exc, tcbk = sys.exc_info() try: - msg = '[%s in %s] %s' % (klass, vid, exc) + msg = '[%s in %s] %s' % (klass, view.id, exc) except: - msg = '[%s in %s] undisplayable exception' % (klass, vid) + msg = '[%s in %s] undisplayable exception' % (klass, view.id) if output is not None: position = getattr(exc, "position", (0,))[0] if position: # define filter - - output = output.splitlines() width = int(log(len(output), 10)) + 1 line_template = " %" + ("%i" % width) + "i: %s" - # XXX no need to iterate the whole file except to get # the line number output = '\n'.join(line_template % (idx + 1, line) @@ -259,12 +252,15 @@ msg+= '\nfor output:\n%s' % output raise AssertionError, msg, tcbk - - def iter_automatic_rsets(self): + + def to_test_etypes(self): + return unprotected_entities(self.schema, strict=True) + + def iter_automatic_rsets(self, limit=10): """generates basic resultsets for each entity type""" - etypes = unprotected_entities(self.schema, strict=True) + etypes = self.to_test_etypes() for etype in etypes: - yield self.execute('Any X WHERE X is %s' % etype) + yield self.execute('Any X LIMIT %s WHERE X is %s' % (limit, etype)) etype1 = etypes.pop() etype2 = etypes.pop() @@ -281,23 +277,26 @@ """returns the list of views that can be applied on `rset`""" req = rset.req only_once_vids = ('primary', 'secondary', 'text') - skipped = ('restriction', 'cell') req.data['ex'] = ValueError("whatever") for vid, views in self.vreg.registry('views').items(): if vid[0] == '_': continue - try: - view = self.vreg.select(views, req, rset) - if view.id in skipped: - continue - if view.category == 'startupview': + if rset.rowcount > 1 and vid in only_once_vids: + continue + views = [view for view in views + if view.category != 'startupview' + and not issubclass(view, NotificationView)] + if views: + try: + view = self.vreg.select(views, req, rset) + if view.linkable(): + yield view + else: + not_selected(self.vreg, view) + # else the view is expected to be used as subview and should + # not be tested directly + except NoSelectableObject: continue - if rset.rowcount > 1 and view.id in only_once_vids: - continue - if not isinstance(view, NotificationView): - yield view - except NoSelectableObject: - continue def list_actions_for(self, rset): """returns the list of actions that can be applied on `rset`""" @@ -305,27 +304,25 @@ for action in self.vreg.possible_objects('actions', req, rset): yield action - def list_boxes_for(self, rset): """returns the list of boxes that can be applied on `rset`""" req = rset.req for box in self.vreg.possible_objects('boxes', req, rset): yield box - def list_startup_views(self): """returns the list of startup views""" req = self.request() for view in self.vreg.possible_views(req, None): - if view.category != 'startupview': - continue - yield view.id - + if view.category == 'startupview': + yield view.id + else: + not_selected(self.vreg, view) + def _test_everything_for(self, rset): """this method tries to find everything that can be tested for `rset` and yields a callable test (as needed in generative tests) """ - rqlst = parse(rset.rql) propdefs = self.vreg['propertydefs'] # make all components visible for k, v in propdefs.items(): @@ -335,7 +332,7 @@ backup_rset = rset._prepare_copy(rset.rows, rset.description) yield InnerTest(self._testname(rset, view.id, 'view'), self.view, view.id, rset, - rset.req.reset_headers(), 'main', not view.binary) + rset.req.reset_headers(), 'main') # We have to do this because some views modify the # resultset's syntax tree rset = backup_rset @@ -348,8 +345,6 @@ for box in self.list_boxes_for(rset): yield InnerTest(self._testname(rset, box.id, 'box'), box.dispatch) - - @staticmethod def _testname(rset, objid, objtype): return '%s_%s_%s' % ('_'.join(rset.column_types(0)), objid, objtype) @@ -360,14 +355,14 @@ ## one each def test_one_each_config(self): self.auto_populate(1) - for rset in self.iter_automatic_rsets(): + for rset in self.iter_automatic_rsets(limit=1): for testargs in self._test_everything_for(rset): yield testargs ## ten each def test_ten_each_config(self): self.auto_populate(10) - for rset in self.iter_automatic_rsets(): + for rset in self.iter_automatic_rsets(limit=10): for testargs in self._test_everything_for(rset): yield testargs @@ -390,4 +385,36 @@ rset2 = rset.limit(limit=1, offset=row) yield rset2 +def not_selected(vreg, vobject): + try: + vreg._selected[vobject.__class__] -= 1 + except (KeyError, AttributeError): + pass +def vreg_instrumentize(testclass): + from cubicweb.devtools.apptest import TestEnvironment + env = testclass._env = TestEnvironment('data', configcls=testclass.configcls, + requestcls=testclass.requestcls) + vreg = env.vreg + vreg._selected = {} + orig_select = vreg.__class__.select + def instr_select(self, *args, **kwargs): + selected = orig_select(self, *args, **kwargs) + try: + self._selected[selected.__class__] += 1 + except KeyError: + self._selected[selected.__class__] = 1 + except AttributeError: + pass # occurs on vreg used to restore database + return selected + vreg.__class__.select = instr_select + +def print_untested_objects(testclass, skipregs=('hooks', 'etypes')): + vreg = testclass._env.vreg + for registry, vobjectsdict in vreg.items(): + if registry in skipregs: + continue + for vobjects in vobjectsdict.values(): + for vobject in vobjects: + if not vreg._selected.get(vobject): + print 'not tested', registry, vobject diff -r a81d3babb582 -r 9d61b146f505 doc/book/en/A000-introduction.en.txt --- a/doc/book/en/A000-introduction.en.txt Thu Jan 15 10:13:25 2009 +0100 +++ b/doc/book/en/A000-introduction.en.txt Wed Apr 15 17:36:09 2009 +0200 @@ -1,5 +1,6 @@ .. -*- coding: utf-8 -*- +.. _Part1: =================================== Part I - Introduction to `CubicWeb` diff -r a81d3babb582 -r 9d61b146f505 doc/book/en/A020-tutorial.en.txt --- a/doc/book/en/A020-tutorial.en.txt Thu Jan 15 10:13:25 2009 +0100 +++ b/doc/book/en/A020-tutorial.en.txt Wed Apr 15 17:36:09 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 a81d3babb582 -r 9d61b146f505 doc/book/en/A02a-create-cube.en.txt --- a/doc/book/en/A02a-create-cube.en.txt Thu Jan 15 10:13:25 2009 +0100 +++ b/doc/book/en/A02a-create-cube.en.txt Wed Apr 15 17:36:09 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 a81d3babb582 -r 9d61b146f505 doc/book/en/A03a-concepts.en.txt --- a/doc/book/en/A03a-concepts.en.txt Thu Jan 15 10:13:25 2009 +0100 +++ b/doc/book/en/A03a-concepts.en.txt Wed Apr 15 17:36:09 2009 +0200 @@ -11,19 +11,19 @@ .. image:: images/archi_globale.en.png -`CubicWeb` framework is a server/client application framework. Those two -parties communicates through RQL (`CubicWeb` query language implementation) +`CubicWeb` framework is a server/client application framework. Those two +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,9 +42,9 @@ 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 - cubes (which defined application entities) that can be explicitely + 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. *entity type* @@ -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). @@ -69,7 +69,7 @@ *relation definition* A relation definition is a 3-uple (subject entity type, relation type, object entity type), with an associated set of property such as cardinality, constraints... - + *repository* This is the RQL server side of `CubicWeb`. Be carefull not to get confused with a Mercurial repository or a debian repository. @@ -77,42 +77,42 @@ *source* 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 + `CubicWeb` repository. This repository has at least one source, `system` which + 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 - - ``all-in-one`` : web interface and repository in a single process. + - ``all-in-one`` : web interface and repository in a single process. The repository could be or not accessible using Pyro. *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 + An instance is a specific installation of one or multiple cubes. All the required configuration files necessary for the well being of your web application 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 - and sometimes to talk of a cube depending on the context. + 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. @@ -127,7 +127,7 @@ *query language* A full-blown query language named RQL is used to formulate requests - to the database or any sources such as LDAP or `Google App Engine`'s + to the database or any sources such as LDAP or `Google App Engine`'s datastore. *views* @@ -143,11 +143,11 @@ 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/ .. _`yams`: http://www.logilab.org/project/yams/ @@ -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 @@ -194,36 +194,36 @@ ~~~~~~~~~~~~~~ The Python API developped to interface with RQL is inspired from the standard db-api, -with a Connection object having the methods cursor, rollback and commit essentially. +with a Connection object having the methods cursor, rollback and commit essentially. The most important method is the `execute` method of a cursor : `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 -:eid_key: - an implementation detail of the RQL queries cache implies that if a substitution +:args: if the query contains substitutions, a dictionary containing the values to use +:eid_key: + 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 The `Connection` object owns the methods `commit` and `rollback`. You *should never need to use them* during the development of the web interface based on -the `CubicWeb` framework as it determines the end of the transaction depending +the `CubicWeb` framework as it determines the end of the transaction depending 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. - + The `Request` class (`cubicweb.web`) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 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,21 +232,21 @@ * `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 * `del_session_data(key)`, suppress the value associated to a key - + :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 @@ -290,7 +290,7 @@ `__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 +We can find a certain number of attributes and methods defined in this class and common to all the application objects. At the recording, the following attributes are dynamically added to @@ -333,7 +333,7 @@ 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 + * `format_date(date, date_format=None, time=False)` returns a string for a mx date time according to application's configuration * `format_time(time)` returns a string for a mx date time according to application's configuration @@ -342,8 +342,8 @@ * `external_resource(rid, default=_MARKER)`, access to a value defined in the configuration file `external_resource` - - * `tal_render(template, variables)`, renders a precompiled page template with + + * `tal_render(template, variables)`, renders a precompiled page template with variables in the given dictionary as context .. note:: @@ -357,7 +357,7 @@ PrimaryView.f(self, arg1) You'd better write: :: - + class Truc(PrimaryView): def f(self, arg1): super(Truc, self).f(arg1) @@ -372,9 +372,9 @@ 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 +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 Forge`_ under a free software license. @@ -388,12 +388,12 @@ A cube is structured as follows: :: - + mycube/ | |-- data/ | |-- cubes.mycube.css - | |-- cubes.mycube.js + | |-- cubes.mycube.js | `-- external_resources | |-- debian/ @@ -437,12 +437,12 @@ | `-- views.py - + We can use subpackages instead of python modules for ``views.py``, ``entities.py``, ``schema.py`` or ``hooks.py``. For example, we could have: :: - + mycube/ | |-- entities.py @@ -451,7 +451,7 @@ |-- forms.py |-- primary.py `-- widgets.py - + where : @@ -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) @@ -472,14 +472,14 @@ * file ``__pkginfo__.py`` provides component meta-data, especially the distribution and the current version (server side and web interface) or sub-cubes used by the cube. - - + + At least you should have: * 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) + XXX false, we may want to have cubes which are only adding a service, + no persistent data (eg embedding for instance) Standard library diff -r a81d3babb582 -r 9d61b146f505 doc/book/en/B000-development.en.txt --- a/doc/book/en/B000-development.en.txt Thu Jan 15 10:13:25 2009 +0100 +++ b/doc/book/en/B000-development.en.txt Wed Apr 15 17:36:09 2009 +0200 @@ -1,5 +1,6 @@ .. -*- coding: utf-8 -*- +.. _Part2: ===================== Part II - Development diff -r a81d3babb582 -r 9d61b146f505 doc/book/en/B0010-define-schema.en.txt --- a/doc/book/en/B0010-define-schema.en.txt Thu Jan 15 10:13:25 2009 +0100 +++ b/doc/book/en/B0010-define-schema.en.txt Wed Apr 15 17:36:09 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 a81d3babb582 -r 9d61b146f505 doc/book/en/B0011-schema-stdlib.en.txt --- a/doc/book/en/B0011-schema-stdlib.en.txt Thu Jan 15 10:13:25 2009 +0100 +++ b/doc/book/en/B0011-schema-stdlib.en.txt Wed Apr 15 17:36:09 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,40 +31,63 @@ * `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 basic cubes we can find for example : -* `comment`, provides an entity type for `Comment` allowing us to comment others - site's entities - -* `mailinglist`, provides an entity type for `Mailinglist` which groups informations - in a discussion list +* addressbook_: PhoneNumber and PostalAddress -* `file`, provides entity types for `File` et `Image` used to represent - files (text or binary) with additionnal informations such as MIME type or - encoding. - -* `link`, provides an entity type for hypertext link (`Link`) +* basket_: Basket (like a shopping cart) -* `blog`, provides an entity type weblog (`Blog`) - -* `person`, provides an entity type for a person (`Person`) +* blog_: Blog (a *very* basic blog) -* `addressbook`, provides an entity type used to represent phone - numbers (`PhoneNumber`) and mailing address (`PostalAddress`) - -* `classtags`, categorization system based on tags (`Tag`) +* comment_: Comment (to attach comment threads to entities) -* `classfolders`, categorization system based on folders hierarchy in order - to create navigation sections (`Folder`) - -* `email`, archiving management for emails (`Email`, `Emailpart`, +* email_: archiving management for emails (`Email`, `Emailpart`, `Emailthread`) -* `basket`, basket management (`Basket`) allowing to group entities +* event_: Event (define events, display them in calendars) + +* file_: File (to allow users to upload and store binary or text files) + +* folder_: Folder (to organize things but grouping them in folders) + +* keyword_: Keyword (to define classification schemes) + +* link_: Link (to collect links to web resources) + +* mailinglist_: MailingList (to reference a mailing-list and the URLs + for its archives and its admin interface) + +* person_: Person (easily mixed with addressbook) + +* tag_: Tag (to tag anything) + +* task_: Task (something to be done between start and stop date) + +* zone_: Zone (to define places within larger places, for example a + city in a state in a country) + +.. _addressbook: http://www.cubicweb.org/project/cubicweb-addressbook +.. _basket: http://www.cubicweb.org/project/cubicweb-basket +.. _blog: http://www.cubicweb.org/project/cubicweb-blog +.. _comment: http://www.cubicweb.org/project/cubicweb-comment +.. _email: http://www.cubicweb.org/project/cubicweb-email +.. _event: http://www.cubicweb.org/project/cubicweb-event +.. _file: http://www.cubicweb.org/project/cubicweb-file +.. _folder: http://www.cubicweb.org/project/cubicweb-folder +.. _keyword: http://www.cubicweb.org/project/cubicweb-keyword +.. _link: http://www.cubicweb.org/project/cubicweb-link +.. _mailinglist: http://www.cubicweb.org/project/cubicweb-mailinglist +.. _person: http://www.cubicweb.org/project/cubicweb-person +.. _tag: http://www.cubicweb.org/project/cubicweb-tag +.. _task: http://www.cubicweb.org/project/cubicweb-task +.. _zone: http://www.cubicweb.org/project/cubicweb-zone To declare the use of a component, once installed, add the name of the component to the variable `__use__` in the file `__pkginfo__.py` of your own component. diff -r a81d3babb582 -r 9d61b146f505 doc/book/en/B0012-schema-definition.en.txt --- a/doc/book/en/B0012-schema-definition.en.txt Thu Jan 15 10:13:25 2009 +0100 +++ b/doc/book/en/B0012-schema-definition.en.txt Wed Apr 15 17:36:09 2009 +0200 @@ -3,26 +3,32 @@ 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. It is exepected to be +defined in the module ``mycube.schema``. - 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 +40,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 +66,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 +89,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 +102,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 +117,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 +139,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 +147,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 +178,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 +223,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 +379,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 a81d3babb582 -r 9d61b146f505 doc/book/en/B0020-define-workflows.en.txt --- a/doc/book/en/B0020-define-workflows.en.txt Thu Jan 15 10:13:25 2009 +0100 +++ b/doc/book/en/B0020-define-workflows.en.txt Wed Apr 15 17:36:09 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,9 +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 a81d3babb582 -r 9d61b146f505 doc/book/en/B0030-data-as-objects.en.txt --- a/doc/book/en/B0030-data-as-objects.en.txt Thu Jan 15 10:13:25 2009 +0100 +++ b/doc/book/en/B0030-data-as-objects.en.txt Wed Apr 15 17:36:09 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` --------------------------------- +Class `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 `mycube.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 @@ -114,34 +114,134 @@ * `relation_vocabulary(rtype, targettype, x, limit=None)`, called internally by `subject_relation_vocabulary` and `object_relation_vocabulary` +Class `TreeMixIn` +----------------- + +This class provides a tree interface. This mixin has to be inherited +explicitly and configured using the tree_attribute, parent_target and +children_target class attribute to benefit from this default implementation. + +This class provides the following methods: + + * `different_type_children(entities=True)`, returns children entities + of different type as this entity. According to the `entities` parameter, + returns entity objects (if entity=True) or the equivalent result set. + + * `same_type_children(entities=True)`, returns children entities of + the same type as this entity. According to the `entities` parameter, + return entity objects (if entity=True) or the equivalent result set. + + * `iterchildren( _done=None)`, iters on the children of the entity. + + * `prefixiter( _done=None)` + + * `path()`, returns the list of eids from the root object to this object. + + * `iterparents()`, iters on the parents of the entity. + + * `notification_references(view)`, used to control References field + of email send on notification for this entity. `view` is the notification view. + Should return a list of eids which can be used to generate message ids + of previously sent email. + +`TreeMixIn` implements also the ITree interface (``cubicweb.interfaces``): + + * `parent()`, returns the parent entity if any, else None (e.g. if we are on the + root) + + * `children(entities=True, sametype=False)`, returns children entities + according to the `entities` parameter, return entity objects or the + equivalent result set. + + * `children_rql()`, returns the RQL query corresponding to the children + of the entity. + + * `is_leaf()`, returns True if the entity does not have any children. + + * `is_root()`, returns True if the entity does not have any parent. + + * `root()`, returns the root object of the tree representation of + the entity and its related entities. + +Example of use +`````````````` + +Imagine you defined three types of entities in your schema, and they +relates to each others as follows in ``schema.py``:: + + class Entity1(EntityType): + title = String() + is_related_to = SubjectRelation('Entity2', 'subject') + + class Entity2(EntityType): + title = String() + belongs_to = SubjectRelation('Entity3', 'subject') + + class Entity3(EntityType): + name = String() + +You would like to create a view that applies to both entity types +`Entity1` and `Entity2` and which lists the entities they are related to. +That means when you view `Entity1` you want to list all `Entity2`, and +when you view `Entity2` you want to list all `Entity3`. + +In ``entities.py``:: + + class Entity1(TreeMixIn, AnyEntity): + id = 'Entity1' + __implements__ = AnyEntity.__implements__ + (ITree,) + __rtags__ = {('is_related_to', 'Entity2', 'object'): 'link'} + tree_attribute = 'is_related_to' + + def children(self, entities=True): + return self.different_type_children(entities) + + class Entity2(TreeMixIn, AnyEntity): + id = 'Entity2' + __implements__ = AnyEntity.__implements__ + (ITree,) + __rtags__ = {('belongs_to', 'Entity3', 'object'): 'link'} + tree_attribute = 'belongs_to' + + def children(self, entities=True): + return self.different_type_children(entities) + +Once this is done, you can define your common view as follows:: + + class E1E2CommonView(baseviews.PrimaryView): + accepts = ('Entity11, 'Entity2') + + def render_entity_relations(self, entity, siderelations): + self.wview('list', entity.children(entities=False)) + *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 a81d3babb582 -r 9d61b146f505 doc/book/en/B0031-define-entities.en.txt --- a/doc/book/en/B0031-define-entities.en.txt Thu Jan 15 10:13:25 2009 +0100 +++ b/doc/book/en/B0031-define-entities.en.txt Wed Apr 15 17:36:09 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. @@ -55,13 +55,21 @@ It is possible to manage attributes/relations in the simple or multiple editing form thanks to the following *rtags*: -* `primary`, indicates that an attribute or a relation has to be inserted - in the simple or multiple editing forms. In the case of a relation, - the related entity editing form will be included in the editing form. +* `primary`, indicates that an attribute or a relation has to be + inserted **in the simple or multiple editing forms**. In the case of + a relation, the related entity editing form will be included in the + editing form and represented as a combobox. Each item of the + combobox is a link to an existing entity. -* `secondary`, indicates that an attribute or a relation has to be inserted - in the simple editing form only. In the case of a relation, the related - entity editing form sill be included in the editing form. +* `secondary`, indicates that an attribute or a relation has to be + inserted **in the simple editing form only**. In the case of a + relation, the related entity editing form will be included in the + editing form and represented as a combobox. Each item of the combobox + is a link to an existing entity. + +* `inlineview`, includes the target entity's form in the editing form + of the current entity. It allows to create the target entity in the + same time as the current entity. * `generic`, indicates that a relation has to be inserted in the simple editing form, in the generic box of relation creation. @@ -110,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: @@ -149,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 a81d3babb582 -r 9d61b146f505 doc/book/en/B0040-migration.en.txt --- a/doc/book/en/B0040-migration.en.txt Thu Jan 15 10:13:25 2009 +0100 +++ b/doc/book/en/B0040-migration.en.txt Wed Apr 15 17:36:09 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 a81d3babb582 -r 9d61b146f505 doc/book/en/B1020-define-views.en.txt --- a/doc/book/en/B1020-define-views.en.txt Thu Jan 15 10:13:25 2009 +0100 +++ b/doc/book/en/B1020-define-views.en.txt Wed Apr 15 17:36:09 2009 +0200 @@ -1,6 +1,6 @@ .. -*- coding: utf-8 -*- -.. _DefinitionVues: +.. _ViewDefinition: Views definition ================ @@ -13,6 +13,8 @@ understanding of the classes and methods available, then detail the view selection principle which makes `CubicWeb` web interface very flexible. +A `View` is an object applied to another object such as an entity. + Basic class for views --------------------- @@ -61,19 +63,18 @@ * `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 * `AnyRsetView`, view applied to any result set * `EmptyRsetView`, view applied to an empty result set + The selection view principle ---------------------------- @@ -83,14 +84,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``. @@ -98,6 +99,9 @@ Registerer `````````` +[Registerers are deprecated: they will soon disappear for explicite +registration...] + A view is also customizable through its attribute ``__registerer__``. This is used at the time the application is launched to manage how objects (views, graphic components, actions, etc.) @@ -107,14 +111,11 @@ 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. -`CubicWeb` provides a lot of standard views for the default class -`EntityType`. You can find them in ``cubicweb/web/views/``. - .. include:: B1022-views-stdlib.en.txt @@ -163,7 +164,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 +180,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 +207,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 +233,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 +243,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 +263,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 +281,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 a81d3babb582 -r 9d61b146f505 doc/book/en/B1021-views-selectors.en.txt --- a/doc/book/en/B1021-views-selectors.en.txt Thu Jan 15 10:13:25 2009 +0100 +++ b/doc/book/en/B1021-views-selectors.en.txt Wed Apr 15 17:36:09 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 a81d3babb582 -r 9d61b146f505 doc/book/en/B1022-views-stdlib.en.txt --- a/doc/book/en/B1022-views-stdlib.en.txt Thu Jan 15 10:13:25 2009 +0100 +++ b/doc/book/en/B1022-views-stdlib.en.txt Wed Apr 15 17:36:09 2009 +0200 @@ -2,6 +2,10 @@ Predefined views in the library ``````````````````````````````` + +`CubicWeb` provides a lot of standard views. You can find them in +``cubicweb/web/views/``. + A certain number of views are used to build the web interface, which apply to one or more entities. Their identifier is what distinguish them from each others and the main ones are: @@ -56,7 +60,8 @@ This view displays usually a side box of some related entities in a primary view. -Start view: + +Start view (e.g. views that don't apply to a result set): *index* This view defines the home page of your application. It does not require diff -r a81d3babb582 -r 9d61b146f505 doc/book/en/B1030-form-management.en.txt --- a/doc/book/en/B1030-form-management.en.txt Thu Jan 15 10:13:25 2009 +0100 +++ b/doc/book/en/B1030-form-management.en.txt Wed Apr 15 17:36:09 2009 +0200 @@ -13,7 +13,7 @@ The form generated by default does not fit your needs? You are not required to re-do all by hands! :) -* rtags primary, secondary, generated, generic, +* rtags primary, secondary, generated, generic, `Entity.relation_category(rtype, x='subject')` * inline_view (now a rtag?) * widget specification @@ -36,8 +36,8 @@ starting by `eid:` and also having a parameter `__type` associated (also *qualified* by eid) -2. For all the attributes and the relations of an entity to edit: - +2. For all the attributes and the relations of an entity to edit: + 1. search for a parameter `edits-` or `edito-` qualified in the case of a relation where the entity is object 2. if found, the value returned is considered as the initial value @@ -50,24 +50,24 @@ 1. if a qualified parameter `__linkto` is specified, its value has to be a string (or a list of string) such as: :: - + :: - + where is either `subject` or `object` and each eid could be separated from the others by a `_`. Target specifies if the *edited entity* is subject or object of the relation and each relation specified will be inserted. 2. if a qualified parameter `__clone_eid` is specified for an entity, the - relations of the specified entity passed as value of this parameter are + relations of the specified entity passed as value of this parameter are copied on the edited entity. 3. if a qualified parameter `__delete` is specified, its value must be a string or a list of string such as follows: :: - + :: - where each eid subject or object can be seperated from the other + where each eid subject or object can be seperated from the other by `_`. Each relation specified will be deleted. 4. if a qualified parameter `__insert` is specified, its value should @@ -84,14 +84,14 @@ .. note:: - + * If the parameter `__action_delete` is found, all the entities specified as to be edited will be deleted. - + * If the parameter`__action_cancel` is found, no action is completed. - * If the parameter `__action_apply` is found, the editing is applied - normally but the redirection is done on the form + * If the parameter `__action_apply` is found, the editing is applied + normally but the redirection is done on the form (see :ref:`RedirectionControl`). * The parameter `__method` is also supported as for the main template @@ -120,7 +120,7 @@ * `__redirectparams`: forms parameters to add to the path -* `__redirectrql`: redirection RQL request +* `__redirectrql`: redirection RQL request * `__redirectvid`: redirection view identifier @@ -132,6 +132,6 @@ * `__form_id`: initial view form identifier, used if `__action_apply` is found -In general we use either `__redirectpath` and `__redirectparams` or +In general we use either `__redirectpath` and `__redirectparams` or `__redirectrql` and `__redirectvid`. diff -r a81d3babb582 -r 9d61b146f505 doc/book/en/B1060-templates.en.txt --- a/doc/book/en/B1060-templates.en.txt Thu Jan 15 10:13:25 2009 +0100 +++ b/doc/book/en/B1060-templates.en.txt Wed Apr 15 17:36:09 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'