Como escrever setup.py para incluir um repositório Git como uma dependência

100

Estou tentando escrever setup.pypara o meu pacote. Meu pacote precisa especificar uma dependência de outro repositório Git.

Isso é o que eu tenho até agora:

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,
)

Quando eu corro:

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

eu recebo

Não foi possível encontrar uma versão que satisfaça o requisito SomePrivateLib> = 0.1.0 (da análise) (das versões:) Nenhuma distribuição correspondente encontrada para SomePrivateLib> = 0.1.0 (da análise)

O que estou fazendo errado?

Ankur Agarwal
fonte
Observe que setup.py e pip são sistemas completamente diferentes. Um problema que eu tive foi que consegui fazer isso funcionar para o pip, mas não para o setup.py.
bcattle

Respostas:

51

Você pode encontrar a maneira certa de fazer isso aqui .

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

A chave não é fornecer um link para um repositório Git, mas um link para um tarball. O GitHub cria um tarball do branch master para você, se você anexar /tarball/masterconforme mostrado acima.

cel
fonte
17
parece que este método está obsoleto por github.com/pypa/pip/issues/3939
muon
3
Este método também é inútil para repositórios privados, já que não há como autenticar.
tedivm de
3
Consegui fazê-lo funcionar e acrescentei outra resposta.
tedivm de
1
O /tarball/mastermétodo não funciona para gitlab
Martin Thoma
5
Descontinuada. A resposta correta é usar Pep508, respondida por @Dick Fox abaixo
SwimBikeRun
117

Depois de vasculhar o problema 3939 do pip vinculado por @muon nos comentários acima e, em seguida, a especificação PEP-508 , tive sucesso ao instalar minha dependência de repo privada setup.pyusando este padrão de especificação em install_requires(não mais dependency_links):

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

O @v1.1indica a tag de lançamento criada no github e pode ser substituída por um branch, commit ou tipo diferente de tag.

Dick Fox
fonte
Nota: Isso funciona bem para pacotes locais / privados, no entanto, você não pode lançar um pacote para PyPI que usa esta sintaxe em sua configuração.py
Brian
7
@Brian Você poderia fornecer um link para a declaração oficial?
Elephant
12
Observe que você pode fazer git+https://github.comse não quiser usar SSH.
multithr3at3d
2
Então, qual é a abordagem correta para fazer um --upgrade? Embora eu especifique uma versão de tag, uma atualização apenas ignora as versões de tag mais recentes
Piacenti
1
@Elephant Não é superoficial, mas são pelo menos comentários sobre o projeto pip do GitHub de membros reais do PyPA: github.com/pypa/pip/issues/4187#issuecomment-415667805 e mais explicações: github.com/pypa/pip / issues / 4187 # issuecomment-415067034
Dominick Pastore
21

A resposta a seguir está obsoleta para Pip 19+


Infelizmente, a outra resposta não funciona com repositórios privados, que é um dos casos de uso mais comuns para isso. Acabei fazendo com que funcionasse com um setup.pyarquivo parecido com este:

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'
    ]
)

As versões mais recentes do pip tornam isso ainda mais fácil, removendo a necessidade 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
fonte
1
você poderia explicar o que -0.1significa em sua abordagem? Você pega o número da versão de um lançamento git ou da setup.pydescrição?
Peteris
2
A partir do arquivo setup.py - se você quiser usar um branch ou tag específico, formate as coisas de maneira um pouco diferente.
tedivm
"Infelizmente, a outra resposta não funciona com repositórios privados" Esta não é mais verdade. A resposta da Fox funciona em repositórios privados sem necessidade dependency_links(que está obsoleto )
Keto
Obrigado @Keto! Não sei por que sua edição foi rejeitada, exceto os mods, mas fui em frente e ignorei essa rejeição para adicionar o aviso de depreciação à resposta.
tedivm
3

Uma resposta mais geral: Para obter as informações do arquivo requirements.txt, eu faço:

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
fonte
1

Na verdade, se você deseja tornar seus pacotes instaláveis ​​recursivamente (Seu Pacote Atual inclui sua SomePrivateLib), por exemplo, quando você deseja incluir Seu Pacote Atual em outro (como Pacote Externo → Seu Pacote Atual → AlgumLibPrivado), você precisará de 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"
]

E certifique-se de ter criado uma tag com o número da sua versão.

Além disso, se o seu projeto Git for privado e você gostar de instalá-lo dentro do contêiner, por exemplo, um Docker ou GitLab runner, você precisará de acesso autorizado ao seu repositório. Considere usar Git + HTTPS com tokens de acesso (como no 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
fonte
0

Tive sucesso com essas três opções no GitLab . Estou usando a versão 11 do GitLab.

Opção 1 - nenhum token especificado. O shell solicitará o nome de usuário / senha.

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"
    ]
)

Opção 2 - token de acesso do usuário especificado. O token gerado acessando GitLab → parte superior direita da conta → configurações → tokens de acesso. Crie o token com direitos read_repository.

Exemplo:

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"
    ]
)

Opção 3 - token de nível de repositório especificado. O token gerado acessando o repositório → configurações → repositório → implantar tokens. A partir daqui, crie um token com direitos read_repository.

Exemplo:

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"
    ]
)

Em todos os três, eu era capaz de fazer simplesmente: "SomePrivateLib @ git + https: //gitlab.server.com/abc/SomePrivateLib.git" sem a marcação #egg no final.

ErikW
fonte