subscribe to this blog

Logilab.org - en

News from Logilab and our Free Software projects, as well as on topics dear to our hearts (Python, Debian, Linux, the semantic web, scientific computing...)

Generating a user interface from a Yams model

2012/01/09 by Nicolas Chauvat

Yams is a pythonic way to describe an entity-relationship model. It is used at the core of the CubicWeb semantic web framework in order to automate lots of things, including the generation and validation of forms. Although we have been using the MVC design pattern to write user interfaces with Qt and Gtk before we started CubicWeb, we never got to reuse Yams. I am on my way to fix this.

Here is the simplest possible example that generates a user interface (using dialog and python-dialog) to input data described by a Yams data model.

First, let's write a function that builds the data model:

def mk_datamodel():
    from yams.buildobjs import EntityType, RelationDefinition, Int, String
    from yams.reader import build_schema_from_namespace

    class Question(EntityType):
        number = Int()
        text = String()

    class Form(EntityType):
        title = String()

    class in_form(RelationDefinition):
        subject = 'Question'
        object = 'Form'
        cardinality = '*1'

    return build_schema_from_namespace(vars().items())

Here is what you get using graphviz or xdot to display the schema of that data model with:

import os
from yams import schema2dot

datamodel = mk_datamodel()
schema2dot.schema2dot(schema, '/tmp/toto.dot')
os.system('xdot /tmp/toto.dot')
http://www.logilab.org/file/87002?vid=download

To make a step in the direction of genericity, let's add a class that abstracts the dialog API:

class InterfaceDialog:
    """Dialog-based Interface"""
    def __init__(self, dlg):
        self.dlg = dlg

    def input_list(self, invite, options) :
        assert len(options) != 0, str(invite)
        choice = self.dlg.radiolist(invite, list=options, selected=1)
        if choice is not None:
            return choice.lower()
        else:
            raise Exception('operation cancelled')

    def input_string(self, invite, default):
        return self.dlg.inputbox(invite, init=default).decode(sys.stdin.encoding)

And now let's put everything together:

datamodel = mk_datamodel()

import dialog
ui = InterfaceDialog(dialog.Dialog())
ui.dlg.setBackgroundTitle('Dialog Interface with Yams')

objs = []
for entitydef in datamodel.entities():
    if entitydef.final:
        continue
    obj = {}
    for attr in entitydef.attribute_definitions():
        if attr[1].type in ('String','Int'):
            obj[str(attr[0])] = ui.input_string('%s.%s' % (entitydef,attr[0]), '')
    try:
        entitydef.check(obj)
    except Exception, exc:
        ui.dlg.scrollbox(str(exc))

print objs
http://www.logilab.org/file/87001?vid=download

The result is a program that will prompt the user for the title of a form and the text/number of a question, then enforce the type constraints and display the inconsistencies.

The above is very simple and does very little, but if you read the documentation of Yams and if you think about generating the UI with Gtk or Qt instead of dialog, or if you have used the form mechanism of CubicWeb, you'll understand that this proof of concept opens a door to a lot of possibilities.

I will come back to this topic in a later article and give an example of integrating the above with pigg, a simple MVC library for Gtk, to make the programming of user-interfaces even more declarative and bug-free.


Interesting things seen at the Afpy Computer Camp

2011/11/28 by Pierre-Yves David

This summer I spent three days in Burgundy at the Afpy Computer Camps. This yearly meeting gathered French speaking python developers for talking and coding. The main points of this 2011 edition were:

http://www.afpy.org/_public/images/logo_afpy.png

The new IPython 0.11 was shown by Olivier Grisel. This new version contains lots of impressive feature like inline figures, asynchronous execution, exportable sessions, and a web-browser based client. IPython was also presented by its main author Fernando Perez during his keynote talk at EuroSciPy. Since then Logilab got involved with IPython. We contributed to the Debian packaging of iPython dependencies and we joined the discussion about Restructured Text formatting for note book.

