2020. 1. 25. 18:17ㆍ분석 Python/구현 및 자료
한 번만 실수로 광고를 눌러주세요! 블로그 운영에 큰 힘이 됩니다. :)
인터넷이 안 되는 환경에 패키지를 설치해야 할 일이 있다.
이런 일이 있을 때, 만약 도커 같은 것을 굉장히 편리하게 할 수 있지만, 아직 안 쓰는 곳도 있을 때는 의존성을 다 확인해서 가져가야 한다.
R에서는 이러한 것을 고려해서 한번 설치하면 모든 dependency를 설치해주는 miniCRAN이라는 방법이 있지만,
아쉽게도 파이썬에서는 모든 dependency까지는 고려해주는 것을 아직까진 본 적이 없다.
pip download 를 사용하면, 해당 패키지에 대한 Dependency까지는 고려해주지만, 그 Dependency의 Dependency 패키지는 설치를 안 해주는 것 같다.
https://pip.pypa.io/en/stable/reference/pip_download/
그래서 이번에는 완벽하지는 않지만, 일단 필요한 것은 전부 긁어오는 것을 만들어봤다.
물론 이 작업을 하고 나서 같은 패키지의 2개의 버전이 생길 수 있다.
예를 들어 아래의 그림과 같은 일이 생긴다.
이러한 문제가 발생하는 이유는 pip download를 통해 한 패키지의 dependency를 설치하는데, 그때는 가장 update된 패키지를 가져오는 일이 발생하기 때문인 것 같다.
그래서 내가 원하는 것은 joblib-0.13.2인데, 다른 패키지 dependency에서 joblib이 있어서 0.14.1를 다운로드하게 되는 일이 발생하는 것 같다.
그래서 이번 글에 목표는 필요한 패키지의 모든 dependency 패키지를 긁어오는 것이다.
import os , re
import numpy as np
일단 내가 원하는 패키지는 다음과 같다.
이제 이것의 모든 dependency를 긁어와보자.
pkgs = ["scikit-learn==0.21.3","scipy==1.2.1",
"tensorflow-gpu==1.14.0","gputil==1.4.0","tqdm==4.35.0",
"mysql-connector-python==8.0.17"]
패키지를 설치하면서 log를 찍으면 다음과 같은 말이 나온다.
Collecting matplotlib==3.1.1
Using cached https://files.pythonhosted.org/packages/57/4f/dd381ecf6c6ab9bcdaa8ea912e866dedc6e696756156d8ecc087e20817e2/matplotlib-3.1.1-cp36-cp36m-manylinux1_x86_64.whl
Saved ./pkg/matplotlib-3.1.1-cp36-cp36m-manylinux1_x86_64.whl
Collecting pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.1 (from matplotlib==3.1.1)
Using cached https://files.pythonhosted.org/packages/5d/bc/1e58593167fade7b544bfe9502a26dc860940a79ab306e651e7f13be68c2/pyparsing-2.4.6-py2.py3-none-any.whl
Saved ./pkg/pyparsing-2.4.6-py2.py3-none-any.whl
Collecting numpy>=1.11 (from matplotlib==3.1.1)
Using cached https://files.pythonhosted.org/packages/62/20/4d43e141b5bc426ba38274933ef8e76e85c7adea2c321ecf9ebf7421cedf/numpy-1.18.1-cp36-cp36m-manylinux1_x86_64.whl
Saved ./pkg/numpy-1.18.1-cp36-cp36m-manylinux1_x86_64.whl
Collecting cycler>=0.10 (from matplotlib==3.1.1)
Using cached https://files.pythonhosted.org/packages/f7/d2/e07d3ebb2bd7af696440ce7e754c59dd546ffe1bbe732c8ab68b9c834e61/cycler-0.10.0-py2.py3-none-any.whl
Saved ./pkg/cycler-0.10.0-py2.py3-none-any.whl
Collecting kiwisolver>=1.0.1 (from matplotlib==3.1.1)
Using cached https://files.pythonhosted.org/packages/f8/a1/5742b56282449b1c0968197f63eae486eca2c35dcd334bab75ad524e0de1/kiwisolver-1.1.0-cp36-cp36m-manylinux1_x86_64.whl
Saved ./pkg/kiwisolver-1.1.0-cp36-cp36m-manylinux1_x86_64.whl
Collecting python-dateutil>=2.1 (from matplotlib==3.1.1)
Using cached https://files.pythonhosted.org/packages/d4/70/d60450c3dd48ef87586924207ae8907090de0b306af2bce5d134d78615cb/python_dateutil-2.8.1-py2.py3-none-any.whl
Saved ./pkg/python_dateutil-2.8.1-py2.py3-none-any.whl
Collecting six (from cycler>=0.10->matplotlib==3.1.1)
Using cached https://files.pythonhosted.org/packages/65/eb/1f97cb97bfc2390a276969c6fae16075da282f5058082d4cb10c6c5c1dba/six-1.14.0-py2.py3-none-any.whl
Saved ./pkg/six-1.14.0-py2.py3-none-any.whl
Collecting setuptools (from kiwisolver>=1.0.1->matplotlib==3.1.1)
Using cached https://files.pythonhosted.org/packages/a7/c5/6c1acea1b4ea88b86b03280f3fde1efa04fefecd4e7d2af13e602661cde4/setuptools-45.1.0-py3-none-any.whl
Saved ./pkg/setuptools-45.1.0-py3-none-any.whl
Successfully downloaded matplotlib pyparsing numpy cycler kiwisolver python-dateutil six setuptools
저 예제에서는 cloudpickle이 하나밖에 없지만 dependecy가 있다면 아래 또 다른 패키지들이 설치될 것이다.
그러면 이제는 아래 만든 함수를 통해서 긁어온다.
그러면 a는 다음과 같이 나오게 된다.
이제 저기서 다시 저것의 dependency를 다운로드하기 위해서 setuptools과 45.1.0만 가져와서
setutools==45.1.0로 만들어야 한다..
a = [re.split("./pkg/", line)[-1].split("\n")[0] for line in lines if re.search("Saved", line)]
## a=[setuptools-45.1.0-py3-none-any.whl]
### => change [setuptools==45.1.0]
이렇게 만드는 함수는 append 함수로 만들었습니다.
def append(a) :
store = []
for i in a :
lists = i.split("-")
if re.search("\d", lists[1] ) is not None :
pkg_name = f'{lists[0]}=={lists[1]}'
else :
pkg_name = f'{lists[0]}-{lists[1]}=={lists[2]}'
pkg_name = pkg_name.split(".tar.gz")[0]
print(pkg_name)
store.append(pkg_name)
return store
## append(a)
### -> [setuptools==45.1.0]
그래서 저렇게 만든 것을 새로 설치할 패키지 list에 추가한다.
store = append(a)
pkgs = pkgs + store
pkgs = list(dict.fromkeys(pkgs))
pkgs.remove(pkg)
위의 코드의 의미는 일단 패키지 list에 붙이고, 중복 제거하고 그리고 설치했으니 해당 패키지를 list에서 지우는 코드이다.
그래서 전체 코드는 다음과 같다.
import os , re
import numpy as np
pkgs = ["scikit-learn==0.21.3","scipy==1.2.1",
"tensorflow-gpu==1.14.0","gputil==1.4.0","tqdm==4.35.0",
"mysql-connector-python==8.0.17"]
def append(a) :
store = []
for i in a :
lists = i.split("-")
if re.search("\d", lists[1] ) is not None :
pkg_name = f'{lists[0]}=={lists[1]}'
else :
pkg_name = f'{lists[0]}-{lists[1]}=={lists[2]}'
pkg_name = pkg_name.split(".tar.gz")[0]
print(pkg_name)
store.append(pkg_name)
return store
total_store = []
while True :
i = 0
before = len(os.listdir("./pkg/"))
pkg = pkgs[i]
ck = os.system(f"pip download {pkg} --only-binary=:all: -d ./pkg --python-version 36 --abi cp36m > installed_{pkg}.txt")
print(f"Install {pkg} Check : {ck}")
if ck != 0 :
ck = os.system(f"pip download {pkg} -d ./pkg > installed_{pkg}.txt")
f = open(f"installed_{pkg}.txt", 'r')
lines = f.readlines()
a = [re.split("./pkg/", line)[-1].split("\n")[0] for line in lines if re.search("Saved", line)]
store = append(a)
print("="*40)
print(store)
print("="*40)
total_store.extend(store)
try :
store.remove(pkg)
except :
pass
total_store = list(dict.fromkeys(total_store))
pkgs = pkgs + store
pkgs = list(dict.fromkeys(pkgs))
pkgs.remove(pkg)
print(pkgs)
after = len(os.listdir("./pkg/"))
print(before , after)
i += 1
if len(pkgs) == 0 :
# if before == after :
print("탈출")
break
이제 돌고 나서 중복을 체크하면 다음과 같은 결과가 나온다.
result = append(os.listdir("./pkg/")[1:])
import collections
dup_check = [store.split("==")[0] for store in result ]
print(collections.Counter(dup_check))
패키지를 모두 가져왔다. 그렇지만 한 패키지에 여러 버전이 같이 다운로드가 된 것을 알 수 있다.
음... 여기서부터는 더 아이디어가 생기면 해결해보겠다.
일단은 여기까지 하면 모든 의존성 패키지를 가져온 것이라고 할 수 있다.
일단 끝~
'분석 Python > 구현 및 자료' 카테고리의 다른 글
[ Python ] 현재 돌아가는 Python Script 선택해서 끄기 (0) | 2020.02.06 |
---|---|
[ Python ] decorator로 Error 정리해서 출력하기 (0) | 2020.01.31 |
[ Python ] Optuna Sampler 비교 (TPESampler VS SkoptSampler) (0) | 2020.01.24 |
[ Python ] numba 사용 예시 (0) | 2020.01.15 |
[ Python ] smtplib을 활용한 메일 보내기 (이미지 , 텍스트 , gif) (0) | 2020.01.05 |