Search Results: "marcot"

6 July 2012

Marco Silva: C-d on UNIX

[...] read also says how many bytes of the file were returned, so end of file is assumed when a read says "zero bytes are being returned." [...] When a program reads from your terminal, each input line is given to the program by the kernel only when you type its newline (i.e, press RETURN). [...] [...] Now try something different: type some characters and then a *ctl*-d rather than a RETURN: $ cat -u
123
ctl-d123 cat prints the characters out immediately. *ctl*-d says, "immediately send the characters I have typed to the program that is reading from my terminal." The *ctl*-d itself is not sent to the program, unlike a newline. Now type a second ctl-d, with no other chracters: $ cat -u
123
ctl-d123ctl-d$ The shell responds with a prompt, because cat read no characters, decided that meant end of file, and stopped. ctl-d sends whatever you have typed to the program that is reading from the terminal. If you haven't typed anything, the program will therefore read no characters, and that looks like the end of the file. That is why *ctl*-d logs you out --- the shell sees no more input. Of course, *ctl*-d is usually used to signal an end-of-file but it is interesting that is has a more general function.
Brian W. Kernighan, Rob Pike. The UNIX Programming Environment. Prentice-Haskell Software Series, 1984, section 2.1, pages 44-45.

2 February 2012

Marco Silva: Intuitive python

>>> x = ['a', 'b']
>>> x
['a', 'b']
>>> x += 'c'
>>> x
['a', 'b', 'c']
>>> x += ''
>>> x
['a', 'b', 'c']
>>> x += ['']
>>> x
['a', 'b', 'c', '']

Marco Silva: Using Horizontal Sharding in SQLAlchemy to display multiple DBs

My problem was: I had a number of databases generated in different machines and I wanted to query them as if they were one, using the database the data came from as a field while querying and while showing results. The databases are SQLite3 files, generated using SQLAlchemy in a Python program. I solved this by using SQLAlchemy, which was good because I could use the same ORM mapping that the program used. I noticed that the Horizontal Sharding SQLAlchemy extension would fit well the problem, although not perfectly. I had to make some changes in some classes of this extension, and now it works fine. It was possible to filter the data using database as a criteria, but I couldn't get the database information from each line of a query result. I made a simple patch to SQLAlchemy, which wasn't likely to be introduced in the distribution, but worked for me, and sent it to its bug tracker. The change was included in SQLAlchemy in a very different fashion, as expected, but since I'm using the released version from SQLAlchemy, I kept on using my version of the patch. I don't want to do direct changes in SQLAlchemy source code, so I made the change in my program:
class ShardedSessionShardId(ShardedSession):
    def __init__(self, *args, **kwargs):
        super(ShardedSessionShardId, self).__init__(*args, **kwargs)
        self._query_cls = ShardedQueryShardId
class ShardedQueryShardId(ShardedQuery):
    def _execute_and_instances(self, context):
        if self._shard_id is not None:
            result = self.session.connection(
                            mapper=self._mapper_zero(),
                            shard_id=self._shard_id).execute(context.statement, self._params)
            news = list(self.instances(result, context))
            for new in news:
                new.shard_id = self._shard_id
            return iter(news)
        else:
            partial = []
            for shard_id in self.query_chooser(self):
                result = self.session.connection(
                            mapper=self._mapper_zero(),
                            shard_id=shard_id).execute(context.statement, self._params)
                news = list(self.instances(result, context))
                for new in news:
                    new.shard_id = shard_id
                partial = partial + news
            # if some kind of in memory 'sorting'
            # were done, this is where it would happen
            return iter(partial)
create_session = sessionmaker(class_=ShardedSessionShardId)
Another problem is that I had to make each result be included in the query, even if two results from different DBs have the same primary key. I achieved this by changing two classes: WeakInstanceDict, and Mapper. For using the new WeakInstanceDict, I had again to change the ShardedSession variation:
class WeakInstanceDictNoIdentity(WeakInstanceDict):
    def add(self, state):
        # if state.key in self:
        #     if dict.__getitem__(self, state.key) is not state:
        #         raise AssertionError("A conflicting state is already "
        #                             "present in the identity map for key %r"
        #                             % (state.key, ))
        # else:
            dict.__setitem__(self, state.key, state)
            self._manage_incoming_state(state)
class ShardedSessionShardId(ShardedSession):
    def __init__(self, *args, **kwargs):
        super(ShardedSessionShardId, self).__init__(*args, **kwargs)
        self._query_cls = ShardedQueryShardId
        self._identity_cls = WeakInstanceDictNoIdentity
        self.identity_map = self._identity_cls()
