Quantcast
Channel: AFPy's Planet
Viewing all 3409 articles
Browse latest View live

[Biologeek] Autoritaire ou coopératif

$
0
0

Il ne s’agit plus du tout de cela, mais bien plutôt d’un choix entre la centralisation ou la distribution, le choix entre un système autoritaire ou un système coopératif.

[…]

Il y a un changement dans le paradigme du pouvoir. Le pouvoir du haut vers le bas, le pouvoir centralisé. La nouvelle génération a une vision complètement différente. La génération Internet ne pense pas entre gauche et droite. Ils ne pensent pas capitalisme ou socialisme. Ces mots ne sont même plus inscrits dans leur vocabulaire. Quand un jeune de la génération internet juge un comportement politique, il pose la question de la manière suivante, que ce soit à un gouvernement, une entreprise, un parti politique ou une école : est-ce que cette institution se comporte de façon centralisée, patriarcale, du haut vers le bas, propriétaire, fermée ? Ou est-ce que cette institution se conduit de façon distributive, collaborative, ouverte, transparente avec des pouvoirs latéraux.

Jeremy Rifkin retranscrit par Pascal Gaillard Du pouvoir vertical au pouvoir latéral…

Dans la théorie, je trouve cela évident. Maintenant lorsqu'il s'agit de le mettre en pratique je deviens sceptique en observant les difficultés que l'on peut déjà avoir à 4 pour changer ce paradigme du pouvoir en étant tous pleinement convaincus de son intérêt. Pour en arriver à affecter la culture et la civilisation comme Jeremy Rifkin l'ambitionne, il va falloir à mon avis énormément de temps (et d'éducation). Or, on manque justement de temps. Et encore, ce n'est pas une mutation mais une création dans notre cas, ce qui s'avère plus facile :

Rachel: GitHub started out flat from the get go. Do you think that in a more traditional structure, people can transition to and ‘go flat’?

Steve: I think it would be difficult to do unless you have a buy-in from everyone on the team. If we had twelve managers and wanted to go flat, we’d have to be like, “So you guys, I don’t know what you’re going to do now. We don’t really need you anymore—.” I don’t know how you’d handle that as a company [laughing].

Steve Smith On Optimizing For Happiness

D'un autre côté, j'ai l'impression que les choses bougent au niveau de la coopération dans l'entreprise. Peut-être est-ce le prisme déformant de mon centre d'intérêt qui me fait découvrir des entreprises et les personnes qui les animent comme Ninja Squad ou Lateral Thoughts mais il est vraiment encourageant de découvrir que cet épiphénomène n'en est peut-être pas un :

Toute entreprise, en tant que système humain organisé autour d’un objectif commun, répond à ces lois relationnelles du vivant qui régissent autant l’infiniment petit que l’infiniment grand. Ainsi, la capacité d’équilibre et d’évolution de l’entreprise repose fondamentalement sur la fluidité de l’information qui circule et la qualité des interactions humaines qu’elle génère.

En outre, et à l’inverse des hiérarchies de contrôle habituelles des sociétés où la règle descend du haut, il s’avère scientifiquement que l’ordre et le changement (homéostasie et évolution) s’élèvent du bas vers le haut : le système s’autogénère à partir d’une coopération spontanément adaptative entre ses parties, pour un bénéfice général.

[…]

Il lui faut pour cela, en premier lieu, respecter et s’appuyer sur le ressort fondamental de l’être humain, qui constitue sa liberté et sa dignité : s’accomplir individuellement, dans et par l’interaction humaine, au service d’une cause co-construite qui transcende ses besoins égotiques pour servir positivement son système d’appartenance (l’humanité).

Pascal Gaillard, Kosmos (3) : un management résolument horizontal

Je vous invite à lire l'intégralité des articles relatifs à la création de cette entreprise (série non terminée) :

Il faudra que j'arrive à écrire ce type d'articles relatifs à scopyleft lorsque j'aurai un peu plus de recul. Mon marque-page actuel est celui d'Amnesty International sur lequel est inscrit :

Mieux vaut allumer une bougie que maudire l'obscurité.


[Biologeek] Diète d'information

$
0
0

Karl m'a récemment transmis un lien vers une vidéo de Gilles Deleuze au départ au sujet de la créativité (première partie de la vidéo) mais dont la seconde se révèle être tout aussi intéressante, si ce n'est plus :

Une information c'est un ensemble de mots d'ordres. Quand on vous informe, on vous dit ce que vous êtes sensés devoir croire. En d'autres termes, informer c'est faire circuler un mot d'ordre. Les déclarations de police sont dites à juste titre des « communiqués ». On nous communique de l'information, c'est-à-dire on nous dit ce que nous sommes sensés être en état de ou devoir croire, ce que nous sommes tenus de croire. Ou même pas de croire mais de faire comme si l'on croyait. On nous demande pas de croire, on nous demande de nous comporter comme si nous le croyons. […] L'information c'est exactement le système du contrôle. […] Les sociétés de contrôle ne passeront plus par des milieux d'enfermement [vs. sociétés de discipline]. […] La contre-information n'est effective que lorsqu'elle devient un acte de résistance.

Gilles Deleuze, Qu'est-ce que l'acte de création ?

Je vous invite à visionner l'intégralité de la vidéo ou l'une de ses transcriptions.

Les propos de Gilles Deleuze prennent un résonance particulière pour moi car ils corroborent mon analyse des effets de ma diète d'information au cours de ces derniers mois. En arrivant au Japon, s'est posée la question de savoir s'il était pertinent de garder un œil sur ce qu'il se passait en France et je m'étais abonné à Mediapart dans cette optique. Je me suis rapidement senti étranger à toute cette information, d'une part en raison de la distance physique, mais surtout par la futilité et/ou la distance en termes d'intérêts qui émanait de cette actualité pessimiste et anxiogène.

De retour après quelques mois, j'ai confirmé mon choix de ne plus être abreuvé d'information en donnant ma télévision, en n'écoutant pas la radio et en ne m'abandonnant à aucun journaux. C'est un réel soulagement. Je ne consulte que la revue délivrée par la mairie pour connaître les actualités locales une fois par mois et je suis parfois informé de ce qu'il se passe à une autre échelle par des proches ou Twitter (ce qui transforme cette information en opinion discutable). Mon empathie est redevenue locale. Elle n'a plus besoin d'être sollicitée incessamment et inutilement pour des situations sur lesquelles je n'ai aucun pouvoir, ni parfois aucune motivation.

J'ai également repris le contrôle de mon attention, celui dont cette société a tant besoin.

[noirbizarre] Création de virtualenvs préconfigurés hors-ligne

$
0
0
Je créée très souvent des virtualenvs avec virtualenvwrapper, et j’ai souvent les mêmes problèmes: il faut installer les mêmes outils de base à chaque fois il faut être connecté pour les télécharger le téléchargement peut être long mkvirtualenv propose un hook, postmkvirtualenv, qui permet d’exécuter des commandes après la création du virtualenv. Je l’utilise pour lancer l’installation…

[hautefeuille] Sonde de température Onewire, Arduino et visualisation OpenGL en Python

$
0
0

L’objectif de cette note est de réaliser un appareil capable de mesurer les températures, de transmettre ces données sans-fil à une station et enfin de réaliser un visualiseur de données en OpenGL.

Je vous conseille de lire une note précédente au sujet du capteur DS1821:

http://hautefeuille.eu/capteur-de-temperature-dallas-1821.html

Travail préparatoire

  • Configurer les modules Xbee correctement,
  • Conception physique et électrique.

Composants matériels

  • Module Arduino,
  • Sonde de température DS1821 avec sa résistance,
  • Ecran LCD avec son module série - http://www.crystalfontz.com,
  • 2 modules Xbee pour émission et réception
  • Un convertisseur série vers usb pour un des modules Xbee.

Composants logiciels

Protocole d’échange sur le port série

J’ai décidé de formater mes paquets de données de la manière suivante:

$val1!val2!...*

Ce choix rend plus facile les manipulations ultérieures des données.

Code source Arduino

#include <SoftwareSerial.h>
#include <OneWire.h>

// DS1821 on digital pin 2 external
OneWire ds(2);

// DS1821 on digital pin 8 internal
OneWire ds1(8);

// LCD on digital pin 6 et 7
SoftwareSerial LCD(6, 7);

// LCD on digital pin 6 et 7
SoftwareSerial XBEE(3, 4);

int led = 13;

void setup(void)
{
    LCD.begin(9600);
    XBEE.begin(57600);
    Serial.begin(9600);

    //start 1821 conversion external
    ds.reset();
    ds.write(0xEE);

    //start 1821 conversion internal
    ds1.reset();
    ds1.write(0xEE);

    pinMode(led, OUTPUT);
    digitalWrite(led,LOW);
}

void loop(void){
    // external _
    // internal 1
    byte temp_, temp1_;
    byte present, present1;

    // protocol
    // $val0|val1|...*
    // start packet
    String paquet = "$";

    digitalWrite(led,LOW);
    delay(1000);

    // Read value external
    present = ds.reset();
    ds.reset();
    ds.write(0xAA);
    temp_ = ds.read();

    // Read value internal
    present1 = ds1.reset();
    ds1.reset();
    ds1.write(0xAA);
    temp1_ = ds1.read();

    //start 1821 conversion external
    ds.reset();
    ds.write(0xEE);

    //start 1821 conversion internal
    ds1.reset();
    ds1.write(0xEE);

    // negative temp external
    if (temp_ >> 7 == 1){
        paquet = paquet + "E";
        paquet = paquet + "!-";
        paquet = paquet + ((temp_ ^ 0xFF) + 1); // bit inversion
    }
    // positive temp external
    else
    {
        paquet = paquet + "E";
        paquet = paquet + "!+";
        paquet = paquet + temp_;

    }
    // negative temp internal
    if (temp1_ >> 7 == 1){
        paquet = paquet + "!I";
        paquet = paquet + "!-";
        paquet = paquet + ((temp1_ ^ 0xFF) + 1); // bit inversion
    }
    // positive temp internal
    else
    {
        paquet = paquet + "!I";
        paquet = paquet + "!+";
        paquet = paquet + temp1_;
    }
    // closing packet
    paquet = paquet + "*";
    Serial.print(paquet);
    LCD.print("?n");
    LCD.print(paquet);
    XBEE.print(paquet);
    digitalWrite(led,HIGH);
    delay(1000); // default 500
}

Code source Python pour le visualiseur

# -*- coding: utf-8 -*-
"""
@author: julien@hautefeuille.eu

#sudo apt-get install python-kivy

Usage: viewerGL.py
"""

import kivy
kivy.require('1.5.1')

from kivy.app import App

from kivy.uix.label import Label
from kivy.uix.boxlayout import BoxLayout
from kivy.clock import Clock

import serial

class MeteoArduino(App):

    title = 'Meteo Arduino'

    def build(self):

        layout = BoxLayout(
            orientation='vertical',
            spacing=10,
            padding=10)

        label_temp = Label(
            text='',
            font_size='60sp',
            size_hint=(1, 0.5))

        label_temp1 = Label(
            text='',
            font_size='60sp',
            size_hint=(1, 0.5))

        layout.add_widget(label_temp)
        layout.add_widget(label_temp1)

        def get_packet(obj):
            data = ser.read(13)
            if data.startswith("$") and data.endswith("*"):
                clean = data.strip('$').strip('*').strip()
                split = clean.split('!')
                label_temp.text = split[1]
                label_temp1.text = split[3]
                print split
            else:
                pass

        Clock.schedule_interval(get_packet, 1)

        return layout

if __name__ == '__main__':
    connection = '/dev/ttyUSB0'
    ser = serial.Serial(connection, 9600)
    MeteoArduino().run()

[raspberry-python] Nouvelle publication DIY

$
0
0

faitmain

Un nouveau magazine vient de paraitre, il s'agit de Fait Main, un magazine collaboratif en ligne et en PDF:

http://www.faitmain.org

On y retrouve divers sujets autour du DIY("Do It Yourself"), et dans ce premier numéro, on y parle bien sur de Raspberry Pi.

J'ai écris l'article "câble d'interface pour Raspberry Pi" Lire l'article 

Mais ce n'est pas tout: 

Contenu du volume 1

La tribune de ce numéro est un parallèle entre web hébergé et OGM. Lire la tribune 

Le premier article présente une application de reconnaissance de feuille écrite pendant un Hackathon. C'est l'application qui a été écrite en 24 heures par Olivier, Ronan & Tarek lors du dernier AngelHack à Paris. On y parle de machine-learning au service des plantes, des hackathons de programmation & de responsive design . Lire l'article

Le deuxième article parle de domotique et vous explique comment piloter des dispositifs sans fils - portails, détecteurs de mouvements etc. On y parle d' Arduino , de Raspberry-PI et de signal en 433 mhz . Lire l'article 
 
Le troisième article présente le travail de Marcin Ignac: des méduses animées en 3D. Des captures d'écran de ces méduses ont ensuite été utilisées pour faire partie d'un projet de livre génératif. On y parle d' animation procédurale , de processing.js & d'hachurage. Lire l'article

Le quatrième article vous donne 5 conseils de photos culinaires pour que vous puissiez prendre en photos vos soupes, gigots et autres desserts comme un(e) pro. Lire l'article 

Suit une interview de Hugues Aubin au LabFab de Rennes. Lire l'article .

Un cinquième article sur la conception d'un Juke box avec un Raspberry-PI, sans aucune soudure requise :) Lire l'article 

Le sixième article vous explique comment recycler une vieille nappe de disque dur pour connecter le GPIO de votre Raspberry. Lire l'article 

Le septième article est une rapide présentation du jeu The Midst , conçu avec Processing et WebPD. Lire l'article 

Enfin, le huitième article aborde les bases du fonctionnement d'une CNC. Lire l'article 
Bonne Lecture!
— Tarek

Equipe

Le projet FaitMain est monté par Tarek Ziadé mais est surtout possible grâce aux créateurs d'articles et aux relecteurs.

Ont participé à ce numéro :

[novapost] Unit test your Django views

$
0
0

How to test views of a Django application?

Django's builtin test client is not suitable for unit testing! It performs system tests: it handles your views as a black box in a project's environment.

This article provides a recipe for developers to replace Django's builtin test client by smaller, fine-grained, view-centric tests.

self.client.get(): system tests for the unaware

Here are some reasons why Django's builtin client performs system tests:

  • it resolves URLs,
  • it traverses middlewares,
  • it traverses decorators,
  • it uses template context processors,
  • it relies on settings,
  • ... and perhaps more. Who knows? Do you really want to know?

All the stuff above is not the view, it is the environment surrounding the view.

It means that, by using the test client, you don't test the view itself, but the system the view is part of. And the environment is quite hard (and boring) to control.

Here, we want to focus on the view, so let's emancipate from all those third party mechanisms.

Testing view functions

Let's consider this simple view:

from django.http import Http404, HttpResponse

def hello(request, name):
    if name == u'Waldo'
        raise Http404("Where's Waldo?")
    return HttpResponse(u'Hello {name}!'.format(name=name))

Then test it:

import unittest

class HelloTestCase(unittest.TestCase):
    def test_get(self):
        """hello view actually tells 'Hello'."""
        # Setup.
        request = 'fake request'
        name = 'world'
        # Run.
        response = hello(request, name)
        # Check.
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.content, u'Hello world!')

    def test_waldo(self):
        """Cannot find Waldo to tell him 'Hello'."""
        # Setup.
        request = 'fake request'
        name = 'Waldo'
        # Run and check.
        self.assertRaises(Http404, hello, request, name)

