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

[hautefeuille] Kivy et sources vidéo sur écrans multiples en OpenGL

$
0
0

Les logiciels qui permettent d’intégrer des flux vidéo de différentes caméras nécessitent souvent une licence.

Aussi je vous propose en guise d’exercice, un prototype d’application capable de visonner 2 flux différents répartis sur des écrans différents.

Un bouton autorise une capture d’image de chaque écran.

Le kit de développement de l’interface graphique se nomme Kivy et propose un affichage OpenGL des informations à traiter. Sa prise en main est rapide et la documentation est abondante.

Kivy.org - http://www.kivy.org

Code de l’application

# -*- coding: utf-8 -*-

"""
@author: julien@hautefeuille.eu

# sudo apt-get install python-kivy

"""
import kivy
kivy.require('1.5.1')

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.camera import Camera
from kivy.uix.video import Video
from kivy.uix.button import Button
from kivy.core.window import Window
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.stacklayout import StackLayout
from kivy.uix.label import Label
from kivy.uix.popup import Popup
from kivy.logger import Logger
from kivy.uix.screenmanager import ScreenManager, Screen

class CamControl(App):

    icon = 'icon.png'
    title = "Cam Control"

    # Callbacks

    def doscreenshot(self,*largs):
        Window.screenshot(name='screenshot%(counter)04d.jpg')
        self.popup.open()

    def next(self,*largs):
        self.sm.current = 'cam2'

    def back(self,*largs):
        self.sm.current = 'cam1'

    def on_start(self):
        Logger.info('Application starts !')

    def on_stop(self):
        Logger.critical('Application quits !')

    # Build UI

    def build(self):

        self.sm = ScreenManager()
        screen1 = Screen(name='cam1')
        screen2 = Screen(name='cam2')

        self.sm.add_widget(screen1)
        self.sm.add_widget(screen2)

        # Create vertical layout
        layout1 = BoxLayout(orientation='vertical', padding=10, spacing=10)
        layout2 = BoxLayout(orientation='vertical', padding=10, spacing=10)

        supralayout1 = BoxLayout(size_hint=(1, .2))
        supralayout2 = BoxLayout(size_hint=(1, .2))

        intralayout1 = BoxLayout(size_hint=(1, .5))
        intralayout2 = BoxLayout(size_hint=(1, .5))

        title_cam1 = Label(text="Cam 1 : Trendnet")
        title_cam2 = Label(text="Cam 2 : Microsoft HD")

        vid = Video(
            source='rtsp://192.168.12.153/mpeg4',
            play=True,
            resolution=(640,480),
            size=(640,480))

        cam=Camera(
             play=True,
             resolution=(640,400),
             size=(640,400))


        content = Label(text='Screenshoot done to current dir !')
        self.popup = Popup(
            content=content,
            auto_dismiss=True,
            title="Info",
            size_hint=(None, None),
            size=(400, 150)
            )
        content.bind(on_press=self.popup.dismiss)

        # Commands
        button1=Button(text="Screenshoot",size_hint=(0.30,0.30))
        button1.bind(on_press=self.doscreenshot)

        button2=Button(text="Screenshoot",size_hint=(0.30,0.30))
        button2.bind(on_press=self.doscreenshot)

        button3=Button(text='Next',size_hint=(0.30,0.30))
        button3.bind(on_press=self.next)

        button4=Button(text='Back',size_hint=(0.30,0.30))
        button4.bind(on_press=self.back)

        # Order is important in vlayout
        layout1.add_widget(supralayout1)
        layout1.add_widget(vid)
        layout1.add_widget(intralayout1)
        supralayout1.add_widget(title_cam1)
        supralayout2.add_widget(title_cam2)
        intralayout1.add_widget(button1)
        intralayout1.add_widget(button3)

        layout2.add_widget(supralayout2)
        layout2.add_widget(cam)
        layout2.add_widget(intralayout2)
        intralayout2.add_widget(button2)
        intralayout2.add_widget(button4)

        screen1.add_widget(layout1)
        screen2.add_widget(layout2)

        return self.sm

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


[noirbizarre] Huit recettes pour Pelican

$
0
0

Après avoir passé beaucoup de temps sur mon blog depuis le passage à Pelican, j’ai décidé de publier quelques recettes que j’utilise.

Libre à vous de les utiliser et de les améliorer. Je suis évidement intéréssé par votre retour.

Arborescence plate

Cette recette n’en est pas vraiment une, mais elle servira de base pour les chemins des autres recettes.

Je l’utilise pour avoir l’arborescence suivante dans mon dépôt git:

├── articles
│   ├── categorie1
│   │   └─ article.rst
│   └── categorie2
├── extras
│   ├─ 404.html
│   └─ robots.txt
├── images
│   ├── theme1
│   │   └─ image.png
│   ├── theme2
│   │   └─ image.png
│   └─ image.png
├── local_plugins
│   └─ plugin.py
├── pages
│   └─ page.rst
├── theme
│   ├── static
│   │   ├── css
│   │   └── images
│   └── templates
│       ├─ template1.html
│       └─ template2.html
├─ .gitignore
├─ Makefile
├─ nginx.conf
├─ pelicanconf.py
├─ publish.sh
├─ publishconf.py
└─ requirements.pip

