Source code for stencila.value

import base64
import json
from io import BytesIO
from collections import OrderedDict

import matplotlib
import numpy
import pandas


[docs]def type(value): """ Get the type code for a value :param value: A Python value :returns: Type code for value """ type_ = __builtins__['type'](value).__name__ if value is None: return 'null' elif type_ == 'bool': return 'boolean' elif type_ == 'int': return 'integer' elif type_ == 'float': return 'float' elif type_ == 'str': return 'string' elif ( isinstance(value, (matplotlib.figure.Figure, matplotlib.artist.Artist)) or (type_ == 'list' and len(value) == 1 and isinstance(value[0], matplotlib.artist.Artist)) ): # Use the special 'matplotlib' type to identify plot values that need # to be converted to the standard 'image' type during `pack()` return 'matplotlib' elif type_ in ('tuple', 'list'): return 'array' elif type_ == 'dict': type_ = value.get('type') if type_ and isinstance(type_, str): return type_ return 'object' elif isinstance(value, pandas.DataFrame): return 'table' else: raise RuntimeError('Unable to pack object\n type: ' + type_)
[docs]def pack(value): """ Pack an object into a value package :param value: A Python value :returns: A value package """ type_ = type(value) format_ = 'text' if value is None: content = 'null' elif type_ == 'boolean': content = 'true' if value else 'false' elif type_ in ('integer', 'float'): content = repr(value) elif type_ == 'string': content = value elif type_ in ('array', 'object'): format_ = 'json' content = json.dumps(value, separators=(',', ':')) elif type_ == 'table': format_ = 'json' columns = OrderedDict() for column in value.columns: col = value[column] # See the list of numpy data types at # https://docs.scipy.org/doc/numpy/reference/arrays.scalars.html#arrays-scalars-built-in values = list(col) if col.dtype in (numpy.bool_, numpy.bool8): column_type = 'boolean' values = [bool(row) for row in values] elif col.dtype in (numpy.int8, numpy.int16, numpy.int32, numpy.int64): column_type = 'integer' values = [int(row) for row in values] elif col.dtype in (numpy.float16, numpy.float32, numpy.float64): column_type = 'float' values = [float(row) for row in values] elif col.dtype in (numpy.str_, numpy.unicode_,): column_type = 'string' elif col.dtype == numpy.object and len(values) > 0: # Get the type from the type of the first value column_type = { str: 'string' }.get(__builtins__['type'](values[0])) else: column_type = col.dtype.name columns[column] = OrderedDict([ ('type', column_type), ('values', values) ]) content = json.dumps(OrderedDict([('type', 'table'), ('data', columns)])) elif type_ == 'matplotlib': image = BytesIO() matplotlib.pyplot.savefig(image, format='png') type_ = 'image' format_ = 'src' content = 'data:image/png;base64,' + base64.encodestring(image.getvalue()).decode() else: raise RuntimeError('Unable to pack object\n type: ' + type_) return {'type': type_, 'format': format_, 'content': content}
[docs]def unpack(pkg): """ Unpack a value package into a Python value :param pkg: The value package :returns: A Python value """ if isinstance(pkg, str): pkg = json.loads(pkg) if not isinstance(pkg, dict): raise RuntimeError('Package should be an `Object`') if not ('type' in pkg and 'format' in pkg and 'content' in pkg): raise RuntimeError('Package should have fields `type`, `format`, `content`') type_ = pkg['type'] format = pkg['format'] content = pkg['content'] if type_ == 'null': return None elif type_ == 'boolean': return content == 'true' elif type_ == 'integer': return int(content) elif type_ == 'float': return float(content) elif type_ == 'string': return content elif type_ == 'object' or type_ == 'array': return json.loads(content) elif type_ == 'table': if format == 'json': table = json.loads(content, object_pairs_hook=OrderedDict) df = pandas.DataFrame() for name, column in table['data'].items(): df[name] = column['values'] return df elif format in ('csv', 'tsv'): sep = ',' if format == 'csv' else '\t' return pandas.read_csv(BytesIO(content.encode()), sep=sep) else: raise RuntimeError('Unable to unpack\n type: ' + type_ + '\n format: ' + format) else: raise RuntimeError('Unable to unpack\n type: ' + type_ + '\n format: ' + format)