Wct, assistant pour l’arborescence des ordinateurs.

Je vous présente dans ce topic l'outil en cours de développement smwct.

Le problème exposé dans ce sujet a été résolu.

Le cas d’usage sembler en effet exister, j’ai l’impression que c’est un peu ce que fait la commande whereis qui cherche dans des répertoires stratégiques, mais à condition qu’on ait un pattern exact à lui donner.

Par exemple :

% whereis ffmpeg
ffmpeg: /usr/bin/ffmpeg /usr/include/ffmpeg /usr/share/ffmpeg /usr/share/man/man1/ffmpeg.1.gz

Il trouve le programme, les libs source, les pages du manuel, … Mais le tien a l’air plus général.

On revient un peu au problème d’origine à savoir que c’est pénible de chercher un élément dans une myriade de répertoire

Honnêtement je suis pas sûr de suivre ce que tu veux dire par là. Tu veux dire avec find ? Ta commande smwct -s --session thing est équivalente à find ~ -name "*thing*" (si j’ai bien compris ce que smwct est censé faire). Je ne sais pas laquelle est la "mieux" dans l’absolu, mais je sais tout de suite comment modifier la commande find pour chercher dans / : find / -name "*thing*", et le pattern accepté est dans un format suffisamment standard pour pouvoir lire ce qui se passe ainsi que pouvoir le modifier facilement. Avec ta commande, on sait pas trop ce que --session veut dire, et on sait pas trop ce que thing représente comme requête : un nom qui matche parfaitement ou bien un match partiel ? On fait comment pour avoir l’autre ? find peut devenir rapidement très pénible à utiliser lorsque les requêtes se complexifient, mais certaines choses sont extrêmement standard sur Linux. Typiquement, lorsque tu as une commande qui explore le système de fichiers, t’as globalement trois possibilités.

  • La commande est bête comme chou et s’exécute dans le répertoire courant, point barre. C’est un peu le niveau zéro de ce qu’on peut faire, mais ça se compose facilement avec cd dans le shell (mais ça suppose de créer un sous-shell dans les scripts, c’est pas forcément super).
  • La commande cherche un ensemble standard et connu, typiquement dans une variable d’environnement (type $PATH comme ce que fait whereis), c’est bien pour tout ce qui est censé interagir avec un environnement donné pour chercher e.g. les exécutables et librairies là où il est standard de le faire.
  • La commande accepte un chemin arbitraire, c’est parfait lorsque la commande se veut un peu tout terrain. Note que pas mal de commandes qui par défaut agissent dans le répertoire courant (e.g. git) ou d’après des variables d’environnement (e.g. whereis) sont aussi capables de prendre des chemins arbitraires. C’est la façon la plus simple, générique, et fiable de gérer tous les cas d’usages bizarres qui peuvent survenir. Il est pas rare sous Linux de créer des environnements locaux sur un coin de disque pour tester quelque chose, auquel cas chercher arbitrairement dans $HOME au lieu de cet environnement local n’est pas très utile.

Dans ton cas, le truc qui demande le moins d’efforts de développement et qui t’assure l’UI la moins surprenante est de bêtement prendre un chemin arbitraire comme racine pour la recherche. Tu couvres de façon évidente les cas classiques de chercher dans / et dans ~ d’une façon beaucoup plus transparente et courte qu’avec --root ou --session, et tu gères gratuitement n’importe quel autre cas qui pourrait être utile à l’utilisateur.

Surtout que logiquement, ta fonction de recherche doit pouvoir prendre en paramètre un dossier arbitraire, sinon c’est qu’il y a une conception bizarre. Et tu as juste à modifier la façon de récupérer l’argument, ce qui est normalement assez simple.

+0 -0

Je n’y avais pas pensé, mais en effet / à la place de --root serait une bonne chose. Idem pour --session qui pourrait être remplacé par ~. Je vais l’implémenter à smwct.

Avec ta commande, on sait pas trop ce que —session veut dire, et on sait pas trop ce que thing représente comme requête : un nom qui matche parfaitement ou bien un match partiel

"thing" représente un "match partiel". Pour mieux comprendre, ça correspondrait à ça :

for item in os.listdiv():
  if sys.argv[3] in item:  # sys.argv[3] correspondrait à "thing"
    print(f'{sys.argv[3] est dans {item}.')
+0 -0

Je n’y avais pas pensé, mais en effet / à la place de --root serait une bonne chose. Idem pour --session qui pourrait être remplacé par ~. Je vais l’implémenter à smwct.

