Partage
  • Partager sur Facebook
  • Partager sur Twitter

Return une value en cas d'erreur

    27 décembre 2016 à 1:18:28

    Bonjour, 

    Je souhaite faire un decorateur qui me retourne ce qui est cree dans la fonction a laquelle je l'attache.

    @registerChanges
    def test():
        a = SomeObject()
        return True
    b = test()

    Par exemple, dans le cas present, b contiendra True et l'instance de a, creee dans la fonction. Mon decorateur enregistre les classes instancees (en vrai, il ne s'agit pas de classes, mais peu importe, le probleme ne porte pas la dessus), execute la fonction, et retourne le tout. Jusqu'ici, pas de probleme.

    Sauf que je souhaiterai, en cas d'erreur, recuperer malgre tout les classes qui ont ete crees. Le souci c'est que si une exception est raise dans mon decorateur, il ne va pas jusqu'au return, la fonction test() n'ira pas non plus jusqu'a son return, et la variable b ne sera meme pas creee. Est-ce quelqu'un aurait une idee de comment proceder pour raise une erreur ET recuperer une valeur return malgre tout ?

    J'ai un peu de mal a expliquer clairement mon probleme, donc si je peux vous aider, n'hesitez pas a me demander des details sur tel ou tel point ! D'avance, merci =]

    (si ca peut aider, voici a quoi ressemble le decorateur)

    def registerChanges(func):
        def wrapper(*args, **kwargs):
            functionReturn = None
            createdNodes = []
            try:
                # adds a callback to store every new object in the list 'createdNodes'
                functionReturn = func(*args, **kwargs)
            except:
                raise
            return functionReturn, createdNodes
        return wrapper
    
    • Partager sur Facebook
    • Partager sur Twitter
      27 décembre 2016 à 9:09:58

      Bonjour,

      Quel est le problème que tu souhaites résoudre ?

      À quoi servirait la valeur retournée si c'est pour lever une exception en même temps ?

      • Partager sur Facebook
      • Partager sur Twitter
        27 décembre 2016 à 16:58:42

        Bonjour, 

        C'est assez specifique, donc je ne suis pas sur que ca aide de savoir le pourquoi du comment, mais dans le doute.... : 

        C'est pour utiliser dans un soft de 3d (autodesk maya), sur une fonction qui cree des objets 3d. Je souhaite 'enregistrer' tous les objets 3d crees, de sorte a pouvoir appeler une fonction 'undo' par la suite, qui supprimera tous les objets que j'ai cree.

        Donc tout le probleme, c'est en cas d'erreur : je veux, en cas d'erreur, que l'erreur, quelle qu'elle soit, remonte jusqu'a l'utilisateur, mais je souhaite quand meme recuperer la liste contenant tous les elements qui ont ete crees pendant la fonction jusqu'a ce qu'elle atteigne l'erreur.

        • Partager sur Facebook
        • Partager sur Twitter
          27 décembre 2016 à 17:11:06

          Bonjour,

          Est-ce que tu veux ton erreur dans le traceback ?

          Sinon tu peux très bien faire un try / except qui écrit ton erreur dans un fichier text, et tu rajoutes dans le finally ton code que tu dois à tout prix executer . 

          • Partager sur Facebook
          • Partager sur Twitter
            27 décembre 2016 à 18:28:28

            hello,

            bonne idee, mais comme tu dis, malheureusement je voudrai mon erreur dans le traceback. Ce serait trop lour d'avoir a ecrire / lire un fichier externe, il me faudrait une solution 'seamless'

            • Partager sur Facebook
            • Partager sur Twitter
              27 décembre 2016 à 22:22:36

              Mais au moment où tu traites l'erreur, tu es bien obligé de l'attraper, qu'est-ce qui pose problème ?

              • Partager sur Facebook
              • Partager sur Twitter
                27 décembre 2016 à 22:49:08

                Ce qui me pose probleme, c'est que des que python rencontre une erreur, le programme s'arrete. Des qu'il rencontre un return, il s'arrete egalement.

                Je voudrai pouvoir raise mon erreur tout en retournant une valeur. La, si je raise d'abord et que je return ensuite, le script narrive jamais jusqu'au return, et si je return dabord et raise ensuite, je n'ai jamais d'erreur puisque le script narrive pas jusque la.

                • Partager sur Facebook
                • Partager sur Twitter
                  27 décembre 2016 à 23:12:30

                  Sauf que pour récupérer le retour tu serais bien obligé de traiter l'erreur. Donc, pourquoi faire ça ? Que voudrais-tu qu'il se passe quand une erreur se produit ?

                  Je ne sais pas comment est architecturé ton code, mais tu pourrais faire en sorte d'écrire dans une liste accessible de l'extérieur, voire même de faire de cette liste un attribut de l'erreur si c'est vraiment nécessaire. Mais je continue de penser que tu conçois mal ton problème.

                  • Partager sur Facebook
                  • Partager sur Twitter
                    27 décembre 2016 à 23:23:32

                    C'est tout a fait possible que je concoive mal mon probleme effectivement, et je me suis aussi pose la question. Mais si tel est le cas, alors je souhaiterai une explication sur comment traiter mon truc autrement ^^

                    La technique d'ecrire dans une liste definie en dehors est cool, et il se trouve que j'ai essaye aussi, pensant que ce serait la soluce ^^ Sauf que non, puisque, toujours pareil, DES que l'erreur est raise, la fonction s'arrete, et donc ne pourrai transmettre aucune donnee au niveau d'au dessus (i.e. au module qui l'a appelee).

                    La seule methode que je vois, c'est de recuperer l'erreur sous forme d'objet, et, en dehors de la fonction, de la raise si elle existe, mais le probleme avec cette methode est que le stack trace est a la ramasse

                    A la limite, je serai ok pour avoir une structure differente, je ne veux pas forcer python a fonctionner d'une maniere qu'il n'est pas cense supporter. Tout mon code est la, entwanne, donc tu vois comment c'est organise. Si tu as une suggestion de comment faire ce que je souhaite faire en organisant mon code different, n'hesite pas, ce sera plus que bienvenue !

                    Merci pour votre aide en tout cas

                    -
                    Edité par fruity' 27 décembre 2016 à 23:26:52

                    • Partager sur Facebook
                    • Partager sur Twitter
                      28 décembre 2016 à 3:38:08

                      Salut,

                      L'idée du fichier serait pas bête. Attrapez les exceptions uniquement et les écrient dans un fichier.

                      Ensuite, affichez simplement ce fichier d'erreurs à l'utilisateur. Soit en popup, soit dans la fenêtre.

                      Le supprimer ou l'archiver dans un fichiers log_erreurs.log, contenant tous les autres erreurs, ainsi que la date, pourrait être la prochaine étapes.

                      Sous forme d'object? un fichier json, pourrait fonctionner?

                      Reste le côté performance, ah ah :-° je sais pas trop

                      -
                      Edité par nolimitech 28 décembre 2016 à 3:39:51

                      • Partager sur Facebook
                      • Partager sur Twitter
                        28 décembre 2016 à 4:20:00

                        hey !

                        oui, comme je disais, l'idee du fichier est cool et je n'y avais pas pense. Malheureusement, pour un usage intensif (et il s'agira la d'un usage intensif !), ca n'est pas viable, j'en ai peur =[

                        Idealement, il faut que pour la personne qui utilise la fonction, l'operation soit completement transparente. Enfin plus precisement, la structure finale ressemble a ca :

                        class Abstract(object):
                        	'''
                        	cette classe n'est pas exposee a l'utilisateur
                        	'''
                        	@registerChanges
                        	def a(self):
                        		pass
                        class X(Abstract):
                        	def a(self):
                        		# l'utilisateur fait ce qu'il a a faire ici




                        L'utilisateur final ne doit donc meme pas avoir connaissance du systeme

                        • Partager sur Facebook
                        • Partager sur Twitter
                          28 décembre 2016 à 11:48:57

                          fruity' a écrit:

                          La technique d'ecrire dans une liste definie en dehors est cool, et il se trouve que j'ai essaye aussi, pensant que ce serait la soluce  ;) Sauf que non, puisque, toujours pareil, DES que l'erreur est raise, la fonction s'arrete, et donc ne pourrai transmettre aucune donnee au niveau d'au dessus (i.e. au module qui l'a appelee).

                          Si la liste est extérieure, tu n'as pas besoin de la retourner.

                          fruity' a écrit:

                          Tout mon code est la, entwanne, donc tu vois comment c'est organise.

                          Pas vraiment non, je vois juste un vague extrait.

                          Tu n'explicites pas ce que tu veux faire en cas d'erreur : arrêter le programme, juste afficher un message, quelque chose d'autre ?

                          • Partager sur Facebook
                          • Partager sur Twitter
                            29 décembre 2016 à 1:34:14

                            Si.

                            fruity' a écrit:

                            Sauf que je souhaiterai, en cas d'erreur, recuperer malgre tout les classes qui ont ete crees. 

                            Pour donner plus de detail, je souhaite, en cas d'erreur, arreter le programme (i.e. raise l'erreur) ET recuperer la variable return par ma fonction (ou en l'occurrence, par mon decorateur, puisque la fonction a error, elle n'a pas pu atteindre son return)

                            Et j'insiste, tout mon code est la, je t'assure ^^ Je peux t'envoyer une capture ecran de mon editeur, si ca peut t'aider ? Mais je doute que ca contribue beaucoup a la resolution de mon probleme ^^

                            La technique de la liste exterieure est peut-etre la solution effectivement. Ma liste etait definie dans mon decorateur (registerChanges), donc j'avais besoin de la return pour la faire 'sortir' de ma fonction. Mais je peux essayer de la creer en dehors de tout appel de fonction, et la faire passer dans la fonction pour qu'elle soit ecrite au fur et a mesure du process. J'essayerai ce soir. D'ici la, si d'autres solutions vous viennent, je suis toujours preneur, cette methode ne me semblant pas tres propre en terme d'organisation du code.

                            (encore une fois, si quelque chose n'est pas clair, n'hesitez pas a me demander des explications)

                            -
                            Edité par fruity' 29 décembre 2016 à 1:35:41

                            • Partager sur Facebook
                            • Partager sur Twitter
                              29 décembre 2016 à 6:06:10

                              Si cela peut aider. Pas de raise, mais une variable que avertis l'erreur.

                              def registerChanges(func):
                                  def wrapper(*args, **kwargs):
                                      functionReturn = None
                                      createdNodes = []
                                      errors = False
                                      try:
                                          # adds a callback to store every new object in the list 'createdNodes'
                                          functionReturn = func(*args, **kwargs)
                                      except:
                                          errors = True
                                      return functionReturn, createdNodes, errors
                                  return wrapper
                              
                              
                              if errors: #utilisateur
                                  raise



                              -
                              Edité par nolimitech 29 décembre 2016 à 6:07:39

                              • Partager sur Facebook
                              • Partager sur Twitter
                                29 décembre 2016 à 10:56:47

                                fruity' a écrit:

                                Si.

                                Non. Dans la phrase que tu cites, tu ne dis pas ce que tu souhaites faire quand l'erreur se produit (stocker les classes crées, ça se fait en amont).

                                Si tu souhaites que le programme s'arrête, à quoi pourra donc servir la liste des objets puisque personne ne sera là pour la prendre en charge ?

                                • Partager sur Facebook
                                • Partager sur Twitter
                                  29 décembre 2016 à 16:52:11

                                  Je lis et relis tes posts, et tout comme entwanne, je ne comprends pas ce que tu veux faire. J'essaie de reprendre pas à pas ce que tu as indiqué. Tout d'abord ton petit exemple du premier post:

                                  fruity' a écrit:

                                  @registerChanges
                                  def test():
                                      a = SomeObject()
                                      return True
                                  b = test()
                                  

                                  Par exemple, dans le cas present, b contiendra True et l'instance de a, creee dans la fonction.

                                  Exemple bizarre, puisque b ne contiendra que ce que retourne la fonction. Et elle ne retourne que True. l'objet SomeObject ayant été créé en local sera détruit lorsque la fonction retournera. Si au moins tu avais un truc du style return True, a, je pourrais comprendre. Mais là, pas vraiment...

                                  fruity' a écrit:

                                  Donc tout le probleme, c'est en cas d'erreur : je veux, en cas d'erreur, que l'erreur, quelle qu'elle soit, remonte jusqu'a l'utilisateur, mais je souhaite quand meme recuperer la liste contenant tous les elements qui ont ete crees pendant la fonction jusqu'a ce qu'elle atteigne l'erreur.

                                  Il faudrait comprendre comment les objets créés par la fonctions sont retournés. Avec les exemples que tu as donné, ils ne sont pas retournés. Donc la question est : dans ton cas concret où vont ces objets ?

                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    29 décembre 2016 à 20:00:49

                                    Dan, justement, je souhaitais que b return ce que retourne la fonction ET une autre variable, geree par le decorateur. Comme tu dis, l'instance de SomeObject() est detruite une fois sortie de la fonction, je voulais donc la 'relayer' au niveau de mon decorateur, qui changeait ce que la fonction return (puisque le True retourne par ma fonction test() est bien 'relaye', apres tout, dans le decorateur lui-meme)

                                    Quoiqu'il en soit, c'est bon, entwanne a rempli a merveille le role du canard en plastique, et j'ai pu regler mon probleme =]

                                    La solution n'etait pas un decorateur, mais un 'wrapper' de fonction, plus simplement. J'ai donc une fonction qui prend en premier argument une autre fonction, et en second argument une liste, qui est updatee au fur et a mesure puisque passee en reference, de sorte qu'en cas d'erreur, je recupere ma liste up to date, ET mon erreur est raise malgre tout.

                                    Merci beaucoup a ceux qui m'ont aide =]

                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                      30 décembre 2016 à 0:43:48

                                      fruity' a écrit:

                                      Quoiqu'il en soit, c'est bon, entwanne a rempli a merveille le role du canard en plastique, et j'ai pu regler mon probleme =]

                                      • Partager sur Facebook
                                      • Partager sur Twitter

                                      Return une value en cas d'erreur

                                      × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                      × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                                      • Editeur
                                      • Markdown