From alan.gauld at yahoo.co.uk Wed Feb 1 12:29:43 2023 From: alan.gauld at yahoo.co.uk (Alan Gauld) Date: Wed, 1 Feb 2023 17:29:43 +0000 Subject: [Tutor] Tkinter and after() method In-Reply-To: References: <7882b9ad-b51d-b64c-d85e-05512a77d174@gmail.com> Message-ID: On 01/02/2023 02:39, Cameron Simpson wrote: >>>> my_dial = None??? # I cannot see an alternative to their use at the >>>> moment >>>> my_canvas = None >>> Why not make them attributes of your root class? > > This ties Phil back to a single dial. And also ties the dial to the > widget kit (tkinter). It's a single value wherever it sits. Thats easy to fix: just change it to my_dials = [] And add the dials as they are created. As for the widget kit, unless he's going to get very fancy and start using MVC patterns etc I think that's a done deal! -- Alan G Author of the Learn to Program web site http://www.alan-g.me.uk/ http://www.amazon.com/author/alan_gauld Follow my photo-blog on Flickr at: http://www.flickr.com/photos/alangauldphotos From alan.gauld at yahoo.co.uk Wed Feb 1 12:45:46 2023 From: alan.gauld at yahoo.co.uk (Alan Gauld) Date: Wed, 1 Feb 2023 17:45:46 +0000 Subject: [Tutor] Tkinter and after() method In-Reply-To: <08c56c52-fbb1-ab19-81fa-82f2a0dec539@gmail.com> References: <138d6531-9e76-49f3-1425-ae2486f8e82d@gmail.com> <08c56c52-fbb1-ab19-81fa-82f2a0dec539@gmail.com> Message-ID: On 01/02/2023 01:51, Phil wrote: >> Then intialise your dial with the addition of the frame and >> canvasName, and do that in Root.__init__. That lets you drop the >> globals entirely. > I see, doesn't that limit the class to only work with Tkinter, and is > that normal practise? I try to make my classes universal so that they > can be used with Tkinter and Wxpython. At the moment I'll be happy if > the Dial class only works with Tkinter. The usual way to deal with multiple UI toolkits(including web and command line!) is to adopt an MVC pattern. Then you have the data object and its representation (as a dial?) as two separate (but related) classes. (MVC has other advantages too if its a non trivial GUI but for simple apps its not necessary.) class SomeDataObjectWithAValue:.... class Dial(Window): # or maybe inherit some other control? # abstract class with methods required to display the value def __init__(self, theValueObject, size, location, colour,...):... def draw(self):... def update(self):... ...other Dial methods... class TkDial(Dial): # Tkinter version of a dial class WxDial(Dial): # wxPython version of a dial Then your program uses the Dial object in its code but somewhere in its initialisation has something like # figure out which widget set is in use if widgets == Tkinter: # or just hard code it! Dial = TkDial else Dial = WxDial But that's getting pretty complex and a lot of exta work, especially if there are multiple widgets, all needing twin versions! So most projects just pick a widget set and run with it. The real issue here is that a Dial is a representation of something else. It's just a way of displaying a value. The thing that should be kept free of GUI widget awareness is the underlying value (object) that the dial is displaying. -- Alan G Author of the Learn to Program web site http://www.alan-g.me.uk/ http://www.amazon.com/author/alan_gauld Follow my photo-blog on Flickr at: http://www.flickr.com/photos/alangauldphotos From phillor9 at gmail.com Wed Feb 1 19:34:07 2023 From: phillor9 at gmail.com (Phil) Date: Thu, 2 Feb 2023 10:34:07 +1000 Subject: [Tutor] Tkinter and after() method In-Reply-To: References: <138d6531-9e76-49f3-1425-ae2486f8e82d@gmail.com> <08c56c52-fbb1-ab19-81fa-82f2a0dec539@gmail.com> Message-ID: <5bedd72a-e270-9be1-6c4c-83fe2acd617e@gmail.com> On 2/2/23 03:45, Alan Gauld via Tutor wrote: > > class TkDial(Dial): > # Tkinter version of a dial > > class WxDial(Dial): > # wxPython version of a dial > Thank you Cameron and Alan for your advice. I spent around four hours on this yesterday afternoon and ended up with two dials of different sizes sweeping their pointers at different time intervals and without any global variables. I solved this by moving all of the calculation routines to the dial class. To overcome the problem of dealing with Tkinter and Wxpython I created? two dial classes (two separate files). The Tkinter version handles the drawing routines and so the root class is very simple to use. The other version passes the result of its calculations to the root class leaving the root class to handle the drawing tasks. This is overly complex and requires the user, me, to have intimate knowledge of the data passed from the dial class. By next week this user will have forgotten what the huge amount of data mean. I couldn't think of a way to import the required class and because of the growing complexity I gave this idea away. Wxpython has its own dial widget anyway. It didn't occur to me to have two classes that differed only by their drawing routines. Anyway, thank you again for you persistence. -- Regards, Phil From edwin.r8 at icloud.com Wed Feb 8 18:54:02 2023 From: edwin.r8 at icloud.com (Edwin Ramirez) Date: Wed, 8 Feb 2023 18:54:02 -0500 Subject: [Tutor] I can't download python Message-ID: <2A715CE4-35E5-47FA-8EE3-A25C9161D127@icloud.com> I pressed don't allow python access to files and now it says download failed. From vala54sm at gmail.com Wed Feb 8 22:19:10 2023 From: vala54sm at gmail.com (Antonio S. Valenzuela Jr) Date: Wed, 8 Feb 2023 20:19:10 -0700 Subject: [Tutor] pycharm community edition won't open in ubuntu Message-ID: <38d14bbf-d007-33ed-6b7a-561ae389697d@gmail.com> I click on PC and pycharm community edition wants to open but on the top there's a little wheel spinning but it just goes away and pycharm just won't open. I tried deleting it and reloading it but no success. Any suggestions. It was working fine. From alan.gauld at yahoo.co.uk Thu Feb 9 05:27:04 2023 From: alan.gauld at yahoo.co.uk (Alan Gauld) Date: Thu, 9 Feb 2023 10:27:04 +0000 Subject: [Tutor] pycharm community edition won't open in ubuntu In-Reply-To: <38d14bbf-d007-33ed-6b7a-561ae389697d@gmail.com> References: <38d14bbf-d007-33ed-6b7a-561ae389697d@gmail.com> Message-ID: On 09/02/2023 03:19, Antonio S. Valenzuela Jr wrote: > I click on PC and pycharm community edition wants to open but on the top > there's a little wheel spinning but it just goes away and pycharm just > won't open. I tried deleting it and reloading it but no success. Any > suggestions. It was working fine. Try starting it from the command line. That should show up any error messages which will help pin-point the problem. -- Alan G Author of the Learn to Program web site http://www.alan-g.me.uk/ http://www.amazon.com/author/alan_gauld Follow my photo-blog on Flickr at: http://www.flickr.com/photos/alangauldphotos From alan.gauld at yahoo.co.uk Thu Feb 9 05:26:03 2023 From: alan.gauld at yahoo.co.uk (Alan Gauld) Date: Thu, 9 Feb 2023 10:26:03 +0000 Subject: [Tutor] I can't download python In-Reply-To: <2A715CE4-35E5-47FA-8EE3-A25C9161D127@icloud.com> References: <2A715CE4-35E5-47FA-8EE3-A25C9161D127@icloud.com> Message-ID: On 08/02/2023 23:54, Edwin Ramirez via Tutor wrote: > I pressed don't allow python access to files and now it says download failed. Python without access to files would be pretty useless. Try allowing access and see if it works. -- Alan G Author of the Learn to Program web site http://www.alan-g.me.uk/ http://www.amazon.com/author/alan_gauld Follow my photo-blog on Flickr at: http://www.flickr.com/photos/alangauldphotos From phillor9 at gmail.com Fri Feb 10 04:00:07 2023 From: phillor9 at gmail.com (Phil) Date: Fri, 10 Feb 2023 19:00:07 +1000 Subject: [Tutor] Tkinter, the correct way Message-ID: <35052dd9-da5f-9586-c611-15f948b20458@gmail.com> There are a dozen ways to achieve the same thing in Tkinter due to backward compatibility so I bought an e-book that promised to show the correct modern way. The code is an example of something that I'd written some time ago and now modified (improved, maybe). A few questions, if I may. Is this code the correct modern way? I don't notice any difference If I omit the frame padding and grid options. VS Code issues warnings to do with import * and value_label = etc is a function without a return. The latter can probably be quelled with a VS Code option but I'm not sure about import *. Finally, moving the scale with the arrow keys show integers but moving the scale with the mouse cause the scale value to be a long floating point number. How might I have the value variable be an integer when the mouse is moved? from tkinter import * from tkinter import ttk class ScaleDemo: ??? def __init__(self, root): ??????? root.title("Scale Demo") ??????? frame = ttk.Frame(root, padding="3 3 12 12") ??????? frame.grid(column=0, row=0, sticky=(N, S, E, W)) ??????? root.columnconfigure(0, weight=1) ??????? root.rowconfigure(0, weight=1) ??????? self.value = DoubleVar() ??????? slider = ttk.Scale( ??????????? frame, ??????????? from_=0, ??????????? to=100, ??????????? orient='horizontal',? # vertical ??????????? command=self.slider_changed, ??????????? variable=self.value) ??????? slider.grid(column=2, row=1, sticky=(E, W)) ??????? value_label = ttk.Label(frame, textvariable=self.value).grid( ??????????? column=2, row=2, sticky=(W, E)) ??????? ttk.Button(frame, text="Exit", command=root.destroy).grid( ??????????? column=3, row=3, sticky=W) ??????? for child in frame.winfo_children(): ??????????? child.grid_configure(padx=5, pady=5) ??????? slider.focus() ??? def slider_changed(self, event): ??????? #print('value changed') ??????? print(f'{self.value.get():,.1f}') root = Tk() ScaleDemo(root) root.mainloop() -- Regards, Phil From alan.gauld at yahoo.co.uk Fri Feb 10 10:40:37 2023 From: alan.gauld at yahoo.co.uk (Alan Gauld) Date: Fri, 10 Feb 2023 15:40:37 +0000 Subject: [Tutor] Tkinter, the correct way In-Reply-To: <35052dd9-da5f-9586-c611-15f948b20458@gmail.com> References: <35052dd9-da5f-9586-c611-15f948b20458@gmail.com> Message-ID: On 10/02/2023 09:00, Phil wrote: > Is this code the correct modern way? There is no such thing. Thre are many styles of tkinter programming. "Correctness" is largely subjective (assuming the code works of course!) > I don't notice any difference If I omit the frame padding and grid options. That normally only makes a difference when you resize a window near its limits(small or large). > VS Code issues warnings to do with import * Sensibly so. I don't think any production Tkinter code should use import *. The style i normally see is import tkinter as tk or similar. > and value_label = etc is a function without a return. Again, correctly. The return from ttk.Label().grid() is None so assigning it to a variable is pointless. > Finally, moving the scale with the arrow keys show integers but moving > the scale with the mouse cause the scale value to be a long floating > point number. How might I have the value variable be an integer when the > mouse is moved? Need to read the docs(and/or Tcl/Tk code?) for the Scale widget. > from tkinter import * > from tkinter import ttk > > class ScaleDemo: > > ??? def __init__(self, root): > > ??????? root.title("Scale Demo") > > ??????? frame = ttk.Frame(root, padding="3 3 12 12") > ??????? frame.grid(column=0, row=0, sticky=(N, S, E, W)) > > ??????? root.columnconfigure(0, weight=1) > ??????? root.rowconfigure(0, weight=1) > > ??????? self.value = DoubleVar() This might be the root of your problem. What happens if you use an IntVar instead of a DoubleVar? But double makes more sense for a Scale if you can set intermediate points. > ??????? slider = ttk.Scale( > ??????????? frame, > ??????????? from_=0, > ??????????? to=100, > ??????????? orient='horizontal',? # vertical > ??????????? command=self.slider_changed, > ??????????? variable=self.value) I would have thought you might want to keep hold of the slider so self.slider = ... > > ??????? slider.grid(column=2, row=1, sticky=(E, W)) > > ??????? value_label = ttk.Label(frame, textvariable=self.value).grid( > ??????????? column=2, row=2, sticky=(W, E)) And this shouldn't work. grid() returns None. Hence your warning from VS. OTOH you don;t stre the value outside __init__() and never use it inside so its totally irrelevant! > ??????? ttk.Button(frame, text="Exit", command=root.destroy).grid( > ??????????? column=3, row=3, sticky=W) This is the more normal approach with no variable used. > ??????? for child in frame.winfo_children(): > ??????????? child.grid_configure(padx=5, pady=5) I'm not sure about this but it doesn't look right to me. I prefer to have all the options supplied per widet even if its slightly more typing (probably less in this case!) My reasoning is that I look for the options where the widget is created, putting some of them in a loop which affects every widget sounds like a debugging nightmare to me! > > ??????? slider.focus() > > ??? def slider_changed(self, event): > ??????? #print('value changed') > ??????? print(f'{self.value.get():,.1f}') Is this the bit where you get the int/double issue? If so I suspect the arrow keys move the slider in unit amounts hence integers and the mouse moves it in a contuinuous manner and returns doubles. ie What I'd expect. But I've never used a ttk.slider so don't know. -- Alan G Author of the Learn to Program web site http://www.alan-g.me.uk/ http://www.amazon.com/author/alan_gauld Follow my photo-blog on Flickr at: http://www.flickr.com/photos/alangauldphotos From phillor9 at gmail.com Fri Feb 10 17:08:23 2023 From: phillor9 at gmail.com (Phil) Date: Sat, 11 Feb 2023 08:08:23 +1000 Subject: [Tutor] Tkinter, the correct way In-Reply-To: References: <35052dd9-da5f-9586-c611-15f948b20458@gmail.com> Message-ID: On 11/2/23 01:40, Alan Gauld via Tutor wrote: > On 10/02/2023 09:00, Phil wrote: > >> Is this code the correct modern way? > There is no such thing. Thre are many styles of tkinter programming. > "Correctness" is largely subjective (assuming the code works of course!) Thank you Alan, I'd developed a template for this type of thing quite awhile ago and I think I'll continue using that. Interestingly, ChatGPT generated code that is similar to my template although the generated scale example was not correct. I have spent quite some time looking for ttk scale examples, reading ttk documentation and I even bought an e-book. The book doesn't cover the use of the scale widget. Perhaps the scale widget is not commonly used? The author of the book discourages the use of the pack manager, instead favours the grid manager. I've tried both and I think I find the pack manager easier to use. I wonder if I should put more effort into learning to use the grid manager? Anyway, thank you again Alan for you thoughts. -- Regards, Phil From alan.gauld at yahoo.co.uk Fri Feb 10 17:59:11 2023 From: alan.gauld at yahoo.co.uk (Alan Gauld) Date: Fri, 10 Feb 2023 22:59:11 +0000 Subject: [Tutor] Tkinter, the correct way In-Reply-To: References: <35052dd9-da5f-9586-c611-15f948b20458@gmail.com> Message-ID: On 10/02/2023 22:08, Phil wrote: > The author of the book discourages the use of the pack manager, instead > favours the grid manager. I've tried both and I think I find the pack > manager easier to use. I wonder if I should put more effort into > learning to use the grid manager? Most modern books prefer grid to pack. I use both. I normally pack the toolbar and status area top and bottom and have a frame in between. Within that frame I use grid for all the actual widgets etc. (I also tend to use pack for managing the tools within the toolbar) Scale widgets have their place, I've used them occasionally programming MS Windows using Delphi and Java but never when using Tkinter. But compared to Labels, Entries, Buttons and Text widgets they are less common. -- Alan G Author of the Learn to Program web site http://www.alan-g.me.uk/ http://www.amazon.com/author/alan_gauld Follow my photo-blog on Flickr at: http://www.flickr.com/photos/alangauldphotos From cs at cskk.id.au Fri Feb 10 17:27:00 2023 From: cs at cskk.id.au (Cameron Simpson) Date: Sat, 11 Feb 2023 09:27:00 +1100 Subject: [Tutor] Tkinter, the correct way In-Reply-To: References: Message-ID: On 10Feb2023 15:40, Alan Gauld wrote: >On 10/02/2023 09:00, Phil wrote: >> ??????? value_label = ttk.Label(frame, >> textvariable=self.value).grid( >> ??????????? column=2, row=2, sticky=(W, E)) > >And this shouldn't work. grid() returns None. >Hence your warning from VS. Just to this. You may well want to keep a reference to the label (eg to modify it). If so, you'd write: value_label = ttk.Label(frame,_ textvariable=self.value) value_label.grid(column=2, row=2, sticky=(W, E)) i.e. store the Label, then grid it. You were keeping the result of the .grid(), not the Label itself. Cheers, Cameron Simpson From phillor9 at gmail.com Fri Feb 10 20:44:57 2023 From: phillor9 at gmail.com (Phil) Date: Sat, 11 Feb 2023 11:44:57 +1000 Subject: [Tutor] Tkinter, the correct way In-Reply-To: References: Message-ID: <6dfed5ba-fd2f-ccdd-27ad-161f94bc7f32@gmail.com> On 11/2/23 08:27, Cameron Simpson wrote: > value_label.grid(column=2, row=2, sticky=(W, E)) I see, thank you Cameron. The label still displays in the same place but VS Code now doesn't generate an error. -- Regards, Phil From dyc1977 at gmail.com Sat Feb 11 12:58:55 2023 From: dyc1977 at gmail.com (Dani Cain) Date: Sat, 11 Feb 2023 12:58:55 -0500 Subject: [Tutor] Anyone available for 1:1 help? Message-ID: New to this and working on a project but find myself spinning my wheels at this point. Super general question but anyone available this weekend to assist? (Preferably experienced in DS or SDLC.) From s.irfan.rizvi5 at gmail.com Sat Feb 11 12:35:53 2023 From: s.irfan.rizvi5 at gmail.com (S.Irfan Rizvi) Date: Sat, 11 Feb 2023 11:35:53 -0600 Subject: [Tutor] Installing Python Message-ID: Need help to install -- Regards ~ S. Irfan Rizvi From mats at wichmann.us Sat Feb 11 17:26:02 2023 From: mats at wichmann.us (Mats Wichmann) Date: Sat, 11 Feb 2023 15:26:02 -0700 Subject: [Tutor] Installing Python In-Reply-To: References: Message-ID: <9e0a52db-4a70-240c-cfc5-b02af2d2879d@wichmann.us> On 2/11/23 10:35, S.Irfan Rizvi wrote: > Need help to install You're going to need to be more descriptive. Otherwise the answer would be as unhelpful as the question, something like: "Get the installer. Run the installer." Platform? Python version? What have you tried? What are your needs? From mats at wichmann.us Sat Feb 11 17:33:08 2023 From: mats at wichmann.us (Mats Wichmann) Date: Sat, 11 Feb 2023 15:33:08 -0700 Subject: [Tutor] Anyone available for 1:1 help? In-Reply-To: References: Message-ID: <18fe9dee-6733-d856-d46b-7f1792d9cff4@wichmann.us> On 2/11/23 10:58, Dani Cain wrote: > New to this and working on a project but find myself spinning my wheels at > this point. Super general question but anyone available this weekend to > assist? (Preferably experienced in DS or SDLC.) This list doesn't work like that, although it's of course possible someone will contact you offlist with an offer (especially if you're willing to pay them). Generally speaking - ask questions, wait for answers, iterate. Usually it works better if they're specific - if you ask conceptual questions without details of something you've tried and how it didn't work, you may get no answers - or, you may get a long philosophical discussion that goes completely off the rails, because... we're humans with opinions :) If by SDLC you mean the Waterfall model of development, that's looked on with some disdain by many current software developers, although of course that doesn't mean some of them are not forced to use it. What do you mean with DS? From alan.gauld at yahoo.co.uk Sat Feb 11 19:45:20 2023 From: alan.gauld at yahoo.co.uk (Alan Gauld) Date: Sun, 12 Feb 2023 00:45:20 +0000 Subject: [Tutor] Anyone available for 1:1 help? In-Reply-To: References: Message-ID: On 11/02/2023 17:58, Dani Cain wrote: > New to this and working on a project but find myself spinning my wheels at > this point. Super general question but anyone available this weekend to > assist? (Preferably experienced in DS or SDLC.) That's not how the mailing list works, not least because it is a mailing list and the delay between sending a mail, readers receiving it and sending back a response can easily be more than 24 hours. Instead post any questions to the list and woever receives the message can respond. With others adding to it as they see the message. For best effect include The OS, Python version, any third-party libraries used and a relevant code snippet(ideally real code not pseudo code) plus any error message in its entirety. -- Alan G Author of the Learn to Program web site http://www.alan-g.me.uk/ http://www.amazon.com/author/alan_gauld Follow my photo-blog on Flickr at: http://www.flickr.com/photos/alangauldphotos From alan.gauld at yahoo.co.uk Sat Feb 11 19:48:49 2023 From: alan.gauld at yahoo.co.uk (Alan Gauld) Date: Sun, 12 Feb 2023 00:48:49 +0000 Subject: [Tutor] Installing Python In-Reply-To: References: Message-ID: On 11/02/2023 17:35, S.Irfan Rizvi wrote: > Need help to install What are you trying to install? Some version of Python? Or an IDE? Or a library? Where did you get it? Which website? On which OS? What have you tried so far? With what results (actual error messages would be helpful)? -- Alan G Author of the Learn to Program web site http://www.alan-g.me.uk/ http://www.amazon.com/author/alan_gauld Follow my photo-blog on Flickr at: http://www.flickr.com/photos/alangauldphotos From mhysnm1964 at gmail.com Sun Feb 12 00:03:52 2023 From: mhysnm1964 at gmail.com (mhysnm1964 at gmail.com) Date: Sun, 12 Feb 2023 16:03:52 +1100 Subject: [Tutor] Learning Flask and having a problem with forms. Message-ID: <001801d93e9f$6837f480$38a7dd80$@GMAIL.COM> All, I am having a problem with the Flask module which allows you to create a web page. The web page I am building is to permit myself to modify a list of dicts that I have built from a bunch of plot files for books. The plot files don't have any good structure, so I couldn't find a method of directly importing the info into a database. Instead I want to show the content in a web page as a table. Column 1 is the keys and column 2 is the values. Column 3 is a list of actions you can perform. Currently I only have a "change key" button. When this button is activated, it is meant to show a hidden form. This is the bit I cannot get to work. Below is the routes.py view code: from flask import render_template, flash, redirect, url_for, request from app import app import pickle, pdb with open('..\\book_list_dict.pkl', 'rb') as file: records = pickle.load(file) def capitalize_key (): fields = ['title', 'author', "genre", "description", "series", "narrated by", "about the author"] for record in records: for key in fields: if key not in record and key.capitalize() not in record: record[key.capitalize()] = "Unknown" elif key in record: record[key.capitalize()] = record.pop(key) @app.route('/') @app.route('/index') def index(): # displays the index.html file and the first dict from the list. capitalize_key() # caplise keys within the records list which exist to make them all the same. page_length = len(records) record_index = 0 page_no = record_index + 1 book = records[record_index] return render_template('index.html', book=book, page_no=page_no, page_length=page_length) # moving between books (records) @app.route('/nextPage/') def nextPage(page_no): # moves to the next list element containing the dict. page_no = int(page_no) page_length = len(records) if page_no <= page_length: page_no += 1 book = records[page_no - 1] return render_template('index.html', book=book, page_no=page_no, page_length=page_length) @app.route('/prevPage/') def prevPage(page_no): # moves to the previous list item containing the dict. page_no = int(page_no) page_length = len(records) if page_no > 1: page_no -= 1 book = records[page_no - 1] else: book = records[0] return render_template('index.html', book=book, page_no=page_no, page_length=page_length) @app.route('/update_key/', methods=["GET", "POST"]) def update_key(selected_key): pdb.set_trace() # accepts the modified fields for the key and key value. Updates the list of dicts and saves back out as a variable. Hack for now. if request.method == "POST": new_key = request.form["key_field"] new_value = request.form["value_field"] for record in records: if selected_key in record: record[new_key] = record.pop(selected_key) record[new_key] = new_value flash("Key updated successfully!") break with open('..\\book_list_dict.pkl', 'wb') as file: pickle.dump(records, file) return redirect(url_for("index")) return render_template("update_key.html", selected_key=selected_key) @app.route('/cancel', methods=["GET"]) def cancel(): # cancel the action and hide the form again. return redirect(url_for("index")) @app.route('/changeKey/', methods=["GET"]) def changeKey(page_no): return redirect(url_for("index")) Below is the HTML template. Nothing fancy for now. Current book {{ book['filename'] }}

