본문 바로가기
Development/Python

Python 프로젝트 배포 및 다른 패키지 가져오기

by IMCOMKING 2020. 1. 9.

Python 프로젝트를 export 또는 import하는 방법

1. pip install을 사용한다.

2. module관리 도구를 사용한다.

3. git clone을 한다.

 

 

1. Pip install 사용하기

먼저 pip로 install하게 하기 위해서는 setup.py와 requirements.txt를 작성해야한다.
그 다음으로 해야할 일은 python 에서 import가 가능한 프로젝트를 패키지 구조로 만드는 것이다. 즉 import <패키지명>의 파이썬 코드로 사용할 수 있도록 그에 맞는 프로젝트의 구조를 만들어야한다.
 
 

# 패키지 구조 만들기

 
위와 같이 따라서 setup.py와 requirements.txt 등 실제 실행되지 않을 코드를 제외한 모든 .py 파일들이 특정한 directory의 하위에 들어가야하고, 그 directory에는 반드시 __init__.py가 있어야한다. 이 구조로 만들고나면, import <directory이름>으로 패키지를 불러와서 사용할 수 있게 된다. 패키지로 묶여지지 않고 root dir에 노출된 .py 파일들은 import로 사용하는 것이 불가능하다.
 
 
 

# pip로 github프로젝트에서 install해오기

pip install git+[github주소]
 
단, 이를 하기 위해서는 setup.py가 정의되어 있어야 한다.

# setup.py 와 requirements.txt의 차이

- setup.py : pip install로 사용하는 일반 사용자를 위한 최소 설치 요구사항

- requirements.txt : 개발자를 위한 설치 요구사항

 

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

https://packaging.python.org/discussions/install-requires-vs-requirements/

 

 

 

# setup.py 작성하기

from setuptools import setup, find_packages

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

with open("README.md", "r") as fh:
long_description = fh.read()

setuptools.setup(
name="simple_scheduler", # 이 패키지를 설치/삭제할 때 사용할 이름을 의미한다. 이 이름과 import할 때 쓰이는 이름은 다르다.
version="0.0.1",
author="Donghyun Kwak",
author_email="donghyun.kwak@naver.com",
description="A simplest scheduler for automated data preprocessing and nlu model training.",
long_description=long_description,
long_description_content_type="text/markdown",
url="https://github.com/dhkwak/simple_scheduler",
packages=setuptools.find_packages(),
classifiers=[
"Programming Language :: Python :: 3",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
],
python_requires='>=3.6',
install_requires=requirements,
)

https://packaging.python.org/tutorials/packaging-projects/

https://docs.python.org/3.6/distutils/setupscript.html

https://www.jetbrains.com/help/pycharm/creating-and-running-setup-py.html

 

 

# requirements.txt 작성하기

requirements.txt에는 내가 확실하게 실행을 보장할 수 있는 package와 그 버전을 명시해야한다.

버전명시 방법

package == 0.5.1 : 정확한 버전
package >= 0.5.1 : 0.5.1과 같거나 높은 버전
package == 0.5.* : 0.5로 시작되는 버전
package ~= 0.5.0 : 0.5.0 버전과 호환성이 있는 버전
 
 
 
~=: Compatible release clause
==: Version matching clause
!=: Version exclusion clause
<=, >=: Inclusive ordered comparison clause
<, >: Exclusive ordered comparison clause
===: Arbitrary equality clause.
 
 

- 상세규칙

It matches any candidate version that is expected to be compatible with the specified version.
 
pip installs the latest compatible version it can select.
 
 

# pip install시, .py 이외의 파일도 같이 설치되도록 만드는 방법

setup.py에 다음 두 줄을 선언한다.
 
setup(
...
package_data={"my_package": ["*.txt"]},
include_package_data=True,
)
 

https://stackoverflow.com/questions/1612733/including-non-python-files-with-setup-py

 

이때 package_data의 경로에는 패키지명을 제외한 그 하위 디렉토리가 와야한다.

