Source code for pyorg.io

"""Read (and write) org mode data from JSON and other formats."""

from .ast import OrgDocument, OrgNode, OrgDataNode, NODE_CLASSES, OrgTimestamp
from .util import TreeNamespace, parse_iso_date


JSON_OBJ_DATA_TYPE_KEY = '$$data_type'


def _node_from_json(data, ctx, recurse_contents=True):
	type_ = data['type']
	ref = data['ref']

	# Parse child nodes first
	props = _mapping_from_json(data['properties'], ctx)
	if recurse_contents:
		contents = _list_from_json(data['contents'], ctx)
	else:
		contents = []

	keywords = _mapping_from_json(data.get('keywords', {}), ctx)

	cls = NODE_CLASSES.get(type_, OrgNode)
	node = cls(type_, properties=props, contents=contents, keywords=keywords, ref=ref)

	return node


def _from_json(data, ctx):
	if isinstance(data, list):
		return _list_from_json(data, ctx)

	if isinstance(data, dict):
		data = dict(data)
		datatype = data.pop(JSON_OBJ_DATA_TYPE_KEY, 'mapping')

		if datatype == 'org-node':
			return _node_from_json(data, ctx)

		if datatype == 'mapping':
			return _mapping_from_json(data, ctx)

		if datatype == 'error':
			ctx.errors.append((ctx._path, data['message']))
			print('Parse error:', data['message'])
			return None

		if datatype == 'timestamp':
			return _timestamp_from_json(data, ctx)

		ctx.errors.append((ctx._path, 'Unknown data type in JSON export : %r' % datatype))
		return None

	if isinstance(data, (type(None), bool, int, float, str)):
		return data

	raise TypeError(type(data))


def _list_from_json(data, ctx):
	return [
		_from_json(c, ctx._push(i))
		for (i, c) in enumerate(data)
	]


def _mapping_from_json(data, ctx):
	return {
		k: _from_json(v, ctx._push(k))
		for k, v in data.items() if k != JSON_OBJ_DATA_TYPE_KEY
	}


def _timestamp_from_json(data, ctx):
	return OrgTimestamp(
		data['type'],
		start=None if data.get('start') is None else parse_iso_date(data['start']),
		end=None if data.get('end') is None else parse_iso_date(data['end']),
	)


def _init_ctx(data):
	return TreeNamespace(data=data, errors=[])


[docs]def org_doc_from_json(data): """Parse an ORG document from exported JSON data. Returns ------- OrgDocument """ data = dict(data) data_type = data.pop(JSON_OBJ_DATA_TYPE_KEY, None) if data_type is not None and data_type != 'org-document': raise ValueError('Expected data type "org-document", got %r' % data_type) ctx = _init_ctx(data) contents = _list_from_json(data['contents'], ctx) root = OrgDataNode('org-data', contents=contents) doc = OrgDocument(root, properties=data['properties']) if ctx.errors: doc.meta['export_errors'] = ctx.errors return doc
[docs]def org_node_from_json(data): """Parse an org AST node from JSON data. Returns ------- .OrgNode """ ctx = _init_ctx(data) node = _node_from_json(data, ctx) if ctx.errors: node.meta['export_errors'] = ctx.errors return node