[Python] Python 및 Custom 패키지 관리하기

2022. 12. 21. 20:53Developers 공간 [Basic]/Software Basic

728x90
반응형

python 프로젝트를 구성하면서 pip으로 패키지를 관리하고, 때로는 패키지를 직접 만들어 사용하기도 합니다.

이런 다양한 방법들을 정리하고자 합니다.

 

<구성>
1. Python 관리하기
    a. python과 pip 설치하기
   b. 패키지 관리하기
2. 패키지 import 경로 순서
   a. 1단계 sys.modules
   b. 2단계 built-in modules
   c. 3단계 sys.path (==$PYTHONPATH)
3. custom 패키지 관리하기
   a. custom 패키지 구성하기 기초
   b. Extension 구성하기

글효과 분류1 : 코드

글효과 분류2 : 폴더/파일

글효과 분류3 : 용어설명

글효과 분류4 : 글 내 참조


1. Python 관리하기

기본적으로 python과 pip을 다루는 것을 먼저 정리하겠습니다.


a. python 과 pip 설치하기
  • 인터넷이 있을 때 python과 pip 설치 : ubuntu에서 python을 설치할 때, apt-get을 활용해 설치한 후, 설치된 python을 활용해 pip을 설치하고 최신 버전으로 업데이트 합니다.
    • 기본적으로 ubuntu 버전에 따라 python3의 버전이 경험상 아래와 같이 설치됩니다.
      Ubuntu 16.04 : python3.5
      Ubuntu 18.04 : python3.6
      Ubuntu 20.04 : python3.8
# python3 설치 
sudo apt-get install python3

# python3 설치 : specific version
sudo apt-get install python3.7
ln -sf /usr/local/bin/python3.7 /usr/bin/python3

# 어떤 버전 python 인지 확인 
which python # binary 위치
whereis python # binary, libraries related to binary
locate python* # python으로 된 모든 파일

# pip3 설치
sudo apt-get install python3-pip

# pip3 설치2
python3 -m pip install pip

# pip3 update
pip3 install --upgrade pip
  • python, pip을 소스로 설치하기
    • wget 이용해서 https://www.python.org/downloads/source/ 에서 설치 Gzipped source tarball을 다운로드
    • 중간에 "can't decompress data; zlib not available" 인경우 apt-get install zlib1g-dev 
wget https://www.python.org/ftp/python/3.6.9/Python-3.6.9.tgz
tar xvf Python-3.6.9.tgz
cd Python-3.6.9
./configure --enable-optimization
make
make altinstall

ln -s /usr/local/bin/python3.6 /usr/local/bin/python3

apt-get update

 

더보기

-----------------------------------------------------------------------------------------------------

< Dockerfile 예시 참조>
RUN apt-get install -y wget build-essential tk-dev libncurses5-dev libncursesw5-dev \
libreadline6-dev libdb5.3-dev libgdbm-dev libsqlite3-dev libssl-dev libbz2-dev \
libexpat1-dev liblzma-dev zlib1g-dev python-dev python-setuptools \
python-pip python-smbus libc6-dev openssl libffi-dev &&\
mkdir /home/Python


WORKDIR /home/Python


RUN wget http://nexus.hae-hpc.com/repository/etc/python/Python-3.6.9.tgz && \
tar xvf Python-3.6.9.tgz
WORKDIR /home/Python/Python-3.6.9


RUN ./configure && \
make && \
make altinstall

RUN python3.6 -m pip install --upgrade pip
RUN python3.6 -m pip install easydict numpy scikit-image opencv-python tqdm Pillow torch ==1.4 torchvision=0.5 tensorboard

-----------------------------------------------------------------------------------------------------

  • pip 소스로 설치하기 : 아래는 python3.8이 존재할 때, pip3.8을 재설치하는 경우입니다.
    • No module named 'distutils.cmd' 에러가 나는 경우 apt-get install python3-distutils
curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py && python3.8 get-pip.py
  • python 삭제하기 
# 소스로 설치한 경우 
rm -rf /usr/bin/python3.*
rm -rf /usr/lib/python3.*
rm -rf /usr/local/bin/python3.*
rm -rf /usr/local/lib/python3.*

# apt-get으로 설치한 경우
apt-get purge python3.*

# apt-get으로 설치한 경우 : 직접삭제
rm -rf /usr/bin/python3.*
rm -rf /usr/lib/python3.*
rm -rf /usr/local/bin/python3.*
rm -rf /usr/local/lib/python3.*