Pretty simple isn't it?

Really, you don't need Django's builtin test client to write such tests!

Use unittest or SimpleTestCase wherever you can

In the example above, we didn't hit the database, so there were no reasons to use django.test.TransactionTestCase [1] or derivatives.

With such a configuration, tests run really fast!

Note

Performance is another reason you should avoid Django's builtin test client. But that's another story.

Wherever you can, use unittest, or django.test.SimpleTestCase [2].

Don't decorate views in place

The "hello" example above would have been broken if the view were decorated in place. As an example:

from django.http import Http404, HttpResponse
from django.contrib.auth.decorators import login_required

@login_required
def hello(request, name):
    if name == u'Waldo'
        raise Http404("Where's Waldo?")
    return HttpResponse(u'Hello {name}!'.format(name=name))

How can we test hello() view now?

We would have to perform (mock) a login, and we would have to check the response with or without authentication. As a consequence, our tests would become longer, less readable, less efficient... Moreover, what if the login decorator has bugs or changes? It would break hello's tests even if hello itself doesn't change. How bad!

So, don't decorate views in place.

Instead:

  • decorate views somewhere related to URLconfs (urls.py), not related to views.
  • have specific tests for decorators, i.e. validate login_required works.
  • have specific tests for URLconfs, i.e. validate login_required is applied to hello in project's configuration (this is a system test).

