PROJET AUTOBLOG


Sam et Max

source: Sam et Max

⇐ retour index

La virgule n’est pas un opérateur en Python

vendredi 22 février 2013 à 11:57

Premiers tutos, et vous apprenez l’existence du tuple :

t = (1, 2)
print t
## (1, 2)
print type(t)
## <type 'tuple'>

Puis en creusant un peu, vous apprenez qu’un tuple, en fait, c’est juste une série d’objets séparés par des virgules :

t = 1, 2
print t
## (1, 2)

Les parenthèses sont optionnelles pour créer un tuple.

Du coup si on rajoute l’unpacking :

a, b = (1, 2)
print a
## 1
print b
## 2

Du coup on peut faire des fonctions qui semblent (mais c’est une illusion), retourner plusieurs valeurs à la fois :

def foo():
    return 1, 2
 
print foo()
## (1, 2)
print type(foo())
## <type 'tuple'>
a, b = foo()
print a
## 1
print b
## 2

Mais un jour, au lieu de faire ça :

t = "a" in ("b", "a")
print t
## True

Vous faites ça

t = "a" in "b", "a"
print t
## (False, 'a')

Enfer, damnation et baba au rhum !

Ce n’est pas du tout ce que vous attendiez !

La raison à cela est que la virgule en Python n’est pas un opérateur, c’est un simple séparateur. Votre expression a donc été analysée comme :

("a" in "b"), "a"

C’est pour cela qu’utiliser les parenthèses est recommandé avec les tuples : pour clarifier la priorisation des opérations. Car comme la virgule n’est pas un opérateur, elle n’a pas de priorité définie comme pour *, /, and et or, et c’est un peu la fête du slip.

Moralité : à part pour l’unpacking, utilisez toujours des parenthèses dans vos tuples.

Ça vous évitera des aventures du genre :

s = "Ceci est un %s %s" % "test", "idiot"
## TypeError: not enough arguments for format string
print s
 
s = "Ceci est un %s" % "test", "idiot"
print s
## ('Ceci est un test', 'idiot')
 
s = "Ceci est un %s %s" % ("test", "idiot")
print s
## Ceci est un test idiot

Télécharger le code source de ce tuto

flattr this!

Nan mais c’est #old ça

jeudi 21 février 2013 à 10:39

Régulièrement je poste des trucs que des gens ont déjà vu, et PoliceAuxFrontières, y a toujours un gros lourd dans le lot, souvent sur Twitter d’ailleurs, pour dire que c’est #old.

Quand quelqu’un joue la modération en disant que oh, hein, hey, l’agresseur se défend avec des arguments super massues tels que :

Ça a fait un peu le buzz quand ça été annoncé donc oui c’est old, 8 mois c’est beaucoup.

Oui, on me l’a sortie celle là.

Je résume.

Quand ça fait du buzz, c’est intéressant et on peut en parler (indépendamment de ses qualités intrinsèques), et après, on peut plus (tout ce qui le rendait intéressant a disparu). 8 mois, c’est tellement vieux putain. C’est au moins, ouah, il y a une demi saison de The Big Bang Theory.

À l’époque j’étais une personne complètement différente. J’ai changé maintenant. Le nouveau moi, plus mature, plus homme. Otez de ma vue ce meme de chaton qui fait LOL, c’est so last year, maintenant il doit faire “tabernacle”. Non, trop tard, ne le twittez pas, c’est déjà passé !

Chère petite masse gluante des internets, vous avez bien conscience que la MAJORITÉ des choses que vous voyez sur le net a déjà été vue ailleurs ? Déjà dans la littérature, le théâtre, le cinéma, la peinture, la science et les groupes de potes à la récré, pour commencer.

Ensuite, que quelque chose ait déjà été vu ne périme pas une info. Ce qui périme une info, c’est qu’elle ne puisse plus servir à personne.

Maintenant, les gens sur imgur, bashfr, lisant des blogs, ou même les gens sur twitters, sont, je le rappelle, une minorité. Bienvenue dans le monde réel, Néo.

