4
votes

Pourquoi le package Python ne s'installe-t-il pas à partir de mon serveur PyPI personnel?

J'ai créé un serveur de "packages" PyPI personnel sur une boîte Debian 9 / Nginx pour que je puisse rendre les constructions de mon serveur déterministes. J'épingle tous mes packages Python et je dois m'assurer que les versions exactes de mes packages Python ainsi que leurs sous-dépendances sont toujours disponibles chaque fois que j'ai besoin de reconstruire mes serveurs de commerce électronique.

J'ai rempli ce serveur avec mes packages requis à l'aide du package pip2pi . Mais lorsque j'exécute la commande "pip install" sur un serveur client pour installer mes packages, j'obtiens l'erreur suivante:

Created temporary directory: /tmp/pip-ephem-wheel-cache-g_hx5tb1
Created temporary directory: /tmp/pip-req-tracker-1bt5psaw
Created requirements tracker '/tmp/pip-req-tracker-1bt5psaw'
Created temporary directory: /tmp/pip-install-dqvtv6ek
Looking in indexes: https://packages.example.com/simple/
Collecting django-rq
  1 location(s) to search for versions of django-rq:
  * https://packages.example.com/simple/django-rq/
  Getting page https://packages.example.com/simple/django-rq/
  Looking up "https://packages.example.com/simple/django-rq/" in the cache
  Request header has "max_age" as 0, cache bypassed
  Starting new HTTPS connection (1): packages.example.com:443
  https://packages.example.com:443 "GET /simple/django-rq/ HTTP/1.1" 304 0
  Analyzing links from page https://packages.example.com/simple/django-rq/
    Skipping link https://packages.example.com/simple/django-rq/django-rq-0.9.0-py2.py3-none-any.whl (from https://packages.example.com/simple/django-rq/); wrong project name (not django-rq)
Cleaning up...
Removed build tracker '/tmp/pip-req-tracker-1bt5psaw'
Exception information:
Traceback (most recent call last):
  File "/home/flaugher/pip3/venv/lib/python3.5/site-packages/pip/_internal/cli/base_command.py", line 179, in main
    status = self.run(options, args)
  File "/home/flaugher/pip3/venv/lib/python3.5/site-packages/pip/_internal/commands/install.py", line 315, in run
    resolver.resolve(requirement_set)
  File "/home/flaugher/pip3/venv/lib/python3.5/site-packages/pip/_internal/resolve.py", line 131, in resolve
    self._resolve_one(requirement_set, req)
  File "/home/flaugher/pip3/venv/lib/python3.5/site-packages/pip/_internal/resolve.py", line 294, in _resolve_one
    abstract_dist = self._get_abstract_dist_for(req_to_install)
  File "/home/flaugher/pip3/venv/lib/python3.5/site-packages/pip/_internal/resolve.py", line 242, in _get_abstract_dist_for
    self.require_hashes
  File "/home/flaugher/pip3/venv/lib/python3.5/site-packages/pip/_internal/operations/prepare.py", line 269, in prepare_linked_requirement
    req.populate_link(finder, upgrade_allowed, require_hashes)
  File "/home/flaugher/pip3/venv/lib/python3.5/site-packages/pip/_internal/req/req_install.py", line 196, in populate_link
    self.link = finder.find_requirement(self, upgrade)
  File "/home/flaugher/pip3/venv/lib/python3.5/site-packages/pip/_internal/index.py", line 688, in find_requirement
    'No matching distribution found for %s' % req
pip._internal.exceptions.DistributionNotFound: No matching distribution found for django-rq

J'ai environ 40 packages dans mes besoins fichier, ce n'est donc qu'un exemple de ce qui se passe. Le package Django sera installé mais pip échouera avec le package django-extensions.

Si j'exécute cette commande sur l'un de mes serveurs clients, j'obtiens l'erreur ci-dessus:

pip install --verbose --index-url=https://packages.example.com/simple/ django-rq

Le fichier d'exigences ressemble à ceci:

directory: simple/django-redis-cache
file: django-redis-cache-1.6.5.tar.gz

Maintenant, sur mon serveur de packages, le répertoire racine du package, / var / www / packages, contient les éléments suivants structure:

directory: simple/django-rq
file: django_rq-0.9.0-py2.py3-none-any.whl

Cette structure de répertoire a été construite et les packages installés à l'aide de la commande pip2tgz de pip2pi:

pip install --index-url=https://packages.example.com/simple/ django-extensions
Looking in indexes: https://packages.example.com/simple/
Collecting django-extensions
  Could not find a version that satisfies the requirement django-extensions (from versions: )
No matching distribution found for django-extensions

Voici les exigences fichier d'entrée lu par pip2tgz:

server {
    ...
    root /var/www/packages;
    ...
}

Voici comment le répertoire racine nginx est défini sur le serveur de packages:

-i https://pypi.org/simple
django==1.8.4
django-extensions=1.5.7
(more packages)

Le pare-feu de mon serveur de paquets est configuré pour autoriser les pings, me permettre d'accéder à SSH et à toutes les connexions http et https.

J'utilise Python 3.5.3 et pip 19.0.3 sur mes serveurs clients .

Je ne suis pas sûr de ce que je fais de mal. La commande pip semble correcte mais je me demande si le package pip2pi configure correctement mes répertoires de packages. Si je modifie l'argument d'index dans le fichier d'exigences de mon client par défaut, https://pypi.org/simple , tous les packages sont restaurés sans erreur.

MISE À JOUR 1

Si j'essaie d'installer django-extensions à partir de la ligne de commande au lieu de via un fichier d'exigences, je toujours une erreur:

pip2tgz /var/www/packages/ -r requirements.txt

