def tournament_deck(cells: ResultSet, competition_id: int,
                    date: datetime.datetime,
                    final: Dict[str, int]) -> Optional[deck.Deck]:
    d: deck.RawDeckDescription = {
        'source': 'Gatherling',
        'competition_id': competition_id,
        'created_date': dtutil.dt2ts(date)
    }
    player = cells[2]
    username = aliased(player.a.contents[0].string)
    d['mtgo_username'] = username
    d['finish'] = final.get(username)
    link = cells[4].a
    d['url'] = gatherling_url(link['href'])
    d['name'] = link.string
    if cells[5].find('a'):
        d['archetype'] = cells[5].a.string
    else:
        d['archetype'] = cells[5].string
    gatherling_id = urllib.parse.parse_qs(
        urllib.parse.urlparse(str(d['url'])).query)['id'][0]
    d['identifier'] = gatherling_id
    existing = deck.get_deck_id(d['source'], d['identifier'])
    if existing is not None:
        return deck.load_deck(existing)
    dlist = decklist.parse(
        fetcher.internal.post(gatherling_url('deckdl.php'),
                              {'id': gatherling_id}))
    d['cards'] = dlist
    if len(dlist['maindeck']) + len(dlist['sideboard']) == 0:
        logger.warning(
            'Rejecting deck with id {id} because it has no cards.'.format(
                id=gatherling_id))
        return None
    return deck.add_deck(d)
def test_parse3() -> None:
    s = """
        3 Barter in Blood
        4 Consume Spirit
        4 Demonic Rising
        4 Devour Flesh
        2 Distress
        2 Dread Statuary
        4 Haunted Plate Mail
        3 Homicidal Seclusion
        4 Hymn to Tourach
        2 Infest
        4 Quicksand
        4 Spawning Pool
        14 Swamp
        2 Ultimate Price
        4 Underworld Connections

        1 Distress
        2 Dystopia
        1 Infest
        4 Memoricide
        2 Nature's Ruin
        1 Pharika's Cure
        4 Scrabbling Claws"""
    s = textwrap.dedent(s)
    d = decklist.parse(s)
    assert len(d['maindeck']) == 15
    assert len(d['sideboard']) == 7
Example #3
0
def set_values(raw_deck: RawDeckType) -> RawDeckType:
    raw_deck = translation.translate(translation.TAPPEDOUT, raw_deck)
    raw_decklist = fetch_tools.fetch('{base_url}?fmt=txt'.format(base_url=raw_deck['url']))
    raw_deck['cards'] = decklist.parse(raw_decklist)
    raw_deck['source'] = 'Tapped Out'
    raw_deck['identifier'] = raw_deck['url']
    return raw_deck
def test_parse10() -> None:
    s = """
        Sideboard"""
    s = textwrap.dedent(s)
    d = decklist.parse(s)
    assert sum(d['maindeck'].values()) == 0
    assert sum(d['sideboard'].values()) == 0
def test_parse8() -> None:
    s = """
        24 Island
        4 Curious Homunculus
        4 Prism Ring
        4 Anticipate
        4 Take Inventory
        4 Dissolve
        3 Void Shatter
        3 Jace's Sanctum
        3 Whelming Wave
        2 Control Magic
        2 Confirm Suspicions
        2 Counterbore
        1 Rise from the Tides
        1 Cryptic Serpent
        1 Convolute
        1 Lone Revenant
        1 Careful Consideration
        1 Opportunity
        4 Annul
        4 Invasive Surgery
        3 Sentinel Totem
    """
    s = textwrap.dedent(s)
    d = decklist.parse(s)
    assert sum(d['maindeck'].values()) == 61
    assert sum(d['sideboard'].values()) == 15
    assert d['maindeck']['Cryptic Serpent'] == 1
    assert d['sideboard']['Convolute'] == 1
