def assign_simple_handler(self, widget_name, model_attr, validator=None):
        '''
        Assign handlers to widgets to change fields in the model.

        :param widget_name:

        :param model_attr:

        :param validator:

        Note: Where widget is a gtk.ComboBox or gtk.ComboBoxEntry then
        the value is assumed to be stored in model[row][0]
        '''
        widget = self.view.widgets[widget_name]
        check(widget is not None, _('no widget with name %s') % widget_name)

        class ProblemValidator(Validator):

            def __init__(self, presenter, wrapped):
                self.presenter = presenter
                self.wrapped = wrapped

            def to_python(self, value):
                try:
                    value = self.wrapped.to_python(value)
                    self.presenter.remove_problem('BAD_VALUE_%s' \
                                             % model_attr,widget)
                except Exception, e:
                    self.presenter.add_problem('BAD_VALUE_%s' \
                                              % model_attr, widget)
                    raise
                return value
Beispiel #2
0
    def invoke(self, search_strategy):
        """
        update search_strategy object with statement results

        Queries can use more database specific features.  This also
        means that the same query might not work the same on different
        database types. For example, on a PostgreSQL database you can
        use ilike but this would raise an error on SQLite.
        """

        domain = self.domain
        check(
            domain in search_strategy._domains
            or domain in search_strategy._shorthand,
            'Unknown search domain: %s' % domain)
        self.domain = search_strategy._shorthand.get(domain, domain)
        self.domain = search_strategy._domains[domain][0]
        self.search_strategy = search_strategy

        result = set()
        if search_strategy._session is not None:
            self.domains = self.filter.needs_join(self)
            self.session = search_strategy._session
            records = self.filter.evaluate(self).all()
            result.update(records)

        return result
Beispiel #3
0
def range_builder(text):
    """Return a list of numbers from a string range of the form 1-3,4,5
    """
    from pyparsing import Word, Group, Suppress, delimitedList, nums, \
        ParseException, ParseResults
    rng = Group(Word(nums) + Suppress('-') + Word(nums))
    range_list = delimitedList(rng | Word(nums))

    token = None
    try:
        tokens = range_list.parseString(text)
    except (AttributeError, ParseException) as e:
        return []
    values = set()
    for rng in tokens:
        if isinstance(rng, ParseResults):
            # get here if the token is a range
            start = int(rng[0])
            end = int(rng[1]) + 1
            check(start<end, 'start must be less than end')
            values.update(range(start, end))
        else:
            # get here if the token is an integer
            values.add(int(rng))
    return list(values)
Beispiel #4
0
    def add_meta(self, domain, cls, properties):
        """Add a domain to the search space

        an example of domain is a database table, where the properties would
        be the table columns to consider in the search.  continuing this
        example, a record is be selected if any of the fields matches the
        searched value.

        :param domain: a string, list or tuple of domains that will resolve
                       a search string to cls.  domain act as a shorthand to
                       the class name.
        :param cls: the class the domain will resolve to
        :param properties: a list of string names of the properties to
                           search by default
        """

        logger.debug('%s.add_meta(%s, %s, %s)' %
                     (self, domain, cls, properties))

        check(
            isinstance(properties, list),
            _('MapperSearch.add_meta(): '
              'default_columns argument must be list'))
        check(
            len(properties) > 0,
            _('MapperSearch.add_meta(): '
              'default_columns argument cannot be empty'))
        if isinstance(domain, (list, tuple)):
            self._domains[domain[0]] = cls, properties
            for d in domain[1:]:
                self._shorthand[d] = domain[0]
        else:
            self._domains[domain] = cls, properties
        self._properties[cls] = properties
    def invoke(self, search_strategy):
        """
        update search_strategy object with statement results

        Queries can use more database specific features.  This also
        means that the same query might not work the same on different
        database types. For example, on a PostgreSQL database you can
        use ilike but this would raise an error on SQLite.
        """

        domain = self.domain
        check(domain in search_strategy._domains or
              domain in search_strategy._shorthand,
              'Unknown search domain: %s' % domain)
        self.domain = search_strategy._shorthand.get(domain, domain)
        self.domain = search_strategy._domains[domain][0]
        self.search_strategy = search_strategy

        result = set()
        if search_strategy._session is not None:
            self.domains = self.filter.needs_join(self)
            self.session = search_strategy._session
            records = self.filter.evaluate(self).all()
            result.update(records)

        return result
Beispiel #6
0
    def add_meta(self, domain, cls, properties):
        """
        Adds search meta to the domain

        :param domain: a string, list or tuple of domains that will resolve
        to cls a search string, domain act as a shorthand to the class name
        :param cls: the class the domain will resolve to
        :param properties: a list of string names of the properties to
        search by default
        """
        check(
            isinstance(properties, list),
            _('MapperSearch.add_meta(): '
              'default_columns argument must be list'))
        check(
            len(properties) > 0,
            _('MapperSearch.add_meta(): '
              'default_columns argument cannot be empty'))
        if isinstance(domain, (list, tuple)):
            # domain[0] is the result key
            self._result_keys[cls] = domain[0]
            self._domains[domain[0]] = cls, properties
            for d in domain[1:]:
                self._shorthand[d] = domain[0]
        else:
            self._result_keys[cls] = domain
            self._domains[d] = cls, properties
        self._properties[cls] = properties
    def add_meta(self, domain, cls, properties):
        """Add a domain to the search space

        an example of domain is a database table, where the properties would
        be the table columns to consider in the search.  continuing this
        example, a record is be selected if any of the fields matches the
        searched value.

        :param domain: a string, list or tuple of domains that will resolve
                       a search string to cls.  domain act as a shorthand to
                       the class name.
        :param cls: the class the domain will resolve to
        :param properties: a list of string names of the properties to
                           search by default
        """

        logger.debug('%s.add_meta(%s, %s, %s)' %
                     (self, domain, cls, properties))

        check(isinstance(properties, list),
              _('MapperSearch.add_meta(): '
                'default_columns argument must be list'))
        check(len(properties) > 0,
              _('MapperSearch.add_meta(): '
                'default_columns argument cannot be empty'))
        if isinstance(domain, (list, tuple)):
            self._domains[domain[0]] = cls, properties
            for d in domain[1:]:
                self._shorthand[d] = domain[0]
        else:
            self._domains[domain] = cls, properties
        self._properties[cls] = properties
Beispiel #8
0
def make_label_clickable(label, on_clicked, *args):
    """
    :param label: a gtk.Label that has a gtk.EventBox as its parent
    :param on_clicked: callback to be called when the label is clicked
      on_clicked(label, event, data)
    """
    eventbox = label.parent

    check(eventbox is not None, 'label must have a parent')
    check(isinstance(eventbox, gtk.EventBox),
          'label must have an gtk.EventBox as its parent')
    label.__pressed = False

    def on_enter_notify(*args):
        label.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse("blue"))

    def on_leave_notify(*args):
        label.modify_fg(gtk.STATE_NORMAL, None)
        label.__pressed = False

    def on_press(*args):
        label.__pressed = True

    def on_release(widget, event, *args):
        if label.__pressed:
            label.__pressed = False
            label.modify_fg(gtk.STATE_NORMAL, None)
            on_clicked(label, event, *args)

    eventbox.connect('enter_notify_event', on_enter_notify)
    eventbox.connect('leave_notify_event', on_leave_notify)
    eventbox.connect('button_press_event', on_press)
    eventbox.connect('button_release_event', on_release, *args)
Beispiel #9
0
def make_label_clickable(label, on_clicked, *args):
    """
    :param label: a gtk.Label that has a gtk.EventBox as its parent
    :param on_clicked: callback to be called when the label is clicked
      on_clicked(label, event, data)
    """
    eventbox = label.parent

    check(eventbox is not None, 'label must have a parent')
    check(isinstance(eventbox, gtk.EventBox),
          'label must have an gtk.EventBox as its parent')
    label.__pressed = False

    def on_enter_notify(*args):
        label.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse("blue"))

    def on_leave_notify(*args):
        label.modify_fg(gtk.STATE_NORMAL, None)
        label.__pressed = False

    def on_press(*args):
        label.__pressed = True

    def on_release(widget, event, *args):
        if label.__pressed:
            label.__pressed = False
            label.modify_fg(gtk.STATE_NORMAL, None)
            on_clicked(label, event, *args)
    eventbox.connect('enter_notify_event', on_enter_notify)
    eventbox.connect('leave_notify_event', on_leave_notify)
    eventbox.connect('button_press_event', on_press)
    eventbox.connect('button_release_event', on_release, *args)
Beispiel #10
0
    def append_children(self, model, parent, kids):
        """
        append object to a parent iter in the model

        :param model: the model the append to
        :param parent:  the parent gtk.TreeIter
        :param kids: a list of kids to append
        @return: the model with the kids appended
        """
        check(parent is not None, "append_children(): need a parent")
        for k in kids:
            i = model.append(parent, [k])
            if self.view_meta[type(k)].children is not None:
                model.append(i, ["_dummy"])
        return model
Beispiel #11
0
    def append_children(self, model, parent, kids):
        """
        append object to a parent iter in the model

        :param model: the model the append to
        :param parent:  the parent gtk.TreeIter
        :param kids: a list of kids to append
        @return: the model with the kids appended
        """
        check(parent is not None, "append_children(): need a parent")
        for k in kids:
            i = model.append(parent, [k])
            if self.view_meta[type(k)].children is not None:
                model.append(i, ["_dummy"])
        return model
Beispiel #12
0
 def set_active_connection_by_name(self, name):
     """
     sets the name of the connection in the name combo, this
     causes on_changed_name_combo to be fired which changes the param
     box type and set the connection parameters
     """
     check(hasattr(self, "name_combo"))
     i = 0
     active = 0
     conn_list = prefs.prefs[bauble.conn_list_pref]
     if conn_list is None:
         return
     for conn in conn_list:
         self.name_combo.insert_text(i, conn)
         if conn == name:
             active = i
         i += 1
     self.name_combo.set_active(active)
Beispiel #13
0
 def set_active_connection_by_name(self, name):
     """
     sets the name of the connection in the name combo, this
     causes on_changed_name_combo to be fired which changes the param
     box type and set the connection parameters
     """
     check(hasattr(self, "name_combo"))
     i = 0
     active = 0
     conn_list = prefs.prefs[bauble.conn_list_pref]
     if conn_list is None:
         return
     for conn in conn_list:
         self.name_combo.insert_text(i, conn)
         if conn == name:
             active = i
         i += 1
     self.name_combo.set_active(active)
