mirror of https://github.com/python/cpython
61 lines
1.8 KiB
Python
61 lines
1.8 KiB
Python
import itertools
|
|
|
|
|
|
class PseudoStr(str):
|
|
pass
|
|
|
|
|
|
class StrProxy:
|
|
def __init__(self, value):
|
|
self.value = value
|
|
def __str__(self):
|
|
return self.value
|
|
def __bool__(self):
|
|
return bool(self.value)
|
|
|
|
|
|
class Object:
|
|
def __repr__(self):
|
|
return '<object>'
|
|
|
|
|
|
def wrapped_arg_combos(*args,
|
|
wrappers=(PseudoStr, StrProxy),
|
|
skip=(lambda w, i, v: not isinstance(v, str)),
|
|
):
|
|
"""Yield every possible combination of wrapped items for the given args.
|
|
|
|
Effectively, the wrappers are applied to the args according to the
|
|
powerset of the args indicies. So the result includes the args
|
|
completely unwrapped.
|
|
|
|
If "skip" is supplied (default is to skip all non-str values) and
|
|
it returns True for a given arg index/value then that arg will
|
|
remain unwrapped,
|
|
|
|
Only unique results are returned. If an arg was skipped for one
|
|
of the combinations then it could end up matching one of the other
|
|
combinations. In that case only one of them will be yielded.
|
|
"""
|
|
if not args:
|
|
return
|
|
indices = list(range(len(args)))
|
|
# The powerset (from recipe in the itertools docs).
|
|
combos = itertools.chain.from_iterable(itertools.combinations(indices, r)
|
|
for r in range(len(indices)+1))
|
|
seen = set()
|
|
for combo in combos:
|
|
for wrap in wrappers:
|
|
indexes = []
|
|
applied = list(args)
|
|
for i in combo:
|
|
arg = args[i]
|
|
if skip and skip(wrap, i, arg):
|
|
continue
|
|
indexes.append(i)
|
|
applied[i] = wrap(arg)
|
|
key = (wrap, tuple(indexes))
|
|
if key not in seen:
|
|
yield tuple(applied)
|
|
seen.add(key)
|