Cómo escribir setup.py para incluir un repositorio de git como dependencia

95

Estoy intentando escribir setup.pypara mi paquete. Mi paquete necesita especificar una dependencia en otro repositorio de git.

Esto es lo que tengo hasta ahora:

from setuptools import setup, find_packages

setup(
    name='abc',
    packages=find_packages(),
    url='https://github.abc.com/abc/myabc',
    description='This is a description for abc',
    long_description=open('README.md').read(),
    install_requires=[
        "requests==2.7.0",
        "SomePrivateLib>=0.1.0",
        ],
    dependency_links = [
     "git+git://github.abc.com/abc/SomePrivateLib.git#egg=SomePrivateLib",
    ],
    include_package_data=True,
)

Cuando corro:

pip install -e https://github.abc.com/abc/myabc.git#egg=analyse

yo obtengo

No se pudo encontrar una versión que satisfaga el requisito SomePrivateLib> = 0.1.0 (de analizar) (de versiones :) No se encontró una distribución coincidente para SomePrivateLib> = 0.1.0 (de analizar)

Qué estoy haciendo mal ?

Ankur Agarwal
fuente
Tenga en cuenta que setup.py y pip son sistemas completamente diferentes. Un problema que tuve fue que pude hacer que esto funcionara para pip pero no para setup.py.
ganado

Respuestas:

50

Puede encontrar la forma correcta de hacerlo aquí .

dependency_links=['http://github.com/user/repo/tarball/master#egg=package-1.0']

La clave no es dar un enlace a un repositorio de git, sino un enlace a un tarball. Github crea un tarball de la rama maestra para usted si agrega /tarball/mastercomo se muestra arriba.

cel
fuente
17
parece que este método está obsoleto según github.com/pypa/pip/issues/3939
muon
2
Este método también es inútil para los repositorios privados, ya que no hay forma de autenticarse.
tedivm
3
Me las arreglé para que funcionara y agregué otra respuesta.
tedivm
1
El /tarball/mastermétodo no funciona para gitlab
Martin Thoma
3
Obsoleto. La respuesta correcta es usar Pep508, respondido por @Dick Fox a continuación
SwimBikeRun
104

Después de investigar el problema de pip 3939 vinculado por @muon en los comentarios anteriores y luego la especificación PEP-508 , encontré éxito al instalar mi dependencia de repositorio privado mediante el setup.pyuso de este patrón de especificación en install_requires(no más dependency_links):

install_requires = [
  'some-pkg @ git+ssh://[email protected]/someorgname/[email protected]#egg=some-pkg',
]

El @v1.1indica la etiqueta de versión creado en github y podría sustituirse con una rama, cometer, o diferente tipo de etiqueta.

Dick Fox
fuente
Nota: Esto funciona bien para paquetes locales / privados, sin embargo, no puede lanzar un paquete a PyPI que use esta sintaxis en su setup.py
Brian
7
@Brian ¿Podría proporcionar un enlace a la declaración oficial?
Elefante
11
Tenga en cuenta que puede hacerlo git+https://github.comsi no desea utilizar SSH.
multithr3at3d
2
Entonces, ¿cuál es el enfoque correcto para hacer una actualización? Aunque especifico una versión de etiqueta, una actualización simplemente ignora las versiones de etiqueta más nuevas
Piacenti
1
@Elephant No es súper oficial, pero estos son al menos comentarios sobre el proyecto pip GitHub de miembros reales de PyPA: github.com/pypa/pip/issues/4187#issuecomment-415667805 y más explicación: github.com/pypa/pip / issues / 4187 # issuecomment-415067034
Dominick Pastore
19

La siguiente respuesta está obsoleta para Pip 19+


Desafortunadamente, la otra respuesta no funciona con repositorios privados, que es uno de los casos de uso más comunes para esto. Finalmente lo hice funcionar con un setup.pyarchivo que se ve así:

from setuptools import setup, find_packages

setup(
    name = 'MyProject',
    version = '0.1.0',
    url = '',
    description = '',
    packages = find_packages(),
    install_requires = [
        # Github Private Repository - needs entry in `dependency_links`
        'ExampleRepo'
    ],

    dependency_links=[
        # Make sure to include the `#egg` portion so the `install_requires` recognizes the package
        'git+ssh://[email protected]/example_organization/ExampleRepo.git#egg=ExampleRepo-0.1'
    ]
)

Las versiones más nuevas de pip hacen que esto sea aún más fácil al eliminar la necesidad de usar "dependency_links" -

from setuptools import setup, find_packages

