Programing

형제 패키지 가져오기

c10106 2022. 3. 17. 21:16
반응형

형제 패키지 가져오기

형제자매 수입에 대한 질문과 패키지 서류까지 읽어보았지만 아직 답을 찾지 못했다.

다음 구조로:

├── LICENSE.md
├── README.md
├── api
│   ├── __init__.py
│   ├── api.py
│   └── api_key.py
├── examples
│   ├── __init__.py
│   ├── example_one.py
│   └── example_two.py
└── tests
│   ├── __init__.py
│   └── test_one.py

의 스크립트는 어떻게 할 수 있는 방법examples그리고tests디렉터리 가져오기api명령줄을 사용하여 모듈을 실행하시겠습니까?

또한, 나는 못생긴 것을 피하고 싶다.sys.path.insert 할 수 물론 파이톤에서 할 수 있는 일이겠죠?

sys.path 해킹에 지쳤나?

얼마든지 있다.sys.path.append-hacks는 가능하지만, 나는 그 문제를 해결할 수 있는 다른 방법을 찾았다.

요약

  • 코드를 하나의 폴더(예:packaged_stuff)
  • 만들다setup.pysetuptools를 사용하는 스크립트.setup() (최소값 참조)setup.py아래)
  • 편집 가능한 상태로 패키지를 설치하십시오.pip install -e <myproject_folder>
  • 다음을 사용하여 가져오기from packaged_stuff.modulename import function_name

세우다

시작점은 당신이 제공한 파일 구조로, 폴더로 포장되어 있다.myproject.

.
└── myproject
    ├── api
    │   ├── api_key.py
    │   ├── api.py
    │   └── __init__.py
    ├── examples
    │   ├── example_one.py
    │   ├── example_two.py
    │   └── __init__.py
    ├── LICENCE.md
    ├── README.md
    └── tests
        ├── __init__.py
        └── test_one.py

나는 전화할 것이다..루트 폴더, 그리고 내 예시에서는 다음 위치에 있다.C:\tmp\test_imports\.

api.py

테스트 사례로 다음 ./api/api.py을 사용하십시오.

def function_from_api():
    return 'I am the return value from api.api!'

test_one.파이를 치다

from api.api import function_from_api

def test_function():
    print(function_from_api())

if __name__ == '__main__':
    test_function()

test_one:

PS C:\tmp\test_imports> python .\myproject\tests\test_one.py
Traceback (most recent call last):
  File ".\myproject\tests\test_one.py", line 1, in <module>
    from api.api import function_from_api
ModuleNotFoundError: No module named 'api'

또한 상대적 가져오기를 시도해도 작동하지 않음:

사용.from ..api.api import function_from_api하게 될 것이다

PS C:\tmp\test_imports> python .\myproject\tests\test_one.py
Traceback (most recent call last):
  File ".\tests\test_one.py", line 1, in <module>
    from ..api.api import function_from_api
ValueError: attempted relative import beyond top-level package

단계

  1. 루트 수준 디렉터리에 setup.py 파일 만들기

에 대한 은 ㅇㅇㅇㅇ.setup.py~일 것이다*

from setuptools import setup, find_packages

setup(name='myproject', version='1.0', packages=find_packages())
  1. 가상 환경 사용

가상 환경에 익숙한 경우 가상 환경을 활성화하고 다음 단계로 건너뛰십시오.가상 환경의 사용은 반드시 필요한 것은 아니지만, 장기적으로 (프로젝트가 하나 이상 진행 중일 때) 정말로 도움이 될 것이다.가장 기본적인 단계는 (루트 폴더에서 실행)

  • 가상 환경 생성
    • python -m venv venv
  • 가상 환경 활성화
    • source ./venv/bin/activate (리눅스, macOS)는./venv/Scripts/activate(승)

이에 대해 자세히 알아보려면 Google에서 "Python 가상 환경 튜토리얼" 또는 이와 유사한 내용을 참조하십시오.생성, 활성화 및 비활성화하는 것 외에 다른 명령은 결코 필요하지 않을 것이다.

가상 환경을 만들고 활성화한 후에는 콘솔에서 가상 환경의 이름을 괄호 안에 지정해야 함

PS C:\tmp\test_imports> python -m venv venv
PS C:\tmp\test_imports> .\venv\Scripts\activate
(venv) PS C:\tmp\test_imports>

그리고 당신의 폴더 트리는 이렇게 보여야한다**

.
├── myproject
│   ├── api
│   │   ├── api_key.py
│   │   ├── api.py
│   │   └── __init__.py
│   ├── examples
│   │   ├── example_one.py
│   │   ├── example_two.py
│   │   └── __init__.py
│   ├── LICENCE.md
│   ├── README.md
│   └── tests
│       ├── __init__.py
│       └── test_one.py
├── setup.py
└── venv
    ├── Include
    ├── Lib
    ├── pyvenv.cfg
    └── Scripts [87 entries exceeds filelimit, not opening dir]
  1. pip 편집 가능한 상태로 프로젝트를 설치하십시오.

package상위지지 install install install install를 하십시오.myproject사용.pip요령이란, 그 요령을 사용하는 것이다.-e설치 시래그 그그 이렇게 파일의 이렇게 하면 편집 가능한 상태로 설치되며 .py 파일의 모든 편집이 설치된 패키지에 자동으로 포함된다.

루트 디렉터리에서 실행

pip install -e ."("missing directorymission, "flause"re"la타냄)를 한다.

을 사용하여 설치된 것을 확인할 수도 있다.pip freeze

(venv) PS C:\tmp\test_imports> pip install -e .
Obtaining file:///C:/tmp/test_imports
Installing collected packages: myproject
  Running setup.py develop for myproject
Successfully installed myproject
(venv) PS C:\tmp\test_imports> pip freeze
myproject==1.0
  1. 추가하다myproject.할 수 있는 것으로.

추가해야 할 참고 사항myproject.다른 방법으로는 작동하지 않는 수입품에만 해당된다.제품 없이 작동한 수입setup.py&pip install그래도 잘 될 거야아래 예를 참조하십시오.


솔루션 테스트

자, 이제 다음을 사용하여 솔루션을 테스트해 봅시다.api.py위에서 정의한test_one.py아래에 정의되어 있다.

test_one.파이를 치다

from myproject.api.api import function_from_api

def test_function():
    print(function_from_api())

if __name__ == '__main__':
    test_function()

시험의 진행

(venv) PS C:\tmp\test_imports> python .\myproject\tests\test_one.py
I am the return value from api.api!

* 자세한 setup.py 예는 setuptools 문서를 참조하십시오.

** 현실에서는 가상 환경을 하드 디스크의 어디에나 배치할 수 있다.

7년후

내가 아래에 답을 썼으니 수정해라.sys.path잘몇.

  • 가상 환경이든 아니든 패키지를 설치하면 원하는 것을 얻을 수 있지만, 직접 setuptools를 사용하는 것보다 pip을 사용하여 패키지를 수행하는 것이 좋다(및 사용).setup.cfg메타데이터 저장)
  • 플래그를 사용하고 패키지로 실행하는 것도 효과가 있다(하지만 작업 디렉토리를 설치 가능한 패키지로 변환하려는 경우 다소 어색하게 된다).
  • 테스트의 경우, 특히 pytest는 이 상황에서 api 패키지를 찾을 수 있으며, pytest는 api 패키지를 관리할 수 있다.sys.path너를 위해 해킹을 하다.

그래서 그것은 정말로 당신이 무엇을 하고 싶은지에 달려있다.하지만, 당신의 경우, 당신의 목표는 어느 시점에 적절한 패키지를 만드는 것 같기 때문에, 다음을 통해 설치한다.pip -e아직 완벽하지는 않더라도 아마도 가장 좋은 선택일 것이다.

구답

다른 곳에서 이미 언급된 바와 같이 끔찍한 사실은 형제자매 모듈이나 부모 패키지에서 수입을 허용하려면 추악한 해킹을 해야 한다는 것이다.__main__모듈이 문제는 PEP 366에 자세히 설명되어 있다. PEP 3122는 보다 합리적인 방법으로 수입을 처리하려고 시도했지만 귀도측은 이 문제를 다음의 설명 중 하나로 거절했다.

유일한 사용 사례는 내가 항상 대척점으로 보아왔던 모듈의 디렉토리 안에 살고 있는 스크립트를 실행하는 것 같다.

(여기)

하지만, 나는 이 패턴을 규칙적으로 사용한다.

# Ugly hack to allow absolute import from the root folder
# whatever its name is. Please forgive the heresy.
if __name__ == "__main__" and __package__ is None:
    from sys import path
    from os.path import dirname as dir

    path.append(dir(path[0]))
    __package__ = "examples"