Donc si VOUS en avez entendu parler, il y a fort à parier que la majorité de l’espèce humaine n’en a pas encore entendu parler. Mais quand bien même c’est un truc réutilisé, ne faites pas chier le monde. Si ça ne vous intéresse pas, fermez votre gueule, et allez voir ailleurs.

Putain, internet c’est grand, et le reste du Web est à un clic de là. Donc plutôt que de gâcher l’électricité, le temps CPU, l’usure des cables et du clavier nécessaire à faire un commentaire bouseux qui met en avant que vous avez vu le truc déjà une fois, cassez-vous.

Y a déjà assez de bruit sur le net entre les “first”, “so gayyyy” et autres posts de remplissage. Donc votre #old, on s’en branle :

Merci

flattr this!

‘Redis’ object has no attribute ‘connection’

mercredi 20 février 2013 à 12:10

Solution très conne à un problème très con.

pip install --upgrade redis django-redis-cache django-redis-sessions

L’api de la lib Python Redis a changé, et si vous utilisez des libs qui en dépendent, certains seront plus à jour. C’est balot, mais ça nous a turlupiné.

flattr this!

Tout ce que vous vouliez savoir sur les URLs Web, sans jamais oser le demander

mardi 19 février 2013 à 13:49

Tout ce que vous vouliez savoir sur les URLs Web, sans jamais oser le demander

Tuto plus long que prévu, donc un peu de zizik:

De plus en plus de gens se servent des URLs, et de moins en moins savent ce qu’elles veulent dire. Cela inclut des développeurs.

Avec les sites en Ajax et les navigateurs qui cachent la moitié des adresses, ça va pas s’arranger.

Principe de base du fonctionnement d’une URL

URL veut dire Uniform Ressource Locator, c’est à dire qu’il s’agit d’une manière de localiser quelque chose sur un réseau. Normalement, à une URL correspond une ressource, c’est à dire que si vous utilisez la même URL deux fois, vous devez accéder deux fois à la même information.

Bref, en gros une URL est une adresse unique, avec un format standardisé.

L’URL la plus simple qu’on puisse rencontrer est celle-ci :

http://monsite.com/

Elle contient quatre parties :

Découpage d'une URI

Ce ne sont pas les termes officiels, je vulgarise mon bon.

Le procotole

Il indique sur quel type de réseau et dans quel langage les informations seront. Il n’y a pas moyen de “deviner” ce que ça sera. Il faut savoir à quel nom de protocole correspond quoi. Le plus connu est le protocole HTTP, c’est celui que nous utilisons pour transmettre des pages Web non sécurisées. Mais il en existe bien d’autres : ftp, files, irc… Si on n’a pas le bon protocole, on ne peut pas lire l’information.

Aujourd’hui les logiciels (comme les navigateurs Web) masquent souvent le protocole, car on utilise souvent les mêmes : ftp pour un client FTP, http / https pour une navigateur, git pour un client git, etc.

Néanmoins sur un logiciel qui gère plusieurs protocoles (encore une fois comme un navigateur Web), il lui faut absolument connaitre le protocole, sinon il ne saura pas quoi faire de l’URL. Une URL avec le protocole FTP ne se traite pas comme une URL avec le protocole HTTP. Le fait que le logiciel masque le protocole ne veut donc pas dire qu’il a disparu, jusque qu’il est caché à l’utilisateur pour les cas les plus courants. Mais il est toujours là, il est indispensable.

Le contexte

Pour lire une URL, on a besoin d’un point de départ. L’URL est en effet un chemin qui part d’un point. Le début de l’URL donne cette information.

// signifie qu’on est dans une URL absolue (nous verrons ce que ça veut dire plus bas), et que le point de départ est le “lieu” qu’on va spécifier juste après.

Le lieu

Le “lieu” entre guillemet car il n’y a pas de notion spatiale. C’est un nom qui permet à la machine de savoir sur quelle partie du réseau se situe la ressource.

Le chemin

