itsource

레퍼런스 요건setuptools setup.py 파일의 install_displays kwarg에 대한 txt

mycopycode 2022. 11. 14. 21:40
반응형

레퍼런스 요건setuptools setup.py 파일의 install_displays kwarg에 대한 txt

는 나나 a a a가 있다requirements.txtTravis-CI 。 것 .requirements.txt ★★★★★★★★★★★★★★★★★」setup.py그래서 저는 파일핸들을 전달하고 싶었습니다.install_requiressetuptools.setup.

이게 가능합니까?그렇다면 어떻게 하면 좋을까요?

제 사진이 .requirements.txt 삭제:

guessit>=0.5.2
tvdb_api>=1.8.2
hachoir-metadata>=1.3.3
hachoir-core>=1.3.3
hachoir-parser>=1.3.4

보기에는 것 requirements.txt ★★★★★★★★★★★★★★★★★」setup.py는 우스꽝스러운 복제품이지만 형태는 비슷하지만 의도한 기능은 매우 다르다는 것을 이해하는 것이 중요합니다.

패키지 작성자의 목표는 종속성을 지정할 때 "이 패키지를 어디에 설치하든 이 패키지가 작동하기 위해 필요한 다른 패키지입니다."라고 말하는 것입니다.

한편, 도입의 작성자(다른 때에 같은 사람일 가능성이 있습니다)는, 「이것이, 집합해 테스트한 패키지의 리스트이며, 인스톨 할 필요가 있는 패키지의 리스트입니다」라고 하는 다른 일을 하고 있습니다.

패키지 작성자는 다양한 시나리오에 대해 기술합니다.왜냐하면 패키지 작성자는 자신이 모르는 방법으로 사용할 수 있도록 작업하고 있으며 패키지와 함께 어떤 패키지가 설치될지 알 수 없기 때문입니다.좋은 네이버가 되어 다른 패키지와의 의존 버전 경합을 피하기 위해 가능한 한 광범위한 의존 버전 범위를 지정해야 합니다. 바로 런 this this입니다.install_requiressetup.py

전개 작성자는, 특정의 컴퓨터에 인스톨 되어 있는 애플리케이션 또는 서비스의 단일 인스턴스라고 하는, 매우 다른, 매우 구체적인 목적을 위해서 기술하고 있습니다.전개를 정밀하게 제어하고 적절한 패키지가 테스트 및 전개되도록 하기 위해 전개 작성자는 의존관계 및 의존관계 등 설치할 모든 패키지의 정확한 버전과 소스 위치를 지정해야 합니다.이 사양을 사용하면 배포를 여러 시스템에 반복적으로 적용하거나 테스트 시스템에서 테스트할 수 있으며 배포 작성자는 매번 동일한 패키지가 배포된다는 확신을 가질 수 있습니다. 바로 게 this this this this this this this this this 。requirements.txt

보시다시피 이 두 가지가 모두 패키지와 버전의 큰 목록처럼 보이지만 이 두 가지는 매우 다른 역할을 합니다.은 '이렇게 하는 것'입니다.requirements.txt모든 다양한 요구 사항에 의해 제기되는 "질문"에 대한 "답변"입니다.setup.py이렇게 으로 쓰는 보다 pip에게 pip을 다 경우setup.py 내의 을 검색하여를 찾은 후 는 "패키지 목록"입니다).pip freeze이름이 유래합니다).

여기서 얻을 수 있는 것은 다음과 같습니다.

  • setup.py는 아직 동작 가능한 가장 느슨한 의존관계 버전을 선언해야 합니다.이 패키지의 역할은 특정 패키지가 무엇을 사용할 수 있는지를 말하는 것입니다.
  • requirements.txt는 전체 설치 작업을 정의하는 배포 매니페스트이며, 하나의 패키지에 연결된 것으로 간주해서는 안 됩니다.이 패키지의 역할은 전개가 작동하는 데 필요한 모든 패키지의 완전한 목록을 선언하는 것입니다.
  • 이 두 가지는 존재하는 내용과 이유가 매우 다르기 때문에 단순히 하나를 다른 것으로 복사하는 것은 가능하지 않습니다.

참고 자료:

''를 '는 '의존속관계는요?setup.py으로 점으로 하다. 으로 점으로 표시하다..인 : 。requirements.txt★★★★★★ 。


할 수 .requirements.txt의한 경우)에 다음의 )을 합니다.pip 9.0.1

