Jak napisać plik setup.py, aby dołączyć repozytorium Git jako zależność

100

Próbuję pisać setup.pydla mojej paczki. Mój pakiet musi określać zależność od innego repozytorium Git.

Oto, co mam do tej pory:

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

Kiedy biegam:

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

dostaję

Nie można znaleźć wersji spełniającej wymaganie SomePrivateLib> = 0.1.0 (z analizy) (z wersji:) Nie znaleziono pasującej dystrybucji dla SomePrivateLib> = 0.1.0 (z analizy)

Co ja robię źle?

Ankur Agarwal
źródło
Zauważ, że setup.py i pip to zupełnie różne systemy. Jednym z problemów, które miałem, było to, że udało mi się to uruchomić dla pip, ale nie dla setup.py.
bcattle

Odpowiedzi:

51

Można znaleźć właściwą drogę, aby to zrobić tutaj .

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

Kluczem nie jest podanie linku do repozytorium Git, ale łącze do archiwum. GitHub tworzy dla Ciebie archiwum z gałęzi master, jeśli dodasz /tarball/masterjak pokazano powyżej.

cel
źródło
17
Wygląda na to, metoda jest przestarzała za github.com/pypa/pip/issues/3939
mion
3
Ta metoda jest również bezużyteczna w przypadku prywatnych repozytoriów, ponieważ nie ma możliwości uwierzytelnienia.
tedivm
3
Udało mi się to uruchomić i dodałem inną odpowiedź.
tedivm
1
Ta /tarball/mastermetoda nie działa w przypadku gitlab
Martin Thoma
5
Przestarzałe. Prawidłowa odpowiedź to użycie Pep508, na co odpowiada @Dick Fox poniżej
SwimBikeRun
117

Po przejrzeniu problemu z pipem 3939 połączonego przez @muon w komentarzach powyżej, a następnie specyfikacji PEP-508 , udało mi się zainstalować moją zależność od prywatnego repozytorium za setup.pypomocą tego wzorca specyfikacji w install_requires(nie więcej dependency_links):

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

@v1.1Wskazuje tag uwalniania utworzonego na github i można zastąpić oddział, popełnienia lub innego rodzaju tagu.

Dick Fox
źródło
Uwaga: Działa to dobrze w przypadku pakietów lokalnych / prywatnych, jednak nie możesz wydać pakietu do PyPI, który używa tej składni w swoim pliku setup.py
Brian
7
@Brian Czy mógłbyś podać link do oficjalnego oświadczenia?
Elephant
12
Pamiętaj, że możesz to zrobić, git+https://github.comjeśli nie chcesz używać SSH.
multithr3at3d
2
Jakie jest więc właściwe podejście do - uaktualnienia? Mimo że określam wersję tagu, aktualizacja po prostu ignoruje nowsze wersje tagów
Piacenti,
1
@Elephant Niezbyt oficjalne, ale są to przynajmniej komentarze na temat projektu pip GitHub od rzeczywistych członków PyPA: github.com/pypa/pip/issues/4187#issuecomment-415667805 i dalsze wyjaśnienie: github.com/pypa/pip / Issues / 4187 # issuecomment-415067034
Dominick Pastore
21

Poniższa odpowiedź jest przestarzała dla Pip 19+


Niestety druga odpowiedź nie działa z prywatnymi repozytoriami, co jest jednym z najczęstszych przypadków użycia. W końcu udało mi się go uruchomić z setup.pyplikiem, który wygląda następująco:

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

Nowsze wersje pip sprawiają, że jest to jeszcze łatwiejsze, eliminując potrzebę używania „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
źródło
1
czy mógłbyś wyjaśnić, co -0.1reprezentuje twoje podejście? Czy bierzesz numer wersji z wydania git czy z setup.pyopisu?
Peteris
2
Z pliku setup.py - jeśli chcesz użyć określonej gałęzi lub tagu, formatujesz rzeczy trochę inaczej.
tedivm
„Niestety, druga odpowiedź nie działa z prywatnymi repozytoriami” To już nie jest prawda . Odpowiedź Foxa działa na prywatnym repozytorium bez konieczności dependency_links(co jest przestarzałe )
Keto
Dzięki @Keto! Nie wiem, dlaczego Twoja zmiana została odrzucona, ale modyfikacje, ale poszedłem dalej i zastąpiłem to odrzucenie, aby dodać informację o wycofaniu do odpowiedzi.
tedivm
3

Bardziej ogólna odpowiedź: Aby uzyskać informacje z pliku requirements.txt :

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
źródło
1

Właściwie, jeśli chcesz, aby Twoje pakiety były instalowane rekurencyjnie (YourCurrentPackage zawiera Twój SomePrivateLib), np. Gdy chcesz dołączyć YourCurrentPackage do innego (np. OuterPackage → YourCurrentPackage → SomePrivateLib), potrzebujesz obu:

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

I upewnij się, że masz utworzony tag z numerem wersji.

Również jeśli Twój projekt Git jest prywatny i chcesz zainstalować go wewnątrz kontenera, np. Docker lub GitLab runner, będziesz potrzebować autoryzowanego dostępu do swojego repozytorium. Rozważ użycie Git + HTTPS z tokenami dostępu (jak na 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
źródło
0

Udało mi się z tymi trzema opcjami w GitLab . Używam wersji 11 GitLab.

Opcja 1 - nie określono tokena. Powłoka zapyta o nazwę użytkownika / hasło.

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

Opcja 2 - określony token dostępu użytkownika. Token wygenerowany poprzez przejście do GitLab → konto w prawym górnym rogu → ustawienia → tokeny dostępu. Utwórz token z prawami read_repository.

Przykład:

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

Opcja 3 - określono token na poziomie repozytorium. Token wygenerowany poprzez przejście do repozytorium → ustawienia → repozytorium → rozmieść tokeny. Stąd utwórz token z uprawnieniami do odczytu_repozytorium.

Przykład:

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

We wszystkich trzech udało mi się po prostu: „SomePrivateLib @ git + https: //gitlab.server.com/abc/SomePrivateLib.git” bez oznaczenia #egg na końcu.

ErikW
źródło