Mots-clé : python

Python : hints & cheats

Son propre fichier basique de log

import datetime
msg = u"Test de log"
dt = datetime.datetime.now()
with open("monlogfile.log", 'a+') as f:
    f.write(u'{:02}:{:02} - {}\n'.format(dt.hour, dt.minute, msg))

Teaching Python

Here

Découpages Python : formation

Checkio

Demystifying Two Factor Auth

https://rcoh.me/posts/two-factor-auth/

Python Open Source Projects of the Year

Here!

Thanks to Dan Bader

  • Python Parallel Computing (in 60 Seconds or less): here
  • Python Decorators: A Step-By-Step Introduction: here
  • Interfacing Python and C: Advanced “ctypes” Features: here
  • Working with Random Numbers in Python » ici
  • Face detection
  • Différentes manières de testers plusieurs flags en même temps en Python :
    x, y, z = 0, 1, 0
    if x == 1 or y == 1 or z == 1:
        print('ok')
    if 1 in (x, y, z):
        print('ok')
    # si l'un d'eux n'est pas vide:
    if x or y or z:
        print('ok')
    if any((x, y, z)):
        print('ok')
  • Comment trier un dictionnaire Python par ses valeurs :
    »»» xs = {'a': 4, 'b': 3, 'c': 2, 'd': 1}
    »»» sorted(xs.items(), key=lambda x: x[1])

    ou bien :
    »»» import operator
    »»» sorted(xs.items(), key=operator.itemgetter(1))
  • Mesurer le temps d’exécution de petits morceaux de code Python :
    »»» import timeit
    »»» timeit.timeit('"-".join(str(n) for n in range(100))',
                      number=10000)
    0.3412662749997253
    »»» timeit.timeit('"-".join([str(n)
                                 for n in range(100)])',
                      number=10000)
    0.2996307989997149
    »»» timeit.timeit('"-".join(map(str, range(100)))',
                      number=10000)
    0.24581470699922647
  • Comment utiliser la classe namedtuples :
    # namedtup1e est une classe :
    »»» from collections import namedtuple
    »»» Car = namedtup1e('Car' , 'color mileage')
    # Our new "Car" class works as expected:
    »»» my_car = Car('red', 3812.4)
    »»» my_car.color
    'red'
    »»» my_car.mileage
    3812.4
    # Une belle représentation repr avec :
    »»» my_car
    Car(color='red' , mileage=3812.4)
    # Comme les tuples, les namedtuples sont immuables :
    »»» my_car.color = 'blue'
    AttributeError: "can't set attribute"
  • « is » vs « == » :
    »»» a = [1, 2, 3]
    »»» b = a
    »»» a is b
    True
    »»» a == b
    True
    »»» c = list(a)
    »»» a == c
    True
    »»» a is c
    False

    is est True si deux variables pointent vers le même objet ;
    == est True si les variables contenues dans les objets sont identiques.

  • Titre Titre  :
    »»» Code code code

Learning Python in minutes
https://learnxinyminutes.com/docs/python3/

How to Send an Email With Python
https://dbader.org/blog/python-send-email

Python Decorators From the Ground Up
https://pabloariasal.github.io/python-decorators-from-the-ground-up/

How — and why — you should use Python Generators
https://medium.freecodecamp.org/how-and-why-you-should-use-python-generators-f6fb56650888

Download information on all your gmail emails and the body text to either csv or json. I developed this to download my 100K + emails stored over several years on gmail.
https://teklern.blogspot.fr/2017/11/download-all-your-email-information.html

Memoization in Python: How to Cache Function Results
https://dbader.org/blog/python-memoization

Implementing a Neural Network from Scratch in Python – An Introduction
https://www.datasciencecentral.com/profiles/blogs/implementing-a-neural-network-from-scratch-in-python-an

—–

Introduction to NumPy and Pandas – A Simple Tutorial
https://cloudxlab.com/blog/numpy-pandas-introduction

Fastest way to uniquify a list in Python >=3.6
https://www.peterbe.com/plog/fastest-way-to-uniquify-a-list-in-python-3.6

8 Python Modules For Files Handling
http://devarea.com/8-python-modules-for-files-handling/

How do async for loops work in Python? Using asynchronous for loops in Python
https://quentin.pradet.me/blog/using-asynchronous-for-loops-in-python.html

How to use Python and Flask to build a web app — an in-depth tutorial
https://medium.freecodecamp.org/how-to-use-python-and-flask-to-build-a-web-app-an-in-depth-tutorial-437dbfe9f1c6

Framework ultra simple pour faire des micro-services en Json
Falcon is a bare-metal Python web API framework for building very fast app backends and microservices.
http://falconframework.org

How to break a CAPTCHA system in 15 minutes with Machine Learning
https://medium.com/@ageitgey/how-to-break-a-captcha-system-in-15-minutes-with-machine-learning-dbebb035a710

