一个类似xml的文档,包含用于值和底层持久数据结构的电子表格公式
persistent-doc的Python项目详细描述
persistent_doc-一个类似xml的文档,包含用于值和底层持久数据结构的电子表格公式
安装
克隆此存储库,然后
pip install -r requirements.txt
示例用法
>>> from persistent_doc.document import Document, FrozenNode as Node, Ex
>>> root = Node("foo", params={"id": "one"})
>>> doc = Document(root)
>>> doc['one'].append(Node("bar", params={"id": "two"}))
>>> doc['one.0']
bar(id=two)[]
>>> doc['one.x'] = 3
>>> doc['one']['x']
3
>>> doc['two.x'] = Ex("`one.x + 3")
>>> doc['two.x']
6
>>> doc['one.x'] += 1
>>> doc['two.x']
7
相对路径、较长的引用链和撤消重做的示例
>>> doc['two.y'] = Ex("`two.parent.x + `two.x")
>>> doc['two.y']
11
>>> doc['one.x'] += 1
>>> doc['two.y']
13
>>> doc.undo()
>>> doc.undo()
>>> doc.undo()
>>> doc.undo()
>>> doc['one.x'], doc['two.y']
(4, 11)
>>> doc.start_group("one_step")
True
>>> doc['one.x'] += 1
>>> doc.end_group("one_step")
>>> doc['one.x'], doc['two.y']
(5, 13)
>>> doc.undo()
>>> doc['one.x'], doc['two.y']
(4, 11)
>>> doc.redo()
>>> doc['one.x'], doc['two.y']
(5, 13)
文档模型
与XML一样,文档也是一棵树,每个节点都有一个子节点列表和参数的键值对。与svg一样,每个节点在文档中都有一个唯一的id
属性。
参数值可以是“公式”,将其他节点的id作为变量(以及父节点、子节点和参数键的相对路径)。
文档是persistent以允许在占用太多内存的情况下轻松撤消重做。持久性意味着对象的突变总是创建一个新版本,但新版本与旧版本共享内存。(它可能允许擦除历史记录以节省更多内存。)
而底层数据结构是不可变的,但具有与可变对象相同的接口。
公式语法
语法将来可能会改变。若要将公式设置为值,请使用要求值的字符串(在此语法中)创建一个ex对象。
- node id:
`foo
计算文档中id为foo
的节点。 - 参数键:
`foo.bar
计算为文档中节点foo
的参数bar
的值。`foo.bar.baz
如果foo.bar
是节点,则工作正常。 - children和parents:
`foo[1]
和`foo.1
都计算为索引1处(具有id的节点)foo
的子节点(即第二个子节点)。`foo.1.0
是foo
的第二个孩子的第一个孩子。`foo.parent
是foo
的父级。 - 函数调用和操作:函数调用
foo(`bar, 3 + `baz)
在python中工作。
如果doc
是persistent_doc.document.Document
,则doc['foo.parent.3.2']
给出foo
父的第四个子的第二个子。函数调用和操作不能与Document.__getitem__
一起使用(相反,在python f(doc['foo.p1'], doc['bar.p1'])
中在外部使用它们)。
公式重新计算
有三种重新评估策略
- 缓存(默认值):当公式依赖于更改时,将重新计算公式。结果被缓存以供读取。
- reeval:每次读取公式时都会对其进行重新计算。
- 首次读取时:在公式所依赖的某个术语更改后,在第一次读取公式时对其进行重新计算。结果被缓存以供读取。
calc
参数传递给Ex
以指示要使用哪个参数。例如Ex(`foo + 3, calc="reeval")
。因此,有可能有一份包含混合重新评估策略的文件。
expr对象
要获取公式的对象而不是其值,请使用doc.get_expr('foo.bar')
,而不是doc['foo.bar']
。
错误和调试
计算时产生错误的表达式将返回EvalError
对象,而不是引发错误。
测试
运行python test.py
。
指针
由于文档是持久的,指向文档中值的指针可能会过时。使用doc.m
或node.L
(而不是doc
和node
)来使用最新版本。
内部构件
默认文档
因为父子关系被编码为查找,不可能在空隙中创建节点的新子树,然后将其绑定到现有节点。它至少需要一个doc(内存)来创建。所以default_doc
有助于这一部分。
如果只有一个文档,persistent_doc.document.default_doc
应该设置为该文档。
惯例
父项设置子项的.parent
。
纽比
numpy
并不是一个真正的需求,但是由于numpy
1.13,等式测试的行为不同,一些多态性在其他情况下不起作用。document.py
包含equal
的另一个定义,如果没有numpy,可以使用这个定义数组作为值。
可变值
可变值应不进行变异。它们应该被替换。
doc['foo.arr'] = numpy.array([1, 2])
doc['foo.arr'] = doc['foo.arr'] + numpy.array([1, 1])
而不是
arr = numpy.array([1, 2])
doc['foo.arr'] = arr
arr += numpy.array([1, 1])
待办事项
- 找到比所有使用
Ex
和Expr
的显式类型检查更好的方法。 - 找到一种方法,在执行操作之前自动决定是否需要将节点替换为其最新版本。也许通过比较时间戳?