A Python CLI tool for arithmetic operations on Magic: The Gathering Cockatrice deck files
Project description
🃏 MTG Wants - Cockatrice Deck Operations
A powerful Python CLI tool and library for performing arithmetic operations on Magic: The Gathering deck files in Cockatrice format (.cod). Perfect for deck management, inventory tracking, and wantslist generation for Cardmarket.
✨ Features
- 🔢 Deck Arithmetic: Add and subtract decks with
--addand--suboperations - 📦 Sideboard Support: Full support for sideboard management
- 🎯 Cardmarket Integration: Export formatted wantslists ready to paste into Cardmarket, automatically copied to clipboard
- 🔄 Sequential Operations: Chain multiple operations in exact order
- 📁 Cockatrice Compatible: Native support for Cockatrice .cod XML format
- 🐍 Python Library: Use as a CLI tool or import as a Python library
🎮 Use Cases
- Build a wantslist: Subtract your collection from a target deck to know what to buy
- Combine decks: Merge multiple decklists into one
- Track inventory: Keep your digital collection synchronized with physical cards
- Deck variations: Create deck variants by adding/removing specific cards
- Budget planning: Calculate exact cards needed for deck upgrades
📦 Installation
From PyPI (Coming Soon)
pip install mtgwants
From Source
git clone https://github.com/Firi0n/mtgwants.git
cd mtgwants
pip install -e .
📋 Requirements
- Python 3.10 or higher
- pyperclip (for clipboard support)
🚀 Quick Start
Basic Usage
# Save a single deck
mtgwants main.cod -o output.cod
# Create a wantslist: deck minus your collection
mtgwants deck.cod --sub collection.cod --print
# Combine multiple decks with sideboard
mtgwants deck1.cod --add deck2.cod --add deck3.cod --sideboard -o combined.cod
📖 Documentation
Command Line Interface
mtgwants MAIN_DECK [OPTIONS]
Required Arguments
MAIN_DECK: The primary deck file in Cockatrice .cod format
Deck Operations
| Option | Short | Description |
|---|---|---|
--add DECK.COD |
-a |
Add cards from deck file (repeatable) |
--sub DECK.COD |
-b |
Subtract cards from deck file (repeatable) |
Important: Operations are executed in the exact order you specify them on the command line. Order matters because subtraction doesn't produce negative quantities.
Other Options
| Option | Short | Description |
|---|---|---|
--sideboard |
-s |
Include sideboard from all decks |
--output FILE |
-o |
Save result to a .cod file |
--print |
-p |
Print cardlist to console (Cardmarket format) and copy it to clipboard |
--deck-name NAME |
-n |
Custom name for output deck (default: "Deck") |
--verbose |
-v |
Verbose output (use -vv for extra detail) |
Note: At least one of --output or --print must be specified.
📚 Examples
Example 1: Generate a Wantslist
You want to build a Commander deck but need to know which cards to buy:
mtgwants commander_deck.cod --sub my_collection.cod --sideboard --print
This outputs a formatted list and copies it directly to your clipboard, ready to paste into Cardmarket's wantslist.
Example 2: Combine Decklists
Merge several decklists into one master list:
mtgwants deck1.cod --add deck2.cod --add deck3.cod -o master_deck.cod
Example 3: Track Inventory
After buying cards, update your collection and recalculate what you still need:
mtgwants target_deck.cod --sub old_collection.cod --add new_cards.cod -o updated_needs.cod --print
Example 4: Short Form Syntax
Use abbreviated flags for quicker commands:
mtgwants main.cod -a extras.cod -b dupes.cod -o final.cod -p
Example 5: Order Matters
Operations are executed left-to-right in exact order:
# Add first, then subtract
mtgwants deck.cod --add new.cod --sub owned.cod -p
# Result: (deck + new) - owned
# Different order, different result
mtgwants deck.cod --sub owned.cod --add new.cod -p
# Result: (deck - owned) + new
Example 6: Debug with Verbose Output
See detailed information about each operation:
mtgwants main.cod -a extras.cod -b dupes.cod -o final.cod -vv
Output:
Loading main deck: main.cod
Main: 60 cards
Adding: extras.cod
Result main: 75 cards
Subtracting: dupes.cod
Result main: 60 cards
Saving to: final.cod
✓ Saved successfully
✓ Operations completed successfully
Final deck: 60 cards in main
🐍 Python Library Usage
Use mtgwants as a library in your Python projects:
from mtgwants import Card, Zone, Deck, CockatriceParser
# Create parser
parser = CockatriceParser(sideboard=True)
# Load decks
deck1 = parser.load("deck1.cod")
deck2 = parser.load("deck2.cod")
# Perform operations
combined = deck1 + deck2
needs = deck1 - deck2
# Access card data
for card, quantity in combined.main.items():
print(f"{quantity}x {card.name}")
# Save result
parser.save(combined, "output.cod", "My Combined Deck")
Core Classes
Card
Represents a Magic: The Gathering card identified by name.
card = Card("Lightning Bolt")
print(card.name) # "Lightning Bolt"
print(card.is_basic_land) # False
Zone
A multiset of cards with arithmetic operations (main deck, sideboard, etc.).
zone = Zone({Card("Lightning Bolt"): 4, Card("Counterspell"): 2})
print(len(zone)) # 6 (total cards)
print(zone.unique_cards) # 2 (different cards)
Deck
Complete deck with main zone and optional sideboard.
main = Zone({Card("Lightning Bolt"): 4})
side = Zone({Card("Counterspell"): 2})
deck = Deck(main, side)
print(deck.has_sideboard) # True
print(len(deck)) # 6 (main + sideboard)
# Get deck without basic lands
result = deck.nonland_deck
print(result.main_lands) # number of basic lands removed from main
print(result.side_lands) # number of basic lands removed from sideboard
print(result.deck) # filtered Deck
ZoneType
Enum for specifying which zone to operate on.
from mtgwants import ZoneType
deck.get_count(Card("Lightning Bolt"), zone=ZoneType.MAIN)
deck.items(zone=ZoneType.SIDEBOARD)
CockatriceParser
Parser for reading and writing .cod files.
parser = CockatriceParser(sideboard=True)
deck = parser.load("deck.cod")
parser.save(deck, "output.cod", "Deck Name")
🛠️ Technical Details
File Format
Cockatrice .cod files are XML files with the following structure:
<?xml version="1.0"?>
<cockatrice_deck version="1">
<deckname>My Deck</deckname>
<comments></comments>
<zone name="main">
<card number="4" name="Lightning Bolt"/>
<card number="2" name="Counterspell"/>
</zone>
<zone name="side">
<card number="3" name="Negate"/>
</zone>
</cockatrice_deck>
Cardmarket Export Format
The --print option generates output ready for Cardmarket's "Add a Deck List" feature, and automatically copies it to your clipboard:
4 Lightning Bolt
2 Counterspell
// Sideboard
3 Negate
Basic lands (Plains, Island, Swamp, Mountain, Forest, Wastes) are automatically excluded from the output.
After pasting into Cardmarket:
- Select all cards → Edit
- Set language, condition, and foil preferences
- Save your wantslist
Arithmetic Operations
Operations follow mathematical rules:
-
Addition: Combines card quantities
deck1 = Zone({Card("Bolt"): 2}) deck2 = Zone({Card("Bolt"): 2}) result = deck1 + deck2 # {Card("Bolt"): 4}
-
Subtraction: Removes cards (negatives become zero)
deck = Zone({Card("Bolt"): 4}) owned = Zone({Card("Bolt"): 2}) needs = deck - owned # {Card("Bolt"): 2}
-
Sequential Operations: Processed in exact command-line order (left to right)
mtgwants A.cod --add B.cod --sub C.cod --add D.cod # Equivalent to: (((A + B) - C) + D)
🤝 Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
📝 License
This project is licensed under the MIT License - see the LICENSE file for details.
🎯 Roadmap
- Cardmarket API integration (when/if they finally release it to private users)
💡 FAQ
Q: Why "mtgwants"?
A: The tool was originally designed to generate wantslists for Cardmarket by subtracting your collection from target decks.
Q: Does this work with other MTG software?
A: Currently only Cockatrice .cod format is supported. Other formats are planned.
Q: What about the Cardmarket API?
A: Cardmarket's API v3.0 for private users has been "coming soon" since 2021. Until then, use the --print option for manual import.
Q: Can I use this in my own Python project?
A: Absolutely! Import the library and use the Card, Zone, ZoneType, Deck, and CockatriceParser classes.
Q: The clipboard copy didn't work.
A: On some Linux systems you may need to install a clipboard backend: sudo apt install xclip or sudo apt install xsel.
🙏 Acknowledgments
- Cockatrice - Open source MTG client
- Cardmarket - European MTG marketplace
- The Magic: The Gathering community
📞 Contact
- GitHub: @Firi0n
- Project Link: https://github.com/Firi0n/mtgwants
⭐ If you find this tool useful, please consider giving it a star on GitHub!
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 mtgwants-0.1.1.tar.gz.
File metadata
- Download URL: mtgwants-0.1.1.tar.gz
- Upload date:
- Size: 16.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.20
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c396b5807f5fc69196dd2dfd29b3acf06bdc48c81ffdbfc151ed6a9551d0ffbf
|
|
| MD5 |
c414499e97ae5deea9776f19733e1fca
|
|
| BLAKE2b-256 |
316bb6e4e87b545a722e6f4b793fc81f95a2589ca85948c82caa4159926f8ea4
|
File details
Details for the file mtgwants-0.1.1-py3-none-any.whl.
File metadata
- Download URL: mtgwants-0.1.1-py3-none-any.whl
- Upload date:
- Size: 14.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.20
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
67181ec02a4414962ab4a7f36dc7c72ced4e3f12b9861ec80f917f54805296d6
|
|
| MD5 |
a9ad12a0ba3afd991157b7baaaeefd0a
|
|
| BLAKE2b-256 |
f99f4cb4515c040a79a54bff916bc675187cf78478a6b6c50496c10f92aa02e1
|