Après le “lieu”, on précise un chemin vers la ressource, c’est à dire comment, en partant du point de départ, on va aller vers l’information. Le chemin le plus simple est “/“, c’est à dire “au tout début”. Nous verrons les chemins plus en détail.

Informations implicites

Souvent on voit (particulièrement sur le Web), des URLs ainsi:

Ce ne sont pas des URLs complètes. Mais comme l’usage le plus courant pour une URL de nos jours est une URL Web, et qu’un site Web a généralement sa page d’accueil sur “/“, et qu’il est accessible en HTTP, on fait l’amalgame. Notez bien que ce sont des suppositions (justifiées, la plupart du temps), mais que ça peut tout à fait ne pas marcher.

Les noms de domaine

Les URLs pour le Web, qui sont celles qui vont le plus nous intéresser aujourd’hui, utilisent comme indicateur de “lieu” sur le réseau un nom de domaine :

Un nom de domaine dans une URL

Le nom de domaine tel que vous le voyez ici est spécifique à une partie d'internet.

Tous les “lieux” de toutes les URLs ne sont pas des noms de domaines, mais sur le Web, c’est ce que l’on utilise.

Un nom de domaine est en fait un surnom qu’on a donné à une une adresse IP sur le Web. L’adresse IP, c’est un tas de chiffres qui permettent à la machines d’en retrouver une autre.

Par exemple, en ce moment Google se trouve à l’adresse : http://74.125.230.247. Mais ce n’est pas très pratique pour les humains. On a donc des noms des domaine, des “surnoms”, pour ces adresses IP.

Google.fr est le nom de domaine, qui, en ce moment, est le “surnom” de 74.125.230.247. Quand vous demandez à votre navigateur Web d’aller sur google.fr, il va chercher quelle adresse IP se cache derrière ce nom de domaine (via une autre machine qu’on appelle un DNS), et il va aller chercher l’information sur 74.125.230.247 pour vous.

Quand on a une adresse :

http://google.fr/

Cela veut dire :

Mais les noms de domaines, eux-même, sont découpés en plusieurs morceaux :

Détail du découpage d'un nom de domaine

Un nom de domaine se lit de droit à gauche, comme en arabe

Tout à droite, il y a le TLD (Top Level Domain). C’est un nom de domaine court, qui représente l’entité juridique qui gère cette partie du réseau. Généralement c’est un pays, mais pas forcément (.eu, .com, .net, .org, ne représentent pas des pays). Aujourd’hui, le TLD ne veut plus dire grand chose et on le choisit surtout soit pour sa sonorité, soit pour sa popularité, soit par les règles qui lui sont liés. En effet, il y a des obligations légales liées à chaque TLD pour la personne qui possède le nom de domaine.

Aucune personne ne possède de TLD, ils sont gérés par des entités juridiques, généralement des États.

Ensuite, plus à gauche, il y a le nom de domaine de deuxième niveau. C’est généralement ce qu’on considère être le “nom” du site Web. C’est le Google de Google.fr, le sametmax de sametmax.com, etc.

C’est aussi le nom que le propriétaire du site loue en payant un loyer régulier pour garder le droit d’avoir ce “surnom” pour sa machine.

Ensuite, on peut rajouter autant de “sous-domaines” que l’on veut :

toto.sametmax.com
supercalifragilisticexpialidocious.toto.sametmax.com

Tout ce qui est le plus à gauche du ndd de 2e niveau est un sous-domaine. Ils sont rajoutés par le propriétaire du site. On peut en faire autant qu’on veut. Les imbriquer autant qu’on veut. Les webmasters les utilisent surtout pour une question d’organisation.

Donc mail.opera.com se lit : site sur le TLD .com, qui s’appelle “opera“, et nous sommes sur la sous-partie “mail” du site d’opera.

Le sous-domaine le plus célèbre est “www” comme dans http://www.afpy.org/. “www” est juste une vieille convention. C’est un sous-domaine comme un autre. Ça ne veut rien dire en particulier, juste qu’on est dans la partie “www” du site en question.