To start using the new Mapper, I simply replaced each call to mapper with MapperNoIdentity:
class MapperNoIdentity(Mapper):
    def _instance_processor(self, context, path, adapter,
                                polymorphic_from=None, extension=None,
                                only_load_props=None, refresh_state=None,
                                polymorphic_discriminator=None):
        """Produce a mapper level row processor callable
           which processes rows into mapped instances."""
        pk_cols = self.primary_key
        if polymorphic_from or refresh_state:
            polymorphic_on = None
        else:
            if polymorphic_discriminator is not None:
                polymorphic_on = polymorphic_discriminator
            else:
                polymorphic_on = self.polymorphic_on
            polymorphic_instances = util.PopulateDict(
                                        self._configure_subclass_mapper(
                                                context, path, adapter)
                                        )
        version_id_col = self.version_id_col
        if adapter:
            pk_cols = [adapter.columns[c] for c in pk_cols]
            if polymorphic_on is not None:
                polymorphic_on = adapter.columns[polymorphic_on]
            if version_id_col is not None:
                version_id_col = adapter.columns[version_id_col]
        identity_class = self._identity_class
        def identity_key(row):
            return identity_class, tuple([row[column] for column in pk_cols])
        new_populators = []
        existing_populators = []
        load_path = context.query._current_path + path
        def populate_state(state, dict_, row, isnew, only_load_props):
            if isnew:
                if context.propagate_options:
                    state.load_options = context.propagate_options
                if state.load_options:
                    state.load_path = load_path
            if not new_populators:
                new_populators[:], existing_populators[:] = \
                                    self._populators(context, path, row,
                                                        adapter)
            if isnew:
                populators = new_populators
            else:
                populators = existing_populators
            if only_load_props:
                populators = [p for p in populators
                                if p[0] in only_load_props]
            for key, populator in populators:
                populator(state, dict_, row)
        session_identity_map = context.session.identity_map
        if not extension:
            extension = self.extension
        translate_row = extension.get('translate_row', None)
        create_instance = extension.get('create_instance', None)
        populate_instance = extension.get('populate_instance', None)
        append_result = extension.get('append_result', None)
        populate_existing = context.populate_existing or self.always_refresh
        if self.allow_partial_pks:
            is_not_primary_key = _none_set.issuperset
        else:
            is_not_primary_key = _none_set.issubset
        def _instance(row, result):
            if translate_row:
                ret = translate_row(self, context, row)
                if ret is not EXT_CONTINUE:
                    row = ret
            if polymorphic_on is not None:
                discriminator = row[polymorphic_on]
                if discriminator is not None:
                    _instance = polymorphic_instances[discriminator]
                    if _instance:
                        return _instance(row, result)
            # determine identity key
            if refresh_state:
                identitykey = refresh_state.key
                if identitykey is None:
                    # super-rare condition; a refresh is being called
                    # on a non-instance-key instance; this is meant to only
                    # occur within a flush()
                    identitykey = self._identity_key_from_state(refresh_state)
            else:
                identitykey = identity_key(row)
            # instance = session_identity_map.get(identitykey)
            # if instance is not None:
            #     state = attributes.instance_state(instance)
            #     dict_ = attributes.instance_dict(instance)
            #     isnew = state.runid != context.runid
            #     currentload = not isnew
            #     loaded_instance = False
            #     if not currentload and \
            #             version_id_col is not None and \
            #             context.version_check and \
            #             self._get_state_attr_by_column(
            #                     state,
            #                     dict_,
            #                     self.version_id_col) != \
            #                             row[version_id_col]:
            #         raise orm_exc.ConcurrentModificationError(
            #                 "Instance '%s' version of %s does not match %s"
            #                 % (state_str(state),
            #                     self._get_state_attr_by_column(
            #                                 state, dict_,
            #                                 self.version_id_col),
            #                         row[version_id_col]))
            # elif refresh_state:
            if refresh_state:
                # out of band refresh_state detected (i.e. its not in the
                # session.identity_map) honor it anyway.  this can happen
                # if a _get() occurs within save_obj(), such as
                # when eager_defaults is True.
                state = refresh_state
                instance = state.obj()
                dict_ = attributes.instance_dict(instance)
                isnew = state.runid != context.runid
                currentload = True
                loaded_instance = False
            else:
                # check for non-NULL values in the primary key columns,
                # else no entity is returned for the row
                if is_not_primary_key(identitykey[1]):
                    return None
                isnew = True
                currentload = True
                loaded_instance = True
                if create_instance:
                    instance = create_instance(self,
                                                context,
                                                row, self.class_)
                    if instance is EXT_CONTINUE:
                        instance = self.class_manager.new_instance()
                    else:
                        manager = attributes.manager_of_class(
                                                instance.__class__)
                        # TODO: if manager is None, raise a friendly error
                        # about returning instances of unmapped types
                        manager.setup_instance(instance)
                else:
                    instance = self.class_manager.new_instance()
                dict_ = attributes.instance_dict(instance)
                state = attributes.instance_state(instance)
                state.key = identitykey
                # manually adding instance to session.  for a complete add,
                # session._finalize_loaded() must be called.
                state.session_id = context.session.hash_key
                session_identity_map.add(state)
            if currentload or populate_existing:
                if isnew:
                    state.runid = context.runid
                    context.progress[state] = dict_
                if not populate_instance or \
                        populate_instance(self, context, row, instance,
                            only_load_props=only_load_props,
                            instancekey=identitykey, isnew=isnew) is \
                            EXT_CONTINUE:
                    populate_state(state, dict_, row, isnew, only_load_props)
            else:
                # populate attributes on non-loading instances which have
                # been expired
                # TODO: apply eager loads to un-lazy loaded collections ?
                if state in context.partials or state.unloaded:
                    if state in context.partials:
                        isnew = False
                        (d_, attrs) = context.partials[state]
                    else:
                        isnew = True
                        attrs = state.unloaded
                        # allow query.instances to commit the subset of attrs
                        context.partials[state] = (dict_, attrs)
                    if not populate_instance or \
                            populate_instance(self, context, row, instance,
                                only_load_props=attrs,
                                instancekey=identitykey, isnew=isnew) is \
                                EXT_CONTINUE:
                        populate_state(state, dict_, row, isnew, attrs)
            if loaded_instance:
                state._run_on_load(instance)
            if result is not None and \
                        (not append_result or
                            append_result(self, context, row, instance,
                                    result, instancekey=identitykey,
                                    isnew=isnew)
                                    is EXT_CONTINUE):
                result.append(instance)
            return instance
        return _instance
I had to include some auxiliary definitions to make the rewrites work:
_none_set = frozenset([None])
_runid = 1L
_id_lock = util.threading.Lock()
def _new_runid():
    global _runid
    _id_lock.acquire()
    try:
        _runid += 1
        return _runid
    finally:
        _id_lock.release()
It would be good to be able to set these identity requirements as a parameter. My last problem was selecting more than one database to search. setshard only worked for one, so I created a new field in query, called shards, and checked for it on querychooser:
def query_chooser(query):
    try:
        return query.shards
    except AttributeError:
        pass
    return tcs.keys()
So, when I want to look only in a list of shards, I set this field. I'm aware that this is not a recommended python idiom, but, well, it works fine.

Marco Silva: Problems with popup-menu signal in GTK+

I'm using GTK+ in my paid work, which is being cool because I like this library. It's not the first time I use it for paid work, and I like these opportunities to learn more about it and possibly report bugs. It's not easy to find bugs in such a widely used library, so much of them end up being simple cosmetic mistakes, like this one. Some others are only a question of interpretation, like this other, which even when I submitted a patch, it was not applied. Yesterday I couldn't make popup-menu create a, well, popup menu. It was working with button-press-event, but not with popup-menu. I created a small code sample to illustrate this problem and asked about it in #pygtk@irc.gimp.org --- yes, I'm using Python:
import gtk
import gobject
def menu():
  item = gtk.ImageMenuItem('gtk-add')
  item.show()
  menu = gtk.Menu()
  menu.add(item)
  return menu
def on_view_popup_menu(obj, *data):
  print 'popup-menu'
  menu().popup(None, None, None, 0, 0)
def on_view_button_press_event(obj, *data):
  print 'button-press-event'
  menu().popup(None, None, None, 0, 0)
store = gtk.ListStore(gobject.TYPE_STRING)
store.append(('teste',))
view = gtk.TreeView(store)
view.append_column(gtk.TreeViewColumn('Coluna', gtk.CellRendererText(), text=0))
view.connect('button-press-event', on_view_button_press_event)
view.connect('popup-menu', on_view_popup_menu)
view.show()
window = gtk.Window()
window.add(view)
window.show()
gtk.main()
When I clicked in the window, with any button in this case, 'button-press-event' is printed to stdout and the menu is displayed. When I press the Menu key, or Shift+F10, 'popup-menu' is printed to stdout, but the menu is not displayed. After getting no response in #pygtk, I decided to try #gtk+. Before that, I thought about trying the same problem in C to see if it was not a problem in the bindings, or in how I was using it. The code:
#include <gtk/gtk.h>
GtkMenu *menu()  
  GtkImageMenuItem *image_menu_item =
      GTK_IMAGE_MENU_ITEM(
          gtk_image_menu_item_new_from_stock(GTK_STOCK_ADD, NULL));
  gtk_widget_show(GTK_WIDGET(image_menu_item));
  GtkMenu *menu = GTK_MENU(gtk_menu_new());
  gtk_container_add(GTK_CONTAINER(menu), GTK_WIDGET(image_menu_item));
  return menu;
 
void on_tree_view_popup_menu(GtkWidget *widget, gpointer user_data)  
  printf("popup-menu\n");
  gtk_menu_popup(
      menu(), NULL, NULL, NULL, NULL, 0, gdk_event_get_time(NULL));
 
void
on_tree_view_button_press_event(
  GtkWidget *widget, GdkEventButton *event, gpointer user_data)  
  printf("button-press-event\n");
  gtk_menu_popup(
      menu(), NULL, NULL, NULL, NULL, 0, gdk_event_get_time(NULL));
 
int main(int argc, char **argv)  
  gtk_init(&argc, &argv);
  GtkListStore *list_store = gtk_list_store_new(1, G_TYPE_STRING);
  GtkTreeIter iter;
  gtk_list_store_append(list_store, &iter);
  gtk_list_store_set(list_store, &iter, 0, "teste", -1);
  GtkTreeView *tree_view =
      GTK_TREE_VIEW(
          gtk_tree_view_new_with_model(GTK_TREE_MODEL(list_store)));
  gtk_tree_view_append_column(
      tree_view,
      gtk_tree_view_column_new_with_attributes(
          "Coluna", gtk_cell_renderer_text_new(), "text", 0, NULL));
  g_signal_connect(
      tree_view, "popup-menu", G_CALLBACK(on_tree_view_popup_menu), NULL);
  g_signal_connect(
      tree_view,
      "button-press-event",
      G_CALLBACK(on_tree_view_button_press_event),
      NULL);
  gtk_widget_show(GTK_WIDGET(tree_view));
  GtkWindow *window = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL));
  gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(tree_view));
  gtk_widget_show(GTK_WIDGET(window));
  gtk_main();
 
Wow. The difference between the codes is impressive. I'm not that used to code in GTK+ using C, and I may have missed something here, but the C code is so verbose that I get tired only by looking at it. I'm glad we have other languages, and GTK+ bindings for them. As expected, the behavior was the same, and I asked in #gtk+ and got no answer. Yes, I did read the documentation before asking, and no, I didn't read it carefully enough. Maybe because of coming from Python, I didn't checked very much the type of the callback function for the signals, and didn't notice the point about the return value: "Returns: TRUE if a menu was activated". And that was not where I was looking for the problem, since I thought the return value was usually related to the treatment of the signal by another functions. Anyway, I changed the type of on_tree_view_popup_menu to return gboolean and returned TRUE. It works! I also updated the type of on_tree_view_button_press_event to do the same, just for compliance. In Python, a simple return True would do it. I know I could use the event parameter in on_tree_view_button_press_event, but the point was exactly to run the same code and see if it would work in one case and not in the other, as happened.

Marco Silva: Using XMonad with Netbeans (or other Java apps)

After testing Emacs, Eclipse, KDevelop and CodeBlocks for writing C++ code, I decided to stick with Netbeans. It seems to be the most simple to configure and yet full of features and plugins. I was having one problem with it that when I focused out the window, and then focused on it again, it would not really grab the focus, in the sense that I would not be able to type without first clicking with the mouse. At first I thought the problem was with Netbeans, then with the JRE. I tried using sun-java6-jre, I tried upgrading my openjdk-6-jre, and nothing worked. I searched a little bit more and got to a discussion about this problem in ion3, and that made me think that the problem could be related to the window manager I use, XMonad. After searching a bit about it, I found on the XMonad FAQ some work arounds for problems with Java apps, but they didn't solve my problem. Then, I found the solution on this bug report. I got the darcs version of xmonad and XMonadContrib, included takeTopFocus on logHook, and now it's working!

Marco Silva: ghc -fvia-C and new binutils

I was trying to build the curl hackage package on Debian unstable with ghc 7.0.3, and one of its modules were failing to build. I searched for the error message and found this GHC ticket. As mentioned in the ticket, I had to downgrade binutils to 2.20. The version of binutils in sid is 2.21. Another possibility would be to change curl to avoid using -fvia-C, but I didn't want to modify the package.

Marco Silva: Intuitive python

>>> x = ['a', 'b']
>>> x
['a', 'b']
>>> x += 'c'
>>> x
['a', 'b', 'c']
>>> x += ''
>>> x
['a', 'b', 'c']
>>> x += ['']
>>> x
['a', 'b', 'c', '']

1 July 2011

Marco Silva: Some C++ stuff

I've been playing with C++ lately, and it's an interesting language. Some random thoughts go here. First, in which situation does "... int x; x = 0 ..." is different from "... int x = 0 ... "? The answer on the end of the post. Second, consider this code:
class A  ;
// void f(const A &a)  
// void f(A a)  
void f(A &a)  
int main()  
  f(A());
  // A a;
  // f(a);
 
It doesn't build under g++ or clang. Some say it builds under MSVC. If the definition of f is swapped by any of the commented ones, it works. If the declaration and call to f on function main is swapped by the commented lines, it also works. Third, dynamic dispatch only works with pointers. Consider this code:
class A  
 public:
  virtual void f()  
    printf("A");
   
 ;
class B : public A  
  void f()  
    printf("B");
   
 ;
int main()  
  A a = B();
  a.f();
  A *p = new B();
  p->f();
  delete p;
  B b;
  A *q = &b
  q->f();
 
It prints ABB. Some things to remember. The answer of the first point is: those codes are different if there is a static before them. This can only happen when they are in the body of a function. In this case, the first would assign x to 0 at each call to the function, and the other only at the first call.

29 June 2011

Marco Silva: Using XMonad with Netbeans (or other Java apps)

After testing Emacs, Eclipse, KDevelop and CodeBlocks for writing C++ code, I decided to stick with Netbeans. It seems to be the most simple to configure and yet full of features and plugins. I was having one problem with it that when I focused out the window, and then focused on it again, it would not really grab the focus, in the sense that I would not be able to type without first clicking with the mouse. At first I thought the problem was with Netbeans, then with the JRE. I tried using sun-java6-jre, I tried upgrading my openjdk-6-jre, and nothing worked. I searched a little bit more and got to a discussion about this problem in ion3, and that made me think that the problem could be related to the window manager I use, XMonad. After searching a bit about it, I found on the XMonad FAQ some work arounds for problems with Java apps, but they didn't solve my problem. Then, I found the solution on this bug report. I got the darcs version of xmonad and XMonadContrib, included takeTopFocus on logHook, and now it's working!

27 June 2011

Marco Silva: darcs setpref test substitute in git

git doesn't have a feature as simple and useful as darcs setpref test. To emulate it, I have created a script in .git/hooks/pre-commit. For instance, if the use was darcs setpref test make, the git script goes as:
erase()  
    rm -rf /tmp/workdir$$ /tmp/patch$$
 
handle()  
    erase
    exit 1
 
git new-workdir  git rev-parse --show-toplevel  /tmp/workdir$$
git diff --cached > /tmp/patch$$
cd /tmp/workdir$$
patch -p1 < ../patch$$
make   handle
erase
By the way, I miss darcs revert, and specially darcs unrevert. It's possible to emulate darcs revert -a using git reset --hard, but this comes without darcs unrevert latter. Yes, there is git stash, but it's not the same thing. Also, I could not find a way to have something like darcs revert.

