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.
- 🔢 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
- 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
pip install mtgwantsgit clone https://github.com/Firi0n/mtgwants.git
cd mtgwants
pip install -e .- Python 3.10 or higher
- pyperclip (for clipboard support)
# 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.codmtgwants MAIN_DECK [OPTIONS]
MAIN_DECK: The primary deck file in Cockatrice .cod format
| 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.
| 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.
You want to build a Commander deck but need to know which cards to buy:
mtgwants commander_deck.cod --sub my_collection.cod --sideboard --printThis outputs a formatted list and copies it directly to your clipboard, ready to paste into Cardmarket's wantslist.
Merge several decklists into one master list:
mtgwants deck1.cod --add deck2.cod --add deck3.cod -o master_deck.codAfter 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 --printUse abbreviated flags for quicker commands:
mtgwants main.cod -a extras.cod -b dupes.cod -o final.cod -pOperations 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) + newSee detailed information about each operation:
mtgwants main.cod -a extras.cod -b dupes.cod -o final.cod -vvOutput:
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
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")Represents a Magic: The Gathering card identified by name.
card = Card("Lightning Bolt")
print(card.name) # "Lightning Bolt"
print(card.is_basic_land) # FalseA 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)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 DeckEnum 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)Parser for reading and writing .cod files.
parser = CockatriceParser(sideboard=True)
deck = parser.load("deck.cod")
parser.save(deck, "output.cod", "Deck Name")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>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
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)
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
This project is licensed under the MIT License - see the LICENSE file for details.
- Cardmarket API integration (when/if they finally release it to private users)
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.
- Cockatrice - Open source MTG client
- Cardmarket - European MTG marketplace
- The Magic: The Gathering community
- GitHub: @Firi0n
- Project Link: https://github.com/Firi0n/mtgwants
⭐ If you find this tool useful, please consider giving it a star on GitHub!