Beispiel #14
0
def make_label_clickable(label, on_clicked, *args):
    """
    :param label: a gtk.Label that has a gtk.EventBox as its parent
    :param on_clicked: callback to be called when the label is clicked
      on_clicked(label, event, data)
    """
    eventbox = label.parent

    check(eventbox is not None, 'label must have a parent')
    check(isinstance(eventbox, gtk.EventBox),
          'label must have an gtk.EventBox as its parent')
    label.__pressed = False

    def on_enter_notify(widget, *args):
        widget.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse("#faf8f7"))
        label.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse("blue"))

    def on_leave_notify(widget, *args):
        widget.modify_bg(gtk.STATE_NORMAL, None)
        label.modify_fg(gtk.STATE_NORMAL, None)
        label.__pressed = False

    def on_press(*args):
        label.__pressed = True

    def on_release(widget, event, *args):
        if label.__pressed:
            label.__pressed = False
            label.modify_fg(gtk.STATE_NORMAL, None)
            on_clicked(label, event, *args)

    try:
        eventbox.disconnect(label.__on_event)
        logger.debug('disconnected previous release-event handler')
        label.__on_event = eventbox.connect(
            'button_release_event', on_release, *args)
    except AttributeError:
        logger.debug('defining handlers')
        label.__on_event = eventbox.connect(
            'button_release_event', on_release, *args)
        eventbox.connect('enter_notify_event', on_enter_notify)
        eventbox.connect('leave_notify_event', on_leave_notify)
        eventbox.connect('button_press_event', on_press)
Beispiel #15
0
def make_label_clickable(label, on_clicked, *args):
    """
    :param label: a gtk.Label that has a gtk.EventBox as its parent
    :param on_clicked: callback to be called when the label is clicked
      on_clicked(label, event, data)
    """
    eventbox = label.parent

    check(eventbox is not None, 'label must have a parent')
    check(isinstance(eventbox, gtk.EventBox),
          'label must have an gtk.EventBox as its parent')
    label.__pressed = False

    def on_enter_notify(widget, *args):
        widget.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse("#faf8f7"))
        label.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse("blue"))

    def on_leave_notify(widget, *args):
        widget.modify_bg(gtk.STATE_NORMAL, None)
        label.modify_fg(gtk.STATE_NORMAL, None)
        label.__pressed = False

    def on_press(*args):
        label.__pressed = True

    def on_release(widget, event, *args):
        if label.__pressed:
            label.__pressed = False
            label.modify_fg(gtk.STATE_NORMAL, None)
            on_clicked(label, event, *args)

    try:
        eventbox.disconnect(label.__on_event)
        logger.debug('disconnected previous release-event handler')
        label.__on_event = eventbox.connect(
            'button_release_event', on_release, *args)
    except AttributeError:
        logger.debug('defining handlers')
        label.__on_event = eventbox.connect(
            'button_release_event', on_release, *args)
        eventbox.connect('enter_notify_event', on_enter_notify)
        eventbox.connect('leave_notify_event', on_leave_notify)
        eventbox.connect('button_press_event', on_press)
    def add_meta(self, domain, cls, properties):
        """
        Adds search meta to the domain

        :param domain: a string, list or tuple of domains that will resolve
        to cls a search string, domain act as a shorthand to the class name
        :param cls: the class the domain will resolve to
        :param properties: a list of string names of the properties to
        search by default
        """
        check(isinstance(properties, list), _('MapperSearch.add_meta(): '\
        'default_columns argument must be list'))
        check(len(properties) > 0, _('MapperSearch.add_meta(): '\
        'default_columns argument cannot be empty'))
        if isinstance(domain, (list, tuple)):
            self._domains[domain[0]] = cls, properties
            for d in domain[1:]:
                self._shorthand[d] = domain[0]
        else:
            self._domains[d] = cls, properties
        self._properties[cls] = properties
Beispiel #17
0
def select_in_search_results(obj):
    """
    :param obj: the object the select
    @returns: a gtk.TreeIter to the selected row

    Search the tree model for obj if it exists then select it if not
    then add it and select it.

    The the obj is not in the model then we add it.
    """
    check(obj is not None, 'select_in_search_results: arg is None')
    view = bauble.gui.get_view()
    if not isinstance(view, SearchView):
        return None
    model = view.results_view.get_model()
    found = utils.search_tree_model(model, obj)
    row_iter = None
    if len(found) > 0:
        row_iter = found[0]
    else:
        row_iter = model.append(None, [obj])
        model.append(row_iter, ['-'])
    view.results_view.set_cursor(model.get_path(row_iter))
    return row_iter
Beispiel #18
0
def select_in_search_results(obj):
    """
    :param obj: the object the select
    @returns: a gtk.TreeIter to the selected row

    Search the tree model for obj if it exists then select it if not
    then add it and select it.

    The the obj is not in the model then we add it.
    """
    check(obj is not None, 'select_in_search_results: arg is None')
    view = bauble.gui.get_view()
    if not isinstance(view, SearchView):
        return None
    model = view.results_view.get_model()
    found = utils.search_tree_model(model, obj)
    row_iter = None
    if len(found) > 0:
        row_iter = found[0]
    else:
        row_iter = model.append(None, [obj])
        model.append(row_iter, ['-'])
    view.results_view.set_cursor(model.get_path(row_iter))
    return row_iter
Beispiel #19
0
    rng = Group(Word(nums) + Suppress("-") + Word(nums))
    range_list = delimitedList(rng | Word(nums))

    token = None
    try:
        tokens = range_list.parseString(text)
    except (AttributeError, ParseException), e:
        logger.debug(e)
        return []
    values = set()
    for rng in tokens:
        if isinstance(rng, ParseResults):
            # get here if the token is a range
            start = int(rng[0])
            end = int(rng[1]) + 1
            check(start < end, "start must be less than end")
            values.update(range(start, end))
        else:
            # get here if the token is an integer
            values.add(int(rng))
    return list(values)


def gc_objects_by_type(tipe):
    """
    Return a list of objects from the garbage collector by type.
    """
    import inspect
    import gc

    if isinstance(tipe, basestring):