Pour cela j’ai modifié mon fichier pelicanconf.py comme suit:

PATH = dirname(__file__)
OUTPUT_PATH = join(PATH, 'output')
ARTICLE_DIR = 'articles'
THEME = 'theme'
STATIC_PATHS = ("images", )
FILES_TO_COPY = (
    ('extras/robots.txt', 'robots.txt'),
)
PLUGINS = (
    'pelican.plugins.gzip_cache',
    'pelican.plugins.sitemap',
    'local_plugins.plugin'
)

Délégation d’authentification OpenID

Mon blog Wordpress me servait aussi à m’authentifier grâce à OpenID. Cette modification a donc été la première que j’ai réalisée. Je l’ai réalisée avec MyOpenId comme fournisseur puisque c’est celui que j’utilise, libre à vous de l’adapter à votre fournisseur.

  1. Créez un template theme/templates/myopenid.html:

    {% if MYOPENID_USERNAME %}
    <link rel="openid.server" href="http://www.myopenid.com/server" />
    <link rel="openid.delegate" href="http://{{MYOPENID_USERNAME}}.myopenid.com/" />
    <link rel="openid2.local_id" href="http://{{MYOPENID_USERNAME}}.myopenid.com" />
    <link rel="openid2.provider" href="http://www.myopenid.com/server" />
    <meta http-equiv="X-XRDS-Location" content="http://www.myopenid.com/xrds?username={{MYOPENID_USERNAME}}.myopenid.com" />
    {% endif %}
    
  2. Dans le bloc <head> du template theme/templates/base.html ajoutez:

    {% include 'myopenid.html' %}
    
  3. Dans le fichier de configuration de publication publishconf.py, ajoutez:

    MYOPENID_USERNAME = 'me'
    

Boutons Google +1, Twitter et Flattr

Cette modification de thème permet d’insérer des boutons de partage chargés de façon asynchrone.

Ces boutons ne seront visibles qu’en mode publié puisqu’ils requierent que SITEURL soit définie.

  1. Créez les templates des boutons

    • theme/templates/plusone.html:

      {% if PLUS_ONE and share_url %}
      <span class="g-plusone" data-href="{{ share_url }}" data-size="medium"></span>
      {% endif %}
      
    • theme/templates/twitter.html:

      {% if TWITTER_USERNAME and share_url and share_title %}
      <a href="http://twitter.com/share" class="twitter-share-button" data-count="horizontal" data-via="{{TWITTER_USERNAME}}" data-related="{{TWITTER_USERNAME}}" data-url="{{share_url}}" data-text="{{share_title|striptags}}">Tweet</a>
      {% endif %}
      
    • theme/templates/flattr.html:

      {% if FLATTR_USERNAME and share_url and share_title %}
      <a class="FlattrButton" style="display:none;"
          title="{{share_title}}" href="{{share_url}}"
          data-flattr-uid="{{FLATTR_USERNAME}}"
          {% if article and article.tags %}data-flattr-tags="{{article.tags|join(',')}}"{% endif %}
          {% if FLATTR_LANG  %}data-flattr-language="{{FLATTR_LANG}}"{% endif %}
          data-flattr-button="compact"
          data-flattr-category="text">
          {{share_title}}
      </a>
      {% endif %}
      
  2. Créez les templates des scripts de chargement asynchrone:

    • theme/templates/plusone_script.html:

      {% if PLUS_ONE and SITEURL %}
      <script type="text/javascript">
        window.___gcfg = {lang: '{{PLUS_ONE_LANG}}'};
        (function() {
          var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true;
          po.src = 'https://apis.google.com/js/plusone.js';
          var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s);
        })();
      </script>
      {% endif %}
      
    • theme/templates/twitter_script.html:

      {% if TWITTER_USERNAME and SITEURL %}
      <script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="https://platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script>
      {% endif %}
      
    • theme/templates/flattr_script.html:

      {% if FLATTR_USERNAME and SITEURL %}
      <script type="text/javascript">
      (function() {
          var s = document.createElement('script');
          var t = document.getElementsByTagName('script')[0];
          s.type = 'text/javascript';
          s.async = true;
          s.src = '//api.flattr.com/js/0.6/load.js?mode=auto';
          t.parentNode.insertBefore(s, t);
      })();
      </script>
      {% endif %}
      
  3. A chaque emplacement où vous désirez voir apparaitre ces boutons, insérez le bloc suivant:

    {% if SITEURL %}
        {%- set share_url = [SITEURL, article.url]|join('/') -%}
        {%- set share_title = article.title -%}
        {% include 'twitter.html' %}
        {% include 'plusone.html' %}
        {% include 'flattr.html' %}
    {% endif %}
    

    Modifiez biensur les variable share_url et share_title en fonction du contexte.

  4. Modifiez votre template theme/templates/base.html pour y insérer à la fin du bloc <body>:

    {% if SITEURL %}
        {% include 'twitter_script.html' %}
        {% include 'plusone_script.html' %}
        {% include 'flattr_script.html' %}
    {% endif %}
    
  5. Renseignez vos identifiant et paramètres dans votre configuration de publication pelicanconf.py:

    TWITTER_USERNAME = 'me'
    
    FLATTR_USERNAME = "me"
    FLATTR_LANG = "fr_FR"
    
    PLUS_ONE = True
    PLUS_ONE_LANG = 'fr'
    