install_reqs = parse_requirements('requirements.txt', session='hack')

이것은 환경 마커를 필터링하지 않습니다.


특히 6.0보다 오래된 이전 버전의 pip에서는 이를 실현하기 위해 사용할 수 있는 퍼블릭 API가 있습니다.요건 파일에는 코멘트를 포함할 수 있습니다(# 파일 )을 포함할 수 --requirement ★★★★★★★★★★★★★★★★★」-r 「 」를 는, 「 」를 참조해 주세요.requirements.txt는 pip parser:는 parser:는 pip parser를 사용할 수.

from pip.req import parse_requirements

# parse_requirements() returns generator of pip.req.InstallRequirement objects
install_reqs = parse_requirements(<requirements_path>)

# reqs is a list of requirement
# e.g. ['django==1.5.1', 'mezzanine==1.4.6']
reqs = [str(ir.req) for ir in install_reqs]

setup(
    ...
    install_requires=reqs
)

파일 핸들을 사용할 수 없습니다.install_requires인수에는 문자열 또는 문자열 목록만 사용할 수 있습니다.

수 .install_requires.

import os
from setuptools import setup

with open('requirements.txt') as f:
    required = f.read().splitlines()

setup(...
install_requires=required,
...)

형식을 이은 "pip"을 가 있는 이 됩니다.이것은, 유저에게 필요한 경우에 한해 유효합니다.setup.py 일부 의 출력을 하는 등 더 제약을 .pip freeze패키지 세트 전체를 기존의 동작 버전으로 프리즈합니다.않은 " " "만합니다.setup.py requirements.txt1번, 1번, 1번, 1번, 1번, 1번.

.

하며, 이 입니다.setup.py같은 디렉토리에 있습니다.

질문에 대한 정확한 답변은 아니지만, 이 문제에 대한 좋은 인식을 위해 https://caremad.io/2013/07/setup-vs-requirement/에 있는 Donald Stufft의 블로그 포스트를 추천합니다.나는 그것을 매우 성공적으로 사용해 왔다.

로 말하면, 요,,,requirements.txt 아니다setup.py대체 수단이지만, 도입 보완 수단입니다. 를 에 합니다.setup.py를 설정합니다.requirements.txt개발, 테스트 또는 프로덕션용 패키지 종속성의 특정 버전을 가져올 수 있습니다.

예: 레포에 포함된 패키지deps/:

# fetch specific dependencies
--no-index
--find-links deps/

# install package
# NOTE: -e . for editable mode
.

의 pip을 합니다.setup.py 에 된 특정 합니다.install_requires이중성이 없고 두 유물 모두 목적이 보존되어 있습니다.

「」를 사용합니다.parse_requirements되지 않기 때문에 .pip API는 공개 문서화되어 있지 .1. 있기 는 breakpip 1.6이 될 .

way a a a a 의 중복을 없애는 보다 신뢰성 높은 방법setup.py ★★★★★★★★★★★★★★★★★」requirements.txt''는요, ''를 구체적으로 예요.setup.py 다음에 리 and를 붙입니다.-e .의 에 your에requirements.txt 일일 the the の of of of の of of file file file file file file file file file file file file file file의 일부 정보pip왜 이것이 더 나은 방법인지에 대한 개발자는 https://caremad.io/blog/setup-vs-requirement/에서 구할 수 있습니다.

위의 다른 답변의 대부분은 현재 버전의 pip API에서 작동하지 않습니다.현재 버전의 pip (작성 시 6.0.8, 7.1.2에서도 동작)를 사용하는 올바른* 방법을 다음에 나타냅니다.pip - V)로 버전을 확인할 수 있습니다.

from pip.req import parse_requirements
from pip.download import PipSession

install_reqs = parse_requirements(<requirements_path>, session=PipSession())

reqs = [str(ir.req) for ir in install_reqs]

setup(
    ...
    install_requires=reqs
    ....
)

* 현재 pip에서 parse_requirements를 사용하는 방법이기 때문에 정답입니다.위의 포스터에서 말한 것처럼 pip은 API를 유지하지 않기 때문에 여전히 최선의 방법은 아닐 수 있습니다.

나는 그런 일을 하는 것을 추천하지 않는다.install_requires ★★★★★★★★★★★★★★★★★」requirements.txt같은 리스트가 되어서는 안 됩니다.그러나 pip의 개인 내부 API와 관련된 오해의 소지가 많은 답변이 있기 때문에 보다 건전한 대안을 검토할 가치가 있을 것입니다.


