Planète AFPy RSS

[afpyro] AFPyro à Berlin - Vendredi 25 Juillet

Publié le 2014-07-25 00:00:00

Fr

A l’occasion d’EuroPython, venez transpirer sur le sable du Yaam en dégustant une bonne bière fraiche

En

The french python community is organising a non official meetup at Yaam on friday. Come an meet us while tasting a fresh beer and dancing on the sand

[gvaroquaux] The 2014 international scikit-learn sprint

Publié le 2014-07-24 22:59:58
A week ago, the 2014 edition of the scikit-learn sprint was held in Paris. This was the third time that we held an internation sprint and it was hugely productive, and great fun, as always. Great people and great venues We had a mix of core contributors and newcomers, which is a great combination, as it enables [...]

[logilab] EP14 Pylint sprint Day 1 report

Publié le 2014-07-24 14:51:00
https://ep2014.europython.eu/static_media/assets/images/logo.png

We've had a fairly enjoyable and productive first day in our little hidden room at EuroPython in Berlin ! Below are some noticeable things we've worked on and discussed about.

First, we discussed and agreed that while we should at some point cut the cord to the logilab.common package, it will take some time notably because of the usage logilab.common.configuration which would be somewhat costly to replace (and is working pretty well). There are some small steps we should do but basically we should mostly get back some pylint/astroid specific things from logilab.common to astroid or pylint. This should be partly done during the sprint, and remaining work will go to tickets in the tracker.

We also discussed about release management. The point is that we should release more often, so every pylint maintainers should be able to do that easily. Sylvain will write some document about the release procedure and ensure access are granted to the pylint and astroid projects on pypi. We shall release pylint 1.3 / astroid 1.2 soon, and those releases branches will be the last one supporting python < 2.7.

During this first day, we also had the opportunity to meet Carl Crowder, the guy behind http://landscape.io, as well as David Halter which is building the Jedi completion library (https://github.com/davidhalter/jedi). Landscape.io runs pylint on thousands of projects, and it would be nice if we could test beta release on some part of this panel. On the other hand, there are probably many code to share with the Jedi library like the parser and ast generation, as well as a static inference engine. That deserves a sprint on his own though, so we agreed that a nice first step would be to build a common library for import resolution without relying on the python interpreter for that, while handling most of the python dark import features like zip/egg import, .pth files and so one. Indeed that may be two nice future collaborations!

Last but not least, we got some actual work done:

  • Michal Novikowsky from Intel in Poland joined us to work on the ability to run pylint in different processes so it may drastically improve performance on multiple cores box.
  • Torsten did continue some work on various improvements of the functionnal test framework.
  • Sylvain did merge logilab.common.modutils module into astroid as it's mostly driven by astroid and pylint needs. Also fixed the annoying namespace package crash.
  • Claudiu keep up the good work he does daily at improving and fixing pylint :)

[Biologeek] Lecture et joie

Publié le 2014-07-20 11:00:00

Je ne milite en aucun cas pour l’abolition de l’école. Je crois, effectivement, qu’il serait catastrophique, en l’état actuel des choses, de la supprimer. Je pense, effectivement, qu’il y a de nombreux parents qui ne pourraient, ne voudraient ou ne sauraient en aucun cas assumer cette nouvelle condition ; je pense, effectivement, que la situation actuelle de nombreuses personnes rendrait irréaliste, voire périlleuse, la non-scolarisation de leurs enfants.

Mais quid de tous ceux qui en ont la possibilité et, peut-être, le désir, mais qui l’ignorent ? C’est à eux que mon témoignage offre, je l’espère, l’inspiration pour une pensée nouvelle. Respecter ses convictions, faire, en toute conscience, des choix personnels, honorer son originalité, être l’artisan de son propre devenir : tout cela, bien davantage que l’endoctrinement des masses, contribue à la progression du monde et à l’apparition de nouveaux paradigmes.

… et je ne suis jamais allé à l’école, André Stern

J’ai terminé de lire … et je ne suis jamais allé à l’école à mon fils. Quelques pages quasiment chaque jour depuis 3 mois. La joie qu’il a manifesté lorsque j’ai sorti le livre les dernières fois m’a vraiment ému. Identifier le livre comme un moment de bonheur. Comme une vaine tentative de le dévorer littéralement aussi :-).

Au fil des pages, je me suis rendu compte à quel point ma lecture à voix haute a changée, une meilleure continuité, une meilleure gestion des liaisons, des différentes voix des personnages. Essayer de rendre la forme aussi intéressante que le fond a été un exercice quotidien, pour une lecture plus lente, plus détaillée, plus profonde. La prose d’André Stern se prête bien à une telle lecture et le propos est lucide et sensé, ça donne des idées…

Prochaine lecture : Libres enfants de Summerhill.

[gvaroquaux] Scikit-learn 0.15 release: lots of speedups!

Publié le 2014-07-15 13:25:57
We have just released the 0.15 version of scikit-learn. Hurray!! Thanks to all involved. A long development stretch It’s been a while since the last release of scikit-learn. So a lot has happened. Exactly 2611 commits according my count. Quite clearly, we have more and more existing code, more and more features to support. This means that when [...]

[logilab] PyLint sprint during EuroPython in Berlin

Publié le 2014-07-11 12:51:00

The three main maintainers/developpers of Pylint/astroid (Claudiu, Torsten and I) will meet together in Berlin during EuroPython 2014. While this is not an "official" EP sprint but it's still worth announcing it since it's a good opportunity to meet and enhance Pylint. We should find place and time to work on Pylint between wednesday 23 and friday 25.

If you're interested, don't hesitate to contact me (sylvain.thenault@logilab.fr / @sythenault).

[cubicweb] CubicWeb roadmap meeting on July 3rd, 2014

Publié le 2014-07-07 14:18:00

The Logilab team holds a roadmap meeting every two months to plan its CubicWeb development effort. The previous roadmap meeting was in May 2014.

Here is the report about the July 3rd, 2014 meeting. Christophe de Vienne (Unlish) and Dimitri Papadopoulos (CEA) joined us to express their concerns and discuss the future of CubicWeb.

Versions

Version 3.17

This version is stable but old and maintainance will continue only as long as some customers will be willing to pay for it (current is 3.17.15 with 3.17.16 in development).

Version 3.18

This version is stable and maintained (current is 3.18.5 with 3.18.6 in development).

Version 3.19

This version was published at the end of April and has now been tested on our internal servers. It includes support for Cross Origin Resource Sharing (CORS) and a heavy refactoring that modifies sessions and sources to lay the path for CubicWeb 4.

For details read the release notes or the list of tickets for CubicWeb 3.19.0. Current is 3.19.2

Version 3.20

This version is under development. It will try to reduce as much as possible the stock of patches in the state "reviewed", "awaiting review" and "in progress". If you have had something in the works that has not been accepted yet, please ready it for 3.20 and get it merged.

It should still include the work done for CWEP-002 (computed attributes and relations.

For details read list of tickets for CubicWeb 3.20.0.

Version 3.21 (or maybe 4.0?)

Removal of the dbapi, merging of Connection and ClientConnection, CWEP-003 (adding a FROM clause to RQL).

Cubes

Cubes published over the past two months

New cubes

  • cubicweb-frbr: Cube providing a schema based on FRBR entities
  • cubicweb-clinipath
  • cubicweb-fastimport

CWEPs

Here is the status of open CubicWeb Evolution Proposals:

CWEP-0002 only missing a bit of migration support, to be finished soon for inclusion in 3.20.

CWEP-0003 has been reviewed and is waiting for a bit of reshaping that should occurs soon. It's targeted for 3.21.

New CWEPs are expected to be written for clarifying the API of the _cw object, supporting persistent sessions and improving the performance of massive imports.

Work in progress

Design

The new logo is now published in the 3.19 line. David showed us his experimentation that modernize a forge's ui with a bit of CSS. There is still a bit of pressure on the bootstrap side though, as it still rely on heavy monkey-patching in the cubicweb-bootstrap cube.

Data import

Also, Dimitry expressed is concerns with the lack of proper data import API. We should soon have some feedback from Aurelien's cubicweb-fastimport experimentation, which may be an answer to Dimitry's need. In the end, we somewhat agreed that there were different needs (eg massive-no-consistency import vs not-so-big-but-still-safe), that cubicweb.dataimport was an attempt to answer them all and then cubicweb-dataio and cubicweb-fastimport were more specific responses. In the end we may reasonably hope that an API will emerge.

Removals

On his way to persistent sessions, Aurélien made a huge progress toward silence of warnings in the 3.19 tests. dbapi has been removed, ClientConnection / Connection merged. We decided to take some time to think about the recurring task management as it is related to other tricky topics (application / instance configuration) and it's not directly related to persistent session.

Rebasing on Pyramid

Last but not least, Christophe demonstrated that CubicWeb could basically live with Pyramid. This experimentation will be pursued as it sounds very promising to get the good parts from the two framework.

Agenda

Logilab's next roadmap meeting will be held at the beginning of september 2014 and Christophe and Dimitri were invited.

[logilab] Nazca notebooks

Publié le 2014-07-07 12:44:00

We have just published the following ipython notebooks explaining how to perform record linkage and entities matching with Nazca:

[anybox] Sphinx autodoc et modules OpenERP

Publié le 2014-07-01 01:00:00
Guide d'intégration complète d'OpenERP et Sphinx, pour les utilisateurs de buildout.

[tarek] NGinxTest

Publié le 2014-06-29 09:40:00

I've been playing with Lua and Nginx lately, using the OpenResty bundle.

This bundle is an Nginx distribution on steroids, that includes some extensions and in particular the HTTPLuaModule which let you script Nginx using the Lua programming language.

Coming from a Python background, I was quite pleased with the Lua syntax, which feels like a cleaner Javascript inspired from Pascal and Python - if that even makes any sense :)

Here's how a Lua function look like:

-- rate limiting
function rate_limit(remote_ip, stats)
    local hits = stats:get(remote_ip)
    if hits == nil then
        stats:set(remote_ip, 1, throttle_time)
        return false
    end

    hits = hits + 1
    stats:set(remote_ip, hits, throttle_time)
    return hits >= max_hits
end

Peformance-wise, interacting with incoming web requests in Lua co-routines in Nginx is blazing fast. And there are a lot of work that can be done there to spare your proxied Python/Node.js/Go/Whatever application some cycles and complexity.

It can also help you standardize and reuse good practices across all your web apps no matter what language/framework they use.

Some things that can be done there:

  • web application firewalling
  • caching
  • dynamic routing
  • logging, load balancing
  • a ton of other pre-work...

To put it simply:

Nginx become very easy to extend with Lua scripting without having to re-compile it all the time, and Lua lowers the barrier for ops and developers to implement new server behaviors.

Testing with Test::Nginx

When you start to add some Lua scripting in your Nginx environment, testing soon become mandatory. Pure unit testing Lua scripts in that context is quite hard because you are interacting with Nginx variables and functions.

The other approach is doing only pure functional tests by launching Nginx with the Lua script loaded, and interacting with the server using an HTTP client.

OpenResty offers a Perl tool to do this, called Test::Nginx where you can describe in a light DSL an interaction with the NGinx server.

Example from the documentation:

# foo.t
use Test::Nginx::Socket;
repeat_each(1);
plan tests => 2 * repeat_each() * blocks();
$ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211;  # make this env take a default value
run_tests();

__DATA__

=== TEST 1: sanity
--- config
location /foo {
    set $memc_cmd set;
    set $memc_key foo;
    set $memc_value bar;
    memc_pass 127.0.0.1:$TEST_NGINX_MEMCACHED_PORT;
}
--- request
    GET /foo
--- response_body_like: STORED
--- error_code: 201

The data section of the Perl script describes the Nginx configuration, the request made and the expected response body and status code.

For simple tests it's quite handy, but as soon as you want to do more complex tests it becomes hard to use the DSL. In my case I needed to run a series of requests in a precise timing to test my rate limiting script.

I missed my usual tools like WebTest, where you can write plain Python to interact with a web server.

Testing with NginxTest

Starting and stopping an Nginx server with a specific configuration loaded is not hard, so I started a small project in Python in order to be able to write my tests using WebTest.

It's called NGinxTest and has no ambitions to provide all the features the Perl tool provides, but is good enough to write complex scenarios in WebTest or whatever Python HTTP client you want in a Python unit test class.

The project provides a NginxServer class that takes care of driving an Nginx server.

Here's a full example of a test using it:

import os
import unittest
import time

from webtest import TestApp
from nginxtest.server import NginxServer

LIBDIR = os.path.normpath(os.path.join(os.path.dirname(__file__),
                        '..', 'lib'))
LUA_SCRIPT = os.path.join(LIBDIR, 'rate_limit.lua')

_HTTP_OPTIONS = """\
lua_package_path "%s/?.lua;;";
lua_shared_dict stats 100k;
""" % LIBDIR


_SERVER_OPTIONS = """\
set $max_hits 4;
set $throttle_time 0.3;
access_by_lua_file '%s/rate_limit.lua';
""" % LIBDIR


class TestMyNginx(unittest.TestCase):

    def setUp(self):
        hello = {'path': '/hello', 'definition': 'echo "hello";'}
        self.nginx = NginxServer(locations=[hello],
                                http_options=_HTTP_OPTIONS,
                                server_options=_SERVER_OPTIONS)
        self.nginx.start()
        self.app = TestApp(self.nginx.root_url, lint=True)

    def tearDown(self):
        self.nginx.stop()

    def test_rate(self):
        # the 3rd call should be returning a 429
        self.app.get('/hello', status=200)
        self.app.get('/hello', status=200)
        self.app.get('/hello', status=404)

    def test_rate2(self):
        # the 3rd call should be returning a 200
        # because the blacklist is ttled
        self.app.get('/hello', status=200)
        self.app.get('/hello', status=200)
        time.sleep(.4)
        self.app.get('/hello', status=200)

Like the Perl script, you provide bits of configuration for your Nginx server -- in this case pointing the Lua script to test and some general configuration.

Then I test my rate limiting feature using Nose:

$ bin/nosetests -sv tests/test_rate_limit.py
test_rate (test_rate_limit.TestMyNginx) ... ok
test_rate2 (test_rate_limit.TestMyNginx) ... ok

----------------------------------------------------------------------
Ran 2 tests in 1.196s

OK

Out of the 1.2 seconds, the test sleeps half a second, and the class starts and stops a full Nginx server twice. Not too bad!

I have not released that project at PyPI - but if you think it's useful to you and if you want some more features in it, let me know!

[tarek] Decentralization Mailing List

Publié le 2014-06-27 14:20:00

This is long time due !

Following up with my previous blog post I have started a Decentralization Mailing list.

