Re: tkinter newbie question
KP wrote: > See my code below (which works). >From the import of lowercase "tkinter" I conclude you are using Python 3. > I'd like to have the 2nd window as a > class in a separate unit. How do I code that unit and how do I call it > from my first unit? > > As always, thanks for all help! Move the code from open_window2() into a class in settings.py, e. g. import tkinter as tk # avoid star-import class SettingsWindow(tk.Toplevel): # Class names start with uppercase letter # Prefer self-explaining names def __init__(self, root): super().__init__(root) self.title('New window') self.geometry('262x65+200+250') self.transient(root) Then use it in your main script: > #!/usr/bin/env python > """ > """ > from tkinter import * import settings > class window1(): > > def open_window2(self): settings.SettingsWindow(self.root) > def setup_menu(self): > self.menubar = Menu(self.root) > self.menu1 = Menu(self.menubar, tearoff=0 ) > self.menu1.add_command(label="Settings", accelerator='Ctrl+S', > command=self.open_window2) self.menubar.add_cascade(label="Menu > 1", menu=self.menu1) self.root.config(menu=self.menubar) > > def __init__(self): > self.root = Tk() > self.root.title('Window #1') > self.setup_menu() > self.root.geometry('800x600+200+200') > # > self.root.mainloop() > > if __name__ == '__main__': > > w1 = window1() -- https://mail.python.org/mailman/listinfo/python-list
Re: Question about asyncio and blocking operations
"Ian Kelly" wrote in message news:calwzidngogpx+cpmvba8vpefuq4-bwmvs0gz3shb0owzi0b...@mail.gmail.com... On Sat, Jan 23, 2016 at 7:38 AM, Frank Millman wrote: > Here is the difficulty. The recommended way to handle a blocking > operation > is to run it as task in a different thread, using run_in_executor(). > This > method is a coroutine. An implication of this is that any method that > calls > it must also be a coroutine, so I end up with a chain of coroutines > stretching all the way back to the initial event that triggered it. This seems to be a common misapprehension about asyncio programming. While coroutines are the focus of the library, they're based on futures, and so by working at a slightly lower level you can also handle them as such. So while this would be the typical way to use run_in_executor: async def my_coroutine(stuff): value = await get_event_loop().run_in_executor(None, blocking_function, stuff) result = await do_something_else_with(value) return result This is also a perfectly valid way to use it: def normal_function(stuff): loop = get_event_loop() coro = loop.run_in_executor(None, blocking_function, stuff) task = loop.create_task(coro) task.add_done_callback(do_something_else) return task I am struggling to get my head around this. 1. In the second function, AFAICT coro is already a future. Why is it necessary to turn it into a task? In fact when I tried that in my testing, I got an assertion error - File: "C:\Python35\lib\asyncio\base_events.py", line 211, in create_task task = tasks.Task(coro, loop=self) File: "C:\Python35\lib\asyncio\tasks.py", line 70, in __init__ assert coroutines.iscoroutine(coro), repr(coro) AssertionError: 2. In the first function, calling 'run_in_executor' unblocks the main loop so that it can continue with other tasks, but the function itself is suspended until the blocking function returns. In the second function, I cannot see how the function gets suspended. It looks as if the blocking function will run in the background, and the main function will continue. I would like to experiment with this further, but I would need to see the broader context - IOW see the 'caller' of normal_function(), and see what it does with the return value. I feel I am getting closer to an 'aha' moment, but I am not there yet, so all info is appreciated. Frank -- https://mail.python.org/mailman/listinfo/python-list
Re: Question about asyncio and blocking operations
"Ian Kelly" wrote in message news:calwzidngogpx+cpmvba8vpefuq4-bwmvs0gz3shb0owzi0b...@mail.gmail.com... On Sat, Jan 23, 2016 at 7:38 AM, Frank Millman wrote: > Here is the difficulty. The recommended way to handle a blocking > operation > is to run it as task in a different thread, using run_in_executor(). > This > method is a coroutine. An implication of this is that any method that > calls > it must also be a coroutine, so I end up with a chain of coroutines > stretching all the way back to the initial event that triggered it. This seems to be a common misapprehension about asyncio programming. While coroutines are the focus of the library, they're based on futures, and so by working at a slightly lower level you can also handle them as such. So while this would be the typical way to use run_in_executor: async def my_coroutine(stuff): value = await get_event_loop().run_in_executor(None, blocking_function, stuff) result = await do_something_else_with(value) return result This is also a perfectly valid way to use it: def normal_function(stuff): loop = get_event_loop() coro = loop.run_in_executor(None, blocking_function, stuff) task = loop.create_task(coro) task.add_done_callback(do_something_else) return task I am struggling to get my head around this. 1. In the second function, AFAICT coro is already a future. Why is it necessary to turn it into a task? In fact when I tried that in my testing, I got an assertion error - File: "C:\Python35\lib\asyncio\base_events.py", line 211, in create_task task = tasks.Task(coro, loop=self) File: "C:\Python35\lib\asyncio\tasks.py", line 70, in __init__ assert coroutines.iscoroutine(coro), repr(coro) AssertionError: 2. In the first function, calling 'run_in_executor' unblocks the main loop so that it can continue with other tasks, but the function itself is suspended until the blocking function returns. In the second function, I cannot see how the function gets suspended. It looks as if the blocking function will run in the background, and the main function will continue. I would like to experiment with this further, but I would need to see the broader context - IOW see the 'caller' of normal_function(), and see what it does with the return value. I feel I am getting closer to an 'aha' moment, but I am not there yet, so all info is appreciated. Frank -- https://mail.python.org/mailman/listinfo/python-list
Re: tkinter newbie question
On Sunday, 24 January 2016 20:20:07 UTC-8, KP wrote: > See my code below (which works). I'd like to have the 2nd window as a class > in a separate unit. How do I code that unit and how do I call it from my > first unit? > > As always, thanks for all help! > > > > > #!/usr/bin/env python > """ > """ > from tkinter import * > from settings import * > > class window1(): > > def open_window2(self): > t = Toplevel(self.root) > t.title('New window') > t.geometry('262x65+200+250') > t.transient(self.root) > > def setup_menu(self): > self.menubar = Menu(self.root) > self.menu1 = Menu(self.menubar, tearoff=0 ) > self.menu1.add_command(label="Settings", accelerator='Ctrl+S', > command=self.open_window2) > self.menubar.add_cascade(label="Menu 1", menu=self.menu1) > self.root.config(menu=self.menubar) > > def __init__(self): > self.root = Tk() > self.root.title('Window #1') > self.setup_menu() > self.root.geometry('800x600+200+200') > # > self.root.mainloop() > > if __name__ == '__main__': > > w1 = window1() Thank you - much appreciated! -- https://mail.python.org/mailman/listinfo/python-list
Re: Question about asyncio and blocking operations
On Jan 25, 2016 2:04 AM, "Frank Millman" wrote: > > "Ian Kelly" wrote in message news:calwzidngogpx+cpmvba8vpefuq4-bwmvs0gz3shb0owzi0b...@mail.gmail.com... >> >> This seems to be a common misapprehension about asyncio programming. >> While coroutines are the focus of the library, they're based on >> futures, and so by working at a slightly lower level you can also >> handle them as such. So while this would be the typical way to use >> run_in_executor: >> >> async def my_coroutine(stuff): >> value = await get_event_loop().run_in_executor(None, >> blocking_function, stuff) >> result = await do_something_else_with(value) >> return result >> >> This is also a perfectly valid way to use it: >> >> def normal_function(stuff): >> loop = get_event_loop() >> coro = loop.run_in_executor(None, blocking_function, stuff) >> task = loop.create_task(coro) >> task.add_done_callback(do_something_else) >> return task > > > I am struggling to get my head around this. > > 1. In the second function, AFAICT coro is already a future. Why is it necessary to turn it into a task? In fact when I tried that in my testing, I got an assertion error - > > File: "C:\Python35\lib\asyncio\base_events.py", line 211, in create_task >task = tasks.Task(coro, loop=self) > File: "C:\Python35\lib\asyncio\tasks.py", line 70, in __init__ >assert coroutines.iscoroutine(coro), repr(coro) > AssertionError: I didn't test this; it was based on the documentation, which says that run_in_executor is a coroutine. Looking at the source, it's actually a function that returns a future, so this may be a documentation bug. There's no need to get a task specifically. We just need a future so that callbacks can be added, so if the result of run_in_executor is already a future then the create_task call is unnecessary. To be safe, you could replace that call with asyncio.ensure_future, which accepts any awaitable and returns a future. > 2. In the first function, calling 'run_in_executor' unblocks the main loop so that it can continue with other tasks, but the function itself is suspended until the blocking function returns. In the second function, I cannot see how the function gets suspended. It looks as if the blocking function will run in the background, and the main function will continue. Correct. It's not a coroutine, so it has no facility for being suspended and resumed; it can only block or return. That's why the callback is necessary to schedule additional code to run after blocking_function finishes. normal_function itself can continue to make other non-blocking calls such as scheduling additional tasks, but it shouldn't do anything that depends on the result of blocking_function since it can't be assumed to be available yet. > I would like to experiment with this further, but I would need to see the broader context - IOW see the 'caller' of normal_function(), and see what it does with the return value. The caller of normal_function can do anything it wants with the return value, including adding additional callbacks or just discarding it. The caller could be a coroutine or another normal non-blocking function. If it's a coroutine, then it can await the future, but it doesn't need to unless it wants to do something with the result. Depending on what the future represents, it might also be considered internal to normal_function, in which case it shouldn't be returned at all. -- https://mail.python.org/mailman/listinfo/python-list
Re: Question about asyncio and blocking operations
On Mon, Jan 25, 2016 at 8:32 AM, Ian Kelly wrote: > > On Jan 25, 2016 2:04 AM, "Frank Millman" wrote: >> >> "Ian Kelly" wrote in message >> news:calwzidngogpx+cpmvba8vpefuq4-bwmvs0gz3shb0owzi0b...@mail.gmail.com... >>> >>> This seems to be a common misapprehension about asyncio programming. >>> While coroutines are the focus of the library, they're based on >>> futures, and so by working at a slightly lower level you can also >>> handle them as such. So while this would be the typical way to use >>> run_in_executor: >>> >>> async def my_coroutine(stuff): >>> value = await get_event_loop().run_in_executor(None, >>> blocking_function, stuff) >>> result = await do_something_else_with(value) >>> return result >>> >>> This is also a perfectly valid way to use it: >>> >>> def normal_function(stuff): >>> loop = get_event_loop() >>> coro = loop.run_in_executor(None, blocking_function, stuff) >>> task = loop.create_task(coro) >>> task.add_done_callback(do_something_else) >>> return task >> >> >> I am struggling to get my head around this. >> >> 1. In the second function, AFAICT coro is already a future. Why is it >> necessary to turn it into a task? In fact when I tried that in my testing, I >> got an assertion error - >> >> File: "C:\Python35\lib\asyncio\base_events.py", line 211, in create_task >>task = tasks.Task(coro, loop=self) >> File: "C:\Python35\lib\asyncio\tasks.py", line 70, in __init__ >>assert coroutines.iscoroutine(coro), repr(coro) >> AssertionError: > > I didn't test this; it was based on the documentation, which says that > run_in_executor is a coroutine. Looking at the source, it's actually a > function that returns a future, so this may be a documentation bug. And now I'm reminded of this note in the asyncio docs: """ Note: In this documentation, some methods are documented as coroutines, even if they are plain Python functions returning a Future. This is intentional to have a freedom of tweaking the implementation of these functions in the future. If such a function is needed to be used in a callback-style code, wrap its result with ensure_future(). """ IMO such methods should simply be documented as awaitables, not coroutines. I wonder if that's already settled, or if it's worth starting a discussion around. -- https://mail.python.org/mailman/listinfo/python-list
Re: tkinter newbie question
On Monday, 25 January 2016 08:22:12 UTC-8, KP wrote: > On Monday, 25 January 2016 00:51:34 UTC-8, Peter Otten wrote: > > KP wrote: > > > > > See my code below (which works). > > > > >From the import of lowercase "tkinter" I conclude you are using Python 3. > > > > > I'd like to have the 2nd window as a > > > class in a separate unit. How do I code that unit and how do I call it > > > from my first unit? > > > > > > As always, thanks for all help! > > > > Move the code from open_window2() into a class in settings.py, e. g. > > > > > > import tkinter as tk # avoid star-import > > > > class SettingsWindow(tk.Toplevel): # Class names start with uppercase letter > ># Prefer self-explaining names > > def __init__(self, root): > > super().__init__(root) > > self.title('New window') > > self.geometry('262x65+200+250') > > self.transient(root) > > > > Then use it in your main script: > > > > > > > #!/usr/bin/env python > > > """ > > > """ > > > from tkinter import * > > import settings > > > > > class window1(): > > > > > > def open_window2(self): > > settings.SettingsWindow(self.root) > > > > > def setup_menu(self): > > > self.menubar = Menu(self.root) > > > self.menu1 = Menu(self.menubar, tearoff=0 ) > > > self.menu1.add_command(label="Settings", accelerator='Ctrl+S', > > > command=self.open_window2) self.menubar.add_cascade(label="Menu > > > 1", menu=self.menu1) self.root.config(menu=self.menubar) > > > > > > def __init__(self): > > > self.root = Tk() > > > self.root.title('Window #1') > > > self.setup_menu() > > > self.root.geometry('800x600+200+200') > > > # > > > self.root.mainloop() > > > > > > if __name__ == '__main__': > > > > > > w1 = window1() > > Dang - almost there. Using your code, I get the new window with the specified > geometry and its type is transient, as expected. > > Its caption, however, is NOT the caption specified, but the caption of the > first window, leaving me with 2 windows with identical caption. > > Any idea why? Forget that post - mea culpa - figured it out - sorry! -- https://mail.python.org/mailman/listinfo/python-list
Re: tkinter newbie question
On Monday, 25 January 2016 00:51:34 UTC-8, Peter Otten wrote: > KP wrote: > > > See my code below (which works). > > >From the import of lowercase "tkinter" I conclude you are using Python 3. > > > I'd like to have the 2nd window as a > > class in a separate unit. How do I code that unit and how do I call it > > from my first unit? > > > > As always, thanks for all help! > > Move the code from open_window2() into a class in settings.py, e. g. > > > import tkinter as tk # avoid star-import > > class SettingsWindow(tk.Toplevel): # Class names start with uppercase letter ># Prefer self-explaining names > def __init__(self, root): > super().__init__(root) > self.title('New window') > self.geometry('262x65+200+250') > self.transient(root) > > Then use it in your main script: > > > > #!/usr/bin/env python > > """ > > """ > > from tkinter import * > import settings > > > class window1(): > > > > def open_window2(self): > settings.SettingsWindow(self.root) > > > def setup_menu(self): > > self.menubar = Menu(self.root) > > self.menu1 = Menu(self.menubar, tearoff=0 ) > > self.menu1.add_command(label="Settings", accelerator='Ctrl+S', > > command=self.open_window2) self.menubar.add_cascade(label="Menu > > 1", menu=self.menu1) self.root.config(menu=self.menubar) > > > > def __init__(self): > > self.root = Tk() > > self.root.title('Window #1') > > self.setup_menu() > > self.root.geometry('800x600+200+200') > > # > > self.root.mainloop() > > > > if __name__ == '__main__': > > > > w1 = window1() Dang - almost there. Using your code, I get the new window with the specified geometry and its type is transient, as expected. Its caption, however, is NOT the caption specified, but the caption of the first window, leaving me with 2 windows with identical caption. Any idea why? -- https://mail.python.org/mailman/listinfo/python-list
Re: .format won't display my value with 2 decimal places: Why?
On Sun, Jan 24, 2016 at 2:20 PM, MRAB wrote: > The format method, on the other hand, belongs to the format string it's > attached to. In this example: > > 'The new price is {}' .format(newPrice, '.2f') > > the format string is 'The new price is {}' and you're calling its 'format' > method with 2 values for that string, the first being 4.0 (used) and the > second on being '.2f' (unused). > > What you want is: > > print('The new price is {:.2f}'.format(newPrice)) Why doesn't str.format raise an exception when passed extra positional arguments? -- https://mail.python.org/mailman/listinfo/python-list
Re[2]: .format won't display my value with 2 decimal places: Why?
On 2016-01-25 16:51:36, "Ian Kelly" wrote: On Sun, Jan 24, 2016 at 2:20 PM, MRAB wrote: The format method, on the other hand, belongs to the format string it's attached to. In this example: 'The new price is {}' .format(newPrice, '.2f') the format string is 'The new price is {}' and you're calling its 'format' method with 2 values for that string, the first being 4.0 (used) and the second on being '.2f' (unused). What you want is: print('The new price is {:.2f}'.format(newPrice)) Why doesn't str.format raise an exception when passed extra positional arguments? That format string uses auto-numbering, and it's equivalent to 'The new price is {0:.2f}'. In general, the positional arguments can be used in any order, and there can also be keyword arguments, so it would need to remember which arguments had been used. Would it be worth it? Do you really want to insist that the format string always used _all_ of the arguments? -- https://mail.python.org/mailman/listinfo/python-list
Re: .format won't display my value with 2 decimal places: Why?
On Tue, Jan 26, 2016 at 3:51 AM, Ian Kelly wrote: > On Sun, Jan 24, 2016 at 2:20 PM, MRAB wrote: >> The format method, on the other hand, belongs to the format string it's >> attached to. In this example: >> >> 'The new price is {}' .format(newPrice, '.2f') >> >> the format string is 'The new price is {}' and you're calling its 'format' >> method with 2 values for that string, the first being 4.0 (used) and the >> second on being '.2f' (unused). >> >> What you want is: >> >> print('The new price is {:.2f}'.format(newPrice)) > > Why doesn't str.format raise an exception when passed extra positional > arguments? That's a very good question. I suspect the answer will have to do with i18n and the way you can reorder arguments; if some translations don't use a token at all, it shouldn't be a fatal error that you have to hack around by formatting something into zero characters. It may be worth adding a special case: if no positional selectors are used, the number of arguments must match the number of placeholders. For comparison, here's how Pike does things (%O is roughly equivalent to Python's {!r}): > sprintf("%O", 1); (1) Result: "1" > sprintf("%O %O", 1, 2); (2) Result: "1 2" > sprintf("%O", 1, 2); Compiler Error: 1: Too many arguments to sprintf (expected 2 arguments). Compiler Error: 1: Got : int(2..2). > sprintf("%[0]O", 1, 2); (3) Result: "1" > sprintf("%[1]O", 1, 2); (4) Result: "2" If you're doing i18n, you probably want to use {0} {1} anyway; and if you're deliberately ignoring some of the parameters, it's not too much hassle to be explicit about which parameters you're not ignoring. IMO this would be a useful protection. You get it with percent formatting, but currently not with .format(). ChrisA -- https://mail.python.org/mailman/listinfo/python-list
Re: .format won't display my value with 2 decimal places: Why?
On Mon, Jan 25, 2016, at 12:19, MRAB wrote: > Do you really want to insist that the format string always used _all_ of > the arguments? Um, yes? Why on earth _wouldn't_ you want to insist that? -- https://mail.python.org/mailman/listinfo/python-list
Re: .format won't display my value with 2 decimal places: Why?
On Mon, Jan 25, 2016, at 12:23, Chris Angelico wrote: > if some translations don't use a token at all, I'm not sure what situation that would be reasonable in. -- https://mail.python.org/mailman/listinfo/python-list
Re: Re[2]: .format won't display my value with 2 decimal places: Why?
On Mon, Jan 25, 2016 at 10:19 AM, MRAB wrote: > > > On 2016-01-25 16:51:36, "Ian Kelly" wrote: > >> >> Why doesn't str.format raise an exception when passed extra positional >> arguments? >> > That format string uses auto-numbering, and it's equivalent to 'The new > price is {0:.2f}'. > > In general, the positional arguments can be used in any order, and there can > also be keyword arguments, so it would need to remember which arguments had > been used. Would it be worth it? > > Do you really want to insist that the format string always used _all_ of the > arguments? Good point, that makes sense. For example, I would expect this to work: '{0} {2}'.format(*some_list) as long as some_list has three elements. I wouldn't expect it to fail just because the middle element is unused, so why should it fail if there are trailing elements that are unused? -- https://mail.python.org/mailman/listinfo/python-list
Re: Re[2]: .format won't display my value with 2 decimal places: Why?
On Tue, Jan 26, 2016 at 4:31 AM, Ian Kelly wrote: >> Do you really want to insist that the format string always used _all_ of the >> arguments? > > Good point, that makes sense. For example, I would expect this to work: > > '{0} {2}'.format(*some_list) > > as long as some_list has three elements. I wouldn't expect it to fail > just because the middle element is unused, so why should it fail if > there are trailing elements that are unused? That's using selectors, so under my suggested semantics, that would still work - as long as it has *at least* three elements, the middle one and any extras after the third are all ignored. ChrisA -- https://mail.python.org/mailman/listinfo/python-list
Re: .format won't display my value with 2 decimal places: Why?
On Tue, Jan 26, 2016 at 4:32 AM, Random832 wrote: > On Mon, Jan 25, 2016, at 12:23, Chris Angelico wrote: >> if some translations don't use a token at all, > > I'm not sure what situation that would be reasonable in. I don't do much with different human languages, but it's possible that you might build up a message in a variety of different ways, and include tokens differently. Maybe you'd include a product name in two different places, and each translation would get to choose which of the lines includes it. Maybe there's a fixed string that carries the sense of what you're saying better than the parameterized one does, so you ignore the parameter. It's the same flexibility as reordering tokens, but some tokens get reordered to nowhere. (Is it still a teleportation spell when the destination is oblivion? -- Venser) ChrisA -- https://mail.python.org/mailman/listinfo/python-list
Re: .format won't display my value with 2 decimal places: Why?
On Mon, Jan 25, 2016 at 9:48 AM, Chris Angelico wrote: > On Tue, Jan 26, 2016 at 4:32 AM, Random832 wrote: > > On Mon, Jan 25, 2016, at 12:23, Chris Angelico wrote: > >> if some translations don't use a token at all, > > > > I'm not sure what situation that would be reasonable in. > > I don't do much with different human languages, but it's possible that > you might build up a message in a variety of different ways, and > include tokens differently. Maybe you'd include a product name in two > different places, and each translation would get to choose which of > the lines includes it. Maybe there's a fixed string that carries the > sense of what you're saying better than the parameterized one does, so > you ignore the parameter. It's the same flexibility as reordering > tokens, but some tokens get reordered to nowhere. (Is it still a > teleportation spell when the destination is oblivion? -- Venser) One of the most useful reasons to not require all arguments be used is when using the string as part of a templating system, though in those cases, using named (over positional) arguments makes it easiest. While I have not seen any cases where some arguments go unused in other languages, it is often useful to generate a bunch of data, and let a designer or translator decide on the exact arguments to use in a specific string. Often times, this will mean using different template strings, which only use a subset (and sometimes even none) of the arguments. While not using Python, a project I am working on uses this for some of the data being displayed. In this case, some of the template strings do not use any template values, while others use multiple, but rather than have to special case each variation, it can just run the template strings though formatting code. This is particularly useful in the cases where a quantity is included, and variations are used for singular vs plural cases. -- https://mail.python.org/mailman/listinfo/python-list
Tkinter spacing
If I want to have some space between, say, btn_last & btn_new, will I have to use a dummy label in between these two or is there a better way? Thanks for any help, as always! from tkinter import * from tkinter import ttk root = Tk() root.geometry("822x600+100+100") nav_bar = ttk.Frame(root, borderwidth=2, relief='ridge', padding=(10, 3, 10, 3)) btn_first = ttk.Button(nav_bar, text='|<', width=4) # for buttons showing text only, this will be text units (= average characters?) btn_prev = ttk.Button(nav_bar, text='<', width=4) # for image buttons, it will be in pixels btn_next = ttk.Button(nav_bar, text='>', width=4) btn_last = ttk.Button(nav_bar, text='>|', width=4) btn_new= ttk.Button(nav_bar, text='New') btn_edit = ttk.Button(nav_bar, text='Edit') btn_delete = ttk.Button(nav_bar, text='Delete') btn_cancel = ttk.Button(nav_bar, text='Cancel') btn_print = ttk.Button(nav_bar, text='Print') btn_help = ttk.Button(nav_bar, text='Help') btn_save = ttk.Button(nav_bar, text='Save') lbl_Recs = ttk.Label(nav_bar, text='Records') lbl_RCount = ttk.Label(nav_bar, text='0 ', width=10, borderwidth=2, relief='sunken', anchor='e') # fake entry look nav_bar.grid(column=0, row=0, columnspan=13) btn_first.grid(column=0, row=0) btn_prev.grid(column=1, row=0) btn_next.grid(column=2, row=0) btn_last.grid(column=3, row=0) btn_new.grid(column=4,row=0) btn_edit.grid(column=5, row=0) btn_delete.grid(column=6, row=0) btn_cancel.grid(column=7, row=0) lbl_Recs.grid(column=8, row=0, padx=5) lbl_RCount.grid(column=9, row=0, padx=5) btn_print.grid(column=10, row=0) btn_help.grid(column=11, row=0) btn_save.grid(column=12, row=0) root.mainloop() -- https://mail.python.org/mailman/listinfo/python-list
Re: Question about asyncio and blocking operations
On Monday, January 25, 2016 at 9:16:13 PM UTC+5:30, Ian wrote: > On Mon, Jan 25, 2016 at 8:32 AM, Ian Kelly wrote: > > > > On Jan 25, 2016 2:04 AM, "Frank Millman" wrote: > >> > >> "Ian Kelly" wrote in message > >>> > >>> This seems to be a common misapprehension about asyncio programming. > >>> While coroutines are the focus of the library, they're based on > >>> futures, and so by working at a slightly lower level you can also > >>> handle them as such. So while this would be the typical way to use > >>> run_in_executor: > >>> > >>> async def my_coroutine(stuff): > >>> value = await get_event_loop().run_in_executor(None, > >>> blocking_function, stuff) > >>> result = await do_something_else_with(value) > >>> return result > >>> > >>> This is also a perfectly valid way to use it: > >>> > >>> def normal_function(stuff): > >>> loop = get_event_loop() > >>> coro = loop.run_in_executor(None, blocking_function, stuff) > >>> task = loop.create_task(coro) > >>> task.add_done_callback(do_something_else) > >>> return task > >> > >> > >> I am struggling to get my head around this. > >> > >> 1. In the second function, AFAICT coro is already a future. Why is it > >> necessary to turn it into a task? In fact when I tried that in my testing, > >> I > >> got an assertion error - > >> > >> File: "C:\Python35\lib\asyncio\base_events.py", line 211, in create_task > >>task = tasks.Task(coro, loop=self) > >> File: "C:\Python35\lib\asyncio\tasks.py", line 70, in __init__ > >>assert coroutines.iscoroutine(coro), repr(coro) > >> AssertionError: > > > > I didn't test this; it was based on the documentation, which says that > > run_in_executor is a coroutine. Looking at the source, it's actually a > > function that returns a future, so this may be a documentation bug. > > And now I'm reminded of this note in the asyncio docs: > > """ > Note: In this documentation, some methods are documented as > coroutines, even if they are plain Python functions returning a > Future. This is intentional to have a freedom of tweaking the > implementation of these functions in the future. If such a function is > needed to be used in a callback-style code, wrap its result with > ensure_future(). > """ > > IMO such methods should simply be documented as awaitables, not > coroutines. I wonder if that's already settled, or if it's worth > starting a discussion around. Bah -- What a bloody mess! And thanks for pointing this out, Ian. Keep wondering whether my brain is atrophying, or its rocket science or... -- https://mail.python.org/mailman/listinfo/python-list
Re: Question about asyncio and blocking operations
Rustom Mody : > Bah -- What a bloody mess! > And thanks for pointing this out, Ian. > Keep wondering whether my brain is atrophying, or its rocket science or... I'm afraid the asyncio idea will not fly. Adding the keywords "async" and "await" did make things much better, but the programming model seems very cumbersome. Say you have an async that calls a nonblocking function as follows: async def t(): ... f() ... def f(): ... g() ... def g(): ... h() ... def h(): ... Then, you need to add a blocking call to h(). You then have a cascading effect of having to sprinkle asyncs and awaits everywhere: async def t(): ... await f() ... async def f(): ... await g() ... async def g(): ... await h() ... async def h(): ... await ... ... A nasty case of nonlocality. Makes you wonder if you ought to declare *all* functions *always* as asyncs just in case they turn out that way. Note that neither the multithreading model (which I dislike) nor the callback hell (which I like) suffer from this problem. Marko -- https://mail.python.org/mailman/listinfo/python-list
Re: Question about asyncio and blocking operations
Marko Rauhamaa writes: > Note that neither the multithreading model (which I dislike) nor the > callback hell (which I like) suffer from this problem. There are some runtimes (GHC and Erlang) where everything is nonblocking under the covers, which lets even the asyncs be swept under the rug. Similarly with some low-tech cooperative multitaskers, say in Forth. When you've got a mixture of blocking and nonblocking, it becomes a mess. -- https://mail.python.org/mailman/listinfo/python-list