Use request factories

Django's builtin test client is a special kind of request factory [3], which uses URL resolution to trigger the views (deep inside the system). Now we have isolated views from system. But a view still takes a request as argument. How to get a request?

In the function-based example above, we used a completely fake request. But sometimes you can't do that and need a HttpRequest.

Django provides django.test.RequestFactory [4] to mock requests.

With a request factory, you get a request instance you can pass as argument to views' methods such as dispatch().

from django.test import RequestFactory

request_factory = RequestFactory()
request = request_factory.post('/fake-path', data={'name': u'Waldo'})

Note

Some notes about request factories, which could make a full article...

  • Django's builtin RequestFactory requires one positional argument: path. But, in the scope of tests of this article, we really don't care about the path. The path is mandatory for the test client to resolve URLs... So, unless your view actually uses the path argument, you can safely use a fake value.
  • If your view uses the messages framework, you'll need to setup (or mock) request._messages. Notice that's a feature, since messages should be tested too ;)
  • Idem about session: you may need to mock request.session if your view depends on the session.
  • Yes, you are now aware of your view's dependencies :)

Testing class-based views

Once we got rid of Django's builtin test client, we can consider views themselves. How do they look like?

Function-based views look like black boxes: things that take a request and return a response. No way to test internals.

With class-based views, we have various methods and attributes. So we can write fine-grained tests!

The idea here is to test every custom method or attribute of the class-based views you write.

Let's consider the following view:

class HelloView(TemplateView):
    def get_context_data(self, **kwargs):
        kwargs = super(HelloView, self).get_context_data(**kwargs)
        kwargs.update('name', self.kwargs.get('name'))
        return kwargs

as_view() is not enough

Testing class-based views using as_view() and RequestFactory is now described in Django's documentation along with django.test.RequestFactory [4].

Ok, it works. But, in the HelloView above, I just overrid the get_context_data() method. So I'd like to test only that.

We can't use as_view() to perform fine-grained testing.

One issue with as_view() is that it returns a function, not an instance of the view class. And this callable is a proxy to view's dispatch(), which involves almost all view's methods, depending on the arguments.

So, using as_view() in tests would be the same as having a function-based view.

Alright, let's get rid of as_view()...

Mimic as_view()

Let's consider you'd like to reproduce this URLconf scenario:

  • view: hello = HelloView.as_view(template_name='hello.html')
  • URL: url(r'(?P<name>\w+)', hello)

Here is a simple replacement for as_view():

def setup_view(view, request, *args, **kwargs):
    """Mimic as_view() returned callable, but returns view instance.

    args and kwargs are the same you would pass to ``reverse()``

    """
    view.request = request
    view.args = args
    view.kwargs = kwargs
    return view

Here is how to use it in a test:

import unittest
from django.test import RequestFactory

class UserDetailTestCase(unittest.TestCase):
    def test_context_data(self):
        """HelloView.get_context_data() sets 'name' in context."""
        # Setup name.
        name = 'django'
        # Setup request and view.
        request = RequestFactory().get('/fake-path')
        view = HelloView(template_name='hello.html')
        view = setup_view(view, request, name=name)
        # Run.
        context = view.get_context_data()
        # Check.
        self.assertIn('name', context)
        self.assertEqual(context['name'], name)

That's all. What happened?

  • Just tested the get_context_data method which we overrid. Other methods inherited from TemplateView are covered by TemplateView test suite.
  • We used unittest since there is no transaction involved.

The fairy as_view() and the ugly dispatch()

Let's end with a story about as_view() magic.

Using as_view() is quite elegant:

request = RequestFactory().get('/fake-path')
view = HelloView.as_view(template_name='hello.html')
response = view(request, name='bob')

Using dispatch() is ugly:

request = RequestFactory().get('/fake-path')
view = HelloView(template_name='hello.html')
view = setup_view(view, request, name='bob')
response = view.dispatch(view.request, *view.args, **view.kwargs)

Got it? dispatch() receives arguments the instance already knows...

Diving into fine-grained tests on Django-style class-based views may awake trolls. Billy-Thread-Safe, Kate-Instance and Frank-Class-Attribute may join the party soon ;)

In fact, it looks like Django's class-based views haven't been designed to be fine-grained tested.

If your are curious, have a look on Django's tests...

What's next

Since you test your views as isolated items, you have to test everything else: middlewares, decorators, context processors, models...

And you can fake/mock many things inside tests of views, so that you don't rely on database, settings, ...

[raspberry-python] Applications pour téléphones mobiles avec Python

$
0
0
C'est une traduction de iPhone app with Python. J'ai eu une forte demande pour la version française.

Grâce a Brython


L’icône Brython GPS

 

Une vraie app pour iPhone?


Le programme lancé, on y voit un écran de démarrage, comme il se doit:

Splash (ancienne carte de Caroline du Nord)

Mais c'est un programme web, et pas une application faite avec xcode.

Le premier écran, mode manuel


Mode mise a jour automatique

J'essaie?


Il suffit d'aller sur le lien de la galerie de Brython, ici:

gallery/geo.html et sur un iPhone, on l'ajoute a l'ecran d'accueil. On peut maintenant lancer le programme comme une vraie application iOS.


J'ai déjà vu cela, non?


