Commit 6fbd314c authored by Sylvain Thénault's avatar Sylvain Thénault
Browse files

backport 3.5

......@@ -68,3 +68,5 @@ ba43e084e8841f62c3b4c2449b26a7546233e5fb cubicweb-version-3.4.8
97273eeaaead11c0f422dc5a4fe2d4f14fc6a2dd cubicweb-debian-version-3.4.8-1
e916f1e856c83aced0fe73f7ae9068e37edcc38c cubicweb-version-3.4.9
24ea70f19a48cce60248ab18695925755009bcb8 cubicweb-debian-version-3.4.9-1
f3d2adf483320d7726136433a41c57b130cbdc15 cubicweb-version-3.4.11
635a25031f4abdd89c44d17f5d2b0d0d43914511 cubicweb-debian-version-3.4.11-1
......@@ -26,10 +26,14 @@ def extract_from_tal(files, output_file):
output.close()
def add_msg(w, msgid):
def add_msg(w, msgid, msgctx=None):
"""write an empty pot msgid definition"""
if isinstance(msgid, unicode):
msgid = msgid.encode('utf-8')
if msgctx:
if isinstance(msgctx, unicode):
msgctx = msgctx.encode('utf-8')
w('msgctxt "%s"\n' % msgctx)
msgid = msgid.replace('"', r'\"').splitlines()
if len(msgid) > 1:
w('msgid ""\n')
......
......@@ -392,7 +392,11 @@ this option is set to yes",
'server/serverctl.py', 'hercule.py',
'devtools/devctl.py', 'goa/goactl.py'):
if exists(join(CW_SOFTWARE_ROOT, ctlfile)):
load_module_from_file(join(CW_SOFTWARE_ROOT, ctlfile))
try:
load_module_from_file(join(CW_SOFTWARE_ROOT, ctlfile))
except ImportError, err:
cls.critical('could not import the command provider %s (cause : %s)' %
(ctlfile, err))
cls.info('loaded cubicweb-ctl plugin %s', ctlfile)
for cube in cls.available_cubes():
pluginfile = join(cls.cube_dir(cube), 'ecplugin.py')
......@@ -808,7 +812,7 @@ the repository',
self.info("loading language %s", language)
try:
tr = translation('cubicweb', path, languages=[language])
self.translations[language] = tr.ugettext
self.translations[language] = (tr.ugettext, tr.upgettext)
except (ImportError, AttributeError, IOError):
self.exception('localisation support error for language %s',
language)
......
......@@ -297,8 +297,7 @@ class CubicWebVRegistry(VRegistry):
def set_schema(self, schema):
"""set instance'schema and load application objects"""
self.schema = schema
clear_cache(self, 'rqlhelper')
self._set_schema(schema)
# now we can load application's web objects
searchpath = self.config.vregistry_path()
self.reset(searchpath, force_reload=False)
......@@ -309,6 +308,11 @@ class CubicWebVRegistry(VRegistry):
etype = str(etype)
self.case_insensitive_etypes[etype.lower()] = etype
def _set_schema(self, schema):
"""set instance'schema"""
self.schema = schema
clear_cache(self, 'rqlhelper')
def update_schema(self, schema):
"""update .schema attribute on registered objects, necessary for some
tests
......@@ -394,16 +398,7 @@ class CubicWebVRegistry(VRegistry):
# objects on automatic reloading
self._needs_iface.clear()
def parse(self, session, rql, args=None):
rqlst = self.rqlhelper.parse(rql)
def type_from_eid(eid, session=session):
return session.describe(eid)[0]
try:
self.rqlhelper.compute_solutions(rqlst, {'eid': type_from_eid}, args)
except UnknownEid:
for select in rqlst.children:
select.solutions = []
return rqlst
# rql parsing utilities ####################################################
@property
@cached
......@@ -411,38 +406,19 @@ class CubicWebVRegistry(VRegistry):
return RQLHelper(self.schema,
special_relations={'eid': 'uid', 'has_text': 'fti'})
def solutions(self, req, rqlst, args):
def type_from_eid(eid, req=req):
return req.describe(eid)[0]
self.rqlhelper.compute_solutions(rqlst, {'eid': type_from_eid}, args)
@deprecated('[3.4] use vreg["etypes"].etype_class(etype)')
def etype_class(self, etype):
return self["etypes"].etype_class(etype)
@deprecated('[3.4] use vreg["views"].main_template(*args, **kwargs)')
def main_template(self, req, oid='main-template', **context):
return self["views"].main_template(req, oid, **context)
@deprecated('[3.4] use vreg[registry].possible_vobjects(*args, **kwargs)')
def possible_vobjects(self, registry, *args, **kwargs):
return self[registry].possible_vobjects(*args, **kwargs)
@deprecated('[3.4] use vreg["actions"].possible_actions(*args, **kwargs)')
def possible_actions(self, req, rset=None, **kwargs):
return self["actions"].possible_actions(req, rest=rset, **kwargs)
@deprecated("[3.4] use vreg['boxes'].select_or_none(...)")
def select_box(self, oid, *args, **kwargs):
return self['boxes'].select_or_none(oid, *args, **kwargs)
@deprecated("[3.4] use vreg['components'].select_or_none(...)")
def select_component(self, cid, *args, **kwargs):
return self['components'].select_or_none(cid, *args, **kwargs)
@deprecated("[3.4] use vreg['actions'].select_or_none(...)")
def select_action(self, oid, *args, **kwargs):
return self['actions'].select_or_none(oid, *args, **kwargs)
@deprecated("[3.4] use vreg['views'].select(...)")
def select_view(self, __vid, req, rset=None, **kwargs):
return self['views'].select(__vid, req, rset=rset, **kwargs)
def parse(self, req, rql, args=None):
rqlst = self.rqlhelper.parse(rql)
try:
self.solutions(req, rqlst, args)
except UnknownEid:
for select in rqlst.children:
select.solutions = []
return rqlst
# properties handling #####################################################
......@@ -515,6 +491,40 @@ class CubicWebVRegistry(VRegistry):
self.warning('%s (you should probably delete that property '
'from the database)', ex)
# deprecated code ####################################################
@deprecated('[3.4] use vreg["etypes"].etype_class(etype)')
def etype_class(self, etype):
return self["etypes"].etype_class(etype)
@deprecated('[3.4] use vreg["views"].main_template(*args, **kwargs)')
def main_template(self, req, oid='main-template', **context):
return self["views"].main_template(req, oid, **context)
@deprecated('[3.4] use vreg[registry].possible_vobjects(*args, **kwargs)')
def possible_vobjects(self, registry, *args, **kwargs):
return self[registry].possible_vobjects(*args, **kwargs)
@deprecated('[3.4] use vreg["actions"].possible_actions(*args, **kwargs)')
def possible_actions(self, req, rset=None, **kwargs):
return self["actions"].possible_actions(req, rest=rset, **kwargs)
@deprecated('[3.4] use vreg["boxes"].select_object(...)')
def select_box(self, oid, *args, **kwargs):
return self['boxes'].select_object(oid, *args, **kwargs)
@deprecated('[3.4] use vreg["components"].select_object(...)')
def select_component(self, cid, *args, **kwargs):
return self['components'].select_object(cid, *args, **kwargs)
@deprecated('[3.4] use vreg["actions"].select_object(...)')
def select_action(self, oid, *args, **kwargs):
return self['actions'].select_object(oid, *args, **kwargs)
@deprecated('[3.4] use vreg["views"].select(...)')
def select_view(self, __vid, req, rset=None, **kwargs):
return self['views'].select(__vid, req, rset=rset, **kwargs)
from datetime import datetime, date, time, timedelta
......
......@@ -215,10 +215,13 @@ class DBAPIRequest(RequestSessionBase):
self.lang = 'en'
# use req.__ to translate a message without registering it to the catalog
try:
self._ = self.__ = self.translations[self.lang]
gettext, pgettext = self.translations[self.lang]
self._ = self.__ = gettext
self.pgettext = pgettext
except KeyError:
# this occurs usually during test execution
self._ = self.__ = unicode
self.pgettext = lambda x,y: y
self.debug('request default language: %s', self.lang)
def decorate_rset(self, rset):
......@@ -361,7 +364,7 @@ paramstyle = 'pyformat'
# connection object ###########################################################
class Connection(object):
"""DB-API 2.0 compatible Connection object for CubicWebt
"""DB-API 2.0 compatible Connection object for CubicWeb
"""
# make exceptions available through the connection object
ProgrammingError = ProgrammingError
......
cubicweb (3.5.0-1) unstable; urgency=low
* new upstream release
-- Sylvain Thénault <sylvain.thenault@logilab.fr> Wed, 16 Sep 2009 17:51:13 +0200
cubicweb (3.4.11-1) unstable; urgency=low
* new upstream release
-- Aurélien Campéas <aurelien.campeas@logilab.fr> Tue, 11 Sep 2009 12:20:00 +0200
cubicweb (3.4.10-1) unstable; urgency=low
* new upstream release
......
......@@ -12,6 +12,7 @@ import sys
from datetime import datetime
from os import mkdir, chdir, getcwd
from os.path import join, exists, abspath, basename, normpath, split, isdir
from copy import deepcopy
from warnings import warn
from logilab.common import STD_BLACKLIST
......@@ -112,93 +113,104 @@ def generate_schema_pot(w, cubedir=None):
def _generate_schema_pot(w, vreg, schema, libconfig=None, cube=None):
from cubicweb.common.i18n import add_msg
from cubicweb.web import uicfg
from cubicweb.schema import META_RTYPES, SYSTEM_RTYPES
no_context_rtypes = META_RTYPES | SYSTEM_RTYPES
w('# schema pot file, generated on %s\n' % datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
w('# \n')
w('# singular and plural forms for each entity type\n')
w('\n')
vregdone = set()
if libconfig is not None:
from cubicweb.cwvreg import CubicWebVRegistry, clear_rtag_objects
libschema = libconfig.load_schema(remove_unused_rtypes=False)
entities = [e for e in schema.entities() if not e in libschema]
rinlined = deepcopy(uicfg.autoform_is_inlined)
appearsin_addmenu = deepcopy(uicfg.actionbox_appearsin_addmenu)
clear_rtag_objects()
cleanup_sys_modules(libconfig)
libvreg = CubicWebVRegistry(libconfig)
libvreg.set_schema(libschema) # trigger objects registration
librinlined = uicfg.autoform_is_inlined
libappearsin_addmenu = uicfg.actionbox_appearsin_addmenu
# prefill vregdone set
list(_iter_vreg_objids(libvreg, vregdone))
else:
libschema = None
entities = schema.entities()
libschema = {}
rinlined = uicfg.autoform_is_inlined
appearsin_addmenu = uicfg.actionbox_appearsin_addmenu
done = set()
for eschema in sorted(entities):
for eschema in sorted(schema.entities()):
etype = eschema.type
add_msg(w, etype)
add_msg(w, '%s_plural' % etype)
if not eschema.is_final():
add_msg(w, 'This %s' % etype)
add_msg(w, 'New %s' % etype)
add_msg(w, 'add a %s' % etype)
add_msg(w, 'remove this %s' % etype)
if eschema.description and not eschema.description in done:
done.add(eschema.description)
add_msg(w, eschema.description)
if etype not in libschema:
add_msg(w, etype)
add_msg(w, '%s_plural' % etype)
if not eschema.is_final():
add_msg(w, 'This %s' % etype)
add_msg(w, 'New %s' % etype)
if eschema.description and not eschema.description in done:
done.add(eschema.description)
add_msg(w, eschema.description)
if eschema.is_final():
continue
for rschema, targetschemas, role in eschema.relation_definitions(True):
for tschema in targetschemas:
if rinlined.etype_get(eschema, rschema, role, tschema) and \
(libconfig is None or not
librinlined.etype_get(eschema, rschema, role, tschema)):
add_msg(w, 'add a %s' % tschema,
'inlined:%s.%s.%s' % (etype, rschema, role))
add_msg(w, 'remove this %s' % tschema,
'inlined:%s:%s:%s' % (etype, rschema, role))
if appearsin_addmenu.etype_get(eschema, rschema, role, tschema) and \
(libconfig is None or not
libappearsin_addmenu.etype_get(eschema, rschema, role, tschema)):
if role == 'subject':
label = 'add %s %s %s %s' % (eschema, rschema,
tschema, role)
label2 = "creating %s (%s %%(linkto)s %s %s)" % (
tschema, eschema, rschema, tschema)
else:
label = 'add %s %s %s %s' % (tschema, rschema,
eschema, role)
label2 = "creating %s (%s %s %s %%(linkto)s)" % (
tschema, tschema, rschema, eschema)
add_msg(w, label)
add_msg(w, label2)
w('# subject and object forms for each relation type\n')
w('# (no object form for final relation types)\n')
w('# (no object form for final or symetric relation types)\n')
w('\n')
if libconfig is not None:
relations = [r for r in schema.relations() if not r in libschema]
else:
relations = schema.relations()
for rschema in sorted(set(relations)):
for rschema in sorted(schema.relations()):
rtype = rschema.type
add_msg(w, rtype)
done.add(rtype)
if rtype not in libschema:
# bw compat, necessary until all translation of relation are done properly...
add_msg(w, rtype)
if rschema.description and rschema.description not in done:
done.add(rschema.description)
add_msg(w, rschema.description)
done.add(rtype)
librschema = None
else:
librschema = libschema.rschema(rtype)
# add context information only for non-metadata rtypes
if rschema not in no_context_rtypes:
libsubjects = librschema and librschema.subjects() or ()
for subjschema in rschema.subjects():
if not subjschema in libsubjects:
add_msg(w, rtype, subjschema.type)
if not (schema.rschema(rtype).is_final() or rschema.symetric):
add_msg(w, '%s_object' % rtype)
if rschema.description and rschema.description not in done:
done.add(rschema.description)
add_msg(w, rschema.description)
w('# add related box generated message\n')
w('\n')
from cubicweb.web import uicfg
appearsin_addmenu = uicfg.actionbox_appearsin_addmenu
for eschema in schema.entities():
if eschema.is_final():
continue
for role, rschemas in (('subject', eschema.subject_relations()),
('object', eschema.object_relations())):
for rschema in rschemas:
if rschema.is_final():
continue
if libconfig is not None:
librschema = libschema.get(rschema)
for teschema in rschema.targets(eschema, role):
if libconfig is not None and librschema is not None:
if role == 'subject':
subjtype, objtype = eschema, teschema
else:
subjtype, objtype = teschema, eschema
if librschema.has_rdef(subjtype, objtype):
continue
if appearsin_addmenu.etype_get(eschema, rschema, role,
teschema):
if role == 'subject':
label = 'add %s %s %s %s' % (eschema, rschema,
teschema, role)
label2 = "creating %s (%s %%(linkto)s %s %s)" % (
teschema, eschema, rschema, teschema)
else:
label = 'add %s %s %s %s' % (teschema, rschema,
eschema, role)
label2 = "creating %s (%s %s %s %%(linkto)s)" % (
teschema, teschema, rschema, eschema)
add_msg(w, label)
add_msg(w, label2)
#cube = (cube and 'cubes.%s.' % cube or 'cubicweb.')
done = set()
if libconfig is not None:
from cubicweb.cwvreg import CubicWebVRegistry
libvreg = CubicWebVRegistry(libconfig)
libvreg.set_schema(libschema) # trigger objects registration
# prefill done set
list(_iter_vreg_objids(libvreg, done))
for objid in _iter_vreg_objids(vreg, done):
if rschema not in no_context_rtypes:
libobjects = librschema and librschema.objects() or ()
for objschema in rschema.objects():
if not objschema in libobjects:
add_msg(w, '%s_object' % rtype, objschema.type)
if rtype not in libschema:
# bw compat, necessary until all translation of relation are done properly...
add_msg(w, '%s_object' % rtype)
for objid in _iter_vreg_objids(vreg, vregdone):
add_msg(w, '%s_description' % objid)
add_msg(w, objid)
def _iter_vreg_objids(vreg, done, prefix=None):
for reg, objdict in vreg.items():
for objects in objdict.values():
......
......@@ -12,6 +12,7 @@ from logilab.common.adbh import get_adv_func_helper
from indexer import get_indexer
from cubicweb.req import RequestSessionBase
from cubicweb.cwvreg import CubicWebVRegistry
from cubicweb.web.request import CubicWebRequestBase
from cubicweb.devtools import BASE_URL, BaseApptestConfiguration
......@@ -34,39 +35,13 @@ class FakeConfig(dict, BaseApptestConfiguration):
def sources(self):
return {}
class FakeVReg(dict):
def __init__(self, schema=None, config=None):
self.schema = schema
self.config = config or FakeConfig()
self.properties = {'ui.encoding': 'UTF8',
'ui.language': 'en',
}
self.update({
'controllers' : {'login': []},
'views' : {},
})
def property_value(self, key):
return self.properties[key]
def etype_class(self, etype):
class Entity(dict):
e_schema = self.schema[etype]
def __init__(self, session, eid, row=0, col=0):
self.req = session
self.eid = eid
self.row, self.col = row, col
def set_eid(self, eid):
self.eid = self['eid'] = eid
return Entity
class FakeRequest(CubicWebRequestBase):
"""test implementation of an cubicweb request object"""
def __init__(self, *args, **kwargs):
if not (args or 'vreg' in kwargs):
kwargs['vreg'] = FakeVReg()
kwargs['vreg'] = CubicWebVRegistry(FakeConfig(), initlog=False)
kwargs['https'] = False
self._url = kwargs.pop('url', 'view?rql=Blop&vid=blop')
super(FakeRequest, self).__init__(*args, **kwargs)
......@@ -147,25 +122,6 @@ class FakeRequest(CubicWebRequestBase):
return self.execute(*args, **kwargs)
# class FakeRequestNoCnx(FakeRequest):
# def get_session_data(self, key, default=None, pop=False):
# """return value associated to `key` in session data"""
# if pop:
# return self._session_data.pop(key, default)
# else:
# return self._session_data.get(key, default)
# def set_session_data(self, key, value):
# """set value associated to `key` in session data"""
# self._session_data[key] = value
# def del_session_data(self, key):
# try:
# del self._session_data[key]
# except KeyError:
# pass
class FakeUser(object):
login = 'toto'
eid = 0
......@@ -176,7 +132,7 @@ class FakeUser(object):
class FakeSession(RequestSessionBase):
def __init__(self, repo=None, user=None):
self.repo = repo
self.vreg = getattr(self.repo, 'vreg', FakeVReg())
self.vreg = getattr(self.repo, 'vreg', CubicWebVRegistry(FakeConfig(), initlog=False))
self.pool = FakePool()
self.user = user or FakeUser()
self.is_internal_session = False
......@@ -209,8 +165,9 @@ class FakeRepo(object):
self.eids = {}
self._count = 0
self.schema = schema
self.vreg = vreg or FakeVReg()
self.config = config or FakeConfig()
self.vreg = vreg or CubicWebVRegistry(self.config, initlog=False)
self.vreg.schema = schema
def internal_session(self):
return FakeSession(self)
......@@ -248,10 +205,3 @@ class FakeSource(object):
class FakePool(object):
def source(self, uri):
return FakeSource(uri)
# commented until proven to be useful
## from logging import getLogger
## from cubicweb import set_log_methods
## for cls in (FakeConfig, FakeVReg, FakeRequest, FakeSession, FakeRepo,
## FakeSource, FakePool):
## set_log_methods(cls, getLogger('fake'))
......@@ -108,9 +108,10 @@ class RQLGeneratorTC(TestCase):
schema = None # set this in concret test
def setUp(self):
self.repo = FakeRepo(self.schema)
self.rqlhelper = RQLHelper(self.schema, special_relations={'eid': 'uid',
'has_text': 'fti'})
self.qhelper = QuerierHelper(FakeRepo(self.schema), self.schema)
self.qhelper = QuerierHelper(self.repo, self.schema)
ExecutionPlan._check_permissions = _dummy_check_permissions
rqlannotation._select_principal = _select_principal
......@@ -129,7 +130,7 @@ class RQLGeneratorTC(TestCase):
#print '********* solutions', solutions
self.rqlhelper.simplify(union)
#print '********* simplified', union.as_string()
plan = self.qhelper.plan_factory(union, {}, FakeSession())
plan = self.qhelper.plan_factory(union, {}, FakeSession(self.repo))
plan.preprocess(union)
for select in union.children:
select.solutions.sort()
......@@ -167,7 +168,7 @@ class BaseQuerierTC(TestCase):
set_debug(debug)
def _rqlhelper(self):
rqlhelper = self.o._rqlhelper
rqlhelper = self.repo.vreg.rqlhelper
# reset uid_func so it don't try to get type from eids
rqlhelper._analyser.uid_func = None
rqlhelper._analyser.uid_func_mapping = {}
......@@ -241,7 +242,7 @@ class BasePlannerTC(BaseQuerierTC):
rqlst = self.o.parse(rql, annotate=True)
self.o.solutions(self.session, rqlst, kwargs)
if rqlst.TYPE == 'select':
self.o._rqlhelper.annotate(rqlst)
self.repo.vreg.rqlhelper.annotate(rqlst)
for select in rqlst.children:
select.solutions.sort()
else:
......@@ -251,7 +252,7 @@ class BasePlannerTC(BaseQuerierTC):
# monkey patch some methods to get predicatable results #######################
from cubicweb.server.rqlrewrite import RQLRewriter
from cubicweb.rqlrewrite import RQLRewriter
_orig_insert_snippets = RQLRewriter.insert_snippets
_orig_build_variantes = RQLRewriter.build_variantes
......
......@@ -89,7 +89,7 @@ Properties defined below are accessible through the following api:
* `*`: 0..n
- `meta` : boolean indicating that the relation is a meta-relation (false by
default)
default, will disappear in *CubicWeb* 3.5)
* optional properties for attributes :
......@@ -216,8 +216,8 @@ It is also possible to use specific groups if they are defined in the precreate
of the cube (``migration/precreate.py``).
Use of RQL expression for writing rights
`````````````````````````````````````````
Use of RQL expression for write permissions
```````````````````````````````````````````
It is possible to define RQL expression to provide update permission
(`add`, `delete` and `update`) on relation and entity types.
......@@ -249,7 +249,7 @@ for the following :
* we can also defined rights on attributes of an entity (non-final relation),
knowing that :
- to defines RQL expression, we have to use the class `RQLExpression`
- to define RQL expression, we have to use the class `RQLExpression`
in which X represents the entity the attribute belongs to
- the permissions `add` and `delete` are equivalent. Only `add`/`read`
......@@ -321,7 +321,7 @@ An attribute is defined in the schema as follows::
attr_name = attr_type(properties*)
where `attr_type` is one of the type listed above and `properties` is
a list of the attribute needs to statisfy (see :ref:`properties`
a list of the attribute needs to statisfy (see :ref:`properties`
for more details).
......@@ -434,6 +434,6 @@ new versions on this project to specific groups. It is important to notice that
* in such case, we have to protect both the entity type "Version" and the relation
associating a version to a project ("version_of")
* because of the genricity of the entity type `CWPermission`, we have to execute
* because of the genericity of the entity type `CWPermission`, we have to execute
a unification with the groups and/or the states if necessary in the expression
("U in_group G, P require_group G" in the above example)
......@@ -5,4 +5,14 @@ Inheritance
When describing a data model, entities can inherit from other entities as is
common in object-oriented programming.
You have the possibility to adapt some entity attributes, as follow:
.. sourcecode:: python
from cubes.OTHER_CUBE import entities