Forum Programmation.python Scripts avec une double interface CLI / CGI

Posté par (page perso) . Licence CC by-sa
Tags : aucun
4
15
oct.
2014

Bonjour,

Dans le cadre de mon activité de biologiste et en qualité de « geek du labo », je développe bricole occasionnellement quelques scripts Python pour automatiser certaines tâches.

Malheureusement, mes collègues ne peuvent guère en profiter tant que ces scripts s’utilisent en ligne de commande uniquement. Leur dire d’utiliser un truc en ligne de commande pour se simplifier la vie, c’est un peu comme dire à un enfant d’aller chez le dentiste pour ne plus avoir mal aux dents : le remède est peut-être bon mais il donne l’impression d’être pire que le mal.

Du coup, j’ai modifié un de ces scripts pour qu’il puisse fonctionner en deux modes : un mode « CLI » (ligne de commande) pour moi, et un mode « CGI » pour mes collègues, où le script appelé sans arguments génère un formulaire HTML basique qui, une fois complété, rappelle le script avec en arguments le contenu du formulaire. Ce script est installé sur une des machines du labo, et est rendu accessible sur le réseau local par un serveur Apache avec mod_cgi.

Pour ce premier essai, j’ai fait les choses à la main et à LA RACHE. En gros, au début du script, je détecte la présence de la variable d’environnement GATEWAY_INTERFACE qui m’indique si je suis en mode CGI, et le cas échéant je détourne l’exécution vers une fonction qui s’occupe, soit de générer le formulaire HTML, soit d’extraire les arguments de la requête CGI. Sinon, par défaut je parse les arguments de la ligne de commande.

Comme l’expérience est concluante (mes collègues sont plus disposés à utiliser une interface web qu’une interface CLI, et moi ça ne me fait toujours qu’un script à développer bricoler), j’aimerais à présent faire la même chose de façon plus automatique.

En gros, je voudrais n’avoir qu’à décrire d’une façon ou d’une autre les arguments attendus par le script, puis appeler une seule fonction magique qui détecterait le mode d’invocation du script (CGI ou CLI), obtiendrait les arguments de la façon appropriée (en parsant la ligne de commande ou par un formulaire HTML) et me renverrait les arguments prêts à être utilisés.

Je n’ai pas trouvé de modules Python qui feraient ça. Il y a une flambée de « CLI Application Framework » pour faciliter le parsing de la ligne de commande, mais aucun d’eux ne semble permettre un double usage CLI/CGI.

Je suis donc à deux doigts de m’atteler à la tâche et de développer bricoler moi-même le module de mes rêves mais, n’étant pas particulièrement sujet au syndrome NIH, je voudrais d’abord vous demander si vous connaissez déjà un tel module, ou une autre solution similaire. Secondairement, pensez-vous qu’un tel module pourrait intéresser du monde, dans l’hypothèse où il n’existerait pas déjà un ?

