- π‘ About
- π¨ UI Screenshots
- π» Tech Stack
- π Architecture & Data Model
- π Getting Started
- πΎ Database Setup
- βοΈ Cloudinary Setup
- π§ͺ Linting & Formatting
- π οΈ Standalone Executable
- π€ Contributing
- π License
PhotoShow is a local desktop application for browsing, organizing, and sharing photo collections. Sign in for a personalized, role-based experience.
β¨ Key Features
- π Create and manage albums
- πΈ Upload and view photos
- π Browse community content
- β€οΈ Like and rate photos
- π¬ Comment on photos
- β Add albums to favorites
- π₯ Follow other users and manage your profile
- π Receive in-app notifications
- π© Report inappropriate content
- π οΈ Admin tools for user and category management
- β Admin review system for reports
- π§ Contact Admin for banned users to appeal their ban
Click to expand and view application screenshots
Core Technologies
- Python 3.14+ - Main programming language.
- Tkinter - GUI framework.
- Pillow - Image processing library.
- pip - Package manager.
Data & Security
- SQLite - Embedded relational database.
- SQLAlchemy - ORM and database toolkit.
- bcrypt - Password hashing.
Cloud Storage
- Cloudinary - Image hosting and management.
- python-cloudinary - Cloudinary SDK.
Code Quality & Linting
- Black - Code formatter.
- flake8 - Code linter.
- isort - Import sorter.
- yamllint - YAML linter.
- mypy - Static type checker.
Testing
- pytest - Testing framework.
- pytest-mock - Mocking in tests.
- pytest-cov - Coverage reporting.
Packaging
- PyInstaller - Build standalone executables.
The database model is shown as a DER (Diagram Entity-Relationship) preview so the main entities and relationships stay readable at a glance.
ORM models live in app/core/db/models/ and are implemented with SQLAlchemy. You can check also in app\core\db\models\__init__.py for a quick overview of all the main entities and their relationships.
- Python 3.14+ β Main programming language (download)
- pip β comes with Python
- Git β for cloning (download)
- (Recommended) Virtual environment support:
python -m venv - DB Browser for SQLite β For viewing and debugging the local database (download)
Verify your tools are available in the PATH:
python --version pip --version git --version
-
Clone the repository:
git clone https://github.com/pedromst2000/PhotoShow.git
-
Navigate to the project directory:
cd PhotoShow -
Create and activate a virtual environment:
Create:
python -m venv .venv
Activate on Windows (Command Prompt):
.venv\Scripts\Activate.bat
Activate on Windows PowerShell (if you get an execution policy error, see note below):
.\.venv\Scripts\Activate.ps1
β οΈ PowerShell Execution Policy Error? If you see "running scripts is disabled on this system", either:- Use Command Prompt (
.batcommand above) instead, OR - Run this once to allow scripts:
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
Activate on macOS/Linux:
source .venv/bin/activateTo deactivate the virtual environment:
- On any OS, simply run:
deactivateThis will return you to your system's default Python environment.
Note: Some dependencies may only work correctly inside the
.venvvirtual environment. It is highly recommended to use the virtual environment for all development and testing. - Use Command Prompt (
-
Install dependencies:
python -m pip install --upgrade pip pip install --upgrade -r dev-requirements.txt
-
Set up environment variables:
cp .env.example .env
Then edit
.envwith your Cloudinary credentials (see Cloudinary Setup below). -
Run the app:
python main.py
PhotoShow uses SQLite for local data storage. The database file (photoshow.db) is created automatically at the project root on first run.
| Command | Description |
|---|---|
python main.py --backupDB |
Backup the database to backups/<timestamp>/ |
python main.py --resetDB |
Reset to initial seed data (auto-backups first) |
python main.py --restoreDB |
Restore from latest backup |
python main.py --restoreDB backups/<folder> |
Restore from specific backup |
When to use:
--backupDBβ Before making risky changes--resetDBβ Return to initial state for testing--restoreDBβ Recover from a previous backup
For detailed instructions on viewing the database in both development and distribution modes, see Database Location in the Standalone Executable section.
β οΈ Backups: Thebackups/folder may contain sensitive data. Keep it local and out of version control (listed in.gitignore).
PhotoShow uses Cloudinary to store photos and avatars. Each developer creates their own free Cloudinary account.
- Sign up for a free account at cloudinary.com
- From your Dashboard, copy these credentials:
- Cloud Name
- API Key
- API Secret
-
If you haven't already, copy
.env.exampleto.env(see Quick Start β Step 5):cp .env.example .env
-
Edit
.envwith your Cloudinary credentials from the dashboard
β οΈ Never commit.envto git. It's in.gitignorefor security.
In your Cloudinary Media Library, create this folder structure:
photo-show/
βββ dev/ # Seed data (reference images)
β βββ profile_avatars/
β βββ photos_gallery/
βββ prod/ # Your uploads
βββ profile_avatars/
βββ photos_gallery/
GUI Path: Media Library β Folders β Home β Create photo-show folder
To add reference images to your dev/ folders:
- Open avatars.csv or photo_image.csv
- For each image URL in the
provider_url_imagecolumn:- Click the URL link to open it in your browser
- Right-click β Save image locally
- Upload to your Cloudinary
photo-show/dev/profile_avatars/orphoto-show/dev/photos_gallery/
π‘ Tip: The
dev/folder preserves seed data during--resetDB. Theprod/folder stores your uploads and is cleared on reset.
| Problem | Fix |
|---|---|
ValueError: Must supply api_key |
Check .env has correct CLOUDINARY_* credentials |
| Images show broken links | Verify folders exist in Cloudinary Media Library with correct names |
Images disappear after --resetDB |
Expected β prod/ folder is cleared. Use --backupDB to save uploads first |
Run these checks locally before committing to keep the codebase consistent and avoid CI failures.
Runs all code quality checks (flake8, mypy, black, isort, yamllint, lint_csv) on files that have changed vs HEAD:
python app/scripts/check_changed_files.pyAuto-fix style issues (black, isort, format_csv) in changed files only:
python app/scripts/check_changed_files.py --fixπ‘ Tip: Use this before committing to catch style and type issues quickly on only the files you changed.
Auto-formats all Python files using Black:
python -m black app tests main.pyChecks Python files for style violations and errors (PEP 8 compliance):
python -m flake8 .Auto-sorts imports in Python files using isort:
python app/scripts/format_imports.pyValidates that all Python files have properly sorted imports:
python app/scripts/check_imports.pyRuns static type checks on app/, tests/, and main.py using mypy:
python -m mypy app tests main.pyChecks YAML configuration files for syntax and formatting issues:
python -m yamllint .Auto-formats CSV seed data files (removes empty rows, strips whitespace, consistent quoting):
python app/scripts/format_csv.pyChecks CSV seed data files for structural and formatting issues:
python app/scripts/lint_csv.pyRun tests using the dedicated test runner script for convenience, or use pytest directly for more control.
Executes the full test suite (smoke, unit, functional, integration, acceptance):
python run_tests.pyRuns quick unit tests plus smoke gate checks:
python run_tests.py --unitRuns business logic verification tests:
python run_tests.py --functionalRuns service interaction tests with real database:
python run_tests.py --integrationRuns complete user workflow tests:
python run_tests.py --acceptanceGenerates a coverage report showing which code lines are tested:
python run_tests.py --coverageThis generates:
- Terminal coverage report (shows percentage per module)
coverage.xmlfile (for CI/CD tools like GitHub Actions, GitLab CI)
If you prefer to use pytest directly instead of the test runner script:
# Run all tests
python -m pytest tests/ -v
# Run with coverage
python -m pytest tests/ -v --cov=app --cov-report=term-missing --cov-report=xml:coverage.xml
# Run specific layer
python -m pytest tests/unit/ -v # Unit tests only
python -m pytest tests/smoke/ -v # Smoke tests only
python -m pytest tests/functional/ -v # Functional tests only
python -m pytest tests/integration/ -v # Integration tests only
python -m pytest tests/acceptance/ -v # Acceptance tests onlyTo produce machine-readable coverage data for CI/CD pipelines and tools:
python -m pytest tests/ --cov=app --cov-report=xml:coverage.xmlYou can compile PhotoShow into a self-contained application folder using PyInstaller, which bundles everything needed to run it. However, please note:
β οΈ Warning: The generated executable is intended for use on your own machine. Running the executable on remote or other machines may trigger antivirus false positives or fail due to environment differences. Distribution is not recommended.
To compile locally, follow these steps:
-
Set up your environment and dependencies (see Getting Started above).
-
Activate your virtual environment (see Getting Started above).
-
Install PyInstaller in your virtual environment:
pip install pyinstaller
-
Compile the application (in your activated virtual environment):
β οΈ Before rebuilding: IfPhotoShow.exeis already running, close it first. Windows locks DLLs of running processes and PyInstaller will fail with aPermissionErrorif the exe is open.Using the build script (recommended - embeds credentials at compile time):
The
build.pyscript handles everything automatically: it takes your Cloudinary credentials, creates.env, embeds it into the executable, runs PyInstaller, and verifies the output.Choose one method:
π’ Interactive (you're prompted for credentials):
python scripts/build.py --interactive
π΅ Command-Line Arguments:
python scripts/build.py --cloud-name your_cloud_name --api-key your_api_key --api-secret your_secret --default-avatar-public-id your_avatar_public_id --default-avatar-url your_avatar_url
What the build script does for you:
- β Takes your credentials (interactive or CLI args)
- β
Creates
.envwith embedded credentials - β
Runs
pyinstaller PhotoShow.spec --clean --noconfirminternally - β
Copies
.envnext toPhotoShow.exeindist/PhotoShow/ - β Verifies the build succeeded
- β Shows you next steps
β οΈ Antivirus false positives β IMPORTANT: PyInstaller bundles Python DLLs (e.g.ucrtbase.dll,python313.dll,msvcrt.dll) into the_internal/folder.To resolve:
- Add
dist/PhotoShow/folder and all its contents to your antivirus exclusion list - Or allow/verify the exe when your antivirus prompts you (click "Run anyway" or "Allow")
- If antivirus blocks DLL access:
PermissionError: [Errno 13] Permission denied: '..._internal\ucrtbase.dll'β exclude the entiredist/PhotoShow/_internal/folder from real-time scanning
After building, a
dist/PhotoShowfolder is created. The executable is platform-specific; rebuild separately on Windows, macOS, or Linux.
- Navigate to the build folder: Open
dist/PhotoShow/in your file explorer - Run the application: Double-click
PhotoShow.exeto launch - Keep files together: Do not move or delete the
_internal/folder or separatePhotoShow.exefrom other files - (Optional) Deploy elsewhere: Move the entire
dist/PhotoShow/folder fromdist/to your Desktop, Program Files, or any location on your system β the portable executable runs standalone without Python
Your data is stored at dist/PhotoShow/photoshow.db (see Database Location for details).
β οΈ CRITICAL: The database location is DIFFERENT depending on how you run PhotoShow. Opening the wrong database file in SQLite Browser will make data changes appear out of sync!
The database location differs between development and distribution modes:
| Mode | Database Location | When to use |
|---|---|---|
| Development (source) | C:\Users\User\Desktop\PhotoShow\photoshow.db (root folder) |
Running python main.py from the repo |
| Distribution (exe) | C:\Users\User\Desktop\PhotoShow\dist\PhotoShow\photoshow.db (dist folder) |
Running dist/PhotoShow/PhotoShow.exe |
Always verify which photoshow.db you're opening in SQLite Browser:
- Dev mode β Open from project root
- Distribution mode β Open from dist/PhotoShow/ folder
- Open DB Browser for SQLite
- File β Open Database
- Select the correct database file based on your mode:
- Dev mode:
photoshow.dbat project root - Distribution mode:
dist/PhotoShow/photoshow.db
- Dev mode:
In development mode: You'll see real-time changes from the app running via python main.py.
In distribution mode: You'll see data from the packaged executable. If changes aren't appearing, verify you opened the correct file in dist/PhotoShow/ folder, not the project root.
β οΈ Do NOT mix them up β opening the wrong file makes it appear data isn't syncing.
Your contributions help improve PhotoShow! Whether you're fixing a bug, improving the UI, or adding a new feature β every contribution matters.
- Found a bug? Report it
- Have an enhancement idea? Suggest it
- Ready to code? Follow the workflow below
| Type | Purpose | Branch Example | Commit Example |
|---|---|---|---|
feat |
New feature | feat/photo-grid |
feat: add photo grid view |
fix |
Bug fix | fix/login-validation |
fix: resolve login error |
docs |
Documentation | docs/update-readme |
docs: update installation steps |
refactor |
Code restructuring | refactor/album-service |
refactor: simplify album logic |
test |
Testing | test/auth-tests |
test: add auth unit tests |
build |
Build system | build/pyinstaller-dist-fixes |
build: automate PyInstaller with compile-time credentials |
ci |
CI/CD pipelines | ci/add-lint-workflow |
ci: add lint workflow |
chore |
Maintenance | chore/update-deps |
chore: update dependencies |
- Fork the repository and clone your fork
- Create a branch:
git checkout -b <type>/<short-description>
- Make your changes
- Commit:
git commit -m "<type>: <short description>" - Push:
git push origin <type>/<short-description>
- Open a Pull Request
PR checklist:
- β Branch name follows naming conventions ( See above )
- β Description explains changes clearly
- β Passes all CI checks. See GitHub Actions tab for details
- β No merge conflicts
Thanks for contributing! π
This project is licensed under the MIT License. See LICENSE for details.

























