[http://www.ianbicking.org/docs/setuptools-presentation/   의 22page참조]

 

# github source에서 바로 설치해야하는 경우

git+https://oss.navercorp.com/nsml/nsml_notebook.git
 
* git뿐만아니라, SVN등 다양한 VCS(Version Control System)에서의 설치를 지원한다.
 

# github source의 특정 브랜치 혹은 특정 commit hash를 설치해야하는 경우

git+https://oss.navercorp.com/nsml/nsml_notebook.git@branch_name
git+https://oss.navercorp.com/nsml/nsml_notebook.git@hash_tag

# pip install <패키지명> 으로 설치하게 하기

기존에 pypi에 올라와있는 패키지와 겹치지 않는 이름을 지어서, distribution package에 upload하면 위와 같은 방식으로 설치가능하다.
 

# python setup.py install로 설치한 것을 uninstall하기

python setup.py install은 사용하지 않는 것이 좋다. 왜냐하면 pip install . 으로 완벽히 대체할 수 있기 대문이다
만약 python setup.py install로 설치된 경우, 일일이 설치된 파일을 찾아다니면서 다 수동으로 삭제해야한다.
이때는 python setup.py install --record files.txt 의 명령어로 다시 설치한다음, 해당 파일들을 한번에 삭제해주도록 해야한다.(아래 링크 참조)
 

# Local 경로에 있는 package 설치하기

pip install path/to/package

# Editable mode로 설치하기

github에서 설치 할 경우, -e 옵션을 넣을 수도 있고, 넣지 않을 수도 있다.
 
-e를 이용해 설치할 경우, 패키지의 소스코드가 수정되었을 때, 새로이 pip install . 을 할 필요없이 바로 적용이 된다. 
이것의 원리는 해당 패키지를 symlink를 이용하여 설치하는 방식으로, 패키지를 특정한 directory에 옮겨서 복사하지 않고, 원본 소스코드를 단순히 module에 등록만 하는 방식이다.
 
pip install -e package#egg=nsml_notebook
 
이 뒷부분에 #egg=<패키지이름>을 입력해주어야만하고, 이 이름으로 아마 pip show에서 확인할 수 있을 것으로 보인다.
 

Egg란 무엇이고 왜 필요할까?

아래 글에 따르면 VCS에서 설치할 경우, 꼭 #egg=<package_name>을 입력하도록 예제에 나오고, 이 값은 오직 dependency check logic에만 사용된다고 나온다.
 
 

 

2. module관리 도구를 사용한다.

git에는 다양한 module관리 도구들이 존재한다. 여기서는 가장 대표적인 submodule과 subtree에 대해서 알아본다.
 

# git-submodule과 git-subtree의 핵심 차이점

일단 이 둘은 완전한 대체제가 아니고, 어떤 방식으로 사용할 지 목적에 맞게 선택해야하는 도구이다. 기본적으로 submodule은 module repo의 commit hash만 link하는 반면, git-subtree는 기본적으로 module의 소스코드 전체를 포함시킨다. 즉 submodule은 server를 통해야하는 반면, subtree는 decentralized되어 있다.

 

비교

submodule은 library의 remote에 push할 때는 편리하지만, pull 할 때는 불편하다.

subtree에서는 library의 remote에 push할 때는 불편하지만, pull 할 때는 편리하다.

 

submodule은 library 내의 변경사항을 library의 remote에 push하지 않고선, 본 프로젝트의 remote repo에서는 관리할 수 없다.

subtree에서는 library 내의 변경사항을 library의 remote에 push하지 않고도, 본 프로젝트의 remote repo에서도 관리할 수 있다.

 

library내의 변경사항을 library remote repo를 통해서 관리할 때 --> Submodule

library내의 변경사항을 프로젝트의 remote repo를 통해서 관리할 때 --> Subtree

 

결론: Subtree가 일반적으로 더 쓰기 편하다!

 

# git-submodule

submodule은 git에서 제공하는 default module관리 도구이다. 만약 submodule을 사용한다면, 절대로 local project을 위한 submodule의 소스코드 변경을 해선 안된다. git-submodule은 library배포와 유사한 개념으로 fixed version의 module이 배포되는 것을 가정하고 있다. 따라서 오직 local project를 위해서 module을 수정하기 시작하면 git-submodule으로 처리할 수 없는 불편한 요소가 매우 많아, 가능하면 이런 식으로사용하지 않기를 권장한다.

장점

- submodule은 library개발에 특화되어 있다. submodule을 쉽고 편하게 git pull을 하여 최신버전으로 update할 수 있고, 체계적으로 submodule의 버전을 나의 repo에서 관리할 수 있다. 또한 submodule에서 발생한 수정사항을 즉, library의 업데이트가 생기면 submodule의 remote repo로 쉽게 push할 수 있다는 점이 있다.(단, 이것을 내 프로젝트의 remote repo로 push하게 되면 크리티컬한 단점 3번이 발생한다.)

 

단점

1. .git에서 local submodule repo의 경로가 따로 관리가 되기 때문에, local에서 repo 위치를 바꿀 경우 매번 직접 gitdir을 수정해주어야 한다. 

2. 기본적으로 submodule의 내용을 웹에서 볼 수 없다. (그러나 이는 git submodule add --force <url> <path>; git submodule update로 해결할 수 있긴하다.)

3. submodule에서 내 프로젝트만을 위한 코드 변경을 할 경우, 이를 제대로 관리할 수 없다. 원칙적으로 submodule내에서의 수정은 submodule의 remote repo를 통해서만 트랙킹해야한다. 만약에 이를 무시하고 내가 수정한 submodule commit을 내 프로젝트의 remote repo에 push를 해버릴 경우, 더이상 submodule의 소스코드를 웹에서 보거나 관리하는 것이 불가능해진다.

4. 수없이 많은 에러. 이 부분은 어쩌면 submodule사용에 매우 숙달될 경우 발생이 덜 할 수 있다. 그러나 내가 매번 항상 겪는 문제는 새로이 git clone을 하면서 아무리 --recursive-module을 입력해도 submodule이 딸려오지 않고, submodule에서 pull을 아무리해도 가져와지지가 않는다.

 

# git-subtree

장점

1. subtree로 관리되는 프로젝트는 아무런 추가 명령어 없이 일반적인 repo와 똑같이 git clone할 수 있다.
2. subproject의 소스코드가 parent project에 완전히 포함되어 관리된다.
3. subproject에 대해서도 pull 및 push가 가능하다.
 

단점

1. 기본적으로 메타파일(.gittrees)없이도 사용할 수 있어서 편리하지만, 누군가에게는 헷갈릴 수 있고 이를 수동으로 추가하려면 여기를 복사해야한다.

 

 

 

 

 

3. git clone을 한다.

# 그다음 child repo의 .git을 삭제하고 일반 module로 포함한다.

Submodule에 비해서, git clone으로 그냥 다른 패키지를 가져와서 쓰는 것은 사용성 측면에서 훨씬 편하다. 유일한 단점은 가져온 repo는 git으로 관리해주지 않는다는 것이다. 

만약 해당 child repo를 많은 프로젝트에서 재사용하지 않는다면 이는 생각보다 별로 문제가 되지 않는다. 그러나 반대로 해당 child repo를 반복해서 재사용하며, 업데이트가 계속 이루어지는 경우, 이 방식은 매우 매우 불편하다. 왜냐하면 child repo에서 업데이트가 일어날 경우, 매번 수동으로 git clone한 다음, .git을 삭제하는 일을 반복해야하기 때문이다.

 

* 주의사항: 이 방식을 사용할 경우, Initial Commit이 원래 repo의 어떤 commit hash인지 반드시 기록해두어야 한다.

 

 

# Parent repo의 .gitignore에 해당 module을 등록한다.

 

 

 

 

 

댓글