def encode_as_pil(obj): """Attempt to convert PIL.Image.Image to base64 data uri""" image = get_module("PIL.Image") if image is not None and isinstance(obj, image.Image): return ImageUriValidator.pil_image_to_uri(obj) else: raise NotEncodable
def clean_to_json_compatible(obj, **kwargs): # Try handling value as a scalar value that we have a conversion for. # Return immediately if we know we've hit a primitive value # Bail out fast for simple scalar types if isinstance(obj, (int, float, string_types)): return obj if isinstance(obj, dict): return {str(k): clean_to_json_compatible(v, **kwargs) for k, v in obj.items()} elif isinstance(obj, (list, tuple)): if obj: # Must process list recursively even though it may be slow return [clean_to_json_compatible(v, **kwargs) for v in obj] # unpack kwargs numpy_allowed = kwargs.get("numpy_allowed", False) datetime_allowed = kwargs.get("datetime_allowed", False) modules = kwargs.get("modules", {}) sage_all = modules["sage_all"] np = modules["np"] pd = modules["pd"] image = modules["image"] # Sage if sage_all is not None: if obj in sage_all.RR: return float(obj) elif obj in sage_all.ZZ: return int(obj) # numpy if np is not None: if obj is np.ma.core.masked: return float("nan") elif isinstance(obj, np.ndarray): if numpy_allowed and obj.dtype.kind in ("b", "i", "u", "f"): return np.ascontiguousarray(obj) elif obj.dtype.kind == "M": # datetime64 array return np.datetime_as_string(obj).tolist() elif obj.dtype.kind == "U": return obj.tolist() elif obj.dtype.kind == "O": # Treat object array as a lists, continue processing obj = obj.tolist() elif isinstance(obj, np.datetime64): return str(obj) # pandas if pd is not None: if obj is pd.NaT: return None elif isinstance(obj, (pd.Series, pd.DatetimeIndex)): if numpy_allowed and obj.dtype.kind in ("b", "i", "u", "f"): return np.ascontiguousarray(obj.values) elif obj.dtype.kind == "M": if isinstance(obj, pd.Series): dt_values = obj.dt.to_pydatetime().tolist() else: # DatetimeIndex dt_values = obj.to_pydatetime().tolist() if not datetime_allowed: # Note: We don't need to handle dropping timezones here because # numpy's datetime64 doesn't support them and pandas's tz_localize # above drops them. for i in range(len(dt_values)): dt_values[i] = dt_values[i].isoformat() return dt_values # datetime and date try: # Need to drop timezone for scalar datetimes. Don't need to convert # to string since engine can do that obj = obj.to_pydatetime() except (TypeError, AttributeError): pass if not datetime_allowed: try: return obj.isoformat() except (TypeError, AttributeError): pass elif isinstance(obj, datetime.datetime): return obj # Try .tolist() convertible, do not recurse inside try: return obj.tolist() except AttributeError: pass # Do best we can with decimal if isinstance(obj, decimal.Decimal): return float(obj) # PIL if image is not None and isinstance(obj, image.Image): return ImageUriValidator.pil_image_to_uri(obj) # Plotly try: obj = obj.to_plotly_json() except AttributeError: pass # Recurse into lists and dictionaries if isinstance(obj, dict): return {k: clean_to_json_compatible(v, **kwargs) for k, v in obj.items()} elif isinstance(obj, (list, tuple)): if obj: # Must process list recursively even though it may be slow return [clean_to_json_compatible(v, **kwargs) for v in obj] return obj