import api

여기,path[0]실행 중인 스크립트의 상위 폴더 및dir(path[0])최상위 폴더.

그러나, 나는 여전히 이것을 가지고 상대적인 수입품을 사용할 수 없었지만, 그것은 최상위 레벨에서 절대 수입을 허용한다. (당신의 예에서)api의 상위 폴더).

에 내가 .tests폴더:

# Path hack.
import sys, os
sys.path.insert(0, os.path.abspath('..'))

해킹할 필요도 없고, 해킹할 필요도 없다.sys.path필요한 경우가 아니라면, 그리고 이 경우에는 그렇지 않다.사용:

import api.api_key # in tests, examples

프로젝트 디렉터리에서 실행:python -m tests.test_one.

너는 아마 움직여야 할 것이다.tests(만약 그것들이 api의 단일한 것이라면) 안에api뛰어가다니다python -m api.test모든 테스트를 실행하다(있는 경우)__main__.py) 또는python -m api.test.test_one뛰다test_one대신에

제거할 수도 있다.__init__.py로부터examples(Python 패키지가 아님) 가상 환경에서 예를 실행하십시오.api: 설치됨)pip install -e .가상 환경으로 설치될 경우api적당한 물건이 있으면 꾸리다.setup.py.

형제/상대적 수입 해킹 없이 관련 없는 프로젝트들 간에 코드를 공유하는 의도된 방법을 알기 위해 나는 아직 Pythonology를 이해할 필요가 없다.그날까지 이것이 나의 해결책이다.을 위해examples또는tests물건을 수입하다..\api, 다음과 같이 보일 것이다.

import sys.path
import os.path
# Import from sibling directory ..\api
sys.path.append(os.path.dirname(os.path.abspath(__file__)) + "/..")
import api.api
import api.api_key

형제 패키지 가져오기의 경우 [sys.path][2] 모듈의 삽입 또는 추가 방법을 사용하십시오.

if __name__ == '__main__' and if __package__ is None:
    import sys
    from os import path
    sys.path.append( path.dirname( path.dirname( path.abspath(__file__) ) ) )
    import api

다음과 같이 스크립트를 실행하는 경우 이 기능이 작동함:

python examples/example_one.py
python tests/test_one.py

반면에 상대적인 가져오기도 사용할 수 있다.

if __name__ == '__main__' and if __package__ is not None:
    import ..api.api

이 경우 '-m' 인수를 사용하여 스크립트를 시작해야 한다(이 경우 '.py' 확장자를 지정하면 안 된다는 점에 유의하십시오).

python -m packageName.examples.example_one
python -m packageName.tests.test_one

물론 다음과 같은 두 가지 접근법을 혼용할 수 있으므로, 어떻게 부르든 대본이 작동하게 된다.

if __name__ == '__main__':
    if __package__ is None:
        import sys
        from os import path
        sys.path.append( path.dirname( path.dirname( path.abspath(__file__) ) ) )
        import api
    else:
        import ..api.api

TLDR

이 방법은 setuptools, 경로 해킹, 추가 명령줄 인수 또는 프로젝트의 모든 파일에 패키지의 최상위 수준을 지정할 필요가 없다.

원하는 모든 항목의 부모 디렉토리에 스크립트를 작성하십시오.__main__例句기든든든 further 읽는다.자세한 설명은 계속 읽으십시오.

설명

이 작업은 새 경로를 함께 해킹하거나, 명령줄 아그를 추가하거나, 각 프로그램에 코드를 추가하여 형제자매를 인식하지 않고도 수행할 수 있다.

내가 이전에 말한 것처럼 이것이 실패하는 이유는 불려지는 프로그램들이 그들의 것을 가지고 있기 때문이다.__name__로 설정하다.__main__이 을 패키지의 이 경우 호출되는 스크립트는 자신을 패키지의 최상위 수준으로 받아들이고 형제 디렉토리에 있는 스크립트를 인식하지 않는다.

그러나, 디렉토리의 최상위 단계 아래의 모든 것은 여전히 최상위 단계 아래의 Everything ENTHER를 인식한다.즉, 형제 디렉토리에 있는 파일이 서로 인식/활용되도록 하려면 상위 디렉토리의 스크립트에서 해당 파일을 호출하는 것이 유일한 작업임을 의미한다.

