def _array(typecode: str, iterable: Iterable = ()): realized_type = realize(typecode) bounds = INT_TYPE_BOUNDS.get(typecode) if bounds: args = [check_int(x, *bounds) for x in iterable] return SymbolicArray(realized_type, args) return array(realized_type, realize(iterable))
def make_date(p: Callable) -> datetime.date: year, month, day = p(int), p(int), p(int) # This condition isn't technically required, but it develops useful # symbolic inequalities before the realization below: if not (1 <= year <= 9999 and 1 <= month <= 12 and 1 <= day <= 31): raise IgnoreAttempt('Invalid date') try: return datetime.date(realize(year), realize(month), realize(day)) except ValueError: raise IgnoreAttempt('Invalid date')
def _fullmatch(self, string, pos=0, endpos=None): if type(string) is SymbolicStr: try: return _match_pattern(self, self.pattern + r"\Z", string, pos, endpos) except ReUnhandled as e: debug("Unable to symbolically analyze regular expression:", self.pattern, e) if endpos is None: return _orig_fullmatch(self, realize(string), pos) else: return _orig_fullmatch(self, realize(string), pos, endpos)
def make_timedelta(p: Callable) -> datetime.timedelta: microseconds, seconds, days = p(int), p(int), p(int) # the normalized ranges, per the docs: if not (0 <= microseconds < 1000000 and 0 <= seconds < 3600 * 24 and -999999999 <= days <= 999999999): raise IgnoreAttempt('Invalid timedelta') try: return datetime.timedelta(days=realize(days), seconds=realize(seconds), microseconds=realize(microseconds)) except OverflowError: raise IgnoreAttempt('Invalid timedelta')
def _realize_args(self, args): newargs = [] for arg in args: if isinstance(arg, self.__class__): newargs.append(arg.__array__()) else: # Call realize() for operations on symbolic floats, etc: newargs.append(realize(arg)) return newargs
def __init__(self, creator: SymbolicFactory): # Our callback gets a SymbolicFactory instance which can produce more # symbolic values when called with a type. self.shape = creator(Tuple[int, ...], "_shape") # Note that we avoid the builtin len() - symbolic creation hooks do not run # under the monkeypatched environment, and calling the real len() would # realize the shape's length. self.ndim = self.shape.__len__() self.dtype = np.dtype(realize(creator(Type[np.number], "_dtype")))
def make_timezone(p: Any) -> datetime.timezone: if p.space.smt_fork(): delta = p(datetime.timedelta, "_offset") if _min_tz_offset < delta < _max_tz_offset: return datetime.timezone(delta, realize(p(str, "_name"))) else: raise IgnoreAttempt("Invalid timezone offset") else: return datetime.timezone.utc
def make_timezone(p: Any) -> datetime.timezone: if p.space.smt_fork(desc="use explicit timezone"): delta = p(datetime.timedelta, "_offset") with ResumedTracing(): if _min_tz_offset < delta < _max_tz_offset: return datetime.timezone(delta, realize(p(str, "_name"))) else: raise IgnoreAttempt("Invalid timezone offset") else: return datetime.timezone.utc
def __array__(self): if any(size < 0 for size in self.shape): raise IgnoreAttempt('ndarray disallows negative dimensions') concrete_shape = tuple(map(int, self.shape)) concrete_dtype = realize(self.dtype) # For the contents, we just construct it with ones. This makes it much # less complete in terms of finding counterexamples, but is sufficient # for array dimension and type reasoning. If we were more ambitious, # we would rewrite a (slow) implementation of numpy in terms of native # Python types. return np.ones(concrete_shape, concrete_dtype)
def __init__(self, creator: Callable): # Our callback gets a `creator` constructor which can produce more # symbolic values when given a type. self.shape = creator(Tuple[int, ...]) self.ndim = len(self.shape) self.dtype = np.dtype(realize(creator(Type[np.number])))
def __ch_realize__(self): self._groups = [(name, realize(start), realize(end)) for name, start, enf in self._groups]