Planète AFPy RSS

[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.

[anybox] Sphinx autodoc et modules OpenERP

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

[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.

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

[Biologeek] Agilité personnelle

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

L’agilité est décrite dans un cadre professionnel, bien trop souvent afin d’améliorer les performances d’une entreprise en ignorant les valeurs sous-jacentes. Or lorsqu’on commence à creuser un peu, on découvre des applications qui peuvent être très personnelles.

À titre individuel, je partage mes réussites, mes doutes, mes envies, mes échecs aussi. Ces rétrospectives me permettant d’avancer et d’insuffler parfois un peu d’énergie pour faire avancer les autres. Une fois dépassée la peur de l’échec, l’estime et la passion sont les clés de l’accomplissement de soi.

En tant que parent, je redécouvre chaque jour que rien n’est acquis et qu’il va falloir s’adapter en permanence, non pas dans une démarche d’amélioration continue mais dans une approche d’éducation continue. Mais pour cela il faut créer une boucle de rétro-action familiale, l’attention et l’amour sont les clés de la vie familiale.

En tant que coopérateur, j’ai le courage de débloquer des situations avant qu’elles ne dégénèrent tout en respectant les singularités de chacun. Je suis prêt à accepter des inconforts pour que le commun aille de l’avant. Lorsque l’on partage le même cap, la confiance et l’empathie sont les clés de la vie collaborative.

En tant que citoyen, je fais partie de la même équipe que mon voisin. Il n’y a pas de partis clivants, de campagnes électorales stériles ou de programmes obsolètes. Il y a des humains qui œuvrent ensemble pour pouvoir vivre sur un même territoire. Rien ne sert de stigmatiser une partie de l’équipe par manque de confiance, l’enthousiasme et la bienveillance sont les clés de la vie en communauté.

[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

[Biologeek] Éducation citoyenne et Web

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

Somewhere in the mid 1990s, we lost our way. The education system largely ignored the explosive growth of computing and the internet, instead focusing on teaching students how to write Word documents. Instead of a nation of builders and entrepreneurs, we were content for our children to become also-rans on the technology stage.

We at the Year of Code are going to help change that. The new computing curriculum starts this September, and it puts coding at the heart of IT education. Coding is the art of telling a computer how to perform complex tasks. Once you know how to code, you can create virtual worlds within the computer where the only limit on what is possible is your imagination. We want to put this power into the hands and hearts of every child in Britain.

Why every child should learn to code

Il y a une recrudescence d’organisations de Coding Goûters et c’est une excellente chose, les parents sont ravis et je me sens forcément concerné ces derniers temps. Je ne remets pas du tout en question cette démarche louable sachant qu’il y a eu débat sur la nécessité ou pas d’apprendre à coder à chaque enfant : toutes les énergies sont bonnes à prendre lorsqu’il s’agit d’éducation.

Suite à ces initiatives, je me suis mis à penser qu’il ne fallait peut-être pas restreindre cela aux enfants. Après tout, l’apprentissage est possible tout au long de la vie si l’on arrive à conserver son enthousiasme. Et d’ailleurs pourquoi même se limiter au développement ? Avez-vous demandé à vos proches leur définition du Web ?

Puis je suis allé plus loin dans ma réflexion suite à l’engouement pour horsweb — la conférence des gens du web, sur tout sauf le web — en m’interrogeant sur sa réciproque : des rencontres sur le Web sans gens du Web. Il est certain que nous avons des choses hors web à nous apprendre entre pairs mais nous pourrions aussi vulgariser notre connaissance auprès de citoyens curieux. Quelle forme est-ce que cela pourrait prendre ? Comment toucher/intéresser un public aussi large ? Quel cadre permettrait d’avoir une meilleure fluidité au sein des participants ?

[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é.

[Biologeek] Utiliser NodeJS

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

Sadly I’m not going to get back where I was, because Javascript is not Python. If there’s a Javascript community I haven’t found it, or it’s at least not a single entity. There is no community that created Javascript like the Python community created Python. Python comes from the internet in a way Javascript does not; Javascript was built for the internet, but Python was built on the internet. And I do miss the Python community, you’re good people.

[…]

I suppose it is the platform that I am drawn to now before language. And the browser seems like the most interesting platform, not because it’s novel (though it is, it’s a runtime like few others), but because of how concrete it is, and of course how relevant it is to… anything. And the browser is no longer just the servant of a server, I prefer now to think of the browser as an independent agent, connecting to services instead of servers. Obviously that doesn’t describe a great number of running web sites, but it’s the model I see for the future, and a better perspective for understanding future architectures.

Saying Goodbye To Python, Ian Bicking

Préambule : il est difficile de comparer Node à Python ou Django car on n’a pas l’équivalent d’une telle plateforme dans l’écosystème Python. Je vais essayer de ne pas comparer des choux et des carottes pour autant.

Thomas demandait sur Twitter « les raisons pour lesquelles vous n’utiliseriez pas Node.js ? » et comme ça a l’air d’être la saison des trolls sur JS, je vais y aller de ma petite expérience. J’ai récemment participé au développement d’une implémentation de référence pour le Marketplace de Mozilla. Comme son nom l’indique, elle n’était pas destinée à être mise en production donc on a eu la liberté d’utiliser la technologie que l’on souhaitait, en l’occurrence : Node.

Confession : je me suis longtemps détourné de JavaScript pour son API DOM que je trouve affreuse, j’aurais mieux fait de coder ces quelques lignes pour ne plus avoir à troller et prendre le temps d’expérimenter

Je vais prendre 3 axes, je pourrais facilement arriver à une telle critique avec Python (packaging, Python 3 et GIL par exemple), il s’agit surtout ici de me rappeler pourquoi est-ce que je n’utilise pas Node aujourd’hui.

  • immaturité : même s’il est plaisant de faire partie de ce bouillonnement qui sort une lib par jour, qui en remet en question une autre par semaine, à la longue c’est épuisant et ça crée un stress dont je ne veux plus. Fatigué de courir après la dernière technologie pour mieux… placer des publicités aux utilisateurs (un billet est à venir là-dessus).
  • documentation : quand je vois une telle page, je me rends compte à quel point la documentation de Django est bien faite. C’est devenu pour moi le niveau de référence que je ne retrouve malheureusement pas ailleurs, à part quelques rares exceptions. D’une manière générale j’ai trouvé les bibliothèques que j’ai eues à utiliser mal documentées dans l’écosystème Node/JS.
  • debugging : je ne compte plus le nombre de fois où le message d’erreur était soit absent, soit une ligne incompréhensible (même après avoir trouvé la solution), soit dépendant de la lib de test que j’utilisais. Ce point est peut-être lié à mes habitudes ou à mon incompétence mais en tout cas pour un débutant c’est très rebutant.

Ces raisons font que je ne partirais pas aujourd’hui sur un projet Node s’il est destiné à être pérenne (un billet est à venir là-dessus aussi) et j’entraînerais encore moins une équipe avec moi. D’un autre côté, je vois très bien que Python s’enlise avec la version 3 et j’ai envie de faire des services pour le Web comme le décrit Ian en introduction. Donc je vais forcément être amené à faire plus de JavaScript, il s’agit avant tout d’une question de tempo. Il y a beaucoup de bonnes choses dans Node, aussi bien au niveau des concepts que de l’universalité. Node n’est juste pas (encore) adapté à l’usage que je souhaite en avoir.

Peut-être que la paternité m’adoucit (sic), peut-être qu’elle me permet de faire la part des choses sur ce que je trouve utile. La réduction de mon temps en ligne le rend plus précieux.

[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 »

[logilab] Mini compte rendu Meetup Debian à Nantes

Publié le 2014-03-13 11:53:00

Hier soir, je suis allé au premier meetup Debian à Nantes. C'était bien sympatique, une vingtaine de personnes ont répondu présent à l'appel de Damien Raude-Morvan et Thomas Vincent. Merci à eux d'avoir lancé l'initiative (le pad d'organisation).

//www.logilab.org/file/228927/raw/debian-france.jpg

Après un tour de table des participants, et de quelques discussions sur debian en général (et une explication par Damien de l'état de Java dans Debian), Damien a présenté l'association Debian France ainsi que le concours du nouveau contributeur Debian. La liste d'idées est longue et sympatique n'hésitez pas à aller jeter un oeil et faire une contribution.

Ensuite Thomas nous a présenté l'équipe de traduction francaise de debian et ses principles de fonctionnement (qualité avant quantité, listes de discussion, IRC, processus de traduction, etc.).

//www.logilab.org/file/228931/raw/saltstack_logo.jpg

Finalement, j'ai rapidement présenté Salt et sa place dans Debian. Pour l'archive publique : les diapos de la présentation.

À la prochaine !

Pour faire un commentaire, il faut s'authentifier ou s'enregistrer.

[Inspyration] Python 3.4

Publié le 2014-03-13 10:27:00
Alors que Python 3.4 RC3 vient de sortir, une mise à jour du livre Python, les fondamentaux du langage s'apprête à faire de même.

[Biologeek] Web et Univers

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

En quelques affirmations simples : l’univers n’est pas statique, il se refroidit et se raréfie. Mais surtout, et c’est pour nous un élément central, la matière s’organise progressivement. Les particules des temps les plus anciens s’associent pour former des structures de plus en plus élaborées. Tel que Lucrèce l’avait deviné, on passe du « simple » au « complexe », du moins efficace au plus efficace. L’histoire de l’univers, c’est l’histoire de la matière qui s’organise.

La plus belle histoire du monde, Hubert Reeves

Je me permets une petite paraphrase pour les 25 ans du Web :

En quelques affirmations simples : le web n’est pas statique, il se privatise et se monétise. Mais surtout, et c’est pour nous un élément central, les contrôles s’organisent progressivement. Les hackers des temps les plus anciens s’associent pour former des agences gouvernementales de plus en plus élaborées. Tel qu’Orwell l’avait imaginé, on passe de la « liberté » au « totalitarisme », du moins marchand au plus espionné. L’histoire du web, c’est l’histoire de la répression qui s’organise.

La plus triste histoire du monde, David Larlet

[cubicweb] Logilab's roadmap for CubicWeb on March 7th, 2014

Publié le 2014-03-10 12:02:00

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

Version 3.17

This version is stable but old and maintainance will stop in a few weeks (current is 3.17.13 and 3.17.14 is upcoming).

Version 3.18

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

Version 3.19

This version is about to be published. It includes a heavy refactoring that modifies sessions and sources to lay the path for CubicWeb 4.

For details read list of tickets for CubicWeb 3.19.0.

Version 3.20

This version 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 CWEP-003 (adding a FROM clause to RQL).

For details read list of tickets for CubicWeb 3.20.0.

Cubes

Here is a list of cubes that had versions published over the past two months: addressbook, awstats, blog, bootstrap, brainomics, comment, container, dataio, genomics, invoice, mediaplayer, medicalexp, neuroimaginge, person, preview, questionnaire, securityprofile, simplefacet, squareui, tag, tracker, varnish, vcwiki, vtimeline.

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

collaboration is a building block that reuses container and helps to define collaborative workflows where entities are cloned, modified and shared.

Our priorities for the next two months are collaboration and container, then narval/apycot, then mercurial-server, then rqlcontroller and signedrequest, then imagesearch.

Mid-term goals

The work done for CWEP-0002 (computed attributes and relations) is expected to land in CubicWeb 3.20.

The work done for CWEP-0003 (explicit data source federation using FROM in RQL) is expected to land in CubicWeb 3.20.

Tools to diagnose performance issues would be very useful. Maybe in 3.21 ?

Caching session data would help and some work was done on this topic during the sprint in february. Maybe in 3.22 ?

WSGI has made progress lately, but still needs work. Maybe in 3.23 ?

RESTfulness is a goal. Maybe in 3.24 ?

Maybe 3.25 will be in fact 4.0 ?

Events

A spring sprint will take place in Logilab's offices in Paris from April 28th to 30th. We invite all the interested parties to join us there!

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 may 2014.

[logilab] Retour sur MiniDebConf Paris 2014

Publié le 2014-03-05 11:32:00
http://www.logilab.org/file/226609/raw/200px-Mini-debconf-paris.png

Nous sommes heureux d'avoir participé à la MiniDebConf Paris.

Nous avons sponsorisé l'évenement mais aussi effectué deux présentations :

Avec une cinquantaine de participants sur les deux jours, c'est toujours agréable de rencontrer la communauté francaise autour de Debian. Merci donc à l'association Debian France d'avoir organisé cette conférence.

[logilab] Second Salt Meetup builds the french community

Publié le 2014-03-04 16:32:00

On the 6th of February, the Salt community in France met in Paris to discuss Salt and choose the tools to federate itself. The meetup was kindly hosted by IRILL.

There were two formal presentations :

  • Logilab did a short introduction of Salt,
  • Majerti presented a feedback of their experience with Salt in various professional contexts.

The presentation space was then opened to other participants and Boris Feld did a short presentation of how Salt was used at NovaPost.

http://www.logilab.org/file/226420/raw/saltstack_meetup.jpeg

We then had a short break to share some pizza (sponsored by Logilab).

After the break, we had some open discussion about various subjects, including "best practices" in Salt and some specific use cases. Regis Leroy talked about the states that Makina Corpus has been publishing on github. The idea of reconciling the documentation and the monitoring of an infrastructure was brought up by Logilab, that calls it "Test Driven Infrastructure".

The tools we collectively chose to form the community were the following :

  • a mailing-list kindly hosted by the AFPY (a pythonic french organization)
  • a dedicated #salt-fr IRC channel on freenode

We decided that the meetup would take place every two months, hence the third one will be in April. There is already some discussion about organizing events to tell as many people as possible about Salt. It will probably start with an event at NUMA in March.

After the meetup was officially over, a few people went on to have some drinks nearby. Thank you all for coming and your participation.

login or register to comment on this blog

[tshirtman] Kpritz

Publié le 2014-03-03 01:23:00

Just because it seemed not to hard, i spent the evening (actually about 2 hours) making a Spritz clone using kivy.

Code is a bit crude and all, but here it is for your enjoyment:

https://gist.github.com/9316552

Here is an apk if you want to actually try it.

Only flat text files are supported, opening the option window is a bit slow (because of ColorPickers), but it’s functionnal, progression is saved, all the options i though were needed are there, and it seems usable.

You can find a lot of free book in the .txt format over at project gutenberg.

[afpyro] AFPyro à Lyon - mercredi 26 février

Publié le 2014-02-26 00:00:00

Un Afpyro aura lieu le mercredi 26 février à partir de 20h à l’Antre Autre - 11 rue Terme - 69001 Lyon.

Une présentation sera donnée sur la réalisation de tests unitaires dans l’écosystème Python.

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] Naissance de la peur

Publié le 2014-02-25 11:00:00

Qui ne s’est, un jour, interrogé sur la vie ?
Qui ne s’est, une fois, demandé ce qu’elle est ?
Questions trop ambitieuses.
Et sans réponses.
Mais à qui, plus modestement, demande :
« Où la vie commence-t-elle ? Et quand ? »
Une réponse vient, immédiate, aussi simple qu’évidente :
« La vie commence à la naissance. »
Et toute inquiétude disparait.
Évidence ?
La vie commence à la naissance…
Vraiment ?
Dans le ventre…
Dans le ventre de sa mère, l’enfant n’est-il pas déjà vivant ? Ne bouge-t-il pas ?
Sans doute, il bouge. Mais il n’y a là, disent certains, que simple activité réflexe.
Activité réflexe ! Non !
Nous savons aujourd’hui, que, bien avant d’avoir « vu le jour », l’enfant perçoit de la lumière. Et qu’il entend. Et que, de son obscure retraite, il est à l’écoute du monde.
Nous savons même qu’il passe de la veille au sommeil. Et même qu’il rêve !
En sorte que, faire commencer la vie à la naissance, c’est se tromper grossièrement.
Qu’est-ce donc, alors, qui commence quand l’enfant vient au monde ? Qu’est-ce donc si ce n’est la vie ?

Ce qui commence
c’est la peur.
La peur et l’enfant
naissent ensemble.
Et ne se quitteront jamais.
La peur,
compagne secrète,
discrète comme l’ombre
et, comme elle, fidèle, obstinée.
La peur
qui ne nous lâchera
qu’à la tombe
où fidèlement
elle nous aura mené.

Shantala, un art traditionnel, le massage des enfants, Frédérick Leboyer (1976)

Comment l’aider à apprivoiser cette peur ? Lui apprendre à vivre avec, se laisser traverser par la peur dirait Franck Herbert pour qu’il puisse être lui. Rien que lui.

Ces réflexions m’amènent à penser à mes propres peurs, celles qui font mon quotidien et celles qui font mon histoire. De quelles peurs demain sera-t-il fait ? Et peut-on d’ailleurs se préparer à la peur ? Faut-il partager ses peurs pour les diluer ou se propagent-elles pleinement d’un individu aux autres telles des virus ?

Comment le rassurer sans être soi-même rassuré ? Comment lui transmettre optimisme et espoir dans un monde morose et laid ?

Dehors, dedans…
Voilà le monde coupé en deux.
Dedans, la faim.
Dehors, le lait.
L’espace
est né.

Dedans, la faim
dehors, le lait.
Et, entre eux deux
l’absence,
l’attente
qui est indicible souffrance.
Et qui s’appelle
le temps.

Et c’est ainsi
que, simplement
avec l’appétit
sont nés
l’espace
et la durée.

Ibid.

Après l’espace et la durée, il me reste à faire naître en lui le choix. La notion complexe du libre arbitre qui fait de nous des humains. Construisant du beau dans la confiance, créant de la joie dans la spontanéité. Une feuille d’arbre allant s’ajouter à d’autres pour former un tout, une feuille blanche qui s’écrit au présent dans la magie du quotidien. Lui apprendre à utiliser sa peur comme moteur de son émerveillement.

[tarek] Running On It

Publié le 2014-02-21 12:05:00

I was reading @ednapiranha blog about her tips on running and recall that I wanted to write something about running in my blog for quite some time now.

Don't worry, this is not going to be yet another lose-some-weight improve-your-health post like the millions you'd find on the internet if you search for running. I won't distill tips or hints on how to run either - the topic is covered at 150% on the internet. (That said, if you want to talk about this topic, I can speak about it for hours.)

It's just my story on how running became a fundamental activity in my life - and I think some people that are in the Mozilla & Python community can relate to what happened to me.

Lost body

Last summer I was in San Francisco for some work at our Mozilla headquarters and as usual I was enjoying the city in the evenings with some friends - trying to taste all the good things to eat and drink this part of the world has to offer.

I have to say the beers are marvelous around the bay area, but after (quite) a few of them my nose started to bleed. I was not that worried, San Franscico can be quite dry sometime, and with all the plane travelling I suppose the nose skin gets very sensitive.

But it bled for 2 days non-stop - no matter how many tissue I was sticking in it. At some point I really freaked out and went to the hospital to check on it. I thought I had some vein issue and I really thought I was dying somehow, my body felt like it was simply going to stop working and my heart stop at any point.

I sat in the waiting room for over 4 hours in the evening and was seated with some homeless people and some other people that were in a very bad shape. One guy was in some kind of drug delirium and scared the crap out of me.

One sad thing I've notice was that most of the homeless that were seated in the waiting room were there just to be seated in a warm place for a while. At some point a couple of people from some kind of organization came to pick all of them to try to bring them to a shelter or something. But you could see they wanted to stay in that hospital waiting room rather than going to another place.

After 4 hours I saw a doctor and that lasted for around 5mn. It was just a typical nose bleeding that happens when the air is very dry. And drinking alcoholic beverages will expand your veins, making the bleeding harder to stop.

When I got back home after a few days I was still a bit shocked by this event: I realized I had lost my body over the years.

My body was not something I owned anymore. It just became a transport for all the food and drinks I wanted my brain to taste. It was just a tool to walk from point A to point B. The hardware to type on a keyboard and look at a screen from most of my days.

I realized that my body had limits I was not really worried about. It was trying to cope with my lifestyle excesses.

Running

After that incident I gave a break to my body for a few months.

No more drinking, healthier food, more sleep etc. I felt great of course, but knew this would not last for ever - I don't want to live like a monk and I want to enjoy most things in life.

I started to run around that time. I started to run every other day and it became obvious that running would help me have a more balanced life. Some weeks I run every day.

When I run, my body becomes a first class citizen. It gets all my attention and I rarely listen to some music. I just listen to my breathing and focus on how my legs and arms move. After a while I am able to reach a state where I don't think about anything else than my run.

Reaching this state takes at least 20 minutes. It turns out that's usually the warm up time needed before a race or a practice. After 20 minutes, your body has fully reached its abilities to run and is ready to sustain a long effort. There are a lot of studies that explain how the body switches to more sustainable energy sources after a while and what chemicals are generated by your brain so you can cope with the run. It's quite fascinating.

Running also became the best place for me to solve complex coding or design problems I can have at work. I guess it's mostly because when you run you can't get distracted by all the things that are distracting us on a screen - that forces us to do a lot of context switching.

Being a remote worker, I now organize my working day around my running sessions - if I am banging my head on a tough issue I am now running on it :)

There's one interesting read about all of this: Murakami's essay on running What I Talk About When I Talk About Running. I can relate to a lot of things he wrote there.

I don't think I am going to stop running anytime soon, I have never felt that way before: balanced.

https://upload.wikimedia.org/wikipedia/commons/thumb/6/60/Maslow%27s_Hierarchy_of_Needs.svg/450px-Maslow%27s_Hierarchy_of_Needs.svg.png

It looks like I was doing the Maslow hierarchy of needs a little bit up-side-down until now ;)

[tshirtman] Using tex_coords in kivy for fun and profit

Publié le 2014-02-19 00:45:00

Your gpu is an awesome thing, it can do all kind of calculations, very fast. For example, instead of telling it exactly how you want each pixels to be, you can throw textures and vertices at it, and have it correctly deduce how this things will have to look.

To do this, though, you must tell it what part of the texture will be stuck to each vertice. This is usually denoted using texture coordinates.

Texture coordinates, like usual coordinates, indicate the place of something. Instead of noting them x and y, they are often called u and v, which allows to clearly note what parts of an equation relate to each.

While kivy offers you high level canvas instructions, it gives you a pretty good access to lower level features, and you can actually manipulate the texture coordinates of your Rectangle instructions. This allow for cheap zooming, repeat-scrolling, and other image manipulations, since your gpu is doing all the actual work.

tex_coords = u, v, u + w, v, u + w, v + h, u, v + h

which is better understood as:

tex_coords = [
    u,     v,
    u + w, v,
    v + w, v + h,
    u,     v + h
]

considering a default tex_coords value, where u and v = 0, and w and h = 1 (all values are relatives, so usually between 0 and 1).

u, v + h-------u + w, v + h
|              |
u, v-----------u + w, v

which means the 4 angles of your texture, will be on the 4 angles of your rectangle, how dull!

One way to play with different values, is to create a little app showing you the effect of deformations.

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.widget import Widget
from kivy.properties import ObjectProperty, ListProperty
from kivy.core.image import Image as CoreImage

kv = '''
#:import chain itertools.chain
RootWidget:
    canvas:
        Color:
            rgba: 1, 1, 1, 1
        Rectangle:
            pos: root.pos
            size: root.size
            texture: app.texture
            # here is our usage of the calculated texture coordinates
            # we devide by 100 because we took the input with a 100x100
            # rectangle as default value
            tex_coords: [x / 100. for x in chain(*root.points)]

        PushMatrix
        # translate the rectangle to make it easier to play with
        Translate:
            xy: root.width / 2, root.height / 2

        Color:
            rgba: 1, 0, 0, .5
        Line:
            points: chain(*root.points + root.points[:1])
            width: 2
        PopMatrix
'''


def dist(point, pos):
    return ((point[0] - pos[0]) ** 2 + (point[1] - pos[1]) ** 2)
    # ** .5 # who cares about square root here? it doesn't change the order


class RootWidget(Widget):
    # the default values, a 100x100 square, displayed around the middle of the screen
    points = ListProperty([[0, 0], [100, 0], [100, 100], [0, 100]])

    def on_touch_down(self, touch, *args):
        # compensate the translation done in canvas
        pos = touch.pos[0] - self.width / 2, touch.pos[1] - self.height / 2

        touch.ud['point'] = min(
            range(4), key=lambda x: dist(self.points[x], pos))

    def on_touch_move(self, touch, *args):
        # compensate the translation done in canvas
        pos = touch.pos[0] - self.width / 2, touch.pos[1] - self.height / 2
        # update the point
        self.points[touch.ud['point']] = pos


class TexCoordsApp(App):
    texture = ObjectProperty(None)

    def build(self):
        self.root = Builder.load_string(kv)
        self.texture = CoreImage.load(
            'GrassGreenTexture0002.jpg').texture
        self.texture.wrap = 'repeat'
        return self.root


if __name__ == '__main__':
    TexCoordsApp().run()

The texture have been scrapped on the web and is not very interesting, but you can find it here.

Of course, this is much more a learning device (helful because these transformation are not quite straighforward for our brains) than a practical application, but a lot more can be done.

Here is, for example, a little infinite scroll app uting this concept.

edit: Ben Rousch kindly created apks out of the two examples, if you want to try them on android: TexCoordsExample ScrollExample

[afpyro] AFPyro à Paris, Mercredi 19 février

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

Contexte

C’est le premier AFPyro parisien de 2014 !

Quand ?

Le Mercredi 19 février à partir de 19h.

Où ?

La Grosse Caisse au 160 rue Montmartre, dans le 2ème arrondissement de Paris.

Voyez la carte OpenStreetMap

[logilab] FOSDEM PGDay 2014

Publié le 2014-02-18 12:50:00

I attended PGDay on January 31st, in Brussels. This event was held just before FOSDEM, which I also attended (expect another blog post). Here are some of the notes I took during the conference.

https://fosdem.org/2014/support/promote/wide.png

Statistics in PostgreSQL, Heikki Linnakangas

Due to transit delays, I only caught the last half of that talk.

The main goal of this talk was to explain some of Postgres' per-column statistics. In a nutshell, Postgres needs to have some idea about tables' content in order to choose an appropriate query plan.

Heikki explained which sorts of statistics gathers, such as most common values and histograms. Another interesting stat is the correlation between physical pages and data ordering (see CLUSTER).

Column statistics are gathered when running ANALYZE and stored in the pg_statistic system catalog. The pg_stats view provides a human-readable version of these stats.

Heikki also explained how to determine whether performance issues are due to out-of-date statistics or not. As it turns out, EXPLAIN ANALYZE shows for each step of the query planner how many rows it expects to process and how many it actually processed. The rule of thumb is that similar values (no more than an order of magnitude apart) mean that column statistics are doing their job. A wider margin between expected and actual rows mean that statistics are possibly preventing the query planner from picking a more optimized plan.

It was noted though that statistics-related performance issues often happen on tables with very frequent modifications. Running ANALYZE manually or increasing the frequency of the automatic ANALYZE may help in those situations.

Advanced Extension Use Cases, Dimitri Fontaine

Dimitri explained with very simple cases the use of some of Postgres' lesser-known extensions and the overall extension mechanism.

Here's a grocery-list of the extensions and types he introduced:

  • intarray extension, which adds operators and functions to the standard ARRAY type, specifically tailored for arrays of integers,
  • the standard POINT type which provides basic 2D flat-earth geometry,
  • the cube extension that can represent N-dimensional points and volumes,
  • the earthdistance extension that builds on cube to provide distance functions on a sphere-shaped Earth (a close-enough approximation for many uses),
  • the pg_trgm extension which provides text similarity functions based on trigram matching (a much simpler thus faster alternative to Levenshtein distances), especially useful for "typo-resistant" auto-completion suggestions,
  • the hstore extension which provides a simple-but-efficient key value store that has everyone talking in the Postgres world (it's touted as the NoSQL killer),
  • the hll extensions which implements the HyperLogLog algorithm which seems very well suited to storing and counting unique visitor on a web site, for example.

An all-around great talk with simple but meaningful examples.

http://tapoueh.org/images/fosdem_2014.jpg

Integrated cache invalidation for better hit ratios, Magnus Hagander

What Magnus presented almost amounted to a tutorial on caching strategies for busy web sites. He went through simple examples, using the ubiquitous Django framework for the web view part and Varnish for the HTTP caching part.

The whole talk revolved around adding private (X-prefixed) HTTP headers in replies containing one or more "entity IDs" so that Varnish's cache can be purged whenever said entities change. The hard problem lies in how and when to call PURGE on Varnish.

The obvious solution is to override Django's save() method on Model-derived objects. One can then use httplib (or better yet requests) to purge the cache. This solution can be slightly improved by using Django's signal mechanism instead, which sound an awful-lot like CubicWeb's hooks.

The problem with the above solution is that any DB modification not going through Django (and they will happen) will not invalidate the cached pages. So Magnus then presented how to write the same cache-invalidating code in PL/Python in triggers.

While this does solve that last issue, it introduces synchronous HTTP calls in the DB, killing write performance completely (or killing it completely if the HTTP calls fail). So to fix those problems, while introducing limited latency, is to use SkyTools' PgQ, a simple message queue based on Postgres. Moving the HTTP calls outside of the main database and into a Consumer (a class provided by PgQ's python bindings) makes the cache-invalidating trigger asynchronous, reducing write overhead.

http://www.logilab.org/file/210615/raw/varnish_django_postgresql.png

A clear, concise and useful talk for any developer in charge of high-traffic web sites or applications.

The Worst Day of Your Life, Christophe Pettus

Christophe humorously went back to that dreadful day in the collective Postgres memory: the release of 9.3.1 and the streaming replication chaos.

My overall impression of the talk: Thank $DEITY I'm not a DBA!

But Christophe also gave some valuable advice, even for non-DBAs:

  • Provision 3 times the necessary disk space, in case you need to pg_dump or otherwise do a snapshot of your currently running database,
  • Do backups and test them:
    • give them to developers,
    • use them for analytics,
    • test the restore, make it foolproof, try to automate it,
  • basic Postgres hygiene:
    • fsync = on (on by default, DON'T TURN IT OFF, there are better ways)
    • full_page_writes = on (on by default, don't turn it off)
    • deploy minor versions as soon as possible,
    • plan upgrade strategies before EOL,
    • 9.3+ checksums (createdb option, performance cost is minimal),
    • application-level consistency checks (don't wait for auto vacuum to "discover" consistency errors).

Materialised views now and in the future, Thom Brown

Thom presented on of the new features of Postgres 9.3, materialized views.

In a nutshell, materialized views (MV) are read-only snapshots of queried data that's stored on disk, mostly for performance reasons. An interesting feature of materialized views is that they can have indexes, just like regular tables.

The REFRESH MATERIALIZED VIEW command can be used to update an MV: it will simply run the original query again and store the new results.

There are a number of caveats with the current implementation of MVs:

  • pg_dump never saves the data, only the query used to build it,
  • REFRESH requires an exclusive lock,
  • due to implementation details (frozen rows or pages IIRC), MVs may exhibit non-concurrent behavior with other running transactions.

Looking towards 9.4 and beyond, here are some of the upcoming MV features:

  • 9.4 adds the CONCURRENTLY keyword:
    • + no longer needs an exclusive lock, doesn't block reads
    • - requires a unique index
    • - may require VACUUM
  • roadmap (no guarantees):
    • unlogged (disables the WAL),
    • incremental refresh,
    • lazy automatic refresh,
    • planner awareness of MVs (would use MVs as cache/index).

Indexes: The neglected performance all-rounder, Markus Winand

http://use-the-index-luke.com/img/alchemie.png

Markus' goal with this talk showed that very few people in the SQL world actually know - let alone really care - about indexes. According to his own experience and that of others (even with competing RDBMS), poorly written SQL is still a leading cause of production downtime (he puts the number at around 50% of downtime though others he quoted put that number higher). SQL queries can indeed put such stress on DB systems and cause them to fail.

One major issue, he argues, is poorly designed indexes. He went back in time to explain possible reasons for the lack of knowledge about indexes with both SQL developers and DBAs. One such reason may be that indexes are not part of the SQL standard and are left as implementation-specific details. Thus many books about SQL barely cover indexes, if at all.

He then took us through a simple quiz he wrote on the topic, with only 5 questions. The questions and explanations were very insightful and I must admit my knowledge of indexes was not up to par. I think everyone in the room got his message loud and clear: indexes are part of the schema, devs should care about them too.

Try out the test : http://use-the-index-luke.com/3-minute-test

PostgreSQL - Community meets Business, Michael Meskes

For the last talk of the day, Michael went back to the history of the Postgres project and its community. Unlike other IT domains such as email, HTTP servers or even operating systems, RDBMS are still largely dominated by proprietary vendors such as Oracle, IBM and Microsoft. He argues that the reasons are not technical: from a developer stand point, Postgres has all the features of the leading RDMBS (and many more) and the few missing administrative features related to scalability are being addressed.

Instead, he argues decision makers inside companies don't yet fully trust Postgres due to its (perceived) lack of corporate backers.

He went on to suggest ways to overcome those perceptions, for example with an "official" Postgres certification program.

A motivational talk for the Postgres community.

http://fosdem2014.pgconf.eu/files/img/frontrotate/slonik.jpg

[afpy.org] PyCon.FR 2014

Publié le 2014-02-13 17:16:21
Il est bientôt temps de commencer à organiser la conférence Python francophone. Cet article est un appel aux bonnes volontés.

[afpy.org] Naissance d'une communauté Saltstack francophone

Publié le 2014-02-13 15:19:27
Saltstack est le logiciel libre de gestion de configuration qui monte. Rejoignez sa communauté francophone !

[cubicweb] CubicWeb sprint / winter 2014

Publié le 2014-02-12 18:30:00

This sprint took place at Logilab's offices in Paris on Feb 13/14. People from CEA, Unlish, Crealibre and Logilab teamed up to push CubicWeb forward.

We did not forget the priorities from the roadmap:

  • CubicWeb 3.17.13 and 3.18.3 were released, and CubicWeb 3.19 made progress
  • the branch about ComputedAttributes and ComputedRelations (CWEP-002) is ready to be merged,
  • the branch about the FROM clause (CWEP-003) made progress (the CWEP was reviewed and part of the resulting spec was implemented),
  • in order to reduce work in progress, the number of patches in state reviewed or pending-review was brought down to 243 (from 302, that is 60 or 20%, which is not bad).

[gvaroquaux] Hiring a programmer for a brain imaging machine-learning Python library

Publié le 2014-02-12 09:03:57
Work with us on putting machine learning in the hand of cognitive scientists Parietal is a research team that creates advanced data analysis to mine functional brain images and solve medical and cognitive science problems. Our day to day work is to write machine-learning and statistics code to understand and use better images of brain function [...]

[tshirtman] Using jinja2 outside of the web.

Publié le 2014-02-09 23:56:00

I may be the last person out there to do that, but i hadn’t actually gotten to that yet.

So here is the thing, sometime you want to produce a text file, with some complex structure, and string.format is not really up to the task, so you scratch your head and wonder what could be useful to… template an output.

Then a nice lib like jinja2 totally makes sense.

For my use case, i want to generate java source code, using info parsed from other java source code (thanks to the awesome plyj lib), so it’s easy to give the general form of the output file, and to pass the content after that.

{% if package %}package {{ package }};{% endif %}
import {{ module.package_declaration.name.value }}.*;
{{ imports }}\

public class {{ cls.name }}{{ suffix }} extends {{ cls.name }} {
    public interface I{{ cls.name }} {\
    {% for method in methods %}
    {{ method.return_type | get_type }} {{ method.name }}({{ method.parameters | render_params }});\
    {% endfor %}
    }

    private I{{ cls.name }} implem = null;

    public void setImplem(I{{ cls.name }} implem) {
    this.implem = implem;
    }

    {% for method in methods %}
    {{ method.return_type | get_type }} {{ method.name }}({{ method.parameters | render_params }}) {
    if (this.implem)
        return this.implem.{{ method.name }}({{ method.parameters | render_params_values }});
    }{% endfor %}
}

One problem i had, though, was when it turned out it would be convenient to use custom filters inside my template, it took me some time to find the relevant documentation about how to register functions as filters in this situation (since people usually use jinja2 in a framework, they document how to do so using the environment used by this framework).

So the answer was not to use jinja2.Template directly, but to build an environment before.

env = jinja2.Environment()

then to setup my filters in this environment:

env.filters['render_params'] = render_params
env.filters['render_params_values'] = render_params_values
env.filters['get_type'] = get_type

and to use env.template_from_string(template_string) to create a Template object from my string.

[cyp] Ajouter un moteur de rendu à Pyramid

Publié le 2014-02-09 15:30:00

Il y a beaucoup de moteur de rendu disponible pour pyramid mais il peut arriver qu'on ait besoin de créer le sien ou d'en ajouter un dont le support n'a pas encore été fait.

Plutôt que donner des exemples abstraits, je vais illustrer avec un module relativement simple que j'ai écrit (lire dont je comprends le code) : pyramid_xslt

C'est quoi xsl ?

Dans le cadre de mon travail, je manipule beaucoup de fichiers XML et notamment je les transforme en fichiers HTML. XSLT est le langage XML qui transforme un contenu XML en XML ou texte.

Soit le XML suivant :

<document>
  <title>Some title</title>
  <section>
    <section-title>First Section</section-title>
    <content>foo bar</content>
  </section>
  <section>
    <section-title>Second Section</section-title>
    <content>baz baz</content>
  </section>
</document>

La XSLT suivante le transforme en HTML :

<?xml version="1.0" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes"/>

<xsl:template match="document">
  <html>
    <head>
       <xsl:apply-templates select='title' mode="meta" />
    </head>
    <body>
     <article>
       <xsl:apply-templates select='title' />
       <xsl:apply-templates select="section" />
     </article>
    </body>
  </html>
</xsl:template>

<xsl:template match="title" mode="meta">
  <title><xsl:value-of select="." /></title>
</xsl:template>

<xsl:template  match="title">
  <h1><xsl:value-of select='.' /></h1>
</xsl:template>

<xsl:template match="section">
  <div>
    <xsl:apply-templates />
  </div>
</xsl:template>

<xsl:template match="section-title">
 <h2><xsl:value-of select="." /></h2>
</xsl:template>

<xsl:template match="content">
  <p>
    <xsl:value-of select="." />
  </p>
</xsl:template>

</xsl:stylesheet>

On exécute en CLI :

$ xsltproc sample.xsl sample.xml > sample.html

ce qui donne comme HTML :

<?xml version="1.0"?>
<html>
 <head>
   <title>Some title</title>
 </head>
 <body>
   <article>
     <h1>Some title</h1>
     <div>
    <h2>First Section</h2>
    <p>foo bar</p>
  </div>
     <div>
    <h2>Second Section</h2>
    <p>baz baz</p>
  </div>
   </article>
 </body>
</html>

Dans python, on peut utiliser lxml :

from lxml import etree

transform = etree.XSLT(etree.parse('sample.xsl'))
print(etree.tostring(transform(etree.parse('sample.xml')))

Voila pour XSLT.

Scénario d'utilisation

Le but du jeu est de me simplifier la vie. Sans l'ajout de moteur de rendu, le code serait comme cela :

from lxml import etree


# la contruction de cet objet pique un peu autant le faire qu'une seule fois.
transform = etree.XSLT(etree.parse('sample.xsl'))

@view_config(name='some_route', renderer='string')
def some_view(request):
    filename = request.POST['select_file']

    return etree.tostring(transform(etree.parse(filename)))

La finalité du moteur de rendu est que le code devienne :

@view_config(name='some_route', renderer='template/sample.xsl')
def some_view(request):
    filename = request.POST['selected_file']

    return etree.parse(filename)

On peut également passer des variables à une XSLT. ce qui donnerait dans notre scénario :

@view_config(name='some_route', renderer='template/sample.xsl')
def some_view(request):
    filename = request.POST['selected_file']
    name = request.POST['name']

    return etree.parse(filename), {'name': name}

L'implémentation

Pour ajouter un moteur de rendu, on a besoin d'une factory, d'un renderer et de rajouter ce rendu à pyramid.

Factory

La factory sert à construire le renderer qui effetura le rendu.

La signature de la factory est la suivante :

def factory(info):
    def renderer(value, system):
        pass

    return renderer

ou la version orientée objet :

class Factory(object):
    def __init__(self, info):
        pass

    def __call__(self, value, system):
        pass

renderer et __call__ doivent retourner une chaine contenant le rendu.

info contient un pyramid.renderers.RendererHelper.

Dans le cas de notre moteur de rendu xsl :

class XsltRendererFactory(object):
    def __init__(self, info):
        """
        Factory constructor.
        """
        self._info = info

    def __call__(self, value, system):
        """
        Call to renderer.

        The renderer is cached for optimize access.
        """

        xsl = XslRenderer(os.path.join(package_path(self._info.package),
                                       system['renderer_name']))
        return xsl(value, system)

XslRenderer est notre objet qui va effectuer la transformation.

Le Rendu

Le rendu doit implémenter l'interface IRenderer [1] de pyramid : juste la méthode __call__ avec la signature suivante :

[1]IRenderer est une interface ZCA : zope.interface : voir l'épisode précédent
def __call__(self, value, system):
    pass

La méthode __call__ doit retourner une chaine avec le résulat du rendu.

value contient la donnée retournée par la méthode décorée par le view_config. system est un dictionnaire contenant :

  • renderer_info : même RendererHelper que info passé à la factory,
  • renderer_name : valeur de renderer du décorateur view_config ; typiquement le chemin vers le template,
  • context : un object pyramid.traversal.DefaultRootFactory,
  • req : l'objet request,
  • request : le même objet request,
  • view : la fonction décorée correspondant à la vue.
@implementer(IRenderer)
class XslRenderer(object):

    def __init__(self, xslfilename):
        """
        Constructor.

        :param: xslfilename : path to the xsl.
        """
        self._transform = etree.XSLT(etree.parse(xslfilename))

    def __call__(self, value, system):
        """
        Rendering.
        """
        xslArgs = {}

        try:
            xslArgs  = {key: str(value[1][key]) for key in  value[1]}
        except IndexError:
            pass

        return etree.tostring(self._transform(value[0], **xslArgs))

Le rendu est très simple à écrire, la version sur github est à peine plus compliquée pour gérer des fichiers, url ou arbre etree.

Utilisation du registre

Si le rendu est très simple, la factory mérite d'être complexifiée. Comme dit plus haut, la construction de la xsl est coûteuse à construire. On va utiliser le registre de pyramid pour contruire une seule fois la classe de rendu. Le registre est un registre ZCA ; le nom de fichier de la xsl servira de clef. La première requête construira la xsl, les suivantes n'auront qu'à utiliser l'objet construit.

class XsltRendererFactory(object):
    def __init__(self, info):
        """
        Factory constructor.
        """
        self._info = info

    def __call__(self, value, system):
        """
        Call to renderer.

        The renderer is cached for optimize access.
        """

        registry = system['request'].registry
        try:
            xsl = registry.getUtility(IRenderer, system['renderer_name'])
        except ComponentLookupError:
            xsl = XslRenderer(os.path.join(package_path(self._info.package),
                                          system['renderer_name']))
            registry.registerUtility(xsl, IRenderer, system['renderer_name'])
        return xsl(value, system)

Inclusion dans pyramid

Il reste encore à ajouter le support du rendu à pyramid. Dans la fonction main de pyramid, on rajoute où config est la configuration de pyramid.

config.add_renderer('.xsl', XsltRendererFactory)

le .xsl permet de reconnaître le moteur de rendu via @view_config.

Rendre le rendu utilisable par d'autres applications pyramid

L'intérêt de porter ou d'écrire un moteur de rendu est de le réutiliser. pyramid a un mécanisme très simple pour cela.

Dans le __init__.py de notre rendu, il suffit d'inclure le code suivant :

def includeme(config):
    """
    Auto include pour pyramid
    """
    config.add_renderer('.xsl', XsltRendererFactory)

Pour l'utiliser dans notre application, où on l'inclus le code suivant dans le main de pyramid :

config.include('pyramid_xslt')

ou dans fichier .ini

pyramid.includes =
    pyramid_xslt

And that's all folk.

[cubicweb] CubicWeb using Postgresql at its best

Publié le 2014-02-08 02:08:00

We had a chat today with a core contributor to Postgresql from whom we may buy consulting services in the future. We discussed how CubicWeb could get the best out of Postgresql:

  • making use of the LISTEN/NOTIFY mechanism built into PG could be useful (to warn the cache about modified items for example) and PgQ is its good friend;
  • views (materialized or not) are another way to implement computed attributes and relations (see CWEP number 002) and it could be that the Entities table is in fact a view of other tables;
  • implementing RQL as an in-database language could open the door to new things (there is PL/pgSQL, PL/Python, what if we had PL/RQL?);
  • Foreign Data Wrappers written with Multicorn would be another way to write data feeds (see LDAP integration for an example);
  • managing dates can be tricky when users reside in different timezones and UTC is important to keep in mind (unicode/str is a good analogy);
  • for transitive closures that are often needed when implementing access control policies with __permissions, Postgresql can go a long way with queries like "WITH ... (SELECT UNION ALL SELECT RETURNING *) UPDATE USING ...";
  • the fastest way to load tabular data that does not need too much pre-processing is to create a temporary table in memory, then COPY-FROM the data into that table, then index it, then write the transform and load step in SQL (maybe with PL/Python);
  • when executing more than 10 updates in a row, it is better to write into a temporary table in memory, then update the actual tables with UPDATE USING (let's check if the psycopg driver does that when executemany is called);
  • reaching 10e8 rows in a table is at the time of this writing the stage when you should start monitoring your db seriously and start considering replication, partition and sharding.
  • full-text search is much better in Postgresql than the general public thinks it is and recent developments made it orders of magnitude faster than tools like Lucene or Solr and ElasticSearch;
  • when dealing with complex queries (searching graphs maybe), an option to consider is to implement a specific data type, use it into a materialized view and use GIN or GIST indexes over it;
  • for large scientific data sets, it could be interesting to link the numpy library into Postgresql and turn numpy arrays into a new data type;
  • Oh, and one last thing: the object-oriented tables of Postgresql are not such a great idea, unless you have a use case that fits them perfectly and does not hit their limitations (CubicWeb's is_instance_of does not seem to be one of these).

Hopin' I got you thinkin' :)

http://developer.postgresql.org/~josh/graphics/logos/elephant.png

[sciunto] Pourquoi je soutiens l'April

Publié le 2014-02-07 23:00:00

L'April est une association pionnière en matière de Logiciel Libre. Créée en 1996, elle était une association d'informaticiens souhaitant promouvoir le Logiciel Libre, inspirée par l'éthique du discours de Richard Stallman.

Un peu comme pour des codes sources, certains sont oubliés, d'autres au contraire savent évoluer et s'ouvrir au monde. Ce dernier est à mon sens le cas de l'April. Un premier tournant fût la loi DADVSI qui souleva des réactions face aux atteintes qui pouvaient être portées aux Logiciels Libres (Ref).

La prise de conscience qu'il ne suffisait pas de promouvoir le Logiciel Libre mais aussi veiller à sa défense, a entraîné une croissance significative du nombre d'adhérents pour dépasser les 5000 en 2009. Outre les personnes physiques qui se sentent concernées, ce sont aussi des personnes morales : entreprises, associations ou des communes comme Toulouse qui rejoignent l'April.

Grâce à ses membres et aux permanents, les actions menées par l'April se sont succédées et multipliées depuis. DADVSI n'étant que le premier du nom, l'April a poursuivi ses actions sur les brevets logiciels, l'hadopi, la lopsi, l'acta... mais l'April sait aussi planter des graines. Elle est l'initiatrice et la coordinatrice de Libre en fête, elle se tourne vers les autres associations et vers la diversité, informe le citoyen sur la position des candidats aux élections ou oeuvre pour une education à l'informatique plus saine. L'April sait rassembler au-delà des frontières de l'informatique et c'est ce qui en fait une grande association.

J'ai eu la chance de côtoyer (la distance ne me le permettant plus) physiquement un certain nombre de bénévoles ainsi que l'équipe de permanents et je peux témoigner de la qualité de l'esprit et du savoir de ces personnes. Le travail abattu est immense tant les projets sont nombreux.

J'oublie bien sûr des facettes de l'April, je ne cite que celles qui me marquent le plus. Néanmoins, ce sont les raisons pour lesquelles je soutiens l'April.

Aujourd'hui, le Logiciel Libre doit réfléchir à de nouvelles problématiques : protection des données personnelles, informatique en nuage avec la variété de concept que cela contient, matériel libre et fablab, etc. Je suis certain que l'April saura trouver un chemin dans ces questions.

L'April a aussi besoin de votre soutien. Un membre de plus, c'est une voix de plus lors d'une prise de parole. C'est aussi permettre un travail continu de veille et d'expertise grâce aux salariés.

Pour ceux qui veulent donner de leur temps (à toutes les échelles), l'April est prête à recevoir. D'expérience, l'association étant assez imposante, il faut savoir prendre son temps pour prendre ses marques, il y a de la place pour tou(te)s et c'est véritablement enrichissant !

Page de la campagne d'adhésion

[tshirtman] Magnet: a widget to easily make your interface more lively

Publié le 2014-02-05 23:38:49

Kivy has a very nice Animation class, that allows you to move move widgets around (or other things), by updating any numeric property to a target value, just by setting a time and a transition function. Still, when you are building a complex interface, it can still be a bit cumbersome to manually trigger animations for all the elements, and to keep track of them.

After being frustrated about this issue for some time, i tried my luck some time ago, at doing a nicer, “90% use cases” interface, and the Magnet garden widget was born.

Its usage is simple, you simply use it to wrap your target widget, and give it rules about how to transition when the magnet is moved. As the magnet is moved or resized by the usual kivy logic, instead of making the wrapped widget immediately follow such constraints, it’ll create and keep track of animations to achieve a smooth transition to the new values for you.

As any garden “flower”, to install it, you need to install and use the garden project.

python setup.py install

(either in a virtualenv or system-wide)

then do:

garden install magnet

you can now import it a kivy application:

from kivy.garden.magnet import Magnet

Garden Magnet video

[sciunto] Ce que python m'a enseigné

Publié le 2014-02-03 23:00:00

Il y a près de deux ou trois ans, je suis passé à Python. A l'époque, je cherchais un langage permettant de scripter des tâches courantes (adminsys, utilitaires...). De Bash, je suis passé à perl qui m'a beaucoup séduit par l'expression du code et ses regexp. Il possède aussi beaucoup de bibliothèques (cf cpan), ce qui le rend intéressant.

Néanmoins, perl ne rime pas vraiment avec science, en tout cas dans mon domaine (il semble que perl ait une bonne communauté chez les bioinformaticiens). Matlab fait largement référence, mais puisque ce n'est pas éthiquement acceptable, je me suis tourné vers python qui se défend très bien. Il se trouve aussi que Python, contrairement à matlab, est un vrai langage de programmation, utilisé par des développeurs pour faire des outils bureau et web. C'est, selon moi, une (et non pas la) raison pour laquelle ce langage devrait être privilégié par rapport à matlab dans l'enseignement car il s'adresse potentiellement à une plus grande diversité de tâches, donc un plus large public.

Mais ce n'est pas ce que je veux traiter dans cet article, je veux plutôt parler de ce que Python m'a apporté et que je n'ai pas découvert au cours de mes études où j'ai appris C et C++.

  • Faire des tests unitaires. Je me limite encore aux situations simples, mais j'apprécie grandement cet investissement car sur le logn terme, retoucher un code ne donne plus la grosse sueur froide de tout casser. Pour une raison que j'ignore, je n'ai pas découvert ces tests avec perl.
  • Intégration continue. Contribuant à des projets sur github, j'ai découvert Travis-CI. Ce n'est pas libre, mais néanmoins plutôt pratique. Comme pour github, si ce service fermait, je pourrai le remplacer à terme par un service auto-hébergé et ce n'est pas critique pour moi. Cette découverte m'a poussé à faire de l'intégration continue pour latex.
  • Faire une documentation systématique. Découvert avec doxygen en C++, j'ai commencé à documenter mes fonctions quasi-systématiquement avec python et j'ai l'occasion d'apprendre à faire une doc correcte grâce aux contributions que je peux faire dans des libs scientifiques.

Ces éléments, je les ai appris ou perfectionné avec python. Je ne dis pas que je ne l'aurais pas appris autrement, mais le fait est que c'est grâce à Python !

[sciunto] Supprimer la première page d'un pdf avec pyPDF2

Publié le 2014-02-01 23:00:00

Dans mon travail de recherche, je manipule beaucoup de PDF dont ceux provenant des sites des journaux scientiques. Le problème est qu'un certain nombre de ces journaux mettent une page "de couverture" au PDF à partir de métadonnées et cette page m'ennuie à plusieurs égards :

  • je dois descendre d'une page pour commencer ma lecture
  • je dois imprimmer une page supplémentaire et une fois sur deux utiliser une feuille supplémentaire
  • la pge étant la même pour tous les articles du journal, je ne repère pas au premier coup d'oeil de quel article il s'agit dans ma pile.

Pour toutes ces raisons, à chaque fois que j'ai un tel PDF entre les mains, je déchire la première page. Il y a sans doute des commandes ghostscripts magiques pour ça. Ici, je propose d'écrire un petit script python dont voici les sources.

C'est terriblement simple :

# Creation d'un fichier temporaire
tmp = tempfile.NamedTemporaryFile()
shutil.copy(filename, tmp.name)

# On ouvre le pdf et on compte les pages
output_file = PdfFileWriter()
input_file = PdfFileReader(open(tmp.name, 'rb'))
num_pages = input_file.getNumPages()

# On esquive la page 0, le reste, on copie
for i in range(1, num_pages):
    output_file.addPage(input_file.getPage(i))

# On ferme, on enregistre
tmp.close()
outputStream = open(filename, "wb")
output_file.write(outputStream)

Voilà, le travail est fait :)

[afpyro] AFPyro à Bruxelles (BE) - le 1 Février

Publié le 2014-02-01 00:00:00

Dear Pythonista friends, write down in your agenda the date of the next AFPyro!

The next Aperos Python Belgium will take place on saturday, February 1st in Brussels, during the FOSDEM conference that takes place at ULB from 1st to 2nd February.

In addition to the regulars of AFPyro, we are also pleased to meet the attendees of FOSDEM using Python.

As usual, you can come just for drinking and sharing one (or many) drinks or if you wish, you can also register for the meal that follows, in a near place, at “Chez Léon” for 20:30, rue des Bouchers 18, B-1000 Brussels.

Meeting from 18:45, on first floor of Delirium cafe, Impasse De La Fidélité 4, 1000 Brussels.

If you are a FOSDEM attendee, you can meet us at the Python stand, 1st floor of K Building, from 18h to go to Delirium cafe together.

Please sign up in order to book the place: http://doodle.com/mn3yck6n3xxidsim

Further information about the next AFPyros in Belgium: Aperos Python Belgium


Amis Pythonistes, notez dans vos agendas la date du prochain AFPyro !

Le prochain Aperos Python Belgium se tiendra le samedi 1 Février à Bruxelles, lors du FOSDEM qui se tient à ULB du 1 au 2 Février.

En plus des habitués de l’AFPyro, nous attendons également avec plaisir les participants du FOSDEM qui utilisent Python.

Comme chaque fois, vous pouvez venir juste pour l’apéro et partager un (ou des) verres, ou si vous le souhaitez, vous inscrire également pour le repas qui suivra, “Chez Léon” à 20h30, rue des Bouchers 18, B-1000 Bruxelles.

Rendez-vous à partir de 18h45, au premier étage du Délirium café, Impasse De La Fidélité 4, 1000 Brussels.

Si vous participez au FOSDEM, nous vous donnons rendez-vous au stand Python, 1° étage du batiment K, à partir de 18h, afin d’aller au Délirium café ensemble.

Pour dimensionner au mieux la réservation, merci de vous inscrire sur: http://doodle.com/mn3yck6n3xxidsim

Toutes les infos des prochains AFPyros en Belgique: Aperos Python Belgium

[tshirtman] Kivy image manipulations with Mesh and Textures

Publié le 2014-01-29 00:05:00

If you want to give a little life to interactive (or not) elements, it’s always nice to have more tricks to manipulate images for nifty effects.

One of such ways is mapping a Texture on a special canvas instruction, that will distort your texture based on the position of its points.

[kivy.graphics.Mesh](http://kivy.org/docs/api-kivy.graphics.html#kivy.graphics.Mesh) is such an instruction, and it has a simple interface, if not 100% straightforward, you basically call it this way.

Mesh:
vertices: (x1, y1, s1, v1, x2, y2, s2, v2, x3, y3, s3, v3...)
indices: (1, 2, 3...)
texture: some_texture
mode: some_mode

where all: x mean the horizontal coordinate of a point y mean the vertical coordinate of a point s mean the horizontal position of the texture attached to this point (between 0 and 1) v mean the vertical position of the texture attached to this point (between 0 and 1)

indices is useful if, for some (very good) reason, you don’t want to give the points in the order you’ll use them, or if you want to refer to a point multiple time (this won’t be demonstrated in this blog post, but try to think about a grid mapping, for example), now we will use it in the most simple way, just give the range of your number of points.

the texture needs to be a texture object, you can get such an object by getting the texture property of a [CoreImage](http://kivy.org/docs/api-kivy.core.image.html#kivy.core.image.Image) or an Image (or even a Label, if you want to).

Let’s say we have an image, for example, kivy logo.

from kivy.core.image import Image as CoreImage

texture = CoreImage('data/logo/kivy-icon-512.png').texture

(this will work wherever you are, because kivy look at his images anyway :))

This image is a circle, lets use that to cut it into a virtual pie and assign a part of the texture to each part, we’ll be using the triangle_fan mode of Mesh, that is a perfect fit for such an operation.

# the central point
points = [Window.width / 2, Window.height / 2, .5, .5]

# now go around
    i = 0
    while i < 2 * pi:
        i += 0.01 * pi
        points.extend([
    Window.width / 2 + cos(i) * 100,
    Window.height / 2 + sin(i) * 100,
    .5 + sin(i),
    .5 + cos(i)])

put that in a more complete program, and you get this:

from kivy.app import App
from kivy.lang import Builder
from kivy.core.image import Image as CoreImage
from kivy.properties import ListProperty, ObjectProperty
from kivy.clock import Clock
from kivy.core.window import Window
from math import sin, cos, pi


kv = '''
Widget:
    canvas:
        Color:
            rgba: 1, 1, 1, 1
        Mesh:
            vertices: app.mesh_points
            indices: range(len(app.mesh_points) / 4)
            texture: app.mesh_texture
            mode: 'triangle_fan'
'''


class MeshBallApp(App):
    mesh_points = ListProperty([])
    mesh_texture = ObjectProperty(None)

    def build(self):
        self.mesh_texture = CoreImage('data/logo/kivy-icon-512.png').texture
        Clock.schedule_interval(self.update_points, 0)
        return Builder.load_string(kv)

    def update_points(self, *args):
        points = [Window.width / 2, Window.height / 2, .5, .5]
        i = 0
        while i < 2 * pi:
            i += 0.01 * pi
            points.extend([
                Window.width / 2 + cos(i) * 100,
                Window.height / 2 + sin(i) * 100,
                .5 + cos(i),
                .5 + sin(i)])

        self.mesh_points = points

if __name__ == '__main__':
    MeshBallApp().run()

Now, this is not very impressive, we just have an image, there were much simpler ways to do that!

But now, we can tweek the rendering a lot, lets add some offseting of the texture, some radius change, and some wobbling, with sliders to control all this.

from kivy.app import App
from kivy.lang import Builder
from kivy.core.image import Image as CoreImage
from kivy.properties import ListProperty, ObjectProperty, NumericProperty
from kivy.clock import Clock
from kivy.core.window import Window
from math import sin, cos, pi


kv = '''
BoxLayout:
    Widget:
        canvas:
            Color:
                rgba: 1, 1, 1, 1
            Mesh:
                vertices: app.mesh_points
                indices: range(len(app.mesh_points) / 4)
                texture: app.mesh_texture
                mode: 'triangle_fan'
    BoxLayout:
        orientation: 'vertical'
        size_hint_x: None
        width: 100
        Slider:
            value: app.offset_x
            on_value: app.offset_x = args[1]
            min: -1
            max: 1
        Slider:
            value: app.offset_y
            on_value: app.offset_y = args[1]
            min: -1
            max: 1
        Slider:
            value: app.radius
            on_value: app.radius = args[1]
            min: 10
            max: 1000
        Slider:
            value: app.sin_wobble
            on_value: app.sin_wobble = args[1]
            min: -50
            max: 50
        Slider:
            value: app.sin_wobble_speed
            on_value: app.sin_wobble_speed = args[1]
            min: 0
            max: 50
            step: 1
'''


class MeshBallApp(App):
    mesh_points = ListProperty([])
    mesh_texture = ObjectProperty(None)
    radius = NumericProperty(500)
    offset_x = NumericProperty(.5)
    offset_y = NumericProperty(.5)
    sin_wobble = NumericProperty(0)
    sin_wobble_speed = NumericProperty(0)

    def build(self):
        self.mesh_texture = CoreImage('data/logo/kivy-icon-512.png').texture
        Clock.schedule_interval(self.update_points, 0)
        return Builder.load_string(kv)

    def update_points(self, *args):
        points = [Window.width / 2, Window.height / 2, .5, .5]
        i = 0
        while i < 2 * pi:
            i += 0.01 * pi
            points.extend([
                Window.width / 2 + cos(i) * (self.radius + self.sin_wobble * sin(i * self.sin_wobble_speed)),
                Window.height / 2 + sin(i) * (self.radius + self.sin_wobble * sin(i * self.sin_wobble_speed)),
                self.offset_x + sin(i),
                self.offset_y + cos(i)])

        self.mesh_points = points

if __name__ == '__main__':
    MeshBallApp().run()

which gives us:

Kivy image manipulations with Mesh and Text

Now we are talking!

[logilab] A Salt Configuration for C++ Development

Publié le 2014-01-27 11:54:00
http://www.logilab.org/file/204916/raw/SaltStack-Logo.png

At Logilab, we've been using Salt for one year to manage our own infrastructure. I wanted to use it to manage a specific configuration: C++ development. When I instantiate a Virtual Machine with a Debian image, I don't want to spend time to install and configure a system which fits my needs as a C++ developer:

This article is a very simple recipe to get a C++ development environment, ready to use, ready to hack.

Give Me an Editor and a DVCS

Quite simple: I use the YAML file format used by Salt to describe what I want. To install these two editors, I just need to write:

vim-nox:
  pkg.installed

emacs23-nox:
  pkg.installed

For Mercurial, you'll guess:

mercurial:
 pkg.installed

You can write these lines in the same init.sls file, but you can also decide to split your configuration into different subdirectories: one place for each thing. I decided to create a dev and editor directories at the root of my salt config with two init.sls inside.

That's all for the editors. Next step: specific C++ development packages.

Install Several "C++" Packages

In a cpp folder, I write a file init.sls with this content:

gcc:
    pkg.installed

g++:
    pkg.installed

gdb:
    pkg.installed

cmake:
    pkg.installed

automake:
    pkg.installed

libtool:
    pkg.installed

pkg-config:
    pkg.installed

colorgcc:
    pkg.installed

The choice of these packages is arbitrary. You add or remove some as you need. There is not a unique right solution. But I want more. I want some LLVM packages. In a cpp/llvm.sls, I write:

llvm:
 pkg.installed

clang:
    pkg.installed

libclang-dev:
    pkg.installed

{% if not grains['oscodename'] == 'wheezy' %}
lldb-3.3:
    pkg.installed
{% endif %}

The last line specifies that you install the lldb package if your Debian release is not the stable one, i.e. jessie/testing or sid in my case. Now, just include this file in the init.sls one:

# ...
# at the end of 'cpp/init.sls'
include:
  - .llvm

Organize your sls files according to your needs. That's all for packages installation. You Salt configuration now looks like this:

.
|-- cpp
|   |-- init.sls
|   `-- llvm.sls
|-- dev
|   `-- init.sls
|-- edit
|   `-- init.sls
`-- top.sls

Launching Salt

Start your VM and install a masterless Salt on it (e.g. apt-get install salt-minion). For launching Salt locally on your naked VM, you need to copy your configuration (through scp or a DVCS) into /srv/salt/ directory and to write the file top.sls:

base:
  '*':
    - dev
    - edit
    - cpp

Then just launch:

> salt-call --local state.highstate

as root.

And What About Configuration Files?

You're right. At the beginning of the post, I talked about a "ready to use" Mercurial with some HG extensions. So I use and copy the default /etc/mercurial/hgrc.d/hgext.rc file into the dev directory of my Salt configuration. Then, I edit it to set some extensions such as color, rebase, pager. As I also need Evolve, I have to clone the source code from https://bitbucket.org/marmoute/mutable-history. With Salt, I can tell "clone this repo and copy this file" to specific places.

So, I add some lines to dev/init.sls.

https://bitbucket.org/marmoute/mutable-history:
    hg.latest:
      - rev: tip
      - target: /opt/local/mutable-history
      - require:
         - pkg: mercurial

/etc/mercurial/hgrc.d/hgext.rc:
    file.managed:
      - source: salt://dev/hgext.rc
      - user: root
      - group: root
      - mode: 644

The require keyword means "install (if necessary) this target before cloning". The other lines are quite self-explanatory.

In the end, you have just six files with a few lines. Your configuration now looks like:

.
|-- cpp
|   |-- init.sls
|   `-- llvm.sls
|-- dev
|   |-- hgext.rc
|   `-- init.sls
|-- edit
|   `-- init.sls
`-- top.sls

You can customize it and share it with your teammates. A step further would be to add some configuration files for your favorite editor. You can also imagine to install extra packages that your library depends on. Quite simply add a subdirectory amazing_lib and write your own init.sls. I know I often need Boost libraries for example. When your Salt configuration has changed, just type: salt-call --local state.highstate.

As you can see, setting up your environment on a fresh system will take you only a couple commands at the shell before you are ready to compile your C++ library, debug it, fix it and commit your modifications to your repository.

[cubicweb] Cubicweb sprints winter/spring 2014

Publié le 2014-01-24 12:19:00

The Logilab team is pleased to announce two Cubicweb sprints to be held in its Paris offices in the upcoming months:

February 13/14th at Logilab in Paris

The agenda would be the FROM clause for which a CWEP is still awaited, and the RQL rewriter according to the CWEP02.

April 28/30th at Logilab in Paris

Agenda to be defined.

Join the party

All users and contributors of CubicWeb are invited to join the party. Just send an email to contact at Logilab.fr if you plan to come.

http://farm1.static.flickr.com/183/419945378_4ead41a76d_m.jpg