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

[Biologeek] Jouets conviviaux

$
0
0

Se couler dans le moule, par paresse, ou pour protéger les siens du regard désapprobateur de la société pour quiconque marche hors du sentier.

Jeune Huron sous le sapin, Clochix

Dans ma quête d'outils conviviaux et son application à mes productions, je me suis demandé si cela était transposable à d'autres domaines ; en particulier en ces périodes de fêtes qui sont propices à l'achat de jouets pour les enfants. Je suis arrivé à la définition suivante :

Un jouet convivial doit :

  • avoir été produit dans des conditions décentes, si possible localement ;
  • pouvoir être réparé et modifié de façon à augmenter sa durée de vie et son évolutivité ;
  • dépendre uniquement de l'énergie de son utilisateur.

Avec ces 3 règles assez simples, on élimine déjà une bonne partie des jouets disponibles dans le commerce (Made in China, obsolescence programmée, à piles, etc). J'ai péniblement trouvé un ensemble de mini Maracas et j'ai construit un mobile inspiré des travaux de Bruno Munari qui s'est appuyé sur l'art concret pour produire des jouets adaptés aux enfants. Peut-être l'occasion de trouver quelques outils pour enfin apprendre à travailler le bois ?

Dès qu'une vie incertaine et fragile perce le niveau de la conscience en mettant les sens en rapport avec l'environnement, la voilà qui s'élance et bande ses muscles dans l'effort incessant pour se réaliser. Il faut que cet effort obscur de l'enfant soit sacré à nos yeux. Il faut que cette manifestation laborieuse nous trouve prêts, car c'est à cette époque créatrice que la future personnalité de l'homme va se déterminer.

L'Enfant dans la famille, Maria Montessori

Je ne suis pas dans cette dynamique culpabilisante de l'approche éducative mais je sens bien l'importance que je peux avoir en terme d'exemplarité. L'équation est complexe dans un contexte holiste.


[carlchenet] Virtual environments with Python 3.3

$
0
0
Follow me on Identi.ca  or Twitter  One of the major features of Python 3.3 is the new venv module, allowing the creation of Python virtual environments on your system. 1. What is a virtual environment? A virtual environment is a directory dedicated to the execution of your Python applications. Activating your virtual environment will force Python to […]

[afpyro] AFPyro à Bruxelles (BE) et Lyon - mercredi 23 Octobre

$
0
0

Bruxelles

Pour ce premier AFPyro-BE de rentrée, nous aurons le plaisir d’assister à trois présentations :

  1. Laurent Peuch nous montrera les différents outils de debug en Python.
  2. Hugo Herter fera un retour d’expériences sur PyBrain (réseaux neuronaux).
  3. Nicolas Pettiaux nous présentera une application Django orienté restauration.

Enfin, nous plannifierons le covoiturage afin de se rendre à la PyCON-FR qui aura lieu le 26-27 octobre à Strasbourg.

Pour les intéressés, un repas est prévu après les présentations.

Comment s’inscrire ?

Via ce formulaire: http://framadate.org/studs.php?sondage=hdx5xtm8thpkv6u6

Quand ?

Mercredi 23 Octobre à partir de 19h.

Où ?

L’évènement aura lieu à l’ULB Solbosch, dans le batiment K, la salle 3.601: http://www.ulb.ac.be/campus/solbosch/plan.html

Lyon

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

Une présentation sera donnée sur Buildbot. Buildbot est un framework d’intégration continue qui permet de construire, tester et distribuer vos logiciels en utilisant le flux de travail que vous aurez choisi (et sans installer d’usine à gaz ;) ).

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] Gaspillage numérique

$
0
0

Lorsque j’essaye d’aller au plus profond de cette question de la sobriété s’éveille en moi la sensation que semblent avoir eu les être premiers, qui proclamaient que rien ne leur appartenait. Que dire de ces peuples qui, malgré l’abondance, restent modérés ? Le peuple sioux, que j’affectionne particulièrement sans savoir vraiment pourquoi, lors des grandes chasses de buffles abondants, ou même surabondants, n’en prélevait que le nombre qui leur permettait de vivre. Rien des animaux sacrifiés ne doit être dilapidé, tout gaspillage étant prohibé par la morale sacrée, en tant qu’offense à la nature et aux principes qui l’animent. Et la gratitude à l’égard de la prodigalité de la terre allait de soi. Cette sobriété dans l’abondance est une leçon de noblesse.

Vers la sobriété heureuse, Pierre Rabhi

Nous sommes à une ère de l’abondance, ou même de la surabondance numérique. On peut stocker des terra-octets de données dans sa poche, on peut streamer des megabits avec son téléphone, on peut faire tourner 8 processeurs sur ses genoux. Quelle leçon de noblesse en tirer ? J’avais écrit un édito dans le magazine Fait main il y a 6 mois mais je pense qu’il faut aller plus loin.

Des photos de vacances non triées aux mails archivés ad vitam aeternam, des films collectionnés aux bibliothèques musicales dont la qualité est devenue obsolète, des livres téléchargés mais jamais ouverts aux projets inachevés, nous disposons tous de poussières numériques plus ou moins évidentes.

À l’heure où le stockage de données domestiques se compte en téra-octets, on pourrait trouver saugrenue l’idée de limiter son impact en terme de stockage numérique. Et pourtant. Songez un instant à cette masse de données accumulées, à ce grenier numérique qui encombre votre disque dur de ses données antédiluviennes, et ces sauvegardes sur d’autres supports, et ces sauvegardes distantes, et ces sauvegardes incrémentales. Autant de duplications et de transferts qui ont un coût écologique non négligeable.