Note que ~ sera automatiquement remplacé par l’emplacement de ton home par le shell. Donc en fait tout ce que tu as à gérer est d’avoir un chemin comme argument positionnel.

"thing" représente un "match partiel"

Au cas où c’était pas clair, je me mettais dans la peau de quelqu’un qui ne connait rien au projet et voit la commande, elle est surprenante par plusieurs aspects. D’ailleurs tant qu’on est à discuter les conventions de CLI, j’ai l’impression que tu demandes à ce que l’ordre -s --(root|session) <thing> soit respecté, faisant effectivement de -s et --(root|session) des arguments positionnels et obligatoires. Or, par convention les arguments en --arg ou -a sont optionnels et leur ordre n’a pas d’importance. -s devrait être une sous-commande qui serait simplement s, et comme on l’a déjà discuté --(root|session) serait plutôt un path. Ça te donne une commande du genre smwct s <path> <thing>.

Par ailleurs, plutôt que de parser les arguments à la main, tu devrais utiliser argparse.

Bonjour,

J’ai il y a peu entamé le fameux algorithme d’exploration de dossier du projet Smwct, mais il s’avère que ma méthode est mauvaise. Jusqu’à présent, je procédais de la façon suivante :

  1. Définition de la variable target_path qui contiendrai les chemins correspondants à la chaîne envoyé par l’utilisateur. Définition de visited_path qui contiendrai les chemins visité (si c’était un dossier) ou simplement déjà itéré (un fichier). Déclaration de starting_path qui contient le chemin de départ (donc est relatif en fonction de --session ou --root) et enfin dernièrement la variable current_folder qui contient le dossier dans lequel on est pour gérer où itérer.
  2. Ensuite, je déclarai une boucle while True dans laquelle je mettais for item in os.listdir(current_folder) : une boucle qui itère sur tous les éléments du dossier actuel. Dans celle-ci il devrait y avoir ceci d’important:
  • Condition n°1: Si la chaîne de caractère demandé est dans l’item du dossier courant, alors l’ajouter à la liste target_value.
  • Condition n°2: Si l’item sur lequel je suis n’est pas dans ma liste visited_path, alors je l’y ajoute, et si celui-ci est en plus de ça un dossier, alors j’entre dedans en changeant la valeur de current_folder à celle du nouveau dossier (avec os.chdir(item_path), item_path qui je ne vous l’ai pas dis, contient le chemin menant vers l’item courant). Je finis avec la valeur continue qui veut dire que je souhaite passer directement à l’itération suivante.
  • Si l’item courant est le dernier du répertoire courant, alors je me déplace dans le répertoire précédant (à l’aide de os.chdir("../")) en changeant à nouveau la valeur de current_path après coût avec os.getcwd() => Get Current Working Directory. Je finis encore une fois avec la valeur continue.
  • Pour finir, Si l’item est le dernier du répertoire courant, et que le dossier courant est celui de starting_path (donc celui initial, alors je m’arrête).

Le problème de ce programme étant qu’il est imbriqué de la manière suivante :

def x():
  while True:
    for i in y:
      if x:
        continue  # Nous ramène en faite seulement à la prochaîne itération sans prendre en compte le  changement de current_path. Ce qui fait que si on tombe sur un dossier non visité, on aura beau entrer dedans, on y sera réellement uniquement quand tous les élément du dossier qui était courant seront parcouru.

J’aimerai que vous me suggériez un nouveau mode de fonctionnement ou de grandes amélioration pour cette partie du programme, vous pouvez aussi rejoindre le projet qui je le rappel, est open-source et est en ce moment même développé par moi et @NightProg.

Cordialement.

+0 -0

Il n’y a aucune raison valable de se passer de pathlib dans du nouveau code. os.path est une vieille abstraction pas super bien faite.

L’algo utilisé est horriblement complexe. Déjà, utiliser os.chdir et se baser sur os.getcwd pour se balader dans l’arborescence rend le truc super casse-gueule parce que ça fait un état global dont il faut se préoccuper pour suivre ce que fait l’algorithme. Ensuite, l’élément clé qu’il manque à l’algorithme que vous utilisez est qu’il doit être récursif d’une façon ou d’une autre. Si vous avez une fonction qui prend un chemin et un truc à trouver, et renvoie un itérateur sur les chemins qui correspondent (def find(path: Path, pattern: str) -> Iterable[Path]), alors à chaque fois que vous rencontrez un dossier, il suffit d’appeler cette fonction récursivement sur le dossier.

Codé vite fait (il y a sûrement plein de corner cases pénibles) :