On se sert souvent des sous-domaines pour faire des sous-sites ou des services annexes / connexes : les apis, les serveurs de contenu statiques (images, fichiers), les serveurs de streaming, etc.

Attention à une exception notable !

Certaines entités n’ont pas donné accès au domaine de second niveau à la population. C’est le cas de l’Angleterre. Si vous voulez achetez un nom de domaine en .uk, vous ne pouvez pas. Vous pouvez uniquement acheter un sous-domaine du domaine de second niveau “co“. Ce qui explique que les sites Web britanniques ont des adresses du genre : http://www.bbc.co.uk/.

Chemins dans les Urls

On a vu le point de départ, mais on a pas vu ensuite le chemin. Quand on est sur //nomdedomaine.tld, // signifie qu’on part de ce site, mais ensuite, on va où pour trouver l’info ?

C’est le chemin qui donne cette indication.

Le chemin est une succession de noms et de “/“. Un slash veut juste dire “dans”.

Si vous avez :

sametmax.com/

Ça veut dire “dans sametmax.com”.

Si vous avez :

http://sametmax.com/contactez-nous/

Ça veut dire “dans sametmax.com” puis “dans contactez-nous”.

On peut avoir des chemins très complexes comme :

http://cdn.unsite.com/media/images/d540/4da2/af28/758f8336-d540-4da2-af28-dc858d2fa1a6/75x75.jpg

Qui veut dire que la ressource “75x75.jpg” (qui est ici une image) est dans “758f8336-d540-4da2-af28-dc858d2fa1a6” qui est dans “af28” qui est dans “4da2” qui est dans “d540” qui est dans “images” qui est dans “media” sur le site cdn.unsite.com.

Ce qu’est réellement “d540” ou “758f8336-d540-4da2-af28-dc858d2fa1a6” derrière ? Peut être un dossier. Peut être une entrée dans une base de données. Peut être juste une configuration dans un fichier. Vous ne pouvez pas savoir. Tout ce que vous pouvez savoir c’est que ceci contient cela.

Les URLs relatives

Cette partie est plus intéressante pour les développeur de site Web.

Quand vous créez des liens dans votre site, vers d’autres parties de votre site, vous n’avez pas besoin d’écrire toute l’URL.

Quand on ne part de nul part, on a besoin d’une URL dite “absolue”, c’est à dire qu’elle vous donne le point de départ.

C’est le but de “//lieu”.

Mais quand votre client (par exemple le navigateur Web), sait d’où vous partez, on peut utiliser des URLs relatives, c’est à dire des URLS qui peuvent omettre des informations.

Par exemple, si l’utilisateur est DEJA sur http://sametmax.com/ et que vous voulez lui faire un lien qui va vers http://sametmax.com/tag/python/, vous pouvez faire ceci:

href="//sametmax.com/tag/python/"

Vous omettez le protocole. C’est tout à fait valide. Si le site est en HTTPS, ça restera en HTTPS. Si il est en HTTP, ça restera en HTTP.

Vous pouvez aussi carrément faire ceci :

href="/tag/python/"

Vous ommettez le nom de domaine.

Une adresse très courante sur le logo d’un site :

href="/"

Ça revient à la page d’acceuil.

Il existe deux autres notations pour les URLS relatives :

Le premier est très utilisé dans les formulaires :

<form action=".">

Puisque la plupart du temps, on veut envoyer les informations sur la page en cours.

Le second est utilisé pour remonter dans l’arborescence du site sans se soucier de là où on est. Par exemple si on est sur :

http://sametmax.com/cours-et-tutos/les-articles-pour-apprendre-python-dans-le-bon-ordre/

Alors :

href="http://sametmax.com/cours-et-tutos/les-articles-pour-apprendre-python-dans-le-bon-ordre/../"

Ou plus simplement :

href=".."

Va vous emmener sur

http://sametmax.com/cours-et-tutos/

Et on peut les cumuler :