다음 구조를 가진 dir에서의 개념 증명:

.
|__Main.py
|
|__Siblings
   |
   |___sib1
   |   |
   |   |__call.py
   |
   |___sib2
       |
       |__callsib.py

Main.py다음 코드가 포함됨:

import sib1.call as call


def main():
    call.Call()


if __name__ == '__main__':
    main()

sib1/call.py은 다음을 포함한다.

import sib2.callsib as callsib


def Call():
    callsib.CallSib()


if __name__ == '__main__':
    Call()

및 sib2/callsib.py 포함 항목:

def CallSib():
    print("Got Called")

if __name__ == '__main__':
    CallSib()

만약 당신이 이 예시를 재현한다면 당신은 전화하는 것을 알게 될 것이다.Main.py은 "Got Call"에서 이다.sib2/callsib.py그럼에도 불구하고.sib2/callsib.py전화를 받았다.sib1/call.py그러나 만약 직접 전화를 한다면sib1/call.py(수입품에 적절한 변경을 한 후) 예외를 둔다.부모 디렉토리에서 스크립트가 호출할 때 작동했음에도 패키지 최상위 수준에 있다고 판단하면 작동하지 않는다.

2021년 독자들에게 : 자신이 없다면pip install -e :

Python 3의 Relative 가져오기(상대 가져오기)의 답변에서 권장하는 대로 이 계층을 고려하십시오.

MyProject
├── src
│   ├── bot
│   │   ├── __init__.py
│   │   ├── main.py
│   │   └── sib1.py
│   └── mod
│       ├── __init__.py
│       └── module1.py
└── main.py

의의 main.py, 여기서 출발점이며 절대 가져오기(선행 점 없음)를 사용한다.

from src.bot import main


if __name__ == '__main__':
    main.magic_tricks()

의의 bot/main.py, 명시적인 상대적 수입의 이점을 활용한다.

from .sib1 import my_drink                # Both are explicit-relative-imports.
from ..mod.module1 import relative_magic

def magic_tricks():
    # Using sub-magic
    relative_magic(in=["newbie", "pain"], advice="cheer_up")
    
    my_drink()
    # Do your work
    ...

이제 그 추리가 나온다.

  • 실할 때 시python MyProject/main.pypath/to/MyProject에 추가되다sys.path.
  • 절대 수입import src.bot읽을거야.
  • from ..mod 부분적으로는 …으로 한 단계 올라갈 것이라는 뜻이다.
    • 우리가 볼 수 있나요?, 그 이후부터path/to/MyProject에 추가되다sys.path.

요점은 다음과 같다.

메인 대본은 에 놓아야죠. MyProject/src그래서 상대적 수술을 할 때, 우리는 외출을 하지 않을 것이다.src, 그리고 절대 수입import src. 당사에 적합한 범위 제공:src/범위

참고 항목:ModuleNotFoundError: 'sib1'이라는 이름의 모듈 없음

수입명세서가 관련 코드에 어떻게 기재되어 있는지 살펴봐야 한다.만약examples/example_one.py다음 가져오기 문구를 사용한다.

import api.api

...그러면 프로젝트의 루트 디렉터리가 시스템 경로에 있을 것으로 예상한다.

해킹 없이 이를 지원하는 가장 쉬운 방법은 다음과 같이 최상위 디렉터리에서 예를 실행하는 것이다.

PYTHONPATH=$PYTHONPATH:. python examples/example_one.py 

