4 :copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2. |
4 :copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2. |
5 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr |
5 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr |
6 :license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses |
6 :license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses |
7 """ |
7 """ |
8 __docformat__ = "restructuredtext en" |
8 __docformat__ = "restructuredtext en" |
|
9 _ = unicode |
9 |
10 |
10 import re |
11 import re |
11 from logging import getLogger |
12 from logging import getLogger |
12 from warnings import warn |
13 from warnings import warn |
13 |
14 |
28 # XXX <3.2 bw compat |
29 # XXX <3.2 bw compat |
29 from yams import schema |
30 from yams import schema |
30 schema.use_py_datetime() |
31 schema.use_py_datetime() |
31 nodes.use_py_datetime() |
32 nodes.use_py_datetime() |
32 |
33 |
33 _ = unicode |
34 # set of meta-relations available for every entity types |
34 |
35 META_RELATIONS_TYPES = set(( |
35 BASEGROUPS = ('managers', 'users', 'guests', 'owners') |
36 'owned_by', 'created_by', 'is', 'is_instance_of', 'identity', |
36 |
37 'eid', 'creation_date', 'modification_date', 'has_text', |
37 LOGGER = getLogger('cubicweb.schemaloader') |
38 ))) |
|
39 |
|
40 # set of entity and relation types used to build the schema |
|
41 SCHEMA_TYPES = set(( |
|
42 'CWEType', 'CWRType', 'CWAttribute', 'CWRelation', |
|
43 'CWConstraint', 'CWConstraintType', 'RQLExpression', |
|
44 'relation_type', 'from_entity', 'to_entity', |
|
45 'constrained_by', 'cstrtype', |
|
46 # XXX those are not really "schema" entity types |
|
47 # but we usually don't want them as @* targets |
|
48 'CWProperty', 'CWPermission', 'State', 'Transition', |
|
49 )) |
|
50 |
|
51 _LOGGER = getLogger('cubicweb.schemaloader') |
38 |
52 |
39 # schema entities created from serialized schema have an eid rproperty |
53 # schema entities created from serialized schema have an eid rproperty |
40 ybo.ETYPE_PROPERTIES += ('eid',) |
54 ybo.ETYPE_PROPERTIES += ('eid',) |
41 ybo.RTYPE_PROPERTIES += ('eid',) |
55 ybo.RTYPE_PROPERTIES += ('eid',) |
42 ybo.RDEF_PROPERTIES += ('eid',) |
56 ybo.RDEF_PROPERTIES += ('eid',) |
66 if '*' in etype or '@' in etype: |
80 if '*' in etype or '@' in etype: |
67 assert len(etype) in (1, 2) |
81 assert len(etype) in (1, 2) |
68 etypes = () |
82 etypes = () |
69 if '*' in etype: |
83 if '*' in etype: |
70 etypes += tuple(self._wildcard_etypes(schema)) |
84 etypes += tuple(self._wildcard_etypes(schema)) |
|
85 # XXX deprecate, too clumsy |
71 if '@' in etype: |
86 if '@' in etype: |
72 etypes += tuple(system_etypes(schema)) |
87 etypes += tuple(system_etypes(schema)) |
73 return etypes |
88 return etypes |
74 return (etype,) |
89 return (etype,) |
75 ybo.RelationDefinition._actual_types = _actual_types |
90 ybo.RelationDefinition._actual_types = _actual_types |
240 |
255 |
241 def system_etypes(schema): |
256 def system_etypes(schema): |
242 """return system entity types only: skip final, schema and application entities |
257 """return system entity types only: skip final, schema and application entities |
243 """ |
258 """ |
244 for eschema in schema.entities(): |
259 for eschema in schema.entities(): |
245 if eschema.is_final() or eschema.schema_entity() or not eschema.meta: |
260 if eschema.is_final() or eschema.schema_entity(): |
246 continue |
261 continue |
247 yield eschema.type |
262 yield eschema.type |
248 |
263 |
249 # Schema objects definition ################################################### |
264 # Schema objects definition ################################################### |
250 |
265 |
319 elif not need_has_text and has_has_text: |
334 elif not need_has_text and has_has_text: |
320 self.schema.del_relation_def(self.type, 'has_text', 'String') |
335 self.schema.del_relation_def(self.type, 'has_text', 'String') |
321 |
336 |
322 def schema_entity(self): |
337 def schema_entity(self): |
323 """return True if this entity type is used to build the schema""" |
338 """return True if this entity type is used to build the schema""" |
324 return self.type in self.schema.schema_entity_types() |
339 return self.type in SCHEMA_TYPES |
325 |
340 |
326 def check_perm(self, session, action, eid=None): |
341 def check_perm(self, session, action, eid=None): |
327 # NB: session may be a server session or a request object |
342 # NB: session may be a server session or a request object |
328 user = session.user |
343 user = session.user |
329 # check user is in an allowed group, if so that's enough |
344 # check user is in an allowed group, if so that's enough |
356 super(CubicWebRelationSchema, self).__init__(schema, rdef, **kwargs) |
371 super(CubicWebRelationSchema, self).__init__(schema, rdef, **kwargs) |
357 if eid is None and rdef is not None: |
372 if eid is None and rdef is not None: |
358 eid = getattr(rdef, 'eid', None) |
373 eid = getattr(rdef, 'eid', None) |
359 self.eid = eid |
374 self.eid = eid |
360 |
375 |
|
376 @property |
|
377 def meta(self): |
|
378 return self.type in META_RELATIONS_TYPES |
361 |
379 |
362 def update(self, subjschema, objschema, rdef): |
380 def update(self, subjschema, objschema, rdef): |
363 super(CubicWebRelationSchema, self).update(subjschema, objschema, rdef) |
381 super(CubicWebRelationSchema, self).update(subjschema, objschema, rdef) |
364 if not self._perms_checked and self._groups: |
382 if not self._perms_checked and self._groups: |
365 for action, groups in self._groups.iteritems(): |
383 for action, groups in self._groups.iteritems(): |
394 card = self.rproperty(subjtype, objtype, 'cardinality') |
412 card = self.rproperty(subjtype, objtype, 'cardinality') |
395 return (target == 'subject' and card[0]) or \ |
413 return (target == 'subject' and card[0]) or \ |
396 (target == 'object' and card[1]) |
414 (target == 'object' and card[1]) |
397 |
415 |
398 def schema_relation(self): |
416 def schema_relation(self): |
399 return self.type in ('relation_type', 'from_entity', 'to_entity', |
417 """return True if this relation type is used to build the schema""" |
400 'constrained_by', 'cstrtype') |
418 return self.type in SCHEMA_TYPES |
401 |
419 |
402 def physical_mode(self): |
420 def physical_mode(self): |
403 """return an appropriate mode for physical storage of this relation type: |
421 """return an appropriate mode for physical storage of this relation type: |
404 * 'subjectinline' if every possible subject cardinalities are 1 or ? |
422 * 'subjectinline' if every possible subject cardinalities are 1 or ? |
405 * 'objectinline' if 'subjectinline' mode is not possible but every |
423 * 'objectinline' if 'subjectinline' mode is not possible but every |
454 rschema.final = True |
472 rschema.final = True |
455 rschema.set_default_groups() |
473 rschema.set_default_groups() |
456 rschema = self.add_relation_type(ybo.RelationType('identity', meta=True)) |
474 rschema = self.add_relation_type(ybo.RelationType('identity', meta=True)) |
457 rschema.final = False |
475 rschema.final = False |
458 rschema.set_default_groups() |
476 rschema.set_default_groups() |
459 |
|
460 def schema_entity_types(self): |
|
461 """return the list of entity types used to build the schema""" |
|
462 return frozenset(('CWEType', 'CWRType', 'CWAttribute', 'CWRelation', |
|
463 'CWConstraint', 'CWConstraintType', 'RQLExpression', |
|
464 # XXX those are not really "schema" entity types |
|
465 # but we usually don't want them as @* targets |
|
466 'CWProperty', 'CWPermission', 'State', 'Transition')) |
|
467 |
477 |
468 def add_entity_type(self, edef): |
478 def add_entity_type(self, edef): |
469 edef.name = edef.name.encode() |
479 edef.name = edef.name.encode() |
470 edef.name = bw_normalize_etype(edef.name) |
480 edef.name = bw_normalize_etype(edef.name) |
471 assert re.match(r'[A-Z][A-Za-z0-9]*[a-z]+[0-9]*$', edef.name), repr(edef.name) |
481 assert re.match(r'[A-Z][A-Za-z0-9]*[a-z]+[0-9]*$', edef.name), repr(edef.name) |
634 self.rqlst = parse(self.full_rql, print_errors=False).children[0] |
644 self.rqlst = parse(self.full_rql, print_errors=False).children[0] |
635 except RQLSyntaxError: |
645 except RQLSyntaxError: |
636 raise RQLSyntaxError(expression) |
646 raise RQLSyntaxError(expression) |
637 for mainvar in mainvars.split(','): |
647 for mainvar in mainvars.split(','): |
638 if len(self.rqlst.defined_vars[mainvar].references()) <= 2: |
648 if len(self.rqlst.defined_vars[mainvar].references()) <= 2: |
639 LOGGER.warn('You did not use the %s variable in your RQL expression %s', |
649 _LOGGER.warn('You did not use the %s variable in your RQL ' |
640 mainvar, self) |
650 'expression %s', mainvar, self) |
641 |
651 |
642 def __str__(self): |
652 def __str__(self): |
643 return self.full_rql |
653 return self.full_rql |
644 def __repr__(self): |
654 def __repr__(self): |
645 return '%s(%s)' % (self.__class__.__name__, self.full_rql) |
655 return '%s(%s)' % (self.__class__.__name__, self.full_rql) |