2022년 4월 23일 토요일

Python 프로젝트 github에 패키지 생성 및 설치 방법(Creating and installing python package from git rep)

0. 들어가기에 앞서


python에서 pip 라는것을 많이 사용하였을것입니다.

pip는 파이썬(python)으로 작성된 패키지 소프트웨어를 설치 관리하는 패키지 관리 시스템 입니다. 그런데 pip install을 하려면 Python Package Index (PyPI)에 등록이 되어 있어야 합니다.
PyPI 등록까지는 어렵더라도 여기에서는 github에 등록된 프로젝트를 pip를 이용하여 설치 하는방법, 그리고 pip 로 설치하려면 github에 어떤식으로 등록이 되어야 하는지 설명하겠습니다.

1. github에 등록된 프로젝트를 pip로 설치하기


pip install git+[github주소]
예)
pip install git+https://github.com/donarts/sourcecode.git

1.1 github source의 특정 브랜치 혹은 특정 commit hash를 설치해야하는 경우
git+https://github.com/donarts/sourcecode.git@branch_name
git+https://github.com/donarts/sourcecode.git@hash_tag


2. pip로 설치하기 위한 github 소스 구성


- setup.py : pip install로 사용시 setuptools가 실행됩니다.
- requirements.txt : 설치 요구 사항, 패키지들의 버전 나열 ( 없어도 됩니다. ) 이렇게 사용하는 이유는 setup.py에서 파일 열어서 install_requires 여기에 구성 목록을 만들기 때문입니다.


2.1 setup.py 

간단한 예제
https://docs.python.org/ko/3.10/distutils/introduction.html#distutils-simple-example
전체적인 설명
https://docs.python.org/ko/3.10/distutils/setupscript.html


2.2 requirements.txt

requirements.txt에는 실행을 보장할 수 있는 package와 그 버전을 명시해야합니다만, 
setup.py 내에 install_requires=requirements 여기에 해당내용이 text로 명시된다면 이 파일을 따로 작성할 필요는 없습니다.

  1. ~=: Compatible release clause
  2. ==: Version matching clause
  3. !=: Version exclusion clause
  4. <=>=: Inclusive ordered comparison clause
  5. <>: Exclusive ordered comparison clause
  6. ===: Arbitrary equality clause.

https://pip.pypa.io/en/latest/reference/requirements-file-format/#requirements-file-format


3. 실전 예제

앞에서 간단하게 설명을 했지만 이해하기도 힘들거란 판단에 실전 예제를 만들었습니다.
import os
import sys

def check_platform():
	return sys.platform

def get_data():
	import data.data
	return data.data.get_d_data()
check_platform 은 window인지 linux 인지 정보를 리턴하는 함수를 제작했습니다. 위 내용은 __init__.py 가 됩니다.
이것을 mypkg로 만들어서 pip install 이 되도록 할예정이고 테스트 코드는 아래와 같습니다.
import mypkg

print(mypkg.check_platform())
print("---")
print(mypkg.get_data())
mypkg가 정상적으로 설치되었다면 적절한 결과가 출력될겁니다.
mypkg.get_data()는 import data.data가 정상 동작하는지에 대한 코드입니다. 이것은 하위 폴더를 제대로 처리할 수 있는지에 대한 예제인데 테스트해보면 에러남을 알 수 있습니다.
즉 하위 폴더의 파일들은 같이 설치되지 않습니다.

3.1 setup.py에서 예제


from setuptools import setup

requirements=[
'PyYAML>=1.0',
]

setup(
    name='mygithub', # pip install/uninstall 설치 삭제시 사용하는 이름
    version='0.1.0',
    author='j',
    packages=['mypkg'], # import 할때 사용하게되는 이름
    package_dir={'mypkg': 'python/example/_41_github_install_pkg'},
    license='LICENSE.txt',
    description='installing python package ',
    python_requires='>=3.6',
    install_requires=requirements,
)

해당 파일은 github의 최상단(root 폴더)에 위치 해야합니다.

3.2 setup.py 중요 인자 설명

name : pip install/uninstall시 사용하는 이름입니다.
version : 버전명입니다.
package : import시 사용하는 이름이 됩니다.
package_dir : 패키지가 어디있는지 소스 위치를 알려줍니다. 패키지가 여러개 있을 수 있으므로 dict type으로 제공합니다.
install_requires : 필요한 패키지들 목록을 기록합니다. 위의 예제에서는 PyYAML 1.0 보다 같거나 큰 버전을 요구하도록 제작했으며 설치가 안되어 있으면 자동으로 PyPI에서 검색해서 설치합니다.

3.3 폴더의 구성


일반적으로 설명할때 이해를 돕기위해서 아래와 같이 설명합니다.
setup.py
src/
    mypkg/
        __init__.py
        module.py     
        data/              # 서브 폴더는 추가되지 않음 이건 따로 처리 필요
            tables.dat
            spoons.dat
            forks.dat
기본 폴더 구성은 위와 같이 제일 상단에 setup.py가 있어야하고 패키지 폴더 아래 __init__.py 파일이 있어야 합니다. 
위의 구성에서는 src/mypkg/는 임의의 이름입니다.


setup(...,
      packages=['mypkg'],
      package_dir={'mypkg': 'src/mypkg'}, # 소스의 위치를 나타낸다. __init__.py 를 찾는다. 그외에 같은 경로에 있는 파일들은 같이 포함됨
      package_data={'mypkg': ['data/*.dat']},
      ...
      )

setup.py에는 위와같은 패키지명외에 

이번 예제에서는 아래에 패키지 소스가 위치하고 패키지 이름은 name='mygithub' 입니다.
sourcecode/python/example/_41_github_install_pkg/