Merci.

  • # re

    Posté par . Évalué à 0. Dernière modification le 15/10/14 à 21:24.

    Salut.
    Désolé, mais je comprends presque rien.

    Je comprends que tu veux faire du CLI(pour toi) et CGI(pour collègues).

    Mais.
    Pour le cli tu veux te connecté directement (via ssh ou genre putty) et executé tes commandes en directe ou envoyer juste la commande à executé via le réseau web comme le CGI ?

    En fonction de cela, pas mal de chose change, une fois réponse, je pourrais pour ma part mieux t'orienté.

    Pour faire court:
    - tu as ton application cgi en python
    - tu détectes et analyse les méthodes get et post
    - tu fais une condition if-else, en fonction du résultat de la condition, tu changes l'instruction pour le CLI ou le CGI.

    "Comme ta création n’est pas en vain, la création de ces événements n’est pas non plus en vain." Bediüzzaman

    • [^] # Re: re

      Posté par (page perso) . Évalué à 2.

      Pour le cli tu veux te connecté directement (via ssh ou genre putty) et executé tes commandes en directe ou envoyer juste la commande à executé via le réseau web comme le CGI ?

      Non, le mode CLI, c’est pour exécuter directement sur ma machine, comme n’importe quel autre de mes scripts. Le mode CGI est un « bonus » pour mes collègues, mais j’écris mes scripts aussi pour moi-même et la ligne de commande est pour moi une interface beaucoup plus naturelle qu’un formulaire dans un navigateur.

      Pour l’instant, ce que je fais ressemble à peu près à ça (en un peu moins à LA RACHE quand même) :

      #!/usr/bin/python
      
      import sys, os, getopt, cgi
      
      if __name__ == '__main__':
      
          # Valeurs par défaut des options
          operation = 'intersection'
          format = 'csv'
      
          if os.getenv('GATEWAY_INTERFACE'):
              # mode CGI, on récupère les paramètres de la requête CGI
              form = cgi.FieldStorage()
              if len(form) == 0:
                  # il n’y en a pas? on affiche le formulaire
                  # qui permettra à l’utilisateur de saisir les paramètres
                  print """Content-Type: text/html
      
      <html>
          <body>
              <form action="script.py" method="post" enctype="multipart/form-data">
                  <p>Operation to perform:</p>
                  <p><input type="text" name="operation" /></p>
                  <p>Output format:</p>
                  <p>
                      <select name="format">
                          <option value="xml">XML</option>
                          <option value="csv">CSV</option>
                      </select>
                  </p>
                  <p><input type="submit" name="submit" /></p>
              </form>
          </body>
      </html>"""
      
                  # et on termine là pour l’instant, la soumission du
                  # formulaire lancera une nouvelle exécution du script
                  sys.exit(0)
      
              else:
                  # Il y a des paramètres ? Bien. On les analyse, on
                  # vérifie que tout est correct (les paramètres obligatoires
                  # sont bien présents, les valeurs sont dans les limites
                  # attendues, etc.)…
                  operation = form['operation']
                  format = form['format']
      
          else:
              # Pas de variable GATEWAY_INTERFACE ? On est en mode CLI,
              # on parse la ligne de commande
      
              try:
                  opts, args = getopt.getopt(sys.argv[1:], 'o:f:', ['operation=', 'format='])
              except getopt.GetoptError:
                  sys.exit(1)
      
              for o, a in opts:
                  if o in ('-o', '--operation'):
                      operation = a
                  elif o in ('-f', '--format'):
                      format = a
      
          # Arrivé ici, on a les paramètres dont on a besoin dans les
          # les variables 'operation' et 'format', on peut commencer
          # le vrai travail que le script est supposé faire, et qui
          # est indépendant de la manière dont le script a été appelé
          # (ou presque : en mode CGI, il faut quand même penser à faire
          # précéder la sortie d’un en-tête Content-Type)

      Et ce que je voudrais, c’est pouvoir faire la même chose avec moins de code, genre quelque chose comme ça :

      #!/usr/bin/python
      
      import ModuleMagique
      
      if __name__ == '__main__':
      
          m = ModuleMagique.ObjetMagique()
          m.addOption('operation', 'o', 'Operation to perform')
          m.addOption('format', 'f', 'Output format', allowedValues=['csv', 'xml'], defaultValue='csv')
      
          m.getArgumentsOrDie()
      
          # Si on arrive ici, c’est que le script a été appelé avec les bons
          # arguments (que ce soit en mode CLI ou en mode CGI), on peut
          # faire ce qu’on a à faire
          operation = m.arguments['operation']
          format = m.arguments['format']

      Ce que je cherche, et que je suis éventuellement prêt à développer bricoler moi-même, c’est ce fameux ModuleMagique

      • [^] # Re: re

        Posté par . Évalué à 0. Dernière modification le 16/10/14 à 02:51.

        Ah je comprend.

        Je suis pas utilisateur python, je pourrais pas te dire s'il y a ou pas.

        Mais quand c'est du python et du web je trouves qu'ils font tous pour facilité le développement, les gros fainaiant quoi, télement fainaiant que je crois qu'il doit existé un tel truc.

        En tous cas j'aimes pas ça fait une surcouche.
        Mais ton utilisation est simple, donc pas trop soucis.

        "Comme ta création n’est pas en vain, la création de ces événements n’est pas non plus en vain." Bediüzzaman

  • # Gooey

    Posté par . Évalué à 3.

    Salut

    cela me fait penser à Gooey, un module pour créer une interface graphique à partir d'un script Python en ligne de commande.
    Il te faudrait la même chose en version web.

    Si tu comptes le faire toi-même, je te conseille de regarder aussi les micro-frameworks web comme flask car tu pourrais créer un outil assez complexe au final.

    • [^] # Re: Gooey

      Posté par (page perso) . Évalué à 2.

      cela me fait penser à Gooey, un module pour créer une interface graphique à partir d'un script Python en ligne de commande.
      Il te faudrait la même chose en version web.

      Oui, c’est exactement ce qu’il me faudrait. Merci d’ailleurs, je ne connaissais ce projet. Je le garde sous le coude, ça pourra me servir…

      TODO: Get OS X version working

      … mais pas pour l’instant :/ avec mes collègues qui sont tous sous Mac OS X.

      tu pourrais créer un outil assez complexe au final.

      Si c’est moi qui m’y colle, il y a peu de chance. :-°

      • [^] # Re: Gooey

        Posté par (page perso) . Évalué à 2. Dernière modification le 16/10/14 à 23:25.

        Pour une interface graphique d'un truc en bash/python il y aussi Galde2script

  • # Pas à ma connaissance

    Posté par . Évalué à 1.

    Effectivement l’idée est pas mal du tout.

    ÀMHA le plus simple ce serait de reprendre un des modules existant de parsing de la ligne de commande. plutôt que de tout réinventer, puis de se servir de ses méthodes/objets voir faire un peut d’introspection. Ça évitera le NIH, quitte à rajouter quelques fonctionnalités supplémentaires via composition/héritage (en redéfinissant les méthodes qui vont bien) : c’est fait pour !

    • [^] # Re: Pas à ma connaissance

      Posté par (page perso) . Évalué à 3.

      Ça me paraît le plus raisonnable effectivement. J’ai déjà commencé à voir ce que je pouvais faire à partir de argparse.

      Si j’aboutis à quelque chose de pas trop moche et presque fonctionnel, je vous en ferai part (ce sera libre, bien évidemment).

  • # Web

    Posté par . Évalué à 2.

    Mon commentaire est sans doute un peu hors-sujet. D'après ce que j'ai compris, tu préfères coder une appli en ligne de commande plutôt qu'une appli web (moi c'est pareil…)
    Je te suggérerais de regarder les continuation based web frameworks.
    Ils permettent de coder une application web un peu comme ça :
    a = input("1er nombre")
    b = input("2ème nombre")
    print "a+b = " + str(a+b)
    Il y a un framework en Python qui fait ça, il s'appelle Nagare. Mais il utilise une version un peu exotique de python. Et ce genre de frameworks ne sont pas utilisés des masses…

    Il y a un framework dans le même genre en Haskell qui a l'air très cool, MFlow. En haut de la page d'accueil, c'est écrit ceci :

    MFlow Create and maintain dynamic Web applications as easy and fast as console applications
    Thou shall not write request handlers

    Après c'est du haskell, c'est sexy comme langage, mais ça prend du temps à apprendre.

    Ca ne va peut-être pas solutionner ton problème, mais c'était juste pour dire que ça existe.

  • # Point of View of Bernard Pivot

    Posté par . Évalué à -1.

    Point de vue de Bernard Pivot : Ce n'est pas plus tôt à l'arrache ? (arracher la victoire ?)

Suivre le flux des commentaires

Note : les commentaires appartiennent à ceux qui les ont postés. Nous n'en sommes pas responsables.