Reviewing Book {{ book['filename'] }}s

Current page: {{page_no}} total pages: {{ page_length }}

{% for key, value in book.items() %} {% endif %} {% endfor %}
Key Value Actions
{{ key }} {{ value }} {% if key != "filename" and key != "original_content" %}

{% if selected_key %}
{{ form.csrf_token }} {{ form.key_field.label }} {{ form.key_field }}
{{ form.value_field.label }} {{ form.value_field }}
{% endif %}
If I don't have the "changeKey" function in routes and use the
in the index.html file. The browser throws Invalid usage of method. Otherwise the first list element is shown again. I cannot get the form to show. My alternative options are: * Create a new template file which is called when the changekey button is pressed. This then shows the key and value. Not sure how to do that yet. Then have a update and cancel button. Update of course then applies the changes. The above code should work in that situation with a slight change. * Have the key and value columns as input fields. In the action column have an update button which takes the two fields being edited and updates them. Not 100% sure how to send two variables to the python function. I suspect it will be similar to what I am trying to do above. I was looking at using the WTF-flask module (hope I got that right) and use a form.py with form classes. Not sure how to get the data from the dict into the forms fields using this approach. Any help here is welcomed. I know this is some what brief. But I hope I have given you enough info. Note: the above script does move between the different dicts stored in the list. Sean From phillor9 at gmail.com Sun Feb 12 20:20:18 2023 From: phillor9 at gmail.com (Phil) Date: Mon, 13 Feb 2023 11:20:18 +1000 Subject: [Tutor] Tkinter custom widgets Message-ID: <4a52fbb1-108d-481d-84e8-4d05d3e40d67@gmail.com> I've been investigating how I might create a custom widget class that contains a draw_circle method. Creating a draw_circle method is a straight forward task, however, positioning the resulting circle with .grid() seems to be logically impossible because the draw method requires a position. I see that a custom widget class is a sub class of frame and further, the custom widgets are based on existing Tkinter widgets. Creating a widget from scratch seems to be a complex, if not impossible, task for the unskilled. I'd like to postilion a button with the grid method and then position a custom widget circle in an adjacent cell. Maybe I could create a small canvas, or several small canvases, then draw the circle on a canvas and use grid() to position the canvas beside the button? It seems possible but messy. -- Regards, Phil From bouncingcats at gmail.com Sun Feb 12 21:29:31 2023 From: bouncingcats at gmail.com (David) Date: Mon, 13 Feb 2023 13:29:31 +1100 Subject: [Tutor] Tkinter custom widgets In-Reply-To: <4a52fbb1-108d-481d-84e8-4d05d3e40d67@gmail.com> References: <4a52fbb1-108d-481d-84e8-4d05d3e40d67@gmail.com> Message-ID: On Mon, 13 Feb 2023 at 12:20, Phil wrote: > I've been investigating how I might create a custom widget class that > contains a draw_circle method. Creating a draw_circle method is a > straight forward task, however, positioning the resulting circle with > .grid() seems to be logically impossible because the draw method > requires a position. Not so. The draw method will require a relative position *inside* the Canvas widget. Which is unrelated to where the widget itself gets drawn. > I see that a custom widget class is a sub class of frame and further, > the custom widgets are based on existing Tkinter widgets. Creating a > widget from scratch seems to be a complex, if not impossible, task for > the unskilled. Just combine the components you need. > I'd like to postilion a button with the grid method and then position a > custom widget circle in an adjacent cell. Maybe I could create a small > canvas, or several small canvases, then draw the circle on a canvas and > use grid() to position the canvas beside the button? It seems possible > but messy. This is the way. Demo executable code example: #!/usr/bin/python3 import tkinter as tk def canvas_create_circle(canvas, x, y, r): # canvas = parent # x,y = centre # r = radius x0 = x - r y0 = y - r x1 = x + r y1 = y + r canvas.create_oval(x0, y0, x1, y1, width=2) class CustomWidget(tk.Frame): def __init__(self, text, *args, **kwargs): tk.Frame.__init__(self, *args, **kwargs) canvas = tk.Canvas(self, bg="white", width=80, height=80) canvas_create_circle(canvas, 40, 40, 20) canvas.grid(row=0, column=1) btn = tk.Button(self, text=text) btn.grid(row=0, column=0) if __name__ == "__main__": root = tk.Tk() cw1= CustomWidget("cw1", root) cw1.pack() cw2= CustomWidget("cw2", root) cw2.pack() root.mainloop() From phillor9 at gmail.com Sun Feb 12 23:59:48 2023 From: phillor9 at gmail.com (Phil) Date: Mon, 13 Feb 2023 14:59:48 +1000 Subject: [Tutor] Tkinter custom widgets In-Reply-To: References: <4a52fbb1-108d-481d-84e8-4d05d3e40d67@gmail.com> Message-ID: <68ac6d2a-22b3-f968-ecb5-205ed616866b@gmail.com> On 13/2/23 12:29, David wrote: > Just combine the components you need. > This is the way. Demo executable code example: Thank you David, your code answers my question exactly. Now I have to massage it to fit into my present class. In the meantime, I have another example from Chatgpt which, while it doesn't match my original question, works well. It uses functions that I've not seen before so now I'm searching the Internet for their meaning. -- Regards, Phil From phillor9 at gmail.com Mon Feb 13 04:42:27 2023 From: phillor9 at gmail.com (Phil) Date: Mon, 13 Feb 2023 19:42:27 +1000 Subject: [Tutor] grid manager question Message-ID: Thank you for reading this. I've been going around in circles for hours and getting nowhere. The code below displays a list of circles, one per column. So far so good until I add any other widget under the row of circles. If I add a widget in column 8 then the circles are unaffected. If I add a widget into any other column (not the same row as the circles) then the circles move apart over that widget. How do I prevent this? Adding pady to the widget doesn't seem to help. It must have something with the way that list of circles is laid out. import tkinter as tk import led3 class App(tk.Tk): ??? def __init__(self, num_leds=8): ??????? tk.Tk.__init__(self) ??????? self.title("LED Example") ??????? self.led_list = [] ??????? for i in range(num_leds): ??????????? led = led3.LED(self, size=20, color='red') ??????????? led.grid(row=0, column=i, padx=5, pady=5) ??????????? self.led_list.append(led) ??????? self.led = led3.LED(self, size=50, color='green') ??????? #self.led.grid(row=2, column=0, padx=25, pady=25) ??????? #tk.Button(self, text='Turn On', command=self.led.turn_on).grid(row=1, column=1, padx=5, pady=15) ??????? tk.Button(self, text='Turn On', command=self.led_list[1].turn_on).grid(row=3, column=2, padx=5, pady=15) ??????? #tk.Button(self, text='Turn Off', command=self.led.turn_off).grid(row=2, column=1, padx=5, pady=15) if __name__ == '__main__': ??? app = App() ??? app.mainloop() -- Regards, Phil From alan.gauld at yahoo.co.uk Mon Feb 13 04:58:01 2023 From: alan.gauld at yahoo.co.uk (Alan Gauld) Date: Mon, 13 Feb 2023 09:58:01 +0000 Subject: [Tutor] grid manager question In-Reply-To: References: Message-ID: On 13/02/2023 09:42, Phil wrote: > The code below displays a list of circles, one per column. So far so > good until I add any other widget under the row of circles. If I add a > widget in column 8 then the circles are unaffected. If I add a widget > into any other column (not the same row as the circles) then the circles > move apart over that widget. The columns auto resize to the size of the widest component in the column. Presumably your new widget is wider than the circle? To get round that you need to make your columns as wide as they need to be at the beginning. Possibly be resizing the frame containing your circles? -- Alan G Author of the Learn to Program web site http://www.alan-g.me.uk/ http://www.amazon.com/author/alan_gauld Follow my photo-blog on Flickr at: http://www.flickr.com/photos/alangauldphotos From phillor9 at gmail.com Mon Feb 13 05:12:55 2023 From: phillor9 at gmail.com (Phil) Date: Mon, 13 Feb 2023 20:12:55 +1000 Subject: [Tutor] grid manager question In-Reply-To: References: Message-ID: On 13/2/23 19:58, Alan Gauld via Tutor wrote: > > The columns auto resize to the size of the widest component in the > column. Presumably your new widget is wider than the circle? > > To get round that you need to make your columns as wide as they > need to be at the beginning. Possibly be resizing the frame containing > your circles? Thank you Alan, I see now what's going on. Off the top of my head I think the best solution is to put the buttons in their own column. Or, go back to my original idea and not use the grid manager to lay out the LEDs. -- Regards, Phil From phonokoye at gmail.com Mon Feb 13 02:10:16 2023 From: phonokoye at gmail.com (Alphonsus Okoye) Date: Mon, 13 Feb 2023 08:10:16 +0100 Subject: [Tutor] What exactly does "await" do? Message-ID: Given below is a part of the python offline doc 3.10: Language reference, section 6.4 > Suspend the execution of coroutine on an awaitable object. Can only be > used inside a coroutine function. > *await_expr* ::= "await" primary > New in version 3.5. Here is another part of the same doc on "Coroutines and tasks" > To actually run a coroutine, asyncio provides three main mechanisms: > > - > > Awaiting on a coroutine. The following snippet of code will print > ?hello? after waiting for 1 second, and then print ?world? after waiting > for *another* 2 seconds: > > import asyncioimport time > async def say_after(delay, what): > await asyncio.sleep(delay) > print(what) > async def main(): > print(f"started at {time.strftime('%X')}") > > await say_after(1, 'hello') > await say_after(2, 'world') > > print(f"finished at {time.strftime('%X')}") > asyncio.run(main()) ... > > > Aren't those two statements contradictory? How does the await statement suspend the execution of a coroutine and still run the coroutine? I know I am missing some fundamentals here. How do I make sense of this? From bouncingcats at gmail.com Mon Feb 13 07:49:04 2023 From: bouncingcats at gmail.com (David) Date: Mon, 13 Feb 2023 23:49:04 +1100 Subject: [Tutor] grid manager question In-Reply-To: References: Message-ID: On Mon, 13 Feb 2023 at 20:43, Phil wrote: > The code below displays a list of circles, one per column. Not for anyone except you it doesn't, because we can't 'import led3'. > So far so > good until I add any other widget under the row of circles. If I add a > widget in column 8 then the circles are unaffected. If I add a widget > into any other column (not the same row as the circles) then the circles > move apart over that widget. As Alan wrote, they move apart because they need to, so that the column can accomodate the widget that you add later, which is wider than the widget that you first put into the column. > How do I prevent this? Adding pady to the widget doesn't seem to help. Adding pady (vertical) wont help because it makes a widget taller, not wider. To make the columns wider, you need to increase padx (horizontal). And do that on the narrow first widget, not on the wider one that you add later. And be sure to make it wider than the later widget plus double whatever padx you specify on the later widget. From bouncingcats at gmail.com Mon Feb 13 08:05:32 2023 From: bouncingcats at gmail.com (David) Date: Tue, 14 Feb 2023 00:05:32 +1100 Subject: [Tutor] What exactly does "await" do? In-Reply-To: References: Message-ID: On Mon, 13 Feb 2023 at 21:41, Alphonsus Okoye wrote: > How does the await > statement suspend the execution of a coroutine and still run the coroutine? > I know I am missing some fundamentals here. How do I make sense of this? Let's choose one of the coroutines you posted, as an example to discuss. This one: > > async def say_after(delay, what): > > await asyncio.sleep(delay) > > print(what) When execution reaches the 'await' statement in that coroutine, it suspends the execution of the running coroutine named 'say_after', and instead runs the coroutine named 'asyncio.sleep'. That's how 'await' both suspends a coroutine (the one it is in) and runs a coroutine (a different one that it starts). When the coroutine named 'asyncio.sleep' returns, the coroutine named 'say_after' will resume, from the 'print(what)' statement. A coroutine can be recognised by having 'async def' in its definition statement, as opposed to just 'def' for the definition of an ordinary function or method. From nulla.epistola at web.de Mon Feb 13 11:12:02 2023 From: nulla.epistola at web.de (Sibylle Koczian) Date: Mon, 13 Feb 2023 17:12:02 +0100 Subject: [Tutor] grid manager question In-Reply-To: References: Message-ID: <5bc3b781-37bf-36fe-66c6-5dbe72109dc2@web.de> Am 13.02.2023 um 13:49 schrieb David: > On Mon, 13 Feb 2023 at 20:43, Phil wrote: > >> The code below displays a list of circles, one per column. > > Not for anyone except you it doesn't, because we can't 'import led3'. > >> So far so >> good until I add any other widget under the row of circles. If I add a >> widget in column 8 then the circles are unaffected. If I add a widget >> into any other column (not the same row as the circles) then the circles >> move apart over that widget. > > As Alan wrote, they move apart because they need to, so that the column > can accomodate the widget that you add later, which is wider than the > widget that you first put into the column. > Or use the "columnspan" option in the call to grid for the button: tk.Button(self, text='Turn On', command=self.led_list[1].turn_on).grid(row=3, column=2, columnspan=2, padx=5, pady=5) I was lazy and looked this up in my very old Tkinter book. But I can't imagine that this option might have vanished or changed its name. Probably all GUI libraries know it. Of course there is also "rowspan". HTH Sibylle From nulla.epistola at web.de Mon Feb 13 11:12:02 2023 From: nulla.epistola at web.de (Sibylle Koczian) Date: Mon, 13 Feb 2023 17:12:02 +0100 Subject: [Tutor] grid manager question In-Reply-To: References: Message-ID: <5bc3b781-37bf-36fe-66c6-5dbe72109dc2@web.de> Am 13.02.2023 um 13:49 schrieb David: > On Mon, 13 Feb 2023 at 20:43, Phil wrote: > >> The code below displays a list of circles, one per column. > > Not for anyone except you it doesn't, because we can't 'import led3'. > >> So far so >> good until I add any other widget under the row of circles. If I add a >> widget in column 8 then the circles are unaffected. If I add a widget >> into any other column (not the same row as the circles) then the circles >> move apart over that widget. > > As Alan wrote, they move apart because they need to, so that the column > can accomodate the widget that you add later, which is wider than the > widget that you first put into the column. > Or use the "columnspan" option in the call to grid for the button: tk.Button(self, text='Turn On', command=self.led_list[1].turn_on).grid(row=3, column=2, columnspan=2, padx=5, pady=5) I was lazy and looked this up in my very old Tkinter book. But I can't imagine that this option might have vanished or changed its name. Probably all GUI libraries know it. Of course there is also "rowspan". HTH Sibylle From phillor9 at gmail.com Mon Feb 13 15:56:34 2023 From: phillor9 at gmail.com (Phil) Date: Tue, 14 Feb 2023 06:56:34 +1000 Subject: [Tutor] grid manager question In-Reply-To: <5bc3b781-37bf-36fe-66c6-5dbe72109dc2@web.de> References: <5bc3b781-37bf-36fe-66c6-5dbe72109dc2@web.de> Message-ID: <5fd1ba1f-91bb-6b99-4bb4-4e1f785fcdee@gmail.com> On 14/2/23 02:12, Sibylle Koczian wrote: > Or use the "columnspan" option in the call to grid for the button: Thank you Sibylle and David, I need to rethink what I'm trying to achieve. Neither widening the columns nor spanning multiple columns suits the look I want. I'm trying to make my led module more universal so that it suits various jobs. Back to the drawing board. -- Regards, Phil From cs at cskk.id.au Mon Feb 13 17:32:54 2023 From: cs at cskk.id.au (Cameron Simpson) Date: Tue, 14 Feb 2023 09:32:54 +1100 Subject: [Tutor] Tkinter custom widgets In-Reply-To: <68ac6d2a-22b3-f968-ecb5-205ed616866b@gmail.com> References: <68ac6d2a-22b3-f968-ecb5-205ed616866b@gmail.com> Message-ID: On 13Feb2023 14:59, Phil wrote: >In the meantime, I have another example from Chatgpt which, while it >doesn't match my original question, works well. It uses functions that >I've not seen before so now I'm searching the Internet for their >meaning. Don't forget that ChatGPT doesn't know how to programme, and is a statistical text model. AIUI, it has simply seen _many_ pieces of code and their explainations/comments. While (apparently) it does produce sometimes usful short programmes, there's no real guarrentee that they mean anything at a high level, or that they mean what you asked for. It does seem to have some ability to explain the code it produces, so maybe asking it to do that will help you understand what it has produced, and whether what it produced is useful for what you asked for. Cheers, Cameron Simpson From bouncingcats at gmail.com Mon Feb 13 17:54:43 2023 From: bouncingcats at gmail.com (David) Date: Tue, 14 Feb 2023 09:54:43 +1100 Subject: [Tutor] grid manager question In-Reply-To: References: Message-ID: On Mon, 13 Feb 2023 at 20:43, Phil wrote: > class App(tk.Tk): > def __init__(self, num_leds=8): > tk.Tk.__init__(self) [...] > app = App() > app.mainloop() Another suggestion that might help to declutter your code and your mind: don't use this pointless App() class. You don't need it. And it's not required, it's something you created in your code. Removing it will provide the benefit of clarifying your code by removing the clutter of useless 'self.' references to a class that is only ever instantiated once. See the demo example I showed in the other thread, which has no App() class. From phillor9 at gmail.com Mon Feb 13 20:20:25 2023 From: phillor9 at gmail.com (Phil) Date: Tue, 14 Feb 2023 11:20:25 +1000 Subject: [Tutor] Tkinter custom widgets In-Reply-To: References: <68ac6d2a-22b3-f968-ecb5-205ed616866b@gmail.com> Message-ID: <4e622243-367b-cf37-4c39-678a7a723b37@gmail.com> On 14/2/23 08:32, Cameron Simpson wrote: > Don't forget that ChatGPT doesn't know how to programme, and is a > statistical text model. AIUI, it has simply seen _many_ pieces of code > and their explainations/comments. While (apparently) it does produce > sometimes usful short programmes, there's no real guarrentee that they > mean anything at a high level, or that they mean what you asked for. > It does seem to have some ability to explain the code it produces, so > maybe asking it to do that will help you understand what it has > produced, and whether what it produced is useful for what you asked for. I've found that ChatGPT's Tkinter answers are very useful as are the code explanations but a bit patchy when asked questions about lesser known libraries. -- Regards, Phil From phillor9 at gmail.com Mon Feb 13 20:45:29 2023 From: phillor9 at gmail.com (Phil) Date: Tue, 14 Feb 2023 11:45:29 +1000 Subject: [Tutor] grid manager question In-Reply-To: References: Message-ID: <3cda58e2-301f-2b2c-9967-2f20c7170a0e@gmail.com> On 14/2/23 08:54, David wrote: > Another suggestion that might help to declutter your > code and your mind: don't use this pointless App() class. > > You don't need it. And it's not required, it's something > you created in your code. > > Removing it will provide the benefit of clarifying your > code by removing the clutter of useless 'self.' references > to a class that is only ever instantiated once. > > See the demo example I showed in the other thread, > which has no App() class. I recently asked a question about the correct way to use Tkinter and ttk because there are a dozen ways to achieve the same result. That question was answered and is in agreement with an e-book that I bought a week ago: OOP being the preferred style although the e-book only contains one OOP example. To that end I have a number code templates, that I tweak when I find something better, that I use because I keep forgetting (it's an age thing) the correct syntax. I agree with you that it's a bit cluttered but isn't that the way the big boys programme? I have played with your demo example and does exactly what I'd ask for. What I have in mind is a bit more complex than a button and a circle but it's a very good starting point. -- Regards, Phil From bouncingcats at gmail.com Mon Feb 13 22:33:04 2023 From: bouncingcats at gmail.com (David) Date: Tue, 14 Feb 2023 14:33:04 +1100 Subject: [Tutor] grid manager question In-Reply-To: <3cda58e2-301f-2b2c-9967-2f20c7170a0e@gmail.com> References: <3cda58e2-301f-2b2c-9967-2f20c7170a0e@gmail.com> Message-ID: On Tue, 14 Feb 2023 at 12:46, Phil wrote: > On 14/2/23 08:54, David wrote: > > See the demo example I showed in the other thread, > > which has no App() class. > I recently asked a question about the correct way to use Tkinter and ttk > because there are a dozen ways to achieve the same result. That question > was answered and is in agreement with an e-book that I bought a week > ago: OOP being the preferred style although the e-book only contains one > OOP example. To that end I have a number code templates, that I tweak > when I find something better, that I use because I keep forgetting (it's > an age thing) the correct syntax. I agree with you that it's a bit > cluttered but isn't that the way the big boys programme? I'm unsure exactly what "big boy" means, but I imagine they would be the master of their own code, and that's the direction I'm trying to guide you towards. So the good news is, you found "something better", like you said above! An App() class is one way to provide namespacing. It's not the only way. If you are getting zero benefit from using an App() class, but it makes you have to write 'self.' in front of oodles of variables where that otherwise wouldn't be required, why clutter up your code with it? Anyway, I'm going to drop that topic now. I only brought it up because you seem to be somewhat lost in the weeds and I'm trying to help you clarify and focus on what's important. > I have played with your demo example and does exactly what I'd ask for. > What I have in mind is a bit more complex than a button and a circle but > it's a very good starting point. My demo example shows how to create a custom widget class. I intentionally targetted exactly what you asked about, with a minimal example that would be complete and educational. Generally, I don't write code for people. I made an exception for this question, because it seemed to be the most efficient and direct way to open your eyes to what you said you wanted to understand. Custom made, just for you personally. I'm sorry it's not an e-book, maybe next time :) My aim was to give you something small that you could study until you become 100% comfortable with every aspect of it and you understand it completely. It demonstrates how to pass arguments to the custom widget, and how the parent-child relationships are created, and how to subclass from tk.Frame(). You can ask here about any aspect of that example that you have even the slightest doubt about. Once that process completes, which hopefully won't take long, I hope it will help you to write code that does what you want instead of looking for examples and trying to hack them together. If you don't do that, then I will realise that my approach to helping you does not suit you, it will stop, and that's fine. Good luck! My goal in replying to you today is to have you feel 100% confident about every part of your code. Your code. Own it! From phillor9 at gmail.com Mon Feb 13 23:36:20 2023 From: phillor9 at gmail.com (Phil) Date: Tue, 14 Feb 2023 14:36:20 +1000 Subject: [Tutor] grid manager question In-Reply-To: References: <3cda58e2-301f-2b2c-9967-2f20c7170a0e@gmail.com> Message-ID: On 14/2/23 13:33, David wrote: > An App() class is one way to provide namespacing. It's not the only way. Thank you David for taking the time to reply, it's greatly appreciated. > > If you are getting zero benefit from using an App() class, but it makes you > have to write 'self.' in front of oodles of variables where that otherwise > wouldn't be required, why clutter up your code with it? OOP programming offers several advantages and two that I can remember at the moment are: An app class can be extended to add new functionality. An app class can be used as a template. I try to create classes that can be imported into a new project. I suppose another advantage is code reusability. > Anyway, I'm going to drop that topic now. I only brought it up because > you seem to be somewhat lost in the weeds and I'm trying to help you > clarify and focus on what's important. "Lost in the weeds" is accurate. > If you don't do that, then I will realise that my approach to helping you > does not suit you, it will stop, and that's fine. Good luck! Not at all accurate. If I don't ask any further questions about custom widgets then that means that I can take it from here. In other words muddle along until something works as expected. > > My goal in replying to you today is to have you feel 100% confident about > every part of your code. Your code. Own it! I like things be correct. Just because something works doesn't mean that it's correct, and I often struggle with that. Anyway, thanks again David for your advice. -- Regards, Phil From bouncingcats at gmail.com Tue Feb 14 00:32:41 2023 From: bouncingcats at gmail.com (David) Date: Tue, 14 Feb 2023 16:32:41 +1100 Subject: [Tutor] grid manager question In-Reply-To: References: <3cda58e2-301f-2b2c-9967-2f20c7170a0e@gmail.com> Message-ID: On Tue, 14 Feb 2023 at 15:36, Phil wrote: > On 14/2/23 13:33, David wrote: > > An App() class is one way to provide namespacing. It's not the only way. > Thank you David for taking the time to reply, it's greatly appreciated. No problem :) > > If you are getting zero benefit from using an App() class, but it makes you > > have to write 'self.' in front of oodles of variables where that otherwise > > wouldn't be required, why clutter up your code with it? > OOP programming offers several advantages and two that I can remember at > the moment are: > An app class can be extended to add new functionality. Any code can also be extended to add new functionality. > An app class can be used as a template. I try to create classes that can > be imported into a new project. Classes in general are great for importing, agreed. And subclassing. However, you're unlikely to do either of those things to your App() class, because it is your entire app. And your entire app will likely have some parts that you never want to import or subclass, so that will prohibit doing that at all, so this isn't a practical benefit in your context. > I suppose another advantage is code reusability. Same response as above. The benefits you are citing are well known advantages of classes, that I use all the time. And it is good that you know these facts. However these advantages are never going to be applicable to the useless App() class that you are choosing to create. The downside is that you have a ridulous amout of useless 'self.' all over the place that interferes with your ability to see the simplicity of what is happening underneath. Instead of root = tk.Tk() you have app = App() combined with class App(tk.Tk) which does exactly the same thing except now you have to write 'self.' a billion times for no benefit. I realise that I'm arguing against commonly seen notions, but I am briefly sticking my head out with absolutely nothing to gain because I believe that they are inapplicable to what's being discussed here and now, and I'm trying to help *you* at the point *you* are at *today*. > > Anyway, I'm going to drop that topic now. oops :) Anyway, as I said, if my advice doesn't work for you then that's fine. I will shut up. I'm not interested in debating these things. I'm just trying to help, you. But, we might not be a good match for each others preferences and teaching/learning styles. If you don't find what I am telling you liberating, that's a sign that this conversation is not going to be successful. Or if you'd rather trust a book than a human, even when the human immediately shows you how to do exactly what you asked for in the simplest possible way :) From phonokoye at gmail.com Mon Feb 13 23:40:57 2023 From: phonokoye at gmail.com (Alphonsus Okoye) Date: Tue, 14 Feb 2023 05:40:57 +0100 Subject: [Tutor] What exactly does "await" do? (David) In-Reply-To: References: Message-ID: > ---------- Forwarded message ---------- > From: David > To: tutor at python.org > Cc: > Bcc: > Date: Tue, 14 Feb 2023 00:05:32 +1100 > Subject: Re: [Tutor] What exactly does "await" do? > On Mon, 13 Feb 2023 at 21:41, Alphonsus Okoye wrote: > > > How does the await > > statement suspend the execution of a coroutine and still run the coroutine? > > I know I am missing some fundamentals here. How do I make sense of this? > > Let's choose one of the coroutines you posted, as an example to discuss. > This one: > > > > async def say_after(delay, what): > > > await asyncio.sleep(delay) > > > print(what) > > When execution reaches the 'await' statement in that coroutine, > it suspends the execution of the running coroutine named 'say_after', > and instead runs the coroutine named 'asyncio.sleep'. > > That's how 'await' both suspends a coroutine (the one it is in) and runs > a coroutine (a different one that it starts). > > When the coroutine named 'asyncio.sleep' returns, the coroutine > named 'say_after' will resume, from the 'print(what)' statement. > > A coroutine can be recognised by having 'async def' in its > definition statement, as opposed to just 'def' for the > definition of an ordinary function or method. Good day Mr David and to everyone here. From what you said, the coroutine can be executed just like a function; the execution of the main function is suspended till the inner function has finished executing. What is then the main purpose of a coroutine? I assume there is a specific problem which isn't straightforward with normal functions. From youtube videos, the purpose of a coroutine seems to be to execute some IO process asynchronously, but I have also read in some stackoverflow page that a coroutine may still not execute asynchronously if not written well. So how do I write asynchronous code using coroutines? More specifically, if I wished to write a program that read from a long text file "spam.txt", and while the process begins to waste time, do other stuff like call function doOtherStuff(), what would the code look like? From bouncingcats at gmail.com Tue Feb 14 04:27:40 2023 From: bouncingcats at gmail.com (David) Date: Tue, 14 Feb 2023 20:27:40 +1100 Subject: [Tutor] What exactly does "await" do? (David) In-Reply-To: References: Message-ID: On Tue, 14 Feb 2023 at 20:03, Alphonsus Okoye wrote: > > From: David > > Date: Tue, 14 Feb 2023 00:05:32 +1100 > > > How does the await > > > statement suspend the execution of a coroutine and still run the coroutine? > > > I know I am missing some fundamentals here. How do I make sense of this? > Good day Mr David and to everyone here. From what you said, the coroutine > can be executed just like a function; the execution of the main function is > suspended till the inner function has finished executing. What is then the > main purpose of a coroutine? Hi Alphonsus Okoye, Here is a good explanation, using Python: https://realpython.com/lessons/what-concurrency/ The simple answer is that when a synchronous function encounters some resource that cannot respond immediately, the function gets stuck there. It cannot proceed. It cannot do anything except wait for the response from the resource. Whereas an asynchronous coroutine in that situation has a capability to transfer execution to some other coroutine task. This means that operations can occur in parallel. While one coroutine might encounter a delay due to some external resource not responding, some other coroutine can proceed. > I assume there is a specific problem which isn't straightforward with > normal functions. From youtube videos, the purpose of a coroutine seems to > be to execute some IO process asynchronously, but I have also read in some > stackoverflow page that a coroutine may still not execute asynchronously if > not written well. Sure. > So how do I write asynchronous code using coroutines? > > More specifically, if I wished to write a program that read from a long > text file "spam.txt", and while the process begins to waste time, do other > stuff like call function doOtherStuff(), what would the code look like? You can find good example Python code here: https://realpython.com/async-io-python/ From mats at wichmann.us Tue Feb 14 11:37:16 2023 From: mats at wichmann.us (Mats Wichmann) Date: Tue, 14 Feb 2023 09:37:16 -0700 Subject: [Tutor] What exactly does "await" do? (David) In-Reply-To: References: Message-ID: <8ac26fd3-0619-7d3d-9b96-890455b2bfb1@wichmann.us> On 2/13/23 21:40, Alphonsus Okoye wrote: >> ---------- Forwarded message ---------- > Good day Mr David and to everyone here. From what you said, the coroutine > can be executed just like a function; the execution of the main function is > suspended till the inner function has finished executing. What is then the > main purpose of a coroutine? Wouldn't express it quite this way. In an async program, you have a main part of the program that keeps running - usually called an event loop. It decides if there's any work that can be done, in the form of resuming things that are now ready. The await keyword is you telling Python that this is a point where it's okay to stash the current state and go off and do other work. So if you fired off a request to a webserver, which is "slow" in terms of computer time, and you flag with await that it's okay not to stall execution until it responds, then the main loop picks back up and figures out if there's other work that can be done. At some point later, the main loop will spot that the thing being awaited is done, and it can restart execution with that saved context. The restarted code then has to give up control again so the main loop can continue - either by returning from the function, or another await. And so on. A coroutine is just a function that is able to be suspended/restarted, which you flag to Python by using the async keyword - you have to have indicated that it's a coroutine to be allowed to use await in it. The async/await syntax was the approach chosen to retrofit async capabilities into an already mature language without breaking the behavior of tons of existing code which does not use async principles (and doesn't need to). From alan.gauld at yahoo.co.uk Tue Feb 14 19:35:36 2023 From: alan.gauld at yahoo.co.uk (Alan Gauld) Date: Wed, 15 Feb 2023 00:35:36 +0000 Subject: [Tutor] What exactly does "await" do? (David) In-Reply-To: References: Message-ID: On 14/02/2023 04:40, Alphonsus Okoye wrote: >> A coroutine can be recognised by having 'async def' in its >> definition statement, as opposed to just 'def' for the >> definition of an ordinary function or method. > main purpose of a coroutine? You've been given the technical answer to that. It's basically a routine that can be run as part of a set of concurrently executing functions. However, it's not just a case of using the async syntax. You also need to take care not to leave global resources in unstable states. For example files written to but not flushed etc. Otherwidse the other coroutines may try to access them and bad things start happening. Similarly it is easy to create deadlock scenarios where two routines compete for the sameresource, each locking the other out. As a result writing concurrent code is a non trivial exercise requiring considerable thought and care. > More specifically, if I wished to write a program that read from a long > text file "spam.txt", and while the process begins to waste time, do other > stuff like call function doOtherStuff(), what would the code look like? In general I'd suggest threading for that scenario rather than async. Simpler and lighter weight. Writing a web server or other transaction based processor is a more common scenario for async. Something where the parallel tasks are more varied and of non determinate nature. Reading from a file may take a while but it is fairly predictable. Of course, if the file were a batch file containing instructions for a variey of transaction types, some of them in turn requiring network, database or file access, then async might well be the appropriate engine for processing the file contents. -- Alan G Author of the Learn to Program web site http://www.alan-g.me.uk/ http://www.amazon.com/author/alan_gauld Follow my photo-blog on Flickr at: http://www.flickr.com/photos/alangauldphotos From phonokoye at gmail.com Fri Feb 17 21:43:33 2023 From: phonokoye at gmail.com (Alphonsus) Date: Sat, 18 Feb 2023 03:43:33 +0100 Subject: [Tutor] What exactly does "await" do? (David)(Mats Wichmann)(Alan Gauld) Message-ID: Good day to you Mr David, Mr Mats and Mr. Alan and also to everyone on this mailing list, I do appreciate your response to my questions which have opened up my understanding on the subject, I also apologize for my delayed response. With this mail message I hope to summarize my idea of the subject from your messages and other sources on the web. Please call me out when my statements are wrong. Thank you in advance. asyncio is python's implementation of Asynchronous IO which in turn is a form of IO where other tasks may continue before the IO transmission has ended. This implementation makes use of generators, coroutines, Task and Future objects. Coroutines are further divided into simple and native coroutines, simple coroutines are generators and native coroutines are blocks of code enclosed in an async def header. The await keyword is used to suspend the execution of the surrounding coroutine and begin the execution of the awaited coroutine. (by coroutine, I speak of the native coroutine) The await function in itself does not specify that the coroutine will run concurrently with some other coroutine and coroutines can only run concurrently with coroutines, but we have to explicitly specify that the coroutines will run concurrently by using asyncio.gather or creating tasks using asyncio.create_task and then awaiting the tasks. But all these are just high level stuff. The low level stuff involves the asyncio event loop, Future objects and some concept called a Transport. All of these may not be used frequently but are important for greater control over an asyncio program. These parts of asyncio are probably the most tricky parts. It is important to understand these parts though, so as to make better programming decisions. I also do not understand the low level approach to IO in python. Can I get references that teach these? From bouncingcats at gmail.com Sat Feb 18 06:02:26 2023 From: bouncingcats at gmail.com (David) Date: Sat, 18 Feb 2023 22:02:26 +1100 Subject: [Tutor] What exactly does "await" do? (David)(Mats Wichmann)(Alan Gauld) In-Reply-To: References: Message-ID: On Sat, 18 Feb 2023 at 20:08, Alphonsus wrote: Hi Alphonsus, You wrote: > The low level stuff involves the asyncio event loop, Future objects and > some concept called a Transport. All of these may not be used frequently > but are important for greater control over an asyncio program. These > parts of asyncio are probably the most tricky parts. It is important to > understand these parts though, so as to make better programming > decisions. I also do not understand the low level approach to IO in > python. Can I get references that teach these? I will answer regarding "low level stuff": I am writing here as just one individual person who sometimes asks or answers questions here. In my opinion, your questions have now moved on to advanced topics. It is possible that other people here might answer them, but it is my understanding that discussing advanced topics is not really the purpose of this list. Everything I know about asyncio has come from the references that I shared with you in a previous message. So, I myself cannot give you any more information. For myself, when I needed to use asyncio, I found those references and read them, and then I used that knowledge to write some code using coroutines. That code runs on an STM32 microcontroller and calls the MicroPython implementation of asyncio. It handles the realtime event loop, which manages coroutines for the user interface, A/D conversions, data output. That code works successfully and it does everything that I need. So, my personal experience has been that I have been able to write useful asyncio code in Python without knowing anything about the advanced aspects of it. Have you tried to write any code using asyncio? May I also ask, why do you think that you need to know the answers to the questions that you are asking? Are you writing code? What is the project? Are you writing an essay? Who will read it? Are you applying for a job? Are you creating an online course? Are you studying a course? As I already said, someone else might answer your question in a different way, because that is how things happen here. We all have different approaches to answering questions. From threesomequarks at proton.me Sat Feb 18 12:35:56 2023 From: threesomequarks at proton.me (ThreeBlindQuarks) Date: Sat, 18 Feb 2023 17:35:56 +0000 Subject: [Tutor] What exactly does "await" do? (David)(Mats Wichmann)(Alan Gauld) In-Reply-To: References: Message-ID: <9RavRPFmIaZwIe-jWBZh-Gs-U8vA9caJS-GQ63alrdrjhRfUzdjfhMLBcXqPuWDmSukiCSFNi7DLexjiamsojX7OBol1NDEBr-VzPaRqoAs=@proton.me> Alphonsus, It looks like you copied paragraphs from a textbook so are we supposed to debate that? I think that various ways that have been developed to do asynchronous programming are probably not beginner topics. They represent very different ways of looking at problems and implementing solutions. Think of it more simply. The simplest Python programs do things a step at a time in a rather deterministic way and that is fine for solving lots of problems albeit not always the most efficient way. Python added concepts where a piece of code does not need to finish all at once. Instead of using something like a list comprehension that makes a list of the first million primes and stores them in memory before your program can use the ones it wants, they made several kind of generator objects that are called and yield one result and are put into stasis. Your program can use that result and if it wants more, the generator starts up again where it left off. If after a dozen primes, your program is done, the remaining 999_987 are never even calculated. Python thus allows you to link up multiple such generators in ways that produce results just in time as many parts of the program run only as needed. But they do not run at the same time. Each part that calls another is suspended while the other runs and then continues when it receives what the other has supplied. Python then allows various ways to multitask that have been around for a while. You can start additional full-blown programs or variations on lightweight threads and these can allow some level of independence as the operating system, or a scheduler within python, regularly stops running code and schedules another and eventually restarts the current code. On machines with many CPU, some ways allow things to really run simultaneously and others still run within the same process sharing the same CPU and more. But you have little control on when a process is suspended or animated. In this context, we have the concept of what it means to wait. Programs that make various requests such as to read a file or do something over a network or even access memory not in the cache, get suspended until the request is ready to be handled. But what if you want to download many images (or anything else) from out there or write it out to somewhere or use some form of interprocess communication and so on? Perhaps your main program has things to do that don't care if the previous operation is finished yet. As an example, you may want to read in a file and not wait but order the next file and not wait and so on. Maybe you want to also have some display monitor the progress of the downloads and show what percent has completed? So you want to start such a process too. Finally, when lots of pieces of code are busily doing what you wish, in some interleaved way, you know you need to wait till one (or all) are done before continuing. The above may barely catch the flavor of what asynchronous means. Python grafted many features on way late in the game and even some other languages that built it in early keep evolving ways to do more. What does await do? It depends. Sometimes you use it directly as you describe so that the caller waits but sometimes it is more subtle and the waiting is done by some other routine. An example is when you call a routine that is itself a generator that monitors your many asynchronous offspring and returns a token of the first one that finishes. The main body of your program (or ANY function like this) can use a sort of FOR loop on the generator and get back one at a time. But it does not get back a result from the asynchronous task but just a sort of object representing it. It can then await on that object and it immediately returns with the result from that object. This is not really waiting but a reuse of the keyword to mean they are ready to inspect the results. Writing asynchronously can be very hard to do properly and takes some serious effort to learn. I repeat, not really beginner stuff. Then again, in languages like JavaScript/NodeJS some people think it is the normal way to do things! Sent with Proton Mail secure email. ------- Original Message ------- On Friday, February 17th, 2023 at 9:43 PM, Alphonsus wrote: > Good day to you Mr David, Mr Mats and Mr. Alan and also to everyone on > this mailing list, I do appreciate your response to my questions which > have opened up my understanding on the subject, I also apologize for > my delayed response. With this mail message I hope to summarize my > idea of the subject from your messages and other sources on the web. > Please call me out when my statements are wrong. Thank you in advance. > > asyncio is python's implementation of Asynchronous IO which in turn is > a form of IO where other tasks may continue before the IO transmission > has ended. This implementation makes use of generators, coroutines, > Task and Future objects. > Coroutines are further divided into simple and native coroutines, > simple coroutines are generators and native coroutines are blocks of > code enclosed in an async def header. > > The await keyword is used to suspend the execution of the surrounding > coroutine and begin the execution of the awaited coroutine. (by > coroutine, I speak of the native coroutine) The await function in > itself does not specify that the coroutine will run concurrently with > some other coroutine and coroutines can only run concurrently with > coroutines, but we have to explicitly specify that the coroutines will > run concurrently by using asyncio.gather or creating tasks using > asyncio.create_task and then awaiting the tasks. But all these are > just high level stuff. > > The low level stuff involves the asyncio event loop, Future objects > and some concept called a Transport. All of these may not be used > frequently but are important for greater control over an asyncio > program. These parts of asyncio are probably the most tricky parts. It > is important to understand these parts though, so as to make better > programming decisions. I also do not understand the low level approach > to IO in python. Can I get references that teach these? > _______________________________________________ > Tutor maillist - Tutor at python.org > To unsubscribe or change subscription options: > https://mail.python.org/mailman/listinfo/tutor From sjeik_appie at hotmail.com Sat Feb 18 14:38:20 2023 From: sjeik_appie at hotmail.com (Albert-Jan Roskam) Date: Sat, 18 Feb 2023 20:38:20 +0100 Subject: [Tutor] grid manager question In-Reply-To: Message-ID: Hi, What I usually find easier with something like a group of buttons is to put them in a tk.Frame object. To debug, you can use e.g. bg="red" to change the background color of the frame to see its shape. The frame itself is another "unit" with its own .grid() method. Albert-Jan From threesomequarks at proton.me Sat Feb 18 15:45:17 2023 From: threesomequarks at proton.me (ThreeBlindQuarks) Date: Sat, 18 Feb 2023 20:45:17 +0000 Subject: [Tutor] What exactly does "await" do? (David)(Mats Wichmann)(Alan Gauld) In-Reply-To: References: Message-ID: I think David has expressed some of my own sentiments better. I too found the discussion to be a tad above most of the questions submitted here as quite general about an advanced topic. Most python programmers have never had a reason to use things like asyncio. For some things it is a luxury not needed on our faster computers. In other cases, the modules or packages we use hide it under the rug and we do not have to worry much about how. Yes, it is well worth learning. But perhaps not here in great detail or perhaps using more focused questions on an easily understood minimal example. The question is why the person asking wants to know? What local resources have they exhausted without getting an answer? Would they benefit from an individual tutor who knows and can show it in person, not this semi-public forum? I would add to David's list of questions, the fact that somebody out there has been known to jump in with fairly abstract or difficult questions and then sat back and watched the debate they cause. One individual seems to then use the discussion for purposes like writing books and getting free consulting of a sort. This may not be the case today, but if the volunteers here get diverted into overly technical discussions, we may simply drive away the main users of this group who simply want a little help on fairly basic items and are stuck. So the added question is whether someone is just asking to see what the responses will be or really has a specific reason they need to know. As an aside, I have had occasion to read really old code in Python, and other languages, and been mystified by some of the code. I had to consult books and other resources to find out about some language feature that was introduced in say version 2.3 and then replaced in version 2.5 but continued to work for a few more releases. So the mysterious code often turned out to be a preliminary method that no longer has much reason to be used. Lots of asyncio is like that. Some has been done in whatever way people could manage and now there may be a better way albeit maybe an incompatible way in some cases. My personal path to learning about asyncio was to pause looking at in in Python and switch to (re)learn JavaScript and Node.JS (close to the same language, not quite) which was designed early on to do things in various asynchronous ways and has been modified in some ways to use newer techniques such as promises. Once I sort of understood that, in a language where using such methods is way more common, I went back to studying some of the Python implementations. This is not a path for many other people, and what David wrote is what many do. Instead of deep study, you work on finding what you hope are similar enough recipes/examples and then trying to adjust the framework for your own needs. That is not at all easy to do in this case as every few releases of Python add new functionality or make older ways get deprecated. But as long as you are writing for a project that will not be using older versions, fine. There are many things to watch out for or to use. In many cases, you need to make sure some functions you use (or generator objects) have been created with or use the "async" keyword properly and in other cases, that they have NOT. There are lots of NEW aspects to the language such as using "async for" instead of a regular for loop or "async with" and others and that includes inside things like list comprehensions. Some of that extends into a new set of dunder methods you might need to be aware of or use. So an object having a __iter__ method in synchronous mode would need a __aiter__ method as one part of being used asynchronously. There are lots of such changes and details and lots of people have created all kinds of modules that hide pesky details if you use their module to perform some tasks where the underlying asynchronous nature is fairly well hidden and you can concentrate on getting THAT task done. If anyone wishes to continue, may I suggest the conversation be moved anywhere else, such as a Python board not intended for beginners? I will not await a response as I am asynchronously moving on to other things I constantly juggle in my life and cannot easily do them all at once. Quark Sent with Proton Mail secure email. ------- Original Message ------- On Saturday, February 18th, 2023 at 6:02 AM, David wrote: > On Sat, 18 Feb 2023 at 20:08, Alphonsus phonokoye at gmail.com wrote: > > > Hi Alphonsus, > > You wrote: > > > The low level stuff involves the asyncio event loop, Future objects and > > some concept called a Transport. All of these may not be used frequently > > but are important for greater control over an asyncio program. These > > parts of asyncio are probably the most tricky parts. It is important to > > understand these parts though, so as to make better programming > > decisions. I also do not understand the low level approach to IO in > > python. Can I get references that teach these? > > > I will answer regarding "low level stuff": > > I am writing here as just one individual person who sometimes asks or > answers questions here. In my opinion, your questions have now moved on to > advanced topics. It is possible that other people here might answer them, > but it is my understanding that discussing advanced topics is not really > the purpose of this list. > > Everything I know about asyncio has come from the references that I shared > with you in a previous message. So, I myself cannot give you any more > information. > > For myself, when I needed to use asyncio, I found those references and read > them, and then I used that knowledge to write some code using coroutines. > That code runs on an STM32 microcontroller and calls the MicroPython > implementation of asyncio. It handles the realtime event loop, which > manages coroutines for the user interface, A/D conversions, data output. > That code works successfully and it does everything that I need. > > So, my personal experience has been that I have been able to write useful > asyncio code in Python without knowing anything about the advanced aspects > of it. Have you tried to write any code using asyncio? > > May I also ask, why do you think that you need to know the answers to the > questions that you are asking? > > Are you writing code? What is the project? > Are you writing an essay? Who will read it? > Are you applying for a job? > Are you creating an online course? > Are you studying a course? > > As I already said, someone else might answer your question in a different > way, because that is how things happen here. We all have different approaches > to answering questions. > _______________________________________________ > Tutor maillist - Tutor at python.org > To unsubscribe or change subscription options: > https://mail.python.org/mailman/listinfo/tutor From alan.gauld at yahoo.co.uk Sat Feb 18 20:36:18 2023 From: alan.gauld at yahoo.co.uk (Alan Gauld) Date: Sun, 19 Feb 2023 01:36:18 +0000 Subject: [Tutor] What exactly does "await" do? (David)(Mats Wichmann)(Alan Gauld) In-Reply-To: References: Message-ID: On 18/02/2023 20:45, ThreeBlindQuarks via Tutor wrote: > I too found the discussion to be a tad above most of the questions submitted here > If anyone wishes to continue, may I suggest the conversation be moved anywhere else, > such as a Python board not intended for beginners? While I agree with most of the sentiments expressed I would like to point out that the tutor list is a list with 2 distinct audiences: 1) Beginners to programming in general, including the Python language(the majority of users) 2) Experienced programmers moving to Python as a new language. The second group, while smaller, often ask quite complex and detailed questions (often comparing to features of languages they already know) and that is perfectly legitimate content for this group. Equally, the first group often ask about more abstract generic programming issues and that is equally valid. What is outside the remit of this list is detailed advice about third-party libraries. But if it's in the standard library then anything is fair game. -- Alan G Author of the Learn to Program web site http://www.alan-g.me.uk/ http://www.amazon.com/author/alan_gauld Follow my photo-blog on Flickr at: http://www.flickr.com/photos/alangauldphotos From leamhall at gmail.com Sun Feb 19 08:50:18 2023 From: leamhall at gmail.com (Leam Hall) Date: Sun, 19 Feb 2023 07:50:18 -0600 Subject: [Tutor] List groups (was: What exactly does "await" do?) In-Reply-To: References: Message-ID: <8fa2d9a3-e4d5-5d56-5d8e-1fade853949b@gmail.com> On 2/18/23 19:36, Alan Gauld via Tutor wrote: > 1) Beginners to programming in general, including the Python > language(the majority of users) > > 2) Experienced programmers moving to Python as a new language. I would suggest that there is a third group; people who have learned some Python (often from this list) and who wish to learn more by helping others. Wiser people than I say that "we never learn so much, as when we teach." For us, it is a joy to be able to give back to the community, since we have been given so much. Hopefully, if we give advice that could be improved upon, that smart people will politely point that out. :) Leam -- Automation Engineer (reuel.net/resume) Scribe: The Domici War (domiciwar.net) General Ne'er-do-well (github.com/LeamHall) From alan.gauld at yahoo.co.uk Sun Feb 19 09:56:58 2023 From: alan.gauld at yahoo.co.uk (Alan Gauld) Date: Sun, 19 Feb 2023 14:56:58 +0000 Subject: [Tutor] List groups (was: What exactly does "await" do?) In-Reply-To: <8fa2d9a3-e4d5-5d56-5d8e-1fade853949b@gmail.com> References: <8fa2d9a3-e4d5-5d56-5d8e-1fade853949b@gmail.com> Message-ID: On 19/02/2023 13:50, Leam Hall wrote: > On 2/18/23 19:36, Alan Gauld via Tutor wrote: >> 1) Beginners to programming in general, including the Python >> language(the majority of users) >> >> 2) Experienced programmers moving to Python as a new language. > > I would suggest that there is a third group; Good point, I should have said 2 *main* groups, or "at least 2 groups"... -- Alan G Author of the Learn to Program web site http://www.alan-g.me.uk/ http://www.amazon.com/author/alan_gauld Follow my photo-blog on Flickr at: http://www.flickr.com/photos/alangauldphotos From phonokoye at gmail.com Sun Feb 19 06:20:24 2023 From: phonokoye at gmail.com (Alphonsus) Date: Sun, 19 Feb 2023 12:20:24 +0100 Subject: [Tutor] What exactly does await do? (ThreeBlindQuarks)(David) Message-ID: I am sorry that the question seemed overly complicated, here I will try to make things as simple as things are. In reply to David's question, I am actually writing a gui program but it is expected to do a ton of request and on request by the user read a file, but while the file is being read, I do not expect the program gui loop to stop, and this is the same with the request. I guess part of the problem is that I do not know where to keep the asynchronous routine that fetches resources from the net, in relation to the code and another problem for me is that while trying to understand this from the docs, I am seeing a lot of terms that I do not understand. Normally I read a file using something like this: with open(filename, 'r') as file_object: file_object.read() but it is my experience that this will stop the gui loop temporarily and this becomes noticeable if the file is large. Looking at the python docs, there are three candidates to solve this problem, asyncio, threading or multiprocessing, but I don't understand them well enough to decide what's best and that is what I am trying to understand. I should also add that I found aiofiles package for reading to files asynchronously and I can do that seperately but I still don't understand much of what is going on behind the scenes to know where to place any code anywhere. So my idea was to get information on these modules and what is actually happening within them to help me write good code and one that I can actually debug. There are still things I do not understand but in trying to keep things simple, I will ask only one question at a time and only if I have understood and still find it necessary do I proceed with another question? Using aiofiles is probably the best option for reading asynchronously from a file if you are a professional and understand what you are doing, but as a beginner, I suggest that it will be better for me to know how to read files asynchronously using the standard library first, so that when I am using aiofiles I actually have an idea of what aiofiles is doing in the background. So my question is how do I read files asynchronously in python using only what the standard library provides like io and asyncio modules, but I am not asking for code (if you do provide one though, I don't mind), I am looking for information of the objects that will appear in the code, what the object will be doing, the functions that will be needed in the code, what the functions will be doing, the loop and what will be happening each time through the loop. Just general information from which I can research further on. I just wish to understand the concepts, not burden anyone with my tasks. From threesomequarks at proton.me Sun Feb 19 13:12:11 2023 From: threesomequarks at proton.me (ThreeBlindQuarks) Date: Sun, 19 Feb 2023 18:12:11 +0000 Subject: [Tutor] List groups (was: What exactly does "await" do?) In-Reply-To: <8fa2d9a3-e4d5-5d56-5d8e-1fade853949b@gmail.com> References: <8fa2d9a3-e4d5-5d56-5d8e-1fade853949b@gmail.com> Message-ID: Leam, Alan has made clear what he expects from this forum so I accept that. He and I were likely talking about the people who come to this mailing list for help of some sort and those may fit into several categories. You bring up the other component, of people who are here to help, including some who expect to learn more in the process. I too fit into that category and often a discussion here leads me to explore aspects I have not heard of or only vaguely knew a little about and at times was wrong in my understanding. I note that there also some opportunity for relative beginners to chime in and help each other. There are no assigned roles. The danger I see is what happens if the tutors start off on a discussion that is not really meant to help those wanting help and end up having meta-discussions amongst themselves. The discussion often can be interesting and for some quite worthy, and I often am personally interested. I was just wondering if after a while, the discussion wanders off and is now continuing in a place it is not so welcome or useful. Alan presumably will now tell us when it is. I come across many topics that I might share with others inclined the same way, often discussions across programming languages. But I think my role here is not to raise such topics except insofar as when someone asks and it is somewhat relevant to a reply. The need is often to have people learn how to solve problems in ways that relate to what they learn in class or even using an older version of Python, so some advice on nifty exotic ways may be a tad off target. I see Alphonsus has provided more info on the original question, as requested. This may allow more focused answers that are helpful and not as abstract. Sent with Proton Mail secure email. ------- Original Message ------- On Sunday, February 19th, 2023 at 8:50 AM, Leam Hall wrote: > On 2/18/23 19:36, Alan Gauld via Tutor wrote: > > > 1) Beginners to programming in general, including the Python > > language(the majority of users) > > > > 2) Experienced programmers moving to Python as a new language. > > > I would suggest that there is a third group; people who have learned some Python (often from this list) and who wish to learn more by helping others. Wiser people than I say that "we never learn so much, as when we teach." > > For us, it is a joy to be able to give back to the community, since we have been given so much. Hopefully, if we give advice that could be improved upon, that smart people will politely point that out. :) > > Leam > > -- > Automation Engineer (reuel.net/resume) > Scribe: The Domici War (domiciwar.net) > General Ne'er-do-well (github.com/LeamHall) > _______________________________________________ > Tutor maillist - Tutor at python.org > To unsubscribe or change subscription options: > https://mail.python.org/mailman/listinfo/tutor From mats at wichmann.us Sun Feb 19 14:24:57 2023 From: mats at wichmann.us (Mats Wichmann) Date: Sun, 19 Feb 2023 12:24:57 -0700 Subject: [Tutor] What exactly does await do? (ThreeBlindQuarks)(David) In-Reply-To: References: Message-ID: On 2/19/23 04:20, Alphonsus wrote: > I am sorry that the question seemed overly complicated, here I will > try to make things as simple as things are. In reply to David's > question, I am actually writing a gui program but it is expected to do > a ton of request and on request by the user read a file, but while the > file is being read, I do not expect the program gui loop to stop, and > this is the same with the request. Okay, you've actually hit on something that is not super-well explored - the coexistence of two programming systems that are both event-loop based. This came up a while back in a forum, I had to go digging because my memory isn't that good: https://discuss.python.org/t/connecting-asyncio-and-tkinter-event-loops/14722/4 maybe some nuggets in that, seems like people do have it working, but Python itself didn't do anything specific to make it easy (see Guido's comment) From wlfraed at ix.netcom.com Mon Feb 20 17:02:30 2023 From: wlfraed at ix.netcom.com (Dennis Lee Bieber) Date: Mon, 20 Feb 2023 17:02:30 -0500 Subject: [Tutor] What exactly does await do? (ThreeBlindQuarks)(David) References: Message-ID: <8sk7vhtja7v7r0j69d4arq8hi0mhsgj8vj@4ax.com> On Sun, 19 Feb 2023 12:20:24 +0100, Alphonsus declaimed the following: > >Normally I read a file using something like this: >with open(filename, 'r') as file_object: > file_object.read() > >but it is my experience that this will stop the gui loop temporarily >and this becomes noticeable if the file is large. Looking at the >python docs, there are three candidates to solve this problem, >asyncio, threading or multiprocessing, but I don't understand them >well enough to decide what's best and that is what I am trying to >understand. > I suspect multiprocessing is NOT an option here -- you are adding the overhead of OS-level process creation, along with setting up a communication protocol to transfer data between the processes. As for the GUI event loop... While the event dispatching may appear asynchronous, many GUI system event loops are, at heart, sequential logic. while True: get next event from system queue look up registered event handler CALL event handler I'd recommend studying the GUI toolkit for how /it/ recommends handling long running events. Long running operations need to be either set up as, say, a separate thread (I don't do asyncio -- I find threading a logical programming model for the way I think... and my exposure to co-routines was what could be implemented in FORTRAN-IV using ASSIGNed GOTO, or schemes where the relinquishing routine specified which routine was to run next); or be capable of being broken up into small chunks that can be run via a series of invocations, using something like an On-Idle GUI event handler. Your example is opening a file, and reading ALL of it in one chunk (and throwing the data away ). Instead I'd break the open/close (NO "with" statement) out from the reading, and read in chunks (for a text file, read one line, for binary, read some predefined length) -- with the reading operation handled by an On-Idle handler. ("datastore" is presumed to be some mutable/empty object used to collect the chunks from each small read) fhandle = open(...) schedule On-Idle handler (reader, fhandle, datastore) data = fhandle.read_line if EOF: fhandle.close signal GUI that data is complete else: datastore.append(data) A threaded version would have the initiation event create&start the reader thread, passing the file name and other parameters. The thread can use the "with" statement form to read the file, and would end with signalling the GUI that the data is complete. For tkinter, look at: https://pythonassets.com/posts/background-tasks-with-tk-tkinter/ The On-Idle example can probably be reworked using a generator function ("yield" statement). > >So my question is how do I read files asynchronously in python using >only what the standard library provides like io and asyncio modules, >but I am not asking for code (if you do provide one though, I don't >mind), I am looking for information of the objects that will appear in >the code, what the object will be doing, the functions that will be >needed in the code, what the functions will be doing, the loop and >what will be happening each time through the loop. Just general >information from which I can research further on. I just wish to >understand the concepts, not burden anyone with my tasks. The answer may vary depending on the rest of the code... If you are using a GUI toolkit, you first need to know what features that toolkit provides for "background processing" (the linked tkinter example relies upon a standard Python thread for the read/write and uses one-shot timer events [via .after()] to schedule a GUI event that checks for completion of the reader thread; wxPython examples https://wiki.wxpython.org/LongRunningTasks using thread, wxPython wxYield, and an OnIdle event). Note that neither example mixes async co-routines with sequential dispatch logic. asyncio/await (to me) just doesn't fit the concept of a long-running process (reading/writing a large file in one chunk). Note that await serializes processing -- the function with the await statement stops at that point until the waited-for function returns; so using await in a GUI event handler to wait for the read/write operation to complete is going to block the GUI. -- Wulfraed Dennis Lee Bieber AF6VN wlfraed at ix.netcom.com http://wlfraed.microdiversity.freeddns.org/ From alan.gauld at yahoo.co.uk Tue Feb 21 14:28:07 2023 From: alan.gauld at yahoo.co.uk (Alan Gauld) Date: Tue, 21 Feb 2023 19:28:07 +0000 Subject: [Tutor] What exactly does await do? (ThreeBlindQuarks)(David) In-Reply-To: References: Message-ID: On 19/02/2023 11:20, Alphonsus wrote: > question, I am actually writing a gui program but it is expected to do > a ton of request and on request by the user read a file, but while the > file is being read, I do not expect the program gui loop to stop, and > this is the same with the request. This is a classic scenario for threading. You could do it with async but that means running an async loop inside the gui loop which gets messy. The easiest way is to launch an async thread to run its loop. But if you are launching a thread then why not just read the file in the thread instead? There are some well publicised(over publicised?) issues with Python threading but those don't apply to I/O intesive operations like reading files. > Normally I read a file using something like this: > with open(filename, 'r') as file_object: > file_object.read() And thats fine inside a thread too. Just make sure you sabe the data into a variable accessible once the thread completes and set some kind of semaphore/flag to indicate when the data is safe to use. (ie you've finished the thread) > but it is my experience that this will stop the gui loop temporarily > and this becomes noticeable if the file is large. Looking at the > python docs, there are three candidates to solve this problem, > asyncio, threading or multiprocessing Generalizing very broadly - Asyncio is best for building transaction processors. I don't tend to use it with GUI driven programs. Its better in a server role IMHO. - Multiprocessing is good where the task is long running and indeterminate in nature (reading a file is relatively short and has a determinate end - when the file is read) For example if you had a "server" process that yout GUI used to perform calculations on an ad-hoc basis during the life of the program. Then starting a concurrent process to do the background processing makes sense. Also, due to Python's threading design processor intensive work would make sense. Say you had an IDE program and wanted to run compilations of your code in the background I'd probably choose to use a concurrent process rather than a thread. Or in a Video editor rendering the video could be another case. - Threads are good for quick(relatively) tasks that would block the GUI but will definitely terminate in "user time". Examples being to read a data file, do a spell check etc. Of course, it's not black and white and many will probably disagree with my arbitrary choices above. You can do parallel processing in many ways and there are no absolute rules. > I should also add that I found aiofiles package for reading to files A new one on me! > There are still things I do not understand but in trying to keep > things simple, I will ask only one question at a time and only if I > have understood and still find it necessary do I proceed with another > question? That's a good approach because asking multiple questions leads to confusing responses where it's not clear which question is being answered! > mind), I am looking for information of the objects that will appear in > the code, what the object will be doing, the functions that will be > needed in the code, what the functions will be doing, the loop and > what will be happening each time through the loop. Just general > information from which I can research further on. I just wish to > understand the concepts, not burden anyone with my tasks. In my tutorial(see below) I have three topics (in the advanced section) devoted to parallel processing using fork(), threading and multiprocessing. The examples may be too simple for your purposes but you might find the discussion useful. -- Alan G Author of the Learn to Program web site http://www.alan-g.me.uk/l2p2 http://www.amazon.com/author/alan_gauld Follow my photo-blog on Flickr at: http://www.flickr.com/photos/alangauldphotos From mats at wichmann.us Tue Feb 21 17:13:44 2023 From: mats at wichmann.us (Mats Wichmann) Date: Tue, 21 Feb 2023 15:13:44 -0700 Subject: [Tutor] What exactly does await do? (ThreeBlindQuarks)(David) In-Reply-To: References: Message-ID: <1c4cfb8e-9f1b-406f-d526-f023c64c28e6@wichmann.us> On 2/21/23 12:28, Alan Gauld via Tutor wrote: > And thats fine inside a thread too. > Just make sure you sabe the data into a variable accessible once > the thread completes and set some kind of semaphore/flag to > indicate when the data is safe to use. (ie you've finished > the thread) the queue module is often used for passing information back from threads (and sometimes to them as well). I know this is "well known" but as it's a largely beginner-oriented list it seems worthwhile to mention here in case anyone stumbles across this thread in the future. From phonokoye at gmail.com Thu Feb 23 14:36:22 2023 From: phonokoye at gmail.com (Alphonsus) Date: Thu, 23 Feb 2023 20:36:22 +0100 Subject: [Tutor] Tutor Digest, Vol 228, Issue 18 In-Reply-To: References: Message-ID: Hello Dennis Lee Bieber, Alan Gauld, Mats Wichmann, and everyone on this mailing list. This message is to thank you all for your helpful replies and references and to let you know that it is greatly appreciated. I am still working on the code for now, and there is not much to that. The skies are blue Your efforts are valued This I needed to do So I say Thank you Have a nice day/night ahead On Wed, Feb 22, 2023 at 6:01 PM wrote: > > Send Tutor mailing list submissions to > tutor at python.org > > To subscribe or unsubscribe via the World Wide Web, visit > https://mail.python.org/mailman/listinfo/tutor > or, via email, send a message with subject or body 'help' to > tutor-request at python.org > > You can reach the person managing the list at > tutor-owner at python.org > > When replying, please edit your Subject line so it is more specific > than "Re: Contents of Tutor digest..." > Today's Topics: > > 1. Re: What exactly does await do? (ThreeBlindQuarks)(David) > (Alan Gauld) > 2. Re: What exactly does await do? (ThreeBlindQuarks)(David) > (Mats Wichmann) > > > > ---------- Forwarded message ---------- > From: Alan Gauld > To: tutor at python.org > Cc: > Bcc: > Date: Tue, 21 Feb 2023 19:28:07 +0000 > Subject: Re: [Tutor] What exactly does await do? (ThreeBlindQuarks)(David) > On 19/02/2023 11:20, Alphonsus wrote: > > > question, I am actually writing a gui program but it is expected to do > > a ton of request and on request by the user read a file, but while the > > file is being read, I do not expect the program gui loop to stop, and > > this is the same with the request. > > This is a classic scenario for threading. You could do it with async > but that means running an async loop inside the gui loop which gets > messy. The easiest way is to launch an async thread to run its loop. > But if you are launching a thread then why not just read the file > in the thread instead? > > There are some well publicised(over publicised?) issues with Python > threading but those don't apply to I/O intesive operations like > reading files. > > > Normally I read a file using something like this: > > with open(filename, 'r') as file_object: > > file_object.read() > > And thats fine inside a thread too. > Just make sure you sabe the data into a variable accessible once > the thread completes and set some kind of semaphore/flag to > indicate when the data is safe to use. (ie you've finished > the thread) > > > but it is my experience that this will stop the gui loop temporarily > > and this becomes noticeable if the file is large. Looking at the > > python docs, there are three candidates to solve this problem, > > asyncio, threading or multiprocessing > > Generalizing very broadly > - Asyncio is best for building transaction processors. I don't > tend to use it with GUI driven programs. Its better in a > server role IMHO. > > - Multiprocessing is good where the task is long running and > indeterminate in nature (reading a file is relatively short > and has a determinate end - when the file is read) For > example if you had a "server" process that yout GUI used > to perform calculations on an ad-hoc basis during the life > of the program. Then starting a concurrent process to do > the background processing makes sense. Also, due to > Python's threading design processor intensive work would > make sense. Say you had an IDE program and wanted to > run compilations of your code in the background I'd probably > choose to use a concurrent process rather than a thread. > Or in a Video editor rendering the video could be another case. > > - Threads are good for quick(relatively) tasks that would > block the GUI but will definitely terminate in "user > time". Examples being to read a data file, do a spell > check etc. > > Of course, it's not black and white and many will probably > disagree with my arbitrary choices above. You can do parallel > processing in many ways and there are no absolute rules. > > > I should also add that I found aiofiles package for reading to files > > A new one on me! > > > There are still things I do not understand but in trying to keep > > things simple, I will ask only one question at a time and only if I > > have understood and still find it necessary do I proceed with another > > question? > > That's a good approach because asking multiple questions > leads to confusing responses where it's not clear which > question is being answered! > > > mind), I am looking for information of the objects that will appear in > > the code, what the object will be doing, the functions that will be > > needed in the code, what the functions will be doing, the loop and > > what will be happening each time through the loop. Just general > > information from which I can research further on. I just wish to > > understand the concepts, not burden anyone with my tasks. > > In my tutorial(see below) I have three topics (in the advanced > section) devoted to parallel processing using fork(), threading > and multiprocessing. The examples may be too simple for your > purposes but you might find the discussion useful. > > -- > Alan G > Author of the Learn to Program web site > http://www.alan-g.me.uk/l2p2 > http://www.amazon.com/author/alan_gauld > Follow my photo-blog on Flickr at: > http://www.flickr.com/photos/alangauldphotos > > > > > > > > ---------- Forwarded message ---------- > From: Mats Wichmann > To: tutor at python.org > Cc: > Bcc: > Date: Tue, 21 Feb 2023 15:13:44 -0700 > Subject: Re: [Tutor] What exactly does await do? (ThreeBlindQuarks)(David) > On 2/21/23 12:28, Alan Gauld via Tutor wrote: > > > And thats fine inside a thread too. > > Just make sure you sabe the data into a variable accessible once > > the thread completes and set some kind of semaphore/flag to > > indicate when the data is safe to use. (ie you've finished > > the thread) > > the queue module is often used for passing information back from threads > (and sometimes to them as well). I know this is "well known" but as it's > a largely beginner-oriented list it seems worthwhile to mention here in > case anyone stumbles across this thread in the future. > > > > _______________________________________________ > Tutor maillist - Tutor at python.org > https://mail.python.org/mailman/listinfo/tutor From dave at nk7z.net Thu Feb 23 22:14:51 2023 From: dave at nk7z.net (Dave (NK7Z)) Date: Thu, 23 Feb 2023 19:14:51 -0800 Subject: [Tutor] Looking for some comments on my code segment... Message-ID: <2e235c53-ffac-38cd-c0a6-1fca84410f5c@nk7z.net> Hi, New to Python programming, (this is part of my first Python program, beyond hello world), and I am working on some telnet stuff... I would like to trap all errors, and think I am on to a start for this, but need a bit of help, too new to know what all I need to look for.... In the code below I am creating a telnet object for use later on in the program. I believe I have it correct, but I am sure I have forgotten something. It seems to run fine.. Here is the function for that: def createtelnet(): global tn, failcode try: tn = telnetlib.Telnet(HOST, PORT, TIMEOUT) logdata = "Telnet object created" logit(logdata) except socket.timeout: # Times out, exit with error. failcode = 1 # Let error handler know what is happening. logdata = 'Unable to create telnet object, timed out' logit(logdata) exitscript() # Leave script. except EOFError: logdata = 'Timeout reached in login.' logit(logdata) failcode = 10 exitscript() # Leave script. All variables are set elsewhere, and the above code seems to work fine. What am I leaving out, or what don't I understand, looking for some comments on my code. Later on I am accessing the connection via: try: result = tn.read_until(b"\r\n", TIMEOUT) # Get a line. if result == 'b\'\'': logdata = 'Stream has failed...' logit(logdata) failcode = 7 exitscript() # Leave script. except socket.error: # If socket error-- exit. logdata = 'Socket Error in watchstream, at read.' logit(logdata) failcode = 8 exitscript() # Leave script. except EOFError: # If time out-- exit with error. failcode = 6 # Let error handler know what is happening. logdata = 'Timeout reached in watchstream' logit(logdata) exitscript() # Leave script. logdata = 'Telnet read succeeded, we got:\n' + str(result) logit(logdata) error = sys.stderr logit(str(error)) Code to take apart the string follows this. logit(), is a function to write a log as to what happened... -- 73, and thanks, Dave (NK7Z) https://www.nk7z.net ARRL Volunteer Examiner ARRL Technical Specialist, RFI ARRL Asst. Director, NW Division, Technical Resources From PythonList at DancesWithMice.info Fri Feb 24 15:14:30 2023 From: PythonList at DancesWithMice.info (dn) Date: Sat, 25 Feb 2023 09:14:30 +1300 Subject: [Tutor] Looking for some comments on my code segment... In-Reply-To: <2e235c53-ffac-38cd-c0a6-1fca84410f5c@nk7z.net> References: <2e235c53-ffac-38cd-c0a6-1fca84410f5c@nk7z.net> Message-ID: On 24/02/2023 16.14, Dave (NK7Z) wrote: > Hi, > New to Python programming, (this is part of my first Python program, > beyond hello world), and I am working on some telnet stuff... Welcome! It is quite a BIG step to go from 'hello world' to simulating telnet! However, picking a topic which 'floats your boat' is good motivation for learning! > I would like to trap all errors, and think I am on to a start for this, > but need a bit of help, too new to know what all I need to look for.... This seems to be more of a question about the protocol than Python. (and it's a somewhat specialised topic/little-corner of the PSL) If you want to cover all the possibilities, then consider what each of the calls to library-methods might return. > In the code below I am creating a telnet object for use later on in the > program.? I believe I have it correct, but I am sure I have forgotten > something.? It seems to run fine.. Which is as good a judgement as any other. What tests are you using to prove the code? > Here is the function for that: > > def createtelnet(): > ??? global tn, failcode Why globals, cf passing these in as parameters/arguments and/or return-ing the values? > ??? try: > ??????? tn = telnetlib.Telnet(HOST, PORT, TIMEOUT) (following-on from the above) where are these constants coming-from? > ??????? logdata = "Telnet object created" > ??????? logit(logdata) Is "logdata" used later? If not, how about: logit( "Telnet object created" ) > ??? except socket.timeout:? # Times out, exit with error. > ??????? failcode = 1??????? # Let error handler know what is happening. > ??????? logdata = 'Unable to create telnet object, timed out' > ??????? logit(logdata) > ??????? exitscript()??????? # Leave script. > > ??? except EOFError: > ??????? logdata = 'Timeout reached in login.' > ??????? logit(logdata) > ??????? failcode = 10 > ??????? exitscript()??????? # Leave script. What is the purpose/use of failcode? > All variables are set elsewhere, and the above code seems to work fine. > What am I leaving out, or what don't I understand, looking for some > comments on my code. > > Later on I am accessing the connection via: > > ??????? try: > ??????????? result = tn.read_until(b"\r\n", TIMEOUT)???? # Get a line. > ??????????? if result == 'b\'\'': > ??????????????? logdata = 'Stream has failed...' > ??????????????? logit(logdata) > ??????????????? failcode = 7 > ??????????????? exitscript()? # Leave script. > > ??????? except socket.error:????????? # If socket error-- exit. > ??????????? logdata = 'Socket Error in watchstream, at read.' > ??????????? logit(logdata) > ??????????? failcode = 8 > ??????????? exitscript()? # Leave script. > > ??????? except EOFError:???????? # If time out-- exit with error. > ??????????? failcode = 6? # Let error handler know what is happening. > ??????????? logdata = 'Timeout reached in watchstream' > ??????????? logit(logdata) > ??????????? exitscript()? # Leave script. > > ??????? logdata = 'Telnet read succeeded, we got:\n' + str(result) > ??????? logit(logdata) > ??????? error = sys.stderr > ??????? logit(str(error)) > > Code to take apart the string follows this.? logit(), is a function to > write a log as to what happened... Good to see use of logging. (we are talking about the logging-library, aren't we?) What is exitscript(), and what is its purpose? Could the calling routine wrap the call in its own try-except? -- Regards, =dn From cs at cskk.id.au Fri Feb 24 17:26:55 2023 From: cs at cskk.id.au (Cameron Simpson) Date: Sat, 25 Feb 2023 09:26:55 +1100 Subject: [Tutor] Looking for some comments on my code segment... In-Reply-To: References: Message-ID: On 25Feb2023 09:18, Cameron Simpson wrote: >Two other things: by using global variables and calling exitscript() >from your set up function you're embedding policy in the function i.e. >that this function will only ever be called once and therefore globals >can store the result, and that failure of this function should exit the >entire programme. I meant to add some commentry here: I find it helpful to distinguish in my mind mechanism and policy. Mechanism is how something is done eg: tn = telnetlib.Telnet(HOST, PORT, TIMEOUT) Policy is deciding how to handle the ways that might play out, particularly failure. By putting eg exitscript() in the function you're putting policy about what happens on failure in the low level function opening the telnet connection. This leaves little flexibility for the user of your function. I know in this case it's a new script and you're the only person using it, but later when you keep code around to solve problems it becomes more and more important. My general principle here is that mechanism lives in the low level functions (well, it happens where it happens, or your programme doesn't work), but policy should be in the outer levels i.e the caller of your functions - as far out as possible. One nice thing about exceptions is that they let you punt on policy as much as you like. Don't know how some exception should be handled (because _in_ the functin you don't know what the function's being used for)? Ignore it and let the exception bubble out - some claller with more context can decide what to do. Cheers, Cameron Simpson From cs at cskk.id.au Fri Feb 24 17:18:39 2023 From: cs at cskk.id.au (Cameron Simpson) Date: Sat, 25 Feb 2023 09:18:39 +1100 Subject: [Tutor] Looking for some comments on my code segment... In-Reply-To: <2e235c53-ffac-38cd-c0a6-1fca84410f5c@nk7z.net> References: <2e235c53-ffac-38cd-c0a6-1fca84410f5c@nk7z.net> Message-ID: On 23Feb2023 19:14, Dave (NK7Z) wrote: >def createtelnet(): > global tn, failcode Try not to use globals, it makes things harder to resue. You could just return these from the function, and have the caller store them in whatever fashion it prefers. > try: > tn = telnetlib.Telnet(HOST, PORT, TIMEOUT) > logdata = "Telnet object created" > logit(logdata) > > except socket.timeout: # Times out, exit with error. > failcode = 1 # Let error handler know what is happening. > logdata = 'Unable to create telnet object, timed out' > logit(logdata) > exitscript() # Leave script. > > except EOFError: > logdata = 'Timeout reached in login.' > logit(logdata) > failcode = 10 > exitscript() # Leave script. As a general principle you should keep try/except clauses as small as possible. I'd shuffle the bove to be: try: tn = telnetlib.Telnet(HOST, PORT, TIMEOUT) except socket.timeout: # Times out, exit with error. failcode = 1 # Let error handler know what is happening. logdata = 'Unable to create telnet object, timed out' logit(logdata) exitscript() # Leave script. except EOFError: logdata = 'Timeout reached in login.' logit(logdata) failcode = 10 exitscript() # Leave script. else: logdata = "Telnet object created" logit(logdata) The more you have in the try/except, the less certainty you have that any exception you catch cme from what you intended to handle i.e. the telnetlib.Telnet() call. Supposing there was an exception during the logit("Telnet object created") call? You'd treat t as though there had been a telnet failure, not a logging failure. >Later on I am accessing the connection via: > > try: > result = tn.read_until(b"\r\n", TIMEOUT) # Get a line. > if result == 'b\'\'': > logdata = 'Stream has failed...' > logit(logdata) > failcode = 7 > exitscript() # Leave script. Again, your try/excepts are too broad. Enclose _only_ the code whose errors you are handling. Two other things: by using global variables and calling exitscript() from your set up function you're embedding policy in the function i.e. that this function will only ever be called once and therefore globals can store the result, and that failure of this function should exit the entire programme. Usually a function might be called from many different situations, and maybe the caller has their own opinion about how failure should be handled, or might open 2 telnet connections, etc. By embedding policy about globals and aborting the programme in the function you remove the caller's flexibility. I'd change the function to be something like this: # get rid of the "global" statement, so "tn" is a local tn = None # placeholder values failcode = None try: tn = telnetlib.Telnet(HOST, PORT, TIMEOUT) except socket.timeout: # Times out, exit with error. failcode = 1 # Let error handler know what is happening. logdata = 'Unable to create telnet object, timed out' logit(logdata) except EOFError: logdata = 'Timeout reached in login.' logit(logdata) failcode = 10 else: logdata = "Telnet object created" logit(logdata) return tn, failcode Then the caller can go: tn, failcode = createtelnet() if tn is None: logit('createtelnet failed, failcode = {failcode}') else: ... use tn to do stuff ... Cheers, Cameron Simpson From ryanhurtt01 at aim.com Fri Feb 24 19:47:21 2023 From: ryanhurtt01 at aim.com (Ryan Hurtt) Date: Sat, 25 Feb 2023 00:47:21 +0000 (UTC) Subject: [Tutor] (no subject) References: <1970531419.408850.1677286041125.ref@mail.yahoo.com> Message-ID: <1970531419.408850.1677286041125@mail.yahoo.com> I'm currently trying to get started with programming python, but I keep getting overwhelmed with information. What's the best, most digestible way to start? From dave at nk7z.net Fri Feb 24 16:13:10 2023 From: dave at nk7z.net (Dave (NK7Z)) Date: Fri, 24 Feb 2023 13:13:10 -0800 Subject: [Tutor] Looking for some comments on my code segment... In-Reply-To: References: <2e235c53-ffac-38cd-c0a6-1fca84410f5c@nk7z.net> Message-ID: <70a79c97-9aef-b9f5-3e4c-9d2ed62ebd34@nk7z.net> Hi, Many thanks for answering!! I'll try and take each of your comments in order... I tend to drop in with both feet into anything I try hence, the hello world to telnet move... Tests to prove code: The entire program is around 800 lines long at this point, and I did not want to drop that into an email... An overview of what I am doing: I have an amateur radio license, and there are telnet servers on the net called clusters, these clusters aggregate incoming spots, (little notes amateurs send to the cluster servers), to tell other amateur radio operators, they have seen a station, on such and such a frequency, using such and such a mode, at such and such a time. The cluster spots are highly formatted, and are designed to be parsed by software. This software is written for two reasons, one to teach me Python, and the other to alert me to selected stations from a list in a file, that changes from time to time. The software logs into one of these clusters, parses the incoming telnet feed stream, and then verbally announces stations I am interested in, as defined in a separate file I populate. Code Proof: The code proof is that it is working, it logs into the clusters, and announces what I expect. All the code works, as far as I can tell, the software logs in, IDs my by callsign to the server, configures the server stream, then looks at the incoming stream of data, and parses it looking at my want list from that other file. A day can have as many as a million spots in it across a 24 hour period. My question is motivated by the far end dropping telnet connection every few days, (reset server, update the server software, etc, does not happen often). I want to be able to trap that drop and gracefully leave the script. Or perhaps relog in after I gain some confidence in my programming ability ion Python. Globals: I am using globals, because in some cases, the variable(s) I use is/are not passed to/from the function. Where are these constants coming from: They are defined very early on in the software. I could drop thej software here, but it is around 800 lines long, so I decided to not as my first post... :) Failcode: I write a log file of my own making, and add the fail codes in the event something dies, I know where... Logging: Not using logging library, I ran across that a few days ago, and will be switching to that method later, after things are running as I want. exitscript: Yes the main calling loop could leave with a try/except, but for now, I am exiting this way, that will guarantee a clean exit. exitscript() is just a routine to kill things, in a way I KNOW will things get killed as I want then to be killed. Because I am interacting with someone else's server, and because this is the first telnet script in Python I have written, I want to INSURE without a doubt I have closed the connection in case of a fail of some sort in my code. As I said, I am VERY new to Python... I just learned how try/except worked a few weeks ago, so I did not put that in my main calling loop, I directed things to a function designed to kill things no matter what happened... I am now using try/except and understand it, and at some point will correct things in the main caller. There will be many changes to the script over time, right now I am working on the telnet portion, and that is why I am asking about that. This entire script is a learning experience for me, and that is why I decided to write it in Python, never wrote in Python before, and for that I am sad... Things seem to just come together in Python. I am having a blast with it! I can't seem to get my head around how to trap the telnet errors though... Again, thanks for your help in all of this, and sorry the questions are so basic. 73, and thanks, Dave (NK7Z) https://www.nk7z.net ARRL Volunteer Examiner ARRL Technical Specialist, RFI ARRL Asst. Director, NW Division, Technical Resources On 2/24/23 12:14, dn via Tutor wrote: > On 24/02/2023 16.14, Dave (NK7Z) wrote: >> Hi, >> New to Python programming, (this is part of my first Python program, >> beyond hello world), and I am working on some telnet stuff... > > Welcome! > > It is quite a BIG step to go from 'hello world' to simulating telnet! > However, picking a topic which 'floats your boat' is good motivation for > learning! > > >> I would like to trap all errors, and think I am on to a start for >> this, but need a bit of help, too new to know what all I need to look >> for.... > > This seems to be more of a question about the protocol than Python. > (and it's a somewhat specialised topic/little-corner of the PSL) > > If you want to cover all the possibilities, then consider what each of > the calls to library-methods might return. > > >> In the code below I am creating a telnet object for use later on in >> the program.? I believe I have it correct, but I am sure I have >> forgotten something.? It seems to run fine.. > > Which is as good a judgement as any other. > > What tests are you using to prove the code? > > >> Here is the function for that: >> >> def createtelnet(): >> ???? global tn, failcode > > Why globals, cf passing these in as parameters/arguments and/or > return-ing the values? > > >> ???? try: >> ???????? tn = telnetlib.Telnet(HOST, PORT, TIMEOUT) > > (following-on from the above) where are these constants coming-from? > > >> ???????? logdata = "Telnet object created" >> ???????? logit(logdata) > > Is "logdata" used later? > If not, how about: > > ??? logit( "Telnet object created" ) > > >> ???? except socket.timeout:? # Times out, exit with error. >> ???????? failcode = 1??????? # Let error handler know what is happening. >> ???????? logdata = 'Unable to create telnet object, timed out' >> ???????? logit(logdata) >> ???????? exitscript()??????? # Leave script. >> >> ???? except EOFError: >> ???????? logdata = 'Timeout reached in login.' >> ???????? logit(logdata) >> ???????? failcode = 10 >> ???????? exitscript()??????? # Leave script. > > What is the purpose/use of failcode? > > >> All variables are set elsewhere, and the above code seems to work >> fine. What am I leaving out, or what don't I understand, looking for >> some comments on my code. >> >> Later on I am accessing the connection via: >> >> ???????? try: >> ???????????? result = tn.read_until(b"\r\n", TIMEOUT)???? # Get a line. >> ???????????? if result == 'b\'\'': >> ???????????????? logdata = 'Stream has failed...' >> ???????????????? logit(logdata) >> ???????????????? failcode = 7 >> ???????????????? exitscript()? # Leave script. >> >> ???????? except socket.error:????????? # If socket error-- exit. >> ???????????? logdata = 'Socket Error in watchstream, at read.' >> ???????????? logit(logdata) >> ???????????? failcode = 8 >> ???????????? exitscript()? # Leave script. >> >> ???????? except EOFError:???????? # If time out-- exit with error. >> ???????????? failcode = 6? # Let error handler know what is happening. >> ???????????? logdata = 'Timeout reached in watchstream' >> ???????????? logit(logdata) >> ???????????? exitscript()? # Leave script. >> >> ???????? logdata = 'Telnet read succeeded, we got:\n' + str(result) >> ???????? logit(logdata) >> ???????? error = sys.stderr >> ???????? logit(str(error)) >> >> Code to take apart the string follows this.? logit(), is a function to >> write a log as to what happened... > > Good to see use of logging. > (we are talking about the logging-library, aren't we?) > > What is exitscript(), and what is its purpose? > Could the calling routine wrap the call in its own try-except? > From dave at nk7z.net Fri Feb 24 19:25:29 2023 From: dave at nk7z.net (Dave (NK7Z)) Date: Fri, 24 Feb 2023 16:25:29 -0800 Subject: [Tutor] Looking for some comments on my code segment... In-Reply-To: References: <2e235c53-ffac-38cd-c0a6-1fca84410f5c@nk7z.net> Message-ID: <9fd5137d-3b11-d8f7-0fbe-d6f5293ec4af@nk7z.net> Cameron, Many thanks to you for this suggestions, and more importantly why you suggested what you did! I will make the suggested changes! 73, and thanks, Dave (NK7Z) https://www.nk7z.net ARRL Volunteer Examiner ARRL Technical Specialist, RFI ARRL Asst. Director, NW Division, Technical Resources On 2/24/23 14:18, Cameron Simpson wrote: > On 23Feb2023 19:14, Dave (NK7Z) wrote: >> def createtelnet(): >> ?? global tn, failcode > > Try not to use globals, it makes things harder to resue. You could just > return these from the function, and have the caller store them in > whatever fashion it prefers. > >> ?? try: >> ?????? tn = telnetlib.Telnet(HOST, PORT, TIMEOUT) >> ?????? logdata = "Telnet object created" >> ?????? logit(logdata) >> >> ?? except socket.timeout:? # Times out, exit with error. >> ?????? failcode = 1??????? # Let error handler know what is happening. >> ?????? logdata = 'Unable to create telnet object, timed out' >> ?????? logit(logdata) >> ?????? exitscript()??????? # Leave script. >> >> ?? except EOFError: >> ?????? logdata = 'Timeout reached in login.' >> ?????? logit(logdata) >> ?????? failcode = 10 >> ?????? exitscript()??????? # Leave script. > > As a general principle you should keep try/except clauses as small as > possible. I'd shuffle the bove to be: > > ??? try: > ??????? tn = telnetlib.Telnet(HOST, PORT, TIMEOUT) > ??? except socket.timeout:? # Times out, exit with error. > ??????? failcode = 1??????? # Let error handler know what is happening. > ??????? logdata = 'Unable to create telnet object, timed out' > ??????? logit(logdata) > ??????? exitscript()??????? # Leave script. > > ??? except EOFError: > ??????? logdata = 'Timeout reached in login.' > ??????? logit(logdata) > ??????? failcode = 10 > ??????? exitscript()??????? # Leave script. > > ??? else: > ??????? logdata = "Telnet object created" > ??????? logit(logdata) > > The more you have in the try/except, the less certainty you have that > any exception you catch cme from what you intended to handle i.e. the > telnetlib.Telnet() call. Supposing there was an exception during the > logit("Telnet object created") call? You'd treat t as though there had > been a telnet failure, not a logging failure. > >> Later on I am accessing the connection via: >> >> ?????? try: >> ?????????? result = tn.read_until(b"\r\n", TIMEOUT)???? # Get a line. >> ?????????? if result == 'b\'\'': >> ?????????????? logdata = 'Stream has failed...' >> ?????????????? logit(logdata) >> ?????????????? failcode = 7 >> ?????????????? exitscript()? # Leave script. > > Again, your try/excepts are too broad. Enclose _only_ the code whose > errors you are handling. > > Two other things: by using global variables and calling exitscript() > from your set up function you're embedding policy in the function i.e. > that this function will only ever be called once and therefore globals > can store the result, and that failure of this function should exit the > entire programme. > > Usually a function might be called from many different situations, and > maybe the caller has their own opinion about how failure should be > handled, or might open 2 telnet connections, etc. By embedding policy > about globals and aborting the programme in the function you remove the > caller's flexibility. > > I'd change the function to be something like this: > > ??? # get rid of the "global" statement, so "tn" is a local > ??? tn = None? # placeholder values > ??? failcode = None > ??? try: > ??????? tn = telnetlib.Telnet(HOST, PORT, TIMEOUT) > ??? except socket.timeout:? # Times out, exit with error. > ??????? failcode = 1??????? # Let error handler know what is happening. > ??????? logdata = 'Unable to create telnet object, timed out' > ??????? logit(logdata) > > ??? except EOFError: > ??????? logdata = 'Timeout reached in login.' > ??????? logit(logdata) > ??????? failcode = 10 > > ??? else: > ??????? logdata = "Telnet object created" > ??????? logit(logdata) > > ??? return tn, failcode > > Then the caller can go: > > ??? tn, failcode = createtelnet() > ??? if tn is None: > ??????? logit('createtelnet failed, failcode = {failcode}') > ??? else: > ??????? ... use tn to do stuff ... > > Cheers, > Cameron Simpson > _______________________________________________ > Tutor maillist? -? Tutor at python.org > To unsubscribe or change subscription options: > https://mail.python.org/mailman/listinfo/tutor From dave at nk7z.net Fri Feb 24 19:28:45 2023 From: dave at nk7z.net (Dave (NK7Z)) Date: Fri, 24 Feb 2023 16:28:45 -0800 Subject: [Tutor] Looking for some comments on my code segment... In-Reply-To: References: Message-ID: ...and yet again, thank you for that input, and the examples... All good advice... Most of this is because I am new to Python... I will implement. I will make the changes you suggested, and hopefully those will trap errors better than my versions did... THANK YOU again sir!! 73, and thanks, Dave (NK7Z) https://www.nk7z.net ARRL Volunteer Examiner ARRL Technical Specialist, RFI ARRL Asst. Director, NW Division, Technical Resources On 2/24/23 14:26, Cameron Simpson wrote: > On 25Feb2023 09:18, Cameron Simpson wrote: >> Two other things: by using global variables and calling exitscript() >> from your set up function you're embedding policy in the function i.e. >> that this function will only ever be called once and therefore globals >> can store the result, and that failure of this function should exit >> the entire programme. > > I meant to add some commentry here: > > I find it helpful to distinguish in my mind mechanism and policy. > Mechanism is how something is done eg: tn = telnetlib.Telnet(HOST, PORT, > TIMEOUT) > > Policy is deciding how to handle the ways that might play out, > particularly failure. > > By putting eg exitscript() in the function you're putting policy about > what happens on failure in the low level function opening the telnet > connection. This leaves little flexibility for the user of your function. > > I know in this case it's a new script and you're the only person using > it, but later when you keep code around to solve problems it becomes > more and more important. > > My general principle here is that mechanism lives in the low level > functions (well, it happens where it happens, or your programme doesn't > work), but policy should be in the outer levels i.e the caller of your > functions - as far out as possible. > > One nice thing about exceptions is that they let you punt on policy as > much as you like. Don't know how some exception should be handled > (because _in_ the functin you don't know what the function's being used > for)? Ignore it and let the exception bubble out - some claller with > more context can decide what to do. > > Cheers, > Cameron Simpson > _______________________________________________ > Tutor maillist? -? Tutor at python.org > To unsubscribe or change subscription options: > https://mail.python.org/mailman/listinfo/tutor From alan.gauld at yahoo.co.uk Fri Feb 24 20:28:54 2023 From: alan.gauld at yahoo.co.uk (Alan Gauld) Date: Sat, 25 Feb 2023 01:28:54 +0000 Subject: [Tutor] (no subject) In-Reply-To: <1970531419.408850.1677286041125@mail.yahoo.com> References: <1970531419.408850.1677286041125.ref@mail.yahoo.com> <1970531419.408850.1677286041125@mail.yahoo.com> Message-ID: On 25/02/2023 00:47, Ryan Hurtt via Tutor wrote: > I'm currently trying to get started with programming python, > but I keep getting overwhelmed with information. What's the > best, most digestible way to start? Find a tutorial that makes sense to you (everyone has their own preferred learning style) and work through it, typing in the code (ideally by hand, it builds "muscle memory"!) Modify the examples and observe what you expect versus what you get. If they are different experiment until you understand why. If you don't understand then ask questions here - it's what we are here for! There are a bunch of tutorials on the beginners pages of the python.org website. Which one suits you depends on your previous programming and/or computing experience. Try a few sample sections and see if they make sense and pick the "best". Having gone through a tutorial you should then quickly go through the official tutorial (aimed at programmers which you will hopefully be by now) to get the "authorised" information and fill any possible gaps. (It should only take a few hours since you will know most of it already.) Then pick a project and have at it. Again, any questions can be directed here. Or you could try my tutorial(below)... it's aimed at experienced computer users who are novice programmers. -- Alan G Author of the Learn to Program web site http://www.alan-g.me.uk/ http://www.amazon.com/author/alan_gauld Follow my photo-blog on Flickr at: http://www.flickr.com/photos/alangauldphotos From PythonList at DancesWithMice.info Fri Feb 24 22:09:31 2023 From: PythonList at DancesWithMice.info (dn) Date: Sat, 25 Feb 2023 16:09:31 +1300 Subject: [Tutor] Looking for some comments on my code segment... In-Reply-To: <70a79c97-9aef-b9f5-3e4c-9d2ed62ebd34@nk7z.net> References: <2e235c53-ffac-38cd-c0a6-1fca84410f5c@nk7z.net> <70a79c97-9aef-b9f5-3e4c-9d2ed62ebd34@nk7z.net> Message-ID: On 25/02/2023 10.13, Dave (NK7Z) wrote: > I tend to drop in with both feet into anything I try hence, the hello > world to telnet move... As long as you don't drive yourself into over-load and right over a cliff into de-motivation... > Tests to prove code: > > The entire program is around 800 lines long at this point, and I did not > want to drop that into an email... Quite right. If the code exhibits an error, the first thing to do is extract the minimum example which will illustrate/demonstrate the error, and post that. (assuming such process doesn't make the solution leap-out) > An overview of what I am doing: > I have an amateur radio license, and there are telnet servers on the net > called clusters, these clusters aggregate incoming spots, (little notes > amateurs send to the cluster servers), to tell other amateur radio > operators, they have seen a station, on such and such a frequency, using > such and such a mode, at such and such a time.? The cluster spots are > highly formatted, and are designed to be parsed by software.? This > software is written for two reasons, one to teach me Python, and the > other to alert me to selected stations from a list in a file, that > changes from time to time. > The software logs into one of these clusters, parses the incoming telnet > feed stream, and then verbally announces stations I am interested in, as > defined in a separate file I populate. I've never been a 'ham' operator. Almost 32-years to the day, I hung-up my three 'radios', amongst other electronic (and other) items: one would now be called a sat-phone - for talking to "Central Command" (I never did figure-out where), an FM/VHF and FA unit for talking with the pilots flying CAP close-by in case we needed them (and when we did, we did - and they did...), and another at some longer wave for talking with Fleet and the grey tin-cans bobbing about in the Gulf. That said, we've just endured a series of natural disasters, and 'this modern generation' have realised that relying upon cell-phones and 'the Internet' is a superficial layer of banality, sorry, security, which separates 'civilisation' from 'breakdown'. Hams + generators have certainly been needed to provide vital comms. Interestingly, (lesson not learned?) a 'solution' has been to fly-in pairs of StarLink + gen-set to separated communities. > Code Proof: > The code proof is that it is working, it logs into the clusters, and > announces what I expect.? All the code works, as far as I can tell, the > software logs in, IDs my by callsign to the server, configures the > server stream, then looks at the incoming stream of data, and parses it > looking at my want list from that other file.? A day can have as many as > a million spots in it across a 24 hour period. > > My question is motivated by the far end dropping telnet connection every > few days, (reset server, update the server software, etc, does not > happen often). I want to be able to trap that drop and gracefully leave > the script.? Or perhaps relog in after I gain some confidence in my > programming ability ion Python. You can test this by removing the Ethernet cable from your computer! To solve the bigger 'problem', break it down into smaller, sub-problems, eg "grabbing data from the server" can be split into connecting, logging-in, call-sign, establish stream, examine ... Try working 'bottom-up'. Take each of these in-turn, and split it off into its own function. What result(s) do you expect from this function? What will it do to create such output? What input will it need? NB "results" because an error-occurring will be a different result from a successful-execution (etc). Now, you can write other code which calls that function, purely with the intent of testing what happens if you give it certain input(s) - and can check to see if the output(s) is/are exactly as-designed. By doing this, breaking the 800-line entirety into smaller "units", you can concentrate on the proverbial one-thing-at-a-time, gain confidence (in yourself, and the code), and test for only relevant issues (undistracted by what else happens at other stages in the process). (there's more to be said about this process, but (hah!) one step at a time cf 'overload'...) Once you have completed a daisy-chain of such units (perhaps as loosely-outlined, above) you can (going bottom-up) work on a 'higher-level' function which will call each of the smaller units, in sequence - feeding them needed data, and controlling the returned-results. (and so-on, until reach the 'mainline') > Globals: > I am using globals, because in some cases, the variable(s) I use is/are > not passed to/from the function. Why not then, pass them into the function? (etc) (see also @Cameron's comments) > Where are these constants coming from: > > They are defined very early on in the software.? I could drop thej > software here, but it is around 800 lines long, so I decided to not as > my first post...? :) Consider that combinations such as "HOST, PORT, TIMEOUT" could be presented as a "collection", eg a tuple. Then there'd only be one identifier to pass-around. You can also select a name which communicates its use/purpose! The point to the question though, was to point-out that these 'magic-constants' just 'appear', whereas tn and failcode are explicitly identified. Don't make me think! (it hurts) Agreed, one lot are 'read-only' and the others read-write, thus appropriate mechanisms must be chosen. However, if you combine thoughts from (above), eg what is the output from this unit of code, they you realise that the telnet object is output from one unit which will become input to another. Thus, no need for it to be a 'global'. (see also @Cameron's comment, aka avoid globals as much as possible - on the grounds that such techniques, whilst perfectly legal, have a nasty habit of coming back to bite you) > Failcode: > I write a log file of my own making, and add the fail codes in the event > something dies, I know where... > > Logging: > Not using logging library, I ran across that a few days ago, and will be > switching to that method later, after things are running as I want. ToDo: See above. Smaller units make 'location' easier. Backlog: read-up about the logging library. > exitscript: > Yes the main calling loop could leave with a try/except, but for now, I > am exiting this way, that will guarantee a clean exit.? exitscript() is > just a routine to kill things, in a way I KNOW will things get killed as > ?I want then to be killed. Complement your development using try...except with raise and Custom Exceptions. In short, defining your own means that you can use try-except at the 'higher level' to achieve exactly what you are currently rolling-by-hand. In short, now that you have learned this new technique, go 'back' and refactor (improve) earlier code to take advantage. (no shame, refactoring is 'best practice') > Because I am interacting with someone else's server, and because this is > the first telnet script in Python I have written, I want to INSURE > without a doubt I have closed the connection in case of a fail of some > sort in my code. Good thinking - we should all be 'good citizens', aka 'the Boy Scout Rule'. There is a time-out on every telnet transaction (not only the logging-in process). You do not need to fear for the remote server! Another powerful technique you might like to add to the 'Backlog' is Python's Context Manager protocol. The philosophy exactly matches your intent. Three tasks: - task commencement - the doing of the task - cleaning-up afterwards Context-managers will guarantee that the last will be completed regardless of the success/state of earlier stages! > As I said, I am VERY new to Python...? I just learned how try/except > worked a few weeks ago, so I did not put that in my main calling loop, I > directed things to a function designed to kill things no matter what > happened...? I am now using try/except and understand it, and at some > point will correct things in the main caller. Recommend sooner rather than later. Let the power of Python (in this case try-except) save you unnecessary work (blood, sweat, or tears). > There will be many changes to the script over time, right now I am > working on the telnet portion, and that is why I am asking about that. ...and we're back to "units"! We develop a unit at a time, and in relative isolation - get it right, and move-on. > This entire script is a learning experience for me, and that is why I > decided to write it in Python, never wrote in Python before, and for > that I am sad...? Things seem to just come together in Python.? I am > having a blast with it! That's why we like it too! > I can't seem to get my head around how to trap the telnet errors though... Which one(s)? Where is current code failing? > Again, thanks for your help in all of this, and sorry the questions are > so basic. That's why this Discussion List exists! "There's no such thing as a stupid-question, only stupid answers". (that said, there are ways of asking a question which will promote the receipt of a good/better/best answer...) -- Regards, =dn From dave at nk7z.net Fri Feb 24 20:03:57 2023 From: dave at nk7z.net (Dave (NK7Z)) Date: Fri, 24 Feb 2023 17:03:57 -0800 Subject: [Tutor] (no subject) In-Reply-To: <1970531419.408850.1677286041125@mail.yahoo.com> References: <1970531419.408850.1677286041125.ref@mail.yahoo.com> <1970531419.408850.1677286041125@mail.yahoo.com> Message-ID: <01f46f6f-6d5f-2f84-cc92-e100dd9dca11@nk7z.net> As one person that just began Python to another, I broke up my program into small chunks, and programed each chunk. I created a hello world program, then decided I needed a parser for for a telnet item I was working on... That keeps the pressure on me to get it going, because I want the result. That led to learning how to log into a telnet server, which led to how to configure things, which led to... You get the picture. At each point I did not know something, (which there were many), I looked it up on the Internet, or in a few Python books I bought. It gets you moving in the right direction... I am not worried about reading a lot of other material in the process, it primes the pump so to speak for me... It lets me know what can be done, not how to do it yet... Then when I need to do something I know it can be done, so I then look up how to do it. My program is now pushing 800 lines of working code... It is a lot of work, but I had forgotten just how much fun programming was... 73, and thanks, Dave (NK7Z) https://www.nk7z.net ARRL Volunteer Examiner ARRL Technical Specialist, RFI ARRL Asst. Director, NW Division, Technical Resources On 2/24/23 16:47, Ryan Hurtt via Tutor wrote: > I'm currently trying to get started with programming python, but I keep getting overwhelmed with information. What's the best, most digestible way to start? > _______________________________________________ > Tutor maillist - Tutor at python.org > To unsubscribe or change subscription options: > https://mail.python.org/mailman/listinfo/tutor From albert1.cornelius at gmail.com Tue Feb 28 04:18:57 2023 From: albert1.cornelius at gmail.com (Albert Cornelius) Date: Tue, 28 Feb 2023 10:18:57 +0100 Subject: [Tutor] What does yield do? Message-ID: I've seen some examples on yield like this: >>> def create_generator():... mylist = range(3)... for i in mylist:... yield i*i ...>>> mygenerator = create_generator() # create a generator>>> print(mygenerator) # mygenerator is an object! >>> for i in mygenerator:... print(i)014 and I've read some amout of text about it. But I still don't really grasp the idea of yield. I'm coming from the Java world and am in my 2nd semester, so please be kind. Can someone please provide an ELI5 (Explain Like I'm 5) explanation of what yield does? From alan.gauld at yahoo.co.uk Tue Feb 28 06:31:50 2023 From: alan.gauld at yahoo.co.uk (Alan Gauld) Date: Tue, 28 Feb 2023 11:31:50 +0000 Subject: [Tutor] What does yield do? In-Reply-To: References: Message-ID: On 28/02/2023 09:18, Albert Cornelius wrote: > and I've read some amout of text about it. But I still don't really > grasp the idea of yield. I'm coming from the Java world I don't think Java has any similar feature so Java probably won't help here. yield is like a "return and pause" statement. It returns the current value but does not terminate the function, instead the function goes to sleep until next called. When it is called the next time it picks up from the statement after the yield. def simpleYield(): yield 1 # result of first use yield 2 # result of 2nd use yield 3 # last use. for n in range(3): print(simpleYield()) Except that doesn't work because the function is not a regular function. By using yield it becomes a generator (personally, I wish they'd defined a new word to make that explicit - defgen or somesuch...) So to use simpleYield we have to "instantiate" it: gen = simpleYield() and now we can use the generator: for n in gen: print(n) #-> 1,2,3 Now that example is pretty pointless. But imagine you want to return an infinitely long list, the list of all odd numbers starting at 1. To do that without a generator(ie yield) would require either a global variable (ugly) or defining a class - quite a lot of work. Defining a generator is simpler: def odds(): n = 1 while True: yield n n += 2 allOdds = odds() for n in allOdds: if n >10: break # avoid going to infinity and beyond! print(n) That's about as simple as I can make it for a (pretty smart!) 5 year old. :-) If you need more, ask away. You might find the original proposal (PEP255) useful if you haven't already read it: https://peps.python.org/pep-0255 -- Alan G Author of the Learn to Program web site http://www.alan-g.me.uk/ http://www.amazon.com/author/alan_gauld Follow my photo-blog on Flickr at: http://www.flickr.com/photos/alangauldphotos From bouncingcats at gmail.com Tue Feb 28 07:48:31 2023 From: bouncingcats at gmail.com (David) Date: Tue, 28 Feb 2023 23:48:31 +1100 Subject: [Tutor] What does yield do? In-Reply-To: References: Message-ID: On Tue, 28 Feb 2023 at 21:50, Albert Cornelius wrote: > Can someone please provide an ELI5 > (Explain Like I'm 5) explanation of what yield does? Hi, This is a frequently asked question, so there's no shortage of people doing their best to answer it. In addition to Alan's answer, here's some more examples you could look through. You might find one that clicks with you. You can ask here if you have any questions about any of them. https://www.reddit.com/r/learnpython/comments/3s8br4/can_someone_please_eli5_the_yield_function/ https://duckduckgo.com/?q=python+what+does+yield+do https://www.geeksforgeeks.org/python-yield-keyword/ https://www.simplilearn.com/tutorials/python-tutorial/yield-in-python https://stackoverflow.com/questions/231767/what-does-the-yield-keyword-do-in-python https://www.educba.com/python-yield/ https://realpython.com/introduction-to-python-generators/ https://geomario1984.medium.com/python-what-does-yield-returns-2cbb4d517a09 https://www.machinelearningplus.com/python/what-does-yield-keyword-do/ https://www.conorjohanlon.com/what-does-the-yield-keyword-do-in-python/ https://sparkbyexamples.com/python/what-does-yield-keyword-do-in-python/ https://www.python-engineer.com/posts/yield-in-python/ https://forpythons.com/what-does-the-yield-keyword-do/ https://thepythonyouneed.com/what-does-the-yield-word-do-in-python https://www.trendradars.com/article-2580467-what-does-the-yield-keyword-do-in-python https://medium.com/analytics-vidhya/what-does-the-yield-do-in-python-44dfaf978906 https://betterprogramming.pub/what-does-the-yield-keyword-do-6b9304149462 https://thelsdj.org/what-does-yield-do-in-python/ https://www.knowledgehut.com/blog/programming/yield-in-python https://www.geeksforgeeks.org/use-yield-keyword-instead-return-keyword-python/ http://net-informations.com/python/iq/yield.htm https://betterstack.com/community/questions/what-does-yield-keyword-do-python/ https://www.guru99.com/python-yield-return-generator.html https://www.i2tutorials.com/what-does-the-yield-keyword-do-in-python/ From dave at nk7z.net Tue Feb 28 13:26:58 2023 From: dave at nk7z.net (Dave (NK7Z)) Date: Tue, 28 Feb 2023 10:26:58 -0800 Subject: [Tutor] Where does the program pointer go when... Message-ID: <32cdf823-8ee7-6c33-37bb-f4452919ba1f@nk7z.net> Hello, First let me think you all for being here to answer questions from folks having difficulty. I am trying to get my head around what is a timeout, and what happens when one occurs. I have a working script that does what I want, but I am now working on trapping errors. i.e. Ethernet dies, telnet server shuts down, telnet server just stops sending data, telnet server starts sending b'', etc. As a result of this effort, I find I have a failed understanding of what happens when a TIMEOUT occurs. I am fairly sure I don't even know WHAT a TIMEOUT is... See assumptions list later. The snippit below is designed to read one line from a telnet stream that never ends, looking for a \n, as the end of a line, while looking to trap errors, and leave me a message as to what failed via logit(logdata). logit() just writes some data for me to read postmortem. relog() waits 10 minutes, then tries to relog into the telnet server. At this point I am NOT trying to relog into the server, I am testing to be sure my understanding of the fail modes is correct. exitscript() just kills the script, leaving the log file for me to look at, to decide what happened to kill things... Script above here initing all variables, etc... try: result = tn.read_until(b"\r\n", TIMEOUT) if result == b'': relogin() configureCluster() exitscript() except socket.error: # If socket error-- exit with error. logdata = 'Socket Error in watchstream(), at main read loop.' logit(logdata) exitscript() except EOFError: failcode = 6 logdata = 'EOF at main read loop.' logit(logdata) exitscript() except OSError: logdata = 'OS Error in watchstream().' logit(logdata) exitscript() Rest of script... I have at least two assumptions I want to check here: 1. TIMEOUT is defined as when when the telnet server just stops spending data, but the telnet connection still exists, and TIMEOUT is exceeded. i.e. the far side data collection died, but left the server connected to my client. Is this correct? 2. I assume the run pointer, (where the next instruction is run), just drops down to the "Rest of script..." and the run continues, if TIMEOUT is reached. Is this correct? I am trying to trap all errors, and recover cleanly from them while not hammering the far side telnet server with login attempts... Until I have this working, I have all errors kill my script, not trigger a relogin. That way nothing gets loose in a relog/fail loop. Any help would be appreciated, I am new to Python... I have looked all over and have not located anything that tells me what a TIMEOUT is exactly. Is it if the telnet server drops, is it if the data flow stops, but the telnet server is still connected, etc... Any help would be appropriated... -- 73, and thanks, Dave (NK7Z) https://www.nk7z.net ARRL Volunteer Examiner ARRL Technical Specialist, RFI ARRL Asst. Director, NW Division, Technical Resources From threesomequarks at proton.me Tue Feb 28 13:19:52 2023 From: threesomequarks at proton.me (ThreeBlindQuarks) Date: Tue, 28 Feb 2023 18:19:52 +0000 Subject: [Tutor] What does yield do? In-Reply-To: References: Message-ID: Albert, Don't yield to the temptation to just give up and never return! It is actually quite simple once you realize that a regular function is called and does things and a "return" statement optionally sends back a result. The details loosely are the function is placed on a stack and then goes away leaving the result on the stack and that is grabbed and goes away and you keep doing what comes next. Functions often are short-lived. What is new in generators of several kinds is that they simply do not go away. They stick around by NOT using return. Instead, when they have calculated the next thing to return, with more perhaps to come later, they "yield" the result and are suspended until needed again. All internal state such as variables remain alive and well. The function that called the generator gets back a result and may later, it or another function, ask for the next iteration and the generator wakes up and calculates to the next "yield" and that is sent back. Some generators never end and some do some kind of return when finally done or send back some signal. So yield is just a cousin of return. There is always more such as YIELD FROM. Just FYI, your example is not quite the best as it calls range() to generate all the values then returns just one at a time. But range itself is a generator now so it does not need to calculate all of them at once. Sent with Proton Mail secure email. ------- Original Message ------- On Tuesday, February 28th, 2023 at 4:18 AM, Albert Cornelius wrote: > I've seen some examples on yield like this: > > > > > def create_generator():... mylist = range(3)... for i in mylist:... yield i*i > > ...>>> mygenerator = create_generator() # create a generator>>> > > print(mygenerator) # mygenerator is an object! > >>> for i in > > mygenerator:... print(i)014 > > > and I've read some amout of text about it. But I still don't really > grasp the idea of yield. I'm coming from the Java world and am in my > 2nd semester, so please be kind. Can someone please provide an ELI5 > (Explain Like I'm 5) explanation of what yield does? > _______________________________________________ > Tutor maillist - Tutor at python.org > To unsubscribe or change subscription options: > https://mail.python.org/mailman/listinfo/tutor From alan.gauld at yahoo.co.uk Tue Feb 28 19:44:16 2023 From: alan.gauld at yahoo.co.uk (Alan Gauld) Date: Wed, 1 Mar 2023 00:44:16 +0000 Subject: [Tutor] Where does the program pointer go when... In-Reply-To: <32cdf823-8ee7-6c33-37bb-f4452919ba1f@nk7z.net> References: <32cdf823-8ee7-6c33-37bb-f4452919ba1f@nk7z.net> Message-ID: On 28/02/2023 18:26, Dave (NK7Z) wrote: > I am trying to get my head around what is a timeout, and what happens > when one occurs. I'll answer this in general terms because there is no single definition of how timeouts work or are used. Basically a timeout just means that an operation is time limited. It will start and if it does not complete within the specified time it either returns empty handed or raises an error or causes some specified handler function to execute. There are multiple ways to implement timeouts from software to hardare and from simple clock lookups to multi-threaded interrupts. So it is impossible to give a single answer to how they work. The simplest form is a simple loop and timecheck: In spseudo code: def timed_op(timeout): start = gettime() while True: time = gettime() if time < start+timeout: result = do_operation() if resultOK(result): return result else: raise TimeoutError So we start a timer and then enter an infinite loop. Every time round we see if the timer has exceeded the timeout period. If not we carry out the desired operation. If the operation succeeds (according to some arbitrary definition of success!) we return the result. Otherwise we go round the loop again. If the timeout is exceeded we rraise a timeout error and the caller must decide what to do next. But both OS and hardware usually have special mechanisms for interrupting a running process after a given time, so a process can invoke that feature too. This tends to be the case with servers and long running processes or tasks which use the network (or other fallible resources). In that case the OS will step in and stop the process and call an interrupt handler function (or signal). That function will probably just return an error code to the caller or similar. > As a result of this effort, I find I have a failed understanding of what > happens when a TIMEOUT occurs. I am fairly sure I don't even know WHAT > a TIMEOUT is... See assumptions list later. For a specific scenario you have to dig deeper into how the library in question expects you to proceed. It may be that you provide a default value, raise an error (or catch an error from the library!) or you may provide the library with an error handlr function that the library calls in the event of timeout. It all depends on the library. Good documentation/tutorials are invaluable here. > The snippit below is designed to read one line from a telnet stream that > never ends, looking for a \n, as the end of a line, while looking to > trap errors, and leave me a message as to what failed via > logit(logdata). > try: > result = tn.read_until(b"\r\n", TIMEOUT) > if result == b'': > relogin() > configureCluster() > exitscript() > except socket.error: # If socket error-- exit with error. > logdata = 'Socket Error in watchstream(), at main read loop.' > logit(logdata) > exitscript() > except EOFError: > failcode = 6 > logdata = 'EOF at main read loop.' > logit(logdata) > exitscript() > except OSError: > logdata = 'OS Error in watchstream().' > logit(logdata) > exitscript() > > Rest of script... > > I have at least two assumptions I want to check here: > > 1. TIMEOUT is defined as when when the telnet server just stops > spending data, but the telnet connection still exists, and TIMEOUT is > exceeded. i.e. the far side data collection died, but left the server > connected to my client. Is this correct? No idea. But the telnet module docs say: ========= Telnet.read_until(expected, timeout=None) Read until a given byte string, expected, is encountered or until timeout seconds have passed. When no match is found, return whatever is available instead, possibly empty bytes. Raise EOFError if the connection is closed and no cooked data is available. ========== So it looks like in this case the timeout causes the function to return as much data as it has collected so far, regardless of wherther it found your expected terminator. Note it also says telnetlib is deprecated and will be removed in 3.13. You should probably move to another library - maybe ssh based? > 2. I assume the run pointer, (where the next instruction is run), just > drops down to the "Rest of script..." and the run continues, if TIMEOUT > is reached. Is this correct? It depends on how the timeout is built. But in your specific case, yes. You get a return from the function as normal. The TIMEOUT is purely to prevent read_until() locking up and never returning. > I am trying to trap all errors, and recover cleanly from them while not > hammering the far side telnet server with login attempts... Good, but unrelated to timeouts! :-) > Any help would be appreciated, I am new to Python... I have looked all > over and have not located anything that tells me what a TIMEOUT is > exactly. Is it if the telnet server drops, is it if the data flow > stops, but the telnet server is still connected, etc... Any and all of the above. There is a brief wikipedia article on "timeout(computing)" that might help. It provides some real-world examples of differet types of timeout you might encounter. -- Alan G Author of the Learn to Program web site http://www.alan-g.me.uk/ http://www.amazon.com/author/alan_gauld Follow my photo-blog on Flickr at: http://www.flickr.com/photos/alangauldphotos From wlfraed at ix.netcom.com Tue Feb 28 23:38:38 2023 From: wlfraed at ix.netcom.com (Dennis Lee Bieber) Date: Tue, 28 Feb 2023 23:38:38 -0500 Subject: [Tutor] Where does the program pointer go when... References: <32cdf823-8ee7-6c33-37bb-f4452919ba1f@nk7z.net> Message-ID: On Tue, 28 Feb 2023 10:26:58 -0800, "Dave (NK7Z)" declaimed the following: >I am trying to get my head around what is a timeout, and what happens >when one occurs. I have a working script that does what I want, but I >am now working on trapping errors. i.e. Ethernet dies, telnet server >shuts down, telnet server just stops sending data, telnet server starts >sending b'', etc. > The library reference manual is a crucial resource. >As a result of this effort, I find I have a failed understanding of what >happens when a TIMEOUT occurs. I am fairly sure I don't even know WHAT >a TIMEOUT is... See assumptions list later. > """ Telnet.read_until(expected, timeout=None) Read until a given byte string, expected, is encountered or until timeout seconds have passed. When no match is found, return whatever is available instead, possibly empty bytes. Raise EOFError if the connection is closed and no cooked data is available. """ Note: "return whatever is available"... Often one buffers the partial data and retries the operation, combining partials until the complete data has been transferred or some more serious error occurs. > >Script above here initing all variables, etc... > > try: > result = tn.read_until(b"\r\n", TIMEOUT) ... which could mean you get stuff up to a but not the , or anything else that might have been sent. > if result == b'': > relogin() > configureCluster() > exitscript() Uhm... why "relogin" if you are just going to exit the program? > except socket.error: # If socket error-- exit with error. > logdata = 'Socket Error in watchstream(), at main read loop.' > logit(logdata) > exitscript() > except EOFError: > failcode = 6 > logdata = 'EOF at main read loop.' > logit(logdata) > exitscript() > except OSError: > logdata = 'OS Error in watchstream().' > logit(logdata) > exitscript() > >Rest of script... > >I have at least two assumptions I want to check here: > >1. TIMEOUT is defined as when when the telnet server just stops >spending data, but the telnet connection still exists, and TIMEOUT is >exceeded. i.e. the far side data collection died, but left the server >connected to my client. Is this correct? No... The far side just doesn't have data to send... Imagine that the far side is sending stuff being typed in by a user at a console (in non-buffered mode). The user walks away to get a cup of coffee, and your end times out with whatever the user last entered. Then they come back and, maybe, enter a few more characters and hit . > >2. I assume the run pointer, (where the next instruction is run), just >drops down to the "Rest of script..." and the run continues, if TIMEOUT >is reached. Is this correct? > On timeout, the next statement executed will be the "if result == b'':" > >Any help would be appreciated, I am new to Python... I have looked all This is not really Python specific -- you probably need to study the BSD TCP socket protocol, and maybe telnet protocol(s) https://www.rfc-editor.org/rfc/rfc854 https://www.rfc-editor.org/rfc/rfc5198 >over and have not located anything that tells me what a TIMEOUT is >exactly. Is it if the telnet server drops, is it if the data flow >stops, but the telnet server is still connected, etc... For .read_until(), a closed connection raises EOFError. It may not be immediately detected (at the socket layer, there may be a buffer containing multiple lines of text and your .read_until() needs to empty that buffer before an actual socket read is next attempted). -- Wulfraed Dennis Lee Bieber AF6VN wlfraed at ix.netcom.com http://wlfraed.microdiversity.freeddns.org/ From dave at nk7z.net Tue Feb 28 22:46:23 2023 From: dave at nk7z.net (Dave (NK7Z)) Date: Tue, 28 Feb 2023 19:46:23 -0800 Subject: [Tutor] Where does the program pointer go when... In-Reply-To: References: <32cdf823-8ee7-6c33-37bb-f4452919ba1f@nk7z.net> Message-ID: Hello Alan, Thank you for the very complete reply! I think I now have abetter understanding, and the comment about telnet being deprecated answers most if not all of my questions... I need to switch away from telnet, and move to something else... Can't use SSH, as the servers I am interacting with do not use SSH... Any suggestions on what lib I should move to in that case? I am doing this as a learning experience so this is not a truly large issue for me... I will have to learn more about another library... Again, thank you for your very nicely constructed help here!!! 73, and thanks, Dave (NK7Z) https://www.nk7z.net ARRL Volunteer Examiner ARRL Technical Specialist, RFI ARRL Asst. Director, NW Division, Technical Resources On 2/28/23 16:44, Alan Gauld via Tutor wrote: > On 28/02/2023 18:26, Dave (NK7Z) wrote: > >> I am trying to get my head around what is a timeout, and what happens >> when one occurs. > > I'll answer this in general terms because there is no single > definition of how timeouts work or are used. > > Basically a timeout just means that an operation is time limited. > It will start and if it does not complete within the specified > time it either returns empty handed or raises an error or > causes some specified handler function to execute. > > There are multiple ways to implement timeouts from software > to hardare and from simple clock lookups to multi-threaded > interrupts. So it is impossible to give a single answer to how they > work. The simplest form is a simple loop and timecheck: > > In spseudo code: > > def timed_op(timeout): > start = gettime() > while True: > time = gettime() > if time < start+timeout: > result = do_operation() > if resultOK(result): > return result > else: raise TimeoutError > > > So we start a timer and then enter an infinite loop. > Every time round we see if the timer has exceeded > the timeout period. If not we carry out the desired > operation. If the operation succeeds (according to > some arbitrary definition of success!) we return > the result. Otherwise we go round the loop again. > If the timeout is exceeded we rraise a timeout error > and the caller must decide what to do next. > > But both OS and hardware usually have special > mechanisms for interrupting a running process > after a given time, so a process can invoke > that feature too. This tends to be the case > with servers and long running processes or tasks > which use the network (or other fallible resources). > In that case the OS will step in and stop the process > and call an interrupt handler function (or signal). > That function will probably just return an error code > to the caller or similar. > > >> As a result of this effort, I find I have a failed understanding of what >> happens when a TIMEOUT occurs. I am fairly sure I don't even know WHAT >> a TIMEOUT is... See assumptions list later. > > For a specific scenario you have to dig deeper into > how the library in question expects you to proceed. > It may be that you provide a default value, raise an > error (or catch an error from the library!) or you > may provide the library with an error handlr function > that the library calls in the event of timeout. It > all depends on the library. Good documentation/tutorials > are invaluable here. > >> The snippit below is designed to read one line from a telnet stream that >> never ends, looking for a \n, as the end of a line, while looking to >> trap errors, and leave me a message as to what failed via >> logit(logdata). > > >> try: >> result = tn.read_until(b"\r\n", TIMEOUT) >> if result == b'': >> relogin() >> configureCluster() >> exitscript() >> except socket.error: # If socket error-- exit with error. >> logdata = 'Socket Error in watchstream(), at main read loop.' >> logit(logdata) >> exitscript() >> except EOFError: >> failcode = 6 >> logdata = 'EOF at main read loop.' >> logit(logdata) >> exitscript() >> except OSError: >> logdata = 'OS Error in watchstream().' >> logit(logdata) >> exitscript() >> >> Rest of script... >> >> I have at least two assumptions I want to check here: >> >> 1. TIMEOUT is defined as when when the telnet server just stops >> spending data, but the telnet connection still exists, and TIMEOUT is >> exceeded. i.e. the far side data collection died, but left the server >> connected to my client. Is this correct? > > No idea. But the telnet module docs say: > ========= > Telnet.read_until(expected, timeout=None) > Read until a given byte string, expected, is encountered or until > timeout seconds have passed. > > When no match is found, return whatever is available instead, possibly > empty bytes. Raise EOFError if the connection is closed and no cooked > data is available. > ========== > > So it looks like in this case the timeout causes the function to return > as much data as it has collected so far, regardless of wherther it found > your expected terminator. > > Note it also says telnetlib is deprecated and will be removed in 3.13. > You should probably move to another library - maybe ssh based? > >> 2. I assume the run pointer, (where the next instruction is run), just >> drops down to the "Rest of script..." and the run continues, if TIMEOUT >> is reached. Is this correct? > > It depends on how the timeout is built. > But in your specific case, yes. You get a return > from the function as normal. The TIMEOUT is purely to prevent > read_until() locking up and never returning. > >> I am trying to trap all errors, and recover cleanly from them while not >> hammering the far side telnet server with login attempts... > > Good, but unrelated to timeouts! :-) > >> Any help would be appreciated, I am new to Python... I have looked all >> over and have not located anything that tells me what a TIMEOUT is >> exactly. Is it if the telnet server drops, is it if the data flow >> stops, but the telnet server is still connected, etc... > > Any and all of the above. > > There is a brief wikipedia article on "timeout(computing)" that might > help. It provides some real-world examples of differet types of > timeout you might encounter. >