qr-code-generator
Generate QR Code images from contact details stored in an Excel file with flexible output formats, customisation options, and an intuitive CLI.
Readme
Loading readme…
Generate QR Code images from contact details stored in an Excel file with flexible output formats, customisation options, and an intuitive CLI.
Loading readme…
v3.0.1 - Generate QR Code images from contact details stored in an Excel file with flexible output formats, customization options, and an intuitive CLI.
For version history, see CHANGELOG.md.
Option 1: Automated Setup (Recommended)
# Run the setup script
powershell -ExecutionPolicy Bypass -File scripts\setup.ps1
# Then use the quick runner
run.bat
Option 2: Manual Setup
Clone and navigate to the repo:
cd qr-code-generator
Create and activate a virtual environment:
python -m venv .venv
.venv\Scripts\activate
Install the package:
pip install -e .
Run with sample data:
python -m qr_code_generator
Option 1: Automated Setup (Recommended)
# Run the setup script
bash scripts/setup.sh
# Then use the quick runner
./run.sh
Option 2: Manual Setup
Clone and navigate to the repo:
cd qr-code-generator
Create and activate a virtual environment:
python3 -m venv .venv
source .venv/bin/activate
Install the package:
pip install -e .
Run with sample data:
python -m qr_code_generator
This generates QR codes from input/contacts.xlsx and saves them to the images/ folder.
Default behavior (Phone-only QR codes with + prefix):
python -m qr_code_generator
Using the CLI shortcut:
qrgen
Specify custom paths (relative):
python -m qr_code_generator --input data.xlsx --output qr_images/
Use absolute paths anywhere on your system:
# Windows
python -m qr_code_generator --input "C:/Users/YourName/Documents/contacts.xlsx" --output "D:/QR_Codes"
# Linux/Mac
python -m qr_code_generator --input "/home/username/documents/contacts.xlsx" --output "/home/username/qr_codes"
Dry-run mode to test configuration:
python -m qr_code_generator --dry-run
Export manifest:
python -m qr_code_generator --export-manifest --manifest-format json
Generate SVG or PDF outputs:
python -m qr_code_generator --output-format svg
python -m qr_code_generator --output-format pdf
Security options:
python -m qr_code_generator --allowed-output-path ./output --redact-logs
| Option | Description | Default |
|---|---|---|
-i, --input | Input Excel file path (absolute or relative) | input/contacts.xlsx |
-o, --output | Output folder for QR codes (absolute or relative) | images |
-s, --sheet | Sheet index | 0 |
--keep-plus | Prefix phone numbers with + | Enabled |
--no-keep-plus | Don't prefix phone numbers | - |
--overwrite | Overwrite existing QR files | Disabled |
--dedup | Skip duplicate phone numbers | Disabled |
--dry-run | Validate without generating | - |
--export-manifest | Export metadata JSON/CSV | - |
--allowed-output-path | Restrict output to directory | - |
--redact-logs | Redact PII from logs | Enabled |
--max-file-size-mb | Max input file size (MB) | 100 |
--max-rows | Max rows to process | 100000 |
-v, --verbose | Verbose logging (DEBUG level) | - |
-q, --quiet | Suppress non-error output | - |
QR Code Appearance:
| Option | Description | Default |
|---|---|---|
--fill-color | Foreground color | black |
--back-color | Background color | white |
--box-size | Pixel size of each box | 10 |
--border | Border size in boxes | 4 |
--error-correction | Error correction: L, M, Q, H | L |
Payload & Filename:
| Option | Description | Default |
|---|---|---|
--payload-format | Format: phone, vcard, mecard, wifi, url, sms, email | phone |
--output-format | File format: png, svg, pdf | png |
--filename-template | Template using {ColumnName} | {Phone} |
Your Excel file should include a Phone column (required). Optional columns like Name and Email are used for vCard/MeCard formats and filename templates.
Example:
| Name | Phone | |
|---|---|---|
| John Smith | john.smith@example.com | 441234567890 |
| Alice Johnson | alice.johnson@example.com | 442345678901 |
Note: Phone numbers can include or omit the
+prefix. The script handles both formats.
Simple text format: Phone: +441234567890
Standard contact card format compatible with most phones:
BEGIN:VCARD
VERSION:3.0
FN:John Smith
TEL:+441234567890
EMAIL:john.smith@example.com
END:VCARD
Compact Japanese format supported by many QR readers:
MECARD:N:John Smith;TEL:+441234567890;EMAIL:john.smith@example.com;;
WiFi network configuration:
WIFI:T:WPA;S:NetworkName;P:Password;H:false;;
Direct URL:
https://example.com
SMS message:
smsto:+441234567890:Message body
Email message:
mailto:user@example.com?subject=Subject&body=Body
Use column names from your Excel file in curly braces:
{Phone} → +441234567890.png{Name} → John Smith.png{Email} → john.smith@example.com.png{Name}_{Phone} → John Smith_+441234567890.pngIf you use --output-format svg or --output-format pdf, the same template is used with .svg or .pdf extensions.
The script automatically sanitizes filenames to remove invalid characters and handle Windows reserved names.
--allowed-output-path to restrict output to a specific directoryIssue: ModuleNotFoundError: No module named 'openpyxl'
Solution: Install openpyxl: pip install openpyxl
Issue: FileNotFoundError: [Errno 2] No such file or directory: 'input/contacts.xlsx'
Solution: Ensure your Excel file exists at the specified path or use --input to specify a different location.
Issue: Required column 'Phone' not found
Solution: Your Excel file must have a column named 'Phone'. Check the column headers.
Issue: QR codes are too small/large
Solution: Adjust --box-size (default: 10) and --border (default: 4) values.
Issue: Script overwrites existing files
Solution: Remove the --overwrite flag. By default, existing files are skipped.
Generate colored QR codes:
python -m qr_code_generator --fill-color darkblue --back-color lightgray
High error correction for damaged/small codes:
python -m qr_code_generator --error-correction H
Process specific Excel sheet:
python -m qr_code_generator --sheet 1
Combine multiple options:
python -m qr_code_generator ^
--input data/employees.xlsx ^
--output qr_codes/employees/ ^
--payload-format vcard ^
--filename-template "{Name}_{Phone}" ^
--fill-color navy ^
--dedup ^
--verbose
qr-code-generator/
├── .venv/ # Virtual environment
├── scripts/
│ ├── setup.ps1 # Windows setup automation
│ └── setup.sh # Linux/Mac setup automation
├── qr_code_generator/ # Main package
│ ├── __init__.py
│ ├── __version__.py
│ ├── cli.py # CLI entry point
│ ├── service.py # Main orchestration
│ ├── di/ # Dependency injection
│ ├── core/ # Core modules
│ │ ├── generator.py # QR generation
│ │ ├── formatter.py # Phone formatting
│ │ ├── sanitizer.py # Filename sanitization
│ │ ├── validator.py # Data validation
│ │ └── interfaces.py # Abstract interfaces
│ ├── plugins/
│ │ ├── payload/ # Payload generators
│ │ └── output/ # Output adapters
│ └── utils/ # Utilities
├── tests/ # Test suite
│ ├── unit/
│ └── integration/
├── input/
│ └── contacts.xlsx # Sample input data
├── images/ # Generated QR codes
├── pyproject.toml # Packaging metadata
├── pytest.ini # Test configuration
├── run.bat # Windows quick runner
├── run.sh # Linux/Mac quick runner
├── .gitignore # Git ignore rules
├── CHANGELOG.md # Version history
├── README.md # This file
├── AGENTS.md # AI agent instructions
└── LICENSE # MIT License
cli.py parses command-line arguments and maps them to service options.service.py (QRCodeService) is the orchestration layer used by CLI and tests. It validates input files/data, applies dedup and filename sanitization, creates payloads, invokes the QR generator, and writes optional manifests.core/generator.py performs QR generation and delegates file writing to output adapters (png/svg/pdf).If you want to use the package from Python code (without invoking the CLI), call QRCodeService directly:
from qr_code_generator.service import QRCodeService
service = QRCodeService()
exit_code = service.generate_from_excel(
input_file="input/contacts.xlsx",
output_folder="images",
payload_format="vcard", # phone|vcard|mecard|wifi|url|sms|email
output_format="svg", # png|svg|pdf
filename_template="{Name}_{Phone}",
dedup=True,
overwrite=False,
dry_run=False,
export_manifest=True,
manifest_format="json", # json|csv
)
if exit_code != 0:
raise RuntimeError("QR generation failed")
Notes:
0 success, 1 failure).allowed_output_path enables output sandboxing when needed.This project uses pyproject.toml as the source of truth for direct dependencies and uses requirements.txt as a lock file for pip install -r requirements.txt workflows.
Install pip-tools once in your active virtual environment:
pip install pip-tools
Sync requirements.txt from pyproject.toml:
# Windows
powershell -ExecutionPolicy Bypass -File scripts\sync-deps.ps1
# Windows dry-run (validate without writing)
powershell -ExecutionPolicy Bypass -File scripts\sync-deps.ps1 -DryRun
# Windows (also generate requirements-dev.txt from [project.optional-dependencies].test)
powershell -ExecutionPolicy Bypass -File scripts\sync-deps.ps1 -IncludeTest
# Linux/Mac
bash scripts/sync-deps.sh
# Linux/Mac dry-run (validate without writing)
bash scripts/sync-deps.sh --dry-run
# Linux/Mac (also generate requirements-dev.txt from [project.optional-dependencies].test)
bash scripts/sync-deps.sh --with-test
requirements-dev.txt is generated with requirements.txt as a constraint, so runtime dependency versions stay aligned between both lock files.
Install from lock files:
# Runtime only
pip install -r requirements.txt
# Runtime + test/dev tooling
pip install -r requirements-dev.txt
Why this approach:
pyproject.toml contains direct dependencies)requirements.txt is generated/locked)pip freeze output into package metadataDependabot setup:
.github/dependabot.yml to use the pip ecosystem and ignore generated lock files (requirements.txt, requirements-*.txt).pyproject.toml rather than compiled requirements output.Pytest configuration is maintained in pytest.ini.
Run the test suite:
python -m pytest tests -v
Run with coverage:
python -m pytest tests --cov=qr_code_generator --cov-report=term-missing
This project is licensed under the MIT License - see the LICENSE file for details.