간단한 합니다.requirements.txt셋업툴에서 파일을 작성하다 setup.py스크립트(pip 없음)setuptools 프로젝트에 필요한 도구가 이미 최상위 패키지에 포함되어 있습니다.pkg_resources.

대략 다음과 같습니다.

#!/usr/bin/env python3

import pathlib

import pkg_resources
import setuptools

with pathlib.Path('requirements.txt').open() as requirements_txt:
    install_requires = [
        str(requirement)
        for requirement
        in pkg_resources.parse_requirements(requirements_txt)
    ]

setuptools.setup(
    install_requires=install_requires,
)

다시 말씀드리지만, 이것은 단순한 경우에만 작동합니다.requirements.txt파일 처리 방법에 대한 자세한 내용은 문서 페이지의 요구 사항 분석참조하십시오.즉, 각 행은 유효한 PEP 508 요건이어야 합니다.실제로 pip에 고유한 표기는 지원되지 않으므로 장애가 발생합니다.


주의사항

이미 설명한 바와 같이 이는 권장되지 않습니다.requirements.txt파일 및 "설치 종속성" 목록은 서로 다른 두 가지 개념이며 서로 호환되지 않습니다.

만약에 setup.py 하다requirements.txt에 이, 이, 이, 이, 이, 이, 이, 이, 이, 이, 이, 이, 이, 이.requirements.txt파일이 「소스 배포」(sdistribution)(sdist)에 포함되어 있지 않으면, 인스톨에 실패합니다.


62.6 부터는 setuptools에서도 이와 쓸 수 .setup.cfg:

[options]
install_requires = file: requirements.txt

른른른 altern altern alternpyproject.toml:

[project]
dynamic = ["dependencies"]

[tool.setuptools.dynamic]
dependencies = requirements.txt

위와 같은 경고 문구가 적용됩니다.

  • 매우 단순한 파일만 지원됩니다.
  • 파일을 sdist에 추가해야 합니다.

또, 현재로서는 「베타」기능으로 간주되고 있습니다.


주의:

트래비스 하면 '어느 정도'가 되지 않게 됩니다.requirements.txt예를 들어 다음과 같습니다.

language: python
python:
  - "2.7"
  - "2.6"
install:
  - pip install -q -e .
script:
  - python runtests.py

에서는 요건 을 에서 .setup.pyDmitiry S의 답변을 변형한 것입니다.이 답변은 Python 3.6+와만 호환됩니다.

D.S.에 따르면requirements.txt인 요건을 버전 할 수 .단, '버전 번호'는 다음과 같습니다.setup.py는 버전 범위가 느슨한 추상 요건을 문서화할 수 있습니다.

는 저의 발췌장.setup.py.

import distutils.text_file
from pathlib import Path
from typing import List

def _parse_requirements(filename: str) -> List[str]:
    """Return requirements from requirements file."""
    # Ref: https://stackoverflow.com/a/42033122/
    return distutils.text_file.TextFile(filename=str(Path(__file__).with_name(filename))).readlines()

setup(...
      install_requires=_parse_requirements('requirements.txt'),
   ...)

:distutils.text_file.TextFile을 사용하다 제 , 하기 를 밟을 는 없는 것 .

from pip.req import parse_requirements는 동작합니다. 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아.

def parse_requirements(requirements):
    with open(requirements) as f:
        return [l.strip('\n') for l in f if l.strip('\n') and not l.startswith('#')]

reqs = parse_requirements(<requirements_path>)

setup(
    ...
    install_requires=reqs,
    ...
)

다음 인터페이스는 pip 10에서 폐지되었습니다.

from pip.req import parse_requirements
from pip.download import PipSession

그래서 단순한 텍스트 구문 분석으로 전환했습니다.

with open('requirements.txt', 'r') as f:
    install_reqs = [
        s for s in [
            line.split('#', 1)[0].strip(' \t\n') for line in f
        ] if s != ''
    ]

사용자에게 pip 설치를 강요하지 않으려면 다음과 같이 동작을 에뮬레이트할 수 있습니다.

import sys

from os import path as p

try:
    from setuptools import setup, find_packages
except ImportError:
    from distutils.core import setup, find_packages


def read(filename, parent=None):
    parent = (parent or __file__)

    try:
        with open(p.join(p.dirname(parent), filename)) as f:
            return f.read()
    except IOError:
        return ''