Beispiel #20
0
def set_privilege(role, privilege):
    """Set the role's privileges.

    Arguments:
    - `role`:
    - `privilege`:
    """
    check(privilege in ('read', 'write', 'admin', None),
          'invalid privilege: %s' % privilege)
    conn = db.engine.connect()
    trans = conn.begin()

    if privilege:
        privs = _privileges[privilege]

    try:
        # revoke everything first
        for table in db.metadata.sorted_tables:
            stmt = 'revoke all on table %s from %s;' % (table.name, role)
            conn.execute(stmt)
            for col in table.c:
                if hasattr(col, 'sequence'):
                    stmt = 'revoke all on sequence %s from %s' % \
                        (col.sequence.name, role)
                    conn.execute(stmt)

        stmt = 'revoke all on database %s from %s' \
            % (bauble.db.engine.url.database, role)
        conn.execute(stmt)

        stmt = 'alter role %s with nocreaterole' % role
        conn.execute(stmt)

        # privilege is None so all permissions are revoked
        if not privilege:
            trans.commit()
            conn.close()
            return

        # change privileges on the database
        if privilege == 'admin':
            stmt = 'grant all on database %s to %s' % \
                (bauble.db.engine.url.database, role)
            if privilege == 'admin':
                stmt += ' with grant option'
            conn.execute(stmt)
            stmt = 'alter role %s with createuser' % role
            conn.execute(stmt)

        # grant privileges on the tables and sequences
        for table in bauble.db.metadata.sorted_tables:
            tbl_privs = filter(lambda x: x.lower() in _table_privs, privs)
            for priv in tbl_privs:
                stmt = 'grant %s on %s to %s' % (priv, table.name, role)
                if privilege == 'admin':
                    stmt += ' with grant option'
                #debug(stmt)
                conn.execute(stmt)
            for col in table.c:
                seq_privs = filter(lambda x: x.lower() in __sequence_privs,
                                   privs)
                for priv in seq_privs:
                    if hasattr(col, 'sequence'):
                        stmt = 'grant %s on sequence %s to %s' % \
                            (priv, col.sequence.name, role)
                        #debug(stmt)
                        if privilege == 'admin':
                            stmt += ' with grant option'
                        conn.execute(stmt)
    except Exception, e:
        error('users.set_privilege(): %s' % utils.utf8(e))
        trans.rollback()
        raise
Beispiel #21
0
    rng = Group(Word(nums) + Suppress('-') + Word(nums))
    range_list = delimitedList(rng | Word(nums))

    token = None
    try:
        tokens = range_list.parseString(text)
    except (AttributeError, ParseException), e:
        logger.debug(e)
        return []
    values = set()
    for rng in tokens:
        if isinstance(rng, ParseResults):
            # get here if the token is a range
            start = int(rng[0])
            end = int(rng[1]) + 1
            check(start < end, 'start must be less than end')
            values.update(range(start, end))
        else:
            # get here if the token is an integer
            values.add(int(rng))
    return list(values)


def gc_objects_by_type(tipe):
    """
    Return a list of objects from the garbage collector by type.
    """
    import inspect
    import gc
    if isinstance(tipe, basestring):
        return [o for o in gc.get_objects() if type(o).__name__ == tipe]
    def on_query(self, s, loc, tokens):
        """
        Called when the parser hits a query token.

        Queries can use more database specific features.  This also
        means that the same query might not work the same on different
        database types. For example, on a PostgreSQL database you can
        use ilike but this would raise an error on SQLite.
        """
        # The method requires that the underlying database support
        # union and intersect. At the time of writing this MySQL
        # didn't.

        # TODO: support 'not' a boolean op as well, e.g sp where
        # genus.genus=Maxillaria and not genus.family=Orchidaceae
        domain, expr = tokens
        check(domain in self._domains or domain in self._shorthand,
              'Unknown search domain: %s' % domain)
        if domain in self._shorthand:
            domain = self._shorthand[domain]
        cls = self._domains[domain][0]
        main_query = self._session.query(cls)
        mapper = class_mapper(cls)
        expr_iter = iter(expr)
        boolop = None
        for e in expr_iter:
            idents, cond, val = e
            # debug('cls: %s, idents: %s, cond: %s, val: %s'
            #       % (cls.__name__, idents, cond, val))
            if val == 'None':
                val = None
            if cond == 'is':
                cond = '='
            elif cond == 'is not':
                cond = '!='
            elif cond in ('ilike', 'icontains', 'ihas'):
                cond = lambda col: \
                    lambda val: utils.ilike(col, '%s' % val)


            if len(idents) == 1:
                # we get here when the idents only refer to a property
                # on the mapper table..i.e. a column
                col = idents[0]
                msg = _('The %(tablename)s table does not have a '\
                       'column named "%(columname)s"') % \
                       dict(tablename=mapper.local_table.name,
                            columname=col)
                check(col in mapper.c, msg)
                if isinstance(cond, str):
                    clause = getattr(cls, col).op(cond)(utils.utf8(val))
                else:
                    clause = cond(getattr(cls, col))(utils.utf8(val))
                query = self._session.query(cls).filter(clause).order_by(None)
            else:
                # we get here when the idents refer to a relation on a
                # mapper/table
                relations = idents[:-1]
                col = idents[-1]
                query = self._session.query(cls)
                query = query.join(*relations)

                # NOTE: SA07 - this depends on Query._joinpoint not changing,
                # it changed in SA05 which broke this
                local_table = query._joinpoint['prev'][0][1].local_table
                if isinstance(cond, str):
                    clause = local_table.c[col].op(cond)(utils.utf8(val))
                else:
                    clause = cond(local_table.c[col])(utils.utf8(val))
                query = query.filter(clause).order_by(None)

            if boolop == 'or':
                main_query = main_query.union(query)
            elif boolop == 'and':
                main_query = main_query.intersect(query)
            else:
                main_query = query

            try:
                boolop = expr_iter.next()
            except StopIteration:
                pass

        self._results.update(main_query.order_by(None).all())