from pathlib import Path
from typing import Iterable

def find(path: Path, pattern: str) -> Iterable[Path]:
    for subpath in path.iterdir():
        if pattern in subpath.name:
            yield subpath
        if subpath.is_dir():
            yield from find(subpath, pattern)

Accessoirement, c’est équivalent (du moins dans l’esprit) à ce que ferait path.glob(f"**/*{pattern}*").

Il faut être prudent avec l’appel chdir, quelque soit le langage. Ça change le repertoire courant pour l’ensemble du processus (du moins sous Linux), ce qui induit des problèmes évidents de cohérence quand plusieurs unités d’exécution concurrentes (thread, coroutine, greenlet, …) parcourent « leur » repertoire courant.

C’est en général le truc qu’on appelle une seule fois au tout début pour avoir une référence (dans le cas où l’outil ne permet pas ou ne rend pas obligatoire d’indiquer explicitement un repertoire de travail). Ensuite, on ne l’appelle plus du tout car ce n’est pas nécessaire puisqu’on se sert de l’arborescence pour pouvoir tout parcourir à sa guise. Le module pahtlib permet cela.

Bonsoir ^^ ,

Smwct a bien évolué depuis sa dernière présentation, d’ailleurs, il s’appel maintenant Wct qui est un raccourcis encore plus poussé, à savoir "Wizard for the Computer Tree". Mais rassurez il n’y a pas que le nom qui a changé. Je vous présente ici toutes les évolutions du projet.

Pour commencer, suite à vos recommandations nous avons, @NightProg et moi, remplacé le module os par pathlib (sauf pour un cas) et nos commandes autrefois gérés manuellement, par le module docopt (j’étais partis sur argparse mais NightProg a sut m’en dissuader). Ce qui fait que la commande fonctionne comme suit: wct (s|d) (~|/|<path>) <pattern>. Notez que <pattern> va être remplacé pour faire place aux regex par NightProg. La commande commençant par avec d n’est pas encore entamé, toutefois, celle avec s l’est.

Ensuite, l'explorateur est fonctionnel, nous l’avons testé sur Windows, MacOS et Linux. Etant le coeur du projet Wct, j’ai mis environ 5 jours pour le développer correctement. Ce dernier est basé sur le programme de la commande tree elle même, ce qui veut dire que je me suis servis de la technique de déplacement de tree pour faire celui de wct. Vous pouvez trouver ici le code de la commande tree sur Unix (dont je me suis servis).

Dernièrement, nous avons essayé de mettre le paquet en ligne mais ça n’a pas marché, alors nous ne savons à vrai dire pas vraiment comment faire.

Le logiciel est vraiment loin derrière find ou même fd, même si je suis quand même satisfait de ce qu’il fait. C’est pourquoi je vous invite à nous partager vos idée pour raccourcir le plus possible le temps de recherche. Nous avons déjà noté les suivantes :

  • Outrepasser les dossiers commençant par ., qui sont nombreux et peu intéressant;
  • Sauter les dossiers ayant un accès restreint (a été développé le 07/07/2022) au lieu d’essayer de rentrer dedans;
  • Passer outre les dossiers qui n’ont absolument aucune importance tels que __pycache__/, build/, venv/, .env, doc/, llvm/, dist/, etc.

Voilà un aperçu de l’utilisation du logiciel :

$ cd Documents/dev/wct
$ python wct.py s /home/b4b4/Documents/dev/wct re

121 folders, 167 files.
~ /home/b4b4/Documents/dev/wct/.git/hooks/pre-applypatch.sample
~ /home/b4b4/Documents/dev/wct/.git/hooks/pre-commit.sample
~ /home/b4b4/Documents/dev/wct/.git/hooks/pre-merge-commit.sample
~ /home/b4b4/Documents/dev/wct/.git/hooks/pre-push.sample
~ /home/b4b4/Documents/dev/wct/.git/hooks/pre-rebase.sample
~ /home/b4b4/Documents/dev/wct/.git/hooks/pre-receive.sample
~ /home/b4b4/Documents/dev/wct/.git/hooks/prepare-commit-msg.sample
~ /home/b4b4/Documents/dev/wct/.git/logs/refs
~ /home/b4b4/Documents/dev/wct/.git/logs/refs/heads/repackaging
~ /home/b4b4/Documents/dev/wct/.git/logs/refs/remotes
~ /home/b4b4/Documents/dev/wct/.git/packed-refs
~ /home/b4b4/Documents/dev/wct/.git/refs
~ /home/b4b4/Documents/dev/wct/.git/refs/heads/repackaging
~ /home/b4b4/Documents/dev/wct/.git/refs/remotes
~ /home/b4b4/Documents/dev/wct/.gitignore
~ /home/b4b4/Documents/dev/wct/src/module/__pycache__/explorer.cpython-310.pyc
~ /home/b4b4/Documents/dev/wct/src/module/__pycache__/ignore_analysis.cpython-310.pyc
~ /home/b4b4/Documents/dev/wct/src/module/explorer.py