git hub에서 폴더 구성을 확인하시면 도움이 될것입니다.


4. 설치 테스트


만약 소스 코드에 로컬에 있다면 아래와 같이 설치합니다.

python setup.py install

설치 결과
running install
running bdist_egg
running egg_info
creating mygithub.egg-info
writing mygithub.egg-info/PKG-INFO
writing dependency_links to mygithub.egg-info/dependency_links.txt
writing top-level names to mygithub.egg-info/top_level.txt
writing manifest file 'mygithub.egg-info/SOURCES.txt'
reading manifest file 'mygithub.egg-info/SOURCES.txt'
writing manifest file 'mygithub.egg-info/SOURCES.txt'
installing library code to build/bdist.win-amd64/egg
running install_lib
running build_py
creating build
creating build/lib
creating build/lib/mypkg
copying python/example/_41_github_install_pkg/__init__.py -> build/lib/mypkg
creating build/bdist.win-amd64
creating build/bdist.win-amd64/egg
creating build/bdist.win-amd64/egg/mypkg
copying build/lib/mypkg/__init__.py -> build/bdist.win-amd64/egg/mypkg
byte-compiling build/bdist.win-amd64/egg/mypkg/__init__.py to __init__.cpython-38.pyc
creating build/bdist.win-amd64/egg/EGG-INFO
copying mygithub.egg-info/PKG-INFO -> build/bdist.win-amd64/egg/EGG-INFO
copying mygithub.egg-info/SOURCES.txt -> build/bdist.win-amd64/egg/EGG-INFO
copying mygithub.egg-info/dependency_links.txt -> build/bdist.win-amd64/egg/EGG-INFO
copying mygithub.egg-info/top_level.txt -> build/bdist.win-amd64/egg/EGG-INFO
zip_safe flag not set; analyzing archive contents...
creating dist
creating 'dist/mygithub-0.1.0-py3.8.egg' and adding 'build/bdist.win-amd64/egg' to it
removing 'build/bdist.win-amd64/egg' (and everything under it)
Processing mygithub-0.1.0-py3.8.egg
Copying mygithub-0.1.0-py3.8.egg to c:/users/user/appdata/local/programs/python/python38/lib/site-packages
Adding mygithub 0.1.0 to easy-install.pth file

Installed c:/users/user/appdata/local/programs/python/python38/lib/site-packages/mygithub-0.1.0-py3.8.egg
Processing dependencies for mygithub==0.1.0
Finished processing dependencies for mygithub==0.1.0

이런식으로 나오면서 설치가 완료됩니다.

그러면 mypkg가 설치가 된것이므로 아래와 같이 실행시키면

import mypkg

print(mypkg.check_platform())
print("---")
print(mypkg.get_data())


결과

win32
---
Traceback (most recent call last):
  File "test.py", line 5, in <module>
    print(mypkg.get_data())
  File "C:\Users\USER\AppData\Local\Programs\Python\Python38\lib\site-packages\mypkg\__init__.py", line 8, in get_data
    import data.data
  File "C:\Users\USER\Documents\GitHub\sourcecode\python\example\_41_github_install_pkg\data\data.py", line 1
    def get_d_data()
                   ^
SyntaxError: invalid syntax

win32는 나왔지만 아래쪽 get_data()가 오류가 발생합니다.

이것은 __init__.py 에서 data 폴더 하위를 패키징 하지 못했기 때문입니다. 이 부분을 조절하려면 setup.py를 수정해야합니다. 그리고 form . import data 와 같이 표현하도록 합니다.

테스트가 끝났으면 uninstall 해줍니다.
C:\Users\USER\Documents\GitHub\sourcecode\python\example\_41_github_install_pkg>pip uninstall mygithub
Uninstalling mygithub-0.1.0:
  Would remove:
    c:\users\user\appdata\local\programs\python\python38\lib\site-packages\mygithub-0.1.0.dist-info\*
    c:\users\user\appdata\local\programs\python\python38\lib\site-packages\mypkg\*
Proceed (y/n)? y
  Successfully uninstalled mygithub-0.1.0

git에 반영을 다했으면, 이번에는 git에 있는 소스로 설치해보겠습니다.

C:\Users\USER\Documents\GitHub\sourcecode\python\example\_41_github_install_pkg>pip install git+https://github.com/donarts/sourcecode.git
Collecting git+https://github.com/donarts/sourcecode.git
  Cloning https://github.com/donarts/sourcecode.git to c:\users\user\appdata\local\temp\pip-req-build-p9ayzlvf
  Running command git clone -q https://github.com/donarts/sourcecode.git 'C:\Users\USER\AppData\Local\Temp\pip-req-build-p9ayzlvf'
Requirement already satisfied: PyYAML>=1.0 in c:\users\user\appdata\local\programs\python\python38\lib\site-packages (from mygithub==0.1.0) (6.0)
Building wheels for collected packages: mygithub
  Building wheel for mygithub (setup.py) ... done
  Created wheel for mygithub: filename=mygithub-0.1.0-cp38-none-any.whl size=2615 sha256=7a2ec0c8b26c376abe40b6391aa4375cb1a2c8d38f8bdf2ceac596c8dfb9efa4
  Stored in directory: C:\Users\USER\AppData\Local\Temp\pip-ephem-wheel-cache-y36_j0mo\wheels\e5\97\0b\62ad10df424d838509a42096c6daf0109efaeb8521434d5384
Successfully built mygithub
Installing collected packages: mygithub
Successfully installed mygithub-0.1.0

정상적으로 설치되었습니다.
test.py로 테스트 하면 동일한 곳에서 에러가 발생합니다.




댓글 없음:

댓글 쓰기