def convert(default_v, v): if isinstance(default_v, RequiredOption): if v is None and not default_v.none_ok: raise OptionException('Option %s on method %s requires a non-None value (%r)' % (k, method, default_v.value,)) default_v = default_v.value if default_v is None or v is None: if isinstance(default_v, _OptionString): raise OptionException('Option %s on method %s requires a non-empty string value' % (k, method,)) if hasattr(default_v, '_valid') and v not in default_v._valid: raise OptionException('Option %s on method %s requires a value in %s' % (k, method, default_v._valid,)) if isinstance(default_v, OptionDefault): v = default_v.default return v if isinstance(default_v, OptionDefault): default_v = default_v.value if isinstance(default_v, dict) and isinstance(v, dict): if default_v: sample_v = first_value(default_v) for chk_v in itervalues(default_v): assert isinstance(chk_v, type(sample_v)) return {k: convert(sample_v, v) for k, v in iteritems(v)} else: return v if isinstance(default_v, (list, set, tuple,)) and isinstance(v, str_types + (list, set, tuple,)): if isinstance(v, str_types): v = (e.strip() for e in v.split(',')) if default_v: sample_v = first_value(default_v) for chk_v in default_v: assert isinstance(chk_v, type(sample_v)) v = (convert(sample_v, e) for e in v) return type(default_v)(v) if isinstance(default_v, (OptionEnum, OptionEnumValue,)): if not (v or None) in default_v._valid: ok = False for cand_prefix in default_v._prefixes: if v.startswith(cand_prefix): ok = True break if not ok: raise OptionException('%r not a permitted value for option %s on method %s (%s)' % (v, k, method, default_v._valid)) return v or None if isinstance(default_v, str_types + num_types) and isinstance(v, str_types + num_types): if isinstance(default_v, _OptionString): v = str(v) if not v: raise OptionException('Option %s on method %s requires a non-empty string value' % (k, method,)) return v if isinstance(default_v, unicode) and isinstance(v, bytes): return v.decode('utf-8') return type(default_v)(v) if (isinstance(default_v, type) and isinstance(v, typefuzz(default_v))) or isinstance(v, typefuzz(type(default_v))): return v if isinstance(default_v, bool) and isinstance(v, (str, int)): lv = str(v).lower() if lv in ('true', '1', 't', 'yes', 'on',): return True if lv in ('false', '0', 'f', 'no', 'off', '',): return False if isinstance(default_v, _date_types): default_v = type(default_v) if default_v in _date_types: try: return typing_conv[default_v.__name__](v) except Exception: raise OptionException('Failed to convert option %s %r to %s on method %s' % (k, v, default_v, method,)) if isinstance(v, str_types) and not v: return type(default_v)() if isinstance(default_v, JobWithFile) or default_v is JobWithFile: defaults = ('', '', False, None,) if default_v is JobWithFile: default_v = defaults if not isinstance(v, (list, tuple,)) or not (2 <= len(v) <= 4): raise OptionException('Option %s (%r) on method %s is not %s compatible' % (k, v, method, type(default_v))) v = tuple(v) + defaults[len(v):] # so all of default_v gets convert()ed. v = [convert(dv, vv) for dv, vv in zip(default_v, v)] return JobWithFile(*v) raise OptionException('Failed to convert option %s of %s to %s on method %s' % (k, type(v), type(default_v), method,))
class OptionDefault(object): """Default selection for complexly typed options. foo={'bar': OptionEnum(...)} is a mandatory option. foo=OptionDefault({'bar': OptionEnum(...)}) isn't. (Default None unless specified.) """ def __init__(self, value, default=None): self.value = value self.default = default typing_conv = dict( set=set, JobWithFile=lambda a: JobWithFile(*a), datetime=lambda a: datetime.datetime(*a), date=lambda a: datetime.date(*a[:3]), time=lambda a: datetime.time(*a[3:]), timedelta=lambda a: datetime.timedelta(seconds=a), ) def _mklist(t): def make(lst): return [t(e) for e in lst] return make def _apply_typing(options, tl):