3 votes

Répertoire local masquant le package tiers

Je suis en train de chercher à savoir s'il s'agit d'une erreur dans mon design, ou d'une erreur dans la bibliothèque redis-py. Essentiellement, ma compréhension de l'espace de noms en Python est que les packages devraient être conçus de telle sorte que tous les composants soient sous l'espace de noms du package. Cela signifie que si j'ai une file d'attente dans packageA et une file d'attente dans packageB, il ne devrait pas y avoir de collision car elles sont namespaced (packageA.queue et packageB.queue). Cependant, je rencontre une erreur dans un package que je suis en train de construire.

Voici la structure de répertoire pour le package que je suis en train de construire :

      arbre  
    .  
     __init__.py  
     net  
        __init__.py  
        rconn.py  
     test.py  

Les fichiers __init__.py sont tous vides. Voici le code de mon fichier test.py :

      cat test.py
    from net import rconn

et voici le code de mon fichier net/rconn.py :

      cat net/rconn.py
    import redis

En exécutant test.py, tout fonctionne, pas d'erreurs. Cependant, si j'ajoute un répertoire queue ici et que je crée un init.py vide à l'intérieur, voici le nouvel arbre :

      arbre  
    .  
     __init__.py  
     net  
       __init__.py  
       rconn.py  
     queue  
       __init__.py  
     test.py  

Exécuter test.py entraîne l'erreur suivante :

    Traceback (most recent call last):
      File "test.py", line 1, in 
        from net.rconn import ass
      File "/Users/yosoyunmaricon/python_test/net/rconn.py", line 1, in 
        import redis
      File "/usr/local/lib/python3.7/site-packages/redis/__init__.py", line 1, in 
        from redis.client import Redis, StrictRedis
      File "/usr/local/lib/python3.7/site-packages/redis/client.py", line 10, in 
        from redis._compat import (b, basestring, bytes, imap, iteritems, iterkeys,
      File "/usr/local/lib/python3.7/site-packages/redis/_compat.py", line 139, in 
        from queue import Queue
    ImportError: cannot import name 'Queue' from 'queue' (/Users/yosoyunmaricon/python_test/queue/__init__.py)

Donc, je comprends ce qui se passe. Le code Redis dit from queue import Queue, et lorsque je crée un répertoire queue vide (c'est-à-dire, sans Queue), cela casse le package. Ma question est la suivante : Est-ce un bon design ? Est-ce que le package Redis devrait être plus explicite et dire quelque chose du genre from redis.queue import Queue, ou s'agit-il simplement d'une erreur dans mon propre design ?

1voto

Gino Mempin Points 1471

Il ne faut pas ajuster ici le package Redis, car il ne peut pas savoir ou gérer les différentes façons dont les utilisateurs pourraient intégrer le package Redis dans leurs propres applications, comme vous avez un package nommé de manière similaire. De plus, il n'y a pas de redis.queue car ce queue ne fait pas partie de redis, mais du package Python intégré queue. Vous pouvez aller à /usr/local/lib/python3.7/site-packages/redis/_compat.py et afficher le queue.__file__, qui vous donnerait le chemin vers le queue de Python. Il s'attend à importer le package queue intégré.

Malheureusement pour vous, lorsque Python construit les chemins de recherche de modules pour résoudre les imports, il les construit dans l'ordre suivant :

  • Le répertoire contenant le script d'entrée (ou le répertoire actuel lorsqu'aucun fichier n'est spécifié).
  • PYTHONPATH (une liste de noms de répertoires, avec la même syntaxe que la variable d'environnement shell PATH).
  • La valeur par défaut dépendante de l'installation.

...ce qui place votre propre queue au début de la liste et c'est ce qui est importé. Donc, oui, obtenir une ImportError parce que vous avez masqué le queue intégré est plutôt une erreur dans votre propre conception.

Vous pourriez probablement jouer avec sys.path ou PYTHONPATH ici, mais pourquoi vous embêter quand vous pouvez simplement renommer votre queue en quelque chose d'autre. Ou, ce que je fais généralement, c'est regrouper mes propres packages dans un dossier parent, nommé d'après l'acronyme du projet ("abcdlibs") ou un identifiant d'application ou quelque chose comme "mylibs":

.
 __init__.py
 mylibs
    queue
        __init__.py
 mynet
    __init__.py
    rconn.py
 test.py

De cette façon, vous pourriez clarifier que mylibs.queue est différent de queue.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X