Python Exceptions: An Introduction
https://realpython.com/python-exceptions/

Python Metaclasses
https://realpython.com/python-metaclasses/

Building a Simple Web App with Bottle, SQLAlchemy, and the Twitter API
https://realpython.com/blog/python/building-a-simple-web-app-with-bottle-sqlalchemy-twitter-api/

Python – Regular Expressions Practical Guide
http://devarea.com/python-regular-expressions-practical-guide/#.Wki2nN_iZhE

A fast high-level screen scraping and web crawling framework.
https://scrapy.org

A fast high-level screen scraping and web crawling framework.
https://pyfiddle.io/

Python : faire un « beep » sur Debian

Le code est simple, il fautt avoir paplay d’installé (je ne sais pas si c’est installé par défaut dans Debian).

A partir de là voici un exemple de code qui joue un fichier ogg :

# python3
>>> import subprocess
>>> subprocess.Popen([
... "paplay",
... "/home/olivier/.local/blah/Mission_Failed.ogg"
... ]).poll()
>>>

Python » PyPI

Contribuer à une librairie Python

Principes

  • Faire un dossier (ex : source)
  • Dans source, cloner la librairie à laquelle on veut contribuer via
    git clone [repo concerné]
  • Faire un dossier pour l’environnement pip (ex : pip_env_lib)
  • Dans pip_env_lib, installer l’environnement pip via pipenv install
  • Dans pip_env_lib, lancer le « shell pip » via pip shell
  • Rarement documenté et important :
    – aller dans le dossier source
    – faire pip install -e .

pip install -e . (n’oubliez pas le . qui change tout, cela indique le répertoire à utiliser) signifie « si jamais le shell Python en cours essaie d’accéder à la librairie à laquelle on veut contribuer, aller la chercher dans source ». En fait, concrètement parlant, pip fait simplement un lien symbolique entre le dossier source d’installation de pip (ici c’est pip_env_lib), et le dossier source. N’oubliez pas que cela ne concerne le shell Python en cours (ici pip_env_lib).

L’avantage pratique de ce « lien symbolique », c’est qu’il est directement relié au code source. Donc, lorsqu’on modifie le code source de la librairie elle-même (dossier source), elle est immédiatement disponible. Si on fait donc des fichiers de tests unitaires, il suffit de les relancer, les modifications du code source sont toujours instantanément prises en compte. Toujours dans le shell Python en cours (ici pip_env_lib).

Résumé : exemple de code

mkdir [source]
cd [source]
git clone [repo concerné]
cd ..
mkdir [pip_env]
cd [pip_env]
pipenv --python 3 install
pip shell
pip install -e .

.. et les modifications dans [source] peuvent commencer !


PyPI : nouveau package / contribution

La documentation détaillée en anglais se trouve ici.
Bien meilleure que ce qui suit, mais longue, longue…

Voici les notes prises à la volées, d’un contributeur plutôt habitué à faire des contributions dans le monde Python.
Toute nouvelle note / correction éventuelle est la bienvenue.

Il y a trois choses différentes qu’on a tendance à confondre, mais qui n’ont fondamentalement aucun rapport. On a tendance à les confondre parce qu’on essaie d’utiliser, pour des raisons pratiques, le même nom, mais dans trois cadres différents.
Ces trois choses à bien dissocier sont :
le nom du package PyPI : dans le fichier de déploiement setup.py, il est défini dans le paramètre « name » de la commande setup(). C’est ce qui est vu dans PyPI.
le nom du projet qu’on met dans github : c’est le répertoire qui contient tous les fichiers du projet (= il peut être totalement différent, en général on s’arrange pour les appeler d’un nom différent) = c’est ce qu’on clone dans l’ordre git clone [repo concerné]
– le développeur final qui fait un « import » dans son code : ce module là peut être aussi différent, car c’est du Python. En général, c’est le répertoire de premier niveau du package (il doit contenir, bien sûr, « __init__.py » pour être vu comme un package et importable par Python). En général : « from [ma lib] import [quelque chose]« .

En général, on essaie de s’arranger pour que le nom du package sur PyPI soit le même que le nom du package dans le code Python même.
Mais s’il est déjà pris (dans un des trois contextes), il faut forcément utiliser un autre nom, et c’est là qu’il faut faire attention à ne pas se mélanger les pinceaux.

Pour faire un nouveau package sur PyPI le plus homogène possible :

  1. essayer de faire un projet « vide »
  2. faites une version squelette « alpha1 »
  3. faites une mise à jour sur PyPI : si ça fonctionne, alors vous pouvez continuer. Sinon, il faut utiliser un autre nom

Versionning

Dans PyPI, les versions sont obligatoirement du type «a.b.c».
En général :
[a].[b].[c]
[a] = fonctionnalités totalement nouvelles / incompatibilité
[b] = améliorations / nouvelles "petites" fonctionnalités
[c] = correctifs bogues