http://ipython.org/ipython-doc/rel-0.11/_static/logo.png

Tarek Ziade bootstrapped his new Red Barrel project and small framework to build modern webservices with multiple back-end including the new socket.io protocol.

Alexis Métaireau and Feth Arezki discovered their common interest into account tracking application. The discussion's result is a first release of I hate money a few months later.

For my part, I spent most of my time working with Boris Feld on the Python Testing Infrastructure , a continuous integration tool to test python distributions available at PyPI.

http://master.pyti.org/data/pyti.ico.png

This yearly Afpy Computer Camps is an event intended for python developers but the Afpy also organize events for non python developer. The next one is tonight in Paris at La cantine : Vous reprendrez bien un peu de python ?. See you tonight ?


Python in Finance (and Derivative Analytics)

2011/10/25 by Damien Garaud

The Logilab team attended (and co-organized) EuroScipy 2011, at the end of August in Paris.

We saw some interesting posters and a presentation dealing with Python in finance and derivative analytics [1].

In order to debunk the idea that "all computation libraries dedicated to financial applications must be written in C/C++ or some other compiled programming language", I would like to introduce a more Pythonic way.

You may know that financial applications such as risk management have in most cases high computational needs. For instance, it can be necessary to quickly perform a large number of Monte Carlo simulations to evaluate an American option in a few seconds.

The Python community provides several reliable and efficient libraries and packages dedicated to numerical computations:

http://numpy.scipy.org/_static/numpy_logo.pnghttps://scikits.appspot.com/static/images/scipyshiny_small.png
  • the well-known SciPy and NumPy libraries. They provide a complete set of tools to work with matrix, linear algebra operations, singular values decompositions, multi-variate regression models, ...
  • scikits is a set of add-on toolkits for SciPy. For instance there are statistical models in statsmodels packages, a toolkit dedicated to timeseries manipulation and another one dedicated to numerical optimization;
  • pandas is a recent Python package which provides "fast, flexible, and expressive data structures designed to make working with relational or labeled data both easy and intuitive.". pandas uses Cython to improve its performance. Moreover, pandas has been used extensively in production in financial applications;
http://docs.cython.org/_static/cython-logo-light.png
  • Cython is a way to write C extensions for the Python language. Since you write Cython code in the same way as you write Python code, it's easy to use it. Is it fast? Yes ! I compared a simple example from Cython's official documentation with a full Python code -- a piece of code which computes the first kth prime numbers. The Cython code is almost thirty times faster than the full-Python code (non-official). Furthermore, you can use NumPy in Cython code !

I believe that thanks to several useful tools and libraries, Python can be used in numerical computation, even in Finance (both research and production). It is easy-to-maintain without sacrificing performances.

Note that you can find some other references on Visixion webpages:


Rss feeds aggregator based on Scikits.learn and CubicWeb

2011/10/17 by Vincent Michel

During Euroscipy, the Logilab Team presented an original approach for querying news using semantic information: "Rss feeds aggregator based on Scikits.learn and CubicWeb" by Vincent Michel This work is based on two major pieces of software:

http://www.cubicweb.org/data/index-cubicweb.png
  • CubicWeb, the pythonic semantic web framework, is used to store and query Dbpedia information. CubicWeb is able to reconstruct links from rdf/nt files, and can easily execute complex queries in a database with more than 8 millions entities and 75 millions links when using a PostgreSQL backend.
http://scipy-lectures.github.com/_images/scikit-learn-logo.png
  • Scikit.learn is a cutting-edge python toolbox for machine learning. It provides algorithms that are simple and easy to use.
http://www.pfeifermachinery.com/img/rss.png

Based on these tools, we built a pure Python application to query the news:

  • Named Entities are extracted from RSS articles of a few mainstream English newspapers (New York Times, Reuteurs, BBC News, etc.), for each group of words in an article, we check if a Dbpedia entry has the same label. If so, we create a semantic link between the article and the Dbpedia entry.
  • An occurrence matrix of "RSS Articles" times "Named Entities" is constructed and may be used against several machine learning algorithms (MeanShift algorithm, Hierachical Clustering) in order to provide original and informative views of recent events.