[…]

Pour venir à bout de cette poussière qui s’accumule, il faut se prêter à deux exercices : un ménage régulier et une hygiène de vie numérique.

Le coût écologique de vos données

Je ne comprends pas qu’une sauvegarde distante doive traverser l’atlantique. Je m’extasiais de l’utilisation du P2P pour faire des sauvegardes croisées il y a 7 ans (!) et rien de nouveau depuis alors que cela semble relativement simple. Quelle part de solidarité numérique pourrait être associée à ces sauvegardes si l’on revient à des échanges d’espace disque locaux ?

Je ne comprends pas qu’il faille une dizaine de serveurs pour faire tourner un simple site. Testing, staging, intégration, QA, pré-prod, statistiques, monitoring, mailing, asynchrone, etc. Chacune de mes pull-requests et la cascade d’actions qu’elle entraîne consomme certainement plus que l’énergie qui m’a permis d’avoir produit la modification de code.

Je ne comprends pas que l’on puisse mettre en production des sites à fort traffic sans tests de consommation côté client. Le site data.gouv.fr est un (mauvais) exemple symptomatique des dommages que cela peut causer, quelle est la facture à l’échelle de la France ? Combien de designers en ont conscience lorsqu’ils ajoutent des parallaxes et autres transformations CSS ?

Je ne comprends pas cet engouement pour le streaming de données récurrentes. À partir de combien d’écoutes est-ce qu’un même morceau consomme plus en streaming qu’en stockage ? Et si une partie de ces sauvegardes croisées n’était pas chiffrée ?

Je ne comprends pas que l’on fasse l’apologie de l’illimité dans un monde fini. Forfaits illimités, stockage illimité, quelles habitudes de consommation est-ce que l’on essaye de nous inculquer à travers le numérique ?

Je ne comprends pas. Mais je m’interroge. Ce n’est pas une ère d’abondance mais de gaspillage numérique dont nous faisons partie. Et cela ne fait que commencer…

[hautefeuille] La boîte à outils Python 2014

$
0
0

Documentation et articles

Générateurs de données

Données géographiques

Développement réseau

Scraping and web crawling

Fuzzing

Parsing et Data Mining

Visualisation de données et interfaces

Traitements de signaux

Conversion

Manipulation de dates

Documentation

Optimisation

Monitoring

Système

Tâches d’administration et de déploiement

Tests

[sciunto] Assembler des images avec PIL ou Pillow

$
0
0

J'ai présenté il y a quelques mois l'utilisation de PIL ou Pillow pour retailler ou "croper" des images.

Pour rappel, Pillow est un fork amical de PIL, dans le but de dynamiser son développement. Aujourd'hui les distributions GNU/Linux majeures sont passées à Pillow. La documentation de Pillow était d'ailleurs encore assez horrible il y a quelques mois et je viens de découvrir que ça s'est grandement amélioré :)

Ici, je vais vous présenter une autre fonction intéressante qui me permet de réaliser des séquences d'images pour retranscrire par exemple une dynamique dans une image.

from PIL import Image

def make_sequence(filenames, output):
    """
    Make a sequence of N pictures

    :params filenames: tuple of filenames
    :params output: output filename
    """
    # Open the picture and get its size
    im1 = Image.open(filenames[0])
    x1, y1 = im1.size

    # Prepare the new picture
    new = Image.new("RGB", (len(filenames)*x1,y1), "Black")
    # Paste each picture of the tuple on the new picture
    for i, im in enumerate(filenames):
        image = Image.open(im)
        new.paste(image, (i*x1, 0))

    # Save the picture
    new.save(output)

On peut aussi avoir besoin de mettre un étalon. Pour celà, on applique un carré blanc (le fond étant noir dans mon cas). On utilise là aussi la fonction paste.

sc1 = Image.new("RGB", (scale1, 10), "White")
new.paste(sc1, (0+50, y1-50))

Une autre fonction pouvant être utile dans ce genre de scripts est la rotation des images :

im.rotate(-1.4, Image.BICUBIC)

Une valeur négative signifie une rotation horraire. Trois méthodes sont possibles : NEAREST, BILINEAR et BICUBIC

J'ai remarqué être confronté souvent à ce même genre de petites tâches, parfois sur des masses de données importantes (comme quelques Go de photos), parfois pour des choses où je veux garder une tracabilité de ce que j'ai fait de manière à pouvoir modifier et rejouer le processus rapidement. Il doit y avoir des logiciels graphiques très performants, mais ces codes sont très flexibles et avec le temps, la banque de snippets permet de couvrir rapidement les besoins.

[afpyro] AFPyro à Lyon - mercredi 22 janvier

$
0
0

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

Claude Huchet de SysGrove donnera une présentation sur Alembic. Alembic est un outil de migration de schéma de base de données à utiliser avec SqlAlchemy.

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] Réseaux sociaux et hypnose

$
0
0