The goal of this mailing list is to discuss technologies related to data decentralization in Mozilla projects - and in particular in the ones we work at in the Cloud Services team (but it can go beyond of course)

A few topic examples that people brought up:

  1. Could remoteStorage be used with Firefox Account to build Firefox OS apps where people can store their own data ?
  2. Can Firefox Sync use a remoteStorage backend ?
  3. Why can't I run a simple "apt-get install firefox-sync" and host my own server ?
  4. What about peer-to-peer ? How does that fit with the services we provide ?

The list is at : https://lists.mozilla.org/listinfo/dev-decentralization

I will wait a week or so to launch topics there, but if you are interested in this topic, if you want to lurk or to launch an idea - please join.

On my side, the first topic I will probably talk about in this ML is #1.

[afpyro] AFPyro à Lyon - mercredi 25 juin

Publié le 2014-06-25 00:00:00

Un Afpyro aura lieu le mercredi 25 juin à partir de 20h à l’Antre Autre - 11 rue Terme - 69001 Lyon.

Cette soirée aura pour thème Docker avec deux présentations :

  • Docker 101 par Geoffrey Bachelet
  • Docker et Python par Haïkel Guémar

L’Antre Autre est un lieu où nous pouvons discuter autour d’un verre, et, pour ceux qui le souhaitent, prendre un repas.

Pour se rendre à l’Antre Autre :

  • en métro : arrêt Hôtel de Ville
  • en bus : lignes C13 et C18 arrêt Mairie du 1er ou lignes 19, C14 et C3 à l’arrêt Terreaux
  • en vélo’v : stations Place Sathonay, Carmélites Burdeau, Place de la paix

[Biologeek] Éducation et informatique

Publié le 2014-06-23 11:00:00

Moins les enfants regarderont les écrans, plus ils développeront leur imagination et leur créativité. Car les écrans contiennent en eux des histoires visuelles et sonores qui empêcheraient les enfants d’imaginer d’autres images et d’autres mondes possibles.

Écran global, reportage de Anne-Sophie Lévy-Chambon

Protéger son enfant des écrans s’avère être une tâche plus difficile que ce que j’imaginais. Le compteur en cumulé doit être aux alentours des 10-15 minutes après 7 mois, ce qui est plutôt dans la limite haute de ce que je m’étais fixé. Et lorsque je vois l’attrait qu’il a pour un écran dès qu’il en croise un, cela me conforte dans l’idée qu’il va falloir attendre qu’il soit en mesure de comprendre un peu ce qu’il y a derrière : une fenêtre déshumanisée sur l’Humanité.

On parle souvent de la limite des 3 ans pour qu’un enfant puisse regarder/interagir avec un écran sans être perturbé par l’absence de retour de sa part. On verra à ce moment là si mon digital native souhaite faire usage de ses doigts.

L’élève sait que les équipements informatiques utilisent une information codée et il est initié au fonctionnement, au processus et aux règles des langages informatiques ; il est capable de réaliser de petites applications utilisant des algorithmes simples.

Socle commun de connaissances, de compétences et de culture

Damien B et Éric D. discutaient ce soir de l’apprentissage du code en primaire sur Twitter. J’ai beaucoup de mal avec cette question car le code constitue une part non négligeable de mon quotidien et de mon métier. Et si je trouve que la connaissance du Web devrait faire partie de l’éducation citoyenne, je suis plus circonspect sur le développement en lui-même. En fait, il s’agit d’une problématique de cohérence. Soit on considère que le codage (sic) est une activité artisanale et dans ce cas il faudrait également enseigner d’autres activités comme le travail du bois en primaire (ce que certaines écoles alternatives font — voir le reportage sus-cité). Soit on considère que l’industrialisation de l’informatique est inévitable et dans ce cas là toute la question algorithmique simple devient inutile puisqu’il s’agira d’empiler les boîtes noires à un autre niveau. Il faut bien définir les objectifs que l’on se fixe avec cet apprentissage du code dès la primaire. Dans quelle mesure permet-il la poursuite d’études, la construction d’un avenir personnel et professionnel et préparer à l’exercice de la citoyenneté ? Tous bidouilleurs, soit, mais que nous laisse-t-on bidouiller par la suite ?

Ce que je vois en filigrane de cette mutation est plus grave, c’est la mise sur un piédestal de ceux qui savent coder par pure incompréhension du changement de paradigme qui est en train de s’effectuer avec le numérique. Ou serait-ce pour pouvoir à terme alimenter plus facilement les canons publicitaires ? La question reste ouverte… jusqu’à la prochaine réforme.

[logilab] Tester MPI avec CMake et un framework de test comme Boost

Publié le 2014-06-20 12:12:00

Objectif

Compiler et exécuter un fichier de test unitaire avec MPI.

Je suppose que :

  • une implémentation de MPI est installée (nous prendrons OpenMPI)
  • les bibliothèques Boost MPI et Boost Unit Test Framework sont présentes
  • vous connaissez quelques rudiments de CMake

CMake

On utilise le bien connu find_package pour Boost et MPI afin de récupérer tout ce qu'il nous faut pour les headers et les futurs links.

find_package (MPI REQUIRED)
find_package (Boost COMPONENTS mpi REQUIRED)

# Boost dirs for headers and libs.
include_directories (SYSTEM ${Boost_INCLUDE_DIR})
link_directories (${Boost_LIBRARY_DIRS})

Par la suite, on a essentiellement besoin des variables CMake :

  • Boost_MPI_LIBRARY pour le link avec Boost::MPI
  • MPI_CXX_LIBRARIES pour le link avec la bibliothèque OpenMPI
  • MPIEXEC qui nous donne la commande pour lancer un exécutable via MPI

On prend un fichier example_mpi.cpp (des exemples simples sont faciles à trouver sur la Toile). Pour le compiler, on fait :

set(CMAKE_CXX_COMPILER mpicxx)

# MPI example.
add_executable(example_mpi example_mpi.cpp)
target_link_libraries(example_mpi ${MPI_CXX_LIBRARIES})

voire juste

target_link_libraries(example_mpi ${Boost_MPI_LIBRARY})

si on décide d'utiliser la bibliothèque Boost MPI.

Note

mpicxx est une commande qui enrobe le compilateur (g++ par exemple). On dit à CMake d'utiliser mpicxx au lieu du compilo par défaut.

Note

Boost::MPI n'est pas une implémentation de MPI. C'est une bibliothèque plus haut niveau qui s'abstrait de l'implémentation de MPI. Il faut nécessairement en installer une (OpenMPI, LAM/MPI, MPICH2, ...).

L'exemple peut très simplement ressembler à :

#include <boost/mpi/environment.hpp>
#include <boost/mpi/communicator.hpp>
#include <iostream>

namespace mpi = boost::mpi;

int main()
{
  mpi::environment env;
  mpi::communicator world;
  std::cout << "I am process " << world.rank() << " of " << world.size()
            << "." << std::endl;
  return 0;
}

Exécuter

Une fois la compilation effectuée, faire simplement :

> mpiexec -np 4 ./example_mpi

pour lancer l'exécutable sur 4 cœurs.

Problème : mais pourquoi tu testes ?

On veut pouvoir faire des exécutables qui soient de vrais tests unitaires et non pas un exemple avec juste une fonction main. De plus, comme j'utilise CMake, je veux pouvoir automatiser le lancement de tous mes exécutables via CTest.

Problème : il faut bien initialiser et bien dire à MPI que j'en ai fini avec toutes mes MPI-series.

En "vrai" MPI, on a :

int main(int argc, char* argv[])
{
  MPI_Init(&argc, &argv);

  int rank;
  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
  // Code here..
  // ... and here
  MPI_Finalize();

  return 0;
}

Note

C'est ce que fait le constructeur/destructeur de boost::mpi::environment.

En d'autres termes, je veux me faire ma propre fonction main pour l'initialisation de tous mes cas tests Boost (ou avec n'importe quel autre framework de test unitaire C/C++).

La documentation de Boost Unit Test, que je trouve parfois très peu claire avec un manque cruel d'exemple, m'a fait galérer quelques heures avant de trouver quelque chose de simple qui fonctionne.

Conseil : aller regarder les exemples des sources en faisant quelques grep est parfois plus efficace que de trouver la bonne info dans la doc en ligne. On peut aussi en lire sur https://github.com/boostorg/test/tree/master/example

Deux solutions :

  1. la première que j'ai trouvée dans les tests de Boost::MPI lui-même. Ils utilisent le minimal testing facility. Mais seule la macro BOOST_CHECK est utilisable. Et oubliez les BOOST_CHECK_EQUAL ainsi que l'enregistrement automatique de vos tests dans la suite de tests.
  2. la deuxième redéfinit la fonction main et appelle boost::unit_test::unit_test_main sans définir ni la macro BOOST_TEST_MODULE ni BOOST_TEST_MAIN qui impliquent la génération automatique de la fonction main par le framework de test (que l'on compile en statique ou dynamique). Pour plus de détails, lire http://www.boost.org/doc/libs/release/libs/test/doc/html/utf/user-guide/test-runners.html

J'utiliserai la deuxième solution.

Note

Ne pensez même pas faire une fixture Boost pour y mettre votre boost::mpi::environment puisque cette dernière sera construite/détruite pour chaque cas test (équivalent du setUp/tearDown). Et il est fort probable que vous ayez ce genre d'erreur :

*** The MPI_Errhandler_set() function was called after MPI_FINALIZE was invoked.
*** This is disallowed by the MPI standard.
*** Your MPI job will now abort.
[hostname:11843] Abort after MPI_FINALIZE completed successfully; not able to guarantee that all other processes were killed!

Un exemple qui marche

On souhaite ici tester que le nombre de procs passés en argument de mpiexec est au moins 2.

Le BOOST_TEST_DYN_LINK dit juste que je vais me lier dynamiquement à Boost::Test.

#define BOOST_TEST_DYN_LINK
#include <boost/test/unit_test.hpp>

#include <boost/mpi/environment.hpp>
#include <boost/mpi/communicator.hpp>

namespace mpi = boost::mpi;

BOOST_AUTO_TEST_CASE(test_check_world_size)
{
    mpi::communicator world;
    BOOST_CHECK(world.size() > 1);
}


// (empty) Initialization function. Can't use testing tools here.
bool init_function()
{
    return true;
}

int main(int argc, char* argv[])
{
    mpi::environment env(argc, argv);
    return ::boost::unit_test::unit_test_main( &init_function, argc, argv );
}

On lance tout ça avec un joli mpiexec -np 2 ./test_mpi et on est (presque) content.

Et un peu de CTest pour finir

Une dernière chose : on aimerait dire à CMake via CTest de lancer cet exécutable, mais avec mpiexec et les arguments qui vont bien.

Un cmake --help-command add_test nous indique qu'il est possible de lancer n'importe quel exécutable avec un nombre variable d'arguments. On va donc lui passer : /usr/bin/mpiexec -np NB_PROC ./test_mpi.

Un œil au module FindMPI.cmake nous dit aussi qu'on peut utiliser d'autres variables CMake MPI pour ce genre de chose.

Reprenons donc notre fichier CMake et ajoutons :

add_executable(test_mpi test_mpi.cpp)
target_link_libraries(test_mpi ${Boost_MPI_LIBRARY})
# Number of procs for MPI.
set (PROCS 2)
# Command to launch by CTest. Need the MPI executable and the number of procs.
add_test (test_mpi ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${PROCS}
   ${MPIEXEC_PREFLAGS}
   test_mpi
   ${MPIEXEC_POSTFLAGS})

où mon exécutable et mon test porte le même nom : test_mpi. On lance le tout avec la commande ctest dans notre dossier de build et hop, le tour est joué !

[Biologeek] Écriture et bonheur

Publié le 2014-06-20 11:00:00

Difficile d’écrire sur le bonheur. Sans faire dans le mièvre. Sans tomber dans les clichés. Sans craindre d’attiser les convoitises et jalousies. Sans avoir peur surtout de briser cet instant en tentant de le décrire. Sans mentir.

6 mois de vie. De survie. De co-vie. Je ne sais pas trop comment appeler cela, ni de quel point de vue. Toujours est-il que ça semble fonctionner. Des doutes, des essais, des désespoirs, des soulagements. Des moments spéciaux. Inattendus. Intimes.

Apprendre à flâner avec une poussette. Se défendre des fumées et des bruits de la ville. Réduire son exposition aux écrans. Se nourrir plus sainement. Sourire très souvent. Apprécier ce rythme plus lent qui contribue au bien-être. Et au bonheur.

Songer à cette question de l’héritage. Vouloir léguer des valeurs et une culture plus que des biens. Amasser du temps de vivre ensemble. Donner son attention avant tout. Et sentir qu’il s’agit d’un échange. Réciproque et gratuit.

Rire et s’émerveiller des nouveautés. Se demander qui éduque qui. S’endormir épuisé mais heureux. Se réveiller sur un simple sourire. Apprendre à se connaître, à apprécier des rituels. À cohabiter.

Et au milieu de tout cela des questionnements. Pourquoi est-ce que j’ai choisi de passer autant de temps avec mon fils ? Comment lui transmettre des valeurs sans ressentir la pression de l’exemplarité ? Quel enseignement lui proposer avant qu’il ne puisse choisir par lui-même ? Quels « effets papillons » lui permettront à terme de battre de ses propres ailes ? Quelle image va-t-il me renvoyer de moi-même ? Que ressent-il vraiment ? Et tant d’autres.

Fermer les yeux. Respirer. Faire le vide. Sourire. Se sentir bien.

[afpyro] AFPyro à Pau - Jeudi 19 Juin

Publié le 2014-06-19 00:00:00

Un Afpyro aura lieu le Jeudi 19 Juin à partir de 20h au Fablab de Pau

Venez rencontrer et échanger avec la comunauté pythoniste paloise en vous délectant de succulant breuvages!

Fablab

4 rue despourrins

64000 PAU

Voir la map

[sciunto] Utiliser pyserial pour dialoguer avec une balance et un port série

Publié le 2014-06-10 22:00:00

Dans mon billet précédent, je présentais une méthode permettant d'obtenir la valeur d'un afficheur à partir d'une prise de photos et d'un traitement d'images suivis d'un machine-learning.

Je passe maintenant au cas où l'appareil est doté d'un port série et de la documentation qui va avec. Je connecte donc ma machine à un adapatateur usb/série et le device apparait dans /dev/ttyUSB0.

On sort python et sa bibliothèque pyserial. Je souhaite ici récupérer la masse en fonction du temps d'une balance Mettler Toledo XS105. Dans la doc, je sais que je dois envoyer la commande 'SI' et que la balance me répondra (même si elle n'est pas stable, cf doc).

Je commence par écrire une petite fonction qui va me récupérer tout ça.

#!/usr/bin/env python2
# -*- coding: utf-8 -*-
# License: GPLv3

# Parameters for the Mettler Toledo XS105 scale:
# 9600
# 8/No
# 1 stopbit
# Xon/Xoff
# <CR><LF>
# Ansi/win
# Off

import serial
import time
import re


def read_weight(socket, timelapse=1):
    """
    Returns the weight in gram and the stability.

    :param socket: serial socket
    :param timelapse: timelapse between each measurement
    :returns: tuple (weight, stability)
    """
    ser.write('\nSI\n')
    time.sleep(1)
    value = ser.read(ser.inWaiting())
    value = value.split('\n')[1][:-1]
    if value[3] == 'S':
        stability = True
    else:
        stability = False
    weight = value[4:-1].strip(' ')
    return (weight, stability)

Ensuite, je procède à l'ouverture d'une socket avec les options que j'ai configuré dans la balance, puis je boucle sur ma fonction pour récupérer régulièrement la masse. Le programme se termine avec un Ctrl-C.

if __name__ == '__main__':

    ser = serial.Serial(port='/dev/ttyUSB0',
                        baudrate=9600,
                        parity=serial.PARITY_NONE,
                        stopbits=serial.STOPBITS_ONE,
                        bytesize=serial.EIGHTBITS
    )

    if not ser.isOpen():
        ser.open()
    with open('data.dat', 'w') as fh:
        fh.write('# Time (s) | Weight (g) | Stability')
        zerotimer = time.time()  # perf_counter might be better py3
        try:
            while True:
                weight, stability = read_weight(ser)
                timer = time.time() - zerotimer
                print('t = ' + str(timer) + 's | M = ' + str(weight) + ' g')
                fh.write(str(timer) + ' ' + weight + ' ' + str(stability) +'\n')
        except KeyboardInterrupt:
            fh.close()

Et voilà !

[logilab] Open Legislative Data Conference 2014

Publié le 2014-06-10 15:57:00

I was at the Open Legislative Data Conference on may 28 2014 in Paris, to present a simple demo I worked on since the same event that happened two years ago.

The demo was called "Law is Code Rebooted with CubicWeb". It featured the use of the cubicweb-vcreview component to display the amendments of the hospital law ("loi hospitalière") gathered into a version control system (namely Mercurial).

The basic idea is to compare writing code and writing law, for both are collaborative and distributed writing processes. Could we reuse for the second one the tools developed for the first?

Here are the slides and a few screenshots.

http://www.logilab.org/file/253394/raw/lawiscode1.png

Statistics with queries embedded in report page.

http://www.logilab.org/file/253400/raw/lawiscode2.png

List of amendments.

http://www.logilab.org/file/253396/raw/lawiscode3.png

User comment on an amendment.

While attending the conference, I enjoyed several interesting talks and chats with other participants, including:

  1. the study of co-sponsorship of proposals in the french parliament
  2. data.senat.fr announcing their use of PostgreSQL and JSON.
  3. and last but not least, the great work done by RegardsCitoyens and SciencesPo MediaLab on visualizing the law making process.

Thanks to the organisation team and the other speakers. Hope to see you again!

[sciunto] Détection de nombres d'un afficheur avec scikit-image et scikit-learn

Publié le 2014-06-07 22:00:00

Dans ce billet, je propose de traiter le problème suivant. Prenons le cas d'un appareil possédant un afficheur digital tel qu'une balance, un voltmètre, un réveil, un hygromètre... mais ne possédant pas de moyen simple de récupérer les données (absence de port série etc). Si on souhaite collecter les données, deux méthodes s'offrent à nous. La première est celle de l'électronicien qui consiste à mettre un moyen de communication là où il n'y en a pas. L'inconvénient est qu'il faut avoir une compétence (que je n'ai pas) et qu'il faut faire du cas par cas. La seconde technique est de prendre en photo l'afficheur et d'analyser les images. C'est ce qu'on va faire ici.