setup(
    name = 'MyProject',
    version = '0.1.0',
    url = '',
    description = '',
    packages = find_packages(),
    install_requires = [
        # Github Private Repository
        'ExampleRepo @ git+ssh://[email protected]/example_organization/ExampleRepo.git#egg=ExampleRepo-0.1'
    ]
)
tedivm
fuente
1
¿Podría por favor explicar qué -0.1representa su enfoque? ¿Toma el número de versión de una versión de git o de la setup.pydescripción?
Peteris
2
Desde el archivo setup.py: si desea utilizar una rama o etiqueta específica, formatee las cosas de manera un poco diferente.
tedivm
"Desafortunadamente, la otra respuesta no funciona con repositorios privados". Esto ya no es cierto. La respuesta de Fox funciona en repositorios privados sin necesidad dependency_links(que está en desuso )
Keto
¡Gracias @Keto! No sé por qué su edición fue rechazada, pero las modificaciones, pero seguí adelante y anulé ese rechazo para agregar el aviso de desaprobación a la respuesta.
tedivm
3

Una respuesta más general, para obtener la información del archivo requeriments.txt, hago:

from setuptools import setup, find_packages
from os import path

loc = path.abspath(path.dirname(__file__))

with open(loc + '/requirements.txt') as f:
    requirements = f.read().splitlines()

required = []
dependency_links = []
# do not add to required lines pointing to git repositories
EGG_MARK = '#egg='
for line in requirements:
    if line.startswith('-e git:') or line.startswith('-e git+') or \
            line.startswith('git:') or line.startswith('git+'):
        if EGG_MARK in line:
            package_name = line[line.find(EGG_MARK) + len(EGG_MARK):]
            required.append(package_name)
            dependency_links.append(line)
        else:
            print('Dependency to a git repository should have the format:')
            print('git+ssh://[email protected]/xxxxx/xxxxxx#egg=package_name')
    else:
        required.append(line)

setup(
    name='myproject',  # Required
    version='0.0.1',  # Required
    description='Description here....',  # Required
    packages=find_packages(),  # Required
    install_requires=required,
    dependency_links=dependency_links,
) 
Gonzalo Odiard
fuente
1

En realidad, si desea que sus paquetes se puedan instalar de forma recursiva (YourCurrentPackage incluye su SomePrivateLib), por ejemplo, cuando desee incluir YourCurrentPackage en otro (como OuterPackage -> YourCurrentPackage -> SomePrivateLib), necesitará ambos:

install_requires=[
    ...,
    "SomePrivateLib @ git+ssh://github.abc.com/abc/[email protected]#egg=SomePrivateLib"
],
dependency_links = [
    "git+ssh://github.abc.com/abc/[email protected]#egg=SomePrivateLib"
]

Y asegúrese de tener una etiqueta creada con su número de versión.

Además, si su proyecto git es privado y desea instalarlo dentro del contenedor, por ejemplo, Docker o GitLab runner, necesitará acceso autorizado a su repositorio. Considere usar git + https con tokens de acceso (como en GitLab: https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html ):

import os
from setuptools import setup

TOKEN_VALUE = os.getenv('EXPORTED_VAR_WITH_TOKEN')

setup(
    ....

    install_requires=[
            ...,
            f"SomePrivateLib @ git+https://gitlab-ci-token:{TOKEN_VALUE}@gitlab.server.com/abc/[email protected]#egg=SomePrivateLib"
    ],
    dependency_links = [
            f"git+https://gitlab-ci-token:{TOKEN_VALUE}@gitlab.server.com/abc/[email protected]#egg=SomePrivateLib"
    ]
)
darencorp
fuente
0

Tuve éxito con estas 3 opciones en gitlab. Estoy usando la versión 11 de gitlab.

opción 1: no se especifica ningún token. shell le pedirá nombre de usuario / contraseña.

from setuptools import setup

TOKEN_VALUE = os.getenv('EXPORTED_VAR_WITH_TOKEN')

setup(
    install_requires=[
        "SomePrivateLib @ git+https://gitlab.server.com/abc/[email protected]#egg=SomePrivateLib"
    ]
)

opción 2: token de acceso de usuario especificado. token generado yendo a gitlab> cuenta arriba a la derecha> configuración> tokens de acceso. crear token con derechos read_repository.

ejemplo:

import os
from setuptools import setup

TOKEN_VALUE = os.getenv('EXPORTED_VAR_WITH_TOKEN')

setup(
    install_requires=[
        f"SomePrivateLib @ git+https://gitlab-ci-token:{TOKEN_VALUE}@gitlab.server.com/abc/[email protected]#egg=SomePrivateLib"
    ]
)

opción 3: token de nivel de repositorio especificado. token generado yendo al repositorio> configuración> repositorio> implementar tokens. desde aquí cree un token con derechos read_repository.

ejemplo:

import os
from setuptools import setup

TOKEN_USER = os.getenv('EXPORTED_TOKEN_USER')
TOKEN_VALUE = os.getenv('EXPORTED_VAR_WITH_TOKEN')

setup(
    install_requires=[
        f"SomePrivateLib @ git+https://{TOKEN_USER}:{TOKEN_VALUE}@gitlab.server.com/abc/[email protected]#egg=SomePrivateLib"
    ]
)

En los 3, pude hacer simplemente: "SomePrivateLib @ git + https: //gitlab.server.com/abc/SomePrivateLib.git" sin la marca #egg al final.

ErikW
fuente