C'est bel et bien une application web, donc basée sur HTML et CSS, mais le code lui même, c'est écrit en Python. En plus, on utilise ici une toute nouvelle fonctionnalité de Brython, en faisant appel a un script Python externe a la page HTML (c'est une nouveauté qui date de cette fin de semaine), plutôt que d'avoir le code a même la page HTML. Cela nous permet une séparation de la présentation, de la logique et du "bling" (le CSS):

Notre HTML


<!DOCTYPE html>
<html>
    <head>
        <title>Brython test</title>
        <meta charset="iso-8859-1">
        <meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1,maximum-scale=1">
        <meta name="apple-mobile-web-app-capable" content="yes">
        <script src="../brython.js"></script>
        <script type="text/python" src="navi.py"></script>
        <link rel="stylesheet" type="text/css" href="navi.css" />
        <link rel="apple-touch-icon" href="icon.png"/>
        <link rel="apple-touch-startup-image" href="splash.png">
    </head>
    <body onLoad="brython()">
        <div id="header">
            <H1>Votre position</H1>
            <div id="switch">
                  <span class="thumb"></span>
                    <input id="refr" type="checkbox" />
                </div>
            </div>
        </div>
        <div id="navarea"></div>
        <div id="maparea"></div>
    </body>
</html>

Application web pour iPhone typique, mais sans jQuery mobile ou autre module du genre. Et pas de onclick dans la page html. L'unique javascript c'est brython.js qui est l’interpréteur Brython même et l'appel a brython() par l'entremise de onload.

Le code Python n'est pas sur la page, mais on voit qu'on y fait reference par src="navi.py"

Allons donc voir ce qu'il y a dans ce fichier navi.py:

Notre Python


# globals #########################
refr = False
geo = win.navigator.geolocation
watchid = 0


# les fonctions ###########################
def navi(pos):
xyz = pos.coords

ul = UL(id="nav")
ul <= LI('lat: %s' % xyz.latitude)
ul <= LI('lon: %s' % xyz.longitude)

mapurl = "http://maps.googleapis.com/maps/api/staticmap?markers=%f,%f&zoom=15&size=320x298&sensor=true" % (xyz.latitude, xyz.longitude)
img = IMG(src = mapurl, id = "map")
try:
doc["nav"].html = ul.html # on met a jour la liste
except KeyError:
doc["navarea"] <= ul # on cree la liste
try:
doc["map"].src = mapurl # on met a jour l'url de l'image
except KeyError:
doc["maparea"] <= img # on cree la balise img

def nonavi(error):
log(error)

def navirefresh(ev):
global refr, watchid
refr = False if refr else True
if refr == True:
doc["switch"].className = "switch on"
watchid = geo.watchPosition(navi, nonavi)
else:
doc["switch"].className = "switch"
geo.clearWatch(watchid)

# au demarrage ###########
if geo:
geo.getCurrentPosition(navi, nonavi)
doc["switch"].className = "switch"
doc["switch"].onclick = navirefresh # on associe un evenement onclick
else:
alert('geolocation not supported')

On établis 2 fonctions de rappel (callback). Une si on a notre géolocalisation (navi), et une s'il y a une erreur (nonavi), et finalement, une autre fonction (navirefresh) pour s'occuper de l’événement onclick du contrôle auto refresh dans la barre de menu de l'application. Le démarrage initial se fait par un appel a geo.getCurrentPosition avec nos fonctions de rappel. Ça fonctionne assez bien comme GPS.

Notre CSS

Le CSS étant un peu long, je ne le mettrai pas sur mon blog, mais vous pouvez trouver le code sur le site brython.info ou sur googlecode: SVN repository. Le CSS pour l'interrupteur genre ios 5 a ete emprunté ici: ios-5-style-switch-control

Ce n'est que le début

Alors voila, c'est un point de depart pour faire toute sortes de choses. Un tracker pour le jogging, le velo (avec local storage et synchro par appel ajax) et bien d'autres choses. Vous pouvez désormais faire tout cela avec votre langage favori (Python, bien sur) que ce soit pour votre téléphone mobile ou tablette. Cet exemple est quelque peu spécifique au iPhone (surtout a cause du CSS), mais fonctionne sur Android aussi et peut être adapté facilement aux tablettes. Et cela ne m'a pas pris beaucoup de temps.

Et si vous avez besoin d'aide, n'oubliez pas qu'il existe une liste en francais:
forum/brython-fr

@f_dion

[Biologeek] Conférences et diversité

$
0
0

Je vais pas mal intervenir ces prochains mois, peut-être l'occasion de se rencontrer et d'échanger :

N'hésitez pas à me soumettre vos pistes/questions avant les interventions si vous souhaitez que je développe un point particulier sur les sujets proposés.

Comme vous pouvez le remarquer, pas (trop) de Python/Django ce semestre. Envie d'explorer de nouveaux horizons et de m'enrichir d'autres communautés.


[novapost] A Django testing challenge

$
0
0

Here at Novapost, we have quite large Django projects. Big projects mean big maintenance. Hopefully, those projects are covered by tests. Thousands of tests. We are quite proud of this fact. Tests save our lives. But we also have some worries and need to improve... Here is our testing challenge!

Some issues...

Here are some problems we encounter...

Performance

In the biggest project, our continuous integration service can't run a full test suite in less than one hour. That's embarrassing, because we can't wait for global test results before we commit.

We'd like a collection of tests that run fast and give us the status of most of the project. So that we can run it before we commit. Then the continuous integration service would cover the rest.

Maintenance

When we change a feature, it sometimes has side effects on some tests which seem unrelated. It looks like our tests involve much more than necessary. Not only it affects performance, but it also affects maintenance: sometimes we know something is wrong because tests fail, but we cannot tell exactly what's wrong. And finally, we have to adapt several tests for only one feature.

We'd like tests to focus on small units, so that, when something goes wrong, tests help us figure out what's exactly wrong. And we'd like to change only what's really related.

Tests pass, deployment fail

Sometimes tests are not enough: we fix things, but we can't tell if the fix works after an upgrade. As an example, changes that involve settings are hard to cover with tests: once the fix is committed and pushed, the story cannot be closed before we make sure the configuration has been updated and everything is ok on servers. We are doing some manual checks...

We'd like to involve more into deployment, supervision and monitoring, so that we can automate some checks related to the issues or features we develop.

Some clues...

We already have some ideas about what's wrong with our testing strategy. Here are some hypotheses:

  • one cause of those long test suites is the heavy use of self.client.get() aka functional/system test for the unaware ;
  • we could mock/fake more things ;
  • we could separate tests that run fast from tests that run slow ;
  • we could split our big all-in-one test suite into smaller parts: unit tests, functional tests, integration tests, health checks...

A challenge

We are aware of some issues with our testing strategy and have some ideas... Let's improve!

We started teamwork as a challenge:

  • try various improvements when we implement features or fix bugs ;
  • adopt improvements that work, measure how it improves things ;
  • give feedback on the blog!

We are to share experience on this blog, through several articles with the testing tag.

Here are articles we already posted:

[Biologeek] Conférences et éditorialisation

$
0
0

J'ai un sentiment partagé sur le choix de sujets de conférences, la mode semble être passée aux votes du (potentiel) futur public — par exemple pour DjangoCon — et j'ai longtemps cru qu'il s'agissait de la solution ultime pour avoir un programme de conférence qui soit optimal. Aujourd'hui, je n'en suis plus convaincu.

Les votes du public vont classer les sujets par popularité sans aucune orientation ce qui va produire un cycle de conférences sans surprises. Ni cohérence. Ni innovation. Un événement consensuel par excellence saupoudré d'une bribe de découverte si des lightning-talks sont spontanément proposés.

Je pense maintenant qu'il est plus important d'avoir une ligne éditoriale cohérente et surprenante. C'est un exercice très difficile de savoir répondre aux attentes d'un public tout en le bousculant (un peu). Qu'il ne reparte peut-être pas pleinement satisfait mais avec des questions restées sans réponses. Des pistes à creuser. Des mondes à explorer.

Thomas qui s'exprimait il y a quelques semaines sur les enjeux de l'éditorialisation donne l'exemple de DotJS. Je comprends le besoin d'avoir fait appel à des personnes connues dans le milieu pour assurer leurs arrières et établir la confiance permettant de vendre les billets mais je déplore également cette starification des développeurs, la position hiérarchique qui s'établie entre les orateurs (actifs) et les écouteurs (passifs).

Le format type barcamp permet d'avoir une approche un peu différente en terme d'éditorialisation car la popularité se fait en direct en prenant en compte à la fois le sujet, l'animateur, l'envie du moment et les participants mais il est relativement peu populaire (en France) car les sessions auto-organisées manquent souvent de rythme avec un public qui n'est pas habitué à participer aux échanges. Sans compter celles qui sont monopolisées par une seule personne qui prend ça pour une mini-conférence. Il y a également la problématique de prendre un billet pour un événement sans programme qui peut en gêner certains.

Restent des formats hybrides qui me ramènent à des réflexions de 2010 pour que chacun puisse se faire sa propre idée et faire évoluer l'événement au cours des ans (ce qui ne s'est pas vraiment produit avec les rencontres Django qui sont globalement restées sur cette approche hybride).