La réponse de Le Bon consiste à dire qu’alors « se forme une âme collective, transitoire sans doute, mais présentant des caractères très nets. La collectivité devient alors ce que, faute d’une expression meilleure, j’appellerai une foule organisée, ou, si l’on préfère, une foule psychologique. Elle forme un seul être et se trouve soumise à la loi de l’unité mentale des foules ». Une conscience collective se constitue spontanément, dès que plusieurs individus sont ensemble. Cette conscience tend à soumettre chacun à ses propres tendances. Le trait de génie de Gustave le Bon est de faire immédiatement un rapprochement avec la relation hypnotiseur/hypnotisé. « L’individu plongé depuis quelques temps au sein d’une foule agissante tombe bientôt dans un état particulier se rapprochant beaucoup de l’état de fascination de l’hypnotisé entre les mains de son hypnotiseur ». Celui qui est hypnotisé perd sa volonté consciente et se soumet aux suggestions de l’hypnotiseur. De même, l’empire du on collectif, l’empire de la foule fait que l’individu devient obéissant aux suggestions collectives.

Sociologie et conscience collective : Conscience collective et individualité

Dans quelle mesure les réseaux sociaux sont-ils des créateurs de foules psychologiques ? La citation suivante est peut-être encore plus emblématique de ce que l’on peut observer sur Twitter :

Les foules ne connaissent que les sentiments simples et extrêmes, les opinions, les idées et croyances qu’on leur suggère, sont acceptées ou rejetées par elles en bloc, et considérées comme vérités absolues ou erreurs non moins absolues. Il en est toujours ainsi des croyances déterminées par voie de suggestion, au lieu d’avoir été engendrées par voie de raisonnement.

Psychologie des foules, Gustave Le Bon (1894)

Comment alors sortir de cette hypnose ? Garder son esprit critique lorsque l’on est bombardé d’informations s’avère être compliqué : plus le temps de croiser, vérifier, confronter. On tombe rapidement dans l’ironie et la dérision ou le micro-débat bien stérile. On devient prompt à colporter les erreurs et les ragots sans partager les réussites et les travaux. Quelle est notre part de responsabilité à faire partie de cette bêtise systémique ? S’auto-exclure d’un environnement hostile et stérile ou tenter de l’adapter et d’en cultiver une petite parcelle ? Je me pose cette question depuis bien trop longtemps, il est temps de retrouver la voie de la raison.


[Biologeek] Sens et utilité

$
0
0

If the people who caused our frustration don’t understand what we do, we find solace in talking to those who do, namely us. We blog on design blogs, we create quick scripts and tools that are almost the same as another one we use (but not quite) and we get a warm fuzzy feeling when people applaud, upvote and tweet what we did for a day. We keep solving the same issues that have been solved, but this time we do it in node.js and python and ruby and not in PHP (just as an example). We run in circles but every year we get better and shinier shoes to run with. We keep busy.

Finding real happiness in our jobs, Christian Heilmann

Je partage de plus en plus ce constat, dans une quête de sens on se retrouve à ne plus raisonner en terme de technologies ou de techniques mais d’usages et d’utilité. Un moyen de ne plus courir en rond mais d’aller arpenter les collines alentours où l’herbe n’est pas plus verte mais plus sauvage. Y rencontrer de nouvelles personnes. Y découvrir de nouvelles contraintes. Y explorer de nouvelles envies aussi.

J’ai beaucoup appris durant cette première année à co-construire scopyleft avec mes collègues. J’ai encore énormément à échanger dans cette aventure collaborative mais j’ai déjà le sentiment d’avoir évolué sur de nombreux plans, pas forcément pour faire de moi un meilleur développeur mais peut-être un meilleur humain :-).

[afpyro] Meetup à Grenoble - jeudi 23 janvier

$
0
0

Un meetup Python aura lieu le jeudi 23 janvier à Grenoble à partir de 19h à la Casemate (place Saint Laurent, 38000 Grenoble).

L’agenda provisoire est le suivant:

  • 19h: Intro
  • 19h15: Arthur Vuillard: Tests Unitaires
  • 20h: Mike Bright: Tendances dévelopements pour 2014
  • 20h45: Discussion sur le groupe

Merci de noter que nous aurons une petite salle disponible avec une capacite de 20 personnes. Pour faire en sorte qu’un maximum de personne puisse venir, merci de vous inscrire/désinscrire sur cette page.

La soirée se terminera autour d’un verre sur place ou dans un bar.

[cubicweb] What's new in CubicWeb 3.18

$
0
0

The migration script does not handle sqlite nor mysql instances.