def parse_requirements(filename, parent=None):
    parent = (parent or __file__)
    filepath = p.join(p.dirname(parent), filename)
    content = read(filename, parent)

    for line_number, line in enumerate(content.splitlines(), 1):
        candidate = line.strip()

        if candidate.startswith('-r'):
            for item in parse_requirements(candidate[2:].strip(), filepath):
                yield item
        else:
            yield candidate

setup(
...
    install_requires=list(parse_requirements('requirements.txt'))
)

parse_requirements동!!

해 주세요.pip.req.parse_requirements밑줄이 대시로 변경됩니다.내가 발견하기 전 며칠간은 이것이 나를 화나게 했다.★★★★

from pip.req import parse_requirements  # tested with v.1.4.1

reqs = '''
example_with_underscores
example-with-dashes
'''

with open('requirements.txt', 'w') as f:
    f.write(reqs)

req_deps = parse_requirements('requirements.txt')
result = [str(ir.req) for ir in req_deps if ir.req is not None]
print result

생산하다

['example-with-underscores', 'example-with-dashes']

재사용 가능한 기능을 만들었습니다.실제로 요건 파일의 디렉토리 전체를 해석하여 extra_require로 설정합니다.

항상 최신 정보를 입수할 수 있습니다.https://gist.github.com/akatrevorjay/293c26fefa24a7b812f5

import glob
import itertools
import os

# This is getting ridiculous
try:
    from pip._internal.req import parse_requirements
    from pip._internal.network.session import PipSession
except ImportError:
    try:
        from pip._internal.req import parse_requirements
        from pip._internal.download import PipSession
    except ImportError:
        from pip.req import parse_requirements
        from pip.download import PipSession


def setup_requirements(
        patterns=[
            'requirements.txt', 'requirements/*.txt', 'requirements/*.pip'
        ],
        combine=True):
    """
    Parse a glob of requirements and return a dictionary of setup() options.
    Create a dictionary that holds your options to setup() and update it using this.
    Pass that as kwargs into setup(), viola

    Any files that are not a standard option name (ie install, tests, setup) are added to extras_require with their
    basename minus ext. An extra key is added to extras_require: 'all', that contains all distinct reqs combined.

    Keep in mind all literally contains `all` packages in your extras.
    This means if you have conflicting packages across your extras, then you're going to have a bad time.
    (don't use all in these cases.)

    If you're running this for a Docker build, set `combine=True`.
    This will set `install_requires` to all distinct reqs combined.

    Example:

    >>> import setuptools
    >>> _conf = dict(
    ...     name='mainline',
    ...     version='0.0.1',
    ...     description='Mainline',
    ...     author='Trevor Joynson <github@trevor.joynson,io>',
    ...     url='https://trevor.joynson.io',
    ...     namespace_packages=['mainline'],
    ...     packages=setuptools.find_packages(),
    ...     zip_safe=False,
    ...     include_package_data=True,
    ... )
    >>> _conf.update(setup_requirements())
    >>> # setuptools.setup(**_conf)

    :param str pattern: Glob pattern to find requirements files
    :param bool combine: Set True to set install_requires to extras_require['all']
    :return dict: Dictionary of parsed setup() options
    """
    session = PipSession()

    # Handle setuptools insanity
    key_map = {
        'requirements': 'install_requires',
        'install': 'install_requires',
        'tests': 'tests_require',
        'setup': 'setup_requires',
    }
    ret = {v: set() for v in key_map.values()}
    extras = ret['extras_require'] = {}
    all_reqs = set()

    files = [glob.glob(pat) for pat in patterns]
    files = itertools.chain(*files)

    for full_fn in files:
        # Parse
        reqs = {
            str(r.req)
            for r in parse_requirements(full_fn, session=session)
            # Must match env marker, eg:
            #   yarl ; python_version >= '3.0'
            if r.match_markers()
        }
        all_reqs.update(reqs)

        # Add in the right section
        fn = os.path.basename(full_fn)
        barefn, _ = os.path.splitext(fn)
        key = key_map.get(barefn)

        if key:
            ret[key].update(reqs)
            extras[key] = reqs

        extras[barefn] = reqs

    if 'all' not in extras:
        extras['all'] = list(all_reqs)

    if combine:
        extras['install'] = ret['install_requires']
        ret['install_requires'] = list(all_reqs)

    def _listify(dikt):
        ret = {}

        for k, v in dikt.items():
            if isinstance(v, set):
                v = list(v)
            elif isinstance(v, dict):
                v = _listify(v)
            ret[k] = v

        return ret

    ret = _listify(ret)

    return ret


