Esempio n. 1
0
def vocabulary_column(name, title, vocabulary):
    """Get getter for the enum-value of an enumerated column.
    """
    if isinstance(vocabulary, basestring): # !+tmp
        vocabulary = get_vocabulary(vocabulary)
    
    #from bungeni.ui.vocabulary import VDEXVocabularyMixin
    def getter(context, formatter, vocabulary=vocabulary):
        # if this is a vocabulary factory, we need to instantiate with context
        # !+ but, when context is irrelevant, call-it-as-factory to get a 
        # context-bound instance seems unnecessarily inefficient! 
        # !+ VDEXVocabularyMixin-based FlatVDEXVocabularyFactory and 
        # TreeVDEXVocabulary (but this is as yet never included in a listing) 
        # already implement getTerm() -- that is all that is needed here, and 
        # the term returned is already localized, so we really do not need to 
        # call-it-as-factory to bind it to context on each lookup...
        #if not isinstance(vocabulary, VDEXVocabularyMixin):
        if IVocabularyFactory.providedBy(vocabulary):
            vocabulary = vocabulary(context)
        try:
            return vocabulary.getTerm(getattr(context, name)).title
        except LookupError:
            # !+NONE_LOOKUPERROR(mr, jul-2012) probably a vdex, 
            # and getattr(context, name)...
            value = getattr(context, name)
            m = "******** LookupError: vocabulary [%s, length:%s] term value [%s] " \
                "for context [%s.%s] -- vocabulary terms: %s" % (
                    vocabulary, len(vocabulary), value, context, name,
                    [ (t.value, t.token, t.title)  for t in vocabulary._terms ])
            log.error(m)
            # we should only have a LookupError on a None value (and it is not 
            # defined in the vocabulary), in which case we return None
            if value is not None:
                raise
    return column.GetterColumn(title, getter)
Esempio n. 2
0
def batch_serialize(type_key="*", start_date=None, end_date=None):
    """Serialize all objects of `type_key` or all types if with a
    wildcard(*) as the type key.
    Item set may be filtered by status date (start_date and/or end date)
    range.
    """
    # keep count of serialized objects for feedback
    serialized_count = 0
    # list of domain classes to be serialized
    domain_models = []
    if type_key == "*":
        types_vocab = get_vocabulary("serializable_type")
        # we add the legislature and the chamber first
        for term in types_vocab(None):
            if term.value in ("legislature", "chamber"):
                info = capi.get_type_info(term.value)
                domain_models.append(info.domain_model)
        # we add the rest now
        for term in types_vocab(None):
            if term.value == "*": 
                continue
            if term.value not in ("legislature", "chamber"):
                info = capi.get_type_info(term.value)
                domain_models.append(info.domain_model)
    else:
        info = capi.get_type_info(type_key)
        if info.workflow:
            domain_models.append(info.domain_model)
    session = Session()
    for domain_model in domain_models:
        query = session.query(domain_model)
        if IWorkflowed.implementedBy(domain_model) and (start_date or end_date):
            column = domain_model.status_date
            if start_date and end_date:
                expression = sql.between(column, start_date, end_date)
            elif start_date:
                expression = (column>=start_date)
            elif end_date:
                expression = (column<=end_date)
            query = query.filter(expression)
        objects = query.all()
        # !+FILTER(ah, 2014-09-19) adding a filter here - sometimes there is a mismatch
        # between the count shown on the screen i.e. X items sent for serialization and 
        # and only X-n items appear in the queue - there seem to be empty objects returned
        # sometimes, so eliminating those
        objects = filter(None, objects)
        map(queue_object_serialization, objects)
        log.error(" COUNTING_TYPES_SERIALIZED -- %s COUNT -- %s", domain_model, len(objects))
        serialized_count += len(objects)
    return serialized_count