href="http://sametmax.com/cours-et-tutos/les-articles-pour-apprendre-python-dans-le-bon-ordre/../../"

Ou

href="../../"

Va vous emmener sur la page d’accueil (/).

Paramètres et ancres

Si les URLs sont si puissantes, c’est parce qu’elle sont très complètes.

Notamment, on peut aussi spécifier que l’on vise une partie d’une ressource en particulier, avec ce qu’on appelle l’ancre (ou hash en anglais).

Par exemple, sur une page Web, le hash permet de dire que l’URL vise une partie de la page Web :

https://en.wikipedia.org/wiki/Hashish#History

Le hash, c’est tout ce qu’il y à partir du “#“. Il se met APRÈS le chemin. Ici, c’est “#History“. Si vous cliquez sur le lien, vous verrez que vous arriverez directement à la partie “History” de la page.

Autre chose : on peut passer des paramètres à une URL. Les paramètres se mettent APRÈS le chemin mais AVANT le hash (qu’il existe ou non), et consiste en tout ce qu’il y a à partir du “?” :

https://duckduckgo.com/?q=choucroute

Ici, les paramètres sont q=choucroute.

Les paramètres servent à passer des informations supplémentaires avec l’URL, pour quelque chose qui n’a pas été prévu par le format URL. Dans notre exemple, il permet de spécifier à DuckDuck go qu’on cherche le mot “choucroute”.

Les paramètres ne sont pas standardisés, ils sont différents pour chaque service qui expose ses ressources via une URL, et donc dans le cas du Web, pour chaque site.

On peut lire les paramètres ainsi :

?nom=valeur&autre_param=autre_valeur&troisieme_param=valeur

Chaque paramètre a un nom et sa valeur, et chaque couple “nom” / “valeur” est séparé par le signe “&“.

Il est courant d’appeler cette partie de l’URL une “query string”.

La totale

On peut tout mélanger bien sûr !

Exemple :

http://www.siteduzero.com/forum/sujet/entrainez-vous-sur-le-langage-python-54161?page=2#message-5579148

En fait on peut même mélanger beaucoup plus. Les urls peuvent contenir des noms d’utilisateur, des mots de passe et tout un tas d’autres informations.

Du fait de cette richesse, on utilise généralement des bibliothèques dédiées pour les analyser. Par exemple en Python:

>>> from urlparse import urlparse
>>> url = urlparse('http://www.siteduzero.com/forum/sujet/entrainez-vous-sur-le-langage-python-54161?page=2#message-5579148')
>>> url.path
'/forum/sujet/entrainez-vous-sur-le-langage-python-54161'
>>> url.query
'page=2'
>>> url.fragment # hash
'message-5579148'
>>> url.netloc # nom de domaine
'www.siteduzero.com'
>>> url.scheme # protocole
'http'

URL, URI et URN

Les puristes vont vous emmerder avec la notion d’URI et d’URN.

Pour faire simple :

Une URL est une URI.
Une URN est une URI.

Personne ne se sert des URN à part quelques obscurs programmeurs Java et XML (ce qui est souvent la même chose).

Vous utilisez des URLs. Le monde entier utilise des URLs. Le Web marche avec des URLs.

Les URIs et URNs peuvent aller se faire foutre.

La notion de ressource

Une URL identifie “où” est une “ressource”.

Mais c’est où “où” ? Et c’est quoi une “ressource” ?

C’est une très bonne question, et qui n’a pas de bonne réponse.

Où, ça peut être n’importe où. Les “ressources” (sur le Web, des pages Web le plus souvent), peuvent être sur une machine quelque part, ou ne pas exister, et être juste créées quand vous les demandez.

C’est un concept abstrait. On IMAGINE qu’il y a “un truc” à “un endroit”. Mais ni le truc, ni l’endroit n’existent. C’est une convention pour que vous et moi, quand on parle d’une vidéo, une page Web, un document PDF, un rapport… On puisse parler de la même chose. On utilise donc l’URL, qui est l’”endroit” où ça se trouve, pour en parler. Parce que c’est la seule manière d’être à peu prêt certain qu’on parle de la même chose.

