{"action":"created","issue":{"url":"https://api.github.com/repos/ipython/ipython/issues/9784","repository_url":"https://api.github.com/repos/ipython/ipython","labels_url":"https://api.github.com/repos/ipython/ipython/issues/9784/labels{/name}","comments_url":"https://api.github.com/repos/ipython/ipython/issues/9784/comments","events_url":"https://api.github.com/repos/ipython/ipython/issues/9784/events","html_url":"https://github.com/ipython/ipython/issues/9784","id":166691636,"number":9784,"title":"IPython 5 + Qt breakage: no QApplication gets created, so inputhook does nothing.","user":{"login":"zpincus","id":174217,"avatar_url":"https://avatars.githubusercontent.com/u/174217?v=3","gravatar_id":"","url":"https://api.github.com/users/zpincus","html_url":"https://github.com/zpincus","followers_url":"https://api.github.com/users/zpincus/followers","following_url":"https://api.github.com/users/zpincus/following{/other_user}","gists_url":"https://api.github.com/users/zpincus/gists{/gist_id}","starred_url":"https://api.github.com/users/zpincus/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/zpincus/subscriptions","organizations_url":"https://api.github.com/users/zpincus/orgs","repos_url":"https://api.github.com/users/zpincus/repos","events_url":"https://api.github.com/users/zpincus/events{/privacy}","received_events_url":"https://api.github.com/users/zpincus/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":{"url":"https://api.github.com/repos/ipython/ipython/milestones/37","html_url":"https://github.com/ipython/ipython/milestones/5.1","labels_url":"https://api.github.com/repos/ipython/ipython/milestones/37/labels","id":1808297,"number":37,"title":"5.1","description":"","creator":{"login":"takluyver","id":327925,"avatar_url":"https://avatars.githubusercontent.com/u/327925?v=3","gravatar_id":"","url":"https://api.github.com/users/takluyver","html_url":"https://github.com/takluyver","followers_url":"https://api.github.com/users/takluyver/followers","following_url":"https://api.github.com/users/takluyver/following{/other_user}","gists_url":"https://api.github.com/users/takluyver/gists{/gist_id}","starred_url":"https://api.github.com/users/takluyver/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/takluyver/subscriptions","organizations_url":"https://api.github.com/users/takluyver/orgs","repos_url":"https://api.github.com/users/takluyver/repos","events_url":"https://api.github.com/users/takluyver/events{/privacy}","received_events_url":"https://api.github.com/users/takluyver/received_events","type":"User","site_admin":false},"open_issues":28,"closed_issues":13,"state":"open","created_at":"2016-06-04T09:30:48Z","updated_at":"2016-07-21T18:58:47Z","due_on":null,"closed_at":null},"comments":4,"created_at":"2016-07-20T21:55:42Z","updated_at":"2016-07-22T06:59:51Z","closed_at":null,"body":"### Problem\r\nIn IPython 4,  `%gui qt` starts up a `QApplication` automatically if one isn't already running, and returns it to the user. This does not happen in IPython 5.\r\n\r\nThis is a problem because unless a `QApplication` instance has been created, the Qt inputhook doesn't do anything. The relevant code for IPython 5, in [terminal/pt_inputhooks/qt.py](https://github.com/ipython/ipython/blob/master/IPython/terminal/pt_inputhooks/qt.py#L4), looks like this:\r\n```python\r\ndef inputhook(context):\r\n    app = QtCore.QCoreApplication.instance()\r\n    if not app:\r\n        return\r\n```\r\n\r\nIn IPython 4, `%gui qt` winds up (through a complex chain of events) executing [lib. inputhookqt4.create_inputhook_qt4()](https://github.com/ipython/ipython/blob/master/IPython/lib/inputhookqt4.py#L66), which does the following:\r\n```python\r\n        app = QtCore.QCoreApplication.instance()\r\n        if app is None:\r\n            app = QtGui.QApplication([\" \"])\r\n```\r\nMoreover, in IPython 4, `%gui qt` returns this `QApplication` instance to the user.\r\n\r\nNone of this happens in IPython 5. Presumably this change was not intentional, and enabling the Qt GUI in IPython 5 should still create a `QApplication`? (There is (ancient?) code in [lib/guisupport.py](https://github.com/ipython/ipython/blob/master/IPython/lib/guisupport.py#L109) that returns or creates a `QApplication`, so someone could use that if they want.)\r\n\r\n### Example\r\nThe following works fine in IPython 4:\r\n```python\r\n%gui qt\r\nfrom PyQt5.QtWidgets import QWidget # or PyQt if you use Qt4\r\nw = QWidget()\r\nw.setGeometry(300, 300, 250, 150)\r\nw.setWindowTitle(\"Test\")\r\nw.show()\r\n```\r\nbut breaks horribly in IPython 5. This fixes things:\r\n```python\r\n%gui qt\r\nfrom PyQt5.QtWidgets import QApplication, QWidget\r\napp = QApplication([''])\r\nw = QWidget()\r\nw.setGeometry(300, 300, 250, 150)\r\nw.setWindowTitle(\"Test\")\r\nw.show()\r\n```\r\n\r\nUsing a virtual environment, one can test this pretty simply by using `pip` to install IPython 4 vs. 5, and pyqt5 via a wheel (statically linked to the Qt libs) that has recently appeared. This is much easier than having fuss with hand-building PyQt etc.\r\n\r\n### Resolution \r\nI would submit a PR, but first I'd like to know where to put the relevant initialization code. \r\n\r\nIn IPython 5, factory-functions like `create_inputhook_qt4()` are not employed. Instead, all that happens when [terminal.pt_inputhooks.get_inputhook_func()](https://github.com/ipython/ipython/blob/master/IPython/terminal/pt_inputhooks/__init__.py#L33) is run is that the relevant module in `terminal/pt_inputhooks` gets imported and the `inputhook` function therein is returned. \r\n\r\nShould something like the following be placed at the module-level in [terminal/pt_inputhooks/qt.py](https://github.com/ipython/ipython/blob/master/IPython/terminal/pt_inputhooks/qt.py), such that it gets run on import?\r\n```python\r\napp = QtCore.QCoreApplication.instance()\r\nif app is None:\r\n    app = QtGui.QApplication([''])\r\n```\r\nAnd if so, should the `inputhook` code just use this module-level `app` variable, or still look it up each time it's called, as it does now? Somehow, having module-level initialization seems a bit gross though.\r\n\r\nAlternately, `get_inputhook_func()` could check the module for an `initialize_gui()` function and run that first. Further, if desired, `get_inputhook_func()` could return the result of `initialize_gui()` along with the `inputhook` function, which would allow the QApplication instance to be returned to whoever calls `%gui qt`, as in IPython 4. This seems like a sensible approach, but advice would be welcome. \r\n\r\nNote also that if the `QApplication` instance ever gets deleted, PyQt doesn't keep a reference to it around, so `QtCore.QCoreApplication.instance()` will return `None`. So in any case, one needs to be careful that the instance gets stashed somewhere..."},"comment":{"url":"https://api.github.com/repos/ipython/ipython/issues/comments/234469329","html_url":"https://github.com/ipython/ipython/issues/9784#issuecomment-234469329","issue_url":"https://api.github.com/repos/ipython/ipython/issues/9784","id":234469329,"user":{"login":"zpincus","id":174217,"avatar_url":"https://avatars.githubusercontent.com/u/174217?v=3","gravatar_id":"","url":"https://api.github.com/users/zpincus","html_url":"https://github.com/zpincus","followers_url":"https://api.github.com/users/zpincus/followers","following_url":"https://api.github.com/users/zpincus/following{/other_user}","gists_url":"https://api.github.com/users/zpincus/gists{/gist_id}","starred_url":"https://api.github.com/users/zpincus/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/zpincus/subscriptions","organizations_url":"https://api.github.com/users/zpincus/orgs","repos_url":"https://api.github.com/users/zpincus/repos","events_url":"https://api.github.com/users/zpincus/events{/privacy}","received_events_url":"https://api.github.com/users/zpincus/received_events","type":"User","site_admin":false},"created_at":"2016-07-22T06:59:50Z","updated_at":"2016-07-22T06:59:50Z","body":"I'm not sure I really understand the objections to the old behavior of creating a `QApplication`. Isn't the whole point of the GUI integration is to make GUI code run differently in IPython vs. plain-Python? (I.e. to shift responsibility for setting up an eventloop from the user code to IPython.)\r\n\r\nTo start an eventloop in Qt, a user generally has to create a `QApplication` and then call its `exec_()` method. The Qt integration in IPython 4.x does both tasks (unless the user had already made a `QApplication`, which would get used instead). Currently, IPython 5 requires that a user do the first task and then IPython does the second. Note that **either way**, things in IPython are different from the plain-Python case. The IPython 4.x solution seems to me to be a bit more self-consistent, though.\r\n\r\nMoreover, I don't really see how this differs from any of the other GUI integration code. Every GUI toolkit usually requires that an eventloop get created and started as part of starting a GUI program -- yet in every instance, the IPython GUI integration both creates/initializes and runs the eventloop. (It's just that the Qt implementation forgot to take care of all of the usual initialization steps, and unsurprisingly broke as a result.)\r\n\r\nFor example, look at the code in `terminal/pt_inputhooks/glut.py`: this is **all** stuff that a user generally has to do in their own `main()` function. Does bypassing the requirement to call `glut.glutInit(sys.argv)` and `glut.glutInitDisplayMode(glut_display_mode)` risk confusing users about what's really going on? \r\n\r\nOr would it be more confusing to require that a user run `glut.glutInit(sys.argv)` before `%gui glut` will work correctly? And if that is unacceptable (I certainly think so), is there any meaningful difference from the proposed requirement that a user run `app = QApplication(sys.argv)` before `%gui qt` will work correctly?"}}
{"actor":{"display_login":"zpincus"}}