성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] VT sequences to "CONOUT$" vs. STD_O...
[정성태] NetCoreDbg is a managed code debugg...
[정성태] Evaluating tail call elimination in...
[정성태] What’s new in System.Text.Json in ....
[정성태] What's new in .NET 9: Cryptography ...
[정성태] 아... 제시해 주신 "https://akrzemi1.wordp...
[정성태] 다시 질문을 정리할 필요가 있을 것 같습니다. 제가 본문에...
[이승준] 완전히 잘못 짚었습니다. 댓글 지우고 싶네요. 검색을 해보...
[정성태] 우선 답글 감사합니다. ^^ 그런데, 사실 저 예제는 (g...
[이승준] 수정이 안되어서... byteArray는 BYTE* 타입입니다...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <h1 style='font-family: Malgun Gothic, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>파이썬 - PyPI 패키지 만들기 (3) entry_points 옵션</h1> <p> 지난 글에 다룬,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 파이썬 - PyPI 패키지 만들기 ; <a target='tab' href='https://www.sysnet.pe.kr/2/0/12863'>https://www.sysnet.pe.kr/2/0/12863</a> 파이썬 - PyPI 패키지 만들기 (2) long_description, cmdclass 옵션 ; <a target='tab' href='https://www.sysnet.pe.kr/2/0/12865'>https://www.sysnet.pe.kr/2/0/12865</a> </pre> <br /> setup.py의 옵션 중에는 entry_points라는 것이 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > setup( name="net-util", description="utility functions for networking", long_description=readme(), long_description_content_type='text/markdown', # cmdclass={'sdist': UserCode}, cmdclass={'bdist_wheel': UserCode}, version=netutil.__version__, author=netutil.__author__, author_email="techsharer@outlook.com", url="https://www.sysnet.pe.kr", license="Ms-PL", packages=find_packages(exclude=[]), install_requires=["requests>=2.22.0"], <span style='color: blue; font-weight: bold'>entry_points={ 'console_scripts': [ 'netutil-admin = netutil.admin:main', ], },</span> ) </pre> <br /> 위와 같이 지정한 경우라면, 당연히 "netutil.admin" 패키지가 있어야 합니다. 예를 들어 간단하게 다음과 같은 식의 파일을 만들 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > # ./netutil/admin/__init__.py def main(): print('net-util administrations') </pre> <br /> 그럼, "pip install ..." 시에 위의 "netutil.admin::main"을 호출하는 'netutil-admin.py'를 사용자 디렉터리(<span class="tex2jax_ignore">$</span>HOME/.local/bin)에 다음과 같은 식으로 pip 프로그램이 생성해 줍니다. <br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > /home/testusr/.local/bin$ <span style='color: blue; font-weight: bold'>cat netutil-admin</span> #!/usr/bin/python3 # -*- coding: utf-8 -*- import re import sys <span style='color: blue; font-weight: bold'>from netutil.admin import main</span> if __name__ == '__main__': sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) sys.exit(<span style='color: blue; font-weight: bold'>main()</span>) </pre> <br /> 따라서 일종의 프로그램을 하나 제공하는 효과를 얻게 되는데 실제로 해당 명령어를 실행하는 것도 가능합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > $ <span style='color: blue; font-weight: bold'>netutil-admin</span> net-util administrations </pre> <br /> 이렇게 만드는 경우 주의할 것이 있다면 바로, 해당 파일(위의 경우 __init__.py)에서 같은 프로젝트에 포함된 모듈을 import하는 경우 명시적으로 상대 경로를 지정해야 하는 상황도 있다는 점입니다.<br /> <br /> 예를 들어, __init__py와 동일한 디렉터리에 info.py가 있고,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > # ./netutil/admin/info.py def help_cmd(): print('netutil-admin') pass </pre> <br /> 위의 기능을 이용하기 위해 단순히 __init__.py에서는 다음과 같이 사용할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > # ./netutil/admin/__init__.py <span style='color: blue; font-weight: bold'>import info</span> def main(): print('net-util administrations') <span style='color: blue; font-weight: bold'>info.help_cmd()</span> </pre> <br /> 하지만, 이것이 entry_points로 등록된 경우라면 상황이 달라집니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > entry_points={ 'console_scripts': [ 'netutil-admin = <span style='color: blue; font-weight: bold'>netutil.admin</span>:main', ], }, </pre> <br /> 저런 경우에는 netutil.admin 패키지에서 site-packages 경로를 기준으로 "import info"를 찾기 때문에 "ModuleNotFoundError: No module named 'info'"라는 예외가 발생합니다.<br /> <br /> 따라서, 상대 경로로 import를 해야 하는데 import 구문에는 상대 경로를 지정할 수 없으므로 sys.path.append를 이용하거나 다음과 같이 from 구문으로 바꿔 상대 경로를 지정하면 됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > # ./netutil/admin/__init__.py from <span style='color: blue; font-weight: bold'>.info</span> import help_cmd def main(): print('net-util administrations') help_cmd() </pre> <br /> <hr style='width: 50%' /><br /> <br /> entry_points로 등록한 경우 리눅스에서는 shell script로 "$HOME/.local/bin" 경로에 파일이 생성되는데, 그렇다면 윈도우의 경우에는 어떨까요?<br /> <br /> 개인적인 예상으로는 사실 지원하지 않을 거라고 생각했습니다. 왜냐하면, 윈도우의 경우 "%USERPROFILE%" 경로가 기본적으로 PATH 환경 변수에 등록되어 있진 않으므로 단순히 jennifer-admin.cmd 파일을 생성한다고 해서 실행되지는 않을 것이므로 여러모로 불편할 수 있습니다.<br /> <br /> 하지만, 지원을 합니다. ^^ 경로는, Python 설치 경로의 ".\Scripts\" 하위 디렉터리에 무려 EXE 파일로 생성이 됩니다. (cmd/bat가 아닌 굳이 왜 EXE로 했는지는 알 수 없지만!)<br /> <br /> 재미있는 것은, 윈도우 버전의 파이썬 Script 디렉터리에 있는 exe 파일들이,<br /> <br /> <img alt='pypi_adv_2.png' src='/SysWebRes/bbs/pypi_adv_2.png' /><br /> <br /> 하나같이 104KB 크기로 된 것으로 봐서는 거의 템플릿화 되어 있는 듯합니다. 게다가 pip.exe 등도 결국 사용자가 컴파일해서 제공하는 것이 아닌, 결국 파이썬 모듈을 호출하는 console_scripts 설정으로 만들어진 실행 모듈이었던 것입니다. 그렇다면, 리눅스에서는 당연히 shell script로 연결된 것이라는 것을 유추할 수 있습니다. ^^<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > $ <span style='color: blue; font-weight: bold'>cat /usr/bin/pip</span> #!/usr/bin/python3 # EASY-INSTALL-ENTRY-SCRIPT: 'pip==20.0.2','console_scripts','pip' __requires__ = 'pip==20.0.2' import re import sys <span style='color: blue; font-weight: bold'>from pkg_resources import load_entry_point</span> if __name__ == '__main__': sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) sys.exit( <span style='color: blue; font-weight: bold'>load_entry_point('pip==20.0.2', 'console_scripts', 'pip')()</span> ) </pre> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
3893
(왼쪽의 숫자를 입력해야 합니다.)