IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Python Discussion :

Gestion de bibliothèques dynamiques.


Sujet :

Python

  1. #1
    Membre à l'essai
    Homme Profil pro
    Inscrit en
    Mars 2011
    Messages
    19
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mars 2011
    Messages : 19
    Points : 14
    Points
    14
    Par défaut Gestion de bibliothèques dynamiques.
    Salut tout le monde.

    Je suis en train de développer un petit script qui a pour but de mettre à jour un nom de domaine en fonction de l'ip dynamique attribuée à l'hôte, un « no-ip » quoi. Pour la mise à jour du nom de domaine automatique, il faut passer par une API, qui elle dépend du provider chez lequel le nom de domaine a été acheté.

    J'ai donc eu l'idée de segmenter mon programme en module pour lui permettre de facilement pouvoir supporter d'autres providers. L'idée pour se faire, est d'utiliser un fichier de configuration de cette forme :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    [no-ip]
    domain_provider = gandi
    ip_resolver = spyzone
     
    [gandi]
    api_key = xxxxxxxxxxxx
    zone = xxxxxx
    subdomain_name = xxxxx
    L'idée est donc simple. La partie « no-ip » contient le nom des modules à utiliser pour gérer le nom de domaine ainsi que le site à interroger pour obtenir notre IP attribuée, et enfin, l'autre partie (ici « gandi » contient les informations nécessaire au bon fonctionnement du module de gestion du nom de domaine).

    Voici la source du script :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    def listToDico(list_):
    	dico_ = dict()
    	for configLine in list_:
    		dico_[configLine[0]] = configLine[1]
    	if len(dico_) == 0:
    		return None
    	return dico_
     
    import sys
    import syslog
    from configparser import SafeConfigParser
     
    syslog.syslog(syslog.LOG_INFO, "Launching of the no-ip script.")
     
    configParser = SafeConfigParser()
    configParser.read("noip.conf")
     
    # Generation of the configuration data.
    providerToUse = configParser.get("no-ip", "domain_provider")
    providerArgumentsInList = configParser.items(providerToUse)
    providerArgumentsInDico = listToDico(providerArgumentsInList)
    IPResolverToUse = configParser.get("no-ip", "ip_resolver")
     
    # We dynamically import modules setted in the noip.conf.
    locals()['urlManager'] = __import__("netsolver." + providerToUse)
    locals()['IPManager'] = __import__("netsolver." + IPResolverToUse)
     
    domainName = urlManager.gandi.GandiHostManager(providerArgumentsInDico)
    ipUsedNow = IPManager.spyzone.SpyzoneManager.getMyExternalIp()
     
    if (domainName.getCurrentIp() == ipUsedNow):
    	syslog.syslog(syslog.LOG_DEBUG, "IP address still good. No need to update.")
    else:
    	domainName.setNewIp(ipUsedNow)
    	syslog.syslog(syslog.LOG_INFO, "IP address updated with value: " + ipUsedNow)
     
    sys.exit(0)
    Aux lignes 25 et 26, nous chargeons dynamiquement les modules dont le nom est marqué dans la partie « no-ip » du fichier de configuration. Cette solution semble bonne car elle permet d'ajouter des modules sans avoir à toucher au script en lui même (il suffira d'ajouter son implémentation dans le dossier « netsolver »).

    Par contre, mon problème se situe aux lignes 28 et 29 : comment pourrais-je faire en sorte de me passer de la partie statique ? Il faut en effet, au moins que j'instancie un objet de la forme « GandiHostManager », ou « OVHHostManager », etc…
    À part avoir un tableau contenant statiquement ces nom dans mon script, je ne vois pas comment faire. Évidemment, la solution ne serait pas optimale car le script devra être modifié à chaque inclusion/exclusion de modules supportés…

    Si vous voyez comment faire, je suis preneur. Merci d'avance !

  2. #2
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Mars 2007
    Messages
    941
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2007
    Messages : 941
    Points : 1 384
    Points
    1 384
    Par défaut
    Salut,

    Citation Envoyé par spydemon Voir le message
    À part avoir un tableau contenant statiquement ces nom dans mon script, je ne vois pas comment faire. Évidemment, la solution ne serait pas optimale car le script devra être modifié à chaque inclusion/exclusion de modules supportés…
    Ben au lieu d'avoir le nom stocké dans un tableau dans ton module principal, tu pourrais simplement l'avoir dans chaque module "netsolver". Je veux dire par là que tous les modules "netsolver" implémenteraient une interface commune.
    Ca donnerait qqch comme ça dans le script principal:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    module_name = "netsolver." + providerToUse
    __import__(module_name)
    urlManager = sys.module[module_name]
     
    domainName = urlManager.getHostManager(providerArgumentsInDico)
    Et, au passage, pourquoi une assignation dans locals() ? locals()['urlManager'] = ..., c'est la même chose que urlManager = ..., non ?

  3. #3
    Membre à l'essai
    Homme Profil pro
    Inscrit en
    Mars 2011
    Messages
    19
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mars 2011
    Messages : 19
    Points : 14
    Points
    14
    Par défaut
    Citation Envoyé par dividee Voir le message
    Ben au lieu d'avoir le nom stocké dans un tableau dans ton module principal, tu pourrais simplement l'avoir dans chaque module "netsolver". Je veux dire par là que tous les modules "netsolver" implémenteraient une interface commune.
    Ca donnerait qqch comme ça dans le script principal:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    module_name = "netsolver." + providerToUse
    __import__(module_name)
    urlManager = sys.module[module_name]
     
    domainName = urlManager.getHostManager(providerArgumentsInDico)
    J'ai pas l'impression que ça fonctionne comme solution. En effet, les interfaces, c'est utile quand on veut utiliser des objets de différentes classes, mais qui sont déjà instanciés. Or ici, rien ne l'est pour le moment… À moins que j'appelle toutes mes classes « getHostManager ». Dans ce cas, le nom de la classe étant le même dans tous les modules, on pourra écrire l'instanciation statiquement comme tu le fais à la ligne 5. Mais c'est vrai que ça semble être la meilleure des solutions pour le moment. Je pense que je ferai comme ça, si on ne trouve rien de mieux.

    Citation Envoyé par dividee Voir le message
    Et, au passage, pourquoi une assignation dans locals() ? locals()['urlManager'] = ..., c'est la même chose que urlManager = ..., non ?
    Je ne m'y connais pas (encore) des masses en Python, et j'avoue avoir choisi cette solution parce que c'était la solution que j'avais trouvé en cherchant comment effectuer une importation dynamique de module. Effectivement, après une petite vérification, il semblerait que la fonction « locals() » retourne simplement un dictionnaire de toutes les variables déclarée localement. J'aurai du vérifier ça avant pour voir que c'était pas nécessaire d'alourdir le code comme ça, merci.

  4. #4
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Mars 2007
    Messages
    941
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2007
    Messages : 941
    Points : 1 384
    Points
    1 384
    Par défaut
    Oui, enfin, "getHostManager" ça doit pas forcément être le nom de la classe; ça peut être une fonction (factory) qui retourne une instance de la classe.

  5. #5
    Membre à l'essai
    Homme Profil pro
    Inscrit en
    Mars 2011
    Messages
    19
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mars 2011
    Messages : 19
    Points : 14
    Points
    14
    Par défaut
    Je pense avoir compris où tu voulais en venir, et j'ai donc modifié mes modules en conséquence, on ajoutant un objet similaire dans chaque modules. Voici par exemple GandiHostManager :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    import sys
    import xmlrpc.client
    import ipaddress
    import syslog
     
    class GandiHostManager(netsolver.hostmanager.HostManager):
             …
     
    class getHostManager (object):
    	def __new__(klass, argsForHostManager):
    		return GandiHostManager(argsForHostManager)
    Et mon noip.py appelle le module de cette façon :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    urlManager_name = "netsolver." + providerToUse
    __import__(urlManager_name)
    urlManager = sys.modules[urlManager_name]
    domainName = urlManager.getHostManager(providerArgumentsInDico)
    Et ça semble fonctionner. J'ai mis des print() de test, et le contenu est bien affiché. Seulement, j'ai un problème au passage de cette instruction dans GandiHostManager :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
             infoSubdomain = self.__api.domain.zone.record.list(self.__apikey, self.__zone, 0, self.__record)
    Qui me génère cette pile de debug au moment de l'exécution via ipython :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    ---------------------------------------------------------------------------
    Fault                                     Traceback (most recent call last)
    /usr/lib/python3.3/site-packages/IPython/utils/py3compat.py in execfile(fname, glob, loc)
         74     def execfile(fname, glob, loc=None):
         75         loc = loc if (loc is not None) else glob
    ---> 76         exec(compile(open(fname, 'rb').read(), fname, 'exec'), glob, loc)
         77 
         78     # Refactor print statements in doctests.
     
    /home/spydemon/depots/packages/no-ip/noip.py in <module>()
         45 ipUsedNow = IPManager.SpyzoneManager.getMyExternalIp()
         46 
    ---> 47 if (domainName.getCurrentIp() == ipUsedNow):
         48         syslog.syslog(syslog.LOG_DEBUG, "IP address still good. No need to update.")
         49 else:
     
    /home/spydemon/depots/packages/netsolver/gandi/netsolver/gandi.py in getCurrentIp(self)
         18         def getCurrentIp(self):
         19                 print("Test d'exécution.")
    ---> 20                 infoSubdomain = self.__api.domain.zone.record.list(self.__apikey, self.__zone, 0, self.__record)
         21                 ipAddressOfTheSubdomain = infoSubdomain[0]['value']
         22                 syslog.syslog(syslog.LOG_DEBUG, "Ip address returned for the subdomain name: " + self.__nameOfTheSubdomain + ": " + ipAddressOfTheSubdomain)
     
    /usr/lib/python3.3/xmlrpc/client.py in __call__(self, *args)
       1088         return _Method(self.__send, "%s.%s" % (self.__name, name))
       1089     def __call__(self, *args):
    -> 1090         return self.__send(self.__name, args)
       1091 
       1092 ##
     
    /usr/lib/python3.3/xmlrpc/client.py in __request(self, methodname, params)
       1417             self.__handler,
       1418             request,
    -> 1419             verbose=self.__verbose
       1420             )
       1421 
     
    /usr/lib/python3.3/xmlrpc/client.py in request(self, host, handler, request_body, verbose)
       1130         for i in (0, 1):
       1131             try:
    -> 1132                 return self.single_request(host, handler, request_body, verbose)
       1133             except socket.error as e:
       1134                 if i or e.errno not in (errno.ECONNRESET, errno.ECONNABORTED, errno.EPIPE):
     
    /usr/lib/python3.3/xmlrpc/client.py in single_request(self, host, handler, request_body, verbose)
       1145             if resp.status == 200:
       1146                 self.verbose = verbose
    -> 1147                 return self.parse_response(resp)
       1148 
       1149         except Fault:
     
    /usr/lib/python3.3/xmlrpc/client.py in parse_response(self, response)
       1316         p.close()
       1317 
    -> 1318         return u.close()
       1319 
       1320 ##
     
    /usr/lib/python3.3/xmlrpc/client.py in close(self)
        655             raise ResponseError()
        656         if self._type == "fault":
    --> 657             raise Fault(**self._stack[0])
        658         return tuple(self._stack)
        659 
     
    Fault: <Fault 500037: 'Error on object : OBJECT_UNKNOWN (CAUSE_BADPARAMETER) [invalid method parameter(s)]'>
    J'en déduis que le module xmlrpc est perdu avec ma gestion de la déclaration des objets, et donc que je ne dois pas faire les choses proprement.

  6. #6
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 435
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 435
    Points : 37 020
    Points
    37 020
    Par défaut
    Salut,
    Que fait la trace dans IPython?
    /usr/lib/python3.3/site-packages/IPython/...
    - W

  7. #7
    Membre à l'essai
    Homme Profil pro
    Inscrit en
    Mars 2011
    Messages
    19
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mars 2011
    Messages : 19
    Points : 14
    Points
    14
    Par défaut
    En parlant de traces, tu veux dire l'exécution du script via pdb, pour voir avec précision où ça plante ? (Ça ne me parait pas très parlant). ^^

    Mais si cela peut t'aider, voila ce que ça donne :

    Je place le début du mode debug une ligne avant l'instruction qui plante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    class GandiHostManager(netsolver.hostmanager.HostManager):
    	…
     
    	def getCurrentIp(self):
    		pdb.set_trace()
    		print("Test d'exécution.")
    		infoSubdomain = self.__api.domain.zone.record.list(self.__apikey, self.__zone, 0, self.__record)
    Et voici le retour à la console :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
     > /home/spydemon/depots/packages/netsolver/gandi/netsolver/gandi.py(21)getCurrentIp()
    -> print("Test d'exécution.")
    (Pdb) n
    Test d exécution.
    > /home/spydemon/depots/packages/netsolver/gandi/netsolver/gandi.py(22)getCurrentIp()
    -> infoSubdomain = self.__api.domain.zone.record.list(self.__apikey, self.__zone, 0, self.__record)
    (Pdb) s
    --Call--
    > /usr/lib/python3.3/xmlrpc/client.py(1435)__getattr__()
    -> def __getattr__(self, name):
    (Pdb) n
    > /usr/lib/python3.3/xmlrpc/client.py(1437)__getattr__()
    -> return _Method(self.__request, name)
    (Pdb) 
    --Return--
    > /usr/lib/python3.3/xmlrpc/client.py(1437)__getattr__()-><xmlrpc.clien...x7fd57403e8d0>
    -> return _Method(self.__request, name)
    (Pdb) 
    --Call--
    > /usr/lib/python3.3/xmlrpc/client.py(1087)__getattr__()
    -> def __getattr__(self, name):
    (Pdb) 
    > /usr/lib/python3.3/xmlrpc/client.py(1088)__getattr__()
    -> return _Method(self.__send, "%s.%s" % (self.__name, name))
    (Pdb) 
    --Return--
    > /usr/lib/python3.3/xmlrpc/client.py(1088)__getattr__()-><xmlrpc.clien...x7fd56f0b1b10>
    -> return _Method(self.__send, "%s.%s" % (self.__name, name))
    (Pdb) 
    --Call--
    > /usr/lib/python3.3/xmlrpc/client.py(1087)__getattr__()
    -> def __getattr__(self, name):
    (Pdb) 
    > /usr/lib/python3.3/xmlrpc/client.py(1088)__getattr__()
    -> return _Method(self.__send, "%s.%s" % (self.__name, name))
    (Pdb) 
    --Return--
    > /usr/lib/python3.3/xmlrpc/client.py(1088)__getattr__()-><xmlrpc.clien...x7fd57403e8d0>
    -> return _Method(self.__send, "%s.%s" % (self.__name, name))
    (Pdb) 
    --Call--
    > /usr/lib/python3.3/xmlrpc/client.py(1087)__getattr__()
    -> def __getattr__(self, name):
    (Pdb) 
    > /usr/lib/python3.3/xmlrpc/client.py(1088)__getattr__()
    -> return _Method(self.__send, "%s.%s" % (self.__name, name))
    (Pdb) 
    --Return--
    > /usr/lib/python3.3/xmlrpc/client.py(1088)__getattr__()-><xmlrpc.clien...x7fd56f0b1b10>
    -> return _Method(self.__send, "%s.%s" % (self.__name, name))
    (Pdb) 
    --Call--
    > /usr/lib/python3.3/xmlrpc/client.py(1089)__call__()
    -> def __call__(self, *args):
    (Pdb) 
    > /usr/lib/python3.3/xmlrpc/client.py(1090)__call__()
    -> return self.__send(self.__name, args)
    (Pdb) 
    xmlrpc.client.Fault: <Fault 500037: 'Error on object : OBJECT_UNKNOWN (CAUSE_BADPARAMETER) [invalid method parameter(s)]'>
    > /usr/lib/python3.3/xmlrpc/client.py(1090)__call__()
    -> return self.__send(self.__name, args)
    (Pdb) p self.__name
    <xmlrpc.client._Method object at 0x7fd56f0b1fd0>
    (Pdb) p args
    ('<api_key>', '<zone>', 0, {'name': '<subdomain_name', 'type': 'A'})

Discussions similaires

  1. [Software] Gestion de bibliothèque
    Par Wookai dans le forum Autres Logiciels
    Réponses: 4
    Dernier message: 02/05/2009, 15h44
  2. [C - Linux] Gestion bibliothèques dynamiques
    Par baptx dans le forum Linux
    Réponses: 2
    Dernier message: 09/01/2009, 13h22
  3. Problème avec la "Gestion des bibliothèques dynamiques"
    Par GoustiFruit dans le forum Delphi
    Réponses: 15
    Dernier message: 31/05/2006, 10h54
  4. [VB6] creation et gestion de contrôle dynamique
    Par olivierx dans le forum VB 6 et antérieur
    Réponses: 13
    Dernier message: 23/04/2004, 01h09
  5. Gestion de table dynamique access avec delphi 7
    Par bob.marley dans le forum Bases de données
    Réponses: 7
    Dernier message: 22/04/2004, 14h12

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo