{ "info": { "author": "asrp", "author_email": "asrp@email.com", "bugtrack_url": null, "classifiers": [], "description": "# persistent_doc - An XML-like document with spreadsheet formulas for values and underlying persistent data structures\n\n## Installing\n\nClone this repository and then\n\n pip install -r requirements.txt\n\n## Sample usage\n\n >>> from persistent_doc.document import Document, FrozenNode as Node, Ex\n >>> root = Node(\"foo\", params={\"id\": \"one\"})\n >>> doc = Document(root)\n >>> doc['one'].append(Node(\"bar\", params={\"id\": \"two\"}))\n >>> doc['one.0']\n bar(id=two)[]\n >>> doc['one.x'] = 3\n >>> doc['one']['x']\n 3\n >>> doc['two.x'] = Ex(\"`one.x + 3\")\n >>> doc['two.x']\n 6\n >>> doc['one.x'] += 1\n >>> doc['two.x']\n 7\n\nExamples of relative paths, longer reference chain and undo-redo\n\n >>> doc['two.y'] = Ex(\"`two.parent.x + `two.x\")\n >>> doc['two.y']\n 11\n >>> doc['one.x'] += 1\n >>> doc['two.y']\n 13\n >>> doc.undo()\n >>> doc.undo()\n >>> doc.undo()\n >>> doc.undo()\n >>> doc['one.x'], doc['two.y']\n (4, 11)\n >>> doc.start_group(\"one_step\")\n True\n >>> doc['one.x'] += 1\n >>> doc.end_group(\"one_step\")\n >>> doc['one.x'], doc['two.y']\n (5, 13)\n >>> doc.undo()\n >>> doc['one.x'], doc['two.y']\n (4, 11)\n >>> doc.redo()\n >>> doc['one.x'], doc['two.y']\n (5, 13)\n\n## Document model\n\nLike XML, the document is a tree where each node has a list of children and key-value pairs for parameters. Like SVG, each node has a unique `id` property within the document.\n\nParameter values can be \"formulas\" treating other nodes' id as variables (and a relative path of parent, children and parameter keys).\n\nThe document is [persistent](https://en.wikipedia.org/wiki/Persistent_data_structure) to allow easy undo-redo with spending too much memory. Persistent means that mutations to an object always creates a new version but the new version shares memory with the old version. (It could potentially allow erasing history to save more on memory.)\n\nWhile the underlying data structures are immutable but have the same interface as mutable objects.\n\n## Formula syntax\n\nSyntax may change in the future. To set a formula as value, create an Ex object with a string (in this syntax) to be evaluated.\n\n- **node id**: `` `foo`` evaluates to the node with id `foo` in the document.\n- **parameter keys**: `` `foo.bar`` evaluates to (the value of) parameter `bar` of node `foo` in the document. `` `foo.bar.baz`` works as expected if `foo.bar` is a node.\n- **children and parents**: `` `foo[1]`` and `` `foo.1`` both evaluates to the child of (the node with id) `foo` at index 1 (i.e., the second child). `` `foo.1.0`` is `foo`'s second child's first child. `` `foo.parent`` is the parent of `foo`.\n- **function calls and operations**: Function calls ``foo(`bar, 3 + `baz)`` work as in Python.\n\nIf `doc` is a `persistent_doc.document.Document`, ``doc['foo.parent.3.2']`` gives `foo`'s parent's fourth child's second child. Function calls and operations cannot be used with `Document.__getitem__` (instead use them outside, in Python ``f(doc['foo.p1'], doc['bar.p1'])``).\n\n## Formula reevaluation\n\nThere are three reevaluation strategies\n\n- **cached** *(default)*: The formula is reevaluated when a term it depends on changes. The result is cached for reads.\n- **reeval**: The formula is reevaluated every time it is read.\n- **on first read**: The formula is reevaluated the first time it is read after one of the terms it depends on has changed. The result is cached for reads.\n\nThe `calc` parameter is passed to `Ex` to indicate which one to use. For example ``Ex(`foo + 3, calc=\"reeval\")``. It is thus possible to have a document with mixed reevaluation strategies.\n\n## Expr objects\n\nTo get the object for a formula instead of its value, use `doc.get_expr('foo.bar')` instead of `doc['foo.bar']`.\n\n## Errors and debugging\n\nExpressions that produce an error when evaluated will return an `EvalError` object instead of raising an error.\n\n## Tests\n\nRun `python test.py`.\n\n## Pointers\n\nBecause the document is persistent, pointers to values in the document can become stale. Use `doc.m` or `node.L` (instead of `doc` and `node`) to use the latest version.\n\n## Internals\n\n### default_doc\n\nBecause parent-child relations are encoded as lookups, its not possible to create a new subtree of Nodes \"in the void\" and then hook it up to existing nodes. It needs at least a doc (memory) to be created. So `default_doc` helps with that part.\n\nIf there's only one document, `persistent_doc.document.default_doc` should be set to that.\n\n### Conventions\n\nParent sets the child's `.parent`.\n\n### numpy\n\n`numpy` isn't really a requirement but since `numpy` 1.13, equality test behave differently and some of the polymorphism doesn't work otherwise. `document.py` contains an alternate definition of `equal` that can be used if there are no numpy arrays as values.\n\n### mutable values\n\nMutable values are expected *not* to be mutated. They should instead be replaced.\n\n doc['foo.arr'] = numpy.array([1, 2])\n doc['foo.arr'] = doc['foo.arr'] + numpy.array([1, 1])\n\ninstead of\n\n arr = numpy.array([1, 2])\n doc['foo.arr'] = arr\n arr += numpy.array([1, 1])\n\n### Todo\n\n- Find something better than all the explicit type checking with `Ex` and `Expr`.\n- Find a way to automatically decide if a node needs to be replaced by its latest version before an operation. Maybe by comparing timestamps?\n\n\n", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/asrp/persistent_doc", "keywords": "persistent tree document formula", "license": "", "maintainer": "", "maintainer_email": "", "name": "persistent-doc", "package_url": "https://pypi.org/project/persistent-doc/", "platform": "", "project_url": "https://pypi.org/project/persistent-doc/", "project_urls": { "Homepage": "https://github.com/asrp/persistent_doc" }, "release_url": "https://pypi.org/project/persistent-doc/0.5.1/", "requires_dist": [ "pyrsistent" ], "requires_python": "", "summary": "An XML-like document with spreadsheet formulas for values and underlying persistent data structures", "version": "0.5.1" }, "last_serial": 4340543, "releases": { "0.5": [ { "comment_text": "", "digests": { "md5": "828607b8400fdb9c1a3000750a79b217", "sha256": "f841b660f4f4dfe1af8d1132d79e34fce8990c43cbe628927dfa96747996cb5b" }, "downloads": -1, "filename": "persistent_doc-0.5-py2-none-any.whl", "has_sig": false, "md5_digest": "828607b8400fdb9c1a3000750a79b217", "packagetype": "bdist_wheel", "python_version": "py2", "requires_python": null, "size": 12497, "upload_time": "2018-10-04T14:02:57", "url": "https://files.pythonhosted.org/packages/31/77/b03765f5b81c6154af6b29411bbe78bb7c3d425c3efe3601273d04d7243f/persistent_doc-0.5-py2-none-any.whl" }, { "comment_text": "", "digests": { "md5": "2e34fd2fe222744cab128ecfababa527", "sha256": "5e1eb91e93b5c137c6a734a3e28a0267f5e89c878b5b9139960548a2708d7b67" }, "downloads": -1, "filename": "persistent_doc-0.5.tar.gz", "has_sig": false, "md5_digest": "2e34fd2fe222744cab128ecfababa527", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 11313, "upload_time": "2018-10-04T14:02:58", "url": "https://files.pythonhosted.org/packages/2d/44/6476ba3d90e76fa766697d956fd5176b61cb66343441eb4ef0ad01369037/persistent_doc-0.5.tar.gz" } ], "0.5.1": [ { "comment_text": "", "digests": { "md5": "f9f9ad85509a37903cf0a8d865a0aefd", "sha256": "7bad807b34a69544366e6130d1144064464a0b11a6d6897d20c9642145723f1b" }, "downloads": -1, "filename": "persistent_doc-0.5.1-py2-none-any.whl", "has_sig": false, "md5_digest": "f9f9ad85509a37903cf0a8d865a0aefd", "packagetype": "bdist_wheel", "python_version": "py2", "requires_python": null, "size": 12529, "upload_time": "2018-10-04T14:24:14", "url": "https://files.pythonhosted.org/packages/20/99/803daa3a046425989ca0297e60f59b9cd92c4cf4e45b6522a4e2c1a2d7d6/persistent_doc-0.5.1-py2-none-any.whl" }, { "comment_text": "", "digests": { "md5": "0ce8c4af00f604817fc8c432414da1bb", "sha256": "23151ec1c9ec1198f24be01c0af692ba92c902897275b7ec11ed03a0672b3800" }, "downloads": -1, "filename": "persistent_doc-0.5.1.tar.gz", "has_sig": false, "md5_digest": "0ce8c4af00f604817fc8c432414da1bb", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 11361, "upload_time": "2018-10-04T14:24:15", "url": "https://files.pythonhosted.org/packages/e9/3f/62c40690ff6785350d67b84071acd1766cd968d0cc50ab8921c186a795c7/persistent_doc-0.5.1.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "f9f9ad85509a37903cf0a8d865a0aefd", "sha256": "7bad807b34a69544366e6130d1144064464a0b11a6d6897d20c9642145723f1b" }, "downloads": -1, "filename": "persistent_doc-0.5.1-py2-none-any.whl", "has_sig": false, "md5_digest": "f9f9ad85509a37903cf0a8d865a0aefd", "packagetype": "bdist_wheel", "python_version": "py2", "requires_python": null, "size": 12529, "upload_time": "2018-10-04T14:24:14", "url": "https://files.pythonhosted.org/packages/20/99/803daa3a046425989ca0297e60f59b9cd92c4cf4e45b6522a4e2c1a2d7d6/persistent_doc-0.5.1-py2-none-any.whl" }, { "comment_text": "", "digests": { "md5": "0ce8c4af00f604817fc8c432414da1bb", "sha256": "23151ec1c9ec1198f24be01c0af692ba92c902897275b7ec11ed03a0672b3800" }, "downloads": -1, "filename": "persistent_doc-0.5.1.tar.gz", "has_sig": false, "md5_digest": "0ce8c4af00f604817fc8c432414da1bb", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 11361, "upload_time": "2018-10-04T14:24:15", "url": "https://files.pythonhosted.org/packages/e9/3f/62c40690ff6785350d67b84071acd1766cd968d0cc50ab8921c186a795c7/persistent_doc-0.5.1.tar.gz" } ] }