Add only-type-any and only-type-all options (#241)

* Added only-type options
* added ci test for only-type options
This commit is contained in:
Wendel Voigt 2019-02-17 22:41:58 -06:00 committed by Peter
parent a796dc59bd
commit 088c3b633d
2 changed files with 140 additions and 10 deletions

View File

@ -27,12 +27,6 @@ LINE_CHOICES = ["line", "dot", "cropmarks", "dot-cropmarks"]
EDITION_CHOICES = ["1", "2", "latest", "all"]
EXPANSION_CHOICES = ["adventures", "alchemy", "base", "cornucopia", "dark ages",
"dominion1stEdition", "dominion2ndEdition", "dominion2ndEditionUpgrade",
"empires", "guilds", "hinterlands",
"intrigue1stEdition", "intrigue2ndEdition", "intrigue2ndEditionUpgrade",
"promo", "prosperity", "renaissance", "seaside", "nocturne"]
FAN_CHOICES = ["animals"]
ORDER_CHOICES = ["expansion", "global", "colour", "cost"]
LANGUAGE_DEFAULT = 'en_us' # the primary language used if a language's parts are missing
@ -63,6 +57,46 @@ def get_resource_stream(path):
return codecs.EncodedFile(pkg_resources.resource_stream('domdiv', path), "utf-8")
def get_expansions():
set_db_filepath = os.path.join("card_db", "sets_db.json")
with get_resource_stream(set_db_filepath) as setfile:
set_file = json.loads(setfile.read().decode('utf-8'))
assert set_file, "Could not load any sets from database"
fan = []
official = []
for s in set_file:
if 'extras' not in s:
# Make sure this are set either True or False
set_file[s]['fan'] = set_file[s].get('fan', False)
if set_file[s]['fan']:
fan.append(s)
else:
official.append(s)
fan.sort()
official.sort()
return official, fan
EXPANSION_CHOICES, FAN_CHOICES = get_expansions()
def get_types(language='en_us'):
# get a list of valid types
language = language.lower()
type_text_filepath = os.path.join("card_db", language, "types_{}.json".format(language))
with get_resource_stream(type_text_filepath) as type_text_file:
type_text = json.loads(type_text_file.read().decode('utf-8'))
assert type_text, "Could not load type file for %r" % language
types = [x.lower() for x in type_text]
types.sort()
return types
TYPE_CHOICES = get_types(LANGUAGE_DEFAULT)
# Load Label information
LABEL_INFO = None
LABEL_CHOICES = []
@ -301,8 +335,7 @@ def parse_opts(cmdline_args=None):
"'*' any number of characters, '?' matches any single character, "
"'[seq]' matches any character in seq, and '[!seq]' matches any character not in seq. "
"For example, 'dominion*' will match all expansions that start with 'dominion'. "
"Choices available in all languages include: %s" %
", ".join("%s" % x for x in EXPANSION_CHOICES))
"Choices available in all languages include: {}".format(", ".join("%s" % x for x in EXPANSION_CHOICES)))
group_select.add_argument(
"--fan",
nargs="*",
@ -316,8 +349,7 @@ def parse_opts(cmdline_args=None):
"Values are not case sensitive. Wildcards may be used: "
"'*' any number of characters, '?' matches any single character, "
"'[seq]' matches any character in seq, and '[!seq]' matches any character not in seq. "
"Choices available in all languages include: %s" %
", ".join("%s" % x for x in FAN_CHOICES))
"Choices available in all languages include: {}".format(", ".join("%s" % x for x in FAN_CHOICES)))
group_select.add_argument(
"--edition",
choices=EDITION_CHOICES,
@ -373,6 +405,27 @@ def parse_opts(cmdline_args=None):
"--exclude-landmarks",
action="store_true",
help="Group all 'Landmark' cards across all expansions into one divider.")
group_select.add_argument(
"--only-type-any", "--only-type", "--type-any",
nargs="*",
action="append",
dest="only_type_any",
help="Limit dividers to only those with the specified types. "
"A divider is kept if ANY of the provided types are associated with the divider. "
"Default is all types are included. "
"Any type with a space in the name must be enclosed in double quotes. "
"Values are not case sensitive. "
"Choices available in all languages include: {}".format(", ".join("%s" % x for x in TYPE_CHOICES)))
group_select.add_argument(
"--only-type-all", "--type-all",
nargs="*",
action="append",
dest="only_type_all",
help="Limit dividers to only those with the specified types. "
"A divider is kept if ALL of the provided types are associated with the divider. "
"Any type with a space in the name must be enclosed in double quotes. "
"Values are not case sensitive. "
"Choices available in all languages include: {}".format(", ".join("%s" % x for x in TYPE_CHOICES)))
# Divider Sleeves/Wrappers
group_wrapper = parser.add_argument_group(
@ -633,6 +686,20 @@ def clean_opts(options):
# keyword to indicate no options. Same as --fan without any expansions given
options.fan = []
if options.only_type_any is None:
# No instance given, so default to empty list
options.only_type_any = []
else:
# options.only_type_any is a list of lists. Reduce to single lowercase list
options.only_type_any = list(set([item.lower() for sublist in options.only_type_any for item in sublist]))
if options.only_type_all is None:
# No instance given, so default to empty list
options.only_type_all = []
else:
# options.only_type_any is a list of lists. Reduce to single lowercase list
options.only_type_all = list(set([item.lower() for sublist in options.only_type_all for item in sublist]))
if options.tabs_only and options.label_name is None:
# default is Avery 8867
options.label_name = "8867"
@ -1359,6 +1426,53 @@ def filter_sort_cards(cards, options):
card_tag=set_tag)
cards.append(c)
# Take care of any --only-type-xxx requirements
if options.only_type_any or options.only_type_all:
# First make a dictionary for easier lookup of Type name used by the program
# The index in each case is lower case for easier matching
# The value in each case is the type index as used in types_en_us.json
types_lookup = defaultdict(dict)
for x in Card.type_names:
types_lookup[x.lower()] = x
types_lookup[Card.type_names[x].lower()] = x
# Start the valid lists
type_unknown = []
type_known_any = []
type_known_all = []
# Assemble a list of valid "any" types. Options are already lowercase.
for x in options.only_type_any:
if x in types_lookup:
type_known_any.append(types_lookup[x])
else:
type_unknown.append(x)
# Assemble a list of valid "all" types. Options are already lowercase.
for x in options.only_type_all:
if x in types_lookup:
type_known_all.append(types_lookup[x])
else:
type_unknown.append(x)
# Indicate if unknown types are given
assert not type_unknown, "Error - unknown type(s): {}".format(", ".join(type_unknown))
# If there are any valid Types left, go through the cards and keep cards that match
if type_known_any or type_known_all:
keep_cards = []
for c in cards:
if type_known_any and any(x in c.types for x in type_known_any):
keep_it = True
elif type_known_all and all(x in c.types for x in type_known_all):
keep_it = True
else:
keep_it = False
if keep_it:
keep_cards.append(c)
cards = keep_cards
# Now sort what is left
cards.sort(key=cardSorter)

View File

@ -111,3 +111,19 @@ def test_languagetool_run(pytestconfig):
except subprocess.CalledProcessError as e:
assert e.output == ''
assert out.decode('utf-8') == ''
def test_only_type():
options = main.parse_opts(['--expansions', 'base', 'alchemy',
'--include-blanks', '5',
'--only-type-any', 'blank', 'curse',
'--only-type-all', 'attack', 'action'])
options = main.clean_opts(options)
options.data_path = '.'
cards = main.read_card_data(options)
cards = main.filter_sort_cards(cards, options)
# Total 8 from
# Blank: +5 added in options
# Curse: +1 from base
# Action Attack: +2 from Alchemy
assert len(cards) == 8