Convert subscription lists to CSV with EUR conversion
Project description
Subscriptions to CSV
A Python package built as a Nix flake utility that provides both CLI and library functionality to convert subscription lists into CSV files with EUR conversions and totals. Includes comprehensive type hints, error handling, and a full test suite.
Description
This tool processes subscription data (from files or strings) containing service names and prices, generates CSV output with columns for Service, Price, Currency, and Price in EUR (with automatic USD to EUR conversion), and calculates total sums in EUR.
Available as both:
- Command-line tool: Process files directly from the terminal
- Python library: Import and use programmatically in your applications
The project includes comprehensive unit tests covering all major functionality and supports PyPI distribution.
Installation
Option 1: PyPI (Library + CLI)
pip install subscriptions-to-csv
This installs both the command-line tool and Python library.
Option 2: Nix Flake (Development/Direct Usage)
Ensure you have Nix installed with flakes enabled.
Clone the Repository
git clone https://github.com/MBanucu/subscriptions-to-csv.git
cd subscriptions-to-csv
# Allow direnv to load the .envrc file (one-time setup)
direnv allow
The project uses direnv for automatic development environment loading. After running direnv allow, the Nix devShell will be automatically activated whenever you enter the directory.
Direct from GitHub
You can also use this flake directly from GitHub without cloning:
# Run with default files
nix run github:MBanucu/subscriptions-to-csv#subscriptions-to-csv
# Specify input and output files
nix run github:MBanucu/subscriptions-to-csv#subscriptions-to-csv path/to/input.txt path/to/output.csv
# Show help
nix run github:MBanucu/subscriptions-to-csv#subscriptions-to-csv -- --help
This approach allows you to use the tool immediately without downloading the source code.
Note: When using nix run directly from GitHub, use positional arguments for input/output files or the -- separator before option flags. Both approaches work the same way. Options work normally when running locally after cloning.
Usage
CLI Usage
Basic Usage
# Enter the development shell (or use direnv for automatic loading)
nix develop
# Run the converter
subscriptions-to-csv
This will read subscriptions.txt and output subscriptions.csv.
Note: If you have direnv installed, the development shell will be automatically activated when you enter the directory, making the nix develop step unnecessary.
Custom Files
# Specify input and output files (positional)
nix run .#subscriptions-to-csv path/to/input.txt path/to/output.csv
# Or using options
nix run .#subscriptions-to-csv --input path/to/input.txt --output path/to/output.csv
Direct Run
nix run .#subscriptions-to-csv
Help
# Show usage information
nix run .#subscriptions-to-csv -- --help
Note: The -- separates nix arguments from application arguments.
Library Usage
When installed via pip, you can use the package as a Python library:
Basic Usage
from subscriptions_to_csv import convert_subscriptions
# Convert from string data
data = """Netflix
$15.99 USD
Spotify
€9.99"""
subscriptions, total = convert_subscriptions(data)
print(f"Total: €{total:.2f}")
for sub in subscriptions:
print(f"{sub['Service']}: {sub['Price']} {sub['Currency']} = €{sub['PriceEUR']}")
Advanced Usage
from subscriptions_to_csv import SubscriptionConverter, fetch_exchange_rate
# Manual control over exchange rates
converter = SubscriptionConverter()
converter.set_exchange_rate(0.85) # Set custom rate
# Convert and get data
subscriptions = converter.convert("Netflix\n$15.99 USD")
total, count = converter.convert_with_total("Netflix\n$15.99 USD")
# Write to CSV file
converter.convert_to_csv("Netflix\n$15.99 USD", "output.csv")
# Individual functions
rate = fetch_exchange_rate()
Input Format
The input file should contain subscription data in the following format:
Service Name
Price Currency
Service Name
Price Currency
Example:
Spotify
12.99 €
Netflix
19.99 €
GutHub Copilot Pro
$10.00 USD
Supported currencies: € (Euro), USD (automatically converted to EUR).
Output
The output CSV contains:
- Service: The subscription name
- Price: The original price
- Currency: The original currency
- PriceEUR: The price in EUR (converted if necessary)
Plus a total sum in EUR printed to the console.
Example output:
Service,Price,Currency,PriceEUR
Spotify,12.99,€,12.99
Netflix,19.99,€,19.99
GutHub Copilot Pro,10.00,USD,8.62
Total in EUR: 41.60
Configuration
- Input file: Default
subscriptions.txt, can be overridden with--inputor positional argument - Output file: Default
subscriptions.csv, can be overridden with--outputor positional argument - Exchange rate: Automatically fetched from exchangerate-api.com
- Fallback: If API fails, uses rate 1.0
Test Coverage
The project includes comprehensive unit tests covering:
- Command-line argument parsing (default, positional, optional)
- Exchange rate API fetching with fallback behavior
- Subscription data parsing and currency conversion
- CSV file generation and total calculations
- Integration testing of the full workflow
Requirements
CLI Usage
- Nix with flakes support (for nix-based installation)
- Internet connection for exchange rate fetching
Library Usage
- Python 3.6+ (3.13 recommended)
- pip for installation
- Internet connection for exchange rate fetching
Development
Project Structure
The project is structured as a proper Python package:
flake.nix: Nix flake configuration for multi-platform buildsflake.lock: Nix flake lock file.envrc: Direnv configuration for automatic devShell loadingpyproject.toml: Python package configuration and build systemsubscriptions_to_csv/: Main Python package__init__.py: Package initialization and exportsconverter.py: Core conversion functions and classescli.py: Command-line interface
tests/test_main.py: Comprehensive unit test suite
Building
Build the Python package:
nix build
This creates a proper Python package using buildPythonPackage that can be installed and distributed.
Testing
Run the comprehensive test suite including CLI integration tests:
# Run unit tests (direnv automatically loads environment)
pytest
# Or manually enter devShell and run tests
nix develop --command pytest
# Run flake checks (includes CLI functionality tests)
nix flake check
# Run specific flake checks
nix build .#checks.x86_64-linux.help-test
nix build .#checks.x86_64-linux.basic-test
nix build .#checks.x86_64-linux.named-args-test
The flake checks verify that:
- The
--helpcommand works correctly - Basic functionality with sample data works
- Positional and named arguments function properly
Testing
# Run the test suite (environment loads automatically with direnv)
pytest
# Or enter devShell manually
nix develop
pytest
# Run specific tests
pytest tests/test_main.py
pytest -k "parse" # Run tests matching pattern
# Manual testing - Run with defaults
nix run .#subscriptions-to-csv
# Test CLI options
nix run .#subscriptions-to-csv -- --help
# Check the output CSV and total
Release Process
The project uses automated semantic versioning with cutting-edge tooling. When you push commits to the main branch:
- Conventional commits trigger automatic version analysis
- Semantic-release v25.0.2 determines version bumps and generates changelogs
- GitHub Actions v6.0.0 handles the complete release pipeline
- Version files are automatically updated and committed
- PyPI publishing via trusted publisher authentication
Example workflow:
# Make changes
git add .
git commit -m "feat: add new export format"
# Push to main - triggers automated release (13-16 seconds)
git push origin main
Tools Used:
- semantic-release: v25.0.2 (latest stable)
- GitHub Action: cycjimmy/semantic-release-action v6.0.0
- Node.js: 24+ compatible
- Plugins: changelog, git (optimized for Python projects)
Code Style
See AGENTS.md for detailed coding guidelines.
Releases
This project uses automated semantic versioning and publishing with semantic-release v25.0.2 and cycjimmy/semantic-release-action v6.0.0:
🎉 Fully automated release system now active!
Automated Releases
- Trigger: Push to
mainbranch with conventional commits - Versioning: Automatic based on commit types (
feat:,fix:, etc.) - Publishing: Automatic PyPI publishing via trusted publisher
- Changelog: Automatically generated from commit messages
- Performance: 13-16 second release cycles
- Compatibility: Latest Node.js 24 and plugin ecosystem support
Commit Types & Releases
| Commit Type | Release Type | Version Bump | Example |
|---|---|---|---|
fix: |
Patch | 0.0.1 | fix: handle empty files |
feat: |
Minor | 0.1.0 | feat: add export formats |
feat!: or BREAKING CHANGE: |
Major | 1.0.0 | feat!: redesign API |
docs:, refactor:, test:, chore: |
No release | - | docs: update README |
Manual Releases
For special cases, create releases manually:
gh release create v1.2.3 --generate-notes
Contributing
- Fork the repository
- Create a feature branch
- Make changes
- Run tests:
pytest(direnv automatically loads the environment) - Test CLI:
nix run .#subscriptions-to-csv -- --help - Test library:
python3 -c "from subscriptions_to_csv import convert_subscriptions; print('Library works')" - Submit a pull request
License
This project is open source. Please check the license file if present.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file subscriptions_to_csv-1.7.1.tar.gz.
File metadata
- Download URL: subscriptions_to_csv-1.7.1.tar.gz
- Upload date:
- Size: 13.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4ba3da17f48cb510e3f281931dd464863523961a96cf5b2be3b919e0be909697
|
|
| MD5 |
d43a6aa1acae2b4e0ccd067cb47fe4e3
|
|
| BLAKE2b-256 |
2207edec1ba6e3e8ab567526e0c3e02d6c3dbb98d1b82403ea5defb9810c60fd
|
Provenance
The following attestation bundles were made for subscriptions_to_csv-1.7.1.tar.gz:
Publisher:
release.yml on MBanucu/subscriptions-to-csv
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
subscriptions_to_csv-1.7.1.tar.gz -
Subject digest:
4ba3da17f48cb510e3f281931dd464863523961a96cf5b2be3b919e0be909697 - Sigstore transparency entry: 834249685
- Sigstore integration time:
-
Permalink:
MBanucu/subscriptions-to-csv@05406dcbb403805f17d99ab984c787bd70972afa -
Branch / Tag:
refs/heads/main - Owner: https://github.com/MBanucu
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@05406dcbb403805f17d99ab984c787bd70972afa -
Trigger Event:
workflow_run
-
Statement type:
File details
Details for the file subscriptions_to_csv-1.7.1-py3-none-any.whl.
File metadata
- Download URL: subscriptions_to_csv-1.7.1-py3-none-any.whl
- Upload date:
- Size: 9.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d9b2fc9c5c69c02795d2d93c20de36d627f9ff83085357c8057900cc78f37b1d
|
|
| MD5 |
e798a029e2f0d0ae5f07bedf76dd13f6
|
|
| BLAKE2b-256 |
79cc81b980333334da19fcdc51a3f3c6c6d852b099603400f03e57dc1c4473fe
|
Provenance
The following attestation bundles were made for subscriptions_to_csv-1.7.1-py3-none-any.whl:
Publisher:
release.yml on MBanucu/subscriptions-to-csv
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
subscriptions_to_csv-1.7.1-py3-none-any.whl -
Subject digest:
d9b2fc9c5c69c02795d2d93c20de36d627f9ff83085357c8057900cc78f37b1d - Sigstore transparency entry: 834249688
- Sigstore integration time:
-
Permalink:
MBanucu/subscriptions-to-csv@05406dcbb403805f17d99ab984c787bd70972afa -
Branch / Tag:
refs/heads/main - Owner: https://github.com/MBanucu
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@05406dcbb403805f17d99ab984c787bd70972afa -
Trigger Event:
workflow_run
-
Statement type: