목차
개요
어떤 프로젝트의 루트 디렉터리에서 종종 setup.py라는 파일을 발견할 수 있습니다. 이 파일은 프로젝트를 패키징 하는 데 사용됩니다.
개인적으로는 직접 작성한 코드를 패키징하여 PyPI에 게시하는 등의 경험은 없었습니다. 그러나 복잡한 프로젝트 구조에서 프로젝트와는 별개로 사용되어야 하는 모듈을 개발하고 사용하는 경우를 접해보았습니다. 간단히 말해서 자체 개발한 Third Party 모듈의 개념이 될 수 있겠습니다.
그래서 setup.py를 통해 프로젝트의 패키징뿐만 아니라 구조적으로 복잡한 프로젝트의 모듈을 완전히 분리하고 조합하는 형태로 개발할 수도 있을 것으로 예상됩니다. 물론 프로젝트 구조가 복잡해지면 의존성도 복잡해진다는 점을 염두에 두어야 합니다.
이 글은 setup.py를 다뤄보고 실험한 내용을 정리한 것입니다. 참고로 제목에 'Q'가 포함된 내용은 패키지 사용 중 궁금한 점을 해결한 내용입니다.
설치하기
setup.py를 이용하는 방법은 pip로 setuptools를 먼저 설치함으로써 사용할 수 있습니다.
pip install setuptools
Enviorment
setup.py를 실험하기 전에 setup.py로 패키징 할 경로와 실제로 사용해 볼 패키징 된 모듈의 경로를 분리하여 실험해 보았습니다.
분리를 굳이 하는 이유는 IDE 때문입니다. 필자는 PyCharm을 사용하고 있으며, PyCharm에서 이를 테스트할 때 패키지가 참조하는 경로를 추적하는 것이 복잡했습니다. 패키징 처리할 대상이 루트 디렉터리와 동일한 경로에 있다면 이 경로를 먼저 참조할 수도 있기 때문입니다.
패키징을 처리할 경로
# /Users/jako/private/git-repo/opt/pkgsample
(venv) ╭─jako@prompt-mini ~/private/git-repo/opt/pkgsample
╰─$ tree -L 3
.
├── setup.py
└── src
│ ├── __init__.py
│ └── sample.py
패키징을 처리할 경로에 들어있는 구조를 살펴보면 src layout 구조를 이용했음을 알 수 있습니다. 저는 src 밑에 코드가 들어가 있는 게 더 보기 편하기에 이러한 구조를 사용했습니다. 참고로 sample.py에는 다음과 같은 코드가 들어있습니다.
class Sample:
def hello(self):
print("World")
import 해서 사용할 경로
(venv) ╭─jako@prompt-mini /Users/jako/private/git-repo/study-python-src
╰─$ tree -L 3
.
├── notepad.py
└── venv
설치된 패키지를 실제로 이용하는 경로입니다. 즉 이 경로에 있는 venv를 통해서 ‘~/private/git-repo/opt/pkgsample’를 설치할 것입니다. 그렇게 되면 notepad.py에서 설치된 pkgsample을 이용할 수 있게 되는 것입니다.
패키지 메타데이터 설정하기
setuptools의 setup 메서드는 패키지 처리를 진행하며 메타데이터를 설정할 수 있게 해 줍니다.
```python
from setuptools import setup, find_packages
setup(
name="pkgsample",
version="0.1",
package_dir={'': 'src'},
)
실험한 내용에서 다루는 메타데이터는 아래 3가지 정도가 전부입니다.
- name : pip가 이 패키지를 참조하는 이름
- 만약 name이 ‘sampe’이면 ‘pip install sample’로 설치가 된다
- versions : 이 패키지의 버전 PyPI에 배포할 때 사용되는 버전
- package_dir: 패키지 위치를 지정할 수 있다. src layout을 사용할 것이기 때문에 위의 예시처럼 지정하여 사용했다.
프로젝트에 따라 패키지에서 설정해야 될 메타데이터가 다양해지는데 이는 seuptools의 문서를 참고하도록 합시다
패키지 설치하기
준비해 놓은 패키지를 실제로 설치해 봅시다. 설치하는 명령은 두 가지 정도가 존재하는 python setup.py install를 이용한 설치와 pip install. 를 통해서도 설치할 수 있습니다. 여기서는 pip install . 를 통해서 설치를 진행할 것입니다
(venv) ╭─jako@prompt-pro ~/private/git-repo/opt/pkgsample
╰─$ pip install . 1 ↵
Processing /Users/jako/private/git-repo/opt/pkgsample
Installing build dependencies ... done
Getting requirements to build wheel ... done
Preparing metadata (pyproject.toml) ... done
Building wheels for collected packages: pkgsmaple
Building wheel for pkgsmaple (pyproject.toml) ... done
Created wheel for pkgsmaple: filename=pkgsmaple-0.1-py3-none-any.whl size=1272 sha256=f76d5626fbb99e2cfad212146ddffcb58a7a8edb54d72ff7c4fd82231078f434
Stored in directory: /private/var/folders/l8/rrrjz5y15l3b6cjbxf3c638r0000gn/T/pip-ephem-wheel-cache-1f3at3uj/wheels/31/3a/4a/98421c9a4fe6e82e6f7206a9b5b537366603e6e94158eb7aab
Successfully built pkgsmaple
Installing collected packages: pkgsmaple
Attempting uninstall: pkgsmaple
Found existing installation: pkgsmaple 0.1
Uninstalling pkgsmaple-0.1:
Successfully uninstalled pkgsmaple-0.1
Successfully installed pkgsmaple-0.1
패키지 사용하기
위와 같이 설치한 경우 venv의 root 디렉터리에는 다음과 같이 sample.py 파일이 생성됩니다.
╭─jako@prompt-pro ~/private/git-repo/study-python-src/venv/lib/python3.11/site-packages
╰─$ tree -L 1
.
├── __init__.py
...
├── sample.py
import 해서 사용하는 경우에는 다음과 같습니다.
# /Users/jako/private/git-repo/study-python-src/notepad.py
from sample import Sample
s = Sample()
s.hello()
Q. 왜 파일만 생기지?
눈여겨볼 점은 from pkgsample.sample import Sample과 같은 방식처럼 import 되는 게 아니라는 점이었습니다. 이는 패키징을 처리할 경로에 있는 src 밑의 패키지를 만들어주지 않았기 때문에 발생했습니다. 다음과 같이 변경하여 다시 설치를 진행해 봅시다.
# /Users/jako/private/git-repo/opt/pkgsample
(venv) ╭─jako@prompt-pro ~/private/git-repo/opt/pkgsample
╰─$ tree -L 3
.
├── setup.py
└── src
└── pkgsample # 변경된 부분
├── __init__.py
└── sample.py
이제 venv에서 설치되어 있는 형태는 다음과 같이 변경되어 있을 것입니다.
╭─jako@prompt-pro ~/private/git-repo/study-python-src/venv/lib/python3.11/site-packages
╰─$ tree -L 2
.
**├── pkgsample
│ ├── __init__.py
│ ├── __pycache__
│ └── sample.py**
이 패키지를 사용하는 쪽에서는 다음과 같이 import 할 수 있게 됩니다.
from pkgsample.sample import Sample
s = Sample()
s.hello()
Q. setup.py install과 pip install 차이점
pip install. 를 통해 설치했습니다.. 원래 pip install은 pypi를 참고하여 설치하는 방식인데. 를 지정했기 때문에 이 명령어를 실행하는 현재 경로의 패키지를 참고하여 설치를 진행하는 셈이 되는 것입니다. python setup.py install 은 setup.py 파일을 사용해 패키지를 설치하는 방식입니다.
사용하는 입장에서 보면 그다지 차이는 없어 보입니다. 로컬에서 패키지를 설치하여 사용하는 입장에서 보면 결과적으로는 둘 다 똑같은 방식으로 사용하기 때문입니다. 단지 python3.11에서 python setup.py install을 실행하면 deprcatedwarning이 발생한다는 점이니 python3.11을 사용할 때 install 대신 다른 방법이 필요하게 된다는 점이 아닐까 싶네요
╰─$ python setup.py install
running install
/Users/jako/private/git-repo/study-python-src/venv/lib/python3.11/site-packages/setuptools/_distutils/cmd.py:66: SetuptoolsDeprecationWarning: setup.py install is deprecated.
!!
********************************************************************************
Please avoid running ``setup.py`` directly.
Instead, use pypa/build, pypa/installer, pypa/build or
other standards-based tools.
See <https://blog.ganssle.io/articles/2021/10/setup-py-deprecated.html> for details.
********************************************************************************
!!
self.initialize_options()
/Users/jako/private/git-repo/study-python-src/venv/lib/python3.11/site-packages/setuptools/_distutils/cmd.py:66: EasyInstallDeprecationWarning: easy_install command is deprecated.
!!
********************************************************************************
Please avoid running ``setup.py`` and ``easy_install``.
Instead, use pypa/build, pypa/installer, pypa/build or
other standards-based tools.
See <https://github.com/pypa/setuptools/issues/917> for details.
********************************************************************************
!!
self.initialize_options()
Editable install: 개발자 모드로 설치하기
이전에 언급한 내용을 통해 패키지 설치 방법, 설치된 패키지의 venv 내 설치 방식, 그리고 패키지를 사용하는 측에서의 import 방법에 대해 알아보았습니다. 완성된 패키지를 설치할 때는 이러한 절차를 따르는 것이 옳은 방향으로 보입니다.
하지만 패키지를 개발 중일 때는 어떻게 해야 할까요?
개발 과정에서는 코드를 여러 번 수정하고 실행하여 결과를 반복적으로 확인합니다. 따라서 코드가 수정될 때마다 즉각적인 확인이 가능하도록 "개발자 모드"라는 기능을 사용합니다. 이 기능도 setuptools에서 제공됩니다.
설치 명령은 'pip install -e.'입니다. setuptools 문서에 따르면 이를 "editable install"로 설명하고 있습니다. 'pip install -e.'로 설치한 경우, venv에. egg-link 파일이 표시됩니다.
egg-link 파일은 패키지를 가리키는 경로가 적힌 파일인데 이 경로를 참조하여 패키지를 사용할 수 있도록 해주는 방식인 듯싶습니다.
맺음말
지금까지 setuptools를 사용하여 패키징을 시도하고, 패키징된 내용을 설치할 때 venv 상에 어떤 변화가 있는지 관찰해 보았습니다. 이번에 다룬 주제는 주로 설치에 관련된 내용이었으며, 패키징 처리에는 의존성 관리와 버전 관리 등 다양한 고민 요소가 존재합니다.
게다가 더 자세히 찾아보면 setup.py를 사용하여 패키징하는 대신 setup.cfg나 pyproject.toml을 이용하여 패키징을 시도하는 경우도 많이 있습니다. 따라서 setup.py만을 이용한 패키징 처리는 어쩌면 전통적인 방법으로 간주될 수 있다고 개인적으로 생각합니다.
이 글의 제목이 'install'에 관련된 내용인 것처럼, 패키지와 관련하여 의존성을 실험하는 시기가 오면 내용을 정리하여 포스팅하는 것으로 이만 글을 마칩니다
'Language > Python' 카테고리의 다른 글
[Python] Selenium Proxy를 이용한 Tor 사용하기 (0) | 2023.07.09 |
---|---|
pytest-django에서 view에 request 던지기 (2) | 2023.06.18 |
함수에 적용되어있는 decorator를 알아내는 방법 (0) | 2023.05.05 |
urllib을 이용한 학교 메일 가져오기 (0) | 2023.04.02 |
pytest-django 에서 자주 사용했던 것들 (3) | 2023.03.19 |