{ "info": { "author": "ZIJIAN JIANG", "author_email": "jiangzijian77@gmail.com", "bugtrack_url": null, "classifiers": [ "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)", "Operating System :: OS Independent", "Programming Language :: Python :: 3" ], "description": "```\n# \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\n# \u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551\u255a\u2588\u2588\u2557\u2588\u2588\u2554\u255d\u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557\u255a\u2550\u2550\u2588\u2588\u2554\u2550\u2550\u255d\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255d \u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255d\u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255d\n# \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u255a\u2588\u2588\u2588\u2554\u255d \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255d\u2588\u2588\u2588\u2588\u2588\u2557\n# \u2588\u2588\u2551\u2584\u2584 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u255d \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u255d\n# \u255a\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255d\u255a\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255d\u2588\u2588\u2551\u2588\u2588\u2554\u255d \u2588\u2588\u2557\u255a\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255d \u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557\u255a\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u255a\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255d\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\n# \u255a\u2550\u2550\u2580\u2580\u2550\u255d \u255a\u2550\u2550\u2550\u2550\u2550\u255d \u255a\u2550\u255d\u255a\u2550\u255d \u255a\u2550\u255d \u255a\u2550\u2550\u2550\u2550\u2550\u255d \u255a\u2550\u255d \u255a\u2550\u2550\u2550\u2550\u2550\u2550\u255d\u255a\u2550\u255d \u255a\u2550\u2550\u2550\u2550\u2550\u255d \u255a\u2550\u2550\u2550\u2550\u2550\u255d \u255a\u2550\u255d \u255a\u2550\u255d\u255a\u2550\u2550\u2550\u2550\u2550\u2550\u255d\n```\n\nQuixote is a minimal dataflow based computational graph skeleton library\n\nIt provides you a clean and right-thinking data processing paradigm.\n\nIn data processing, we concern about three things:\n1. Where is the data came from\n2. What is the purpose of the data\n3. Where is the destination of data\n\nSo quixote's graph consists of two things, Node and Bind, Node is in which the data is transformed, Bind binds two nodes' data interface into pipeline.\nAnd quixote's dataflow graph is like below.\n![graph](image/graph.png)(image is powered by graphviz, rectangle represents Node, and data Bind is presented by arrowed spline, green ones are updated with newest data feed, this image is from one real airplane system project I'm leading)\n\n___In the quixote dataflow graph, left node(or forward nodes) is data feed of right linked ones. Once left node is updated successfully, it will output and push its newest result into linked node's input. When one node's forward, or \"data dependent nodes\", all updated successfully (newest data feed is ready), this node will try to update itself's output with respect to the newest data inputs. The `update` function is user defined, quixote graph will call it on evaluation time in data dependency order. When node's `update` function is called, quixote will make sure that all it's data inputs are updated and ready to be read. All the node should do is take different sources of data and calculate or transform input data and put them into its outputs. (Tunnel is a simple node takes one input and transform into one output, it helps graph more self explainable when node's input takes single specific data over a large amount of complex data with a lot of redundant information, I mean if our data interface is opaque, how can we expect node's behavior from that?)___\n\n> Be noticed that you should not change forward node's input data, it is possible to but quite an undefined behavior.\n\n# WHY? \n\nYou must have question like \"WHY WE BOTHER DO THIS\"?\n\nLet me list some of advantages comes with quixote's data processing paradigm.\n\n* Data Lineage is sound and clear\n* Focus on data interface makes user rethink about design of architecture \n* Debug is more painless than if I have a junk of codes and I have no idea what's are going on\n* Nodes provide nature variable scope isolation which makes functions purer and unsurprised\n* Errors can be caught easily, and not interfere other nodes' functions when they have no dependency\n* Refactoring should be quick and easy\n* MOST IMPORT ONE - New project team member could immediately participate in development\n* ...\n\nIt would be unfair if I don't list some shortages.\n\n* At present quixote.core is written in python\n* It _force_ you to write code in specific way rather than a powerful and unconstrained style you are thinking of.\n\n\n# Installation\n\nYou could get quixote by pip.\n``` \npip install pyquixote\n```\n\nYou can validate the installation by `import quixote.core` and you should see \ud83d\ude0a\n```\nimport quixote.core\n#\n# ==(W{==========- /===-\n# || (.--.) /===-_---~~~~~~~~~------____\n# | \\_,|**|,__ |===-~___ _,-'\n# -==\\\\ `\\ ' `--' ), `//~\\\\ ~~~~`---.___.-~~\n# ______-==| /`\\_. .__/\\ \\ | | \\\\ _-~`\n# __--~~~ ,-/-==\\\\ ( | . |~~~~| | | `\\ ,'\n# _-~ /' | \\\\ )__/==0==-\\<>/ / / \\ /\n# .' / | \\\\ /~\\___/~~\\/ /' / \\ /'\n# / ____ / | \\`\\.__/-~~ \\ |_/' / \\/'\n# /-'~ ~~~~~---__ | ~-/~ ( ) /' _--~`\n# \\_| / _) | ; ), __--~~\n# '~~--_/ _-~/- |/ \\ '-~ \\\n# {\\__--_/} / \\\\_>-|)<__\\ \\\n# /' (_/ _-~ | |__>--<__| |\n# | _/) )-~ | |__>--<__| |\n# / /~ ,_/ / /__>---<__/ |\n# o-o _// /-~_>---<__-~ /\n# (^(~ /~_>---<__- _-~\n# ,/| /__>--<__/ _-~\n# ,//('( |__>--<__| / .----_\n# ( ( ')) |__>--<__| | /' _---_~\\\n# `-)) )) ( |__>--<__| | /' / ~\\`\\\n# ,/,'//( ( \\__>--<__\\ \\ /' // ||\n# ,( ( ((, )) ~-__>--<_~-_ ~--____---~' _/'/ /'\n# `~/ )` ) ,/| ~-_~>--<_/-__ __-~ _/\n# ._-~//( )/ )) ` ~~-'_/_/ /~~~~~~~__--~\n# ;'( ')/ ,)( ~~~~~~~~~~\n# ' ') '( (/\n# ' ' `\n....\n```\n\nGraphviz library is optional, if you want to visualize the data graph please install `graphviz`\n\nIt is recommanded to use `anaconda` for `graphviz` installation and development.\n\n```\nconda install graphviz\n```\nThis will install `graphviz` c library into anaconda environment\n```\npip install graphviz\n```\nAnd this will install `graphviz` python binding package\n\n> You may found some additional operation like enviroment variable settings on Windows operation system. If you have any further question about how to install `graphviz` please refer to:\n\n* [https://pypi.org/project/graphviz/](https://pypi.org/project/graphviz/)\n* [https://graphviz.readthedocs.io/en/stable/manual.html](https://graphviz.readthedocs.io/en/stable/manual.html)\n* [https://stackoverflow.com/questions/18438997/why-is-pydot-unable-to-find-graphvizs-executables-in-windows-8](https://stackoverflow.com/questions/18438997/why-is-pydot-unable-to-find-graphvizs-executables-in-windows-8)\n\n# Usage\n```Python\n\nfrom quixote.core import QNode, QGraph, QTunnel, qlog\nfrom typing import List, Dict, Tuple\n\nclass Contact(QNode):\n def __init__(self):\n super().__init__() # don't forget init super class QNode\n\n # EVERY THING SHOULD BE DEFINED HERE WITH TYPE HINTS, before evaluation starts\n\n # `const`, `var`, `qin`, `qout` are builtin js-object like object in `QNode`\n # every thing defined in `const` should not be modified after first assignment\n self.const.mycontacts: List[Dict[str, str]] = [\n {\n \"name\": \"Johanna\",\n \"phone\": \"132-987-098\"\n }, \n {\n \"name\": \"Steve\",\n \"phone\": \"167-321-777\"\n }\n ]\n # Things defined in `var` are mutable, they are states maintained in `QNode` itself\n # and not accessible to other `QNode`s\n self.var.count: int = 0\n\n # attribute defined in `qout` is `QNode`'s data \"interface\", it will be pushed to \n # linked `QNode`'s `qin.some_attrib` when it `update` successfully\n self.qout.contacts: List[Tuple[str, str]] = [] # type hint tells the difference!\n\n def update(self) -> bool: # `update` is abstract method should be implemented\n try:\n self.var.count = len(self.const.mycontacts)\n self.qout.contacts = [ (contact[\"name\"], contact[\"phone\"]) for contact in self.const.mycontacts ]\n except Exception:\n print(\"some error\")\n return False # quixote will pause the following evaluation when it meets `update` error\n\n return True # `update` successfully\n\nclass PrintNames(QNode):\n def __init__(self):\n super().__init__()\n self.qin.contacts: List[Tuple[str, str]] = []\n self.qin.names: List[str] = []\n\n def update(self) -> bool:\n print(self.qin.names)\n return True\n\nif \"__main__\" == __name__:\n\n contactbook = Contact()\n prints = PrintNames()\n\n datatunnel = QTunnel( lambda contacts: [ x[0] for x in contacts ] )\n\n contactbook.bind(\"contacts\", datatunnel).bind(\"names\", prints) # forward bind data interface\n prints.rbind(\"contacts\", contactbook) # also can reverse bind data interface\n # prints.rbind(\"contacts\", contactbook, \"contacts\") do the same thing... the line above is a suger\n\n QGraph.get_default().view() # Graphviz Libaray must be installed if you want to see graph\n QGraph.get_default().debugstepview = True # show every step debug graph\n prints.eval() # evaluate the terminal node and see how much time elapsed\n```\n\nThe example's result will be like below.\n![sample-graph](image/sample-graph.png)\n```\n['Johanna', 'Steve'] \nPress Enter to continue...\n```\n\nBest wishes:\nI hope you enjoy using this library \ud83d\ude0a\n\nAuthor: ZIJIAN JIANG\n\n\n\n\n\n\n\n\n\n\n", "description_content_type": "", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/CallmeNezha/quixote", "keywords": "", "license": "", "maintainer": "", "maintainer_email": "", "name": "pyquixote", "package_url": "https://pypi.org/project/pyquixote/", "platform": "", "project_url": "https://pypi.org/project/pyquixote/", "project_urls": { "Homepage": "https://github.com/CallmeNezha/quixote" }, "release_url": "https://pypi.org/project/pyquixote/0.0.3/", "requires_dist": [ "typing (>=3.6.6)", "setuptools (>=39.0.1)", "pip (>=9.0.3)", "PyYAML (>=3.13)" ], "requires_python": "", "summary": "A minimal dataflow based computational graph library", "version": "0.0.3" }, "last_serial": 4882380, "releases": { "0.0.1": [ { "comment_text": "", "digests": { "md5": "d8403d5c13a7e7d64718652b54678c30", "sha256": "dd8c56511e23035b09b42f1bfd595fcf119ea6879b266712487caf3f056a1ed4" }, "downloads": -1, "filename": "pyquixote-0.0.1-py3-none-any.whl", "has_sig": false, "md5_digest": "d8403d5c13a7e7d64718652b54678c30", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 22824, "upload_time": "2018-12-02T14:16:37", "url": "https://files.pythonhosted.org/packages/2f/7a/af2a54fff5efc1e3453c3deb44ad8a1f34697f06c25411c44a3869d6cd84/pyquixote-0.0.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "93ed93e6846dd57adcccb5df2f58be52", "sha256": "334b778df234b820d428e6aa2ef5577a028302b934bc8c5fb1925395580bc695" }, "downloads": -1, "filename": "pyquixote-0.0.1.tar.gz", "has_sig": false, "md5_digest": "93ed93e6846dd57adcccb5df2f58be52", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7083, "upload_time": "2018-12-02T14:16:39", "url": "https://files.pythonhosted.org/packages/dc/04/9bdcb517f8e05efeca8d2f3e8e0d8526b54a9b8b3a9c6275846ddb4ee6e2/pyquixote-0.0.1.tar.gz" } ], "0.0.2": [ { "comment_text": "", "digests": { "md5": "5573e5e112a990791523d6fdcc58e0fb", "sha256": "74452c975e13a5f96b53ae5468b42662c6735d77ad6bb0f68f871416b44a5d0d" }, "downloads": -1, "filename": "pyquixote-0.0.2-py3-none-any.whl", "has_sig": false, "md5_digest": "5573e5e112a990791523d6fdcc58e0fb", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 27073, "upload_time": "2018-12-25T17:18:56", "url": "https://files.pythonhosted.org/packages/e3/c5/068a1b1709ef344070979ff9ce0a3c406f7252e747a522911705ecaae5a0/pyquixote-0.0.2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "7a331f132e62ac8e0a0c8d40830c83ae", "sha256": "24491917cb60002c6b0752e87291e14d2776c20c5d2cd9ed9c4b62668229b0ea" }, "downloads": -1, "filename": "pyquixote-0.0.2.tar.gz", "has_sig": false, "md5_digest": "7a331f132e62ac8e0a0c8d40830c83ae", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 11193, "upload_time": "2018-12-25T17:18:58", "url": "https://files.pythonhosted.org/packages/fb/cc/c5fd9d2f960ceb84f9997984a1d9a5666d426a4ad68cb69f57eba6f7ebb4/pyquixote-0.0.2.tar.gz" } ], "0.0.3": [ { "comment_text": "", "digests": { "md5": "a94e5f1d0fd29cc29d99ac0be601e2a8", "sha256": "6b7e4313c3ec488c27dc5b5fb6b363d2312b7c303cdcea5b5bc6e05209768d21" }, "downloads": -1, "filename": "pyquixote-0.0.3-py3-none-any.whl", "has_sig": false, "md5_digest": "a94e5f1d0fd29cc29d99ac0be601e2a8", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 19395, "upload_time": "2019-03-01T05:31:44", "url": "https://files.pythonhosted.org/packages/22/c0/3044c5ce0289075428b69cef71d4ec020b480276e37fe2055185439f117f/pyquixote-0.0.3-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "d26b5e02c64ebb4e5c5651d779271384", "sha256": "521e74e98acb3f098b8df9cb6388ee77c5d4c3ad41abb4e029e549ccff5f89af" }, "downloads": -1, "filename": "pyquixote-0.0.3.tar.gz", "has_sig": false, "md5_digest": "d26b5e02c64ebb4e5c5651d779271384", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 11395, "upload_time": "2019-03-01T05:31:46", "url": "https://files.pythonhosted.org/packages/33/e9/775d575d6d5d45370725e2d5ca054e2da1fdc33cff353d400983f4da9036/pyquixote-0.0.3.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "a94e5f1d0fd29cc29d99ac0be601e2a8", "sha256": "6b7e4313c3ec488c27dc5b5fb6b363d2312b7c303cdcea5b5bc6e05209768d21" }, "downloads": -1, "filename": "pyquixote-0.0.3-py3-none-any.whl", "has_sig": false, "md5_digest": "a94e5f1d0fd29cc29d99ac0be601e2a8", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 19395, "upload_time": "2019-03-01T05:31:44", "url": "https://files.pythonhosted.org/packages/22/c0/3044c5ce0289075428b69cef71d4ec020b480276e37fe2055185439f117f/pyquixote-0.0.3-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "d26b5e02c64ebb4e5c5651d779271384", "sha256": "521e74e98acb3f098b8df9cb6388ee77c5d4c3ad41abb4e029e549ccff5f89af" }, "downloads": -1, "filename": "pyquixote-0.0.3.tar.gz", "has_sig": false, "md5_digest": "d26b5e02c64ebb4e5c5651d779271384", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 11395, "upload_time": "2019-03-01T05:31:46", "url": "https://files.pythonhosted.org/packages/33/e9/775d575d6d5d45370725e2d5ca054e2da1fdc33cff353d400983f4da9036/pyquixote-0.0.3.tar.gz" } ] }