!pip install git+https://github.com/yeonsookim-wt/lgtm#egg=lgtm
Collecting lgtm Cloning https://github.com/yeonsookim-wt/lgtm to /private/var/folders/xt/5rx58mwn1p5g_dghf90jzwbw0000gp/T/pip-install-0ug3fe0x/lgtm_b658156aad80408aae1b187f2bb08d25 Running command git clone -q https://github.com/yeonsookim-wt/lgtm /private/var/folders/xt/5rx58mwn1p5g_dghf90jzwbw0000gp/T/pip-install-0ug3fe0x/lgtm_b658156aad80408aae1b187f2bb08d25 Collecting Click~=7.0 Using cached click-7.1.2-py2.py3-none-any.whl (82 kB) Collecting Pillow~=6.2.0 Using cached Pillow-6.2.2-cp38-cp38-macosx_10_9_x86_64.whl (2.1 MB) Collecting requests~=2.22.0 Using cached requests-2.22.0-py2.py3-none-any.whl (57 kB) Collecting idna<2.9,>=2.5 Using cached idna-2.8-py2.py3-none-any.whl (58 kB) Requirement already satisfied: certifi>=2017.4.17 in /Users/yeonsookim/Workspaces/python-src/venv/lib/python3.8/site-packages (from requests~=2.22.0->lgtm) (2020.12.5) Collecting urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 Using cached urllib3-1.25.11-py2.py3-none-any.whl (127 kB) Collecting chardet<3.1.0,>=3.0.2 Using cached chardet-3.0.4-py2.py3-none-any.whl (133 kB) Using legacy 'setup.py install' for lgtm, since package 'wheel' is not installed. Installing collected packages: urllib3, idna, chardet, requests, Pillow, Click, lgtm Attempting uninstall: urllib3 Found existing installation: urllib3 1.26.3 Uninstalling urllib3-1.26.3: Successfully uninstalled urllib3-1.26.3 Attempting uninstall: idna Found existing installation: idna 2.10 Uninstalling idna-2.10: Successfully uninstalled idna-2.10 Attempting uninstall: chardet Found existing installation: chardet 4.0.0 Uninstalling chardet-4.0.0: Successfully uninstalled chardet-4.0.0 Attempting uninstall: requests Found existing installation: requests 2.25.1 Uninstalling requests-2.25.1: Successfully uninstalled requests-2.25.1 Running setup.py install for lgtm ... done Successfully installed Click-7.1.2 Pillow-6.2.2 chardet-3.0.4 idna-2.8 lgtm-1.0.0 requests-2.22.0 urllib3-1.25.11
# 도움말 표시
!lgtm --help
Usage: lgtm [OPTIONS] KEYWORD LGTM 이미지 생성 도구 Options: -m, --message TEXT 이미지에 추가할 문자열 [default: LGTM] --help Show this message and exit.
# 'book'으로 이미지 검색을 수행해 output.png를 생성
# 키워드 대신 이미지 경로나 이미지 URL도 지정할 수 있음
!lgtm book
# requests 설치
%pip install requests==2.22.0
Requirement already satisfied: requests==2.22.0 in /Users/yeonsookim/Workspaces/python-src/venv/lib/python3.8/site-packages (2.22.0) Requirement already satisfied: certifi>=2017.4.17 in /Users/yeonsookim/Workspaces/python-src/venv/lib/python3.8/site-packages (from requests==2.22.0) (2020.12.5) Requirement already satisfied: idna<2.9,>=2.5 in /Users/yeonsookim/Workspaces/python-src/venv/lib/python3.8/site-packages (from requests==2.22.0) (2.8) Requirement already satisfied: chardet<3.1.0,>=3.0.2 in /Users/yeonsookim/Workspaces/python-src/venv/lib/python3.8/site-packages (from requests==2.22.0) (3.0.4) Requirement already satisfied: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 in /Users/yeonsookim/Workspaces/python-src/venv/lib/python3.8/site-packages (from requests==2.22.0) (1.25.11) Note: you may need to restart the kernel to use updated packages.
from urllib import request, parse, error
import json
query = parse.urlencode({'q': 'python'})
# httpbin은 요청 내용을 반환해 줌
url = f'https://httpbin.org/get?{query}'
try:
with request.urlopen(url) as f:
res = f.read().decode('utf-8')
except error.HTTPError as e:
print(e)
json.loads(res)
--------------------------------------------------------------------------- SSLCertVerificationError Traceback (most recent call last) /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/urllib/request.py in do_open(self, http_class, req, **http_conn_args) 1318 try: -> 1319 h.request(req.get_method(), req.selector, req.data, headers, 1320 encode_chunked=req.has_header('Transfer-encoding')) /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/http/client.py in request(self, method, url, body, headers, encode_chunked) 1229 """Send a complete request to the server.""" -> 1230 self._send_request(method, url, body, headers, encode_chunked) 1231 /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/http/client.py in _send_request(self, method, url, body, headers, encode_chunked) 1275 body = _encode(body, 'body') -> 1276 self.endheaders(body, encode_chunked=encode_chunked) 1277 /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/http/client.py in endheaders(self, message_body, encode_chunked) 1224 raise CannotSendHeader() -> 1225 self._send_output(message_body, encode_chunked=encode_chunked) 1226 /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/http/client.py in _send_output(self, message_body, encode_chunked) 1003 del self._buffer[:] -> 1004 self.send(msg) 1005 /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/http/client.py in send(self, data) 943 if self.auto_open: --> 944 self.connect() 945 else: /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/http/client.py in connect(self) 1398 -> 1399 self.sock = self._context.wrap_socket(self.sock, 1400 server_hostname=server_hostname) /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/ssl.py in wrap_socket(self, sock, server_side, do_handshake_on_connect, suppress_ragged_eofs, server_hostname, session) 499 # ctx._wrap_socket() --> 500 return self.sslsocket_class._create( 501 sock=sock, /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/ssl.py in _create(cls, sock, server_side, do_handshake_on_connect, suppress_ragged_eofs, server_hostname, context, session) 1039 raise ValueError("do_handshake_on_connect should not be specified for non-blocking sockets") -> 1040 self.do_handshake() 1041 except (OSError, ValueError): /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/ssl.py in do_handshake(self, block) 1308 self.settimeout(None) -> 1309 self._sslobj.do_handshake() 1310 finally: SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1108) During handling of the above exception, another exception occurred: URLError Traceback (most recent call last) <ipython-input-5-4c30eeb42713> in <module> 6 url = f'https://httpbin.org/get?{query}' 7 try: ----> 8 with request.urlopen(url) as f: 9 res = f.read().decode('utf-8') 10 except error.HTTPError as e: /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/urllib/request.py in urlopen(url, data, timeout, cafile, capath, cadefault, context) 220 else: 221 opener = _opener --> 222 return opener.open(url, data, timeout) 223 224 def install_opener(opener): /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/urllib/request.py in open(self, fullurl, data, timeout) 523 524 sys.audit('urllib.Request', req.full_url, req.data, req.headers, req.get_method()) --> 525 response = self._open(req, data) 526 527 # post-process response /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/urllib/request.py in _open(self, req, data) 540 541 protocol = req.type --> 542 result = self._call_chain(self.handle_open, protocol, protocol + 543 '_open', req) 544 if result: /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/urllib/request.py in _call_chain(self, chain, kind, meth_name, *args) 500 for handler in handlers: 501 func = getattr(handler, meth_name) --> 502 result = func(*args) 503 if result is not None: 504 return result /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/urllib/request.py in https_open(self, req) 1360 1361 def https_open(self, req): -> 1362 return self.do_open(http.client.HTTPSConnection, req, 1363 context=self._context, check_hostname=self._check_hostname) 1364 /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/urllib/request.py in do_open(self, http_class, req, **http_conn_args) 1320 encode_chunked=req.has_header('Transfer-encoding')) 1321 except OSError as err: # timeout error -> 1322 raise URLError(err) 1323 r = h.getresponse() 1324 except: URLError: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1108)>
import requests
res = requests.get('https://httpbin.org/get',
params={'q': 'python'})
res.json()
{'args': {'q': 'python'}, 'headers': {'Accept': '*/*', 'Accept-Encoding': 'gzip, deflate', 'Host': 'httpbin.org', 'User-Agent': 'python-requests/2.22.0'}, 'origin': '153.182.176.137, 153.182.176.137', 'url': 'https://httpbin.org/get?q=python'}
res = requests.post('https://httpbin.org/post',
data={'q': 'python'})
res.json()['form']
{'q': 'python'}
# Click 설치
%pip install Click==7.0
Collecting Click==7.0 Downloading Click-7.0-py2.py3-none-any.whl (81 kB) |████████████████████████████████| 81 kB 1.7 MB/s eta 0:00:011 Installing collected packages: Click Attempting uninstall: Click Found existing installation: click 7.1.2 Uninstalling click-7.1.2: Successfully uninstalled click-7.1.2 Successfully installed Click-7.0 Note: you may need to restart the kernel to use updated packages.
!cat greet.py
import click @click.command() @click.option('--words', default='Hello') @click.argument('name') def greet(name, words): click.echo(f'{words}, {name}!') if __name__ == '__main__': greet()
!python3 greet.py user
Hello, user!
!python3 greet.py user --words Hi
Hi, user!
# Pillow 설치
%pip install Pillow==6.2.1
Collecting Pillow==6.2.1 Downloading Pillow-6.2.1-cp38-cp38-macosx_10_9_x86_64.whl (2.1 MB) |████████████████████████████████| 2.1 MB 2.8 MB/s eta 0:00:01 Installing collected packages: Pillow Attempting uninstall: Pillow Found existing installation: Pillow 6.2.2 Uninstalling Pillow-6.2.2: Successfully uninstalled Pillow-6.2.2 Successfully installed Pillow-6.2.1 Note: you may need to restart the kernel to use updated packages.
import os
from PIL import Image
def thumbnail(infile, size=(128, 128)):
outfile = os.path.splitext(
infile)[0] + ".thumbnail"
try:
im = Image.open(infile)
im.thumbnail(size)
im.save(outfile, "JPEG")
except IOError:
print("cannot create thumbnail for", infile)
# 임의의 JPEG 파일을 지정함
thumbnail('dog.jpg')
%cd workspace
/Users/yeonsookim/Workspaces/personal/python-src/13-application/workspace
!git init
Initialized empty Git repository in /Users/yeonsookim/Workspaces/personal/python-src/13-application/workspace/.git/
# git 설치 직후라면 다음을 실행함
!git config --global user.email "you@example.com"
!git config --global user.name "Your Name"
!cat requirements.txt
Click==7.0 Pillow==6.2.1 requests==2.22.0
%pip install -r requirements.txt
Requirement already satisfied: Click==7.0 in /Users/suyamar/github/python-practice-book/src/13-application/venv/lib/python3.8/site-packages (from -r requirements.txt (line 1)) (7.0)
Requirement already satisfied: Pillow==6.2.1 in /Users/suyamar/github/python-practice-book/src/13-application/venv/lib/python3.8/site-packages (from -r requirements.txt (line 2)) (6.2.1)
Requirement already satisfied: requests==2.22.0 in /Users/suyamar/github/python-practice-book/src/13-application/venv/lib/python3.8/site-packages (from -r requirements.txt (line 3)) (2.22.0)
Requirement already satisfied: chardet<3.1.0,>=3.0.2 in /Users/suyamar/github/python-practice-book/src/13-application/venv/lib/python3.8/site-packages (from requests==2.22.0->-r requirements.txt (line 3)) (3.0.4)
Requirement already satisfied: certifi>=2017.4.17 in /Users/suyamar/github/python-practice-book/src/13-application/venv/lib/python3.8/site-packages (from requests==2.22.0->-r requirements.txt (line 3)) (2019.11.28)
Requirement already satisfied: idna<2.9,>=2.5 in /Users/suyamar/github/python-practice-book/src/13-application/venv/lib/python3.8/site-packages (from requests==2.22.0->-r requirements.txt (line 3)) (2.8)
Requirement already satisfied: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 in /Users/suyamar/github/python-practice-book/src/13-application/venv/lib/python3.8/site-packages (from requests==2.22.0->-r requirements.txt (line 3)) (1.25.7)
WARNING: You are using pip version 19.2.3, however version 19.3.1 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
Note: you may need to restart the kernel to use updated packages.
%pip freeze > requirements.lock
Note: you may need to restart the kernel to use updated packages.
# 빈 __init__.py를 작성
# Windows에서는 type nul > lgtm/__init__.py
!touch lgtm/__init__.py
!cat .circleci/config.yml
version: 2 jobs: setup_dependencies: docker: - image: circleci/python:3.8.1 steps: - checkout - restore_cache: key: deps-{{ checksum "requirements.lock" }} - run: command: | pip install --user -r requirements.lock - save_cache: key: deps-{{ checksum "requirements.lock" }} paths: - "~/.local" test: docker: - image: circleci/python:3.8.1 steps: - checkout - restore_cache: key: deps-{{ checksum "requirements.lock" }} - run: command: | python3 -m unittest -v workflows: version: 2 all: jobs: - setup_dependencies - test: requires: - setup_dependencies
!python3 main.py --help
Usage: main.py [OPTIONS] KEYWORD LGTM画像生成ツール Options: -m, --message TEXT 画像に乗せる文字列 [default: LGTM] --help Show this message and exit.
!cat lgtm/image_source.py
from io import BytesIO import requests from pathlib import Path class LocalImage: """ファイルから画像を取得する""" def __init__(self, path): self._path = path def get_image(self): return open(self._path, 'rb') class RemoteImage: """URLから画像を取得する""" def __init__(self, path): self._path = path def get_image(self): data = requests.get(self._path) # バイトデータをファイルオブジェクトに変換 return BytesIO(data.content) class RemoteImage: """URLから画像を取得する""" def __init__(self, path): self._url = path def get_image(self): data = requests.get(self._url) # バイトデータをファイルオブジェクトに変換 return BytesIO(data.content) class _LoremFlickr(RemoteImage): """キーワード検索で画像を取得する""" LOREM_FLICKR_URL = 'https://loremflickr.com' WIDTH = 800 HEIGHT = 600 def __init__(self, keyword): super().__init__(self._build_url(keyword)) def _build_url(self, keyword): return (f'{self.LOREM_FLICKR_URL}/' f'{self.WIDTH}/{self.HEIGHT}/{keyword}') KeywordImage = _LoremFlickr # 関数だがコンストラクタとして利用する def ImageSource(keyword): """最適なイメージソースクラスを返す""" if keyword.startswith(('http://', 'https://')): return RemoteImage(keyword) elif Path(keyword).exists(): return LocalImage(keyword) else: return KeywordImage(keyword) def get_image(keyword): """画像のファイルオブジェクトを返す""" return ImageSource(keyword).get_image()
!cat lgtm/drawer.py
from PIL import Image, ImageDraw, ImageFont # 画像全体に対するメッセージ描画可能エリアの比率 MAX_RATIO = 0.8 # フォント関連の定数 FONT_MAX_SIZE = 256 FONT_MIN_SIZE = 24 # WindowsやLinuxではパスが異なる FONT_NAME = '/Library/Fonts/Arial Bold.ttf' FONT_COLOR_WHITE = (255, 255, 255, 0) # アウトプット関連の定数 OUTPUT_NAME = 'output.png' OUTPUT_FORMAT = 'PNG' def save_with_message(fp, message): image = Image.open(fp) draw = ImageDraw.Draw(image) # メッセージを描画できる領域のサイズ # タプルの要素ごとに計算する image_width, image_height = image.size message_area_width = image_width * MAX_RATIO message_area_height = image_height * MAX_RATIO # フォントサイズを決める for font_size in range(FONT_MAX_SIZE, FONT_MIN_SIZE, -1): font = ImageFont.truetype(FONT_NAME, font_size) # 描画に必要なサイズ text_width, text_height = draw.textsize( message, font=font) w = message_area_width - text_width h = message_area_height - text_height # 幅、高さともに領域内におさまる値を採用 if w > 0 and h > 0: position = ((image_width - text_width) / 2, (image_height - text_height) / 2) # メッセージの描画 draw.text(position, message, fill=FONT_COLOR_WHITE, font=font) break # 画像の保存 image.save(OUTPUT_NAME, OUTPUT_FORMAT)
!cat lgtm/core.py
import click from lgtm.drawer import save_with_message from lgtm.image_source import get_image @click.command() @click.option('--message', '-m', default='LGTM', show_default=True, help='画像に乗せる文字列') @click.argument('keyword') def cli(keyword, message): """LGTM画像生成ツール""" lgtm(keyword, message) def lgtm(keyword, message): with get_image(keyword) as fp: save_with_message(fp, message)
# 결과 이미지는 얻는 이미지에 따라 다름
!python3 main.py book
!cat setup.py
from setuptools import find_packages, setup setup( name='lgtm', version='1.0.0', packages=find_packages(exclude=('tests',)), install_requires=[ 'Click', 'Pillow', 'requests', ], entry_points={ 'console_scripts': [ 'lgtm=lgtm.core:cli' ] } )
%pip install -e .
Obtaining file:///Users/suyamar/github/python-practice-book/src/13-application/workspace
Requirement already satisfied: Click in /Users/suyamar/github/python-practice-book/src/13-application/venv/lib/python3.8/site-packages (from lgtm==1.0.0) (7.0)
Requirement already satisfied: Pillow in /Users/suyamar/github/python-practice-book/src/13-application/venv/lib/python3.8/site-packages (from lgtm==1.0.0) (6.2.1)
Requirement already satisfied: requests in /Users/suyamar/github/python-practice-book/src/13-application/venv/lib/python3.8/site-packages (from lgtm==1.0.0) (2.22.0)
Requirement already satisfied: certifi>=2017.4.17 in /Users/suyamar/github/python-practice-book/src/13-application/venv/lib/python3.8/site-packages (from requests->lgtm==1.0.0) (2019.11.28)
Requirement already satisfied: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 in /Users/suyamar/github/python-practice-book/src/13-application/venv/lib/python3.8/site-packages (from requests->lgtm==1.0.0) (1.25.7)
Requirement already satisfied: idna<2.9,>=2.5 in /Users/suyamar/github/python-practice-book/src/13-application/venv/lib/python3.8/site-packages (from requests->lgtm==1.0.0) (2.8)
Requirement already satisfied: chardet<3.1.0,>=3.0.2 in /Users/suyamar/github/python-practice-book/src/13-application/venv/lib/python3.8/site-packages (from requests->lgtm==1.0.0) (3.0.4)
Installing collected packages: lgtm
Found existing installation: lgtm 1.0.0
Not uninstalling lgtm at /Users/suyamar/github/python-practice-book/src/13-application/workspace, outside environment /Users/suyamar/github/python-practice-book/src/13-application/venv
Can't uninstall 'lgtm'. No files were found to uninstall.
Running setup.py develop for lgtm
Successfully installed lgtm-1.0.0
WARNING: You are using pip version 19.2.3, however version 19.3.1 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
Note: you may need to restart the kernel to use updated packages.
# 명령어가 등록됨
!lgtm
Usage: lgtm [OPTIONS] KEYWORD Try "lgtm --help" for help. Error: Missing argument "KEYWORD".
!lgtm book