pyxshell (à prononcer comme vous pouvez) est un module Python qui permet d’enchaîner des fonctions de traitement de flux avec un opérateur « tube » — pipe, en anglais — (|
) , de la même manière qu’avec un shell.
Si — comme moi — vous devez régulièrement analyser à la main des données textuelles diversement structurées sous différents environnements. Si vous affectionnez la ligne de commande sans raffoler de la syntaxe de Bash, vous apprécierez d’avoir tout sous la main à côté de vos outils Python favoris.
Par exemple :
>>> out=[]
>>> (random.randint(0,2) for i in range(10)) | map(lambda x: ["Oui ","nous sommes ","tous différents "][x]) | sort | uniq | tee(sys.stdout) > out
Oui tous différents nous sommes
>>> print(out)
['Oui ', 'tous différents ', 'nous sommes ']
Dit autrement, pyxshell permet d’appeler séquentiellement des générateurs sur des structures de données itérables avec une notation infixée. Il descend du ciel avec un ensemble de fonctions qui rappellent celles de la pile GNU, principalement pour traiter des versets textuels ligne par ligne.
Le module permet une redirection des flux vers des fichiers et/ou des variables à l’aide des vénérables opérateurs >
et >>
. Il permet également d’étendre l’utilisation des tubes à vos glorieuses fonctions, à l’aide d’un décorateur consacré : @pipe
. Il dispose en sus d’augustes opérateurs permettant de combiner des flux (avec +
) ou d’en faire le produit cartésien de leurs bienheureux éléments (avec *
).
pyxshell vous est révélé sous la « (Un)license ».
D’autres exemples tirés des écritures :
>>> import sys
>>> from pyxshell.common import *
>>> list( ['Vous', 'êtes', 'tous','des','individus'] | grep(r'[aeo]') )
['Vous', 'êtes', 'tous', 'des']
>>> ["Je dis que vous êtes le Messie","Et je m'y connais","J'en ai suivi un paquet"] | map(lambda x: "— "+x+"\n") | grep("'") | cut([-2,-1]) | traverse | glue > sys.stdout
m'y connais un paquet
Pour les mécréants qui voudraient utiliser leurs commandes shell de la même façon, depuis un interpréteur, mais sans avoir à utiliser des ré‐implémentations en pur Python, le module Plumbum leur conviendra mieux.
Aller plus loin
- Projet github (153 clics)
- Documentation web (114 clics)
# Joli!
Posté par gawel (site web personnel) . Évalué à 2.
Dans la même idée, j'ai crée https://chut.readthedocs.org/en/latest/ Qui est grosso modo un wrapper à subprocess qui permet de lancer des commandes shell de façon pythonique et d'utiliser les pipe unix, aussi de facon pythonique.
Ca se recoupe un peu. Sauf que pyxshell a fait le choix de manipuler du python, et chut de laisser faire les outils système.
En tout cas, j'aime l'api :)
[^] # Re: Joli!
Posté par nojhan (site web personnel, Mastodon) . Évalué à 5.
Comme dit dans la dépêche, Plumbum fait la même chose que chut, mais par dessus le module sh, qui utilise un hack très élégant pour l'import des commandes shell sous la forme de fonction. L'API est uber-cool, tu peux appeler les commandes sans même voir que c'est de l'appel système :
Tu devrais regarder leur code pour simplifier l'appel de tes commandes dans chut ;-)
[^] # Re: Joli!
Posté par gawel (site web personnel) . Évalué à 3.
Oui, ça marche pareil. Je supporte aussi from chut import * qui importe les commandes "courantes":
https://chut.readthedocs.org/en/latest/basics.html#about-imports
L'autre gros avantage de chut, c'est de pouvoir générer des scripts standalone:
https://chut.readthedocs.org/en/latest/chutify.html
Par exemple j'ai réécris ssh-copy-id:
https://github.com/gawel/chut/blob/master/docs/_static/binaries/ssh-copy-id
Tu choppes le script, le rends executable, et ça marche. Quelque soit la version de python installée (py2.6+)
Ca permet d'utiliser ton script sans avoir a faire un virtualenv ou installer quoique ce soit en plus.
[^] # Re: Joli!
Posté par nojhan (site web personnel, Mastodon) . Évalué à 3.
Et si on fusionnait les deux ? J'aimerais assez avoir le choix de l'origine des commandes utilisées (système ou python).
Par exemple, on aurait le choix d'utiliser
from chut.sys import *
(commandes dispo sur le système) oufrom chut.cmd import *
(réimplémentations pure python).# Coquille
Posté par bastien (site web personnel) . Évalué à 1.
s/prononcez/prononcer
[^] # Re: Coquille
Posté par Benoît Sibaud (site web personnel) . Évalué à 2.
Corrigé, merci.
# Lazy ?
Posté par chimrod (site web personnel) . Évalué à 2.
Je n'ai pas vu dans la doc si c'étais lazy ou non (c'est à dire, comme dans vrai pipe unix, attend que la sortie soit traitée avant de prendre la prochaine entrée).
En tout cas l'utilisation du | pour traiter les données en séquence est vraiment bien trouvée, ça fait partie des choses qui changent la manière dont on écrit le code…
[^] # Re: Lazy ?
Posté par nojhan (site web personnel, Mastodon) . Évalué à 2.
Les commandes sont implémentées comme des générateurs (cf. la doc sur
yield
), donc la chaîne complète forme une fonction, qui s'exécute en entier tant que l'itérable passé a qqchose à envoyer (et qu'il n'y a que des générateurs dans la séquence). Donc, sur des traitements long, tu verras les lignes s'afficher au fur et à mesure.Dans l'exemple suivant, la fonction
sleep
ne fait qu'attendre avant de passer le prochain item, et les chiffres s'affichent bien au fur et à mesure :[^] # Re: Lazy ?
Posté par nojhan (site web personnel, Mastodon) . Évalué à 1.
Du coup j'ai rajouté une commande
sleep
:-)[^] # Re: Lazy ?
Posté par THE_ALF_ . Évalué à 2.
Est-ce fondamentalement différent de faire:
plutôt que:
La deuxième est plus "pythonesque", et demanderait de créer une classe de donnée possédant les différentes opérations que l'on désire piper, plutôt que de créer des fonction indépendantes qui soient "pipables".
[^] # Re: Lazy ?
Posté par chimrod (site web personnel) . Évalué à 3.
En fait, si on prend l'exemple des listes donné dans la dépêche, la syntaxe en pipe est plutôt équivalente à :
et là, la différence est claire, les pipes sont beaucoup plus lisibles pour moi…
[^] # Re: Lazy ?
Posté par miun . Évalué à 6.
Nom de Zeus, nous avons ressuscité le LISP!!!!
[^] # Re: Lazy ?
Posté par MsieurHappy . Évalué à 1. Dernière modification le 17 janvier 2013 à 22:45.
Une macro de rien du tout, et hop, une épine ôtée du pied:
[^] # Re: Lazy ?
Posté par nojhan (site web personnel, Mastodon) . Évalué à 7.
Je ne sais pas si vous vous en rendez compte, mais c'est un vieux troll, qui a eu ses beaux jours à l'arrivée de la POO.
De fait, les différentes syntaxes sont équivalentes, mais il y en a d'autres, aussi… quelques exemples :
Personnellement, j'ai l'habitude de traiter les flux en shell, et j'aime bien que le traitement se lise de gauche à droite, sans fioritures. D'ailleurs, je me garderais bien de décréter que tel ou tel style est le plus pythonique dans ce cas précis. le fait est que l'infixé avec pipe me parait à la fois plus concis, plus intuitive et est plus simple à implémenter. CQFD.
[^] # Re: Lazy ?
Posté par THE_ALF_ . Évalué à 1.
En fait, pour voir les pipes comme plus pythonique, il faut comprendre le | comme un opérateur. Or a | b est équivalent à a.__or__(b). On peut donc facilement définir les pipes par:
Ce qui peut être utilisé ainsi:
Intéressant :-)
[^] # Re: Lazy ?
Posté par THE_ALF_ . Évalué à 2.
Il fallait bien sur lire:
[^] # Re: Lazy ?
Posté par reno . Évalué à 2.
Une chose que je note: il y a 3 styles qui sont "cohérent":le "style shell infixé" (se lit de gauche à droite) et lex "style shell préfixé/infixé" (se lisent de droite à gauche), les autres c'est le bazar..
Le premier a l'avantage pour nous Français d'être dans l'ordre "normal" mais l'inconvénient que 'var' doit soit existé déjà soit être déclarée automagiquement, autrement on se retrouve avec une notation un peu bizarre:
"op1 | op2 > var res:Result".
Le style fonctionnel préfixé est un peu lourd avec les parenthèses(*), le infixé est pas mal, mais le '$' ne donne pas le sens de lecture donc on pourrait avoir:
var <- op3 <- op2 <- arg op1 <- data
L'espace pour séparer les arguments d'une fonction c'est élégants pour les lignes courtes mais difficile a lire quand ça devient complexe:
var <- op3 <- op2(arg, op1 data)
C'est quoi le nom du style suivant:
var res <- op3 <- op2(arg) <- op1 <- data
WTFFunc?
*: par contre l'ordre dans l'exemple me parait incorrecte ce serait plutôt
var := op3(op2(arg,op1(data)))
[^] # Re: Lazy ?
Posté par nojhan (site web personnel, Mastodon) . Évalué à 2.
WTFOO : What The Fuck Object Oriented. C'est une vanne sur la lourdeur syntaxique du C++.
Pour des exemples d'opérateur
$
, voir le langage fonctionnel Haskell.Je me garderais bien de donner un avis tranché sur l'élégance, quant à moi :-)
[^] # Re: Lazy ?
Posté par steph1978 . Évalué à 4.
De ce que je comprends:
dans
il y a 3 threads qui traitent les données, en parallèle, au fur et à mesure qu'elle sont disponible.
dans
il y a une thread qui traite les données, opération par opération, par ensemble complet.
Si c'est bien le cas, l'utilisation des ressources CPU+RAM est totalement différente.
Me trompe-je ?
[^] # Re: Lazy ?
Posté par Michaël (site web personnel) . Évalué à 2.
C'est quand même pas une idée très originale, si?
Si tu utilises un langage de programmation fonctionnelle, pas trop, puisque l'opérateur de pipe est un opérateur de composition de fonctions (avec un sens de lecture inversé).
Cf. par exemple la fonction Shell.call de la bibliothèque OCamlnet: http://projects.camlcity.org/projects/dl/ocamlnet-3.6.3/doc/html-main/Shell.html
[^] # Re: Lazy ?
Posté par chimrod (site web personnel) . Évalué à 2.
J'ai pris l'habitude d'utiliser le
|>
de batteries qui permet de composer les fonctions de cette manière.Par contre il faut reconnaître que l'on ne voit pas souvent de composition de fonction dans les langages non fonctionnels (ok, python est un peu à part), et c'est dommage. C'est dans ce sens ou je dis que ça change la manière d'écrire le code, on change de paradigme : on n'est plus en train d'appliquer une méthode à objet, mais on prend un objet dans un contexte, et on lui applique une série de traitement pour le transformer en un autre objet.
Bon je m'arrête là car ça n'est pas le sujet de la dépêche, et l'on parle de la même chose…
# Licence
Posté par 🚲 Tanguy Ortolo (site web personnel) . Évalué à 4.
Il n'est pas possible en France de placer une œuvre dans le domaine public, mais si tu veux t'en approcher autant que possible, la CC0 serait peut-être plus appropriée.
https://creativecommons.org/choose/zero/
[^] # Re: Licence
Posté par gnuzer (site web personnel) . Évalué à 6.
Quand on dit « en France », on parle de quoi exactement ? De la nationalité de l'auteur ? Du lieu de résidence de l'auteur ? Du lieu où a été créée l'œuvre ? Du lieu où celle-ci a été publiée (en l'occurrence le serveur de github, USA) ?
[^] # Re: Licence
Posté par DerekSagan . Évalué à 2.
Dans les cas où la loi française s'applique.
Je pense (mais je ne suis pas juriste) qu'il faut et qu'il suffit qu'une partie significative du processus de création de l'œuvre de l'esprit (= le développement) aie lieu en France. Ça inclut les DOM/TOM, les eaux territoriales et les ambassades et consulats.
La nationalité de l'auteur n'a je pense aucune incidence, pas plus que sa résidence (sauf si c'est le lieu de création) ou les différents lieux, moyens et intermédiaires de publication.
En même temps pour du logiciel, la différence entre CC0, domaine public ou MIT n'est pas hyper flagrante dans ses effets.
[^] # Re: Licence
Posté par Michaël (site web personnel) . Évalué à 2.
Non pas du tout. Au regard du droit français ou européen, il faut écrire dans le contrat de licence quel droit s'applique. La GPL ne le fait pas, ceci est présenté comme une vulnérabilité de la licence par les juristes qui ont concocté les licences CeCILL.
http://www.cecill.info/faq.fr.html#international
[^] # Re: Licence
Posté par DerekSagan . Évalué à 1.
On peut préciser une juridiction dans un contrat, c'est d'ailleurs exactement ce que dit le lien que tu cites.
Et je me permets de remarquer que la question portait sur le domaine public, lequel ne fait justement pas l'objet de contrat, ce qui laisse peu d'endroit ou écrire une clause d'attribution de compétence…
[^] # Re: Licence
Posté par laurentb (site web personnel) . Évalué à 1.
Cependant ce paragraphe seul a le même effet qu'une licence BSD/MIT/etc.
Du coup, je trouve ça plutôt intéressant, même dans un pays où le reste n'est pas possible. Cela semble voulu : http://ar.to/2010/01/dissecting-the-unlicense
# Amis lusitaniens…
Posté par liberforce (site web personnel) . Évalué à 1. Dernière modification le 16 janvier 2013 à 18:47.
Un bel exemple de projet made in Portugal !
# pypi
Posté par laurentb (site web personnel) . Évalué à 2.
La documentation mentionne pypi et pip, mais je ne vois rien sur https://pypi.python.org/pypi/pyxshell.
Sinon, est-ce que comme github l'indique, c'est un fork de calabash ? Pourquoi avoir renommé la chose, c'est devenu incompatible ?
[^] # Re: pypi
Posté par nojhan (site web personnel, Mastodon) . Évalué à 2.
C'est encore la doc de calabash, je n'ai pas encore pris le temps de soumettre ça sur pypi.
C'est un fork plus ou moins compatible (calabash n'est pas en python3, mais sinon c'est juste une extension). Les explications sur le changement de nom sont dans mon premier commit.
En gros, calabash était déjà très googlé et pas très vendeur.
[^] # Re: pypi
Posté par laurentb (site web personnel) . Évalué à 1.
OK. Note que publier sur pypi, c'est
./setup.py sdist register upload
et hop :)Pour packager/installer automatiquement la chose c'est plus pratique qu'un snapshot github.
C'est vrai que j'ai toujours été étonné par le peu de popularité de calabash… j'espère que ça changera avec un nouveau nom, mainteneur et le support de Python 3 !
# Commentaire supprimé
Posté par Anonyme . Évalué à 2.
Ce commentaire a été supprimé par l’équipe de modération.
[^] # Commentaire supprimé
Posté par Anonyme . Évalué à 1.
Ce commentaire a été supprimé par l’équipe de modération.
[^] # Re: À coupler avec pysh ?
Posté par nojhan (site web personnel, Mastodon) . Évalué à 1.
Avec Plumbum, je ne sais pas trop, mais avec chut ou pyxshell, c'est trivial, il suffit d'utiliser map avec une fonction (lambda, par exemple).
Ça devrait être un truc du genre :
# Ajouter un contexte ?
Posté par lolop (site web personnel) . Évalué à 7.
Pour pouvoir écrire:
:-)
Votez les 30 juin et 7 juillet, en connaissance de cause. http://www.pointal.net/VotesDeputesRN
[^] # Re: Ajouter un contexte ?
Posté par lolop (site web personnel) . Évalué à 3.
Ça permettrais des écritures plus simples et sécurisées sur d'autres choses.
Par exemple le changement temporaire de répertoire:
Et quand on sort du bloc, on revient dans le répertoire précédent.
Votez les 30 juin et 7 juillet, en connaissance de cause. http://www.pointal.net/VotesDeputesRN
[^] # Re: Ajouter un contexte ?
Posté par barmic . Évalué à 3.
C'est inspiré de ce que propose fabric ? Une brève histoire de context
Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)
[^] # Re: Ajouter un contexte ?
Posté par lolop (site web personnel) . Évalué à 2.
Non, mais c'est pas étonnant que quelque chose d'aussi évident en Python ait déjà été pensé ailleurs.
Votez les 30 juin et 7 juillet, en connaissance de cause. http://www.pointal.net/VotesDeputesRN
# Switcher à python comme shell
Posté par Thomas Douillard . Évalué à 2.
(ma vie) C'est marrant j'étais en train de me dire que je scriptai de plus en plus en python pour des trucs qui seraient faisable en shell. D'ailleurs j'étais même presque sur le point de tenter d'expérimenter un peu avec ipython comme shell principal, il manque pas grand chose à python pour faire office de shell un peu plus puissant que bash, avec moins d'ésotérisme dans la syntaxe, l'interprétation des variables, la cohérence du langage, la structuration des types …
C'est d'autant plus tentant avec ce genre de projets qui complémentent bien les fonctionnalités d'ipython.
Quelqu'un a des expériences avec ce genre de tentative ?
[^] # Re: Switcher à python comme shell
Posté par dzecniv . Évalué à 1.
C'est aussi mon rêve !
On peut commencer par rester dans le shell et faire plus de choses en python, comme avec the Pyed Piper
https://code.google.com/p/pyp/
puis passer à la console Qt de ipython
http://ipython.org/ipython-doc/stable/interactive/qtconsole.html
elle est pas parfaite du tout pour le shell mais fait plutôt rêver.
[^] # Re: Switcher à python comme shell
Posté par Michaël (site web personnel) . Évalué à 2.
Je te le déconseille fortement.
Je connais très bien la programmation en Bourne shell pourtant mon shell intéractif est TCSH. La raison? Je ne sais pas programmer TCSH, donc je n'écris pas de ligne de commande imbitable.
Si j'ai quelque chose de compliqué à faire j'ouvre mon éditeur et je l´écris, et je le relis. Cela ne prend pas plus de temps et je fais moins de faute parceque mon programme jetable est mieux présenté, colorié et tout. ET c'est plus facile d'insérer une fonction intermédiaire si je décide que mon programme en serait plus facile à écrire — chose que tu ne feras jamais en ligne de commande.
Je te conseille de faire la même chose: si tu adores décrire tes tâches en Python pourquoi le faire dans un interpréteur plutôt que dans un éditeur de texte?
[^] # Re: Switcher à python comme shell
Posté par Thomas Douillard . Évalué à 4.
J'ai assez d'expérience pour savoir quand ça vaut le coup de dégainer l'éditeur de texte ou non, je trouve d'ailleurs avoir tendance à le faire un peu trop : tu fais un script que tu perds du temps à relire voire à génériciser excessivement pour une tâche qui ne mériterait même pas d'être scriptée, c'est presque une tendance dont j'aimerai me débarrasser.
Du coup je suis pas du tout d'accord avec tes arguments. En plus si jamais au cours du codage tu changes d'avis et décide que finalement ce serait mieux de coder le truc, rien qu'en bash il y a un raccourcis pour ouvrir un éditeur de texte sur la commande que tu es en train d'écrire, et si ton shell est dans le même langage que le langage que tu utilises il y a toujours moyen de copier / coller le code. C'est aussi possible de décrire des fonctions simple de manière interractives, d'ailleurs.
[^] # Re: Switcherà pythoncomme shell
Posté par Juke (site web personnel) . Évalué à 2.
Qu'est ce ? Y-a t-il un equivalent pour zsh ?
[^] # Re: Switcherà pythoncomme shell
Posté par Thomas Douillard . Évalué à 2.
Cx Ce pour bash, je sais pas, j'ai trouvé ça sur stackoverflow en googlant à l'instant.
[^] # Re: Switcher à python comme shell
Posté par Michaël (site web personnel) . Évalué à 2.
Ce dont je parle ce n'est ni de généreciser excessivement ni de passer 10 plombes à relire. Seulement, je trouve d'une part que même pour écrire une simple boucle
for
l'éditeur permet d'écrire plus proprement et de faire moins d'erreur; d'autre part que l'idiome classiqueSELECT | EDIT | PROCESS
est plus clair quand on l'écrit avec trois fonctions. Donne un nom à un bloc de code en sh dure 1/2 seconde, surtout si on a déjà les noms.Par exemple pour renommer les fichiers selon un schéma à la noix SELECT utillise find pour trouver les noms des fichiers, EDIT produit des lignes
vieux_nom|nouveau_nom
etPROCESS
renomme les fichiers (IFS).[^] # Re: Switcher à python comme shell
Posté par barmic . Évalué à 4.
Moi ça dépend, j'utilise un fichier uniquement si je veux réutiliser plusieurs fois l'algo. Je crée des commandes relativement complexes (utilisation de boucle, de variables, de fonctions, de l'historique et de substitution de processus) dans mon shell interactif (zsh). C'est généralement un peu moins propre (je me soucie peu de l'affichage tant que moi j'arrive à lire) car ce n'est jamais distribué. C'est très souvent des algo réellement jetables, je ne m'en resert jamais.
Toute fois je suis d'accord pour dire que c'est moin agréable d'éditer ça de manière interactive. bash possède pour ça une parade Ctrl+x Ctrl+e pour ouvrir la commande courante dans un éditeur (
$EDITOR
). Je ne doute pas que zle (le readline de zsh) doit le permettre mais pour le moment je n'ai ni trouvé ni cherché.Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)
[^] # Re: Switcher à python comme shell
Posté par Michaël (site web personnel) . Évalué à 2.
Pour un traitement complexe, meme si je ne m'en sers qu'une fois, j'utilise un fichier. Cela évite de faire des erreurs, et rend l'édition plus facile.
Comme j'utilise TCSH, je ne réfléchis pas. S'il y a un risque de boucle for, j'utilise l'éditeur. Ne pas réfléchir, cela fait gagner du temps. :) (Dans ce cas là bien-sûr!)
Je ne cherche pas à en faire une position de principe: chacun fait au final comme il veut. Pendant longtemps je jouais au Samouraï de la ligne de commande, j'avoue que j'en tirais parfois une petite fierté. Mais un jour sur la ML de FreeBSD j'ai lu le témoignage de quelqu'un présentant le point de vue que je défends aujourd'hui. L'argument que TCSH est une horreur à programmer et que c'est exactement la raison qui en fait le meilleur SHELL intéractif m'a paru saugrenu. Cependant, j'ai essayé et je ne suis jamais revenu en arrière. L'intérêt principal étant d'éviter de se poser la question «éditeur ou pas?».
[^] # Re: Switcher à python comme shell
Posté par Strash . Évalué à 5.
Ben justement ipython te permet de commencer à faire du script interactif en quelques lignes puis si ça commence à devenir trop gros, un simple
%save mon_script 1-num_dernière_ligne
et roule ma poule !Si on a plein de lignes à taper, un petit %edit, ça ouvre ton éditeur favoris, tu tapes, c'est plein de jolies couleurs, tu fermes en sauvegardant, puis ça exécute !
Dans ipython tu peux aussi écrire en tout ce que tu aurais pu écrire sur ton shell, simplement précéder la commande de !
Bref, c'est une habitude à prendre, mais je sais que mon ipython me sert souvent !
[^] # Re: Switcher à python comme shell
Posté par DerekSagan . Évalué à 1.
Les vrais hommes utilisent brainfuck comme shell, pas python.
;-)
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.