def test_parse9() -> None:
    s = """
        2 Bonded Horncrest
        4 Boros Guildgate
        2 Charging Monstrosaur
        2 Frenzied Raptor
        3 Imperial Lancer
        8 Mountain
        2 Nest Robber
        2 Pious Interdiction
        9 Plains
        1 Pterodon Knight
        2 Rallying Roar
        2 Shining Aerosaur
        3 Sky Terror
        2 Slash of Talons
        4 Stone Quarry
        2 Sure Strike
        2 Swashbuckling
        3 Territorial Hammerskull
        2 Thrash of Raptors
        1 Tilonalli's Skinshifter
        2 Unfriendly Fire

        Sideboard"""
    s = textwrap.dedent(s)
    d = decklist.parse(s)
    assert sum(d['maindeck'].values()) == 60
    assert sum(d['sideboard'].values()) == 0
    assert d['maindeck']['Shining Aerosaur'] == 2
Example #7
0
def test_sideboard_with_sb() -> None:
    s = """
        Main
        4 Bastion of Remembrance
        4 Bloodthrone Vampire
        4 Cauldron Familiar
        3 Dark Prophecy
        4 Dark Ritual
        4 Mayhem Devil
        4 Mogg War Marshal
        2 Putrid Goblin
        4 Sling-Gang Lieutenant
        3 Unearth
        4 Witch's Oven
        1 Barbarian Ring
        4 Bloodfell Caves
        3 Mountain
        7 Swamp
        4 Temple of Malice
        1 Tomb of Urami

        Sideboard
        SB: 3 Claim the Firstborn
        SB: 3 Duress
        SB: 2 Slagstorm
        SB: 2 Slaughter Games
        SB: 3 Soul-Guide Lantern
        SB: 2 Goblin Cratermaker
    """
    s = textwrap.dedent(s)
    d = decklist.parse(s)
    assert sum(d['maindeck'].values()) == 60
    assert sum(d['sideboard'].values()) == 15
def test_parse7() -> None:
    s = """
        16 Forest
        4 Animist's Awakening
        4 Copperhorn Scout
        4 Harvest Season
        4 Jaddi Offshoot
        4 Krosan Wayfarer
        4 Loam Dryad
        4 Nantuko Monastery
        4 Nest Invader
        4 Quest for Renewal
        4 Rofellos, Llanowar Emissary
        4 Sky Skiff
        4 Dystopia
        1 Infest
        4 Memoricide
        2 Nature's Ruin
        1 Pharika's Cure
        4 Scrabbling Claws
    """
    s = textwrap.dedent(s)
    d = decklist.parse(s)
    assert sum(d['maindeck'].values()) == 64
    assert sum(d['sideboard'].values()) == 12
    assert len(d['maindeck']) == 13
    assert len(d['sideboard']) == 5
Example #9
0
def test_explicit_main_sb() -> None:
    s = """
        Main:
        4 Teferi, Mage of Zhalfir
        2 Knowledge Pool
        4 Mana Leak
        4 Memory Lapse
        4 Miscast
        4 Swan Song
        4 Fact or Fiction
        4 Engulf the Shore
        4 Everflowing Chalice
        4 Frantic Inventory
        4 Mystic Sanctuary
        18 Island

        Sideboard:
        2 Nezahal, Primal Tide
        4 Soul-Guide Lantern
        3 Marrow Shards
        4 Flashfreeze
        2 Control Magic
    """
    s = textwrap.dedent(s)
    d = decklist.parse(s)
    assert sum(d['maindeck'].values()) == 60
    assert sum(d['sideboard'].values()) == 15
Example #10
0
def test_parse_double_blank_line() -> None:
    s = """
        4 Deeproot Champion
        2 Quench
        1 Spell Rupture
        3 Terramorphic Expanse
        4 Quirion Dryad
        3 Hooting Mandrills
        1 Snapback
        4 Forest
        1 Unsummon
        4 Gitaxian Probe
        2 Prohibit
        3 Gush
        4 Peek
        2 Censor
        4 Mental Note
        2 Negate
        3 Treasure Cruise
        4 Evolving Wilds
        9 Island


        4 Scrabbling Claws
        3 Naturalize
        3 Snapback
        4 Invasive Surgery
        1 Boomerang
    """
    s = textwrap.dedent(s)
    d = decklist.parse(s)
    assert sum(d['maindeck'].values()) == 60
    assert sum(d['sideboard'].values()) == 15
