Les deux révisions précédentesRévision précédenteProchaine révision | Révision précédente |
issue134:mon_histoire [2018/07/23 12:44] – auntiee | issue134:mon_histoire [2018/07/25 20:04] (Version actuelle) – andre_domenech |
---|
Je devais décider si je voulais écrire un programme en ligne de commande (CLI) ou avec une interface utilisateur graphique (GUI). Un programme écrit pour CLI est lancé dans un terminal, par exemple grep ou mp3diags alors qu'en GUI, il y a des fenêtres et des icônes, par exemple Audacity ou l'éditeur de texte de Gnome (gedit). | Je devais décider si je voulais écrire un programme en ligne de commande (CLI) ou avec une interface utilisateur graphique (GUI). Un programme écrit pour CLI est lancé dans un terminal, par exemple grep ou mp3diags alors qu'en GUI, il y a des fenêtres et des icônes, par exemple Audacity ou l'éditeur de texte de Gnome (gedit). |
| |
Bien entendu, un programme en GUI est plus sympa et semble le choix préférable. Comme j'ai dit dans l'introduction, j'avais besoin de rafraîchir mes connaissances en programmation et je n'avais aucune expérience dans une environnement graphique Linux/Gnome. Si on y ajoute que ce serait mon premier programme en Python, l'idée de prendre cette voie-là me rendait très sceptique. | Bien entendu, un programme en GUI est plus sympa et semble le choix préférable. Comme j'ai dit dans l'introduction, j'avais besoin de rafraîchir mes connaissances en programmation et je n'avais aucune expérience dans un environnement graphique Linux/Gnome. Si on y ajoute que ce serait mon premier programme en Python, l'idée de prendre cette voie-là me rendait très sceptique. |
| |
**I have also seen that some linux applications are CLI based and then they also have GUI version, which looked like it was using the command based program to do the job. For example some software management application, like the graphical updater, are invoking a terminal command (apt) and then rendering the output in a more friendly way. Thus my decision was made. I was going to write a CLI based program and eventually I’d write a GUI interface on top of it. | **I have also seen that some linux applications are CLI based and then they also have GUI version, which looked like it was using the command based program to do the job. For example some software management application, like the graphical updater, are invoking a terminal command (apt) and then rendering the output in a more friendly way. Thus my decision was made. I was going to write a CLI based program and eventually I’d write a GUI interface on top of it. |
Je l'ai appelé fixrhy en supposant qu'il réparerait quelque chose que rhythmbox ne faisait pas comme je voulais. Je sais que c'est discutable, mais après tout, c'est mon application et je peux lui donner le nom que je veux. | Je l'ai appelé fixrhy en supposant qu'il réparerait quelque chose que rhythmbox ne faisait pas comme je voulais. Je sais que c'est discutable, mais après tout, c'est mon application et je peux lui donner le nom que je veux. |
| |
Étant prêt à commencer mon tout premier programme en Python, j'ai lancé l'éditeur de texte de Gnome qui me semblait plus qu'assez pour la tâche à accomplir. | Étant prêt à commencer mon tout premier programme en Python, j'ai lancé l'éditeur de texte de Gnome qui me semblait plus que suffisant pour la tâche à accomplir. |
| |
**The logic of the program is very simple. As input it requires the name of the artist, the name of the album, the sorting name of the artist and the sorting name of the album. After writing the basic code I added a fifth parameter which I’ll talk about later. The output would be just some confirmation messages, while the real action is actually manipulating the xml file that rhythmbox uses to store its database. The full code of the final version is available here: https://pastebin.com/zBuhmi1y and I would like to go through it not to teach python or programming but to share the logic and its development. I will stop only on significant parts of the program. | **The logic of the program is very simple. As input it requires the name of the artist, the name of the album, the sorting name of the artist and the sorting name of the album. After writing the basic code I added a fifth parameter which I’ll talk about later. The output would be just some confirmation messages, while the real action is actually manipulating the xml file that rhythmbox uses to store its database. The full code of the final version is available here: https://pastebin.com/zBuhmi1y and I would like to go through it not to teach python or programming but to share the logic and its development. I will stop only on significant parts of the program. |
#!/usr/bin/python** | #!/usr/bin/python** |
| |
La logique du programme est très simple. Vous devez renseigner le nom de l'artiste, le nom de l'album, le nom de tri de l'artiste et le nom de tris de album. Après avoir écrit le code de base, j'ai rajouté un cinquième paramètre dont je parlerai plus tard. La sortie serait tout simplement quelques messages de confirmation, tandis que la véritable action manipule en fait le fichier xml où rhythmbox stocke sa base de données. Le code complet de la version finale est disponible ici : https://pastebin.com/zBuhmi1y et je vais vous le présenter, pas pour vous enseigner le Python ou la programmation, mais d'en partager la logique et son développement. Je m'arrêterai uniquement sur les parties significatives du programme. | La logique du programme est très simple. Vous devez renseigner le nom de l'artiste, le nom de l'album, le nom de tri de l'artiste et le nom de tri de l'album. Après avoir écrit le code de base, j'ai rajouté un cinquième paramètre dont je parlerai plus tard. La sortie sera tout simplement quelques messages de confirmation, tandis que la véritable action manipule en fait le fichier xml où rhythmbox stocke sa base de données. Le code complet de la version finale est disponible ici : https://pastebin.com/zBuhmi1y et je vais vous le présenter, pas pour vous enseigner le Python ou la programmation, mais pour en partager la logique et son développement. Je m'arrêterai uniquement sur les parties significatives du programme. |
| |
La ligne 14 est : | La ligne 14 est : |
sys.setdefaultencoding( "UTF-8" )** | sys.setdefaultencoding( "UTF-8" )** |
| |
Techniquement, ceci est nécessaire pour que le code soit exécuter comme programme en Python. Pour ce qui me concerne, c'est la déclaration que je voulais mettre en pratique quelque chose que j'ai apprise dans les pages du magazine Full Circle, tout en sachant que, si j'ai besoin d'aide, une communauté existe qui serait prête à m'aider. J'aurais pu utiliser C (ou C++) que je connaissais déjà, mais cela aurait enlevé un peut de mon plaisir. Apprendre quelque chose de nouveau est toujours un défit et il offre plus d'occasions de faire appel à d'autres et de participer dans la vie de la communauté. Un exemple concret est que j'ai fini par écrire à Greg Walter et à Ronnie Tucker (J'y reviendrai plus tard). | Techniquement, ceci est nécessaire pour que le code soit exécuté comme un programme en Python. Pour ce qui me concerne, c'est la déclaration que je voulais mettre en pratique, quelque chose que j'ai appris dans les pages du magazine Full Circle, tout en sachant que, si j'ai besoin d'aide, une communauté existe qui serait prête à m'aider. J'aurais pu utiliser C (ou C++) que je connaissais déjà, mais cela aurait enlevé un peu de mon plaisir. Apprendre quelque chose de nouveau est toujours un défi et il offre plus d'occasions de faire appel à d'autres et de participer à la vie de la communauté. Un exemple concret est que j'ai fini par écrire à Greg Walter et à Ronnie Tucker (J'y reviendrai plus tard). |
| |
la ligne 18 est : | la ligne 18 est : |
import xml.etree.ElementTree as ET | import xml.etree.ElementTree as ET |
| |
Ceci est nécessaire pour pouvoir utiliser la bibliothèque ElementTree pour analyser les fichiers XML. J'aurais pu le faire moi-même, mais cela aurait fait plus de travail sans bonne raison. Si demain les spécifications XML changent ou évoluent, vous pouvez compter sur la bibliothèque de se mettre à jour en conséquence. Cela signifie qu'il y a de grandes chances que votre code continuera à fonctionner tel quel. C'est pour cette raison-là que, si vous recherchez « python xml » sur Google, ElementTree se trouve à la première place dans la documentation Python officielle. Sacher que je travaillais avec une bibliothèque entièrement prise en charge m'a bien tranquillisé l'esprit. | Ceci est nécessaire pour pouvoir utiliser la bibliothèque ElementTree pour analyser les fichiers XML. J'aurais pu le faire moi-même, mais cela aurait fait plus de travail sans bonne raison. Si demain les spécifications XML changent ou évoluent, vous pouvez compter sur la mise à jour de bibliothèque en conséquence. Cela signifie qu'il y a de grandes chances que votre code continuera à fonctionner tel quel. C'est pour cette raison-là que, si vous recherchez « python xml » sur Google, ElementTree se trouve à la première place dans la documentation Python officielle. Savoir que je travaillais avec une bibliothèque entièrement prise en charge m'a bien tranquillisé l'esprit. |
| |
La ligne 22 est : | La ligne 22 est : |
if len(sys.argv) < 5: | if len(sys.argv) < 5: |
| |
Notez que nous vérifions pour 5, puisque la première valeur est toujours le nom du script (regardez à https://docs.python.org/2/library/sys.html). Les lignes 26 à 30 affichent de l'aide. Je les ai écrites pour rester cohérent avec les programmes typiques sous Linux, bien que, au départ, ce script était principalement pour moi. J'essayais de penser aux autres et de respecter des normes auxquelles tout le monde pouvait adhérer. Continuez et vous verrez que dans les lignes 32 à 35, nous sauvegardons les données saisies et les lignes 37-40 vérifient s'il y a un drapeau supplémentaire « force ». | Notez que nous vérifions pour 5, puisque la première valeur est toujours le nom du script (regardez à https://docs.python.org/2/library/sys.html). Les lignes 26 à 30 affichent de l'aide. Je les ai écrites pour rester cohérent avec les programmes typiques sous Linux, bien que, au départ, ce script était principalement pour moi. J'essayais de penser aux autres et de respecter des normes auxquelles tout le monde pourrait adhérer. Continuez et vous verrez que, dans les lignes 32 à 35, nous sauvegardons les données saisies et les lignes 37-40 vérifient s'il y a un drapeau supplémentaire « force ». |
| |
**Line 42 and 43 looks like debugging lines: | **Line 42 and 43 looks like debugging lines: |
print "Sorting as", sr_alb, "by", sr_art | print "Sorting as", sr_alb, "by", sr_art |
| |
et, en fait, elles l'étaient au départ. Je les ai gardées parce que, à nouveau, je pensais que le lendemain moi (ou quelqu'un d'autre) pourrais écrire un programme GUI par-dessus et qu'elles pourraient aider lors de l'analyse. | et, en fait, elles l'étaient au départ. Je les ai gardées parce que, à nouveau, je pensais que, le lendemain, je (ou quelqu'un d'autre) pourrais écrire un programme GUI par-dessus et qu'elles pourraient aider lors de l'analyse. |
| |
De 45 à 50, nous réglons tout, chargeant la base de données de Rhythmbox dans un arbre (47) et déclarant quelques variables de comptage. | De 45 à 50, nous réglons tout, chargeant la base de données de Rhythmbox dans un arbre (47) et déclarant quelques variables de comptage. |
| |
Le véritable traitement commence à la ligne 52 ou nous parcourons chaque entrée dans l'arbre. Voici une séquence simple de vérifications, s'agit-il d'une chanson ? Est-ce le bon artiste ? Est-ce le bon album ? | Le véritable traitement commence à la ligne 52 ou nous parcourons chaque entrée dans l'arbre. Voici une séquence simple de vérifications. S'agit-il d'une chanson ? Est-ce le bon artiste ? Est-ce le bon album ? |
| |
if entry.attrib == {'type': 'song'}: | if entry.attrib == {'type': 'song'}: |
The rest of the code builds on that, and there is a similar part of the album sort information. The only two points I want to make here are that I put in the code the parameter to choose if to modify existing data or not. Personally I would always change it, but I wanted to write a program that eventually could be used by others, maybe with different needs. Also note that since I couldn’t change the element if existing I destroy and create a new one (68-70). Most of the print commands are there for debug originally and then to be used by GUI as I said before about line 42/43.** | The rest of the code builds on that, and there is a similar part of the album sort information. The only two points I want to make here are that I put in the code the parameter to choose if to modify existing data or not. Personally I would always change it, but I wanted to write a program that eventually could be used by others, maybe with different needs. Also note that since I couldn’t change the element if existing I destroy and create a new one (68-70). Most of the print commands are there for debug originally and then to be used by GUI as I said before about line 42/43.** |
| |
À partir de la ligne 58, nous vérifions si l'information de tri de l'artiste existe déjà, parce que, si le champ est manquant, il faut le créer à nouveau (60) et s'il y est déjà, nous devons le changer (ou le laisser tel quel). Dans le premier cas, nous ne pourrions pas modifier quelque chose qui n'existe pas, et dans le dernier, nous ne devrions pas créer quelque chose qui est déjà présente. | À partir de la ligne 58, nous vérifions si l'information de tri de l'artiste existe déjà, parce que, si le champ est manquant, il faut le créer à nouveau (60) et s'il y est déjà, nous devons le changer (ou le laisser tel quel). Dans le premier cas, nous ne pourrions pas modifier quelque chose qui n'existe pas, et dans le dernier, nous ne devrions pas créer quelque chose qui est déjà présent. |
| |
Le reste du code s'y appuie et il y a une partie similaire pour les informations de tri de l'album. Autrement dit, j'ai mis dans le code le paramètre nécessaire pour choisir si on modifie des données existantes ou pas. Personnellement, je le changerais toujours, mais je voulais écrire un programme qui pourrait finalement être utilisé par d'autres, peut-être avec des besoins différents. Il faut également noter que, puisque je ne pourrais pas changer l'élément s'il existe, je le détruis et j'en crée un nouveau (68-70). La plupart des commandes print était là au départ pour le débogage, puis pour être utiliser par la GUI, comme j'ai dit auparavant au sujet des lignes 42/43. | Le reste du code s'appuie dessus et il y a une partie similaire pour les informations de tri de l'album. Autrement dit, j'ai mis dans le code le paramètre nécessaire pour choisir si on modifie des données existantes ou pas. Personnellement, je le changerai toujours, mais je voulais écrire un programme qui pourrait finalement être utilisé par d'autres, peut-être avec des besoins différents. Il faut également noter que, puisque je ne pourrais pas changer l'élément s'il existe, je le détruis et j'en crée un nouveau (68-70). La plupart des commandes print étaient là au départ pour le débogage, puis pour être utilisées par le GUI, comme j'ai dit auparavant au sujet des lignes 42/43. |
| |
**Finally before saving we make a backup copy (always important!): | **Finally before saving we make a backup copy (always important!): |
I am quite happy with my first Python program ever. It does what it says on the tin but there is room for much improvements. Amongst them surely pass the file position as a parameter (like this you should run the script in the folder with the Rhythmbox DB file). The parsing maybe not the most efficient and fast. The naming could be done automatically, for example a clever program could learn that “The Doors” should be “Doors, The” without entering it every single time. And many more, including having a GUI. And that’s where we are heading to...** | I am quite happy with my first Python program ever. It does what it says on the tin but there is room for much improvements. Amongst them surely pass the file position as a parameter (like this you should run the script in the folder with the Rhythmbox DB file). The parsing maybe not the most efficient and fast. The naming could be done automatically, for example a clever program could learn that “The Doors” should be “Doors, The” without entering it every single time. And many more, including having a GUI. And that’s where we are heading to...** |
| |
Enfin, avant de l'enregistrer, nous créer une copie de sauvegarde (toujours important à faire !) : | Enfin, avant de l'enregistrer, nous créons une copie de sauvegarde (toujours important à faire !) : |
| |
shutil.copy2(filename,backup) | shutil.copy2(filename,backup) |
et l'arbre qui est en mémoire depuis si longtemps va dans le fichier. | et l'arbre qui est en mémoire depuis si longtemps va dans le fichier. |
| |
Mon tout premier programme en Python me plaît bien. Il fait ce qu'il est censé faire, mais il y a une marge de progression et il peut être amélioré. Parmi de telles améliorations, on pourrait certainement passer la position du fichier comme un paramètre, car, ainsi, vous devriez exécuter le script dans le dossier contenant le fichier Rhythmbox DB). L'analyse n'est peut-être pas la plus rapide et efficace. Les noms pourraient être attribués automatiquement, par exemple, un programme astucieux pourrait apprendre que « The Doors » devrait être « Doors, The » sans avoir besoin de le saisir chaque fois. Et beaucoup plus encore, y compris une GUI. C'est vers cela que nous nous dirigeons... | Mon tout premier programme en Python me plaît bien. Il fait ce qu'il est censé faire, mais il y a une marge de progression et il peut être amélioré. Parmi de telles améliorations, on pourrait certainement passer la position du fichier comme un paramètre (car, tel qu'il est, vous devrez exécuter le script dans le dossier contenant le fichier Rhythmbox DB). L'analyse n'est peut-être pas la plus rapide et efficace. Les noms pourraient être attribués automatiquement, par exemple, un programme astucieux pourrait apprendre que « The Doors » devrait être « Doors, The » sans avoir besoin de le saisir chaque fois. Et beaucoup plus encore, y compris un GUI. C'est vers cela que nous nous dirigeons... |
| |
| |
| |