Pour la démonstration, je vais utiliser python, une balance dont la masse affichée fluctue au cours du temps et les photos de l'afficheur.

Une fois le lot de photos sur le disque (ex: Img0001.png), on va chercher à détecter les chiffres (ou digits). Scikit-image va nous être précieux. Il nous faut :

  • appliquer un seuil à l'image pour enlever les parasites et passer en binaire. Otsu est intéressant car local, ce qui permet de se prémunir de variation de contraste à grande échelle.
  • connecter les morceaux dans le cas d'un afficheur 7 segments ou d'un seuillage trop agressif.
  • remplir les trous pour qu'il ne soit pas détecté comme objet
  • étiqueter les régions et ne considérer que celles supérieures à une taille critique
  • les extraire

Ceci est fait par ce code (qui manque encore de soin)

import os.path
import glob

import numpy as np
from scipy import ndimage
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches

import skimage.io
from skimage.filter import threshold_otsu
from skimage.segmentation import clear_border
from skimage.morphology import closing, square
from skimage.measure import regionprops, label
from skimage.color import label2rgb


def segment_digit(image, filename, output_dir, digit_height=100, digit_width=52,
                  border=7, black_on_white=True, closingpx=4):
    """
    Segement each digit of a picture

    :param image: grey scale picture
    :param filename: filename of the picture source
    :param output_dir: path for the output
    :param digit_height: height of a digit
    :param digit_width: width of a digit
    :param border: pixels to shift the border
    :param black_on_white: black digit on clear background
    :param closingpx: number of pixels to close
    """
    # apply threshold
    thresh = threshold_otsu(image)
    if black_on_white:
        bw = closing(image > thresh, square(closingpx))
    else:
        bw = closing(image < thresh, square(closingpx))

    filled = ndimage.binary_fill_holes(bw)
    #plt.imshow(filled)
    #plt.show()

    # remove artifacts connected to image border
    cleared = filled.copy()
    clear_border(cleared)

    # label image regions
    label_image = label(cleared)
    borders = np.logical_xor(filled, cleared)
    label_image[borders] = -1
    image_label_overlay = label2rgb(label_image, image=image)

    fig, ax = plt.subplots(ncols=1, nrows=1, figsize=(6, 6))
    ax.imshow(image_label_overlay)

    regions = regionprops(label_image)

    for item, region in enumerate(regions):
        # skip small elements
        if region['Area'] < 300:
            continue

        # draw rectangle around segmented digits
        minr, minc, maxr, maxc = region['BoundingBox']
        rect = mpatches.Rectangle((minc, minr), maxc - minc, maxr - minr,
                                  fill=False, edgecolor='red', linewidth=2)

        # uniq size
        img = np.zeros((100, 75), 'uint8')
        img[bw[minr:maxr, minc:maxc]!=0] = 255
        newname = os.path.splitext(os.path.basename(filename))[0] + '-' + str(item) + '.png'
        skimage.io.imsave(os.path.join(output_dir, newname), img)
        ax.add_patch(rect)

    plt.show()
Segmentation de chaque digit

Segmentation de chaque digit

On s'est donc fabriqué un lot d'images (Img0001-0.png, Img0001-1.png...) correspondant à chaque digit.

Il nous reste maintenant à les identifier. Une première méthode serait de faire du template matching, mais ça peut vite s'avérer peu robuste. On va donc préférer passer par du machine-learning. Scikit-learn est là pour ça.

Le principe :

  • On identifie un sous lot d'images. Dans mon cas, j'ai identifié trois images pour chaque digit (donc 30) et elles sont nommées sous la forme digit-id.png).
  • On entraine l'algorithme sur ces images identifiées.
  • On demande de deviner les images inconnues.

Pour la partie connue :

import glob
import os

import numpy as np
import pylab as pl

from sklearn import svm, metrics
import skimage.io

def load_knowndata(filenames):
    training = {'images': [], 'targets': [], 'data' : [], 'name' : []}

    for index, filename in enumerate(filenames):
        target = os.path.splitext(os.path.basename(filename))[0]
        target = int(target.split('-')[0])
        image = skimage.io.imread(filename)
        training['targets'].append(target)
        training['images'].append(image)
        training['name'].append(filename)
        training['data'].append(image.flatten().tolist())
        pl.subplot(6, 5, index + 1)
        pl.axis('off')
        pl.imshow(image, cmap=pl.cm.gray_r, interpolation='nearest')
        pl.title('Training: %i' % target)

    ## To apply an classifier on this data, we need to flatten the image, to
    ## turn the data in a (samples, feature) matrix:
    n_samples = len(training['images'])
    training['images'] = np.array(training['images'])
    training['targets'] = np.array(training['targets'])
    training['data'] = np.array(training['data'])
    return training

Pour la partie inconnue :

def load_unknowndata(filenames):
    training = {'images': [], 'targets': [], 'data' : [], 'name' : []}

    for index, filename in enumerate(filenames):
        image = skimage.io.imread(filename)
        training['targets'].append(-1) # Target = -1: unkown
        training['images'].append(image)
        training['name'].append(filename)
        training['data'].append(image.flatten().tolist())

    ## To apply an classifier on this data, we need to flatten the image, to
    ## turn the data in a (samples, feature) matrix:
    n_samples = len(training['images'])
    training['images'] = np.array(training['images'])
    training['targets'] = np.array(training['targets'])
    training['data'] = np.array(training['data'])
    return training

et on écrit un main rapidement pour enchainer tout ça


if __name__ == '__main__':
    filenames = sorted(glob.glob('learn/*-*.png'))
    training = load_knowndata(filenames)
    pl.show()
    pl.close()

    # Create a classifier: a support vector classifier
    classifier = svm.SVC(gamma=1e-8)

    # We learn the digits on the first half of the digits
    classifier.fit(training['data'], training['targets'])

    filenames = sorted(glob.glob('data/*.png'))
    unknown = load_unknowndata(filenames)

    filenames = glob.glob('data/*.png')
    filenames = set([os.path.splitext(os.path.basename(fn))[0].split('-')[0] for fn in filenames])

    for filename in filenames:
        print('----')
        print(filename)
        print('----')
        fn = sorted(glob.glob('data/' + filename  + '*.png'))
        unknown = load_unknowndata(fn)
        # Now predict the value of the digit on the second half:
        #expected = digits.target[n_samples / 2:]
        predicted = classifier.predict(unknown['data'])

        result = ''
        for pred, image, name in zip(predicted, unknown['images'], unknown['name']):
            print(pred)
            print(name)
            result += str(pred)

        # Check
        fn = 'pictures/' + filename  + '.png'
        image = skimage.io.imread(fn)
        pl.imshow(image[:150, 56:], cmap=pl.cm.gray_r, interpolation='nearest')
        pl.title('Predicted: %s' % result)
        pl.show()

Le résultat est que sur des images de 150 par 300 pixels, contenant 5 digits chacune, j'ai eu 100% de succès sur un test de 60 images. L'algo est même robuste à un changement de valeur du dernier chiffre significatif de la balance lors de la prise de la photo qui se traduit par une superposition de deux digits sur la photos. L'algo détecte l'une ou l'autre des valeurs qu'un humain verrait.

detection de nombres avec une fluctuation : 24774

detection de nombres avec une fluctuation : 24774

En conclusion, on se retrouve avec un moyen simple de récupérer les valeurs de n'importe quel afficheur et sans effort ni bricolage.

[afpyro] AFPyro à Lyon - mercredi 28 mai

Publié le 2014-05-28 00:00:00

Un Afpyro aura lieu le mercredi 28 mai à partir de 20h à l’Antre Autre - 11 rue Terme - 69001 Lyon.

Une présentation sur Celery sera donnée. Celery est un gestionnaire de tâches qui permet de les traiter de manière asynchrone.

L’Antre Autre est un lieu où nous pouvons discuter autour d’un verre, et, pour ceux qui le souhaitent, prendre un repas.

Pour se rendre à l’Antre Autre :

  • en métro : arrêt Hôtel de Ville
  • en bus : lignes C13 et C18 arrêt Mairie du 1er ou lignes 19, C14 et C3 à l’arrêt Terreaux
  • en vélo’v : stations Place Sathonay, Carmélites Burdeau, Place de la paix

[cubicweb] Logilab's roadmap for CubicWeb on May 15th, 2014

Publié le 2014-05-22 15:24:00

The Logilab team holds a roadmap meeting every two months to plan its CubicWeb development effort. Here is the report about the May 15th, 2014 meeting. The previous report posted to the blog was the march 2014 roadmap.

Versions

Version 3.17

This version is stable but old and maintainance will continue only as long as some customers will be willing to pay for it (current is 3.17.15).

Version 3.18

This version is stable and maintained (current is 3.18.4).

Version 3.19

This version was published at the end of April. It includes support for Cross Origin Resource Sharing (CORS) and a heavy refactoring that modifies sessions and sources to lay the path for CubicWeb 4.

For details read the release notes or the list of tickets for CubicWeb 3.19.0.

Version 3.20

This version is under development. It will try to reduce as much as possible the stock of patches in the state "reviewed", "awaiting review" and "in progress". If you have had something in the works that has not been accepted yet, please ready it for 3.20 and get it merged.

It should also include the work done for CWEP-002 (computed attributes and relations) and the merging of Connection and ClientConnection if it happens to be simple enough to get done quickly (in case the removal of dbapi would really help, this merging will wait for 3.21).

For details read list of tickets for CubicWeb 3.20.0.

Version 3.21 (or maybe 4.0?)

Removal of the dbapi and merging of CWEP-003 (adding a FROM clause to RQL).

Cubes

Here is a list of cubes that had versions published over the past two months: accidents, awstats, book, bootstrap, brainomics, cmt, collaboration, condor, container, dataio, expense, faq, file, forge, forum, genomics, geocoding, inlineedit, inventory, keyword, link, mailinglist, mediaplayer, medicalexp, nazcaui, ner, neuroimaging, newsaggregator, processing, questionnaire, rqlcontroller, semnews, signedrequest, squareui, task, testcard, timesheet, tracker, treeview, vcsfile, workorder.

Here are a the new cubes we are pleased to announce:

rqlcontroller receives via a POST a list of RQL queries and executes them. This is a way to build web services.

wsme is helping build a web service API on top of a CubicWeb database.

signedrequest is a simple token based authentication system. This is a way for scripts or callback urls to access an instance without login/pwd information.

relationwidget is a widget usable in forms to edit relationships between objects. It depends on CubicWeb 3.19.

searchui is an experiment on adding blocks to the list of facets that allow building complex RQL queries step by step by clicking with the mouse instead of directly writing the RQL with the keyboard.

ckan is using the REST API of a CKAN data portal to mirror its content.

CWEPs

Here is the status of open CubicWeb Evolution Proposals:

CWEP-0002 is now in good shape and the goal is to have it merged into 3.20. It lacks some documentation and a migration script.

CWEP-0003 has made good progress during the latest sprint, but will need a thorough review before being merged. It will probably not be ready for 3.20 and have to wait for 3.21.

