{ "info": { "author": "Matt Kafonek", "author_email": "kafonek@gmail.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 3 - Alpha", "Framework :: IPython", "Intended Audience :: Developers", "Programming Language :: Python" ], "description": "# ipython_blocking\n[![Binder](https://mybinder.org/badge.svg)](https://mybinder.org/v2/gh/kafonek/ipython_blocking/master)\n\n`ipython_blocking` is a context manager for capturing cell execution messages in a Jupyter notebook, along with magic commands `%block` and `%blockrun` for convenience. The primary use-case for blocking notebook execution is to wait for users to interact with [ipywidgets](https://github.com/jupyter-widgets/ipywidgets) and then reference the values entered in those Widgets.\n\n\n### Install\n`ipython_blocking` is on [PyPI](https://pypi.org/project/ipython_blocking/), install with pip.\n\n```python\npip install ipython_blocking\n```\n\n\n### Usage\nTry out the demo notebooks in Binder to see `ipython_blocking` in action. The most common way to use `ipython_blocking` is with the `%blockrun` magic and running a notebook with \"cell -> run all\". `%blockrun button` stops the cell execution messages from the initial \"cell -> run all\", and attaches a \"cell -> run all below\" handler to the button so that a notebook can be run in a linear fashion without callback functions after a user has filled out other Widget values.\n\n```python\n### cell #1\nimport ipywidgets as widgets\nimport ipython_blocking # enables %block and %blockrun magic\n\ntext = widgets.Text()\ndropdown = widgets.Dropdown(options=['', 'foo', 'bar', 'baz'])\nbutton = widgets.Button(description='Run')\nbox = widgets.VBox(children=[text, dropdown, button])\nbox\n\n### cell #2\n%blockrun button\n\n### cell #3 -- doesn't execute until the 'Run' button is pressed\n### This gives the user a chance to interact with the Text and Dropdown widgets\nprint(text.value)\nprint(dropdown.value)\n```\n\n*(The dropdown menu doesn't appear in this .gif because its treated as a \"separate window\" in Windows screen capture, sorry!)*\n\n![](example.gif)\n\n#### CaptureExecution\nThe way `ipython_blocking` \"blocks\" cell execution is by creating a context manager that changes the behavior of the `IPython.shell.kernel['execute_request']` handler. When you execute a cell in a Jupyter notebook, it sends a `execute_request` comms message to the kernel with that code. \n\nWhile the `CaptureExecution` manager is \"blocking\", it stores those messages in a list instead of actually executing them. When the context manager exits, it resets the handler to its original behavior and then either replays the stored messages or drops them.\n\n```python\nimport ipython_blocking\nctx = ipython_blocking.CaptureExecution(replay=True)\nwith ctx:\n while True:\n if break_function():\n break\n ctx.step() # handles all other messages that aren't 'execute_request' including widget value changes\n```\n\n#### %block\nThe `%block` magic is enabled upon importing `ipython_blocking`. It takes either a function or widget object and creates the `CaptureExecution` manager to block until that function returns True or the widget value changes.\n\n```python\n# cell 1\nimport ipywidgets as widgets\nimport ipython_blocking\ndd = widgets.Dropdown(options=['', 'foo', 'bar', baz'])\ndd\n\n# cell 2\n%block dd\n\n# cell 3\n# Won't actually be executed until the user chooses an option in the dd widget\nprint(dd.value)\n```\n\n#### %blockrun\nThe `%blockrun` magic is similar to `%block` but it only accepts an `ipywidgets.Button` target and it attaches a \"cell -> run all below\" handler to the button. If you expect the application logic of your Notebook to be run more than once (and/or don't want to reinitialize the Widgets because the user might only change one of many options), then `%blockrun` is the better magic to use.\n\nIt is often handy to make the target `Button` unclickable when the Notebook first renders, then add `.observe` handlers on other Widgets that can make the `Button` clickable once some input validation has happened.\n\n```python\n# cell 1\nimport ipywidgets as widgets\nimport ipython_blocking\ntext = widgets.Text()\ndd = widgets.Dropdown(options=['', 'foo', 'bar', 'baz'])\nbutton = widgets.Button(description='Run', disabled=True)\n\ndef validation(ev):\n \"make button clickable if user has put in more than 5 characters and chosen a dropdown option\"\n if len(text.value) > 5 and dd.value:\n button.disabled = False\n else:\n button.disabled = True\ntext.observe(validation)\ndd.observe(validation)\n\nbox = widgets.VBox(children=[text, dd, button])\nbox\n\n# cell 2\n%blockrun button\n\n# cell 3\nprint(text.value)\nprint(dd.value)\n```\n\n\n### Alternatives\nThe other ways to get the value of a widget after a user has interacted with the widget is to structure your notebook with [event callbacks](https://ipywidgets.readthedocs.io/en/latest/examples/Widget%20Events.html) or to write your code [asynchronously](https://ipywidgets.readthedocs.io/en/latest/examples/Widget%20Asynchronous.html). \n\nI believe there are major benefits to writing the **application logic** of a Jupyter Notebook in a **linear and synchronous** fashion, with as many variables as possible in the notebook global scope. Those benefits include:\n\n * Better introspection and comprehension of the workflow (without littering your code with `global` and `print` statements)\n * More direct debug when something goes wrong\n * Easier to break code into small blocks/cells\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\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/kafonek/ipython_blocking", "keywords": "", "license": "BSD", "maintainer": "", "maintainer_email": "", "name": "ipython-blocking", "package_url": "https://pypi.org/project/ipython-blocking/", "platform": "", "project_url": "https://pypi.org/project/ipython-blocking/", "project_urls": { "Homepage": "https://github.com/kafonek/ipython_blocking" }, "release_url": "https://pypi.org/project/ipython-blocking/0.2.0/", "requires_dist": [ "IPython", "ipywidgets" ], "requires_python": "", "summary": "Context manager for blocking cell execution within a Jupyter notebook", "version": "0.2.0" }, "last_serial": 5139498, "releases": { "0.1.0": [ { "comment_text": "", "digests": { "md5": "481570c9b11decd4ffafee7c852ed1ef", "sha256": "968b10d34c00ee8975a6cf77eb9c645c9f55743cef1579ea8af74755ddf1f3d0" }, "downloads": -1, "filename": "ipython_blocking-0.1.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "481570c9b11decd4ffafee7c852ed1ef", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 7702, "upload_time": "2018-08-27T03:48:19", "url": "https://files.pythonhosted.org/packages/23/f7/afb602911486afb741a58dd55b0344766100747c7b67dda90b953eda66d2/ipython_blocking-0.1.0-py2.py3-none-any.whl" } ], "0.1.1": [ { "comment_text": "", "digests": { "md5": "5747a3ba73ccb16ff56b9d8162b34a71", "sha256": "6a743969ca4a78f35eef144d74fde51aeed1c53d81d4fe7378ca52fee480955c" }, "downloads": -1, "filename": "ipython_blocking-0.1.1-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "5747a3ba73ccb16ff56b9d8162b34a71", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 10105, "upload_time": "2018-08-30T03:01:04", "url": "https://files.pythonhosted.org/packages/78/ef/51d7515b59b93b80a6a6669745be908026599cafac98643434a3ce74e8fa/ipython_blocking-0.1.1-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "f05eabe551f9ac69f3ea98fe1d37b85b", "sha256": "b71f5d560f5245c4ace9ed39f30c2a84f9fd8af0e207499c5b284922e150b6ce" }, "downloads": -1, "filename": "ipython_blocking-0.1.1.tar.gz", "has_sig": false, "md5_digest": "f05eabe551f9ac69f3ea98fe1d37b85b", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 8555, "upload_time": "2018-08-30T03:01:11", "url": "https://files.pythonhosted.org/packages/95/97/81f23f0efb8b7f2d3e5abebb446943c2c4a6898f137925c00c1416e7b890/ipython_blocking-0.1.1.tar.gz" } ], "0.1.1.post1": [ { "comment_text": "", "digests": { "md5": "6df550c785606b7a17211e2f51eb5e67", "sha256": "915c422aa3118c2f764b99bb9f98b9097108495039044819a6a22ec8fa3a85d1" }, "downloads": -1, "filename": "ipython_blocking-0.1.1.post1-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "6df550c785606b7a17211e2f51eb5e67", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 10791, "upload_time": "2018-09-01T14:24:38", "url": "https://files.pythonhosted.org/packages/b2/a8/f093ec527805ac17ed995ec31992c4e7c452bd469e50a8fd756e92e0cad0/ipython_blocking-0.1.1.post1-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "969aa44f65565351273788b9f43fe50c", "sha256": "1a60c6fe3c9cba220595bcd4f8ac83f5f289b5bca6021cd26463a7889acd1832" }, "downloads": -1, "filename": "ipython_blocking-0.1.1.post1.tar.gz", "has_sig": false, "md5_digest": "969aa44f65565351273788b9f43fe50c", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 9193, "upload_time": "2018-09-01T14:24:47", "url": "https://files.pythonhosted.org/packages/4e/d1/77d0bb59236aa9e09ab728422a49c272b84932335ca3252f65addca18025/ipython_blocking-0.1.1.post1.tar.gz" } ], "0.2.0": [ { "comment_text": "", "digests": { "md5": "fb12680d9831d10a6cbf85b98803aef7", "sha256": "753c93263338b573886a2322d29083c49ecd7807c912294791fee7dff5e7f6f1" }, "downloads": -1, "filename": "ipython_blocking-0.2.0-py3-none-any.whl", "has_sig": false, "md5_digest": "fb12680d9831d10a6cbf85b98803aef7", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 7032, "upload_time": "2019-04-13T23:37:22", "url": "https://files.pythonhosted.org/packages/c9/47/232b1f6961ab6e8fc5b7796b3ad66508ed2fb634a3c57eaddebc9df8093b/ipython_blocking-0.2.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "4d19939ea72750bcc1d3b8bda68167bb", "sha256": "df13f5c5d9ab36ece020ee79514a6172129dbd2c76bc8553604d41321830ab87" }, "downloads": -1, "filename": "ipython_blocking-0.2.0.tar.gz", "has_sig": false, "md5_digest": "4d19939ea72750bcc1d3b8bda68167bb", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5378, "upload_time": "2019-04-13T23:37:23", "url": "https://files.pythonhosted.org/packages/d4/cb/44567d22e1c9cdd3c37f150dcf4c04855ae2281546ad0047ad0ded25cc0f/ipython_blocking-0.2.0.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "fb12680d9831d10a6cbf85b98803aef7", "sha256": "753c93263338b573886a2322d29083c49ecd7807c912294791fee7dff5e7f6f1" }, "downloads": -1, "filename": "ipython_blocking-0.2.0-py3-none-any.whl", "has_sig": false, "md5_digest": "fb12680d9831d10a6cbf85b98803aef7", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 7032, "upload_time": "2019-04-13T23:37:22", "url": "https://files.pythonhosted.org/packages/c9/47/232b1f6961ab6e8fc5b7796b3ad66508ed2fb634a3c57eaddebc9df8093b/ipython_blocking-0.2.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "4d19939ea72750bcc1d3b8bda68167bb", "sha256": "df13f5c5d9ab36ece020ee79514a6172129dbd2c76bc8553604d41321830ab87" }, "downloads": -1, "filename": "ipython_blocking-0.2.0.tar.gz", "has_sig": false, "md5_digest": "4d19939ea72750bcc1d3b8bda68167bb", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5378, "upload_time": "2019-04-13T23:37:23", "url": "https://files.pythonhosted.org/packages/d4/cb/44567d22e1c9cdd3c37f150dcf4c04855ae2281546ad0047ad0ded25cc0f/ipython_blocking-0.2.0.tar.gz" } ] }