New functionalities

  • add a security debugging tool (see #2920304)
  • introduce an add permission on attributes, to be interpreted at entity creation time only and allow the implementation of complex update rules that don't block entity creation (before that the update attribute permission was interpreted at entity creation and update time) (see #2965518)
  • the primary view display controller (uicfg) now has a set_fields_order method similar to the one available for forms
  • new method ResultSet.one(col=0) to retrieve a single entity and enforce the result has only one row (see #3352314)
  • new method RequestSessionBase.find to look for entities (see #3361290)
  • the embedded jQuery copy has been updated to version 1.10.2, and jQuery UI to version 1.10.3.
  • initial support for wsgi for the debug mode, available through the new wsgi cubicweb-ctl command, which can use either python's builtin wsgi server or the werkzeug module if present.
  • a rql-table directive is now available in ReST fields
  • cubicweb-ctl upgrade can now generate the static data resource directory directly, without a manual call to gen-static-datadir.

API changes

  • not really an API change, but the entity write permission checks are now systematically deferred to an operation, instead of a) trying in a hook and b) if it failed, retrying later in an operation
  • The default value storage for attributes is no longer String, but Bytes. This opens the road to storing arbitrary python objects, e.g. numpy arrays, and fixes a bug where default values whose truth value was False were not properly migrated.
  • symmetric relations are no more handled by an rql rewrite but are now handled with hooks (from the activeintegrity category); this may have some consequences for applications that do low-level database manipulations or at times disable (some) hooks.
  • unique together constraints (multi-columns unicity constraints) get a name attribute that maps the CubicWeb contraint entities to the corresponding backend index.
  • BreadCrumbEntityVComponent's open_breadcrumbs method now includes the first breadcrumbs separator
  • entities can be compared for equality and hashed
  • the on_fire_transition predicate accepts a sequence of possible transition names
  • the GROUP_CONCAT rql aggregate function no longer repeats duplicate values, on the sqlite and postgresql backends

Deprecation

  • pyrorql sources have been deprecated. Multisource will be fully dropped in the next version. If you are still using pyrorql, switch to datafeed NOW!
  • the old multi-source system
  • find_one_entity and find_entities in favor of find (see #3361290)
  • the TmpFileViewMixin and TmpPngView classes (see #3400448)

Deprecated Code Drops

  • ldapuser have been dropped; use ldapfeed now (see #2936496)
  • action GotRhythm was removed, make sure you do not import it in your cubes (even to unregister it) (see #3093362)
  • all 3.8 backward compat is gone
  • all 3.9 backward compat (including the javascript side) is gone
  • the twisted (web-only) instance type has been removed

[hautefeuille] Parallélisation des traitements en Python

$
0
0

Introduction

Je suis amené régulièrement à réaliser des récupérations de fichiers sur des supports effacés ou défectueux. Un des logiciels que j’utilise est Photorec.

PhotoRec est un programme de récupération de données conçu pour récupérer des images perdues provenant de carte mémoire d’appareil photo, d’où le nom de PhotoRec provenant de l’anglais Photo Recovery. Il peut aussi récupérer de nombreux fichiers perdus, tels que de la vidéo, des documents et des archives stockés sur un disque dur ou sur un CD-ROM.

PhotoRec ignore le système de fichiers et va directement aux données fondamentales, il devrait donc fonctionner même si le système de fichiers est sévèrement endommagé ou formaté. PhotoRec est sûr d’utilisation, il n’essayera jamais d’écrire sur votre disque dur ou autre support mémoire que vous voulez récupérer. Les fichiers récupérés seront écrits sur le disque dur où vous exécutez PhotoRec.

Photorec crée sur le disque un ensemble de dossiers contenant l’ensemble des fichiers dumpés.

La demande la plus récurrente qui m’est formulée est de récupérer des photos perdues ou effacées par inadvertance. Il faut donc un script qui parcourt l’ensemble des dossiers pour en extraire les photos qui nous intéressent (celles qui disposent d’une taille raisonnable de visualisation).

Le script Python pyphotorec.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
Help to sort files from PhotoRec

"""

from multiprocessing import Pool
import path
from PIL import Image

IN = "/mnt/big/DISQUE_DUMP/"
OU = "/mnt/big/DISQUE_DUMP_JPG/"
WIDTH = 240
HEIGHT = 180

def get_jpg(folder):
    initfolder = path.path(folder)
    folders = [elem for elem in initfolder.dirs()]
    return [f for elem in folders for f in elem.files('*.jpg')]

def copy_jpg(filename):
    p = path.path(filename)
    fbase = p.basename()
    im = Image.open(filename)
    fwidth, fheight = im.size
    if fwidth > WIDTH and fheight > HEIGHT:
        im.save(OU + fbase, "JPEG")
        print fbase, "=> Image saved"

if __name__ == "__main__":
    pool = Pool()
    pool.map(copy_jpg, get_jpg(IN))
    pool.close()
    pool.join()

Remarques

La lecture du script n’oppose pas de difficulté particulière. La notion intéressante dans ce script est l’utilisation de la fonction map() et du multiprocessing pour paralléliser les traitements.

Liens

map

[Biologeek] Protéger, lâcher prise et rêver

$
0
0

Maybe each of these activities (listening to high end audio gear, drinking high end wine, having needles inserted into your chakras) is really about ritualizing a sensory experience. By putting on headphones you know are high quality, or drinking expensive wine, or entering the chiropractor’s office, you are telling yourself, "I am going to focus on this moment. I am going to savor this." It’s the act of savoring, rather than the savoring tool, that results in both happiness and a longer life.

Placebo-philes

Protéger

J’ai une petite vie naissante aux creux de mes bras. Elle a besoin d’amour et de soin pour sortir sa première feuille. Je souhaite l’aider en lui laissant le répit de cette année avant d’être confrontée à la société.

Quelques jours d’existence et déjà capable de ressentir les tensions dans une pièce. Grandir consiste peut-être à perdre cette faculté, progressivement devenir insensible aux échanges d’énergies et désapprendre à communiquer de manière silencieuse. Se construire une carapace protectrice, années après années, et ne plus être capable de s’ouvrir au monde le moment venu. J’ai beaucoup à réapprendre.

Lâcher prise

Besoin de me recentrer sur des choses qui comptent sur le long terme. Vous me verrez probablement peu à des conférences techniques cette année. Ou participer à des projets Open-Source pour le plaisir de coder. Ou bloguer/tweeter du futile.

En revanche, j’ai envie de discuter avec des personnes qui ont besoin de mes compétences pour co-construire des projets utiles. J’ai envie de rencontrer des utilisateurs d’outils qui peuvent être améliorés. J’ai envie d’écrire quelque chose de plus dense, construit, fouillé.

Moins de Twitter, de Github et d’IRC. Plus de rencontres, d’outils conviviaux et de discussions de visu.

Rêver

Ce monde a besoin de réenchantement. Même en faisant une diète d’infos, je vois bien que cette charnière historique que l’on a la chance de vivre et que l’on pourrait résumer par un passage de la pyramide au graphe se fait dans une morosité ambiante anxiogène et délétère. Or elle pourrait s’effectuer dans la joie d’une autonomie retrouvée et d’une initiative reconsidérée. J’ai envie de rêver et de partager mes rêves, d’apporter des sourires et de la motivation.

Dans les épisodes précédents

[tshirtman] Building a background application on android with Kivy.

$
0
0

Kivy runs on android using the python-for-android project, which support android services. This works in a simple way, you basically bundle two main.py in your application, one for the UI, one for the service. The UI can start the services on start. From that point though, things may be a little uneasy. Why? Because you have two applications, and now you have to make them talk to each over if you want to do anything useful.

Android’s way of having an Activity and a Service talk to each other is Broadcast signals, which can be limited to part of your applications, howether, it’s not straightforward to use them with pyjnius, which is the magical interface we use to use java code from python.

Another way is to use network, i’ve been doing it with twisted in the past, setting a twisted server in the Service, and using twisted as a client in the Activity, howether, i find this to be heavy lifting for the trivial task of communicating between two programs on the same device. And including Twisted in your app, certainly add some weight to it.

Howether, in order to support TUIO, kivy ships with a simple OSC implementation, OSC is a simple connectionless network protocol, that allow you to pack messages, and send them to an ip/port/api URI, turns out we don’t need anything more, and a connectionless protocol avoid us dealing with disconnections (like the UI being closed, or the service not being started yet) that could give us some headaches (and certainly gave me some). We just need to have both part of the program listen for OSC messages, and have them send data to each other, if confirmation is needed, it’s possible to have a messages been sent back on a specific api.

So let’s get started.

getting a minimal kivy app

The usual things, let’s put a simple UI with a Button.

from kivy.app import App
from kivy.lang import Builder

kv = '''
Button:
    text: 'push me!'
'''

class ServiceApp(App):
    def build(self):
        return Builder.load_string(kv)

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

here we just load a kv string that defines a button, and return the result, nothing fancy.

getting a minimal service

from time import sleep

if __name__ == '__main__':
    while True:
        sleep(.1)

Yeah, nothing much needed, actually, the sleep isn’t even needed, but the program have to run, and we’ll need this loop anyway.

starting the service

For your service to run, you need to tell your UI to start it.

from kivy.app import App
from kivy.lang import Builder
from kivy.utils import platform

kv = '''
Button:
    text: 'push me!'
'''

class ServiceApp(App):
    def build(self):
        if platform == 'android':
            from android import AndroidService
            service = AndroidService('my pong service', 'running')
            service.start('service started')
            self.service = service

        return Builder.load_string(kv)

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

We make the test for android, so you can still test your app on desktop, by starting manually both parts.

Packaging them for android

both files must be named main.py, the UI one is at the root of the project, the other one is in a service directory directly under the root of the project.

├── main.py
└── service
    └── main.py

To package, i’ll be using buildozer.

As we are using network don’t forget to add the NETWORK permission when editing buildozer.spec

buildozer init
editor buildozer.spec
buildozer android debug deploy run logcat

After some time, you should see the (not very exciting) app start on your plugged android device.

setting up OSC

Whatever the side, OSC needs a port to listen on, and to have functions to call when things happen. The basic setup is simple.

from kivy.lib import osc

def some_api_callback(message, *args):
   print("got a message! %s" % message)

osc.init()
oscid = osc.listen(ipAddr='0.0.0.0', port=someport)
osc.bind(oscid, some_api_callback, '/some_api')

and then

osc.readQueue(oscid)

needs to be called regularly.

for the service, we’ll just put this call in the loop:

from time import sleep
from kivy.lib import osc

service = 3000

def some_api_callback(message, *args):
   print("got a message! %s" % message)

if __name__ == '__main__':
    osc.init()
    oscid = osc.listen(ipAddr='127.0.0.1', port=service)
    osc.bind(oscid, some_api_callback, '/some_api')

    while True:
        osc.readQueue(oscid)
        sleep(.1)

And for UI, we’ll use kivy.clock.Clock’s schedule_interval method.

from kivy.app import App
from kivy.lang import Builder
from kivy.lib import osc
from kivy.utils import platform
from kivy.clock import Clock

activityport = 3001

def some_api_callback(message, *args):
   print("got a message! %s" % message)

kv = '''
Button:
    text: 'push me!'
'''

class ServiceApp(App):
    def build(self):
        if platform == 'android':
            from android import AndroidService
            service = AndroidService('my pong service', 'running')
            service.start('service started')
            self.service = service

        osc.init()
        oscid = osc.listen(ipAddr='127.0.0.1', port=activityport)
        osc.bind(oscid, some_api_callback, '/some_api')
        Clock.schedule_interval(lambda *x: osc.readQueue(oscid), 0)

        return Builder.load_string(kv)

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

Now, both sides can receive messages, that’s a good first step, but nothing will really happen, since none of them send any message.

sending messagse

The osc api to send message is very simple:

osc.sendMsg(api, data_list, port=someport, ipAddr=someaddress)

now, ipAddr is by default localhost, which is fine for us, so we only need to find the api we want to hit, the data list, and the port, which will be the one the other side listens on.

Let’s make our button send a message to the Service.

from kivy.app import App
from kivy.lang import Builder
from kivy.lib import osc
from kivy.clock import Clock

activityport = 3001
serviceport = 3000

def some_api_callback(message, *args):
   print("got a message! %s" % message)

kv = '''
Button:
    text: 'push me!'
    on_press: app.ping()
'''

class ServiceApp(App):
    def build(self):
        if platform == 'android':
            from android import AndroidService
            service = AndroidService('my pong service', 'running')
            service.start('service started')
            self.service = service

        osc.init()
        oscid = osc.listen(ipAddr='127.0.0.1', port=activityport)
        osc.bind(oscid, some_api_callback, '/some_api')
        Clock.schedule_interval(lambda *x: osc.readQueue(oscid), 0)

        return Builder.load_string(kv)

    def ping(self):
        osc.sendMsg('/some_api', ['ping', ], port=someotherport)


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

Yes, at that point, you can run it, and see that when you press the button, your adb logcat on android, yay!

Now, let’s make our service answer, and our UI display the answer!

from time import sleep
from kivy.lib import osc

serviceport = 3000
activityport = 3001

def some_api_callback(message, *args):
    print("got a message! %s" % message)
    answer_message()

def answer_message():
    osc.sendMsg('/some_api', [asctime(localtime()), ], port=activityport)

if __name__ == '__main__':
    osc.init()
    oscid = osc.listen(ipAddr='127.0.0.1', port=serviceport)
    osc.bind(oscid, some_api_callback, '/some_api')

    while True:
        osc.readQueue(oscid)
        sleep(.1)

and for the UI to answer:

from kivy.app import App
from kivy.lang import Builder
from kivy.lib import osc
from kivy.utils import platform
from kivy.clock import Clock

activityport = 3001
serviceport = 3000

kv = '''
Button:
    text: 'push me!'
    on_press: app.ping()
'''

class ServiceApp(App):
    def build(self):
        if platform == 'android':
            from android import AndroidService
            service = AndroidService('my pong service', 'running')
            service.start('service started')
            self.service = service

        osc.init()
        oscid = osc.listen(ipAddr='127.0.0.1', port=activityport)
        osc.bind(oscid, some_api_callback, '/some_api')
        Clock.schedule_interval(lambda *x: osc.readQueue(oscid), 0)

        return Builder.load_string(kv)

    def ping(self):
        osc.sendMsg('/some_api', ['ping', ], port=someotherport)

    def some_api_callback(self, message, *args):
        print("got a message! %s" % message)
        self.root.text += '\n%s' % message[2]

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

The only thing a bit confusing here is that the real message is in message[2], don’t ask me why, it’s probably explained in some documenation i didn’t care enough to search for :).

conclusion

That’s not much code! And it should be quite easy to extend to allow for more complex patterns, detecting if your service is running or not can be done by making it send pings at regular intervals, you can also make your service fetch/work on data from somewhere else in the background, and pass it to the UI when it’s ready.

A slightly more complex demo based on this can be found here.

[sciunto] bibtexparser en python

$
0
0

Utilisant bibtex comme base de données bibliographiques, j'ai cherché une bibliothèque python permettant de traiter de tels fichiers. Je pensais que je trouverais facilement mon bonheur car python regorge de bibliothèques. Erreur... je n'ai rien trouvé de fonctionnel et documenté.

Pour ceux qui ne savent pas, bibtex est un format pour stocker des infos bibliographiques et ça ressemble à ça.

 @book{Ben62,
    title = "L'Oxydation des m\'etaux",
    author = "J. B{\'e}nard and J. Bardolle and F. Bouillon and M. Cagnet%
       and J. Moreau and G. Valensi",
    publisher = "Gauthier-Villars",
    year = "1962"
 }

En fuinant dans des codes sources de logiciels, j'ai fini par trouver un projet de l'OKFN qui se nomme bibserver. Vu le nom, je devais bien trouver un bout de code qui s'arrange avec ces fichiers.

C'était effectivement le cas, et le parser était vraiment satisfaisant sur mes fichiers. J'ai alors décidé d'en faire un projet à part entière de manière à ce que tout le monde puisse avoir un parser en python pour ses besoins. La license de bibserver est la AGPLv3. Ce qui fait sens pour ce type de project. Le problème est que cela peut être un peu trop restrictif pour certains usages et un utilisateur m'a d'ailleurs demandé si je pouvais passer à une license de type LGPL.

Il s'en est suivi une pêche à l'autorisation. J'ai commencé l'été dernier par l'auteur principal de bibserver, mais je n'ai pas eu de réponse. Puis, je suis passé au second contributeur qui n'y voyait pas de problème, a mis le premier auteur en copie de son message. Le premier auteur m'a répondu dans la foulée pour me dire OK, mais les droits sont reversés à l'OKFN, il faut donc leur demander l'autorisation. Je suis passé par leur courriel de contact, deux fois, mais je n'ai pas eu de réponse. Ma dernière chance était la liste de discussion et tada ! j'ai eu la permission.

Le code est donc passé en LGPLv3. Ce fût une longue bataille, qui montre aussi l'importance de bien choisir la licence de départ. En effet, si l'AGPL est tout à fait approprié à bibserver, cette sous-partie peut très bien faire l'objet d'une bibliothèque à part entière et c'est dommage de ne pas étendre les possibilités de cette sous-partie. J'ai coutume de dire que l'on ne passe jamais à tous les usages possibles, ce qui est l'essence du hacking et qu'il faut essayer, autant que faire ce peu, d'ouvrir au maximum la réutilisation de ce que l'on écrit.

Un grand merci aux personnes de l'OKFN pour cette permission.


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

$
0
0

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

[tshirtman] Publisher/Consumer model in Kivy

$
0
0

Few things are worse to an user than an unresponsive UI, well i can think of a crashing UI, of course, but not much more. So, in an event driven environment, it’s important to avoid blocking the UI for too long.

But sometime you have a task that will take an unacceptable time for such constraint, if the task can’t really be chunked, a Thread is likely to be the acceptable solution, but threads have constraints and in Kivy, you can’t update the UI from one, you have to schedule something to happen on the main thread, and update things from here. If the task is chunkable, it’s even easier, but the following idea can apply to both situation.

So, a solution that i find convenient, is to use a publisher/consumer model.

The idea is simple, have a scheduled action each frame do a small part of your task, until a timeout is triggered, and then wait for next frame to continue.
To trigger work, just put (publish) it in a list of tasks to be treated py the consumer.

So let’s start by setting a consumer for adding elements to a list, we don’t want to add 100 elements in the same frame, because that would take too much time.

from kivy.app import App
from kivy.clock import Clock
from kivy.lang import Builder
from kivy.properties import ListProperty
from kivy.uix.label import Label

kv = '''
BoxLayout:
    ScrollView:
        GridLayout:
            cols: 1
            id: target
            size_hint: 1, None
            height: self.minimum_height
     Button:
        text: 'add 100'
        on_press: app.consumables.extend(range(100))
'''

class PubConApp(App):
    consumables = ListProperty([])

    def build(self):
        Clock.schedule_interval(self.consume, 0)
        return Builder.load_string(kv)'

    def consume(self, *args):
        if self.consumables:
            item = self.consumables.pop(0)
            label = Label(text='%s' % item)
            self.root.ids.target.add_widget(label)

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

Now, i’m only taking one item each frame, it’s probably good enough, but if we have a lot of item, we still may want to take as much is possible, considering kivy loop is frame-limited to 60fps, 100 items will take more than a second, why wait if we have the power? Let’s use a slightly smarter version.

add this import near of the top

from kivy.clock import _default_time as time

then change consume definition to be:

def consume(self, *args):
    limit = Clock.get_time() + 1 / 60.
    while self.consumables and time() < limit:
        item = self.consumables.pop(0)
        label = Label(text='%s' % item)
        self.root.ids.target.add_widget(label)

Of course, this only work because we know creating and adding one widget takes considerably less time than one frame, so it’s not like one of such operation will make our loop hang too long.

Now, filling the consumable list here is done from main UI, but it could totally be done from a Thread, assuming locking is correctly handled (or that extend/pop are atomic, which seems to be the case), so if your filling of work to be displayed is slow, doing the exact same thing as a background task will allow you to do heavy lifting, while keeping your app snappy.

A slightly more demonstrative version of this example can be found here

[Biologeek] API internes et Hypermedia

$
0
0

“Small pieces loosely joined,” David Weinberger’s appealing theory of the Web, has much to say to programmers as well. It always inspires me to reduce the size of individual code components. The hard part, though, is rarely the “small” – it’s the “loose”.

Transformative Programming, Simon St. Laurent

Je coopère depuis maintenant 6 mois avec l’équipe des paiements du Marketplace de Mozilla. C’est typiquement un cas où une grosse application monolithique a été scindée en plusieurs petites API qui communiquent entre elles. On retrouve donc bien le small pieces (même si c’est discutable) mais qu’en est-il du loosely joined ? Ces différentes briques communiquent entre elles via HTTP en essayant de le respecter au mieux mais la partie hypermedia relève de l’anecdotique avec quelques liens pas forcément exploités. Dans quelle mesure est-ce problématique au quotidien ?

Le couplage fort nécessite parfois la modification du client et du serveur de manière simultanée. Rien de grave lorsque l’on contrôle les 2 mais la seule alternative serait de coder de manière très défensive avec tout le code mort que cela occasionne sur le moyen terme. L’utilisation d’hypermedia permettrait de réduire cela (pas forcément d’y pallier totalement) en proposant de nouvelles façons de parcourir le graphe sans qu’elles deviennent indispensables. La logique défensive ne se situerait plus au niveau du client mais du serveur qui devrait gérer le cycle de vie de ses URI.

Il peut y avoir ambiguité dans les identifiants. Parfois ce sont des UUID, d’autres fois des primary keys, d’autres fois des ids, d’autres fois enfin des URI. Difficile de s’y retrouver et de faire la distinction entre ce qui est unique ou non, se baser sur un schéma d’URI cohérent permettrait de lever cette ambiguité tout en conservant un vocabulaire commun entre les différents projets. Plus l’architecture devient complexe, plus la cohérence devient importante et nécessite d’avoir une vision à long terme. Non pas en anticipant les problèmes mais en se laissant la possibilité d’évoluer sans tout casser.

La logique est cachée dans le code. Et la documentation lorsqu’elle est à jour et pertinente. Il est quasi-impossible de comprendre les interactions entre les différentes parties en analysant leurs seuls échanges ce qui rend difficile l’intégration sur un projet. La vision d’ensemble est endommagée par une telle pratique. Il n’est pas possible de naviguer dans le graphe des interactions pour en comprendre les tenants et les aboutissants, l’effort de documentation se trouve être décuplé.

Est-ce que l’utilisation d’hypermedia était indispensable dans ce cas là ? Pas forcément, avec le recul je me demande même si l’utilisation d’HTTP est une bonne chose pour ce style d’API internes. Quitte à garder un couplage fort, l’utilisation de protocoles binaires comme Apache Thrift ou Google Protocol Buffers permettrait de gagner en performances sans forcément complexifier le code. La culture s’en trouverait par contre certainement altérée en perdant le côté Web, mais plutôt que d’utiliser le Web à mauvais escient, peut-être qu’il appartient aux développeurs web de s’ouvrir à d’autres options…

Pour en revenir à l’article initialement lié, je m’interroge de plus en plus sur cette notion de flux de données et sur l’importance que l’on accorde à son stockage, sa serialization, sa transformation, son transport et son accès. Chacune de ces étapes dans la vie d’une donnée devrait être traitée avec le même soin.

[Biologeek] Dogmatiques défauts

$
0
0

Préambule : je n’ai pas trouvé de meilleure traduction à opinionated qui est tout de même assez différent.

To understand the Zen principles, a good starting point is shibumi. It is an overarching concept, an ideal. It has no precise definition in Japanese, but its meaning is reserved for objects and experiences that exhibit in paradox and all at once the very best of everything and nothing: Elegant simplicity. Effortless effectiveness. Understated excellence. Beautiful imperfection.

7 Design Principles, Inspired By Zen Wisdom

J’annonçais récemment sur Twitter qu’il existait un marché pour les sites comme Medium ou Exposure en version facilement installable chez soi. Ce à quoi Nicolas me rétorquait que n’importe quel CMS pourrait convenir. Maurice et Michel surenchérissaient en rappelant l’importance prépondérante du marketing sur ce type de projets. Je pense pour ma part qu’il s’agit d’une histoire de défauts : proposer un design suffisamment engagé pour qu’il puisse créer une tendance.

C’est bien sûr reproductible, il n’y a qu’à voir le nombre de sites qui arborent une énorme photo floue en tête de page avec un titre en 50px. Et je suis d’accord qu’il est possible de faire ça assez facilement avec un Wordpress ou un Dotclear. Tout est dans le « assez ». À la limite, distribuer officiellement l’un de ces outils avec un thème par défaut s’en approchant pourrait avoir un impact sur la communauté mais sinon il faut bien réaliser que la modification d’un outil web par des utilisateurs non techniciens tient de l’épiphénomène.

En fait la communauté des Logiciels Libres est tellement peu consciente des problématiques d’expérience utilisateur qu’il y aurait un marché pour n’importe quel outil Open-source dont l’ergonomie et le design seraient retravaillés. Peut-être qu’il s’agit de fainéantise de ma part de vouloir quelque chose qui fonctionne du premier coup, pire j’encourage ainsi la stupidité et chaque citoyen/enfant devrait apprendre à coder pour bidouiller son propre outil. Dans ce monde de Bisounours, plus personne n’aurait le temps de bloguer par contre :-).

[cubicweb] Logilab's roadmap for CubicWeb on January 9th, 2014

$
0
0

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

Version 3.17

This version is stable and maintained (current is 3.17.11 and 3.17.12 is upcoming).

Version 3.18

This version was released on Jan 10th. Read the release notes or the details of CubicWeb 3.18.0.

Version 3.19

This version includes a heavy refactoring that modifies sessions and sources to lay the path for CubicWeb 4. It is currently the default development head in the repository and is expected to be released before the end of january.

For details read list of tickets for CubicWeb 3.19.0.

Version 3.20

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

For details read list of tickets for CubicWeb 3.20.0.

Cubes

The current trend is to develop more and more new features in dedicated cubes than to add more code to the core of CubicWeb. If you thought CubicWeb development was slowing down, you made a mistake, because cubes are ramping up.

Here is a list of versions that were published in the past two months: timesheet, postgis, leaflet, bootstrap, worker, container, embed, geocoding, vcreview, trackervcs, vcsfile, zone, dataio, mercurial-server, queueing, questionnaire, genomics, medicalexp, neuroimaging, brainomics, elections.

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

Bootstrap works and we do not create a new application without it.

relationwidget provides a modal window to edit relations in forms (use uicfg to activate it).

resourcepicker provides a modal window to insert links to images and files into structured text.

rqlcontroller allows to use the INSERT, DELETE and SET keywords when sending RQL queries over HTTP. It returns JSON. Get used to it and you may forget about asking for specific web services in your apps, for it is a generic web service.

imagesearch is an image gallery with facets. You may use it as a demo of a visual search tool.

Mid-term goals

A new repository was created to have all the CubicWeb Evolution Proposals in one place.

CWEP-0002 is a work in progress about computed relations and computed attributes, or maybe more. It will be a focus of the next sprint and is targeted at CubicWeb 3.20.

A new CWEP is expected about the adding FROM keyword to RQL to implement explicit data source federation. It will be a focus of the next sprint and is targeted at CubicWeb 3.21.

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

Caching session data would help. Maybe in 3.23 ?

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

RESTfulness is a goal. Maybe in 3.25 ?

Maybe 3.26 will be in fact 4.0 ?

Events

A sprint will take place in Logilab's offices in Paris around mid-february or at the end of april. We invite all the interested parties to join us there!

Last but not least

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

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

Viewing all 3409 articles
Browse latest View live