독학/python

[파이썬] cx_freeze pyinstaller 실행 파일 배포 .exe 만들기: on console 'NoneType' object has no attribute write error 해결 방법

JC story 2023. 4. 12. 22:55
반응형

안녕하세요 종백이입니다😎

 

오늘은 파이썬 .py 스크립트를 누구나 사용할 수 있게 .exe 만드는 방법을 알아보려고 합니다!

exe파일

실행파일 배포 대표적인 2가지 모듈

1. pyinstaller

2. cx_freeze

 

위 두 모듈을 이용해서 main.py 를 .exe 파일로 배포하는 것을 알아보겠습니다😎

1. pyinstaller

설치 방법

pip install pyinstaller

 

사용방법

기본 배포

pyinstaller main.py

 

한 파일로 배포(-F or --onfile)

pyinstaller -F main.py

 

한 폴더로 배포(-D or --onedir)

pyinstaller -D main.py

 

배포시 .exe 아이콘 변경

pyinstaller --icon="iconPath/iconfile.ico" main.py

 

이름 변경

pyinstaller --name test.exe main.py

 

no console

pyinstaller --noconsole main.py

위 옵션을 섞고 싶을 땐 띄어쓰기로 여러 옵션을 추가해서 사용하시면 됩니다! 예를 들어 한파일로 배포하고 노콘솔로 하고 싶으시면

pyinstaller -F --noconsole main.py 

위와 같은 방식으로 하시면 됩니다😎

 

가끔 pyinstaller로 배포파일을 만들었을 때 이유 모를 오류가 있는데 이럴 때 cx_freeze를 사용하면 오류 없이 실행되는 경우가 있어서 cx_freeze도 같이 사용합니다!

2. cx_freeze

설치방법

pip install cx_freeze

사용방법

cx_freeze는 main.py 스크립트와 동일한 폴더에 setup.py를 구성해야 합니다.

setup.py

from cx_Freeze import setup, Executable

buildOptions = {
	"packages":[
    	'requests','time','zipfile','shutil','os','win32gui', 'win32con', 'subprocess'
    ],
    "excludes":[
    	"tkinter","matplotlib"
    ]
}
 
exe = [Executable('main.py', base='Win32GUI')]
 
setup(
    name='main',
    version='1.0',
    author='me',
    options = dict(build_exe = buildOptions),
    executables = exe
)

위와 같이 setup.py를 구성하면 됩니다.

 

설명을 드리자면 buildOptions "packages" 부분에는 사용하는 패키지를 넣어주시면 됩니다! 그리고 "excludes" 부분에는 사용하지 않는 패키지를 넣어주시면 됩니다!

여기서 사용하지 않는 패키지를 넣는 이유는 buildOptions 부분 없이 돌리면 cx_freeze 가 대충 모듈 다 다운로드하기 때문에 용량이 커지는데 여기서 buildOptions을 통해 필요한 패키지만 넣어주기 위해서 buildOptions을 사용합니다 ㅎㅎ

 

exe 부분은 실행할 스크립트를 넣어주시면 됩니다! 여기서 base="Win32GUI"를 보실 수 있는데요 이 부분은 pyinstaller에서 noconsole 옵션과 똑같습니다. 콘솔을 띄우실 분들은 base부분을 제외하시고 exe=[Executable('main.py')] 만 쓰시면 됩니다!

 

setup부분에는 필요한 내용을 넣으시고 setup.py 가 완료되었다면 해당 폴더 cmd 창에서 해당 폴더 path에 들어가셔서

python setup.py build

를 외치면 됩니다!

 

no console 에러

'NoneType' object has no attribute write error

pyinstaller나 cx_freeze 사용 시 GUI를 따로 구성하신 분들은 noconsole 옵션을 많이 사용하시는데요? 여기서 자주 에러가 발생합니다!

 

그 이유는 콘솔에 로그를 찍는 모듈이 포함되어 있을 때 콘솔이 없으면 로그를 기록할 위치가 없어서 에러가 발생하기 때문인데요!

 

이럴 경우에는 고인 물천국인 스택오버플로우에서 해결방법을 알려주었습니다!

스택오버플로우해결방법

 

CX_FREEZE Window - AttributeError: 'NoneType' object has no attribute write

I am currently using cx_freeze 6.1 (had some different issues with 6.2 and 6.3) to generate MSI windows installer for an OpenCV python application. Compilation was successful and generated MSI inst...

stackoverflow.com

우리의 해결사 스택오버플로우 형님들의 내용을 빠르게 요약해 보겠습니다!

LoggerWriter class 만들어서 main.py에 로그 찍어주는 스크립트 추가해! 이겁니다 ㅎㅎ

 

main.py

class LoggerWriter:
	def __init__(self, level):
   	 # self.level is really like using log.debug(message)
   	 # at least in my case
   	 self.level = level

	def write(self, message):
  	  # if statement reduces the amount of newlines that are
  	  # printed to the logger
  	  if message != '\n':
        self.level(message)

	def flush(self):
  	  # create a flush method so things can be flushed when
   	  # the system wants to. Not sure if simply 'printing'
  	  # sys.stderr is the correct way to do it, but it seemed
  	  # to work properly for me.
  	  self.level(sys.stderr)
      
# Create Logger if doesn't exist
Path("log").mkdir(parents=True, exist_ok=True)
formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")
handler = TimedRotatingFileHandler('log/error.log', when="midnight", 
interval=1, encoding='utf8')
handler.suffix = "%Y-%m-%d"
handler.setFormatter(formatter)
logger = logging.getLogger()
logger.setLevel(logging.ERROR)
logger.addHandler(handler)
sys.stdout = LoggerWriter(logging.debug)
sys.stderr = LoggerWriter(logging.warning)

.......

main.py 위에 위 내용 그냥 그대로 갖다 넣으면 로그를 콘솔이 아닌 파일에 찍어주면서 모든 오류가 사라지고 noconsole 옵션으로. exe 파일을 무사히 배포할 수 있게 됩니다 ㅎㅎ

 

글 내용이 도움이 되셨다면 좋아요 부탁드립니다 ㅎㅎ

 

반응형