Example #11
0
 def parse_decklist(self) -> None:
     self.cards: DecklistType = {}
     if self.decklist.startswith('<?xml'):
         try:
             self.cards = decklist.parse_xml(self.decklist)
         except InvalidDataException:
             self.errors['decklist'] = 'Unable to read .dek decklist. Try exporting from Magic Online as Text and pasting the result.'
     else:
         try:
             self.cards = decklist.parse(self.decklist)
         except InvalidDataException as e:
             self.errors['decklist'] = '{specific}. Try exporting from Magic Online as Text and pasting the result.'.format(specific=str(e))
def test_parse5() -> None:
    s = """
        4 Animist's Awakening
        4 Copperhorn Scout
        14 Forest
        4 Harvest Season
        4 Jaddi Offshoot
        4 Krosan Wayfarer
        4 Loam Dryad
        4 Nantuko Monastery
        4 Nest Invader
        4 Quest for Renewal
        4 Rofellos, Llanowar Emissary
        2 Sky Skiff
        4 Throne of the God-Pharaoh

        0 Villainous Wealth
    """
    s = textwrap.dedent(s)
    d = decklist.parse(s)
    assert len(d['maindeck']) == 13
    assert len(d['sideboard']) == 0
def test_parse12() -> None:
    s = """
        1 Felidar Sovereign
        3 Elixir of Immortality
        4 Ivory Tower
        4 Rest for the Weary
        4 Revitalize
        2 Banishing Light
        4 Healing Hands
        4 Renewed Faith
        4 Reviving Dose
        4 Ritual of Rejuvenation
        3 Survival Cache
        4 Faith's Fetters
        2 Boon Reflection
        3 End Hostilities
        4 Planar Outburst
        1 Final Judgment
        2 Sanguine Sacrament
        4 Encroaching Wastes
        2 Kjeldoran Outpost
        19 Plains
        4 Thawing Glaciers
        3 Urza's Factory
        2 Cataclysmic Gearhulk
        1 Felidar Sovereign
        2 Purify the Grave
        4 Scrabbling Claws
        1 Banishing Light
        4 Invoke the Divine
        1 End Hostilities
        """
    s = textwrap.dedent(s)
    d = decklist.parse(s)
    assert sum(d['maindeck'].values()) == 85
    assert sum(d['sideboard'].values()) == 15
def test_parse_tappedout_commander() -> None:
    s = """
        1 Altered Ego
        1 Blighted Woodland
        1 Bloodwater Entity
        1 Bogardan Hellkite
        1 Bounty of the Luxa
        1 Broken Bond
        1 Cackling Counterpart
        1 Chandra's Ignition
        1 Charmbreaker Devils
        1 Chromatic Lantern
        1 Circuitous Route
        1 Clone
        1 Confiscate
        1 Conqueror's Galleon
        1 Cryptoplasm
        1 Crystal Ball
        1 Cultivator's Caravan
        1 Curse of the Swine
        1 Dack's Duplicate
        1 Diluvian Primordial
        1 Elemental Bond
        1 Evolving Wilds
        1 Felhide Spiritbinder
        1 Flameshadow Conjuring
        1 Followed Footsteps
        9 Forest
        1 Gateway Plaza
        1 Gilded Lotus
        1 Grow from the Ashes
        1 Gruul Guildgate
        1 Gruul Signet
        1 Helm of the Host
        1 Highland Lake
        1 Identity Thief
        1 Insidious Will
        1 Intet, the Dreamer
        7 Island
        1 Izzet Guildgate
        1 Journeyer's Kite
        1 Kederekt Leviathan
        1 Memorial to Genius
        1 Memorial to Unity
        1 Memorial to War
        1 Mercurial Pretender
        1 Molten Primordial
        4 Mountain
        1 Ondu Giant
        1 Protean Raider
        1 Pyramid of the Pantheon
        1 Quasiduplicate
        1 Rampant Growth
        1 Rattleclaw Mystic
        1 Rishkar's Expertise
        1 Rogue's Passage
        1 Rugged Highlands
        1 Rupture Spire
        1 Saheeli's Artistry
        1 Salvager of Secrets
        1 Sculpting Steel
        1 Simic Guildgate
        1 Soul Foundry
        1 Spelltwine
        1 Sphinx of Uthuun
        1 Stolen Identity
        1 Sunbird's Invocation
        1 Tatyova, Benthic Druid
        1 Temur Ascendancy
        1 Thawing Glaciers
        1 Transguild Promenade
        1 Treasure Cruise
        1 Trophy Mage
        1 Trygon Predator
        1 Unexpected Results
        1 Urban Evolution
        1 Vesuvan Shapeshifter
        1 Vivid Grove
        1 Whispersilk Cloak
        1 Wildest Dreams
        1 Woodland Stream
        1 Yavimaya Hollow
        1 Zealous Conscripts
        1 Zendikar Resurgent
        1 Zndrsplt's Judgment
    """
    s = textwrap.dedent(s)
    d = decklist.parse(s)
    assert sum(d['maindeck'].values()) == 100
    assert len(d['maindeck']) == 83
    assert len(d['sideboard']) == 0
