제가 이미 작성한 이 파이썬 코드들을 클린한 코드로 만들고 싶어 Template Pattern을 사용해야겠다고 생각이 들었습니다.
일단 첫 시작 코드 입니다.
from googleapiclient.discovery import build
from googleapiclient.http import MediaFileUpload
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
import os
import pickle
from plyer import notification
import tkinter as tk
from tkinter import scrolledtext
import threading
import queue
import datetime
import time
import io
from googleapiclient.http import MediaIoBaseDownload
def download_file(service, file_id, file_name):
request = service.files().get_media(fileId=file_id)
fh = io.BytesIO()
downloader = MediaIoBaseDownload(fh, request)
done = False
while done is False:
status, done = downloader.next_chunk()
print(f"Download {int(status.progress() * 100)}%.")
fh.seek(0)
with open(file_name, 'wb') as f:
f.write(fh.read())
print(f"{file_name} 다운로드 완료.")
def upload_file(service, file_name, folder_id):
file_metadata = {'name': file_name, 'parents': [folder_id]}
media = MediaFileUpload(file_name, resumable=True)
file = service.files().create(body=file_metadata, media_body=media, fields='id').execute()
print(f"Uploaded file with ID: {file.get('id')}")
# GUI 생성 함수
def create_gui(queue):
window = tk.Tk()
window.title("파일 이동 프로그램")
# 스크롤 가능한 텍스트 창
text_area = scrolledtext.ScrolledText(window, wrap=tk.WORD, width=40, height=10)
text_area.pack(padx=10, pady=10)
text_area.config(state='disabled')
# 큐에서 메시지를 가져와 텍스트 창에 표시하는 함수
def update_text_area():
while True:
message = queue.get()
if message == "EXIT":
break
text_area.config(state='normal')
text_area.insert(tk.END, message + '\n')
text_area.yview(tk.END)
text_area.config(state='disabled')
# 텍스트 창 업데이트 스레드 시작
threading.Thread(target=update_text_area, daemon=True).start()
window.mainloop()
def main_logic (queue):
# 인증 정보 설정
SCOPES = ['https://www.googleapis.com/auth/drive']
creds = None
# token.pickle 파일이 있는 경우, 이미 인증된 사용자 정보를 불러옴
if os.path.exists('token.pickle'):
with open('token.pickle', 'rb') as token:
creds = pickle.load(token)
# 인증 정보가 유효하지 않은 경우, 새로운 인증 정보를 생성
if not creds or not creds.valid:
if creds and creds.expired and creds.refresh_token:
creds.refresh(Request())
else:
flow = InstalledAppFlow.from_client_secrets_file(
'credentials.json', SCOPES)
creds = flow.run_local_server(port=0)
with open('token.pickle', 'wb') as token:
pickle.dump(creds, token)
# Google Drive API 클라이언트 생성
service = build('drive', 'v3', credentials=creds)
# 'TEST' 폴더와 'META_응원' 폴더의 ID를 찾기
folders = service.files().list(q="mimeType='application/vnd.google-apps.folder'").execute()
folder_id_test = None
folder_id_meta = None
for folder in folders['files']:
if folder['name'] == 'TEST':
folder_id_test = folder['id']
elif folder['name'] == 'META':
folder_id_meta = folder['id']
while True: # 무한 루프
now = datetime.datetime.now()
print(f"{now.strftime('%Y-%m-%d %H:%M:%S')}에 파일을 찾습니다.")
queue.put(f"{now.strftime('%Y-%m-%d %H:%M:%S')}에 파일을 찾습니다.")
# 시간에 따른 파일 번호 결정
file_number = None
if now.hour == 10:
file_number = '1'
elif now.hour == 11:
file_number = '2'
elif now.hour == 12:
file_number = '3'
# 파일 이름 생성 (예: 2023_11_13_1.PNG 또는 2023_11_13_1.png)
file_name_to_move_upper = f"{now.strftime('%Y_%m_%d')}_{file_number}.PNG"
file_name_to_move_lower = f"{now.strftime('%Y_%m_%d')}_{file_number}.png"
# 찾을 파일 이름 출력
print(f"찾을 파일 이름: {file_name_to_move_upper} 또는 {file_name_to_move_lower}")
queue.put(f"찾을 파일 이름: {file_name_to_move_upper}")
if folder_id_test and file_number:
query = f"parents = '{folder_id_test}' and (name = '{file_name_to_move_upper}' or name = '{file_name_to_move_lower}')"
files = service.files().list(q=query).execute()
print(f"이동할 파일 개수: {len(files['files'])}")
queue.put(f"이동할 파일 개수: {len(files['files'])}")
for file in files['files']:
# 파일 다운로드
download_file(service, file['id'], file['name'])
# 파일 업로드 (META 폴더로)
if folder_id_meta:
upload_file(service, file['name'], folder_id_meta)
print(f"{file['name']} 파일을 META 폴더로 업로드했습니다.")
queue.put(f"{file['name']} 파일을 META 폴더로 업로드했습니다.")
# 로컬 파일 삭제
os.remove(file['name'])
print(f"로컬 파일 {file['name']} 삭제 완료.")
queue.put(f"로컬 파일 {file['name']} 삭제 완료.")
# Google Drive 내 파일 삭제
service.files().delete(fileId=file['id']).execute()
print(f"Google Drive 내 파일 {file['name']} 삭제 완료.")
queue.put(f"Google Drive 내 파일 {file['name']} 삭제 완료.")
else:
print("META_응원 폴더를 찾을 수 없습니다.")
queue.put("META_응원 폴더를 찾을 수 없습니다.")
else:
print("이동할 파일을 찾을 수 없거나, 지정된 시간이 아닙니다.")
queue.put("이동할 파일을 찾을 수 없거나, 지정된 시간이 아닙니다.")
# 2분 대기
print("30초 대기")
queue.put("30초 대기")
time.sleep(30)
# 큐와 스레드를 사용하여 GUI와 메인 로직 실행
if __name__ == "__main__":
message_queue = queue.Queue()
gui_thread = threading.Thread(target=create_gui, args=(message_queue,))
logic_thread = threading.Thread(target=main_logic, args=(message_queue,))
gui_thread.start()
logic_thread.start()
이 코드를 클린한 코드로 변경하기 위해
파이썬 클린코드 EBOOK에서 템플릿을 가져왔습니다
점프 투 파이썬Docstring이 왜 좋아?
가장 큰 이유는 파이썬이 동적 타이핑을 하기 때문이다. 파이썬은 파라미터 타입이나 반환 타입 체크를 강요하지 않는다. 다른 언어를 배워본 적이 있다면, 파라미터나, 리턴 타입을 통해서 어떤 데이터가 들어오고 나가는 지 추론할 수 있다는 것을 알 수 있을 것이다.
이렇게 Docstring에 대한 설명을 듣고 이에 대한 템플릿인
def get_user_name(user):
"""
Description:
유저의 객체를 통해 유저의 이름을 알아내는 함수.
Param:
some_module.user.User 클래스의 객체를 파라미터로 받음.
Return:
some_module.user_name.UserName 객체를 반환.
"""
...
return user_name
이 코드를 제 코드와 함께 지피티에게 넣어 함수마다 docstring을 만들어달라고 해봤습니다.
다음과 같은 결과가 나왔습니다
GPT
이 코드에서 로컬 파일 삭제 부분 바로 다음에 Google Drive 내의 파일을 삭제하는 코드를 추가하면 됩니다. service.files().delete() 함수를 사용하여 Google Drive에서 파일을 삭제할 수 있습니다. 아래는 해당 부분을 수정한 코드입니다:
pythonCopy code# ... [이전 코드] ...
for file in files['files']:
# 파일 다운로드
download_file(service, file['id'], file['name'])
# 파일 업로드 (META 폴더로)
if folder_id_meta:
upload_file(service, file['name'], folder_id_meta)
print(f"{file['name']} 파일을 META 폴더로 업로드했습니다.")
queue.put(f"{file['name']} 파일을 META 폴더로 업로드했습니다.")
# 로컬 파일 삭제
os.remove(file['name'])
print(f"로컬 파일 {file['name']} 삭제 완료.")
queue.put(f"로컬 파일 {file['name']} 삭제 완료.")
# Google Drive 내 파일 삭제
service.files().delete(fileId=file['id']).execute()
print(f"Google Drive 내 파일 {file['name']} 삭제 완료.")
queue.put(f"Google Drive 내 파일 {file['name']} 삭제 완료.")
else:
print("META_응원 폴더를 찾을 수 없습니다.")
queue.put("META_응원 폴더를 찾을 수 없습니다.")
# ... [이후 코드] ...
이 코드는 Google Drive 내에 있는 파일의 ID를 사용하여 해당 파일을 삭제합니다. 파일을 업로드한 후에 로컬 파일을 삭제하는 것과 동일한 방식으로 Google Drive에서 파일을 삭제합니다.
You
ed!def get_user_name(user): """ Description: 유저의 객체를 통해 유저의 이름을 알아내는 함수. Param: some_module.user.User 클래스의 객체를 파라미터로 받음. Return: some_module.user_name.UserName 객체를 반환. """ ... return user_name --- 이런 templete를 활용해서 너가 만들어준 --- # ... [이전 코드] ... for file in files['files']: # 파일 다운로드 download_file(service, file['id'], file['name']) # 파일 업로드 (META 폴더로) if folder_id_meta: upload_file(service, file['name'], folder_id_meta) print(f"{file['name']} 파일을 META 폴더로 업로드했습니다.") queue.put(f"{file['name']} 파일을 META 폴더로 업로드했습니다.") # 로컬 파일 삭제 os.remove(file['name']) print(f"로컬 파일 {file['name']} 삭제 완료.") queue.put(f"로컬 파일 {file['name']} 삭제 완료.") # Google Drive 내 파일 삭제 service.files().delete(fileId=file['id']).execute() print(f"Google Drive 내 파일 {file['name']} 삭제 완료.") queue.put(f"Google Drive 내 파일 {file['name']} 삭제 완료.") else: print("META_응원 폴더를 찾을 수 없습니다.") queue.put("META_응원 폴더를 찾을 수 없습니다.") # ... [이후 코드] ... --- 이 코드를 템플릿에 맞춰서 다시 만들어줘 Please write in Korean language.
ChatGPT
아래는 주어진 템플릿에 맞춰 코드를 재구성한 것입니다:
pythonCopy codedef move_and_cleanup_files(service, folder_id_meta, folder_id_test, files, queue):
"""
Description:
Google Drive의 'TEST' 폴더에서 파일을 찾아 'META' 폴더로 이동시키고, 로컬 및 Google Drive에서 해당 파일을 삭제하는 함수.
Param:
service: Google Drive API 서비스 객체.
folder_id_meta: 'META' 폴더의 ID.
folder_id_test: 'TEST' 폴더의 ID.
files: 이동할 파일 목록.
queue: 메시지를 전송할 큐.
Return:
없음.
"""
for file in files['files']:
# 파일 다운로드
download_file(service, file['id'], file['name'])
# 파일 업로드 (META 폴더로)
if folder_id_meta:
upload_file(service, file['name'], folder_id_meta)
print(f"{file['name']} 파일을 META 폴더로 업로드했습니다.")
queue.put(f"{file['name']} 파일을 META 폴더로 업로드했습니다.")
# 로컬 파일 삭제
os.remove(file['name'])
print(f"로컬 파일 {file['name']} 삭제 완료.")
queue.put(f"로컬 파일 {file['name']} 삭제 완료.")
# Google Drive 내 파일 삭제
service.files().delete(fileId=file['id']).execute()
print(f"Google Drive 내 파일 {file['name']} 삭제 완료.")
queue.put(f"Google Drive 내 파일 {file['name']} 삭제 완료.")
else:
print("META_응원 폴더를 찾을 수 없습니다.")
queue.put("META_응원 폴더를 찾을 수 없습니다.")
이 코드는 주어진 파일 목록에서 각 파일을 찾아 Google Drive의 'META' 폴더로 이동시키고, 로컬 및 Google Drive에서 해당 파일을 삭제하는 기능을 수행합니다. 함수는 Google Drive 서비스 객체, 'META' 및 'TEST' 폴더의 ID, 이동할 파일 목록, 그리고 큐 객체를 파라미터로 받습니다.
따라서 Docstring 덕분에 나중에 이 코드를 유지보수 해야하거나, 오랜만에 코드를 다시 읽어야 할 때 시간을 상당히 많이 단축시킬 수 있었습니다!
2. format of recipe pattern
윈도우 PC에서 외부 IP주소를 변경하는 것을 알고 싶은 마음에 이 패턴으로 질문을 하였다. 내가 아는 지식을 어느정도 적어주고, 거기에 대한 step을 답변 받을 수 있었다.
Me
나는 내 윈도우 PC의 외부 IP주소를 변경하는게 목표, 목적이야. VPN을 사용하던가, 프록시 서버를 사용하던가 이 둘중에 해야한다는 건 알아 이 두개의 방법에 대해서 정말 자세하게 전체 단계 순서를 알려주세요. 누락된 단계가 있으면 입력하세요. 파이썬 코드가 필요하면 코드를 만들어주세요
ChatGPT
외부 IP 주소를 변경하기 위한 두 가지 방법, 즉 VPN 사용과 프록시 서버 사용에 대해 자세히 설명하겠습니다. 이 두 방법은 사용자의 실제 외부 IP 주소를 숨기고 다른 주소를 통해 인터넷에 연결할 수 있게 해줍니다.
VPN 사용하기
VPN 서비스 선택:
시장에는 다양한 VPN 서비스가 있습니다. NordVPN, ExpressVPN, CyberGhost와 같은 유명한 서비스를 고려해볼 수 있습니다.
VPN 서비스를 선택할 때는 서버 위치, 속도, 보안, 가격 및 사용자 리뷰를 고려하세요.
VPN 소프트웨어 설치:
선택한 VPN 서비스의 공식 웹사이트에서 VPN 클라이언트 소프트웨어를 다운로드하세요.
다운로드한 파일을 실행하여 설치 과정을 따르세요.
VPN 설정:
설치가 완료되면 VPN 소프트웨어를 실행하세요.
일반적으로 계정 정보를 입력하여 로그인해야 합니다.
VPN 서버 위치를 선택하세요. 일부 VPN은 자동으로 최적의 서버를 선택해줍니다.
VPN 연결:
서버를 선택한 후 연결 버튼을 클릭하여 VPN에 연결하세요.
연결이 완료되면 외부 IP 주소가 VPN 서버의 주소로 변경됩니다.
IP 주소 확인:
웹 브라우저를 열고 "내 IP 확인"과 같은 검색어로 검색하여 새로운 IP 주소를 확인할 수 있습니다.
프록시 서버 사용하기
프록시 서버 선택:
인터넷에서 무료 또는 유료 프록시 서비스를 찾을 수 있습니다.
유료 서비스는 일반적으로 더 안정적이고 빠른 속도를 제공합니다.
프록시 서버 설정:
웹 브라우저의 설정 메뉴로 이동합니다.
네트워크 설정 또는 연결 설정을 찾습니다.
프록시 설정을 클릭하여 프록시 서버 주소와 포트 번호를 입력합니다.
예: 프록시 서버 주소가 123.45.67.89이고 포트 번호가 8080인 경우, 이를 해당 필드에 입력합니다.
프 록시 연결 확인:
설정을 저장하고 브라우저를 재시작합니다.
프록시 서버가 작동하는지 확인하기 위해 웹사이트에 접속해보세요.
프록시 서버를 통한 연결이 잘 이루어지고 있으면, 웹사이트가 정상적으로 로드됩니다.
IP 주소 확인:
"내 IP 확인"과 같은 검색어로 검색하여 새로운 IP 주소를 확인할 수 있습니다.
파이썬을 사용한 IP 주소 확인
VPN 또는 프록시 연결 후 새로운 IP 주소를 확인하기 위해 파이썬 코드를 사용할 수도 있습니다. 다음은 IP 주소를 확인하는 간단한 코드입니다:
pythonCopy codeimport requests
def get_public_ip():
try:
response = requests.get('https://api.ipify.org?format=json')
ip = response.json()['ip']
return ip
except requests.RequestException as e:
return f"Error: {e}"
# 현재 공용 IP 주소 출력
current_ip = get_public_ip()
print(f"현재 공용 IP 주소: {current_ip}")
이 코드는 인터넷에 연결된 컴퓨터의 현재 공용 IP 주소를 확인해줍니다.