Pour adapter les paramètres à vos besoins, consultez les documentations officielles:

Filtre “urlencode” pour Jinja

Jinja 2 ne propose plus de filtre urlencode par défaut (Issue #17 et Pull Request #62).

Si pour une raison ou une autre vous en avez besoin, vous pouvez le rajouter vous même dans votre fichier pelicanconf.py:

import urllib
from jinja2.utils import Markup

def urlencode_filter(s):
    if type(s) == 'Markup':
        s = s.unescape()
    s = s.encode('utf8')
    s = urllib.quote_plus(s)
    return Markup(s)

JINJA_FILTERS = {
    'urlencode': urlencode_filter,
}

Marquer la page active dans le menu

Si vous desirez marquer la page active dans le menu, vous pouvez vous appuyer sur l’astuce Highlighting Active Menu Items.

Voici ma recette adaptée à Pelican:

  1. Modifier votre template theme/templates/base.html pour y ajouter le menu et y déclarer la variable du context active_page:

    {%- set active_page = active_page|default(None) -%}
    <nav id="menu">
        <ul>
            <li {% if active_page == 'index' %}class="active"{% endif %}>
                <a href="{{ SITEURL }}/">Accueil</a>
            </li>
            <li {% if active_page == 'category' %}class="active"{% endif %}><a href="{{ SITEURL }}/categories">Catégories</a>
                <ul>
                    {% for cat, null in categories %}
                    <li><a href="{{ SITEURL }}/{{ cat.url }}">{{ cat }}</a></li>
                    {% endfor %}
                </ul>
            </li>
            {% if DISPLAY_PAGES_ON_MENU %}
            {% for pag in PAGES %}
                <li {% if page == pag %}class="active"{% endif %}>
                    <a href="{{ SITEURL }}/{{ pag.url }}">{{ pag.title }}</a>
                </li>
            {% endfor %}
            {% endif %}
        </ul>
    </nav>
    
  2. Modifiez les pages qui doivent déclarer un nom de page, dans mon cas:

    • theme/templates/index.html:

      {% extends "base.html" %}
      {% set active_page = 'index' -%}
      
    • theme/templates/categories.html:

      {% extends "base.html" %}
      {% set active_page = "category" %}
      
    • theme/templates/category.html:

      {% extends "base.html" %}
      {% set active_page = 'category' -%}
      

    Adaptez-le suivant votre hierarchie de templates et de menu.

Balises META

Cette recette permet déclarer les balises <meta> dans le fichier de configuration.

  1. Déclarez un dictionnaire META dans votre fichier pelicanconf.py:

    from pelican import __version__ as PELICAN_VERSION
    METAS = {
        'author': u'Me',
        'description': u"My blog description",
        'keywords': u'some, keywords, for, seo',
        'generator': u'Pelican %s' % PELICAN_VERSION,
    }
    
  2. Ajoutez dans le bloc <head> du template theme/templates/base.html:

    {% for name, content in METAS.iteritems() %}
    <meta name="{{name}}" content="{{content}}" />
    {% endfor %}
    

Page d’erreur 404

Cette recette fourni une page d’erreur 404 personnalisée avec le thème de votre blog. Elle fonctionne avec NGinx mais est adaptable à tout autre serveur.

  1. Créez le template de votre page d’erreur 404, dans mon cas extras/404.html:

    {% extends "base.html" %}
    {% block content_title %}Erreur 404{% endblock %}
    {% block content %}
    <section class="body page">
        <h1 class="page-title">Erreur 404</h1>
        La page que vous cherchez n'existe pas.
    </section>
    {% endblock content %}
    
  2. Déclarez cette page dans votre configuration pelicanconf.py:

    TEMPLATE_PAGES = {'extras/404.html': '404.html'}
    
  3. Indiquez à NGinx où trouver cette page:

    server {
        # ...
        error_page 404 /404.html;
        # ...
    }
    

Publication par git post-receive hook

Cette recette me permet de déployer mon blog dès que je push sur mon serveur.

A la fin de chaque déploiement, je ping les moteurs de recherche pour les notifier des modification du fichier sitemap.xml généré par le plugin Sitemap.

La configuration de NGinx et les dépendances Python sont elles aussi stoquées dans mon dépôt git, respectivement dans les fichiers nginx.conf et requirements.pip. Dans mon cas, j’utilise virtualenv mais vous pouvez l’adapter à votre configuration.

  1. Sur votre serveur, modifiez ou créez le fichier blog.git/hooks/post-receive:

    #!/bin/sh
    
    STAGING="/home/me/staging/blog"
    
    GIT_WORK_TREE=$STAGING git checkout -f
    cd $STAGING
    ./publish.sh
    

    Ce fichier doit être exécutable.

  2. Dans votre dépôt git, ajoutez le fichier publish.sh à la racine:

    #!/bin/sh
    
    VENV="venv"
    PUBLIC="/path/to/your/public/blog"
    SITEMAP=http://your.blog/sitemap.xml.gz
    
    # Setup virtualenv
    if [ ! -d "$VENV" ]; then
        virtualenv --distribute $VENV
    fi
    . $VENV/bin/activate
    pip install -r requirements.pip --use-mirrors
    
    # Deploy blog
    pelican -v -o $PUBLIC -s publishconf.py
    cp -f nginx.conf /etc/nginx/sites-available/your.blog
    sudo service nginx reload
    
    # Ping sitemap
    GOOGLE=http://www.google.com/webmasters/tools/ping?sitemap=$SITEMAP
    BING=http://www.bing.com/webmaster/ping.aspx?siteMap=$SITEMAP
    
    for url in $GOOGLE $BING; do
        curl -s -w "%{http_code} %{url_effective}\\n" "$url" -o /dev/null
    done
    

    Pour ne pas perdre de temps à chaque push, je commente la ligne qui installe les dépendances python et je la décommente uniquement lorsque je les modifie.

  3. Donnez les droits pour recharger NGinx via sudo à votre utilisateur:

    # Reload nginx command
    Cmnd_Alias NGINX_RELOAD = /usr/sbin/service nginx reload
    
    # User privilege specification
    me  ALL=NGINX_RELOAD, NOPASSWD: NGINX_RELOAD
    

[Biologeek] Éduquer à la joie

$
0
0

Ce livre est un appel aux parents, aux enseignants, aux maîtres et maîtresses d'école, aux adultes qui ne savent plus rêver, pour qu'ils mettent de côté, le temps de cette lecture, la masse des connaissances intellectuelles, de savoirs et de théories éducatives qu'ils ont appris sur leurs enfants, ce qu'ils croient « être bon » pour eux et pour leur développement. C'est une proposition impertinente de ne pas « faire les devoirs » que l'éducation nous a imposés tout au long de notre vie (réussir, aller vite, être les premiers…), mais de se laisser plutôt embarquer par le vent du changement qui parcourt notre monde aujourd'hui, y compris celui de l'école. Pour en finir avec le mépris systémique de ce qui, avec la pensée, nous distingue des animaux — à savoir notre capacité de rêver —, nous nous devons de redonner à l'éducation son rôle d'éveil. Chacun de nous recèle un don, un talent inné qui, s'il est respecté et honoré, nous transformera en être humain heureux, en contact avec sa joie de vivre, en accord avec soi-même et les autres. L'éducation a le devoir de reconnaître ce trésor, de le révéler et d'aider tout individu à le développer : l'enjeu n'est rien d'autre que l'accomplissement d'un monde en paix.

Antonella Verdiani, Ces écoles qui rendent les enfants heureux

Je suis en train de pas mal me renseigner sur les pédagogies et méthodes d'éducation dites alternatives suite à mes recherches sur l'Anthroposophie et sur ce qui distingue une secte d'une approche non traditionnelle (Montessori, Steiner, Freinet, modèle scandinave, éducation démocratique, éducation lente, école à la maison, etc).

Le point commun de ces écoles est qu'elles sont animées par des valeurs et des notions communes avant tout intérêt financier :

  • Reliance
  • Ouverture au questionnement existentiel
  • Transdisciplinarité
  • Complexité
  • (In)novation
  • Autorisation
  • Incertitude
  • Planter là où c'est fertile

Aussi lorsque j'apprends l'ouverture d'une nouvelle école dédiée à l'excellence de la France en matière de numérique (avec tout un vocabulaire anglophone mais passons), je ne peux que me réjouir et chercher les valeurs associées à cette méthode d'éducation qui se veut atypique et innovante. Malheureusement, la recherche est vaine. Le seul fil rouge du site est financier :

  • comment vous rendre « rapidement opérationnel » pour l'entreprise ?
  • comment devenir un « informaticien aux compétences recherchées » ?
  • comment « coller à des réalités économiques » ?

J'ose espérer que mon métier ne se résume pas à une telle approche. Que mes futurs collaborateurs n'auront pas été formés comme des « commandos de Marines » pour sélectionner les meilleurs d'entre eux. Le rêve de ce regroupement d'entrepreneurs est finalement de créer une armée de mercenaires pour concrétiser leurs idées à bas prix. Et ce sans poser de questions car si ce n'est pas toi, ressource, ce sera ton voisin qui a reçu la même formation industrialisée basée sur la performance.

Né pour coder ? Non. Né pour prendre du plaisir à coder. Nuance.

[tarek] News from the Quality front

$
0
0

Flake8 plugins

Some time ago, we've unified our efforts to build & maintain code quality checkers. For instance, Flake8 is now entirely based on plugins: there's a pep8, pyflakes & mccabe plugin and you can add more.

The family of Flake8 plugin is growing & Florent has started listing them at http://flake8.readthedocs.org/en/latest/extensions.html#existing-extensions

Mailing list

Another good news is the creation of a mailing list dedicated to all the code quality tools : http://mail.python.org/mailman/listinfo/code-quality

If you're interested in those tools, or you are maintaing one yourself, consider joining this mailing list.

[QuiSaura] Python et les boucles imbriquées via itertools.product

[Biologeek] Fondée sur des valeurs

$
0
0

J'étais à Devoxx hier soir comme annoncé pour présenter une approche différente de la SSII et je devais décrire l'expérience scopyleft :

scopyleft est une SCOP (Société Coopérative et Participative) toute jeune — seulement 3 mois — ce qui ne permet pas d'avoir le recul nécessaire pour valider ou invalider une approche. Ni même pour juger de sa viabilité. C'est pourquoi j'ai choisi de vous parler de sa genèse : autrement dit, de l'avant scopyleft.

Notre approche a été de ne pas commencer par le traditionnel business plan mais de nous aligner entre nous 4 sur les valeurs fondatrices que nous voulions comme cap au cours de la vie de l'entreprise. Si l'approche économique nous donnait une vision pour environ 1 an avec son lot d'incertitudes et autres pivotages, passer par des valeurs nous amenait à considérer une durée beaucoup plus longue… de l'ordre de la décennie. Ambitieux projet.

Cela commence par mieux se connaître, discuter de valeurs permet d'aller beaucoup plus en profondeur qu'une discussion sur le retour sur investissement, les salaires ou le titre que l'on souhaite avoir dans l'entreprise. Une fois d'accord sur le fond — honnêteté intellectuelle, courage, bien-être, respect et partage —, nous sommes arrivés à formuler une phrase (à défaut d'un manifeste) résumant notre objectif commun :