setup.py

Lorsque vous faites une nouvelle contribution, vous devez obligatoirement fournir un fichier setup.py.
Dans ce fichier, setup.py, il y a une fonction, ici aussi, obligatoire : setup().
Cette fonction, parmi tous les paramètres, a un paramètre particulier : classifiers qui permet au niveau de PyPI de dire « ce package est rangé dans telle(s) catégorie(s) ». La liste des expressions disponibles se trouve ici.

Django 2.1 : les autorisations de l’administration grandement facilitées

Voici le (petit) souci que tout le monde a forcément dès qu’on commence à vouloir un peu pousser la customization de l’administration Django : on aimerait avoir la possibilité d’accéder à certains modèles, mais uniquement en lecture seule. J’ai des tonnes d’exemples simples, mais très souvent, ce sont des modèles avec des choix « fixes » qui ne risquent pas d’évoluer dans le temps (exemple : sexe « féminin »/ »masculin »). Seulement (1) on ne veut pas le voir apparaître dans l’admin (2) si on ne veut pas le voir apparaître, il ne faut pas le déclarer, et Django ne veut pas accéder à un modèle qui n’est pas déclaré (= erreur), donc on en arrive toujours à (3) on déclare le modèle, on applique une solution « bidouille » que je ne décris pas ici mais même si le modèle n’apparaît pas dans l’interface, en tapant à la main la bonne URL (facile à deviner qui plus est), on peut tout de même modifier ce modèle. Heureusement la version 2.1 de Django pallie à ce manque !

Eh oui, dans la classe interne «Meta», ils ont fait évoluer default_permissions, qui est écrit en base. Donc en passant à Django 2.1 il vous faudra faire le fameux makemigrations migrate.

Là ou cela devient intéressant, c’est que dans les options vous avez default_permissions et elles sont ('add', 'change', 'delete', 'view'). Le plus important et le nouveau est donc 'view' qui pallie parfaitement au problème expliqué en haut !

Il vous suffit de déclarer votre modèle, de faire la classe dérivée de ModelAdmin et de préciser uniquement ('view',).
Attention, je n’ai pas testé, si quelqu’un veut tester et confirmer que ce code fonctionne (ou pas), je suis preneur !

class SexeAdmin(models.ModelAdmin):
    class Meta:
        default_permissions = ('view',)

Plein de code en moins, plus aucune bidouille ici, plus de lisibilité, bref, de mieux en mieux !

Django Async Roadmap

Petite parenthèse sur l’évolution de Django. Aujourd’hui, ce qui commence à importer plus que la vitesse, c’est la parallélisation des choses.
Donc avoir un serveur Web asynchrone, c’est censé être mieux qu’un serveur Web synchrone (= bloquant).

  • Django 2.1 : rien d’asynchrone. Aucun travail dessus.
  • Django 2.2 : travail initial pour ajouter la possibilité de faire de l’asynchrone sur l’ORM et les vues, sachant que c’est une option et que tout sera synchrone par défaut. Le support async sera principalement basé sur des pools de threads.
  • Django 3.0 : Ré-écriture de la gestion interne des requêtes pour être 100% asynchrone, ajout de la gestion asynchrone des middleware, forms, cache, sessions, auth. Début du process de dépréciation pour toutes les APIs prévues pour être uniquement asynchrones.
  • Django 3.1 : amélioration du support async, peut-être changement du templating
  • Django 3.2 : Fin du process de dépréciation et Django sera presque entièrement asynchrone.

Django : autorisations sur mesure – custom authorizations

Voici comment créer manuellement des groupes + des autorisations personnalisées :

from django.contrib.auth.models import Group, Permission
from django.contrib.contenttypes.models import ContentType
from django.contrib.auth.models import User
new_group, created = Group.objects.get_or_create(
    name ='co_branding_trainer')
ct = ContentType.objects.get_for_model(User)
permission_co_branding_trainer = Permission.objects.create(
    codename='co_branding_trainer',
    name='Co-branding trainer', content_type=ct)
new_group.permissions.add(permission_co_branding_trainer)

Une fois cela fait, on a deux possibilités :

  • aller dans le template et se servir de
    {% if perms.app_label.can_do_something %}
    {% endif %}
  • ou modifier le code vue dans le fichier Python. Dans ce cas, on n’a rien dans le template et si la personne connectée n’a pas les droits, la vue fait un forbidden

Comme je préfère la seconde (qui évite d’avoir dans le template des « if » un peu partout), voici comment faire : on crée un mixin qui se chargera de vérifier si, dans la vue, on a les droits : il suffit de chercher PermissionRequiredMixin dans le code de Django, et vous verrez que tout est simple, à partir de là vous pourrez faire descendre vos vues génériques de PermissionRequiredMixin.