20 May 2011

Marco Silva: Multiline make functions

I needed a way to generate a list of commands in make automatically. I was using $(foreach i,$(list),cmd $i;), that is, a semicollon to intercalate commands. The problem with this approach is that if the first command fails, make would not detect the error. After searching for a while, I found the solution on this link. It's possible to create a newline in make functions using this technique. The code ended up being:
define \n
endef
target:
        $(foreach i,$(list),cmd $i$(\n))

26 April 2011

Marco Silva: ghc -fvia-C and new binutils

I was trying to build the curl hackage package on Debian unstable with ghc 7.0.3, and one of its modules were failing to build. I searched for the error message and found this GHC ticket. As mentioned in the ticket, I had to downgrade binutils to 2.20. The version of binutils in sid is 2.21. Another possibility would be to change curl to avoid using -fvia-C, but I didn't want to modify the package.

10 February 2011

Marco Silva: Using Horizontal Sharding in SQLAlchemy to display multiple DBs

My problem was: I had a number of databases generated in different machines and I wanted to query them as if they were one, using the database the data came from as a field while querying and while showing results. The databases are SQLite3 files, generated using SQLAlchemy in a Python program. I solved this by using SQLAlchemy, which was good because I could use the same ORM mapping that the program used. I noticed that the Horizontal Sharding SQLAlchemy extension would fit well the problem, although not perfectly. I had to make some changes in some classes of this extension, and now it works fine. It was possible to filter the data using database as a criteria, but I couldn't get the database information from each line of a query result. I made a simple patch to SQLAlchemy, which wasn't likely to be introduced in the distribution, but worked for me, and sent it to its bug tracker. The change was included in SQLAlchemy in a very different fashion, as expected, but since I'm using the released version from SQLAlchemy, I kept on using my version of the patch. I don't want to do direct changes in SQLAlchemy source code, so I made the change in my program:
class ShardedSessionShardId(ShardedSession):
    def __init__(self, *args, **kwargs):
        super(ShardedSessionShardId, self).__init__(*args, **kwargs)
        self._query_cls = ShardedQueryShardId
class ShardedQueryShardId(ShardedQuery):
    def _execute_and_instances(self, context):
        if self._shard_id is not None:
            result = self.session.connection(
                            mapper=self._mapper_zero(),
                            shard_id=self._shard_id).execute(context.statement, self._params)
            news = list(self.instances(result, context))
            for new in news:
                new.shard_id = self._shard_id
            return iter(news)
        else:
            partial = []
            for shard_id in self.query_chooser(self):
                result = self.session.connection(
                            mapper=self._mapper_zero(),
                            shard_id=shard_id).execute(context.statement, self._params)
                news = list(self.instances(result, context))
                for new in news:
                    new.shard_id = shard_id
                partial = partial + news
            # if some kind of in memory 'sorting'
            # were done, this is where it would happen
            return iter(partial)
create_session = sessionmaker(class_=ShardedSessionShardId)
Another problem is that I had to make each result be included in the query, even if two results from different DBs have the same primary key. I achieved this by changing two classes: WeakInstanceDict, and Mapper. For using the new WeakInstanceDict, I had again to change the ShardedSession variation:
class WeakInstanceDictNoIdentity(WeakInstanceDict):
    def add(self, state):
        # if state.key in self:
        #     if dict.__getitem__(self, state.key) is not state:
        #         raise AssertionError("A conflicting state is already "
        #                             "present in the identity map for key %r"
        #                             % (state.key, ))
        # else:
            dict.__setitem__(self, state.key, state)
            self._manage_incoming_state(state)
class ShardedSessionShardId(ShardedSession):
    def __init__(self, *args, **kwargs):
        super(ShardedSessionShardId, self).__init__(*args, **kwargs)
        self._query_cls = ShardedQueryShardId
        self._identity_cls = WeakInstanceDictNoIdentity
        self.identity_map = self._identity_cls()
