From jonathan at torres-herrera.com Mon May 2 18:35:04 2022 From: jonathan at torres-herrera.com (Jonathan Torres-Herrera) Date: Mon, 2 May 2022 16:35:04 -0600 Subject: [Tutor] Help with Excel Workbook and URLs, in Python Charm Message-ID: Hi Tutors, Here's my dilemma. I have a couple of excel workbooks, let's call them workbook-A and workbook-B. Workbook-A holds a unique identifier, which happens to be a list of email addresses. On workbook-B, I have a list of URLs, each URL opens a unique online excel workbook with information that includes emails as well. Here is what I'm asking for help with. What would be the best approach to have python take each email address on workbook-A, and look it up against the list of URLs in workbook-B, and then return which URL it found it on in workbook-A (on a blank column)? From alan.gauld at yahoo.co.uk Tue May 3 04:36:41 2022 From: alan.gauld at yahoo.co.uk (Alan Gauld) Date: Tue, 3 May 2022 09:36:41 +0100 Subject: [Tutor] Help with Excel Workbook and URLs, in Python Charm In-Reply-To: References: Message-ID: On 02/05/2022 23:35, Jonathan Torres-Herrera wrote: > Workbook-A holds a unique identifier, which happens to be a list of email > addresses. > > On workbook-B, I have a list of URLs, each URL opens a unique online excel > workbook with information that includes emails as well. > > Here is what I'm asking for help with. > > What would be the best approach to have python take each email address on > workbook-A, and look it up against the list of URLs in workbook-B, and then > return which URL it found it on in workbook-A (on a blank column)? Since network access wull be slow you shoulsd aim to minimise that, so I'd traverse the list of URLs and build up a local cacche of the email addresses. Perjhaps a dictionary keyed by email address? You can then loop over the other spreadsheet and add the corresponding URL. It's not clear from your description if a single email address can occur on more than one URL or vice versa. Nor whether thre is a one to one correspondence - could there be addresses with no corresponding email or emails with no corresponding URL? You will need to decide what to do in those cases. As for reading Excel, there are a couple of third party libraries that make that easier. Google "excel python reader module" -- 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 Mon May 9 08:01:59 2022 From: leamhall at gmail.com (Leam Hall) Date: Mon, 9 May 2022 07:01:59 -0500 Subject: [Tutor] Feedback on coding style Message-ID: Hey all, I'm looking for general Python code critique, feel free to share snarky comments. :) The parameters are: 1. Code to Python 3.6 or so. 2. Use only the standard library or locally created modules. 3. Keep it clean and simple so new Pythonistas can understand and contribute. Let me know how to make this better. Leam -- Automation Engineer (reuel.net/resume) Scribe: The Domici War (domiciwar.net) General Ne'er-do-well (github.com/LeamHall) ### #!/usr/bin/env python3 # name: bp_tracker.py # version: 0.0.1 # date: 20220509 # author: Leam Hall # desc: Track and report on blood pressure numbers. # Notes: # Datafile expects three ints and one float, in order. # TODO # Add statistical analysis for standard deviation. # Report based on time of day (early, midmorning, afternoon, evening) # (?) Add current distance from goal? import argparse from datetime import datetime import os.path def array_from_file(report_file): data = [] with open(report_file, 'r') as file: for line in file: line.strip() datum = line.split() if len(datum) == 4: data.append(datum) else: continue return data def report(report_data): highest_systolic = 0 highest_diastolic = 0 highest_pulse = 0 latest = -1.0 for datum in report_data: systolic = int(datum[0]) diastolic = int(datum[1]) pulse = int(datum[2]) date = float(datum[3]) if systolic > highest_systolic: highest_systolic = systolic highest_systolic_event = datum if diastolic > highest_diastolic: highest_diastolic = diastolic highest_diastolic_event = datum if pulse > highest_pulse: highest_pulse = pulse highest_pulse_event = datum if date > latest: latest_record = datum print("Highest Systolic: {}/{} {} {}".format(*highest_systolic_event)) print("Highest Diastolic: {}/{} {} {}".format(*highest_diastolic_event)) print("Highest Pulse: {}/{} {} {}".format(*highest_pulse_event)) print("Latest Record: {}/{} {} {}".format(*latest_record)) def result_string(report_list): return "{} {} {} {}".format(*report_list) report_file = "bp_numbers.txt" parser = argparse.ArgumentParser() parser.add_argument("-a", "--add", nargs=3, help = "Add in the order of systolic, diastolic, pulse") parser.add_argument("-f", "--file", help = "Report file") args = parser.parse_args() if args.file: report_file = args.file if args.add: # This format allows sequencing now and parsing later. timestamp = datetime.now().strftime("%Y%m%d.%H%M") this_report = args.add this_report.append(timestamp) with open(report_file, 'a') as file: file.write(result_string(this_report) + "\n") else: # Default behavior is to report. if os.path.exists(report_file): try: report_data = array_from_file(report_file) report(report_data) except: print("Error processing report data") else: print("Cannot find ", report_file) ### From wlfraed at ix.netcom.com Mon May 9 11:24:24 2022 From: wlfraed at ix.netcom.com (Dennis Lee Bieber) Date: Mon, 09 May 2022 11:24:24 -0400 Subject: [Tutor] Feedback on coding style References: Message-ID: On Mon, 9 May 2022 07:01:59 -0500, Leam Hall declaimed the following: >Hey all, > >I'm looking for general Python code critique, feel free to share snarky comments. :) The parameters are: > 1. Code to Python 3.6 or so. First thing... Ditch 3.6. End-of-Life for 3.6 was back in December. 3.7 still has a year before it goes out of support. Second -- make it easy on us and don't put your code AFTER your signature block. Decent news and email clients are designed to NOT QUOTE stuff after the "-- " signature marker. I had to manually cut&paste... > >#!/usr/bin/env python3 > ># name: bp_tracker.py ># version: 0.0.1 ># date: 20220509 ># author: Leam Hall ># desc: Track and report on blood pressure numbers. > ># Notes: ># Datafile expects three ints and one float, in order. > ># TODO ># Add statistical analysis for standard deviation. ># Report based on time of day (early, midmorning, afternoon, evening) ># (?) Add current distance from goal? I believe common practice is to use a "doc string" for this type of information. (Unless you have some system in place that parses and updates comments of specific forms). #!whatever """ name: bp_tracker.py version: 0.0.1 date: 20220509 etc. """ >def array_from_file(report_file): From my viewpoint, "report_file" is misleading -- it does not appear to be a "report" but rather an accumulating datastore/database or "record of readings". Same for the use of "report_data" -- again it does not seem to be a "report" (to me, a report is a formatted output document meant for human reading, and is not used for updates or input). Also, I'd suggest using the standard CSV module (you could set up a dialect using tab-separation if comma-separation seems "ugly"). This would simplify some of the parsing code you are doing. cf: https://docs.python.org/3.7/library/csv.html (normally Google reports the most recent version, I decided to change the drop-down to the oldest still supported version). In truth though -- presuming "report_file" truly is the data store, and is only manipulated using this program (ie: no using a text editor to make changes) -- I'd bypass the CSV module and go directly to the standard library sqlite3 module. That removes the need to read/parse the "report_file" into an array on start-up, and writing it back out on exit should your "add" command option be invoked. You'd want to add a command line option to initialize a database file (create table definition). SQLite3 is rather flexible in data input -- define the columns as numeric and so long as the string representation of the data is "numeric" it will be taken and used as such. All the stuff for min/max should be possible using some set of SQL SELECT statement (the min/max is no problem, but it may take a two-step select to get the whole record with date: off the cuff... select * from bp where systolic = (select max(systolic) from bp); NOTE: this could return multiple matches if there are ties for max(systolic) ) Adding a new entry becomes a simple INSERT statement. Criteria #2 is met fully -- all standard library modules Criteria #1 -- well, as advised version 3.6 should be considered dead, 3.7 is the minimum "live" version (I'll probably be on 3.8 until it dies in two years). Criteria #3? SQLite3 may be pushing it as it requires learning the basics of SQL access to relational databases -- but for your example program it looks like only one relation is required (I use relation/tuple in the meaning applied by relational theory -- all data in a tuple is related to the primary key. NOT the common understanding of SQL JOINs and foreign keys). So, with one relation, they don't have to learn database normalization, primary/foreign keys, etc. immediately. Such can be postponed until a situation arises using multiple interlinked relations. OTOH: SQLite3 obviates the need for logic to load/parse the entire dataset on entry, and format/save the dataset on exit, reducing the chances for dataloss (if the computer crashes in the middle of overwriting the dataset file) or having to code something like "save to temporary file, rename original to backup, rename temporary as original, delete backup" along with start-up logic to test for the presence of a backup or the temporary file during start-up (both indicate something died and recovery efforts need to be performed). Using CSV module (which will format/parse the fields) still leaves one with having to convert text data on input to suitable numeric types (as mentioned SQLite3 is forgiving -- if the data looks like a number and the field is numeric, interpret it as a number; otherwise store it as-is) along with slowly building up lists ("array" is a module in the standard library, and has different behavior from Python lists). -- Wulfraed Dennis Lee Bieber AF6VN wlfraed at ix.netcom.com http://wlfraed.microdiversity.freeddns.org/ From wlfraed at ix.netcom.com Mon May 9 14:52:06 2022 From: wlfraed at ix.netcom.com (Dennis Lee Bieber) Date: Mon, 09 May 2022 14:52:06 -0400 Subject: [Tutor] Feedback on coding style References: Message-ID: o/~ Talking to myself in public o/~ On Mon, 09 May 2022 11:24:24 -0400, Dennis Lee Bieber declaimed the following: For some reason I felt challenged, and spent three hours to produce this variation... WARNING: news client may be adding undesirable line wrapping -- and should be viewed with fixed width font! NOTE: I should have created a helper function to do the formatting rather than repeating all those print blocks. I'm actually surprised the DML_MAX_* statements worked first time. Whereas I must have spent over half an hour tweaking the report format. -=-=- #!/usr/bin/env python3 """ name: bp_tracker.py version: 0.0.1-a date: 20220509 author: Leam Hall desc: Track and report on blood pressure numbers revisions: 20220509 Dennis Lee Bieber rewritten as an exercise to use SQLite3 for the data store TODO: ADD TRY/EXCEPT BLOCKS TO HANDLE ERRORS IN DATABASE OPERATIONS TODO: add SQLite3 aggregate function for std. deviations TODO: Add report options for time-of-day (early, mid-morning, afternoon, evening) TODO: Add current distance from goal (requires input of target) """ import argparse import datetime import os.path as op import sqlite3 as db #TIMESTAMP is the name used by the Python API for #conversion as SQLite3 does not have a native #date/datetime data type #I always create an integer primary key, even if not #needed by the application DDL = """CREATE TABLE IF NOT EXISTS reading ( ID INTEGER PRIMARY KEY, reading_date TIMESTAMP NOT NULL, systolic INTEGER NOT NULL, diastolic INTEGER NOT NULL, pulse INTEGER NOT NULL ) """ DML_ADD = """INSERT INTO reading (reading_date, systolic, diastolic, pulse) VALUES (?, ?, ?, ?) """ DML_MAX_SYSTOLIC = """ SELECT r.ID, r.reading_date, r.systolic, r.diastolic, r.pulse FROM reading AS r INNER JOIN (SELECT max(m.systolic) AS mx FROM reading AS m) ON r.systolic = mx ORDER BY r.reading_date """ DML_MAX_DIASTOLIC = """ SELECT r.ID, r.reading_date, r.systolic, r.diastolic, r.pulse FROM reading AS r INNER JOIN (SELECT max(m.diastolic) AS mx FROM reading AS m) ON r.diastolic = mx ORDER BY r.reading_date """ DML_MAX_PULSE = """ SELECT r.ID, r.reading_date, r.systolic, r.diastolic, r.pulse FROM reading AS r INNER JOIN (SELECT max(m.pulse) AS mx FROM reading AS m) ON r.pulse = mx ORDER BY r.reading_date """ DML_MAX_DATE = """ SELECT r.ID, r.reading_date, r.systolic, r.diastolic, r.pulse FROM reading AS r INNER JOIN (SELECT max(m.reading_date) AS mx FROM reading AS m) ON r.reading_date = mx """ DML_SUMMARY = """ SELECT count(*) AS Count, max(systolic) AS Max_Systolic, min(systolic) AS Min_Systolic, avg(systolic) AS Avg_Systolic, max(diastolic) AS Max_Diastolic, min(diastolic) AS min_Diastolic, avg(diastolic) AS Avg_Diastolic, max(pulse) AS Max_Pulse, min(pulse) AS Min_Pulse, avg(pulse) AS Avg_Pulse FROM reading """ DEFAULT_DATABASE = "bp_numbers.sqlite" def open_database(db_name): """ Opens the specified database file.write Creates table schema (use of IF NOT EXISTS should mean this is safe for pre-existing database, yet will initialize a new database. CAVEAT: it also means if some random database file is provided a new table will be created within that database!) """ #specify that datatypes should be parsed -- used to #associate datetime converters con = db.connect(db_name, detect_types=db.PARSE_DECLTYPES) cur = con.cursor() cur.execute(DDL) con.commit() cur.close() return con def add_reading(connection, datestamp, systolic, diastolic, pulse): """ Using the provided database connection, adds a new record with provided datestamp, systolic, diastolic, pulse """ cur = connection.cursor() cur.execute(DML_ADD, (datestamp, systolic, diastolic, pulse)) connection.commit() cur.close() def generate_report(connection): """ Produce a summary report showing the record(s) with maximum systolic, diastolic, pulse, datestamp. Also list overall maximum and minimum, means (SQLite3 does not have a built-in standard deviation function; one can be defined in Python and registered to the SQLite3 API so it can be called in SQL statements -- this is left for the future) """ cur = connection.cursor() #obtain summary max/min values cur.execute(DML_SUMMARY) summary = cur.fetchone() #there is only one record #should use a dictionary cursor for this, so later formatting #can reference by column name, rather than having to know #index #collect the full records for each maximum category cur.execute(DML_MAX_SYSTOLIC) systolic = cur.fetchall() cur.execute(DML_MAX_DIASTOLIC) diastolic = cur.fetchall() cur.execute(DML_MAX_PULSE) pulse = cur.fetchall() cur.execute(DML_MAX_DATE) date = cur.fetchall()[0] print("\n\n\n%s\n" % "*************************************") print("\tSummary for %s readings\n" % summary[0]) print(" %-9s %-9s %-9s" % ("Systolic", "Diastolic", " Pulse")) print(" %-9s %-9s %-9s" % ("=========", "=========", "=========")) print("%-9s %9s %9s %9s" % ("MAX", summary[1], summary[4], summary[7])) print("%-9s %9s %9s %9s" % ("MIN", summary[2], summary[5], summary[8])) print("%-9s %9.9s %9.9s %9.9s" % ("AVERAGE", summary[3], summary[6], summary[9])) print("\n\t******\n") print("\tMaximum %s event(s)" % "SYSTOLIC") print("%-9s %-30s %-9s %-9s %-9s" % (" ID", " Datestamp", "Systolic", "Diastolic", " Pulse")) print("%-9s %-30s %-9s %-9s %-9s" % ("=========", "=============================", "=========", "=========", "=========")) for record in systolic: print("%9s %-30s %9s %9s %9s" % (record[0], record[1], record[2], record[3], record[4])) print() print("\tMaximum %s event(s)" % "DIASTOLIC") print("%-9s %-30s %-9s %-9s %-9s" % (" ID", " Datestamp", "Systolic", "Diastolic", " Pulse")) print("%-9s %-30s %-9s %-9s %-9s" % ("=========", "=============================", "=========", "=========", "=========")) for record in diastolic: print("%9s %-30s %9s %9s %9s" % (record[0], record[1], record[2], record[3], record[4])) print() print("\tMaximum %s event(s)" % "PULSE") print("%-9s %-30s %-9s %-9s %-9s" % (" ID", " Datestamp", "Systolic", "Diastolic", " Pulse")) print("%-9s %-30s %-9s %-9s %-9s" % ("=========", "=============================", "=========", "=========", "=========")) for record in pulse: print("%9s %-30s %9s %9s %9s" % (record[0], record[1], record[2], record[3], record[4])) print() print("\tMaximum %s event" % "DATESTAMP") print("%-9s %-30s %-9s %-9s %-9s" % (" ID", " Datestamp", "Systolic", "Diastolic", " Pulse")) print("%-9s %-30s %-9s %-9s %-9s" % ("=========", "=============================", "=========", "=========", "=========")) if date: print("%9s %-30s %9s %9s %9s" % (date[0], date[1], date[2], date[3], date[4])) print("\n\n\n%s\n" % "*************************************") if __name__ == "__main__": #create argument/command line parser parser = argparse.ArgumentParser() parser.add_argument("-a", "--add", nargs=3, help = "Add in the order of systolic, diastolic, pulse. " "Date/Time is assumed") parser.add_argument("-f", "--file", help = "Database file", default = DEFAULT_DATABASE) args = parser.parse_args() if args.file: database = args.file #open/initialize database con = open_database(database) if args.add: #generate timestamp datestamp = datetime.datetime.now() add_reading(connection=con, datestamp=datestamp, systolic=args.add[0], diastolic=args.add[1], pulse=args.add[2]) #produce summary report regardless of any other actions generate_report(connection=con) #close database con.close() -=-=- Designed as an IMPORTable module so other programs could import it, call the database open, add entry, and report generation functions (though the latter should be configured to take an output destination so the report could be sent to a file, not just blatted out on the console). -=-=- C:\Users\Wulfraed\Documents\_Hg-Repositories\Python Progs\LH_BP_tracker>bp_tracker.py -a 123 98 69 ************************************* Summary for 5 readings Systolic Diastolic Pulse ========= ========= ========= MAX 136 98 70 MIN 115 65 65 AVERAGE 126.8 86.4 68.4 ****** Maximum SYSTOLIC event(s) ID Datestamp Systolic Diastolic Pulse ========= ============================= ========= ========= ========= 1 2022-05-09 14:14:37.494260 136 92 70 2 2022-05-09 14:20:40.620195 136 88 68 Maximum DIASTOLIC event(s) ID Datestamp Systolic Diastolic Pulse ========= ============================= ========= ========= ========= 5 2022-05-09 14:34:50.873347 123 98 69 Maximum PULSE event(s) ID Datestamp Systolic Diastolic Pulse ========= ============================= ========= ========= ========= 1 2022-05-09 14:14:37.494260 136 92 70 3 2022-05-09 14:21:19.428237 124 89 70 Maximum DATESTAMP event ID Datestamp Systolic Diastolic Pulse ========= ============================= ========= ========= ========= 5 2022-05-09 14:34:50.873347 123 98 69 ************************************* -=-=- C:\Users\Wulfraed\Documents\_Hg-Repositories\Python Progs\LH_BP_tracker>sqlite3 bp_numbers.sqlite SQLite version 3.37.2 2022-01-06 13:25:41 Enter ".help" for usage hints. sqlite> .mode box sqlite> select * from reading; +----------------------------------------------------------------+ ? ID ? reading_date ? systolic ? diastolic ? pulse ? +----+----------------------------+----------+-----------+-------? ? 1 ? 2022-05-09 14:14:37.494260 ? 136 ? 92 ? 70 ? ? 2 ? 2022-05-09 14:20:40.620195 ? 136 ? 88 ? 68 ? ? 3 ? 2022-05-09 14:21:19.428237 ? 124 ? 89 ? 70 ? ? 4 ? 2022-05-09 14:32:31.471217 ? 115 ? 65 ? 65 ? ? 5 ? 2022-05-09 14:34:50.873347 ? 123 ? 98 ? 69 ? +----------------------------------------------------------------+ sqlite> -=-=- -- Wulfraed Dennis Lee Bieber AF6VN wlfraed at ix.netcom.com http://wlfraed.microdiversity.freeddns.org/ From alexkleider at gmail.com Mon May 9 15:51:27 2022 From: alexkleider at gmail.com (Alex Kleider) Date: Mon, 9 May 2022 12:51:27 -0700 Subject: [Tutor] Feedback on coding style In-Reply-To: References: Message-ID: Would you consider putting this code (or Dennis' version of it) on github? I've played around with some python code to keep track of blood pressure but haven't used it for a long time. (https://github.com/alexKleider/blood-pressure-record) My "data base" is a simple text file. When an entry is ready to be made I have an alias command defined within .bashrc as follows: export BPS=$HOME/Git/BP/bps.txt alias bpdate="date +'%a %b %d %H:%M %Y' >> $BPS && vim $BPS" So all that is necessary is to issue the $ bpdate command. One then finds oneself in vim poised to make a BP reading entry. That solves data entry without any python; Then one can use python for analysis. I've never used sqlite but would be interested in continuing to follow this thread as well as learning how to use it and how to collaborate using git. On Mon, May 9, 2022 at 5:03 AM Leam Hall wrote: > > Hey all, > > I'm looking for general Python code critique, feel free to share snarky comments. :) The parameters are: > 1. Code to Python 3.6 or so. > 2. Use only the standard library or locally created modules. > 3. Keep it clean and simple so new Pythonistas can understand and contribute. > > Let me know how to make this better. > > Leam > -- > Automation Engineer (reuel.net/resume) > Scribe: The Domici War (domiciwar.net) > General Ne'er-do-well (github.com/LeamHall) > > ### > > #!/usr/bin/env python3 > > # name: bp_tracker.py > # version: 0.0.1 > # date: 20220509 > # author: Leam Hall > # desc: Track and report on blood pressure numbers. > > # Notes: > # Datafile expects three ints and one float, in order. > > # TODO > # Add statistical analysis for standard deviation. > # Report based on time of day (early, midmorning, afternoon, evening) > # (?) Add current distance from goal? > > import argparse > from datetime import datetime > import os.path > > def array_from_file(report_file): > data = [] > with open(report_file, 'r') as file: > for line in file: > line.strip() > datum = line.split() > if len(datum) == 4: > data.append(datum) > else: > continue > return data > > def report(report_data): > highest_systolic = 0 > highest_diastolic = 0 > highest_pulse = 0 > latest = -1.0 > for datum in report_data: > systolic = int(datum[0]) > diastolic = int(datum[1]) > pulse = int(datum[2]) > date = float(datum[3]) > if systolic > highest_systolic: > highest_systolic = systolic > highest_systolic_event = datum > if diastolic > highest_diastolic: > highest_diastolic = diastolic > highest_diastolic_event = datum > if pulse > highest_pulse: > highest_pulse = pulse > highest_pulse_event = datum > if date > latest: > latest_record = datum > > print("Highest Systolic: {}/{} {} {}".format(*highest_systolic_event)) > print("Highest Diastolic: {}/{} {} {}".format(*highest_diastolic_event)) > print("Highest Pulse: {}/{} {} {}".format(*highest_pulse_event)) > print("Latest Record: {}/{} {} {}".format(*latest_record)) > > def result_string(report_list): > return "{} {} {} {}".format(*report_list) > > report_file = "bp_numbers.txt" > > parser = argparse.ArgumentParser() > parser.add_argument("-a", "--add", nargs=3, > help = "Add in the order of systolic, diastolic, pulse") > parser.add_argument("-f", "--file", help = "Report file") > args = parser.parse_args() > > if args.file: > report_file = args.file > > if args.add: > # This format allows sequencing now and parsing later. > timestamp = datetime.now().strftime("%Y%m%d.%H%M") > this_report = args.add > this_report.append(timestamp) > with open(report_file, 'a') as file: > file.write(result_string(this_report) + "\n") > else: > # Default behavior is to report. > if os.path.exists(report_file): > try: > report_data = array_from_file(report_file) > report(report_data) > except: > print("Error processing report data") > else: > print("Cannot find ", report_file) > > ### > _______________________________________________ > Tutor maillist - Tutor at python.org > To unsubscribe or change subscription options: > https://mail.python.org/mailman/listinfo/tutor -- alex at kleider.ca (sent from my current gizmo) From leamhall at gmail.com Mon May 9 16:11:16 2022 From: leamhall at gmail.com (Leam Hall) Date: Mon, 9 May 2022 15:11:16 -0500 Subject: [Tutor] Feedback on coding style In-Reply-To: References: Message-ID: Alex, Because the code was getting a bit long, I asked Alan if it should be in the body of the message or if I should just give the GitHub URL. https://github.com/LeamHall/admin_tools/blob/master/bp_tracker.py For simple stuff like this, plain text is best. I love SQLite but using it here adds complexity and code that isn't really needed. The use case here is simple; "How bad has it been?" and "Am I making progress?" The former pushes me to maintain health changes and the latter reminds me that I still have a ways to go. The later statistical stuff is just to push me to play with statistics; I'm not at the point of needing a math library. If you want a short demo of SQLite code: https://github.com/makhidkarun/Names/blob/master/getName.py If you're interested in trying out stuff, either python or collaboration, let me know. I'm not the best or the brightest, but I enjoy helping people. Lots of people have helped me. Leam On 5/9/22 14:51, Alex Kleider wrote: > Would you consider putting this code (or Dennis' version of it) on github? > I've played around with some python code to keep track of blood > pressure but haven't used it for a long time. > (https://github.com/alexKleider/blood-pressure-record) > My "data base" is a simple text file. > When an entry is ready to be made I have an alias command defined within .bashrc > as follows: > export BPS=$HOME/Git/BP/bps.txt > alias bpdate="date +'%a %b %d %H:%M %Y' >> $BPS && vim $BPS" > So all that is necessary is to issue the > $ bpdate > command. One then finds oneself in vim poised to make a BP reading entry. > That solves data entry without any python; > Then one can use python for analysis. > > I've never used sqlite but would be interested in continuing to follow > this thread as well as learning how to use it and how to collaborate > using git. > > > On Mon, May 9, 2022 at 5:03 AM Leam Hall wrote: >> >> Hey all, >> >> I'm looking for general Python code critique, feel free to share snarky comments. :) The parameters are: >> 1. Code to Python 3.6 or so. >> 2. Use only the standard library or locally created modules. >> 3. Keep it clean and simple so new Pythonistas can understand and contribute. >> >> Let me know how to make this better. >> >> Leam >> -- >> Automation Engineer (reuel.net/resume) >> Scribe: The Domici War (domiciwar.net) >> General Ne'er-do-well (github.com/LeamHall) >> >> ### >> >> #!/usr/bin/env python3 >> >> # name: bp_tracker.py >> # version: 0.0.1 >> # date: 20220509 >> # author: Leam Hall >> # desc: Track and report on blood pressure numbers. >> >> # Notes: >> # Datafile expects three ints and one float, in order. >> >> # TODO >> # Add statistical analysis for standard deviation. >> # Report based on time of day (early, midmorning, afternoon, evening) >> # (?) Add current distance from goal? >> >> import argparse >> from datetime import datetime >> import os.path >> >> def array_from_file(report_file): >> data = [] >> with open(report_file, 'r') as file: >> for line in file: >> line.strip() >> datum = line.split() >> if len(datum) == 4: >> data.append(datum) >> else: >> continue >> return data >> >> def report(report_data): >> highest_systolic = 0 >> highest_diastolic = 0 >> highest_pulse = 0 >> latest = -1.0 >> for datum in report_data: >> systolic = int(datum[0]) >> diastolic = int(datum[1]) >> pulse = int(datum[2]) >> date = float(datum[3]) >> if systolic > highest_systolic: >> highest_systolic = systolic >> highest_systolic_event = datum >> if diastolic > highest_diastolic: >> highest_diastolic = diastolic >> highest_diastolic_event = datum >> if pulse > highest_pulse: >> highest_pulse = pulse >> highest_pulse_event = datum >> if date > latest: >> latest_record = datum >> >> print("Highest Systolic: {}/{} {} {}".format(*highest_systolic_event)) >> print("Highest Diastolic: {}/{} {} {}".format(*highest_diastolic_event)) >> print("Highest Pulse: {}/{} {} {}".format(*highest_pulse_event)) >> print("Latest Record: {}/{} {} {}".format(*latest_record)) >> >> def result_string(report_list): >> return "{} {} {} {}".format(*report_list) >> >> report_file = "bp_numbers.txt" >> >> parser = argparse.ArgumentParser() >> parser.add_argument("-a", "--add", nargs=3, >> help = "Add in the order of systolic, diastolic, pulse") >> parser.add_argument("-f", "--file", help = "Report file") >> args = parser.parse_args() >> >> if args.file: >> report_file = args.file >> >> if args.add: >> # This format allows sequencing now and parsing later. >> timestamp = datetime.now().strftime("%Y%m%d.%H%M") >> this_report = args.add >> this_report.append(timestamp) >> with open(report_file, 'a') as file: >> file.write(result_string(this_report) + "\n") >> else: >> # Default behavior is to report. >> if os.path.exists(report_file): >> try: >> report_data = array_from_file(report_file) >> report(report_data) >> except: >> print("Error processing report data") >> else: >> print("Cannot find ", report_file) >> >> ### >> _______________________________________________ >> Tutor maillist - Tutor at python.org >> To unsubscribe or change subscription options: >> https://mail.python.org/mailman/listinfo/tutor > > > > -- > alex at kleider.ca (sent from my current gizmo) -- Automation Engineer (reuel.net/resume) Scribe: The Domici War (domiciwar.net) General Ne'er-do-well (github.com/LeamHall) From wlfraed at ix.netcom.com Mon May 9 17:51:00 2022 From: wlfraed at ix.netcom.com (Dennis Lee Bieber) Date: Mon, 09 May 2022 17:51:00 -0400 Subject: [Tutor] Feedback on coding style References: Message-ID: <2n0j7hd3uvkd0m33cavosd5nics0091gm7@4ax.com> On Mon, 9 May 2022 12:51:27 -0700, Alex Kleider declaimed the following: >Would you consider putting this code (or Dennis' version of it) on github? I don't "do" git/github. I do have Mercurial installed locally just to allow me to track history of my fiddling around. As long as attribution is maintained I have no concerns of what others may do with stuff I post on this forum (how better to experiment than to start with something functional and modify it?). I'd probably recommend that the first thing to change would be to create that helper function so that -=-=- print("\tMaximum %s event(s)" % "SYSTOLIC") print("%-9s %-30s %-9s %-9s %-9s" % (" ID", " Datestamp", "Systolic", "Diastolic", " Pulse")) print("%-9s %-30s %-9s %-9s %-9s" % ("=========", "=============================", "=========", "=========", "=========")) for record in systolic: print("%9s %-30s %9s %9s %9s" % (record[0], record[1], record[2], record[3], record[4])) print() -=-=- becomes a simple generate_section("SYSTOLIC", systolic) (and repeat for diastolic, pulse, date [latest event]). Second change would then be to pass the output destination, changing all the print() calls into dest.write() calls (with applicable addition of \n to the formats). {Heh -- I just did create the helper in my version} > >I've never used sqlite but would be interested in continuing to follow >this thread as well as learning how to use it and how to collaborate >using git. > Things to read: the Python DB-API PEP (for the general goals of the API and some of the variations you may encounter if using other RDBMs), the Python sqlite3 module documentation (for the features specific to SQLite3), and the SQLite3 documentation itself https://www.sqlite.org/docs.html for the underlying engine. In particular you will want to read about SQLite3's data model https://www.sqlite.org/datatype3.html (there are only TEXT, INTEGER, REAL, and BLOB data types -- the DDL parser accepts most any RDBM data declaration and maps them to the closest (char, varchar => TEXT, int, integer, => INTEGER, float, double => REAL). BUT it also does not throw an error if one provides something "invalid" -- it will freely accept "one" in an integer field, though obviously one can't do things like avg() a column with such a value. And, of course, for anything significant, you'll want to study some guide to database normalization (at least to 3rd Normal Form) along with a good description of general SQL statements (unique/duplicate allowed indices, foreign keys, constraints). SQLite3 is a "file server" engine -- every application links to the engine and hence is accessing database files using the privileges of the logged in user (vs "client/server" where the clients send commands to a separately running server process, and only the server accesses database files). -- Wulfraed Dennis Lee Bieber AF6VN wlfraed at ix.netcom.com http://wlfraed.microdiversity.freeddns.org/ From alan.gauld at yahoo.co.uk Mon May 9 19:18:05 2022 From: alan.gauld at yahoo.co.uk (Alan Gauld) Date: Tue, 10 May 2022 00:18:05 +0100 Subject: [Tutor] Feedback on coding style In-Reply-To: References: Message-ID: On 09/05/2022 13:01, Leam Hall wrote: > import argparse > from datetime import datetime > import os.path > > def array_from_file(report_file): > data = [] > with open(report_file, 'r') as file: > for line in file: > line.strip() > datum = line.split() > if len(datum) == 4: > data.append(datum) > else: > continue else: continue is not needed. The loop will restart without it. > def report(report_data): > highest_systolic = 0 > highest_diastolic = 0 > highest_pulse = 0 > latest = -1.0 > for datum in report_data: > systolic = int(datum[0]) > diastolic = int(datum[1]) > pulse = int(datum[2]) > date = float(datum[3]) > if systolic > highest_systolic: > highest_systolic = systolic > highest_systolic_event = datum > if diastolic > highest_diastolic: > highest_diastolic = diastolic > highest_diastolic_event = datum > if pulse > highest_pulse: > highest_pulse = pulse > highest_pulse_event = datum > if date > latest: > latest_record = datum OK down to here, but you should return the calculated values as a tuple > > print("Highest Systolic: {}/{} {} {}".format(*highest_systolic_event)) > print("Highest Diastolic: {}/{} {} {}".format(*highest_diastolic_event)) > print("Highest Pulse: {}/{} {} {}".format(*highest_pulse_event)) > print("Latest Record: {}/{} {} {}".format(*latest_record)) The print calls should be outside the function. Keep logic and presentation separate in case you decide to change UI to a GUI, Web page, curses etc. > def result_string(report_list): > return "{} {} {} {}".format(*report_list) Seems overkill to have this inside a function. > if args.add: > # This format allows sequencing now and parsing later. > timestamp = datetime.now().strftime("%Y%m%d.%H%M") > this_report = args.add > this_report.append(timestamp) This is extremely fragile. You really should check the format and data in add before adding it to your precious daa, it could end up corrupting the file if badly formed - for example a float rather than an int value?. > with open(report_file, 'a') as file: > file.write(result_string(this_report) + "\n") Is that really much clearer than: file.write("{} {} {} {}\n.format(*this_report)) > else: > # Default behavior is to report. > if os.path.exists(report_file): > try: > report_data = array_from_file(report_file) > report(report_data) > except: > print("Error processing report data") > else: > print("Cannot find ", report_file) -- 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 Mon May 9 19:29:49 2022 From: alan.gauld at yahoo.co.uk (Alan Gauld) Date: Tue, 10 May 2022 00:29:49 +0100 Subject: [Tutor] Feedback on coding style In-Reply-To: <2n0j7hd3uvkd0m33cavosd5nics0091gm7@4ax.com> References: <2n0j7hd3uvkd0m33cavosd5nics0091gm7@4ax.com> Message-ID: On 09/05/2022 22:51, Dennis Lee Bieber wrote: > In particular you will want to read about SQLite3's data model > https://www.sqlite.org/datatype3.html (there are only TEXT, INTEGER, REAL, > and BLOB data types -- the DDL parser accepts most any RDBM data > declaration and maps them to the closest In case anyone is worrying about an obvious gap, sqlite has a set of functions for manipulating/comparing dates/times which are stored internally as formatted strings. So although there is no DATETIME type you can still do the usual date/time manipulations you'd expect with a database. -- 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 Mon May 9 20:54:28 2022 From: leamhall at gmail.com (Leam Hall) Date: Mon, 9 May 2022 19:54:28 -0500 Subject: [Tutor] Feedback on coding style In-Reply-To: References: Message-ID: <1db68454-160d-086e-ed63-0e8edae299a5@gmail.com> On 5/9/22 18:18, Alan Gauld via Tutor wrote: > On 09/05/2022 13:01, Leam Hall wrote: >> if len(datum) == 4: >> data.append(datum) >> else: >> continue > > else: continue is not needed. > The loop will restart without it. Good point. The else had been set up for some error checking, but I fixed that with nargs in the parser. > The print calls should be outside the function. > Keep logic and presentation separate in case you > decide to change UI to a GUI, Web page, curses etc. Fixed. > >> def result_string(report_list): >> return "{} {} {} {}".format(*report_list) > > Seems overkill to have this inside a function. Removed. >> if args.add: >> # This format allows sequencing now and parsing later. >> timestamp = datetime.now().strftime("%Y%m%d.%H%M") >> this_report = args.add >> this_report.append(timestamp) > > This is extremely fragile. You really should check the format > and data in add before adding it to your precious daa, it > could end up corrupting the file if badly formed - for example > a float rather than an int value?. Yeah, there's no real error checking. I plead "coding too early in the morning". No real tests, either, which needs to be fixed. > >> with open(report_file, 'a') as file: >> file.write(result_string(this_report) + "\n") > > Is that really much clearer than: > > file.write("{} {} {} {}\n.format(*this_report)) Nope, so it's fixed. Thanks! Leam -- Automation Engineer (reuel.net/resume) Scribe: The Domici War (domiciwar.net) General Ne'er-do-well (github.com/LeamHall) From wlfraed at ix.netcom.com Mon May 9 21:09:06 2022 From: wlfraed at ix.netcom.com (Dennis Lee Bieber) Date: Mon, 09 May 2022 21:09:06 -0400 Subject: [Tutor] Feedback on coding style References: <2n0j7hd3uvkd0m33cavosd5nics0091gm7@4ax.com> Message-ID: On Tue, 10 May 2022 00:29:49 +0100, Alan Gauld via Tutor declaimed the following: >In case anyone is worrying about an obvious gap, sqlite has >a set of functions for manipulating/comparing dates/times >which are stored internally as formatted strings. > If the data is a TEXT type... REAL favors using them as Julian Day number, and INTEGER as Seconds since Jan 1 1970. See section 2.2 of the linked documentation. >So although there is no DATETIME type you can still do the >usual date/time manipulations you'd expect with a database. However, the Python module, with proper options, is supposed to handle conversion of Python datetime.date and datetime.datetime structures in/out SQLite3 when using "non-supported" "date" and "timestamp" as the data types in the table definition. Note that I did NOT create a formatted datetime when providing the timestamp in the INSERT DML (I did not check if the converters worked on the SELECT DML, all I know is the printed reported had a formatted datetime and not something like ) Per section 3.1, "date" and "timestamp" both fall under rule #5 and get the generic NUMERIC affinity (which probably translates to the formatted string from the converters since such aren't "well-formed" INT or REAL values ) -- Wulfraed Dennis Lee Bieber AF6VN wlfraed at ix.netcom.com http://wlfraed.microdiversity.freeddns.org/ From juliushamilton100 at gmail.com Wed May 11 17:13:36 2022 From: juliushamilton100 at gmail.com (Julius Hamilton) Date: Wed, 11 May 2022 23:13:36 +0200 Subject: [Tutor] Search package for path to class Message-ID: Hey, In a Python shell I would like to find the path to a class in a package in order to import it. So if class ?ServiceRunner? is imported via yapapi.services.service_runner but I don?t know that, I would like to do something like: find(?ServiceRunner?) and return the result ?yapapi.services.service_runner? - assuming I already imported yapapi. How would this be possible? Thanks very much, Julius From joel.goldstick at gmail.com Wed May 11 17:22:14 2022 From: joel.goldstick at gmail.com (Joel Goldstick) Date: Wed, 11 May 2022 17:22:14 -0400 Subject: [Tutor] Search package for path to class In-Reply-To: References: Message-ID: On Wed, May 11, 2022 at 5:15 PM Julius Hamilton wrote: > > Hey, > > In a Python shell I would like to find the path to a class in a package in > order to import it. > > So if class ?ServiceRunner? is imported via yapapi.services.service_runner > but I don?t know that, I would like to do something like: > > find(?ServiceRunner?) > > and return the result > > ?yapapi.services.service_runner? - assuming I already imported yapapi. > > How would this be possible? > > Thanks very much, > Julius > _______________________________________________ > Tutor maillist - Tutor at python.org > To unsubscribe or change subscription options: > https://mail.python.org/mailman/listinfo/tutor I'm not sure if pydoc would do what you want to do, but you could play around with it. It's a great tool. I think it comes with a standard python install. -- Joel Goldstick From cs at cskk.id.au Wed May 11 17:32:31 2022 From: cs at cskk.id.au (Cameron Simpson) Date: Thu, 12 May 2022 07:32:31 +1000 Subject: [Tutor] Search package for path to class In-Reply-To: References: Message-ID: On 11May2022 23:13, Julius Hamilton wrote: >So if class ?ServiceRunner? is imported via >yapapi.services.service_runner >but I don?t know that, I would like to do something like: > >find(?ServiceRunner?) ServiceRunner.__module__ maybe? Cheers, Cameron Simpson From rex.oni at gmail.com Wed May 11 11:27:22 2022 From: rex.oni at gmail.com (Rex Oni) Date: Wed, 11 May 2022 16:27:22 +0100 Subject: [Tutor] Project Question: HELP ME SIR Message-ID: We need to import two modules for myPythonFunctions.py: the random module and the os module. We?ll be using the randint() function from the random module. The randint() function generates a random integer within the range provided by us. We?ll use that to generate numbers for our questions later. >From the os module, we?ll be using the remove() and rename() functions. Help me Try importing these two modules. *Rex Oni (OCP)* *Oracle Programmer | Oracle Financials Support Engineer | Database Administrator | Data Analyst | Worship Leader | Vocal Artist | Song Writer | Pastor | General Security* *MOBILE: +2349080519328* From simon.n.connah at protonmail.com Wed May 11 15:57:38 2022 From: simon.n.connah at protonmail.com (Simon Connah) Date: Wed, 11 May 2022 19:57:38 +0000 Subject: [Tutor] Python, Poetry, PyCharm Pro and macOS Message-ID: Hi, I have installed Python 3.10.4 on my Apple Silicon Mac. I then downloaded PyCharm Pro version 2022.1 and started a new project. When asked what package manager I wanted to use (the options were pipenv, virtualenv, poetry and conda) I chose Poetry because I hadn't tried it before and after reading the website a bit it sounded better than using virtualenv which is what I have used in the past. Anyway, things seemed to work correctly but then I tried to install scrypt and the build failed. I wanted to delete the poetry environment so I could start again from scratch but I then realised I had no idea where poetry on macOS stored the environment. Can someone point me in the right direction, please? Simon. From learn2program at gmail.com Wed May 11 18:41:14 2022 From: learn2program at gmail.com (Alan Gauld) Date: Wed, 11 May 2022 23:41:14 +0100 Subject: [Tutor] Python, Poetry, PyCharm Pro and macOS In-Reply-To: References: Message-ID: <2b1ddf43-4cc4-b889-7d5d-139c618b73ac@yahoo.co.uk> On 11/05/2022 20:57, Simon Connah via Tutor wrote: > to delete the poetry environment so I could start again > from scratch but I then realised I had no idea where > poetry on macOS stored the environment. > > Can someone point me in the right direction, please? This is really off topic for this list which is about the Python language and its standard library. However there are some Mac users here (including myself, except I don't use virtual envs of any variety) so someone might know. Failing that, you should ask on the poetry support forum. If there is no support forum I'd take that as a very good reason not to use it! -- 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 learn2program at gmail.com Wed May 11 18:47:00 2022 From: learn2program at gmail.com (Alan Gauld) Date: Wed, 11 May 2022 23:47:00 +0100 Subject: [Tutor] Project Question: HELP ME SIR In-Reply-To: References: Message-ID: <0910e52d-43f2-6604-3cd1-7f06e5f60531@yahoo.co.uk> On 11/05/2022 16:27, Rex Oni wrote: > We need to import two modules for myPythonFunctions.py: the > random module and the os module. This sounds like a homework? We won't do your homework. How to import modules should be covered very early in any Python tutorial. You basically can't do much without importing things... > We?ll be using the randint() function from the random module. > From the os module, we?ll be using the remove() and rename() > functions. What have you tried? There are several different import options, each has value depending on what you need. import MODULE [as alias] from MODULE import NAME [ as alias] import * from MODULE????? # usually only at the >>> prompt Read the docs to decide which is most appropriate for you. -- 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 Wed May 11 18:47:14 2022 From: wlfraed at ix.netcom.com (Dennis Lee Bieber) Date: Wed, 11 May 2022 18:47:14 -0400 Subject: [Tutor] Search package for path to class References: Message-ID: On Wed, 11 May 2022 23:13:36 +0200, Julius Hamilton declaimed the following: >find(?ServiceRunner?) > >and return the result > >?yapapi.services.service_runner? - assuming I already imported yapapi. > >How would this be possible? > I suspect you would have to perform a recursive walk of each visible module, keeping track of the levels (parent modules), checking if the target is in the dir(modulepath), and return the module path for each match (I say each as I'd recommend not bailing out on the first find -- you may discover names are used in multiple modules, or a parent did a "from xyz import name"). Problem: dir() returns strings, and type() just says it is a string. Instead, use sys.modules (which appears to obviate the need for recursion) Unfortunately, that is a long list even for an empty "shell" C:\Users\Wulfraed>python Python ActivePython 3.8.2 (ActiveState Software Inc.) based on on win32 Type "help", "copyright", "credits" or "license" for more information. >>> import sys >>> for item in sys.modules: ... print(item) ... sys builtins _frozen_importlib _imp _warnings _frozen_importlib_external _io marshal nt _thread _weakref winreg time zipimport _codecs codecs encodings.aliases encodings encodings.utf_8 encodings.cp1252 _signal __main__ encodings.latin_1 _abc abc io _stat stat _collections_abc genericpath ntpath os.path os _sitebuiltins _locale _bootlocale types importlib._bootstrap importlib._bootstrap_external warnings importlib importlib.machinery importlib.abc _operator operator keyword _heapq heapq itertools reprlib _collections collections _functools functools contextlib importlib.util paste google google.cloud google.logging google.iam logilab mpl_toolkits pywin32_bootstrap repoze sphinxcontrib zope site __future__ pyreadline.py3k_compat pyreadline.unicode_helper _socket collections.abc math select selectors enum errno socket _sre sre_constants sre_parse sre_compile copyreg re token tokenize linecache traceback _weakrefset weakref _string string threading atexit logging _struct struct _compat_pickle _pickle pickle _queue queue copy logging.handlers pyreadline.logger _ctypes ctypes._endian ctypes ctypes.wintypes pyreadline.keysyms.winconstants pyreadline.keysyms.common pyreadline.keysyms.keysyms pyreadline.keysyms pyreadline.clipboard.win32_clipboard pyreadline.clipboard pyreadline.lineeditor pyreadline.lineeditor.wordmatcher pyreadline.lineeditor.lineobj pyreadline.lineeditor.history posixpath fnmatch glob pyreadline.error pyreadline.modes.basemode pyreadline.modes.emacs pyreadline.modes.notemacs pyreadline.modes.vi pyreadline.modes pyreadline.console.ansi zlib _compression _bz2 bz2 _lzma lzma shutil signal msvcrt _winapi subprocess ctypes.util pyreadline.console.event pyreadline.console.console pyreadline.console pyreadline.release pyreadline.rlmain pyreadline readline rlcompleter >>> For each, check if dir() has the sought after name... (I just did a loop over some -- you probably want something like if findname in dir(item): print(item, findname) ) >>> for item in sys.modules: ... if item.startswith("google"): ... for names in dir(item): ... print(item, names) ... google __add__ google __class__ google __contains__ google __delattr__ google __dir__ google __doc__ google __eq__ google __format__ google __ge__ google __getattribute__ google __getitem__ google __getnewargs__ google __gt__ google __hash__ google __init__ google __init_subclass__ google __iter__ google __le__ google __len__ google __lt__ google __mod__ google __mul__ google __ne__ google __new__ google __reduce__ google __reduce_ex__ google __repr__ google __rmod__ google __rmul__ google __setattr__ google __sizeof__ google __str__ google __subclasshook__ google capitalize google casefold google center google count google encode google endswith google expandtabs google find google format google format_map google index google isalnum google isalpha google isascii google isdecimal google isdigit google isidentifier google islower google isnumeric google isprintable google isspace google istitle google isupper google join google ljust google lower google lstrip google maketrans google partition google replace google rfind google rindex google rjust google rpartition google rsplit google rstrip google split google splitlines google startswith google strip google swapcase google title google translate google upper google zfill google.cloud __add__ google.cloud __class__ google.cloud __contains__ google.cloud __delattr__ google.cloud __dir__ google.cloud __doc__ google.cloud __eq__ google.cloud __format__ google.cloud __ge__ google.cloud __getattribute__ google.cloud __getitem__ google.cloud __getnewargs__ google.cloud __gt__ google.cloud __hash__ google.cloud __init__ google.cloud __init_subclass__ google.cloud __iter__ google.cloud __le__ google.cloud __len__ google.cloud __lt__ google.cloud __mod__ google.cloud __mul__ google.cloud __ne__ google.cloud __new__ google.cloud __reduce__ google.cloud __reduce_ex__ google.cloud __repr__ google.cloud __rmod__ google.cloud __rmul__ google.cloud __setattr__ google.cloud __sizeof__ google.cloud __str__ -- Wulfraed Dennis Lee Bieber AF6VN wlfraed at ix.netcom.com http://wlfraed.microdiversity.freeddns.org/ From simon.n.connah at protonmail.com Wed May 11 22:36:36 2022 From: simon.n.connah at protonmail.com (Simon Connah) Date: Thu, 12 May 2022 02:36:36 +0000 Subject: [Tutor] Python, Poetry, PyCharm Pro and macOS In-Reply-To: <2b1ddf43-4cc4-b889-7d5d-139c618b73ac@yahoo.co.uk> References: <2b1ddf43-4cc4-b889-7d5d-139c618b73ac@yahoo.co.uk> Message-ID: ------- Original Message ------- On Wednesday, May 11th, 2022 at 23:41, Alan Gauld wrote: > > > On 11/05/2022 20:57, Simon Connah via Tutor wrote: > > > to delete the poetry environment so I could start again > > from scratch but I then realised I had no idea where > > poetry on macOS stored the environment. > > > > Can someone point me in the right direction, please? > > > This is really off topic for this list which is about the Python > language and its standard library. > > However there are some Mac users here (including myself, except I don't > use virtual > envs of any variety) so someone might know. > > Failing that, you should ask on the poetry support forum. If there is no > support > forum I'd take that as a very good reason not to use it! > > -- > 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 > > _______________________________________________ > Tutor maillist - Tutor at python.org > To unsubscribe or change subscription options: > https://mail.python.org/mailman/listinfo/tutor I apologise. I didn't realise it was off-topic for the mailing list. I'll only use it for the language and the standard library in the future. Sorry. Simon. From mats at wichmann.us Thu May 12 14:25:58 2022 From: mats at wichmann.us (Mats Wichmann) Date: Thu, 12 May 2022 12:25:58 -0600 Subject: [Tutor] Python, Poetry, PyCharm Pro and macOS In-Reply-To: References: Message-ID: <91e16f73-8531-ac97-d4d7-9db4b912c6e4@wichmann.us> On 5/11/22 13:57, Simon Connah via Tutor wrote: > Hi, > > I have installed Python 3.10.4 on my Apple Silicon Mac. I then downloaded PyCharm Pro version 2022.1 and started a new project. When asked what package manager I wanted to use (the options were pipenv, virtualenv, poetry and conda) I chose Poetry because I hadn't tried it before and after reading the website a bit it sounded better than using virtualenv which is what I have used in the past. > > Anyway, things seemed to work correctly but then I tried to install scrypt and the build failed. I wanted to delete the poetry environment so I could start again from scratch but I then realised I had no idea where poetry on macOS stored the environment. Since you did that *through* PyCharm, PyCharm should know where it is. From nathan-tech at hotmail.com Mon May 16 22:05:12 2022 From: nathan-tech at hotmail.com (Nathan Smith) Date: Tue, 17 May 2022 03:05:12 +0100 Subject: [Tutor] subprocess figuring out what is in stdout Message-ID: I'm working with a program which requires interactive shell like reading of the output, EG user types input in response to various outputs displayed to them. Unfortunately, in some cases, the program being run is not either printing an "\n" at the end of particular lines, or is not flushing? it. This only happens with specific points and is easily responsed. Unfortunately, the unflushed data does not appear until the question being asked is answered (rather unhelpful to the user) My current implementation uses readline which is why I suspect the problem may be that there is no "\n" character at the end, hence why readline is not flushing it until more output is added. One possible solution I found is to do stdout.read(1) and do it character by character, but the efficiency seems low and this also presents some other problems with other parts of my program. To that end I was wondering, perhaps is there a way to tell how many characters/bytes are in a stdout buffer before it is read? That way read(x) could give the exact number. I've seen some references talk about a way of making non blocking ports, but these seem to be linux solutions and don't play nice with windows so this doesn't really seem to be an option. thanks in advance for any tips. -- Best Wishes, Nathan Smith, BSC My Website: https://nathantech.net From mats at wichmann.us Tue May 17 10:34:26 2022 From: mats at wichmann.us (Mats Wichmann) Date: Tue, 17 May 2022 08:34:26 -0600 Subject: [Tutor] subprocess figuring out what is in stdout In-Reply-To: References: Message-ID: <8360ae62-3422-1c1a-fd74-4fe06f467ab9@wichmann.us> On 5/16/22 20:05, Nathan Smith wrote: > I'm working with a program which requires interactive shell like reading > of the output, EG user types input in response to various outputs > displayed to them. > > Unfortunately, in some cases, the program being run is not either > printing an "\n" at the end of particular lines, or is not flushing? it. It's not entirely clear what you're trying to accomplish, so this is guessing... Getting this to work well depends on how much control you have over the external program. If you don't have control over it, you might look at how the Python version of expect works (https://pexpect.readthedocs.io/en/stable) - or maybe even be able to use it? It's normally up to the external process to decide how to handle its own stdout/stderr. You can sometimes make things work by wiring up the plumbing appropriately. On Linux, the standard library does buffering if the output is a pipe, so if you can "make it look like a terminal" (i.e. plug in a pseudo-tty), it might work better for you - see pexpect's FAQ on this topic: https://pexpect.readthedocs.io/en/stable/FAQ.html?highlight=unbuffer From nathan-tech at hotmail.com Tue May 17 14:32:42 2022 From: nathan-tech at hotmail.com (Nathan Smith) Date: Tue, 17 May 2022 19:32:42 +0100 Subject: [Tutor] subprocess figuring out what is in stdout In-Reply-To: <8360ae62-3422-1c1a-fd74-4fe06f467ab9@wichmann.us> References: <8360ae62-3422-1c1a-fd74-4fe06f467ab9@wichmann.us> Message-ID: Hi Mats, thanks for that. I did end up going down pexpect 's path, though I went with winpexpect for windows. Worked a treat. Nathan On 17/05/2022 15:34, Mats Wichmann wrote: > On 5/16/22 20:05, Nathan Smith wrote: >> I'm working with a program which requires interactive shell like reading >> of the output, EG user types input in response to various outputs >> displayed to them. >> >> Unfortunately, in some cases, the program being run is not either >> printing an "\n" at the end of particular lines, or is not flushing? it. > It's not entirely clear what you're trying to accomplish, so this is > guessing... > > Getting this to work well depends on how much control you have over the > external program. If you don't have control over it, you might look at > how the Python version of expect works > (https://nam12.safelinks.protection.outlook.com/?url=https%3A%2F%2Fpexpect.readthedocs.io%2Fen%2Fstable&data=05%7C01%7C%7C4da2f22d48ae40ee40f108da3812996b%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C637883949776396684%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000%7C%7C%7C&sdata=W73FQxzF2dbAvQlozmavHMTAbIlqCluU0QuWXC%2FZIQA%3D&reserved=0) - or maybe even be able to > use it? > > It's normally up to the external process to decide how to handle its own > stdout/stderr. You can sometimes make things work by wiring up the > plumbing appropriately. On Linux, the standard library does buffering > if the output is a pipe, so if you can "make it look like a terminal" > (i.e. plug in a pseudo-tty), it might work better for you - see > pexpect's FAQ on this topic: > > https://nam12.safelinks.protection.outlook.com/?url=https%3A%2F%2Fpexpect.readthedocs.io%2Fen%2Fstable%2FFAQ.html%3Fhighlight%3Dunbuffer&data=05%7C01%7C%7C4da2f22d48ae40ee40f108da3812996b%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C637883949776396684%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000%7C%7C%7C&sdata=Uo1LVcpOBi%2BJuNtugMuPCfJuGQfjHvVEyrNfYMKVf2k%3D&reserved=0 > > _______________________________________________ > Tutor maillist - Tutor at python.org > To unsubscribe or change subscription options: > https://nam12.safelinks.protection.outlook.com/?url=https%3A%2F%2Fmail.python.org%2Fmailman%2Flistinfo%2Ftutor&data=05%7C01%7C%7C4da2f22d48ae40ee40f108da3812996b%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C637883949776396684%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000%7C%7C%7C&sdata=OJc5sIX0ctguw5CeTBdXXwSuNYSldv3tNO24KyBhCoc%3D&reserved=0 -- Best Wishes, Nathan Smith, BSC My Website: https://nathantech.net From rjwilcox at gmail.com Thu May 19 08:28:47 2022 From: rjwilcox at gmail.com (Robert Wilcox) Date: Thu, 19 May 2022 08:28:47 -0400 Subject: [Tutor] Count Within a G on Message-ID: Cheers, I have a dataframe of IDs that has a specific order. I need a rolling count of IDs for each ID. Below my example has 2 IDs with 2 other data fields in order. The Count field is what I need to add to the dataframe: ID Value_1 Value_2 Count 1234 x a 1 1234 x b 2 1234 y c 3 2222 s a 1 2222 t b 2 Thanks, Bob From leamhall at gmail.com Thu May 19 14:19:03 2022 From: leamhall at gmail.com (Leam Hall) Date: Thu, 19 May 2022 13:19:03 -0500 Subject: [Tutor] Count Within a G on In-Reply-To: References: Message-ID: What code have you tried so far? On Thu, May 19, 2022, 12:57 PM Robert Wilcox wrote: > Cheers, > I have a dataframe of IDs that has a specific order. I need a rolling count > of IDs for each ID. > Below my example has 2 IDs with 2 other data fields in order. The Count > field is what I need to add to the dataframe: > ID Value_1 Value_2 Count > 1234 x a 1 > 1234 x b 2 > 1234 y c 3 > 2222 s a 1 > 2222 t b 2 > > Thanks, > Bob > _______________________________________________ > Tutor maillist - Tutor at python.org > To unsubscribe or change subscription options: > https://mail.python.org/mailman/listinfo/tutor > From learn2program at gmail.com Mon May 23 03:46:15 2022 From: learn2program at gmail.com (Alan Gauld) Date: Mon, 23 May 2022 08:46:15 +0100 Subject: [Tutor] Fwd: Request to mailing list Tutor rejected In-Reply-To: References: Message-ID: <6ef17780-f87f-89a6-ac07-2e16f7b999ea@yahoo.co.uk> Forwarding to group from owner... ------------------- Hello Thankyou for replying.? e.g. t = t['physical square shape'1] the text in single quotes is actually the shape of a square not text.? It was a question in my python asssessment last week. There were three of them like this. I can't get any answers from the course instructors but I would like to be able to know for my own information at least if these questions where of an incorrect format.? Any information is greatly appreciated.? Kr Belinda Chisholm ------------------------------------------------------------------------ From dimitarxivanov at gmail.com Tue May 24 09:27:17 2022 From: dimitarxivanov at gmail.com (Dimitar Ivanov) Date: Tue, 24 May 2022 14:27:17 +0100 Subject: [Tutor] Object destruction Message-ID: Hi all, I'm trying to come up with a (working) design of tracking an object throughout its lifecycle but I'm unable to find quite what I'm looking for, so I hope you folks will be able to give me some tips. I have an object that is being created and I want to "trace" that object in a separate static class that other threads and objects will be able to access if necessary: class TestClass: def __init__(self, name): self.name = name self._finalizer = weakref.finalize(self, self.finalize) def do_stuff(self): print(f"Object {self.name} doing stuff") Tracer.trace(self.name) time.sleep(5) def finalize(self): print(f"Entered finalize method for object {self.name}") Tracer.untrace(self.name) Here, I have the static object that "traces" those objects: class Tracer: traced_objects = [] @staticmethod def trace(some_object): Tracer.traced_objects.append(some_object) @staticmethod def untrace(some_object): Tracer.traced_objects.remove(some_object) And here's my main method where I test creating the objects, kicking off their do_stuff methods in a thread and then deleting them and checking if they've been removed from the traced_objects list in the Tracer class: if __name__ == '__main__': objectOne = TestClass("Object1") objectTwo = TestClass("Object2") thrd1 = Thread(target=objectOne.do_stuff) thrd2 = Thread(target=objectTwo.do_stuff) thrd1.start() thrd2.start() thrd1.join() thrd2.join() del objectOne del objectTwo print("Threads are done, checking Tracer's dict") print(f"Tracer's dict: {Tracer.traced_objects}") It seems like the Finalizer is only kicking off the objects' finalize methods once the program exits, which, if I'm reading the documentation right, is the correct behaviour; however, I need that finalize method kicked off as soon as any reference to those objects is removed. Can I achieve that in any way? Thanks a lot in advance and please, do let me know if my explanation is vague and/or unclear! Regards, Dimitar From alan.gauld at yahoo.co.uk Tue May 24 19:07:11 2022 From: alan.gauld at yahoo.co.uk (Alan Gauld) Date: Wed, 25 May 2022 00:07:11 +0100 Subject: [Tutor] Object destruction In-Reply-To: References: Message-ID: On 24/05/2022 14:27, Dimitar Ivanov wrote: > I'm trying to come up with a (working) design of tracking an object > throughout its lifecycle but I'm unable to find quite what I'm looking for, Thats because I think you are looking for the wrong thing. I think you ae getting confused between objects and names. > def __init__(self, name): > self.name = name > self._finalizer = weakref.finalize(self, self.finalize) This only registers a metjod that will be called when the object is garbage collected. That in turn will be "some time" after the last strong reference is broken. > Here, I have the static object that "traces" those objects: > > class Tracer: > > traced_objects = [] > > @staticmethod > def trace(some_object): > Tracer.traced_objects.append(some_object) > > @staticmethod > def untrace(some_object): > Tracer.traced_objects.remove(some_object) This seems like a pointless class. It could (should?) just be two functions. > if __name__ == '__main__': > objectOne = TestClass("Object1") > objectTwo = TestClass("Object2") > thrd1 = Thread(target=objectOne.do_stuff) > thrd2 = Thread(target=objectTwo.do_stuff) > thrd1.start() > thrd2.start() > thrd1.join() > thrd2.join() > del objectOne > del objectTwo But these del statements don't delete the object, they simply delete the name from the namespace. Doing so reduces the reference count but does not delete the object. (As you've discovered) So which are you really interested in? Is it the lifecycle of the object? The lifecycle of the name? Or the references? > It seems like the Finalizer is only kicking off the objects' finalize > methods once the program exits, which, if I'm reading the documentation > right, is the correct behaviour Only because that's the point that the object is destroyed. You are correctly monitoring the object lifecycle. ; however, I need that finalize method > kicked off as soon as any reference to those objects is removed. Any reference? a = MyClass() b = a objects = [a,b] del a del b del objects Should that call the finalizer once? or twice? or three times? or four? And when? > Can I achieve that in any way? You need to be clearer what you want. You are already tracking object lifecycles successfully. You are not tracking references, that would need a different approach entirely. -- 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 Tue May 24 19:10:03 2022 From: cs at cskk.id.au (Cameron Simpson) Date: Wed, 25 May 2022 09:10:03 +1000 Subject: [Tutor] Object destruction In-Reply-To: References: Message-ID: On 24May2022 14:27, Dimitar Ivanov wrote: >I'm trying to come up with a (working) design of tracking an object >throughout its lifecycle but I'm unable to find quite what I'm looking for, >so I hope you folks will be able to give me some tips. > >I have an object that is being created and I want to "trace" that object in >a separate static class that other threads and objects will be able to >access if necessary: [...] >It seems like the Finalizer is only kicking off the objects' finalize >methods once the program exits, which, if I'm reading the documentation >right, is the correct behaviour; however, I need that finalize method >kicked off as soon as any reference to those objects is removed. Can I >achieve that in any way? _Any_ reference, or when the final-reference-except-for-your-tracer reference is removed? For the latter, see the weakref module: https://docs.python.org/3/library/weakref.html#module-weakref For making references to objects which do not contribute to their reference count. My SingletonMixin class uses a WeakValueDictionary to keep references to existing instances without extending their lifespan. A WeakValueDictionary may well fit your use case. Cheers, Cameron Simpson From cs at cskk.id.au Tue May 24 19:59:34 2022 From: cs at cskk.id.au (Cameron Simpson) Date: Wed, 25 May 2022 09:59:34 +1000 Subject: [Tutor] Object destruction In-Reply-To: References: Message-ID: On 25May2022 09:10, Cameron Simpson wrote: >On 24May2022 14:27, Dimitar Ivanov wrote: >>I'm trying to come up with a (working) design of tracking an object >>throughout its lifecycle but I'm unable to find quite what I'm looking for, >>so I hope you folks will be able to give me some tips. [...] > >_Any_ reference, or when the final-reference-except-for-your-tracer >reference is removed? For the latter, see the weakref module: >https://docs.python.org/3/library/weakref.html#module-weakref >For making references to objects which do not contribute to their >reference count. I did not notice that you are already using weakref. Apologies, Cameron Simpson From roel at roelschroeven.net Tue May 24 19:41:05 2022 From: roel at roelschroeven.net (Roel Schroeven) Date: Wed, 25 May 2022 01:41:05 +0200 Subject: [Tutor] Object destruction In-Reply-To: References: Message-ID: Dimitar Ivanov schreef op 24/05/2022 om 15:27: > It seems like the Finalizer is only kicking off the objects' finalize > methods once the program exits, which, if I'm reading the documentation > right, is the correct behaviour; however, I need that finalize method > kicked off as soon as any reference to those objects is removed. Can I > achieve that in any way? I get the feeling that you are trying to achieve something like RAII ("Resource acquisition is initialization") in C++. Is that correct? In C++ it's indeed possible, and the recommend way of doing things, to do finalization in the destructor which in C++ is closely tied to the object's scope. In Python things work differently. The recommended way to handle resource management is through context managers (with 'with' statements). Many of the built-in classes provide context managers, as in this example: ??? with open('hello.txt', 'r') as f: ??????? for line in f: ??????????? ... The file is automatically closed after the 'with' statement, or when an exception is raised. You can create context managers for your own classes, too. See e.g. https://betterprogramming.pub/everything-you-need-to-know-about-context-managers-in-python-f83556fbdfb -- "Your scientists were so preoccupied with whether they could, they didn't stop to think if they should" -- Dr. Ian Malcolm From marcus.luetolf at bluewin.ch Wed May 25 13:19:07 2022 From: marcus.luetolf at bluewin.ch (marcus.luetolf at bluewin.ch) Date: Wed, 25 May 2022 19:19:07 +0200 Subject: [Tutor] problem solving with lists: preliminary solution Message-ID: <000001d8705b$8acbb350$a06319f0$@bluewin.ch> ....sorry, forgott correct e_mail address..... Hello Experts, hello dn, In resuming my task to write code for a special constellation of the "SocialGolferProblem" (SGP) : number_of_days (number_of_weeks) = 5 number_of_flights (number_of_groupings) = 4 seize of flight (players_per_grouping) = 4 and given the solution below (draws for week 1 through 5) I've come up with a code of which I only post part of it (for it gets to big): for day 1( hardcoded) and for day 2 (as a function to be used through day 5). The crucial part of my functions for day 2 to 5 are the conditional statements. These conditional statements do not follow a consistent pattern. This inconsistency casts some doubt on the effectiveness of my code below and I'd appreciate critical comments. My code so far: def startlist(): all_players = list('abcdefghijklmnop') n = 4 # n = seize of flight a_flight_day_1 = [] b_flight_day_1 = [] c_flight_day_1 = [] d_flight_day_1 = [] a_flight_day_2 = [] b_flight_day_2 = [] c_flight_day_2 = [] d_flight_day_2 = [] a_flight_day_3 = [] b_flight_day_3 = [] c_flight_day_3 = [] d_flight_day_3 = [] a_flight_day_4 = [] b_flight_day_4 = [] c_flight_day_4 = [] d_flight_day_4 = [] a_flight_day_5 = [] b_flight_day_5 = [] c_flight_day_5 = [] d_flight_day_5 = [] history = {'a':[], 'b':[],'c':[],'d':[],'e':[],'f':[],'g':[],'h':[],'i':[],'j':[],'k':[],'l':[],'m':[],'n':[],'o':[],'p':[]} [a_flight_day_1.append(player)for player in all_players[0:n]] print('a_flight_day_1: ', a_flight_day_1) del all_players[0:n] [b_flight_day_1.append(player)for player in all_players[0:n]] print('b_flight_day_1: ', b_flight_day_1) del all_players[0:n] [c_flight_day_1.append(player)for player in all_players[0:n]] print('c_flight_day_1: ', c_flight_day_1) del all_players[0:n] [d_flight_day_1.append(player)for player in all_players[0:n]] print('d_flight_day_1: ', d_flight_day_1) history['a'].extend(a_flight_day_1) history['b'].extend(a_flight_day_1) history['c'].extend(a_flight_day_1) history['d'].extend(a_flight_day_1) history['e'].extend(b_flight_day_1) history['f'].extend(b_flight_day_1) history['g'].extend(b_flight_day_1) history['h'].extend(b_flight_day_1) history['i'].extend(c_flight_day_1) history['j'].extend(c_flight_day_1) history['k'].extend(c_flight_day_1) history['l'].extend(c_flight_day_1) history['m'].extend(d_flight_day_1) history['n'].extend(d_flight_day_1) history['o'].extend(d_flight_day_1) history['p'].extend(d_flight_day_1) def day_2_flights(): lead_player = 'a' temp = history[lead_player][:] for i in range(n-1): for player in all_players: if player not in temp: a_flight_day_2.extend(player) temp.extend(history[player]) break history[lead_player].append(player) history[lead_player] = list(set(history[lead_player])) #eliminate duplicates a_flight_day_2.extend(lead_player) a_flight_day_2.sort() print('a_flight_day_2: ', a_flight_day_2) [history[pl].extend(a_flight_day_2) for pl in a_flight_day_2[1:]] lead_player = 'b' temp = history['a'][:] for i in range(n-1): for player in all_players: if player not in temp: b_flight_day_2.extend(player) temp.extend(history[player]) break history[lead_player].append(player) history[lead_player] = list(set(history[lead_player])) #eliminate duplicates b_flight_day_2.extend(lead_player) b_flight_day_2.sort() print('b_flight_day_2: ', b_flight_day_2) [history[pl].extend(b_flight_day_2) for pl in b_flight_day_2[1:]] lead_player = 'c' temp = history['a'][:] for i in range(n-1): for player in all_players: if player not in temp and player not in history['b']: c_flight_day_2.extend(player) temp.extend(history[player]) break history[lead_player].append(player) history[lead_player] = list(set(history[lead_player])) #eliminate duplicates c_flight_day_2.extend(lead_player) c_flight_day_2.sort() print('c_flight_day_2: ', c_flight_day_2) [history[pl].extend(c_flight_day_2) for pl in c_flight_day_2[1:]] lead_player = 'd' temp = history['a'][:] for i in range(n-1): for player in all_players: if player not in temp and player not in history['b'] and player not in history['c']: d_flight_day_2.extend(player) temp.extend(history[player]) break history[lead_player].append(player) history[lead_player] = list(set(history[lead_player])) #eliminate duplicates d_flight_day_2.extend(lead_player) d_flight_day_2.sort() print('d_flight_day_2: ', d_flight_day_2) [history[pl].extend(d_flight_day_2) for pl in d_flight_day_2[1:]] all_players = list('abcdefghijklmnop') n = 4 #n = seize of flight day_2_flights() startlist() Regards, Marcus. -----Urspr?ngliche Nachricht----- Von: Tutor Im Auftrag von dn Gesendet: Montag, 21. M?rz 2022 06:35 An: tutor at python.org Betreff: Re: [Tutor] problem solving with lists Have I managed to understand the problem, this time? On 21/03/2022 05.05, Dennis Lee Bieber wrote: > On Sun, 20 Mar 2022 15:55:27 +0100, > declaimed the following: > >>> all_letters = ?abcdefghijklmnop? >>> number_of_lists = 5 >>> number_of_sublists per list = 4 >>> number_per_sublist = 4 >> to >>> all_letters = ?abcdefghi? >>> number_of_lists = 4 >>> number_of_sublists per list = 3 >>> number_per_sublist = 3 >> to >>> all_letters = 'abcdef'. > The discussion would be much easier if you gave real names to all > those... (since you later confirm this is the SGP) > > number of weeks > number of groupings > players per grouping > > This avoids all confusion over lists, sublists, etc... "week 1", > "group 3", "player 2". How about these as 'meaningful names': players = "abcdefghijklmnop" number_of_weeks = 5 number_of_groupings = 4 players_per_grouping = 4 >> seems rather straightforward. But for now I cannot see yet how to use it >> to remove all non-uniques sublists/teams. > You don't "remove" them! "Remove" implies you already placed a > grouping into the solution and now are checking for if they meet the > constraints. > Instead you check the constraints for a candidate grouping BEFORE ADDING it > to the solution. Yes, the more 'constructivist' approach is probably easier - it is easier to 'see' as things are added to the solution, than it is to keep track of what was there 'before' when subtracting/pruning. YMMV! This solution keeps track of each player's history, ie if player-a is grouped with players 'b', 'c', and 'd' in the first game, then: player_history['a'] == {'b','c','d'} and in the second game (s)he is grouped with players 'e', 'i', 'm'; then it becomes: player_history['a'] == {'b','c','d', 'e', 'i', 'm'} and so-on (see output-report, below) The player's history is used whenever (s)he is 'selected' to ensure that there is no repetition of anyone who has participated in that player's previous groupings. >> SPG exactly describes my goal. > > The SGP is not a week-end programming exercise. It is the subject of > multiple university research papers in developing/optimizing > constraint-based solver algorithms. > > A one-time pass over the output of .combinations() will not be > sufficient (especially as the criteria per week that no player appears > more than once means going from "abcd" [the first foursome > .combinations() spits out] has to skip all other groups that begin > with "a", "b", "c" or "d" -- and you can't get them back later. At a > minimum you need to restart the > .combinations() on each week. You'll really need to implement some way > of backtracking ("we ran out of groupings without being able to place > one ink 'this' position, back up and change the previously placed > grouping and start over on this position") -- it is possible you might > have to back all the way up to the first grouping and try a different > value for it. Which all serves to make me think that I have yet to grasp the full-measure of the problem! Herewith the output-report. The "draw" for each week (who is playing whom during that week) appears as four Python-lists under the week's sub-title. (the 'real' output) Inspecting the "draw", one can visually-check that each player only plays against everyone else, once - and only once - and exactly once (per @Dennis' comment about byes - no, none of them necessary with this combination of definitions)! The 16-player listing (debug-print) underneath each week's draw, shows how the program[me] keeps a record of which players each player has played to-date - thus after each week's game it extends by another three players' names/letters. Finally, by the end of the league/tournament (whatever you want to call the five-weeks of play, per definitions), every player is shown to have played against every other player:- /usr/bin/python3 /home/dn/Projects/Experiments/marcus.py Draw for 5 week league Draw for week 1 ['a', 'b', 'c', 'd'] ['e', 'f', 'g', 'h'] ['i', 'j', 'k', 'l'] ['m', 'n', 'o', 'p'] a ['a', 'b', 'c', 'd'] b ['a', 'b', 'c', 'd'] c ['a', 'b', 'c', 'd'] d ['a', 'b', 'c', 'd'] e ['e', 'f', 'g', 'h'] f ['e', 'f', 'g', 'h'] g ['e', 'f', 'g', 'h'] h ['e', 'f', 'g', 'h'] i ['i', 'j', 'k', 'l'] j ['i', 'j', 'k', 'l'] k ['i', 'j', 'k', 'l'] l ['i', 'j', 'k', 'l'] m ['m', 'n', 'o', 'p'] n ['m', 'n', 'o', 'p'] o ['m', 'n', 'o', 'p'] p ['m', 'n', 'o', 'p'] Draw for week 2 ['a', 'e', 'i', 'm'] ['b', 'f', 'j', 'n'] ['c', 'g', 'k', 'o'] ['d', 'h', 'l', 'p'] a ['a', 'b', 'c', 'd', 'e', 'i', 'm'] b ['a', 'b', 'c', 'd', 'f', 'j', 'n'] c ['a', 'b', 'c', 'd', 'g', 'k', 'o'] d ['a', 'b', 'c', 'd', 'h', 'l', 'p'] e ['a', 'e', 'f', 'g', 'h', 'i', 'm'] f ['b', 'e', 'f', 'g', 'h', 'j', 'n'] g ['c', 'e', 'f', 'g', 'h', 'k', 'o'] h ['d', 'e', 'f', 'g', 'h', 'l', 'p'] i ['a', 'e', 'i', 'j', 'k', 'l', 'm'] j ['b', 'f', 'i', 'j', 'k', 'l', 'n'] k ['c', 'g', 'i', 'j', 'k', 'l', 'o'] l ['d', 'h', 'i', 'j', 'k', 'l', 'p'] m ['a', 'e', 'i', 'm', 'n', 'o', 'p'] n ['b', 'f', 'j', 'm', 'n', 'o', 'p'] o ['c', 'g', 'k', 'm', 'n', 'o', 'p'] p ['d', 'h', 'l', 'm', 'n', 'o', 'p'] Draw for week 3 ['a', 'f', 'k', 'p'] ['b', 'e', 'l', 'o'] ['c', 'h', 'i', 'n'] ['d', 'g', 'j', 'm'] a ['a', 'b', 'c', 'd', 'e', 'f', 'i', 'k', 'm', 'p'] b ['a', 'b', 'c', 'd', 'e', 'f', 'j', 'l', 'n', 'o'] c ['a', 'b', 'c', 'd', 'g', 'h', 'i', 'k', 'n', 'o'] d ['a', 'b', 'c', 'd', 'g', 'h', 'j', 'l', 'm', 'p'] e ['a', 'b', 'e', 'f', 'g', 'h', 'i', 'l', 'm', 'o'] f ['a', 'b', 'e', 'f', 'g', 'h', 'j', 'k', 'n', 'p'] g ['c', 'd', 'e', 'f', 'g', 'h', 'j', 'k', 'm', 'o'] h ['c', 'd', 'e', 'f', 'g', 'h', 'i', 'l', 'n', 'p'] i ['a', 'c', 'e', 'h', 'i', 'j', 'k', 'l', 'm', 'n'] j ['b', 'd', 'f', 'g', 'i', 'j', 'k', 'l', 'm', 'n'] k ['a', 'c', 'f', 'g', 'i', 'j', 'k', 'l', 'o', 'p'] l ['b', 'd', 'e', 'h', 'i', 'j', 'k', 'l', 'o', 'p'] m ['a', 'd', 'e', 'g', 'i', 'j', 'm', 'n', 'o', 'p'] n ['b', 'c', 'f', 'h', 'i', 'j', 'm', 'n', 'o', 'p'] o ['b', 'c', 'e', 'g', 'k', 'l', 'm', 'n', 'o', 'p'] p ['a', 'd', 'f', 'h', 'k', 'l', 'm', 'n', 'o', 'p'] Draw for week 4 ['a', 'g', 'l', 'n'] ['b', 'h', 'k', 'm'] ['c', 'e', 'j', 'p'] ['d', 'f', 'i', 'o'] a ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'i', 'k', 'l', 'm', 'n', 'p'] b ['a', 'b', 'c', 'd', 'e', 'f', 'h', 'j', 'k', 'l', 'm', 'n', 'o'] c ['a', 'b', 'c', 'd', 'e', 'g', 'h', 'i', 'j', 'k', 'n', 'o', 'p'] d ['a', 'b', 'c', 'd', 'f', 'g', 'h', 'i', 'j', 'l', 'm', 'o', 'p'] e ['a', 'b', 'c', 'e', 'f', 'g', 'h', 'i', 'j', 'l', 'm', 'o', 'p'] f ['a', 'b', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'n', 'o', 'p'] g ['a', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k', 'l', 'm', 'n', 'o'] h ['b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'k', 'l', 'm', 'n', 'p'] i ['a', 'c', 'd', 'e', 'f', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o'] j ['b', 'c', 'd', 'e', 'f', 'g', 'i', 'j', 'k', 'l', 'm', 'n', 'p'] k ['a', 'b', 'c', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'o', 'p'] l ['a', 'b', 'd', 'e', 'g', 'h', 'i', 'j', 'k', 'l', 'n', 'o', 'p'] m ['a', 'b', 'd', 'e', 'g', 'h', 'i', 'j', 'k', 'm', 'n', 'o', 'p'] n ['a', 'b', 'c', 'f', 'g', 'h', 'i', 'j', 'l', 'm', 'n', 'o', 'p'] o ['b', 'c', 'd', 'e', 'f', 'g', 'i', 'k', 'l', 'm', 'n', 'o', 'p'] p ['a', 'c', 'd', 'e', 'f', 'h', 'j', 'k', 'l', 'm', 'n', 'o', 'p'] Draw for week 5 ['a', 'h', 'j', 'o'] ['b', 'g', 'i', 'p'] ['c', 'f', 'l', 'm'] ['d', 'e', 'k', 'n'] a ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p'] b ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p'] c ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p'] d ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p'] e ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p'] f ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p'] g ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p'] h ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p'] i ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p'] j ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p'] k ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p'] l ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p'] m ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p'] n ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p'] o ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p'] p ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p'] Process finished with exit code 0 Is this what we're trying to achieve? -- Regards, =dn _______________________________________________ Tutor maillist - Tutor at python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor From breamoreboy at gmail.com Wed May 25 13:35:38 2022 From: breamoreboy at gmail.com (Mark Lawrence) Date: Wed, 25 May 2022 18:35:38 +0100 Subject: [Tutor] problem solving with lists: preliminary solution In-Reply-To: <000001d8705b$8acbb350$a06319f0$@bluewin.ch> References: <000001d8705b$8acbb350$a06319f0$@bluewin.ch> Message-ID: > > Which all serves to make me think that I have yet to grasp the full-measure > of the problem! > Yes. You've been told that on multiple occasions. So why do you keep bothering us? -- My fellow Pythonistas, ask not what our language can do for you, ask what you can do for our language. Mark Lawrence From PythonList at DancesWithMice.info Wed May 25 16:01:56 2022 From: PythonList at DancesWithMice.info (dn) Date: Thu, 26 May 2022 08:01:56 +1200 Subject: [Tutor] problem solving with lists: preliminary solution In-Reply-To: <000001d8705b$8acbb350$a06319f0$@bluewin.ch> References: <000001d8705b$8acbb350$a06319f0$@bluewin.ch> Message-ID: <542f45fa-5af2-7676-d53b-87eb9bab0ff0@DancesWithMice.info> Hi Marcus, This is a bit of 'blast from the past' - and I haven't gone 'back' to look at our previous correspondence/this message hasn't "threaded". May I offer a few criticisms and suggestions:- On 26/05/2022 05.19, marcus.luetolf at bluewin.ch wrote: > ....sorry, forgott correct e_mail address..... > > Hello Experts, hello dn, and not forgetting @wlfraed who mentioned university research papers dealing with the intricacies (and insolubles) of the "SGP". Did you try following-up on any of those? > In resuming my task to write code for a special constellation of the > "SocialGolferProblem" (SGP) : > number_of_days (number_of_weeks) = 5 > number_of_flights (number_of_groupings) = 4 > seize of flight (players_per_grouping) = 4 Criticism: although each of these terms is perfectly understandable, and easily converted into a 'readable' pythonic identifier, later the code uses "n" (for example) - which of the two values commencing "*n*umber_" is it? > and given the solution below (draws for week 1 through 5) I've come up with > a code of which I only post part of it (for it gets to big): > for day 1( hardcoded) and for day 2 (as a function to be used through day > 5). The word "hardcoded" immediately stopped me in my tracks! The whole point of using the computer is to find 'repetition' and have the machine/software save us from such boredom (or nit-picking detail in which we might make an error/become bored). That said, may I suggest that you grab a whiteboard/blackboard, or a convenient wall and a bunch of Post-It notes, and try to solve the problem manually - first for week-one (which is largely trivial), but then recording the 'history' and moving-on to the extra decision-layer for week-two. If your brain doesn't go 'click'*, go on to deal with week-three and see how the algorithm develops... * keeping my 'pocket handkerchief' lawn tidy doesn't require 'heavy machinery', but after many years of service my little electric mower 'died'. I bought a new Bosch model which needed to be partly assembled from the box. The accompanying manual featured explanations in dozens of languages. However, the (single/all-language) diagram showing where the back-wheels were to be joined to the axles featured (only) the English explanation: "Click". Perhaps other languages do use the word (?spelling), but the term "going click in your mind" has long been used for the idea explained in today's idiom as an "ahah! moment". > The crucial part of my functions for day 2 to 5 are the conditional > statements. These conditional statements do not follow a consistent pattern. > This inconsistency casts some doubt on the effectiveness of my code below > and I'd appreciate critical comments. > ... > a_flight_day_1 = [] > b_flight_day_1 = [] > c_flight_day_1 = [] ... > history = {'a':[], > 'b':[],'c':[],'d':[],'e':[],'f':[],'g':[],'h':[],'i':[],'j':[],'k':[],'l':[],'m':[],'n':[],'o':[],'p':[]} ... Following-on from talking about looping (repetition), yes we need to use multiple conditional expressions to ensure that history is taken into account (consistently). The other 'side' of both of these code-constructs is the data-construct. Code-loops require data-collections! The hard-coded "a" and "day_1" made me shudder. (not a pretty sight - the code, nor me shuddering!) Would you benefit from spending a little time, putting aside the SGP for a moment, and looking at a tutorial on "nesting" lists (and dictionaries) in Python? Again, the above-mentioned 'whiteboard' exercise may help 'reveal' the patterns in the data, as well as identifying an algorithm. Sadly, the 'hard-coded' parts may 'help' sort-out week-one, but (IMHO) have made things impossibly-difficult to proceed into week-two (etc). (and I'm back to mentioning that I haven't searched for our previous discussions - specifically whether we talked-about a data-construct for 'history', and also to referring-back to the 'whiteboard' suggestion) We were warned! The SGP can be made to work for this particular combination of weeks/flights/players. Which gives credence to the first-thought: "it looks so easy". However, the wider problem is more complex than one at-first imagines! This is the reason why 'combinatorial problems' are so interesting. Did I say "interesting"? Perhaps "frustrating" and/or "frustratingly difficult to solve" - or even: 'cannot (always) be solved'! This is no 'little kitten' or some old piece of rope, you have "a tiger by the tail"... -- Regards, =dn From PythonList at DancesWithMice.info Wed May 25 18:39:57 2022 From: PythonList at DancesWithMice.info (dn) Date: Thu, 26 May 2022 10:39:57 +1200 Subject: [Tutor] problem solving with lists: preliminary solution In-Reply-To: <542f45fa-5af2-7676-d53b-87eb9bab0ff0@DancesWithMice.info> References: <000001d8705b$8acbb350$a06319f0$@bluewin.ch> <542f45fa-5af2-7676-d53b-87eb9bab0ff0@DancesWithMice.info> Message-ID: Marcus, (with apologies for apparently 'answering' my own post) In one of those serendipitous quirks of life, shortly after posting 'here', someone walked-in and asked for help solving a (wait for it...) 'combinatorial problem'. So, with our discussion fresh in-mind, I suggested to him that we stand around a white-board and puzzle-through*. -- Regards, =dn From outlook_A315F2BB3FCE4786 at outlook.com Sat May 28 23:53:50 2022 From: outlook_A315F2BB3FCE4786 at outlook.com (Piyush Tomar) Date: Sun, 29 May 2022 03:53:50 +0000 Subject: [Tutor] Python Learner - Piyush Message-ID: Hi, I am looking forward to learn Python and I am super excited to join this community. Thanks Piyush Sent from Mail for Windows From __peter__ at web.de Sun May 29 12:02:30 2022 From: __peter__ at web.de (Peter Otten) Date: Sun, 29 May 2022 18:02:30 +0200 Subject: [Tutor] Object destruction In-Reply-To: References: Message-ID: <93fb1d90-cb7b-7e28-f001-af1fbb075f4f@web.de> On 24/05/2022 15:27, Dimitar Ivanov wrote: > Hi all, Hi Dimitar! > > I'm trying to come up with a (working) design of tracking an object > throughout its lifecycle but I'm unable to find quite what I'm looking for, > so I hope you folks will be able to give me some tips. > > I have an object that is being created and I want to "trace" that object in > a separate static class that other threads and objects will be able to > access if necessary: > > class TestClass: > > def __init__(self, name): > self.name = name > self._finalizer = weakref.finalize(self, self.finalize) A bound method keeps a reference to an instance of the class. Therefore this instance is never garbage-collected unless the method object is released. In your case this method object is kept alive until the instance is released... > > def do_stuff(self): > print(f"Object {self.name} doing stuff") > Tracer.trace(self.name) > time.sleep(5) > > def finalize(self): > print(f"Entered finalize method for object {self.name}") > Tracer.untrace(self.name) An easy fix would be to turn the finalize() method into a function: def finalize(name): print("finalizing", name) Tracer.untrace(name) class TestClass: def __init__(self, name): self.name = name self._finalizer = weakref.finalize(self, lambda: finalize(name)) def do_stuff(self): print(f"Object {self.name} doing stuff") Tracer.trace(self.name) time.sleep(5) > Here, I have the static object that "traces" those objects: > > class Tracer: > > traced_objects = [] > > @staticmethod > def trace(some_object): > Tracer.traced_objects.append(some_object) > > @staticmethod > def untrace(some_object): > Tracer.traced_objects.remove(some_object) > > And here's my main method where I test creating the objects, kicking off > their do_stuff methods in a thread and then deleting them and checking if > they've been removed from the traced_objects list in the Tracer class: > > if __name__ == '__main__': > objectOne = TestClass("Object1") > objectTwo = TestClass("Object2") > thrd1 = Thread(target=objectOne.do_stuff) > thrd2 = Thread(target=objectTwo.do_stuff) > thrd1.start() > thrd2.start() > thrd1.join() > thrd2.join() > del objectOne > del objectTwo > print("Threads are done, checking Tracer's dict") > print(f"Tracer's dict: {Tracer.traced_objects}") > > It seems like the Finalizer is only kicking off the objects' finalize > methods once the program exits, which, if I'm reading the documentation > right, is the correct behaviour; however, I need that finalize method > kicked off as soon as any reference to those objects is removed. Can I > achieve that in any way? > > Thanks a lot in advance and please, do let me know if my explanation is > vague and/or unclear! > > Regards, > Dimitar > _______________________________________________ > Tutor maillist - Tutor at python.org > To unsubscribe or change subscription options: > https://mail.python.org/mailman/listinfo/tutor > From cs at cskk.id.au Sun May 29 21:26:49 2022 From: cs at cskk.id.au (Cameron Simpson) Date: Mon, 30 May 2022 11:26:49 +1000 Subject: [Tutor] Python Learner - Piyush In-Reply-To: References: Message-ID: On 29May2022 03:53, Piyush Tomar wrote: >I am looking forward to learn Python and I am super excited to join >this community. Welcome! - Cameron Simpson