Beispiel #23
0
def create_abcd(decorated_objects, authors=True, validate=True):
    """
    :param objects: a list/tuple of objects that implement the ABCDDecorator
      interface
    :param authors: flag to control whether to include the authors in the
      species name
    :param validate: whether we should validate the data before returning
    :returns: a valid ABCD ElementTree
    """
    import bauble.plugins.garden.institution as institution
    inst = institution.Institution()
    if not verify_institution(inst):
        msg = _('Some or all of the information about your institution or ' \
                'business is not complete. Please make sure that the ' \
                'Name, Technical Contact, Email, Contact and Institution '
                'Code fields are filled in.')
        utils.message_dialog(msg)
        institution.InstitutionEditor().start()
        return create_abcd(decorated_objects, authors, validate)

    datasets = DataSets()
    ds = ABCDElement(datasets, 'DataSet')
    tech_contacts = ABCDElement(ds, 'TechnicalContacts')
    tech_contact = ABCDElement(tech_contacts, 'TechnicalContact')

    # TODO: need to include contact information in bauble meta when
    # creating a new database
    ABCDElement(tech_contact, 'Name', text=inst.inst_technical_contact)
    ABCDElement(tech_contact, 'Email', text=inst.inst_email)
    cont_contacts = ABCDElement(ds, 'ContentContacts')
    cont_contact = ABCDElement(cont_contacts, 'ContentContact')
    ABCDElement(cont_contact, 'Name', text=inst.inst_contact)
    ABCDElement(cont_contact, 'Email', text=inst.inst_email)
    metadata = ABCDElement(
        ds,
        'Metadata',
    )
    description = ABCDElement(metadata, 'Description')

    # TODO: need to get the localized language
    representation = ABCDElement(description,
                                 'Representation',
                                 attrib={'language': 'en'})
    revision = ABCDElement(metadata, 'RevisionData')
    ABCDElement(revision, 'DateModified', text='2001-03-01T00:00:00')
    title = ABCDElement(representation, 'Title', text='TheTitle')
    units = ABCDElement(ds, 'Units')

    # build the ABCD unit
    for obj in decorated_objects:
        unit = ABCDElement(units, 'Unit')
        ABCDElement(unit, 'SourceInstitutionID', text=inst.inst_code)

        # TODO: don't really understand the SourceID element
        ABCDElement(unit, 'SourceID', text='Bauble')

        unit_id = ABCDElement(unit, 'UnitID', text=obj.get_UnitID())
        ABCDElement(unit, 'DateLastEdited', text=obj.get_DateLastEdited())

        # TODO: add list of verifications to Identifications

        # scientific name identification
        identifications = ABCDElement(unit, 'Identifications')
        identification = ABCDElement(identifications, 'Identification')
        result = ABCDElement(identification, 'Result')
        taxon_identified = ABCDElement(result, 'TaxonIdentified')
        higher_taxa = ABCDElement(taxon_identified, 'HigherTaxa')
        higher_taxon = ABCDElement(higher_taxa, 'HigherTaxon')

        # TODO: ABCDDecorator should provide an iterator so that we can
        # have multiple HigherTaxonName's
        higher_taxon_name = ABCDElement(higher_taxon,
                                        'HigherTaxonName',
                                        text=obj.get_family())
        higher_taxon_rank = ABCDElement(higher_taxon,
                                        'HigherTaxonRank',
                                        text='familia')

        scientific_name = ABCDElement(taxon_identified, 'ScientificName')
        ABCDElement(scientific_name,
                    'FullScientificNameString',
                    text=obj.get_FullScientificNameString(authors))

        name_atomised = ABCDElement(scientific_name, 'NameAtomised')
        botanical = ABCDElement(name_atomised, 'Botanical')
        ABCDElement(botanical,
                    'GenusOrMonomial',
                    text=obj.get_GenusOrMonomial())
        ABCDElement(botanical, 'FirstEpithet', text=obj.get_FirstEpithet())
        author_team = obj.get_AuthorTeam()
        if author_team is not None:
            ABCDElement(botanical, 'AuthorTeam', text=author_team)
        ABCDElement(identification, 'PreferredFlag', text='true')

        # vernacular name identification
        # TODO: should we include all the vernacular names or only the default
        # one
        vernacular_name = obj.get_InformalNameString()
        if vernacular_name is not None:
            identification = ABCDElement(identifications, 'Identification')
            result = ABCDElement(identification, 'Result')
            taxon_identified = ABCDElement(result, 'TaxonIdentified')
            ABCDElement(taxon_identified,
                        'InformalNameString',
                        text=vernacular_name)

        # add all the extra non standard elements
        obj.extra_elements(unit)
        # TODO: handle verifiers/identifiers
        # TODO: RecordBasis

        # notes are last in the schema and extra_elements() shouldn't
        # add anything that comes past Notes, e.g. RecordURI,
        # EAnnotations, UnitExtension
        notes = obj.get_Notes()
        if notes:
            ABCDElement(unit, 'Notes', text=notes)

    if validate:
        check(validate_xml(datasets), 'ABCD data not valid')

    return ElementTree(datasets)