[   0.02940511703491211 seconds.   ]   
Note

121 folders, 167 files correspond bien au nombres de dossiers et fichiers visités par l’explorateur, pas ceux trouvés.

La description des avancés est terminé et j’aimerais toutefois vous rappeler que le projet est open source et qu’il n’attend que que vous le forkiez puis cloniez pour l’améliorer. NightProg et moi n’iront vraiment pas loin si nous le faisons qu’à deux. Rejoignez le projet !.

Cordialement, l’aimable auteur du logiciel Wct.

+0 -0

Les dossiers masqués, ceux commençant par ., sont justement ceux où on trouve le plus de vieux fichiers de configurations, alors ça me paraitrait bizarre de les ignorer. Par ailleurs, est-ce que le programme détecte les dossiers qui correspondent au pattern ? Si je veux supprimer les fichiers de truc, et qu’il y a un dossier .truc mais qui contient uniquement des fichiers nommés par exemple conf.txt, je veux que le dossier .truc apparaisse.

+0 -0

Les dossiers masqués, ceux commençant par ., sont justement ceux où on trouve le plus de vieux fichiers de configurations, alors ça me paraitrait bizarre de les ignorer. Par ailleurs, est-ce que le programme détecte les dossiers qui correspondent au pattern ? Si je veux supprimer les fichiers de truc, et qu’il y a un dossier .truc mais qui contient uniquement des fichiers nommés par exemple conf.txt, je veux que le dossier .truc apparaisse.

Moté

Oui, tout à fait. Si Wcd passe sur un item quel qui soit qui match avec le pattern il l’ajoute dans une liste nommé target_list, et c’est cette liste que le logiciel vous retourne (donc le chemin menant à X dossier / fichier qui correspond au pattern).

Wct en action avec une requête commeçant par un point
Wct en action avec une requête commeçant par un point

Pour information, il a fallut 18.67 secondes à Wct pour fouiller tout le répertoire /home/b4b4/.

+0 -0

Salut,

Pour commencer, suite à vos recommandations nous avons, @NightProg et moi, remplacé le module os par pathlib (sauf pour un cas) et nos commandes autrefois gérés manuellement, par le module docopt (j’étais partis sur argparse mais NightProg a sut m’en dissuader).

On peut critiquer l’interface de argparse qui est effectivement un peu mal fichue, mais je serais curieux des arguments de @NightProg pour :

  • d’une part ne pas se servir d’argparse malgré ses défauts étant donné que c’est en gros le standard du marché et qu’il est inclus dans la lib standard de Python, à moins de se heurter à ses limitations je ne vois pas de bonne raison de s’en passer ;
  • et a fortiori préférer docopt parmi la myriade d’alternatives alors qu’elle est moins flexible qu’argparse et que son développement est complètement mort (dernier commit il y a 4 ans, dernière release il y a 8 ans, Python a bougé pas mal entre temps !).

Ce qui fait que la commande fonctionne comme suit: wct (s|d) (~|/|<path>) <pattern>. Notez que <pattern> va être remplacé pour faire place aux regex par NightProg. La commande commençant par avec d n’est pas encore entamé, toutefois, celle avec s l’est.

Ça me parait un peu curieux comme choix, s et d ne représentent pas des opérations orthogonales, d est plutôt une action à effectuer sur le résultat de s. Par ailleurs, ~ et / ne sont que des cas particulier de path (j’ai l’impression en jettant un oeil au code que ~ est traité comme un cas spécial alors que de toute façon il sera remplacé par le shell par le chemin vers ton home avant même que python soit lancé, ton programme verra jamais un ~ à moins que celui-ci soit échappé, ce qui voudrait dire que l’utilisateur veut traiter un dossier qui s’appelle littéralement ~ !).

Dernièrement, nous avons essayé de mettre le paquet en ligne mais ça n’a pas marché, alors nous ne savons à vrai dire pas vraiment comment faire.