http://wiki.dbpedia.org/images/dbpedia_logo.png

Moreover, queries may be used jointly with semantic information from Dbpedia:

  • All musical artists in the news:

    DISTINCT Any E, R WHERE E appears_in_rss R, E has_type T, T label "musical artist"
    
  • All living office holder persons in the news:

    DISTINCT Any E WHERE E appears_in_rss R, E has_type T, T label "office holder", E has_subject C, C label "Living people"
    
  • All news that talk about Barack Obama and any scientist:

    DISTINCT Any R WHERE E1 label "Barack Obama", E1 appears_in_rss R, E2 appears_in_rss R, E2 has_type T, T label "scientist"
    
  • All news that talk about a drug:

    Any X, R WHERE X appears_in_rss R, X has_type T, T label "drug"
    

Such a tool may be used for informetrics and news analysis. Feel free to download the complete slides of the presentation.


Helping pylint to understand things it doesn't

2011/10/10 by Sylvain Thenault

The latest release of logilab-astng (0.23), the underlying source code representation library used by PyLint, provides a new API that may change pylint users' life in the near future...

It aims to allow registration of functions that will be called after a module has been parsed. While this sounds dumb, it gives a chance to fix/enhance the understanding PyLint has about your code.

I see this as a major step towards greatly enhanced code analysis, improving the situation where PyLint users know that when running it against code using their favorite framework (who said CubicWeb? :p ), they should expect a bunch of false positives because of black magic in the ORM or in decorators or whatever else. There are also places in the Python standard library where dynamic code can cause false positives in PyLint.

The problem

Let's take a simple example, and see how we can improve things using the new API. The following code:

import hashlib

def hexmd5(value):
    """"return md5 checksum hexadecimal digest of the given value"""
    return hashlib.md5(value).hexdigest()

def hexsha1(value):
    """"return sha1 checksum hexadecimal digest of the given value"""
    return hashlib.sha1(value).hexdigest()

gives the following output when analyzed through pylint:

[syt@somewhere ~]$ pylint -E example.py
No config file found, using default configuration
************* Module smarter_astng
E:  5,11:hexmd5: Module 'hashlib' has no 'md5' member
E:  9,11:hexsha1: Module 'hashlib' has no 'sha1' member

However:

[syt@somewhere ~]$ python
Python 2.7.1+ (r271:86832, Apr 11 2011, 18:13:53)
[GCC 4.5.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import smarter_astng
>>> smarter_astng.hexmd5('hop')
'5f67b2845b51a17a7751f0d7fd460e70'
>>> smarter_astng.hexsha1('hop')
'cffb6b20e0eef296772f6c1457cdde0049bdfb56'

The code runs fine... Why does pylint bother me then? If we take a look at the hashlib module, we see that there are no sha1 or md5 defined in there. They are defined dynamically according to Openssl library availability in order to use the fastest available implementation, using code like:

for __func_name in __always_supported:
    # try them all, some may not work due to the OpenSSL
    # version not supporting that algorithm.
    try:
        globals()[__func_name] = __get_hash(__func_name)
    except ValueError:
        import logging
        logging.exception('code for hash %s was not found.', __func_name)

Honestly I don't blame PyLint for not understanding this kind of magic. The situation on this particular case could be improved, but that's some tedious work, and there will always be "similar but different" case that won't be understood.

The solution

The good news is that thanks to the new astng callback, I can help it be smarter! See the code below:

from logilab.astng import MANAGER, scoped_nodes

def hashlib_transform(module):
    if module.name == 'hashlib':
        for hashfunc in ('sha1', 'md5'):
            module.locals[hashfunc] = [scoped_nodes.Class(hashfunc, None)]

def register(linter):
    """called when loaded by pylint --load-plugins, register our tranformation
    function here
    """
    MANAGER.register_transformer(hashlib_transform)

What's in there?

  • A function that will be called with each astng module built during a pylint execution, i.e. not only the one that you analyses, but also those accessed for type inference.
  • This transformation function is fairly simple: if the module is the 'hashlib' module, it will insert into its locals dictionary a fake class node for each desired name.
  • It is registered using the register_transformer method of astng's MANAGER (the central access point to built syntax tree). This is done in the pylint plugin API register callback function (called when module is imported using 'pylint --load-plugins'.

Now let's try it! Suppose I stored the above code in a 'astng_hashlib.py' module in my PYTHONPATH, I can now run pylint with the plugin activated:

[syt@somewhere ~]$ pylint -E --load-plugins astng_hashlib example.py
No config file found, using default configuration
************* Module smarter_astng
E:  5,11:hexmd5: Instance of 'md5' has no 'hexdigest' member
E:  9,11:hexsha1: Instance of 'sha1' has no 'hexdigest' member

Huum. We have now a different error :( Pylint grasp there are some md5 and sha1 classes but it complains they don't have a hexdigest method. Indeed, we didn't give a clue about that.

We could continue on and on to give it a full representation of hashlib public API using the astng nodes API. But that would be painful, trust me. Or we could do something clever using some higher level astng API:

from logilab.astng import MANAGER
from logilab.astng.builder import ASTNGBuilder

def hashlib_transform(module):
    if module.name == 'hashlib':
    fake = ASTNGBuilder(MANAGER).string_build('''

class md5(object):
  def __init__(self, value): pass
  def hexdigest(self):
    return u''

class sha1(object):
  def __init__(self, value): pass
  def hexdigest(self):
    return u''

''')
    for hashfunc in ('sha1', 'md5'):
        module.locals[hashfunc] = fake.locals[hashfunc]

def register(linter):
    """called when loaded by pylint --load-plugins, register our tranformation
    function here
    """
    MANAGER.register_transformer(hashlib_transform)

The idea is to write a fake python implementation only documenting the prototype of the desired class, and to get an astng from it, using the string_build method of the astng builder. This method will return a Module node containing the astng for the given string. It's then easy to replace or insert additional information into the original module, as you can see in the above example.

Now if I run pylint using the updated plugin:

[syt@somewhere ~]$ pylint -E --load-plugins astng_hashlib example.py
No config file found, using default configuration

No error anymore, great!

What's next?

This fairly simple change could quickly provide great enhancements. We should probably improve the astng manipulation API now that it's exposed like that. But we can also easily imagine a code base of such pylint plugins maintained by each community around a python library or framework. One could then use a plugins stack matching stuff used by its software, and have a greatly enhanced experience of using pylint.

For a start, it would be great if pylint could be shipped with a plugin that explains all the magic found in the standard library, wouldn't it? Left as an exercice to the reader!


Text mode makes it into hgview 1.4.0

2011/10/06 by Alain Leufroy

Here is at last the release of the version 1.4.0 of hgview.

http://www.logilab.org/image/77974?vid=download

Small description

Besides the classic bugfixes this release introduces a new text based user interface thanks to the urwid library.

Running hgview in a shell, in a terminal, over a ssh session is now possible! If you are trying not to use X (or use it less), have a geek mouse-killer window manager such as wmii/dwm/ion/awesome/... this is for you!

This TUI (Text User Interface!) adopts the principal features of the Qt4 based GUI. Although only the main view has been implemented for now.

In a nutshell, this interface includes the following features :

  • display the revision graph (with working directory as a node, and basic support for the mq extension),
  • display the files affected by a selected changeset (with basic support for the bfiles extension)
  • display diffs (with syntax highlighting thanks to pygments),
  • automatically refresh the displayed revision graph when the repository is being modified (requires pyinotify),
  • easy key-based navigation in revisions' history of a repo (same as the GUI),
  • a command system for special actions (see help)

Installation

There are packages for debian and ubuntu in the logilab's debian repository.

Note:you have to install the hgview-curses package to get the text based interface.

Or you can simply clone our Mercurial repository:

hg clone http://hg.logilab.org/hgview

(more on the hgview home page)

Running the text based interface

A new --interface option is now available to choose the interface:

hgview --interface curses

Or you can fix it in the [hgview] section of your ~/.hgrc:

[hgview]
interface = curses # or qt or raw

Then run:

hgview

What's next

We'll be working on including other features from the Qt4 interface and making it fully configurable.

We'll also work on bugfixes and new features, so stay tuned! And feel free to file bugs and feature requests.


Drawing UML diagrams with Python

2011/09/26 by Nicolas Chauvat
http://www.umlgraph.org/doc/seq-eg.gif?vid=download

It started with a desire to draw diagrams of hierarchical systems with Python. Since this is similar to what we do in CubicWeb with schemas of the data model, I read the code and realized we had that graph submodule in the logilab.common library. This module uses dot from graphviz as a backend to draw the diagrams.

Reading about UML diagrams drawn with GraphViz, I learned about UMLGraph, that uses GNU Pic to draw sequence diagrams. Pic is a language based on groff and the pic2plot tool is part of plotutils (apt-get install plotutils). Here is a tutorial. I have found some Python code wrapping pic2plot available as plugin to wikipad. It is worth noticing that TeX seems to have a nice package for UML sequence diagrams called pgf-umlsd.

Since nowadays everything is moving into the web browser, I looked for a javascript library that does what graphviz does and I found canviz which looks nice.

If (only) I had time, I would extend pyreverse to draw sequence diagrams and not only class diagrams...


EuroSciPy'11 - Annual European Conference for Scientists using Python.

2011/08/24 by Alain Leufroy
http://www.logilab.org/image/9852?vid=download

The EuroScipy2011 conference will be held in Paris at the Ecole Normale Supérieure from August 25th to 28th and is co-organized and sponsored by INRIA, Logilab and other companies.

The conference is dedicated to cross-disciplinary gathering focused on the use and development of the Python language in scientific research.

August 25th and 26th are dedicated to tutorial tracks -- basic and advanced tutorials. August 27th and 28th are dedicated to talks, posters and demos sessions.

Damien Garaud, Vincent Michel and Alain Leufroy (and others) from Logilab will be there. We will talk about a RSS feeds aggregator based on Scikits.learn and CubicWeb and we have a poster about LibAster (a python library for thermomechanical simulation based on Code_Aster).


Pylint 0.24 / logilab-astng 0.22

2011/07/21 by Sylvain Thenault

Hi there!

I'm pleased to announce new releases of pylint and its underlying library logilab-astng. See http://www.logilab.org/project/pylint/0.24.0 and http://www.logilab.org/project/logilab-astng/0.22.0 for more info.

Those releases include mostly fixes and a few enhancements. Python 2.6 relative / absolute imports should now work fine and Python 3 support has been enhanced. There are still two remaining failures in astng test suite when using python 3, but we're unfortunatly missing resources to fix them yet.

Many thanks to everyone who contributed to this release by submitting patches or by participating to the latest bugs day.


pylint bug day #3 on july 8, 2011

2011/07/04 by Sylvain Thenault

Hey guys,

we'll hold the next pylint bug day on july 8th 2011 (friday). If some of you want to come and work with us in our Paris office, you'll be welcome.

You can also join us on jabber / irc:

I know the announce is a bit late, but I hope some of you will be able to come or be online anyway!

Regarding the program, the goal is to decrease the number of tickets in the tracker. I'll try to do some triage earlier this week so you'll get a chance to talk about your super-important ticket that has not been selected. Of course, if you intend to work on it, there is a bigger chance of it being fixed next week-end ;)