rm -rf /var/lib/dpkg/info/python3*
rm -rf /var/lib/dpkg/info/libpython*

apt-get purge python3.*
apt-get purge libpython*

apt-get update
dpkg --configure -a

# 확인
dpkg -l | grep python3
  • python과 관련된 우선순위 지정해주기
# Symbolic Link 활용하기
ln -s /usr/bin/python3.6 /usr/bin/python3

# update-alternatives 활용하기
update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.5 1
update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.6 2

update-alternatives --config python3

 


b. 패키지 관리하기
  • 기본적으로 패키지를 설치하고, 재설치하고, 확인하는 명령어는 아래와 같습니다.
# Install
pip3 install package


# Re-Install
pip3 install --upgrade --force-reinstall 

# Check List
pip3 list

# Uninstall
pip3 uninstall package
  • 프로젝트에 셋팅된 설치 파일 한번에 설치하기 : 아래는 requirements.txt
alabaster==0.7.12
alembic==1.0.11
appnope==0.1.0
atomicwrites==1.3.0
attrs==19.1.0
Babel==2.7.0
b
ackcall==0.1.0
...
idna==2.8
imagesize==1.1.0
importlib-metadata==0.19
ipykernel==5.1.2
ipython==7.7.0
ipython-genutils==0.2.0
ipywidgets==7.5.1
itsdangerous==1.1.0
jdcal==1.4.1
pip3 install -r requirements.txt
  • 패키지 버전 및 연결 상태 확인
    • <Package>.__version__ : python 내에서 버전 확인
    • <Package>.__file__ : 위치를 확인할 수 있다.
    • pip3 show : python 패키지에 대해 자세한 정보를 보여주는 명령어 입니다.
python3 -c 'import torch; print(torch.__version__);print(torch.version.cuda)' 
python3 -c 'import mmdet3d; print(mmdet3d.__file__)'
  • torch 환경 확인하기 
    • python3 -m torch.utils.collect_env : PyTorch와 연결된 환경을 모두 알기 위한 방법입니다.
    • from torch.utils.collect_env import get_running_cuda_version, run
      get_running_cuda_version(run) : 현재 설치된 CUDA의 버전을 알려주는 명령어입니다. 어떤 GPU가 몇개 있는지 까지 확인할 수 있습니다.
    • pip3 show tensorflow : torch 의 경우 CUDA버전 확인 아래와 같이 가능

[torch.utils.collect_env 결과]

  • 인터넷 없이 패키지 설치하기
pip3 download tensorflow

python3 get-pip.py install pip-10.0.1-py2.py3-none-any.whl

 


2. 패키지 import 경로 순서

python 파일에서 import를 하면 아래와 같은 순서로 import 를 진행합니다. 이를 알고 프로젝트를 구성하면 편할 때가 많습니다.


a. 1단계 sys.modules

 

  • 한 번 이상 import가 되었다면 여기에 추가 됩니다.
  • python3 -c 'import sys; print(sys.modules)'
    ex) {'sys': <module 'sys' (built-in)>, 'builtins': <module 'builtins' (built-in)>, '_frozen_importlib': <module 'importlib._bootstrap' (frozen)>, '_imp': <module '_imp' (built-in)>, '_thread': <module '_thread' (built-in)>, '_warnings': <module '_warnings' (built-in)>, '_weakref': <module '_weakref' (built-in)>, 'zipimport': <module 'zipimport' (built-in)>, '_frozen_importlib_external': <module 'importlib._bootstrap_external' (frozen)>, '_io': <module 'io' (built-in)>, 'marshal': <module 'marshal' (built-in)>, 'posix': <module 'posix' (built-in)>, 'encodings': <module 'encodings' from ....

 


b. 2단계 built-in modules 
  • 파이썬에서 공식으로 제공하는 라이브러리로 내장되어있습니다. Python Standard Library(os,  sys, time 등)이 여기에 포함됩니다.
  • 위 예시에 보면 builtins 라고 표시된 것들이 built-in modules입니다.

 


c. 3단계 sys.path (==$PYTHONPATH)
  • sys.path는 실행한 .py 파일이 속한 절대 경로가 기본적으로 포함되어있고, 추가로 $PYTHONPATH에 있는 경로가 추가됩니다.
  • python3 -c 'import sys; print(sys.path)'
  • root에 접근이 불가능할 때나 python 경로에 라이브러리가 추가되어있지 않을 때 $PYTHONPATH를 활용해 지정하면 해결할 수 잇습니다.
    ex) /usr/local/lib/python3.6/site-packages를 추가

 

 

 

 