Avec l’exemple clé en main que j’ai fourni il n’y a plus qu’à créer un compte sur pypi et créer la wheel et l’uploader avec python3 -m build puis python3 -m twine upload dist/*.

Le logiciel est vraiment loin derrière find ou même fd, même si je suis quand même satisfait de ce qu’il fait. C’est pourquoi je vous invite à nous partager vos idée pour raccourcir le plus possible le temps de recherche. Nous avons déjà noté les suivantes :

  • Outrepasser les dossiers commençant par ., qui sont nombreux et peu intéressant;
  • Sauter les dossiers ayant un accès restreint (a été développé le 07/07/2022) au lieu d’essayer de rentrer dedans;
  • Passer outre les dossiers qui n’ont absolument aucune importance tels que __pycache__/, build/, venv/, .env, doc/, llvm/, dist/, etc.

L’implémentation de explorer est encore ultra-compliquée ! Surtout par rapport à l’alternative que je propose (à savoir utiliser path.glob massivement). En vrac en parcourant le code :

  • beaucoup d’appels à pathlib.Path (souvent sur un truc qui est déjà un Path !) au lieu de ne manipuler que des Path directement ;
  • les appels inlines à set_satistics qui font des appels systèmes pour vérifier des trucs qui ont déjà été testés par ailleurs ;
  • la gymnastique coûteuse pour enlever WindowsPath de str(tup) (ça n’a rien à faire là d’ailleurs) alors que pathlib gère déjà tout ça correctement ;
  • le plus gros problème je pense (sans profiler on peut se planter) est l’appel sorted([path for path in os.listdir(directory)]) puis itérer sur ces trucs, c’est un problème pour plusieurs raisons:
    • il y a trois grosses listes qui sont crées au lieu de zéro si on utilise un itérateur comme dans mon implémentation ;
    • trier la liste de tous les fichiers coûte cher, pour trier la sortie, autant ne trier que le résultat de la recherche ;
    • parcourir le système de fichier dans cet ordre arbitraire sera plus lent que de suivre les inodes dans l’ordre ;
    • il y a des conversions entre pathlib, str (pour le tri) et la représentation interne de os.path sur tous le chemins (c’est aussi sûrement la raison pour laquelle vous avez saupoudré le code d’appels à pathlib.Path…) ;
    • c’est mineur par rapport aux autres points, mais itérer ensuite sur la liste via un index au lieu de la liste elle même coûte plus cher (à cause des accès en Python au lieu d’avoir des appels en C directement dans l’itérateur de la libstandard).
  • enfin, tant que l’exploration elle-même sera faite directement en Python plutôt que se reposer au maximum sur des implémentations bas niveau (comme pathlib.Path.glob), vous allez forcément perdre en performances. On peut espérer que les appels au filesystem masquent les coûts de la VM Python, mais j’en suis pas convaincu à priori (par contre, ce qu’il y a de sûr, c’est que les perfs du filesystem dépendent énormément de ce qu’il y a en cache, surtout sous Linux qui est beaucoup plus aggressif sur le cache que Windows).

Voilà un aperçu de l’utilisation du logiciel :

$ cd Documents/dev/wct
$ python wct.py s /home/b4b4/Documents/dev/wct re

Si tu es déjà dans le répertoire ~/Documents/dev/wct, tu peux juste appeler python wct.py s . re au lieu de réécrire le path complètement (si c’est pas le cas, c’est qu’il y a un problème dans la transformation de l’argument en Path).

Bonjour,

On peut critiquer l’interface de argparse qui est effectivement un peu mal fichue, mais je serais curieux des arguments de @NightProg pour :

  • d’une part ne pas se servir d’argparse malgré ses défauts étant donné que c’est en gros le standard du marché et qu’il est inclus dans la lib standard de Python, à moins de se heurter à ses limitations je ne vois pas de bonne raison de s’en passer ;
  • et a fortiori préférer docopt parmi la myriade d’alternatives alors qu’elle est moins flexible qu’argparse et que son développement est complètement mort (dernier commit il y a 4 ans, dernière release il y a 8 ans, Python a bougé pas mal entre temps !).

@NightProg ne voulait pas utiliser argparse parce que la syntaxe est incompréhensible, d’abord  ; Et il a donc voulu docopt par sa facilité de syntaxe (ce qui au final n’est à mon goût pas vraiment le cas). docopt est du coup, après utilisation avec pas pratique du tout.

Ça me parait un peu curieux comme choix, s et d ne représentent pas des opérations orthogonales, d est plutôt une action à effectuer sur le résultat de s. Par ailleurs, ~ et / ne sont que des cas particulier de path (j’ai l’impression en jettant un oeil au code que ~ est traité comme un cas spécial alors que de toute façon il sera remplacé par le shell par le chemin vers ton home avant même que python soit lancé, ton programme verra jamais un ~ à moins que celui-ci soit échappé, ce qui voudrait dire que l’utilisateur veut traiter un dossier qui s’appelle littéralement ~ !).

Tu as tout à fait raison, je vais retirer d et ajouter un argument --delete. Pour ce qui est des arguments ~ et / je les traites comme des cas spéciaux et c’est peut être pour ça qu’ils ne fonctionne pas. Je vais simplement traiter <path> par la suite.

beaucoup d’appels à pathlib.Path (souvent sur un truc qui est déjà un Path !) au lieu de ne manipuler que des Path directement ;

  • les appels inlines à set_satistics qui font des appels systèmes pour vérifier des trucs qui ont déjà été testés par ailleurs ;
  • la gymnastique coûteuse pour enlever WindowsPath de str(tup) (ça n’a rien à faire là d’ailleurs) alors que pathlib gère déjà tout ça correctement ;
  • le plus gros problème je pense (sans profiler on peut se planter) est l’appel sorted([path for path in os.listdir(directory)]) puis itérer sur ces trucs, c’est un problème pour plusieurs raisons:
    • il y a trois grosses listes qui sont crées au lieu de zéro si on utilise un itérateur comme dans mon implémentation ;
    • trier la liste de tous les fichiers coûte cher, pour trier la sortie, autant ne trier que le résultat de la recherche ;
    • parcourir le système de fichier dans cet ordre arbitraire sera plus lent que de suivre les inodes dans l’ordre ;
    • il y a des conversions entre pathlib, str (pour le tri) et la représentation interne de os.path sur tous le chemins (c’est aussi sûrement la raison pour laquelle vous avez saupoudré le code d’appels à pathlib.Path…) ;
  • c’est mineur par rapport aux autres points, mais itérer ensuite sur la liste via un index au lieu de la liste elle même coûte plus cher (à cause des accès en Python au lieu d’avoir des appels en C directement dans l’itérateur de la libstandard).
  • enfin, tant que l’exploration elle-même sera faite directement en Python plutôt que se reposer au maximum sur des implémentations bas niveau (comme pathlib.Path.glob), vous allez forcément perdre en performances. On peut espérer que les appels au filesystem masquent les coûts de la VM Python, mais j’en suis pas convaincu à priori (par contre, ce qu’il y a de sûr, c’est que les perfs du filesystem dépendent énormément de ce qu’il y a en cache, surtout sous Linux qui est beaucoup plus aggressif sur le cache que Windows).

Pour faire simple, la base du programme que tu me propose résout tout ces problèmes ? Je trouve étonnant qu’un programme entièrement basé sur la commande tree elle même d’Unix soit si mal faite.

Cordialement ^^ .

+0 -0

@NightProg ne voulait pas utiliser argparse parce que la syntaxe est incompréhensible, d’abord  ; Et il a donc voulu docopt par sa facilité de syntaxe (ce qui au final n’est à mon goût pas vraiment le cas). docopt est du coup, après utilisation avec pas pratique du tout.

b4b4

Qu’il y ait une certaine marche à passer pour apprendre à l’utiliser je veux bien l’entendre, mais qu’est-ce qui rendrait la syntaxe d'argparse incompréhensible ?

Pour faire simple, la base du programme que tu me propose résout tout ces problèmes ? Je trouve étonnant qu’un programme entièrement basé sur la commande tree elle même d’Unix soit si mal faite.

b4b4

Le lien que tu donnes n’est pas LE projet tree mais des propositions d’implémentation du programme dans différents langages. Le « vrai » tree se trouve ici : https://gitlab.com/OldManProgrammer/unix-tree

Pour faire simple, la base du programme que tu me propose résout tout ces problèmes ? Je trouve étonnant qu’un programme entièrement basé sur la commande tree elle même d’Unix soit si mal faite.

En plus du fait que tu ne regardais pas le vrai tree, il y a deux choses à considérer :

  • tree affiche toute l’arborescence depuis ton point d’entrée d’une façon "jolie", il est donc raisonnable qu’il visite tout l’arbre une fois en le triant. C’est un besoin différent de find, et c’est aussi différent de ce que tu fais en visitant l’arbre deux fois, dont une fois dans l’ordre trié.
  • adapter un algo C directement en Python est rarement une bonne idée. Les structures de données ne sont pas du tout les mêmes, et Python s’exécute dans une VM hyper-dynamique et de fait plutôt lente. Un bon algo C peut avoir des performances désastreuses en Python, et souvent en Python ça vaut le coup d’appeler du code bas niveau même si l’algo implémenté dans ce bas niveau est sous-optimal plutôt qu’un algo optimal en Python pur parce que le coût de la VM est gigantesque.

Un truc que tu peux tester est comparer les trois commandes dans ton dépôt git (en les faisant tourner plusieurs fois jusqu’à ce que les temps se stabilisent pour éviter les effets de cache) :

$ time python wct.py s . re
$ time python -c "from pathlib import Path;print(*Path().glob('**/*re*'), sep='\n')"
$ time find . -name "*re*"