New CWEPs are expected to be written for clarifying the API of the _cw object, supporting persistent sessions and improving the performance of massive imports.

Visual identity

CubicWeb has a new logo that will appear before the end of may on its revamped homepage at http://www.cubicweb.org

Last but not least

As already said on the mailing list, other developers and contributors are more than welcome to share their own goals in order to define a roadmap that best fits everyone's needs.

Logilab's next roadmap meeting will be held at the beginning of july 2014.

[logilab] SaltStack Meetup with Thomas Hatch in Paris France

Publié le 2014-05-22 11:25:00

This monday (19th of may 2014), Thomas Hatch was in Paris for dotScale 2014. After presenting SaltStack there (videos will be published at some point), he spent the evening with members of the French SaltStack community during a meetup set up by Logilab at IRILL.

http://www.logilab.org/file/248338/raw/thomas-hatch.png

Here is a list of what we talked about :

  • Since Salt seems to have pushed ZMQ to its limits, SaltStack has been working on RAET (Reliable Asynchronous Event Transport Protocol ), a transport layer based on UDP and elliptic curve cryptography (Dan Berstein's CURVE-255-19) that works more like a stack than a socket and has reliability built in. RAET will be released as an optionnal beta feature in the next Salt release.
  • Folks from Dailymotion bumped into a bug that seems related to high latency networks and the auth_timeout. Updating to the very latest release should fix the issue.
  • Thomas told us about how a dedicated team at SaltStack handles pull requests and another team works on triaging github issues to input them into their internal SCRUM process. There are a lot of duplicate issues and old inactive issues that need attention and clutter the issue tracker. Help will be welcome.
http://www.logilab.org/file/248336/raw/Salt-Logo.png
  • Continuous integration is based on Jenkins and spins up VMs to test pull request. There is work in progress to test multiple clouds, various latencies and loads.
  • For the Docker integration, salt now keeps track of forwarded ports and relevant information about the containers.
  • salt-virt bumped into problems with chroots and timeouts due to ZMQ.
  • Multi-master: the problem lies with syncronisation of data which is sent to minions but also the data that is sent to the masters. Possible solutions to be explored are : the use of gitfs, there is no built-in solution for keys (salt-key has to be run on all masters), mine.send should send the data at both masters, for the jobs cache: one could use an external returner.
  • Thomas talked briefly about ioflo which should bring queuing, data hierarchy and data pub-sub to Salt.
http://www.logilab.org/file/248335/raw/ioflo.png
  • About the rolling release question: versions in Salt are definitely not git snapshots, things get backported into previous versions. No clear definition yet of length of LTS versions.
  • salt-cloud and libcloud : in the next release, libcloud will not be a hard dependency. Some clouds didn't work in libcloud (for example AWS), so these providers got implemented directly in salt-cloud or by using third-party libraries (eg. python-boto).
  • Documentation: a sprint is planned next week. Reference documentation will not be completly revamped, but tutorial content will be added.

Boris Feld showed a demo of vagrant images orchestrated by salt and a web UI to monitor a salt install.

http://www.vagrantup.com/images/logo_vagrant-81478652.png

Thanks again to Thomas Hatch for coming and meeting up with (part of) the community here in France.

[tarek] French Services Hackaton #1

Publié le 2014-05-22 08:35:00

The Mozilla Cloud Services team just got a little bit reorganized and I am now managing a new subteam.

I am very happy about the new subteam I am part of: Alexis, Rémy and myself are the French Cloud Services team. We're still working on projects with other teams of course - but being a team in the same timezone and speaking the same native language helps a lot.

One topic that is owned by our team is building and maintaining tools that help build, deploy & run web services.

Currently, the three most active projects are:

  • Loads -- a distributed load testing tool we use to verify that a given service scales.
  • Circus -- an extensible process supervisor we're using in all our deployments
  • Cornice -- a Python framework on the top of Pyramid that helps you write web services - as opposed to "web pages"

Hackaton #1

Rémy & Alexis are in Rennes, and I am located not far from Dijon - so we're very close to each other. Closer than from our colleagues from the US or Canada. When the team was set, we've decided that we would gather for a couple of days once every month at the Mozilla Paris office to work on tools.

That's what we did this week. And that event is open to the community - we had the pleasure to have Boris coming and working with us during those 2 days.

We worked on the following topics:

  • We released the long overdue Circus 0.11
  • We made the Circus web dashboard compatible with several Circus instances. In other words, you can now supervise processes that are running on several servers from the same dashboard
  • We looked at some improvements in how Cornice publishes its APIs specifications.

But the most important task: we socialized, had fun around food/drinks.

The next hackaton will be sometimes in June. I'll try to announce it so more people can join us.

[logilab] Compte rendu présentation Salt à Solution Linux

Publié le 2014-05-21 18:57:00

Logilab était à l'édition 2014 de Solutions Linux qui se déroulait au CNIT à Paris. David Douard participait à la table ronde sur les outils libres pour la supervision lors de la session Administration Système, Devops, au cours de laquelle un certain nombre de projets libres ont été mentionnés : nagios, shinken, graphite, ElasticSearch, logstash, munin, saltstack, kibana, centreon, rsyslog.

http://www.logilab.org/file/248048/raw/solutionlinux.png

Suite à des présentations sur OpenLDAP, LXC, btrfs et ElasticSearch David Douard a présenté notre approche agile de l'administration système articulée autour de Salt et en particulier le principe de l'administration système pilotée par les tests (diapos) (Test-Driven Infrastructure).

https://www.logilab.org/file/248098/raw/Screenshot%20from%202014-05-21%2017%3A55%3A35.png

Merci aux organisateurs de Solutions Linux pour cette édition 2014.

[logilab] Salt April Meetup in Paris (France)

Publié le 2014-05-14 12:28:00

On the 15th of april, in Paris (France), we took part in yet another Salt meetup. The community is now meeting up once every two months.

We had two presentations:

  • Arthur Lutz made an introduction to returners and the scheduler using the SalMon monitoring system as an example. Salt is not only about configuration management Indeed!
  • The folks from Is Cool Entertainment did a presentation about how they are using salt-cloud to deploy and orchestrate clusters of EC2 machines (islands in their jargon) to reproduce parts of their production environment for testing and developement.

More discussions about various salty subjects followed and were pursued in an Italian restaurant (photos here).

In case it is not already in your diary : Thomas Hatch is coming to Paris next week, on Monday the 19th of May, and will be speaking at dotscale during the day and at a Salt meetup in the evening. The Salt Meetup will take place at IRILL (like the previous meetups, thanks again to them) and should start at 19h. The meetup is free and open to the public, but registering on this framadate would be appreciated.

[logilab] Quelques pointeurs présentés lors d'un atelier sur le web sémantique à Nantes

Publié le 2014-05-14 11:36:00

À l'appel du DataLab Pays de la Loire, nous avons co-animé (avec Hala Skaf-Molli) un atelier sur le web sémantique à la Cantine Numérique de Nantes.

Voici quelques diapos avec essentiellement des pointeurs pour donner des exemples de réalisations web sémantique mais aussi pour appuyer les concepts présentés. Vous trouverez les diapos de Hala Skaf sur sa page web (dans les prochains jours).

Si vous avez raté cette session et êtes intéressé par le sujet, n'hésitez pas à le faire savoir au DataLab.

http://www.datalab-paysdelaloire.org/auth/public/images/datalab.png

[hautefeuille] Distribution d’une application Python sous Windows

Publié le 2014-05-13 21:05:00

Introduction

Même si la majorité des développeurs Python travaillent sur des environnements de développement Unix, il est parfois nécessaire de fournir une distribution d’une application Python sous le système d’exploitation Windows. Ce document constitue davantage une prise de notes qu’un tutoriel complet puisque je passe les éventuelles étapes d’installation de Cython, MinGW, Visual Studio ou Nuitka. J’utilise les versions 32 bits pour l’interpréteur Python 2.7, les packages Python et les compilateurs. J’utilise à la place de MinGW, la distribution TDM-GCC.

Ces méthodes ne servent pas à obfusquer votre code mais à distribuer l’interpréteur Python, les bibliothèques associées et votre application sous forme d’un paquet.

Sous Windows, pour développer, j’utilise

Sublime Text 2.

La distribution Python fournie par ActiveState.

Les paquets Python disponibles sur ce site pour Windows.

Microsoft Visual Studio Express 2008.

Microsoft Visual C++ 2008 Redistributable Package (x86).

Admettons que nous ayons une application Python sous cette forme

Un dossier principal nommé “supershape”.

Un fichier principal main.py résidant dans ce dossier et qui constitue l’application principale.

J’utilise ici une application développée avec l’outil Kivy.

Avec Pyinstaller

On initialise d’abord un fichier de spécifications

pyinstaller --name supershape supershape\main.py

On édite le fichier supershape.spec créé.

Pour un dossier regroupant l’exécutable et les dll, on édite le fichier comme suivant

# -*- mode: python -*-
from kivy.tools.packaging.pyinstaller_hooks import install_hooks
install_hooks(globals())

a = Analysis(['SuperShape\\main.py'],
             pathex=['C:\\Users\\ANTEC\\Documents'],
             hiddenimports=[],
             runtime_hooks=None)
pyz = PYZ(a.pure)
exe = EXE(pyz,
          a.scripts,
          exclude_binaries=True,
          name='supershape.exe',
          debug=False,
          strip=None,
          upx=True,
          console=False )
coll = COLLECT(exe, Tree('C:\\Users\\ANTEC\\Documents\\Supershape'),
               a.binaries,
               a.zipfiles,
               a.datas,
               strip=None,
               upx=True,
               name='supershape')

Pour un exécutable standalone qui regroupe l’interpréteur

# -*- mode: python -*-
from kivy.tools.packaging.pyinstaller_hooks import install_hooks
install_hooks(globals())

a = Analysis(['SuperShape\\main.py'],
             pathex=['C:\\Users\\ANTEC\\Documents'],
             hiddenimports=[],
             runtime_hooks=None)
pyz = PYZ(a.pure)
exe = EXE(pyz,  Tree('C:\\Users\\ANTEC\\Documents\\Supershape'),
          a.scripts,
          a.binaries,
          a.zipfiles,
          a.datas,
          name='supershape.exe',
          debug=False,
          strip=None,
          upx=True,
          console=False )

Enfin on enveloppe le tout par la commande suivante

pyinstaller supershape.spec

Avec Nuikta

On génère la compilation en C avec la commande suivante

nuikta --recurse-all main.py

Avec Cython

On transforme le fichier Python en C

cython main.py -o supershape.c --embed

On compile le C avec Visual Studio et son compilateur

cl.exe /nologo /Ox /MD /W3 /GS- /DNDEBUG -Ic:\Python27\include -Ic:\Python27\PC /supershape.c /link /OUT:"supershape.exe" /SUBSYSTEM:CONSOLE /MACHINE:X86 /LIBPATH:c:\Python27\libs /LIBPATH:c:\Python27\PCbuild

[tarek] Un an de course

Publié le 2014-05-11 20:05:00

For once, I'll blog in French - if you want this post translated in English, mail me. It's about Running.

Je cours sérieusement depuis un an. C'est l'heure du bilan.

Mertics Pr0n

Je collecte des statistiques avec ma montre GPS depuis le 6 Août 2013 - donc presque un an aussi. A la louche, 10% de mon activité seulement n'a pas été trackée (course en tapis, fausse manip' au début d'une course) - donc les données que j'ai récupérées sont assez proches de la réalité.

En dix mois environ - ou 40 semaines, J'ai fait 1477 km en 192 séances avec donc une moyenne de 7.6km par séance. Si l'on retire les quelques données parasites comme les séances de 1mn pour cause de fausse manipulation - ou les séances de chauffe qui précèdent une plus longue séance, on est plus proche de séances de 10km en moyenne.

Mais le kilométrage est plus parlant, ca représente une moyenne de 36km par semaine, ce qui est beaucoup en période de compétition. (j'y reviendrais.)

Le temps total passé à courir est de 118h, à une allure moyenne de 4'48"/KM soit environ 12.5 KM/h. L'énergie dépensé est estimée à 92966 calories. Ce calcul calorique est un peu bidon puisque la montre ne connaît pas mon rythme cardiaque (elle pourrait) et ne prend pas en compte le dénivelé.

Mais je viens de commander une ceinture cardio donc dans un an j'aurais des stats plus précises grâce à la collecte du rythme cardique.

Impact sur la santé et l'alimentation

Je suis passé d'un rythme cardique au repos (au réveil) de 70 pulsations à 46. Les petits mal de dos chroniques après une journée penché sur le clavier ont disparus. Mon état général est passé de moyennement motivé pour me lever le matin, crevé le soir à une bonne pêche toute la journée.

Je ne bois quasiment plus d'alcool car je suis très vite saoul (deux bières peuvent suffire). Avant de me mettre au sport c'était parfois 2/3 (bonnes) bières le même soir. La faible tolérance à l'alcool est probablement lié à la chute de poids: je suis passé de 75kg à 60kg pour 1M68. On me dira que c'est mieux pour ma santé mais c'est frustrant ;)

Mon alimentation a pas mal changée aussi: je suis devenu végétarien et je mange peu mais souvent. En gros des petits repas, et plein d'encas toute la journée, comme des graines bien grasses (noix de cajou, noisettes, amandes). Aussi une quantitée anormale de pommes (3/4 par jour en moyenne - Chirac serait ravi). Je bois aussi 1 litre de thé par jour environ - plutôt du thé vert. Je passe donc plus de temps aux toilettes - mais grâce au wifi j'y travaille très bien.

En terme de bobos, je n'ai pas eu de problèmes majeurs. Juste des ongles noirs liés à l'impact des chaussures qui ont disparus une fois que je me suis décidé à porter des chaussures à ma taille - soit une taille de plus vu que les pieds gonflent un peu en course. Je suis aussi adepte de la course pieds nus de temps en temps, ca réveille les sens et à petite dose ca évite les petites blessures.

Le passage à une nouvelle paire de chaussure m'a aussi fait un peu mal aux genoux pendant quelque temps, mais rien de très grave. Quand je lis les histoires horribles sur les forums de course à pied, je me dis que j'ai de la chance globalement.

Pratique en Club

J'ai été très surpris du nombre de licenciés de course à pied, et du dynamise de ce sport en France. Il y a des évènements partout, tout le temps - avec des gens de tous les ages et couches sociales.

Il y a deux types de clubs:

Les clubs qui se prennent très au sérieux - qui s'entraînent principalement sur piste - le genre de club où le coach va te pousser à te surpasser ou te faire une remarque si tu n'as pas fait un sprint à l'arrivée d'une course (!?). La moyenne d'age semble un peu plus jeune.

Le deuxième type: les clubs à la cool, avec des gens de tous niveau et tout age, où l'on boira du vin chaud après le cross.

Je me suis inscris en novembre/décembre dernier à un petit club local, l'Association des Coureurs de Route (ACR) de Dijon - après avoir regardé un peu les clubs existants.

J'essaye de faire un entraînement par semaine avec le club, et le reste tout seul car je suis trop éloigné de Dijon pour y aller plus souvent.

C'est un club à la cool, mais avec quelques coureurs très fort avec qui je progresse.

Compétition

Je me suis pris au jeu des compétitions - ca brise la monotonie des joggings dans son coin.

Le site de la FFA track les courses que je fais en France pour moi, c'est assez bien fait. Voici ma fiche.

J'ai fait aussi deux courses à l'étranger. Un semi-marathon à San Francisco et un 5K à Montreal.

Mes records:

  • 5K: 18mn17s
  • 10K: 37mn45s à Chalon-s-Saone (il faisait 50m de plus, 37mn56s à l'arrivée)
  • semi-marathon: 1h24mn38s au semi de SF

Pas de marathon en compétition encore (une sortie de 32km c'est ma plus longue distance).

Le bilan des compet': au top de ma forme j'ai un niveau "R5" environ (Régional 5 du barême FFA) - en gros je termine en général dans les 10% les plus rapides dans les petites courses locales, mais je ne pourrais jamais faire un "podium" (les 3 premiers).

J'ai le défaut classique du débutant: je pars trop vite et je fini trop lentement. C'est très difficile de conserver ses allures et ne pas se faire emporter par l'adrénaline du départ. J'y travaille.

Depuis le début du printemps, j'enchaine les courses tous les week-ends et je ne me repose plus assez. Tous mes chronos commencent à régresser. Le sur-entraînement est facile à atteindre quand on débute. Pareil, il faut que le métier rentre.

Bilan et suite

La course me convient bien. Ca se goupille bien avec le télé-travail et je suis en meilleur forme physique. C'est une activité qui évacue bien le stress.

Je bloguerais dans un an environ sur ce même sujet, pour voir l'évolution.

[cubicweb] What's new in CubicWeb 3.19

Publié le 2014-05-06 12:51:00

New functionalities

  • implement Cross Origin Resource Sharing (CORS) (see #2491768)
  • system_source.create_eid can return a range of IDs, to reduce overhead of batch entity creation

Behaviour Changes

  • The anonymous property of Session and Connection is now computed from the related user login. If it matches the anonymous-user in the config the connection is anonymous. Beware that the anonymous-user config is web specific. Therefore, no session may be anonymous in a repository only setup.

New Repository Access API

Connection replaces Session

A new explicit Connection object replaces Session as the main repository entry point. A Connection holds all the necessary methods to be used server-side (execute, commit, rollback, call_service, entity_from_eid, etc...). One obtains a new Connection object using session.new_cnx(). Connection objects need to have an explicit begin and end. Use them as a context manager to never miss an end:

with session.new_cnx() as cnx:
    cnx.execute('INSERT Elephant E, E name "Babar"')
    cnx.commit()
    cnx.execute('INSERT Elephant E, E name "Celeste"')
    cnx.commit()
# Once you get out of the "with" clause, the connection is closed.

Using the same Connection object in multiple threads will give you access to the same Transaction. However, Connection objects are not thread safe (hence at your own risks).

repository.internal_session is deprecated in favor of repository.internal_cnx. Note that internal connections are now safe by default, i.e. the integrity hooks are enabled.

Backward compatibility is preserved on Session.

dbapi vs repoapi

A new API has been introduced to replace the dbapi. It is called repoapi.

There are three relevant functions for now:

  • repoapi.get_repository returns a Repository object either from an URI when used as repoapi.get_repository(uri) or from a config when used as repoapi.get_repository(config=config).
  • repoapi.connect(repo, login, **credentials) returns a ClientConnection associated with the user identified by the credentials. The ClientConnection is associated with its own Session that is closed when the ClientConnection is closed. A ClientConnection is a Connection-like object to be used client side.
  • repoapi.anonymous_cnx(repo) returns a ClientConnection associated with the anonymous user if described in the config.

repoapi.ClientConnection replaces dbapi.Connection and company

On the client/web side, the Request is now using a repoapi.ClientConnection instead of a dbapi.Connection. The ClientConnection has multiple backward compatible methods to make it look like a dbapi.Cursor and dbapi.Connection.

Sessions used on the Web side are now the same as the ones used Server side. Some backward compatibility methods have been installed on the server side Session to ease the transition.

The authentication stack has been altered to use the repoapi instead of the dbapi. Cubes adding new elements to this stack are likely to break.

New API in tests

All current methods and attributes used to access the repo on CubicWebTC are deprecated. You may now use a RepoAccess object. A RepoAccess object is linked to a new Session for a specified user. It is able to create Connection, ClientConnection and web side requests linked to this session:

access = self.new_access('babar') # create a new RepoAccess for user babar
with access.repo_cnx() as cnx:
    # some work with server side cnx
    cnx.execute(...)
    cnx.commit()
    cnx.execute(...)
    cnx.commit()

with access.client_cnx() as cnx:
    # some work with client side cnx
    cnx.execute(...)
    cnx.commit()

with access.web_request(elephant='babar') as req:
    # some work with web request
    elephant_name = req.form['elephant']
    req.execute(...)
    req.cnx.commit()

By default testcase.admin_access contains a RepoAccess object for the default admin session.

API changes

  • RepositorySessionManager.postlogin is now called with two arguments, request and session. And this now happens before the session is linked to the request.
  • SessionManager and AuthenticationManager now take a repo object at initialization time instead of a vreg.
  • The async argument of _cw.call_service has been dropped. All calls are now synchronous. The zmq notification bus looks like a good replacement for most async use cases.
  • repo.stats() is now deprecated. The same information is available through a service (_cw.call_service('repo_stats')).
  • repo.gc_stats() is now deprecated. The same information is available through a service (_cw.call_service('repo_gc_stats')).
  • repo.register_user() is now deprecated. The functionality is now available through a service (_cw.call_service('register_user')).
  • request.set_session no longer takes an optional user argument.
  • CubicwebTC does not have repo and cnx as class attributes anymore. They are standard instance attributes. set_cnx and _init_repo class methods become instance methods.
  • set_cnxset and free_cnxset are deprecated. The database connection acquisition and release cycle is now more transparent.
  • The implementation of cascading deletion when deleting composite entities has changed. There comes a semantic change: merely deleting a composite relation does not entail any more the deletion of the component side of the relation.
  • _cw.user_callback and _cw.user_rql_callback are deprecated. Users are encouraged to write an actual controller (e.g. using ajaxfunc) instead of storing a closure in the session data.
  • A new entity.cw_linkable_rql method provides the rql to fetch all entities that are already or may be related to the current entity using the given relation.

Deprecated Code Drops

  • The session.hijack_user mechanism has been dropped.
  • EtypeRestrictionComponent has been removed, its functionality has been replaced by facets a while ago.
  • the old multi-source support has been removed. Only copy-based sources remain, such as datafeed or ldapfeed.

[Biologeek] Création de coopératives

Publié le 2014-04-24 11:00:00

Coopératives. Le mot semblerait presque désuet. À l’heure où l’économie est aux mains d’une finance high-tech, le mot sonne comme l’écho d’une vision vieillote, celle des utopies fouriéristes et d’un capitalisme soucieux de la condition ouvrière. La première coopérative a en effet vu le jour dans la ville minière du Rochdale, au Royaume-Uni, en 1844. Mais, en dépit de cette origine lointaine, le modèle coopératif n’a rien perdu de sa pertinence et il démontre tous les jours sa modernité.

Une coopérative est une structure de production de biens et de services dans laquelle les salariés sont copropriétaires du capital, codécisionnaires (« un membre, une voix ») et coélecteurs des dirigeants, ces derniers étant responsables devant eux. Une partie des bénéfices est obligatoirement réinvestie dans le développement de la coopérative et une autre est distribuée aux membres associés, sous forme de bénéfices sociaux. Avec l’accord des membres, la coopérative soutient aussi des activités extérieures, dans un esprit d’engagement envers la communauté. Le modèle coopératif est donc une forme d’organisation tournée vers l’intérêt collectif — c’est d’ailleurs à ce titre que l’Onu le défend (2012 Année internationale des coopératives) —, mais son dynamisme, ses capacités entrepreneuriales et ses résultats en font un substitut crédible au capitalisme financier.

Les coopératives emploient aujourd’hui 100 millions de salariés dans le monde, soit 20% de plus que les multinationales. […]

Ce modèle florissant vaut donc la peine d’être examiné. D’autant qu’il donne aux citoyens des leviers d’action sur l’économie, qu’il constitue un puissant outil de redistribution sociale et qu’il résiste mieux aux crises que les autres.

un million de révolutions tranquilles, Bénédicte Manier

Dans la perspective d’une refonte du site internet de scopyleft je m’interroge sur la pertinence d’avoir une partie dédiée à la création d’une SCOP (Société Coopérative et Participative). Il y aurait de la matière à partager sur ce que cela demande en termes administratif, comptable et stratégique. Mais aussi sur notre expérience.

Il y a des personnes qui nous ont contacté individuellement au cours de cette année, comme les happyculteurs, pour répondre ponctuellement à des questions précises relatives à la création et peut-être que cela suffit. Ou peut-être que cette partie du site serait aussi un acte de partage militant. Ou peut-être que cela nécessite un site dédié qui puisse être facilement enrichi par tous ?

Je suis prêt à passer un peu de temps là-dessus mais j’ai besoin de savoir si ça intéresse 2, 20 ou 200 personnes de façon à pouvoir trouver le support approprié. Quelles seraient vos attentes sur la création d’une telle ressource ?

[Biologeek] OpenData et évaluation

Publié le 2014-04-24 11:00:00

[De mémoire] J’aurais aimé que vous soyez là hier lorsque nous avons discuté, en partant de banalités jusqu’aux points de crispation très précis liés à l’OpenData.

Marylise Lebranchu, Ministre de la Décentralisation, de la Réforme de l’État et de la Fonction Publique lors de la Conférence de Paris

Il est peut-être temps d’initier notre gouvernement aux formats ouverts comme les Barcamps ou les OpenSpaces et ainsi que la parole publique cesse d’être une langue morte pour beaucoup de nos concitoyens comme le souhaite si candidement notre ministre. Mais les fauteuils de l’estrade de la Cour des Comptes semblent tellement confortables… et puis il faudrait rester plus d’une heure au contact des citoyens et réutilisateurs de données.

Ce n’est pourtant pas la partie de son discours qui m’a choqué. Alors que ses homologues anglais (Francis Maude) ou irlandais (Brendan Howlin T.D.) évoquaient l’importance de la transparence pour rétablir la confiance, Marylise Lebranchu a bien insisté sur le fait que l’OpenData est également un outil de mesure et d’évaluation pour pouvoir analyser la performance et l’efficacité de l’administration. Et je doute sincèrement que cet angle d’attaque permette d’avoir une approche sincère de la part des services de la puissance publique pour co-construire avec les citoyens.

En fixant des critères d’évaluation, on oriente complètement la réponse qui ne peut plus être innovante. C’est ce qui arrive avec l’école qui tue la créativité par la notation. C’est ce qui arrive avec la compétition sportive qui détruit le plaisir par les classements. C’est ce qui arrivera avec l’OpenData public qui ne pourra plus prendre le risque d’innover, de défricher ce terreau fertile avec les citoyens et se contentera de copier ce qui est considéré comme une réussite, bien souvent à l’étranger. En évaluant, on sanctionne l’échec ce qui crée de la peur et de la frustration. Je rêve d’un OpenData qui commence par rétablir la confiance au sein même de l’administration. Ce n’est qu’en rétablissant cette confiance en interne qu’elle pourra ensuite être transmise aux citoyens. Ce n’est qu’en embrassant une culture (de la donnée) que l’on peut la propager.

Aujourd’hui on n’a pas beaucoup entendu de citoyens.

Rolf Alter, Directeur de la Gouvernance publique et du Développement territorial, OCDE

[gvaroquaux] Google summer of code projects for scikit-learn

Publié le 2014-04-23 05:56:46
I’d like to welcome the four students that were accepted for the GSoC this year: Issam: Extending Neural networks Hamzeh: Sparse Support for Ensemble Methods Manoj: Making Linear models faster Maheshakya: Locality Sensitive Hashing Welcome to all of you. Your submissions were excellent, and you demonstrated a good will to integrate in the project, with its social and coding dynamics. It is [...]

[afpyro] AFPyro à Lyon - mercredi 23 avril

Publié le 2014-04-23 00:00:00

Un Afpyro aura lieu le mercredi 23 avril à partir de 20h à l’Antre Autre - 11 rue Terme - 69001 Lyon.

Une présentation sur WTForms sera donnée. WTForms est une librairie permettant de simplifier la gestion des formulaires au sein d’une application web.

L’Antre Autre est un lieu où nous pouvons discuter autour d’un verre, et, pour ceux qui le souhaitent, prendre un repas.

Pour se rendre à l’Antre Autre :

  • en métro : arrêt Hôtel de Ville
  • en bus : lignes C13 et C18 arrêt Mairie du 1er ou lignes 19, C14 et C3 à l’arrêt Terreaux
  • en vélo’v : stations Place Sathonay, Carmélites Burdeau, Place de la paix

[logilab] Pylint 1.2 released!

Publié le 2014-04-22 12:56:00

Once again, a lot of work has been achieved since the latest 1.1 release. Claudiu, who joined the maintainer team (Torsten and me) did a great work in the past few months. Also lately Torsten has backported a lot of things from their internal G[oogle]Pylint. Last but not least, various people contributed by reporting issues and proposing pull requests. So thanks to everybody!

Notice Pylint 1.2 depends on astroid 1.1 which has been released at the same time. Currently, code is available on Pypi, and Debian/Ubuntu packages should be ready shortly on Logilab's acceptance repositories.

Below is the changes summary, check the changelog for more info.

New and improved checks:

  • New message 'eval-used' checking that the builtin function eval was used.
  • New message 'bad-reversed-sequence' checking that the reversed builtin receive a sequence (i.e. something that implements __getitem__ and __len__, without being a dict or a dict subclass) or an instance which implements __reversed__.
  • New message 'bad-exception-context' checking that raise ... from ... uses a proper exception context (None or an exception).
  • New message 'abstract-class-instantiated' warning when abstract classes created with abc module and with abstract methods are instantied.
  • New messages checking for proper class __slots__: 'invalid-slots-object' and 'invalid-slots'.
  • New message 'undefined-all-variable' if a package's __all__ variable contains a missing submodule (#126).
  • New option logging-modules giving the list of module names that can be checked for 'logging-not-lazy'.
  • New option include-naming-hint to show a naming hint for invalid name (#138).
  • Mark file as a bad function when using python2 (#8).
  • Add support for enforcing multiple, but consistent name styles for different name types inside a single module.
  • Warn about empty docstrings on overridden methods.
  • Inspect arguments given to constructor calls, and emit relevant warnings.
  • Extend the number of cases in which logging calls are detected (#182).
  • Enhance the check for 'used-before-assignment' to look for nonlocal uses.
  • Improve cyclic import detection in the case of packages.

Bug fixes:

  • Do not warn about 'return-arg-in-generator' in Python 3.3+.
  • Do not warn about 'abstract-method' when the abstract method is implemented through assignment (#155).
  • Do not register most of the 'newstyle' checker warnings with python >= 3.
  • Fix 'unused-import' false positive with augment assignment (#78).
  • Fix 'access-member-before-definition' false negative with augment assign (#164).
  • Do not crash when looking for 'used-before-assignment' in context manager assignments (#128).
  • Do not attempt to analyze non python file, eg '.so' file (#122).
  • Pass the current python path to pylint process when invoked via epylint (#133).

Command line:

  • Add -i / --include-ids and -s / --symbols back as completely ignored options (#180).
  • Ensure init-hooks is evaluated before other options, notably load-plugins (#166).

Other:

  • Improve pragma handling to not detect 'pylint:*' strings in non-comments (#79).
  • Do not crash with UnknownMessage if an unknown message identifier/name appears in disable or enable in the configuration (#170).
  • Search for rc file in ~/.config/pylintrc if ~/.pylintrc doesn't exists (#121).
  • Python 2.5 support restored (#50 and #62).

Astroid:

  • Python 3.4 support
  • Enhanced support for metaclass
  • Enhanced namedtuple support

Nice easter egg, no?

[logilab] Ecriture de liaisons C++ pour Python

Publié le 2014-04-18 11:02:00

Dans le cadre des travaux d'interfaçage de l'application Code_TYMPAN avec du code Python, nous avons réalisé l'étude ci-dessous sur les différents moyens de générer des liaisons Python pour du code C++. Cette étude n'a pas vocation à être exhaustive et s'est concentrée sur les aspects qui nous intéressaient directement pour les travaux susmentionnés.

Solutions existantes

Une recherche des solutions existantes a été effectuée, qui a permis d'obtenir la liste suivante pour une écriture manuelle du code d'interfaçage :

  • Cython, un langage de programmation inspiré de Python, basé sur Pyrex
  • Boost.Python, une librairie C++ de la collection Boost permettant d'écrire des liaisons Python
  • PyBindGen, un outil implémenté en Python et permettant de décrire des liaisons C++ directement dans ce langage
  • Swig, un outil permettant de générer des liaisons C++ pour plusieurs langages de programmation
  • Shiboken, un générateur de code d'enrobage pour des bibliothèques C/C++ basé sur du CPython

Des solutions existent pour automatiser cette écriture. Ce sont des outils qui se basent sur des compilateurs (gcc, clang) pour faire l'analyse grammaticale du code C++ et générer le code d'interfaçage correspondant. Par exemple :

  • XDress, qui permet de générer des fichiers Cython (.pyx, .pxd) à partir de gcc-xml ou de libclang
  • PyBindGen dispose de fonctionnalités permettant de générer des liaisons python à partir de gcc
  • Ce billet explique comment utiliser libclang pour parcourir l'AST d'un code C++ et générer des liaisons Boost.Python

Aspects pris en compte

Cet article est intéressant car il aborde de façon très complète les problématiques découlant de l'écriture de liaisons C++ pour des langages de haut niveau. Il a été écrit lors des travaux de développement de Shiboken.

Dans notre cas, les critères pour le choix d'une solution finale portaient sur différents aspects :

  • Le coût de développement : prise en main de l'outil, quantité de code à écrire pour enrober une classe C++ donnée, coût de l'intégration dans le système de build, degré d'automatisation de la solution, lisibilité du code généré, etc.
  • La gestion de la mémoire : comptage de référence, gestion de la propriété des objets
  • La qualité et l'exhaustivité du support C++ : compatibilité STL, gestion des références et pointeurs, des templates, surcharges d'opérateurs, etc.
  • La pérennité de la solution : technologies mises en œuvre par l'outil, qualité de la documentation, support, taille et degré d'activité de la communauté de développeurs

Solutions envisagées

Swig n'a pas été retenu partant de l'a priori que c'était une solution plutôt lourde et davantage orientée C que C++, constat tiré lors de travaux réalisés par Logilab il y a quelques mois de cela. La solution Boost.Python n'a pas été explorée car notre souhait était de nous rapprocher davantage du Python que du C++. Shiboken semble prometteur, bien que peu documenté et mal référencé (les premières recherches tombent sur d'anciennes pages du projet, donnant l'impression que la dernière release date d'il y a plusieurs années, alors qu'en fait, non). Il a été écarté par manque de temps.

PyBindGen et Cython ont fait l'objet de tests.

La cible des tests a été l'interfaçage de smart pointers, puisque cela correspond à un de nos besoins sur le projet Code_TYMPAN.

Les essais ont été réalisés sur des classes simplifiées:

  • MyElement, classe qui représente un élément à encapsuler dans un smart pointer et hérite de IRefCount qui implémente un comptage de référence
  • SmartPtr, classe smart pointer "maison" de l'application
  • Quelques fonctions de test manipulant des smart pointers SmartPtr

Voici un extrait des en-têtes du code C++:

#ifndef MY_ELEMENT_H
#define MY_ELEMENT_H
#include <iostream>
using namespace std;
#include "SmartPtr.h"

class MyElement : public IRefCount
{
    public:
        MyElement ();
        MyElement (string);
            string Name(){ return _name; }
            virtual ~MyElement ();

    protected:
        string _name;
};
typedef SmartPtr<MyElement> SPMyElement;
#endif

#ifndef SMART_PTR_H
#define SMART_PTR_H
template <class T> class SmartPtr
{
    public:
        SmartPtr();
        SmartPtr(T*);
        const T* getRealPointer() const;

    protected:
        T* _pObj;
}
#endif

SPMyElement BuildElement();
void UseElement(SPMyElement elt);

Cython

Cet outil offre maintenant un bon support du C++ (globalement depuis la version 0.17). Son avantage est qu'il permet la manipulation d'objets à la fois C++ et Python dans des fichiers Cython.

Utilisation
  • Écriture (facultative) d'un fichier .pxd qui contient une recopie des headers à enrober (avec un lien vers les fichiers): déclarations des types, classes, fonctions...
  • Écriture d'un fichier .pyx qui contient des appels de fonctions, constructions d'objets C ou python. Les fonctions et classes de ce module sont utilisables depuis un script Python
  • Compilation du code Cython décrivant les interfaçages C++, génération et compilation du code C++ correspondant et production d'une librairie Python.

Cython offre un support pour les conteneurs de la STL, les templates, la surcharge de la plupart des opérateurs ("->" non supporté), le passage d'arguments par référence et par pointeur, etc.

Actuellement en version 0.20.1, la dernière release date du 11 février 2014. Les outils Cython sont relativement bien documentés et sa communauté de développeurs est active.

Exemple

Voici le code d'interfaçage Cython correspondant à l'exemple exposé ci-dessus:

setup.py:

from distutils.core import setup
from Cython.Build import cythonize

setup(name='smartptr',
    ext_modules=cythonize('*.pyx',
        ),
)

smartptr.pxd:

from libcpp.string cimport string

cdef extern from "src/SmartPtr.h":
    cdef cppclass SmartPtr[T]:
        SmartPtr()
        SmartPtr(T *)
        T *getRealPointer() # Pas de surcharge de ->. L'accès à l'objet ne peut être qu'explicite

cdef extern from "src/MyElement.h":
    cdef cppclass MyElement:
        MyElement()
        MyElement(string)
        string Name()

cdef extern from "src/Test.h":
    SmartPtr[MyElement] BuildSPElement()
    void UseSPElement(SmartPtr[MyElement])

smartptr.pyx:

# distutils: language = c++
# distutils: libraries = element

cimport smartptr
cimport cython

cdef class PySPMyElement:
    cdef SmartPtr[MyElement] thisptr

    def __cinit__(self, name=""):
        """ PySPMyElement constructor """
        if name == "":
            self.thisptr = SmartPtr[MyElement](new MyElement())
        else:
            self.thisptr = SmartPtr[MyElement](new MyElement(name))

    def get_name(self):
        """ Returns the name of the element """
        return self.thisptr.getRealPointer().Name()

@cython.locals(elt=PySPMyElement)
def build_sp_elt():
    """ Calls the C++ API to build an element """
    elt = PySPMyElement.__new__(PySPMyElement)
    elt.thisptr = BuildSPElement()
    return elt

@cython.locals(elt=PySPMyElement)
def use_sp_elt(elt):
    """ Lends elt to the C++ API """
    UseSPElement(elt.thisptr)

XDress

XDress est un générateur automatique de code d'interfaçage C/C++ écrit en Python, basé sur Cython.

Utilisation
  • On liste dans un fichier xdressrc.py les classes et fonctions à envelopper (il n'est pas nécessaire de mettre la signature, le nom suffit. On peut choisir d'envelopper seulement certaines classes d'un .h).
  • On exécute xdress qui génère les .pyx et .pxd correspondants

XDress permet d'envelopper des conteneurs STL via son générateur stlwrap (les conteneurs à enrober doivent être listés dans le xdressrc.py). A titre d'exemple, les vecteurs sont convertis en numpy array du type contenu.

Ce projet est récent et pas très documenté, mais il semble prometteur.

PyBindGen

Utilisation
  • Écriture d'un script Python qui décrit les classes/fonctions C++ à enrober en s'appuyant sur le module PyBindGen (1) → permet de générer un fichier .cpp
  • Compilation du code C++ généré, avec la librairie du programme à envelopper et génération d'une librairie Python.

Ce processus peut être automatisé:

  • Écriture d'un script Python qui utilise les outils PyBindGen pour lister les modules (headers) à envelopper, les lire et lancer la génération automatique des liaisons c++

ou:

  • Écriture d'un script Python qui utilise les outils PyBindGen pour lister les modules (headers) à envelopper et générer le script Python décrit en (1) (ce qui permettrait une étape intermédiaire pour personnaliser les liaisons)

PyBindGen offre un support pour la STL, l'héritage (multiple), la gestion des exceptions C++ côté Python, la surcharge d'opérateurs, le comptage de référence, la gestion de la propriété des objets. Mais il supporte mal les templates.

Actuellement en version 0.17, la dernière release date du 15 février 2014 (entre autres ajout de la compatibilité Python 3.3).

Exemple

PyBindGen, en l'état, n'offre pas la possibilité d'envelopper simplement des templates, ni des smart pointers "maison" par extension.

Une classe de ce package permet d'envelopper des shared pointers de Boost (boost::shared_ptr). Il serait à priori possible de la modifier légèrement pour enrober les smart pointers de l'application Code_TYMPAN (non testé).

Voici néanmoins à titre d'exemple le code permettant d'envelopper la classe MyElement et des fonctions manipulant non plus des smart pointers mais des 'MyElement *'

Test.h :

MyElement *BuildElement();
void UseElement(MyElement *elt);

smartptr.py :

import pybindgen
import sys
from pybindgen import retval
from pybindgen import param

mod = pybindgen.Module('smartptr')

# File includes
mod.add_include('"src/MyElement.h"')
mod.add_include('"src/Test.h"')

# Class MyElement
MyElement = mod.add_class('MyElement')
MyElement.add_constructor([])
MyElement.add_method('Name', retval('std::string'), [])


# Test functions
# transfer_ownership=False : here Python program keeps the ownership of the element it passes to the C++ API
mod.add_function('UseElement', None, [param('MyElement *', 'elt', transfer_ownership=False)])
# caller_owns_return=True : here Python program will be responsible for destructing the element returned by BuildElement
mod.add_function('BuildElement', retval('MyElement *',  caller_owns_return=True), [])

if __name__ == '__main__':
    mod.generate(sys.stdout)

Boost.Python

Les liaisons Python s'écrivent directement en C++.

C'est un outil très fiable et pérenne, avec de par sa nature un très bon support C++ : gestion de la mémoire, templates, surcharges d'opérateurs, comptage de référence, smart pointers, héritage, etc.

Inconvénient : la syntaxe (en mode templates C++) n'est pas très intuitive.

Conclusion

Les solutions Cython et PyBindGen ont été explorées autour de la problématique d'enrobage de smart pointers. Il en est ressorti que:

  • Il est possible d'enrober facilement des smart pointers Code_TYMPAN en Cython. L'approche qui a été choisie est de manipuler depuis Python les objets C++ directement au travers de smart pointers (les objets Python contenus dans le .pyx encapsulent des objets SmartPtr[T *], agissant donc comme des proxys vers les objets). De cette façon, l'utilisation depuis Python d'un objet C++ incrémente le compteur de référence côté C++ et cela garantit qu'on ne perdra pas la référence à un objet au cours de son utilisation côté Python. Un appel à getRealPointer() pour enrober des fonctions manipulant directement des T * sera toujours possible dans le code Cython au besoin.
  • PyBindGen présente l'intérêt d'offrir des moyens de gérer l'attribution de la propriété des éléments entre C++ et Python (transfer_ownership, caller_owns_return). Malheureusement, il n'offre pas la possibilité d'enrober des smart pointers sans modification de classes PyBindGen, ni d'envelopper des templates.

Par ailleurs, après utilisation de PyBindGen, il nous a semblé que bien qu'il présente des idées intéressantes, sa documentation, ses tutoriels et son support sont trop succints. Le projet est développé par une seule personne et sa viabilité est difficile à déterminer. Cython en revanche offre un meilleur support et plus de fiabilité.

Le choix final s'est donc porté sur Cython. Il a été motivé par un souci d'utiliser un outil fiable limitant les coûts de développement (élimination de PyBindGen), aussi proche de Python que possible (élimination de Boost.Python). Cet outil semble fournir un support C++ suffisant par rapport à nos besoins tels que perçus à ce stade du projet.

De plus si on cherche un moyen de générer automatiquement les liaisons Python, XDress présente l'avantage de permettre l'utilisation de libclang comme alternative à gcc-xml (PyBindGen est basé sur gcc-xml uniquement). Une possibilité serait par ailleurs d'utiliser XDress pour générer uniquement le .pxd et d'écrire le .pyx manuellement.

Une question qui n'a pas été abordée au cours de cette étude car elle ne correspondait pas à un besoin interne, mais qui est néanmoins intéressante est la suivante: est-il possible de dériver depuis Python des classes de base définies en C++ et enveloppées en Cython, et d'utiliser les objets résultants dans l'application C++ ?

[logilab] Open Science à Toulouse : barcamp sur les Biens Communs

Publié le 2014-04-16 11:17:00

Le deuxième apéritif et barcamp de la communauté Open Science Toulousaine aura lieu le 24 avril à 19h00 au bar El Deseo, 11 rue des Lois, à deux pas du Capitole et de St Sernin sur le thème des biens communs.

Plus d'informations sur http://hackyourphd.org/2014/04/aperitif-open-science-toulouse-les-biens-communs/

[afpyro] AFPyro à Montreal - le 12 Avril

Publié le 2014-04-12 00:00:00

A l’occasion de Pycon U.S., l’AFPy organise son premier AFPyro à Montréal ! Venez échanger autour d’une bonne bière artisanale avec la comunauté francophone python !

AFPy is organizing its first AFPyro at PyCon U.S. in Montreal! Come and meet the french python community around a good craft beer!

Quand ? When ?

Le Samedi 12 Avril, vers 19h

Saturday 12th of April at 7PM

Ou ? / Where ?

Le Benelux Sherbrooke (map)

25, rue Sherbrooke Ouest

Montréal, QC H2X 1X7

[j-mad] DjangoIsland, parce que les poneys savent nager

Publié le 2014-04-10 15:41:02
Vous êtes djangonautes ? Et vous n’avez pas encore acheté votre billet pour DjangoCon Europe ? Alors peut-être que vous ne le saviez pas. Après tout, même si on a essayé de faire un maximum de com sur le sujet, on n’en fait jamais assez et il est fort possible que vous soyez passé à coté. Donc, [...]

[logilab] Deuxième hackathon codes libres de mécanique

Publié le 2014-04-07 17:12:00

Organisation

Le 27 mars 2014, Logilab a accueilli un hackathon consacré aux codes libres de simulation des phénomènes mécaniques. Etaient présents:

  • Patrick Pizette, Sébastien Rémond (Ecole des Mines de Douai / DemGCE)
  • Frédéric Dubois, Rémy Mozul (LMGC Montpellier / LMGC90)
  • Mickaël Abbas, Mathieu Courtois (EDF R&D / Code_Aster)
  • Alexandre Martin (LAMSID / Code_Aster)
  • Luca Dall'Olio, Maximilien Siavelis (Alneos)
  • Florent Cayré, Nicolas Chauvat, Denis Laxalde, Alain Leufroy (Logilab)

DemGCE et LMGC90

Patrick Pizette et Sébastien Rémond des Mines de Douai sont venus parler de leur code de modélisation DemGCE de "sphères molles" (aussi appelé smooth DEM), des potentialités d'intégration de leurs algorithmes dans LMGC90 avec Frédéric Dubois du LMGC et de l'interface Simulagora développée par Logilab. DemGCE est un code DEM en 3D développé en C par le laboratoire des Mines de Douai. Il effectuera bientôt des calculs parallèles en mémoire partagée grâce à OpenMP. Après une présentation générale de LMGC90, de son écosystème et de ses applications, ils ont pu lancer leurs premiers calculs en mode dynamique des contacts en appelant via l'interface Python leurs propres configurations d'empilements granulaires.

Ils ont grandement apprécié l'architecture logicielle de LMGC90, et en particulier son utilisation comme une bibliothèque de calcul via Python, la prise en compte de particules de forme polyhédrique et les aspects visualisations avec Paraview. Il a été discuté de la réutilisation de la partie post/traitement visualisation via un fichier standard ou une bibliothèque dédiée visu DEM.

Frédéric Dubois semblait intéressé par l'élargissement de la communauté et du spectre des cas d'utilisation, ainsi que par certains algorithmes mis au point par les Mines de Douai sur la génération géométrique d'empilements. Il serait envisageable d'ajouter à LMGC90 les lois d'interaction de la "smooth DEM" en 3D, car elles ne sont aujourd'hui implémentées dans LMGC90 que pour les cas 2D. Cela permettrait de tester en mode "utilisateur" le code LMGC90 et de faire une comparaison avec le code des Mines de Douai (efficacité parallélisation, etc.).

Florent Cayré a fait une démonstration du potentiel de Simulagora.

LMGC90 et Code_Aster dans Debian

Denis Laxalde de Logilab a travaillé d'une part avec Rémy Mozul du LMGC sur l'empaquetage Debian de LMGC90 (pour intégrer en amont les modifications nécessaires), et d'autre part avec Mathieu Courtois d'EDF R&D, pour finaliser l'empaquetage de Code_Aster et notamment discuter de la problématique du lien avec la bibliothèque Metis: la version actuellement utilisée dans Code_Aster (Metis 4), n'est pas publiée dans une licence compatible avec la section principale de Debian. Pour cette raison, Code_Aster n'est pas compilé avec le support MED dans Debian actuellement. En revanche la version 5 de Metis a une licence compatible et se trouve déjà dans Debian. Utiliser cette version permettrait d'avoir Code_Aster avec le support Metis dans Debian. Cependant, le passage de la version 4 à la version 5 de Metis ne semble pas trivial.

Voir les tickets:

Replier LibAster dans Code_Aster

Alain Leufroy et Nicolas Chauvat de Logilab ont travaillé à transformer LibAster en une liste de pull request sur la forge bitbucket de Code_Aster. Ils ont présenté leurs modifications à Mathieu Courtois d'EDF R&D ce qui facilitera leur intégration.

Voir les tickets:

Suppression du superviseur dans Code_Aster

En fin de journée, Alain Leufroy, Nicolas Chauvat et Mathieu Courtois ont échangé leurs idées sur la simplification/suppression du superviseur de commandes actuel de Code_Aster. Il est souhaitable que la vérification de la syntaxe (choix des mots-clés) soit dissociée de l'étape d'exécution.

La vérification pourrait s'appuyer sur un outil comme pylint, la description de la syntaxe des commandes de Code_Aster pour pylint pourrait également permettre de produire un catalogue compréhensible par Eficas.

L'avantage d'utiliser pylint serait de vérifier le fichier de commandes avant l'exécution même si celui-ci contient d'autres instructions Python.

Allocation mémoire dans Code_Aster

Mickaël Abbas d'EDF R&D s'est intéressé à la modernisation de l'allocation mémoire dans Code_Aster et a listé les difficultés techniques à surmonter ; l'objectif visé est un accès facilité aux données numériques du Fortran depuis l'interface Python. Une des difficultés est le partage des types dérivés Fortran en Python. Rémy Mozul du LMGC et Denis Laxalde de Logilab ont exploré une solution technique basée sur Cython et ISO-C-Bindings. De son côté Mickaël Abbas a contribué à l'avancement de cette tâche directement dans Code_Aster.

Doxygen pour documentation des sources de Code_Aster

Luca Dall'Olio d'Alneos et Mathieu Courtois ont testé la mise en place de Doxygen pour documenter Code_Aster. Le fichier de configuration pour doxygen a été modifié pour extraire les commentaires à partir de code Fortran (les commentaires doivent se trouver au dessus de la déclaration de la fonction, par exemple). La configuration doxygen a été restituée dans le depôt Bitbucket. Reste à évaluer s'il y aura besoin de plusieurs configurations (pour la partie C, Python et Fortran) ou si une seule suffira. Une configuration particulière permet d'extraire, pour chaque fonction, les points où elle est appelée et les autres fonctions utilisées. Un exemple a été produit pour montrer comment écrire des équations en syntaxe Latex, la génération de la documentation nécessite plus d'une heure (seule la partie graphique peut être parallélisée). La documentation produite devrait être publiée sur le site de Code_Aster.

La suite envisagée est de coupler Doxygen avec Breathe et Sphinx pour compléter la documentation extraite du code source de textes plus détaillés.

La génération de cette documentation devrait être une cible de waf, par exemple waf doc. Un aperçu rapide du rendu de la documentation d'un module serait possible par waf doc file1.F90 [file2.c [...]].

Voir Code Aster #18 configure doxygen to comment the source files

Catalogue d'éléments finis

Maximilien Siavelis d'Alneos et Alexandre Martin du LAMSID, rejoints en fin de journée par Frédéric Dubois du LMGC ainsi que Nicolas Chauvat et Florent Cayré de Logilab, ont travaillé à faciliter la description des catalogues d'éléments finis dans Code_Aster. La définition de ce qui caractérise un élément fini a fait l'objet de débats passionnés. Les points discutés nourriront le travail d'Alexandre Martin sur ce sujet dans Code_Aster. Alexandre Martin a déjà renvoyé aux participants un article qu'il a écrit pour résumer les débats.

Remontée d'erreurs de fortran vers Python

Mathieu Courtois d'EDF R&D a montré à Rémy Mozul du LMGC un mécanisme de remontée d'exception du Fortran vers le Python, qui permettra d'améliorer la gestion des erreurs dans LMGC90, qui a posé problème dans un projet réalisé par Denis Laxalde de Logilab pour la SNCF.

Voir aster_exceptions.c

Conclusion

Tous les participants semblaient contents de ce deuxième hackathon, qui faisait suite à la première édition de mars 2013 . La prochaine édition aura lieu à l'automne 2014 ou au printemps 2015, ne la manquez pas !

[logilab] Naissance de la communauté Open Science Toulousaine

Publié le 2014-04-02 17:50:00

Ils étaient une vingtaine à se (re)trouver à l’occasion du premier apéritif & barcamp Open Science à Toulouse organisé par Logilab et Hack your PhD. La plupart étaient avant tout curieux de voir qui et quoi se cachaient derrière cette annonce :

un rendez-vous périodique, informel et sympathique a pour but de favoriser les échanges entre tous les acteurs intéressés par un aspect de l’Open Science : Open Data, les rapports Sciences & Société, Open Source, Open Access, Big Data & Data Science, etc.

Curieux souvent parce qu’ils s’étaient reconnus dans l’une ou l’autre – et souvent plusieurs – de ces facettes de l’Open Science sans avoir déjà rencontré l’étiquette Open Science pour autant.

Les échangent se nouent dans la communauté Open Science

Mais alors l’Open Science : c’est quoi ?

Heureusement personne n’a asséné de définition définitive. J’ai tenté de montrer, à travers une brève présentation de Hack your PhD et de Logilab comment l’Open Science est avant tout une démarche d’ouverture dans la pratique de la recherche scientifique qui s’étend au delà du cadre du laboratoire.

L’objectif de la soirée était de permettre à la communauté Open Science locale de se découvrir ; aux acteurs de science ou d’ouverture de faire connaissance. De fait les discussions et prises de contacts informelles allaient bon train autour d’un verre et quelques tapas… et c’est donc à chacun des participants de partager ses échanges sur le thème que fait-on à Toulouse ?

Le fournisseur d’accès associatif tetaneutral nous met à disposition une liste de diffusion à l’adresse open-science-toulouse@lists.tetaneutral.net. Merci à eux ! J’invite vivement les participants à l’apéro à s’y présenter en quelques mots : faites nous part de votre perception de cet événement et partager vos intérêts et projets.

On se retrouvera bientôt pour un prochain événement qui tiendra plus de l’atelier. Quelques suggestion qui sont dores et déjà apparues : un atelier sur les outils pratiques pour être ouvert, un séminaire dans un centre de recherche universitaire, un atelier sur les alignements de données publiques et l’évolutivité des schéma de données avec CubicWeb, …

Vos propositions sont très bienvenues : la communauté Open Science Toulousaine deviendra ce qu’ensemble nous en ferons !

Ce compte rendu a été initialement publié sur le site de hackyourphd : http://hackyourphd.org/2014/02/naissance-de-la-communaute-toulousaine/

[logilab] Code_Aster back in Debian unstable

Publié le 2014-04-01 12:44:00

Last week, a new release of Code_Aster entered Debian unstable. Code_Aster is a finite element solver for partial differential equations in mechanics, mainly developed by EDF R&D (Électricité de France). It is arguably one of the most feature complete free software available in this domain.

Aster has been in Debian since 2012 thanks to the work of debian-science team. Yet it has always been somehow a problematic package with a couple of persistent Release Critical (RC) bugs (FTBFS, instalability issues) and actually never entered a stable release of Debian.

Logilab has committed to improving Code_Aster for a long time in various areas, notably through the LibAster friendly fork, which aims at turning the monolithic Aster into a library, usable from Python.

Recently, the EDF R&D team in charge of the development of Code_Aster took several major decisions, including:

  • the move to Bitbucket forge as a sign of community opening (following the path opened by LibAster that imported the code of Code_Aster into a Mercurial repository) and,
  • the change of build system from a custom makefile-style architecture to a fine-grained Waf system (taken from that of LibAster).

The latter obviously led to significant changes on the Debian packaging side, most of which going into a sane direction: the debian/rules file slimed down from 239 lines to 51 and a bunch of tricky install-step manipulations were dropped leading to something much simpler and closer to upstream (see #731211 for details). From upstream perspective, this re-packaging effort based on the new build-system may be the opportunity to update the installation scheme (in particular by declaring the Python library as private).

Clearly, there's still room for improvements on both side (like building with the new metis library, shipping several versions of Aster stable/testing, MPI/serial). All in all, this is good for both Debian users and upstream developers. At Logilab, we hope that this effort will consolidate our collaboration with EDF R&D.

[sciunto] Manuscript : Scikit-image : Traitement d'images en Python

Publié le 2014-03-30 22:00:00

Scikit-image est une bibliothèque de traitement d'images en Python. Nous venons de soumettre un manuscript à PeerJ dont le PrePrint est téléchargeable. EDIT: et le papier publié est ici version finale.

Je suis très heureux d'avoir eu l'occasion de participer à la rédaction de ce manuscript où j'ai pu illustrer un code utilisé à des fins de recherche académique dont j'ai implémenté l'algorithme dans la bibliothèque. L'histoire a voulu qu'ayant en tête cette application précise, j'ai cherché un algorithme et ne trouvant pas une implémentation qui me plaisait en Python, j'en ai proposé une à scikit-image. J'en parlais il y a un an dans cet article (transformée de Hough). La boucle est bouclée !

J'ai aussi écrit la partie "getting started" pour découvrir la bibliothèque en douceur, si vous ne la connaissez pas.

Le manuscript a l'avantage de présenter des cadres divers d'utilisation de scikit-image, grâce à la diversité des auteur(e)s. On trouve de la recherche en biologie, une application en entreprise pour détecter des défauts sur des surfaces, l'utilisation de la bibliothèque dans l'enseignement et enfin, une belle illustration du recollement d'images, le résultat est vraiment impressionnant.

Outre ces usages, on mets en avant le fait que scikit-image s'appuie fortement sur NumPy, ce qui permet facilement d'appliquer d'autres algo disponibles dans SciPy, Scikit-learn, etc.

C'est la première fois que j'écris un papier de manière collaborative avec git et le mécanisme de pull requests de github, et je dois dire que c'est très efficace. Le commentaire ligne à ligne avant l'inclusion permet d'atteindre très rapidement un document de qualité. Merci aux co-auteurs pour cette expérience !

[Biologeek] Talents publicitaires

Publié le 2014-03-30 11:00:00

Dans le milieu informatique, les outils et services que nous utilisons sur l’ordinateur et en réseau engagent certaines réactions. Ce qui me paralyse de plus en plus avec les services proposés en ligne, avec les univers policés crées par des armées de designers et de personnes en charge du UX est la contrainte grandissante de l’outil dans un type d’actions très contrôlées. L’optimisation du contrôle afin de rendre « l’expérience plus efficace. » Mais bien souvent, en faisant cela, nous perdons également toutes ces souplesses qui rendent les gens créatifs, qui incitent chacun à s’investir, à s’approprier et à créer les espaces de leur choix.

De nombreux services en ligne ne sont pas là pour maximiser l’appropriation de l’utilisateur, mais bien pour optimiser la rentabilité et la profitabilité du service.

La flexibilité de l’environnement, Karl Dubost

Hypothèse qui se révèle être confirmée dans le cas de Facebook lors d’une refonte récente un peu trop optimisée pour l’utilisateur (et pas assez pour les revenus). Est-ce qu’il faut pour autant penser que la publicité soit le moteur du Web comme l’affirme Christian Heilmann ?

Hang on a second. Whether we like it or not, ads are what makes the current internet work. They are what ensures the “free” we crave and benefit from, and if you dig deep enough you will find that nobody working in web development or design is not in one way or another paid by income stemming from ad sales on the web. Thus, us pretending that ads are for other people is sheer arrogance.

Why “just use Adblock” should never be a professional answer

Ayant pour client Mozilla qui tire une bonne partie de ses revenus de Google, je ne peux malheureusement qu’acquiescer. Et me sentir acteur de ce blanchiment pseudo-éthique d’argent sale. Adworld, cliquez-ici pour acheter un rêve mondialisé.

Car par la même occasion, ces mastodontes nivellent les goûts et le monde ressemble à une banlieue australienne, standardisée for ever, à coup d’adolescents éternels et du divorce des parents : are you up to date ? La mise à jour permanente de nos besoins infinis passe aujourd’hui par l’écoute laconique de nos goûts sans démesure, le goût des autres est aussi le nôtre, et l’on ciblera l’humeur du moment selon que l’on "clique" ici ou là. Quand je pense aux utopies que nous balancions fiers et jeunes au début de ce que l’on croyait être le "web indépendant" : ah les cons ! D’autres ont bien mieux compris ce que l’on pouvait tirer de cette rêverie en termes monétaires : de la bulle financière comme dans un bain moussant.

Tout dans le client !

Quelles options reste-t-il pour passer entre les bulles ? Travailler avec le public est une possibilité, les bulles financières se transformant en savonnettes politiques. Terrain glissant dont les ambitions et les moyens sont limités à 5 ans. Après nous le déluge d’URLs cassées. Sans savon.

The reason why I find business models so fascinating is because your business model is your destiny; newspapers made their bed with advertisers, and when advertisers left for a better product, the newspaper was doomed. To change destiny, journalists need to fundamentally rethink their business

Newspapers Are Dead; Long Live Journalism

Encourager l’innovation est une autre option, en accompagnant des projets depuis leur départ. En brisant trop souvent des rêves impossibles qui ne méritent que de maigrir avec le dernier régime à la mode. Et puis il reste la question du financement. Et des taxes.

Hiring was delayed, partly because of social taxes that companies pay on salaries. In France, the share of nonwage costs for employers to fund unemployment benefits, education, health care and pensions is more than 33 percent. In Britain, it is around 20 percent.

Au Revoir, Entrepreneurs

Quelle honte d’accorder 33% de son revenu à son espace de vie. À l’éducation que l’on a reçu, aux soins dont on bénéficie. Mais rassurez-vous, vous pouvez en être dispensé grâce au fabuleux statut de JEI qui fait pâlir d’envie outre-atlantique :

  • Someone throws a “but what about the high taxes?” at you – you respond with “I subsidize all of my R&D with Government grants (up to €100M/year), and my company has a JEI status which wipes out employment taxes on engineers.“
  • Someone throws a “What about strict employment laws?” at you, and you better be ready with “All our employees start with a legal 6-month trial period which allows me to fire them at a moment’s notice, and most of France’s strict employment laws don’t kick in until you have 50 employees: that’s how many WhatsApp had when it was acquired for $19 Billion.”

Bonjour, Entrepreneurs – Only you can prevent French-Bashing

Et cerise sur le gâteau, on peut virer ses salariés dans les 6 mois sans aucun risque. Sous réserve de rester en-dessous des 50 salariés (excluant les stagiaires bien entendu). Et puis un développeur français est si peu cher, pourquoi s’en priver ?

Voilà, Tariq, les talents français du code sont au mieux de la chair à canons publicitaires US. Ce n’est pas d’un Github à la française dont nous avons besoin, mais d’une multitude de projets citoyens. Pour créer du lien social, du lien inter-générationel, du lien local, du lien politique. Pour se sentir utile en tant que développeur, pour se sentir agile en tant qu’humain.

[hautefeuille] Programmation asynchrone avec Python 3.4 et le module asyncio

Publié le 2014-03-28 16:50:00

Introduction

Le module Python Asyncio est un module qui fournit une infrastructure pour écrire du code monothreadé concurrent en utilisant des coroutines, en multiplexant les Entrées/Sorties au-dessus de sockets ou d’autres ressources, et en démarrant des clients et des serveurs.

Les coroutines

Une coroutine est exécutée par l’expression yield from. Une coroutine est une fonction qui contient au moins une expression yield from.

Les tâches

Une tâche n’est pas exécutée par l’expression yield from. Une tâche est un objet qui gère une coroutine. Une tâche permet d’annuler une coroutine déjà exécutée. Une tâche permet d’exécuter une coroutine sous une coroutine existante.

Exemple de communication avec des websockets

Le projet Websockets permet d’utiliser simplement les websockets au-dessus du module asyncio. Ce sont ces websockets que nous allons utiliser pour réaliser le pattern consommateur/producteur.

Pour son installation :

sudo pip3.4 install websockets

Exemple :

import asyncio
import websockets

# Server
@asyncio.coroutine
def producer(websocket, uri):
    count = 0
    while websocket.open:
        yield from asyncio.sleep(1)
        count = count + 1
        yield from websocket.send(str(count))

# Client
@asyncio.coroutine
def consumer():
    websocket = yield from websockets.connect('ws://localhost:8765/')
    while websocket.open:
        count = yield from websocket.recv()
        print("%s" % count)

start_server = websockets.serve(producer, 'localhost', 8765)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_until_complete(consumer())
asyncio.get_event_loop().run_forever()

Ce qui est intéressant dans ce cas, est que le consommateur peut être un client Javascript.

Exemple de communication avec une file d’attente

Dans cet exemple, nous allons utiliser une file d’attente illimitée pour échanger entre les coroutines. Si l’on choisit une file d’attente de taille fixe, celle-ci est bloquante si elle n’est pas vidée.

Exemple :

import asyncio

q = asyncio.Queue(maxsize=0)

@asyncio.coroutine
def producer():
    for elem in range(5):
        yield from q.put(elem)

@asyncio.coroutine
def consumer():
    while True:
        elems = yield from q.get()
        print(elems)

asyncio.get_event_loop().run_until_complete(producer())
asyncio.get_event_loop().run_until_complete(consumer())
asyncio.get_event_loop().run_forever()

L’intérêt ici, est l’utilisation d’une file d’attente sur laquelle on peut s’appuyer pour un contrôle de flux.

Liens

doc asyncio module

[afpyro] AFPyro à Paris - le 27 Mars

Publié le 2014-03-27 00:00:00

C’est l’été ou presque. Il est temps de profiter des terrasses!

Venez discuter de votre langage de programmation favori autour d’un verre et plus si affinités.

Quand ?

Le Jeudi 27 Mars, vers 19h00.

Où ?

Café Chéri(e) (plan)

44 bd de la Villette, 75019 Paris (FR).

Métro: Belleville / Colonel Fabien

[afpyro] AFPyro à Lyon - mardi 25 mars

Publié le 2014-03-25 00:00:00

Un Afpyro aura lieu le mardi 25 mars à partir de 19h à l’Antre Autre - 11 rue Terme - 69001 Lyon.

Cet apéro Python sera commun avec l’apéro Php.

Une présentation sera faite sur la sécurité web. Après un aperçu des principales failles présentes dans les applications web, une réflexion sur les failles XSS sera faite et une méthode de protection efficace contre une partie de celles-ci sera présentée. Enfin, le thème de la sécurité sera abordé de façon plus général (politique de sécurité, bonnes pratiques...).

L’Antre Autre est un lieu où nous pouvons discuter autour d’un verre, et, pour ceux qui le souhaitent, prendre un repas.

Pour se rendre à l’Antre Autre :

  • en métro : arrêt Hôtel de Ville
  • en bus : lignes C13 et C18 arrêt Mairie du 1er ou lignes 19, C14 et C3 à l’arrêt Terreaux
  • en vélo’v : stations Place Sathonay, Carmélites Burdeau, Place de la paix

[afpy.org] 1er Python Meetup le 9 avril à la Cantine de Nantes

Publié le 2014-03-22 01:34:24
GrapheekDB une base de données graph rapide !

[hautefeuille] Golang API pour le site cex.io

Publié le 2014-03-21 16:50:00

Cex.io est un site d’achat et de vente de possibilités de générer des Bitcoins. Il permet d’acheter ou de vendre des GH/s. Le GH/s correspond à la capacité de calcul nécessaire à générer des Bitcoins.

Le site Cex.io propose les API pour les langages suivants : Php, Node.js et Python. Malheureusement, certaines de ces API ne me conviennent pas ou sont incomplètes.

Le projet qui nécessite d’utiliser une telle API est un projet réalisé en langage Go. J’ai donc essayé de développer une API dans ce langage pour le site Cex.io et pour les besoins du projet.

La partie du code source la plus intéressante est celle qui concerne l’authentification. La description des contraintes d’authentification est détaillée sur la page dédiée à l’API du site Cex.io.

Nonce” est un nombre entier arbitraire. Il doit être incrémenté à chaque requête. J’utilise ici le temps Unix retourné en nanoseconde.

Signature” est un message chiffré avec l’algorithme HMAC-SHA256. Ce message contient : le nombre entier (Nonce), le nom de l’utilisateur (client id) et la clé de l’API. Le code HMAC-SHA256 doit être généré en utilisant une clé secrète qui est générée avec la clé de l’API. Le code doit être converti dans sa représentation hexadécimale en majuscule.

Le code de l’authentification qui résout ces contraintes :

// Key structure
type CexKey struct {
    Username string
    Api_key string
    Api_secret string
}

// Return Unix time in nano
func (cexapi *CexKey) Nonce() string {
    return strconv.FormatInt(time.Now().UnixNano(), 10)
}

// Return sha256 hashing
func (cexapi *CexKey) ToHmac256(message string, secret string) string {
    key := []byte(secret)
    h := hmac.New(sha256.New, key)
    h.Write([]byte(message))
    return strings.ToUpper(hex.EncodeToString(h.Sum(nil)))
}

// Return formatted signature
func (cexapi *CexKey) Signature() (string, string) {
    nonce := cexapi.Nonce()
    message := nonce + cexapi.Username + cexapi.Api_key
    signature := cexapi.ToHmac256(message, cexapi.Api_secret)
    return signature, nonce
}

L’API est disponible à cette adresse : https://github.com/jhautefeuille/go-cexio-api.

L’API s’utilise de la façon suivante :

package main

import (
    "github.com/jhautefeuille/go-cexio-api"
    "fmt"
)

func main() {
    cexapi := cexio.CexKey{
        Username:"your_username", 
        Api_key:"your_api_key", 
        Api_secret:"your_api_secret"}

    // Public
    fmt.Printf("Ticker => %s\n", cexapi.Ticker("GHS/BTC"))
    //fmt.Printf("Order Book => %s\n", cexapi.OrderBook("GHS/BTC"))
    //fmt.Printf("Trade History => %s\n", cexapi.TradeHistory("GHS/BTC"))

    // Private
    fmt.Printf("Balance => %s\n", cexapi.Balance())
    fmt.Printf("Open Orders => %s\n", cexapi.OpenOrders("GHS/BTC"))

    // Trading orders
    //fmt.Printf("Place Order => %s\n", cexapi.PlaceOrder("buy", "0.001", "0.017", "GHS/BTC"))
    //fmt.Printf("Cancel Order => %s\n", cexapi.CancelOrder("477571539"))

    // Workers 
    fmt.Printf("Hashrate => %s\n", cexapi.Hashrate())
    fmt.Printf("Workers => %s\n", cexapi.Workers())
}

Dans une application, on peut également profiter du package “encoding/json” :

package main

import (
    "go-cexio-api"
    "fmt"
    "encoding/json"
)

type Ticker_ struct {
    Timestamp string
    Bid float64
    Ask float64
    Low string
    High string
    Last string
    Volume string
}

func main() {
    cexapi := cexio.CexKey{
        Username:"your_username", 
        Api_key:"your_api_key", 
        Api_secret:"your_api_secret"}

    my_json := cexapi.Ticker("GHS/BTC")
    var myticker Ticker_
    json.Unmarshal([]byte(my_json), &myticker)

    fmt.Println("ticker", myticker.Bid)
}

La conversion du JSON vers la structure est une fonction très puissante dans le langage Go :

json.Unmarshal([]byte(my_json), &myticker)

Un utilisateur m’a contacté au sujet de cette API. D’autres versions améliorées sont à prévoir. Le développement de cette application m’a permis d’appréhender le langage Go que je n’avais pas encore utilisé.

[tshirtman] Prepare for the Kivy contest #2

Publié le 2014-03-16 01:50:00

Developers, developers… rejoice!

kivy contest

The kivy project is organizing a second contest!

From the 15th of April, when the theme will be revealed, to the 15th of May, the final deadline, all the interested candidates will compete to produce the nicest application possible, once month to make the difference, and collect prices :).

Prizes will be announced before the beginning of the contest, the python software foundation kindly offered to sponsor the contest, if you are or know somebody interested in sponsoring the contest, please contact us at contest@kivy.org.

[afpy.org] « Les Ateliers Python » au NUMA de Paris, lundi 24 mars à 19h

Publié le 2014-03-14 11:24:18
L'AFPy organise au NUMA un événement consistant en 4 présentations de 20 minutes chacune, autour du thème : « Python pour DevOps : Ansible & SaltStack »