La question revient finalement à positionner pour les organisateurs le curseur de la curiosité. Doit-elle venir des participants ou être imposée par les organisateurs et les orateurs ? Vaste débat.

[Inspyration] Les décorateurs

$
0
0
Lorsqu'on les croise pour la première fois, les décorateurs revêtent cet aspect magique. On ne sait pas trop comment çà fonctionne, mais on trouve çà classe. C'est facile à utiliser, çà demande peut d'efforts et c'est très puissant. Que demande le peuple ? Par contre, lorsque l'on souhaite en créer, c'est une autre paire de manches. Comme dirait un coach de rugby : "On va tout mettre sur la table et repartir des fondamentaux".

[novapost] Testing Django decorators

$
0
0

How to test view decorators of Django applications? Here are some tips.

In a post before, I recommended to avoid decorating views in place (i.e. not in views.py). Once decorators and views are separated, we can unit test the views. That was the topic of the post before. This article focuses on testing decorators.

The examples described below are available as a Python file at https://gist.github.com/benoitbryon/5156512

Use unittest.mock

Learn about unittest.mock [2] (or backward-compatible mock [1]) library! This article makes heavy use of those wonderful features.

In tests.py:

try:
    from unittest import mock
except ImportError:
    import mock

And in project's or app's setup.py:

# ...
requirements = []
try:
    from unittest import mock
except ImportError:
    requirements.append('mock')
# ...
setup(
    # ...
    install_requires(requirements),
    # ...
)

Fake the request

We want to focus on the decorator. Does it rely on the request to perform some actions? Fake/stub/mock all and only what you need.

django.test.RequestFactory [3] can be useful. But sometimes it is overkill and django.http.HttpRequest [4] is enough.

In the hello world example below, we'll use a completely fake request:

request = 'fake request'

In the authenticated_user_passes_test example below, we use mocks to support request.user.is_authenticated():

request = mock.MagicMock()
request.user.is_authenticated = mock.MagicMock(return_value=True)

Stub the decorated view

We want to focus on the decorator. We don't care about decorated view implementation. But we care about how the decorator handles the view. Let's use unittest.mock [2].

Decorated views are functions (or callables). We can instantiate and check a mocked-view like this:

import unittest

class MockViewTestCase(unittest.TestCase):
    def test_stub(self):
        # Setup.
        request = 'fake request'
        view = mock.MagicMock(return_value='fake response')
        # Run.
        response = view(request)
        # Check.
        view.assert_called_once_with(request)
        self.assertEqual(response, view.return_value)

hello_world decorator

Before we dive into a real-life example, let's consider a really simple one.

Here is the decorator:

from django.http import HttpResponse

def hello_world(view_func):
    """Run the decorated view, but return "Hello world!"."""
    def decorated_view(request, *args, **kwargs):
        view_func(request, *args, **kwargs)
        return HttpResponse(u'Hello world!')
    return decorated_view

Here is the test case:

import unittest

class HelloWorldTestCase(unittest.TestCase):
    def test_hello_decorator(self):
        """hello_world decorator runs view and returns greetings."""
        # Setup.
        request = 'fake request'
        request_args = ('foo', )
        request_kwargs = {'bar': 'baz'}
        view = mock.MagicMock(return_value='fake response')
        # Run.
        decorated = hello_world(view)
        response = decorated(request, *request_args, **request_kwargs)
        # Check.
        # View was called.
        view.assert_called_once_with(request, *request_args, **request_kwargs)
        # But response is "Hello world!".
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.content, u"Hello world!")

The test looks like a documentation for the decorator :)

Some noticeable points:

  • we haven't used Django's builtin test client. We haven't needed to setup URLconfs, settings, "real" views...
  • there is no database transaction involved, so we used unittest.TestCase.

authenticated_user_passes_test decorator

Now let's consider a real-life example, with a custom decorator:

from functools import wraps

from django.utils.decorators import available_attrs

def authenticated_user_passes_test(test_func,
                                   unauthorized=UnauthorizedView.as_view(),
                                   forbidden=ForbiddenView.as_view()):
    """Make sure user is authenticated and passes test.

    This is an adaptation of
    ``django.contrib.auth.decorators.user_passes_test`` where:

    * if user is anonymous, the request is routed to ``unauthorized`` view.
      No additional tests are performed in that case.

    * if user is authenticated and doesn't pass ``test_func ``test, the
      request is routed to ``forbidden`` view.

    * else, request and arguments are passed to decorated view.

    Typical ``unauthorized`` view returns HTTP 401 status code and gives the
    user an opportunity to log in: access may be granted after
    authentication.

    Typical ``forbidden`` view returns HTTP 403 status code: with active
    user account, access is refused. As explained in rfc2616, 401 and 403
    status codes could be suitable.

    .. seealso::

       * http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4
       * https://en.wikipedia.org/wiki/List_of_HTTP_status_codes

    """
    def decorator(view_func):
        @wraps(view_func, assigned=available_attrs(view_func))
        def _wrapped_view(request, *args, **kwargs):
            if not request.user.is_authenticated():
                return unauthorized(request)
            if not test_func(request.user):
                return forbidden(request)
            return view_func(request, *args, **kwargs)
        return _wrapped_view
    return decorator

This decorator depends on some additional stuff:

from django.http import HttpResponse, HttpResponseForbidden
from django.views.generic import TemplateView

class HttpResponseUnauthorized(HttpResponse):
    status_code = 401

class UnauthorizedView(TemplateView):
    response_class = HttpResponseUnauthorized
    template_name = '401.html'

class ForbiddenView(TemplateView):
    response_class = HttpResponseForbidden
    template_name = '403.html'

And, here is the test case! It seems quite long, but isn't it readable? The whole test lives in the TestCase: no external URLconf, no external views...

  • First we setup fakes or mocks for all dependencies: request.user, test_func, unauthorized view, forbidden view, and the view to be decorated.
  • Then we declare a run_decorated_view function to avoid repeating code.
  • Finally we test the 3 main situations: unauthorized, forbidden, authorized.
import unittest

