This guide will walk you through creating standalone executable builds of Bazaar for Windows, Ubuntu/Linux, and macOS.
- Prerequisites
- Installing PyInstaller
- Building for Windows
- Building for Ubuntu/Linux
- Building for macOS
- Build Optimization
- Testing Your Build
- Distribution
- Troubleshooting
- Python 3.8 or higher installed
- All project dependencies installed:
pip install -r requirements.txt - PyInstaller:
pip install pyinstaller - Approximately 500 MB of free disk space for build process
Windows:
- No additional requirements
Ubuntu/Linux:
python3-devpackage:sudo apt-get install python3-devtkinter:sudo apt-get install python3-tk
macOS:
- Xcode Command Line Tools:
xcode-select --install - Python 3 from python.org (recommended over system Python)
Install PyInstaller in your project environment:
# Make sure you're in the project directory
cd /path/to/bazaar
# Install PyInstaller
pip install pyinstaller
# Verify installation
pyinstaller --versionExpected output: 6.x.x or higher
Before building, you can create platform-specific icons from your logo:
# Uses assets/logo.png to create .ico and .icns files
python3 create_icons.pyThis will create:
assets/icon.ico- Windows icon (multiple sizes: 16x16 to 256x256)assets/icon.icns- macOS icon
Requirements: Pillow library (pip install Pillow)
If you prefer to create icons manually:
For Windows (.ico):
- Use online tools: https://convertio.co/png-ico/
- Or IcoFX software
- Required sizes: 16, 32, 48, 64, 128, 256 pixels
For macOS (.icns):
- Use online tools: https://cloudconvert.com/png-to-icns
- Or use macOS iconutil:
python3 create_icons.py # Creates iconset iconutil -c icns assets/Bazaar.iconset
Note: The build script automatically uses icons if they exist in assets/ folder.
# Remove old build artifacts
rmdir /s /q build dist
del /f /q *.specpyinstaller --onefile --windowed --name Bazaar main.pyFirst, create or obtain a .ico file for your application icon. Then:
pyinstaller ^
--onefile ^
--windowed ^
--name Bazaar ^
--icon=assets/icon.ico ^
--add-data "VERSION;." ^
--hidden-import=yfinance ^
--hidden-import=pandas ^
--hidden-import=requests ^
--clean ^
main.pyParameters Explained:
--onefile: Creates a single executable file--windowed: No console window (GUI only)--name Bazaar: Names the executable "Bazaar.exe"--icon: Adds application icon--add-data: Includes VERSION file (format: "source;destination")--hidden-import: Explicitly includes dependencies--clean: Cleans PyInstaller cache before building
The executable will be in: dist/Bazaar.exe
Expected Size: 60-90 MB
# Install required packages
sudo apt-get update
sudo apt-get install python3-dev python3-tk
# Verify tkinter is working
python3 -c "import tkinter; print('tkinter OK')"# Remove old build artifacts
rm -rf build dist
rm -f *.specpyinstaller --onefile --windowed --name Bazaar main.pypyinstaller \
--onefile \
--windowed \
--name Bazaar \
--add-data "VERSION:." \
--hidden-import=yfinance \
--hidden-import=pandas \
--hidden-import=requests \
--clean \
main.pyNote: On Linux, the --add-data separator is : (colon), not ; (semicolon)
# Make the binary executable
chmod +x dist/Bazaar
# Test it
./dist/BazaarThe executable will be in: dist/Bazaar
Expected Size: 70-100 MB
# Ensure you have Python from python.org
# NOT from Homebrew for best results
python3 --version
# Install PyInstaller
pip3 install pyinstaller# Remove old build artifacts
rm -rf build dist
rm -f *.specpyinstaller \
--onefile \
--windowed \
--name Bazaar \
--add-data "VERSION:." \
--hidden-import=yfinance \
--hidden-import=pandas \
--hidden-import=requests \
--osx-bundle-identifier "com.bazaar.app" \
--clean \
main.pymacOS-Specific Options:
--osx-bundle-identifier: Unique bundle ID for the app
For a proper .app bundle with icon:
pyinstaller \
--name Bazaar \
--windowed \
--onefile \
--icon=assets/icon.icns \
--osx-bundle-identifier "com.bazaar.app" \
--add-data "VERSION:." \
--hidden-import=yfinance \
--hidden-import=pandas \
--hidden-import=requests \
--clean \
main.pyIf you're distributing outside the Mac App Store:
# Sign the application
codesign --deep --force --verify --verbose --sign "Developer ID Application: Your Name" dist/Bazaar.app
# Verify signature
codesign --verify --deep --strict --verbose=2 dist/Bazaar.app
# Notarize (requires Apple Developer account)
xcrun altool --notarize-app --file dist/Bazaar.appThe application will be in: dist/Bazaar.app (or dist/Bazaar for --onefile)
Expected Size: 70-100 MB
Create a Bazaar.spec file and edit the excludes:
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
a = Analysis(
['main.py'],
pathex=[],
binaries=[],
datas=[('VERSION', '.')],
hiddenimports=['yfinance', 'pandas', 'requests'],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[
'matplotlib',
'scipy',
'numpy.testing',
'PIL',
'IPython',
'notebook',
'jupyter',
'pytest',
'setuptools',
],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False,
)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
[],
name='Bazaar',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=False,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
)Then build with:
pyinstaller Bazaar.specDownload UPX from https://upx.github.io/
Windows:
pyinstaller --onefile --windowed --name Bazaar --upx-dir="C:\path\to\upx" main.pyLinux/macOS:
pyinstaller --onefile --windowed --name Bazaar --upx-dir=/path/to/upx main.pyPotential size reduction: 30-50%
strip dist/BazaarCreate test_build.py:
#!/usr/bin/env python3
"""
Test script to verify the built executable
"""
import os
import sys
import subprocess
import platform
def test_build():
"""Test the built executable"""
system = platform.system()
if system == "Windows":
executable = "dist/Bazaar.exe"
elif system == "Darwin":
executable = "dist/Bazaar.app/Contents/MacOS/Bazaar"
else:
executable = "dist/Bazaar"
# Check if executable exists
if not os.path.exists(executable):
print(f"❌ Executable not found: {executable}")
return False
# Check file size
size_mb = os.path.getsize(executable) / (1024 * 1024)
print(f"✅ Executable found: {executable}")
print(f"📦 Size: {size_mb:.2f} MB")
# Check if executable is executable
if system != "Windows" and not os.access(executable, os.X_OK):
print("❌ File is not executable")
return False
print("✅ File is executable")
# Try to run (will open GUI - close it manually)
print("\n🚀 Attempting to launch application...")
print(" (Close the window to complete the test)")
try:
process = subprocess.Popen([executable])
print("✅ Application launched successfully")
print(f" Process ID: {process.pid}")
return True
except Exception as e:
print(f"❌ Failed to launch: {e}")
return False
if __name__ == "__main__":
success = test_build()
sys.exit(0 if success else 1)Run the test:
python3 test_build.py- Executable starts without errors
- GUI window appears correctly
- Data loads successfully (requires internet)
- Refresh button works
- Auto-refresh works
- Window can be resized
- Scrolling works
- Application closes cleanly
# Create a distributable folder
mkdir Bazaar-Windows
copy dist\Bazaar.exe Bazaar-Windows\
copy README.md Bazaar-Windows\
copy VERSION Bazaar-Windows\
# Create ZIP
powershell Compress-Archive -Path Bazaar-Windows -DestinationPath Bazaar-Windows-v1.0.0.zipUse Inno Setup or NSIS to create an installer:
Inno Setup Example:
- Download Inno Setup: https://jrsoftware.org/isinfo.php
- Create
installer.iss:
[Setup]
AppName=Bazaar
AppVersion=1.0.0
DefaultDirName={pf}\Bazaar
DefaultGroupName=Bazaar
OutputDir=output
OutputBaseFilename=Bazaar-Setup-v1.0.0
Compression=lzma
SolidCompression=yes
[Files]
Source: "dist\Bazaar.exe"; DestDir: "{app}"
Source: "README.md"; DestDir: "{app}"
Source: "VERSION"; DestDir: "{app}"
[Icons]
Name: "{group}\Bazaar"; Filename: "{app}\Bazaar.exe"
Name: "{commondesktop}\Bazaar"; Filename: "{app}\Bazaar.exe"- Compile with Inno Setup
Create an AppImage for easy distribution:
# Install appimagetool
wget https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage
chmod +x appimagetool-x86_64.AppImage
# Create AppDir structure
mkdir -p Bazaar.AppDir/usr/bin
cp dist/Bazaar Bazaar.AppDir/usr/bin/
# Create desktop entry
cat > Bazaar.AppDir/Bazaar.desktop << EOF
[Desktop Entry]
Name=Bazaar
Exec=Bazaar
Icon=bazaar
Type=Application
Categories=Finance;
EOF
# Create AppImage
./appimagetool-x86_64.AppImage Bazaar.AppDirResult: Bazaar-x86_64.AppImage
# Create package structure
mkdir -p bazaar_1.0.0_amd64/DEBIAN
mkdir -p bazaar_1.0.0_amd64/usr/local/bin
mkdir -p bazaar_1.0.0_amd64/usr/share/applications
# Copy executable
cp dist/Bazaar bazaar_1.0.0_amd64/usr/local/bin/
# Create control file
cat > bazaar_1.0.0_amd64/DEBIAN/control << EOF
Package: bazaar
Version: 1.0.0
Section: utils
Priority: optional
Architecture: amd64
Maintainer: Your Name <your.email@example.com>
Description: Indian Stock Market Dashboard
A lightweight GUI application for real-time Indian stock market data
EOF
# Build package
dpkg-deb --build bazaar_1.0.0_amd64# Create DMG
hdiutil create -volname Bazaar -srcfolder dist/Bazaar.app -ov -format UDZO Bazaar-macOS-v1.0.0.dmgSolution: Add missing modules with --hidden-import:
pyinstaller --onefile --windowed --name Bazaar \
--hidden-import=missing_module_name \
main.pySolution:
- Try without
--windowedflag to see console errors:pyinstaller --onefile --name Bazaar main.py
- Run the executable from command prompt to see error messages
Solution:
- Use
--exclude-moduleto remove unnecessary packages - Enable UPX compression
- Use virtual environment with only required packages
Solution:
chmod +x dist/BazaarSolution:
# Remove quarantine attribute
xattr -cr dist/Bazaar.app
# Or, allow apps from anywhere (temporarily)
sudo spctl --master-disableSolution:
- This is common with PyInstaller executables
- Sign the executable (Windows/macOS)
- Report as false positive to antivirus vendor
- Consider using code signing certificate
Solution:
- Verify tkinter is included:
--hidden-import=tkinter - Test with a simpler UI first
- Check system DPI scaling settings
Create a debug build that shows console output:
# Remove --windowed flag
pyinstaller --onefile --name Bazaar-Debug main.pyRun the debug build and check console output for errors.
Create build.py:
#!/usr/bin/env python3
"""
Automated build script for Bazaar
"""
import os
import sys
import shutil
import platform
import subprocess
def clean_build():
"""Remove old build artifacts"""
print("🧹 Cleaning old builds...")
for item in ['build', 'dist', '*.spec']:
if os.path.exists(item):
if os.path.isdir(item):
shutil.rmtree(item)
else:
os.remove(item)
print("✅ Clean complete\n")
def build_executable():
"""Build the executable"""
system = platform.system()
print(f"🔨 Building for {system}...\n")
# Common arguments
base_args = [
'pyinstaller',
'--onefile',
'--windowed',
'--name', 'Bazaar',
'--add-data', f'VERSION{os.pathsep}.',
'--hidden-import', 'yfinance',
'--hidden-import', 'pandas',
'--hidden-import', 'requests',
'--clean',
'main.py'
]
# Platform-specific arguments
if system == 'Darwin': # macOS
base_args.extend([
'--osx-bundle-identifier', 'com.bazaar.app'
])
# Run PyInstaller
try:
subprocess.run(base_args, check=True)
print("\n✅ Build successful!")
# Show output location
if system == "Windows":
print(f"\n📦 Executable: dist\\Bazaar.exe")
elif system == "Darwin":
print(f"\n📦 Application: dist/Bazaar.app")
else:
print(f"\n📦 Executable: dist/Bazaar")
# Show size
if system == "Windows":
exe_path = "dist/Bazaar.exe"
elif system == "Darwin":
exe_path = "dist/Bazaar.app"
else:
exe_path = "dist/Bazaar"
if os.path.exists(exe_path):
size_mb = os.path.getsize(exe_path) / (1024 * 1024)
print(f"📏 Size: {size_mb:.2f} MB")
return True
except subprocess.CalledProcessError as e:
print(f"\n❌ Build failed: {e}")
return False
def main():
"""Main entry point"""
print("=" * 60)
print(" Bazaar Build Script")
print("=" * 60)
print()
# Check if PyInstaller is installed
try:
subprocess.run(['pyinstaller', '--version'],
capture_output=True, check=True)
except (subprocess.CalledProcessError, FileNotFoundError):
print("❌ PyInstaller not found!")
print(" Install it with: pip install pyinstaller")
sys.exit(1)
# Clean and build
clean_build()
success = build_executable()
print("\n" + "=" * 60)
if success:
print(" ✅ Build Complete!")
else:
print(" ❌ Build Failed!")
print("=" * 60)
sys.exit(0 if success else 1)
if __name__ == "__main__":
main()Make it executable and run:
# Linux/macOS
chmod +x build.py
./build.py
# Windows
python build.pyWindows:
pyinstaller --onefile --windowed --name Bazaar --clean main.pyLinux:
pyinstaller --onefile --windowed --name Bazaar --clean main.py && chmod +x dist/BazaarmacOS:
pyinstaller --onefile --windowed --name Bazaar --osx-bundle-identifier com.bazaar.app --clean main.pypython build.py && python test_build.py- PyInstaller Documentation: https://pyinstaller.org/en/stable/
- PyInstaller GitHub: https://github.com/pyinstaller/pyinstaller
- Icon Converters:
- PNG to ICO: https://convertio.co/png-ico/
- PNG to ICNS: https://cloudconvert.com/png-to-icns
- Code Signing:
After building:
- Test thoroughly on a clean machine (without Python installed)
- Create distribution package (ZIP, DMG, AppImage, etc.)
- Write installation instructions for end users
- Set up version control for releases
- Consider automated builds with CI/CD (GitHub Actions, etc.)
| Platform | Command | Output | Size |
|---|---|---|---|
| Windows | pyinstaller --onefile --windowed --name Bazaar main.py |
dist/Bazaar.exe |
~60-90 MB |
| Linux | pyinstaller --onefile --windowed --name Bazaar main.py |
dist/Bazaar |
~70-100 MB |
| macOS | pyinstaller --onefile --windowed --name Bazaar --osx-bundle-identifier com.bazaar.app main.py |
dist/Bazaar.app |
~70-100 MB |
Happy Building! 🎉
For questions or issues, refer to the Troubleshooting section or check the PyInstaller documentation.