Esempio n. 3
0
def vocabulary_column(name, title, vocabulary):
    """Get getter for the enum-value of an enumerated column.
    """
    if isinstance(vocabulary, basestring):  # !+tmp
        vocabulary = get_vocabulary(vocabulary)

    #from bungeni.ui.vocabulary import VDEXVocabularyMixin
    def getter(context, formatter, vocabulary=vocabulary):
        # if this is a vocabulary factory, we need to instantiate with context
        # !+ but, when context is irrelevant, call-it-as-factory to get a
        # context-bound instance seems unnecessarily inefficient!
        # !+ VDEXVocabularyMixin-based FlatVDEXVocabularyFactory and
        # TreeVDEXVocabulary (but this is as yet never included in a listing)
        # already implement getTerm() -- that is all that is needed here, and
        # the term returned is already localized, so we really do not need to
        # call-it-as-factory to bind it to context on each lookup...
        #if not isinstance(vocabulary, VDEXVocabularyMixin):
        if IVocabularyFactory.providedBy(vocabulary):
            vocabulary = vocabulary(context)
        try:
            return vocabulary.getTerm(getattr(context, name)).title
        except LookupError:
            # !+NONE_LOOKUPERROR(mr, jul-2012) probably a vdex,
            # and getattr(context, name)...
            value = getattr(context, name)
            m = "******** LookupError: vocabulary [%s, length:%s] term value [%s] " \
                "for context [%s.%s] -- vocabulary terms: %s" % (
                    vocabulary, len(vocabulary), value, context, name,
                    [ (t.value, t.token, t.title)  for t in vocabulary._terms ])
            log.error(m)
            # we should only have a LookupError on a None value (and it is not
            # defined in the vocabulary), in which case we return None
            if value is not None:
                raise

    return column.GetterColumn(title, getter)
Esempio n. 4
0
 def validate_derived_table_schema(self, action, data):
     """Look-ahead validate against database contraints.
     """
     dm = self.domain_model
     ti = capi.get_type_info(dm)
     derived_table_schema = ti.derived_table_schema
     errors = []
     for name in derived_table_schema:
         ff = self.form_fields.get(name)
         # skip if no form does not define a corresponding form field
         if not ff:
             continue
         # !+ skip if field not included in this form "mode"?
         #if name not in getattr("%s_columns" % (self.mode), ti.descriptor_model):
         #    continue
         
         field = derived_table_schema.get(name)
         assert field is ff.field, name # !+TMP sanity check
         value = data.get(name, None)
         
         ''' !+VTF disabling for now, as attempting to preset a contextualized
         vocab fails for subsequent lodaing of a *view*, as this is executed 
         when validating a *submit* -- may still work if executed right moment.
         
         # !+VTF bungeni.ui.fields.VocabularyTextField -- here a vocabulary 
         # field is not necessarily the type defined by bungeni 
         # e.g. zope.schema._field.Choice that during validation attempts to
         # retrieve the vocabulary and initialize it with a None context...
         # To preempt the error that this causes, we check for and stuff
         # an appropiately initialized vocabulary instance onto this field...
         if hasattr(field, "vocabulary"):
             # preset a vocabulary on self.context, or reset with one off current 
             # context if the one preset previously was off a different context
             if (field.vocabulary is None or (
                     # a vocab was preset previously
                     hasattr(field, "_vtf_last_context") and
                     # and it was prepared with a different context
                     getattr(field, "_vtf_last_context") is not self.context)
                 ):
                 from bungeni.alchemist.utils import get_vocabulary
                 field.vocabulary = get_vocabulary(field.vocabularyName)(self.context)
                 # remember last context used to preset vocabulary
                 field._vtf_last_context = self.context
                 log.debug("Validation of vocabulary field (%r, %r) with value=%r -- "
                     "stuffing vocabulary instance %s [context: %r] onto field %s ...", 
                     name, field.vocabularyName, value, field.vocabulary, self.context, field)
         '''
         # !+VTF a "temporary" and simpler version of above, to avoid 
         # AttributeError in try block below (and incorrectly failed validation).
         TMP_SET_VOCAB = False
         if hasattr(field, "vocabulary") and field.vocabulary is None:
             TMP_SET_VOCAB = True
             from bungeni.alchemist.utils import get_vocabulary
             field.vocabulary = get_vocabulary(field.vocabularyName)(self.context)
         # standard field validation !+ necessary, already called elsewhere? 
         try:
             widget_error = field.validate(value)
         except (RequiredMissing,) as exc:
             widget_error = exc
         # !+ other possible exceptions, should never pass here?
         except (formlib.form.NoInputData, interface.Invalid, Exception,) as exc:
             widget_error = exc
             probing.log_exc(sys.exc_info(), log_handler=log.error)
             log.debug(probing.class_inheritance(exc))
             log.error("\n"
                 "    %r.validate(%r) FAILED (field %r)\n"
                 "    [context: %r]", field, value, name, self.context)
             #raise # !+?
         # !+VTF clear any vocabulary that we preset above
         if TMP_SET_VOCAB:
             field.vocabulary = None
         if widget_error:
             errors.append(self.set_widget_error(name, widget_error))
             widget_error = None
             continue
         
         # get db column definition
         domain_attr = getattr(dm, name)
         if not isinstance(domain_attr, sa.orm.attributes.InstrumentedAttribute):
             continue
         domain_attr_property = domain_attr.property
         assert isinstance(domain_attr_property, sa.orm.properties.ColumnProperty), name # !+TMP sanity check
         # !+MULTIPLE_COLUMNS only single columns supported (so far)
         if len(domain_attr_property.columns) == 1:
             col = domain_attr_property.columns[0]
             #!+AttributeError: '_Label' object has no attribute 'nullable'
             # not: sa.sql.expression._Label, sa.sql.expression.ColumnElement
             assert isinstance(col, sa.schema.Column), col 
         else:
             log.warn("SQLAlchemy property %r NOT defined as a single column, "
                 "skipping derived_table_schema validation...", name)
             continue
         
         # validate against db column definition
         # nullable
         if value is None:
             if not col.nullable:
                 errors.append(self.set_widget_error(name, _(u"May not be null")))
             continue
         # sa.String
         if isinstance(col.type, sa.types.String):
             # length
             length = col.type.length
             if length is not None:
                 if length < len(value):
                     errors.append(self.set_widget_error(name, 
                             _(u"May not be longer than ${length}", 
                                 mapping={"length": length})))
     return errors
Esempio n. 5
0
    def validate_derived_table_schema(self, action, data):
        """Look-ahead validate against database contraints.
        """
        dm = self.domain_model
        ti = capi.get_type_info(dm)
        derived_table_schema = ti.derived_table_schema
        errors = []
        for name in derived_table_schema:
            ff = self.form_fields.get(name)
            # skip if no form does not define a corresponding form field
            if not ff:
                continue
            # !+ skip if field not included in this form "mode"?
            #if name not in getattr("%s_columns" % (self.mode), ti.descriptor_model):
            #    continue

            field = derived_table_schema.get(name)
            assert field is ff.field, name  # !+TMP sanity check
            value = data.get(name, None)
            ''' !+VTF disabling for now, as attempting to preset a contextualized
            vocab fails for subsequent lodaing of a *view*, as this is executed 
            when validating a *submit* -- may still work if executed right moment.
            
            # !+VTF bungeni.ui.fields.VocabularyTextField -- here a vocabulary 
            # field is not necessarily the type defined by bungeni 
            # e.g. zope.schema._field.Choice that during validation attempts to
            # retrieve the vocabulary and initialize it with a None context...
            # To preempt the error that this causes, we check for and stuff
            # an appropiately initialized vocabulary instance onto this field...
            if hasattr(field, "vocabulary"):
                # preset a vocabulary on self.context, or reset with one off current 
                # context if the one preset previously was off a different context
                if (field.vocabulary is None or (
                        # a vocab was preset previously
                        hasattr(field, "_vtf_last_context") and
                        # and it was prepared with a different context
                        getattr(field, "_vtf_last_context") is not self.context)
                    ):
                    from bungeni.alchemist.utils import get_vocabulary
                    field.vocabulary = get_vocabulary(field.vocabularyName)(self.context)
                    # remember last context used to preset vocabulary
                    field._vtf_last_context = self.context
                    log.debug("Validation of vocabulary field (%r, %r) with value=%r -- "
                        "stuffing vocabulary instance %s [context: %r] onto field %s ...", 
                        name, field.vocabularyName, value, field.vocabulary, self.context, field)
            '''
            # !+VTF a "temporary" and simpler version of above, to avoid
            # AttributeError in try block below (and incorrectly failed validation).
            TMP_SET_VOCAB = False
            if hasattr(field, "vocabulary") and field.vocabulary is None:
                TMP_SET_VOCAB = True
                from bungeni.alchemist.utils import get_vocabulary
                field.vocabulary = get_vocabulary(field.vocabularyName)(
                    self.context)
            # standard field validation !+ necessary, already called elsewhere?
            try:
                widget_error = field.validate(value)
            except (RequiredMissing, ) as exc:
                widget_error = exc
            # !+ other possible exceptions, should never pass here?
            except (
                    formlib.form.NoInputData,
                    interface.Invalid,
                    Exception,
            ) as exc:
                widget_error = exc
                probing.log_exc(sys.exc_info(), log_handler=log.error)
                log.debug(probing.class_inheritance(exc))
                log.error(
                    "\n"
                    "    %r.validate(%r) FAILED (field %r)\n"
                    "    [context: %r]", field, value, name, self.context)
                #raise # !+?
            # !+VTF clear any vocabulary that we preset above
            if TMP_SET_VOCAB:
                field.vocabulary = None
            if widget_error:
                errors.append(self.set_widget_error(name, widget_error))
                widget_error = None
                continue

            # get db column definition
            domain_attr = getattr(dm, name)
            if not isinstance(domain_attr,
                              sa.orm.attributes.InstrumentedAttribute):
                continue
            domain_attr_property = domain_attr.property
            assert isinstance(
                domain_attr_property,
                sa.orm.properties.ColumnProperty), name  # !+TMP sanity check
            # !+MULTIPLE_COLUMNS only single columns supported (so far)
            if len(domain_attr_property.columns) == 1:
                col = domain_attr_property.columns[0]
                #!+AttributeError: '_Label' object has no attribute 'nullable'
                # not: sa.sql.expression._Label, sa.sql.expression.ColumnElement
                assert isinstance(col, sa.schema.Column), col
            else:
                log.warn(
                    "SQLAlchemy property %r NOT defined as a single column, "
                    "skipping derived_table_schema validation...", name)
                continue

            # validate against db column definition
            # nullable
            if value is None:
                if not col.nullable:
                    errors.append(
                        self.set_widget_error(name, _(u"May not be null")))
                continue
            # sa.String
            if isinstance(col.type, sa.types.String):
                # length
                length = col.type.length
                if length is not None:
                    if length < len(value):
                        errors.append(
                            self.set_widget_error(
                                name,
                                _(u"May not be longer than ${length}",
                                  mapping={"length": length})))
        return errors
Esempio n. 6
0
 def vocabulary(self):
     return get_vocabulary(self.vocabulary_name)
Esempio n. 7
0
def obj2dict(obj, depth, parent=None, include=[], exclude=[], lang=None, root_key=None):
    """ Returns dictionary representation of a domain object.
    """
    if lang is None:
        lang = getattr(obj, "language", capi.default_language)
    result = {}
    obj = zope.security.proxy.removeSecurityProxy(obj)
    descriptor = None
    if IAlchemistContent.providedBy(obj):
        try:
            descriptor = utils.get_descriptor(obj)
        except KeyError:
            log.error("Could not get descriptor for IAlchemistContent %r", obj)
        
        if parent is not None and IWorkflowed.providedBy(obj):
            permissions = get_object_state_rpm(obj).permissions
            result["permissions"] = get_permissions_dict(permissions)
            result["tags"] = IStateController(obj).get_state().tags
        
    # Get additional attributes
    for name in include:
        value = getattr(obj, name, None)
        if value is None:
            continue
        if not name.endswith("s"):
            name += "s"
        if isinstance(value, collections.Iterable):
            res = []
            # !+ allowance for non-container-api-conformant alchemist containers
            if IAlchemistContainer.providedBy(value):
                value = value.values()
            for item in value:
                i = obj2dict(item, 0, lang=lang, root_key=root_key)
                res.append(i)
            result[name] = res
        else:
            result[name] = value
    
    # Get mapped attributes
    seen_keys = []
    mapper = class_mapper(obj.__class__)
    for mproperty in mapper.iterate_properties:
        if mproperty.key.startswith("_vp"):
            #skip vertical props
            continue
        if mproperty.key in exclude:
            continue
        seen_keys.append(mproperty.key)
        value = getattr(obj, mproperty.key)
        if value == parent:
            continue
        if value is None:
            continue
        
        if isinstance(mproperty, RelationshipProperty) and depth > 0:
            if isinstance(value, collections.Iterable):
                result[mproperty.key] = []
                for item in value:
                    # !+DEPTH(ah, 2014-09-19) depth was set to 1 here, this causes 
                    # a very deep branching for upper level groups like legislature and chamber
                    # and legislature times out occasionally. Doesnt seem neccessary to go depth=1
                    # for child objects, because they get serialized independently anyway, changing
                    # depth to depth-1 so all dependent objects are iterated 1 level lower than the 
                    # parent.
                    # UPDATE(ah, 2014-11-03) Item Schedule is an exceptional case of an object 
                    # whose context is within a parent container but is not visible outside of the sitting
                    # it is not a type defined in types.xml and does not have its own 
                    # wokflow so we need to handle that in a unique way
                    # we don't decrement the depth and instead process it as is 
                    active_depth = depth
                    if item.__class__.__name__ == "ItemSchedule":
                        active_depth = depth
                    else:
                        active_depth = depth-1
                    result[mproperty.key].append(
                         obj2dict(
                            item,
                            active_depth, 
                            parent=obj,
                            include=["owner", "item_schedule", "item_schedule_discussion"],
                            exclude=exclude + INNER_EXCLUDES,
                            lang=lang,
                            root_key=root_key
                         )
                    )
            else:
                result[mproperty.key] = obj2dict(value, depth-1, 
                    parent=obj,
                    include=["owner"],
                    exclude=exclude + INNER_EXCLUDES,
                    lang=lang,
                    root_key=root_key
                )
        else:
            if isinstance(mproperty, RelationshipProperty):
                continue
            elif isinstance(mproperty, ColumnProperty):
                columns = mproperty.columns
                if len(columns) == 1:
                    if is_column_binary(columns[0]):
                        fname = PersistFiles.store_file(obj, parent, 
                            columns[0].key, root_key)
                        if fname:
                            result[columns[0].key] = dict(saved_file=fname)
                        continue
            if descriptor:
                columns = mproperty.columns
                is_foreign = False
                if len(columns) == 1:
                    if len(columns[0].foreign_keys):
                        is_foreign = True
                if (not is_foreign) and (mproperty.key in descriptor.keys()):
                    field = descriptor.get(mproperty.key)
                    if (field and field.property and
                            (schema.interfaces.IChoice.providedBy(field.property) or
                                IVocabularyTextField.providedBy(field.property))
                        ):
                        factory = field.property.vocabulary or field.property.source
                        if factory is None:
                            vocab_name = getattr(field.property, "vocabularyName", None)
                            factory = get_vocabulary(vocab_name)
                        # !+VOCABULARIES(mb, aug-2012)some vocabularies
                        # expect an interaction to generate values
                        # todo - update these vocabularies to work 
                        # with no request e.g. in notification threads
                        display_name = None
                        try:
                            vocabulary = factory(obj)                             
                            # handle vdex hierarchical terms
                            if ITreeVocabulary.providedBy(factory):
                                values = value.splitlines()
                                term_values = []
                                for val in values:
                                    term_values.append(dict(
                                            name=mproperty.key,
                                            value=val,
                                            displayAs=factory.getTermCaption(
                                                factory.getTermById(val), lang=lang)))
                                result[mproperty.key] = term_values
                                continue
                            term = vocabulary.getTerm(value)
                            if lang:
                                if hasattr(factory, "getTermCaption"):
                                    display_name = factory.getTermCaption(
                                            factory.getTermById(value), lang=lang)
                                else:
                                    display_name = translate(
                                        term.title or term.value,
                                        target_language=lang,
                                        domain="bungeni")
                            else:
                                display_name = term.title or term.value
                        except zope.security.interfaces.NoInteraction:
                            log.error("This vocabulary %s expects an interaction "
                                "to generate terms.", factory)
                            # try to use dc adapter lookup
                            try:
                                _prop = mapper.get_property_by_column(
                                    mproperty.columns[0])
                                _prop_value = getattr(obj, _prop.key)
                                dc = IDCDescriptiveProperties(_prop_value, None)
                                if dc:
                                    display_name = IDCDescriptiveProperties(
                                            _prop_value).title
                            except KeyError:
                                log.warn("No display text found for %s on " 
                                    "object %s. Unmapped in orm.",
                                    property.key, obj)
                        except Exception, e:
                            log.error("Could not instantiate vocabulary %s. "
                                "Exception: %s", factory, e)
                        finally:
                            # fallback we cannot look up vocabularies/dc
                            if display_name is None:
                                if not isinstance(value, unicode):
                                    display_name = unicode(value)
                        if display_name is not None:
                            result[mproperty.key] = dict(
                                name=mproperty.key,
                                value=value,
                                displayAs=display_name)
                            continue