La première est ton code, la deuxième te donnera une idée du temps minimal que tu peux espérer atteindre en Python pur, et la troisième pour comparer avec find (sur un test rapide chez moi, find est trois fois plus rapide que la solution avec glob ! Cet écart va sûrement dépendre aussi de la taille de l’arborescence et de la requête).

+0 -0

Qu’il y ait une certaine marche à passer pour apprendre à l’utiliser je veux bien l’entendre, mais qu’est-ce qui rendrait la syntaxe d’argparse incompréhensible ?

alors pour ma defance je n’ai pas dit que "la syntaxe d’argparse etait incompréhensible" juste que je ne l’aimais pas. Tout dev a ses opinions sur des lib, moi j’en ai une sur argparse qui est plutot mauvaise et voila (cane veux pas dire que argparse est nul )

+0 -0

Qu’il y ait une certaine marche à passer pour apprendre à l’utiliser je veux bien l’entendre, mais qu’est-ce qui rendrait la syntaxe d’argparse incompréhensible ?

alors pour ma defance je n’ai pas dit que "la syntaxe d’argparse etait incompréhensible" juste que je ne l’aimais pas. Tout dev a ses opinions sur des lib, moi j’en ai une sur argparse qui est plutot mauvaise et voila (cane veux pas dire que argparse est nul )