Travailler entre humains, sur des projets éthiques et intéressants, tout en privilégiant le bien-être et le plaisir de chacun.

Ces valeurs et cette maxime nous guident dans nos choix stratégiques au quotidien pour accepter ou non un client, pour concrétiser une initiative ou pour accompagner un projet.

C'est notamment ce qui nous a menés à choisir le statut de SCOP, un statut basé sur une gouvernance démocratique (1 homme = 1 voix) et favorisant la pérennité des emplois et du projet d'entreprise (co-entrepreunariat et réserve importante imposés). Ce statut met l'humain au cœur de l'entreprise, ce qui diffère d'une entreprise traditionnelle qui se concentre sur son capital. C'est un changement de paradigme majeur dans une société capitaliste. Nous avons enrichi ces statuts d'une co-gérance tournante (faute de pouvoir gérer à 4) et d'une égalité salariale.

Un autre aspect de la SCOP qui a attisé notre curiosité est la notion de solidarité inter-entreprises au sein de la confédération des SCOP. C'est notamment ce que l'on a pu constater avec les entreprises qui nous ressemblent, il existe relativement peu de SCOP (dans l'informatique) mais elles se serrent les coudes !

Ces 3 derniers mois nous ont permis de reconsidérer notre approche économique, de mieux nous connaître, d'avoir énormément de retours (à la fois de nos clients et de nos pairs), de coder ensemble, d'accompagner ensemble, d'assister à des conférences ensemble, de stresser ensemble, de faire de l'administratif ensemble, autant de tâches qui sont loin d'être insurmontables et qui sont le lot quotidien du créateur d'entreprise mais qui s'avèrent être moins pénibles lorsque l'on poursuit un objectif un peu plus « élevé » (sain ?) que le simple aspect financier. Augmenté par le fait de le réaliser à plusieurs.

Cette aventure aurait difficilement pu être envisageable sans avoir confiance dans notre savoir-faire acquis lors de nos expériences respectives à nos comptes. Malgré notre expérience dans le domaine, l'un de nos objectifs à terme est de nous libérer de la prestation pour co-produire des produits utiles, éthiques et open-source.

Pour résumer, scopyleft est une entreprise fondée sur des valeurs pour créer de la valeur. En coopérant.

Je n'ai pas dû dire la moitié de tout ça au final car l'approche monologue était un peu ennuyante et je préférais avoir plus de temps pour discuter. Et là je n'ai pas été déçu car les réactions ont été nombreuses, un peu décousues et agressives mais cela montrait un intérêt certain.

Décousues car on était nombreux à pouvoir répondre (une dizaine) et qu'il y avait beaucoup de questions qui passaient brutalement du fond à la forme selon le niveau de réflexion de chacun. Peut-être qu'un autre format (groupes de discussions par exemple) se prêtait mieux à la discussion ouverte mais la salle n'était pas adaptée.

Agressives principalement car le titre NoSSII a été interprété comme un affrontement alors que l'on avait bien mis en avant le côté Not only. Dommage, l'idée n'était pas du tout d'aller dans ce sens mais il est peut-être normal que certains se sentent déstabilisés lorsqu'on présente quelque chose de différent.

Quelques questions dont je me souviens :

À quoi cela sert-il de créer une SCOP vs. un GIE (Groupement d'intérêt économique) d'indépendants ?

L'objectif n'est pas du tout le même, principalement car on ne se regroupe pas en SCOP pour un intérêt économique mais pour partager et échanger à un autre niveau.

Qu'est-ce qui vous différencie d'une SSII classique finalement ?

D'une part le fait d'avoir le contrôle sur les objectifs de la société, ils peuvent être lucratifs ou pas, ils peuvent être citoyens ou pas, ils peuvent être éthiques ou pas, ils peuvent s'émanciper de la prestation ou pas. D'autre part, le fait de mettre l'humain au cœur du cadre de travail est un changement radical, ce qui change aussi les relations avec les clients.

Comment gérez-vous les problèmes d'éthiques ?

Nous n'avons pas de règle pré-définie, chaque cas aux limites est discuté longuement et un vote suivant les pratiques de l'Open-Source (et de Django) permet de trancher.

Est-ce que ça peut fonctionner à plus grande échelle ?

L'exemple du handbook de Valve a été mis en avant avec quelques autres. La question c'est plutôt de savoir quel est l'intérêt de passer à une autre échelle ? Dans notre cas par exemple, c'est une volonté forte de rester à taille humaine.

Ça rejoint d'ailleurs une question relative au référencement dans les services achats des grosses entreprises. C'est peut-être plus difficile en étant petit mais en fait ça nous intéresse peu de travailler avec ce type de structures donc ça limite le problème. Beaucoup de questions n'allaient pas assez loin dans le pourquoi et se limitaient au comment.

Comment trouvez-vous des clients ?

On ne sait pas démarcher. Partant de ce constat, ça passe plutôt par de la recommandation ou des connaissances qui nous suivent depuis longtemps et le partage de nos expériences. On a également la chance d'avoir des entreprises partageant nos valeurs qui nous transmettent des demandes.

Les réactions à chaud sont plutôt positives, j'espère que l'on aura réussi avec Ninja Squad et Lateral Thoughts à au moins attiser la curiosité de certains et pourquoi pas à en motiver pour monter leur propre structure !

[logilab] PyLint 10th years anniversary, 1.0 sprint

$
0
0

In a few week, pylint will be 10 years old (0.1 released on may 19 2003!). At this occasion, I would like to release a 1.0. Well, not exactly at that date, but not too long after would be great. Also, I think it would be a good time to have a few days sprint to work a bit on this 1.0 but also to meet all together and talk about pylint status and future, as more and more contributions come from outside Logilab (actually mostly Google, which employs Torsten and Martin, the most active contributors recently).

The first thing to do is to decide a date and place. Having discussed a bit with Torsten about that, it seems reasonable to target a sprint during june or july. Due to personal constraints, I would like to host this sprint in Logilab's Toulouse office.

So, who would like to jump in and sprint to make pylint even better? I've created a doodle so every one interested may tell his preferences: http://doodle.com/4uhk26zryis5x7as

Regarding the location, is everybody ok with Toulouse? Other ideas are Paris, or Florence around EuroPython, or... <add your proposition here>.

We'll talk about the sprint topics later, but there are plenty of exciting ideas around there.

Please, answer quickly so we can move on. And I hope to see you all there!

[blog.afpy.org] Comment écrire un blog post ?

$
0
0

Tous les membres de l'AFPy peuvent proposer un article si ils le souhaitent. La procédure est simple:

  • récupérez les sources du blog:

    hg clone http://hg.afpy.org/blog
    
  • vérifiez que le blog se compile bien correctement: après avoir installer pelican en local, tapez:

    make install
    
  • pushez votre code sur le hg de l'afpy:

    hg add votre_fichier.py
    hg commit -m "votre message" -u username
    hg push
    
  • et voilà !

Si vous souhaitez uniquement proposer un article, vous pouvez utiliser la fonctionalité de "draft" de pelican, il suffit de mettre ":status: draft" comme métadonnée pour que l'article ne soit pas publié.

Tout cela est rappelé dans le fichier README du dépôt !


[Biologeek] Propriéterre

$
0
0

Le premier qui, ayant enclos un terrain, s'avisa de dire « Ceci est à moi », et trouva des gens assez simples pour le croire, fut le vrai fondateur de la société civile. Que de crimes, de guerres, de meurtres, que de misères et d'horreurs n'eût point épargnés au genre humain celui qui, arrachant les pieux ou comblant le fossé, eût crié à ses semblables : « Gardez-vous d'écouter cet imposteur ; vous êtes perdus, si vous oubliez que les fruits sont à tous, et que la terre n'est à personne. »

Jean-Jacques Rousseau, L'origine de l'inégalité parmi les hommes (2ème Discours seconde partie)

Thomas me demandait hier mon avis sur la propriété (vs. location) et je dois dire que mon avis n'a pas changé au cours de ces dernières années : j'ai beaucoup de mal à concevoir que l'on puisse être propriétaire d'un morceau de planète. Je ne peux cautionner les dérives que cela a engendré.

Ce qui m'importe par contre c'est le suivi volontaire de mon adresse postale, de mon numéro de téléphone ou de mon nom de domaine. Les affaires peuvent changer de lieux, les amis de répertoire, les données de serveurs mais le plus important est de pouvoir y accéder de manière pérenne. Quel que soit le nombre de redirections nécessaires. Malheureusement, si cela est facile et encouragé sur le web, il est beaucoup plus difficile de le mettre en pratique pour un numéro de téléphone ou une adresse physique, les redirections étant temporaires (et coûteuses) a fortiori lorsque l'on change de pays !

La propriété de la terre est souvent mise en avant comme un héritage — on se dédouane de cet acte en proposant ses enfants comme alibi, excuse culpabilisante classique. Or il se trouve que je suis également contre le mécanisme d'héritage ;-). L'autre argument courant est « si les choses tournent mal » et là je suis assez circonspect. Si ça tourne vraiment mal, il vaudra mieux être prêt à survivre de manière itinérante qu'à avoir un lieu fixe à défendre. S'il s'agit juste de la peur de la vieillesse et de la rupture du lien social avec sa famille et ses enfants il y a d'autres questions à se poser en amont pour éviter cette situation.

J'aime la liberté et la légèreté que me procure la location, l'idée d'être « de passage » dans cet endroit et d'en apprécier pleinement chaque instant, l'idée de se limiter dans ses appartenances pour pouvoir être mobile. De plus, la propriété d'un bien m'est beaucoup plus stressante que son éphémérité.

[afpy.org] Le nouveau site de l'AFPy

$
0
0
Le week-end du 30-31 Mars 2013, nous avons terminé et mis en prod le nouveau site de l'AFPy...

[Biologeek] Manuel vs. jardin

$
0
0

Gawel me faisait remarquer que mes réflexions sur ce site laissaient un goût d'inachevé. Cela m'a fait pas mal réfléchir après 3 mois à publier un jour sur deux et je pense avoir trouvé la raison de cette insatisfaction. J'écrivais auparavant surtout des articles techniques qui expliquent une bonne pratique ou une façon de faire quelque chose de précis à la manière d'un manuel. Ce n'est plus le cas, je sème aujourd'hui des graines de réflexions pour qu'elles puissent germer chez d'autres. Je ne cherche plus à apporter des réponses toutes faites, je souhaite qu'elles se développent indépendamment du semeur. À vous de faire fleurir votre jardin !

PS : j'accepte aussi les graines étrangères dans mon jardin.

[afpyro] AFPyro à Paris - le 19 avril 2013

$
0
0

Le premier Afpyro du printemps aura lieu le vendredi 19 avril, à partir de 19h30, à JMSI / HackSpark, 64 Rue Alexandre Dumas, Paris.

Nous pourrons prendre des bières au bar à côté, et profiter des locaux de JMSI pour discuter.

Pour se rendre à JMDS / HackSpark :
  • en métro : arrêt Alexandre Dumas
  • en bus : bus 76, arrêt Alexandre Dumas

[Inspyration] Relations et dépendances

$
0
0
La gestion des relations entre entités SQL est un point important qui n'est pas trivial. Voici quelques bonnes pratiques.

[Inspyration] Stratégies de chargement

$
0
0
En SQL plus qu'ailleurs, la performance compte. Or, lorsque l'on utilise un ORM, il n'y a rien de plus simple que de mettre une requête dans une boucle sans s'en apercevoir.

[sciunto] Mat : supprimer les métadonnées de fichiers

$
0
0
mat est un logiciel libre (GPLv2) utilisable en console et en interface graphique. Il permet de supprimer les métadonnées présents dans des fichiers (images, documents, multimédia). Ces métadonnées peuvent contenir des noms d’auteur, des numéros de série d’appareil ou encore des données de localisation. Je suis le mainteneur du logiciel pour archlinux. Mat est écrit [...]

[tarek] Declaring dependencies in Python

$
0
0

In Python Packaging, when you are giving for your project a list of dependencies, the right approach is to do whatever works for the majority of your users because there's a plethora of techniques used by people out there to deploy Python software.

That's the case for 2 main reasons:

  1. Most Python projects can be deployed in different operating systems - and unless you're doing a specific packaging work for each one of them, you are doomed to provide a good enough generic package.
  2. There are different installers with different approaches and your Python projects should try to be compatible with all of them.

Some of users will have issues with your projects, you have to accept this fact and just make sure you provide enough documentation and hints for them to work around those issues.

This blog entry tries to summarize my current knowledge on what's the best way to defining dependencies - I hope I'll have some feedback so I can update it with better techniques. Also, note that I have not applied this to all my projects. I should.

So if you disagree on my approach please comment !

Note

I am not talking about Virtualenv on purpose here, to avoid extra complexity.

Nature of your project

The first thing to think about is the nature of your project. They are two kind of projects in the Python world that can be installed by users:

  1. library & tools that will be used in conjunction with other Python projects.
  2. End-user applications that are using a plethora of other Python projects themselves.

The first category is what we create most of the time: utility modules, extensions for some frameworks, library to connect to a database, etc.

The second is a bit specific. It can be a framework, a website or a desktop application - Most of the time it's driving the whole Python environment it's running in and dictates what should be installed.

Library & tools

For library & tools, my advice is to do the following:

  1. provide a setup.py file that uses distribute/setuptools install_requires option, and when appliable provide a pure distutils fallback.
  2. do not pin any dependencies in your setup.py - it turns out it's making people's life a pain when they want to tweak the versions of the libraries themselves in tools like zc.buildout
  3. provide a pip requirements file where everything is pinned. That's your dependencies documentation. It says what versions of each dependencies your project depends on. When possible, add indirect dependencies as well in it.
  4. In your installation instructions, explain that using the pip requirements file is the recommended way -- I usually even provide a Makefile that does it - but that running pip install directly should work fine.
  5. In your continuous integration tool - you are using one, right? ;) use tox to run your tests in all Python versions you are supporting, and also by deploying your code with pinned dependencies and unpinned dependencies.

Here's a setup.py example:

try:
    from setuptools import setup

    install_requires = ['gevent', 'requests']

    try:
        import argparse
    except ImportError:
        install_requires.append('argparse')

    kws = {'install_requires': install_requires}
except ImportError:
    from distutils.core import setup
    kws = {}


setup(name='yourproject', version='1.1', etc.., **kws)

And the Pip requirements file for Python 2.6

gevent==0.13.8
requests==1.2.0
argparse==1.2.1

End-user application

Not maintaining one myself, I have no clue what's the best way to do this but I suspect you really want to maintain a list of projects versions that are working with a given version of your project.

I recall Zope has this pretty neat thing called the Known Good Set (KGS) where they maintain a list of versions that are known to work well together: https://pypi.python.org/pypi/zope.kgs

In any case, deploying a whole Python stack in real life cannot be done with a simple pip install PROJECT call, unless it's a small thing. So maintaining a pip requirements file sounds like a good approach here.

So all-in-all I guess every advice I gave in the first section can be applied for end-user applications as well - as long as you make it clear that running pip install PROJECT won't be enough.

[Inspyration] Relations et dépendances

$
0
0
La gestion des relations entre entités SQL est un point important qui n'est pas trivial. Voici quelques bonnes pratiques.

[Inspyration] Stratégies de chargement

$
0
0
En SQL plus qu'ailleurs, la performance compte. Or, lorsque l'on utilise un ORM, il n'y a rien de plus simple que de mettre une requête dans une boucle sans s'en apercevoir.

[Biologeek] Être geek

$
0
0

Si j'en crois les récents et moins récents billets, le geek serait un paralytique. Doublé d'un perfectionniste à la limite de l'autisme. Dur.

Difficile pour moi car c'est justement ce que je considère être la définition du geek : non pas celle de la paralysie mais celle de la curiosité (maladive parfois, soit). Pour moi le terme « geek » n'est plus du tout connoté informatique et encore moins lié à une culture, c'est le fait de pouvoir se renseigner dans un domaine particulier de façon efficace et rationnelle.

Cette faculté se développe souvent au service de la consommation car cela permet de croiser facilement des données tangibles mais pas uniquement. Il y a des geeks dans tous les domaines qui vont être à la recherche de la rareté, de la qualité, de l'esthétique dans leurs professions et/ou dans leurs loisirs. Qui vont se réaliser dans l'apprentissage de nouveaux métiers qui ne leur serviront parfois qu'une fois dans leur vie mais ils auront au moins eu le sentiment d'avoir essayé de bien le faire (de façon insatisfaisante d'après eux mais c'est un autre débat).

Revenons à l'informatique, connaissez-vous un autre métier qui génère autant de diversité ? On pourrait y voir un manque de maturité du domaine tout jeune, j'y vois plutôt cette approche geek poussée à l'extrême : creuser tout ce qui peut l'être, faire pousser l'arbre des possibles autant que cela est faisable, rejoindre un horizon qui en ouvre tant d'autres. La chance de l'informatique ce n'est pas d'être un secteur encore à défricher mais un catalyseur à personnes curieuses. Et c'est la raison pour laquelle j'aime mon métier, en mouvement :-).

[tshirtman] Kivy hackathon in paris

$
0
0

Last week saw the first 24h hackathon event entirely dedicated to Kivy happening, in Paris. It was initiated by a hightly motivated student of the Cifacom school in paris, David Scheck, and attended by 4 groups of students, each with 3 to 5 members. I was pleased to share the hard task to help students discover the technology with my colleague Julien Miotte, from Majerti during the event.

The student weren’t very familiar with Python, and totally new to kivy, so it was a really challenging situation for both the student and the framework, would they be able to achieve anything in the hard limit of 24 hours?

First, after the students brainstormed on their project ideas, we got them through the major concepts and important classes of Kivy, using the Getting started page, it’s hard to get the point of properties accross in 10 minutes to student that didn’t have experienced the need of them, but I tried to at least make them aware it would be useful. The kv language presentation at this point, even if rudimentary, was probably useful, as we will see later.

Then students went on to try to build their project, except for a few quickly solved issues with windows installation, the starting was smooth. Julien and I gave some more explanations about how to start building a basic App (the doc is there, but who reads the doc? ;)) and people started designing their interface, and build the core of their application.