Django Channels sous Windows : attention !

Bah oui !

Sous Linux, Django Channels est compatible Python 3.5 et plus : c’est vrai.
Pof, comme d’habitude, sudo apt-get install blabla, pip3 install blabla et tout fonctionne.
Sous Windows, ce n’est pas le cas (cela changera sûrement dans les semaines à venir et cet article va rapidement ne plus être vrai), mais pour l’instant, Django Channels ne fonctionne pas sous Windows avec Python 3.6, mais uniquement avec Python 3.5.

De plus, vous devrez télécharger des Gigas et des Gigas de données Microsoft pour avoir le compilateur C++ 14 (si ma mémoire est bonne).

Parce que mon ami Microsoft © a retiré les liens (et si vous les avez je suis preneur) du compilateur en ligne C++, et vous devez télécharger Visual Studio et toutes ses immondices qui vont autour, « téléchargez la version pro », « payez un abonnement », ou le pire : « vous devez être enregistré pour pouvoir lancer Visual Studio » (ce qui, à mon sens, est totalement inadmissible et fait partie des wagons (trains entiers ?) de choses qui font que je prône Linux).

2,8 Go chez moi pour Visual Studio Community ainsi que 5,3 Go pour Microsoft SDKs.

Bref, sous Windows :

  • Installez Python 3.5 (toujour à la racine « C:\Python35« ) pour éviter les problèmes de droits quand il est dans « Program Files« 
  • Installez via la ligne de commande classique « channels » (sans passer par PyCharm) : python.exe -m pip install -U channels

Les requêtes « à la » Django : howto / principes

Voici une requête « à la Django ».
« objects » est un objet statique destiné à faire les requêtes
p = un objet du modèle « Person » = un modèle base de données que j’ai fait
g = un objet du modèle « Game » = un modèle base de données que j’ai fait

J’ai crée un modèle intermédiaire « PersonGame » qui lie les deux tables en n/n. Pour comprendre l’idée :
Q(person=p) signifie « dont la personne == p »
~Q(person=p) signifie « dont la personne != p »

Si on met deux « __ » cela signifie « faire une jointure entre les deux modèles », par exemple « person__user » signifie « LEFT JOIN PERSON p ON p.id_user = user.id »

Donc pour tout reprendre :
« Aller chercher dans PersonGame toutes les personnes qui ne sont pas le joueur p »
PersonGame.objects.filter(~Q(person=p), game=g)

…et dont le username vaut « u »
.get(person__user__username=u)

Ce qui donne au final :
PersonGame.objects.filter(
    ~Q(person=p),
    game=g).get(person__user__username=u)

Et voici la requête qu’il aurait fallu écrire « à la main » :

SELECT * FROM PersonGame pg
WHERE pg.id_person != p.id
AND pg.id_game = g.id
LEFT JOIN Person pe on pe.id = p.id
LEFT JOIN User us on us.id = pe.id_user
WHERE us.username = u
LIMIT 1;

En fait ça peut paraître rébarbatif, ou surprenant, mais :
– ça tient en une ligne ;
– quand on a fait 3-4 requêtes comme ça :
  – on arrive à faire n’importe quelle requête un peu complexe très très vite ;
  – on arrive à lire très facilement n’importe quelle requête ;
  – le générateur de requêtes est incroyablement mieux optimisé que celui de Symfony (en fait, techniquement, il est parfait, il génère les LEFT JOIN exactement comme il faut et dans l’ordre le plus efficace en fonction des clés qu’on a précisées dans le modèle, voire il fait des requêtes plus efficaces que ce qu’on aurait éventuellement fait à la main (cela m’est arrivé par deux fois)).

Conclusion : ici aussi, en termes de maintenance = ce qui coûte le plus cher, c’est exceptionnellement rentable.

Comment détecter le père Noël / deep learning, Python, and a Raspberry Pi

Comment détecter le père Noël (détection d’image en Python) ?

C’est un article à la fois super marrant, mais très poussé techniquement, qui apprend au Raspberry Pi comment détecter le père Noël.

Attention, c’est en anglais !

How to build Santa/Not Santa detector with deep learning, Python, and a Raspberry Pi

Comment transférer des fichiers très rapidement entre deux PCs distants ?

Petite astuce très pratique : vous voulez transférer des fichiers d’un PC à un autre, sans forcément partager le répertoire, vous faire suer avec les problèmes de droits, etc. ?

Rien de plus simple, lancez un serveur local Python qui servira les fichiers de manière statique :

  • Python 2 : python -m SimpleHTTPServer
  • Python 3 : python3 -m http.server

Et à distance, tapez l’URL du PC sur lequel tourne le serveur, et hop, vous pouvez récupérer ce que vous voulez !

Exemple de python webserver
Exemple de python webserver