Showing posts with label python. Show all posts
Showing posts with label python. Show all posts

Loading object properties from an external file

Recently I came up with the idea that I will hold the running properties in the configuration file. The idea was to use the Python syntax but keeps it simple as possible.
The second thing is that the config file can be anywhere and I do not want force people to make any Python modules (with those strange __init__.py files). They will simply forget to create.
On the other hand I want to keep those attributes in the class object because then I can use that object in other part of the program. First idea was to simply use execfile()
Here is how I overcome the problem, I create a BaseSettings class with the constructor that takes an path to the settings file:

class BaseSettings(object):
  def __init__(self, settings_file):
    """Constructor of the settings class.

      Args:
        settings_file: The full path to the settings file.
    """

    _required_sections = set([
        'ANGLES', 
        'DIHEDRALS', 
        'PAIRS', 
        'ATOM_PAIRS', 
        'BOND_CONFIG',
        'TOTAL_NUMBER_OF_CROSSLINKS'
        ])
    settings_variables = {}
    copy_globals = globals().copy()
    try:
      execfile(settings_file, copy_globals, settings_variables)
    except SyntaxError as ex:
      print 'There is an error in your config file %s in line %s' % (
          ex.filename, ex.lineno)
      print '%d: %s' % (ex.lineno, ex.text)
      print ex.msg
      sys.exit(2)

    # Checks if some attributes are missing in the settings file.
    missing_sections = _required_sections - set(settings_variables)

    if missing_sections:
      Exception(
          'Invalid settings file, those sections are missing: %s' % (
              ','.join(missing_sections))
    # Loads the variables as it they would be and attributes of the class.
    self.__dict__.update(settings_variables)

and then I use execfile() with the copied globals() and the empty dict settings_variables that works as the container for the locals(). I had to copy globals dict because otherwise I had those attributes in the globals.
Afterwards the variables from the settings file can be found in the settings_variables dictionary. So the only things was to update the __dict__ of the class with those variables.

Composite unique constraint

Composite unique constraint are very common in real database entities. In Django models, those constraints are expressed by the unique_together property of the Meta class.
Lets say that we have an Django model class:
class ModelA(models.Model):
  property1 = models.CharField(max_length=255, null=True)
  property2 = models.IntegerField()

  class Meta(object):
    unique_together = ('property1', 'property2')

It looks fine, now lets say that we want to save something in this model:
m3 = ModelA(property1=None, property2=1)
m3.save()
m4 = ModelA(property1=None, property2=1)
m4.save()

What we could expect is that the second save will fail because of the composite unique constraint. What actually will happen is that there will be two rows in db with property1 set to NULL and property2 set to 1. This is because the SQL standard define that NULL is not a value but the state so in that case the NULL value is not treat as unique accros the rows.  
To solve the issue we have to take care about checking the uniqueness on the Django model level. The save method of the models has to be overwrite. Below is the example how to define abstract class which can be used instead of Django models.Model class.

class Model(models.Model):
  class Meta(object):
    abstract = True

  def _check_uniqueness(self):
    nullable_field_names = set([x.name for x in self._meta._fields() if x.null])

    for unique_together in self._meta.unique_together:
      if set(unique_together).intersection(nullable_field_names):
        values = [(x, getattr(self, x)) for x in unique_together]
        queryset = {}
        for field, value in values:
          if value is None:
            queryset['%s__isnull' % field] = True
          else:
            queryset[field] = value
        exists_query = self.__class__.objects.filter(**queryset)
        if self.pk is not None:
          exists_query = exists_query.exclude(id=self.id)
        if exists_query.exists():
          return unique_together
    return None

    def save(self, *args, **kwargs):
      unique_together = self._check_uniqueness()
      if unique_together is not None:
        raise db.IntegrityError('columns %s are not unique' % ', '.join(unique_together))
      super(Model, self).save(*args, **kwargs)

Remote PDB and Django

Recently I have had to debug some error in Django system. In fact the problem was somewhere inside views and the debug page did not give any important information (as usually) and randomly show different place in .py files where exception was raised. I could not put standard pdb debugger, cause the problem  appeared only on nginx+uwsgi setup. I could not reproduce it on internal django webserver.
How to put debugger in uwsgi environment? Of course we do not have access to terminal in that case but we can use remote debugger. I have found very small and simply debugger rpdb:

http://tamentis.com/projects/rpdb/ 
Simply install it by pip and then put in the code:
 
import rpdb; rpdb.set_trace()
 
By default, rpdb listen on 4444 port so the next step is to connect to it by e.g. nc:
 
$ nc zuzia 4444

[teodor@zuzia production]$ nc zuzia 4444
--Call--
> /home/teodor/project/test/lib/python2.7/site-packages/rpdb/__init__.py(37)shutdown()
-> def shutdown(self):
(Pdb) w
  /home/teodor/project/test/lib/python2.7/site-packages/django/core/management/commands/runserver.py(107)inner_run()
-> run(self.addr, int(self.port), handler, ipv6=self.use_ipv6)
  /home/teodor/project/test/lib/python2.7/site-packages/django/core/servers/basehttp.py(696)run()
-> httpd.serve_forever()
  /usr/lib64/python2.7/SocketServer.py(227)serve_forever()
-> self._handle_request_noblock()
  /usr/lib64/python2.7/SocketServer.py(284)_handle_request_noblock()
-> self.process_request(request, client_address)
  /usr/lib64/python2.7/SocketServer.py(310)process_request()
-> self.finish_request(request, client_address)
  /usr/lib64/python2.7/SocketServer.py(323)finish_request()
-> self.RequestHandlerClass(request, client_address, self)
  /home/teodor/project/test/lib/python2.7/site-packages/django/core/servers/basehttp.py(570)__init__()
-> BaseHTTPRequestHandler.__init__(self, *args, **kwargs)
  /usr/lib64/python2.7/SocketServer.py(639)__init__()
-> self.handle()
  /home/teodor/project/test/lib/python2.7/site-packages/django/core/servers/basehttp.py(615)handle()
-> handler.run(self.server.get_app())
  /home/teodor/project/test/lib/python2.7/site-packages/django/core/servers/basehttp.py(283)run()
-> self.result = application(self.environ, self.start_response)
  /home/teodor/project/test/lib/python2.7/site-packages/django/contrib/staticfiles/handlers.py(68)__call__()
-> return self.application(environ, start_response)
  /home/teodor/project/test/lib/python2.7/site-packages/django/core/handlers/wsgi.py(273)__call__()
-> response = self.get_response(request)
  /home/teodor/project/test/lib/python2.7/site-packages/django/core/handlers/base.py(111)get_response()
-> response = callback(request, *callback_args, **callback_kwargs)
  /media/Crypted/teodor/projects/test/web/views.py(525)wrapper()
-> return panel_view(request, *args, **kw)
  /media/Crypted/teodor/projects/test/web/views.py(540)test()
-> import rpdb; rpdb.set_trace()
  /home/teodor/project/test/lib/python2.7/site-packages/rpdb/__init__.py(62)set_trace()
-> debugger.shutdown()
> /home/teodor/project/test/lib/python2.7/site-packages/rpdb/__init__.py(37)shutdown()
-> def shutdown(self):
(Pdb) 

Suspend plugin for Rhythmbox

Suspend plugin for Rhythmbox music player. This plugin shutdown or suspend your computer after the last song from your playlist or queue. It is very useful when you listening to music at night and you don't remember to shutdown/suspend your computer.

Download

Last version is always available on Google Code:
Google Code downloads

Instalation

  • uncompress files from archive
  • put folder suspend-plugin in .gnome2/rhythmbox/plugins