Eat Smart

One of the most required feature was certainly the use of multiple screens in an application, to build menu, so the use of ScreenManager was explained to at least two groups. Most of the end results consisted of interfaces done mainly in Kv, and some internal logic to display data, most group had a quite ambitious target, using geolocalisation, databases, complex interactions, and I wasn’t very optimistic on the odds of seeing them completed. Although I was right in that, I was still happy of the good designs they came up with, applications were incomplete (to a notable exception, will come back to that soon), but some interfaces were beautiful, reactive and engaging, so it was nice to see the magic happen in such a short time.

Floor2be

One group had a very different objective of the others, and although they had a difficult start, it turns out they were probably the best at teamwork, and had chosen a target they could actually achieve, a game! These motivated coders/artists came up with a classic 2D sidescroller, when the main character has to avoid elements on her way. Simple, to the point, and a quite a good realisation in such a short time, the fact that they created original artworks and integrated them in their game, and that the general theme had a nice touch of humour in the current political events in France certainly hearned them points, on top of having a completed project. They even could test it on Android during the competition time, and it was running perfectly. Their hard work earned them the right to run in a bigger international competition in the near future the angel hack in paris, next month, congratulation! I can only hope they’ll chose kivy as their secret weapon in this competion too.

The BoutinRun team at work

I would love to have better pictures, but i didn’t think much of taking them during the event, I should have better ones soon.

Viewing all 3409 articles
Browse latest View live