Eclipse에서 Pydev를 사용하는 사람이 여기에 있는 경우: 왼쪽 메뉴 Pydev-PYthonPATH에서 Project->Properties 및 Setting External Libraries를 사용하여 형제자매의 부모 경로(따라서 호출 모듈의 부모 경로)를 외부 라이브러리 폴더로 추가할 수 있다.그런 다음 형제로부터 가져올 수 있다(예:from sibling import some_class.

pytest를 사용하는 경우 pytest 문서에는 별도의 테스트 패키지의 소스 패키지를 참조하는 방법이 설명된다.

제안된 프로젝트 디렉토리 구조:

setup.py
src/
    mypkg/
        __init__.py
        app.py
        view.py
tests/
    __init__.py
    foo/
        __init__.py
        test_view.py
    bar/
        __init__.py
        test_view.py

setup.py파일:

from setuptools import setup, find_packages

setup(name="PACKAGENAME", packages=find_packages())

편집 가능한 모드로 패키지 설치:

pip install -e .

이 시험 기사는 이오넬 크리스티안 미드리오의 블로그 글을 인용하고 있다.

나는 내가 이것을 어떻게 처리했는지를 증명하기 위해 샘플 프로젝트를 만들었는데, 이것은 위에서 언급한 것과 같은 또 다른 sys.path 해킹이다.다음에 의존하는 Python Brother 가져오기 예제:

if __name__ == '__main__': import os import sys sys.path.append(os.getcwd())

당신의 작업 디렉토리가 파이톤 프로젝트의 근원을 유지하는 한, 이것은 꽤 효과적인 것 같다.

np8에서 제공하는 솔루션에 대해 코멘트를 하고 싶었지만 평판이 좋지 않아 setup.py 파일을 그들이 제안한 대로 정확히 만들 수 있다고만 언급하고 나서 그렇게 하도록 하겠다.pipenv install --dev -e .편집 가능한 종속성으로 전환하기 위해 프로젝트 루트 디렉터리에서.그러면 당신의 절대 수입품이 예를 들어 효과가 있을 것이다.from api.api import foo시스템 전체 설치 작업을 망치지 않아도 된다.

문서화

기본 파일에 다음을 추가하십시오.

import sys
import os 
sys.path.append(os.path.abspath(os.path.join(__file__,mainScriptDepth)))

mainScriptDepth = 프로젝트 루트에서 가져온 메인 파일의 깊이.

여기 당신의 사례가 있다.mainScriptDepth = "../../". 그런 다음 경로를 지정하여 가져올 수 있다.from api.api import *프로젝트의 루트부터 입니다.

주요 질문의 경우:

형제 폴더를 모듈로 호출:

..에서 형제 폴더 가져오기

형제 폴더에서 a_file.py를 모듈로 호출:

from ..folder 가져오기 a_file

형제 폴더의 파일 내부에 있는 a_function을 모듈로 호출:

그..정맥류에서 온거야a_file 가져오기 func_name_name_in_a_file

가장 쉬운 방법.

lib/site-protection 폴더로 이동하십시오.

'install_install.pth' 파일이 있는 경우 해당 파일을 편집하고 해당 파일을 모듈로 만들 스크립트가 있는 디렉터리를 추가하십시오.

만약 존재하지 않는다면, 그냥 하나로 만들어라...그리고 네가 원하는 폴더를 거기에 놓아라.

당신이 그것을 추가한 후에... 파이톤은 자동으로 그 폴더를 사이트와 유사하게 인식하게 될 것이고 당신은 그 폴더나 하위 폴더의 모든 스크립트를 모듈로 호출할 수 있다.

나는 이것을 핸드폰으로 썼고, 모든 사람들이 읽기 편하게 설정하기 힘들었다.

첫째, 모듈 자체와 이름이 같은 파일은 사용하지 마십시오.그것은 다른 수입품들을 깨뜨릴 수도 있다.

파일을 가져올 때 먼저 통역이 현재 디렉터리를 확인한 다음 전역 디렉터리를 검색한다.

내부examples또는tests다음 주소로 전화:

from ..api import api
  1. 프로젝트

1.1 사용자

1.1.1 대략.파이를 치다

1.1.2 초기화.파이를 치다

1.2 테크

1.2.1 정보.파이를 치다

1.1.2 초기화.파이를 치다

이제 사용자 패키지about.py 모듈에 액세스하려면 Tech 패키지info.py 모듈에서 cmd(윈도우즈) 경로를 Project(예: 프로젝트)로 가져와야 한다.**C:\Users\Personal\Desktop\Project]****위의 패키지 예시그리고 이 경로에서 python -m Package_name.module_name을 입력해야 한다. 예를 들어 위의 패키지에 대해서는 우리가 해야 한다.

C:\Users\Personal\Desktop\Project]python -m Tech.info

imf 포인트

  1. 정보 모듈(예: python -m Tech.info.py) 후에는 .py 확장을 사용하지 마십시오.
  2. 형제 패키지 수준이 같은 경우 이 항목을 입력하십시오.
  3. -m은 깃발이고, 그것을 확인하려면 cmd python --help에서 타이핑하면 된다.

참조URL: https://stackoverflow.com/questions/6323860/sibling-package-imports

반응형