

Building & Packaging a Simple Python Desktop App into a Standalone Exe
Everything here is step‑by‑step, beginner‑friendly, and fully reproducible.
1. Create the Project Folder -> Create a folder anywhere on your system:
Code
TextLineCounterApp/
├── app.py → main Python script
├── requirements.txt → optional dependency list
└── logs/ → folder where the app will write logs.Make sure the logs/ folder exists (empty is fine)
2. Add the Python Application Code. Open app.py and paste the following complete working code:
import os
import datetime
import tkinter as tk
from tkinter import filedialog, messagebox
def get_base_dir():
import sys
if hasattr(sys, "_MEIPASS"):
return sys._MEIPASS
return os.path.dirname(os.path.abspath(__file__))
BASE_DIR = get_base_dir()
LOGS_DIR = os.path.join(BASE_DIR, "logs")
def ensure_logs_dir():
if not os.path.exists(LOGS_DIR):
os.makedirs(LOGS_DIR, exist_ok=True)
def log_message(message: str):
ensure_logs_dir()
log_file = os.path.join(LOGS_DIR, "app.log")
timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
with open(log_file, "a", encoding="utf-8") as f:
f.write(f"[{timestamp}] {message}\n")
def count_lines_in_file(file_path: str) -> int:
with open(file_path, "r", encoding="utf-8", errors="ignore") as f:
return sum(1 for _ in f)
def on_select_file():
file_path = filedialog.askopenfilename(
title="Select a text file",
filetypes=[("Text files", "*.txt"), ("All files", "*.*")]
)
if not file_path:
return
try:
line_count = count_lines_in_file(file_path)
result_label.config(text=f"Lines in file: {line_count}")
log_message(f"Processed file: {file_path} | Lines: {line_count}")
except Exception as e:
messagebox.showerror("Error", f"Failed to process file:\n{e}")
log_message(f"Error processing file {file_path}: {e}")
def create_main_window():
window = tk.Tk()
window.title("Text Line Counter")
window.geometry("400x200")
title_label = tk.Label(window, text="Text Line Counter", font=("Arial", 16))
title_label.pack(pady=10)
select_button = tk.Button(window, text="Select Text File", command=on_select_file)
select_button.pack(pady=10)
global result_label
result_label = tk.Label(window, text="No file selected yet.")
result_label.pack(pady=10)
footer_label = tk.Label(window, text="Logs are stored in the 'logs' folder.", font=("Arial", 8))
footer_label.pack(side=tk.BOTTOM, pady=5)
return window
if __name__ == "__main__":
ensure_logs_dir()
log_message("Application started.")
main_window = create_main_window()
main_window.mainloop()
log_message("Application closed.")
This app: Opens a GUI window.Lets the user select a .txt file. Counts the number of lines.
Writes logs into the logs/ folder. Works both in development and after packaging
3. Test the App Before Packaging. run the app -> "python app.py"
You should see: A window titled Text Line Counter.A button to select a text file .A result label .Logs created inside logs/app.log
If this works, you’re ready to package.
4. Install auto‑py‑to‑exe
Run-> "pip install auto-py-to-exe"
Then launch it: "auto-py-to-exe"
This opens a GUI tool that wraps PyInstaller.
5. Configure auto‑py‑to‑exe (Important Section)
Inside the GUI:
A. Script Location -> Select your app.py.
B. Onefile vs Onedir -> Choose: One Directory (Recommended)
This gives you a folder with: app.exe
DLLs ,Python runtime,Your custom folders (logs/resources)
C. Console Window -> Choose: Window Based (no console)
D. Add Custom Folders -> Scroll to Additional Files → click Add Folder.
Source: TextLineCounterApp/logs
Destination: logs
This ensures the logs/ folder appears next to the .exe.
E. Output Directory -> Choose where the final build should go.
F. Build Click: "Convert .py to .exe"
Wait until you see “Completed Successfully”.
6. Inspect the Build Output
Inside your output folder, you’ll see:
TextLineCounterApp/
├── TextLineCounterApp.exe
├── logs/
├── python DLLs
└── runtime files
This folder is fully portable.
7. Test the Packaged EXE
Double‑click: "TextLineCounterApp.exe"
Test:
Select a text file
See the line count
Check logs/app.log
If everything works, your app is ready for distribution.
8. Prepare the App for Users -> Zip the entire folder: "TextLineCounterApp_v1.0.zip"
This is what you will share with users.
9. How Users Will Install & Use the App
Step 1 — Download
User downloads: "TextLineCounterApp_v1.0.zip"
Step 2 — Extract -> "Right‑click → Extract All"
Step 3 — Run Inside the extracted folder: "Double‑click TextLineCounterApp.exe"
Step 4 — Use
Click Select Text File
Choose a .txt file
See the line count
Logs appear in the logs/ folder
No Python installation required.
10. Optional: Add a README for Users .Create a file named README.txt:
Code
Text Line Counter App
---------------------
How to Use:
1. Extract the ZIP file.
2. Open the folder.
3. Double-click "TextLineCounterApp.exe".
4. Click "Select Text File" and choose a .txt file.
5. The app will show the number of lines.
6. Logs are stored in the "logs" folder.
No Python installation is required.
Include this file before zipping.
11. Troubleshooting
App doesn’t open -> Ensure you extracted the ZIP. Ensure antivirus didn’t block the .exe
Logs not created -> Make sure the logs/ folder exists. Ensure you added it in auto‑py‑to‑exe
File dialog doesn’t open -> Run the .exe from inside the folder. Don’t move the .exe alone
12. Finally You now know how to:
Build a simple Python GUI app
Create a clean folder structure
Package it using auto‑py‑to‑exe
Include custom folders
Generate a portable .exe
Distribute it to users
Ensure it runs without Python installed
This is the same workflow used for:
PDF tools
OCR utilities
Data processing apps
Internal business tools
Personal productivity apps
Once you master this, you can package any Python project into a Windows application.
Thanks,
Jyoti.