NightProg

Si vous cherchez toujours une bonne alternative à argparse, je conseille chaleureusement l’excellent click, de Pallets, qui a une interface très agréable (comme toutes les libs de Pallets, en réalité ^^ ).

+2 -0

Si vous cherchez toujours une bonne alternative à argparse, je conseille chaleureusement l’excellent click, de Pallets, qui a une interface très agréable (comme toutes les libs de Pallets, en réalité ^^ ).

je connais , et je l’adore , et je le conseille

+1 -0

Bonjour,

L’assistant de recherche et de modération Wct fait aujourd’hui, enfin, correctement tout ce qu’il est censé faire. La forme de la commande est la suivante :

python /path/to/wct.py <path> (<pattern> | <regex>) [-d | --delete]

Je ne vais pas autant développer chaque argument comme dans le README du projet GitHub (lien en bas), mais je vais tout de même vous expliquer simplement l’utilité de chacun des arguments :

  • <path> : chemin où doit commencer la recherche, ou le point d’entrer, si vous préférez ;
  • <pattern> et <regex> : le premier correspond au motif que l’on cherche, et le second correspond comme son nom l’indique à une expression régulière. Notez que c’est sois l’un sois l’autre, et que le pattern sera considéré comme pattern uniquement s’il ne correspond aucunement à une regex.
  • -d ou --delete : argument optionnel qui permet à la fin de la recherche de supprimer ce qui a été trouvé. Plus justement, ça ne supprime pas directement ce qui a été trouvé, ça vous propose soit de tout supprimer (DE), de quitter (Enter) ou de choisir à l’aide des index ceux que vous ne voulez surtout pas supprimer.

Si le projet vous intéresse, vous pouvez toujours y contribuer (Wct est développé en Python) en suivant le lien GitHub ci-dessous, ou si vous voulez simplement l’utiliser ou en savoir plus à son propos, je vous invites à aller voir le README associé, toujours à l’aide du lien ci-dessous :

+ https://github.com/b4-b4/wct

Vous l’avez sûrement remarqué, le préfixe de wct est fatalement python3 /path/to/wct.py, je le reconnais, c’est honteux. C’est en fait dû au fait que je n’ai réussi sur aucun de mes ordinateurs à le déposer sur PyPi, mais en théorie, ça devrait y faire son apparition un jour ou l’autre.

Voici deux exemples qui illustrent le nouveau fonctionnement du projet :

Recherche le motif "v" dans tout le répertoire NazaraEngine

