(e-mail address removed) a écrit :
Looks like an option parser... If so, there's all you need in the
standard lib (look for the optparse module).
First : use boolean logic (truth table, Kernaugh diagram, etc) to
simplify things. As an example, rule #3 is useless - it's a subset of
rule #1 (-A and -B and -D implies -A and -B). This should greatly reduce
the number of needed tests.
Good idea, but doesn't scale well. Simple code can weed out redundant
rules, including any accidental duplicates that may creep into a long
list. See code listing at end.
Then, write a simple rule system describing either valid inputs or
invalid inputs (preferably the smallest set !-). FWIW, it can be as
simple as a list of lambdas/error messages pairs, with lambdas being
predicate taking dict keys as params:
_RULES = [
(lambda keys : '-A' in keys and '-B' in keys,
"can't have both options -A and -B"),
(lambda keys : '-A' in keys and '-C' in keys,
"can't have both options -A and -C"),
# etc...
]
The evil HR director won't let the PHB pay me on a per LOC basis, so
I've had to come up with a compact table-driven approach
def validate(options, rules):
keys = options.keys()
for predicate, message in rules:
if not predicate(keys):
raise ValueError(message)
Cheers,
John
C:\junk>type option_combos.py
bad_combos = ['ABD', 'AC', 'AB', 'CA']
def rule_compaction(bc_list, verbose=False):
# The next few lines are admittedly oldfashioned
bc_sets = [set(x) for x in bc_list]
deco = [(len(y), y) for y in bc_sets]
deco.sort()
bc_sets = [z[1] for z in deco]
del deco
if verbose:
print "bc_sets #1:", bc_sets
for k in xrange(len(bc_sets)-1, 0, -1):
candidate = bc_sets[k]
for ko in bc_sets[:k]:
if ko <= candidate:
if verbose:
print candidate, "knocked out by", ko
del bc_sets[k]
break
if verbose:
print "bc_sets #2:", bc_sets
return bc_sets
option_rules = rule_compaction(bad_combos, verbose=True)
def combo_disallowed_by(opt_set, rules):
for rule in rules:
if opt_set >= rule:
return rule
return None # redundantly, for emphasis
if __name__ == "__main__":
import sys
for opt_string in sys.argv[1:]:
failer = combo_disallowed_by(set(opt_string), option_rules)
if failer:
print repr(opt_string), "disallowed by", failer
else:
print repr(opt_string), "is OK"
=== a test ===
C:\junk>option_combos.py A AB AC AD BC ABD ABX XBA BX
bc_sets #1: [set(['A', 'C']), set(['A', 'B']), set(['A', 'C']),
set(['A', 'B', 'D'])]
set(['A', 'B', 'D']) knocked out by set(['A', 'B'])
set(['A', 'C']) knocked out by set(['A', 'C'])
bc_sets #2: [set(['A', 'C']), set(['A', 'B'])]
'A' is OK
'AB' disallowed by set(['A', 'B'])
'AC' disallowed by set(['A', 'C'])
'AD' is OK
'BC' is OK
'ABD' disallowed by set(['A', 'B'])
'ABX' disallowed by set(['A', 'B'])
'XBA' disallowed by set(['A', 'B'])
'BX' is OK
=== the end ===