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.batOption 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.shOption 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_generatorUsing the CLI shortcut:
qrgenSpecify 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-runExport manifest:
python -m qr_code_generator --export-manifest --manifest-format jsonGenerate SVG or PDF outputs:
python -m qr_code_generator --output-format svg
python -m qr_code_generator --output-format pdfSecurity 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.png
If 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.
- Path Traversal Prevention: Template variables are validated to prevent path traversal attacks
- Output Sandbox: Use
--allowed-output-pathto restrict output to a specific directory - PII Redaction: Phone numbers and emails are masked in logs by default
- File Validation: Excel files are validated for magic bytes and size limits
Issue: 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 lightgrayHigh error correction for damaged/small codes:
python -m qr_code_generator --error-correction HProcess specific Excel sheet:
python -m qr_code_generator --sheet 1Combine 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 ^
--verboseqr-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.pyparses 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.pyperforms 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:
- Return value is an exit-style status code (
0success,1failure). allowed_output_pathenables output sandboxing when needed.- This is the same workflow the CLI uses internally, so behavior stays consistent.
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-toolsSync 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-testrequirements-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.txtWhy this approach:
- Keep packaging metadata clean for PyPI (
pyproject.tomlcontains direct dependencies) - Keep reproducible installs for local/CI (
requirements.txtis generated/locked) - Avoid copying full
pip freezeoutput into package metadata
Dependabot setup:
- Dependabot is configured in
.github/dependabot.ymlto use thepipecosystem and ignore generated lock files (requirements.txt,requirements-*.txt). - This keeps automated dependency PRs focused on
pyproject.tomlrather than compiled requirements output.
Pytest configuration is maintained in pytest.ini.
Run the test suite:
python -m pytest tests -vRun with coverage:
python -m pytest tests --cov=qr_code_generator --cov-report=term-missingThis project is licensed under the MIT License - see the LICENSE file for details.