En pratique, une URL peut pointer sur une ressource de n’importe quelle nature :

C’est le serveur (dans notre cas) le site qui décide ce que signifie “où” et ce que sera “quoi”. Mais au final, sur un réseau TOUT est URL. Absolument tout.

En fait, derrière, la ressource peut très bien changer (résultat du moteur de recherche, page de profile, etc). Donc une ressource, c’est un truc mouvant.


PS: putain quand je me suis lancé dans la rédaction de l’article, je m’attendais pas à passer la matinée dessus. C’est dingue tout ce qu’il y a à savoir sur une si petite notion. Toute l’informatique est comme ça : c’est pas compliqué, mais y a tellement de trucs à savoir. Faut pas s’étonner que les non geeks ont de plus en plus de mal à suivre. Ils ont autre chose à foutre que de lire 1500 pages de manuel pour envoyer une photo de leur cul à leur voisin.

flattr this!

Pourquoi il faut spécifier l’exception qu’on gère

lundi 18 février 2013 à 15:33

On utilise beaucoup la gestion des exceptions en Python, mais le langage permet de faire des trucs apocryphes comme:

try:
    # un code qui va chier des bulles
except: # je les attrappe tous, comme les pokemons
    pass

Ceci n’est ni plus ni moins que l’équivalent de @ pour silent les erreurs en PHP.

C’est caca.

Et la raison pour laquelle j’oppose une aversion si mesurée mais néanmoins portée par des arguments forts, c’est que c’est le grand kiff de Max d’en mettre partout, et que la semaine dernière ça lui a valu un debuggage en prod.

Depuis le dernier déploiement, les logs d’un des workers d’un serveur d’encoding affichaient en boucle :

“Error accessing Database, check your connexion”

Du coup Max a cherché d’ou venait ce problème de database par les cas usuels : port ? Permission ? Network ? Mise à jour de lib de l’ORM ? Daemonisation ?

Le snippet qui provoquait ce message était (en simplifié) :

try:
    new_model = Model.objects.create(params)
except:
    self.logger.error("Error accessing Database, check your connexion")
    # + trucs pour gérer le bouzin

La raison du try / except est que parfois, sur ce serveur, et seulement sur ce serveur, la connection avec la DB distante droppait. Bug aléatoire ou de config ? Parfois il est plus simple de ne pas résoudre le problème et laisser le truc foirer de temps en temps, et juste garder un recovery. Ça évite un spécial case pour un seul serveur, et ça évite de migrer le serveur.

Sauf que ce try / except était générique, et il attrapait tout, même les rhumes.

Je lui ai demandé de virer le try / except pour voir ce qui se passait vraiment, et…

raise MissingDependency("The 'solr' backend requires the installation of 'pysolr'. Please refer to the documentation.")

Le truc qui n’a RIEN à voir avec la base de données. Solr est notre moteur de recherche, et c’est juste qu’à la création d’un objet de modèle Django, un signal est propagé pour mettre à jour l’index de Solr. Le nouveau déploiement était incomplet : il manquait une lib. La lib était importée à ce moment là, ça levait une exception, qui était attrapée bêtement par le try/except générique.

Bref, le code a été remplacé par

try:
    new_model = Model.objects.create(params)
except DataBaseError:
    self.logger.error("Error accessing Database, check your connexion")
    # + trucs pour gérer le bouzin

Si on l’avait eu depuis le début, l’erreur aurait été apparente tout de suite et rapidement corrigée.

Ne faites JAMAIS de try/except sans préciser l’exception que vous allez gérer. La seule raison pour laquelle cette feature existe, c’est qu’elle est pratique à utiliser dans un shell. En fait, même DataBaseError est trop générique comme Exception si vous voulez vraiment un controle fin.

Notez également qu’un except: pass est rarement une bonne idée. Au moins prenez le temps de logger ce qui se passe dans la clause except. Un bon log, c’est le début du bonheur.

flattr this!