We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
'TCanvas' object has no attribute 'name'
Hi,

I am seeing weird issues with the interactive module. It looks like the TCanvas is not 'decorated' when loading rootpy.interactive.

```
>>> from ROOT import *
>>> t = TCanvas()
>>> from rootpy.interactive import wait
/usr/local/lib/python2.7/site-packages/IPython/frontend.py:30: UserWarning: The top-level `frontend` package has been deprecated. All its subpackages have been moved to the top `IPython` level.
  warn("The top-level `frontend` package has been deprecated. "
w>>> wait()
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/usr/local/Cellar/python/2.7.5/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/rootpy-dev-py2.7.egg/rootpy/interactive/rootwait.py", line 206, in wait_for_zero_canvases
    log.debug("waiting for canvas {0} to close".format(canvas.name))
AttributeError: 'TCanvas' object has no attribute 'name'
```

Albert


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `rootpy/interactive/rootwait.py`
Content:
```
1 # Copyright 2012 the rootpy developers
2 # distributed under the terms of the GNU General Public License
3 """
4 The functions in this module provide a way of pausing code execution until
5 canvases are closed. This can be useful when testing code and you don't want to
6 keep the objects alive outside of your function.
7 
8 The wait function can be called repeatedly to pause multiple times.
9 
10 wait_for_zero_canvases()
11     Keeps root alive until CTRL-c is pressed or all canvases are closed
12 
13 wait_for_zero_canvases(middle_mouse_close=True)
14     allows canvases to be closed with the middle mouse button (see below)
15 
16 wait is shorthand for wait_for_zero_canvases
17 
18 Examples
19 --------
20 
21     from rootpy.plotting import Canvas
22     from rootpy.interactive import wait
23 
24     c = Canvas()
25     c.Update()
26     wait()
27 
28     c2 = Canvas()
29     c2.Update()
30     wait(True)
31     # This canvas can be killed by middle clicking on it or hitting
32     # escape whilst it has focus
33 
34 """
35 from __future__ import absolute_import
36 
37 import threading
38 from atexit import register
39 
40 import ROOT
41 
42 from . import log; log = log[__name__]
43 from ..defaults import extra_initialization
44 from ..memory.keepalive import keepalive
45 from .canvas_events import attach_event_handler
46 
47 __all__ = [
48     'wait_for_zero_canvases',
49     'wait_for_browser_close',
50     'wait',
51 ]
52 
53 _processRootEvents = None
54 _finishSchedule = None
55 __ACTIVE = False
56 
57 
58 @extra_initialization
59 def fetch_vars():
60     global _processRootEvents, _finishSchedule, __ACTIVE
61     PyGUIThread = getattr(ROOT, 'PyGUIThread', None)
62     if PyGUIThread is not None:
63         _processRootEvents = getattr(PyGUIThread, "_Thread__target", None)
64         _finishSchedule = getattr(PyGUIThread, "finishSchedule", None)
65     if _processRootEvents is None:
66         log.warning(
67             "unable to access ROOT's GUI thread either because "
68             "PyROOT's finalSetup() was called while in batch mode "
69             "or because PyROOT is using the new PyOS_InputHook "
70             "based mechanism that is not yet supported in rootpy "
71             "(PyConfig.StartGuiThread == 'inputhook' or "
72             "gSystem.InheritsFrom('TMacOSXSystem')). wait() etc. will "
73             "instead call raw_input() and wait for [Enter]")
74     else:
75         __ACTIVE = True
76 
77 
78 def wait_failover(caller):
79     if not ROOT.gROOT.IsBatch():
80         log.warning(
81             "{0} is failing over to raw_input()".format(caller.__name__))
82         raw_input("press [Enter] to continue")
83 
84 
85 def start_new_gui_thread():
86     """
87     Attempt to start a new GUI thread, if possible.
88 
89     It is only possible to start one if there was one running on module import.
90     """
91     PyGUIThread = getattr(ROOT, 'PyGUIThread', None)
92 
93     if PyGUIThread is not None:
94         assert not PyGUIThread.isAlive(), "GUI thread already running!"
95 
96     assert _processRootEvents, (
97         "GUI thread wasn't started when rootwait was imported, "
98         "so it can't be restarted")
99 
100     ROOT.keeppolling = 1
101     ROOT.PyGUIThread = threading.Thread(
102         None, _processRootEvents, None, (ROOT,))
103 
104     ROOT.PyGUIThread.finishSchedule = _finishSchedule
105     ROOT.PyGUIThread.setDaemon(1)
106     ROOT.PyGUIThread.start()
107     log.debug("successfully started a new GUI thread")
108 
109 
110 def stop_gui_thread():
111     """
112     Try to stop the GUI thread. If it was running returns True,
113     otherwise False.
114     """
115     PyGUIThread = getattr(ROOT, 'PyGUIThread', None)
116 
117     if PyGUIThread is None or not PyGUIThread.isAlive():
118         log.debug("no existing GUI thread is runnng")
119         return False
120 
121     ROOT.keeppolling = 0
122     try:
123         PyGUIThread.finishSchedule()
124     except AttributeError:
125         log.debug("unable to call finishSchedule() on PyGUIThread")
126         pass
127     PyGUIThread.join()
128     log.debug("successfully stopped the existing GUI thread")
129     return True
130 
131 
132 def get_visible_canvases():
133     """
134     Return a list of active GUI canvases
135     (as opposed to invisible Batch canvases)
136     """
137     try:
138         return [c for c in ROOT.gROOT.GetListOfCanvases() if not c.IsBatch()]
139     except AttributeError:
140         # We might be exiting and ROOT.gROOT will raise an AttributeError
141         return []
142 
143 
144 def run_application_until_done():
145 
146     had_gui_thread = stop_gui_thread()
147 
148     ROOT.gApplication._threaded = True
149     ROOT.gApplication.Run(True)
150 
151     if had_gui_thread:
152         start_new_gui_thread()
153 
154 
155 def dispatcher(f):
156     disp = ROOT.TPyDispatcher(f)
157     keepalive(disp, f)
158     return disp
159 
160 
161 def wait_for_zero_canvases(middle_mouse_close=False):
162     """
163     Wait for all canvases to be closed, or CTRL-c.
164 
165     If `middle_mouse_close`, middle click will shut the canvas.
166 
167     incpy.ignore
168     """
169     if not __ACTIVE:
170         wait_failover(wait_for_zero_canvases)
171         return
172 
173     @dispatcher
174     def count_canvases():
175         """
176         Count the number of active canvases and finish gApplication.Run()
177         if there are none remaining.
178 
179         incpy.ignore
180         """
181         if not get_visible_canvases():
182             try:
183                 ROOT.gSystem.ExitLoop()
184             except AttributeError:
185                 # We might be exiting and ROOT.gROOT will raise an AttributeError
186                 pass
187 
188     @dispatcher
189     def exit_application_loop():
190         """
191         Signal handler for CTRL-c to cause gApplication.Run() to finish.
192 
193         incpy.ignore
194         """
195         ROOT.gSystem.ExitLoop()
196 
197     # Handle CTRL-c
198     sh = ROOT.TSignalHandler(ROOT.kSigInterrupt, True)
199     sh.Add()
200     sh.Connect("Notified()", "TPyDispatcher",
201                exit_application_loop, "Dispatch()")
202 
203     visible_canvases = get_visible_canvases()
204 
205     for canvas in visible_canvases:
206         log.debug("waiting for canvas {0} to close".format(canvas.name))
207         canvas.Update()
208 
209         if middle_mouse_close:
210             attach_event_handler(canvas)
211 
212         if not getattr(canvas, "_py_close_dispatcher_attached", False):
213             # Attach a handler only once to each canvas
214             canvas._py_close_dispatcher_attached = True
215             canvas.Connect("Closed()", "TPyDispatcher",
216                            count_canvases, "Dispatch()")
217             keepalive(canvas, count_canvases)
218 
219     if visible_canvases and not ROOT.gROOT.IsBatch():
220         run_application_until_done()
221 
222         # Disconnect from canvases
223         for canvas in visible_canvases:
224             if getattr(canvas, "_py_close_dispatcher_attached", False):
225                 canvas._py_close_dispatcher_attached = False
226                 canvas.Disconnect("Closed()", count_canvases, "Dispatch()")
227 
228 wait = wait_for_zero_canvases
229 
230 
231 def wait_for_frame(frame):
232     """
233     wait until a TGMainFrame is closed or ctrl-c
234     """
235     if not frame:
236         # It's already closed or maybe we're in batch mode
237         return
238 
239     @dispatcher
240     def close():
241         ROOT.gSystem.ExitLoop()
242 
243     if not getattr(frame, "_py_close_dispatcher_attached", False):
244         frame._py_close_dispatcher_attached = True
245         frame.Connect("CloseWindow()", "TPyDispatcher", close, "Dispatch()")
246 
247     @dispatcher
248     def exit_application_loop():
249         """
250         Signal handler for CTRL-c to cause gApplication.Run() to finish.
251 
252         incpy.ignore
253         """
254         ROOT.gSystem.ExitLoop()
255 
256     # Handle CTRL-c
257     sh = ROOT.TSignalHandler(ROOT.kSigInterrupt, True)
258     sh.Add()
259     sh.Connect("Notified()", "TPyDispatcher",
260                exit_application_loop, "Dispatch()")
261 
262     if not ROOT.gROOT.IsBatch():
263         run_application_until_done()
264         # Need to disconnect to prevent close handler from running when python
265         # teardown has already commenced.
266         frame.Disconnect("CloseWindow()", close, "Dispatch()")
267 
268 
269 def wait_for_browser_close(b):
270     """
271     Can be used to wait until a TBrowser is closed
272     """
273     if b:
274         if not __ACTIVE:
275             wait_failover(wait_for_browser_close)
276             return
277         wait_for_frame(b.GetBrowserImp().GetMainFrame())
278 
279 
280 def prevent_close_with_canvases():
281     """
282     Register a handler which prevents python from exiting until
283     all canvases are closed
284     """
285     register(wait_for_zero_canvases)
286
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/rootpy/interactive/rootwait.py b/rootpy/interactive/rootwait.py
--- a/rootpy/interactive/rootwait.py
+++ b/rootpy/interactive/rootwait.py
@@ -203,7 +203,7 @@
     visible_canvases = get_visible_canvases()
 
     for canvas in visible_canvases:
-        log.debug("waiting for canvas {0} to close".format(canvas.name))
+        log.debug("waiting for canvas {0} to close".format(canvas.GetName()))
         canvas.Update()
 
         if middle_mouse_close:

{"golden_diff": "diff --git a/rootpy/interactive/rootwait.py b/rootpy/interactive/rootwait.py\n--- a/rootpy/interactive/rootwait.py\n+++ b/rootpy/interactive/rootwait.py\n@@ -203,7 +203,7 @@\n     visible_canvases = get_visible_canvases()\n \n     for canvas in visible_canvases:\n-        log.debug(\"waiting for canvas {0} to close\".format(canvas.name))\n+        log.debug(\"waiting for canvas {0} to close\".format(canvas.GetName()))\n         canvas.Update()\n \n         if middle_mouse_close:\n", "issue": "'TCanvas' object has no attribute 'name'\nHi,\n\nI am seeing weird issues with the interactive module. It looks like the TCanvas is not 'decorated' when loading rootpy.interactive.\n\n```\n>>> from ROOT import *\n>>> t = TCanvas()\n>>> from rootpy.interactive import wait\n/usr/local/lib/python2.7/site-packages/IPython/frontend.py:30: UserWarning: The top-level `frontend` package has been deprecated. All its subpackages have been moved to the top `IPython` level.\n  warn(\"The top-level `frontend` package has been deprecated. \"\nw>>> wait()\nTraceback (most recent call last):\n  File \"<console>\", line 1, in <module>\n  File \"/usr/local/Cellar/python/2.7.5/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/rootpy-dev-py2.7.egg/rootpy/interactive/rootwait.py\", line 206, in wait_for_zero_canvases\n    log.debug(\"waiting for canvas {0} to close\".format(canvas.name))\nAttributeError: 'TCanvas' object has no attribute 'name'\n```\n\nAlbert\n\n", "before_files": [{"content": "# Copyright 2012 the rootpy developers\n# distributed under the terms of the GNU General Public License\n\"\"\"\nThe functions in this module provide a way of pausing code execution until\ncanvases are closed. This can be useful when testing code and you don't want to\nkeep the objects alive outside of your function.\n\nThe wait function can be called repeatedly to pause multiple times.\n\nwait_for_zero_canvases()\n    Keeps root alive until CTRL-c is pressed or all canvases are closed\n\nwait_for_zero_canvases(middle_mouse_close=True)\n    allows canvases to be closed with the middle mouse button (see below)\n\nwait is shorthand for wait_for_zero_canvases\n\nExamples\n--------\n\n    from rootpy.plotting import Canvas\n    from rootpy.interactive import wait\n\n    c = Canvas()\n    c.Update()\n    wait()\n\n    c2 = Canvas()\n    c2.Update()\n    wait(True)\n    # This canvas can be killed by middle clicking on it or hitting\n    # escape whilst it has focus\n\n\"\"\"\nfrom __future__ import absolute_import\n\nimport threading\nfrom atexit import register\n\nimport ROOT\n\nfrom . import log; log = log[__name__]\nfrom ..defaults import extra_initialization\nfrom ..memory.keepalive import keepalive\nfrom .canvas_events import attach_event_handler\n\n__all__ = [\n    'wait_for_zero_canvases',\n    'wait_for_browser_close',\n    'wait',\n]\n\n_processRootEvents = None\n_finishSchedule = None\n__ACTIVE = False\n\n\n@extra_initialization\ndef fetch_vars():\n    global _processRootEvents, _finishSchedule, __ACTIVE\n    PyGUIThread = getattr(ROOT, 'PyGUIThread', None)\n    if PyGUIThread is not None:\n        _processRootEvents = getattr(PyGUIThread, \"_Thread__target\", None)\n        _finishSchedule = getattr(PyGUIThread, \"finishSchedule\", None)\n    if _processRootEvents is None:\n        log.warning(\n            \"unable to access ROOT's GUI thread either because \"\n            \"PyROOT's finalSetup() was called while in batch mode \"\n            \"or because PyROOT is using the new PyOS_InputHook \"\n            \"based mechanism that is not yet supported in rootpy \"\n            \"(PyConfig.StartGuiThread == 'inputhook' or \"\n            \"gSystem.InheritsFrom('TMacOSXSystem')). wait() etc. will \"\n            \"instead call raw_input() and wait for [Enter]\")\n    else:\n        __ACTIVE = True\n\n\ndef wait_failover(caller):\n    if not ROOT.gROOT.IsBatch():\n        log.warning(\n            \"{0} is failing over to raw_input()\".format(caller.__name__))\n        raw_input(\"press [Enter] to continue\")\n\n\ndef start_new_gui_thread():\n    \"\"\"\n    Attempt to start a new GUI thread, if possible.\n\n    It is only possible to start one if there was one running on module import.\n    \"\"\"\n    PyGUIThread = getattr(ROOT, 'PyGUIThread', None)\n\n    if PyGUIThread is not None:\n        assert not PyGUIThread.isAlive(), \"GUI thread already running!\"\n\n    assert _processRootEvents, (\n        \"GUI thread wasn't started when rootwait was imported, \"\n        \"so it can't be restarted\")\n\n    ROOT.keeppolling = 1\n    ROOT.PyGUIThread = threading.Thread(\n        None, _processRootEvents, None, (ROOT,))\n\n    ROOT.PyGUIThread.finishSchedule = _finishSchedule\n    ROOT.PyGUIThread.setDaemon(1)\n    ROOT.PyGUIThread.start()\n    log.debug(\"successfully started a new GUI thread\")\n\n\ndef stop_gui_thread():\n    \"\"\"\n    Try to stop the GUI thread. If it was running returns True,\n    otherwise False.\n    \"\"\"\n    PyGUIThread = getattr(ROOT, 'PyGUIThread', None)\n\n    if PyGUIThread is None or not PyGUIThread.isAlive():\n        log.debug(\"no existing GUI thread is runnng\")\n        return False\n\n    ROOT.keeppolling = 0\n    try:\n        PyGUIThread.finishSchedule()\n    except AttributeError:\n        log.debug(\"unable to call finishSchedule() on PyGUIThread\")\n        pass\n    PyGUIThread.join()\n    log.debug(\"successfully stopped the existing GUI thread\")\n    return True\n\n\ndef get_visible_canvases():\n    \"\"\"\n    Return a list of active GUI canvases\n    (as opposed to invisible Batch canvases)\n    \"\"\"\n    try:\n        return [c for c in ROOT.gROOT.GetListOfCanvases() if not c.IsBatch()]\n    except AttributeError:\n        # We might be exiting and ROOT.gROOT will raise an AttributeError\n        return []\n\n\ndef run_application_until_done():\n\n    had_gui_thread = stop_gui_thread()\n\n    ROOT.gApplication._threaded = True\n    ROOT.gApplication.Run(True)\n\n    if had_gui_thread:\n        start_new_gui_thread()\n\n\ndef dispatcher(f):\n    disp = ROOT.TPyDispatcher(f)\n    keepalive(disp, f)\n    return disp\n\n\ndef wait_for_zero_canvases(middle_mouse_close=False):\n    \"\"\"\n    Wait for all canvases to be closed, or CTRL-c.\n\n    If `middle_mouse_close`, middle click will shut the canvas.\n\n    incpy.ignore\n    \"\"\"\n    if not __ACTIVE:\n        wait_failover(wait_for_zero_canvases)\n        return\n\n    @dispatcher\n    def count_canvases():\n        \"\"\"\n        Count the number of active canvases and finish gApplication.Run()\n        if there are none remaining.\n\n        incpy.ignore\n        \"\"\"\n        if not get_visible_canvases():\n            try:\n                ROOT.gSystem.ExitLoop()\n            except AttributeError:\n                # We might be exiting and ROOT.gROOT will raise an AttributeError\n                pass\n\n    @dispatcher\n    def exit_application_loop():\n        \"\"\"\n        Signal handler for CTRL-c to cause gApplication.Run() to finish.\n\n        incpy.ignore\n        \"\"\"\n        ROOT.gSystem.ExitLoop()\n\n    # Handle CTRL-c\n    sh = ROOT.TSignalHandler(ROOT.kSigInterrupt, True)\n    sh.Add()\n    sh.Connect(\"Notified()\", \"TPyDispatcher\",\n               exit_application_loop, \"Dispatch()\")\n\n    visible_canvases = get_visible_canvases()\n\n    for canvas in visible_canvases:\n        log.debug(\"waiting for canvas {0} to close\".format(canvas.name))\n        canvas.Update()\n\n        if middle_mouse_close:\n            attach_event_handler(canvas)\n\n        if not getattr(canvas, \"_py_close_dispatcher_attached\", False):\n            # Attach a handler only once to each canvas\n            canvas._py_close_dispatcher_attached = True\n            canvas.Connect(\"Closed()\", \"TPyDispatcher\",\n                           count_canvases, \"Dispatch()\")\n            keepalive(canvas, count_canvases)\n\n    if visible_canvases and not ROOT.gROOT.IsBatch():\n        run_application_until_done()\n\n        # Disconnect from canvases\n        for canvas in visible_canvases:\n            if getattr(canvas, \"_py_close_dispatcher_attached\", False):\n                canvas._py_close_dispatcher_attached = False\n                canvas.Disconnect(\"Closed()\", count_canvases, \"Dispatch()\")\n\nwait = wait_for_zero_canvases\n\n\ndef wait_for_frame(frame):\n    \"\"\"\n    wait until a TGMainFrame is closed or ctrl-c\n    \"\"\"\n    if not frame:\n        # It's already closed or maybe we're in batch mode\n        return\n\n    @dispatcher\n    def close():\n        ROOT.gSystem.ExitLoop()\n\n    if not getattr(frame, \"_py_close_dispatcher_attached\", False):\n        frame._py_close_dispatcher_attached = True\n        frame.Connect(\"CloseWindow()\", \"TPyDispatcher\", close, \"Dispatch()\")\n\n    @dispatcher\n    def exit_application_loop():\n        \"\"\"\n        Signal handler for CTRL-c to cause gApplication.Run() to finish.\n\n        incpy.ignore\n        \"\"\"\n        ROOT.gSystem.ExitLoop()\n\n    # Handle CTRL-c\n    sh = ROOT.TSignalHandler(ROOT.kSigInterrupt, True)\n    sh.Add()\n    sh.Connect(\"Notified()\", \"TPyDispatcher\",\n               exit_application_loop, \"Dispatch()\")\n\n    if not ROOT.gROOT.IsBatch():\n        run_application_until_done()\n        # Need to disconnect to prevent close handler from running when python\n        # teardown has already commenced.\n        frame.Disconnect(\"CloseWindow()\", close, \"Dispatch()\")\n\n\ndef wait_for_browser_close(b):\n    \"\"\"\n    Can be used to wait until a TBrowser is closed\n    \"\"\"\n    if b:\n        if not __ACTIVE:\n            wait_failover(wait_for_browser_close)\n            return\n        wait_for_frame(b.GetBrowserImp().GetMainFrame())\n\n\ndef prevent_close_with_canvases():\n    \"\"\"\n    Register a handler which prevents python from exiting until\n    all canvases are closed\n    \"\"\"\n    register(wait_for_zero_canvases)\n", "path": "rootpy/interactive/rootwait.py"}], "after_files": [{"content": "# Copyright 2012 the rootpy developers\n# distributed under the terms of the GNU General Public License\n\"\"\"\nThe functions in this module provide a way of pausing code execution until\ncanvases are closed. This can be useful when testing code and you don't want to\nkeep the objects alive outside of your function.\n\nThe wait function can be called repeatedly to pause multiple times.\n\nwait_for_zero_canvases()\n    Keeps root alive until CTRL-c is pressed or all canvases are closed\n\nwait_for_zero_canvases(middle_mouse_close=True)\n    allows canvases to be closed with the middle mouse button (see below)\n\nwait is shorthand for wait_for_zero_canvases\n\nExamples\n--------\n\n    from rootpy.plotting import Canvas\n    from rootpy.interactive import wait\n\n    c = Canvas()\n    c.Update()\n    wait()\n\n    c2 = Canvas()\n    c2.Update()\n    wait(True)\n    # This canvas can be killed by middle clicking on it or hitting\n    # escape whilst it has focus\n\n\"\"\"\nfrom __future__ import absolute_import\n\nimport threading\nfrom atexit import register\n\nimport ROOT\n\nfrom . import log; log = log[__name__]\nfrom ..defaults import extra_initialization\nfrom ..memory.keepalive import keepalive\nfrom .canvas_events import attach_event_handler\n\n__all__ = [\n    'wait_for_zero_canvases',\n    'wait_for_browser_close',\n    'wait',\n]\n\n_processRootEvents = None\n_finishSchedule = None\n__ACTIVE = False\n\n\n@extra_initialization\ndef fetch_vars():\n    global _processRootEvents, _finishSchedule, __ACTIVE\n    PyGUIThread = getattr(ROOT, 'PyGUIThread', None)\n    if PyGUIThread is not None:\n        _processRootEvents = getattr(PyGUIThread, \"_Thread__target\", None)\n        _finishSchedule = getattr(PyGUIThread, \"finishSchedule\", None)\n    if _processRootEvents is None:\n        log.warning(\n            \"unable to access ROOT's GUI thread either because \"\n            \"PyROOT's finalSetup() was called while in batch mode \"\n            \"or because PyROOT is using the new PyOS_InputHook \"\n            \"based mechanism that is not yet supported in rootpy \"\n            \"(PyConfig.StartGuiThread == 'inputhook' or \"\n            \"gSystem.InheritsFrom('TMacOSXSystem')). wait() etc. will \"\n            \"instead call raw_input() and wait for [Enter]\")\n    else:\n        __ACTIVE = True\n\n\ndef wait_failover(caller):\n    if not ROOT.gROOT.IsBatch():\n        log.warning(\n            \"{0} is failing over to raw_input()\".format(caller.__name__))\n        raw_input(\"press [Enter] to continue\")\n\n\ndef start_new_gui_thread():\n    \"\"\"\n    Attempt to start a new GUI thread, if possible.\n\n    It is only possible to start one if there was one running on module import.\n    \"\"\"\n    PyGUIThread = getattr(ROOT, 'PyGUIThread', None)\n\n    if PyGUIThread is not None:\n        assert not PyGUIThread.isAlive(), \"GUI thread already running!\"\n\n    assert _processRootEvents, (\n        \"GUI thread wasn't started when rootwait was imported, \"\n        \"so it can't be restarted\")\n\n    ROOT.keeppolling = 1\n    ROOT.PyGUIThread = threading.Thread(\n        None, _processRootEvents, None, (ROOT,))\n\n    ROOT.PyGUIThread.finishSchedule = _finishSchedule\n    ROOT.PyGUIThread.setDaemon(1)\n    ROOT.PyGUIThread.start()\n    log.debug(\"successfully started a new GUI thread\")\n\n\ndef stop_gui_thread():\n    \"\"\"\n    Try to stop the GUI thread. If it was running returns True,\n    otherwise False.\n    \"\"\"\n    PyGUIThread = getattr(ROOT, 'PyGUIThread', None)\n\n    if PyGUIThread is None or not PyGUIThread.isAlive():\n        log.debug(\"no existing GUI thread is runnng\")\n        return False\n\n    ROOT.keeppolling = 0\n    try:\n        PyGUIThread.finishSchedule()\n    except AttributeError:\n        log.debug(\"unable to call finishSchedule() on PyGUIThread\")\n        pass\n    PyGUIThread.join()\n    log.debug(\"successfully stopped the existing GUI thread\")\n    return True\n\n\ndef get_visible_canvases():\n    \"\"\"\n    Return a list of active GUI canvases\n    (as opposed to invisible Batch canvases)\n    \"\"\"\n    try:\n        return [c for c in ROOT.gROOT.GetListOfCanvases() if not c.IsBatch()]\n    except AttributeError:\n        # We might be exiting and ROOT.gROOT will raise an AttributeError\n        return []\n\n\ndef run_application_until_done():\n\n    had_gui_thread = stop_gui_thread()\n\n    ROOT.gApplication._threaded = True\n    ROOT.gApplication.Run(True)\n\n    if had_gui_thread:\n        start_new_gui_thread()\n\n\ndef dispatcher(f):\n    disp = ROOT.TPyDispatcher(f)\n    keepalive(disp, f)\n    return disp\n\n\ndef wait_for_zero_canvases(middle_mouse_close=False):\n    \"\"\"\n    Wait for all canvases to be closed, or CTRL-c.\n\n    If `middle_mouse_close`, middle click will shut the canvas.\n\n    incpy.ignore\n    \"\"\"\n    if not __ACTIVE:\n        wait_failover(wait_for_zero_canvases)\n        return\n\n    @dispatcher\n    def count_canvases():\n        \"\"\"\n        Count the number of active canvases and finish gApplication.Run()\n        if there are none remaining.\n\n        incpy.ignore\n        \"\"\"\n        if not get_visible_canvases():\n            try:\n                ROOT.gSystem.ExitLoop()\n            except AttributeError:\n                # We might be exiting and ROOT.gROOT will raise an AttributeError\n                pass\n\n    @dispatcher\n    def exit_application_loop():\n        \"\"\"\n        Signal handler for CTRL-c to cause gApplication.Run() to finish.\n\n        incpy.ignore\n        \"\"\"\n        ROOT.gSystem.ExitLoop()\n\n    # Handle CTRL-c\n    sh = ROOT.TSignalHandler(ROOT.kSigInterrupt, True)\n    sh.Add()\n    sh.Connect(\"Notified()\", \"TPyDispatcher\",\n               exit_application_loop, \"Dispatch()\")\n\n    visible_canvases = get_visible_canvases()\n\n    for canvas in visible_canvases:\n        log.debug(\"waiting for canvas {0} to close\".format(canvas.GetName()))\n        canvas.Update()\n\n        if middle_mouse_close:\n            attach_event_handler(canvas)\n\n        if not getattr(canvas, \"_py_close_dispatcher_attached\", False):\n            # Attach a handler only once to each canvas\n            canvas._py_close_dispatcher_attached = True\n            canvas.Connect(\"Closed()\", \"TPyDispatcher\",\n                           count_canvases, \"Dispatch()\")\n            keepalive(canvas, count_canvases)\n\n    if visible_canvases and not ROOT.gROOT.IsBatch():\n        run_application_until_done()\n\n        # Disconnect from canvases\n        for canvas in visible_canvases:\n            if getattr(canvas, \"_py_close_dispatcher_attached\", False):\n                canvas._py_close_dispatcher_attached = False\n                canvas.Disconnect(\"Closed()\", count_canvases, \"Dispatch()\")\n\nwait = wait_for_zero_canvases\n\n\ndef wait_for_frame(frame):\n    \"\"\"\n    wait until a TGMainFrame is closed or ctrl-c\n    \"\"\"\n    if not frame:\n        # It's already closed or maybe we're in batch mode\n        return\n\n    @dispatcher\n    def close():\n        ROOT.gSystem.ExitLoop()\n\n    if not getattr(frame, \"_py_close_dispatcher_attached\", False):\n        frame._py_close_dispatcher_attached = True\n        frame.Connect(\"CloseWindow()\", \"TPyDispatcher\", close, \"Dispatch()\")\n\n    @dispatcher\n    def exit_application_loop():\n        \"\"\"\n        Signal handler for CTRL-c to cause gApplication.Run() to finish.\n\n        incpy.ignore\n        \"\"\"\n        ROOT.gSystem.ExitLoop()\n\n    # Handle CTRL-c\n    sh = ROOT.TSignalHandler(ROOT.kSigInterrupt, True)\n    sh.Add()\n    sh.Connect(\"Notified()\", \"TPyDispatcher\",\n               exit_application_loop, \"Dispatch()\")\n\n    if not ROOT.gROOT.IsBatch():\n        run_application_until_done()\n        # Need to disconnect to prevent close handler from running when python\n        # teardown has already commenced.\n        frame.Disconnect(\"CloseWindow()\", close, \"Dispatch()\")\n\n\ndef wait_for_browser_close(b):\n    \"\"\"\n    Can be used to wait until a TBrowser is closed\n    \"\"\"\n    if b:\n        if not __ACTIVE:\n            wait_failover(wait_for_browser_close)\n            return\n        wait_for_frame(b.GetBrowserImp().GetMainFrame())\n\n\ndef prevent_close_with_canvases():\n    \"\"\"\n    Register a handler which prevents python from exiting until\n    all canvases are closed\n    \"\"\"\n    register(wait_for_zero_canvases)\n", "path": "rootpy/interactive/rootwait.py"}]}