En examinant mes autres paquets, je vois un modèle ici. L'erreur se produit chaque fois que j'essaie d'installer un package dans lequel le nom du fichier wheel contient un trait de soulignement ("_") mais le nom normalisé du répertoire du package contient un hypen ("-") par Python PEP 503.

Par exemple, django-rq échoue:

# /var/www/packages:
├── Django-1.8.4-py2.py3-none-any.whl
├── django_extensions-1.5.7-py2.py3-none-any.whl
├── simple
    ├── django
    │   ├── Django-1.8.4-py2.py3-none-any.whl -> ../../Django-1.8.4-py2.py3-none-any.whl
    │   └── index.html
    ├── django-extensions
    │   ├── django-extensions-1.5.7-py2.py3-none-any.whl -> ../../django_extensions-1.5.7-py2.py3-none-any.whl
    │   └── index.html
    ├── index.html

D'un autre côté, django-redis-cache n'échoue pas:

-i https://packages.example.com/simple
Django==1.8.4
django-extensions==1.5.7
(more packages)

Voici l'erreur:

pip install -r requirements.txt

La clé semble être la ligne 15 où il est dit "Ignorer le lien ... nom de projet incorrect ( pas django-rq). " Je ne sais pas pourquoi il ignore le lien.


5 commentaires

Qu'est-ce que vous obtenez lorsque vous ouvrez https://packages.example.com/simple dans votre navigateur?


Comme vous vous en doutez, j'obtiens une liste de liens vers les fichiers wheel pour tous les packages installés sur le serveur de packages.


alors tout me va bien. essayez de spécifier l'option --extra-index-url pour installer pip à la ligne de commande


J'ai essayé mais j'obtiens toujours une erreur. Voir MISE À JOUR à la fin de ma question ci-dessus. Merci pour la suggestion.


On dirait que pip2pi envoie un nom de projet incorrect si les tirets sont remplacés par des traits de soulignement dans le nom du package. Je ne sais pas si renommer les roues (par exemple django_extensions en django-extensions ) aidera, mais je conseillerais également de passer de pip2pi à devpi (voir la réponse de @ wim) si le serveur a des difficultés avec la substitution de nom de paquet.


3 Réponses :


1
votes

Pour mon serveur de paquets privé, la seule chose qui fonctionnait était --extra-index-url:

--extra-index-url https://foo.redacted.com/
Django
my_other_package

Cela vérifiera d'abord pypi, puis votre serveur privé. Une chose qui a aidé à le déboguer est d'utiliser --verbose pour montrer ce qui se passe avec la connexion.


2 commentaires

L'ajout de l'argument détaillé est utile pour le débogage. Mais utiliser '--extra-index-url' au lieu de '--index-url' va à l'encontre de mon objectif car cela entraîne l'installation de la dernière version du paquet plutôt que de ma (ancienne) version épinglée.


Idée stupide; pourquoi ne pas simplement définir le numéro de version de votre package personnalisé sur quelque chose qui n'existe pas dans le référentiel normal? Ensuite, vous pouvez simplement utiliser --extra-index-url car cette version ne sera pas trouvée dans le référentiel pypi normal



1
votes

Il semble que le projet pip2pi que vous utilisez est bogué et n'a pas été maintenu récemment, avec plusieurs problèmes ouverts concernant les points / tirets dans les noms de distribution:

Problème avec les packages avec tiret dans le nom # 84

Correction d'une normalisation incorrecte des noms de fichiers binaires pour les paquets avec des tirets dans les noms # 67 < / p>

Modification de dir2pi pour utiliser le nom de fichier d'origine dans le lien de fichier. # 85

Je recommande plutôt de consulter devpi-server .


4 commentaires

Je travaille maintenant sur le didacticiel, mais il semblerait que le devpi crée un miroir de tout l'index PyPI, ce qui n'est pas ce que je veux. Cela me permettra-t-il de créer un index privé compatible PyPI sur mon serveur de packaging qui ne contient que la quarantaine de packages spécifiques dont j'ai besoin dans les versions dont j'ai besoin? Idéalement, j'ai besoin d'un outil qui prendra un fichier requirements.txt contenant une liste de packages épinglés, et n'installe que ces packages (de préférence leurs roues) sur mon serveur de packaging. Je ne veux pas refléter tout PyPI et ensuite installer les dernières versions de mes packages.


La mise en miroir de PyPI est une option de configuration pour devpi-server . Vous pouvez désactiver cela si vous ne le souhaitez pas.


Bien que très élégant et bien documenté, devpi ne semble pas être une bonne solution pour mes besoins. devppi semble davantage orienté vers une équipe de développement développant des packages Python. Je suis développeur solo avec une application web Python / Django. Je n'ai pas de fichier setup.py et je n'utilise pas tox. J'ai un fichier d'exigences que je transmets à virtualenv ou pipenv pour créer mon environnement virtuel. J'ai juste besoin d'un index PyPI privé où je peux télécharger des versions spécifiques de mes packages Python requis et rien de plus. Mais j'apprécie la suggestion.


Jim, pourquoi ne pas utiliser simplement un répertoire local, alors? Ou un partage réseau monté? Pip prend également en charge les chemins locaux pour «l'url d'index».



0
votes

Il semble que pypi-server répondra le mieux à mes besoins. Il réussit à installer les packages sur lesquels pip2pi a échoué comme je l'ai décrit ci-dessus. Ce n'est pas trop compliqué à configurer et il peut être exécuté sur un serveur distant via Nginx ou Apache. J'ai trouvé cet article Configurer un serveur PyPI très utile (bien qu'il y ait eu quelques fautes de frappe).


0 commentaires