python 3์์ apistar๋ฅผ ์คํ ์ค์ด๊ณ werkzeug ๋ฆฌ๋ก๋๋ก ์ด์ด์ง๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ต๋๋ค.
(fresh) C:\Users\uskaxb07\PycharmProjects\testapi>apistar run
Starting up...
* Restarting with stat
File "C:\Users\uskaxb07\env\fresh\Scripts\apistar.exe", line 1
SyntaxError: Non-UTF-8 code starting with '\x90' in file C:\Users\uskaxb07\env\fresh\Scripts\apistar.exe on line 1, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details
์ ๊ฑฐ ์ค use_reloader
๋ก ํธ์ถ์์์ run_simple()
์๋ํฉ๋๋ค. ๋ช ๊ฐ์ง ์๊ฒฌ์ ํํค์น ํ https://github.com/pallets/werkzeug/blob/master/werkzeug/_reloader.py#L118 ์ด latin1์ ๋ํ ์ธ์ฝ๋ฉ์ ์ํํ๊ณ ์์ง๋ง OS๊ฐ Windows์ด๊ณ ํ์ด์ฌ ๋ฒ์ ์ธ ๊ฒฝ์ฐ์๋ง ํด๋น is 2. ์ด๊ฒ์ด ๋ด๊ฐ python3์์ ๋ฐ๋ ๋น UTF-8 ๊ตฌ๋ฌธ ์ค๋ฅ์ ์์ธ์ด ๋ ์ ์์ต๋๊น?
์ด๊ฒ์ ์ฌํํ๋ ๋ฐ ์ฌ์ฉํ ์ ์๋ ์์ ์๊ฐ ์์ต๋๊น? apistar ์ฌ์ฉ์ ์ต์ํ์ง ์๊ณ Windows๋ฅผ ์ ๊ธฐ์ ์ผ๋ก ์ฌ์ฉํ์ง ์์ต๋๋ค.
์กฐ๊ธ ๋ ํ๊ณ ๋ค์์ต๋๋ค. ๋ฌธ์ ๋ ์ค์ ๋ก _get_args_for_reloading() ์
๋๋ค. ์ด ๋ฉ์๋๋ subprocess.call()
์ ๋ฌ๋ ๋ ํด๋น ์ค๋ฅ๋ฅผ ์์ฑํ๋ ['python.exe', 'apistar.exe', 'run']
์ธ ์ธ์๋ฅผ ๋ฐํํฉ๋๋ค. ๋ช
๋ น์ค์์ python.exe apistar.exe run
๋ฅผ ํธ์ถํ๋ ๊ฒ๊ณผ ๋ค๋ฅด์ง ์์ต๋๋ค.
๋ฐ๋ผ์ ๋ฌธ์ ๋ ๋ด๊ฐ ์๋ ์๊ฐํ๋ ๊ฒ๊ณผ ๊ฐ์ ํ๊ฒฝ ์ธ์ฝ๋ฉ์ด ์๋๋๋ค. ๋ค๋ฅธ werkzueg ๊ธฐ๋ฐ ํ๋ ์์ํฌ์์ ๋งค์ฐ ์ผ๋ฐ์ ์ผ๋ก ๋ฐ์ํ๋ค๋ ์ ์ ๊ฐ์ํ ๋ console_script์์ ์์ฑ๋ .exe๋ฅผ ํตํด ํธ์ถํ ์ ์๋ค๋ ์ฌ์ค์ ๊ณ ๋ คํ์ฌ ์ด ๋ฐฉ๋ฒ์ ๋ณ๊ฒฝํ๋ฉด ๋ชจ๋ Windows ์ฌ์ฉ์์๊ฒ ๋์์ด ๋ ๊ฒ์ ๋๋ค.
๋๋ ์ด๊ฒ์ ์ค๋ช ํ๊ธฐ ์ํด ๋ฌธ์ ์ ๋ชฉ์ ๋ณ๊ฒฝํฉ๋๋ค.
์ด ๋ฉ์๋๊ฐ Windows ๊ฒ์ฌ ๋ด์์ rv์ sys.executable ์์๋ฅผ ์ญ์ ํ๋ฉด ๋ค์ ๋ก๋๊ฐ ์ฑ๊ณตํ ๊ฒ์ ๋๋ค.
def _get_args_for_reloading():
"""Returns the executable. This contains a workaround for windows
if the executable is incorrectly reported to not have the .exe
extension which can cause bugs on reloading.
"""
rv = [sys.executable]
py_script = sys.argv[0]
if os.name == 'nt' and not os.path.exists(py_script) and \
os.path.exists(py_script + '.exe'):
py_script += '.exe'
rv.pop()
rv.append(py_script)
rv.extend(sys.argv[1:])
return rv
PR์ ์ ์ถํ๊ณ ์ถ๋ค๋ฉด ๊ธฐ๊บผ์ด ๊ฒํ ํ๊ฒ ์ต๋๋ค.
๋๋ ํ์คํ ํ๊ณ ์ถ์ง๋ง ์ด๊ฒ์ ๋ํ ํ ์คํธ๋ฅผ ์์ฑํ๋ ๋ฐ ์ฝ๊ฐ ๋งํ์ต๋๋ค. ๋๋ ์ด๊ฒ์ด unittest.mock ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ํจ๊ป ์๋ํ๊ณ sys.executable ๋ฐ os.name์ ํจ์นํ๋ ๊ฒ๋ง ๋ณผ ์ ์์ง๋ง 27์์๋ ์๋ํ๋ ํ ์คํธ๋ฅผ ์ง์ํด์ผ ํ๊ธฐ ๋๋ฌธ์ ์ด๊ฒ์ด ํ๋ก์ ํธ์์ ์๋ํ์ง ์์ ๊ฒ์ด๋ผ๊ณ ๊ฐ์ ํฉ๋๋ค. ์ด๋ค ์ถฉ๊ณ ?
๋ํ ์ฌ๊ธฐ์ ์ฌ์ฉ๋ ๋ถ๊ธฐ ์ ๋ต์ ๋ฌด์์ ๋๊น? ๋ฌธ์ ์ ๋ํ pull ์์ฒญ์ ํ์ฌ ์ ์ง ๊ด๋ฆฌ ๋ถ๊ธฐ์ ์ ์ฉ๋ฉ๋๊น?
0.12-maintenance์์ ๋ถ๊ธฐํ ์ ์์ต๋๋ค. ๋จผ์ ํจ์น๊ฐ ์ด๋ป๊ฒ ์๊ฒผ๋์ง ํ์ธํ ๋ค์ ํ ์คํธ๋ฅผ ์์๋ณด๊ฒ ์ต๋๋ค.
ํ ๋ฆฌํ์คํธ๋ฅผ ์ ์ถํ์ต๋๋ค. Travis CI๊ฐ ๋ด๊ฐ ๋ณ๊ฒฝํ ๊ฒ๊ณผ ๊ด๋ จ์ด ์๋ ์ด์ ๋ก ์คํจํ ๊ฒ ๊ฐ์ต๋๋ค. ํ ๋ฆฌํ์คํธ๋ ์ด๋ฒ์ด ์ฒ์์ด๋ผ ์ด๋์๋ถํฐ ํด์ผํ ์ง ๋ชจ๋ฅด๊ฒ ์ต๋๋ค.
์ด๊ฒ์ setuptools์ exe ์คํ ํ๋ก๊ทธ๋จ์ด ์ค์น๋์ด ์์ ๋ ๋ฐ์ํฉ๋๋ค. ์ต์ pip๋ฅผ ํตํด ์ค์นํ๋ฉด Python์ด ์ง์ ์คํํ ์ ์๋ zip( runpy docs ) ๋ด๋ถ์ exe์ ์คํ๊ธฐ ์คํฌ๋ฆฝํธ๋ฅผ ๋ฒ๋ค๋ก ๋ฌถ๋ ์๋ก์ด ์ข ๋ฅ์ exe ์คํ๊ธฐ(
์ด๊ฒ์ ์ด๊ฒ์ด ์์ ๋์ด์๋ ์๋๋ค๋ ๊ฒ์ ์๋ฏธํ์ง๋ ์์ง๋ง, ์ด๊ฒ์ ์ฌํํ ์ ์๋ ๊ฒฝ์ฐ๋ฅผ ์๋ ๊ฒ์ด ๋์์ด ๋ฉ๋๋ค. ์๋ฅผ ๋ค์ด Flask๋ฅผ ๊ฐ๋ฐ ๋ชจ๋( pip install -e
)๋ก ์ค์นํ๋ฉด ๊ณ์ ๋ฐ์ํฉ๋๋ค.
@androiddrew @davidism ์ด PR์ ๋ํ ์ ๋ฐ์ดํธ๊ฐ ์์ต๋๊น?
@segevfiner ๊ฐ์ฅ ์ต๊ทผ ๋๊ธ์ ์ข ๋ ์์ธํ ๋ด์ฉ์ ์ถ๊ฐํ ์ ์์ต๋๊น? Flask๊ฐ ์๋ setuptools์์ ๊ทผ๋ณธ ์์ธ์ ์์ ํด์ผ ํ๋ค๊ณ ์ ์ํ๊ณ ์์ต๋๊น?
@ewpete ๊ทผ๋ณธ ์์ธ์ setuptools์์ ์์ฑ๋ ๋ฐ์ฒ๋ฅผ ์ฌ์ฉํ ๋,
sys.argv[0]์ Python ์คํฌ๋ฆฝํธ๋ก ์คํํ ์ ์์ต๋๋ค.
๋ฐ์ฒ exe. ์ค์ ์คํฌ๋ฆฝํธ๋ "-script"๋ฅผ ์ฌ์ฉํ์ฌ exe์ ๊ฐ์ ์ด๋ฆ์ ์ง์ ํฉ๋๋ค.
์ถ๊ฐ๋๊ณ exe๊ฐ ๋ก๋ํ๊ณ ์คํํฉ๋๋ค.
exe๋ ์ง์ ์คํํ ์ ์์ต๋๋ค(๊ทธ๋ฆฌ๊ณ Python ์คํฌ๋ฆฝํธ๋ ๋ง์ฐฌ๊ฐ์ง์
๋๋ค).
๋ด๊ฐ ๋ฏฟ๋ shebang์ setuptools๊ฐ unices์์ ์์ฑํ๋ ๊ฒ์ด๋ผ๊ณ ์๊ฐํฉ๋๋ค. ํ์ง๋ง
Windows์์ ์ผ๋ฐ Python ์คํฌ๋ฆฝํธ์ ๋ํด ๊ทธ๋ ๊ฒ ํ๋ ๊ฒ์ ์ ๋ขฐํ ์ ์์ต๋๋ค.
pylauncher๊ฐ ์ค์น๋์ง ์์), ์์์ Python์ผ๋ก ์์๋๋ฏ๋ก
๋ค๋ฅผ ์ ์๋ ๋ ์ง์คํธ๋ฆฌ์ .py ํ์ผ์ ์ฐ๊ฒฐ๋จ
์ฐ๋ฆฌ๊ฐ ํ์ฌ ์ฌ์ฉํ๊ณ ์๋ ํ์ด์ฌ๋ณด๋ค. ๋ฌผ๋ก ๋ค์์๋ ๋์ผํ๊ฒ ์ ์ฉ๋ฉ๋๋ค.
์ฐ๋ฆฌ๊ฐ ํธ์ถํ ์ ์๋ ์์์ Python ์คํฌ๋ฆฝํธ
์คํ ๊ฐ๋ฅ.
pip๋ ๋์ distlib๋ฅผ ํตํด ์๋ก์ด ์ข
๋ฅ์ exe ์คํ๊ธฐ๋ฅผ ์ค์นํฉ๋๋ค.
zip ํ์ผ์ ๋์ ์ถ๊ฐ๋ ์์ฑ๋ ๋ฐ์ฒ ์คํฌ๋ฆฝํธ
์คํ ๊ฐ๋ฅ. ์ด๊ฒ์ __main__.py ์คํฌ๋ฆฝํธ(A
zipapp) ์คํ์ ์ํด Python์ ์ง์ ์ ๋ฌํ ์ ์์ต๋๋ค.
setuptools์์ ์ด๊ฒ์ ์์ ํ๋ ๊ฒ์ ์ ์ฌ/๋์ผํ ์ข
๋ฅ๋ฅผ ์์ฑํ๋ ๊ฒ์ ์๋ฏธํฉ๋๋ค
setuptools์ ๋ฐ์ฒ. ๊ทธ๋ฆฌ๊ณ http://xkcd.com/1172/ ์ ์ ์ ์ผ๋ก ์ด๊ฒ์
setuptools ์คํ๊ธฐ๋ฅผ ์์ํ๊ณ ์๋ํ๋ ์ฝ๋๋ฅผ ๊นจ๋จ๋ฆด ๊ฐ๋ฅ์ฑ์ด ์์ต๋๋ค.
"*-script.py" ํ์ผ์ ์ฌ์ฉํ์ฌ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํฉ๋๋ค. ๋๋ ํ์ธํ์ง ์์๋ค
์ด๋ฏธ ์ด์ ๋ํ ๋ฌธ์ /ํ๋ณด๊ฐ ์๋์ง ์ฌ๋ถ.
Werkzeug๊ฐ
reloader๋ setuptools์ ํ์ฌ ์คํ์ผ์ด ์๋ ๊ฒฝ์ฐ์๋ ์๋ํฉ๋๋ค.
๋ฐ์ฌ๊ธฐ. ๊ทธ๋ฌ๋ ๊ทธ๊ฒ์ ์ค์ ๋ก ํ๋ก์ ํธ ๊ด๋ฆฌ์์๊ฒ ๋ฌ๋ ค ์์ต๋๋ค.
ืืชืืจืื 28 ืื ืื' 2017 20:46, "ewpete" [email protected] ืืชื:
@androiddrew https://github.com/androiddrew @davidism
https://github.com/davidism ์ด PR์ ๋ํ ์ ๋ฐ์ดํธ๊ฐ ์์ต๋๊น?@segevfiner https://github.com/segevfiner ์ข ๋ ์ถ๊ฐํ ์ ์๋์?
๊ฐ์ฅ ์ต๊ทผ ๋๊ธ์ ๋ํ ์ธ๋ถ์ ๋ณด? ์ฐ๋ฆฌ๊ฐ ํด์ผ ํ๋ค๊ณ ์ ์ํฉ๋๊น?
Flask๊ฐ ์๋ setuptools์์ ๊ทผ๋ณธ ์์ธ์ ์์ ํ์๊ฒ ์ต๋๊น?โ
๋น์ ์ด ์ธ๊ธ๋์๊ธฐ ๋๋ฌธ์ ์ด๊ฒ์ ๋ฐ๋ ๊ฒ์ ๋๋ค.
์ด ์ด๋ฉ์ผ์ ์ง์ ๋ต์ฅํ๊ณ GitHub์์ ํ์ธํ์ธ์.
https://github.com/pallets/werkzeug/issues/1136#issuecomment-347623921 ,
๋๋ ์ค๋ ๋ ์์๊ฑฐ
https://github.com/notifications/unsubscribe-auth/AXlg_8OSR3NdbPJzM87dyKPUAA9NpXJ6ks5s7FT7gaJpZM4N5Fcb
.๊ทธ๋งํผ
@ewpet ์ ์ฒซ PR์ด์์ต๋๋ค. ํ ์คํธ๋ฅผ ์์ฑํ๊ณ ๊ฐ๋ฐ ๊ฐ์ด๋๋ฅผ ๋ฐ๋ฅด๊ณ PR์ ๋ฐฐ์นํ๊ธฐ ์ํด ์ต์ ์ ๋คํ์ต๋๋ค. ์ด ์์ ์ ์ํํ๋ ๋ฐฉ๋ฒ์ ๋ํ ๋ง์ ์ง์นจ์ด ์์์ง๋ง PR ์๊ฒฌ์์ ์ ์๋ ๋ณ๊ฒฝ ์ฌํญ์ ์ ์ฉํ์ต๋๋ค. ๋๋ ๊ทธ๊ฒ์ด ์์ฑ๋์๋ค๊ณ ์๊ฐํ์ง๋ง ๊ทธ๊ฒ์ด ํ๋ก์ ํธ ํ์ ๊ธฐ๋์ ๋ถ์ํ๋์ง์ ๋ํ ๋ต์ ๋ฃ์ง ๋ชปํ์ต๋๋ค. ๊ทธ ์ดํ๋ก ๊ทธ๊ฒ์ ๋ณธ ์ ์ด ์์ผ๋ฉฐ ์ฌ๋๋ค์ด ๊ทธ๊ฒ์ ๊ฐ์ง๊ณ ๋ฌด์์ ํ๊ณ ์ถ์ดํ๋์ง ๋ชจ๋ฅด๊ฒ ์ต๋๋ค.
๋๋ ์ฌ๋ฌ ํ๋ก์ ํธ์์ ๋งค์ฐ ์ ํ๋ ์๊ฐ์ ๊ฐ์ง๊ณ ์์ต๋๋ค. ๊ฑฑ์ ํ์ง ๋ง์ญ์์ค. ์ด๊ฒ์ ์์ง ๋ง์ญ์์ค.
@davidism ์๋ต๋ง ํ๋ ๊ฒ์ด ์๋๋ผ ์ด ํ๋ก์ ํธ๋ฅผ ๊ณ์ ์ ์งํ๊ธฐ ์ํด ์ข์ ์ผ์ ํด์ฃผ์ ์ ๊ฐ์ฌํฉ๋๋ค!
์ด๊ฒ์ด ์์ง ๋ณํฉ๋์ง๋ ์์์ง๋ง ํ ๊ฐ์ง ๊ฐ๋ฅํ ์์ ์์ ์ _get_args_for_reloading()
ํจ์๊ฐ ์ฌ์ฉ๋๊ธฐ ์ ์ ์ด๋๊ฐ์ ์์ญ์ด ํจ์น๋ฅผ ์ ์ฉํ๋ ๊ฒ์
๋๋ค. Flask ์คํฌ๋ฆฝํธ์ ๊ฒฝ์ฐ manage.py
ํ์ผ ์์ ๋ถ๋ถ์ ๋ค์์ ์ถ๊ฐํ๋ฉด ๋์์ด ๋ฉ๋๋ค.
import werkzeug._reloader
import os, sys
def _get_args_for_reloading():
rv = [sys.executable]
py_script = sys.argv[0]
if os.name == 'nt' and not os.path.exists(py_script) and \
os.path.exists(py_script + '.exe'):
py_script += '.exe'
if os.path.splitext(rv[0])[1] == '.exe' and os.path.splitext(py_script)[1] == '.exe':
rv.pop()
rv.append(py_script)
rv.extend(sys.argv[1:])
return rv
werkzeug._reloader._get_args_for_reloading = _get_args_for_reloading