def test_parse11() -> None:
    s = """
        1 Groundskeeper
        1 Jaddi Offshoot
        1 Scute Mob
        1 Frontier Guide
        1 Llanowar Scout
        1 Grazing Gladehart
        1 Mwonvuli Beast Tracker
        1 Ranging Raptors
        1 Embodiment of Fury
        1 Grove Rumbler
        1 Mina and Denn, Wildborn
        1 Cultivator of Blades
        1 Embodiment of Insight
        1 Garruk's Packleader
        1 Akoum Hellkite
        1 Baloth Woodcrasher
        1 Oran-Rief Hydra
        1 Rubblehulk
        1 Borborygmos
        1 Skarrg Goliath
        1 Myojin of Infinite Rage
        1 Apocalypse Hydra
        1 Lay of the Land
        1 Blackblade Reforged
        1 Broken Bond
        1 Evolution Charm
        1 Fork in the Road
        1 Ground Assault
        1 Rampant Growth
        1 Signal the Clans
        1 Deep Reconnaissance
        1 Elemental Bond
        1 Fires of Yavimaya
        1 Grow from the Ashes
        1 Hammer of Purphoros
        1 Harrow
        1 Journey of Discovery
        1 Nissa's Pilgrimage
        1 Retreat to Valakut
        1 Ghirapur Orrery
        1 Seek the Horizon
        1 Seer's Sundial
        1 Splendid Reclamation
        1 Overwhelming Stampede
        1 Rude Awakening
        1 Nissa's Renewal
        1 Animist's Awakening
        1 Clan Defiance
        1 Blighted Woodland
        1 Evolving Wilds
        16 Forest
        1 Gruul Guildgate
        1 Kazandu Refuge
        14 Mountain
        1 Mountain Valley
        1 Rogue's Passage
        1 Rugged Highlands
        1 Sylvan Ranger
        1 Vinelasher Kudzu
        1 Viridian Emissary
        1 Zhur-Taa Druid
        1 Tunneling Geopede
        1 World Shaper
        1 Zendikar Incarnate
        1 Verdant Force
        1 Strata Scythe
        1 Sylvan Awakening
        1 The Mending of Dominaria
        1 Zendikar's Roil
        1 Sunbird's Invocation
        1 Zendikar Resurgent
        1 Timber Gorge
        """
    s = textwrap.dedent(s)
    d = decklist.parse(s)
    assert sum(d['maindeck'].values()) == 100
    assert sum(d['sideboard'].values()) == 0
    assert d['maindeck']['Timber Gorge'] == 1
def scrape_decklist(d: Container) -> decklist.DecklistType:
    url = 'https://www.mtggoldfish.com/deck/download/{identifier}'.format(
        identifier=d.identifier)
    return decklist.parse(fetch_tools.fetch(url))