To start using the new Mapper, I simply replaced each call to mapper with MapperNoIdentity:
class MapperNoIdentity(Mapper):
    def _instance_processor(self, context, path, adapter,
                                polymorphic_from=None, extension=None,
                                only_load_props=None, refresh_state=None,
                                polymorphic_discriminator=None):
        """Produce a mapper level row processor callable
           which processes rows into mapped instances."""
        pk_cols = self.primary_key
        if polymorphic_from or refresh_state:
            polymorphic_on = None
        else:
            if polymorphic_discriminator is not None:
                polymorphic_on = polymorphic_discriminator
            else:
                polymorphic_on = self.polymorphic_on
            polymorphic_instances = util.PopulateDict(
                                        self._configure_subclass_mapper(
                                                context, path, adapter)
                                        )
        version_id_col = self.version_id_col
        if adapter:
            pk_cols = [adapter.columns[c] for c in pk_cols]
            if polymorphic_on is not None:
                polymorphic_on = adapter.columns[polymorphic_on]
            if version_id_col is not None:
                version_id_col = adapter.columns[version_id_col]
        identity_class = self._identity_class
        def identity_key(row):
            return identity_class, tuple([row[column] for column in pk_cols])
        new_populators = []
        existing_populators = []
        load_path = context.query._current_path + path
        def populate_state(state, dict_, row, isnew, only_load_props):
            if isnew:
                if context.propagate_options:
                    state.load_options = context.propagate_options
                if state.load_options:
                    state.load_path = load_path
            if not new_populators:
                new_populators[:], existing_populators[:] = \
                                    self._populators(context, path, row,
                                                        adapter)
            if isnew:
                populators = new_populators
            else:
                populators = existing_populators
            if only_load_props:
                populators = [p for p in populators
                                if p[0] in only_load_props]
            for key, populator in populators:
                populator(state, dict_, row)
        session_identity_map = context.session.identity_map
        if not extension:
            extension = self.extension
        translate_row = extension.get('translate_row', None)
        create_instance = extension.get('create_instance', None)
        populate_instance = extension.get('populate_instance', None)
        append_result = extension.get('append_result', None)
        populate_existing = context.populate_existing or self.always_refresh
        if self.allow_partial_pks:
            is_not_primary_key = _none_set.issuperset
        else:
            is_not_primary_key = _none_set.issubset
        def _instance(row, result):
            if translate_row:
                ret = translate_row(self, context, row)
                if ret is not EXT_CONTINUE:
                    row = ret
            if polymorphic_on is not None:
                discriminator = row[polymorphic_on]
                if discriminator is not None:
                    _instance = polymorphic_instances[discriminator]
                    if _instance:
                        return _instance(row, result)
            # determine identity key
            if refresh_state:
                identitykey = refresh_state.key
                if identitykey is None:
                    # super-rare condition; a refresh is being called
                    # on a non-instance-key instance; this is meant to only
                    # occur within a flush()
                    identitykey = self._identity_key_from_state(refresh_state)
            else:
                identitykey = identity_key(row)
            # instance = session_identity_map.get(identitykey)
            # if instance is not None:
            #     state = attributes.instance_state(instance)
            #     dict_ = attributes.instance_dict(instance)
            #     isnew = state.runid != context.runid
            #     currentload = not isnew
            #     loaded_instance = False
            #     if not currentload and \
            #             version_id_col is not None and \
            #             context.version_check and \
            #             self._get_state_attr_by_column(
            #                     state,
            #                     dict_,
            #                     self.version_id_col) != \
            #                             row[version_id_col]:
            #         raise orm_exc.ConcurrentModificationError(
            #                 "Instance '%s' version of %s does not match %s"
            #                 % (state_str(state),
            #                     self._get_state_attr_by_column(
            #                                 state, dict_,
            #                                 self.version_id_col),
            #                         row[version_id_col]))
            # elif refresh_state:
            if refresh_state:
                # out of band refresh_state detected (i.e. its not in the
                # session.identity_map) honor it anyway.  this can happen
                # if a _get() occurs within save_obj(), such as
                # when eager_defaults is True.
                state = refresh_state
                instance = state.obj()
                dict_ = attributes.instance_dict(instance)
                isnew = state.runid != context.runid
                currentload = True
                loaded_instance = False
            else:
                # check for non-NULL values in the primary key columns,
                # else no entity is returned for the row
                if is_not_primary_key(identitykey[1]):
                    return None
                isnew = True
                currentload = True
                loaded_instance = True
                if create_instance:
                    instance = create_instance(self,
                                                context,
                                                row, self.class_)
                    if instance is EXT_CONTINUE:
                        instance = self.class_manager.new_instance()
                    else:
                        manager = attributes.manager_of_class(
                                                instance.__class__)
                        # TODO: if manager is None, raise a friendly error
                        # about returning instances of unmapped types
                        manager.setup_instance(instance)
                else:
                    instance = self.class_manager.new_instance()
                dict_ = attributes.instance_dict(instance)
                state = attributes.instance_state(instance)
                state.key = identitykey
                # manually adding instance to session.  for a complete add,
                # session._finalize_loaded() must be called.
                state.session_id = context.session.hash_key
                session_identity_map.add(state)
            if currentload or populate_existing:
                if isnew:
                    state.runid = context.runid
                    context.progress[state] = dict_
                if not populate_instance or \
                        populate_instance(self, context, row, instance,
                            only_load_props=only_load_props,
                            instancekey=identitykey, isnew=isnew) is \
                            EXT_CONTINUE:
                    populate_state(state, dict_, row, isnew, only_load_props)
            else:
                # populate attributes on non-loading instances which have
                # been expired
                # TODO: apply eager loads to un-lazy loaded collections ?
                if state in context.partials or state.unloaded:
                    if state in context.partials:
                        isnew = False
                        (d_, attrs) = context.partials[state]
                    else:
                        isnew = True
                        attrs = state.unloaded
                        # allow query.instances to commit the subset of attrs
                        context.partials[state] = (dict_, attrs)
                    if not populate_instance or \
                            populate_instance(self, context, row, instance,
                                only_load_props=attrs,
                                instancekey=identitykey, isnew=isnew) is \
                                EXT_CONTINUE:
                        populate_state(state, dict_, row, isnew, attrs)
            if loaded_instance:
                state._run_on_load(instance)
            if result is not None and \
                        (not append_result or
                            append_result(self, context, row, instance,
                                    result, instancekey=identitykey,
                                    isnew=isnew)
                                    is EXT_CONTINUE):
                result.append(instance)
            return instance
        return _instance
I had to include some auxiliary definitions to make the rewrites work:
_none_set = frozenset([None])
_runid = 1L
_id_lock = util.threading.Lock()
def _new_runid():
    global _runid
    _id_lock.acquire()
    try:
        _runid += 1
        return _runid
    finally:
        _id_lock.release()
It would be good to be able to set these identity requirements as a parameter. My last problem was selecting more than one database to search. setshard only worked for one, so I created a new field in query, called shards, and checked for it on querychooser:
def query_chooser(query):
    try:
        return query.shards
    except AttributeError:
        pass
    return tcs.keys()
So, when I want to look only in a list of shards, I set this field. I'm aware that this is not a recommended python idiom, but, well, it works fine.

1 February 2011

Marco Silva: A Super Vaca for DebConf11

In Portuguese we use the word vaquinha, which means little cow, to refer to a group of people contributing money for some common goal. In a meeting of the organization of the DebConf12 BID of Belo Horizonte, I, Rafael, R gis and Samuel decided to create a vaquinha to become a sponsor of DebConf11. With the help of Amazing Val ssio, we created a website and we are collecting donations. The idea is simple: people donate and their name is shown on the website. If they give more than R$50,00, they also receive an exclusive T-shirt. We mixed the idea of vaquinha with the Super Cow Powers from APT. The site is only in Portuguese, since our main focus is to ask for donations from brazilians, but nothing stops foreigns from donating. Our plan is to become Bronze Sponsors, but if we can't all that money, we'll just give to DebConf11 whatever we have. I hope you like the idea, and maybe have a similar initative in your country.

10 December 2010

Marco Silva: Problems with popup-menu signal in GTK+

I'm using GTK+ in my paid work, which is being cool because I like this library. It's not the first time I use it for paid work, and I like these opportunities to learn more about it and possibly report bugs. It's not easy to find bugs in such a widely used library, so much of them end up being simple cosmetic mistakes, like this one. Some others are only a question of interpretation, like this other, which even when I submitted a patch, it was not applied. Yesterday I couldn't make popup-menu create a, well, popup menu. It was working with button-press-event, but not with popup-menu. I created a small code sample to illustrate this problem and asked about it in #pygtk@irc.gimp.org --- yes, I'm using Python:
import gtk
import gobject
def menu():
  item = gtk.ImageMenuItem('gtk-add')
  item.show()
  menu = gtk.Menu()
  menu.add(item)
  return menu
def on_view_popup_menu(obj, *data):
  print 'popup-menu'
  menu().popup(None, None, None, 0, 0)
def on_view_button_press_event(obj, *data):
  print 'button-press-event'
  menu().popup(None, None, None, 0, 0)
store = gtk.ListStore(gobject.TYPE_STRING)
store.append(('teste',))
view = gtk.TreeView(store)
view.append_column(gtk.TreeViewColumn('Coluna', gtk.CellRendererText(), text=0))
view.connect('button-press-event', on_view_button_press_event)
view.connect('popup-menu', on_view_popup_menu)
view.show()
window = gtk.Window()
window.add(view)
window.show()
gtk.main()
When I clicked in the window, with any button in this case, 'button-press-event' is printed to stdout and the menu is displayed. When I press the Menu key, or Shift+F10, 'popup-menu' is printed to stdout, but the menu is not displayed. After getting no response in #pygtk, I decided to try #gtk+. Before that, I thought about trying the same problem in C to see if it was not a problem in the bindings, or in how I was using it. The code:
#include <gtk/gtk.h>
GtkMenu *menu()  
  GtkImageMenuItem *image_menu_item =
      GTK_IMAGE_MENU_ITEM(
          gtk_image_menu_item_new_from_stock(GTK_STOCK_ADD, NULL));
  gtk_widget_show(GTK_WIDGET(image_menu_item));
  GtkMenu *menu = GTK_MENU(gtk_menu_new());
  gtk_container_add(GTK_CONTAINER(menu), GTK_WIDGET(image_menu_item));
  return menu;
 
void on_tree_view_popup_menu(GtkWidget *widget, gpointer user_data)  
  printf("popup-menu\n");
  gtk_menu_popup(
      menu(), NULL, NULL, NULL, NULL, 0, gdk_event_get_time(NULL));
 
void
on_tree_view_button_press_event(
  GtkWidget *widget, GdkEventButton *event, gpointer user_data)  
  printf("button-press-event\n");
  gtk_menu_popup(
      menu(), NULL, NULL, NULL, NULL, 0, gdk_event_get_time(NULL));
 
int main(int argc, char **argv)  
  gtk_init(&argc, &argv);
  GtkListStore *list_store = gtk_list_store_new(1, G_TYPE_STRING);
  GtkTreeIter iter;
  gtk_list_store_append(list_store, &iter);
  gtk_list_store_set(list_store, &iter, 0, "teste", -1);
  GtkTreeView *tree_view =
      GTK_TREE_VIEW(
          gtk_tree_view_new_with_model(GTK_TREE_MODEL(list_store)));
  gtk_tree_view_append_column(
      tree_view,
      gtk_tree_view_column_new_with_attributes(
          "Coluna", gtk_cell_renderer_text_new(), "text", 0, NULL));
  g_signal_connect(
      tree_view, "popup-menu", G_CALLBACK(on_tree_view_popup_menu), NULL);
  g_signal_connect(
      tree_view,
      "button-press-event",
      G_CALLBACK(on_tree_view_button_press_event),
      NULL);
  gtk_widget_show(GTK_WIDGET(tree_view));
  GtkWindow *window = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL));
  gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(tree_view));
  gtk_widget_show(GTK_WIDGET(window));
  gtk_main();
 