def create_abcd(decorated_objects, authors=True, validate=True):
    """
    :param objects: a list/tuple of objects that implement the ABCDDecorator
      interface
    :param authors: flag to control whether to include the authors in the
      species name
    :param validate: whether we should validate the data before returning
    :returns: a valid ABCD ElementTree
    """
    import bauble.plugins.garden.institution as institution
    inst = institution.Institution()
    if not verify_institution(inst):
        msg = _('Some or all of the information about your institution or ' \
                'business is not complete. Please make sure that the ' \
                'Name, Technical Contact, Email, Contact and Institution '
                'Code fields are filled in.')
        utils.message_dialog(msg)
        institution.InstitutionEditor().start()
        return create_abcd(decorated_objects, authors, validate)

    datasets = DataSets()
    ds = ABCDElement(datasets, 'DataSet')
    tech_contacts = ABCDElement(ds, 'TechnicalContacts')
    tech_contact = ABCDElement(tech_contacts, 'TechnicalContact')

    # TODO: need to include contact information in bauble meta when
    # creating a new database
    ABCDElement(tech_contact, 'Name', text=inst.inst_technical_contact)
    ABCDElement(tech_contact, 'Email', text=inst.inst_email)
    cont_contacts = ABCDElement(ds, 'ContentContacts')
    cont_contact = ABCDElement(cont_contacts, 'ContentContact')
    ABCDElement(cont_contact, 'Name', text=inst.inst_contact)
    ABCDElement(cont_contact, 'Email', text=inst.inst_email)
    metadata = ABCDElement(ds, 'Metadata', )
    description = ABCDElement(metadata, 'Description')

    # TODO: need to get the localized language
    representation = ABCDElement(description, 'Representation',
                                    attrib={'language': 'en'})
    revision = ABCDElement(metadata, 'RevisionData')
    ABCDElement(revision, 'DateModified', text='2001-03-01T00:00:00')
    title = ABCDElement(representation, 'Title', text='TheTitle')
    units = ABCDElement(ds, 'Units')

    # build the ABCD unit
    for obj in decorated_objects:
        unit = ABCDElement(units, 'Unit')
        ABCDElement(unit, 'SourceInstitutionID', text=inst.inst_code)

        # TODO: don't really understand the SourceID element
        ABCDElement(unit, 'SourceID', text='Bauble')

        unit_id = ABCDElement(unit, 'UnitID', text=obj.get_UnitID())
        ABCDElement(unit, 'DateLastEdited', text=obj.get_DateLastEdited())

        # TODO: add list of verifications to Identifications

        # scientific name identification
        identifications = ABCDElement(unit, 'Identifications')
        identification = ABCDElement(identifications, 'Identification')
        result = ABCDElement(identification, 'Result')
        taxon_identified = ABCDElement(result, 'TaxonIdentified')
        higher_taxa = ABCDElement(taxon_identified, 'HigherTaxa')
        higher_taxon = ABCDElement(higher_taxa, 'HigherTaxon')

        # TODO: ABCDDecorator should provide an iterator so that we can
        # have multiple HigherTaxonName's
        higher_taxon_name = ABCDElement(higher_taxon, 'HigherTaxonName',
                                        text=obj.get_family())
        higher_taxon_rank = ABCDElement(higher_taxon, 'HigherTaxonRank',
                                        text='familia')

        scientific_name = ABCDElement(taxon_identified, 'ScientificName')
        ABCDElement(scientific_name, 'FullScientificNameString',
                       text=obj.get_FullScientificNameString(authors))

        name_atomised = ABCDElement(scientific_name, 'NameAtomised')
        botanical = ABCDElement(name_atomised, 'Botanical')
        ABCDElement(botanical, 'GenusOrMonomial',
                       text=obj.get_GenusOrMonomial())
        ABCDElement(botanical, 'FirstEpithet', text=obj.get_FirstEpithet())
        author_team = obj.get_AuthorTeam()
        if author_team is not None:
            ABCDElement(botanical, 'AuthorTeam', text=author_team)
        ABCDElement(identification, 'PreferredFlag', text='true')

        # vernacular name identification
        # TODO: should we include all the vernacular names or only the default
        # one
        vernacular_name = obj.get_InformalNameString()
        if vernacular_name is not None:
            identification = ABCDElement(identifications, 'Identification')
            result = ABCDElement(identification, 'Result')
            taxon_identified = ABCDElement(result, 'TaxonIdentified')
            ABCDElement(taxon_identified, 'InformalNameString',
                           text=vernacular_name)

        # add all the extra non standard elements
        obj.extra_elements(unit)
        # TODO: handle verifiers/identifiers
        # TODO: RecordBasis

        # notes are last in the schema and extra_elements() shouldn't
        # add anything that comes past Notes, e.g. RecordURI,
        # EAnnotations, UnitExtension
        notes = obj.get_Notes()
        if notes:
            ABCDElement(unit, 'Notes', text=notes)

    if validate:
        check(validate_xml(datasets), 'ABCD data not valid')

    return ElementTree(datasets)
