def _get_multicolor_cards(self, pretend=False): if pretend: if self.sort_spec.get('multicolor_subsections', False): return {} else: return [] cube_cards = Card.objects.filter(cube=self.cube) log.debug('all cube cards: {}', cube_cards) # this is going to leverage the assumptions that magic has not # yet combined one color of a "special" mana with a different color # of mana, except in the case of multicolor hybrid, which is being # handled qs = cube_cards.filter(_mono_hybrid_mana_bitfield=0, _phyrexian_mana_bitfield=0) log.debug('cards that don\'t have special stuff: {}', qs) for color_name in color_bitfield_keys: color_value = int(getattr(Card._standard_mana_bitfield, color_name)) # checking against the int values of these flags checks for EXACTLY # those values, e.g. not green AND black qs = qs.exclude(_standard_mana_bitfield=color_value) log.debug('cards after removing {}: {}', color_name, qs) qs = qs.exclude(_standard_mana_bitfield=0) hybrid_cards = cube_cards.exclude(_hybrid_mana_bitfield=0) log.debug('non-hybrid multicolor cards left: {}', qs) return cube_cards.filter(Q(name__in=hybrid_cards.values("name"))| Q(name__in=qs.values("name"))).distinct()
def get_all_inserted_names(cls, redis_conn=None): """ Used to test what names are associated with cards in the database. :return: a set of all cards in database, this needs to be added to after server startup to stay current """ if redis_conn is None: redis_conn = cls._get_redis() if not redis_conn.llen('_inserted'): log.debug('reupdating the list of inserted names') cls.update_all_inserted_names(redis_conn) return [name.decode('utf8') for name in (redis_conn.lrange('_inserted', 0, -1) or [])]
def _get_monocolor_cards(self, multicolor_cards, colorless_cards, pretend): """ :param multicolor_cards: what constitutes a mono-colored card is based on what is not a multicolor card """ if pretend: return [] cube_cards = Card.objects.filter(cube=self.cube) log.debug('all cube cards: {}', cube_cards) log.debug('multicolor cards: {}', multicolor_cards) not_multicolor_cards = cube_cards.exclude(name__in=multicolor_cards.values('name')) log.debug('not multicolor cards: {}', not_multicolor_cards) monocolor_cards = not_multicolor_cards.exclude(name__in=colorless_cards.values('name')) log.debug('monocolor cards: {}', monocolor_cards) return monocolor_cards
def _get_colorless_cards(self, multicolor_cards, pretend=False): if pretend: return [] log.debug("looking for colorless cards") cube_cards = Card.objects.filter(cube=self.cube) not_mc_cards = cube_cards.exclude(name__in=multicolor_cards.values('name')) log.debug("not multicolor: {}", not_mc_cards) colorless_cards = not_mc_cards.filter(Q(mana_cost__contains="Land")| (Q(_standard_mana_bitfield=0)& Q(_hybrid_mana_bitfield=0)& Q(_mono_hybrid_mana_bitfield=0)& Q(_phyrexian_mana_bitfield=0)) ) log.debug("colorless: {}", colorless_cards) return colorless_cards
def insert_cards(names, redis_conn, post_insert_hook=None): """ Search gather for cards with the given name, insert that information into the database. This doesn't check for existing cards that have that name, and the act of inserting them :param names: the names of the cards to insert :param redis_conn: used to cache information about the cards :param post_insert_hook: this callable will be invoked with the card that was just inserted :return: if names were provided: { 'inserted': cards_to_insert, 'refetched': refetched_cards, 'mismatches': relevant_mismatches, 'invalid': invalid_names, } else, empty dict """ if not names: return {} invalid_names = [] refetched_names = [] inserted_cards = [] relevant_mismatches = {} content_map = {} unique_names = Counter(names) duplicate_inserts = [] inserted_names = Card.get_all_inserted_names() if post_insert_hook is None: post_insert_hook = lambda c: log.debug('inserted: {.name}', c) for name in unique_names: try: card_content = get_json_card_content(name) except CardFetchingError: invalid_names.append(name) log.debug('problem fetching card with name: %r', name) continue fetched_name = card_content['name'] if name != fetched_name: Card.add_new_mismatches({name: fetched_name}, redis_conn) relevant_mismatches[name] = fetched_name if fetched_name in inserted_names: refetched_names.append(fetched_name) continue else: # mitigation against isse #14 .e.g make a mismatch mapping # proactively to support searching with ascii names Card.add_new_mismatches({name: fetched_name}, redis_conn) if fetched_name not in content_map: content_map[fetched_name] = card_content card = Card(**card_content) try: card.save() except IntegrityError: # assume a different thread inserted it duplicate_inserts.append(card.name) card = None except: log.exception('unknown error inserting %r', card) card = None else: Card.mark_card_as_inserted(card, redis_conn) inserted_cards.append(card) finally: post_insert_hook(card) else: duplicate_inserts.append(fetched_name) refetched_cards = list(Card.objects.filter(name__in=refetched_names)) disposition = { 'inserted': inserted_cards, 'refetched': refetched_cards, 'mismatches': relevant_mismatches, 'invalid': invalid_names, } # this needs to actually account for mismatched names # if settings.DEBUG: # assertExpectatations(inserted_cards + refetched_cards + # invalid_names + duplicate_inserts, # unique_names) return disposition