3. custom 패키지 관리하기

 

우리는 프로젝트를 패키지화 하기위해 *.pyx, *.cpp, *.cu 등을 컴파일하기도 합니다.

이렇게 하면 pip3로 설치한 것 처럼 할 수도 있고, 개인적으로 만들어 배포하고 안정적으로 관리하기에 유용합니다.

 


a. custom 패키지 구성하기 기초
  • 먼저 custom 패키지 구성은 아래와 같이 합니다.
    ├── setup.py
    ├── src
          ├── fastfile.cpp
    └── Include
          └── version.h
  • setup.py 내용
    • from setuptools import setup : custom 패키지를 빌드하기 위한 패키지입니다.
      from distutils.core import setup : distutils를 활용할 수도 있습니다.
    • distutils:  리눅스배포 관리자에게 python project를 linux 배포 패키지(apt-get,pip등)으로 변환하는 표준 방법을 제공합니다. 
      • python 2.0이 출시된 이후 수년동안 build system과 package설치 프로그램을 언어 런타임 배포주기에 밀접하게 연결하는 것은 문제가 되는 것으로 밝혀져서 이제 프로젝트는 distutils를 사용하는 것보다 setuptools빌드 시스템+pip을 사용하는하도록 권장합니다.
      • 결론 : distutils보다는 setuptools이 좋습니다.
    • Parameters
      • name : 패키지 이름
      • version : 패키지 버전
      • extra-compile-args : 컴파일 옵션을 줍니다.
      • ext_modules : torch.utils.cpp_extension.CUDAExtension() 등을 활용해 실제 사용할 source 선택합니다.
        ** distutils를 활용하는 경우 from distutils.core import Extension를 활용합니다.
      • cmdclass : build_ext 등 명령어 따라 다르게 동작하도록 추가해줍니다.
from setuptools import setup, Extension

    setup(
        name = 'fstfilepackage',
        version = '0.1.1',
        extra-compile-args={'cxx':['-lsource/include'], "nvcc":['-lsource/include']} //** -l : include 추가
        ext_modules = [
        Extension(
                name = 'fastfilepackage'
                sources = ['source/fastfile.cpp', 'source/fastfile.cu'], //** : source 추가
                include_dirs = ["-lsource/include"],
        	)
        ]
)
  • 실행
    • python3 setup.py install : 한번의 실행으로 모든 모듈을 빌드하고 설치, python의 기본 path에 설치해버리는 것 
    • python3 setup.py install --install-lib ./FOLDER : --install-lib로 해당 모든 모듈의 빌드 디렉토리를 지정할 수 있습니다. 하지만 프로젝트에서 작업할 때는 부르기 어려우므로, $PYTHONPATH에 추가해두면 좋습니다.
    • python3 setup.py build : 모든 것을 빌드합니다. 이후에 install하면 build 디렉터리의 모든 내용이 최신 상태이므로 수행할 작업이 없음을 빠르게 알 수 있습니다.
    • python3 setup.py build_ext : C/C++이나 Cython extension 등을 빌드 
    • python3 setup.py build_ext --inplace : build-lib를 무시하고 compiled extensions을 pure Python modules 옆에 source directory에 넣어두는 방법입니다.
    • pip3 install -e . : setup.py 파일이 있는 위치에서 실행하면 -e 혹은 --editable로 현재 자리에서 shared object를 만들고 python 기본 path에 현재 위치를 환경 변수로 추가합니다.
python3 setup.py --help-commands

python3 setup.py --help install
python3 setup.py install
python3 setup.py install --install-lib ./temp

python3 setup.py --help build_ext
python3 setup.py build_ext
python3 setup.py build_ext --inplace

pip3 install -e .
  • 경로 참조하기 예시
    • import os; os.path.dirname(os.path.abspath(__file__)) : 현재 위치를 프린트
    • 아래는 Include 경로와 Src 경로를 얻는 방법입니다.
import numpy as np

np_include_path = np.__file__.replace("__init__.py", "core/include/")
INCLUDE_PATH = [
	np_include_path
]

import glob
INCLUDE_PATH = glob.glob("~/THE_PATH/include/*")
import glob

SRC_PATH = glob.glob("THE_PATH/src/*.cpp")+glob.glob("THE_PATH/src/*.cu")

 


 

b. Extension 구성하기

 

이제 *.pyx, *.cpp, *.cu 등을 컴파일하기 위해 setup 함수를 어떻게 구성하는지 순서대로 설명하겠습니다.

 

  • 종류 : Extension은 기본적인 Cythonize등과 함께 활용하는 Extension, CppExtension, CUDAExtension 등이 있습니다. 기본적으로 setuptools에서 제공하는 Extension을 활용하지만, torch에서 제공하는 함수를 사용하기도 합니다.
# 필수
from setuptools import setup

# 1. for Cpp
from torch.utils.cpp_extension import BuildExtension,CppExtension

# 2. for CUDA
from torch.utils.cpp_extension import BuildExtension,CUDAExtension

# 3. for Cython
from Cython.Build import cythonize
from setuptools import Extension
  • CppExtension 예시 : C++파일들을 위한 Extension을 구성하는 방법입니다. RealName이라고 되어있는 부분이 import 할 때 쓰이는 이름입니다. 
from torch.utils.cpp_extension import BuildExtension, CppExtension

setup(
    name="Name",
    ext_modules=[CppExtension(
        name="RealName",
        sources=["~mysource/*.cpp"],
        extra_compile_args={
			"cxx": ["-O2", "-I{}".format("~/myinclude")],
        },
        include_dirs=["~/myinclude"],
    )],
    cmdclass={
		"build_ext" : BuildExtension
    }
)
  • CUDAExtension 예시 : cpp extension에 포함되며 C++/CUDA파일들을 위한 Extension을 구성하는 방법입니다. RealName이라고 되어있는 부분이 import 할 때 쓰이는 이름입니다. 
    • python3 setup.py install 한 경우 결과파일은 출력결과는 build폴더 외에 dist, RealName.egg-info 폴더 이렇게 생깁니다.
    • 이중에 build폴더 내의 RealName.cpython-36m-x86_64-linux-gnu.so/usr/local/lib/python/ 등의 위치에 복사되기 떄문에 import하여 사용할 수 있습니다.
from torch.utils.cpp_extension import BuildExtension, CUDAExtension

setup(
    name="Name",
    ext_modules=[CUDAExtension(
        name="RealName",
        sources=[
            "~mysource/*.cpp"
            "~mysource/*.cu"
        ],
        extra_compile_args={
            "cxx": ["-O2", "-I{}".format("~/myinclude")],
            "nvcc": ["-O2", "-I{}".format("~/myinclude")],
            '-D__CUDA_NO_HALF_OPERATORS__',
            '-D__CUDA_NO_HALF_CONVERSIONS__',
            '-D__CUDA_NO_HALF2_OPERATORS__',
        },
        define_macros = [
			('WITH_CUDA', None)
        ],
        include_dirs=["~/myinclude"],
    )],
    cmdclass={
		"build_ext" : BuildExtension
    }
)
  • Cythonize 예시 : Cython은 C로 컴파일되며, 실행하는 작업에 따라 적게는 몇 퍼센트에서 많게는 몇 배 더 높은 성능을 제공합니다. 파일 포맷은 *.pyx 이며, 해당 포맷에 맞는 문법이 존재합니다. RealName이라고 되어있는 부분이 import 할 때 쓰이는 이름입니다. 
    • python3 setup.py build_ext --inplace한 경우 결과 파일은 build폴더 외에 RealName.cpython-36m-x86_64-linux-gnu.soRealName.c 이렇게 생깁니다.
    • 이중에 RealName.cpython-36m-x86_64-linux-gnu.so를 직접 import 하여 사용할 수 있습니다.
from Cython.Build import cythonize
from setuptools import Extension

setup(
    name="Name",
    ext_modules = cythonize(Extension(
            name="RealName",
            sources=["~mysource/*.pyx"],
            include_dirs=["~/myinclude"],
        
    ))
)
  • Custom 패키지 사용하기 : 위와 같이 빌드된 이후에 import하는 방법은 아래와 같습니다. 위에 install과 build_ext 별로 다르게 만들어지는 것과 같이, install의 경우 직접 import할 수 있지만 build_ext는 파일위치로 직접 가서 import를 해야합니다.
# install 인 경우
try 
	import RealName
except ImportError:
	print("ERROR")
    RealName = None
    
# build_ext인 경우
try :
	from PATHTO import RealName
except ImportError:
	print("ERROR")
    RealName = None
    
# cpp, cu : ~.h 내에 Function()을 정의한 경우
# pyx : pyx 내에 Function()를 정의한 경우
RealName.Function()

 


https://docs.python.org/ko/3/distutils/configfile.html

https://yurmu.tistory.com/10

https://docs.python.org/ko/3/install/index.html

 

 

 

 

728x90
반응형