Wow. The difference between the codes is impressive. I'm not that used to code in GTK+ using C, and I may have missed something here, but the C code is so verbose that I get tired only by looking at it. I'm glad we have other languages, and GTK+ bindings for them. As expected, the behavior was the same, and I asked in #gtk+ and got no answer. Yes, I did read the documentation before asking, and no, I didn't read it carefully enough. Maybe because of coming from Python, I didn't checked very much the type of the callback function for the signals, and didn't notice the point about the return value: "Returns: TRUE if a menu was activated". And that was not where I was looking for the problem, since I thought the return value was usually related to the treatment of the signal by another functions. Anyway, I changed the type of on_tree_view_popup_menu to return gboolean and returned TRUE. It works! I also updated the type of on_tree_view_button_press_event to do the same, just for compliance. In Python, a simple return True would do it. I know I could use the event parameter in on_tree_view_button_press_event, but the point was exactly to run the same code and see if it would work in one case and not in the other, as happened.

10 November 2010

Marco Silva: Bringing icons back to buttons and menus in GTK+

For some GTK+ themes, icons are not shown in buttons and in menus. They can be made visible again editing some gconf keys, possibly with gconf-editor. The keys to be changed are /desktop/gnome/interface/buttons_have_icons for buttons and /desktop/gnome/interface/menus_have_icons for menus.

28 October 2010

Marco Silva: An utility for sshpass

I just discovered sshpass and saw some comments of people complaining that there's no good use case that justifies it. Well, I have a use case. That's in fact what made me search about the theme and found it. I created a user on a machine and I can't remember which password I used, but I know it's probably one of a small list I can think of. The list is composed of variations of the same string, in a way that I could generate with a program. It would take me time to try all the passwords by hand, so using sshpass make things much easier:
$ generate-password > pass-list
$ for i in  cat pass-list ; do sshpass -p $i ssh host; done

20 September 2010

Marco Silva: Handling spam with SpamAssassin + Bogofilter + Procmail + Sup

This is mostly inspired on this article. The main difference is that I talk about sup instead of mutt, and use SpamAssassin together with bogofilter. Having all these utilities installed and the sources for sup configured, you only need to touch procmail and sup configuration files. My ~/.procmailrc contains a lot of comments, but what it does is basicly the following: If the message is smaller than 250 KiB, it calls SpamAssassin with it. This will create the headers X-Spam-Level and X-Spam-Status in this message. Only messages smaller than 250KiB are considered because most spam isn't bigger than that, and considering big messages would overload SpamAssassin. Then, if SpamAssassin consider this message as spam, tell bogofilter about it. Next, call bogofilter, which will add the X-Bogosity header to the message. Now we have to configure sup. We need to tell it to update bogofilter when we manually mark a message as spam. For this we can use ~/.sup/hooks/mark-as-spam.rb. We must consider two cases: the case where bogofilter thought it was not spam, and the case where bogofilter was not sure about its status. In the first case, we must tell it to forget that the message was not spam and to register it as spam now. In the second, just register it as spam. Also, we don't want spam on inbox. So we can edit ~/.sup/hooks/before-add-message.rb to look for the headers generated by SpamAssassin and Bogofilter and remove the :inbox label. It's important to mark unsure messages with a label so that we don't forget to mark it as spam if it is, and as not spam if it's not. So we need a way to mark messages as not spam. I included a new keybinding in ~/.sup/hooks/startup.rb. Unfortunatelly, I don't know how to include a new keybinding in sup without repeating all the keybindings for the mode I'm dealing with, so that's how I've made it. The command removes the :unsure label and mark it as non-spam. It also sets the undo command, unregistering the message in bogofilter. The case where the message was previously marked as spam, and not unsure, is also handled. I'm sure there's a lot of room for improvement, specially in the Ruby part, but it seems to be working.

8 September 2010

Marco Silva: New version of darcs-monitor

There was a feature missing in darcs-monitor which I wanted: to send the e-mail to multiple recipients when a new patch arrives. I tried using:
apply posthook darcs-monitor --charset=UTF-8 email addr1@example.com,addr2@example.com
But it didn't worked. I also tried "addr1@example.com, addr2@example.com", but it also didn't worked. So I included this feature in darcs-monitor and released a new version. I also updated my e-mail address and darcs repository address. While I was working at the debian package, I noticed a bug in 0.3.8-1, and made a upload of 0.3.8-2 to fix it. I also uploaded the new 0.4.0 to experimental. I'm another one using flattr now. I've created my blog as a thing: Flattr this I also created a thing for darcs-monitor: Flattr this

25 August 2010

Marco Silva: Change of blog server

I'm now using ikiwiki with darcs in my own server and saying goodbye to wordpress.com. I tried to install wordpress before trying ikiwiki, but it was just eating all the memory of the server. And after using ikiwiki, I thanked wordpress for misbehaving, because ikiwiki is so much better. It's everything I wanted, but I didn't knew I wanted until I tried it. Just like sup. My homepage, which used to be my page on the Debian wiki is not being hosted here too, and it's great to have it so nicely integrated with the blog. I also thought about trying gitit, since it's written in Haskell, but it doesn't seem to support blog easily. And now I'm so happy with ikiwiki that I doubt I'll change.

Next.