class AuthenticatedUserPassesTestTestCase(unittest.TestCase):
    def setUp(self):
        """Common setup: fake request, stub views, stub user test function."""
        super(AuthenticatedUserPassesTestTestCase, self).setUp()
        # Fake request and its positional and keywords arguments.
        self.request = mock.MagicMock()
        self.request.user.is_authenticated = mock.MagicMock()
        self.request_args = ['fake_arg']
        self.request_kwargs = {'fake': 'kwarg'}
        # Mock user test function.
        self.test_func = mock.MagicMock()
        # Mock unauthorized and forbidden views.
        self.unauthorized_view = mock.MagicMock(
            return_value=u"401 - You may log in.")
        self.forbidden_view = mock.MagicMock(
            return_value=u"403 - Insufficient privileges.")
        # Mock the view to decorate.
        self.authorized_view = mock.MagicMock(
            return_value=u"200 - Greetings, Professor Falken.")

    def run_decorated_view(self, is_authenticated=True, user_passes_test=True):
        """Setup, decorate and call view, then return response."""
        # Custom setup.
        self.request.user.is_authenticated.return_value = is_authenticated
        self.test_func.return_value = user_passes_test
        # Get decorator.
        decorator = authenticated_user_passes_test(
            self.test_func,
            unauthorized=self.unauthorized_view,
            forbidden=self.forbidden_view)
        # Decorate view.
        decorated_view = decorator(self.authorized_view)
        # Return response.
        return decorated_view(self.request,
                              *self.request_args,
                              **self.request_kwargs)

    def test_unauthorized(self):
        """authenticated_user_passes_test first tests user authentication."""
        response = self.run_decorated_view(is_authenticated=False)
        # Check: unauthorized view was called with request as unique positional
        # argument.
        self.unauthorized_view.assert_called_once_with(self.request)
        self.assertEqual(response, self.unauthorized_view.return_value)
        # Test func was not called.
        self.assertFalse(self.test_func.called)
        # Of course, authorized and forbidden views were not called.
        self.assertFalse(self.authorized_view.called)
        self.assertFalse(self.forbidden_view.called)

    def test_test_func_args(self):
        """authenticated_user_passes_test passes user instance to test func."""
        self.run_decorated_view(is_authenticated=True)
        # Check: test_func was called with one argument: user instance.
        self.test_func.assert_called_once_with(self.request.user)

    def test_forbidden(self):
        """authenticated_user_passes_test runs forbidden view if user fails."""
        response = self.run_decorated_view(is_authenticated=True,
                                           user_passes_test=False)
        # Check: forbidden view was called with request as unique positional
        # argument.
        self.forbidden_view.assert_called_once_with(self.request)
        self.assertEqual(response, self.forbidden_view.return_value)
        # Of course, authorized and unauthorized views were not triggered.
        self.assertFalse(self.authorized_view.called)
        self.assertFalse(self.unauthorized_view.called)

    def test_authorized(self):
        """authenticated_user_passes_test runs view if user passes test."""
        response = self.run_decorated_view(is_authenticated=True,
                                           user_passes_test=True)
        # Check: decorated view has been called, request and other arguments
        # were proxied as is, response was not altered.
        self.authorized_view.assert_called_once_with(self.request,
                                                     *self.request_args,
                                                     **self.request_kwargs)
        self.assertEqual(response, self.authorized_view.return_value)
        # Of course, forbidden and unauthorized views were not triggered.
        self.assertFalse(self.forbidden_view.called)
        self.assertFalse(self.unauthorized_view.called)

Would you trust the authenticated_user_passes_test decorator?

[Biologeek] TEDx Montpellier 2013

$
0
0

L'édition 2013 de TEDx Montpellier portait sur le sujet « e-médecine & prospectives humaines ». Quelques prises de notes et questions sur cette journée.

C'est pas moi, c'est mes gènes ! — Sophie Nahum

Quels choix serions-nous prêts à faire avec l'avancée de la médecine (génomique, robotique, clonage, etc) ? Comment vieillir en bonne santé ? Comment anticiper la maladie ?

Dommage que la réflexion n'ait pas été poussée un peu plus loin sur le « pourquoi vivre longtemps ? » ou sur les questions d'éthique relatives à ces nouvelles pratiques de la médecine.

Interniste 2.0 — Laurent Chiche

Comment utiliser la e-médecine pour améliorer le quotidien des personnes affectées par les maladies rares ? Comment communiquer ses informations médicales en cas d'urgence ?

C'est un sujet qui me tient à cœur car j'ai commencé à rédiger une telle page web suite à la visite médicale d'aptitude à l'embauche pour scopyleft afin d'avoir un suivi numérique de mes vaccins, puis de centraliser des informations et finalement d'en faire une page à consulter en cas d'urgence dont j'ai collé l'URL sur ma carte d'identité que j'emporte lorsque je m'absente pour aller gambader. Je retiens de cette intervention le fait de traduire ces informations en plusieurs langues.

Je vois également dans ce carnet de notes du patient une dé-responsabilisation avouée des médecins qui ne remplissent pas la fiche transférée destinée à leurs confrères, ou peut-être est-ce une responsabilisation salutaire du patient sur son état de santé ?

L'ouverture se faisait sur du big data épidémiologique qui permettrait en agrégeant les données anonymisées des fiches de patients de servir la communauté. Quid des intérêts financiers des laboratoires dans le domaine ?

Communauté de patients — Michael Chekroun

Savoir profane vs. savoir professionnel ? Communauté de patients en ligne ? Intelligence collective accélérant la recherche médicale ?

Réflexion sur le côté anxiogène entre le fait de ne pas avoir d'informations et celui d'en avoir de fausses, associé aux dérives de l'auto-diagnostique et de l'auto-médication.

1/3 des requêtes sur Dr Google portent sur un problème de santé (et ça ne m'étonne même pas).

Développement d'une plateforme permettant au « patient de devenir acteur de sa santé » avec une horizontalité du rapport médecin/patient qui entrent en collaboration, voire en coopération.

Ouverture sur la notion de double peine du patient : souffrance dans la maladie et isolation sociale causée par la maladie.

Building a model Brain — Richard Walker

The Human Brain Project: if you want to understand a complex system, you should build it.

Aggregating biological signatures of deceases with many patients to identify a model and find an appropriated treatment.

Are you going to make an artificial brain ? Is it dangerous ? No.

For scientific reasons: the brain is changing and continuously adapting, the project doesn't model that process because we don't have the knowledge to achieve this.

Techniques chirurgicales : des origines, à la robotique — Bertin Nahum

Électrodes dans le cerveau reliées à des stimulateurs placés sous la peau pour éviter les tremblements et raideurs de la maladie de parkinson. Chirurgie réalisée sur patient éveillé pour trouver le réglage fin propre à la personne.

Dommage de ne pas avoir pu avoir une photo du robot en fonction développé par la personne effectuant la présentation ou une vidéo du placement des électrodes.

e-santé & bien vieillir — Philippe Guillet

Comment augmenter l'espérance de vie en santé ?

Augmentation de la fragilité des personnes âgées au cours des 30 dernières années (différence avec la courte d'espérance de vie), première cause de décès des personnes de plus de 70 ans devant le cancer.

Autour de la respiration — Jeanine Guey

Ode à la méditation pour être heureux.

Exercice de relaxation, que je pensais au début proche du T'ai chi ch'uan mais c'était juste l'introduction et ça se révèle être finalement beaucoup plus reposant. Plutôt sceptique initialement — surtout dans un groupe — je me suis prêté au jeu et j'ai vraiment senti qu'il y avait quelque chose à creuser dans ce moment, ne serait-ce que par son silence. Dommage que la sortie de méditation ait été aussi brutale avec le mouvement de groupe vers le repas.

5 in 5 — Christel Beltran

5 sens dans 5 ans.

Prospectives peu réjouissantes à mon goût. Le support semblait intéressant mais illisible.

De la plainte de la mémoire à la maladie d'alzheimer — Pr Jacques Touchon

Comment gérer l'autonomie des patients atteints afin qu'ils puissent rester chez eux ? Défi : maintient à domicile.

Vers une télé-médecine avec des tablettes et des données en temps-réel des patients pour qu'ils suivent leurs indicateurs de santé. J'imagine une sorte de dashboard pour son corps. Pourrait être associé à des outils pour lutter contre le handicap (ex : exo-squelette) ou de prévention via des systèmes de sécurité.

Un cerveau qui n'est pas stimulé est un cerveau qui meurt. La routine est une tueuse de neurones.

Utilisation des serious games pour y pallier et lutter contre l'appauvrissement du cerveau.

Cas de l'isolement qui est une problématique majeure (misère sociale, dépression, risque suicidaire) qui pourrait être solutionnée par une mise en contact du sujet âgé avec les proches grâce aux robots. Cela me semble être très éloigné d'un lien social…

Ouverture sur la finalité : la dignité des patients.

Des capteurs au service du patient ? — Daniel Laune

Comprendre les mécanismes des pathologies pour avoir une médecine personnalisée.

Utilisation de SmartPill par ingestion permettant d'avoir une transmission de données gastriques en temps-réel.

Développement du premier pancréas artificiel autonome qui ouvre la voie de l'appification de l'organisme (la gestion se fait via son smartphone).

La mesure de soi prend une tournure esthétique avec les tatouages électroniques permettant de surveiller le corps.

Designing hands — Ted Varley

Designing a prosthetic is very unusual because you can't use it yourself.

When you fall, your reaction can't anticipate to move your hand fast enough and most of prosthetics break (lack of feedback from sensors too). Possibility to replace fingers and use of very strong materials.

I wonder why they designed the hand to be black, it feels very unnatural to me (probably related to marketing with the brand name: bebionic).

Comment contrôler le cerveau ? — Xavier Vasques

What are your available data to predict the clinical evolution vs. how can I improve the quality of life of the patient?

Back to the deep brain stimulation technique with the idea to put (restore?) electricity in the brain to resolve problems.

Lève-toi et marche ! — Jean-Michel Fournier

Point de vue d'un proche de patient qui a eu une dystonie traitée par les stimulations électriques précédemment exposées. Enfin l'avis des personnes concernées ! Retour lucide et clair qui ne tombe pas dans l'affectif. Évoque l'inquiétude des patients traités (crainte de la panne) et de ceux qui se demandent s'ils pourront être traités aussi miraculeusement.

Fonde de grands espoirs dans la conjonction de la médecine et de la technologie.

At the boundaries of the self — Andréa Sérino

How the brain generate your self and represents the space where our body interacts with the environment?

The Peri Personal Space is plastic, it extends to incorporate the tool in use with the hand. That what happens with prosthetics. The system changes depending what we do, where the action takes place. Empathy leads to an extension of the space (works with politic faces too!).

Social networks: how our brain adapts to these solutions?

Nous ne sommes pas faits pour mourir — Pr. Christophe De Jaeger

La mort est-elle une fatalité ?

C'est la seule chose certaine lorsque l'on nait : nous allons mourir. Quels changements culturels — et même de civilisation — seraient engendrés par la découverte de l'immortalité ? On peut déjà réaliser cela à l'échelle de cellules.

We're all amateurs… we don't live long enough to become anything else. — Sir Charles Spencer "Charlie" Chaplin

50 ans est un âge clé : on sait ce que l'on n'est plus (vitalité des enfants) mais on sait ce que l'on n'a pas envie de devenir (vieillesse des parents).

Il ne tient qu'à nous d'avoir une bonne gestion de notre capital santé pour vieillir en conservant notre autonomie. C'est un système combinant gènes, capital santé et environnement. L'âge physiologique est différent de l'âge chronologique, il faut avoir envie de vieillir différemment en apportant une compensation physiologique.

Dans une logique d'espèce, nous devrions nous améliorer par sélection naturelle. Mais la religion et l'amour du prochain est venue contrecarrer ceci. Vouloir intervenir sur la mort remet d'une certaine façon en cause notre destinée.

Ouverture sur la réflexion des cycles de vie : du traditionnel formation/travail/retraite à des cycles formation/travail/pause répétés.

Un peu frustré d'avoir eu seulement des indications relatives à notre action sur le capital santé sans mentionner la possibilité de choisir/modifier son environnement également (en comparaison avec les gènes qui son innés).

Bilan personnel

Les intervenants et les thématiques abordées étaient intéressants mais je reste sur un sentiment mitigé avec la sensation que les sujets ont été traités de manière très superficielle, je reste clairement sur ma faim en terme de contenu que ce soit au niveau de la technique ou du partage d'expérience.

La partie éthique des interventions est passée complètement à la trappe ce qui est surprenant compte-tenu de la problématique et des enjeux sous-jacents.

Toute la journée, le concept de smart (cities, sensor, pill, phone, hospital, etc) a été abordé sans pour autant se poser la question de savoir pourquoi on avait besoin de s'entourer d'autant de choses intelligentes. Sommes-nous devenus stupides ? Est-ce cet environnement d'assistance qui nous a rendu stupides ? Quelle est la part d'éducation à introduire pour y pallier ?

Le second fil rouge de la journée était clairement la peur de la mort avec diverses tentatives de repousser les limites de la vie en santé pour finir en apothéose avec une apologie de la sportivation de la vie. Cela soulève forcément la question de l'utilité de vivre aussi longtemps…

[Biologeek] Agrégation et découverte

$
0
0

Suite à l'arrêt du service Reader de Google que j'utilisais par l'intermédiaire de Reeder, je me suis demandé quelle alternative me permettrait de remplacer cet outil. Je me suis naturellement intéressé à FeedHQ développé par Bruno car il utilise des technologies que j'utilise au quotidien et qu'il me permet de l'installer chez moi si je le souhaite.

J'ai ensuite remis en question le fait d'avoir un agrégateur, finalement ce qui m'intéresse dans cette fonction ce n'est pas l'agrégation à proprement parler, c'est plutôt le fait de découvrir des contenus récurrents. Et en grattant encore un peu plus, c'est aussi un des usages que j'ai de Twitter : découvrir des contenus.

Or il se trouve que j'ai développé un outil permettant de naviguer des contenus et soudain tout s'est éclairé : il suffit d'ajouter une fonctionnalité de découvrabilité à partir de sources connues (OPML) et moins connues (Twitter) pour combiner de la navigation à base de confiance mais également de sérenpidité sociale. En bonus, ces contenus se trouveront être indexés et sauvegardés localement.

Avant de changer d'outil, toujours se rappeler l'usage personnel que l'on fait de cet outil.

[Inspyration] Python.org : Visualisez le nouveau site

$
0
0
Python.org fait peau neuve, le nouveau site est en prévisualisation pour test, avant le PyCON.

[Biologeek] Nostalgie d'expatrié

$
0
0

Je me surprends :

  • à m'incliner pour remercier quelqu'un ;
  • à marcher sur la gauche des trottoirs ;
  • à parler avec des interjections ;
  • à déambuler sans précipitation ;
  • à prendre soin des cartes de visite ;
  • à communiquer avec bienveillance ;
  • à m'étonner qu'on puisse vivre dans la saleté ;
  • à avoir envie d'un bain chaud ;
  • à photographier les premières fleurs du printemps ;
  • à sourire aux personnes que je croise ;
  • à trouver que la ville manque de petites musiques ;
  • à regretter qu'il n'y ait pas plus d'arbres dans nos villes ;
  • à m'émerveiller de petits détails de la vie.

Je me surprends à transporter un bout de Japon avec moi. En moi. Et ça me plaît.

[novapost] Django : Comment booster ses tests en 1 minute

$
0
0

Introduction

Hier, Boris, en stage ici pour 6 mois, me parle d'une astuce pour Django ultra simple, mais qui a tout bonnement divisé par deux notre temps de tests :O

Connexion, views et tests

Lors des tests, on doit souvent se connecter pour tester les droits de l'utilisateur ou encore accéder à des certaines pages de l'application Django décorée par un user_passes_test ou un login_required.

Si vous n'utilisez pas encore les techniques de tests unitaires des views proposée la semaine dernière par Benoît Bryon, cette solution simple va déjà vous faire gagner un temps fou.

À un problème, une solution

Grâce à l'article de Igor Sobreira [1], on s'est rendu compte que le temps passé dans le hachage des mots de passe était significatif sur la durée totale des tests.

Nous avons donc essayé la solution proposée par l'article (utiliser un UnsaltedMD5PasswordHasher pour les tests) et avons effectivement constaté une amélioration du temps total des tests.

En regardant le code de UnsaltedMD5PasswordHasher on s'est dit qu'on pouvait gagner encore plus de temps à la fois sur le hachage du mot de passe et sur la vérification de celui-ci.

En effet, tous les hasher Django utilisent une méthode de comparaison des mots de passe en temps constant afin d'éviter les problèmes de timing attaques [2].

Et en pratique ?

Il suffit de définir un PASSWORD_HASHER simplifié pour les tests pour gagner un temps fou lors de l'exécution des tests.

C'est aussi simple que ça.

La première étape consiste à définir un PASSWORD_HASHER minimaliste

# -*- coding: utf-8 -*-
from django.contrib.auth.hashers import BasePasswordHasher, mask_hash
from django.utils.datastructures import SortedDict


class PlainPasswordHasher(BasePasswordHasher):
    """
    The plain password hashing algorithm for test (DO NOT USE in production)
    """
    algorithm = "plain"

    def salt(self):
        return ''

    def encode(self, password, salt):
        return '%s$$%s' % (self.algorithm, password)

    def verify(self, password, encoded):
        algorithm, hash = encoded.split('$$', 1)
        assert algorithm == self.algorithm
        return password == hash

    def safe_summary(self, encoded):
        return SortedDict([
            ('algorithm', self.algorithm),
            ('hash', mask_hash(encoded, show=3)),
        ])

Ensuite dans le fichier de settings propre aux tests, on modifie la liste des PASSWORD_HASHERS.

settings_test.py

from myapp.settings import *
PASSWORD_HASHERS = (
    'myapp.hashers.PlainPasswordHasher',
),

Attention à ne pas utiliser cela en production, car tous les mots de passes seraient stockés en clair dans la base de données.

Je vous invite à tester cette astuce sur votre base de tests pour voir vous-même la différence de temps et nous faire un retour en commentaire du post.

Si vous utilisez des fixtures de user, vous pouvez également utiliser la solution ci-dessous dans votre settings de test afin que les tests puissent décoder les mots de passe déjà stockés dans la base avec un autre algorithme de mot de passe.

settings_test.py

from myapp.settings import *
PASSWORD_HASHERS = ['myapp.hashers.PlainPasswordHasher'] + list(PASSWORD_HASHERS)

Conclusion

Cette astuce commence à être connue dans le monde Django, il y a même un ticket de Django qui en parle [3] et elle est maintenant décrite dans la documentation officielle de Django [4].

Notre hasher personnalisé permet juste de gagner encore un peu plus de temps. Sur notre base de tests nous avons gagné 10 minutes sur 50 minutes soit 20% de temps de tests en passant du UnsaltedMD5PasswordHasher à notre PlainTextPasswordHasher

Nous avions initialement divisé par deux notre temps de tests en passant à UnsaltedMD5PasswordHasher

[afpyro] AFPyro à Lyon - le 27 mars 2013

$
0
0

Le premier Afpyro du printemps aura lieu le mercredi 27 mars à partir de 20h à l’Antre Autre - 11 rue Terme - 69001 Lyon.

Simon Sapin nous fera une présentation sur Sphinx. Sphinx est un outil qui permet de créer de la documentation pour vos projets ou vos produits.

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] Mémoire nationale numérique

$
0
0

C’est ni plus ni moins que notre mémoire nationale numérique qui fuite (car un datacenter est un lieu de mémoire hyper-industriel).

Parce que nous ne disposons pas d’une infrastructure de stockage et de traitement des données qui fait tourner les industries culturelles et relationnelles du numérique, notre pays est contraint de subir une politique qui n’est pas la nôtre, que nous n’avons pas choisi et à laquelle pourtant nous nous soumettons. Il y a aliénation digitale dans la mesure où les données françaises ne sont pas stockées là ou elles sont produites, et l’on peut généraliser la situation : là ou nous investissons dans le numérique les autres en tirent les bénéfices.

Quelle politique de reterritorialisation des data faut-il mener, et comment stopper la vampirisation internationale des données ?

Christian Fauré, L’hypercriticité numérique de la France

Une seule réponse possible : rendre le réseau symétrique.

Il n'y a qu'une politique d'échanges de données en pairs à pairs performante qui permettra de revenir à une certaine indépendance vu le retard que l'on accuse dans le domaine. Cela requiert la possibilité d'envoyer autant — si ce n'est plus — de données que ce que l'on en reçoit. Il faudrait avoir une vision sur le long terme pour prendre de telles décisions, ce qui se révèle être de fait bien éloigné des actions politiques actuelles.

Cela me rappelle l'expression « la fuite des cerveaux » relative aux chercheurs migrant vers les US au terme de leur formation. Chaque lien qui est stocké sur un serveur américain est une synapse offerte.

[Biologeek] Accompagnement EMI

$
0
0

Accompagner, c'est célébrer, c'est manifester l'incroyable splendeur qu'est chacun(e).

Marie Milis

J'intervenais cette semaine à l'EMI CFD comme précédemment mentionné. L'occasion de rencontrer une promotion orientée graphisme et rédaction bien éloignée de la sphère des développeurs.

L'objet était de produire une petite application en une semaine qui utilise des données sur la thématique du Festival de Cannes, ce qui s'est avéré être un challenge intéressant autant du point de vue de l'accompagnement en lui-même que de celui du sociologue qui sommeille en moi.

Il y a eu 2 problèmes transverses aux équipes accompagnées sur lesquels je voudrais revenir :

  • le manque de démarche expérimentale : lorsque l'on commence à « s'imbiber de données » (sic), il est important de formuler des hypothèses qui doivent être vérifiée par les données et non énoncer des points de vues que l'on cherche absolument à prouver avec des données. Il ne faut pas avoir peur de produire des esquisses de données — à travers des graphes tout simples — avant de penser en termes d'infographies. Pressés par le temps, nous n'avons pas pu développer la discussion sur la rigueur scientifique des journalistes mais cela aurait pu être intéressant, il est trop tentant de vouloir raconter une histoire pour sa simple audience.
  • le manque de coopération : il y avait 3 équipes qui sont restées dans leur bulle tout le long de la semaine, quel dommage ! Chaque équipe — même dans le cadre d'une coopétition — aurait gagnée à mutualiser des données ou à se challenger sur les résultats obtenus. Cela aurait encouragé également une démarche itérative pour que ces échanges soient rendus possibles. Note : on nous a récemment qualifiés d'« intégristes de la coopération » avec scopyleft et j'assume pleinement ce rôle.

En recherche d'efficacité optimale, j'ai introduit la méthode MoSCoW la dernière journée en improvisant un ersatz de backlog priorisé. Le résultat s'est révélé être au-delà de mes espérances en terme de fluidité des cartes au sein de l'équipe pour effectuer les dernières tâches rapidement.

Il était assez frustrant de ne pas avoir le temps d'expliquer la vision que j'ai de mon métier et de transmettre une façon de travailler permettant de garder un rythme soutenable et procurant du plaisir. Frustration également (salutaire cette fois) de se retenir de trop encadrer, certaines expériences devant se faire par soi-même. Cela étant dit, mon seul vrai regret sur la semaine aura été de ne pas avoir pu rester à la fin lors de la rétro accompagnateurs et du pot qui aurait pu permettre de parler d'autre chose que de données :-).

Quelques idées pour améliorer la formation :

  • donner quelques rudiments méthodologiques pour faire fonctionner les groupes, au moins en leur expliquant les différents axes possibles d'organisation (centralisé, démocratique, sociocratique, etc), la méthode à la RACHE ayant montré ses limites ;
  • lisser la pression, elle ne devrait pas être croissante comme j'ai pu l'observer quel que soit le groupe, l'approche itérative permet d'y arriver efficacement ;
  • donner davantage de temps pour affiner la vision initiale en leur proposant le thème plus tôt, beaucoup de temps a été perdu par simple manque de réflexion en amont.

L'éducation authentique ne se fait pas de A vers B, ni de A sur B, mais par A avec B, par l'intermédiaire du monde.

Paulo Freire

J'ai au moins autant appris que les « étudiants » cette semaine en ayant eu la possibilité d'observer des groupes de travail à l'ouvrage et en constatant une fois de plus la difficulté à travailler ensemble même en poursuivant un but commun. La concrétisation d'un projet ne doit jamais se faire au détriment de la communication dans l'équipe. Auquel cas on perd non seulement le projet, mais également l'équipe…

Pour finir, je voudrais remercier Yohan qui m'a permis de participer à cette formation (et de dormir sur son bateau pendant une semaine !).

Viewing all 3409 articles
Browse latest View live