schema.py
changeset 2459 d088d0ff48a1
parent 2456 aa25d6b244c8
child 2460 ce1a7ffc6c90
equal deleted inserted replaced
2458:4d114865098f 2459:d088d0ff48a1
    15 
    15 
    16 from logilab.common.decorators import cached, clear_cache, monkeypatch
    16 from logilab.common.decorators import cached, clear_cache, monkeypatch
    17 from logilab.common.deprecation import obsolete
    17 from logilab.common.deprecation import obsolete
    18 from logilab.common.compat import any
    18 from logilab.common.compat import any
    19 
    19 
    20 from yams import BadSchemaDefinition, buildobjs as ybo
    20 from yams import BadSchemaDefinition, buildobjs as ybo, constraints
    21 from yams.schema import Schema, ERSchema, EntitySchema, RelationSchema
    21 from yams.schema import Schema, ERSchema, EntitySchema, RelationSchema
    22 from yams.constraints import BaseConstraint, StaticVocabularyConstraint
    22 from yams.constraints import BaseConstraint, StaticVocabularyConstraint
    23 from yams.reader import CONSTRAINTS, PyFileReader, SchemaLoader, \
    23 from yams.reader import CONSTRAINTS, PyFileReader, SchemaLoader, \
    24      obsolete as yobsolete
    24      obsolete as yobsolete
    25 
    25 
    59         msg = '%s has been renamed to %s, please update your code' % (
    59         msg = '%s has been renamed to %s, please update your code' % (
    60             etype, ETYPE_NAME_MAP[etype])
    60             etype, ETYPE_NAME_MAP[etype])
    61         warn(msg, DeprecationWarning, stacklevel=4)
    61         warn(msg, DeprecationWarning, stacklevel=4)
    62         etype = ETYPE_NAME_MAP[etype]
    62         etype = ETYPE_NAME_MAP[etype]
    63     return etype
    63     return etype
    64 
       
    65 
       
    66 ## cubicweb provides a RichString class for convenience
       
    67 class RichString(ybo.String):
       
    68     """Convenience RichString attribute type
       
    69     The following declaration::
       
    70 
       
    71       class Card(EntityType):
       
    72           content = RichString(fulltextindexed=True, default_format='text/rest')
       
    73 
       
    74     is equivalent to::
       
    75 
       
    76       class Card(EntityType):
       
    77           content_format = String(internationalizable=True,
       
    78                                   default='text/rest', constraints=[format_constraint])
       
    79           content  = String(fulltextindexed=True)
       
    80     """
       
    81     def __init__(self, default_format='text/plain', format_constraints=None, **kwargs):
       
    82         self.default_format = default_format
       
    83         self.format_constraints = format_constraints or [format_constraint]
       
    84         super(RichString, self).__init__(**kwargs)
       
    85 
       
    86 PyFileReader.context['RichString'] = yobsolete(RichString)
       
    87 
       
    88 ## need to monkeypatch yams' _add_relation function to handle RichString
       
    89 yams_add_relation = ybo._add_relation
       
    90 @monkeypatch(ybo)
       
    91 def _add_relation(relations, rdef, name=None, insertidx=None):
       
    92     if isinstance(rdef, RichString):
       
    93         format_attrdef = ybo.String(internationalizable=True,
       
    94                                     default=rdef.default_format, maxsize=50,
       
    95                                     constraints=rdef.format_constraints)
       
    96         yams_add_relation(relations, format_attrdef, name+'_format', insertidx)
       
    97     yams_add_relation(relations, rdef, name, insertidx)
       
    98 
       
    99 
       
   100 @monkeypatch(ybo.EntityType, methodname='add_relation')
       
   101 @classmethod
       
   102 def add_relation(cls, rdef, name=None):
       
   103     ybo.add_relation_function(cls, rdef, name)
       
   104     if isinstance(rdef, RichString) and not rdef in cls._defined:
       
   105         format_attr_name = (name or rdef.name) + '_format'
       
   106         rdef = cls.get_relations(format_attr_name).next()
       
   107         cls._ensure_relation_type(rdef)
       
   108 
    64 
   109 def display_name(req, key, form=''):
    65 def display_name(req, key, form=''):
   110     """return a internationalized string for the key (schema entity or relation
    66     """return a internationalized string for the key (schema entity or relation
   111     name) in a given form
    67     name) in a given form
   112     """
    68     """
   924             for filepath in self.get_schema_files(cube):
   880             for filepath in self.get_schema_files(cube):
   925                 self.info('loading %s', filepath)
   881                 self.info('loading %s', filepath)
   926                 self.handle_file(filepath)
   882                 self.handle_file(filepath)
   927 
   883 
   928 
   884 
       
   885 set_log_methods(CubicWebSchemaLoader, getLogger('cubicweb.schemaloader'))
       
   886 set_log_methods(BootstrapSchemaLoader, getLogger('cubicweb.bootstrapschemaloader'))
       
   887 set_log_methods(RQLExpression, getLogger('cubicweb.schema'))
       
   888 
   929 # _() is just there to add messages to the catalog, don't care about actual
   889 # _() is just there to add messages to the catalog, don't care about actual
   930 # translation
   890 # translation
   931 PERM_USE_TEMPLATE_FORMAT = _('use_template_format')
   891 PERM_USE_TEMPLATE_FORMAT = _('use_template_format')
   932 
   892 NEED_PERM_FORMATS = [_('text/cubicweb-page-template')]
   933 class FormatConstraint(StaticVocabularyConstraint):
   893 
   934     need_perm_formats = [_('text/cubicweb-page-template')]
   894 @monkeypatch(constraints.FormatConstraint)
   935 
   895 def vocabulary(self, entity=None, req=None):
   936     regular_formats = (_('text/rest'),
   896     if req is None and entity is not None:
   937                        _('text/html'),
   897         req = entity.req
   938                        _('text/plain'),
   898     if req is not None and req.user.has_permission(PERM_USE_TEMPLATE_FORMAT):
   939                        )
   899         return self.regular_formats + tuple(NEED_PERM_FORMATS)
   940     def __init__(self):
   900     return self.regular_formats
   941         pass
       
   942 
       
   943     def serialize(self):
       
   944         """called to make persistent valuable data of a constraint"""
       
   945         return None
       
   946 
       
   947     @classmethod
       
   948     def deserialize(cls, value):
       
   949         """called to restore serialized data of a constraint. Should return
       
   950         a `cls` instance
       
   951         """
       
   952         return cls()
       
   953 
       
   954     def vocabulary(self, entity=None, req=None):
       
   955         if req is None and entity is not None:
       
   956             req = entity.req
       
   957         if req is not None and req.user.has_permission(PERM_USE_TEMPLATE_FORMAT):
       
   958             return self.regular_formats + tuple(self.need_perm_formats)
       
   959         return self.regular_formats
       
   960 
       
   961     def __str__(self):
       
   962         return 'value in (%s)' % u', '.join(repr(unicode(word)) for word in self.vocabulary())
       
   963 
       
   964 
       
   965 format_constraint = FormatConstraint()
       
   966 CONSTRAINTS['FormatConstraint'] = FormatConstraint
       
   967 PyFileReader.context['format_constraint'] = format_constraint
       
   968 
       
   969 set_log_methods(CubicWebSchemaLoader, getLogger('cubicweb.schemaloader'))
       
   970 set_log_methods(BootstrapSchemaLoader, getLogger('cubicweb.bootstrapschemaloader'))
       
   971 set_log_methods(RQLExpression, getLogger('cubicweb.schema'))
       
   972 
   901 
   973 # XXX monkey patch PyFileReader.import_erschema until bw_normalize_etype is
   902 # XXX monkey patch PyFileReader.import_erschema until bw_normalize_etype is
   974 # necessary
   903 # necessary
   975 orig_import_erschema = PyFileReader.import_erschema
   904 orig_import_erschema = PyFileReader.import_erschema
   976 def bw_import_erschema(self, ertype, schemamod=None, instantiate=True):
   905 def bw_import_erschema(self, ertype, schemamod=None, instantiate=True):