Beispiel #25
0
def set_privilege(role, privilege):
    """Set the role's privileges.

    Arguments:
    - `role`:
    - `privilege`:
    """
    check(privilege in ("read", "write", "admin", None), "invalid privilege: %s" % privilege)
    conn = db.engine.connect()
    trans = conn.begin()

    if privilege:
        privs = _privileges[privilege]

    try:
        # revoke everything first
        for table in db.metadata.sorted_tables:
            stmt = "revoke all on table %s from %s;" % (table.name, role)
            conn.execute(stmt)
            for col in table.c:
                if hasattr(col, "sequence"):
                    stmt = "revoke all on sequence %s from %s" % (col.sequence.name, role)
                    conn.execute(stmt)

        stmt = "revoke all on database %s from %s" % (bauble.db.engine.url.database, role)
        conn.execute(stmt)

        stmt = "alter role %s with nocreaterole" % role
        conn.execute(stmt)

        # privilege is None so all permissions are revoked
        if not privilege:
            trans.commit()
            conn.close()
            return

        # change privileges on the database
        if privilege == "admin":
            stmt = "grant all on database %s to %s" % (bauble.db.engine.url.database, role)
            if privilege == "admin":
                stmt += " with grant option"
            conn.execute(stmt)
            stmt = "alter role %s with createuser" % role
            conn.execute(stmt)

        # grant privileges on the tables and sequences
        for table in bauble.db.metadata.sorted_tables:
            tbl_privs = filter(lambda x: x.lower() in _table_privs, privs)
            for priv in tbl_privs:
                stmt = "grant %s on %s to %s" % (priv, table.name, role)
                if privilege == "admin":
                    stmt += " with grant option"
                # debug(stmt)
                conn.execute(stmt)
            for col in table.c:
                seq_privs = filter(lambda x: x.lower() in __sequence_privs, privs)
                for priv in seq_privs:
                    if hasattr(col, "sequence"):
                        stmt = "grant %s on sequence %s to %s" % (priv, col.sequence.name, role)
                        # debug(stmt)
                        if privilege == "admin":
                            stmt += " with grant option"
                        conn.execute(stmt)
    except Exception, e:
        error("users.set_privilege(): %s" % utils.utf8(e))
        trans.rollback()
        raise
Beispiel #26
0
    rng = Group(Word(nums) + Suppress('-') + Word(nums))
    range_list = delimitedList(rng | Word(nums))

    token = None
    try:
        tokens = range_list.parseString(text)
    except (AttributeError, ParseException), e:
        logger.debug(e)
        return []
    values = set()
    for rng in tokens:
        if isinstance(rng, ParseResults):
            # get here if the token is a range
            start = int(rng[0])
            end = int(rng[1]) + 1
            check(start < end, 'start must be less than end')
            values.update(range(start, end))
        else:
            # get here if the token is an integer
            values.add(int(rng))
    return list(values)


def gc_objects_by_type(tipe):
    """
    Return a list of objects from the garbage collector by type.
    """
    import inspect
    import gc
    if isinstance(tipe, basestring):
        return [o for o in gc.get_objects() if type(o).__name__ == tipe]
Beispiel #27
0
    def on_query(self, s, loc, tokens):
        """
        Called when the parser hits a query token.

        Queries can use more database specific features.  This also
        means that the same query might not work the same on different
        database types. For example, on a PostgreSQL database you can
        use ilike but this would raise an error on SQLite.
        """
        # The method requires that the underlying database support
        # union and intersect. At the time of writing this MySQL
        # didn't.

        # TODO: support 'not' a boolean op as well, e.g sp where
        # genus.genus=Maxillaria and not genus.family=Orchidaceae
        domain, expr = tokens
        check(domain in self._domains or domain in self._shorthand,
              'Unknown search domain: %s' % domain)
        if domain in self._shorthand:
            domain = self._shorthand[domain]
        cls = self._domains[domain][0]
        main_query = self._session.query(cls)
        mapper = class_mapper(cls)
        expr_iter = iter(expr)
        boolop = None
        for e in expr_iter:
            idents, cond, val = e
            # debug('cls: %s, idents: %s, cond: %s, val: %s'
            #       % (cls.__name__, idents, cond, val))
            if val == 'None':
                val = None
            if cond == 'is':
                cond = '='
            elif cond == 'is not':
                cond = '!='
            elif cond in ('ilike', 'icontains', 'ihas'):
                return col.op.ilike(val)
                # cond = lambda col: \
                #     lambda val: utils.ilike(col, '%s' % val)

            if len(idents) == 1:
                # we get here when the idents only refer to a property
                # on the mapper table..i.e. a column
                col = idents[0]
                msg = _('The %(tablename)s table does not have a '\
                        'column named "%(columname)s"') % \
                       dict(tablename=mapper.local_table.name,
                            columname=col)
                check(col in mapper.c, msg)
                if isinstance(cond, str):
                    #clause = getattr(cls, col).op(cond)(utils.utf8(val))
                    clause = getattr(cls, col).op(cond)(val)
                else:
                    #clause = cond(getattr(cls, col))(utils.utf8(val))
                    clause = cond(getattr(cls, col))(val)
                query = self._session.query(cls).filter(clause).order_by(None)
            else:
                # we get here when the idents refer to a relation on a
                # mapper/table
                relations = idents[:-1]
                col = idents[-1]
                query = self._session.query(cls)
                query = query.join(*relations)

                # NOTE: SA07 - this depends on Query._joinpoint not changing,
                # it changed in SA05 which broke this
                local_table = query._joinpoint['prev'][0][1].local_table
                if isinstance(cond, str):
                    #clause = local_table.c[col].op(cond)(utils.utf8(val))
                    clause = local_table.c[col].op(cond)(val)
                else:
                    #clause = cond(local_table.c[col])(utils.utf8(val))
                    clause = cond(local_table.c[col])(val)
                query = query.filter(clause).order_by(None)

            if boolop == 'or':
                main_query = main_query.union(query)
            elif boolop == 'and':
                main_query = main_query.intersect(query)
            else:
                main_query = query

            try:
                boolop = next(expr_iter)
            except StopIteration:
                pass

        self._results[self._result_keys[cls]] = main_query.order_by(None).all()
Beispiel #28
0
    def get_objects(self):
        '''return the list of objects to be exported

        if "based_on" is "selection", return the top level selection only.

        if "based_on" is something else, return all that is needed to create
        a complete export.
        '''
        if self._choices['based_on'] == 'selection':
            class EmptySelectionException(Exception):
                pass
            from bauble.view import SearchView
            view = bauble.gui.get_view()
            try:
                check(isinstance(view, SearchView))
                tree_view = view.results_view.get_model()
                check(tree_view is not None)
            except CheckConditionError:
                utils.message_dialog(_('Search for something first.'))
                return

            return [row[0] for row in tree_view]

        ## export disregarding selection
        result = []
        if self._choices['based_on'] == 'plants':
            plants = self.session.query(Plant).order_by(Plant.code).join(
                Accession).order_by(Accession.code).all()
            plantnotes = self.session.query(PlantNote).all()
            ## only used locations and accessions
            locations = self.session.query(Location).filter(
                Location.id.in_([j.location_id for j in plants])).all()
            accessions = self.session.query(Accession).filter(
                Accession.id.in_([j.accession_id for j in plants])).order_by(
                Accession.code).all()
            ## notes are linked in opposite direction
            accessionnotes = self.session.query(AccessionNote).filter(
                AccessionNote.accession_id.in_(
                    [j.id for j in accessions])).all()
            # extend results with things not further used
            result.extend(locations)
            result.extend(plants)
            result.extend(plantnotes)
        elif self._choices['based_on'] == 'accessions':
            accessions = self.session.query(Accession).order_by(
                Accession.code).all()
            accessionnotes = self.session.query(AccessionNote).all()

        ## now the taxonomy, based either on all species or on the ones used
        if self._choices['based_on'] == 'taxa':
            species = self.session.query(Species).order_by(
                Species.sp).all()
        else:
            # prepend results with accession data
            result = accessions + accessionnotes + result

            species = self.session.query(Species).filter(
                Species.id.in_([j.species_id for j in accessions])).order_by(
                Species.sp).all()

        ## and all used genera and families
        genera = self.session.query(Genus).filter(
            Genus.id.in_([j.genus_id for j in species])).order_by(
            Genus.genus).all()
        families = self.session.query(Familia).filter(
            Familia.id.in_([j.family_id for j in genera])).order_by(
            Familia.family).all()

        ## prepend the result with the taxonomic information
        result = families + genera + species + result

        ## done, return the result
        return result
    def assign_completions_handler(self, widget, get_completions,
                                   on_select=lambda v: v):
        """
        Dynamically handle completions on a gtk.Entry.

        :param widget: a gtk.Entry instance or widget name

        :param get_completions: the method to call when a list of
          completions is requested, returns a list of completions

        :param on_select: callback for when a value is selected from
          the list of completions
        """
        if not isinstance(widget, gtk.Entry):
            widget = self.view.widgets[widget]
        PROBLEM = hash(widget.get_name())
        def add_completions(text):
            if get_completions is None:
                # get_completions is None usually means that the
                # completions model already has a static list of
                # completions
                return
            # get the completions using [0:key_length] as the start of
            # the string
            def idle_callback(values):
                completion = widget.get_completion()
                utils.clear_model(completion)
                completion_model = gtk.ListStore(object)
                for v in values:
                    completion_model.append([v])
                completion.set_model(completion_model)
            key_length = widget.get_completion().props.minimum_key_length
            values = get_completions(text[:key_length])
            gobject.idle_add(idle_callback, values)

        def on_changed(entry, *args):
            text = entry.get_text()
            comp = entry.get_completion()
            comp_model = comp.get_model()
            found = []
            if comp_model:
                # search the tree model to see if the text in the
                # entry matches one of the completions, if so then
                # emit the match-selected signal, this allows us to
                # type a match in the entry without having to select
                # it from the popup
                def _cmp(row, data):
                    return utils.utf8(row[0]) == text
                found = utils.search_tree_model(comp_model, text, _cmp)
                if len(found) == 1:
                    v = comp.get_model()[found[0]][0]
                    # only auto select if the full string has been entered
                    if text.lower() == utils.utf8(v).lower():
                        comp.emit('match-selected', comp.get_model(), found[0])
                    else:
                        found = None

            if text != '' and not found and PROBLEM not in self.problems:
                self.add_problem(PROBLEM, widget)
                on_select(None)

            key_length = widget.get_completion().props.minimum_key_length
            if (not comp_model and len(text)>key_length) or \
                    len(text) == key_length:
                add_completions(text)

            # if entry is empty select nothing and remove all problem
            if text == '':
                on_select(None)
                self.remove_problem(PROBLEM, widget)

            return True

        def on_match_select(completion, compl_model, treeiter):
            value = compl_model[treeiter][0]
            # temporarily block the changed ID so that this function
            # doesn't get called twice
            widget.handler_block(_changed_sid)
            widget.props.text = utils.utf8(value)
            widget.handler_unblock(_changed_sid)
            self.remove_problem(PROBLEM, widget)
            on_select(value)
            return True # return True or on_changed() will be called with ''

        completion = widget.get_completion()
        check(completion is not None, 'the gtk.Entry %s doesn\'t have a '\
              'completion attached to it' % widget.get_name())

        _changed_sid = self.view.connect(widget, 'changed', on_changed)
        self.view.connect(completion, 'match-selected', on_match_select)