__all__ = ['setup_requirements']

if __name__ == '__main__':
    reqs = setup_requirements()
    print(reqs)

또 다른 가능한 해결책...

def gather_requirements(top_path=None):
    """Captures requirements from repo.

    Expected file format is: requirements[-_]<optional-extras>.txt

    For example:

        pip install -e .[foo]

    Would require:

        requirements-foo.txt

        or

        requirements_foo.txt

    """
    from pip.download import PipSession
    from pip.req import parse_requirements
    import re

    session = PipSession()
    top_path = top_path or os.path.realpath(os.getcwd())
    extras = {}
    for filepath in tree(top_path):
        filename = os.path.basename(filepath)
        basename, ext = os.path.splitext(filename)
        if ext == '.txt' and basename.startswith('requirements'):
            if filename == 'requirements.txt':
                extra_name = 'requirements'
            else:
                _, extra_name = re.split(r'[-_]', basename, 1)
            if extra_name:
                reqs = [str(ir.req) for ir in parse_requirements(filepath, session=session)]
                extras.setdefault(extra_name, []).extend(reqs)
    all_reqs = set()
    for key, values in extras.items():
        all_reqs.update(values)
    extras['all'] = list(all_reqs)
    return extras

그리고 나서...

reqs = gather_requirements()
install_reqs = reqs.pop('requirements', [])
test_reqs = reqs.pop('test', [])
...
setup(
    ...
    'install_requires': install_reqs,
    'test_requires': test_reqs,
    'extras_require': reqs,
    ...
)

SO 질문에 대한 답변을 크로스 투고하여 심플하고 pip 버전 증명 솔루션을 제공합니다.

try:  # for pip >= 10
    from pip._internal.req import parse_requirements
    from pip._internal.download import PipSession
except ImportError:  # for pip <= 9.0.3
    from pip.req import parse_requirements
    from pip.download import PipSession

requirements = parse_requirements(os.path.join(os.path.dirname(__file__), 'requirements.txt'), session=PipSession())

if __name__ == '__main__':
    setup(
        ...
        install_requires=[str(requirement.req) for requirement in requirements],
        ...
    )

나서, 필요한 .requirements.txt프로젝트 루트 디렉터리에 있습니다.

다른 또나하parse_requirements를 환경지 into로 extras_require:

from collections import defaultdict
from pip.req import parse_requirements

requirements = []
extras = defaultdict(list)
for r in parse_requirements('requirements.txt', session='hack'):
    if r.markers:
        extras[':' + str(r.markers)].append(str(r.req))
    else:
        requirements.append(str(r.req))

setup(
    ...,
    install_requires=requirements,
    extras_require=extras
)

sdist와 binary dist를 모두 지원합니다.

, 田른 as as as as as as as as as as as as as as as as as.parse_requirements에는 몇 가지 단점이 있기 때문에 공공 프로젝트에서는 이 방법을 사용할 수 없지만 내부/개인 프로젝트에서는 충분할 수 있습니다.

나는 이렇게 했다:

import re

def requirements(filename):
    with open(filename) as f:
        ll = f.read().splitlines()
    d = {}
    for l in ll:
        k, v = re.split(r'==|>=', l)
        d[k] = v
    return d

def packageInfo():
    try:
        from pip._internal.operations import freeze
    except ImportError:
        from pip.operations import freeze

    d = {}
    for kv in freeze.freeze():
        k, v = re.split(r'==|>=', kv)
        d[k] = v
    return d

req = getpackver('requirements.txt')
pkginfo = packageInfo()

for k, v in req.items():
    print(f'{k:<16}: {v:<6} -> {pkginfo[k]}')

.pip 9.0.1)는, Romain의 대답에 근거하고 있습니다.requirements.txt현재 환경 마커에 따라 필터링합니다.

from pip.req import parse_requirements

requirements = []
for r in parse_requirements('requirements.txt', session='hack'):
    # check markers, such as
    #
    #     rope_py3k    ; python_version >= '3.0'
    #
    if r.match_markers():
        requirements.append(str(r.req))

print(requirements)

언급URL : https://stackoverflow.com/questions/14399534/reference-requirements-txt-for-the-install-requires-kwarg-in-setuptools-setup-py

반응형