b4b4@b4b4-old-laptop:~/Documents/dev$ python3 wct/wct.py NazaraEngine/ v

2 folders, 22 files.
| NazaraEngine/thirdparty/include/vma
| NazaraEngine/thirdparty/include/vma/vk_mem_alloc.h
| NazaraEngine/thirdparty/include/vma/vk_mem_alloc.natvis
| NazaraEngine/thirdparty/include/vulkan
| NazaraEngine/thirdparty/include/vulkan/vk_icd.h
| NazaraEngine/thirdparty/include/vulkan/vk_layer.h
| NazaraEngine/thirdparty/include/vulkan/vk_platform.h
| NazaraEngine/thirdparty/include/vulkan/vk_sdk_platform.h
| NazaraEngine/thirdparty/include/vulkan/vulkan.h
| NazaraEngine/thirdparty/include/vulkan/vulkan_android.h
| NazaraEngine/thirdparty/include/vulkan/vulkan_beta.h
| NazaraEngine/thirdparty/include/vulkan/vulkan_core.h
| NazaraEngine/thirdparty/include/vulkan/vulkan_directfb.h
| NazaraEngine/thirdparty/include/vulkan/vulkan_fuchsia.h
| NazaraEngine/thirdparty/include/vulkan/vulkan_ggp.h
| NazaraEngine/thirdparty/include/vulkan/vulkan_ios.h
| NazaraEngine/thirdparty/include/vulkan/vulkan_macos.h
| NazaraEngine/thirdparty/include/vulkan/vulkan_metal.h
| NazaraEngine/thirdparty/include/vulkan/vulkan_vi.h
| NazaraEngine/thirdparty/include/vulkan/vulkan_wayland.h
| NazaraEngine/thirdparty/include/vulkan/vulkan_win32.h
| NazaraEngine/thirdparty/include/vulkan/vulkan_xcb.h
| NazaraEngine/thirdparty/include/vulkan/vulkan_xlib.h
| NazaraEngine/thirdparty/include/vulkan/vulkan_xlib_xrandr.h

[   0.05797529220581055 seconds   ]

Recherche toujours le motif "v" dans tout le répertoire NazaraEngine, et demande à ce que la suppression des résultats soit ajouté

b4b4@b4b4-old-laptop:~/Documents/dev$ python3 wct/wct.py NazaraEngine/ v --delete

2 folders, 22 files.
0 | NazaraEngine/thirdparty/include/vma
1 | NazaraEngine/thirdparty/include/vma/vk_mem_alloc.h
2 | NazaraEngine/thirdparty/include/vma/vk_mem_alloc.natvis
3 | NazaraEngine/thirdparty/include/vulkan
4 | NazaraEngine/thirdparty/include/vulkan/vk_icd.h
5 | NazaraEngine/thirdparty/include/vulkan/vk_layer.h
6 | NazaraEngine/thirdparty/include/vulkan/vk_platform.h
7 | NazaraEngine/thirdparty/include/vulkan/vk_sdk_platform.h
8 | NazaraEngine/thirdparty/include/vulkan/vulkan.h
9 | NazaraEngine/thirdparty/include/vulkan/vulkan_android.h
10 | NazaraEngine/thirdparty/include/vulkan/vulkan_beta.h
11 | NazaraEngine/thirdparty/include/vulkan/vulkan_core.h
12 | NazaraEngine/thirdparty/include/vulkan/vulkan_directfb.h
13 | NazaraEngine/thirdparty/include/vulkan/vulkan_fuchsia.h
14 | NazaraEngine/thirdparty/include/vulkan/vulkan_ggp.h
15 | NazaraEngine/thirdparty/include/vulkan/vulkan_ios.h
16 | NazaraEngine/thirdparty/include/vulkan/vulkan_macos.h
17 | NazaraEngine/thirdparty/include/vulkan/vulkan_metal.h
18 | NazaraEngine/thirdparty/include/vulkan/vulkan_vi.h
19 | NazaraEngine/thirdparty/include/vulkan/vulkan_wayland.h
20 | NazaraEngine/thirdparty/include/vulkan/vulkan_win32.h
21 | NazaraEngine/thirdparty/include/vulkan/vulkan_xcb.h
22 | NazaraEngine/thirdparty/include/vulkan/vulkan_xlib.h
23 | NazaraEngine/thirdparty/include/vulkan/vulkan_xlib_xrandr.h

[   0.06256699562072754 seconds   ]

Using the index, write the individual items you do not want to delete separated by commas.
Otherwise, enter <DE> to delete everything or <Enter> to exit.
>  
+2 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte