From robertvstepp at gmail.com  Wed Jan  1 13:30:13 2020
From: robertvstepp at gmail.com (boB Stepp)
Date: Wed, 1 Jan 2020 12:30:13 -0600
Subject: [Tutor] How to refactor a simple,
 straightforward script into a "proper" program?
Message-ID: <CANDiX9JjoXfpEBvnmsJWrAyumLvsKUN39VcaTvoG05-Cnm1DHA@mail.gmail.com>

In a November thread I started, "How to type annotate complex
dictionary containing lambdas?"
(https://mail.python.org/pipermail/tutor/2019-November/115726.html), I
justifiably received multiple critiques on what an awful dictionary I
had created.  Eventually I responded that the program that that
dictionary was from (and other dictionaries like it) came from using
what originally was a very simple script which over time became rather
complex and gnarly from using it to try out different things I was
learning about over time.  At the time I started the aforementioned
thread my learning topic of the day was type annotations, and, of
course, I used my go to "simple" (Hah!) script to play around with
that concept.  So perhaps in line with D. L. Neil's "Friday Finking"
series on the main Python list, I would like to start a discussion on
how to properly transform a simple Python script into a
battle-hardened program suitable for release to the general public.

Below is my best reconstruction of what I probably originally wrote
once upon a time:

<version1.py => A simple throwaway script>
============================================================================
#!/usr/bin/env python3
"""Calculate the number of pages per day needed to read a book by a
given date."""

from datetime import date

COUNT_TODAY = 1

num_pages_in_book = int(input("How many pages are there in your book?  "))
num_pages_read = int(input("How many pages have you read?  "))
today_date = date.today()
goal_date = date.fromisoformat(
    input("What is your date to finish the book (yyyy-mm-dd)?  ")
)

days_to_goal = (goal_date - today_date).days
pages_per_day = (num_pages_in_book - num_pages_read) / (days_to_goal +
COUNT_TODAY)
print(
    "\nYou must read",
    pages_per_day,
    "pages each day (starting today) to reach your goal.",
)
============================================================================

As this script is I believe it to be easy to read and understand by an
outside reader.  For my original purposes it quickly gave me what I
wanted out of it.  But if I wanted to "give it away" to the general
public there are some things that bother me:

1)  There is no error checking.  If someone deliberately or mistakenly
enters incorrect input the program will terminate with a ValueError
exception.
2)  There are no checks for logic errors.  For instance, a person
could enter a goal date that is prior to today or enter a date in the
future that falls well beyond any human's possible lifespan (with
current technology).
3)  There is no formatting of output.  It is possible to generate
float output with many decimal places, something most users would not
want to see.  And does it make any sense to have non-integral numbers
of pages anyway?
4)  There are duplicated patterns of input in the code as is.  Surely
that duplication could be removed?
5)  A minor, but bothersome quibble:  If the reader need only read one
page per day, the program would display an annoying "... 1.0 pages
...", which is grammatically incorrect.
6)  There are no tests, which makes it more difficult to grow/maintain
the program in the future.
7)  The user must restart the program each time he/she wishes to try
out different goal dates.
8)  [Optional] There are no type annotations.

So I am curious as to how you pros would approach the refactoring
process.  I think that such a demonstration would surely be
educational for myself, and hopefully others.  But I do realize that
everyone does their thing voluntarily and my thoughts might not align
with yours.  So I am *hoping* a few experts go along with this, but,
regardless, in typical boB fashion I will plow away and post my future
efforts to transform version1.py into something more robust.  Then
those that wish to can critique version2.py leading ultimately to
version-who-knows-what.py ...

Anyway, it seems like a useful New Year's exercise that might actually
be helpful.

HAPPY NEW YEAR TO YOU AND YOURS!!!

-- 
boB

From gogonegro at gmail.com  Wed Jan  1 11:20:08 2020
From: gogonegro at gmail.com (Robert Alexander)
Date: Wed, 1 Jan 2020 17:20:08 +0100
Subject: [Tutor] Setting thresholds in a compact way
Message-ID: <CADiDnXdTeR3vmB-n=8aWnpD11WKsFXQ0f5pnrnmdZhtNO5ZeLA@mail.gmail.com>

Dear friends,
First of all let me wish a great 2020 for all of you kind souls and seekers
of knowledge :)

I am trying to setup a varying time.sleep value (in house) depending on a
priorly determined threshold.

If threshold <= .9 AND > .8 then sleep should be 6 hours
if threshold <= 0.8 AND > .4 then sleep should be 4 hours
if threshold <= .4 AND > .1 then sleep should be 3 hours
if threshold <= .1 then sleep should be set to 1 hour

Instead of a complex/lengthy series of (nested?) if/ands based on the
above, I was wondering if I could declare a dictionary such as:

sleep_thresholds_hours = {.9:6, .8:4, .4:3, .1:1}

And then use some sort of single statement to set the sleep_time to the the
proper value.

Not even quite sure that using floats (albeit single decimal) as dictionary
keys will be ok.

Getting old and in 2020 even older and my brain fogged by too much food :)

Thanks in advance

From Richard at Damon-Family.org  Wed Jan  1 14:18:53 2020
From: Richard at Damon-Family.org (Richard Damon)
Date: Wed, 1 Jan 2020 14:18:53 -0500
Subject: [Tutor] Setting thresholds in a compact way
In-Reply-To: <CADiDnXdTeR3vmB-n=8aWnpD11WKsFXQ0f5pnrnmdZhtNO5ZeLA@mail.gmail.com>
References: <CADiDnXdTeR3vmB-n=8aWnpD11WKsFXQ0f5pnrnmdZhtNO5ZeLA@mail.gmail.com>
Message-ID: <d8a9a65a-f5df-0138-916d-0c613e637fa8@Damon-Family.org>

On 1/1/20 11:20 AM, Robert Alexander wrote:
> Dear friends,
> First of all let me wish a great 2020 for all of you kind souls and seekers
> of knowledge :)
>
> I am trying to setup a varying time.sleep value (in house) depending on a
> priorly determined threshold.
>
> If threshold <= .9 AND > .8 then sleep should be 6 hours
> if threshold <= 0.8 AND > .4 then sleep should be 4 hours
> if threshold <= .4 AND > .1 then sleep should be 3 hours
> if threshold <= .1 then sleep should be set to 1 hour
>
> Instead of a complex/lengthy series of (nested?) if/ands based on the
> above, I was wondering if I could declare a dictionary such as:
>
> sleep_thresholds_hours = {.9:6, .8:4, .4:3, .1:1}
>
> And then use some sort of single statement to set the sleep_time to the the
> proper value.
>
> Not even quite sure that using floats (albeit single decimal) as dictionary
> keys will be ok.
>
> Getting old and in 2020 even older and my brain fogged by too much food :)
>
> Thanks in advance

The straight forward way to state that (since you ranges are all 
consecutive) would be

if threshold <= 0.1: sleep(1 hour)

elif threshold <= 0.4: sleep (3 hour)

elif threshold <= 0.8: sleep(4 hours)

elif threshold <= 0.9: sleep(6 hours)

else: # what you want to do otherwise.


You can also simplify your if statements (and get the right syntax with

if 0.8 < threshold <= 0.9: sleep 6 hours

if 0.4 < threshold <= 0.8: sleep 4 hours

if 0.1 < threshold <= 0.4: sleep 3 hours

if threshold <= 0.1: sleep 1 hour


The dictionary is an interesting idea, but I don't know of a built in 
way do the sort of lookup you are suggesting. Dictionaries are designed 
to optimize looking up exact values quickly, not find the next value.


-- 
Richard Damon


From robertvstepp at gmail.com  Wed Jan  1 14:21:28 2020
From: robertvstepp at gmail.com (boB Stepp)
Date: Wed, 1 Jan 2020 13:21:28 -0600
Subject: [Tutor] Setting thresholds in a compact way
In-Reply-To: <CADiDnXdTeR3vmB-n=8aWnpD11WKsFXQ0f5pnrnmdZhtNO5ZeLA@mail.gmail.com>
References: <CADiDnXdTeR3vmB-n=8aWnpD11WKsFXQ0f5pnrnmdZhtNO5ZeLA@mail.gmail.com>
Message-ID: <CANDiX9+heVzOiYgf+BaHUUvFYRsgg=cUAJ-WfeYz0nv45=S4GQ@mail.gmail.com>

Greetings!

On Wed, Jan 1, 2020 at 12:47 PM Robert Alexander <gogonegro at gmail.com> wrote:

> I am trying to setup a varying time.sleep value (in house) depending on a
> priorly determined threshold.
>
> If threshold <= .9 AND > .8 then sleep should be 6 hours
> if threshold <= 0.8 AND > .4 then sleep should be 4 hours
> if threshold <= .4 AND > .1 then sleep should be 3 hours
> if threshold <= .1 then sleep should be set to 1 hour

Python allows you to write a somewhat simpler if condition instead of
using "and":

if 0.8 < threshold <= 0.9:
    <your code block here>
etc.

Are you aware of Python's if - elif - else structure?  In your case it could be:

if 0.8 < threshold <= 0.9:
    <code block 1>
elif 0.4 < threshold <= 0.8:
    <code block 2>
elif 0.1 < threshold <= 0.4:
    <code block 3>
elif threshold <= 0.1:  # What about negative values of threshold?
    <code block 4>
else:
    <Throw an exception or something similar for all other possible values?>

I'll leave your other questions to someone else.

HAPPY NEW YEAR TO YOU AND YOURS!!!

-- 
boB

From mats at wichmann.us  Wed Jan  1 15:08:06 2020
From: mats at wichmann.us (Mats Wichmann)
Date: Wed, 1 Jan 2020 13:08:06 -0700
Subject: [Tutor] Setting thresholds in a compact way
In-Reply-To: <CADiDnXdTeR3vmB-n=8aWnpD11WKsFXQ0f5pnrnmdZhtNO5ZeLA@mail.gmail.com>
References: <CADiDnXdTeR3vmB-n=8aWnpD11WKsFXQ0f5pnrnmdZhtNO5ZeLA@mail.gmail.com>
Message-ID: <d1eacbf9-287d-44f9-706f-8418b7ed5849@wichmann.us>

On 1/1/20 9:20 AM, Robert Alexander wrote:

> Not even quite sure that using floats (albeit single decimal) as dictionary
> keys will be ok.

It's not ideal - it isn't illegal, but comparison of binary floats can 
be trickier than you expect (not just in Python!), and because 
dictionary lookups are based on hashing the key, you can get interesting 
problems.

It's fairly easy to mitigate that problem - round your threshold value, 
or use decimal floats, or use the old trick of multiplying by 10 and 
calling it an int - that is, for 0.4, use 4, etc.

dictionaries, however, aren't really that natural a fit for this kind of 
thing. They're perfect when you're doing an exact match - give me the 
value for key "foo".  But you want find where you fall in ranges instead.

As others have said, I think the if/elif sequence would be fine for 
this, although it will look ugly if you have too many different buckets.


From robertvstepp at gmail.com  Wed Jan  1 17:27:57 2020
From: robertvstepp at gmail.com (boB Stepp)
Date: Wed, 1 Jan 2020 16:27:57 -0600
Subject: [Tutor] Setting thresholds in a compact way
In-Reply-To: <d1eacbf9-287d-44f9-706f-8418b7ed5849@wichmann.us>
References: <CADiDnXdTeR3vmB-n=8aWnpD11WKsFXQ0f5pnrnmdZhtNO5ZeLA@mail.gmail.com>
 <d1eacbf9-287d-44f9-706f-8418b7ed5849@wichmann.us>
Message-ID: <CANDiX9+5fBoOBPjg3H3Y5_UWPXu0HsvnqhGpZMdtkrv3C8dQ_A@mail.gmail.com>

On Wed, Jan 1, 2020 at 2:08 PM Mats Wichmann <mats at wichmann.us> wrote:

> As others have said, I think the if/elif sequence would be fine for
> this, although it will look ugly if you have too many different buckets.

Is there any sensible/better thing to do if one is stuck with a long
sequence of "if" conditions?  I seem to recall some discussion on this
topic on the main list, but do not recollect anything gaining a
consensus as to best practice.

HAPPY NEW YEAR TO YOU AND YOURS!!!

-- 
boB

From Richard at Damon-Family.org  Wed Jan  1 17:45:54 2020
From: Richard at Damon-Family.org (Richard Damon)
Date: Wed, 1 Jan 2020 17:45:54 -0500
Subject: [Tutor] Setting thresholds in a compact way
In-Reply-To: <CANDiX9+5fBoOBPjg3H3Y5_UWPXu0HsvnqhGpZMdtkrv3C8dQ_A@mail.gmail.com>
References: <CADiDnXdTeR3vmB-n=8aWnpD11WKsFXQ0f5pnrnmdZhtNO5ZeLA@mail.gmail.com>
 <d1eacbf9-287d-44f9-706f-8418b7ed5849@wichmann.us>
 <CANDiX9+5fBoOBPjg3H3Y5_UWPXu0HsvnqhGpZMdtkrv3C8dQ_A@mail.gmail.com>
Message-ID: <8f282d5a-0c64-8d53-c140-61af0f6cad66@Damon-Family.org>

On 1/1/20 5:27 PM, boB Stepp wrote:
> On Wed, Jan 1, 2020 at 2:08 PM Mats Wichmann <mats at wichmann.us> wrote:
>
>> As others have said, I think the if/elif sequence would be fine for
>> this, although it will look ugly if you have too many different buckets.
> Is there any sensible/better thing to do if one is stuck with a long
> sequence of "if" conditions?  I seem to recall some discussion on this
> topic on the main list, but do not recollect anything gaining a
> consensus as to best practice.
>
> HAPPY NEW YEAR TO YOU AND YOURS!!!
>
IF you DO have a very long list, or otherwise want a data driven design, 
you could build a list of tuples, the tuples specifying the range and 
value, and search that list for the entry you want. If you build the 
list in a sorted order, you could binary search the list, and/or make it 
just hold the upper bounds.

-- 
Richard Damon


From wpdickey at usc.edu  Wed Jan  1 18:22:22 2020
From: wpdickey at usc.edu (William Dickey)
Date: Wed, 1 Jan 2020 15:22:22 -0800
Subject: [Tutor] Beginning String Problems
Message-ID: <CANv814=9YGOE1Na+kvFzfVeO44OYXbUG+QyOdjgw6qej_Kiv-A@mail.gmail.com>

I am learning Python via an online video "Beginning Python" by William
Fiset. I am at the end of chapter 2 and I am supposed to be inputting a
string that has an output of a persons full name in  this order *First M.
Last*, but when I copied what he was doing it is not working. Here is what
I input:

first_name = str(input("Please enter your first name: "))
middle_name = str(input("Please enter your middle name: "))
last_name = str(input("Please enter your last name: "))

first_name = first_name.capitalize()
middle_name = middle_name.capitalize()
last_name = last_name.capitalize()

name_format = "{first} {middle:.1s} {last}"
print(name_format.format(first=first_name, middle=middle_name,
last=last_name))

and here is what I get when I open it in the command line

I enter the file location and I get:
Please enter your first name:

I enter william and I get this error:

Traceback (most recent call):
    File "C:\xxx\xxx\xxx\xxx", line 3, in <module>
       first_name = str(input("Please enter your first name: "))
    File "<string>", line 1, in <module>
NameError: name 'william' is not defined

I am using Windows 10 64 bit, Atom text editor, Python 3.4.

Thank you
William

From PyTutor at danceswithmice.info  Wed Jan  1 19:19:19 2020
From: PyTutor at danceswithmice.info (DL Neil)
Date: Thu, 2 Jan 2020 13:19:19 +1300
Subject: [Tutor] How to refactor a simple,
 straightforward script into a "proper" program?
In-Reply-To: <CANDiX9JjoXfpEBvnmsJWrAyumLvsKUN39VcaTvoG05-Cnm1DHA@mail.gmail.com>
References: <CANDiX9JjoXfpEBvnmsJWrAyumLvsKUN39VcaTvoG05-Cnm1DHA@mail.gmail.com>
Message-ID: <45f1a074-d8bc-ec13-9757-4686ee60462d@DancesWithMice.info>

Echo: Best New Year wishes to you and yours.


Surprise: I run a series? OK, yes it must be true.
On-line it is usually an extension of discussions, I or A.N.Other has 
provoked over-the-tea-cups/during a tea/coffee/meal break, which has 
become something of a Friday tradition amongst one of the teams with 
which I often work. It is a mentoring program(me) - a training 
opportunity for 'master' level programmers and a learning-opportunity 
for 'apprentices', and often, 'journeymen'.

(all due apologies...)


On 2/01/20 7:30 AM, boB Stepp wrote:
> In a November thread I started, "How to type annotate complex
> dictionary containing lambdas?"
> (https://mail.python.org/pipermail/tutor/2019-November/115726.html), I
> justifiably received multiple critiques on what an awful dictionary I
> had created.  Eventually I responded that the program that that
> dictionary was from (and other dictionaries like it) came from using
> what originally was a very simple script which over time became rather
> complex and gnarly from using it to try out different things I was
> learning about over time.  At the time I started the aforementioned
> thread my learning topic of the day was type annotations, and, of
> course, I used my go to "simple" (Hah!) script to play around with
> that concept.  So perhaps in line with D. L. Neil's "Friday Finking"
> series on the main Python list, I would like to start a discussion on
> how to properly transform a simple Python script into a
> battle-hardened program suitable for release to the general public.
...

> So I am curious as to how you pros would approach the refactoring
> process.  I think that such a demonstration would surely be
> educational for myself, and hopefully others.  But I do realize that
> everyone does their thing voluntarily and my thoughts might not align
> with yours.  So I am *hoping* a few experts go along with this, but,
> regardless, in typical boB fashion I will plow away and post my future
> efforts to transform version1.py into something more robust.  Then
> those that wish to can critique version2.py leading ultimately to
> version-who-knows-what.py ...
> 
> Anyway, it seems like a useful New Year's exercise that might actually
> be helpful.
> 
> HAPPY NEW YEAR TO YOU AND YOURS!!!


Why did I cut-out the code and the suggested improvements? Because the 
reason why many of us are reluctant to "maintain" or "improve" 
someone-else's code is an anxiety that if we fail to understand every 
nuance of thinking that went into the original author's work, we will 
introduce errors!

Indeed, any number of programming 'management' books (or chapters in 
'advanced' texts) will recount how programming (dept) productivity 
declines with the age of a (any) system. The reason is not merely the 
lethargy or reluctance devs have for maintenance work, but the reality 
of the system's growing complexity requiring every 'change' to be the 
culmination of an every-growing effort to investigate any 'corner' of 
the system which may contribute input or require output from the code in 
question! Even looking at this single routine, not only will the 
code-complexity creep upwards (as described, above), but 'just a little 
change' and 'quick fix' type approaches lead to such ghastly artifacts 
becoming common-place!


Accordingly, should we pay any regard to 'the rest', before completing:

> 6)  There are no tests, which makes it more difficult to grow/maintain
> the program in the future.


I've just re-read an interesting observation of the collection of tests 
one might build-up, as a system grows - a challenging question to ponder:

- if the code and all other documentation of a program/system were 
'lost', could you?should you, be able to reconstruct the whole from the 
test-set alone?


I am currently working on code which aims to re-use other classes. There 
are three different data-structures which may be used as input, from 
basic strings, through PSL class, to a locally-coded data-object; the 
consideration then becomes: were all the inputs provided or do 
(different for the various sub-classes) defaults apply; then there are 
all the different real-world combinations which the data represents, eg 
does the transaction currently 'exist' or is it hypothetical at this 
point; and they're only the first three considerations which generate 
permutations or combinations!

During the task, I have found that the new code has failed because I 
didn't adequately code around my own tests (TDD's intent), but also two 
further conditions:

1 my assumptions about how the underlying classes work were 
incomplete/faulty - and thus my 'new code' was inadequate, and

2 that when certain things didn't work, it was a fault in the provided 
classes - apparently a combination of factors they did not anticipate, 
and in at least one case, had no test to reveal (but my tests of my code 
(unintentionally) did).


Whilst the latter was frustrating (which is one of the points I'm 
making), the advantage of being given not just the code (classes, etc) 
for re-use, but the tests to verify that code (and consequently the 
superstructure I was building 'above' it) have been an enormous 
advantage - had I needed to 'read the code' with no further help, 
perhaps I would have thrown it out and 're-invented the wheel'!

(which decision, strangely enough, has justified many an (expensive!) 
system-rewrite project!)
-- 
Regards =dn

From robertvstepp at gmail.com  Wed Jan  1 20:01:42 2020
From: robertvstepp at gmail.com (boB Stepp)
Date: Wed, 1 Jan 2020 19:01:42 -0600
Subject: [Tutor] Beginning String Problems
In-Reply-To: <CANv814=9YGOE1Na+kvFzfVeO44OYXbUG+QyOdjgw6qej_Kiv-A@mail.gmail.com>
References: <CANv814=9YGOE1Na+kvFzfVeO44OYXbUG+QyOdjgw6qej_Kiv-A@mail.gmail.com>
Message-ID: <CANDiX9KyVYVBUv0B5VEy1tvhr4WN9QHeZD3v-cQazSN3JkuGZA@mail.gmail.com>

Greetings!

On Wed, Jan 1, 2020 at 6:15 PM William Dickey <wpdickey at usc.edu> wrote:
>
> I am learning Python via an online video "Beginning Python" by William
> Fiset. I am at the end of chapter 2 and I am supposed to be inputting a
> string that has an output of a persons full name in  this order *First M.
> Last*, but when I copied what he was doing it is not working. Here is what
> I input:
>
> first_name = str(input("Please enter your first name: "))
> middle_name = str(input("Please enter your middle name: "))
> last_name = str(input("Please enter your last name: "))

N.B.:  Using str() on the above 3 lines is unnecessary as input()
always returns a string from the user's input.

> first_name = first_name.capitalize()
> middle_name = middle_name.capitalize()
> last_name = last_name.capitalize()
>
> name_format = "{first} {middle:.1s} {last}"
> print(name_format.format(first=first_name, middle=middle_name,
> last=last_name))
>
> and here is what I get when I open it in the command line
>
> I enter the file location and I get:
> Please enter your first name:
>
> I enter william and I get this error:
>
> Traceback (most recent call):
>     File "C:\xxx\xxx\xxx\xxx", line 3, in <module>
>        first_name = str(input("Please enter your first name: "))
>     File "<string>", line 1, in <module>
> NameError: name 'william' is not defined
>
> I am using Windows 10 64 bit, Atom text editor, Python 3.4.

I am just a hobbyist programmer.  But when I copy and pasted your code
as given in your email into a file and then ran it in the terminal
(I'm on Linux, using Python 3.7.5) everything worked well:

bob at Dream-Machine1:~/Projects/Tutor_Help$ python3 ./test.py
Please enter your first name: boB
Please enter your middle name: Vincent
Please enter your last name: Stepp
Bob V Stepp

So I am puzzled.  Are you certain that you do not have your name
"william" written on the top line of your Python file?  If yes, then
Python will see that as an undefined variable name, since you wouldn't
have assigned anything to it.  That is my best guess anyway.

BTW, for a first time poster I feel you did a rather good job asking
your question!

HAPPY NEW YEAR TO YOU AND YOURS!!!
-- 
boB

From mats at wichmann.us  Wed Jan  1 20:06:17 2020
From: mats at wichmann.us (Mats Wichmann)
Date: Wed, 1 Jan 2020 18:06:17 -0700
Subject: [Tutor] Beginning String Problems
In-Reply-To: <CANDiX9KyVYVBUv0B5VEy1tvhr4WN9QHeZD3v-cQazSN3JkuGZA@mail.gmail.com>
References: <CANv814=9YGOE1Na+kvFzfVeO44OYXbUG+QyOdjgw6qej_Kiv-A@mail.gmail.com>
 <CANDiX9KyVYVBUv0B5VEy1tvhr4WN9QHeZD3v-cQazSN3JkuGZA@mail.gmail.com>
Message-ID: <b1996a4b-ae50-cf87-f15b-60a260ad7f72@wichmann.us>

On 1/1/20 6:01 PM, boB Stepp wrote:
> Greetings!
> 
> On Wed, Jan 1, 2020 at 6:15 PM William Dickey <wpdickey at usc.edu> wrote:

>> I am using Windows 10 64 bit, Atom text editor, Python 3.4.

this has *nothing* to do with your issue, which I can't think about 
because I have to finish putting dinner on the table :)   but... don't 
use 3.4.  It's quite old, going on six years if I recall.  3.8 is the 
current release.  If your material says "install 3.4", you should be 
able to safely use 3.8 in all but some real edge cases that no course 
would likely ever touch (the alternative is not true: something written 
for 3.8 might hit more issues using 3.4).

> 
> I am just a hobbyist programmer.  But when I copy and pasted your code
> as given in your email into a file and then ran it in the terminal
> (I'm on Linux, using Python 3.7.5) everything worked well:
> 
> bob at Dream-Machine1:~/Projects/Tutor_Help$ python3 ./test.py
> Please enter your first name: boB
> Please enter your middle name: Vincent
> Please enter your last name: Stepp
> Bob V Stepp
> 
> So I am puzzled.  Are you certain that you do not have your name
> "william" written on the top line of your Python file?  If yes, then
> Python will see that as an undefined variable name, since you wouldn't
> have assigned anything to it.  That is my best guess anyway.
> 
> BTW, for a first time poster I feel you did a rather good job asking
> your question!
> 
> HAPPY NEW YEAR TO YOU AND YOURS!!!
> 


From alan.gauld at yahoo.co.uk  Wed Jan  1 20:07:42 2020
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Thu, 2 Jan 2020 01:07:42 +0000
Subject: [Tutor] Setting thresholds in a compact way
In-Reply-To: <CANDiX9+5fBoOBPjg3H3Y5_UWPXu0HsvnqhGpZMdtkrv3C8dQ_A@mail.gmail.com>
References: <CADiDnXdTeR3vmB-n=8aWnpD11WKsFXQ0f5pnrnmdZhtNO5ZeLA@mail.gmail.com>
 <d1eacbf9-287d-44f9-706f-8418b7ed5849@wichmann.us>
 <CANDiX9+5fBoOBPjg3H3Y5_UWPXu0HsvnqhGpZMdtkrv3C8dQ_A@mail.gmail.com>
Message-ID: <d420069b-473d-0e95-0e1a-994508e472ab@yahoo.co.uk>

On 01/01/2020 22:27, boB Stepp wrote:

> Is there any sensible/better thing to do if one is stuck with a long
> sequence of "if" conditions?  

Richard already suggested a sorted list of tuples, which is
usually the simplest option, although that carries the overhead
of a loop to test the list entries.

The other option is to use a sparse array where the values
are the functions to be called and the test values are the
indices into the array. (multiple indices potentially mapping
to the same code.)
However that requires that you can reduce your test values
to some kind of quantum value (possibly by multiplying
the float by 10,100 etc and then using rounding)

You can use a statically created array or build a class
that generates the required array from a set of input values.


-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos


From alan.gauld at yahoo.co.uk  Wed Jan  1 20:17:01 2020
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Thu, 2 Jan 2020 01:17:01 +0000
Subject: [Tutor] Beginning String Problems
In-Reply-To: <CANv814=9YGOE1Na+kvFzfVeO44OYXbUG+QyOdjgw6qej_Kiv-A@mail.gmail.com>
References: <CANv814=9YGOE1Na+kvFzfVeO44OYXbUG+QyOdjgw6qej_Kiv-A@mail.gmail.com>
Message-ID: <1527b498-92dc-90fb-ddfa-b2a7f27f6463@yahoo.co.uk>

On 01/01/2020 23:22, William Dickey wrote:

> first_name = str(input("Please enter your first name: "))

> I enter william and I get this error:
> 
> Traceback (most recent call):
>     File "C:\xxx\xxx\xxx\xxx", line 3, in <module>
>        first_name = str(input("Please enter your first name: "))
>     File "<string>", line 1, in <module>
> NameError: name 'william' is not defined
> 
> I am using Windows 10 64 bit, Atom text editor, Python 3.4.

How are you running the code?
The error you get is what I would expect if you were using Python v2.
If you are just typing

python script.py

Then you may be picking up a default v2 install of Python.
Try changing the command to

python3 script.py

There is also a tool called py.exe, which is supposed to help
with this kind of thing on Windows, but I've never used it
so don't know how it works...

-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos


From robertvstepp at gmail.com  Wed Jan  1 21:38:20 2020
From: robertvstepp at gmail.com (boB Stepp)
Date: Wed, 1 Jan 2020 20:38:20 -0600
Subject: [Tutor] How to refactor a simple,
 straightforward script into a "proper" program?
In-Reply-To: <CANDiX9JjoXfpEBvnmsJWrAyumLvsKUN39VcaTvoG05-Cnm1DHA@mail.gmail.com>
References: <CANDiX9JjoXfpEBvnmsJWrAyumLvsKUN39VcaTvoG05-Cnm1DHA@mail.gmail.com>
Message-ID: <CANDiX9+RsSys2QQ9QWowwg+zyt0Tu=L5suFzFaSJ9tcNgX573A@mail.gmail.com>

On Wed, Jan 1, 2020 at 12:30 PM boB Stepp <robertvstepp at gmail.com> wrote:
> <version1.py => A simple throwaway script>
> ============================================================================
> #!/usr/bin/env python3
> """Calculate the number of pages per day needed to read a book by a
> given date."""
>
> from datetime import date
>
> COUNT_TODAY = 1
>
> num_pages_in_book = int(input("How many pages are there in your book?  "))
> num_pages_read = int(input("How many pages have you read?  "))
> today_date = date.today()
> goal_date = date.fromisoformat(
>     input("What is your date to finish the book (yyyy-mm-dd)?  ")
> )
>
> days_to_goal = (goal_date - today_date).days
> pages_per_day = (num_pages_in_book - num_pages_read) / (days_to_goal +
> COUNT_TODAY)
> print(
>     "\nYou must read",
>     pages_per_day,
>     "pages each day (starting today) to reach your goal.",
> )
> ============================================================================
>
> As this script is I believe it to be easy to read and understand by an
> outside reader.  For my original purposes it quickly gave me what I
> wanted out of it.  But if I wanted to "give it away" to the general
> public there are some things that bother me:
>
> 1)  There is no error checking.  If someone deliberately or mistakenly
> enters incorrect input the program will terminate with a ValueError
> exception.
> 2)  There are no checks for logic errors.  For instance, a person
> could enter a goal date that is prior to today or enter a date in the
> future that falls well beyond any human's possible lifespan (with
> current technology).
> 3)  There is no formatting of output.  It is possible to generate
> float output with many decimal places, something most users would not
> want to see.  And does it make any sense to have non-integral numbers
> of pages anyway?
> 4)  There are duplicated patterns of input in the code as is.  Surely
> that duplication could be removed?
> 5)  A minor, but bothersome quibble:  If the reader need only read one
> page per day, the program would display an annoying "... 1.0 pages
> ...", which is grammatically incorrect.
> 6)  There are no tests, which makes it more difficult to grow/maintain
> the program in the future.
> 7)  The user must restart the program each time he/she wishes to try
> out different goal dates.
> 8)  [Optional] There are no type annotations.

OK, I have made some progress, but this has been for me a more
difficult exercise than I thought it would be.  I feel that in my
efforts to be DRY that I am coding as if I were wet behind my ears!
Anyway, here is what I currently have:

<version2.py => Not all goals accomplished -- yet.>
============================================================================
#!/usr/bin/env python3
"""Calculate the number of pages per day needed to read a book by a
given date."""

from datetime import date


def get_input(str_converter, msg):
    """Prompt user with a message and return user input with the
correct data type."""
    while True:
        try:
            return str_converter(input(msg))
        except ValueError:
            if str_converter == int:
                print("\nPlease enter a positive integer!")
            elif str_converter == date.fromisoformat:
                print("\nPlease enter a valid date in the following
format yyyy-mm-dd!")


def get_input_params():
    """Collect all needed input parameters."""
    str_converters = [int, int, date.fromisoformat]
    input_msgs = [
        "How many pages are there in your book?  ",
        "How many pages have you read?  ",
        "What is your date to finish the book (yyyy-mm-dd)?  ",
    ]
    num_pages_in_book, num_pages_read, goal_date = map(
        get_input, str_converters, input_msgs
    )
    days_to_goal = (goal_date - date.today()).days
    return num_pages_in_book, num_pages_read, days_to_goal


def calc_pages_per_day(num_pages_in_book, num_pages_read, days_to_goal):
    """Return number of pages to read each day to attain goal."""
    COUNT_TODAY = 1
    pages_per_day = (num_pages_in_book - num_pages_read) /
(days_to_goal + COUNT_TODAY)
    return pages_per_day


def main():
    """Run program and display results."""
    input_params = get_input_params()
    print(
        "\nYou must read",
        calc_pages_per_day(*input_params),
        "pages each day (starting today) to reach your goal.",
    )


if __name__ == "__main__":
    main()
============================================================================
I think I have removed all "perceived" duplication, but I had to
struggle to get to this point.  I have never used the map() function
before, but it was the only way I was able to avoid writing multiple
calls to get_input() as separate lines.

ValueErrors are now handled, but I don't have checks in place yet for
input that does not raise an unhandled exception, but would cause
erroneous results, such as negative numbers of days, in the past
dates, etc.

I *think* the code still reads reasonably well, but is not as
straightforward to understand as the original simple script.

I have not written tests yet (Bad boB!).  Nor have I addressed better
display formatting.

I still think that you guys would do something remarkably easier, so I
am awaiting your comments with bated breath.

HAPPY NEW YEAR TO YOU AND YOURS!!!

-- 
boB

From robertvstepp at gmail.com  Wed Jan  1 22:56:31 2020
From: robertvstepp at gmail.com (boB Stepp)
Date: Wed, 1 Jan 2020 21:56:31 -0600
Subject: [Tutor] How to refactor a simple,
 straightforward script into a "proper" program?
In-Reply-To: <45f1a074-d8bc-ec13-9757-4686ee60462d@DancesWithMice.info>
References: <CANDiX9JjoXfpEBvnmsJWrAyumLvsKUN39VcaTvoG05-Cnm1DHA@mail.gmail.com>
 <45f1a074-d8bc-ec13-9757-4686ee60462d@DancesWithMice.info>
Message-ID: <CANDiX9Kv=675fXb=it=tTh2hf+Nx4rTyD7bHS4St9UUizYtZDw@mail.gmail.com>

On Wed, Jan 1, 2020 at 6:19 PM DL Neil via Tutor <tutor at python.org> wrote:

> Why did I cut-out the code and the suggested improvements? Because the
> reason why many of us are reluctant to "maintain" or "improve"
> someone-else's code is an anxiety that if we fail to understand every
> nuance of thinking that went into the original author's work, we will
> introduce errors!

Methinks you giveth me too much credit for potential subtlety!  If
there are any "nuances" in the simple script I posted I am totally
oblivious to them!

[...]

> Accordingly, should we pay any regard to 'the rest', before completing:
>
> > 6)  There are no tests, which makes it more difficult to grow/maintain
> > the program in the future.

Aha!  You are holding me to a proper standard of coding expectations.
Alas, I am a mere hobbyist programmer with overly high aspirations who
routinely falls short of the lofty heights for which I strive
(SPLAT!).

> I've just re-read an interesting observation of the collection of tests
> one might build-up, as a system grows - a challenging question to ponder:
>
> - if the code and all other documentation of a program/system were
> 'lost', could you?should you, be able to reconstruct the whole from the
> test-set alone?

That is a very interesting question!  My initial reaction is no, but
the better the test suite the better the precise intent of the unseen
source code should be evident.

> I am currently working on code which aims to re-use other classes. There
> are three different data-structures which may be used as input, from
> basic strings, through PSL class, to a locally-coded data-object; the
> consideration then becomes: were all the inputs provided or do
> (different for the various sub-classes) defaults apply; then there are
> all the different real-world combinations which the data represents, eg
> does the transaction currently 'exist' or is it hypothetical at this
> point; and they're only the first three considerations which generate
> permutations or combinations!
>
> During the task, I have found that the new code has failed because I
> didn't adequately code around my own tests (TDD's intent), but also two
> further conditions:
>
> 1 my assumptions about how the underlying classes work were
> incomplete/faulty - and thus my 'new code' was inadequate, and
>
> 2 that when certain things didn't work, it was a fault in the provided
> classes - apparently a combination of factors they did not anticipate,
> and in at least one case, had no test to reveal (but my tests of my code
> (unintentionally) did).
>
>
> Whilst the latter was frustrating (which is one of the points I'm
> making), the advantage of being given not just the code (classes, etc)
> for re-use, but the tests to verify that code (and consequently the
> superstructure I was building 'above' it) have been an enormous
> advantage - had I needed to 'read the code' with no further help,
> perhaps I would have thrown it out and 're-invented the wheel'!
>
> (which decision, strangely enough, has justified many an (expensive!)
> system-rewrite project!)

Very interesting and thought provoking!


-- 
boB

From martin at linux-ip.net  Wed Jan  1 22:25:49 2020
From: martin at linux-ip.net (Martin A. Brown)
Date: Wed, 1 Jan 2020 19:25:49 -0800
Subject: [Tutor] Setting thresholds in a compact way
In-Reply-To: <CADiDnXdTeR3vmB-n=8aWnpD11WKsFXQ0f5pnrnmdZhtNO5ZeLA@mail.gmail.com>
References: <CADiDnXdTeR3vmB-n=8aWnpD11WKsFXQ0f5pnrnmdZhtNO5ZeLA@mail.gmail.com>
Message-ID: <alpine.LSU.2.20.2001011904270.3119@qnttre.jbaqresebt.arg>


Hello there,

>First of all let me wish a great 2020 for all of you kind souls and seekers
>of knowledge :)
>
>I am trying to setup a varying time.sleep value (in house) depending on a
>priorly determined threshold.
>
>If threshold <= .9 AND > .8 then sleep should be 6 hours
>if threshold <= 0.8 AND > .4 then sleep should be 4 hours
>if threshold <= .4 AND > .1 then sleep should be 3 hours
>if threshold <= .1 then sleep should be set to 1 hour
>
>Instead of a complex/lengthy series of (nested?) if/ands based on the
>above, I was wondering if I could declare a dictionary such as:
>
>sleep_thresholds_hours = {.9:6, .8:4, .4:3, .1:1}
>
>And then use some sort of single statement to set the sleep_time to the the
>proper value.

I saw the thread here and thought I'd spend a few minutes writing a few
functions that I think you might find helpful.

I like the suggestion Mats had about multiplying (or using some other
mathematical function) based on the input value.  But, that may not work in
your case.

I don't know how to apply the sparse array solution, suggested by Alan.

Here is an example or two, of possible utility.  If you are simply testing
ranges, you can always cover the search space in order (I start from the
"bottom"):

  def series_of_ifs(val):
      assert val == abs(val)  # -- ineffably positive
      if val <= 0.0: return None
      if val <= 0.1: return 1
      if val <= 0.4: return 3
      if val <= 0.8: return 4
      if val <= 0.9: return 6
      return None

  def data_driven_dict(val):
      assert val == abs(val)  # -- ineffably positive
      thresholds = [(0, None),
                    (0.1, 1),
                    (0.4, 3),
                    (0.8, 4),
                    (0.9, 6)
                    ]
      for threshold, result in thresholds:
          if val <= threshold:
              return result
      return None

Attached is a small script with these functions and a little testing 
code around them, that should allow you to test other ways of 
writing what you want.

If I knew I would want to monkey with the thresholds later, I'd use 
the data_driven_dict() solution.

Oh, and I didn't know what you wanted to do with values above 0.9, 
so I just chose to "return None" for those.  Also, given your sample 
data, I sort of assumed that your data were in the range of [0, 1), 
but if they are not, you may need to handle negative, as well.  I 
chose to assert, effectively terminating the program if the value is 
negative.

>Not even quite sure that using floats (albeit single decimal) as dictionary
>keys will be ok.

Yep!  This will be quite OK.  This may be a bit odd, but from a 
Python interpreter, I used something as a key, and then, for no 
specific reason, I assigned the value to the type of that value.  
Which had the amusing side effect that after I was done, I could 
write a little loop to assert that the key (retrieved in a loop) was 
actually of the type indicated.

  >>> d = dict()
  >>> d[17] = int
  >>> d[0.2] = float
  >>> d['hedgehog'] = str
  >>> d[('a', 'b', 7)] = tuple
  >>> d
  {17: <type 'int'>, ('a', 'b', 7): <type 'tuple'>, 0.2: <type 'float'>, 'hedgehog': <type 'str'>}
  >>> for k, v in d.items():
  ...     assert type(k) is v
  ... 
  >>> 

Best of luck,

-Martin

-- 
Martin A. Brown
http://linux-ip.net/

From PyTutor at DancesWithMice.info  Wed Jan  1 23:45:06 2020
From: PyTutor at DancesWithMice.info (David L Neil)
Date: Thu, 2 Jan 2020 17:45:06 +1300
Subject: [Tutor] Setting thresholds in a compact way
In-Reply-To: <CADiDnXdTeR3vmB-n=8aWnpD11WKsFXQ0f5pnrnmdZhtNO5ZeLA@mail.gmail.com>
References: <CADiDnXdTeR3vmB-n=8aWnpD11WKsFXQ0f5pnrnmdZhtNO5ZeLA@mail.gmail.com>
Message-ID: <67a7e2a2-23fe-17f7-5ca7-f389f079a5f8@DancesWithMice.info>

On 2/01/20 5:20 AM, Robert Alexander wrote:
> I am trying to setup a varying time.sleep value (in house) depending on a
> priorly determined threshold.
> 
> If threshold <= .9 AND > .8 then sleep should be 6 hours
> if threshold <= 0.8 AND > .4 then sleep should be 4 hours
> if threshold <= .4 AND > .1 then sleep should be 3 hours
> if threshold <= .1 then sleep should be set to 1 hour
> 
> Instead of a complex/lengthy series of (nested?) if/ands based on the
> above, I was wondering if I could declare a dictionary such as:
> 
> sleep_thresholds_hours = {.9:6, .8:4, .4:3, .1:1}
> 
> And then use some sort of single statement to set the sleep_time to the the
> proper value.
> 
> Not even quite sure that using floats (albeit single decimal) as dictionary
> keys will be ok.
> 
> Getting old and in 2020 even older and my brain fogged by too much food :)


A worked-solution...


Perhaps the seasonal influences explain it, but my (aged and decrepit) 
mind prefers to construct the problem in the reverse of how it is stated 
here...

Familiar with Cartesian coordinates and similar, to me the
x-axis/time-line starts at zero and goes 'up' to the right - and the 
y-axis starts at zero and goes 'up', um, as the y-value goes 'up'. That 
said, increasing/rising ranges seem easier (for me) to visualise:

<=	.1	1
	.4	3
	.8	4
	.9	6

(per 'excuses', below, am ignoring values of .9 or above, and similarly, 
numbers which may/not be 'below' the illustrated range)

Notice that (in mathematical terminology) we now have two (ordered) 
vectors (or 1-D matrices - or a single 2-D matrix, if you prefer. 
Yeah/nah, leave that until the end...)


Let's call the left column-vector "sleep_threshold", and the right, 
"sleep_hours". In Python:

sleep_threshold = [.1, .4, .8, .9]
sleep_hours = [ 1, 3, 4, 6 ]

Proving that we know what we're doing (maybe):-

for ptr in range( 0, len( sleep_threshold ) ):
      print( f"{ ptr } { sleep_threshold[ ptr ] } { sleep_hours[ ptr ] }" )

0	0.1	1
1	0.4	3
2	0.8	4
3	0.9	6

(apologies, email word-wrapping may produce a less-than pleasing 
graphological presentation. Similarly, when coding tests/"proofs", I've 
saved vertical-space by typing the entire for-loop on a single line - 
which many of my colleagues will (quite rightly) decry...)


Right, time to get to work! We could (per an earlier suggestion) try 
iterating through the "sleep_threshold" list, in order to select the 
corresponding "sleep_hours" element:

def sleepy( value ):
     for ptr in range( 0, len( sleep_threshold ) ):
             if value < sleep_threshold[ ptr ]:
                     print( f"{ value } results in sleep for { 
sleep_hours[ ptr ] }" )
                     break

Yes, a function *should* be named using a verb which describes what it 
does. I don't really know what you want it to do! (what a feeble excuse!)

Also, in this case, I'm only bothering to print the amount of sleep-time 
by way of illustration. Presumably, you will want such a function to 
return the sleep_hours value, or to execute the sleep right 
there-and-then...]


What more criticism? Yes! Why did I put this code inside a function?
1. Presumption on my part (of your needs)
2. Programming style - each separate action is to be carried-out by a 
single function/method ("separation of concerns")
3. For ease of testing!


Speaking of testing: how would we know if our magnificent-creation is 
working, without testing the code? Normally, I would use PyTest, but as 
this is being presented as a running-commentary, let's code some tests, 
in-line:-

test_data = [ .05, .1, .2, .6, .85 ]
for test_value in test_data: print( test_value )

0.05
0.1
0.2
0.6
0.85

Please note that I've only used one 'border' value (0.1) and ignored any 
concept of "outliers". (I'm going to claim simplicity. You can say 
'laziness'...).


Now we're ready to experiment:-

for test_value in test_data: sleepy( test_value )

0.05 results in sleep for 1
0.1 results in sleep for 3
0.2 results in sleep for 3
0.6 results in sleep for 4
0.85 results in sleep for 6

What brilliance! It's almost as good-looking as am I!


Did you notice the 'oops!' in the test-data output? (*and* in the code?)

A very common error when coding such a 'ladder', is the comparison. How 
do we regard values 'on the border' - are they 'in' or 'out' (in 
mathematics: "inclusive" or "exclusive" of the range)? In this case, 
your outline clearly shows them as "inclusive" and therefore the second 
test (0.1 to sleep for 3) *failed*.


Let's correct 'my' error (and evaluate the results, again), before we go 
any further...

def sleepy( value ):
     for ptr in range( 0, len( sleep_threshold ) ):
             if value <= sleep_threshold[ ptr ]:
                     print( f"{ value } results in sleep for { 
sleep_hours[ ptr ] }" )
                     break

for test_value in test_data: sleepy( test_value )

0.05 results in sleep for 1
0.1 results in sleep for 1
0.2 results in sleep for 3
0.6 results in sleep for 4
0.85 results in sleep for 6

That's better! Now are you happy?


Good, but I'm not!
(some say I'm never happy...)


A second, similar, and also startlingly-common, error, in this coding 
idiom is the "out by one error". In this case, I've not fallen into such 
a 'trap', but essentially the 'danger' is in looping (in this case, over 
the test data) one time too few, or one time too many, ie "out by one"!

Is this correct: for ptr in range( 0, len( sleep_threshold ) )?


I describe the above "style" as coding in a Java or C (or ...) idiom. A 
'purist' would say that it has *no* place in Python.

Python's language-design gives us a significantly more-powerful for 
statement, which can be differentiated from 'the others' by terming it a 
"for-each" statement, ie for-each element in a collection, do...

Thus, we don't need to know how large the collection happens to be 
(len()), and the 'out by one' error goes away - 'out by one' thrown-out? 
- consigned to languish in the history of cyber-space...


OK, so with for-each in mind, we could try:

for threshold in sleep_threshold: etc

but what to do when we want to access the corresponding element in 
sleep_hours, ie sleep_hours[ ptr ]???

Back to the drawing-board? Back to using a "pointer"?


No! Python has another trick up its sleeve (another 'battery' - when 
they say that Python has "batteries included").

Somehow, we need to link the two lists/column-vectors (sleep_threshold 
and sleep_hours). We can do this with zip() - we zip the two lists into 
a single list, such that each element of the new list is comprised of 
two values.

(remember how other posts talked of using a Python dictionary? A 
dictionary's elements have two components, a "key", and a "value". 
Similar motivation: finding a method of keeping the two 'together')

NB 'linking' lists using zip() is *not* the same as a ComSc concept or 
algorithm called "linked lists"!


Onwards:-

sleep_thresholds_hours = zip( sleep_threshold, sleep_hours )
print( sleep_thresholds_hours )

<zip object at 0x7f747579a640>

Oh dear, it's not going to show us what we want to see. Let's use a bit 
more power - more POWER!!!

for row in sleep_thresholds_hours: print( row )

(0.1, 1)
(0.4, 3)
(0.8, 4)
(0.9, 6)

Will you look at that, I'm back to mathematics and raving about 
matrices/matrixes! Someone (please) stop him...


Here's revised code, written to be "pythonic", ie using a Python idiom, 
and ridding us of any distasteful Java-influence (or whatever) - "we" 
are so much better than "they"!

Engaging the powers of zip() and for-each:-

def sleepy_zip( value ):
     for sleep_threshold, sleep_hours in sleep_thresholds_hours:
             if value <= sleep_threshold:
                     print( f"{ threshold } results in sleep for { 
sleep_hours }" )
                     break

for test_value in test_data: sleepy_zip( test_value )

Incidentally, if it will help comprehension, the twin-components of each 
sleep_thresholds_hours element are a tuple - and therefore you might 
prefer the more *explicit* syntax:-

     for ( sleep_threshold, sleep_hours ) in sleep_thresholds_hours:

The 'Zen of Python' does recommend preferring the explicit over 
implications!


Yahoo! Finally, it's time to go home...

No! Not so fast. Where's the output?

Um, there was none!
Do you 'see' any problem with this?


What happened is that zip() produces an iterator object 
(https://docs.python.org/3.5/library/functions.html#zip), and iterators 
can only be "consumed" once.

Think about it, if you zip 'up' a piece of clothing (ie use the zip()), 
and then "consume" the zip in the for-loop (unzipping it), you can't 
thereafter "consume" it again - the zip has been unzipped all the way 
'down' and so can't be unzipped any further...

(As 'home-spun wisdom' goes, that's not too bad - or is it "home-zipped 
wisdom"?)


So, when I demonstrated the results of the zip() by printing-out the 
contents for you, It was "consumed". Thus, when we came to run 
sleepy_zip(), there was no 'zip' left to 'unzip', and to borrow from 
another piece of 'wisdom': no data in, no data out.

My fault, AGAIN!


Sure enough:-

print( "v"*8 )
for row in sleep_thresholds_hours: print( row )
print( "^"*8 )

vvvvvvvv
^^^^^^^^

(the 'results' should appear between the two lines of 'arrows')


Let's re-start, this time with feeling (yes, I can feel that zip going 
'up'!). This time, let's put the zip() where it is going to be consumed, 
ie where there's no chance that someone, or something else, will consume 
it before we execute the function/do the business:-

def sleepy_zip( value ):
     for threshold, hours  in zip( sleep_threshold, sleep_hours ):
             if value <= threshold:
                     print( f"{ value } results in sleep for { hours }" )
                     break

for test_value in test_data: sleepy_zip( test_value )

0.05 results in sleep for 1
0.1 results in sleep for 1
0.2 results in sleep for 3
0.6 results in sleep for 4
0.85 results in sleep for 6


BTW have you spotted the virtue of using "break" - or what might happen 
if we didn't? Mind you, I do feel a little short of sleep - so I'm not 
complaining!


Hope this helps. If I have misunderstood any of the 'real' criteria, 
hopefully you will be able to adapt-to-suit.

As mentioned, normally I use PyTest to help prove my code. Thus the "for 
test_value etc" lines would be located elsewhere (rather than in-line). 
Also, were I to start writing this all over again, but still using 
in-line testing, I'd zip() test_value with the expected results - if we 
go to the trouble of assembling a test-data-set, then let's ensure we 
also know/remember the (correct) answers! In fact, you might even ask 
the computer to check its own results, then:-

	assert returned_result == expected_result

Python will come to an abrupt halt if things are not tickety-boo!

Similarly, you could improve the output by formatting the f-strings 
within our print()-s. More power to you!

However, in time-honored fashion, I shall leave such 'extras' to you, 
"as an exercise" (and/or when you're ready for such more-advanced coding 
techniques)...

-- 
Regards =dn

From gogonegro at gmail.com  Thu Jan  2 04:19:09 2020
From: gogonegro at gmail.com (Robert Alexander)
Date: Thu, 2 Jan 2020 10:19:09 +0100
Subject: [Tutor] Setting thresholds in a compact way
In-Reply-To: <67a7e2a2-23fe-17f7-5ca7-f389f079a5f8@DancesWithMice.info>
References: <CADiDnXdTeR3vmB-n=8aWnpD11WKsFXQ0f5pnrnmdZhtNO5ZeLA@mail.gmail.com>
 <67a7e2a2-23fe-17f7-5ca7-f389f079a5f8@DancesWithMice.info>
Message-ID: <CADiDnXcjpL7t-4uo9DMZML98Lo_QeZLW4DosH5g=yeJtz5yMog@mail.gmail.com>

Thank you all for your great replies which go a long way into making me
better understand python and my brain :)

While you prepared your better replies I actually had wrapped my beginner
head around the simple nested if as follows:

def set_frequency(down, up, loss):
    """Depending on the speed degradation change email frequency.

    The returned frequency is expressed in hours.
    """
    down_degradation = down / TD
    if down_degradation <= .1:
        return 1
    elif (down_degradation > .1) and (down_degradation <= .4):
        return 3
    elif (down_degradation > .4) and (down_degradation <= .8):
        return 4
    elif (down_degradation > .8) and (down_degradation <= .9):
        return 6
    else:
        return DEFAULT_TEST_FREQUENCY

As you can surmise DEFAULT_TEST_FREQUENCY is an external constant (set to
24) and currently uses only the passed download value.

As you suggested I had tested this function with a small main calling it
with random.random() value that provides a float between 0 and 1 and
printing the value it returned. I am satisfies by the behaviour.

I will spend the next month poring through the wisdom and arcane :) tricks
in your emails.

Would it be of any value for me to share the whole program (on GitHub) on
the list when it?s soundly working to see if you can suggest some overall
betterment of the style or flow?

Again very grateful for your inputs.

Ciao from Rome, Italy

PS The program monitors your ADSL speeds and when values drop under
thresholds sends a warning email
PPS The critical feature I still have to implement is to be able to reply
in a safe way to the email and stop the monitor in case I am traveling
around the planet and the ADSL goes bonkers and programs spits out an email
per hour ;)


On 2 January 2020 at 05:45:38, David L Neil via Tutor (tutor at python.org)
wrote:

On 2/01/20 5:20 AM, Robert Alexander wrote:
> I am trying to setup a varying time.sleep value (in house) depending on a
> priorly determined threshold.
>
> If threshold <= .9 AND > .8 then sleep should be 6 hours
> if threshold <= 0.8 AND > .4 then sleep should be 4 hours
> if threshold <= .4 AND > .1 then sleep should be 3 hours
> if threshold <= .1 then sleep should be set to 1 hour
>
> Instead of a complex/lengthy series of (nested?) if/ands based on the
> above, I was wondering if I could declare a dictionary such as:
>
> sleep_thresholds_hours = {.9:6, .8:4, .4:3, .1:1}
>
> And then use some sort of single statement to set the sleep_time to the
the
> proper value.
>
> Not even quite sure that using floats (albeit single decimal) as
dictionary
> keys will be ok.
>
> Getting old and in 2020 even older and my brain fogged by too much food
:)


A worked-solution...


Perhaps the seasonal influences explain it, but my (aged and decrepit)
mind prefers to construct the problem in the reverse of how it is stated
here...

Familiar with Cartesian coordinates and similar, to me the
x-axis/time-line starts at zero and goes 'up' to the right - and the
y-axis starts at zero and goes 'up', um, as the y-value goes 'up'. That
said, increasing/rising ranges seem easier (for me) to visualise:

<= .1 1
.4 3
.8 4
.9 6

(per 'excuses', below, am ignoring values of .9 or above, and similarly,
numbers which may/not be 'below' the illustrated range)

Notice that (in mathematical terminology) we now have two (ordered)
vectors (or 1-D matrices - or a single 2-D matrix, if you prefer.
Yeah/nah, leave that until the end...)


Let's call the left column-vector "sleep_threshold", and the right,
"sleep_hours". In Python:

sleep_threshold = [.1, .4, .8, .9]
sleep_hours = [ 1, 3, 4, 6 ]

Proving that we know what we're doing (maybe):-

for ptr in range( 0, len( sleep_threshold ) ):
print( f"{ ptr } { sleep_threshold[ ptr ] } { sleep_hours[ ptr ] }" )

0 0.1 1
1 0.4 3
2 0.8 4
3 0.9 6

(apologies, email word-wrapping may produce a less-than pleasing
graphological presentation. Similarly, when coding tests/"proofs", I've
saved vertical-space by typing the entire for-loop on a single line -
which many of my colleagues will (quite rightly) decry...)


Right, time to get to work! We could (per an earlier suggestion) try
iterating through the "sleep_threshold" list, in order to select the
corresponding "sleep_hours" element:

def sleepy( value ):
for ptr in range( 0, len( sleep_threshold ) ):
if value < sleep_threshold[ ptr ]:
print( f"{ value } results in sleep for {
sleep_hours[ ptr ] }" )
break

Yes, a function *should* be named using a verb which describes what it
does. I don't really know what you want it to do! (what a feeble excuse!)

Also, in this case, I'm only bothering to print the amount of sleep-time
by way of illustration. Presumably, you will want such a function to
return the sleep_hours value, or to execute the sleep right
there-and-then...]


What more criticism? Yes! Why did I put this code inside a function?
1. Presumption on my part (of your needs)
2. Programming style - each separate action is to be carried-out by a
single function/method ("separation of concerns")
3. For ease of testing!


Speaking of testing: how would we know if our magnificent-creation is
working, without testing the code? Normally, I would use PyTest, but as
this is being presented as a running-commentary, let's code some tests,
in-line:-

test_data = [ .05, .1, .2, .6, .85 ]
for test_value in test_data: print( test_value )

0.05
0.1
0.2
0.6
0.85

Please note that I've only used one 'border' value (0.1) and ignored any
concept of "outliers". (I'm going to claim simplicity. You can say
'laziness'...).


Now we're ready to experiment:-

for test_value in test_data: sleepy( test_value )

0.05 results in sleep for 1
0.1 results in sleep for 3
0.2 results in sleep for 3
0.6 results in sleep for 4
0.85 results in sleep for 6

What brilliance! It's almost as good-looking as am I!


Did you notice the 'oops!' in the test-data output? (*and* in the code?)

A very common error when coding such a 'ladder', is the comparison. How
do we regard values 'on the border' - are they 'in' or 'out' (in
mathematics: "inclusive" or "exclusive" of the range)? In this case,
your outline clearly shows them as "inclusive" and therefore the second
test (0.1 to sleep for 3) *failed*.


Let's correct 'my' error (and evaluate the results, again), before we go
any further...

def sleepy( value ):
for ptr in range( 0, len( sleep_threshold ) ):
if value <= sleep_threshold[ ptr ]:
print( f"{ value } results in sleep for {
sleep_hours[ ptr ] }" )
break

for test_value in test_data: sleepy( test_value )

0.05 results in sleep for 1
0.1 results in sleep for 1
0.2 results in sleep for 3
0.6 results in sleep for 4
0.85 results in sleep for 6

That's better! Now are you happy?


Good, but I'm not!
(some say I'm never happy...)


A second, similar, and also startlingly-common, error, in this coding
idiom is the "out by one error". In this case, I've not fallen into such
a 'trap', but essentially the 'danger' is in looping (in this case, over
the test data) one time too few, or one time too many, ie "out by one"!

Is this correct: for ptr in range( 0, len( sleep_threshold ) )?


I describe the above "style" as coding in a Java or C (or ...) idiom. A
'purist' would say that it has *no* place in Python.

Python's language-design gives us a significantly more-powerful for
statement, which can be differentiated from 'the others' by terming it a
"for-each" statement, ie for-each element in a collection, do...

Thus, we don't need to know how large the collection happens to be
(len()), and the 'out by one' error goes away - 'out by one' thrown-out?
- consigned to languish in the history of cyber-space...


OK, so with for-each in mind, we could try:

for threshold in sleep_threshold: etc

but what to do when we want to access the corresponding element in
sleep_hours, ie sleep_hours[ ptr ]???

Back to the drawing-board? Back to using a "pointer"?


No! Python has another trick up its sleeve (another 'battery' - when
they say that Python has "batteries included").

Somehow, we need to link the two lists/column-vectors (sleep_threshold
and sleep_hours). We can do this with zip() - we zip the two lists into
a single list, such that each element of the new list is comprised of
two values.

(remember how other posts talked of using a Python dictionary? A
dictionary's elements have two components, a "key", and a "value".
Similar motivation: finding a method of keeping the two 'together')

NB 'linking' lists using zip() is *not* the same as a ComSc concept or
algorithm called "linked lists"!


Onwards:-

sleep_thresholds_hours = zip( sleep_threshold, sleep_hours )
print( sleep_thresholds_hours )

<zip object at 0x7f747579a640>

Oh dear, it's not going to show us what we want to see. Let's use a bit
more power - more POWER!!!

for row in sleep_thresholds_hours: print( row )

(0.1, 1)
(0.4, 3)
(0.8, 4)
(0.9, 6)

Will you look at that, I'm back to mathematics and raving about
matrices/matrixes! Someone (please) stop him...


Here's revised code, written to be "pythonic", ie using a Python idiom,
and ridding us of any distasteful Java-influence (or whatever) - "we"
are so much better than "they"!

Engaging the powers of zip() and for-each:-

def sleepy_zip( value ):
for sleep_threshold, sleep_hours in sleep_thresholds_hours:
if value <= sleep_threshold:
print( f"{ threshold } results in sleep for {
sleep_hours }" )
break

for test_value in test_data: sleepy_zip( test_value )

Incidentally, if it will help comprehension, the twin-components of each
sleep_thresholds_hours element are a tuple - and therefore you might
prefer the more *explicit* syntax:-

for ( sleep_threshold, sleep_hours ) in sleep_thresholds_hours:

The 'Zen of Python' does recommend preferring the explicit over
implications!


Yahoo! Finally, it's time to go home...

No! Not so fast. Where's the output?

Um, there was none!
Do you 'see' any problem with this?


What happened is that zip() produces an iterator object
(https://docs.python.org/3.5/library/functions.html#zip), and iterators
can only be "consumed" once.

Think about it, if you zip 'up' a piece of clothing (ie use the zip()),
and then "consume" the zip in the for-loop (unzipping it), you can't
thereafter "consume" it again - the zip has been unzipped all the way
'down' and so can't be unzipped any further...

(As 'home-spun wisdom' goes, that's not too bad - or is it "home-zipped
wisdom"?)


So, when I demonstrated the results of the zip() by printing-out the
contents for you, It was "consumed". Thus, when we came to run
sleepy_zip(), there was no 'zip' left to 'unzip', and to borrow from
another piece of 'wisdom': no data in, no data out.

My fault, AGAIN!


Sure enough:-

print( "v"*8 )
for row in sleep_thresholds_hours: print( row )
print( "^"*8 )

vvvvvvvv
^^^^^^^^

(the 'results' should appear between the two lines of 'arrows')


Let's re-start, this time with feeling (yes, I can feel that zip going
'up'!). This time, let's put the zip() where it is going to be consumed,
ie where there's no chance that someone, or something else, will consume
it before we execute the function/do the business:-

def sleepy_zip( value ):
for threshold, hours in zip( sleep_threshold, sleep_hours ):
if value <= threshold:
print( f"{ value } results in sleep for { hours }" )
break

for test_value in test_data: sleepy_zip( test_value )

0.05 results in sleep for 1
0.1 results in sleep for 1
0.2 results in sleep for 3
0.6 results in sleep for 4
0.85 results in sleep for 6


BTW have you spotted the virtue of using "break" - or what might happen
if we didn't? Mind you, I do feel a little short of sleep - so I'm not
complaining!


Hope this helps. If I have misunderstood any of the 'real' criteria,
hopefully you will be able to adapt-to-suit.

As mentioned, normally I use PyTest to help prove my code. Thus the "for
test_value etc" lines would be located elsewhere (rather than in-line).
Also, were I to start writing this all over again, but still using
in-line testing, I'd zip() test_value with the expected results - if we
go to the trouble of assembling a test-data-set, then let's ensure we
also know/remember the (correct) answers! In fact, you might even ask
the computer to check its own results, then:-

assert returned_result == expected_result

Python will come to an abrupt halt if things are not tickety-boo!

Similarly, you could improve the output by formatting the f-strings
within our print()-s. More power to you!

However, in time-honored fashion, I shall leave such 'extras' to you,
"as an exercise" (and/or when you're ready for such more-advanced coding
techniques)...

-- 
Regards =dn
_______________________________________________
Tutor maillist - Tutor at python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor

From alan.gauld at yahoo.co.uk  Thu Jan  2 05:16:10 2020
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Thu, 2 Jan 2020 10:16:10 +0000
Subject: [Tutor] Setting thresholds in a compact way
In-Reply-To: <alpine.LSU.2.20.2001011904270.3119@qnttre.jbaqresebt.arg>
References: <CADiDnXdTeR3vmB-n=8aWnpD11WKsFXQ0f5pnrnmdZhtNO5ZeLA@mail.gmail.com>
 <alpine.LSU.2.20.2001011904270.3119@qnttre.jbaqresebt.arg>
Message-ID: <ebbc395e-80bf-e206-51eb-e6d27ae9fc31@yahoo.co.uk>

On 02/01/2020 03:25, Martin A. Brown wrote:

> I don't know how to apply the sparse array solution, suggested by Alan.

Sparse arrays are a bit of a faff and only worthwhile in the specific
scenario where there are a lot of choices, so an if/elif ladder would be
cumbersome - I'm thinking at least double digit lengths...20 or 30 say.
They are also effective where you have a broad range of possible test
values but only a relatively few sub-ranges which require action.

It was purely a response to Bob's question about how to handle the
long ladder case. Not a general recommendation.
Certainly not for this particular problem.

-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos


From gogonegro at gmail.com  Thu Jan  2 13:12:36 2020
From: gogonegro at gmail.com (Robert Alexander)
Date: Thu, 2 Jan 2020 19:12:36 +0100
Subject: [Tutor] Please correct my error handling
Message-ID: <CADiDnXeG9Fu+vQz7R9fCpZqq=8jf0_Q_z+S4fv+wPA5AJVJ5Kg@mail.gmail.com>

I am having an hard time to properly address some errors in external
programs launched by my python code.

Here follows a sample, in which you can see 3 similar ?stanzas?, first is
to check behaviour of a well formed external command and is all as
expected, the second shows the same command with an illegal option and
again all behaves as expected. The problem I have is to catch the ?non
existing command? as per the third example.

Thank you very much.

Robert

============== test.py
import subprocess

# 1) try a legit (*nix) command
process = subprocess.Popen(
        ['/bin/ls', '-l'],
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
    )
stdout, stderr = process.communicate()
if not stderr:
    print('--No errors--\n', stdout.decode())
else:
    print('--Error found--\n', stderr.decode())

# 2) repeat with an illegal option
process = subprocess.Popen(
        ['/bin/ls', '-I'],
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
    )
stdout, stderr = process.communicate()
if not stderr:
    print('--No errors--\n', stdout.decode())
else:
    print('--Error found--\n', stderr.decode())

# 3) repeat with an illegal ;) command
process = subprocess.Popen(
        ['/bin/lsd', '-I'],
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
    )
stdout, stderr = process.communicate()
if not stderr:
    print('--No errors--\n', stdout.decode())
else:
    print('--Error found--\n', stderr.decode())

From mats at wichmann.us  Thu Jan  2 13:29:58 2020
From: mats at wichmann.us (Mats Wichmann)
Date: Thu, 2 Jan 2020 11:29:58 -0700
Subject: [Tutor] Please correct my error handling
In-Reply-To: <CADiDnXeG9Fu+vQz7R9fCpZqq=8jf0_Q_z+S4fv+wPA5AJVJ5Kg@mail.gmail.com>
References: <CADiDnXeG9Fu+vQz7R9fCpZqq=8jf0_Q_z+S4fv+wPA5AJVJ5Kg@mail.gmail.com>
Message-ID: <333804d7-8544-5454-9df6-43998ef29c25@wichmann.us>

On 1/2/20 11:12 AM, Robert Alexander wrote:
> I am having an hard time to properly address some errors in external
> programs launched by my python code.

Popen fails directly if it can't open a process for the requested 
command, so you have to check a different way for that case.  Try this:

> # 3) repeat with an illegal ;) command

try:
     process = subprocess.Popen(
             ['/bin/lsd', '-E'],
             stdout=subprocess.PIPE,
             stderr=subprocess.PIPE,
         )
except FileNotFoundError as e:
     print("--Command not found--\n", e)
     sys.exit(2)
     # or you could just "raise":

stdout, stderr = process.communicate()
if not stderr:
     print('--No errors--\n', stdout.decode())
else:
     print('--Error found--\n', stderr.decode())


From david at graniteweb.com  Thu Jan  2 13:39:18 2020
From: david at graniteweb.com (David Rock)
Date: Thu, 2 Jan 2020 12:39:18 -0600
Subject: [Tutor] Please correct my error handling
In-Reply-To: <CADiDnXeG9Fu+vQz7R9fCpZqq=8jf0_Q_z+S4fv+wPA5AJVJ5Kg@mail.gmail.com>
References: <CADiDnXeG9Fu+vQz7R9fCpZqq=8jf0_Q_z+S4fv+wPA5AJVJ5Kg@mail.gmail.com>
Message-ID: <20200102183918.fpt53zvu7g72oxxy@apple.graniteweb.com>

* Robert Alexander <gogonegro at gmail.com> [2020-01-02 19:12]:
> I am having an hard time to properly address some errors in external
> programs launched by my python code.

> # 3) repeat with an illegal ;) command
> process = subprocess.Popen(
>         ['/bin/lsd', '-I'],
>         stdout=subprocess.PIPE,
>         stderr=subprocess.PIPE,
>     )
> stdout, stderr = process.communicate()
> if not stderr:
>     print('--No errors--\n', stdout.decode())
> else:
>     print('--Error found--\n', stderr.decode())


The problem is process.communicate() is thowing an exception.  That's
not the same thing as getting stdout, stderr

Traceback (most recent call last):
  File "test.py", line 6, in <module>
    stderr=subprocess.PIPE,
  File "/usr/lib/python3.5/subprocess.py", line 676, in __init__
    restore_signals, start_new_session)
  File "/usr/lib/python3.5/subprocess.py", line 1282, in _execute_child
    raise child_exception_type(errno_num, err_msg)
FileNotFoundError: [Errno 2] No such file or directory: '/bin/lsd'


The FileNotFoundError is an exception from process.communicate() failing
outright.  You need to catch that exception and do something with it.
For example, put the call to process.communicate() in a try block.

try:
    stdout, stderr = process.communicate()
except FileNotFoundError:
    print( "command not found" )
else:
    if not stderr:
        print('--No errors--\n', stdout.decode())
    else:
        print('--Error found--\n', stderr.decode())

-- 
David Rock
david at graniteweb.com

From david at graniteweb.com  Thu Jan  2 13:43:06 2020
From: david at graniteweb.com (David Rock)
Date: Thu, 2 Jan 2020 12:43:06 -0600
Subject: [Tutor] Please correct my error handling
In-Reply-To: <20200102183918.fpt53zvu7g72oxxy@apple.graniteweb.com>
References: <CADiDnXeG9Fu+vQz7R9fCpZqq=8jf0_Q_z+S4fv+wPA5AJVJ5Kg@mail.gmail.com>
 <20200102183918.fpt53zvu7g72oxxy@apple.graniteweb.com>
Message-ID: <20200102184306.hk5a2jem52hxmx43@apple.graniteweb.com>

* David Rock <david at graniteweb.com> [2020-01-02 12:39]:
> 
> The problem is process.communicate() is thowing an exception.  That's
> not the same thing as getting stdout, stderr
> 
> Traceback (most recent call last):
>   File "test.py", line 6, in <module>
>     stderr=subprocess.PIPE,
>   File "/usr/lib/python3.5/subprocess.py", line 676, in __init__
>     restore_signals, start_new_session)
>   File "/usr/lib/python3.5/subprocess.py", line 1282, in _execute_child
>     raise child_exception_type(errno_num, err_msg)
> FileNotFoundError: [Errno 2] No such file or directory: '/bin/lsd'
> 

Oops, I should look closer at my own tracebacks.  As mentioned, this is
an exception in popen, not subprocess.communicate().  It's not even
getting that far.

-- 
David Rock
david at graniteweb.com

From mats at wichmann.us  Thu Jan  2 13:44:56 2020
From: mats at wichmann.us (Mats Wichmann)
Date: Thu, 2 Jan 2020 11:44:56 -0700
Subject: [Tutor] Please correct my error handling
In-Reply-To: <CADiDnXeG9Fu+vQz7R9fCpZqq=8jf0_Q_z+S4fv+wPA5AJVJ5Kg@mail.gmail.com>
References: <CADiDnXeG9Fu+vQz7R9fCpZqq=8jf0_Q_z+S4fv+wPA5AJVJ5Kg@mail.gmail.com>
Message-ID: <a6ba80ba-9627-3e7b-3033-df143d23aa28@wichmann.us>

On 1/2/20 11:12 AM, Robert Alexander wrote:
> I am having an hard time to properly address some errors in external
> programs launched by my python code.
> 
> Here follows a sample, in which you can see 3 similar ?stanzas?, first is
> to check behaviour of a well formed external command and is all as
> expected, the second shows the same command with an illegal option and
> again all behaves as expected. The problem I have is to catch the ?non
> existing command? as per the third example.

also... there are "simpler" ways to do this vs Popen + communicate. I 
ran a "command fails" sequence in the interpreter:


 >>> x = subprocess.run(['/bin/ls', '-E'], stdout=subprocess.PIPE, 
stderr=subprocess.PIPE)
 >>> type(x)
 >>> <class 'subprocess.CompletedProcess'>
 >>> help(subprocess.CompletedProcess)
Help on class CompletedProcess in module subprocess:

class CompletedProcess(builtins.object)
  |  CompletedProcess(args, returncode, stdout=None, stderr=None)
  |
  |  A process that has finished running.
  |
  |  This is returned by run().
  |
  |  Attributes:
  |    args: The list or str args passed to run().
  |    returncode: The exit code of the process, negative for signals.
  |    stdout: The standard output (None if not captured).
  |    stderr: The standard error (None if not captured).
  |
  |  Methods defined here:
  |
  |  __init__(self, args, returncode, stdout=None, stderr=None)
  |      Initialize self.  See help(type(self)) for accurate signature.
  |
  |  __repr__(self)
  |      Return repr(self).
  |
  |  check_returncode(self)
  |      Raise CalledProcessError if the exit code is non-zero.
  |
  |  ----------------------------------------------------------------------
  |  Data descriptors defined here:
  |
  |  __dict__
  |      dictionary for instance variables (if defined)
  |
  |  __weakref__
  |      list of weak references to the object (if defined)

 >>> x.args
['/bin/ls', '-E']
 >>> x.returncode
2
 >>> x.stdout
b''
 >>> x.stderr
b"/bin/ls: invalid option -- 'E'\nTry '/bin/ls --help' for more 
information.\n"
 >>>

From basicbare at gmail.com  Thu Jan  2 06:19:54 2020
From: basicbare at gmail.com (Alan Thwaits)
Date: Thu, 2 Jan 2020 06:19:54 -0500
Subject: [Tutor] Beginning String Problems
In-Reply-To: <CANv814=9YGOE1Na+kvFzfVeO44OYXbUG+QyOdjgw6qej_Kiv-A@mail.gmail.com>
References: <CANv814=9YGOE1Na+kvFzfVeO44OYXbUG+QyOdjgw6qej_Kiv-A@mail.gmail.com>
Message-ID: <CALC_W0ucsxuy6H00b_Vf5OZ95Khdxaq_jTp3NEqtHu-rC9RP1g@mail.gmail.com>

I copied, pasted, and ran your code, and it worked well. I'm running
Anaconda3 and Spyder on a Windows 10 64-bit machine.

I'm very much a beginning Python user, so don't know enough to suggest why
it's not working for you. Just thought I'd let you know that your code
seems alright.

Cheers!

Alan

On Wed, Jan 1, 2020 at 7:15 PM William Dickey <wpdickey at usc.edu> wrote:

> I am learning Python via an online video "Beginning Python" by William
> Fiset. I am at the end of chapter 2 and I am supposed to be inputting a
> string that has an output of a persons full name in  this order *First M.
> Last*, but when I copied what he was doing it is not working. Here is what
> I input:
>
> first_name = str(input("Please enter your first name: "))
> middle_name = str(input("Please enter your middle name: "))
> last_name = str(input("Please enter your last name: "))
>
> first_name = first_name.capitalize()
> middle_name = middle_name.capitalize()
> last_name = last_name.capitalize()
>
> name_format = "{first} {middle:.1s} {last}"
> print(name_format.format(first=first_name, middle=middle_name,
> last=last_name))
>
> and here is what I get when I open it in the command line
>
> I enter the file location and I get:
> Please enter your first name:
>
> I enter william and I get this error:
>
> Traceback (most recent call):
>     File "C:\xxx\xxx\xxx\xxx", line 3, in <module>
>        first_name = str(input("Please enter your first name: "))
>     File "<string>", line 1, in <module>
> NameError: name 'william' is not defined
>
> I am using Windows 10 64 bit, Atom text editor, Python 3.4.
>
> Thank you
> William
> _______________________________________________
> Tutor maillist  -  Tutor at python.org
> To unsubscribe or change subscription options:
> https://mail.python.org/mailman/listinfo/tutor
>

From gogonegro at gmail.com  Fri Jan  3 09:54:15 2020
From: gogonegro at gmail.com (Robert Alexander)
Date: Fri, 3 Jan 2020 15:54:15 +0100
Subject: [Tutor] Please correct my error handling
In-Reply-To: <a6ba80ba-9627-3e7b-3033-df143d23aa28@wichmann.us>
References: <CADiDnXeG9Fu+vQz7R9fCpZqq=8jf0_Q_z+S4fv+wPA5AJVJ5Kg@mail.gmail.com>
 <a6ba80ba-9627-3e7b-3033-df143d23aa28@wichmann.us>
Message-ID: <CADiDnXeHLARWmG__eVzDWDw1PaJA1eQ1wagSOVRu8WJ0OFoKnA@mail.gmail.com>

Thank you guys.

So as you pointed out I was catching the error at the wrong place.

Following is the corrected code. I?ll also investigate the easier
alternatives you proposed later on.

Take care

import subprocess

# first try a legit (*nix) command
process = subprocess.Popen(
    ["/bin/ls", "-l"], stdout=subprocess.PIPE, stderr=subprocess.PIPE
)
stdout, stderr = process.communicate()
if not stderr:
    print("--No errors--\n", stdout.decode())
else:
    print("--Error found--\n", stderr.decode())

# now repeat with an illegal option
process = subprocess.Popen(
    ["/bin/ls", "-I"], stdout=subprocess.PIPE, stderr=subprocess.PIPE
)
stdout, stderr = process.communicate()
if not stderr:
    print("--No errors--\n", stdout.decode())
else:
    print("--Error found--\n", stderr.decode())

# now repeat with an inexisting command
# and catch the Popen error this time
try:
    process = subprocess.Popen(
        ["/bin/lsd", "-I"], stdout=subprocess.PIPE, stderr=subprocess.PIPE
    )
except FileNotFoundError:
    print("Command not found. Did you install it?")
else:
    stdout, stderr = process.communicate()
    if not stderr:
        print("--No errors--\n", stdout.decode())
    else:
        print("--Error found--\n", stderr.decode())

From robertvstepp at gmail.com  Sat Jan  4 02:10:43 2020
From: robertvstepp at gmail.com (boB Stepp)
Date: Sat, 4 Jan 2020 01:10:43 -0600
Subject: [Tutor] How to refactor a simple,
 straightforward script into a "proper" program?
In-Reply-To: <CANDiX9Kv=675fXb=it=tTh2hf+Nx4rTyD7bHS4St9UUizYtZDw@mail.gmail.com>
References: <CANDiX9JjoXfpEBvnmsJWrAyumLvsKUN39VcaTvoG05-Cnm1DHA@mail.gmail.com>
 <45f1a074-d8bc-ec13-9757-4686ee60462d@DancesWithMice.info>
 <CANDiX9Kv=675fXb=it=tTh2hf+Nx4rTyD7bHS4St9UUizYtZDw@mail.gmail.com>
Message-ID: <CANDiX9+Rx-syD++J2XuNHyknEccwBC=wBFPpHd7A6DYKYkubNQ@mail.gmail.com>

I now believe that I have a finalized version2.py that I am satisfied
with.  I have not done the optional type annotations and am in
progress adding tests.  I may have some questions about the resulting
tests once I complete them.  But for my New Year's Python 3 exercise,
I wish to throw out the below code for code review by anyone who
wishes to assist boB on his ongoing learning journey.  Let me know of
*anything* that you think I should have done better or more
professionally or in a more Pythonic style, etc.

Another goal I had hoped to accomplish, but have apparently failed at,
was to draw in fellow Python learners into the discussion.  So many
times we are asked on this list what can we do to learn how to program
in Python, and the oft-recommended advice is to come up with a project
and code it, asking for help as necessary.  I thought showing a simple
program and working on improving it might be helpful for other
learners.  Of course the end result to this point has grown from an
original 23 LOC to 97 LOC (including blank lines), so have I really
improved the original product?  I await the scores from the judges!

<final version2.py>
============================================================================
#!/usr/bin/env python3
"""Calculate the number of pages per day needed to read a book by a
given date."""

from datetime import date


def get_input(str_converter, msg):
    """Prompt user with a message and return user input with the
correct data type."""
    while True:
        try:
            return str_converter(input(msg))
        except ValueError:
            if str_converter == int:
                print("\nPlease enter a whole number!")
            elif str_converter == date.fromisoformat:
                print("\nPlease enter a valid date in the following
format yyyy-mm-dd!")


def get_input_params():
    """Collect all needed input parameters."""
    while True:
        str_converters = [int, int, date.fromisoformat]
        input_msgs = [
            "How many pages are there in your book?  ",
            "How many pages have you read?  ",
            "What is your date to finish the book (yyyy-mm-dd)?  ",
        ]
        num_pages_in_book, num_pages_read, goal_date = map(
            get_input, str_converters, input_msgs
        )
        input_params = num_pages_in_book, num_pages_read, goal_date
        if validate_input_params(*input_params):
            return input_params
        print()


def validate_input_params(num_pages_in_book, num_pages_read, goal_date):
    """Verify input parameters for logical correctness."""
    valid_input = True
    print()
    if num_pages_in_book <= 0:
        print("The number of pages in a book must be a positive integer!")
        valid_input = False
    if num_pages_read < 0:
        print("The number of pages read must be a whole number!")
        valid_input = False
    if num_pages_read == num_pages_in_book and num_pages_in_book > 0:
        print(
            "You have already read the entire book!  Why are you
running this program?"
        )
    if num_pages_read > num_pages_in_book:
        print("You cannot have read more pages than there are in the book!")
        valid_input = False
    if goal_date < date.today():
        print("You cannot set a goal date in the past!")
        valid_input = False
    return valid_input


def calc_pages_per_day(num_pages_in_book, num_pages_read, goal_date):
    """Return number of pages to read each day to attain goal."""
    COUNT_TODAY = 1
    days_to_goal = (goal_date - date.today()).days
    pages_per_day = (num_pages_in_book - num_pages_read) /
(days_to_goal + COUNT_TODAY)
    return pages_per_day


def display_result(pages_per_day):
    """Display how many pages per day the reader must read to finish
the book."""
    if 0 < pages_per_day <= 1:
        word_to_display = "page"
    else:
        word_to_display = "pages"
    print(
        "You must read {0:.2n} {1} per day to reach your goal.".format(
            pages_per_day, word_to_display
        )
    )


def main():
    """Run program and display results."""
    print(
        'Welcome to "HOW MANY PAGES???"\n'
        "Follow on-screen directions to determine how many pages to
read each day to "
        "finish your book.\n\n"
    )
    while True:
        input_params = get_input_params()
        display_result(calc_pages_per_day(*input_params))
        run_again = input("Enter 'q' to quit or anything else to continue:  ")
        if run_again.lower().startswith("q"):
            break


if __name__ == "__main__":
    main()
============================================================================

boB

From joel.goldstick at gmail.com  Sat Jan  4 16:33:04 2020
From: joel.goldstick at gmail.com (Joel Goldstick)
Date: Sat, 4 Jan 2020 16:33:04 -0500
Subject: [Tutor] How to refactor a simple,
 straightforward script into a "proper" program?
In-Reply-To: <CANDiX9+Rx-syD++J2XuNHyknEccwBC=wBFPpHd7A6DYKYkubNQ@mail.gmail.com>
References: <CANDiX9JjoXfpEBvnmsJWrAyumLvsKUN39VcaTvoG05-Cnm1DHA@mail.gmail.com>
 <45f1a074-d8bc-ec13-9757-4686ee60462d@DancesWithMice.info>
 <CANDiX9Kv=675fXb=it=tTh2hf+Nx4rTyD7bHS4St9UUizYtZDw@mail.gmail.com>
 <CANDiX9+Rx-syD++J2XuNHyknEccwBC=wBFPpHd7A6DYKYkubNQ@mail.gmail.com>
Message-ID: <CAPM-O+wdNSLjha_91dV_84FSJWReZxGcv1qdYmp9CXpb2K27ag@mail.gmail.com>

I'll chime in.  My comments interleaved with your code

On Sat, Jan 4, 2020 at 2:11 AM boB Stepp <robertvstepp at gmail.com> wrote:
>
> I now believe that I have a finalized version2.py that I am satisfied
> with.  I have not done the optional type annotations and am in
> progress adding tests.  I may have some questions about the resulting
> tests once I complete them.  But for my New Year's Python 3 exercise,
> I wish to throw out the below code for code review by anyone who
> wishes to assist boB on his ongoing learning journey.  Let me know of
> *anything* that you think I should have done better or more
> professionally or in a more Pythonic style, etc.
>
> Another goal I had hoped to accomplish, but have apparently failed at,
> was to draw in fellow Python learners into the discussion.  So many
> times we are asked on this list what can we do to learn how to program
> in Python, and the oft-recommended advice is to come up with a project
> and code it, asking for help as necessary.  I thought showing a simple
> program and working on improving it might be helpful for other
> learners.  Of course the end result to this point has grown from an
> original 23 LOC to 97 LOC (including blank lines), so have I really
> improved the original product?  I await the scores from the judges!
>
> <final version2.py>
> ============================================================================
> #!/usr/bin/env python3
> """Calculate the number of pages per day needed to read a book by a
> given date."""
>
> from datetime import date
>
>
The above looks fine to me.  You may want to say what you want the
user to input in order to accomplish this, and what is valid for them
to input.

> def get_input(str_converter, msg):
>     """Prompt user with a message and return user input with the
> correct data type."""
>     while True:
>         try:
>             return str_converter(input(msg))
>         except ValueError:
>             if str_converter == int:
>                 print("\nPlease enter a whole number!")
>             elif str_converter == date.fromisoformat:
>                 print("\nPlease enter a valid date in the following
> format yyyy-mm-dd!")
>

This one baffles me a little.  If str_converter(input(msg)) doesn't
produce a ValueError exception, it returns data, otherwise it prints
something, and returns nothing.
>
> def get_input_params():
>     """Collect all needed input parameters."""
>     while True:
>         str_converters = [int, int, date.fromisoformat]
>         input_msgs = [
>             "How many pages are there in your book?  ",
>             "How many pages have you read?  ",
>             "What is your date to finish the book (yyyy-mm-dd)?  ",
>         ]
>         num_pages_in_book, num_pages_read, goal_date = map(
>             get_input, str_converters, input_msgs
>         )
>         input_params = num_pages_in_book, num_pages_read, goal_date
>         if validate_input_params(*input_params):
>             return input_params
>         print()
>

Your docstring is useless.  A docstring should describe what the code
requires coming in, what it returns, and what function it performs.
Its not useful to say something like you have:  it does what it needs
to do?
Also, get_input_parameters has no arguments.  and it either returns
something, or it returns nothing.
>
> def validate_input_params(num_pages_in_book, num_pages_read, goal_date):
>     """Verify input parameters for logical correctness."""
>     valid_input = True
>     print()
>     if num_pages_in_book <= 0:
>         print("The number of pages in a book must be a positive integer!")
>         valid_input = False
>     if num_pages_read < 0:
>         print("The number of pages read must be a whole number!")
>         valid_input = False
>     if num_pages_read == num_pages_in_book and num_pages_in_book > 0:
>         print(
>             "You have already read the entire book!  Why are you
> running this program?"
>         )
>     if num_pages_read > num_pages_in_book:
>         print("You cannot have read more pages than there are in the book!")
>         valid_input = False
>     if goal_date < date.today():
>         print("You cannot set a goal date in the past!")
>         valid_input = False
>     return valid_input
>

Again, you are too general in your docstring. And you don't spell out
what this thing returns
>
> def calc_pages_per_day(num_pages_in_book, num_pages_read, goal_date):
>     """Return number of pages to read each day to attain goal."""
>     COUNT_TODAY = 1
>     days_to_goal = (goal_date - date.today()).days
>     pages_per_day = (num_pages_in_book - num_pages_read) /
> (days_to_goal + COUNT_TODAY)
>     return pages_per_day
>

This one is ok i guess
>
> def display_result(pages_per_day):
>     """Display how many pages per day the reader must read to finish
> the book."""
>     if 0 < pages_per_day <= 1:
>         word_to_display = "page"
>     else:
>         word_to_display = "pages"
>     print(
>         "You must read {0:.2n} {1} per day to reach your goal.".format(
>             pages_per_day, word_to_display
>         )
>     )
>

I would prefer that I do prints with values returned from functions,
rather than have the function print some value.
>
> def main():
>     """Run program and display results."""
>     print(
>         'Welcome to "HOW MANY PAGES???"\n'
>         "Follow on-screen directions to determine how many pages to
> read each day to "
>         "finish your book.\n\n"
>     )
>     while True:
>         input_params = get_input_params()
>         display_result(calc_pages_per_day(*input_params))
>         run_again = input("Enter 'q' to quit or anything else to continue:  ")
>         if run_again.lower().startswith("q"):
>             break
>
This might be simplified like:
while True:
    display_results(calc_pages_per_day(*get_input_params())
    if  input("bla bla").lower().startswith('q'):
        break;
>
> if __name__ == "__main__":
>     main()
> ============================================================================
>
> boB
> _______________________________________________
> Tutor maillist  -  Tutor at python.org
> To unsubscribe or change subscription options:
> https://mail.python.org/mailman/listinfo/tutor



-- 
Joel Goldstick
http://joelgoldstick.com/blog
http://cc-baseballstats.info/stats/birthdays

From robertvstepp at gmail.com  Sat Jan  4 18:05:50 2020
From: robertvstepp at gmail.com (boB Stepp)
Date: Sat, 4 Jan 2020 17:05:50 -0600
Subject: [Tutor] How to refactor a simple,
 straightforward script into a "proper" program?
In-Reply-To: <CAPM-O+wdNSLjha_91dV_84FSJWReZxGcv1qdYmp9CXpb2K27ag@mail.gmail.com>
References: <CANDiX9JjoXfpEBvnmsJWrAyumLvsKUN39VcaTvoG05-Cnm1DHA@mail.gmail.com>
 <45f1a074-d8bc-ec13-9757-4686ee60462d@DancesWithMice.info>
 <CANDiX9Kv=675fXb=it=tTh2hf+Nx4rTyD7bHS4St9UUizYtZDw@mail.gmail.com>
 <CANDiX9+Rx-syD++J2XuNHyknEccwBC=wBFPpHd7A6DYKYkubNQ@mail.gmail.com>
 <CAPM-O+wdNSLjha_91dV_84FSJWReZxGcv1qdYmp9CXpb2K27ag@mail.gmail.com>
Message-ID: <CANDiX9JM3na92Umtdi=iE2mwKxor4U3PgFDL7htxMw9V=U4k9g@mail.gmail.com>

Thank you, Joel, for your comments.  I have found them valuable.

On first reading, the bulk of your comments are about code
documentation, and, I believe, expose weaknesses in my understanding
of what is expected and required.  After I complete this initial
reaction to your comments, I am going to hit the 'Net and review
docstrings and code commenting and then return with some code updates
to see if my understanding has improved.  One thing that struck me on
my initial read is that while I was trying to refactor the original
simple script into something more robust, I was still retaining a
"simple script" mentality for my code documentation.  I expect this is
a faulty habit I have fallen into from not having any oversight of my
coding efforts (Other than my questions on this list.).

One question I do wish to ask up front:  _If_ type annotations are
used, does this affect how the code is documented?  My impression is
that with my code as is (no type annotations) I should have added a
section for each function explaining the expected type and function of
each parameter and value returned.  But if I do use type annotations,
that would seem redundant.

On Sat, Jan 4, 2020 at 3:33 PM Joel Goldstick <joel.goldstick at gmail.com> wrote:

> On Sat, Jan 4, 2020 at 2:11 AM boB Stepp <robertvstepp at gmail.com> wrote:

> > <final version2.py>
> > ============================================================================
> > #!/usr/bin/env python3
> > """Calculate the number of pages per day needed to read a book by a
> > given date."""
> >
> > from datetime import date
> >
> >
> The above looks fine to me.  You may want to say what you want the
> user to input in order to accomplish this, and what is valid for them
> to input.
>
> > def get_input(str_converter, msg):
> >     """Prompt user with a message and return user input with the
> > correct data type."""
> >     while True:
> >         try:
> >             return str_converter(input(msg))
> >         except ValueError:
> >             if str_converter == int:
> >                 print("\nPlease enter a whole number!")
> >             elif str_converter == date.fromisoformat:
> >                 print("\nPlease enter a valid date in the following
> > format yyyy-mm-dd!")
> >
>
> This one baffles me a little.  If str_converter(input(msg)) doesn't
> produce a ValueError exception, it returns data, otherwise it prints
> something, and returns nothing.

My intent was to continue looping, warning the user of his/her error,
until the user enters syntactically valid input, and only then
returning the input for further validation.  Should I have approached
this differently?

> > def get_input_params():
> >     """Collect all needed input parameters."""
> >     while True:
> >         str_converters = [int, int, date.fromisoformat]
> >         input_msgs = [
> >             "How many pages are there in your book?  ",
> >             "How many pages have you read?  ",
> >             "What is your date to finish the book (yyyy-mm-dd)?  ",
> >         ]
> >         num_pages_in_book, num_pages_read, goal_date = map(
> >             get_input, str_converters, input_msgs
> >         )
> >         input_params = num_pages_in_book, num_pages_read, goal_date
> >         if validate_input_params(*input_params):
> >             return input_params
> >         print()
> >
>
> Your docstring is useless.  A docstring should describe what the code
> requires coming in, what it returns, and what function it performs.
> Its not useful to say something like you have:  it does what it needs
> to do?

I did restate the obvious, didn't I?  I know I am supposed to have
some sort of meaningful one-liner to start the docstring before
providing more detailed information below the opening line.  I am
obviously struggling on what to put on this summary line.

> Also, get_input_parameters has no arguments.  and it either returns
> something, or it returns nothing.

Again, I am looping until the user provides logically valid input
before considering the input valid and returning it.  Same question:
Should I have done this differently?

> > def validate_input_params(num_pages_in_book, num_pages_read, goal_date):
> >     """Verify input parameters for logical correctness."""
> >     valid_input = True
> >     print()
> >     if num_pages_in_book <= 0:
> >         print("The number of pages in a book must be a positive integer!")
> >         valid_input = False
> >     if num_pages_read < 0:
> >         print("The number of pages read must be a whole number!")
> >         valid_input = False
> >     if num_pages_read == num_pages_in_book and num_pages_in_book > 0:
> >         print(
> >             "You have already read the entire book!  Why are you
> > running this program?"
> >         )
> >     if num_pages_read > num_pages_in_book:
> >         print("You cannot have read more pages than there are in the book!")
> >         valid_input = False
> >     if goal_date < date.today():
> >         print("You cannot set a goal date in the past!")
> >         valid_input = False
> >     return valid_input
> >
>
> Again, you are too general in your docstring. And you don't spell out
> what this thing returns

Duly noted.

> > def calc_pages_per_day(num_pages_in_book, num_pages_read, goal_date):
> >     """Return number of pages to read each day to attain goal."""
> >     COUNT_TODAY = 1
> >     days_to_goal = (goal_date - date.today()).days
> >     pages_per_day = (num_pages_in_book - num_pages_read) /
> > (days_to_goal + COUNT_TODAY)
> >     return pages_per_day
> >
>
> This one is ok i guess
> >
> > def display_result(pages_per_day):
> >     """Display how many pages per day the reader must read to finish
> > the book."""
> >     if 0 < pages_per_day <= 1:
> >         word_to_display = "page"
> >     else:
> >         word_to_display = "pages"
> >     print(
> >         "You must read {0:.2n} {1} per day to reach your goal.".format(
> >             pages_per_day, word_to_display
> >         )
> >     )
> >
>
> I would prefer that I do prints with values returned from functions,
> rather than have the function print some value.

I am not sure I am comprehending your point.  Are you saying that the
above function, display_result(pages_per_day), should not have passed
in, pages_per_day, but instead called calc_pages_per_day(), and then
printed that returned result?  If this is correct, what are the
significant differences between the two approaches?  This is what I am
not seeing.

> > def main():
> >     """Run program and display results."""
> >     print(
> >         'Welcome to "HOW MANY PAGES???"\n'
> >         "Follow on-screen directions to determine how many pages to
> > read each day to "
> >         "finish your book.\n\n"
> >     )
> >     while True:
> >         input_params = get_input_params()
> >         display_result(calc_pages_per_day(*input_params))
> >         run_again = input("Enter 'q' to quit or anything else to continue:  ")
> >         if run_again.lower().startswith("q"):
> >             break
> >
> This might be simplified like:
> while True:
>     display_results(calc_pages_per_day(*get_input_params())
>     if  input("bla bla").lower().startswith('q'):
>         break;

That does seem simpler and clearer.  Thanks.

> > if __name__ == "__main__":
> >     main()
> > ============================================================================



-- 
boB

From alan.gauld at yahoo.co.uk  Sat Jan  4 18:43:16 2020
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Sat, 4 Jan 2020 23:43:16 +0000
Subject: [Tutor] How to refactor a simple,
 straightforward script into a "proper" program?
In-Reply-To: <CANDiX9+Rx-syD++J2XuNHyknEccwBC=wBFPpHd7A6DYKYkubNQ@mail.gmail.com>
References: <CANDiX9JjoXfpEBvnmsJWrAyumLvsKUN39VcaTvoG05-Cnm1DHA@mail.gmail.com>
 <45f1a074-d8bc-ec13-9757-4686ee60462d@DancesWithMice.info>
 <CANDiX9Kv=675fXb=it=tTh2hf+Nx4rTyD7bHS4St9UUizYtZDw@mail.gmail.com>
 <CANDiX9+Rx-syD++J2XuNHyknEccwBC=wBFPpHd7A6DYKYkubNQ@mail.gmail.com>
Message-ID: <928a7db3-50a7-9bca-7ce3-01323222b237@yahoo.co.uk>

On 04/01/2020 07:10, boB Stepp wrote:
> I now believe that I have a finalized version2.py that I am satisfied
> with. 

I've just joined this thread, but I believe the intent was to produce an
industrial standard module?

A few comments...

> <final version2.py>

Terrible name for a module! :-)
Rename it to express what it does.

> ============================================================================
> #!/usr/bin/env python3
> """Calculate the number of pages per day needed to read a book by a
> given date."""

Give some examples. eg. If a book has 400 pages and there is one day it
will be 400, if 20 days, 20 pages/day. Something like that.

> 
> from datetime import date
> 
> 
> def get_input(str_converter, msg):
>     """Prompt user with a message and return user input with the
> correct data type."""

That's what it says it does but....

>     while True:
>         try:
>             return str_converter(input(msg))
>         except ValueError:
>             if str_converter == int:
>                 print("\nPlease enter a whole number!")
>             elif str_converter == date.fromisoformat:
>                 print("\nPlease enter a valid date in the following
> format yyyy-mm-dd!")

And if its not one of those types? I get a ValueError raised then it
does nothing. It just returns None. That's not very friendly.
Maybe you should mention that. And describe the type limitations
in the doc string. Or rename the function to get_number_input()

This sounds like a reusable function, but in fact its pretty tied into
the problem at hand.

> def get_input_params():
>     """Collect all needed input parameters."""

What? For anything? Wow! a magic function that I can use to get any
input parameters I ever need. Fantastic. Except.... That's not
really what it does.

Again this is not reusable code, its just a bit of the main function
broken out. Thats OK but you need to tell people that its problem
specific and maybe indicate its not reusable by renaming it
_get_input_params() or something?


>     while True:
>         str_converters = [int, int, date.fromisoformat]
>         input_msgs = [
>             "How many pages are there in your book?  ",
>             "How many pages have you read?  ",
>             "What is your date to finish the book (yyyy-mm-dd)?  ",
>         ]
>         num_pages_in_book, num_pages_read, goal_date = map(
>             get_input, str_converters, input_msgs
>         )
>         input_params = num_pages_in_book, num_pages_read, goal_date
>         if validate_input_params(*input_params):
>             return input_params
>         print()

Frankly this isn't helping with DRY, you could just as well put the
innards into main(). It is all specific to the main function, there is
only one call to the function. So you might as well put the code where
it is needed.

Personally, I think 3 calls to get_input() with the different
arguments would be nicer too. Its not repeated code because you are
passing different values. Its like using print(). Just because we call
print() multiple times doesn't mean we should build some kind of output
function that stores all of the output strings and then displays them,
with pauses at key points etc. It doable (via yield etc) but not good
code. We just call print() with different values.

> def validate_input_params(num_pages_in_book, num_pages_read, goal_date):
>     """Verify input parameters for logical correctness."""

Needs much more work to describe what goes in, what comes out and what
exceptions might be thrown.... see comments below on that topic.


>     valid_input = True
>     print()
>     if num_pages_in_book <= 0:
>         print("The number of pages in a book must be a positive integer!")
>         valid_input = False
>     if num_pages_read < 0:
>         print("The number of pages read must be a whole number!")
>         valid_input = False
>     if num_pages_read == num_pages_in_book and num_pages_in_book > 0:
>         print(
>             "You have already read the entire book!  Why are you
> running this program?"
>         )

Note, that last clause returns True. So even though it makes no sense
you consider these valid inputs? Maybe that needs to be explained in the
doc-string too.

But...
Validation functions really shouldn't have lots of prints in them.
Separate logic from presentation. This should either return a boolean.
Or you can throw suitable errors as found. Let the caller decide what
to tell the user. This function should only validate the inputs.

>     if num_pages_read > num_pages_in_book:
>         print("You cannot have read more pages than there are in the book!")
>         valid_input = False
>     if goal_date < date.today():
>         print("You cannot set a goal date in the past!")
>         valid_input = False
>     return valid_input
> 

Personally I'd opt to raise ValueErrors for te fails with the strings
attached. Then return True if the function passes (so you can use
it in a test).

> def calc_pages_per_day(num_pages_in_book, num_pages_read, goal_date):
>     """Return number of pages to read each day to attain goal."""

I'd remove the calc from the name. Call it after what it returns.
I'd rather read

ppd = pages_per_day(bp, rp, due)

than

ppd = calc_pages_per_day(bp,rp,due)

Maybe its just me but the calc seems implied by the function call.

>     COUNT_TODAY = 1
>     days_to_goal = (goal_date - date.today()).days
>     pages_per_day = (num_pages_in_book - num_pages_read) /
> (days_to_goal + COUNT_TODAY)
>     return pages_per_day

> def display_result(pages_per_day):
>     """Display how many pages per day the reader must read to finish
> the book."""
>     if 0 < pages_per_day <= 1:
>         word_to_display = "page"

Would you really say page if it was 0.5 pages per day?
I'd only use 'page' if it was exactly 1.

But since its a float you need to use an epsilon value.
So

e = 0.0001
if 1-e < pages_per_day < 1+e:
    word_to_display = 'page'
else: word_to_display = 'pages'

>     else:
>         word_to_display = "pages"
>     print(
>         "You must read {0:.2n} {1} per day to reach your goal.".format(
>             pages_per_day, word_to_display
>         )
>     )

> def main():
>     """Run program and display results."""
>     print(
>         'Welcome to "HOW MANY PAGES???"\n'
>         "Follow on-screen directions to determine how many pages to
> read each day to "
>         "finish your book.\n\n"
>     )

Why the mixed quotes? Make them all single quotes?
Or use one pair of triple quotes?

>     while True:
>         input_params = get_input_params()
>         display_result(calc_pages_per_day(*input_params))
>         run_again = input("Enter 'q' to quit or anything else to continue:  ")
>         if run_again.lower().startswith("q"):
>             break
> 
> if __name__ == "__main__":
>     main()

In summary:
1) expand the doc-strings to describe input/output/errors
   and limitations. Think about using the type inference
   style notation for showing input and return types.
2) if a function isn't generally reusable make it obvious
   by putting an underscore in front of the name. (or
   make it generally reusable...usually much harder :-)
3) separate presentation and logic.
4) use exceptions more

Finally, consider wider usage. eBooks don't have consistent
numbers of pages - it depends on font-size set by the user
etc. So maybe an option to use lines or characters instead
of pages? Or even percent as reported by a Kindle?

The calculations are the same.
The validation might need extra work.
The output display would be different - needing a unit added?


-- 
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 mats at wichmann.us  Sat Jan  4 18:45:45 2020
From: mats at wichmann.us (Mats Wichmann)
Date: Sat, 4 Jan 2020 16:45:45 -0700
Subject: [Tutor] How to refactor a simple,
 straightforward script into a "proper" program?
In-Reply-To: <CANDiX9JM3na92Umtdi=iE2mwKxor4U3PgFDL7htxMw9V=U4k9g@mail.gmail.com>
References: <CANDiX9JjoXfpEBvnmsJWrAyumLvsKUN39VcaTvoG05-Cnm1DHA@mail.gmail.com>
 <45f1a074-d8bc-ec13-9757-4686ee60462d@DancesWithMice.info>
 <CANDiX9Kv=675fXb=it=tTh2hf+Nx4rTyD7bHS4St9UUizYtZDw@mail.gmail.com>
 <CANDiX9+Rx-syD++J2XuNHyknEccwBC=wBFPpHd7A6DYKYkubNQ@mail.gmail.com>
 <CAPM-O+wdNSLjha_91dV_84FSJWReZxGcv1qdYmp9CXpb2K27ag@mail.gmail.com>
 <CANDiX9JM3na92Umtdi=iE2mwKxor4U3PgFDL7htxMw9V=U4k9g@mail.gmail.com>
Message-ID: <dc5ce6b1-f5d1-64fd-7732-8e76c7d05e42@wichmann.us>

On 1/4/20 4:05 PM, boB Stepp wrote:
> Thank you, Joel, for your comments.  I have found them valuable.
...
> One question I do wish to ask up front:  _If_ type annotations are
> used, does this affect how the code is documented?  My impression is
> that with my code as is (no type annotations) I should have added a
> section for each function explaining the expected type and function of
> each parameter and value returned.  But if I do use type annotations,
> that would seem redundant.

I think there may not be full consensus yet, as type hints are still 
kind of new to people, and with many people having to live with Python 2 
use, either "until recently" or "for a while yet because of our 
project", haven't really been fully utilized. The idea is to convey 
information so it's useful to humans _and_ to tools you may choose to 
use. If you were targeting a Python version that didn't have the hints, 
they had to go in an external hints file for the tools to find, and that 
provides no help to human readers. In 2020, maybe that consideration 
isn't as important, with many people able to target just "modern" Python.

Yes, if you have a type hint, the type part of docstring parameter 
markup is redundant, and can be left out. You probably still want to say 
other things about the parameter, however.

That is, unannotated, you could express validate_input_parameters as 
(using the "Google docstring format"):

def validate_input_params(num_pages_in_book, num_pages_read, goal_date):
     """Verify input parameters for logical correctness.

     Args:
         num_pages_in_book (int): number of pages available
         num_pages_read (int): number of pages read
         goal_date (datetime.date): target finish date

     Returns:
         bool: input validity

     """

but with annotations, maybe:

def validate_input_params(num_pages_in_book: int, num_pages_read: int, 
goal_date: datetime.date) -> bool:
     """Verify input parameters for logical correctness.

     Args:
         num_pages_in_book: number of pages available
         num_pages_read: number of pages read
         goal_date: target finish date

     """

Or not... as you know, there's nothing mandatory about this, it's how 
you think the information is best conveyed - to future you, and to any 
other readers (or if part of a larger project, following the conventions 
that project follows).  You could argue, for example, that you've chosen 
such exquisite variable names that you don't need to bother saying what 
they're for.  In the case of this function, that wouldn't be a totally 
off-base assertion.


From PyTutor at danceswithmice.info  Sat Jan  4 21:06:36 2020
From: PyTutor at danceswithmice.info (DL Neil)
Date: Sun, 5 Jan 2020 15:06:36 +1300
Subject: [Tutor] How to refactor a simple,
 straightforward script into a "proper" program?
In-Reply-To: <CANDiX9JM3na92Umtdi=iE2mwKxor4U3PgFDL7htxMw9V=U4k9g@mail.gmail.com>
References: <CANDiX9JjoXfpEBvnmsJWrAyumLvsKUN39VcaTvoG05-Cnm1DHA@mail.gmail.com>
 <45f1a074-d8bc-ec13-9757-4686ee60462d@DancesWithMice.info>
 <CANDiX9Kv=675fXb=it=tTh2hf+Nx4rTyD7bHS4St9UUizYtZDw@mail.gmail.com>
 <CANDiX9+Rx-syD++J2XuNHyknEccwBC=wBFPpHd7A6DYKYkubNQ@mail.gmail.com>
 <CAPM-O+wdNSLjha_91dV_84FSJWReZxGcv1qdYmp9CXpb2K27ag@mail.gmail.com>
 <CANDiX9JM3na92Umtdi=iE2mwKxor4U3PgFDL7htxMw9V=U4k9g@mail.gmail.com>
Message-ID: <3364d7bd-482f-f538-da1f-90839ccaa493@DancesWithMice.info>

On 5/01/20 12:05 PM, boB Stepp wrote:
> On first reading, the bulk of your comments are about code
> documentation, and, I believe, expose weaknesses in my understanding
> of what is expected and required.  After I complete this initial
> reaction to your comments, I am going to hit the 'Net and review
> docstrings and code commenting and then return with some code updates
> to see if my understanding has improved.  One thing that struck me on
> my initial read is that while I was trying to refactor the original
> simple script into something more robust, I was still retaining a
> "simple script" mentality for my code documentation.  I expect this is
> a faulty habit I have fallen into from not having any oversight of my
> coding efforts (Other than my questions on this list.).

Hopefully the readings will answer that level of your question.

+1 to the mind-set of "simple-script" being incorrect, even, unprofessional.

When you think about it every function/method should be "simple"! If 
this is not immediately-apparent, recommend adding to your DRY-intent a 
paper/page or two about the principles of "successive refinement" and 
"separation of concerns".

If you take the principle of "re-use" (not quite to the point of 
absurdity), is there much of a concept of a "simple script mentality"?


+1 your attitude to improving/re-factoring code, towards improvement.

If you do not consider OOP to be (too) 'advanced', what may help is 
drawing a UML diagram - if UML is not in your portfolio (and to ease 
email-presentation), instead make two (equivalent to UML) lists:-

What is the subject of the computation? A book.
How are you measuring its size? Nr Pages.

What is the objective of the computation: set a reading-rate in pages 
per day. (more/better expression?)


List 1: what pieces of data do you need to know, to describe the book, 
and carry-out computation


List 2: what computations do you need to carry-out (in relation to the 
book), eg can we have a book with a non-positive number of pages? with a 
'number' of pages (in book, or read) which is non-numeric?


Does this process help to 'refine' the problem into smaller problems?
Does it help to organise the data?
Does it help to see what you might need to code as functions/methods?


NB it doesn't really matter which way-around you write the lists, and 
in-truth you may find that writing one stimulates additions/alterations 
to what you've already written on the other.

NBB some will argue about whether considerations of the number of pages 
in a book belong with "book" or are better tackled as 'input', but for 
this particular/introductory/illustrative thought-process it will not 
matter...


After such an exercise, does it (combined with earlier comments about 
functionality) help your thinking towards program design?


> One question I do wish to ask up front:  _If_ type annotations are
> used, does this affect how the code is documented?  My impression is
> that with my code as is (no type annotations) I should have added a
> section for each function explaining the expected type and function of
> each parameter and value returned.  But if I do use type annotations,
> that would seem redundant.

One of my favorite comments about comments (and docstrings) was 
"mumbling". My recollection is that this was describing comments that 
were either of no real use, eg "# adding a to b"; or were purely there 
in order to satisfy 'requirements' - I've been known to persuade a 
linter to shut-up by writing ''' Docstring. ''' (don't forget the u/case 
nor the final punctuation!) BTW I think I'm fooling the linter, but I'm 
really only fooling myself...


Others have recommended improved names (and the above design-exercise 
may also help with that). If a name is 'good', it requires no comment:

	number_of_pages	# book size in pages	<<<--- mumbling!

That said, does that name refer to the number of pages in the book - 
what about the number of pages the reader has already consumed?

Stating the data-type is useful. As you've already noted, the ratio of 
remaining pages must be computed with numeric values, whereas the input 
data was strings! Having this information presented as 
typing-annotations saves us from putting it in a comment.
(which is 'better' is another discussion, for another day)


That said, for your consideration:
(with apologies that email will re-format/mess-up presentation)

	function calculate_remaining_pages(
			number_of_pages_in_book:int,
			number_of_pages_already_read:int,
			)->int:
		return ( number_of_pages_in_book -
					( number_of_pages_in_book -
					number_of_pages_already_read
					)
			)

With the choice of reasonable (if improvable - in your application) 
names, and very simple functionality, what could be added through 
'documentation'?


However, consider a function which had the objective of accepting 
("only") a single numeric input value. Could you (anyone) write a 
function/method which required no supportive documentation?


So, in the same way that functions/methods written in Python describe 
functionality, what is the purpose of 'documentation'?
(and for bonus-points: who is documentation written to/for?)
-- 
Regards =dn

From robertvstepp at gmail.com  Sun Jan  5 00:40:57 2020
From: robertvstepp at gmail.com (boB Stepp)
Date: Sat, 4 Jan 2020 23:40:57 -0600
Subject: [Tutor] How to refactor a simple,
 straightforward script into a "proper" program?
In-Reply-To: <928a7db3-50a7-9bca-7ce3-01323222b237@yahoo.co.uk>
References: <CANDiX9JjoXfpEBvnmsJWrAyumLvsKUN39VcaTvoG05-Cnm1DHA@mail.gmail.com>
 <45f1a074-d8bc-ec13-9757-4686ee60462d@DancesWithMice.info>
 <CANDiX9Kv=675fXb=it=tTh2hf+Nx4rTyD7bHS4St9UUizYtZDw@mail.gmail.com>
 <CANDiX9+Rx-syD++J2XuNHyknEccwBC=wBFPpHd7A6DYKYkubNQ@mail.gmail.com>
 <928a7db3-50a7-9bca-7ce3-01323222b237@yahoo.co.uk>
Message-ID: <CANDiX9+B=ZwXCdd_pJzVkYbq_DbZgQQnyAmyJGRowVmYP5bP9w@mail.gmail.com>

On Sat, Jan 4, 2020 at 5:43 PM Alan Gauld via Tutor <tutor at python.org> wrote:
>
> On 04/01/2020 07:10, boB Stepp wrote:

> I've just joined this thread, but I believe the intent was to produce an
> industrial standard module?
>
> A few comments...

Uh, oh.  Alan is joining in.  Now I am going to get it good!  ~(:>))

> > <final version2.py>
>
> Terrible name for a module! :-)
> Rename it to express what it does.

Drat!  I was hoping to keep upping the number on the end...

> > ============================================================================
> > #!/usr/bin/env python3
> > """Calculate the number of pages per day needed to read a book by a
> > given date."""
>
> Give some examples. eg. If a book has 400 pages and there is one day it
> will be 400, if 20 days, 20 pages/day. Something like that.

As I said in response to Joel's comments, I am currently engaged on
some supplementary reading on this topic.  But in particular for a
stand-alone program file, I have found a lot of contradictory advice
in the past of what *should* be put at the top of the file.

> >
> > from datetime import date
> >
> >
> > def get_input(str_converter, msg):
> >     """Prompt user with a message and return user input with the
> > correct data type."""
>
> That's what it says it does but....
>
> >     while True:
> >         try:
> >             return str_converter(input(msg))
> >         except ValueError:
> >             if str_converter == int:
> >                 print("\nPlease enter a whole number!")
> >             elif str_converter == date.fromisoformat:
> >                 print("\nPlease enter a valid date in the following
> > format yyyy-mm-dd!")
>
> And if its not one of those types? I get a ValueError raised then it
> does nothing. It just returns None. That's not very friendly.

Huh?  Joel said something similar.  Maybe I am being dense, but it
*does* do something.  If the user types in something that is not one
of the allowed types, he gets a helpful message telling him/her what
the program is expecting, and the program loops back to the original
message requesting input.  The function will not terminate until the
user enters the expected input.  Once the user does enter
syntactically valid input, it will return that value.  What am I
missing or not understanding?

> Maybe you should mention that. And describe the type limitations
> in the doc string. Or rename the function to get_number_input()

But it also does date input.  And if in the future I wanted other
sorts of input I need only add new string converters for the new data
types.

> This sounds like a reusable function, but in fact its pretty tied into
> the problem at hand.

Again, I wonder if I am being dense, but my intent with this function
is to handle a variety of input types.  I would have to add new
ValueError possibilities for new data types.  Is this what bothers
you?

Hmm.  I see that in case of ValueError it could look elsewhere for
what sort of user friendly error message to display for a particular
value of str_converter.  Is this what you are getting at?

> > def get_input_params():
> >     """Collect all needed input parameters."""
>
> What? For anything? Wow! a magic function that I can use to get any
> input parameters I ever need. Fantastic. Except.... That's not
> really what it does.

Not a winning docstring selection.

> Again this is not reusable code, its just a bit of the main function
> broken out. Thats OK but you need to tell people that its problem
> specific and maybe indicate its not reusable by renaming it
> _get_input_params() or something?
>
>
> >     while True:
> >         str_converters = [int, int, date.fromisoformat]
> >         input_msgs = [
> >             "How many pages are there in your book?  ",
> >             "How many pages have you read?  ",
> >             "What is your date to finish the book (yyyy-mm-dd)?  ",
> >         ]
> >         num_pages_in_book, num_pages_read, goal_date = map(
> >             get_input, str_converters, input_msgs
> >         )
> >         input_params = num_pages_in_book, num_pages_read, goal_date
> >         if validate_input_params(*input_params):
> >             return input_params
> >         print()
>
> Frankly this isn't helping with DRY, you could just as well put the
> innards into main(). It is all specific to the main function, there is
> only one call to the function. So you might as well put the code where
> it is needed.
>
> Personally, I think 3 calls to get_input() with the different
> arguments would be nicer too. Its not repeated code because you are
> passing different values. Its like using print(). Just because we call
> print() multiple times doesn't mean we should build some kind of output
> function that stores all of the output strings and then displays them,
> with pauses at key points etc. It doable (via yield etc) but not good
> code. We just call print() with different values.

This function/portion of the code is what I struggled with the most.
Yes, its existence is to call get_input() as many times as needed for
the total number of pieces of data it needs from the user and to
validate each datum for logical correctness.  And it is where a lot of
problem specific things are being kept. str_converters and input_msgs
and the identifiers for each datum needed from the user.  I still feel
awkward about this function, but it looks worse to me as originally
presented in the "simple" script.  I have quickly looked over D. L.
Neil's comments, and, combined with yours, wonder if I should redesign
the whole shebang from the ground up?  Maybe this problem does need an
OO approach.

> > def validate_input_params(num_pages_in_book, num_pages_read, goal_date):
> >     """Verify input parameters for logical correctness."""
>
> Needs much more work to describe what goes in, what comes out and what
> exceptions might be thrown.... see comments below on that topic.
>
>
> >     valid_input = True
> >     print()
> >     if num_pages_in_book <= 0:
> >         print("The number of pages in a book must be a positive integer!")
> >         valid_input = False
> >     if num_pages_read < 0:
> >         print("The number of pages read must be a whole number!")
> >         valid_input = False
> >     if num_pages_read == num_pages_in_book and num_pages_in_book > 0:
> >         print(
> >             "You have already read the entire book!  Why are you
> > running this program?"
> >         )
>
> Note, that last clause returns True. So even though it makes no sense
> you consider these valid inputs? Maybe that needs to be explained in the
> doc-string too.

After some thought I decided that this should be logically valid input
despite the user being a bit thick-headed in this case.  So if the
user has already read the book, he is dutifully told this and the
program will ultimately tell him he needs to read zero pages per day.
I did not explicitly code "valid_input = True" as that is the default.
Perhaps I should have put in a comment regarding this design decision?

> But...
> Validation functions really shouldn't have lots of prints in them.
> Separate logic from presentation. This should either return a boolean.
> Or you can throw suitable errors as found. Let the caller decide what
> to tell the user. This function should only validate the inputs.

I grudgingly concede your point.  Grudgingly because now I have to
figure out how to accomplish this.  ~(:>))

> >     if num_pages_read > num_pages_in_book:
> >         print("You cannot have read more pages than there are in the book!")
> >         valid_input = False
> >     if goal_date < date.today():
> >         print("You cannot set a goal date in the past!")
> >         valid_input = False
> >     return valid_input
> >
>
> Personally I'd opt to raise ValueErrors for te fails with the strings
> attached. Then return True if the function passes (so you can use
> it in a test).
>
> > def calc_pages_per_day(num_pages_in_book, num_pages_read, goal_date):
> >     """Return number of pages to read each day to attain goal."""
>
> I'd remove the calc from the name. Call it after what it returns.
> I'd rather read
>
> ppd = pages_per_day(bp, rp, due)
>
> than
>
> ppd = calc_pages_per_day(bp,rp,due)
>
> Maybe its just me but the calc seems implied by the function call.

But I thought the great preference was for function and method names
to be verbs not nouns?

> >     COUNT_TODAY = 1
> >     days_to_goal = (goal_date - date.today()).days
> >     pages_per_day = (num_pages_in_book - num_pages_read) /
> > (days_to_goal + COUNT_TODAY)
> >     return pages_per_day
>
> > def display_result(pages_per_day):
> >     """Display how many pages per day the reader must read to finish
> > the book."""
> >     if 0 < pages_per_day <= 1:
> >         word_to_display = "page"
>
> Would you really say page if it was 0.5 pages per day?

Actually, yes.  Just as I would say a half page per day.  OTOH, I
would say zero pages per day.  Maybe I need to dust off a grammar
book...

> I'd only use 'page' if it was exactly 1.
>
> But since its a float you need to use an epsilon value.
> So
>
> e = 0.0001
> if 1-e < pages_per_day < 1+e:
>     word_to_display = 'page'
> else: word_to_display = 'pages'

Do I really need an epsilon value for this particular case?  I am not
seeing where my intentions would fail here.  Can you provide an
example?  I am happy, say, if a user puts in some absurd goal date
that results in a pages per day of 1.7 e -100, if he/she really wants
to.  Originally I thought I would prohibit such things, but I finally
thought if the user wishes to be silly here, why not?

> >     else:
> >         word_to_display = "pages"
> >     print(
> >         "You must read {0:.2n} {1} per day to reach your goal.".format(
> >             pages_per_day, word_to_display
> >         )
> >     )
>
> > def main():
> >     """Run program and display results."""
> >     print(
> >         'Welcome to "HOW MANY PAGES???"\n'
> >         "Follow on-screen directions to determine how many pages to
> > read each day to "
> >         "finish your book.\n\n"
> >     )
>
> Why the mixed quotes? Make them all single quotes?
> Or use one pair of triple quotes?

I originally in my code did not use mixed quotes.  But when I saved
the file my new code formatting tyrant, Black, changed my consistent
quoting style to mixed quotes.  Apparently it insists on all double
quotes unless there are embedded quotes within when it converts those
to single quotes.

> >     while True:
> >         input_params = get_input_params()
> >         display_result(calc_pages_per_day(*input_params))
> >         run_again = input("Enter 'q' to quit or anything else to continue:  ")
> >         if run_again.lower().startswith("q"):
> >             break
> >
> > if __name__ == "__main__":
> >     main()
>
> In summary:
> 1) expand the doc-strings to describe input/output/errors
>    and limitations. Think about using the type inference
>    style notation for showing input and return types.
> 2) if a function isn't generally reusable make it obvious
>    by putting an underscore in front of the name. (or
>    make it generally reusable...usually much harder :-)

This is where I was hoping for some concrete, helpful examples.  I do
indeed find this "much harder".

> 3) separate presentation and logic.

Again, I find this not so easy.

> 4) use exceptions more
>
> Finally, consider wider usage. eBooks don't have consistent
> numbers of pages - it depends on font-size set by the user
> etc. So maybe an option to use lines or characters instead
> of pages? Or even percent as reported by a Kindle?
>
> The calculations are the same.
> The validation might need extra work.
> The output display would be different - needing a unit added?

FEATURE CREEP!  Actually sounds like an interesting addition.  But I
don't much like eReaders myself.  I do read my newspaper on an iPad
the company kindly supplied, but usually not books.  I like the feel
of a tangible book, but I'm an old fart, I guess.  I'd have to
research this some to consider implementing it.  My wife would make a
good source of info as she is always reading stuff on her phone or
Surface Pro.

Thanks for the detailed breakdown!

boB

From johnf at jfcomputer.com  Sun Jan  5 01:22:08 2020
From: johnf at jfcomputer.com (john)
Date: Sat, 4 Jan 2020 22:22:08 -0800
Subject: [Tutor] dealing with wheels
Message-ID: <64ce7aaf-2228-19d8-94d9-91a94e679c70@jfcomputer.com>

Hi,

In some cases it is possible to download a .whl for use offline.? But in 
some cases I don't see the whl file.? It appears it (the module) can be 
installed using "pip install".

So if can be installed using pip where is the .whl file?

I need to be able to install while offline.

Johnf

From gogonegro at gmail.com  Sun Jan  5 11:00:54 2020
From: gogonegro at gmail.com (Robert Alexander)
Date: Sun, 5 Jan 2020 17:00:54 +0100
Subject: [Tutor] Please help disentangle my program logic
Message-ID: <CADiDnXf=aDNirX7xtjV57riqWC6GJC6J2WQ-pQsNdDA6wOhAXA@mail.gmail.com>

Dear friends and tutors,
Also thanks to some of your help I have written my first little python
program.

It now lives on Github https://github.com/rjalexa/adsl-warn and its purpose
is to monitor my home ADSL speeds, log them and if they degrade send me a
Gmail email with increasing frequency.

While is does work ok, thinking about it?s overall flow there are things I
do not like.

The next iteration should always log a line covering all cases from the LAN
not functioning, to Internet not reachable (and of course in these cases I
should log but not attempt to send an email), to the degraded (log + email)
and normal (log only) speeds.

I usually run this program as described in the requirements.txt file as
"nohup python -u speedtest.py >> adsl.log &"

As you can see in the current version the st_json function spits out two
log lines which have a different format from the usual ones and quits
altogether breaking the while True loop. This might be acceptable in the
?Speedtest prerequisite not installed? case but not for the ?Internet down
case? which should be logged (the frequencies of logging are computed in
the set_frequency function and currently do not contemplate the
Internet-offline case).

So currently the function calls in the main are a bit of spaghetti logic
which makes it hard to define a standard modular log line that could be
parseable in the future.

Two main questions are:

A) Are there tools to quickly/neatly look at a flow of your program? For
example how would you modify the st_json function to handle both a
successful measure but also the other two cases (Internet not reachable and
speediest CLI not installed)?

B) Suggestions to make this little program more rational?

Thank you all very much in advance
Robert

From mayoadams at gmail.com  Sun Jan  5 12:42:52 2020
From: mayoadams at gmail.com (Mayo Adams)
Date: Sun, 5 Jan 2020 12:42:52 -0500
Subject: [Tutor] Please help disentangle my program logic
In-Reply-To: <CADiDnXf=aDNirX7xtjV57riqWC6GJC6J2WQ-pQsNdDA6wOhAXA@mail.gmail.com>
References: <CADiDnXf=aDNirX7xtjV57riqWC6GJC6J2WQ-pQsNdDA6wOhAXA@mail.gmail.com>
Message-ID: <CALaREKb2JB=yzypB0nroxK5oyt2x9Pb3f5Z7O-nLt-bjivcjMg@mail.gmail.com>

The pages of Phillip Guo might possibly help, though your stuff looks
pretty advanced (pythontutor.com/visualize).

On Sun, Jan 5, 2020 at 11:01 AM Robert Alexander <gogonegro at gmail.com>
wrote:

> Dear friends and tutors,
> Also thanks to some of your help I have written my first little python
> program.
>
> It now lives on Github https://github.com/rjalexa/adsl-warn and its
> purpose
> is to monitor my home ADSL speeds, log them and if they degrade send me a
> Gmail email with increasing frequency.
>
> While is does work ok, thinking about it?s overall flow there are things I
> do not like.
>
> The next iteration should always log a line covering all cases from the LAN
> not functioning, to Internet not reachable (and of course in these cases I
> should log but not attempt to send an email), to the degraded (log + email)
> and normal (log only) speeds.
>
> I usually run this program as described in the requirements.txt file as
> "nohup python -u speedtest.py >> adsl.log &"
>
> As you can see in the current version the st_json function spits out two
> log lines which have a different format from the usual ones and quits
> altogether breaking the while True loop. This might be acceptable in the
> ?Speedtest prerequisite not installed? case but not for the ?Internet down
> case? which should be logged (the frequencies of logging are computed in
> the set_frequency function and currently do not contemplate the
> Internet-offline case).
>
> So currently the function calls in the main are a bit of spaghetti logic
> which makes it hard to define a standard modular log line that could be
> parseable in the future.
>
> Two main questions are:
>
> A) Are there tools to quickly/neatly look at a flow of your program? For
> example how would you modify the st_json function to handle both a
> successful measure but also the other two cases (Internet not reachable and
> speediest CLI not installed)?
>
> B) Suggestions to make this little program more rational?
>
> Thank you all very much in advance
> Robert
> _______________________________________________
> Tutor maillist  -  Tutor at python.org
> To unsubscribe or change subscription options:
> https://mail.python.org/mailman/listinfo/tutor
>


-- 
Mayo Adams

287 Erwin Rd.
Chapel Hill, NC 27514
(919)-780-3917
mayoadams at gmail.com

From gogonegro at gmail.com  Sun Jan  5 12:47:44 2020
From: gogonegro at gmail.com (Robert Alexander)
Date: Sun, 5 Jan 2020 18:47:44 +0100
Subject: [Tutor] Please help disentangle my program logic
In-Reply-To: <CALaREKb2JB=yzypB0nroxK5oyt2x9Pb3f5Z7O-nLt-bjivcjMg@mail.gmail.com>
References: <CADiDnXf=aDNirX7xtjV57riqWC6GJC6J2WQ-pQsNdDA6wOhAXA@mail.gmail.com>
 <CALaREKb2JB=yzypB0nroxK5oyt2x9Pb3f5Z7O-nLt-bjivcjMg@mail.gmail.com>
Message-ID: <CADiDnXcA=t+vL_F8_qfpjj0t2c1=Nz=Txt9ZfOmbEhp4c8gK9g@mail.gmail.com>

Thank you very much,  but it gives a 404 not found error.


On 5 January 2020 at 18:43:03, Mayo Adams (mayoadams at gmail.com) wrote:

The pages of Phillip Guo might possibly help, though your stuff looks
pretty advanced (pythontutor.com/visualize).

On Sun, Jan 5, 2020 at 11:01 AM Robert Alexander <gogonegro at gmail.com>
wrote:

> Dear friends and tutors,
> Also thanks to some of your help I have written my first little python
> program.
>
> It now lives on Github https://github.com/rjalexa/adsl-warn and its
> purpose
> is to monitor my home ADSL speeds, log them and if they degrade send me a
> Gmail email with increasing frequency.
>
> While is does work ok, thinking about it?s overall flow there are things I
> do not like.
>
> The next iteration should always log a line covering all cases from the LAN
> not functioning, to Internet not reachable (and of course in these cases I
> should log but not attempt to send an email), to the degraded (log + email)
> and normal (log only) speeds.
>
> I usually run this program as described in the requirements.txt file as
> "nohup python -u speedtest.py >> adsl.log &"
>
> As you can see in the current version the st_json function spits out two
> log lines which have a different format from the usual ones and quits
> altogether breaking the while True loop. This might be acceptable in the
> ?Speedtest prerequisite not installed? case but not for the ?Internet down
> case? which should be logged (the frequencies of logging are computed in
> the set_frequency function and currently do not contemplate the
> Internet-offline case).
>
> So currently the function calls in the main are a bit of spaghetti logic
> which makes it hard to define a standard modular log line that could be
> parseable in the future.
>
> Two main questions are:
>
> A) Are there tools to quickly/neatly look at a flow of your program? For
> example how would you modify the st_json function to handle both a
> successful measure but also the other two cases (Internet not reachable and
> speediest CLI not installed)?
>
> B) Suggestions to make this little program more rational?
>
> Thank you all very much in advance
> Robert
> _______________________________________________
> Tutor maillist  -  Tutor at python.org
> To unsubscribe or change subscription options:
> https://mail.python.org/mailman/listinfo/tutor
>


--
Mayo Adams

287 Erwin Rd.
Chapel Hill, NC 27514
(919)-780-3917
mayoadams at gmail.com

From mayoadams at gmail.com  Sun Jan  5 13:11:19 2020
From: mayoadams at gmail.com (Mayo Adams)
Date: Sun, 5 Jan 2020 13:11:19 -0500
Subject: [Tutor] Please help disentangle my program logic
In-Reply-To: <CADiDnXcA=t+vL_F8_qfpjj0t2c1=Nz=Txt9ZfOmbEhp4c8gK9g@mail.gmail.com>
References: <CADiDnXf=aDNirX7xtjV57riqWC6GJC6J2WQ-pQsNdDA6wOhAXA@mail.gmail.com>
 <CALaREKb2JB=yzypB0nroxK5oyt2x9Pb3f5Z7O-nLt-bjivcjMg@mail.gmail.com>
 <CADiDnXcA=t+vL_F8_qfpjj0t2c1=Nz=Txt9ZfOmbEhp4c8gK9g@mail.gmail.com>
Message-ID: <CALaREKbZ6vHJbmz3aSyo-3_D57ApJvr4d6Ztub7Uzjq3nWzdaQ@mail.gmail.com>

If you "Google" Visualize Python, you might have better luck. I just did
it, no problem.It's an interesting tool to help you understand program
execution. Even if it's too basic for what you're up to, I think it's
worthwhile to know about.

On Sun, Jan 5, 2020 at 12:47 PM Robert Alexander <gogonegro at gmail.com>
wrote:

> Thank you very much,  but it gives a 404 not found error.
>
>
> On 5 January 2020 at 18:43:03, Mayo Adams (mayoadams at gmail.com) wrote:
>
> The pages of Phillip Guo might possibly help, though your stuff looks
> pretty advanced (pythontutor.com/visualize).
>
> On Sun, Jan 5, 2020 at 11:01 AM Robert Alexander <gogonegro at gmail.com>
> wrote:
>
>> Dear friends and tutors,
>> Also thanks to some of your help I have written my first little python
>> program.
>>
>> It now lives on Github https://github.com/rjalexa/adsl-warn and its
>> purpose
>> is to monitor my home ADSL speeds, log them and if they degrade send me a
>> Gmail email with increasing frequency.
>>
>> While is does work ok, thinking about it?s overall flow there are things I
>> do not like.
>>
>> The next iteration should always log a line covering all cases from the
>> LAN
>> not functioning, to Internet not reachable (and of course in these cases I
>> should log but not attempt to send an email), to the degraded (log +
>> email)
>> and normal (log only) speeds.
>>
>> I usually run this program as described in the requirements.txt file as
>> "nohup python -u speedtest.py >> adsl.log &"
>>
>> As you can see in the current version the st_json function spits out two
>> log lines which have a different format from the usual ones and quits
>> altogether breaking the while True loop. This might be acceptable in the
>> ?Speedtest prerequisite not installed? case but not for the ?Internet down
>> case? which should be logged (the frequencies of logging are computed in
>> the set_frequency function and currently do not contemplate the
>> Internet-offline case).
>>
>> So currently the function calls in the main are a bit of spaghetti logic
>> which makes it hard to define a standard modular log line that could be
>> parseable in the future.
>>
>> Two main questions are:
>>
>> A) Are there tools to quickly/neatly look at a flow of your program? For
>> example how would you modify the st_json function to handle both a
>> successful measure but also the other two cases (Internet not reachable
>> and
>> speediest CLI not installed)?
>>
>> B) Suggestions to make this little program more rational?
>>
>> Thank you all very much in advance
>> Robert
>> _______________________________________________
>> Tutor maillist  -  Tutor at python.org
>> To unsubscribe or change subscription options:
>> https://mail.python.org/mailman/listinfo/tutor
>>
>
>
> --
> Mayo Adams
>
> 287 Erwin Rd.
> Chapel Hill, NC 27514
> (919)-780-3917
> mayoadams at gmail.com
>
>

-- 
Mayo Adams

287 Erwin Rd.
Chapel Hill, NC 27514
(919)-780-3917
mayoadams at gmail.com

From mats at wichmann.us  Sun Jan  5 13:18:11 2020
From: mats at wichmann.us (Mats Wichmann)
Date: Sun, 5 Jan 2020 11:18:11 -0700
Subject: [Tutor] Please help disentangle my program logic
In-Reply-To: <CADiDnXf=aDNirX7xtjV57riqWC6GJC6J2WQ-pQsNdDA6wOhAXA@mail.gmail.com>
References: <CADiDnXf=aDNirX7xtjV57riqWC6GJC6J2WQ-pQsNdDA6wOhAXA@mail.gmail.com>
Message-ID: <3b4dcc39-c49f-c13a-1a4a-bf4eec9f5b33@wichmann.us>

On 1/5/20 9:00 AM, Robert Alexander wrote:
> Dear friends and tutors,
> Also thanks to some of your help I have written my first little python
> program.
> 
> It now lives on Github https://github.com/rjalexa/adsl-warn and its purpose
> is to monitor my home ADSL speeds, log them and if they degrade send me a
> Gmail email with increasing frequency.
> 
> While is does work ok, thinking about it?s overall flow there are things I
> do not like.
> 
> The next iteration should always log a line covering all cases from the LAN
> not functioning, to Internet not reachable (and of course in these cases I
> should log but not attempt to send an email), to the degraded (log + email)
> and normal (log only) speeds.

quick reaction: look into the logging module to control how, where and 
what to log. No need to reinvent the wheel.

> 
> I usually run this program as described in the requirements.txt file as
> "nohup python -u speedtest.py >> adsl.log &"

You shouldn't need to depend on shell syntax to get this stuff to 
work... the logging module will handle appending, or you can do it 
yourself (print can take a a file= argument to show where to send the 
output, and you open that file first in the appropriate mode)

From gogonegro at gmail.com  Sun Jan  5 13:23:56 2020
From: gogonegro at gmail.com (Robert Alexander)
Date: Sun, 5 Jan 2020 19:23:56 +0100
Subject: [Tutor] Please help disentangle my program logic
In-Reply-To: <3b4dcc39-c49f-c13a-1a4a-bf4eec9f5b33@wichmann.us>
References: <CADiDnXf=aDNirX7xtjV57riqWC6GJC6J2WQ-pQsNdDA6wOhAXA@mail.gmail.com>
 <3b4dcc39-c49f-c13a-1a4a-bf4eec9f5b33@wichmann.us>
Message-ID: <CADiDnXcW=djbcJTwwBk3BkTFyz-2CJqcbsdhkADBbUPMX_r2NA@mail.gmail.com>

Thank you Mats. Very interesting observation.

May you kindly expand on why you are suggesting this?

In my opinion specifying a log name at runtime gives me more flexibility
but I might be not considering some other important reason.

Ciao

PS Etiquette question please: Is it better to reply to both the sender and
the list or the list only?


On 5 January 2020 at 19:18:30, Mats Wichmann (mats at wichmann.us) wrote:

On 1/5/20 9:00 AM, Robert Alexander wrote:
> Dear friends and tutors,
> Also thanks to some of your help I have written my first little python
> program.
>
> It now lives on Github https://github.com/rjalexa/adsl-warn and its
purpose
> is to monitor my home ADSL speeds, log them and if they degrade send me a
> Gmail email with increasing frequency.
>
> While is does work ok, thinking about it?s overall flow there are things I
> do not like.
>
> The next iteration should always log a line covering all cases from the
LAN
> not functioning, to Internet not reachable (and of course in these cases I
> should log but not attempt to send an email), to the degraded (log +
email)
> and normal (log only) speeds.

quick reaction: look into the logging module to control how, where and
what to log. No need to reinvent the wheel.

>
> I usually run this program as described in the requirements.txt file as
> "nohup python -u speedtest.py >> adsl.log &"

You shouldn't need to depend on shell syntax to get this stuff to
work... the logging module will handle appending, or you can do it
yourself (print can take a a file= argument to show where to send the
output, and you open that file first in the appropriate mode)
_______________________________________________
Tutor maillist - Tutor at python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor

From mats at wichmann.us  Sun Jan  5 13:34:32 2020
From: mats at wichmann.us (Mats Wichmann)
Date: Sun, 5 Jan 2020 11:34:32 -0700
Subject: [Tutor] Please help disentangle my program logic
In-Reply-To: <CADiDnXcW=djbcJTwwBk3BkTFyz-2CJqcbsdhkADBbUPMX_r2NA@mail.gmail.com>
References: <CADiDnXf=aDNirX7xtjV57riqWC6GJC6J2WQ-pQsNdDA6wOhAXA@mail.gmail.com>
 <3b4dcc39-c49f-c13a-1a4a-bf4eec9f5b33@wichmann.us>
 <CADiDnXcW=djbcJTwwBk3BkTFyz-2CJqcbsdhkADBbUPMX_r2NA@mail.gmail.com>
Message-ID: <32d4b470-c050-eb32-b4de-948e7679a678@wichmann.us>

On 1/5/20 11:23 AM, Robert Alexander wrote:
> Thank you Mats. Very interesting observation.
> 
> May you kindly expand on why you are suggesting this?
> 
> In my opinion specifying a log name at runtime gives me more flexibility
> but I might be not considering some other important reason.

Not sure I'm answering the right question here, but...

You can still specify the logging location on the command line by 
accepting an argument, and having a default in the program if it's not 
on the command line.

The logigng module gives you the flexibility to log to different places, 
even - you can put every reading in the log, and important events (like 
Internet connection is down) somewhere else - your console, sending by 
email (I'm not sure that's directly supported, but wouldn't be hard to 
set up), by assigning different log levels to different types of events.

> 
> Ciao
> 
> PS Etiquette question please: Is it better to reply to both the sender and
> the list or the list only?
> 
> 
> On 5 January 2020 at 19:18:30, Mats Wichmann (mats at wichmann.us) wrote:
> 

> quick reaction: look into the logging module to control how, where and
> what to log. No need to reinvent the wheel.

From gogonegro at gmail.com  Sun Jan  5 13:37:18 2020
From: gogonegro at gmail.com (Robert Alexander)
Date: Sun, 5 Jan 2020 19:37:18 +0100
Subject: [Tutor] Please help disentangle my program logic
In-Reply-To: <32d4b470-c050-eb32-b4de-948e7679a678@wichmann.us>
References: <CADiDnXf=aDNirX7xtjV57riqWC6GJC6J2WQ-pQsNdDA6wOhAXA@mail.gmail.com>
 <3b4dcc39-c49f-c13a-1a4a-bf4eec9f5b33@wichmann.us>
 <CADiDnXcW=djbcJTwwBk3BkTFyz-2CJqcbsdhkADBbUPMX_r2NA@mail.gmail.com>
 <32d4b470-c050-eb32-b4de-948e7679a678@wichmann.us>
Message-ID: <CADiDnXep1XrTbqT5LiGK89-LuJmS-170XwEHhGqBw6KPTZG7aA@mail.gmail.com>

That makes a lot of sense.

I already have such situation.

My program currently handles an ?exception? and exits if a prerequisite
external program is not found. So that would go to STDOUT/ERR and the logs
proper to a log via the logging module.

Excellent suggestion.

Thanks a lot.

Robert

On 5 January 2020 at 19:34:51, Mats Wichmann (mats at wichmann.us) wrote:

On 1/5/20 11:23 AM, Robert Alexander wrote:
> Thank you Mats. Very interesting observation.
>
> May you kindly expand on why you are suggesting this?
>
> In my opinion specifying a log name at runtime gives me more flexibility
> but I might be not considering some other important reason.

Not sure I'm answering the right question here, but...

You can still specify the logging location on the command line by
accepting an argument, and having a default in the program if it's not
on the command line.

The logigng module gives you the flexibility to log to different places,
even - you can put every reading in the log, and important events (like
Internet connection is down) somewhere else - your console, sending by
email (I'm not sure that's directly supported, but wouldn't be hard to
set up), by assigning different log levels to different types of events.

>
> Ciao
>
> PS Etiquette question please: Is it better to reply to both the sender
and
> the list or the list only?
>
>
> On 5 January 2020 at 19:18:30, Mats Wichmann (mats at wichmann.us) wrote:
>

> quick reaction: look into the logging module to control how, where and
> what to log. No need to reinvent the wheel.
_______________________________________________
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 Jan  5 18:19:40 2020
From: cs at cskk.id.au (Cameron Simpson)
Date: Mon, 6 Jan 2020 10:19:40 +1100
Subject: [Tutor] Please help disentangle my program logic
In-Reply-To: <CADiDnXep1XrTbqT5LiGK89-LuJmS-170XwEHhGqBw6KPTZG7aA@mail.gmail.com>
References: <CADiDnXep1XrTbqT5LiGK89-LuJmS-170XwEHhGqBw6KPTZG7aA@mail.gmail.com>
Message-ID: <20200105231940.GA49876@cskk.homeip.net>

On 05Jan2020 19:37, Robert Alexander <gogonegro at gmail.com> wrote:
>My program currently handles an ?exception? and exits if a prerequisite
>external program is not found. So that would go to STDOUT/ERR and the logs
>proper to a log via the logging module.

The default logger sends to stderr, BTW. So for simple things I just log 
errors etc via the default logging calls and they come out on stderr as 
normal for a UNIXy command line.

Another nice thing about the logging module is that the format facility 
lets you configure it to do boilerplate like the timestamp or log level 
label, for example:

    '%(asctime)s %(levelname)s %(message)s'

However, your setup line:

  nohup python -u speedtest.py >> adsl.log &

expects stuff to come from the standard output. You'd want:

  nohup python -u speedtest.py >> adsl.log 2>&1 &

to use the default logging arrangement.

On the subject of starting long running daemons, personally I kick a lot 
of daemony things off in tmux (like a more modern screen) instead of 
using nohup.  That way I've got a nicely named session I can reconnect 
to, and I can just interrupt it and restart it differently or whatever.

>> PS Etiquette question please: Is it better to reply to both the 
>> sender and the list or the list only?

I tend to reply to the list and the sender by default, with the 
Reply-To: set to the list address. But just-to-the-list is also normal, 
and arguably more polite.

Cheers,
Cameron Simpson <cs at cskk.id.au>

From alan.gauld at yahoo.co.uk  Sun Jan  5 19:29:21 2020
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Mon, 6 Jan 2020 00:29:21 +0000
Subject: [Tutor] How to refactor a simple,
 straightforward script into a "proper" program?
In-Reply-To: <3364d7bd-482f-f538-da1f-90839ccaa493@DancesWithMice.info>
References: <CANDiX9JjoXfpEBvnmsJWrAyumLvsKUN39VcaTvoG05-Cnm1DHA@mail.gmail.com>
 <45f1a074-d8bc-ec13-9757-4686ee60462d@DancesWithMice.info>
 <CANDiX9Kv=675fXb=it=tTh2hf+Nx4rTyD7bHS4St9UUizYtZDw@mail.gmail.com>
 <CANDiX9+Rx-syD++J2XuNHyknEccwBC=wBFPpHd7A6DYKYkubNQ@mail.gmail.com>
 <CAPM-O+wdNSLjha_91dV_84FSJWReZxGcv1qdYmp9CXpb2K27ag@mail.gmail.com>
 <CANDiX9JM3na92Umtdi=iE2mwKxor4U3PgFDL7htxMw9V=U4k9g@mail.gmail.com>
 <3364d7bd-482f-f538-da1f-90839ccaa493@DancesWithMice.info>
Message-ID: <1c4a6bad-dfa6-c2d4-d59b-697bf9c4405f@yahoo.co.uk>

On 05/01/2020 02:06, DL Neil via Tutor wrote:

> One of my favorite comments about comments (and docstrings) was 
> "mumbling". My recollection is that this was describing comments that 
> were either of no real use, eg "# adding a to b"; or were purely there 
> in order to satisfy 'requirements' - I've been known to persuade a 
> linter to shut-up by writing ''' Docstring. ''' (don't forget the u/case 
> nor the final punctuation!) BTW I think I'm fooling the linter, but I'm 
> really only fooling myself...

I once worked on a large (very large - 10,000+ files) C project.
It was initially written by a US tech company and sent to us.
They in turn had employed many short term contractors to meet
the project deadline...
When we reviewed the code we found lots of files with things
like this at the top:

/* Scooby dooby dooo.....

<insert 50 blank lines...>

Where are you.... */

Or

/* I need comments to pass the metrics program....


<followed by the lyrics of a popular song.>

My favourite was "I did it my way..."
but another apropos title was the chorus of
"The Marvellous Toy"  :-)

-- 
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  Sun Jan  5 19:30:12 2020
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Mon, 6 Jan 2020 00:30:12 +0000
Subject: [Tutor] Fwd: Re:  How to refactor a simple,
 straightforward script into a "proper" program?
In-Reply-To: <ff0449a0-c664-cf70-1441-5451b55d858b@btinternet.com>
References: <ff0449a0-c664-cf70-1441-5451b55d858b@btinternet.com>
Message-ID: <974c5136-d8bc-ba3c-f169-9341b2299482@yahoo.co.uk>


On 05/01/2020 05:40, boB Stepp wrote:

>>>     while True:
>>>         try:
>>>             return str_converter(input(msg))
>>>         except ValueError:
>>>             if str_converter == int:
>>>                 print("\nPlease enter a whole number!")
>>>             elif str_converter == date.fromisoformat:
>>>                 print("\nPlease enter a valid date in the following
>>> format yyyy-mm-dd!")
>>
>> And if its not one of those types? I get a ValueError raised then it
>> does nothing. It just returns None. That's not very friendly.
> 
> Huh?  Joel said something similar.  Maybe I am being dense, but it
> *does* do something.  If the user types in something that is not one
> of the allowed types, he gets a helpful message telling him/her what
> the program is expecting, and the program loops back to the original
> message requesting input.

My bad it does not "return None" in the technical sense.
It displays nothing just returns to the prompt.
Try writing your own string convertor:

def myInt(s):
   return int(s)

Now use myInt as the string convertor and see what happens...
It does 'work' but is less user friendly.

> But it also does date input.  And if in the future I wanted other
> sorts of input I need only add new string converters for the new data
> types.

Yes, but the udr of your module will expect to be able to write their
own string convertors and they wont work without modifying the module -
thats bad.

You would need to have a dict of string convertors and error messages so
that the error handler could look up the error message using the string
convertor as a key:


except ValueError:
       print conv_msg[string_convertor]

And the user can then add their own error message:

module.conv_msg[myInt] = "Enter an integer"


>> This sounds like a reusable function, but in fact its pretty tied into
>> the problem at hand.
> 
> Again, I wonder if I am being dense, but my intent with this function
> is to handle a variety of input types.  I would have to add new
> ValueError possibilities for new data types.  Is this what bothers
> you?

Yes because when I download your "industrial strength" module I
discover I either have to contact you every time I need a new
string converter or I have to fix up the module myself!
Neither is good from a users perspective.

> Hmm.  I see that in case of ValueError it could look elsewhere for
> what sort of user friendly error message to display for a particular
> value of str_converter.  Is this what you are getting at?

Yes, see the dict example above.

> presented in the "simple" script.  I have quickly looked over D. L.
> Neil's comments, and, combined with yours, wonder if I should redesign
> the whole shebang from the ground up?  Maybe this problem does need an
> OO approach.

You shouldn't need an OO approach for something this small.
But you do need a bit of a rethink in tems of splitting out the
functions cleanly. And exactly what is published API and what
is just internal utility code.

> I grudgingly concede your point.  Grudgingly because now I have to
> figure out how to accomplish this.  ~(:>))

I think exceptions are the way to go.

>> ppd = calc_pages_per_day(bp,rp,due)
>>
>> Maybe its just me but the calc seems implied by the function call.
> 
> But I thought the great preference was for function and method names
> to be verbs not nouns?

Hmmm, yes. OK I'll give you that one :-)

>> Would you really say page if it was 0.5 pages per day?
> 
> Actually, yes.  Just as I would say a half page per day.  OTOH, I
> would say zero pages per day.  Maybe I need to dust off a grammar
> book...

a half page is not the same as 0,5 pages.
The a forces it to single. So in your code you need to add
an 'a' before the value to make it grammatical.
Thats more work, but doable, but what would you say
for a value like 0.82? What kind of fraction is that?
Are you going to convert it to say

a 82 hundredth of a page?

Good luck with that...

>> I'd only use 'page' if it was exactly 1.
>>
>> But since its a float you need to use an epsilon value.
>> So
>>
>> e = 0.0001
>> if 1-e < pages_per_day < 1+e:
>>     word_to_display = 'page'
>> else: word_to_display = 'pages'
> 
> Do I really need an epsilon value for this particular case?  I am not
> seeing where my intentions would fail here.  Can you provide an
> example?  

This is because the computer cannot accurately represent floats so you
may get a value like 0.999999999 or 1.00000001 when you want to treat it
as 1. So you either use an epsilon or you do a float to some minimal
number of decimals.

> thought if the user wishes to be silly here, why not?

Its not about the user, its the floating point division
in a digital computer.

> I originally in my code did not use mixed quotes.  But when I saved
> the file my new code formatting tyrant, Black, changed my consistent
> quoting style to mixed quotes.  Apparently it insists on all double
> quotes unless there are embedded quotes within when it converts those
> to single quotes.

Yukkkk!

>> 2) if a function isn't generally reusable make it obvious
>>    by putting an underscore in front of the name. (or
>>    make it generally reusable...usually much harder :-)
> 
> This is where I was hoping for some concrete, helpful examples.  I do
> indeed find this "much harder".

Everyone does. Management routinely ask devs to create reusable code,
but studies show that writing reusable code is from 3-5 times more
expensive than writing single-use code. Some studies say more like 10
times if you factor in maintenance costs too.

And there is no easy answer, it takes painful lessons and
experience, and you'll still mess it up!

>> 3) separate presentation and logic.
> 
> Again, I find this not so easy.

This is easier and just takes a little practice to get used to it.
Basically every function should either do display or logic. If its
doing logic then return values that the caller can use/display.


> FEATURE CREEP!  Actually sounds like an interesting addition.  But I
> don't much like eReaders myself.  

I didn't used to but, on holiday, I save a ton of weight by taking a
Kindle. And having got used to them I now occasionally even read
tech books on it. Although code formatting often gets messed up.
But I'm currently reading a book on curses programming in C and
converting it to python - maybe to become a page in my tutor
someday - and that's a Kindle book.


-- 
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  Sun Jan  5 19:59:01 2020
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Mon, 6 Jan 2020 00:59:01 +0000
Subject: [Tutor] Fwd: Re: How to refactor a simple,
 straightforward script into a "proper" program?
In-Reply-To: <974c5136-d8bc-ba3c-f169-9341b2299482@yahoo.co.uk>
References: <ff0449a0-c664-cf70-1441-5451b55d858b@btinternet.com>
 <974c5136-d8bc-ba3c-f169-9341b2299482@yahoo.co.uk>
Message-ID: <4ae7ac28-053a-e0f5-eeaf-2b6bd6072970@yahoo.co.uk>

On 06/01/2020 00:30, Alan Gauld via Tutor wrote:

> as 1. So you either use an epsilon or you do a float to some minimal
> number of decimals.

...do a round.... doh!


-- 
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 PyTutor at DancesWithMice.info  Sun Jan  5 21:35:31 2020
From: PyTutor at DancesWithMice.info (David L Neil)
Date: Mon, 6 Jan 2020 15:35:31 +1300
Subject: [Tutor] How to refactor a simple,
 straightforward script into a "proper" program?
In-Reply-To: <1c4a6bad-dfa6-c2d4-d59b-697bf9c4405f@yahoo.co.uk>
References: <CANDiX9JjoXfpEBvnmsJWrAyumLvsKUN39VcaTvoG05-Cnm1DHA@mail.gmail.com>
 <45f1a074-d8bc-ec13-9757-4686ee60462d@DancesWithMice.info>
 <CANDiX9Kv=675fXb=it=tTh2hf+Nx4rTyD7bHS4St9UUizYtZDw@mail.gmail.com>
 <CANDiX9+Rx-syD++J2XuNHyknEccwBC=wBFPpHd7A6DYKYkubNQ@mail.gmail.com>
 <CAPM-O+wdNSLjha_91dV_84FSJWReZxGcv1qdYmp9CXpb2K27ag@mail.gmail.com>
 <CANDiX9JM3na92Umtdi=iE2mwKxor4U3PgFDL7htxMw9V=U4k9g@mail.gmail.com>
 <3364d7bd-482f-f538-da1f-90839ccaa493@DancesWithMice.info>
 <1c4a6bad-dfa6-c2d4-d59b-697bf9c4405f@yahoo.co.uk>
Message-ID: <d8963c1b-f83e-329e-ffd4-10c673b30996@DancesWithMice.info>

On 6/01/20 1:29 PM, Alan Gauld via Tutor wrote:
> On 05/01/2020 02:06, DL Neil via Tutor wrote:
> 
>> One of my favorite comments about comments (and docstrings) was
>> "mumbling". My recollection is that this was describing comments that
>> were either of no real use, eg "# adding a to b"; or were purely there
>> in order to satisfy 'requirements' - I've been known to persuade a
>> linter to shut-up by writing ''' Docstring. ''' (don't forget the u/case
>> nor the final punctuation!) BTW I think I'm fooling the linter, but I'm
>> really only fooling myself...
> 
> I once worked on a large (very large - 10,000+ files) C project.
> It was initially written by a US tech company and sent to us.
> They in turn had employed many short term contractors to meet
> the project deadline...
> When we reviewed the code we found lots of files with things
> like this at the top:
> 
> /* Scooby dooby dooo.....
> 
> <insert 50 blank lines...>
> 
> Where are you.... */
> 
> Or
> 
> /* I need comments to pass the metrics program....
> 
> 
> <followed by the lyrics of a popular song.>
> 
> My favourite was "I did it my way..."
> but another apropos title was the chorus of
> "The Marvellous Toy"  :-)


Way back, in the 80s(?), I had a salesman trying to sell me one of those 
'measure the performance of your programmers'-type products. Even he 
admitted that we could expect just such behavior!
(I think it also flagged goto-statements as 'red flags'!)


Classic example of 'the law of unintended consequences'! If you make an 
(artificial/boorish/stupid/...) rule, people feel forced to obey the 
'letter of the law' but 'miss' (either deliberately or ignorantly) 'the 
spirit of the law'.

My favorite of these was during one of my UN assignments to a country I 
shall not name (to protect the 'innocent'). These folk had a 
laissez-faire culture and thus attitude to 9-5 work-hours. A pair of 
colleagues from India/Sri-Lanka, whose culture is quite different and 
whose attitude to such poor time-keeping was one of major criticism, if 
not anger; decided, without discussion amongst the team or with many of 
our host management, to install time-card machines. They were amazed to 
read the first monthly-report and find that one department's personnel 
almost all arrived for work something like 90-minutes before 'time' - 
and that they all left within minutes (again, usually 'over' time). 
Casual observation showed that this was not reality. It took them ages 
to work-out how it was done - which showed another cultural-gap in 
group-dynamics, and attitudes to 'team-work'!

BTW lest anyone think I was criticising any one race/creed/culture, let 
me say that one of my first meetings in London a short-time later, 
featured me waiting well beyond the 1000 appointment-time, whilst my 
'host' completed reading his morning newspaper... I don't think a 
time-card would have solved his problem - nor improved his documentation!


In partial response to a couple of comments made earlier in this thread:
these days we don't need to comment-out chunks of code (per Scooby Doo, 
above) when we are refactoring/replacing it - we have VCS enabling us to 
revert to version n-1, or to run a compare-analysis if/when required!

For similar reasons, many of the web-articles talking about the various 
comments we can/should/must add to the beginning of our program(me)s 
have become anachronistic, eg we used to keep notes of how the code had 
been changed, release by release (per Release Notes, but on a 
module/class basis). No longer necessary because those comments should 
document each VCS-commit! Similarly, the version numbering system comes 
from delivering a repository's 'latest version' to the 'delivery 
mechanism'(s).

-- 
Regards =dn

From robertvstepp at gmail.com  Sun Jan  5 22:25:52 2020
From: robertvstepp at gmail.com (boB Stepp)
Date: Sun, 5 Jan 2020 21:25:52 -0600
Subject: [Tutor] How to refactor a simple,
 straightforward script into a "proper" program?
In-Reply-To: <3364d7bd-482f-f538-da1f-90839ccaa493@DancesWithMice.info>
References: <CANDiX9JjoXfpEBvnmsJWrAyumLvsKUN39VcaTvoG05-Cnm1DHA@mail.gmail.com>
 <45f1a074-d8bc-ec13-9757-4686ee60462d@DancesWithMice.info>
 <CANDiX9Kv=675fXb=it=tTh2hf+Nx4rTyD7bHS4St9UUizYtZDw@mail.gmail.com>
 <CANDiX9+Rx-syD++J2XuNHyknEccwBC=wBFPpHd7A6DYKYkubNQ@mail.gmail.com>
 <CAPM-O+wdNSLjha_91dV_84FSJWReZxGcv1qdYmp9CXpb2K27ag@mail.gmail.com>
 <CANDiX9JM3na92Umtdi=iE2mwKxor4U3PgFDL7htxMw9V=U4k9g@mail.gmail.com>
 <3364d7bd-482f-f538-da1f-90839ccaa493@DancesWithMice.info>
Message-ID: <CANDiX9+4c8em_NkTsYmpTapWhOwpJego=sF4cGBPoYyvNn9+5w@mail.gmail.com>

I have been doing much pondering of yesterday's remarks.  In
particular your and Alan's thoughts have me reflecting deeply.

On Sat, Jan 4, 2020 at 8:07 PM DL Neil via Tutor <tutor at python.org> wrote:
>
> On 5/01/20 12:05 PM, boB Stepp wrote:

> If you do not consider OOP to be (too) 'advanced', what may help is
> drawing a UML diagram - if UML is not in your portfolio (and to ease
> email-presentation), instead make two (equivalent to UML) lists:-

Other than some toy, play around with code programs to explore OOP, I
have yet to write anything for serious use with that style of code
organization (Unless you throw out that everything in Python is an
object, etc.).  I keep circling around the OOP pool, but have yet to
leap in and try to swim.

> What is the subject of the computation? A book.
> How are you measuring its size? Nr Pages.

When I read this in the wee morning hours today, I was startled that
it made sense to consider multiple books (Or other sorts of reading
materials, per Alan.) even in light of the original simple script.
Say I was a student (I always am, just not "officially".).  I could
see in light of a multiple course load, each with multiple readings to
accomplish with each having different due dates, that I (or my
mythical user) might want to keep track of all of this and how many
pages each day to read in each text.  And that thinking leads to
persistent storage and upon opening the program updating the pages per
day of each text.  So this along with Alan' and your comments have me
shifting my thinking from procedural code organization to OO
organization.  So I keep threatening in previous comments I have made
on this list to tackle the OOP learning curve.  Perhaps now is the
timely time?

So I have been thinking a lot about this today and find myself
stumbling around in a confused daze despite making lists, crude
UML-like diagrams, etc.  So questions!

I think the basic unit of code organization would be a ReadingMaterial
class, choosing this name to reflect Alan's thoughts that ultimately
there might be other things to read besides paper-based books.  To
keep with the current confines of the original problem as stated, an
object of this class would have the following user-entered attributes:
 title, total_amount_to_read, total_amount_read, and goal_date.  I
switched from "pages" to "amount" as my best wording to reflect a
potential shift from pages read to percent of item read or lines read
or whatever.  This means that I will have to throw in the concept of
"units" if I do this generalization now.  I know the Agile people
might say stick with today's problem (pages) and worry about other
units when one is forced to.  So I may stick with pages after I hash
out more important difficulties.  So back to "pages" for now.

So I am really struggling with "separation of concerns" on getting the
four needed attributes of ReadingMaterial from the user's screen to
the particular instance of this class that the user wishes to create.
First point of confusion:  the creation of the ReadingMaterial object.
Should it start with (a) my_book = ReadingMaterial() or with (b)
my_book = Reading_Material(title [, total_pages_to_read,
total_pages_read, goal_date])?  The brackets indicate optionally
starting with all four attributes from the get-go.  In other words in
(a) the object would see to initiating the acquisition of user input
itself, while the second has some other entity taking care of user
input and then passing it into the instantiation process.  Which is
the proper way to proceed?  On the (a) side, ReadingMaterial knows
what it needs and it is the natural location for future additional
attributes that may need to be acquired someday.  This is the
direction I am currently leaning.  So the initialization of a
ReadingMaterial object might look like:

class ReadingMaterial:
    def __init__(self):
        self.title = _get_input(???)
        self.total_pages_to_read = _get_input(???)
        self.total_pages_read = _get_input(???)
        self.goal_date = _get_input(???)

    def _get_input(self, ???):
        return input_manager.get_input(???)

Based on my previous code explorations, I need to do two forms of
input validation:  (1) syntactical, so no ValueErrors result and (2)
logical:  Things like the number of pages read are less than the
length of what is being read, etc.  It seems to me that the
InputManager (yet to be fleshed out) should do (1) and ReadingMaterial
should do (2), especially as it cannot be done until *all* of the
input is acquired.  So what about (???) ?  Only ReadingMaterial knows
about the details of each attribute, especially validating the "type"
of input.  Also, it seems natural that in case of type validation
exception being thrown, the resulting message to the user should be
customized to the input being asked for.  That suggests to me that
such error messages should be stored in the ReadingMaterial class.
Additionally, the input prompt for each attribute to be acquired needs
to be customized appropriately as well.  And if I am engaging in
"good"  OOD thinking then that suggest that (???) should minimally be
the input type being requested (str -- not really an issue since
input() returns a string, int, date object, etc), the customized input
prompt and the customized error message.  I presume good practice
would for the InputManager to pass the input prompt to a
DisplayManager to be printed to the user's screen and that the
InputManager would convert the user input to the requested (by
ReadingMaterial) type, syntactically validate it, if that fails send
the error message to the DisplayManager and await a new effort at
valid input.  Is this how I should be thinking about this problem?

*If* I am on the right track, where does the InputManager get
instantiated?  DisplayManager?  Is this where in the MVC pattern, the
program's main() would instantiate a Controller and then the
Controller would be responsible for coordinating these?

Anyway this is where I am at now staring at a mostly empty split
Neovim screen, split between reading_tracker.py (Name change per Alan
~(:>)) ) and test_reading_tracker.py with

============================================================================
#!/usr/bin/env python3
"""Pages per day needed to complete a reading on time.

[Usage message]

[Third-party or custom imports]

[A list of any classes, exception, functions, and any other objects
exported by the module]
class ReadingMaterial

"""

class ReadingMaterial:
    """A class to represent reading material such as books."""

    pass


if __name__ == "__main__":
    pass
============================================================================

on the left side and

============================================================================
#!/usr/bin/env python3
"""Tests for reading_tracker.

[Usage message]

[Third-party or custom imports]

[A list of any classes, exception, functions, and any other objects
exported by the module]

"""

import unittest

from reading_tracker import ReadingMaterial

if __name__ == "__main__":
    unittest.main()
============================================================================

on the right side.


-- 
boB

From PyTutor at danceswithmice.info  Sun Jan  5 22:39:05 2020
From: PyTutor at danceswithmice.info (DL Neil)
Date: Mon, 6 Jan 2020 16:39:05 +1300
Subject: [Tutor] Fwd: Re: How to refactor a simple,
 straightforward script into a "proper" program?
In-Reply-To: <974c5136-d8bc-ba3c-f169-9341b2299482@yahoo.co.uk>
References: <ff0449a0-c664-cf70-1441-5451b55d858b@btinternet.com>
 <974c5136-d8bc-ba3c-f169-9341b2299482@yahoo.co.uk>
Message-ID: <a48e6a3c-aca5-3f59-4c13-e44f33bbee44@DancesWithMice.info>

On 6/01/20 1:30 PM, Alan Gauld via Tutor wrote:
> On 05/01/2020 05:40, boB Stepp wrote:

>> presented in the "simple" script.  I have quickly looked over D. L.
>> Neil's comments, and, combined with yours, wonder if I should redesign
>> the whole shebang from the ground up?  Maybe this problem does need an
>> OO approach.
> 
> You shouldn't need an OO approach for something this small.

You're just baiting me, right?

Which comes first: the chicken or the egg? the data-objects or the 
algorithm? (Alan and I will argue this, just for fun...)


On a personal note, I usually find that organising the data - the 
"entities" involved in a problem, is the?my best way of understanding 
the problem and peeling-back the onion-skin process of moderating one 
large 'problem' into a number of smaller, and more easily-solved 
challenges. YMMV!

Accordingly, I keep separate the process of gathering input, from the 
calculation, from the niceties of presentation...

As the divided-problems become single tasks, the can be implemented as 
Python methods/functions without much thought.

Surely it is also much easier, at this single-task level, to analyse 
what might 'go wrong', and to test or to code precautions accordingly?

In the case of the input, once the 'problem' of collecting one integer 
value from the user has been 'solved', it also becomes possible to see 
how that routine could be re-used to collect the other integer value(s)...
(thus addressing the single-use/re-use discussion, below)


> But you do need a bit of a rethink in tems of splitting out the
> functions cleanly. And exactly what is published API and what
> is just internal utility code.

+1


>> I grudgingly concede your point.  Grudgingly because now I have to
>> figure out how to accomplish this.  ~(:>))
> 
> I think exceptions are the way to go.

+1
Have a function return ONE data-type/meaning, and only one! Thus if the 
function is to collect a (valid) integer from user-input, return that 
integer. If it ALSO is to interpret a null-entry or perhaps a 
negative-number as a "sentinel value" to cease execution, then code that 
condition to raise an Exception.
(in Python exceptions are not necessarily "errors"!)


>> But I thought the great preference was for function and method names
>> to be verbs not nouns?
> 
> Hmmm, yes. OK I'll give you that one :-)

I wasn't going to raise this unexpected utterance - thinking myself too 
polite.

(oh forget it - who am I trying to convince?)...


>>> Would you really say page if it was 0.5 pages per day?
>>
>> Actually, yes.  Just as I would say a half page per day.  OTOH, I
>> would say zero pages per day.  Maybe I need to dust off a grammar
>> book...
> 
> a half page is not the same as 0,5 pages.
> The a forces it to single. So in your code you need to add
> an 'a' before the value to make it grammatical.
> Thats more work, but doable, but what would you say
> for a value like 0.82? What kind of fraction is that?
> Are you going to convert it to say
> 
> a 82 hundredth of a page?
> 
> Good luck with that...

We used to spend quite a bit of time and effort worrying about correct 
grammar. However, these days, such politesse seems more honored in the 
breach, than the observance!


>>> I'd only use 'page' if it was exactly 1.
>>>
>>> But since its a float you need to use an epsilon value.

The points about floating-point's lack of accuracy in using binary to 
portray decimal values is worth noting. Few bother to teach/learn 
numerical analysis these days!

That said, as someone who often has to 'budget' reading (either to 
finish, or to limit myself in order to 'do' things), I already 'round' 
my calculations. Thus, if I have five days before a book is due back to 
the library, a similar calculation galvanises/motivates me to read (say) 
at least three chapters per day. Pages/day would be a more precise 
measure but may not fit with the material! Sections of chapters? Also, 
if I end-up with only one chapter to read (remainder to integer 
division!) then that's a 'bonus' or even an additional measure of 
success - I don't complain about having worked 'too hard' during 
previous days.

What might the added precision of page-fractions add - in the user's mind?


>> I originally in my code did not use mixed quotes.  But when I saved
>> the file my new code formatting tyrant, Black, changed my consistent
>> quoting style to mixed quotes.  Apparently it insists on all double
>> quotes unless there are embedded quotes within when it converts those
>> to single quotes.
> 
> Yukkkk!

"Tyrant". Tools that are not your friends are what? Things growing in my 
garden which will not end-up 'in the pot' or on my table are called what?

Yes, recommend using 'advisory' linters - you may then choose what to 
learn, when! and why!


>>> 2) if a function isn't generally reusable make it obvious
>>>     by putting an underscore in front of the name. (or
>>>     make it generally reusable...usually much harder :-)
>>
>> This is where I was hoping for some concrete, helpful examples.  I do
>> indeed find this "much harder".
> 
> Everyone does. Management routinely ask devs to create reusable code,
> but studies show that writing reusable code is from 3-5 times more
> expensive than writing single-use code. Some studies say more like 10
> times if you factor in maintenance costs too.
> 
> And there is no easy answer, it takes painful lessons and
> experience, and you'll still mess it up!

YAGNI applies!

NB OOP is not (necessarily) "reusable", nor does "reusable" imply OOP!

Tested/testable code, over 'it seems to work', *every* time!


Conversely to the above, management equally-routinely take stuff which 
we were initially told would only be used once or for a short period, 
and re-define those words to mean 'every day' and/or for decades...

Elsewhere I threw in my 2c/2.5p ("tuppence ha'penny" in ?old-money) 
about "tests"...

If the code has been written so that its intent and method are clear, 
then faced with the need, 'single-use' code could be re-worked and 
generalised into reusable code. Whereas a 'mess' might work for 
single-use, but is rapidly rated as 'disposable' should the situation 
'develop'!

Important message: you can't win!
(but what made you think you could???)


>>> 3) separate presentation and logic.
>> Again, I find this not so easy.
> This is easier and just takes a little practice to get used to it.
> Basically every function should either do display or logic. If its
> doing logic then return values that the caller can use/display.

+1
See also, "Separation of Concerns"

answer = process( validated_input, validated_input, ... )
report( answer )


>> FEATURE CREEP!  Actually sounds like an interesting addition.  But I
>> don't much like eReaders myself.
> 
> I didn't used to but, on holiday, I save a ton of weight by taking a
> Kindle. And having got used to them I now occasionally even read
> tech books on it. Although code formatting often gets messed up.
> But I'm currently reading a book on curses programming in C and
> converting it to python - maybe to become a page in my tutor
> someday - and that's a Kindle book.

I prefer a book. Recent studies have show that, given a choice of 
text-presentations, the majority of even today's, screen-native, 
tertiary-students will choose a book over an eBook.

I live in a country famed for its bright sunlight* (I can never believe 
the difference between here and London or Washington, for example). 
Accordingly, it can be very difficult to read iPads, portable computer 
screens, smart-phones, etc. However, a Kindle works with reflective light!
* and the highest rates of skin-cancers, which just goes to show: life's 
a beach, and then you...
-- 
Regards =dn

From gogonegro at gmail.com  Mon Jan  6 06:19:12 2020
From: gogonegro at gmail.com (Robert Alexander)
Date: Mon, 6 Jan 2020 12:19:12 +0100
Subject: [Tutor] Please help disentangle my program logic
In-Reply-To: <32d4b470-c050-eb32-b4de-948e7679a678@wichmann.us>
References: <CADiDnXf=aDNirX7xtjV57riqWC6GJC6J2WQ-pQsNdDA6wOhAXA@mail.gmail.com>
 <3b4dcc39-c49f-c13a-1a4a-bf4eec9f5b33@wichmann.us>
 <CADiDnXcW=djbcJTwwBk3BkTFyz-2CJqcbsdhkADBbUPMX_r2NA@mail.gmail.com>
 <32d4b470-c050-eb32-b4de-948e7679a678@wichmann.us>
 <32d4b470-c050-eb32-b4de-948e7679a678@wichmann.us>
Message-ID: <CADiDnXf8skgV15zHtWg1fM0bJTq8AOo=cj7ScQ9G-usJpWSJ5Q@mail.gmail.com>

As per Mats suggestion I am wrangling with the logging module.
Almost there but I don?t understand what I?m doing wrong since I wish the
log
to go only into a specified log file but my current code spits out TWO
different
Log lines:

A) an unwanted and strangely formatted log on the screen with lines such as
INFO:__main__:DL:211.2;UL:29.8;PL:0
WARNING:__main__:DL:125.8;UL:29.6;PL:0

B) The properly formatted log lines in the specified log file. Here the
format
2020-01-06 12:07:05;INFO;DL:211.2;UL:29.8;PL:0
2020-01-06 12:08:01;WARNING;DL:125.8;UL:29.6;PL:0

Here?s the code:

import logging
?.
#  setup logging
log_file_handler = logging.FileHandler('adsllog.log')
log_formatter = logging.Formatter("%(asctime)s;%(levelname)s;%(message)s",
"%Y-%m-%d %H:%M:%S")
log_file_handler.setFormatter(log_formatter)

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
# add file handler to logger
logger.addHandler(log_file_handler)
?
speedtest_values_string = (
                f"DL:{down_speed:3.1f};UL:{up_speed:2.1f};PL:{packet_loss}"
            )
if down_speed < TD or up_speed < TU or packet_loss > TL:
                logger.warning(f"{speedtest_values_string}")
            else:
                logger.info(f"{speedtest_values_string}?)

In the above code TD,TU,TL are numeric thresholds and down_speed, up_speed
and packet_loss are my measurements of my ADSL line.

Thank you for any clarification.

Robert

On 5 January 2020 at 19:34:51, Mats Wichmann (mats at wichmann.us) wrote:

On 1/5/20 11:23 AM, Robert Alexander wrote:
> Thank you Mats. Very interesting observation.
>
> May you kindly expand on why you are suggesting this?
>
> In my opinion specifying a log name at runtime gives me more flexibility
> but I might be not considering some other important reason.

Not sure I'm answering the right question here, but...

You can still specify the logging location on the command line by
accepting an argument, and having a default in the program if it's not
on the command line.

The logigng module gives you the flexibility to log to different places,
even - you can put every reading in the log, and important events (like
Internet connection is down) somewhere else - your console, sending by
email (I'm not sure that's directly supported, but wouldn't be hard to
set up), by assigning different log levels to different types of events.

>
> Ciao
>
> PS Etiquette question please: Is it better to reply to both the sender
and
> the list or the list only?
>
>
> On 5 January 2020 at 19:18:30, Mats Wichmann (mats at wichmann.us) wrote:
>

> quick reaction: look into the logging module to control how, where and
> what to log. No need to reinvent the wheel.
_______________________________________________
Tutor maillist - Tutor at python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor

From alan.gauld at yahoo.co.uk  Mon Jan  6 06:29:57 2020
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Mon, 6 Jan 2020 11:29:57 +0000
Subject: [Tutor] How to refactor a simple,
 straightforward script into a "proper" program?
In-Reply-To: <CANDiX9+4c8em_NkTsYmpTapWhOwpJego=sF4cGBPoYyvNn9+5w@mail.gmail.com>
References: <CANDiX9JjoXfpEBvnmsJWrAyumLvsKUN39VcaTvoG05-Cnm1DHA@mail.gmail.com>
 <45f1a074-d8bc-ec13-9757-4686ee60462d@DancesWithMice.info>
 <CANDiX9Kv=675fXb=it=tTh2hf+Nx4rTyD7bHS4St9UUizYtZDw@mail.gmail.com>
 <CANDiX9+Rx-syD++J2XuNHyknEccwBC=wBFPpHd7A6DYKYkubNQ@mail.gmail.com>
 <CAPM-O+wdNSLjha_91dV_84FSJWReZxGcv1qdYmp9CXpb2K27ag@mail.gmail.com>
 <CANDiX9JM3na92Umtdi=iE2mwKxor4U3PgFDL7htxMw9V=U4k9g@mail.gmail.com>
 <3364d7bd-482f-f538-da1f-90839ccaa493@DancesWithMice.info>
 <CANDiX9+4c8em_NkTsYmpTapWhOwpJego=sF4cGBPoYyvNn9+5w@mail.gmail.com>
Message-ID: <bacdff09-5c3b-8cf1-3aee-18931bd9cb1f@yahoo.co.uk>

On 06/01/2020 03:25, boB Stepp wrote:

> So I have been thinking a lot about this today and find myself
> stumbling around in a confused daze despite making lists, crude
> UML-like diagrams, etc.  So questions!

OK, This switches the emphasis of the thread but lets go...

> I think the basic unit of code organization would be a ReadingMaterial
> class, choosing this name to reflect Alan's thoughts that ultimately
> there might be other things to read besides paper-based books.

Good thinking. But...

I'd create a very thin abstract class with just the interface
 - remember think about behaviour first not attributes.
Attributes are only there to support behaviour.

Then forget about eReaders etc for now and create a subclass
that deals with the concrete problem of a paper book.


> keep with the current confines of the original problem as stated, an
> object of this class would have the following user-entered attributes:
>  title, total_amount_to_read, total_amount_read, and goal_date.  I
> switched from "pages" to "amount" as my best wording to reflect a
> potential shift from pages read to percent of item read or lines read
> or whatever.  This means that I will have to throw in the concept of
> "units" if I do this generalization now.  

The units are specific to te subclass. Amount are the generalized concept.

My only question is whether the dates are relevant to the book? Or do
you need a Reader object? It is the reader who has reading goals. The
book will tell you how much to read and current position. But it is not
interested in dates.

So now we have two objects interacting. And in theory you could have
multiple readers reading the same book, and one reader reading multiple
books.

> I know the Agile people
> might say stick with today's problem (pages) and worry about other
> units when one is forced to.  So I may stick with pages after I hash
> out more important difficulties.  So back to "pages" for now.

Correct approach. Recognize that you may have another type of
ReadingMaterial to deal with in the future, but park it for
now - its a differnt class.

> First point of confusion:  the creation of the ReadingMaterial object.
> Should it start with (a) my_book = ReadingMaterial() or with (b)
> my_book = Reading_Material(title [, total_pages_to_read,
> total_pages_read, goal_date])?  The brackets indicate optionally
> starting with all four attributes from the get-go.  In other words in
> (a) the object would see to initiating the acquisition of user input
> itself, while the second has some other entity taking care of user
> input and then passing it into the instantiation process. 

Separate user interaction from logic. What happens when you want to use
this ReadingMaterial object in a GUI? So you have a ReadingMaterialView
that can deal with interacting with the user to create the book. In an
industrial version of this we probably have a database of readMaterial
and the readers select an existing book. The creation of the book is a
database(library?) admins job.

So I'd definitely opt for a separate data collection function/object
and then instantiate the object with the data already gathered.

> the proper way to proceed?  On the (a) side, ReadingMaterial knows
> what it needs and it is the natural location for future additional
> attributes that may need to be acquired someday. 

It knows what it needs but it does that by being created with it. Thats
what __init__() - ie. initialization - is for.

> direction I am currently leaning.  So the initialization of a
> ReadingMaterial object might look like:
> 
> class ReadingMaterial:
>     def __init__(self):
>         self.title = _get_input(???)
>         self.total_pages_to_read = _get_input(???)
>         self.total_pages_read = _get_input(???)
>         self.goal_date = _get_input(???)

Again, how does that work in a GUI? Or on the web?

> Based on my previous code explorations, I need to do two forms of
> input validation:  (1) syntactical, so no ValueErrors result 

Thats the job of the user interaction mechanism...

> logical:  Things like the number of pages read are less than the
> length of what is being read, etc.

That's the job of the book. It should check the logical
validity of the data and if necessary raise a ValueError.

> InputManager (yet to be fleshed out) should do (1) and ReadingMaterial
> should do (2), especially as it cannot be done until *all* of the
> input is acquired.  So what about (???) ?  Only ReadingMaterial knows
> about the details of each attribute, especially validating the "type"
> of input.  

The "input manager" knows the types required - that's part of
the creation API. So to create the object it must provide the
required types.

> Also, it seems natural that in case of type validation
> exception being thrown, the resulting message to the user should be
> customized to the input being asked for.  

The message can be added to the error when it is raised, so it is
type/value specific.

> such error messages should be stored in the ReadingMaterial class.

They are "stored" wherever you raise the exception.
(Again, being truly industrial, you store them in a separate list
and use i18n code to extract them in whatever language/locale is in use.
But that's way beyond the scope of this exercise!! And outside of the
class in any case.)

> Additionally, the input prompt for each attribute to be acquired needs
> to be customized appropriately as well.  And if I am engaging in
> "good"  OOD thinking then that suggest that (???) should minimally be
> the input type being requested (str -- not really an issue since
> input() returns a string, int, date object, etc), the customized input
> prompt and the customized error message.  I presume good practice
> would for the InputManager to pass the input prompt to a
> DisplayManager to be printed to the user's screen and that the
> InputManager would convert the user input to the requested (by
> ReadingMaterial) type, syntactically validate it, if that fails send
> the error message to the DisplayManager and await a new effort at
> valid input.  Is this how I should be thinking about this problem?

What you are working towards is the classic Model-View-Controller
architecture. Google MVC!

In essence the model is the logic and core data.
The view is what goes n the screen
The controller gets input and passes it to the view and/or model.

There are a ton of variations on this theme but its all about
keeping these elements decoupled. And you are right to be struggling,
it is hard, and that's why there is a standard model. Personally
I tend to favour the simplified version where you only have a Model
and View.
The View does all the display/interaction and the Model does all the
application stuff.

Understand that views are application specific and therefore not
usually reusable, whereas models should be reusable. So design
the dependencies such that the view depends on the model,
not the other way round.
That way you can create different views for CLI, GUI and web,
with no change to the model.

> *If* I am on the right track, where does the InputManager get
> instantiated?  DisplayManager?  Is this where in the MVC pattern, the
> program's main() would instantiate a Controller and then the
> Controller would be responsible for coordinating these?

I am answering your issues as I go and in each case you have
already guessed the response. I think thats a good thing! :-)

> Anyway this is where I am at now staring at a mostly empty split
> Neovim screen, split between reading_tracker.py (Name change per Alan
> ~(:>)) ) and test_reading_tracker.py with
> 
> ============================================================================
> #!/usr/bin/env python3
> """Pages per day needed to complete a reading on time.
> 
> [Usage message]
> 
> [Third-party or custom imports]
> 
> [A list of any classes, exception, functions, and any other objects
> exported by the module]
> class ReadingMaterial
> 
> """
> 
> class ReadingMaterial:
>     """A class to represent reading material such as books."""
> 
>     pass
> 
> 
> if __name__ == "__main__":
>     pass
> ============================================================================

That's a good start.

Now start writing some usecases. Forget about code for now.
How does the user interact with this application?
That should start to give you clues as to what methods
the classes need to support.

As a start the context diagram consists of the SUD
with Reader and ReadingMaterial/PaperBook objects.(Assume
the MVC objects are all part of the same thing for use-case
purposes)
The only(?) Actors are the Admin and User.

Users are associated with a reader which is associated with 0..N books

Books are set up by Admin. Depending on your vision Readers
(or ReadingGoals? or ReadingProjects?) may beset up by admin
(if it was a book-club or Language class maybe) or by the users.
And a user and admin could be different roles of a single person.

It is really important to have it clear in your head how
this app will work as a dialog with the user. That is fundamental to
understanding what operations it needs to support. And operations
translate to methods. And then you decide which object supports
which operations. That in turn will tell you which attributes are
needed in which class.


-- 
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  Mon Jan  6 17:42:51 2020
From: cs at cskk.id.au (Cameron Simpson)
Date: Tue, 7 Jan 2020 09:42:51 +1100
Subject: [Tutor] How to refactor a simple,
 straightforward script into a "proper" program?
In-Reply-To: <bacdff09-5c3b-8cf1-3aee-18931bd9cb1f@yahoo.co.uk>
References: <bacdff09-5c3b-8cf1-3aee-18931bd9cb1f@yahoo.co.uk>
Message-ID: <20200106224251.GA74763@cskk.homeip.net>

On 06Jan2020 11:29, Alan Gauld <alan.gauld at yahoo.co.uk> wrote:
>On 06/01/2020 03:25, boB Stepp wrote:
>> I think the basic unit of code organization would be a 
>> ReadingMaterial
>> class, choosing this name to reflect Alan's thoughts that ultimately
>> there might be other things to read besides paper-based books.
>
>Good thinking. But...
>
>I'd create a very thin abstract class with just the interface
> - remember think about behaviour first not attributes.
>Attributes are only there to support behaviour.
>
>Then forget about eReaders etc for now and create a subclass
>that deals with the concrete problem of a paper book.

Just to this; I often find it easier to write the concrete class (no 
abstract superclass), and _then_ consider the concrete class and pull 
out the abstract bits of it. So you start with a working:

    class SubClass:

        def __init__(self, total, blah...):
            self.units = 'pages'
            self.sofar = 0
            self.total = total
            self.blah = blah
            ...

        def portion(self):
            return self.sofar / self.total

and later, when working, split it off into a common superclass with a 
specific subclass, dividing things up between what is generic and what 
is specific.

    class SuperClass:

        def __init__(self, total, units, blah...):
            self.units = units
            self.sofar = 0
            self.total = total
            self.blah = blah
            ...

        def portion(self):
            return self.sofar / self.total

    class PagesSubClass(SuperClass):

        def __init__(self, total, blah...):
            super().__init__(total, 'pages', blah...)

Cheers,
Cameron Simpson <cs at cskk.id.au>

From akleider at sonic.net  Mon Jan  6 19:55:43 2020
From: akleider at sonic.net (Alex Kleider)
Date: Mon, 06 Jan 2020 16:55:43 -0800
Subject: [Tutor] how best to remove an item from a dict
Message-ID: <8e2e92530cda46bcc4376eec6b4f0f3d@sonic.net>


Which is best:

  >>>   _ = d.pop(key)
or
  >>>    del d[key]
??

  >>> import this
...
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
...

Cheers,
-- 
Alex Kleider
(sent from my current gizmo)


From alan.gauld at yahoo.co.uk  Mon Jan  6 20:33:14 2020
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Tue, 7 Jan 2020 01:33:14 +0000
Subject: [Tutor] how best to remove an item from a dict
In-Reply-To: <8e2e92530cda46bcc4376eec6b4f0f3d@sonic.net>
References: <8e2e92530cda46bcc4376eec6b4f0f3d@sonic.net>
Message-ID: <c216585b-7f43-8818-da9c-03518d8dae45@yahoo.co.uk>

On 07/01/2020 00:55, Alex Kleider wrote:
> 
> Which is best:
> 
>   >>>   _ = d.pop(key)
> or
>   >>>    del d[key]
> ??
> 
>   >>> import this
> ..
> There should be one-- and preferably only one --obvious way to do it.
> Although that way may not be obvious at first unless you're Dutch.

The second one is best, it clearly describes the intended effect.

The first one uses a side-effect of the pop/assignment operation,
its only when the _ changes value that the dict item goes out
of scope and is deleted.

A clearly defined operation is always better than a disguised one.
Especially from a maintenance point of view, and given maintenance
is the most expensive part of programming, that is critical.

-- 
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 PyTutor at DancesWithMice.info  Mon Jan  6 23:31:06 2020
From: PyTutor at DancesWithMice.info (David L Neil)
Date: Tue, 7 Jan 2020 17:31:06 +1300
Subject: [Tutor] How to refactor a simple,
 straightforward script into a "proper" program?
In-Reply-To: <bacdff09-5c3b-8cf1-3aee-18931bd9cb1f@yahoo.co.uk>
References: <CANDiX9JjoXfpEBvnmsJWrAyumLvsKUN39VcaTvoG05-Cnm1DHA@mail.gmail.com>
 <45f1a074-d8bc-ec13-9757-4686ee60462d@DancesWithMice.info>
 <CANDiX9Kv=675fXb=it=tTh2hf+Nx4rTyD7bHS4St9UUizYtZDw@mail.gmail.com>
 <CANDiX9+Rx-syD++J2XuNHyknEccwBC=wBFPpHd7A6DYKYkubNQ@mail.gmail.com>
 <CAPM-O+wdNSLjha_91dV_84FSJWReZxGcv1qdYmp9CXpb2K27ag@mail.gmail.com>
 <CANDiX9JM3na92Umtdi=iE2mwKxor4U3PgFDL7htxMw9V=U4k9g@mail.gmail.com>
 <3364d7bd-482f-f538-da1f-90839ccaa493@DancesWithMice.info>
 <CANDiX9+4c8em_NkTsYmpTapWhOwpJego=sF4cGBPoYyvNn9+5w@mail.gmail.com>
 <bacdff09-5c3b-8cf1-3aee-18931bd9cb1f@yahoo.co.uk>
Message-ID: <345ffab0-b6ed-b1ef-3dd9-50bc0d0af2fd@DancesWithMice.info>

On 7/01/20 12:29 AM, Alan Gauld via Tutor wrote:
> On 06/01/2020 03:25, boB Stepp wrote:
> 
>> So I have been thinking a lot about this today and find myself
>> stumbling around in a confused daze despite making lists, crude
>> UML-like diagrams, etc.  So questions!
> 
> OK, This switches the emphasis of the thread but lets go...

Maybe, but doesn't *some* of the discussion relate to design decisions?


>> I think the basic unit of code organization would be a ReadingMaterial
>> class, choosing this name to reflect Alan's thoughts that ultimately
>> there might be other things to read besides paper-based books.
> 
> Good thinking. But...
> 
> I'd create a very thin abstract class with just the interface
>   - remember think about behaviour first not attributes.
> Attributes are only there to support behaviour.
> 
> Then forget about eReaders etc for now and create a subclass
> that deals with the concrete problem of a paper book.
> 
> 
>> keep with the current confines of the original problem as stated, an
>> object of this class would have the following user-entered attributes:
>>   title, total_amount_to_read, total_amount_read, and goal_date.  I
>> switched from "pages" to "amount" as my best wording to reflect a
>> potential shift from pages read to percent of item read or lines read
>> or whatever.  This means that I will have to throw in the concept of
>> "units" if I do this generalization now.
> 
> The units are specific to te subclass. Amount are the generalized concept.
> 
> My only question is whether the dates are relevant to the book? Or do
> you need a Reader object? It is the reader who has reading goals. The
> book will tell you how much to read and current position. But it is not
> interested in dates.

Not necessarily. The reader doesn't know if (s)he is about to drop dead!

Alternately, if the book has been borrowed (eg library), then it has a 
finite availability.


> So now we have two objects interacting. And in theory you could have
> multiple readers reading the same book, and one reader reading multiple
> books.
> 
>> I know the Agile people
>> might say stick with today's problem (pages) and worry about other
>> units when one is forced to.  So I may stick with pages after I hash
>> out more important difficulties.  So back to "pages" for now.
> 
> Correct approach. Recognize that you may have another type of
> ReadingMaterial to deal with in the future, but park it for
> now - its a differnt class.

+1
Make it work before you make it better!


>> First point of confusion:  the creation of the ReadingMaterial object.
>> Should it start with (a) my_book = ReadingMaterial() or with (b)
>> my_book = Reading_Material(title [, total_pages_to_read,
>> total_pages_read, goal_date])?  The brackets indicate optionally
>> starting with all four attributes from the get-go.  In other words in
>> (a) the object would see to initiating the acquisition of user input
>> itself, while the second has some other entity taking care of user
>> input and then passing it into the instantiation process.
> 
> Separate user interaction from logic. What happens when you want to use
> this ReadingMaterial object in a GUI? So you have a ReadingMaterialView
> that can deal with interacting with the user to create the book. In an
> industrial version of this we probably have a database of readMaterial
> and the readers select an existing book. The creation of the book is a
> database(library?) admins job.
> 
> So I'd definitely opt for a separate data collection function/object
> and then instantiate the object with the data already gathered.

+1, which aligns with earlier mention of MVC
Once again, keeping in-mind the future possibility of using a GUI, first 
write the code to work from the terminal-only.


>> the proper way to proceed?  On the (a) side, ReadingMaterial knows
>> what it needs and it is the natural location for future additional
>> attributes that may need to be acquired someday.
> 
> It knows what it needs but it does that by being created with it. Thats
> what __init__() - ie. initialization - is for.
> 
>> direction I am currently leaning.  So the initialization of a
>> ReadingMaterial object might look like:
>>
>> class ReadingMaterial:
>>      def __init__(self):
>>          self.title = _get_input(???)
>>          self.total_pages_to_read = _get_input(???)
>>          self.total_pages_read = _get_input(???)
>>          self.goal_date = _get_input(???)
> 
> Again, how does that work in a GUI? Or on the web?

Alternate view: Were the get_input() coded as part of ReadingMaterial, 
how would we be able to re-use the method when needing to input into 
some other class, on some other project, some other day, ...


> I am answering your issues as I go and in each case you have
> already guessed the response. I think thats a good thing! :-)

+1


> Now start writing some usecases. Forget about code for now.
> How does the user interact with this application?
> That should start to give you clues as to what methods
> the classes need to support.
...

> It is really important to have it clear in your head how
> this app will work as a dialog with the user. That is fundamental to
> understanding what operations it needs to support. And operations
> translate to methods. And then you decide which object supports
> which operations. That in turn will tell you which attributes are
> needed in which class.

+1

-- 
Regards =dn

From akleider at sonic.net  Tue Jan  7 02:20:45 2020
From: akleider at sonic.net (Alex Kleider)
Date: Mon, 06 Jan 2020 23:20:45 -0800
Subject: [Tutor] how best to remove an item from a dict
In-Reply-To: <c216585b-7f43-8818-da9c-03518d8dae45@yahoo.co.uk>
References: <8e2e92530cda46bcc4376eec6b4f0f3d@sonic.net>
 <c216585b-7f43-8818-da9c-03518d8dae45@yahoo.co.uk>
Message-ID: <4d9d91e4e0f536d79ce67e3095196104@sonic.net>

On 2020-01-06 17:33, Alan Gauld via Tutor wrote:
> On 07/01/2020 00:55, Alex Kleider wrote:
>> 
>> Which is best:
>> 
>>   >>>   _ = d.pop(key)
>> or
>>   >>>    del d[key]
>> ??


> 
> The second one is best, it clearly describes the intended effect.
> 
> The first one uses a side-effect of the pop/assignment operation,
> its only when the _ changes value that the dict item goes out
> of scope and is deleted.
> 
> A clearly defined operation is always better than a disguised one.
> Especially from a maintenance point of view, and given maintenance
> is the most expensive part of programming, that is critical.

How obvious it seems now that you've explained it!
Thanks, Alan

From alan.gauld at yahoo.co.uk  Tue Jan  7 05:37:36 2020
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Tue, 7 Jan 2020 10:37:36 +0000
Subject: [Tutor] How to refactor a simple,
 straightforward script into a "proper" program?
In-Reply-To: <345ffab0-b6ed-b1ef-3dd9-50bc0d0af2fd@DancesWithMice.info>
References: <CANDiX9JjoXfpEBvnmsJWrAyumLvsKUN39VcaTvoG05-Cnm1DHA@mail.gmail.com>
 <45f1a074-d8bc-ec13-9757-4686ee60462d@DancesWithMice.info>
 <CANDiX9Kv=675fXb=it=tTh2hf+Nx4rTyD7bHS4St9UUizYtZDw@mail.gmail.com>
 <CANDiX9+Rx-syD++J2XuNHyknEccwBC=wBFPpHd7A6DYKYkubNQ@mail.gmail.com>
 <CAPM-O+wdNSLjha_91dV_84FSJWReZxGcv1qdYmp9CXpb2K27ag@mail.gmail.com>
 <CANDiX9JM3na92Umtdi=iE2mwKxor4U3PgFDL7htxMw9V=U4k9g@mail.gmail.com>
 <3364d7bd-482f-f538-da1f-90839ccaa493@DancesWithMice.info>
 <CANDiX9+4c8em_NkTsYmpTapWhOwpJego=sF4cGBPoYyvNn9+5w@mail.gmail.com>
 <bacdff09-5c3b-8cf1-3aee-18931bd9cb1f@yahoo.co.uk>
 <345ffab0-b6ed-b1ef-3dd9-50bc0d0af2fd@DancesWithMice.info>
Message-ID: <d2cfb99c-e5c3-bbee-cf84-a3d4f2fbde64@yahoo.co.uk>

On 07/01/2020 04:31, David L Neil via Tutor wrote:

>> My only question is whether the dates are relevant to the book? Or do
>> you need a Reader object? It is the reader who has reading goals. The
>> book will tell you how much to read and current position. But it is not
>> interested in dates.
> 
> Not necessarily. The reader doesn't know if (s)he is about to drop dead!
> 
> Alternately, if the book has been borrowed (eg library), then it has a 
> finite availability.

That's true and raises a moot point. If building a library app its
possible to have a LendableItem class from which all loanable objects
derive, Or you can create a Loanable mixin that is added to all loanable
stock. But it is also possible to have a Loan class associated with a
StockItem... All 3 approaches work.

My preference is for a separate Loan since it avoids having twin
versions of every kind of library item - loanable and reference...
A Loan captures the transitive relationship between a borrower and
a StockItem. It is responsible for monitoring duration, issuing
notifications, raising fines etc.

-- 
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 cmcgon at berkeley.edu  Tue Jan  7 06:00:41 2020
From: cmcgon at berkeley.edu (Casey McGonigle)
Date: Tue, 7 Jan 2020 01:00:41 -1000
Subject: [Tutor] openpyxl module not recognized
Message-ID: <CAOs74To1rfdp4u2qOcFuPoNSSMq+BbqMiLdvtbd6zBH1xWk_6Q@mail.gmail.com>

Hello,

I'm working on a project using pandas DataFrames that I'd like to export to
excel. I'm using Mac OS Mojave. I understand the way to do this is through
the df.to_excel() function, which requires the openpyxl module.

As such, I've installed the module (using pip install openpyxl) -- my
terminal tells me it was successfully installed and it shows up in my
finder.

However, when I run the df.to_excel("excel file") function, I get a
ModuleNotFoundError: No module named 'openpyxl'.

Please advise how to remedy this incongruity

-- 
UC Berkeley
Class of 2021

From arj.python at gmail.com  Tue Jan  7 07:11:21 2020
From: arj.python at gmail.com (Abdur-Rahmaan Janhangeer)
Date: Tue, 7 Jan 2020 16:11:21 +0400
Subject: [Tutor] openpyxl module not recognized
In-Reply-To: <CAOs74To1rfdp4u2qOcFuPoNSSMq+BbqMiLdvtbd6zBH1xWk_6Q@mail.gmail.com>
References: <CAOs74To1rfdp4u2qOcFuPoNSSMq+BbqMiLdvtbd6zBH1xWk_6Q@mail.gmail.com>
Message-ID: <CADrxXXnOajRuw93qxOAC-gPAEDSAL2f7fyq_3kywcP3dCxZ0Fw@mail.gmail.com>

If you used only pip install there's a possibility pip installed it in
another python version

Retry with python -m pip install ...

Then see.

On Tue, 7 Jan 2020, 15:04 Casey McGonigle, <cmcgon at berkeley.edu> wrote:

> Hello,
>
> I'm working on a project using pandas DataFrames that I'd like to export to
> excel. I'm using Mac OS Mojave. I understand the way to do this is through
> the df.to_excel() function, which requires the openpyxl module.
>
> As such, I've installed the module (using pip install openpyxl) -- my
> terminal tells me it was successfully installed and it shows up in my
> finder.
>
> However, when I run the df.to_excel("excel file") function, I get a
> ModuleNotFoundError: No module named 'openpyxl'.
>
> Please advise how to remedy this incongruity
>
> --
> UC Berkeley
> Class of 2021
> _______________________________________________
> Tutor maillist  -  Tutor at python.org
> To unsubscribe or change subscription options:
> https://mail.python.org/mailman/listinfo/tutor
>

From deepakdixit0001 at gmail.com  Tue Jan  7 09:44:45 2020
From: deepakdixit0001 at gmail.com (Deepak Dixit)
Date: Tue, 7 Jan 2020 20:14:45 +0530
Subject: [Tutor] How memory works in Python
Message-ID: <CAPmM==aBX51REGFCuFgy5HBwXuLut=inWkEZFWeXjjCYFWVxhg@mail.gmail.com>

Hi Team,

I was thinking on the memory management in Python but little confused here
because when I assign same value of type number and string to different
variable, it points to same memory but when I do it for list or tuple it
points to different memory locations.

Here is the code and the output:

# test.py
x1 = 10
y1 = 10

x2 = "Hello"
y2 = "Hello"

x3 = [10]
y3 = [10]

x4 = (10,)
y4 = (10,)

print id(x1) == id(y1)
print id(x2) == id(y2)
print id(x3) == id(y3)
print id(x4) == id(y4)

deepak at Deepak-PC:~$ python test.py
True
True
False
False


Can you help me to understand how it works?
-- 


*With Regards,*
*Deepak Kumar Dixit*

From mats at wichmann.us  Tue Jan  7 10:06:46 2020
From: mats at wichmann.us (Mats Wichmann)
Date: Tue, 7 Jan 2020 08:06:46 -0700
Subject: [Tutor] How memory works in Python
In-Reply-To: <CAPmM==aBX51REGFCuFgy5HBwXuLut=inWkEZFWeXjjCYFWVxhg@mail.gmail.com>
References: <CAPmM==aBX51REGFCuFgy5HBwXuLut=inWkEZFWeXjjCYFWVxhg@mail.gmail.com>
Message-ID: <3e399a67-d6b0-a719-b479-f7afcf5029dd@wichmann.us>

On 1/7/20 7:44 AM, Deepak Dixit wrote:
> Hi Team,
> 
> I was thinking on the memory management in Python but little confused here
> because when I assign same value of type number and string to different
> variable, it points to same memory but when I do it for list or tuple it
> points to different memory locations.
> 
> Here is the code and the output:
> 
> # test.py
> x1 = 10
> y1 = 10
> 
> x2 = "Hello"
> y2 = "Hello"
> 
> x3 = [10]
> y3 = [10]
> 
> x4 = (10,)
> y4 = (10,)
> 
> print id(x1) == id(y1)
> print id(x2) == id(y2)
> print id(x3) == id(y3)
> print id(x4) == id(y4)
> 
> deepak at Deepak-PC:~$ python test.py
> True
> True
> False
> False
> 
> 
> Can you help me to understand how it works?


quite simply, if works as you expect, but with some optimizations. 
Turns out small integers are cached in CPython - they reuse the same 
object. The current range of that is something like up to 256 (I think a 
small number of negative integers also have this happen).  Try that 
experiment again with bigger numbers.

Similarly for strings, small strings are interned, try it with a 
considerably longer string.

You can cause the string interning to happen yourself with the intern 
function, see this example:

 >>> y1 = "Hello, this is a much longer string"
 >>> y2 = "Hello, this is a much longer string"
 >>> print(id(y1) == id(y2))
False
 >>> import sys
 >>> y1 = sys.intern("Hello, this is a much longer string")
 >>> y2 = sys.intern("Hello, this is a much longer string")
 >>> print(id(y1) == id(y2))
True
 >>>



From PyTutor at DancesWithMice.info  Tue Jan  7 14:04:45 2020
From: PyTutor at DancesWithMice.info (David L Neil)
Date: Wed, 8 Jan 2020 08:04:45 +1300
Subject: [Tutor] How memory works in Python
In-Reply-To: <CAPmM==aBX51REGFCuFgy5HBwXuLut=inWkEZFWeXjjCYFWVxhg@mail.gmail.com>
References: <CAPmM==aBX51REGFCuFgy5HBwXuLut=inWkEZFWeXjjCYFWVxhg@mail.gmail.com>
Message-ID: <304f6b6a-ad2e-cce4-dfd7-3ee94f68b73d@DancesWithMice.info>

On 8/01/20 3:44 AM, Deepak Dixit wrote:
> Hi Team,
> 
> I was thinking on the memory management in Python but little confused here
> because when I assign same value of type number and string to different
> variable, it points to same memory but when I do it for list or tuple it
> points to different memory locations.
> 
> Here is the code and the output:
> 
> # test.py
> x1 = 10
> y1 = 10
> 
> x2 = "Hello"
> y2 = "Hello"
> 
> x3 = [10]
> y3 = [10]
> 
> x4 = (10,)
> y4 = (10,)
> 
> print id(x1) == id(y1)
> print id(x2) == id(y2)
> print id(x3) == id(y3)
> print id(x4) == id(y4)
> 
> deepak at Deepak-PC:~$ python test.py
> True
> True
> False
> False
> 
> 
> Can you help me to understand how it works?


You may find http://pythontutor.com/visualize.html#mode=edit helpful.
NB no formal relationship with this list (to my knowledge)

It is designed as a learning aid by illustrating storage allocations and 
usage.
-- 
Regards =dn

From cmcgon at berkeley.edu  Tue Jan  7 15:31:34 2020
From: cmcgon at berkeley.edu (Casey McGonigle)
Date: Tue, 7 Jan 2020 10:31:34 -1000
Subject: [Tutor] openpyxl module not recognized
In-Reply-To: <CADrxXXnOajRuw93qxOAC-gPAEDSAL2f7fyq_3kywcP3dCxZ0Fw@mail.gmail.com>
References: <CAOs74To1rfdp4u2qOcFuPoNSSMq+BbqMiLdvtbd6zBH1xWk_6Q@mail.gmail.com>
 <CADrxXXnOajRuw93qxOAC-gPAEDSAL2f7fyq_3kywcP3dCxZ0Fw@mail.gmail.com>
Message-ID: <CAOs74Tqq0MJw27BOEFPYD2FXCVNKgm7=qrhmrDBs_L2eLhpTkw@mail.gmail.com>

I've done this -- it gives me the message

Requirement already satisfied: openpyxl in
/anaconda3/lib/python3.7/site-packages (3.0.2)

anything else that could be causing the issue?


On Tue, Jan 7, 2020 at 2:11 AM Abdur-Rahmaan Janhangeer <
arj.python at gmail.com> wrote:

> If you used only pip install there's a possibility pip installed it in
> another python version
>
> Retry with python -m pip install ...
>
> Then see.
>
> On Tue, 7 Jan 2020, 15:04 Casey McGonigle, <cmcgon at berkeley.edu> wrote:
>
>> Hello,
>>
>> I'm working on a project using pandas DataFrames that I'd like to export
>> to
>> excel. I'm using Mac OS Mojave. I understand the way to do this is through
>> the df.to_excel() function, which requires the openpyxl module.
>>
>> As such, I've installed the module (using pip install openpyxl) -- my
>> terminal tells me it was successfully installed and it shows up in my
>> finder.
>>
>> However, when I run the df.to_excel("excel file") function, I get a
>> ModuleNotFoundError: No module named 'openpyxl'.
>>
>> Please advise how to remedy this incongruity
>>
>> --
>> UC Berkeley
>> Class of 2021
>> _______________________________________________
>> Tutor maillist  -  Tutor at python.org
>> To unsubscribe or change subscription options:
>> https://mail.python.org/mailman/listinfo/tutor
>>
>

-- 
UC Berkeley
Class of 2021

From alan.gauld at yahoo.co.uk  Tue Jan  7 20:34:17 2020
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Wed, 8 Jan 2020 01:34:17 +0000
Subject: [Tutor] openpyxl module not recognized
In-Reply-To: <CAOs74Tqq0MJw27BOEFPYD2FXCVNKgm7=qrhmrDBs_L2eLhpTkw@mail.gmail.com>
References: <CAOs74To1rfdp4u2qOcFuPoNSSMq+BbqMiLdvtbd6zBH1xWk_6Q@mail.gmail.com>
 <CADrxXXnOajRuw93qxOAC-gPAEDSAL2f7fyq_3kywcP3dCxZ0Fw@mail.gmail.com>
 <CAOs74Tqq0MJw27BOEFPYD2FXCVNKgm7=qrhmrDBs_L2eLhpTkw@mail.gmail.com>
Message-ID: <b32f1b24-790e-2cc0-3ea9-bcf25362e284@yahoo.co.uk>

On 07/01/2020 20:31, Casey McGonigle wrote:
> I've done this -- it gives me the message
> 
> Requirement already satisfied: openpyxl in
> /anaconda3/lib/python3.7/site-packages (3.0.2)
...
>>> However, when I run the df.to_excel("excel file") function, I get a
>>> ModuleNotFoundError: No module named 'openpyxl'.
>>>

Please send the full command line used to launch the
program plus the full error trace you received,
not just the last lines.

-- 
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 sarfraaz at gmail.com  Wed Jan  8 00:36:12 2020
From: sarfraaz at gmail.com (Sarfraaz Ahmed)
Date: Wed, 8 Jan 2020 11:06:12 +0530
Subject: [Tutor] openpyxl module not recognized
In-Reply-To: <CAOs74To1rfdp4u2qOcFuPoNSSMq+BbqMiLdvtbd6zBH1xWk_6Q@mail.gmail.com>
References: <CAOs74To1rfdp4u2qOcFuPoNSSMq+BbqMiLdvtbd6zBH1xWk_6Q@mail.gmail.com>
Message-ID: <CAKvdLD71HkKOp2_y70psgoye52SE8Z74tFVsLQskN2xPFgAv9g@mail.gmail.com>

Hello Casey,

Am taking a wild guess and assuming that you are executing your code from
some sort of an editor or some such and may be that editor is not picking
the right version of Python. If that is really the case, then I found a
comment on stackoverflow that talks about solving it.

The relevant comment for your scenario : "check your python version first,
then refer to this answer :
https://stackoverflow.com/questions/23161604/how-to-set-which-version-of-python-sublime-text-uses
"

The original question :
https://stackoverflow.com/questions/44223621/no-module-named-openpyxl-python-3-6-osx

Hope that helps.

On Tue, Jan 7, 2020 at 4:35 PM Casey McGonigle <cmcgon at berkeley.edu> wrote:

> Hello,
>
> I'm working on a project using pandas DataFrames that I'd like to export to
> excel. I'm using Mac OS Mojave. I understand the way to do this is through
> the df.to_excel() function, which requires the openpyxl module.
>
> As such, I've installed the module (using pip install openpyxl) -- my
> terminal tells me it was successfully installed and it shows up in my
> finder.
>
> However, when I run the df.to_excel("excel file") function, I get a
> ModuleNotFoundError: No module named 'openpyxl'.
>
> Please advise how to remedy this incongruity
>
> --
> UC Berkeley
> Class of 2021
> _______________________________________________
> Tutor maillist  -  Tutor at python.org
> To unsubscribe or change subscription options:
> https://mail.python.org/mailman/listinfo/tutor
>


-- 
        Thanks
               -- Sarfraaz Ahmed

From cal.97g at gmail.com  Wed Jan  8 05:28:20 2020
From: cal.97g at gmail.com (Cal97g .)
Date: Wed, 8 Jan 2020 10:28:20 +0000
Subject: [Tutor] How memory works in Python
In-Reply-To: <CAPmM==aBX51REGFCuFgy5HBwXuLut=inWkEZFWeXjjCYFWVxhg@mail.gmail.com>
References: <CAPmM==aBX51REGFCuFgy5HBwXuLut=inWkEZFWeXjjCYFWVxhg@mail.gmail.com>
Message-ID: <CABEZvgpA1=ZgXq=WZaFgGR_-2PUSun_pV1p+rOs0yTuOkdoxww@mail.gmail.com>

What is happening is that python sees you have some small variables which
are identical. As these variables are immutable python knows they cannot be
changed.

Instead of creating a new memory location for each variable, python
references the same memory location for both items.

This is why your the id for (x1, y1) + (x2, y2) is identical.

Many Thanks

Callam Delaney


On Tue, 7 Jan 2020 at 14:45, Deepak Dixit <deepakdixit0001 at gmail.com> wrote:

> Hi Team,
>
> I was thinking on the memory management in Python but little confused here
> because when I assign same value of type number and string to different
> variable, it points to same memory but when I do it for list or tuple it
> points to different memory locations.
>
> Here is the code and the output:
>
> # test.py
> x1 = 10
> y1 = 10
>
> x2 = "Hello"
> y2 = "Hello"
>
> x3 = [10]
> y3 = [10]
>
> x4 = (10,)
> y4 = (10,)
>
> print id(x1) == id(y1)
> print id(x2) == id(y2)
> print id(x3) == id(y3)
> print id(x4) == id(y4)
>
> deepak at Deepak-PC:~$ python test.py
> True
> True
> False
> False
>
>
> Can you help me to understand how it works?
> --
>
>
> *With Regards,*
> *Deepak Kumar Dixit*
> _______________________________________________
> Tutor maillist  -  Tutor at python.org
> To unsubscribe or change subscription options:
> https://mail.python.org/mailman/listinfo/tutor
>

From deepakdixit0001 at gmail.com  Wed Jan  8 05:49:06 2020
From: deepakdixit0001 at gmail.com (Deepak Dixit)
Date: Wed, 8 Jan 2020 16:19:06 +0530
Subject: [Tutor] How memory works in Python
In-Reply-To: <CABEZvgpA1=ZgXq=WZaFgGR_-2PUSun_pV1p+rOs0yTuOkdoxww@mail.gmail.com>
References: <CAPmM==aBX51REGFCuFgy5HBwXuLut=inWkEZFWeXjjCYFWVxhg@mail.gmail.com>
 <CABEZvgpA1=ZgXq=WZaFgGR_-2PUSun_pV1p+rOs0yTuOkdoxww@mail.gmail.com>
Message-ID: <CAPmM==ZfDrVuschUBwG2Zbvbq1EtU98mFRpiKbig23NHp0RsSw@mail.gmail.com>

As you can see in the code, we are getting different location for tuple
which is also immutable. So it should not be dependent on type of variable.

Anyway, Thanks for your help.

On Wed, Jan 8, 2020, 3:58 PM Cal97g . <cal.97g at gmail.com> wrote:

> What is happening is that python sees you have some small variables which
> are identical. As these variables are immutable python knows they cannot be
> changed.
>
> Instead of creating a new memory location for each variable, python
> references the same memory location for both items.
>
> This is why your the id for (x1, y1) + (x2, y2) is identical.
>
> Many Thanks
>
> Callam Delaney
>
>
> On Tue, 7 Jan 2020 at 14:45, Deepak Dixit <deepakdixit0001 at gmail.com>
> wrote:
>
>> Hi Team,
>>
>> I was thinking on the memory management in Python but little confused here
>> because when I assign same value of type number and string to different
>> variable, it points to same memory but when I do it for list or tuple it
>> points to different memory locations.
>>
>> Here is the code and the output:
>>
>> # test.py
>> x1 = 10
>> y1 = 10
>>
>> x2 = "Hello"
>> y2 = "Hello"
>>
>> x3 = [10]
>> y3 = [10]
>>
>> x4 = (10,)
>> y4 = (10,)
>>
>> print id(x1) == id(y1)
>> print id(x2) == id(y2)
>> print id(x3) == id(y3)
>> print id(x4) == id(y4)
>>
>> deepak at Deepak-PC:~$ python test.py
>> True
>> True
>> False
>> False
>>
>>
>> Can you help me to understand how it works?
>> --
>>
>>
>> *With Regards,*
>> *Deepak Kumar Dixit*
>> _______________________________________________
>> Tutor maillist  -  Tutor at python.org
>> To unsubscribe or change subscription options:
>> https://mail.python.org/mailman/listinfo/tutor
>>
>

From niharika1883 at gmail.com  Wed Jan  8 07:56:16 2020
From: niharika1883 at gmail.com (Niharika Jakhar)
Date: Wed, 8 Jan 2020 13:56:16 +0100
Subject: [Tutor] Query regarding file conversion - DOT files
Message-ID: <CABrCUu1cdv32SkL2i8KTQceL3vK7-fDrNUbnJv6u-R4Ue=KTFw@mail.gmail.com>

Hello

I am a masters student, and beginner in python programming. I seek help and
guidance from the tutors here. Thanks in advance.

Problem: Convert DOT files to PDF.

I came across pydot for this and tried following:
#####code####
import os
import pydot
(graph,) = pydot.graph_from_dot_file('hello.dot')
graph.write_png('hellow.png')

Error:
 assert process.returncode == 0, process.returncode

AssertionError: 1



Python version: 3.7.4
Development environment: Spyder

Best regards
Niharika

From gogonegro at gmail.com  Wed Jan  8 12:28:02 2020
From: gogonegro at gmail.com (Robert Alexander)
Date: Wed, 8 Jan 2020 09:28:02 -0800
Subject: [Tutor] Query regarding file conversion - DOT files
In-Reply-To: <CABrCUu1cdv32SkL2i8KTQceL3vK7-fDrNUbnJv6u-R4Ue=KTFw@mail.gmail.com>
References: <CABrCUu1cdv32SkL2i8KTQceL3vK7-fDrNUbnJv6u-R4Ue=KTFw@mail.gmail.com>
Message-ID: <CADiDnXdhRuWb7r=UQEJaOJM5qphNTyvkBQQhHBuk-0im0xQthg@mail.gmail.com>

Should?nt the line be

graph = pydot.graph_from_dot_file('hello.dot?)

?

HTH
Robert


On 8 January 2020 at 18:25:30, Niharika Jakhar (niharika1883 at gmail.com)
wrote:

Hello

I am a masters student, and beginner in python programming. I seek help and
guidance from the tutors here. Thanks in advance.

Problem: Convert DOT files to PDF.

I came across pydot for this and tried following:
#####code####
import os
import pydot
(graph,) = pydot.graph_from_dot_file('hello.dot')
graph.write_png('hellow.png')

Error:
assert process.returncode == 0, process.returncode

AssertionError: 1



Python version: 3.7.4
Development environment: Spyder

Best regards
Niharika
_______________________________________________
Tutor maillist - Tutor at python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor

From alan.gauld at yahoo.co.uk  Wed Jan  8 12:42:15 2020
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Wed, 8 Jan 2020 17:42:15 +0000
Subject: [Tutor] Query regarding file conversion - DOT files
In-Reply-To: <CABrCUu1cdv32SkL2i8KTQceL3vK7-fDrNUbnJv6u-R4Ue=KTFw@mail.gmail.com>
References: <CABrCUu1cdv32SkL2i8KTQceL3vK7-fDrNUbnJv6u-R4Ue=KTFw@mail.gmail.com>
Message-ID: <042e0a76-199f-f95e-27cf-530e93f956e4@yahoo.co.uk>

On 08/01/2020 12:56, Niharika Jakhar wrote:

> I came across pydot for this and tried following:
> #####code####
> import os
> import pydot
> (graph,) = pydot.graph_from_dot_file('hello.dot')
> graph.write_png('hellow.png')
> 
> Error:
>  assert process.returncode == 0, process.returncode
> 
> AssertionError: 1

Please, always post the full error trace, do not summarize
or shorten it. They contain a lot of useful detail and
without it we are only making guesses.

Also, for specialist libraries that are not part of
the python core, it is always worth contacting the
package maintainer or support forum. They will have
more experience than us.

-- 
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 mats at wichmann.us  Wed Jan  8 12:52:34 2020
From: mats at wichmann.us (Mats Wichmann)
Date: Wed, 8 Jan 2020 10:52:34 -0700
Subject: [Tutor] Query regarding file conversion - DOT files
In-Reply-To: <042e0a76-199f-f95e-27cf-530e93f956e4@yahoo.co.uk>
References: <CABrCUu1cdv32SkL2i8KTQceL3vK7-fDrNUbnJv6u-R4Ue=KTFw@mail.gmail.com>
 <042e0a76-199f-f95e-27cf-530e93f956e4@yahoo.co.uk>
Message-ID: <3c28d846-9e94-c3dd-3928-2e3f8e16a379@wichmann.us>

On 1/8/20 10:42 AM, Alan Gauld via Tutor wrote:
> On 08/01/2020 12:56, Niharika Jakhar wrote:
> 
>> I came across pydot for this and tried following:
>> #####code####
>> import os
>> import pydot
>> (graph,) = pydot.graph_from_dot_file('hello.dot')
>> graph.write_png('hellow.png')
>>
>> Error:
>>   assert process.returncode == 0, process.returncode
>>
>> AssertionError: 1
> 
> Please, always post the full error trace, do not summarize
> or shorten it. They contain a lot of useful detail and
> without it we are only making guesses.

what he said :)

Is graphviz installed? I believe pydot and its descendants (like 
pydotplus) require an installation of graphviz, which does not come in 
when you install pydot*.

if the failure comes from the graph.write_png call - we can't tell 
because the proper error trace is missing - this may well be the issue, 
it's either not installed, or not found.



From niharika1883 at gmail.com  Wed Jan  8 12:38:12 2020
From: niharika1883 at gmail.com (Niharika Jakhar)
Date: Wed, 8 Jan 2020 18:38:12 +0100
Subject: [Tutor] Query regarding file conversion - DOT files
In-Reply-To: <CADiDnXdhRuWb7r=UQEJaOJM5qphNTyvkBQQhHBuk-0im0xQthg@mail.gmail.com>
References: <CABrCUu1cdv32SkL2i8KTQceL3vK7-fDrNUbnJv6u-R4Ue=KTFw@mail.gmail.com>
 <CADiDnXdhRuWb7r=UQEJaOJM5qphNTyvkBQQhHBuk-0im0xQthg@mail.gmail.com>
Message-ID: <CABrCUu2ZyY-SBgnLEzM6pTmWEqnbv3ZmY+QuSm3qycGSq4kjQw@mail.gmail.com>

No, it doesn't work for me.
Error:
graph.write_png('hellow.png')

AttributeError: 'list' object has no attribute 'write_png'

On Wed, Jan 8, 2020 at 6:28 PM Robert Alexander <gogonegro at gmail.com> wrote:

> Should?nt the line be
>
> graph = pydot.graph_from_dot_file('hello.dot?)
>
> ?
>
> HTH
> Robert
>
>
> On 8 January 2020 at 18:25:30, Niharika Jakhar (niharika1883 at gmail.com)
> wrote:
>
> Hello
>
> I am a masters student, and beginner in python programming. I seek help
> and
> guidance from the tutors here. Thanks in advance.
>
> Problem: Convert DOT files to PDF.
>
> I came across pydot for this and tried following:
> #####code####
> import os
> import pydot
> (graph,) = pydot.graph_from_dot_file('hello.dot')
> graph.write_png('hellow.png')
>
> Error:
> assert process.returncode == 0, process.returncode
>
> AssertionError: 1
>
>
>
> Python version: 3.7.4
> Development environment: Spyder
>
> Best regards
> Niharika
> _______________________________________________
> Tutor maillist - Tutor at python.org
> To unsubscribe or change subscription options:
> https://mail.python.org/mailman/listinfo/tutor
>
>

From alan.gauld at yahoo.co.uk  Wed Jan  8 16:25:30 2020
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Wed, 8 Jan 2020 21:25:30 +0000
Subject: [Tutor] Query regarding file conversion - DOT files
In-Reply-To: <CABrCUu2ZyY-SBgnLEzM6pTmWEqnbv3ZmY+QuSm3qycGSq4kjQw@mail.gmail.com>
References: <CABrCUu1cdv32SkL2i8KTQceL3vK7-fDrNUbnJv6u-R4Ue=KTFw@mail.gmail.com>
 <CADiDnXdhRuWb7r=UQEJaOJM5qphNTyvkBQQhHBuk-0im0xQthg@mail.gmail.com>
 <CABrCUu2ZyY-SBgnLEzM6pTmWEqnbv3ZmY+QuSm3qycGSq4kjQw@mail.gmail.com>
Message-ID: <f80abf8f-510c-7241-7c48-db6f16b379da@yahoo.co.uk>

On 08/01/2020 17:38, Niharika Jakhar wrote:
> No, it doesn't work for me.
> Error:
> graph.write_png('hellow.png')
> 
> AttributeError: 'list' object has no attribute 'write_png'

Please post the full error trace, not just the last line.

Also note that Robert suggested changing the tuple on
the left side, not the function call:

>> graph = pydot.graph_from_dot_file('hello.dot?)


-- 
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 mats at wichmann.us  Wed Jan  8 17:16:36 2020
From: mats at wichmann.us (Mats Wichmann)
Date: Wed, 8 Jan 2020 15:16:36 -0700
Subject: [Tutor] openpyxl module not recognized
In-Reply-To: <CAOs74Tqq0MJw27BOEFPYD2FXCVNKgm7=qrhmrDBs_L2eLhpTkw@mail.gmail.com>
References: <CAOs74To1rfdp4u2qOcFuPoNSSMq+BbqMiLdvtbd6zBH1xWk_6Q@mail.gmail.com>
 <CADrxXXnOajRuw93qxOAC-gPAEDSAL2f7fyq_3kywcP3dCxZ0Fw@mail.gmail.com>
 <CAOs74Tqq0MJw27BOEFPYD2FXCVNKgm7=qrhmrDBs_L2eLhpTkw@mail.gmail.com>
Message-ID: <2a128815-68cc-347a-3396-7cdde0711169@wichmann.us>

On 1/7/20 1:31 PM, Casey McGonigle wrote:
> I've done this -- it gives me the message
> 
> Requirement already satisfied: openpyxl in
> /anaconda3/lib/python3.7/site-packages (3.0.2)
> 
> anything else that could be causing the issue?

>>> I'm working on a project using pandas DataFrames that I'd like to export
>>> to
>>> excel. I'm using Mac OS Mojave. I understand the way to do this is through
>>> the df.to_excel() function, which requires the openpyxl module.
>>>
>>> As such, I've installed the module (using pip install openpyxl) -- my
>>> terminal tells me it was successfully installed and it shows up in my
>>> finder.
>>>
>>> However, when I run the df.to_excel("excel file") function, I get a
>>> ModuleNotFoundError: No module named 'openpyxl'.

The good news is we know exactly what's wrong.  That message always 
means a path problem, one of two possibilities:

- the module is not installed. that is, there is no path at all on the 
system that would work to import it.
- or, the module is installed, but the python instance you're using 
doesn't know the path to it.

You don't want a history lesson, but there was a time when if you had 
python, everything was attached to that Python, and it was a little 
simpler.  These days, odds are pretty good you have more than one, and 
ones you have may or may not have several distinct instances 
(virtualenvs). The message at the top indicates you have a separate 
distribution via Anaconda, so if you've installed a regular Python.org 
python, or are running Linux or Mac (which come with a system-provided 
version), in which case you have at least two. I'm not an Anaconda user, 
but I believe Conda is quite aggressive in setting up virtualenvs.

For any given invocation of Python, here's how you see where it knows to 
look:

 >>> import sys
 >>> print(sys.path)

One persistent problem we're seeing a lot of these days is that 
instructions for things say to do

pip install this-wonderful-package

If you have several Pythons installed, how can you know which Python pip 
is going to install for?  Therefore, it's usually worth modifying that 
instruction they have given you and invoke it this way:

python -m pip install this-wonderful-package

then whatever is installed matches the python you invoked that command with.

However... if you're using Anaconda, it has its own installation system 
and doesn't install using pip, but you also indicated you used pip to 
install it, so at this point I'm pretty confused.  Conda should be able 
to get things right - but then you have to invoke the same Python as it 
does.

This is without even getting into the complication of virtualenvs.

So the challenge is to get things to match.  For whichever Python you 
used that gave you the failure, try this:

python -m pip list

and see if it lists openpyxl

or invoke it interactively and try the import:

 >>> import openpyxl


Hope this gets you at least a little closer to understanding, if not 
solving.

>>> UC Berkeley
>>> Class of 2021


Cheers!

-- mats, UC Berkeley Class of Long Ago
(well, okay, 1981)

From zebra05 at gmail.com  Mon Jan 13 08:33:43 2020
From: zebra05 at gmail.com (S D)
Date: Mon, 13 Jan 2020 15:33:43 +0200
Subject: [Tutor] Imports (Py 3)
Message-ID: <CAH-SnCCkXBtXh-hjJJvcaEnqqjuO77k7QGZ+ua_5RwMQxLPz5w@mail.gmail.com>

I have a folder `abc_app`, which contains a module `utils`. In the
`abc_app` folder, I also have a subfolder `tests` which contains a module
`test_api`

How do I import a function from the `utils` module from the `test_api`
module?


Kind regards,
- SD

From mats at wichmann.us  Mon Jan 13 09:49:24 2020
From: mats at wichmann.us (Mats Wichmann)
Date: Mon, 13 Jan 2020 07:49:24 -0700
Subject: [Tutor] Imports (Py 3)
In-Reply-To: <CAH-SnCCkXBtXh-hjJJvcaEnqqjuO77k7QGZ+ua_5RwMQxLPz5w@mail.gmail.com>
References: <CAH-SnCCkXBtXh-hjJJvcaEnqqjuO77k7QGZ+ua_5RwMQxLPz5w@mail.gmail.com>
Message-ID: <351d2a55-c3da-dbcf-40d5-03d91654f6a3@wichmann.us>

On 1/13/20 6:33 AM, S D wrote:
> I have a folder `abc_app`, which contains a module `utils`. In the
> `abc_app` folder, I also have a subfolder `tests` which contains a module
> `test_api`
> 
> How do I import a function from the `utils` module from the `test_api`
> module?

"relative imports".  which can be vaguely confusing, it's worth reading 
a tutorial on them to be sure you understand.

if "foo" is in "utils", what you described ought to look like:

from ..utils import foo

(unless I managed to confuse myself!)



From akleider at sonic.net  Mon Jan 13 16:59:42 2020
From: akleider at sonic.net (Alex Kleider)
Date: Mon, 13 Jan 2020 13:59:42 -0800
Subject: [Tutor] Imports (Py 3)
In-Reply-To: <351d2a55-c3da-dbcf-40d5-03d91654f6a3@wichmann.us>
References: <CAH-SnCCkXBtXh-hjJJvcaEnqqjuO77k7QGZ+ua_5RwMQxLPz5w@mail.gmail.com>
 <351d2a55-c3da-dbcf-40d5-03d91654f6a3@wichmann.us>
Message-ID: <9ac1a64c4284268735c372d345914553@sonic.net>

On 2020-01-13 06:49, Mats Wichmann wrote:
> On 1/13/20 6:33 AM, S D wrote:
>> I have a folder `abc_app`, which contains a module `utils`. In the
>> `abc_app` folder, I also have a subfolder `tests` which contains a 
>> module
>> `test_api`
>> 
>> How do I import a function from the `utils` module from the `test_api`
>> module?
> 
> "relative imports".  which can be vaguely confusing, it's worth
> reading a tutorial on them to be sure you understand.
> 
> if "foo" is in "utils", what you described ought to look like:
> 
> from ..utils import foo
> 
> (unless I managed to confuse myself!)
> 

This is a problem with which I also have struggled and was never able to 
get the (..) syntax of relative imports to work so I solved it another 
way placing the following code at the top of the file containing the 
tests:

path2add = os.path.expandvars("${CLUB}/Utils")
sys.path.append(path2add)

If the first line confuses you just ignore it and assign the full path 
name to and including your 'utils.py' file to the path2add variable.


From nandishn17 at gmail.com  Thu Jan 16 08:00:33 2020
From: nandishn17 at gmail.com (Nandish N)
Date: Thu, 16 Jan 2020 18:30:33 +0530
Subject: [Tutor] Fetch CPU and GPU values from python
Message-ID: <CAA_5kuEfYc_srVWDyMH+fc6DGBdTExez9Hai2yYPOB7Ua5X88Q@mail.gmail.com>

Hi,

I want to fetch system cpu,process cpu and gpu values from task manager, on
exploring I got to know about psutil.cpu_percent() and GPUtil and here is
the code used:



import os
import time
import psutil
from GPUtil import GPUtil


string=xyz
timer=124
listOfProcessNames=[]

pInfoDict={}
while timer != 1:

    for x in range(3):

        print(psutil.cpu_percent(1))

        #print("GPU:",GPUtil.showUtilization())

    psutil.process_iter()

    for proc in psutil.process_iter():

            processName = proc.name()

            processID = proc.pid

            if processName.find("xyz") != -1:

                #print(proc)

                print(processName)

                print(processID)

                cpu=proc.cpu_percent()

                print(cpu)

                pInfoDict = proc.as_dict(attrs=('name', 'cpu_percent'))

                # Append dict of process detail in list

                listOfProcessNames.append(pInfoDict)


    #print(listOfProcessNames)

    os.system('wmic cpu get loadpercentage')

    timer=timer-1

    time.sleep(5)

What is the output of psutil.cpu_percent() is it system cpu values?

And does proc.cpu_percent() give process cpu value?
Is there any function to get values for Data-In/Data-Out, Memeory info?

How to call shell script from python?

I kindly request you to help me in getting the above values mentioned,
Thanks in advance.



Regards,

Nandish.

From jf_byrnes at comcast.net  Thu Jan 16 14:20:05 2020
From: jf_byrnes at comcast.net (Jim)
Date: Thu, 16 Jan 2020 13:20:05 -0600
Subject: [Tutor] OT - gmane
Message-ID: <65d78a9d-d7ad-c4c4-7947-7bbfbe93444e@comcast.net>

Is anyone else having trouble connecting to gmane?

I know that tutor is pretty sporadic on it but until today I have been 
able to connect and read other groups.

Thanks,  Jim

From mats at wichmann.us  Thu Jan 16 14:25:06 2020
From: mats at wichmann.us (Mats Wichmann)
Date: Thu, 16 Jan 2020 12:25:06 -0700
Subject: [Tutor] OT - gmane
In-Reply-To: <65d78a9d-d7ad-c4c4-7947-7bbfbe93444e@comcast.net>
References: <65d78a9d-d7ad-c4c4-7947-7bbfbe93444e@comcast.net>
Message-ID: <da938764-7454-1fc6-7bc4-19cb28f1e7af@wichmann.us>

On 1/16/20 12:20 PM, Jim wrote:
> Is anyone else having trouble connecting to gmane?
> 
> I know that tutor is pretty sporadic on it but until today I have been 
> able to connect and read other groups.
> 
> Thanks,? Jim
> _______________________________________________
> Tutor maillist? -? Tutor at python.org
> To unsubscribe or change subscription options:
> https://mail.python.org/mailman/listinfo/tutor

a quick check shows everything down...

https://notopening.com/site/gmane.org

From zachary.ware+pytut at gmail.com  Thu Jan 16 14:38:28 2020
From: zachary.ware+pytut at gmail.com (Zachary Ware)
Date: Thu, 16 Jan 2020 13:38:28 -0600
Subject: [Tutor] OT - gmane
In-Reply-To: <65d78a9d-d7ad-c4c4-7947-7bbfbe93444e@comcast.net>
References: <65d78a9d-d7ad-c4c4-7947-7bbfbe93444e@comcast.net>
Message-ID: <CAKJDb-ME_fNJxPQJpc86DapSap8+4ZdiToBzJGuA2_rgc1POZw@mail.gmail.com>

On Thu, Jan 16, 2020 at 1:23 PM Jim <jf_byrnes at comcast.net> wrote:
> Is anyone else having trouble connecting to gmane?
>
> I know that tutor is pretty sporadic on it but until today I have been
> able to connect and read other groups.

Gmane has moved:
https://lars.ingebrigtsen.no/2020/01/15/news-gmane-org-is-now-news-gmane-io/

-- 
Zach

From alan.gauld at yahoo.co.uk  Thu Jan 16 15:23:44 2020
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Thu, 16 Jan 2020 20:23:44 +0000
Subject: [Tutor] OT - gmane
In-Reply-To: <65d78a9d-d7ad-c4c4-7947-7bbfbe93444e@comcast.net>
References: <65d78a9d-d7ad-c4c4-7947-7bbfbe93444e@comcast.net>
Message-ID: <445924ab-3a7e-2008-0cf5-02054a3f8ffb@yahoo.co.uk>

On 16/01/2020 19:20, Jim wrote:
> Is anyone else having trouble connecting to gmane?
> 
> I know that tutor is pretty sporadic on it but until today I have been 
> able to connect and read other groups.

Tutor has not worked on gmane since the great unsubscription
event a few months ago.

Gmane works by subscribing to the list and getting a feed.
It was unsubscribed along with everyone else. But gmane
is not maintained so nobody is there to resubscribe...

I note that gmane has a new home. It might now be possible
to get somebody to reinstate the tutor link. I'll see if
I can find someone to do so...

-- 
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 jf_byrnes at comcast.net  Thu Jan 16 15:50:33 2020
From: jf_byrnes at comcast.net (Jim)
Date: Thu, 16 Jan 2020 14:50:33 -0600
Subject: [Tutor] OT - gmane
In-Reply-To: <445924ab-3a7e-2008-0cf5-02054a3f8ffb@yahoo.co.uk>
References: <65d78a9d-d7ad-c4c4-7947-7bbfbe93444e@comcast.net>
 <445924ab-3a7e-2008-0cf5-02054a3f8ffb@yahoo.co.uk>
Message-ID: <2ca3730f-b106-0b67-e427-3295747546d7@comcast.net>

On 1/16/20 2:23 PM, Alan Gauld via Tutor wrote:
> On 16/01/2020 19:20, Jim wrote:
>> Is anyone else having trouble connecting to gmane?
>>
>> I know that tutor is pretty sporadic on it but until today I have been
>> able to connect and read other groups.
> 
> Tutor has not worked on gmane since the great unsubscription
> event a few months ago.
> 
> Gmane works by subscribing to the list and getting a feed.
> It was unsubscribed along with everyone else. But gmane
> is not maintained so nobody is there to resubscribe...
> 
> I note that gmane has a new home. It might now be possible
> to get somebody to reinstate the tutor link. I'll see if
> I can find someone to do so...
> 

Thanks to everyone for letting me know it's not just me.

I never unsubscribed when the problems started, so I occasionally 
actually get a tutor message off of gmane.

Jim

From alan.gauld at yahoo.co.uk  Thu Jan 16 16:10:35 2020
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Thu, 16 Jan 2020 21:10:35 +0000
Subject: [Tutor] OT - gmane
In-Reply-To: <CAKJDb-ME_fNJxPQJpc86DapSap8+4ZdiToBzJGuA2_rgc1POZw@mail.gmail.com>
References: <65d78a9d-d7ad-c4c4-7947-7bbfbe93444e@comcast.net>
 <CAKJDb-ME_fNJxPQJpc86DapSap8+4ZdiToBzJGuA2_rgc1POZw@mail.gmail.com>
Message-ID: <b47fada5-52d5-1765-72c0-1ad057153ed8@yahoo.co.uk>

On 16/01/2020 19:38, Zachary Ware wrote:

> Gmane has moved:
> https://lars.ingebrigtsen.no/2020/01/15/news-gmane-org-is-now-news-gmane-io/
> 

Has anyone succeeded in getting the nntp feed to work
on the new servers?

Not just the tutor list - anything at all?

I failed miserably.

-- 
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 robertvstepp at gmail.com  Thu Jan 16 23:13:18 2020
From: robertvstepp at gmail.com (boB Stepp)
Date: Thu, 16 Jan 2020 22:13:18 -0600
Subject: [Tutor] Fetch CPU and GPU values from python
In-Reply-To: <CAA_5kuEfYc_srVWDyMH+fc6DGBdTExez9Hai2yYPOB7Ua5X88Q@mail.gmail.com>
References: <CAA_5kuEfYc_srVWDyMH+fc6DGBdTExez9Hai2yYPOB7Ua5X88Q@mail.gmail.com>
Message-ID: <CANDiX9KMYtwERfGv43rk0G2vJfO5cDCKuUoW6r3-RZTKx=B+uw@mail.gmail.com>

On Thu, Jan 16, 2020 at 7:25 AM Nandish N <nandishn17 at gmail.com> wrote:

> And does proc.cpu_percent() give process cpu value?
> Is there any function to get values for Data-In/Data-Out, Memeory info?

Searching for "psutil docs" I found:
https://psutil.readthedocs.io/en/latest/#system-related-functions

> How to call shell script from python?

Perhaps the subprocess module in the Python 3 standard library might
be helpful?  https://docs.python.org/3/library/subprocess.html



-- 
boB

From jf_byrnes at comcast.net  Fri Jan 17 12:08:46 2020
From: jf_byrnes at comcast.net (Jim)
Date: Fri, 17 Jan 2020 11:08:46 -0600
Subject: [Tutor] OT - gmane
In-Reply-To: <b47fada5-52d5-1765-72c0-1ad057153ed8@yahoo.co.uk>
References: <65d78a9d-d7ad-c4c4-7947-7bbfbe93444e@comcast.net>
 <CAKJDb-ME_fNJxPQJpc86DapSap8+4ZdiToBzJGuA2_rgc1POZw@mail.gmail.com>
 <b47fada5-52d5-1765-72c0-1ad057153ed8@yahoo.co.uk>
Message-ID: <d9d62c66-6e75-0fb8-5458-89a01a3b18dd@comcast.net>

On 1/16/20 3:10 PM, Alan Gauld via Tutor wrote:
> On 16/01/2020 19:38, Zachary Ware wrote:
> 
>> Gmane has moved:
>> https://lars.ingebrigtsen.no/2020/01/15/news-gmane-org-is-now-news-gmane-io/
>>
> 
> Has anyone succeeded in getting the nntp feed to work
> on the new servers?
> 
> Not just the tutor list - anything at all?
> 
> I failed miserably.
> 

Alan,

I just managed to download all the messages from the newsgroups I had 
subscribed to using the old gmane. This includes Tutor and even one I 
tried to subscribe to on the old gmane as a test.

I use Thunderbird on Linux Mint. All I did was go to the server settings 
and change news.gmane.org to news.gmane.io.

I am sending you this message using tutor at python.org.

I will send you a test message from new.gmane.io after I send this.

Regards,  Jim

From jf_byrnes at comcast.net  Fri Jan 17 12:10:25 2020
From: jf_byrnes at comcast.net (Jim)
Date: Fri, 17 Jan 2020 11:10:25 -0600
Subject: [Tutor] OT - gmane
In-Reply-To: <b47fada5-52d5-1765-72c0-1ad057153ed8@yahoo.co.uk>
References: <65d78a9d-d7ad-c4c4-7947-7bbfbe93444e@comcast.net>
 <CAKJDb-ME_fNJxPQJpc86DapSap8+4ZdiToBzJGuA2_rgc1POZw@mail.gmail.com>
 <b47fada5-52d5-1765-72c0-1ad057153ed8@yahoo.co.uk>
Message-ID: <qvspq1$3s7e$1@ciao.gmane.io>

On 1/16/20 3:10 PM, Alan Gauld via Tutor wrote:
> On 16/01/2020 19:38, Zachary Ware wrote:
> 
>> Gmane has moved:
>> https://lars.ingebrigtsen.no/2020/01/15/news-gmane-org-is-now-news-gmane-io/
>>
> 
> Has anyone succeeded in getting the nntp feed to work
> on the new servers?
> 
> Not just the tutor list - anything at all?
> 
> I failed miserably.
> 

Ok, here I am replying to a message on the new news.gmane.io

Jim


From alan.gauld at yahoo.co.uk  Fri Jan 17 18:35:09 2020
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Fri, 17 Jan 2020 23:35:09 +0000
Subject: [Tutor] OT - gmane
In-Reply-To: <qvspq1$3s7e$1@ciao.gmane.io>
References: <65d78a9d-d7ad-c4c4-7947-7bbfbe93444e@comcast.net>
 <CAKJDb-ME_fNJxPQJpc86DapSap8+4ZdiToBzJGuA2_rgc1POZw@mail.gmail.com>
 <b47fada5-52d5-1765-72c0-1ad057153ed8@yahoo.co.uk>
 <qvspq1$3s7e$1@ciao.gmane.io>
Message-ID: <4d484f92-6bbe-227c-425f-739a9b2d62b7@yahoo.co.uk>

On 17/01/2020 17:10, Jim wrote:
> On 1/16/20 3:10 PM, Alan Gauld via Tutor wrote:
>> On 16/01/2020 19:38, Zachary Ware wrote:
>>
>>> Gmane has moved:
>>> https://lars.ingebrigtsen.no/2020/01/15/news-gmane-org-is-now-news-gmane-io/
>>>
>>
>> Has anyone succeeded in getting the nntp feed to work
>> on the new servers?
>>
>> Not just the tutor list - anything at all?
>>
>> I failed miserably.
>>
> 
> Ok, here I am replying to a message on the new news.gmane.io
> 

Thanks, I got both of them.

Ok I'll try again...


-- 
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  Fri Jan 17 18:45:26 2020
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Fri, 17 Jan 2020 23:45:26 +0000
Subject: [Tutor] OT - gmane
In-Reply-To: <4d484f92-6bbe-227c-425f-739a9b2d62b7@yahoo.co.uk>
References: <65d78a9d-d7ad-c4c4-7947-7bbfbe93444e@comcast.net>
 <CAKJDb-ME_fNJxPQJpc86DapSap8+4ZdiToBzJGuA2_rgc1POZw@mail.gmail.com>
 <b47fada5-52d5-1765-72c0-1ad057153ed8@yahoo.co.uk>
 <qvspq1$3s7e$1@ciao.gmane.io>
 <4d484f92-6bbe-227c-425f-739a9b2d62b7@yahoo.co.uk>
Message-ID: <qvtgun$2de7$1@ciao.gmane.io>

On 17/01/2020 23:35, Alan Gauld via Tutor wrote:

>>> Has anyone succeeded in getting the nntp feed to work
>>> on the new servers?
>>>
>>> Not just the tutor list - anything at all?
>>>
>>> I failed miserably.
>>
>> Ok, here I am replying to a message on the new news.gmane.io
> 
> Thanks, I got both of them.
> 
> Ok I'll try again...


Yep, all working now.
I must just have been a tad early yesterday...

This is very good news. :-)


-- 
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 jf_byrnes at comcast.net  Fri Jan 17 20:04:26 2020
From: jf_byrnes at comcast.net (Jim)
Date: Fri, 17 Jan 2020 19:04:26 -0600
Subject: [Tutor] OT - gmane
In-Reply-To: <qvtgun$2de7$1@ciao.gmane.io>
References: <65d78a9d-d7ad-c4c4-7947-7bbfbe93444e@comcast.net>
 <CAKJDb-ME_fNJxPQJpc86DapSap8+4ZdiToBzJGuA2_rgc1POZw@mail.gmail.com>
 <b47fada5-52d5-1765-72c0-1ad057153ed8@yahoo.co.uk>
 <qvspq1$3s7e$1@ciao.gmane.io>
 <4d484f92-6bbe-227c-425f-739a9b2d62b7@yahoo.co.uk>
 <qvtgun$2de7$1@ciao.gmane.io>
Message-ID: <qvtliq$3la6$1@ciao.gmane.io>

On 1/17/20 5:45 PM, Alan Gauld via Tutor wrote:
> On 17/01/2020 23:35, Alan Gauld via Tutor wrote:
> 
>>>> Has anyone succeeded in getting the nntp feed to work
>>>> on the new servers?
>>>>
>>>> Not just the tutor list - anything at all?
>>>>
>>>> I failed miserably.
>>>
>>> Ok, here I am replying to a message on the new news.gmane.io
>>
>> Thanks, I got both of them.
>>
>> Ok I'll try again...
> 
> 
> Yep, all working now.
> I must just have been a tad early yesterday...
> 
> This is very good news. :-)

I agree.

Jim



From caudilho at cock.li  Mon Jan 20 14:50:24 2020
From: caudilho at cock.li (Alessandro Caudilho)
Date: Mon, 20 Jan 2020 22:50:24 +0300
Subject: [Tutor] Variable and a raw string
Message-ID: <20200120225024.32f26c1cdb9a759b4ad8177a@cock.li>

Hello all

my code below:

============================
from datetime import datetime

state = 'colorado/us'

with open('/home/user/' + state + '.txt', 'a') as f:
    time = datetime.today().strftime('%Y-%m-%d %H:%M:%S')
    f.write(time)
    f.close()
============================

And I get FileNotFoundError: [Errno 2] No such file or directory: "/home/user/colorado/us'.txt"

So how can I create a variable and assign the raw string to it? Are there other solutions for this problem?

-- 
Alessandro Caudilho <caudilho at cock.li>

From joel.goldstick at gmail.com  Mon Jan 20 15:21:08 2020
From: joel.goldstick at gmail.com (Joel Goldstick)
Date: Mon, 20 Jan 2020 15:21:08 -0500
Subject: [Tutor] Variable and a raw string
In-Reply-To: <20200120225024.32f26c1cdb9a759b4ad8177a@cock.li>
References: <20200120225024.32f26c1cdb9a759b4ad8177a@cock.li>
Message-ID: <CAPM-O+wy7xmNCFSKQYD+JoDQSXE9JXH0ShpRAMP5_9_FT6dZ2Q@mail.gmail.com>

On Mon, Jan 20, 2020 at 3:15 PM Alessandro Caudilho <caudilho at cock.li> wrote:
>
> Hello all
>
> my code below:
>
> ============================
> from datetime import datetime
>
> state = 'colorado/us'
>
the following line is causing your problem.  'state' is 'colorado/us
so you are trying to open
/home/user/colorado/us.txt

You could change the / to _ and it should work
> with open('/home/user/' + state + '.txt', 'a') as f:
>     time = datetime.today().strftime('%Y-%m-%d %H:%M:%S')
>     f.write(time)
>     f.close()
> ============================
>
> And I get FileNotFoundError: [Errno 2] No such file or directory: "/home/user/colorado/us'.txt"
>
> So how can I create a variable and assign the raw string to it? Are there other solutions for this problem?
>
> --
> Alessandro Caudilho <caudilho at cock.li>
> _______________________________________________
> Tutor maillist  -  Tutor at python.org
> To unsubscribe or change subscription options:
> https://mail.python.org/mailman/listinfo/tutor



-- 
Joel Goldstick
http://joelgoldstick.com/blog
http://cc-baseballstats.info/stats/birthdays

From mats at wichmann.us  Mon Jan 20 15:43:15 2020
From: mats at wichmann.us (Mats Wichmann)
Date: Mon, 20 Jan 2020 13:43:15 -0700
Subject: [Tutor] Variable and a raw string
In-Reply-To: <CAPM-O+wy7xmNCFSKQYD+JoDQSXE9JXH0ShpRAMP5_9_FT6dZ2Q@mail.gmail.com>
References: <20200120225024.32f26c1cdb9a759b4ad8177a@cock.li>
 <CAPM-O+wy7xmNCFSKQYD+JoDQSXE9JXH0ShpRAMP5_9_FT6dZ2Q@mail.gmail.com>
Message-ID: <900d745c-fcf2-d9ba-ec3e-bd9895fae8f7@wichmann.us>

On 1/20/20 1:21 PM, Joel Goldstick wrote:
> On Mon, Jan 20, 2020 at 3:15 PM Alessandro Caudilho <caudilho at cock.li> wrote:
>>
>> Hello all
>>
>> my code below:
>>
>> ============================
>> from datetime import datetime
>>
>> state = 'colorado/us'
>>
> the following line is causing your problem.  'state' is 'colorado/us
> so you are trying to open
> /home/user/colorado/us.txt
> 
> You could change the / to _ and it should work
>> with open('/home/user/' + state + '.txt', 'a') as f:
>>      time = datetime.today().strftime('%Y-%m-%d %H:%M:%S')
>>      f.write(time)
>>      f.close()
>> ============================
>>
>> And I get FileNotFoundError: [Errno 2] No such file or directory: "/home/user/colorado/us'.txt"
>>
>> So how can I create a variable and assign the raw string to it? Are there other solutions for this problem?

In particular, it's causing a problem because you're asking to create a 
file in a directory /home/user/colorado that doesn't exist.  If you 
follow Joel's suggestion and change state to 'colorado_us', then you're 
trying to create the file 'colorado_us.text' in /home/user, which will 
work (as long as /home/user exists).

You can also add logic to create necessary directories if you want to 
organize your data by directories...



From PyTutor at DancesWithMice.info  Mon Jan 20 16:15:16 2020
From: PyTutor at DancesWithMice.info (David L Neil)
Date: Tue, 21 Jan 2020 10:15:16 +1300
Subject: [Tutor] Variable and a raw string
In-Reply-To: <20200120225024.32f26c1cdb9a759b4ad8177a@cock.li>
References: <20200120225024.32f26c1cdb9a759b4ad8177a@cock.li>
Message-ID: <1042c43d-f0c1-a6ee-8e82-7a3d4b237416@DancesWithMice.info>

On 21/01/20 8:50 AM, Alessandro Caudilho wrote:
> Hello all
> 
> my code below:
> 
> ============================
> from datetime import datetime
> 
> state = 'colorado/us'
> 
> with open('/home/user/' + state + '.txt', 'a') as f:
>      time = datetime.today().strftime('%Y-%m-%d %H:%M:%S')
>      f.write(time)
>      f.close()
> ============================
> 
> And I get FileNotFoundError: [Errno 2] No such file or directory: "/home/user/colorado/us'.txt"


Did you re-type the code or did you copy-paste it from the editor into 
this email msg???
(the mixture of quotation-marks/double-quotes and 
apostrophe/single-quote in the err.msg, indicates that the above code is 
NOT the original)

1 if the code is being run (by "user") from his/her home-directory (ie 
/home/user) then all that may be omitted from the open()

2 if your intent is to separate each US State into its own directory, 
then would "...US/Colorado..." make for a better stepwise-refinement?

3 otherwise if the "us" part is merely a label, perhaps to distinguish 
from some "colorado" in another country, then please see previous responses.

4 Please review open-append in 
https://docs.python.org/3/library/functions.html?highlight=open#open 
(see also "absolute" and "relative", per (1) above). What happens if one 
opens a file in a directory which does not (yet) exist? How does this 
differ from attempting to open a file which does not exist (read) or 
does not yet exist (append)? (experiment in the Python REPL)

5 given that the file is being processed in-context (with), the close() 
is unnecessary, because it is provided auto-magically as part of the 
context-manager 
(https://docs.python.org/3/reference/compound_stmts.html#the-with-statement)

-- 
Regards =dn

From Richard at Damon-family.org  Mon Jan 20 17:21:39 2020
From: Richard at Damon-family.org (Richard Damon)
Date: Mon, 20 Jan 2020 17:21:39 -0500
Subject: [Tutor] Variable and a raw string
In-Reply-To: <20200120225024.32f26c1cdb9a759b4ad8177a@cock.li>
References: <20200120225024.32f26c1cdb9a759b4ad8177a@cock.li>
Message-ID: <8DE18B16-69D4-482A-B40E-05B8382DE869@Damon-family.org>

Does the directory /home/user/colorado exist? (And is writable?)
The function fopen can create the file, but it won?t create the directory. 

> On Jan 20, 2020, at 3:15 PM, Alessandro Caudilho <caudilho at cock.li> wrote:
> 
> ?Hello all
> 
> my code below:
> 
> ============================
> from datetime import datetime
> 
> state = 'colorado/us'
> 
> with open('/home/user/' + state + '.txt', 'a') as f:
>    time = datetime.today().strftime('%Y-%m-%d %H:%M:%S')
>    f.write(time)
>    f.close()
> ============================
> 
> And I get FileNotFoundError: [Errno 2] No such file or directory: "/home/user/colorado/us'.txt"
> 
> So how can I create a variable and assign the raw string to it? Are there other solutions for this problem?
> 
> -- 
> Alessandro Caudilho <caudilho at cock.li>
> _______________________________________________
> Tutor maillist  -  Tutor at python.org
> To unsubscribe or change subscription options:
> https://mail.python.org/mailman/listinfo/tutor


From alan.gauld at yahoo.co.uk  Mon Jan 20 19:08:31 2020
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Tue, 21 Jan 2020 00:08:31 +0000
Subject: [Tutor] Variable and a raw string
In-Reply-To: <20200120225024.32f26c1cdb9a759b4ad8177a@cock.li>
References: <20200120225024.32f26c1cdb9a759b4ad8177a@cock.li>
Message-ID: <a78b8e20-946d-5a0c-4e39-1be49f033bf3@yahoo.co.uk>

On 20/01/2020 19:50, Alessandro Caudilho wrote:

> state = 'colorado/us'
> 
> with open('/home/user/' + state + '.txt', 'a') as f:
> 
> And I get FileNotFoundError: [Errno 2] No such file or directory: "/home/user/colorado/us'.txt"

Notice the error has a spurious ' within it - between /us and .txt.
That quote is not in your code which suggests that there must be some
code you are not showing us?

Eliminate that quote and it should work - assuming you have access
to the directory and that it exists.

Also note that you don't need a close() when you use the with
structure to open the file. close() is done automatically
by Python.

-- 
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 PyTutor at DancesWithMice.info  Mon Jan 20 23:44:29 2020
From: PyTutor at DancesWithMice.info (David L Neil)
Date: Tue, 21 Jan 2020 17:44:29 +1300
Subject: [Tutor] Variable and a raw string
In-Reply-To: <20200121063014.3b86ffa0f909aef381111650@cock.li>
References: <20200120225024.32f26c1cdb9a759b4ad8177a@cock.li>
 <1042c43d-f0c1-a6ee-8e82-7a3d4b237416@DancesWithMice.info>
 <20200121063014.3b86ffa0f909aef381111650@cock.li>
Message-ID: <1509a9ed-4d54-d618-de24-bae27207528c@DancesWithMice.info>

On 21/01/20 4:30 PM, Alessandro Caudilho wrote:
> On Tue, 21 Jan 2020 10:15:16 +1300
> David L Neil via Tutor <tutor at python.org> wrote:
>> Did you re-type the code or did you copy-paste it from the editor into
>> this email msg???
>> (the mixture of quotation-marks/double-quotes and
>> apostrophe/single-quote in the err.msg, indicates that the above code is
>> NOT the original)
>>
>> 1 if the code is being run (by "user") from his/her home-directory (ie
>> /home/user) then all that may be omitted from the open()
>>
>> 2 if your intent is to separate each US State into its own directory,
>> then would "...US/Colorado..." make for a better stepwise-refinement?
>>
>> 3 otherwise if the "us" part is merely a label, perhaps to distinguish
>> from some "colorado" in another country, then please see previous responses.
>>
>> 4 Please review open-append in
>> https://docs.python.org/3/library/functions.html?highlight=open#open
>> (see also "absolute" and "relative", per (1) above). What happens if one
>> opens a file in a directory which does not (yet) exist? How does this
>> differ from attempting to open a file which does not exist (read) or
>> does not yet exist (append)? (experiment in the Python REPL)
> 
> Thanks David! I copy-pasted the code from my editor.
> 
> This code is a part of the one that uses weather API. When I call, it returns me number of bulk values with current weather forecasts. One of values is a ). I know that I can`t create file because of '/' in 'colorado/us'. But maybe is there some way to avoid removing or replacing slash in 'state'?
> 
> My fault - I should give more information on this in my first message


No problem - we live and learn. We try to be a friendly group but we are 
here to help learners/learning.
(also, please check email headers to ensure answers go to the list so 
that others might learn/contribute suggestions)

As you will see, others also suggest that the err.msg does not smell 
right...

Not sure what is meant by "One of values is a )." (above). Is the 
right-parenthesis a response from the API?

Also (sorry to keep grumbling), DuckDuckGo returned at least three 
different hits for "weather API" from the US alone. Which one?

Why not also supply the query you are using and the data-returned 
(sub-set, as appropriate), so that we can see what you're facing...


Sorry, but I don't think it can be done: the problem with the (above) 
specification is that a slash (/) has particular meaning within a Posix 
filename (even on MS-Windows which uses back-slashes within its native 
rules). I don't think that the slash can be "escaped".
(but better minds than mine may correct/elucidate...)


Three thoughts:

1 if the "/us" component does not add-value to your application
...cut it out => "out damn spot"*!

 >>> state = 'colorado/us'
 >>> state_only = state[ :-3 ]
'colorado'

- assuming that the '/us' suffix is entirely consistent across (your) 
data-set!

2 if you must keep the "us" within the directoryNM, then change 
("translate") the slash to an underline (or similar).

3 go through and manually bulk-create the 50+ directories, which will 
obviate the exception.

4 (who said I could count?)
create a dictionary with the API's labels as "keys", eg 'colorado/us', 
and your own preference (and legal directoryNM) as "values", eg 
'colorado' or 'CO'. Use that as a translation-table to construct legal 
paths from the API labels.


* Shakespeare reference (in a bid to appear learned???)
-- 
Regards =dn

From caudilho at cock.li  Mon Jan 20 22:30:14 2020
From: caudilho at cock.li (Alessandro Caudilho)
Date: Tue, 21 Jan 2020 06:30:14 +0300
Subject: [Tutor] Variable and a raw string
In-Reply-To: <1042c43d-f0c1-a6ee-8e82-7a3d4b237416@DancesWithMice.info>
References: <20200120225024.32f26c1cdb9a759b4ad8177a@cock.li>
 <1042c43d-f0c1-a6ee-8e82-7a3d4b237416@DancesWithMice.info>
Message-ID: <20200121063014.3b86ffa0f909aef381111650@cock.li>

On Tue, 21 Jan 2020 10:15:16 +1300
David L Neil via Tutor <tutor at python.org> wrote:

> Did you re-type the code or did you copy-paste it from the editor into 
> this email msg???
> (the mixture of quotation-marks/double-quotes and 
> apostrophe/single-quote in the err.msg, indicates that the above code is 
> NOT the original)
> 
> 1 if the code is being run (by "user") from his/her home-directory (ie 
> /home/user) then all that may be omitted from the open()
> 
> 2 if your intent is to separate each US State into its own directory, 
> then would "...US/Colorado..." make for a better stepwise-refinement?
> 
> 3 otherwise if the "us" part is merely a label, perhaps to distinguish 
> from some "colorado" in another country, then please see previous responses.
> 
> 4 Please review open-append in 
> https://docs.python.org/3/library/functions.html?highlight=open#open 
> (see also "absolute" and "relative", per (1) above). What happens if one 
> opens a file in a directory which does not (yet) exist? How does this 
> differ from attempting to open a file which does not exist (read) or 
> does not yet exist (append)? (experiment in the Python REPL)

Thanks David! I copy-pasted the code from my editor.

This code is a part of the one that uses weather API. When I call, it returns me number of bulk values with current weather forecasts. One of values is a state (e.g. 'colorado/us'). I know that I can`t create file because of '/' in 'colorado/us'. But maybe is there some way to avoid removing or replacing slash in 'state'?

My fault - I should give more information on this in my first message


-- 
Alessandro Caudilho <caudilho at cock.li>

From aaliyahrebeccawood at gmail.com  Thu Jan 23 14:00:00 2020
From: aaliyahrebeccawood at gmail.com (Aaliyah Wood)
Date: Thu, 23 Jan 2020 12:00:00 -0700
Subject: [Tutor] Commands
Message-ID: <CAL2w5ti62UOcg6XD82-Fm4C=2-BSSJxGKGCn_2Ya5pp2hd+exA@mail.gmail.com>

I recently started learning Python two days ago using different lessons
online so my question may sound very uneducated. Python is not recognizing
any commands (True, False, Print, Int.) I know that these commands turn a
different color when they're recognized (True and False turn orange) How do
I fix this?

Thank you!
Aaliyah

From david at graniteweb.com  Thu Jan 23 18:56:24 2020
From: david at graniteweb.com (David Rock)
Date: Thu, 23 Jan 2020 17:56:24 -0600
Subject: [Tutor] Commands
In-Reply-To: <CAL2w5ti62UOcg6XD82-Fm4C=2-BSSJxGKGCn_2Ya5pp2hd+exA@mail.gmail.com>
References: <CAL2w5ti62UOcg6XD82-Fm4C=2-BSSJxGKGCn_2Ya5pp2hd+exA@mail.gmail.com>
Message-ID: <79A4C283-18FD-45FD-82B4-73D307EB6FA8@graniteweb.com>


> On Jan 23, 2020, at 13:00, Aaliyah Wood <aaliyahrebeccawood at gmail.com> wrote:
> 
> I recently started learning Python two days ago using different lessons
> online so my question may sound very uneducated. Python is not recognizing
> any commands (True, False, Print, Int.) I know that these commands turn a
> different color when they're recognized (True and False turn orange) How do
> I fix this?

Welcome, Aaliyah.

What you are describing is called syntax highlighting, and is a function of the text editor you are using.  Python itself is not responsible for changing colors of text in the file.

When you say ?Python is not recognizing any commands,? what is the context where you are seeing this?
What text editor are you using?
What version of Python are you using?
What Operating system are you using?

The more information you can give us about what you are doing and what you expect to see, the better we can help.

? 
David Rock
david at graniteweb.com





From alan.gauld at yahoo.co.uk  Thu Jan 23 19:11:19 2020
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Fri, 24 Jan 2020 00:11:19 +0000
Subject: [Tutor] Commands
In-Reply-To: <CAL2w5ti62UOcg6XD82-Fm4C=2-BSSJxGKGCn_2Ya5pp2hd+exA@mail.gmail.com>
References: <CAL2w5ti62UOcg6XD82-Fm4C=2-BSSJxGKGCn_2Ya5pp2hd+exA@mail.gmail.com>
Message-ID: <r0dcn8$1orr$1@ciao.gmane.io>

On 23/01/2020 19:00, Aaliyah Wood wrote:
> I recently started learning Python two days ago using different lessons
> online so my question may sound very uneducated. Python is not recognizing
> any commands (True, False, Print, Int.) 

One thing about programming is that you need to be very precise in your
language. A command in Python is something very specific. None of the
above words are Python commands. Also spelling, punctuation and spacing
are all incredibly important too.

True and False are Python values. They are also "reserved words" meaning
you can't use them for variable names.

Print is just a name(*) to Python. It is very different to print(lower
case) which is a *function* in Python 3 and a *command* in
Python 2 - two very different things!

Int likewise is just a name. int(lower case) however is a built-in type.
It is also a conversion function used to create integers from
(valid)strings(another type) and floats(yet another type).

(*)-------------------
 Names in python are just labels that you can attach to objects. They
usually appear as variables or functions. For example:

foo = 66

creates a name foo and gives it a value of 66

def Print(): pass

creates name a Print and gives it a value of a function which
does nothing(pass). Print won't get a special colour in IDLE but
it will be remembered and offered as an option if you try
typing Pri<tab>. (see below)
------------------------

> I know that these commands turn a
> different color when they're recognized (True and False turn orange)

reserved words turn orange, so True, False, None, if, while, class, def
etc all turn orange - assuming you are using IDLE. The actual colour
will vary depending on the tool you use.

>  How do I fix this?

Mainly by typing the correct word and in the correct place.
But if using IDLE (and some other tools) you do get a little
extra help in that you can type a tab and Python will offer
up a choice of valid options. If you have mistyped there will
be no options(or perhaps a very limited set)

You can select the one you want and IDLE will fill it in
for you - a bit like smart typing on your phone.


Does that help?
-- 
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 david at graniteweb.com  Thu Jan 23 21:27:40 2020
From: david at graniteweb.com (David Rock)
Date: Thu, 23 Jan 2020 20:27:40 -0600
Subject: [Tutor] Commands
In-Reply-To: <CAL2w5tjWKwG8zZnLemCX3nrJi_+6Tdy5rK+fcbd4OJyG8AxTsg@mail.gmail.com>
References: <CAL2w5ti62UOcg6XD82-Fm4C=2-BSSJxGKGCn_2Ya5pp2hd+exA@mail.gmail.com>
 <79A4C283-18FD-45FD-82B4-73D307EB6FA8@graniteweb.com>
 <CAL2w5tjWKwG8zZnLemCX3nrJi_+6Tdy5rK+fcbd4OJyG8AxTsg@mail.gmail.com>
Message-ID: <C487093E-26B8-4BF1-93FD-2D3C3B13EDF6@graniteweb.com>


> On Jan 23, 2020, at 20:04, Aaliyah Wood <aaliyahrebeccawood at gmail.com> wrote:
> 
> Hi David,
> 
> Thank you for getting back to me so quickly, my version of Python is 3.8.1 for Windows. Essentially what is happening is Python is not recognizing and commands like True, False, print. I attached a couple pictures to explain better. The screenshot is a lesson I am watching on YouTube, this is an example of what my program is supposed to look like. The photo of my laptop is what the program looks like on my computer. I?m just confused as to why I cannot run a program and why it doesn?t look right. It was working two days ago when I began learning and now it isn?t. If you need any more explanation just let me know!
> 
> Thank you again,
> Aaliyah 
> <IMG_0370.jpg>
> <IMG_0368.jpg>
> <IMG_0371.jpg>

Ok, that helps a lot.  One thing to note, make sure when you reply, you reply to the tutor mailing list, not the individual.  That way, everyone can help, and not just one person.  In this case, it?s actually good you did, because the mailing list would have dropped the images, so we would not have seen what they look like.

I can tell from the pictures that you are using PyCharm, which is part of the issue.  PyCharm is a great IDE for Python, but it has its own learning curve.  What?s happened is you created a generic text file named ?App?, rather than an ?App.py? python file.  That?s why PyCharm isn?t coloring things for you; it does not know it?s supposed to be a Python file.

If you do File->New Project and create a new, blank project, then Right-click on the project name and pick New->Python File 

That should get you a file that PyCharm knows is a Python File and should behave as you expect.

I?d also look around for tutorials specifically on using PyCharm.  That will go a long way to helping you deal with the quirks of working in that specific IDE.
For something simpler, you could also try using IDLE, the built-in editor that comes with Python installs.  It will also give you syntax highlighting, without the overhead of also learning an IDE at the same time.

?
David



From PyTutor at DancesWithMice.info  Thu Jan 23 23:32:46 2020
From: PyTutor at DancesWithMice.info (DL Neil)
Date: Fri, 24 Jan 2020 17:32:46 +1300
Subject: [Tutor] Friday Finking: Enum by gum (cross-posted from Python-list)
Message-ID: <fe8a6daa-9fa3-1dd2-a4c7-0573e967ac31@DancesWithMice.info>

[@Alan: should you feel cross-posting inappropriate, please delete...]


When, why, and how do you employ Python/PSL enums?


TLDR? Fair enough! Much of this text recounts a voyage of discovery. 
More specific questions appear at the bottom...


Last century, when I learned to program (in-between working part-time at 
the dinosaur farm) neither FORTRAN II/IV nor COBOL-68 offered enums. 
Interestingly, whilst most of our team-members learned about them 
(ComSc) or had been trained to use them in xyz-language, few remember 
any mention of them in Python courses/books/tutorials - nor could anyone 
recall (local) usage.


This fascinated me (small things amuse small minds) because I had been 
called-in to settle a 'disagreement' where users thought they should 
enter data 'one way' into an interface/API, whereas the design had 
directed it otherwise. Was it a user issue, a design problem, an 
inflexible interface, poor documentation, weak design, ...?

This in-turn led me to consider: can we both illustrate the interface 
(not just in docs) AND ease the user-side of the interface AND/OR 
improve the error-checking*/feedback? (and do it cheaply~$0, and take no 
time at all, and leap tall-buildings at a single...)
* perhaps by controlling what control-data (cf statistics/source-data) 
may be input.

Accordingly, as 'they' say, there is a "first time for everything", and 
I starting playing with enums...


The PSL manual is somewhat sparse. The examples are weak and almost 
solely introspective: if I have an enum, I can ask it what it is. Should 
that sum-up the total use of enums?

By-and-large, most web-refs seem weak and pointless repetitions of the 
PSL docs (perhaps only the parts that the author actually understood?); 
reciting uses such as defining the suits in a pack/deck of cards, but 
not describing how the enum might actually be used in (real) code.

Negative motivations resulted from the first part of Mike 'the Mouse' 
Driscoll's comment: "Whilst I don?t think the enum module is really 
necessary for Python, it is a neat tool...", but interest was recovered 
with the closing observation. "Neat" for what exactly?


With the stated-intention that enums would be back-ported/re-factored 
into the PSL, the PEP(s) dance-around the idea that existing code may 
run off integer parameters which are understood to hold particular 
meanings, eg

0 => hourly,
1 => daily,
2 => weekly, etc

In the normal course of Python there is nothing to stop one from setting 
such an parameter to 10, which has no actual meaning within the API (~my 
user-issue, above). Nor is the user (or the original coder) prevented 
from using the parameter for a purpose other than its temporal intention!

Enter the enum: applying semantic meaning:

  >>> Frequency = enum.Enum( "Frequency", "HOURLY DAILY WEEKLY" )

Here, whilst there is an int value, it can't be used as such:

  >>> Frequency.HOURLY
<Frequency.HOURLY: 1>
  >>> Frequency.HOURLY + 2
Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'Frequency' and 'int'

Unless (are we "all adults here"?):

  >>> Frequency.HOURLY.value + 2
3

OK, so it can be used, mis-used, and abused...

Plus, be aware:
  >>> 1 in Frequency
__main__:1: DeprecationWarning: using non-Enums in containment checks 
will raise TypeError in Python 3.8
False


However, ignoring the value completely, setting

  >>> argument = Frequency.DAILY

and then posting argument into the API, the parameter assumes 
semantic-meaning:

  >>> if parameter is Frequency.DAILY:
...     # multiply by 24 to use hours as common metric

So, in my thinking about interfaces: if the first code-line is on the 
calling-side of an API and the latter inside our 'black-box', that 
code-snippet seemed to fit my spec and illustrate an actual and useful 
purpose for enums. (OK, I might be slow, but I'll get there...) Agreed?

Thus, alongside the API we need to publish the enum, and 'advertise' it 
as a "helper". A good choice of name (in the users' view(s)) may also 
avoid mis-communications and other errors... Do you agree?


The earlier PEP talked of "enumerated values hiding as much as possible 
about their implementation" which also makes sense in this application, 
because I don't care about any underlying value for Frequency.DAILY, 
only that it be checked/compared - and that if someone enters 0, 1, or 
something of their own devising (or even Fr:"QUOTIDIEN" (== En:"DAILY")) 
it is not (in this case) regarded as 'equal' or otherwise equivalent!

This point is picked-up in PEP 435: "an enumeration ensures that such 
values are distinct from any others including, importantly, values 
within other enumerations". Hence (in the snippet, above) the "is", ie 
looking at "identity" rather than value!


Questions:

Have I made proper sense of this? (please don't laugh too much)

Is the above 'interfacing' an appropriate use of enum-s; or is it really 
'overkill' or posturing?

Do you use enum-s very often?

What other 'pattern' of application do you employ?

Python v3.6+ brings Flag-enums into the game. These seem better for 
interface use, as described. Do you prefer them to the 'plain-vanilla' 
enum, and for what reason?


WebRefs:
By gum: https://www.phrases.org.uk/meanings/82225.html
Mike Driscoll: 
https://www.blog.pythonlibrary.org/2018/03/20/python-3-an-intro-to-enumerations/
PSL enums: https://docs.python.org/3.7/library/enum.html
PEP 354 (superseded): https://www.python.org/dev/peps/pep-0354/
PEP 435 (accepted): https://www.python.org/dev/peps/pep-0435/

-- 
Regards,
=dn

PS: life has been 'exciting' here. Some thoughtless person cut-through 
our local fiber back-haul, and even since the service was restored, 
there have been throughput problems, connection issues, ... Apologies if 
I haven't caught-up with you amongst the massive backlog - it's not you, 
it's me!

-- 
https://mail.python.org/mailman/listinfo/python-list

From suresh.gm at gmail.com  Fri Jan 24 08:12:36 2020
From: suresh.gm at gmail.com (Panchanathan Suresh)
Date: Fri, 24 Jan 2020 05:12:36 -0800
Subject: [Tutor] How to remove the comma only at the end?
Message-ID: <CACh5xi9hmedV_PFytZQFSxW02dvnfKeb_t7-VZ9Ev7r_syKJ4Q@mail.gmail.com>

Hi everyone,

How to remove the last comma , from the variable members?
I tried members[:-1], members.rstrip(","), but no luck. It is
always returning:
Mike, Karen, Jake, Tasha,

I want it to return Mike, Karen, Jake, Tasha (no comma after Tasha)

Below is my code:

*****
def group_list(group, users):
  members = ""
  members1 = ""
  for x in range(0,len(users)):
      #print(users[x])
      members = members + users[x] + ", "
  return members[:-1]


print(group_list("Marketing", ["Mike", "Karen", "Jake", "Tasha"])) # Should
be "Marketing: Mike, Karen, Jake, Tasha"

*****

Thanks so much,
Suresh

From marc.tompkins at gmail.com  Fri Jan 24 12:43:24 2020
From: marc.tompkins at gmail.com (Marc Tompkins)
Date: Fri, 24 Jan 2020 09:43:24 -0800
Subject: [Tutor] How to remove the comma only at the end?
In-Reply-To: <CACh5xi9hmedV_PFytZQFSxW02dvnfKeb_t7-VZ9Ev7r_syKJ4Q@mail.gmail.com>
References: <CACh5xi9hmedV_PFytZQFSxW02dvnfKeb_t7-VZ9Ev7r_syKJ4Q@mail.gmail.com>
Message-ID: <CAKK8jXbh09B_5Cd3sjLMCZztbXppseOuZhfLAwojuaY7RPxXdw@mail.gmail.com>

On Fri, Jan 24, 2020 at 9:21 AM Panchanathan Suresh <suresh.gm at gmail.com>
wrote:

> Hi everyone,
>
> How to remove the last comma , from the variable members?
> I tried members[:-1], members.rstrip(","), but no luck. It is
> always returning:
> Mike, Karen, Jake, Tasha,
>

Use the string.join() method:

>>> marketing = ["Mike", "Karen", "Jake", "Tasha"]
>>> ", ".join(marketing)
'Mike, Karen, Jake, Tasha'

Essentially, this says "Take the members of the list and glue them together
into a string, using this string (a comma and a space in this instance) as
glue".

From alan.gauld at yahoo.co.uk  Fri Jan 24 12:45:53 2020
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Fri, 24 Jan 2020 17:45:53 +0000
Subject: [Tutor] How to remove the comma only at the end?
In-Reply-To: <CACh5xi9hmedV_PFytZQFSxW02dvnfKeb_t7-VZ9Ev7r_syKJ4Q@mail.gmail.com>
References: <CACh5xi9hmedV_PFytZQFSxW02dvnfKeb_t7-VZ9Ev7r_syKJ4Q@mail.gmail.com>
Message-ID: <r0fagi$qq8$1@ciao.gmane.io>

On 24/01/2020 13:12, Panchanathan Suresh wrote:

> How to remove the last comma , from the variable members?
> I tried members[:-1], 

That will remove the last character from a string but....

>   for x in range(0,len(users)):
>       members = members + users[x] + ", "

You are adding a comma and a space at the end, so your
code will remove the space but not the comma.

However, you are probably better using the rstrip()
method of the string

return members.rstrip(', ')

Or maybe you are better not using a string at all?
Would a dictionary be a better fit and then only
convert to a string on output? Especially if you
plan on having multiple departments.

If you really want a string you could use join:

def group_list(group, users):
  members = group +": "
  return members + ','.join(users)

Which only inserts the comma between the inner members.

-- 
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 akleider at sonic.net  Fri Jan 24 12:50:06 2020
From: akleider at sonic.net (Alex Kleider)
Date: Fri, 24 Jan 2020 09:50:06 -0800
Subject: [Tutor] How to remove the comma only at the end?
In-Reply-To: <CACh5xi9hmedV_PFytZQFSxW02dvnfKeb_t7-VZ9Ev7r_syKJ4Q@mail.gmail.com>
References: <CACh5xi9hmedV_PFytZQFSxW02dvnfKeb_t7-VZ9Ev7r_syKJ4Q@mail.gmail.com>
Message-ID: <28ab54254ae0a86b316efc2b69977b96@sonic.net>

On 2020-01-24 05:12, Panchanathan Suresh wrote:
> Hi everyone,
> 
> How to remove the last comma , from the variable members?
> I tried members[:-1], members.rstrip(","), but no luck. It is
> always returning:
> Mike, Karen, Jake, Tasha,
> 
> I want it to return Mike, Karen, Jake, Tasha (no comma after Tasha)
> 
> Below is my code:
> 
> *****
> def group_list(group, users):
>   members = ""
>   members1 = ""
>   for x in range(0,len(users)):
>       #print(users[x])
>       members = members + users[x] + ", "
>   return members[:-1]
> 
> 
> print(group_list("Marketing", ["Mike", "Karen", "Jake", "Tasha"])) # 
> Should
> be "Marketing: Mike, Karen, Jake, Tasha"
> 

You might find the str join method useful;
more specifically:
>>> ', '.join(["Mike", "Karen", "Jake", "Tasha"])

From mats at wichmann.us  Fri Jan 24 13:12:12 2020
From: mats at wichmann.us (Mats Wichmann)
Date: Fri, 24 Jan 2020 11:12:12 -0700
Subject: [Tutor] How to remove the comma only at the end?
In-Reply-To: <CACh5xi9hmedV_PFytZQFSxW02dvnfKeb_t7-VZ9Ev7r_syKJ4Q@mail.gmail.com>
References: <CACh5xi9hmedV_PFytZQFSxW02dvnfKeb_t7-VZ9Ev7r_syKJ4Q@mail.gmail.com>
Message-ID: <80865e83-99b9-b0f6-0dbe-f6fa722e43cc@wichmann.us>

On 1/24/20 6:12 AM, Panchanathan Suresh wrote:
> Hi everyone,
> 
> How to remove the last comma , from the variable members?
> I tried members[:-1], members.rstrip(","), but no luck. It is
> always returning:
> Mike, Karen, Jake, Tasha,
> 
> I want it to return Mike, Karen, Jake, Tasha (no comma after Tasha)
> 
> Below is my code:
> 
> *****
> def group_list(group, users):
>   members = ""
>   members1 = ""
>   for x in range(0,len(users)):
>       #print(users[x])
>       members = members + users[x] + ", "
>   return members[:-1]
> 
> 
> print(group_list("Marketing", ["Mike", "Karen", "Jake", "Tasha"])) # Should
> be "Marketing: Mike, Karen, Jake, Tasha"

I'm going to jump in with my own comment here - you should cringe almost
any time you see  "for x in range(len(foo)):"

If users is something you can iterate over (as a list, it is), then
iterate over it.  Don't artifcially generate an item count, use range to
generate a NEW thing you can iterate over, and then index into the
original list.  You can write this more expressively as:

for user in users:
    members = members + user + ", "

and yes, if you're solving the problem this way, you wanted:

return members[:-2]    # because you put in two chars at the end!

that's line is not terribly expressive (-2 is "magic", avoid "magic"),
so how about if you define:

sep = ", "

then you can

return sep.join(users)

or

members = members + user + sep
...
return members[:-len(sep)]





From cs at cskk.id.au  Fri Jan 24 14:34:07 2020
From: cs at cskk.id.au (Cameron Simpson)
Date: Sat, 25 Jan 2020 06:34:07 +1100
Subject: [Tutor] How to remove the comma only at the end?
In-Reply-To: <CACh5xi9hmedV_PFytZQFSxW02dvnfKeb_t7-VZ9Ev7r_syKJ4Q@mail.gmail.com>
References: <CACh5xi9hmedV_PFytZQFSxW02dvnfKeb_t7-VZ9Ev7r_syKJ4Q@mail.gmail.com>
Message-ID: <20200124193407.GA78968@cskk.homeip.net>

On 24Jan2020 05:12, Panchanathan Suresh <suresh.gm at gmail.com> wrote:
>How to remove the last comma , from the variable members?
>I tried members[:-1], members.rstrip(","), but no luck. It is
>always returning:
>Mike, Karen, Jake, Tasha,

Note that your code is adding ", ", so there is a comma and a space.  

Using "members[:-1]" only skips the space. -2 would help.

Likewise, rstrip strips trailing commas, but there are no trailing 
commas, only a trailing space.

If you:

    print(repr(members))

as a debugging statement, this would become more evident.

Personally, I prefer not to strip the trailing stuff, but to only add 
the separator on the second and following members. Eg:

    if members:
        members += ', '
    members += users[x]

That way there is never a trailing separator.

However, I recommend what others have suggested: use str.join.  

Incrementally extending string is ok for small strings, but as the lis 
of users gets bigger the cost gets significantly larger because the 
members string gets copied at each append, leading to O(n^2) behaviour 
in the long term.

Cheers,
Cameron Simpson <cs at cskk.id.au>

From breamoreboy at gmail.com  Fri Jan 24 12:40:19 2020
From: breamoreboy at gmail.com (Mark Lawrence)
Date: Fri, 24 Jan 2020 17:40:19 +0000
Subject: [Tutor] How to remove the comma only at the end?
In-Reply-To: <CACh5xi9hmedV_PFytZQFSxW02dvnfKeb_t7-VZ9Ev7r_syKJ4Q@mail.gmail.com>
References: <CACh5xi9hmedV_PFytZQFSxW02dvnfKeb_t7-VZ9Ev7r_syKJ4Q@mail.gmail.com>
Message-ID: <r0fa64$3vs2$1@ciao.gmane.io>

On 24/01/2020 13:12, Panchanathan Suresh wrote:
> Hi everyone,
> 
> How to remove the last comma , from the variable members?
> I tried members[:-1], members.rstrip(","), but no luck. It is
> always returning:
> Mike, Karen, Jake, Tasha,
> 
> I want it to return Mike, Karen, Jake, Tasha (no comma after Tasha)
> 
> Below is my code:
> 
> *****
> def group_list(group, users):
>    members = ""
>    members1 = ""

Your for loop is poor Python, you should use:-

for user in users:

>    for x in range(0,len(users)):
>        #print(users[x])
>        members = members + users[x] + ", "
>    return members[:-1]

But you simply don't need the above, just the string join method 
https://docs.python.org/3/library/stdtypes.html#str.join hence using the 
interactive prompt:-

 >>> print("Marketing:", ', '.join(["Mike", "Karen", "Jake", "Tasha"]))
Marketing: Mike, Karen, Jake, Tasha

> 
> 
> print(group_list("Marketing", ["Mike", "Karen", "Jake", "Tasha"])) # Should
> be "Marketing: Mike, Karen, Jake, Tasha"
> 
> *****
> 
> Thanks so much,
> Suresh

-- 
My fellow Pythonistas, ask not what our language can do for you, ask
what you can do for our language.

Mark Lawrence


From suresh.gm at gmail.com  Fri Jan 24 13:03:29 2020
From: suresh.gm at gmail.com (Panchanathan Suresh)
Date: Fri, 24 Jan 2020 10:03:29 -0800
Subject: [Tutor] How to remove the comma only at the end?
In-Reply-To: <CACh5xi9BzbHq2Ap7_4UN3QSBG9JK7OoCdJYF41M6Ys-uJxVSSg@mail.gmail.com>
References: <CACh5xi9hmedV_PFytZQFSxW02dvnfKeb_t7-VZ9Ev7r_syKJ4Q@mail.gmail.com>
 <28ab54254ae0a86b316efc2b69977b96@sonic.net>
 <CACh5xi9BzbHq2Ap7_4UN3QSBG9JK7OoCdJYF41M6Ys-uJxVSSg@mail.gmail.com>
Message-ID: <CACh5xi9fYpSrjd5tnxUvbAipKV2VJPy=w0LrY-_yTTvY5_GAWg@mail.gmail.com>

Thanks a lot Mark and Alex, really appreciate it.

I thought about this more and then this worked  return members[:-2]
(-2 because there is an extra space after , in members = members + users[x]
+ ", ")

I was all along trying -1 and was unsuccessful.

Thanks again.

On Fri, Jan 24, 2020 at 10:02 AM Panchanathan Suresh <suresh.gm at gmail.com>
wrote:

> Thanks a lot Mark and Alex, really appreciate it.
>
> I thought about this more and then this worked  return members[:-2]
> (-2 because there is an extra space after , in members = members +
> users[x] + ", ")
>
> On Fri, Jan 24, 2020 at 9:50 AM Alex Kleider <akleider at sonic.net> wrote:
>
>> On 2020-01-24 05:12, Panchanathan Suresh wrote:
>> > Hi everyone,
>> >
>> > How to remove the last comma , from the variable members?
>> > I tried members[:-1], members.rstrip(","), but no luck. It is
>> > always returning:
>> > Mike, Karen, Jake, Tasha,
>> >
>> > I want it to return Mike, Karen, Jake, Tasha (no comma after Tasha)
>> >
>> > Below is my code:
>> >
>> > *****
>> > def group_list(group, users):
>> >   members = ""
>> >   members1 = ""
>> >   for x in range(0,len(users)):
>> >       #print(users[x])
>> >       members = members + users[x] + ", "
>> >   return members[:-1]
>> >
>> >
>> > print(group_list("Marketing", ["Mike", "Karen", "Jake", "Tasha"])) #
>> > Should
>> > be "Marketing: Mike, Karen, Jake, Tasha"
>> >
>>
>> You might find the str join method useful;
>> more specifically:
>> >>> ', '.join(["Mike", "Karen", "Jake", "Tasha"])
>>
>

From suresh.gm at gmail.com  Sat Jan 25 12:33:57 2020
From: suresh.gm at gmail.com (Panchanathan Suresh)
Date: Sat, 25 Jan 2020 09:33:57 -0800
Subject: [Tutor] Tutor Digest, Vol 191, Issue 32
In-Reply-To: <mailman.8.1579971603.13032.tutor@python.org>
References: <mailman.8.1579971603.13032.tutor@python.org>
Message-ID: <CACh5xi_a00us6J7SuJWOQX7OK=9AB4rYggAdeZH-L5pcG3udVQ@mail.gmail.com>

Brilliant suggestions from everyone. Thanks a ton!

On Sat, Jan 25, 2020 at 9:01 AM <tutor-request at python.org> wrote:

> Send Tutor mailing list submissions to
>         tutor at python.org
>
> To subscribe or unsubscribe via the World Wide Web, visit
>         https://mail.python.org/mailman/listinfo/tutor
> or, via email, send a message with subject or body 'help' to
>         tutor-request at python.org
>
> You can reach the person managing the list at
>         tutor-owner at python.org
>
> When replying, please edit your Subject line so it is more specific
> than "Re: Contents of Tutor digest..."
> Today's Topics:
>
>    1. Re: How to remove the comma only at the end? (Panchanathan Suresh)
>
>
>
> ---------- Forwarded message ----------
> From: Panchanathan Suresh <suresh.gm at gmail.com>
> To: tutor at python.org
> Cc:
> Bcc:
> Date: Fri, 24 Jan 2020 10:03:29 -0800
> Subject: Re: [Tutor] How to remove the comma only at the end?
> Thanks a lot Mark and Alex, really appreciate it.
>
> I thought about this more and then this worked  return members[:-2]
> (-2 because there is an extra space after , in members = members + users[x]
> + ", ")
>
> I was all along trying -1 and was unsuccessful.
>
> Thanks again.
>
> On Fri, Jan 24, 2020 at 10:02 AM Panchanathan Suresh <suresh.gm at gmail.com>
> wrote:
>
> > Thanks a lot Mark and Alex, really appreciate it.
> >
> > I thought about this more and then this worked  return members[:-2]
> > (-2 because there is an extra space after , in members = members +
> > users[x] + ", ")
> >
> > On Fri, Jan 24, 2020 at 9:50 AM Alex Kleider <akleider at sonic.net> wrote:
> >
> >> On 2020-01-24 05:12, Panchanathan Suresh wrote:
> >> > Hi everyone,
> >> >
> >> > How to remove the last comma , from the variable members?
> >> > I tried members[:-1], members.rstrip(","), but no luck. It is
> >> > always returning:
> >> > Mike, Karen, Jake, Tasha,
> >> >
> >> > I want it to return Mike, Karen, Jake, Tasha (no comma after Tasha)
> >> >
> >> > Below is my code:
> >> >
> >> > *****
> >> > def group_list(group, users):
> >> >   members = ""
> >> >   members1 = ""
> >> >   for x in range(0,len(users)):
> >> >       #print(users[x])
> >> >       members = members + users[x] + ", "
> >> >   return members[:-1]
> >> >
> >> >
> >> > print(group_list("Marketing", ["Mike", "Karen", "Jake", "Tasha"])) #
> >> > Should
> >> > be "Marketing: Mike, Karen, Jake, Tasha"
> >> >
> >>
> >> You might find the str join method useful;
> >> more specifically:
> >> >>> ', '.join(["Mike", "Karen", "Jake", "Tasha"])
> >>
> >
>
> _______________________________________________
> Tutor maillist  -  Tutor at python.org
> https://mail.python.org/mailman/listinfo/tutor
>

From zebra05 at gmail.com  Mon Jan 27 06:51:58 2020
From: zebra05 at gmail.com (S D)
Date: Mon, 27 Jan 2020 13:51:58 +0200
Subject: [Tutor] Getting first item in dictionary
Message-ID: <CAH-SnCC7kcs6HgCwssARSa+VPh=aH9m9Y=CZ6UGSHFfmHDbMzA@mail.gmail.com>

I have a dictionary which contains one item (?current_location?, which is a
nested dict) and I would like to access that nested dict. However, I cannot
use the key as the code will break if a different key is passed, e.g.
?different_location".

How can I access the first item in a dictionary without using a key? The
dict looks like this:

```
{'current_location': {'date': '2020-01-27T10:28:24.148Z', 'type_icon':
'partly-cloudy-day', 'description': 'Mostly Cloudy', 'temperature': 68.28,
'wind': {'speed': 10.48, 'bearing': 178, 'gust': 12.47}, 'rain_prob': 0.02,
'latitude': '-33.927407', 'longitude': '18.415747', 'request_id': 31364,
'request_location': 'Current location'}}
```


Kind regards,
- SD

From mats at wichmann.us  Mon Jan 27 10:07:09 2020
From: mats at wichmann.us (Mats Wichmann)
Date: Mon, 27 Jan 2020 08:07:09 -0700
Subject: [Tutor] Getting first item in dictionary
In-Reply-To: <CAH-SnCC7kcs6HgCwssARSa+VPh=aH9m9Y=CZ6UGSHFfmHDbMzA@mail.gmail.com>
References: <CAH-SnCC7kcs6HgCwssARSa+VPh=aH9m9Y=CZ6UGSHFfmHDbMzA@mail.gmail.com>
Message-ID: <773c138a-b323-ee0d-426d-22a3d468c983@wichmann.us>

On 1/27/20 4:51 AM, S D wrote:
> I have a dictionary which contains one item (?current_location?, which is a
> nested dict) and I would like to access that nested dict. However, I cannot
> use the key as the code will break if a different key is passed, e.g.
> ?different_location".
> 
> How can I access the first item in a dictionary without using a key? The
> dict looks like this:
> 
> ```
> {'current_location': {'date': '2020-01-27T10:28:24.148Z', 'type_icon':
> 'partly-cloudy-day', 'description': 'Mostly Cloudy', 'temperature': 68.28,
> 'wind': {'speed': 10.48, 'bearing': 178, 'gust': 12.47}, 'rain_prob': 0.02,
> 'latitude': '-33.927407', 'longitude': '18.415747', 'request_id': 31364,
> 'request_location': 'Current location'}}
> ```


Two simple ways:

>>> d = {'key': 'value'}

1. use the dict's get method, which returns None if not found:

>>> v = d.get('key')
>>> print(v)
value
>>> v = d.get('foo')
>>> print(v)
None
>>> 

2. use a try/except:

>>> for k in ('key', 'foo'):
...     try:
...         print(d[k])
...     except KeyError:
...         print("No such key:", k)
...
value
No such key: foo
>>> 

From joel.goldstick at gmail.com  Mon Jan 27 10:14:34 2020
From: joel.goldstick at gmail.com (Joel Goldstick)
Date: Mon, 27 Jan 2020 10:14:34 -0500
Subject: [Tutor] Getting first item in dictionary
In-Reply-To: <773c138a-b323-ee0d-426d-22a3d468c983@wichmann.us>
References: <CAH-SnCC7kcs6HgCwssARSa+VPh=aH9m9Y=CZ6UGSHFfmHDbMzA@mail.gmail.com>
 <773c138a-b323-ee0d-426d-22a3d468c983@wichmann.us>
Message-ID: <CAPM-O+zmm5if+7JrYq0jk4_dkmKVZ5_K-uV2Rha+dMBTaviVnA@mail.gmail.com>

On Mon, Jan 27, 2020 at 10:07 AM Mats Wichmann <mats at wichmann.us> wrote:
>
> On 1/27/20 4:51 AM, S D wrote:
> > I have a dictionary which contains one item (?current_location?, which is a
> > nested dict) and I would like to access that nested dict. However, I cannot
> > use the key as the code will break if a different key is passed, e.g.
> > ?different_location".
> >
> > How can I access the first item in a dictionary without using a key? The
> > dict looks like this:
> >
> > ```
> > {'current_location': {'date': '2020-01-27T10:28:24.148Z', 'type_icon':
> > 'partly-cloudy-day', 'description': 'Mostly Cloudy', 'temperature': 68.28,
> > 'wind': {'speed': 10.48, 'bearing': 178, 'gust': 12.47}, 'rain_prob': 0.02,
> > 'latitude': '-33.927407', 'longitude': '18.415747', 'request_id': 31364,
> > 'request_location': 'Current location'}}
> > ```
>
>
> Two simple ways:
>
> >>> d = {'key': 'value'}
>
> 1. use the dict's get method, which returns None if not found:
>
> >>> v = d.get('key')
> >>> print(v)
> value
> >>> v = d.get('foo')
> >>> print(v)
> None
> >>>
>
> 2. use a try/except:
>
> >>> for k in ('key', 'foo'):
> ...     try:
> ...         print(d[k])
> ...     except KeyError:
> ...         print("No such key:", k)
> ...
> value
> No such key: foo
> >>>
> _______________________________________________
> Tutor maillist  -  Tutor at python.org
> To unsubscribe or change subscription options:
> https://mail.python.org/mailman/listinfo/tutor


Try d.values()

Python 3.6.9 (default, Nov  7 2019, 10:44:02)
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> d = {'current_location': {'date': '2020-01-27T10:28:24.148Z', 'type_icon':
... 'partly-cloudy-day', 'description': 'Mostly Cloudy', 'temperature': 68.28,
... 'wind': {'speed': 10.48, 'bearing': 178, 'gust': 12.47}, 'rain_prob': 0.02,
... 'latitude': '-33.927407', 'longitude': '18.415747', 'request_id': 31364,
... 'request_location': 'Current location'}}
>>> d
{'current_location': {'date': '2020-01-27T10:28:24.148Z', 'type_icon':
'partly-cloudy-day', 'description': 'Mostly Cloudy', 'temperature':
68.28, 'wind': {'speed': 10.48, 'bearing': 178, 'gust': 12.47},
'rain_prob': 0.02, 'latitude': '-33.927407', 'longitude': '18.415747',
'request_id': 31364, 'request_location': 'Current location'}}
>>> d.values()
dict_values([{'date': '2020-01-27T10:28:24.148Z', 'type_icon':
'partly-cloudy-day', 'description': 'Mostly Cloudy', 'temperature':
68.28, 'wind': {'speed': 10.48, 'bearing': 178, 'gust': 12.47},
'rain_prob': 0.02, 'latitude': '-33.927407', 'longitude': '18.415747',
'request_id': 31364, 'request_location': 'Current location'}])



-- 
Joel Goldstick
http://joelgoldstick.com/blog
http://cc-baseballstats.info/stats/birthdays

From alan.gauld at yahoo.co.uk  Mon Jan 27 13:16:55 2020
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Mon, 27 Jan 2020 18:16:55 +0000
Subject: [Tutor] Getting first item in dictionary
In-Reply-To: <CAH-SnCC7kcs6HgCwssARSa+VPh=aH9m9Y=CZ6UGSHFfmHDbMzA@mail.gmail.com>
References: <CAH-SnCC7kcs6HgCwssARSa+VPh=aH9m9Y=CZ6UGSHFfmHDbMzA@mail.gmail.com>
Message-ID: <r0n9en$2fcr$1@ciao.gmane.io>

On 27/01/2020 11:51, S D wrote:
> I have a dictionary which contains one item (?current_location?, which is a
> nested dict) and I would like to access that nested dict. However, I cannot
> use the key as the code will break if a different key is passed, e.g.
> ?different_location".

That doesn't make much sense. If you cannot use a key to
access the data why did you put it in a dictionary which
is a structure accessed by keys?

When you say the code will break if you use a wrong key
surely all you should get is a Keyerror? And you can avoid
that by using  dict.get(key) which returns None if the key
is not found. (Although using try/except to catch the error
would be better in this scenario because you should want
to know why you have a wrong key and prevent it!

> How can I access the first item in a dictionary without using a key? 

If that's what you really want you should be using a list
instead of a dictionary.

But you can kind of get that by using dict.values() which
gives you back a list of values (actually a fancy type
of structure that acts like a list)




> dict looks like this:
> 
> ```
> {'current_location': {'date': '2020-01-27T10:28:24.148Z', 'type_icon':
> 'partly-cloudy-day', 'description': 'Mostly Cloudy', 'temperature': 68.28,
> 'wind': {'speed': 10.48, 'bearing': 178, 'gust': 12.47}, 'rain_prob': 0.02,
> 'latitude': '-33.927407', 'longitude': '18.415747', 'request_id': 31364,
> 'request_location': 'Current location'}}
> ```

Have you considered creating a class?
With that amount of nested dicts etc I'd have thought
a class would be a better fit. Then maybe a list of instances.


-- 
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 PyTutor at DancesWithMice.info  Mon Jan 27 16:10:47 2020
From: PyTutor at DancesWithMice.info (David L Neil)
Date: Tue, 28 Jan 2020 10:10:47 +1300
Subject: [Tutor] Getting first item in dictionary
In-Reply-To: <r0n9en$2fcr$1@ciao.gmane.io>
References: <CAH-SnCC7kcs6HgCwssARSa+VPh=aH9m9Y=CZ6UGSHFfmHDbMzA@mail.gmail.com>
 <r0n9en$2fcr$1@ciao.gmane.io>
Message-ID: <95dad860-2e16-02b7-466d-02498faced5e@DancesWithMice.info>

On 28/01/20 7:16 AM, Alan Gauld via Tutor wrote:
> On 27/01/2020 11:51, S D wrote:
>> I have a dictionary which contains one item (?current_location?, which is a
>> nested dict) and I would like to access that nested dict. However, I cannot
>> use the key as the code will break if a different key is passed, e.g.
>> ?different_location".
> 
> That doesn't make much sense. If you cannot use a key to
> access the data why did you put it in a dictionary which
> is a structure accessed by keys?

+1
(however, if we're going to abuse data structures, please see below)


> When you say the code will break if you use a wrong key
> surely all you should get is a Keyerror? And you can avoid
> that by using  dict.get(key) which returns None if the key
> is not found. (Although using try/except to catch the error
> would be better in this scenario because you should want
> to know why you have a wrong key and prevent it!
> 
>> How can I access the first item in a dictionary without using a key?
> 
> If that's what you really want you should be using a list
> instead of a dictionary.
> 
> But you can kind of get that by using dict.values() which
> gives you back a list of values (actually a fancy type
> of structure that acts like a list)

+1
see below...


>> dict looks like this:
>>
>> ```
>> {'current_location': {'date': '2020-01-27T10:28:24.148Z', 'type_icon':
>> 'partly-cloudy-day', 'description': 'Mostly Cloudy', 'temperature': 68.28,
>> 'wind': {'speed': 10.48, 'bearing': 178, 'gust': 12.47}, 'rain_prob': 0.02,
>> 'latitude': '-33.927407', 'longitude': '18.415747', 'request_id': 31364,
>> 'request_location': 'Current location'}}
>> ```
> 
> Have you considered creating a class?
> With that amount of nested dicts etc I'd have thought
> a class would be a better fit. Then maybe a list of instances.

+1

python3
Python 3.7.5 (default, Dec 15 2019, 17:54:26)
[GCC 9.2.1 20190827 (Red Hat 9.2.1-1)] on linux
Type "help", "copyright", "credits" or "license" for more information.
 >>> d = {'current_location': {'date': '2020-01-27T10:28:24.148Z', 
'type_icon':
... 'partly-cloudy-day', 'description': 'Mostly Cloudy', 'temperature': 
68.28,
... 'wind': {'speed': 10.48, 'bearing': 178, 'gust': 12.47}, 
'rain_prob': 0.02,
... 'latitude': '-33.927407', 'longitude': '18.415747', 'request_id': 31364,
... 'request_location': 'Current location'}}
 >>> list( d.values() )[ 0 ]
{'date': '2020-01-27T10:28:24.148Z', 'type_icon': 'partly-cloudy-day', 
'description': 'Mostly Cloudy', 'temperature': 68.28, 'wind': {'speed': 
10.48, 'bearing': 178, 'gust': 12.47}, 'rain_prob': 0.02, 'latitude': 
'-33.927407', 'longitude': '18.415747', 'request_id': 31364, 
'request_location': 'Current location'}
 >>> # alternately
 >>> d[ list( d.keys() )[ 0 ] ]
{'date': '2020-01-27T10:28:24.148Z', 'type_icon': 'partly-cloudy-day', 
'description': 'Mostly Cloudy', 'temperature': 68.28, 'wind': {'speed': 
10.48, 'bearing': 178, 'gust': 12.47}, 'rain_prob': 0.02, 'latitude': 
'-33.927407', 'longitude': '18.415747', 'request_id': 31364, 
'request_location': 'Current location'}


Why do you have a dict without knowing its key(s)?
If calling an API realises this data, surely the call includes 
sufficient data to be, or to assemble, the key?
-- 
Regards =dn

From roel at roelschroeven.net  Mon Jan 27 14:30:09 2020
From: roel at roelschroeven.net (Roel Schroeven)
Date: Mon, 27 Jan 2020 20:30:09 +0100
Subject: [Tutor] Getting first item in dictionary
In-Reply-To: <CAH-SnCC7kcs6HgCwssARSa+VPh=aH9m9Y=CZ6UGSHFfmHDbMzA@mail.gmail.com>
References: <CAH-SnCC7kcs6HgCwssARSa+VPh=aH9m9Y=CZ6UGSHFfmHDbMzA@mail.gmail.com>
Message-ID: <r0ndo0$5ei$1@ciao.gmane.io>

S D schreef op 27/01/2020 om 12:51:
> I have a dictionary which contains one item (?current_location?, which is a
> nested dict) and I would like to access that nested dict. However, I cannot
> use the key as the code will break if a different key is passed, e.g.
> ?different_location".
> 
> How can I access the first item in a dictionary without using a key? The
> dict looks like this:
> 
> ```
> {'current_location': {'date': '2020-01-27T10:28:24.148Z', 'type_icon':
> 'partly-cloudy-day', 'description': 'Mostly Cloudy', 'temperature': 68.28,
> 'wind': {'speed': 10.48, 'bearing': 178, 'gust': 12.47}, 'rain_prob': 0.02,
> 'latitude': '-33.927407', 'longitude': '18.415747', 'request_id': 31364,
> 'request_location': 'Current location'}}
> ```

If you are really sure that there is only one item in the dictionary, 
you can simply retrieve the first value without even looking at the key:

from pprint import pprint
loc_dict = {'current_location': {'date': '2020-01-27T10:28:24.148Z',
                       'description': 'Mostly Cloudy',
                       'latitude': '-33.927407',
                       'longitude': '18.415747',
                       'rain_prob': 0.02,
                       'request_id': 31364,
                       'request_location': 'Current location',
                       'temperature': 68.28,
                       'type_icon': 'partly-cloudy-day',
                       'wind': {'bearing': 178,
                                'gust': 12.47,
                                'speed': 10.48}}}
first_value = list(loc_dict.values())[0]
pprint(first_value)

Outputs:

{'date': '2020-01-27T10:28:24.148Z',
  'description': 'Mostly Cloudy',
  'latitude': '-33.927407',
  'longitude': '18.415747',
  'rain_prob': 0.02,
  'request_id': 31364,
  'request_location': 'Current location',
  'temperature': 68.28,
  'type_icon': 'partly-cloudy-day',
  'wind': {'bearing': 178, 'gust': 12.47, 'speed': 10.48}}


That should extract the one item from a dictionary, if there is only 
one. And I think it should extract the first item even if there are 
multiple items, but that "first item" might not be what you expect 
depending on your expectations and the version of Python you use.


-- 
"Honest criticism is hard to take, particularly from a relative, a
friend, an acquaintance, or a stranger."
         -- Franklin P. Jones

Roel Schroeven


From PyTutor at DancesWithMice.info  Mon Jan 27 19:22:53 2020
From: PyTutor at DancesWithMice.info (David L Neil)
Date: Tue, 28 Jan 2020 13:22:53 +1300
Subject: [Tutor] Getting first item in dictionary
In-Reply-To: <r0ndo0$5ei$1@ciao.gmane.io>
References: <CAH-SnCC7kcs6HgCwssARSa+VPh=aH9m9Y=CZ6UGSHFfmHDbMzA@mail.gmail.com>
 <r0ndo0$5ei$1@ciao.gmane.io>
Message-ID: <83ab2af7-6273-714f-6b00-fa4421b76069@DancesWithMice.info>

On 28/01/20 8:30 AM, Roel Schroeven wrote:
> S D schreef op 27/01/2020 om 12:51:
>> I have a dictionary which contains one item (?current_location?, which 
>> is a
>> nested dict) and I would like to access that nested dict. However, I 
>> cannot
>> use the key as the code will break if a different key is passed, e.g.
>> ?different_location".
>>
>> How can I access the first item in a dictionary without using a key? The
>> dict looks like this:
...

> That should extract the one item from a dictionary, if there is only 
> one. And I think it should extract the first item even if there are 
> multiple items, but that "first item" might not be what you expect 
> depending on your expectations and the version of Python you use.


v3.7+
"the insertion-order preservation nature of dict objects has been 
declared to be an official part of the Python language spec."
https://docs.python.org/3/whatsnew/3.7.html
-- 
Regards =dn

From Yuanyuan.A.Olsen at HealthPartners.Com  Mon Jan 27 20:10:58 2020
From: Yuanyuan.A.Olsen at HealthPartners.Com (Olsen, Avalow Y)
Date: Tue, 28 Jan 2020 01:10:58 +0000
Subject: [Tutor] Jupyternotebook  set up
Message-ID: <25bf7bb0fd8f4f719541bdf4b716fd3c@REGEXCH05.HealthPartners.int>

Hi All,

I am using Jupyter Notebook for Python programing through Anaconda.

Anaconda Navigator version = 1.9.7

Jupyter Notebook version= 6.0.2

When running the following code, presumably there are 6 entries with the value "Not available" in the frequency.  Since the output is a long list, the "Not available" value is omitted in the outcome pane by .. as shown below.

               cars.horsepower.value_counts()

                   150.0    22
       90.0     19
       110.0    19
       100.0    16
       88.0     14
                ..
       230.0     1
       107.0     1
       158.0     1
       137.0     1
       167.0     1
       Name: horsepower, Length: 85, dtype: int64

Here is the proof that "Not available " exists in the horsepower variable
cars.horsepower.value_counts().loc["Not available "]

       6

There are 6 entries with the value "Not available"


My question is how to setup Jupyter Notebook in order to let the whole list of values be shown like below?


                   150.0    22
       90.0     19
       110.0    19
       100.0    16
       88.0     14
       105.0    12
       95.0     10
       85.0      9
       70.0      8
       145.0     7
       Not available 6
       84.0      5
                ..
       230.0     1
       107.0     1
       158.0     1
       137.0     1
       167.0     1



Thank you in advance!
Ava



________________________________

This e-mail and any files transmitted with it are confidential and are intended solely for the use of the individual or entity to whom they are addressed. If you are not the intended recipient or the individual responsible for delivering the e-mail to the intended recipient, please be advised that you have received this e-mail in error and that any use, dissemination, forwarding, printing, or copying of this e-mail is strictly prohibited.

If you have received this communication in error, please return it to the sender immediately and delete the original message and any copy of it from your computer system. If you have any questions concerning this message, please contact the sender. Disclaimer R001.0

From garylarose at outlook.com  Mon Jan 27 21:40:43 2020
From: garylarose at outlook.com (Gary LaRose)
Date: Tue, 28 Jan 2020 02:40:43 +0000
Subject: [Tutor] Jupyternotebook  set up
In-Reply-To: <25bf7bb0fd8f4f719541bdf4b716fd3c@REGEXCH05.HealthPartners.int>
References: <25bf7bb0fd8f4f719541bdf4b716fd3c@REGEXCH05.HealthPartners.int>
Message-ID: <BN8PR04MB56492401225BAC060C9E9EDFD70A0@BN8PR04MB5649.namprd04.prod.outlook.com>

It appears you are printing value counts from a pandas dataframe column (series)

Check this stackoverflow post

https://stackoverflow.com/questions/19124601/pretty-print-an-entire-pandas-series-dataframe#30691921

Try option_context ( from above post )


with pd.option_context('display.max_rows', None):  # more options can be specified also
    print(cars.horsepower.value_counts())

Or try pd.option_context as above with:
print(cars[?horsepower?].value_counts())


On Jan 27, 2020, at 8:11 PM, Olsen, Avalow Y <Yuanyuan.A.Olsen at healthpartners.com> wrote:

?Hi All,

I am using Jupyter Notebook for Python programing through Anaconda.

Anaconda Navigator version = 1.9.7

Jupyter Notebook version= 6.0.2

When running the following code, presumably there are 6 entries with the value "Not available" in the frequency.  Since the output is a long list, the "Not available" value is omitted in the outcome pane by .. as shown below.

              cars.horsepower.value_counts()

                  150.0    22
      90.0     19
      110.0    19
      100.0    16
      88.0     14
               ..
      230.0     1
      107.0     1
      158.0     1
      137.0     1
      167.0     1
      Name: horsepower, Length: 85, dtype: int64

Here is the proof that "Not available " exists in the horsepower variable
cars.horsepower.value_counts().loc["Not available "]

      6

There are 6 entries with the value "Not available"


My question is how to setup Jupyter Notebook in order to let the whole list of values be shown like below?


                  150.0    22
      90.0     19
      110.0    19
      100.0    16
      88.0     14
      105.0    12
      95.0     10
      85.0      9
      70.0      8
      145.0     7
      Not available 6
      84.0      5
               ..
      230.0     1
      107.0     1
      158.0     1
      137.0     1
      167.0     1



Thank you in advance!
Ava



________________________________

This e-mail and any files transmitted with it are confidential and are intended solely for the use of the individual or entity to whom they are addressed. If you are not the intended recipient or the individual responsible for delivering the e-mail to the intended recipient, please be advised that you have received this e-mail in error and that any use, dissemination, forwarding, printing, or copying of this e-mail is strictly prohibited.

If you have received this communication in error, please return it to the sender immediately and delete the original message and any copy of it from your computer system. If you have any questions concerning this message, please contact the sender. Disclaimer R001.0
_______________________________________________
Tutor maillist  -  Tutor at python.org
To unsubscribe or change subscription options:
https://nam10.safelinks.protection.outlook.com/?url=https%3A%2F%2Fmail.python.org%2Fmailman%2Flistinfo%2Ftutor&amp;data=02%7C01%7C%7C87478238f7294eaaf99208d7a38efe51%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C637157706850698976&amp;sdata=05RKoT8ZvgE%2B07PPbFSjlytANDEydgBYt6qPmLIRpGw%3D&amp;reserved=0

From Yuanyuan.A.Olsen at HealthPartners.Com  Mon Jan 27 23:01:47 2020
From: Yuanyuan.A.Olsen at HealthPartners.Com (Olsen, Avalow Y)
Date: Tue, 28 Jan 2020 04:01:47 +0000
Subject: [Tutor] Jupyternotebook  set up
In-Reply-To: <BN8PR04MB56492401225BAC060C9E9EDFD70A0@BN8PR04MB5649.namprd04.prod.outlook.com>
References: <25bf7bb0fd8f4f719541bdf4b716fd3c@REGEXCH05.HealthPartners.int>
 <BN8PR04MB56492401225BAC060C9E9EDFD70A0@BN8PR04MB5649.namprd04.prod.outlook.com>
Message-ID: <ef8784934e6c48ca9fa02ad3a7b7eab6@REGEXCH05.HealthPartners.int>

Thanks, Gary!
You are right. Pandas has its own built-in options for display.  The following code works:

pd.options.display.max_rows = None
pd.options.display.min_rows = None  #  this line is a must. Otherwise it would still only show head and tail.

Really appreciate it!  Thank you!
Ava
From: Gary LaRose [mailto:garylarose at outlook.com]
Sent: Monday, January 27, 2020 8:41 PM
To: Olsen, Avalow Y <Yuanyuan.A.Olsen at HealthPartners.Com>
Cc: tutor at python.org
Subject: [EXTERNAL]Re: [Tutor] Jupyternotebook set up


External Email: Don't click links or attachments unless you trust the email.
It appears you are printing value counts from a pandas dataframe column (series)

Check this stackoverflow post

https://stackoverflow.com/questions/19124601/pretty-print-an-entire-pandas-series-dataframe#30691921

Try option_context ( from above post )


with pd.option_context('display.max_rows', None):  # more options can be specified also

    print(cars.horsepower.value_counts())
Or try pd.option_context as above with:
print(cars[?horsepower?].value_counts())



On Jan 27, 2020, at 8:11 PM, Olsen, Avalow Y <Yuanyuan.A.Olsen at healthpartners.com<mailto:Yuanyuan.A.Olsen at healthpartners.com>> wrote:
?Hi All,

I am using Jupyter Notebook for Python programing through Anaconda.

Anaconda Navigator version = 1.9.7

Jupyter Notebook version= 6.0.2

When running the following code, presumably there are 6 entries with the value "Not available" in the frequency.  Since the output is a long list, the "Not available" value is omitted in the outcome pane by .. as shown below.

              cars.horsepower.value_counts()

                  150.0    22
      90.0     19
      110.0    19
      100.0    16
      88.0     14
               ..
      230.0     1
      107.0     1
      158.0     1
      137.0     1
      167.0     1
      Name: horsepower, Length: 85, dtype: int64

Here is the proof that "Not available " exists in the horsepower variable
cars.horsepower.value_counts().loc["Not available "]

      6

There are 6 entries with the value "Not available"


My question is how to setup Jupyter Notebook in order to let the whole list of values be shown like below?


                  150.0    22
      90.0     19
      110.0    19
      100.0    16
      88.0     14
      105.0    12
      95.0     10
      85.0      9
      70.0      8
      145.0     7
      Not available 6
      84.0      5
               ..
      230.0     1
      107.0     1
      158.0     1
      137.0     1
      167.0     1



Thank you in advance!
Ava



________________________________

This e-mail and any files transmitted with it are confidential and are intended solely for the use of the individual or entity to whom they are addressed. If you are not the intended recipient or the individual responsible for delivering the e-mail to the intended recipient, please be advised that you have received this e-mail in error and that any use, dissemination, forwarding, printing, or copying of this e-mail is strictly prohibited.

If you have received this communication in error, please return it to the sender immediately and delete the original message and any copy of it from your computer system. If you have any questions concerning this message, please contact the sender. Disclaimer R001.0
_______________________________________________
Tutor maillist  -  Tutor at python.org<mailto:Tutor at python.org>
To unsubscribe or change subscription options:
https://nam10.safelinks.protection.outlook.com/?url=https%3A%2F%2Fmail.python.org%2Fmailman%2Flistinfo%2Ftutor&amp;data=02%7C01%7C%7C87478238f7294eaaf99208d7a38efe51%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C637157706850698976&amp;sdata=05RKoT8ZvgE%2B07PPbFSjlytANDEydgBYt6qPmLIRpGw%3D&amp;reserved=0

From mrkarimbo at gmail.com  Tue Jan 28 07:37:21 2020
From: mrkarimbo at gmail.com (Karim Beidas)
Date: Tue, 28 Jan 2020 15:37:21 +0300
Subject: [Tutor] Runtime Error
Message-ID: <5e302b03.1c69fb81.b27ab.8113@mx.google.com>

Can you please help me fix this?
C:\Users\MSIi\Desktop\Fortnite Py Bot\Fortnite Py Bot\Fortnite PY bot\fortnitepy-bot-master>py fortnite.py
Traceback (most recent call last):
  File "fortnite.py", line 28, in <module>
    import fortnitepy
  File "C:\Users\MSIi\AppData\Local\Programs\Python\Python38-32\lib\site-packages\fortnitepy\__init__.py", line 48, in <module>
    get_event_loop()
  File "C:\Users\MSIi\AppData\Local\Programs\Python\Python38-32\lib\site-packages\fortnitepy\client.py", line 116, in get_event_loop
    raise RuntimeError('asyncio.ProactorEventLoop is not supported')
RuntimeError: asyncio.ProactorEventLoop is not supported

C:\Users\MSIi\Desktop\Fortnite Py Bot\Fortnite Py Bot\Fortnite PY bot\fortnitepy-bot-master>cmd /k
C:\Users\MSIi\Desktop\Fortnite Py Bot\Fortnite Py Bot\Fortnite PY bot\fortnitepy-bot-master>
This is what it says when I try start the start bot file.
And why does it say RuntimeError: asyncio.ProactorEventLoop is not supported
Please respond as quick as possible.
Thank you.

Sent from Mail for Windows 10


From alan.gauld at yahoo.co.uk  Tue Jan 28 11:14:19 2020
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Tue, 28 Jan 2020 16:14:19 +0000
Subject: [Tutor] Runtime Error
In-Reply-To: <5e302b03.1c69fb81.b27ab.8113@mx.google.com>
References: <5e302b03.1c69fb81.b27ab.8113@mx.google.com>
Message-ID: <r0pmkr$3aj0$1@ciao.gmane.io>

On 28/01/2020 12:37, Karim Beidas wrote:

>   File "fortnite.py", line 28, in <module>
>     import fortnitepy
>   File "C:\Users\MSIi\AppData\Local\Programs\Python\Python38-32\lib\site-packages\fortnitepy\__init__.py", line 48, in <module>
>     get_event_loop()
>   File "C:\Users\MSIi\AppData\Local\Programs\Python\Python38-32\lib\site-packages\fortnitepy\client.py", line 116, in get_event_loop
>     raise RuntimeError('asyncio.ProactorEventLoop is not supported')

My immediate suspicion is that there is a missing module.
You may need to install another package to make it work.

But I'm not familiar with the fortnitepy module, so you
would need to check the documentation there for any dependencies.
But that's my guess.


-- 
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 marc.tompkins at gmail.com  Tue Jan 28 11:34:23 2020
From: marc.tompkins at gmail.com (Marc Tompkins)
Date: Tue, 28 Jan 2020 08:34:23 -0800
Subject: [Tutor] Runtime Error
In-Reply-To: <r0pmkr$3aj0$1@ciao.gmane.io>
References: <5e302b03.1c69fb81.b27ab.8113@mx.google.com>
 <r0pmkr$3aj0$1@ciao.gmane.io>
Message-ID: <CAKK8jXaz-Qzi+C6oM0KF9DUBduYeY3p78C8+iBMr02qViVgHPg@mail.gmail.com>

On Tue, Jan 28, 2020 at 8:15 AM Alan Gauld via Tutor <tutor at python.org>
wrote:

> On 28/01/2020 12:37, Karim Beidas wrote:
>
> >   File "fortnite.py", line 28, in <module>
> >     import fortnitepy
> >   File
> "C:\Users\MSIi\AppData\Local\Programs\Python\Python38-32\lib\site-packages\fortnitepy\__init__.py",
> line 48, in <module>
> >     get_event_loop()
> >   File
> "C:\Users\MSIi\AppData\Local\Programs\Python\Python38-32\lib\site-packages\fortnitepy\client.py",
> line 116, in get_event_loop
> >     raise RuntimeError('asyncio.ProactorEventLoop is not supported')
>
> My immediate suspicion is that there is a missing module.
> You may need to install another package to make it work.
>
> But I'm not familiar with the fortnitepy module, so you
> would need to check the documentation there for any dependencies.
> But that's my guess.
>
> Looking at the documentation for ProactorEventLoop, there are so many
instances of "is not supported" and "is only supported if" that I wonder -
is it just that the OP's Windows configuration is subtly different from
whoever wrote the fortnitepy module?
https://docs.python.org/3.6/library/asyncio-eventloops.html#asyncio.ProactorEventLoop

From mats at wichmann.us  Tue Jan 28 11:45:56 2020
From: mats at wichmann.us (Mats Wichmann)
Date: Tue, 28 Jan 2020 09:45:56 -0700
Subject: [Tutor] Runtime Error
In-Reply-To: <CAKK8jXaz-Qzi+C6oM0KF9DUBduYeY3p78C8+iBMr02qViVgHPg@mail.gmail.com>
References: <5e302b03.1c69fb81.b27ab.8113@mx.google.com>
 <r0pmkr$3aj0$1@ciao.gmane.io>
 <CAKK8jXaz-Qzi+C6oM0KF9DUBduYeY3p78C8+iBMr02qViVgHPg@mail.gmail.com>
Message-ID: <c546f6af-334c-78a7-5eba-9b69daf9b30d@wichmann.us>

On 1/28/20 9:34 AM, Marc Tompkins wrote:
> On Tue, Jan 28, 2020 at 8:15 AM Alan Gauld via Tutor <tutor at python.org>
> wrote:
> 
>> On 28/01/2020 12:37, Karim Beidas wrote:
>>
>>>   File "fortnite.py", line 28, in <module>
>>>     import fortnitepy
>>>   File
>> "C:\Users\MSIi\AppData\Local\Programs\Python\Python38-32\lib\site-packages\fortnitepy\__init__.py",
>> line 48, in <module>
>>>     get_event_loop()
>>>   File
>> "C:\Users\MSIi\AppData\Local\Programs\Python\Python38-32\lib\site-packages\fortnitepy\client.py",
>> line 116, in get_event_loop
>>>     raise RuntimeError('asyncio.ProactorEventLoop is not supported')
>>
>> My immediate suspicion is that there is a missing module.
>> You may need to install another package to make it work.

Like the others, never heard of this. But searching a bit gets me this page:

https://github.com/xMistt/fortnitepy-bot

Which says, with lots of shouting:

Install Python 3.6 (suggested, any 3.x version should work, APART FROM
3.8 DO NOT USE 3.8 OR ELSE YOU'LL GET A LOT OF ERRORS.)

And the traceback above clearly shows Python 3.8 is in the picture.



From alan.gauld at btinternet.com  Tue Jan 28 21:46:21 2020
From: alan.gauld at btinternet.com (Alan Gauld)
Date: Wed, 29 Jan 2020 02:46:21 -0000
Subject: [Tutor] How to refactor a simple,
 straightforward script into a "proper" program?
In-Reply-To: <CANDiX9+B=ZwXCdd_pJzVkYbq_DbZgQQnyAmyJGRowVmYP5bP9w@mail.gmail.com>
References: <CANDiX9JjoXfpEBvnmsJWrAyumLvsKUN39VcaTvoG05-Cnm1DHA@mail.gmail.com>
 <45f1a074-d8bc-ec13-9757-4686ee60462d@DancesWithMice.info>
 <CANDiX9Kv=675fXb=it=tTh2hf+Nx4rTyD7bHS4St9UUizYtZDw@mail.gmail.com>
 <CANDiX9+Rx-syD++J2XuNHyknEccwBC=wBFPpHd7A6DYKYkubNQ@mail.gmail.com>
 <928a7db3-50a7-9bca-7ce3-01323222b237@yahoo.co.uk>
 <CANDiX9+B=ZwXCdd_pJzVkYbq_DbZgQQnyAmyJGRowVmYP5bP9w@mail.gmail.com>
Message-ID: <ff0449a0-c664-cf70-1441-5451b55d858b@btinternet.com>

On 05/01/2020 05:40, boB Stepp wrote:

>>>     while True:
>>>         try:
>>>             return str_converter(input(msg))
>>>         except ValueError:
>>>             if str_converter == int:
>>>                 print("\nPlease enter a whole number!")
>>>             elif str_converter == date.fromisoformat:
>>>                 print("\nPlease enter a valid date in the following
>>> format yyyy-mm-dd!")
>>
>> And if its not one of those types? I get a ValueError raised then it
>> does nothing. It just returns None. That's not very friendly.
> 
> Huh?  Joel said something similar.  Maybe I am being dense, but it
> *does* do something.  If the user types in something that is not one
> of the allowed types, he gets a helpful message telling him/her what
> the program is expecting, and the program loops back to the original
> message requesting input.

My bad it does not "return None" in the technical sense.
It displays nothing just returns to the prompt.
Try writing your own string convertor:

def myInt(s):
   return int(s)

Now use myInt as the string convertor and see what happens...
It does 'work' but is less user friendly.

> But it also does date input.  And if in the future I wanted other
> sorts of input I need only add new string converters for the new data
> types.

Yes, but the udr of your module will expect to be able to write their
own string convertors and they wont work without modifying the module -
thats bad.

You would need to have a dict of string convertors and error messages so
that the error handler could look up the error message using the string
convertor as a key:


except ValueError:
       print conv_msg[string_convertor]

And the user can then add their own error message:

module.conv_msg[myInt] = "Enter an integer"


>> This sounds like a reusable function, but in fact its pretty tied into
>> the problem at hand.
> 
> Again, I wonder if I am being dense, but my intent with this function
> is to handle a variety of input types.  I would have to add new
> ValueError possibilities for new data types.  Is this what bothers
> you?

Yes because when I download your "industrial strength" module I
discover I either have to contact you every time I need a new
string converter or I have to fix up the module myself!
Neither is good from a users perspective.

> Hmm.  I see that in case of ValueError it could look elsewhere for
> what sort of user friendly error message to display for a particular
> value of str_converter.  Is this what you are getting at?

Yes, see the dict example above.

> presented in the "simple" script.  I have quickly looked over D. L.
> Neil's comments, and, combined with yours, wonder if I should redesign
> the whole shebang from the ground up?  Maybe this problem does need an
> OO approach.

You shouldn't need an OO approach for something this small.
But you do need a bit of a rethink in tems of splitting out the
functions cleanly. And exactly what is published API and what
is just internal utility code.

> I grudgingly concede your point.  Grudgingly because now I have to
> figure out how to accomplish this.  ~(:>))

I think exceptions are the way to go.

>> ppd = calc_pages_per_day(bp,rp,due)
>>
>> Maybe its just me but the calc seems implied by the function call.
> 
> But I thought the great preference was for function and method names
> to be verbs not nouns?

Hmmm, yes. OK I'll give you that one :-)

>> Would you really say page if it was 0.5 pages per day?
> 
> Actually, yes.  Just as I would say a half page per day.  OTOH, I
> would say zero pages per day.  Maybe I need to dust off a grammar
> book...

a half page is not the same as 0,5 pages.
The a forces it to single. So in your code you need to add
an 'a' before the value to make it grammatical.
Thats more work, but doable, but what would you say
for a value like 0.82? What kind of fraction is that?
Are you going to convert it to say

a 82 hundredth of a page?

Good luck with that...

>> I'd only use 'page' if it was exactly 1.
>>
>> But since its a float you need to use an epsilon value.
>> So
>>
>> e = 0.0001
>> if 1-e < pages_per_day < 1+e:
>>     word_to_display = 'page'
>> else: word_to_display = 'pages'
> 
> Do I really need an epsilon value for this particular case?  I am not
> seeing where my intentions would fail here.  Can you provide an
> example?  

This is because the computer cannot accurately represent floats so you
may get a value like 0.999999999 or 1.00000001 when you want to treat it
as 1. So you either use an epsilon or you do a float to some minimal
number of decimals.

> thought if the user wishes to be silly here, why not?

Its not about the user, its the floating point division
in a digital computer.

> I originally in my code did not use mixed quotes.  But when I saved
> the file my new code formatting tyrant, Black, changed my consistent
> quoting style to mixed quotes.  Apparently it insists on all double
> quotes unless there are embedded quotes within when it converts those
> to single quotes.

Yukkkk!

>> 2) if a function isn't generally reusable make it obvious
>>    by putting an underscore in front of the name. (or
>>    make it generally reusable...usually much harder :-)
> 
> This is where I was hoping for some concrete, helpful examples.  I do
> indeed find this "much harder".

Everyone does. Management routinely ask devs to create reusable code,
but studies show that writing reusable code is from 3-5 times more
expensive than writing single-use code. Some studies say more like 10
times if you factor in maintenance costs too.

And there is no easy answer, it takes painful lessons and
experience, and you'll still mess it up!

>> 3) separate presentation and logic.
> 
> Again, I find this not so easy.

This is easier and just takes a little practice to get used to it.
Basically every function should either do display or logic. If its
doing logic then return values that the caller can use/display.


> FEATURE CREEP!  Actually sounds like an interesting addition.  But I
> don't much like eReaders myself.  

I didn't used to but, on holiday, I save a ton of weight by taking a
Kindle. And having got used to them I now occasionally even read
tech books on it. Although code formatting often gets messed up.
But I'm currently reading a book on curses programming in C and
converting it to python - maybe to become a page in my tutor
someday - and that's a Kindle book.


-- 
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 btinternet.com  Tue Jan 28 22:30:11 2020
From: alan.gauld at btinternet.com (Alan Gauld)
Date: Wed, 29 Jan 2020 03:30:11 -0000
Subject: [Tutor] stalker-m3u.py
In-Reply-To: <CAAH=Ob31bRv80P5n2dWxpBuDaAiot5p9wvfX_Faz188cyD4NmQ@mail.gmail.com>
References: <CAAH=Ob31bRv80P5n2dWxpBuDaAiot5p9wvfX_Faz188cyD4NmQ@mail.gmail.com>
Message-ID: <05a307ee-d835-48ef-9ff0-95a062b89956@btinternet.com>

On 23/12/2019 09:27, Aleksa wrote:
> Error: Please upgrade your API plan to use filters or paging.
> 
> NOT WORK.....

What doesn't work? When you upgraded your API plan to use filters
or paging did your code break? Did you get a different error message?
Did the wrong data come back?

And is it the same using filters as it is with paging?

We have no idea what we are looking for.

Personally I don't even know what the library does, nor what
paging and filters entails. But even if I did I couldn't help
without more details.

> Is there another way

I suspect you'd need to ask the package/API provider.
This is not a standard part of Python so the likelihood of anyone
on this list using it is quite small.


> def grab_file (IP,PORT,FILE):
> print ("[*] Testing: "+IP+" on Port: "+PORT+"[*]\n")
> try:

Your code has been mangled by the email system, you need
to post in plain text to preserve formatting.


-- 
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 bob at ralexander.it  Wed Jan 29 11:37:23 2020
From: bob at ralexander.it (Robert Alexander)
Date: Wed, 29 Jan 2020 17:37:23 +0100
Subject: [Tutor] Remove some known text around text I need to keep
Message-ID: <etPan.5e31b4c3.7085dbbc.c7f@ralexander.it>

Dear friends,
I have 200 text files in which a doctor has ?tagged? parts of the text as symptom, sign or therapy (in Italian SINTOMO, SEGNO, TERAPIA) as follows:

[SEGNO: edemi declivi >> a sinistra]
[SINTOMO: non lamenta dispnea]
[SINTOMO: paziente sintomatica per dispnea moderata]
[SEGNO: Non edemi]
[SEGNO: calo di 2 kg (55,8 kg)]
[TERAPIA: ha ridotto la terapia diuretica]
[TERAPIA: Lieve riduzione della terapia diuretica]
[TERAPIA: Lieve riduzione della terapia diuretica]

and so forth. These lines can span over a single text line and I need to remove just the tags and rewrite the original text without them. To give you an example on the same lines as above what I need to write back in the new ?clean? files are like the following:


edemi declivi >> a sinistra]
non lamenta dispnea]
paziente sintomatica per dispnea moderata]
Non edemi]
calo di 2 kg (55,8 kg)]
ha ridotto la terapia diuretica]
Lieve riduzione della terapia diuretica]
?Lieve riduzione della terapia diuretica]

if there was a newline in the text I should respect it and rewrite it out.
I am not 100% sure about thehandling of the space between the tags (eg [SEGNO:) and the first word within it.

What would you recommend? Regular expressions? Have a tutorial or document I can study?

Thank you very much.

From alan.gauld at yahoo.co.uk  Wed Jan 29 13:46:32 2020
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Wed, 29 Jan 2020 18:46:32 +0000
Subject: [Tutor] Remove some known text around text I need to keep
In-Reply-To: <etPan.5e31b4c3.7085dbbc.c7f@ralexander.it>
References: <etPan.5e31b4c3.7085dbbc.c7f@ralexander.it>
Message-ID: <r0sju9$3qnu$1@ciao.gmane.io>

On 29/01/2020 16:37, Robert Alexander wrote:
]
> [SINTOMO: paziente sintomatica per dispnea moderata]
> [SEGNO: Non edemi]
> [SEGNO: calo di 2 kg (55,8 kg)]
> [TERAPIA: ha ridotto la terapia diuretica]

> the same lines as above what I need to write back in the new ?clean? files are like the following:

> paziente sintomatica per dispnea moderata]
> Non edemi]
> calo di 2 kg (55,8 kg)]
> ha ridotto la terapia diuretica]

Look at the partition method of strings:

partition(...)
 S.partition(sep) -> (head, sep, tail)

 Search for the separator sep in S, and return the part before it,
 the separator itself, and the part after it.  If the separator is not
 found, return S and two empty strings.


Example:

>>> "FRED: Heris a partition: that looks like s".partition(':')
('FRED', ':', ' Heris a partition: that looks like s')
>>>

It should work with embedded \n too.


-- 
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 gogonegro at gmail.com  Wed Jan 29 13:51:13 2020
From: gogonegro at gmail.com (Robert Alexander)
Date: Wed, 29 Jan 2020 10:51:13 -0800
Subject: [Tutor] Remove some known text around text I need to keep
In-Reply-To: <r0sju9$3qnu$1@ciao.gmane.io>
References: <etPan.5e31b4c3.7085dbbc.c7f@ralexander.it>
 <r0sju9$3qnu$1@ciao.gmane.io>
Message-ID: <CADiDnXcmDG2g4paNmbO2h6LSVVaC2XgQGoVWuvs6Vwex-ahHmw@mail.gmail.com>

Thanks Alan,
Good to learn :)

I?ll look into it even though at a later reflection I might do this without
python with just an awk command killing all [TAG: and ] chars from the
files :)

Take care,
Robert


On 29 January 2020 at 19:46:55, Alan Gauld via Tutor (tutor at python.org)
wrote:

On 29/01/2020 16:37, Robert Alexander wrote:
]
> [SINTOMO: paziente sintomatica per dispnea moderata]
> [SEGNO: Non edemi]
> [SEGNO: calo di 2 kg (55,8 kg)]
> [TERAPIA: ha ridotto la terapia diuretica]

> the same lines as above what I need to write back in the new ?clean?
files are like the following:

> paziente sintomatica per dispnea moderata]
> Non edemi]
> calo di 2 kg (55,8 kg)]
> ha ridotto la terapia diuretica]

Look at the partition method of strings:

partition(...)
S.partition(sep) -> (head, sep, tail)

Search for the separator sep in S, and return the part before it,
the separator itself, and the part after it. If the separator is not
found, return S and two empty strings.


Example:

>>> "FRED: Heris a partition: that looks like s".partition(':')
('FRED', ':', ' Heris a partition: that looks like s')
>>>

It should work with embedded \n too.


-- 
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

From joel.goldstick at gmail.com  Wed Jan 29 16:09:41 2020
From: joel.goldstick at gmail.com (Joel Goldstick)
Date: Wed, 29 Jan 2020 16:09:41 -0500
Subject: [Tutor] Remove some known text around text I need to keep
In-Reply-To: <CADiDnXcmDG2g4paNmbO2h6LSVVaC2XgQGoVWuvs6Vwex-ahHmw@mail.gmail.com>
References: <etPan.5e31b4c3.7085dbbc.c7f@ralexander.it>
 <r0sju9$3qnu$1@ciao.gmane.io>
 <CADiDnXcmDG2g4paNmbO2h6LSVVaC2XgQGoVWuvs6Vwex-ahHmw@mail.gmail.com>
Message-ID: <CAPM-O+xA5rV4zmZLcQNt44+UCK842AGmqt0m7DC-_ZnqHtdZ_g@mail.gmail.com>

On Wed, Jan 29, 2020 at 1:51 PM Robert Alexander <gogonegro at gmail.com> wrote:
>
> Thanks Alan,
> Good to learn :)
>
> I?ll look into it even though at a later reflection I might do this without
> python with just an awk command killing all [TAG: and ] chars from the
> files :)
>
> Take care,
> Robert
>
>
> On 29 January 2020 at 19:46:55, Alan Gauld via Tutor (tutor at python.org)
> wrote:
>
> On 29/01/2020 16:37, Robert Alexander wrote:
> ]
> > [SINTOMO: paziente sintomatica per dispnea moderata]
> > [SEGNO: Non edemi]
> > [SEGNO: calo di 2 kg (55,8 kg)]
> > [TERAPIA: ha ridotto la terapia diuretica]
>
> > the same lines as above what I need to write back in the new ?clean?
> files are like the following:
>
> > paziente sintomatica per dispnea moderata]
> > Non edemi]
> > calo di 2 kg (55,8 kg)]
> > ha ridotto la terapia diuretica]
>
> Look at the partition method of strings:
>
> partition(...)
> S.partition(sep) -> (head, sep, tail)
>
> Search for the separator sep in S, and return the part before it,
> the separator itself, and the part after it. If the separator is not
> found, return S and two empty strings.
>
>
> Example:
>
> >>> "FRED: Heris a partition: that looks like s".partition(':')
> ('FRED', ':', ' Heris a partition: that looks like s')
> >>>
>
> It should work with embedded \n too.
>
>
> --
> 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
> _______________________________________________
> Tutor maillist  -  Tutor at python.org
> To unsubscribe or change subscription options:
> https://mail.python.org/mailman/listinfo/tutor

I didn't know about str.partition, but in your case str.split(":")
will return a list with the part you don't want first, followed by the
part you want

>>> s = "[SEGNO: edemi declivi >> a sinistra]"
>>> s.split(":")
['[SEGNO', ' edemi declivi >> a sinistra]']
>>>


-- 
Joel Goldstick
http://joelgoldstick.com/blog
http://cc-baseballstats.info/stats/birthdays

From PyTutor at danceswithmice.info  Wed Jan 29 17:05:04 2020
From: PyTutor at danceswithmice.info (DL Neil)
Date: Thu, 30 Jan 2020 11:05:04 +1300
Subject: [Tutor] Remove some known text around text I need to keep
In-Reply-To: <CAPM-O+xA5rV4zmZLcQNt44+UCK842AGmqt0m7DC-_ZnqHtdZ_g@mail.gmail.com>
References: <etPan.5e31b4c3.7085dbbc.c7f@ralexander.it>
 <r0sju9$3qnu$1@ciao.gmane.io>
 <CADiDnXcmDG2g4paNmbO2h6LSVVaC2XgQGoVWuvs6Vwex-ahHmw@mail.gmail.com>
 <CAPM-O+xA5rV4zmZLcQNt44+UCK842AGmqt0m7DC-_ZnqHtdZ_g@mail.gmail.com>
Message-ID: <ad404a80-14ea-e099-b8d9-fc2e2c4ba268@DancesWithMice.info>

>>> [SINTOMO: paziente sintomatica per dispnea moderata]
>>> [SEGNO: Non edemi]
>>> [SEGNO: calo di 2 kg (55,8 kg)]
>>> [TERAPIA: ha ridotto la terapia diuretica]
>>
>>> the same lines as above what I need to write back in the new ?clean?
>> files are like the following:
>>
>>> paziente sintomatica per dispnea moderata]
>>> Non edemi]
>>> calo di 2 kg (55,8 kg)]
>>> ha ridotto la terapia diuretica]
>>
>> Look at the partition method of strings:
>>
>> partition(...)
>> S.partition(sep) -> (head, sep, tail)
...
> I didn't know about str.partition, but in your case str.split(":")
> will return a list with the part you don't want first, followed by the
> part you want
> 
>>>> s = "[SEGNO: edemi declivi >> a sinistra]"
>>>> s.split(":")
> ['[SEGNO', ' edemi declivi >> a sinistra]']


Some call it "pedantry", others "attention to detail" but don't forget 
the closing square-bracket!

Depending upon the read-mechanism (whether the end-of-line character(s) 
are included - NB OpSys variations then apply!), a string-slice to 
remove the last character(s), possibly even before the above, will 
do-the-trick!
-- 
Regards =dn

From cs at cskk.id.au  Wed Jan 29 17:19:44 2020
From: cs at cskk.id.au (Cameron Simpson)
Date: Thu, 30 Jan 2020 09:19:44 +1100
Subject: [Tutor] Remove some known text around text I need to keep
In-Reply-To: <CADiDnXcmDG2g4paNmbO2h6LSVVaC2XgQGoVWuvs6Vwex-ahHmw@mail.gmail.com>
References: <CADiDnXcmDG2g4paNmbO2h6LSVVaC2XgQGoVWuvs6Vwex-ahHmw@mail.gmail.com>
Message-ID: <20200129221944.GA55881@cskk.homeip.net>

On 29Jan2020 10:51, Robert Alexander <gogonegro at gmail.com> wrote:
>Thanks Alan,
>Good to learn :)
>
>I?ll look into it even though at a later reflection I might do this without
>python with just an awk command killing all [TAG: and ] chars from the
>files :)

sed will be even smaller.

Cheers,
Cameron Simpson <cs at cskk.id.au>

From alan.gauld at yahoo.co.uk  Wed Jan 29 18:28:32 2020
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Wed, 29 Jan 2020 23:28:32 +0000
Subject: [Tutor] Remove some known text around text I need to keep
In-Reply-To: <CAPM-O+xA5rV4zmZLcQNt44+UCK842AGmqt0m7DC-_ZnqHtdZ_g@mail.gmail.com>
References: <etPan.5e31b4c3.7085dbbc.c7f@ralexander.it>
 <r0sju9$3qnu$1@ciao.gmane.io>
 <CADiDnXcmDG2g4paNmbO2h6LSVVaC2XgQGoVWuvs6Vwex-ahHmw@mail.gmail.com>
 <CAPM-O+xA5rV4zmZLcQNt44+UCK842AGmqt0m7DC-_ZnqHtdZ_g@mail.gmail.com>
Message-ID: <r0t4f0$1232$1@ciao.gmane.io>

On 29/01/2020 21:09, Joel Goldstick wrote:

> I didn't know about str.partition, but in your case str.split(":")
> will return a list with the part you don't want first, followed by the
> part you want

The problem with split is that if the string has a colon in it
split will split into 3 parts, not 2. You can specify the maxsplits
but that?s extra complexity. Partition only splits on the first occurrence.
split also loses the separator - although not an isssue here - but
partition retains the whole string.



-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos



From alan.gauld at yahoo.co.uk  Wed Jan 29 18:30:38 2020
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Wed, 29 Jan 2020 23:30:38 +0000
Subject: [Tutor] Remove some known text around text I need to keep
In-Reply-To: <ad404a80-14ea-e099-b8d9-fc2e2c4ba268@DancesWithMice.info>
References: <etPan.5e31b4c3.7085dbbc.c7f@ralexander.it>
 <r0sju9$3qnu$1@ciao.gmane.io>
 <CADiDnXcmDG2g4paNmbO2h6LSVVaC2XgQGoVWuvs6Vwex-ahHmw@mail.gmail.com>
 <CAPM-O+xA5rV4zmZLcQNt44+UCK842AGmqt0m7DC-_ZnqHtdZ_g@mail.gmail.com>
 <ad404a80-14ea-e099-b8d9-fc2e2c4ba268@DancesWithMice.info>
Message-ID: <r0t4iu$1232$2@ciao.gmane.io>

On 29/01/2020 22:05, DL Neil via Tutor wrote:
>>>> [SINTOMO: paziente sintomatica per dispnea moderata]
>>>> [SEGNO: Non edemi]
>>>> [SEGNO: calo di 2 kg (55,8 kg)]
>>>> [TERAPIA: ha ridotto la terapia diuretica]
>>>
>>>> the same lines as above what I need to write back in the new ?clean?
>>> files are like the following:
>>>
>>>> paziente sintomatica per dispnea moderata]
>>>> Non edemi]
>>>> calo di 2 kg (55,8 kg)]
>>>> ha ridotto la terapia diuretica]

> Some call it "pedantry", others "attention to detail" but don't forget 
> the closing square-bracket!

Although, looking at the OPs original post, he retained the closing
bracket...
But I think he did intend to remove them...
So either a slice, or better, rstrip('] ') will deal with those.


-- 
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 PyTutor at DancesWithMice.info  Wed Jan 29 19:35:12 2020
From: PyTutor at DancesWithMice.info (David L Neil)
Date: Thu, 30 Jan 2020 13:35:12 +1300
Subject: [Tutor] Remove some known text around text I need to keep
In-Reply-To: <r0t4iu$1232$2@ciao.gmane.io>
References: <etPan.5e31b4c3.7085dbbc.c7f@ralexander.it>
 <r0sju9$3qnu$1@ciao.gmane.io>
 <CADiDnXcmDG2g4paNmbO2h6LSVVaC2XgQGoVWuvs6Vwex-ahHmw@mail.gmail.com>
 <CAPM-O+xA5rV4zmZLcQNt44+UCK842AGmqt0m7DC-_ZnqHtdZ_g@mail.gmail.com>
 <ad404a80-14ea-e099-b8d9-fc2e2c4ba268@DancesWithMice.info>
 <r0t4iu$1232$2@ciao.gmane.io>
Message-ID: <157e9bfb-a48a-20c8-cd2b-3a0532a8a092@DancesWithMice.info>

On 30/01/20 12:30 PM, Alan Gauld via Tutor wrote:
> On 29/01/2020 22:05, DL Neil via Tutor wrote:
>>>>> [SINTOMO: paziente sintomatica per dispnea moderata]
>>>>> [SEGNO: Non edemi]
>>>>> [SEGNO: calo di 2 kg (55,8 kg)]
>>>>> [TERAPIA: ha ridotto la terapia diuretica]
>>>>
>>>>> the same lines as above what I need to write back in the new ?clean?
>>>> files are like the following:
>>>>
>>>>> paziente sintomatica per dispnea moderata]
>>>>> Non edemi]
>>>>> calo di 2 kg (55,8 kg)]
>>>>> ha ridotto la terapia diuretica]
> 
>> Some call it "pedantry", others "attention to detail" but don't forget
>> the closing square-bracket!
> 
> Although, looking at the OPs original post, he retained the closing
> bracket...
> But I think he did intend to remove them...
> So either a slice, or better, rstrip('] ') will deal with those.


Hah! You're correct - I read the word "tags". Further, the idea of using 
RegEx seemed to support the idea of finding "contents" rather than 
trimming a prefix...

In Italian, do parentheses, brackets, braces, etc, not come in pairs?
-- 
Regards =dn

From gogonegro at gmail.com  Thu Jan 30 02:06:20 2020
From: gogonegro at gmail.com (Robert Alexander)
Date: Thu, 30 Jan 2020 08:06:20 +0100
Subject: [Tutor] Remove some known text around text I need to keep
In-Reply-To: <157e9bfb-a48a-20c8-cd2b-3a0532a8a092@DancesWithMice.info>
References: <etPan.5e31b4c3.7085dbbc.c7f@ralexander.it>
 <r0sju9$3qnu$1@ciao.gmane.io>
 <CADiDnXcmDG2g4paNmbO2h6LSVVaC2XgQGoVWuvs6Vwex-ahHmw@mail.gmail.com>
 <CAPM-O+xA5rV4zmZLcQNt44+UCK842AGmqt0m7DC-_ZnqHtdZ_g@mail.gmail.com>
 <ad404a80-14ea-e099-b8d9-fc2e2c4ba268@DancesWithMice.info>
 <r0t4iu$1232$2@ciao.gmane.io>
 <157e9bfb-a48a-20c8-cd2b-3a0532a8a092@DancesWithMice.info>
Message-ID: <CADiDnXdfrEt1E4K2iOi-vH+m7VtkDh8=2qiOsHKxu2bu-VvYcA@mail.gmail.com>

Dear tutors,
thanks a lot for the input. It taught me a few new tricks :)

The OP just forgot to eliminate the closing square bracket in his example.
May he suffer consequences for this oversight! and yes we usually tend to
use parenthesis, whatever their shape, always in pairs, also in this
country ;)

A good day to all of you.

Robert

On 30 January 2020 at 01:35:41, David L Neil via Tutor (tutor at python.org)
wrote:

On 30/01/20 12:30 PM, Alan Gauld via Tutor wrote:
> On 29/01/2020 22:05, DL Neil via Tutor wrote:
>>>>> [SINTOMO: paziente sintomatica per dispnea moderata]
>>>>> [SEGNO: Non edemi]
>>>>> [SEGNO: calo di 2 kg (55,8 kg)]
>>>>> [TERAPIA: ha ridotto la terapia diuretica]
>>>>
>>>>> the same lines as above what I need to write back in the new ?clean?
>>>> files are like the following:
>>>>
>>>>> paziente sintomatica per dispnea moderata]
>>>>> Non edemi]
>>>>> calo di 2 kg (55,8 kg)]
>>>>> ha ridotto la terapia diuretica]
>
>> Some call it "pedantry", others "attention to detail" but don't forget
>> the closing square-bracket!
>
> Although, looking at the OPs original post, he retained the closing
> bracket...
> But I think he did intend to remove them...
> So either a slice, or better, rstrip('] ') will deal with those.


Hah! You're correct - I read the word "tags". Further, the idea of using
RegEx seemed to support the idea of finding "contents" rather than
trimming a prefix...

In Italian, do parentheses, brackets, braces, etc, not come in pairs?
-- 
Regards =dn
_______________________________________________
Tutor maillist - Tutor at python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor

From gogonegro at gmail.com  Thu Jan 30 02:29:40 2020
From: gogonegro at gmail.com (Robert Alexander)
Date: Thu, 30 Jan 2020 08:29:40 +0100
Subject: [Tutor] Namespaces in Python
Message-ID: <CADiDnXeEFzqY9Dkb_cgMxWOhPzZS0w3DFg1HwZLPY17MFV9fgA@mail.gmail.com>

Not 100% sure this is appropriate, if not please correct me and won?t do it
in the future but I thought some people on this list might like to know
about a very well written Medium article on namespaces in Python:
https://medium.com/better-programming/namespacing-with-python-79574d125564

From frahmanf89 at gmail.com  Thu Jan 30 12:22:19 2020
From: frahmanf89 at gmail.com (faslur rahman)
Date: Thu, 30 Jan 2020 20:22:19 +0300
Subject: [Tutor] Regarding learning python
Message-ID: <CAKhQZ=wjJ4QpX=tytGQXA268zhDE16YtotU3nZtXmfnvwDqFwQ@mail.gmail.com>

I am faslur rahman from Sri Lanka, last six months i was trying to learn
python programming by my self, But unfortunately i did not found any good
resource to learn about python. Even i try from python website, there I got
some books to refer and this email ID also.
can you please advise me where to learn python full course?.

Thank you

From suresh.gm at gmail.com  Thu Jan 30 15:23:47 2020
From: suresh.gm at gmail.com (Panchanathan Suresh)
Date: Thu, 30 Jan 2020 12:23:47 -0800
Subject: [Tutor] Input is Dictionary1,
 Output is Dictionary2 (using keys and values of Dictionary1)
Message-ID: <CACh5xi8XX73EuBrYpVUeaY-_hdBjxfwY_mnxd2Xh79gsFhuEPQ@mail.gmail.com>

Hi Everyone,

I spent a lot of time on this, trying out many things, but I am unable to
create a new dictionary with the users as keys and a list of their groups
as values.

Input Dictionary is {"local": ["admin", "userA"],"public":  ["admin",
"userB"],"administrator": ["admin"] }
Expected Output Dictionary is {"userA": ["admin","public"], "userB":
["admin"], "administrator": ["admin"]}

--- How to create an unique group for a particular user?
--- And then how to add this user key and the user's value (which will be
the list of groups the user belongs to)

*****
def groups_per_user(group_dictionary):
        user_groups = {}
        groups = []
        # Go through group_dictionary
        for group,user in group_dictionary.items():
                # Now go through the users in the group
                for user1 in user:
                        groups.append(group)
                        print(user1,groups)

        return(user_groups)

print(groups_per_user({"local": ["admin", "userA"],"public":  ["admin",
"userB"],"administrator": ["admin"] }))

*****

Thanks so much

From alan.gauld at yahoo.co.uk  Thu Jan 30 16:32:58 2020
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Thu, 30 Jan 2020 21:32:58 +0000
Subject: [Tutor] Regarding learning python
In-Reply-To: <CAKhQZ=wjJ4QpX=tytGQXA268zhDE16YtotU3nZtXmfnvwDqFwQ@mail.gmail.com>
References: <CAKhQZ=wjJ4QpX=tytGQXA268zhDE16YtotU3nZtXmfnvwDqFwQ@mail.gmail.com>
Message-ID: <r0vi2b$16t2$1@ciao.gmane.io>

On 30/01/2020 17:22, faslur rahman wrote:
> I am faslur rahman from Sri Lanka, last six months i was trying to learn
> python programming by my self, But unfortunately i did not found any good
> resource to learn about python.

It would help if you can be more specific about what was
wrong with the resources you tried.

Also what is your background? Can you program in other languages,
is it just python you ate struggling with? Or are you new to
programming itself, in which case there are a lot of concepts
to learn as well as how they are done in python.

>  Even i try from python website, there I got
> some books to refer and this email ID also.

The official tutorial is very good if you can already program
in another language. But it is not so good for total beginners.
Thats where the non programmers page comes into play...

> can you please advise me where to learn python full course?.

Well, obviously I can't resist the opportunity to push my
tutorial - see my signature below... :-)

And if you get stuck (in any tutorial, not just mine) ask
specific questions here. Send the code that doesn't work,
any errors you get, tell us what you expected to happen
and what did happen./ Then we can help/explain.

Also tell us whether you are using Python 2 or 3.
I strongly recommend using Python 3 and making sure
your chosen tutorial also uses 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 mats at wichmann.us  Thu Jan 30 16:47:15 2020
From: mats at wichmann.us (Mats Wichmann)
Date: Thu, 30 Jan 2020 14:47:15 -0700
Subject: [Tutor] Input is Dictionary1,
 Output is Dictionary2 (using keys and values of Dictionary1)
In-Reply-To: <CACh5xi8XX73EuBrYpVUeaY-_hdBjxfwY_mnxd2Xh79gsFhuEPQ@mail.gmail.com>
References: <CACh5xi8XX73EuBrYpVUeaY-_hdBjxfwY_mnxd2Xh79gsFhuEPQ@mail.gmail.com>
Message-ID: <f83118fb-1779-87e9-4054-fe8350c5c1c5@wichmann.us>

On 1/30/20 1:23 PM, Panchanathan Suresh wrote:
> Hi Everyone,
> 
> I spent a lot of time on this, trying out many things, but I am unable to
> create a new dictionary with the users as keys and a list of their groups
> as values.
> 
> Input Dictionary is {"local": ["admin", "userA"],"public":  ["admin",
> "userB"],"administrator": ["admin"] }
> Expected Output Dictionary is {"userA": ["admin","public"], "userB":
> ["admin"], "administrator": ["admin"]}
> 
> --- How to create an unique group for a particular user?
> --- And then how to add this user key and the user's value (which will be
> the list of groups the user belongs to)
> 
> *****
> def groups_per_user(group_dictionary):
>         user_groups = {}
>         groups = []
>         # Go through group_dictionary
>         for group,user in group_dictionary.items():
>                 # Now go through the users in the group
>                 for user1 in user:
>                         groups.append(group)
>                         print(user1,groups)
> 
>         return(user_groups)
> 
> print(groups_per_user({"local": ["admin", "userA"],"public":  ["admin",
> "userB"],"administrator": ["admin"] }))
> 
> *****

Hopefully this isn't a homework problem :)

You're not adding anything to your new dictionary. What you want to do
is use the user as a key, and a list of groups as the value; the trick
is that you may need to add several times to a user's entry, so you need
to handle both the case of "user not yet in dictionary" and the case of
"user has a grouplist, add to that list".  As a quick and dirty hack,
like this (I changed a name a bit for clarity):

    for group, userlist in group_dictionary.items():
        # Now go through the users in the group
        for user in userlist:
            try:
                user_groups[user].append(group)
            except KeyError:
                user_groups[user] = [group]


From PyTutor at DancesWithMice.info  Thu Jan 30 17:51:38 2020
From: PyTutor at DancesWithMice.info (David L Neil)
Date: Fri, 31 Jan 2020 11:51:38 +1300
Subject: [Tutor] Input is Dictionary1,
 Output is Dictionary2 (using keys and values of Dictionary1)
In-Reply-To: <CACh5xi8XX73EuBrYpVUeaY-_hdBjxfwY_mnxd2Xh79gsFhuEPQ@mail.gmail.com>
References: <CACh5xi8XX73EuBrYpVUeaY-_hdBjxfwY_mnxd2Xh79gsFhuEPQ@mail.gmail.com>
Message-ID: <c7c8d9fd-5c82-01e9-10a7-008bbf9aed5d@DancesWithMice.info>

Greetings Suresh!
What is your level of Python skill?
... skills with data structures?


On 31/01/20 9:23 AM, Panchanathan Suresh wrote:
> Hi Everyone,
> 
> I spent a lot of time on this, trying out many things, but I am unable to
> create a new dictionary with the users as keys and a list of their groups
> as values.
> 
> Input Dictionary is {"local": ["admin", "userA"],"public":  ["admin",
> "userB"],"administrator": ["admin"] }
> Expected Output Dictionary is {"userA": ["admin","public"], "userB":
> ["admin"], "administrator": ["admin"]}
> 
> --- How to create an unique group for a particular user?
> --- And then how to add this user key and the user's value (which will be
> the list of groups the user belongs to)
> 
> *****
> def groups_per_user(group_dictionary):
>          user_groups = {}
>          groups = []
>          # Go through group_dictionary
>          for group,user in group_dictionary.items():
>                  # Now go through the users in the group
>                  for user1 in user:
>                          groups.append(group)
>                          print(user1,groups)
> 
>          return(user_groups)
> 
> print(groups_per_user({"local": ["admin", "userA"],"public":  ["admin",
> "userB"],"administrator": ["admin"] }))
> 
> *****


This idea might be a bit more than you really want/are ready to try:

The problem with inheriting from dict and list in Python
https://treyhunner.com/2019/04/why-you-shouldnt-inherit-from-list-and-dict-in-python/

Although the article addresses a completely different set of interests, 
the example used is class TwoWayDict( ... ) which implements a dict 
having not only entries in the form key:value, but adds the 
complementary?inverted value:key.

He calls it "bi-directional": "When a key-value pair is added, the key 
maps to the value but the value also maps to the key.".

This is not *exactly* the spec in this post, in that Trey is using a 
single dict, but there is absolutely no reason why the article's 
solution(s) couldn't be extended so that the TwoWayDict class actually 
manages two dicts - one key:value and the other value:key.

This would then allow extension to the 1:m relationship*:
	forward_dict ~ key1:value1,value2,value3
	inverted_dict ~ value1:key1,key2
			value2:key2,key5
			...

The philosophical difference in this approach lies in the *assembling* 
of a data structure that it is prepared for future use/'ready for 
action'; rather than using the algorithmic 'translation' currently 
envisaged, in-between assembling the original dict, and being able to 
make use of its inversion!
ie the complexity is in the 'writing' to the dict (or 'loading' it), 
rather than in the 'reading' (or getting items from it)!

OTOH understanding and coding the above will require some 
reasonably-advanced Python knowledge and skills - hence the opening 
questions!


* apologies if this term is unfamiliar: "one to many relationship", 
refers to the idea that (here) one key may yield multiple values, cf 
"one to one", eg your ID/SocialSecurityNR which can only apply to you 
(and vice-versa).

NB PSL's collections.UserDict stores its (single dict) keys and values 
in a dict called "data" (IIRC). Thus adding a parallel, but reversed, 
dict, eg "inverse" should be quite smooth to implement.
(YMMV ? famous last words)
-- 
Regards =dn

From breamoreboy at gmail.com  Thu Jan 30 18:52:37 2020
From: breamoreboy at gmail.com (Mark Lawrence)
Date: Thu, 30 Jan 2020 23:52:37 +0000
Subject: [Tutor] Input is Dictionary1,
 Output is Dictionary2 (using keys and values of Dictionary1)
In-Reply-To: <CACh5xi8XX73EuBrYpVUeaY-_hdBjxfwY_mnxd2Xh79gsFhuEPQ@mail.gmail.com>
References: <CACh5xi8XX73EuBrYpVUeaY-_hdBjxfwY_mnxd2Xh79gsFhuEPQ@mail.gmail.com>
Message-ID: <r0vq86$1cvv$1@ciao.gmane.io>

On 30/01/2020 20:23, Panchanathan Suresh wrote:
> Hi Everyone,
> 
> I spent a lot of time on this, trying out many things, but I am unable to
> create a new dictionary with the users as keys and a list of their groups
> as values.
> 
> Input Dictionary is {"local": ["admin", "userA"],"public":  ["admin",
> "userB"],"administrator": ["admin"] }
> Expected Output Dictionary is {"userA": ["admin","public"], "userB":
> ["admin"], "administrator": ["admin"]}
> 

I have no idea what you're trying to achieve as your input key "local" 
doesn't appear in the output, your "public" key does and the 
"administrator": ["admin"] key/value pair appears in both.

-- 
My fellow Pythonistas, ask not what our language can do for you, ask
what you can do for our language.

Mark Lawrence


From dewshrs at gmail.com  Thu Jan 30 16:31:46 2020
From: dewshrs at gmail.com (Dewan Shrestha)
Date: Thu, 30 Jan 2020 15:31:46 -0600
Subject: [Tutor] Regarding learning python
In-Reply-To: <CAKhQZ=wjJ4QpX=tytGQXA268zhDE16YtotU3nZtXmfnvwDqFwQ@mail.gmail.com>
References: <CAKhQZ=wjJ4QpX=tytGQXA268zhDE16YtotU3nZtXmfnvwDqFwQ@mail.gmail.com>
Message-ID: <CAGMSKbMt4PfjaPCce2PEYUDO86AzqAEAXo_TiRKWdq=qswASwA@mail.gmail.com>

You can try coursera

On Thu, Jan 30, 2020 at 3:23 PM faslur rahman <frahmanf89 at gmail.com> wrote:

> I am faslur rahman from Sri Lanka, last six months i was trying to learn
> python programming by my self, But unfortunately i did not found any good
> resource to learn about python. Even i try from python website, there I got
> some books to refer and this email ID also.
> can you please advise me where to learn python full course?.
>
> Thank you
> _______________________________________________
> Tutor maillist  -  Tutor at python.org
> To unsubscribe or change subscription options:
> https://mail.python.org/mailman/listinfo/tutor
>

From suresh.gm at gmail.com  Thu Jan 30 18:10:59 2020
From: suresh.gm at gmail.com (Panchanathan Suresh)
Date: Thu, 30 Jan 2020 15:10:59 -0800
Subject: [Tutor] Input is Dictionary1,
 Output is Dictionary2 (using keys and values of Dictionary1)
In-Reply-To: <mailman.5126.1580424713.9275.tutor@python.org>
References: <mailman.5126.1580424713.9275.tutor@python.org>
Message-ID: <CACh5xi9xeB0cOncbPk+4xzQBURr9te+BOh+9uPjbaEPBkh_8qg@mail.gmail.com>

Thanks a lot Mats and David! I am not yet that familiar with data
structures.

This statement indeed works: user_groups[user].append(group)

But how can we use 'append' keyword for a dictionary? Is not append used
only for appending to a List?
Is it because Group is a already a List in the original dictionary? This is
a bit confusing...

Can we append to the list of dictionary values for a given key, using
Append command?


On Thu, Jan 30, 2020 at 2:52 PM <tutor-request at python.org> wrote:

> Send Tutor mailing list submissions to
>         tutor at python.org
>
> To subscribe or unsubscribe via the World Wide Web, visit
>         https://mail.python.org/mailman/listinfo/tutor
> or, via email, send a message with subject or body 'help' to
>         tutor-request at python.org
>
> You can reach the person managing the list at
>         tutor-owner at python.org
>
> When replying, please edit your Subject line so it is more specific
> than "Re: Contents of Tutor digest..."
> Today's Topics:
>
>    1. Regarding learning python (faslur rahman)
>    2. Input is Dictionary1, Output is Dictionary2 (using keys and
>       values of Dictionary1) (Panchanathan Suresh)
>    3. Re: Regarding learning python (Alan Gauld)
>    4. Re: Input is Dictionary1, Output is Dictionary2 (using keys
>       and values of Dictionary1) (Mats Wichmann)
>    5. Re: Input is Dictionary1, Output is Dictionary2 (using keys
>       and values of Dictionary1) (David L Neil)
>
>
>
> ---------- Forwarded message ----------
> From: faslur rahman <frahmanf89 at gmail.com>
> To: tutor at python.org
> Cc:
> Bcc:
> Date: Thu, 30 Jan 2020 20:22:19 +0300
> Subject: [Tutor] Regarding learning python
> I am faslur rahman from Sri Lanka, last six months i was trying to learn
> python programming by my self, But unfortunately i did not found any good
> resource to learn about python. Even i try from python website, there I got
> some books to refer and this email ID also.
> can you please advise me where to learn python full course?.
>
> Thank you
>
>
>
>
> ---------- Forwarded message ----------
> From: Panchanathan Suresh <suresh.gm at gmail.com>
> To: tutor at python.org
> Cc:
> Bcc:
> Date: Thu, 30 Jan 2020 12:23:47 -0800
> Subject: [Tutor] Input is Dictionary1, Output is Dictionary2 (using keys
> and values of Dictionary1)
> Hi Everyone,
>
> I spent a lot of time on this, trying out many things, but I am unable to
> create a new dictionary with the users as keys and a list of their groups
> as values.
>
> Input Dictionary is {"local": ["admin", "userA"],"public":  ["admin",
> "userB"],"administrator": ["admin"] }
> Expected Output Dictionary is {"userA": ["admin","public"], "userB":
> ["admin"], "administrator": ["admin"]}
>
> --- How to create an unique group for a particular user?
> --- And then how to add this user key and the user's value (which will be
> the list of groups the user belongs to)
>
> *****
> def groups_per_user(group_dictionary):
>         user_groups = {}
>         groups = []
>         # Go through group_dictionary
>         for group,user in group_dictionary.items():
>                 # Now go through the users in the group
>                 for user1 in user:
>                         groups.append(group)
>                         print(user1,groups)
>
>         return(user_groups)
>
> print(groups_per_user({"local": ["admin", "userA"],"public":  ["admin",
> "userB"],"administrator": ["admin"] }))
>
> *****
>
> Thanks so much
>
>
>
>
> ---------- Forwarded message ----------
> From: Alan Gauld <alan.gauld at yahoo.co.uk>
> To: tutor at python.org
> Cc:
> Bcc:
> Date: Thu, 30 Jan 2020 21:32:58 +0000
> Subject: Re: [Tutor] Regarding learning python
> On 30/01/2020 17:22, faslur rahman wrote:
> > I am faslur rahman from Sri Lanka, last six months i was trying to learn
> > python programming by my self, But unfortunately i did not found any good
> > resource to learn about python.
>
> It would help if you can be more specific about what was
> wrong with the resources you tried.
>
> Also what is your background? Can you program in other languages,
> is it just python you ate struggling with? Or are you new to
> programming itself, in which case there are a lot of concepts
> to learn as well as how they are done in python.
>
> >  Even i try from python website, there I got
> > some books to refer and this email ID also.
>
> The official tutorial is very good if you can already program
> in another language. But it is not so good for total beginners.
> Thats where the non programmers page comes into play...
>
> > can you please advise me where to learn python full course?.
>
> Well, obviously I can't resist the opportunity to push my
> tutorial - see my signature below... :-)
>
> And if you get stuck (in any tutorial, not just mine) ask
> specific questions here. Send the code that doesn't work,
> any errors you get, tell us what you expected to happen
> and what did happen./ Then we can help/explain.
>
> Also tell us whether you are using Python 2 or 3.
> I strongly recommend using Python 3 and making sure
> your chosen tutorial also uses 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
>
>
>
>
>
>
> ---------- Forwarded message ----------
> From: Mats Wichmann <mats at wichmann.us>
> To: tutor at python.org
> Cc:
> Bcc:
> Date: Thu, 30 Jan 2020 14:47:15 -0700
> Subject: Re: [Tutor] Input is Dictionary1, Output is Dictionary2 (using
> keys and values of Dictionary1)
> On 1/30/20 1:23 PM, Panchanathan Suresh wrote:
> > Hi Everyone,
> >
> > I spent a lot of time on this, trying out many things, but I am unable to
> > create a new dictionary with the users as keys and a list of their groups
> > as values.
> >
> > Input Dictionary is {"local": ["admin", "userA"],"public":  ["admin",
> > "userB"],"administrator": ["admin"] }
> > Expected Output Dictionary is {"userA": ["admin","public"], "userB":
> > ["admin"], "administrator": ["admin"]}
> >
> > --- How to create an unique group for a particular user?
> > --- And then how to add this user key and the user's value (which will be
> > the list of groups the user belongs to)
> >
> > *****
> > def groups_per_user(group_dictionary):
> >         user_groups = {}
> >         groups = []
> >         # Go through group_dictionary
> >         for group,user in group_dictionary.items():
> >                 # Now go through the users in the group
> >                 for user1 in user:
> >                         groups.append(group)
> >                         print(user1,groups)
> >
> >         return(user_groups)
> >
> > print(groups_per_user({"local": ["admin", "userA"],"public":  ["admin",
> > "userB"],"administrator": ["admin"] }))
> >
> > *****
>
> Hopefully this isn't a homework problem :)
>
> You're not adding anything to your new dictionary. What you want to do
> is use the user as a key, and a list of groups as the value; the trick
> is that you may need to add several times to a user's entry, so you need
> to handle both the case of "user not yet in dictionary" and the case of
> "user has a grouplist, add to that list".  As a quick and dirty hack,
> like this (I changed a name a bit for clarity):
>
>     for group, userlist in group_dictionary.items():
>         # Now go through the users in the group
>         for user in userlist:
>             try:
>                 user_groups[user].append(group)
>             except KeyError:
>                 user_groups[user] = [group]
>
>
>
>
>
> ---------- Forwarded message ----------
> From: David L Neil <PyTutor at danceswithmice.info>
> To: tutor at python.org
> Cc:
> Bcc:
> Date: Fri, 31 Jan 2020 11:51:38 +1300
> Subject: Re: [Tutor] Input is Dictionary1, Output is Dictionary2 (using
> keys and values of Dictionary1)
> Greetings Suresh!
> What is your level of Python skill?
> ... skills with data structures?
>
>
> On 31/01/20 9:23 AM, Panchanathan Suresh wrote:
> > Hi Everyone,
> >
> > I spent a lot of time on this, trying out many things, but I am unable to
> > create a new dictionary with the users as keys and a list of their groups
> > as values.
> >
> > Input Dictionary is {"local": ["admin", "userA"],"public":  ["admin",
> > "userB"],"administrator": ["admin"] }
> > Expected Output Dictionary is {"userA": ["admin","public"], "userB":
> > ["admin"], "administrator": ["admin"]}
> >
> > --- How to create an unique group for a particular user?
> > --- And then how to add this user key and the user's value (which will be
> > the list of groups the user belongs to)
> >
> > *****
> > def groups_per_user(group_dictionary):
> >          user_groups = {}
> >          groups = []
> >          # Go through group_dictionary
> >          for group,user in group_dictionary.items():
> >                  # Now go through the users in the group
> >                  for user1 in user:
> >                          groups.append(group)
> >                          print(user1,groups)
> >
> >          return(user_groups)
> >
> > print(groups_per_user({"local": ["admin", "userA"],"public":  ["admin",
> > "userB"],"administrator": ["admin"] }))
> >
> > *****
>
>
> This idea might be a bit more than you really want/are ready to try:
>
> The problem with inheriting from dict and list in Python
>
> https://treyhunner.com/2019/04/why-you-shouldnt-inherit-from-list-and-dict-in-python/
>
> Although the article addresses a completely different set of interests,
> the example used is class TwoWayDict( ... ) which implements a dict
> having not only entries in the form key:value, but adds the
> complementary?inverted value:key.
>
> He calls it "bi-directional": "When a key-value pair is added, the key
> maps to the value but the value also maps to the key.".
>
> This is not *exactly* the spec in this post, in that Trey is using a
> single dict, but there is absolutely no reason why the article's
> solution(s) couldn't be extended so that the TwoWayDict class actually
> manages two dicts - one key:value and the other value:key.
>
> This would then allow extension to the 1:m relationship*:
>         forward_dict ~ key1:value1,value2,value3
>         inverted_dict ~ value1:key1,key2
>                         value2:key2,key5
>                         ...
>
> The philosophical difference in this approach lies in the *assembling*
> of a data structure that it is prepared for future use/'ready for
> action'; rather than using the algorithmic 'translation' currently
> envisaged, in-between assembling the original dict, and being able to
> make use of its inversion!
> ie the complexity is in the 'writing' to the dict (or 'loading' it),
> rather than in the 'reading' (or getting items from it)!
>
> OTOH understanding and coding the above will require some
> reasonably-advanced Python knowledge and skills - hence the opening
> questions!
>
>
> * apologies if this term is unfamiliar: "one to many relationship",
> refers to the idea that (here) one key may yield multiple values, cf
> "one to one", eg your ID/SocialSecurityNR which can only apply to you
> (and vice-versa).
>
> NB PSL's collections.UserDict stores its (single dict) keys and values
> in a dict called "data" (IIRC). Thus adding a parallel, but reversed,
> dict, eg "inverse" should be quite smooth to implement.
> (YMMV ? famous last words)
> --
> Regards =dn
>
> _______________________________________________
> Tutor maillist  -  Tutor at python.org
> https://mail.python.org/mailman/listinfo/tutor
>

From alan.gauld at yahoo.co.uk  Thu Jan 30 19:37:10 2020
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Fri, 31 Jan 2020 00:37:10 +0000
Subject: [Tutor] Input is Dictionary1,
 Output is Dictionary2 (using keys and values of Dictionary1)
In-Reply-To: <CACh5xi9xeB0cOncbPk+4xzQBURr9te+BOh+9uPjbaEPBkh_8qg@mail.gmail.com>
References: <mailman.5126.1580424713.9275.tutor@python.org>
 <CACh5xi9xeB0cOncbPk+4xzQBURr9te+BOh+9uPjbaEPBkh_8qg@mail.gmail.com>
Message-ID: <r0vsrn$12nq$1@ciao.gmane.io>

On 30/01/2020 23:10, Panchanathan Suresh wrote:

> But how can we use 'append' keyword for a dictionary? Is not append used
> only for appending to a List?
> Is it because Group is a already a List in the original dictionary? This is
> a bit confusing...
> 
> Can we append to the list of dictionary values for a given key, using
> Append command?

Yes, because the list inside the dictionary is still a list, no
different to any other list. so you use the dictionary key to get a
reference to the list and then call the lists append method.

Note that append is not a keyword it is a method of the list object.
A keyword is something reserved by the language, like 'for', 'while',
'def' etc. The method or function names can be overridden.

for example, you could, if you wished, create your own print() function

def print(s):pass

that would hide the normal print. Then you couldn't print anything(*)!
Not very useful, but possible(in Python3) because print is just a
function name not a keyword.

(*)Actually you can by referencing the builtin function
via the __builtins__ module. But you get the idea, I hope.

-- 
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 mats at wichmann.us  Thu Jan 30 20:55:14 2020
From: mats at wichmann.us (Mats Wichmann)
Date: Thu, 30 Jan 2020 18:55:14 -0700
Subject: [Tutor] Regarding learning python
In-Reply-To: <r0vi2b$16t2$1@ciao.gmane.io>
References: <CAKhQZ=wjJ4QpX=tytGQXA268zhDE16YtotU3nZtXmfnvwDqFwQ@mail.gmail.com>
 <r0vi2b$16t2$1@ciao.gmane.io>
Message-ID: <4ee936d4-27dc-75dc-53f1-0d8ac0b429c5@wichmann.us>

On 1/30/20 2:32 PM, Alan Gauld via Tutor wrote:

> The official tutorial is very good if you can already program
> in another language. But it is not so good for total beginners.
> Thats where the non programmers page comes into play...

The problem with any recommendation any one of us could give is that
everyone learns differently. What works for some doesn't work for
others. Specifically, a vast number of really good Python programmers
have learned the language from the "official" tutorial, but I find parts
of it terrible now I look back at it.  For example, the chapter on
classes gets rolling by contrasting Python's approach to Smalltalk and
Modula-3. As if that would be of any actual use to almost anyone these
days. That sets a bad tone right off the bat - Modula-3? So What. I
really don't like pointing people at it any longer (Modula-3 not being
the main reason, of course).  I'd point to Alan's material over it, to
be sure :)

From PyTutor at DancesWithMice.info  Thu Jan 30 21:24:03 2020
From: PyTutor at DancesWithMice.info (David L Neil)
Date: Fri, 31 Jan 2020 15:24:03 +1300
Subject: [Tutor] Input is Dictionary1,
 Output is Dictionary2 (using keys and values of Dictionary1)
In-Reply-To: <CACh5xi9xeB0cOncbPk+4xzQBURr9te+BOh+9uPjbaEPBkh_8qg@mail.gmail.com>
References: <mailman.5126.1580424713.9275.tutor@python.org>
 <CACh5xi9xeB0cOncbPk+4xzQBURr9te+BOh+9uPjbaEPBkh_8qg@mail.gmail.com>
Message-ID: <747843ae-4197-3daa-6364-37a78c6b8baf@DancesWithMice.info>

On 31/01/20 12:10 PM, Panchanathan Suresh wrote:
> Thanks a lot Mats and David! I am not yet that familiar with data
> structures.

In which case the earlier suggestion of creating a 'clever class' was 
inappropriate for such a skill-level. Don't worry though, you'll get 
there...


> This statement indeed works: user_groups[user].append(group)

great!


> But how can we use 'append' keyword for a dictionary? Is not append used
> only for appending to a List?
> Is it because Group is a already a List in the original dictionary? This is
> a bit confusing...

More-so for us because the code has (presumably) changed since last 
shown to us!

Please copy-paste the (relevant part of the) code from your editor/the 
REPL into future email msgs (plus any err.msgs, if necessary).


> Can we append to the list of dictionary values for a given key, using
> Append command?

Please review Built-in Types 
(https://docs.python.org/3/library/stdtypes.html)


You will find that a list is a sequence type, whereas a dict is a 
mapping type.

What does this mean? Lists/sequences are intended to be accessed 
serially, ie one element at a time, one after the other. So, if you have 
a play-list of tunes/songs, the intent is to listen to one after the other.

Whereas dicts/maps are direct-access structures. In this case, if each 
song has a name or an ID, the individual song may be accessed, using its 
name as a "key", without (first) accessing every other (previous) element.


Note also that a list is comprised of elements which are individual 
values (objects), eg

 >>> l = [ 1,
	"b",
	3.14159
	]
 >>> len( l )
3

but a dict's elements come in pairs - there must be a "key" and a 
"value", eg

 >>> d = { "question":Suresh",
		"answer":"dn"
		}
 >>> len( d )
2


So, to access an individual element, because the structures are 
different, the access mechanisms must necessarily also differ:

 >>> l[ 1 ]
'b'

- the list is a "sequence" therefore we "address" the individual element 
by its "index", its position within the sequence (an integer, starting 
from zero).

 >>> d[ "question" ]
'Suresh'

- the dict is a "mapping" thus we identify the individual element using 
its key - the key "maps" directly to a particular element with no 
reference to any other elements 'before' or 'after' it in the dict.


Right, let's talk about "append"! The word means quite literally 'add to 
the end'. End of what? If we were talking about a shopping list, then 
'the end' is the last entry - so we write the new item at 'the bottom' 
of the shopping list (and don't forget to take the shopping list with 
you to the store!). So l.append( ... ) has meaning!

What about a dictionary? Let's say you have a (book) dictionary, but 
it's getting out-of-date with modern jargon or may not have the 
complicated, fancy, words we use in computer jargon. Say you want to add 
a new word to that dictionary. Would you write it on the last page? No, 
better to add it 'in the right place'. So, if the new word was 
"meta-class", you would want to locate it somewhere after "meat" and 
before "moat". Thus d.append() has NO meaning - at the end? Instead try:

d[ "meta-class" ] = "Class inheriting from type"

We are now back to the earlier term: "direct access". In addition to 
"retrieving" data directly/by key, we are able to "store" data directly 
as well!

Good news! We don't have to work-out where in the dict Python stores 
things, as long as we know the keys we want to use!


So, there are some "methods" which can be used with both lists and 
dicts, but there are others which can only be used with lists and not 
dicts, and yet more which can be used with dicts but not lists. 
Accordingly, it follows that lists have a particular purpose and dicts 
have another. (the earlier web.ref lists methods for each, and more)

Just the same as a Green-billed Coucal and a Kiwi are both birds (not 
quite data structures). Both have wings and thus a flap 'method'. So, 
you'd think they could both fly. Not true! Different purposes, different 
lives, different islands!


NB the descriptions (above) are just that. The contents of lists can be 
much more complex - and often are; plus the rules about what we can use 
as "keys" for a dict, are significantly more involved (for example).


Have you spotted Alan's tutorial, or looked at Python courses on 
coursera.org or edx.org? (all free-access!) They might help you to learn 
under-pinnings like data structures, as well as Python itself...
-- 
Regards =dn

From PyTutor at DancesWithMice.info  Thu Jan 30 21:25:45 2020
From: PyTutor at DancesWithMice.info (David L Neil)
Date: Fri, 31 Jan 2020 15:25:45 +1300
Subject: [Tutor] Regarding learning python
In-Reply-To: <CAGMSKbMt4PfjaPCce2PEYUDO86AzqAEAXo_TiRKWdq=qswASwA@mail.gmail.com>
References: <CAKhQZ=wjJ4QpX=tytGQXA268zhDE16YtotU3nZtXmfnvwDqFwQ@mail.gmail.com>
 <CAGMSKbMt4PfjaPCce2PEYUDO86AzqAEAXo_TiRKWdq=qswASwA@mail.gmail.com>
Message-ID: <aca3008e-9c78-64f3-7609-f55691155be5@DancesWithMice.info>

On 31/01/20 10:31 AM, Dewan Shrestha wrote:
> You can try coursera

Did you?
Which series of courses?
Please provide feedback...
-- 
Regards =dn

From PyTutor at DancesWithMice.info  Thu Jan 30 22:01:54 2020
From: PyTutor at DancesWithMice.info (David L Neil)
Date: Fri, 31 Jan 2020 16:01:54 +1300
Subject: [Tutor] Regarding learning python
In-Reply-To: <4ee936d4-27dc-75dc-53f1-0d8ac0b429c5@wichmann.us>
References: <CAKhQZ=wjJ4QpX=tytGQXA268zhDE16YtotU3nZtXmfnvwDqFwQ@mail.gmail.com>
 <r0vi2b$16t2$1@ciao.gmane.io>
 <4ee936d4-27dc-75dc-53f1-0d8ac0b429c5@wichmann.us>
Message-ID: <5073ad0c-7286-6038-5fb4-faf560739b19@DancesWithMice.info>

On 31/01/20 2:55 PM, Mats Wichmann wrote:
> On 1/30/20 2:32 PM, Alan Gauld via Tutor wrote:
> 
>> The official tutorial is very good if you can already program
>> in another language. But it is not so good for total beginners.
>> Thats where the non programmers page comes into play...
> 
> The problem with any recommendation any one of us could give is that
> everyone learns differently. What works for some doesn't work for
> others. Specifically, a vast number of really good Python programmers
> have learned the language from the "official" tutorial, but I find parts
> of it terrible now I look back at it.  For example, the chapter on
> classes gets rolling by contrasting Python's approach to Smalltalk and
> Modula-3. As if that would be of any actual use to almost anyone these
> days. That sets a bad tone right off the bat - Modula-3? So What. I
> really don't like pointing people at it any longer (Modula-3 not being
> the main reason, of course).  I'd point to Alan's material over it, to
> be sure :)


OK, so will you now tell us what was the (large) present Alan sent you 
for Christmas?
(joke)


You are absolutely correct. However, coders, and indeed systems 
programmers, rarely make the best tutors/user documentation authors - 
and after coding some update to Python (or a PSL library), how much time 
would be 'left over' for writing docs anyway? (thinking of a number of 
places where I've worked...) There is a Python project team dedicated to 
improving 'our documentation'. (who would no doubt appreciate any and 
all 'open source' contributions!)


Yes, it is intensely annoying to find design (only) rationale, eg we 
wanted this because SmallTalk had it, jtest, ... Such requires expansion 
in user docs - why did SmallTalk have it? So, say that! What advantages 
does it confer? etc, etc.

This goes 'double' when such blather (largely more to establish the 
author's 'credentials' than to enable the reader) appears in some 
article or tutorial, purporting to "explain".

That said, I take the feed from PlanetPython. The number of 'updates' 
which are announced, but which don't explain what the library actually 
does, is a frequent source of dismay (and motivation to hit the Del(ete) 
key!)


Imagine approaching a business-owner to justify porting feature-xyz from 
SmallTalk to Python? The process is flawed - and likely the project 
floored! The business-boys do have advice to offer though: to quickly 
grab attention, they talk about an "elevator pitch". 
(https://www.mindtools.com/pages/article/elevator-pitch.htm)


Sadly, writing 'grabbing' docs, ANN(nouncements), training courses, etc, 
is an under-stated skill (and one which too many of our 'authors', do 
not actually possess/exhibit).
-- 
Regards =dn

From robertvstepp at gmail.com  Thu Jan 30 22:56:39 2020
From: robertvstepp at gmail.com (boB Stepp)
Date: Thu, 30 Jan 2020 21:56:39 -0600
Subject: [Tutor] Corrupt file(s) likelihood and prevention?
Message-ID: <CANDiX9+GtH12vUK4mwjiXBF8_dR3UQcPyWLLxnN00WN0RwgBTA@mail.gmail.com>

I just finished reading a thread on the main list that got a little
testy.  The part that is piquing my interest was some discussion of
data files perhaps getting corrupted.  I have wondered about this off
and on.  First what is the likelihood nowadays of a file becoming
corrupted, and, second, what steps should one take to prevent/minimize
this from happening?  I notice that one of the applications I work
with at my job apparently uses checksums to detect when one of its
files gets modified from outside of the application.

-- 
boB

From cs at cskk.id.au  Fri Jan 31 00:01:34 2020
From: cs at cskk.id.au (Cameron Simpson)
Date: Fri, 31 Jan 2020 16:01:34 +1100
Subject: [Tutor] Corrupt file(s) likelihood and prevention?
In-Reply-To: <CANDiX9+GtH12vUK4mwjiXBF8_dR3UQcPyWLLxnN00WN0RwgBTA@mail.gmail.com>
References: <CANDiX9+GtH12vUK4mwjiXBF8_dR3UQcPyWLLxnN00WN0RwgBTA@mail.gmail.com>
Message-ID: <20200131050134.GA24378@cskk.homeip.net>

On 30Jan2020 21:56, boB Stepp <robertvstepp at gmail.com> wrote:
>I just finished reading a thread on the main list that got a little
>testy.  The part that is piquing my interest was some discussion of
>data files perhaps getting corrupted.  I have wondered about this off
>and on.  First what is the likelihood nowadays of a file becoming
>corrupted, and, second, what steps should one take to prevent/minimize
>this from happening?

I can't speak to specific likelihoods, but these days things should be 
pretty stable. Hard drives have long mean time to failure, memory is 
often ECC (eg fixing single bit errors and noticing mulitbit errors), 
and data sizes are large enough that if failures were common nothing 
would work. (Of course that goes both ways.) Some filesystems checksum 
their blocks (ZFS in particular sticks in my mind for this, and it is in 
its way a flexible RAID, meaning a bad block gets fixed from a good one 
as discovered).

>I notice that one of the applications I work
>with at my job apparently uses checksums to detect when one of its
>files gets modified from outside of the application.

That can often be worth doing. It depends on the app. If a file is 
modified outside the app then many things it may be assuming in its 
internal state may need discarding or checking (conceptually: flush 
cached knowledge).

Leaving aside system failures, there's also malice. In another life we 
used to checksum the OS files on a regular basis looking for changed 
files.

Cheers,
Cameron Simpson <cs at cskk.id.au>

From alan.gauld at yahoo.co.uk  Fri Jan 31 07:15:40 2020
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Fri, 31 Jan 2020 12:15:40 +0000
Subject: [Tutor] Corrupt file(s) likelihood and prevention?
In-Reply-To: <CANDiX9+GtH12vUK4mwjiXBF8_dR3UQcPyWLLxnN00WN0RwgBTA@mail.gmail.com>
References: <CANDiX9+GtH12vUK4mwjiXBF8_dR3UQcPyWLLxnN00WN0RwgBTA@mail.gmail.com>
Message-ID: <r115pc$32hs$1@ciao.gmane.io>

On 31/01/2020 03:56, boB Stepp wrote:
> I just finished reading a thread on the main list that got a little
> testy.  The part that is piquing my interest was some discussion of
> data files perhaps getting corrupted.  I have wondered about this off
> and on.  First what is the likelihood nowadays of a file becoming
> corrupted, 

The likelihood is 100% - if you wait long enough!
Corruption is caused by several things including the physical
deterioration of the media upon which it is stored. It can be
due to sun spot activity, local radiation sources, high
magnetic fields and heat related stress on the platters.

In addition there is corruption due to software misoperation.
Buffers filling or overflowing, power outages at the wrong
moment(either to the computer itself or to a card due to vibration)

The bottom line is that corruption is inevitable eventually.

But the average life of a file on a single device is not infinite,
and most files get moved around (another potential cause of
corruption of course!) Every time you copy or move a file to
a new location you effectively start the clock from zero.

And most files time out in their value too. So you get to
a point where nobody cares.

But if you do care, take backups. Corruption is real and not
going to go away any time soon. Modern storage devices and
technologies are vastly more reliable than they were 50 years
ago, or even 20 years ago. But nothing is foolproof.

> and, second, what steps should one take to prevent/minimize
> this from happening?  

Reliable disks, RAID configured, use checksums to detect it.
And backup, then backup your backups. And test that your
retrieval strategy works. (It is astonishing how many times
I've found sites where they took regular backups but never
actually tried restoring anything until it was too late.
Then discovered their retrieval mechanism was broken...)

> I notice that one of the applications I work
> with at my job apparently uses checksums to detect when one of its
> files gets modified from outside of the application.

A wise precaution for anything that needs to be checked, either for
modification by external systems or where any corruption is critical.
Remember that corruption is not always (not often!) fatal to a file.
If its just a single byte getting twiddled then it might just change
a value - Your bank balance switches from $1000 to $9000 or vice versa,
say! Checksums are about the only reliable way to detect those kinds of
corruption.
 But in the real world don't stress too much. It is a rare
occurrence and I've only had it cause real problems a dozen
or so times in 40 years. But when computers hold millions of
files, many of which are millions or even billions of bytes,
some corruption is bound to occur eventually.

-- 
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 PyTutor at danceswithmice.info  Fri Jan 31 18:20:11 2020
From: PyTutor at danceswithmice.info (DL Neil)
Date: Sat, 1 Feb 2020 12:20:11 +1300
Subject: [Tutor] Corrupt file(s) likelihood and prevention?
In-Reply-To: <CANDiX9+GtH12vUK4mwjiXBF8_dR3UQcPyWLLxnN00WN0RwgBTA@mail.gmail.com>
References: <CANDiX9+GtH12vUK4mwjiXBF8_dR3UQcPyWLLxnN00WN0RwgBTA@mail.gmail.com>
Message-ID: <c4169bca-ef4e-acbd-081d-ca9320e1997f@DancesWithMice.info>

On 31/01/20 4:56 PM, boB Stepp wrote:
> I just finished reading a thread on the main list that got a little
> testy.  The part that is piquing my interest was some discussion of
> data files perhaps getting corrupted.  I have wondered about this off
> and on.  First what is the likelihood nowadays of a file becoming
> corrupted, and, second, what steps should one take to prevent/minimize
> this from happening?  I notice that one of the applications I work
> with at my job apparently uses checksums to detect when one of its
> files gets modified from outside of the application.


Hi boB,
(I haven't looked at it again, since posting yesterday) Yes the thread 
did seem to become argumentative - unnecessarily (IMHO) because the 
'right answer' only exists in the OP's mind, not any of 'us'/ours. 
However...)

To put this question into the context of the original post, the issue 
was not so much the likelihood of a file becoming corrupt, per-se; it 
was a question of whether the mechanism of (one of) the proposed 
'solutions' exposed the user to an higher, or perhaps less-obvious, risk 
of corruption.

One idea was to keep a dynamic list within a (disk) file. As the program 
ran, this list would be extended and/or altered to record progress/success.

  - when a file is opened (+a or +w) it must be closed properly.

  - the OP specified being able to interrupt operation using Ctrl+c.

Put those two together and the risk becomes 'obvious' (to those with the 
experience/expertise to see it).

Some mitigation was offered.

As an alternative, using an RDBMS was suggested. This was disputed.

The other alternative (me causing 'trouble' again), was to query the 
need to use such a blunt instrument (Ctrl+c) to 'exit'.


So, if I've interpreted your interest correctly, the pertinent part of 
that (perhaps less apparent in your question) is: what can we do about 
the risk  of corruption, when files which may have been updated, have 
not been/cannot be, closed properly?


"Here be dragons!"
(and by that I don't mean that Alan is about to take you on a hike 
around Snowdonia/Wales...)
-- 
Regards =dn

From adam_slow at hotmail.com  Fri Jan 31 13:30:48 2020
From: adam_slow at hotmail.com (Adam Slowley)
Date: Fri, 31 Jan 2020 18:30:48 +0000
Subject: [Tutor] Printing Bold Text
Message-ID: <DM6PR07MB5020C8E7AF93D11DA881DA019E070@DM6PR07MB5020.namprd07.prod.outlook.com>

So I?m a beginner, learning Python for the first time so this might be a dumb question but here goes. I?m trying to print a text in bold. For example:

def main():
    name=input("Enter your name:")
    print("You entered for name a value of",name)

I want whatever the user inputs as his/her name to be printed in Bold


From adam_slow at hotmail.com  Fri Jan 31 19:04:42 2020
From: adam_slow at hotmail.com (Adam Slowley)
Date: Sat, 1 Feb 2020 00:04:42 +0000
Subject: [Tutor] Corrupt file(s) likelihood and prevention?
In-Reply-To: <c4169bca-ef4e-acbd-081d-ca9320e1997f@DancesWithMice.info>
References: <CANDiX9+GtH12vUK4mwjiXBF8_dR3UQcPyWLLxnN00WN0RwgBTA@mail.gmail.com>,
 <c4169bca-ef4e-acbd-081d-ca9320e1997f@DancesWithMice.info>
Message-ID: <DM6PR07MB5020C19C79160B3CB2765AE29E060@DM6PR07MB5020.namprd07.prod.outlook.com>

What is this ? I never asked about corrupt files

________________________________
From: Tutor <tutor-bounces+adam_slow=hotmail.com at python.org> on behalf of DL Neil via Tutor <tutor at python.org>
Sent: Friday, January 31, 2020 6:20:11 PM
To: tutor <tutor at python.org>
Subject: Re: [Tutor] Corrupt file(s) likelihood and prevention?

On 31/01/20 4:56 PM, boB Stepp wrote:
> I just finished reading a thread on the main list that got a little
> testy.  The part that is piquing my interest was some discussion of
> data files perhaps getting corrupted.  I have wondered about this off
> and on.  First what is the likelihood nowadays of a file becoming
> corrupted, and, second, what steps should one take to prevent/minimize
> this from happening?  I notice that one of the applications I work
> with at my job apparently uses checksums to detect when one of its
> files gets modified from outside of the application.


Hi boB,
(I haven't looked at it again, since posting yesterday) Yes the thread
did seem to become argumentative - unnecessarily (IMHO) because the
'right answer' only exists in the OP's mind, not any of 'us'/ours.
However...)

To put this question into the context of the original post, the issue
was not so much the likelihood of a file becoming corrupt, per-se; it
was a question of whether the mechanism of (one of) the proposed
'solutions' exposed the user to an higher, or perhaps less-obvious, risk
of corruption.

One idea was to keep a dynamic list within a (disk) file. As the program
ran, this list would be extended and/or altered to record progress/success.

  - when a file is opened (+a or +w) it must be closed properly.

  - the OP specified being able to interrupt operation using Ctrl+c.

Put those two together and the risk becomes 'obvious' (to those with the
experience/expertise to see it).

Some mitigation was offered.

As an alternative, using an RDBMS was suggested. This was disputed.

The other alternative (me causing 'trouble' again), was to query the
need to use such a blunt instrument (Ctrl+c) to 'exit'.


So, if I've interpreted your interest correctly, the pertinent part of
that (perhaps less apparent in your question) is: what can we do about
the risk  of corruption, when files which may have been updated, have
not been/cannot be, closed properly?


"Here be dragons!"
(and by that I don't mean that Alan is about to take you on a hike
around Snowdonia/Wales...)
--
Regards =dn
_______________________________________________
Tutor maillist  -  Tutor at python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor

From alan.gauld at yahoo.co.uk  Fri Jan 31 19:20:21 2020
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Sat, 1 Feb 2020 00:20:21 +0000
Subject: [Tutor] Corrupt file(s) likelihood and prevention?
In-Reply-To: <DM6PR07MB5020C19C79160B3CB2765AE29E060@DM6PR07MB5020.namprd07.prod.outlook.com>
References: <CANDiX9+GtH12vUK4mwjiXBF8_dR3UQcPyWLLxnN00WN0RwgBTA@mail.gmail.com>
 <c4169bca-ef4e-acbd-081d-ca9320e1997f@DancesWithMice.info>
 <DM6PR07MB5020C19C79160B3CB2765AE29E060@DM6PR07MB5020.namprd07.prod.outlook.com>
Message-ID: <r12g85$gq9$1@ciao.gmane.io>

On 01/02/2020 00:04, Adam Slowley wrote:
> What is this ? I never asked about corrupt files
> 
> ________________________________
> From: Tutor <tutor-bounces+adam_slow=hotmail.com at python.org> on behalf of DL Neil via Tutor <tutor at python.org>

You are subscribed to the list which means you get all of the
tutor emails, not just the ones you send/receive. That's how
we learn from each other - by being exposed to issues we may
not even have considered before.

If the traffic is too high for you then you have the option
of choosing to receive the digest instead if individual messages.
All of the same material but in a single message instead of
a stream.

-- 
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  Fri Jan 31 19:38:15 2020
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Sat, 1 Feb 2020 00:38:15 +0000
Subject: [Tutor] Printing Bold Text
In-Reply-To: <DM6PR07MB5020C8E7AF93D11DA881DA019E070@DM6PR07MB5020.namprd07.prod.outlook.com>
References: <DM6PR07MB5020C8E7AF93D11DA881DA019E070@DM6PR07MB5020.namprd07.prod.outlook.com>
Message-ID: <r12h9n$3tsm$1@ciao.gmane.io>

On 31/01/2020 18:30, Adam Slowley wrote:
> So I?m a beginner, learning Python for the first time so this might be a dumb question but here goes.

Not a dumb question, but a surprisingly difficult one.

>  I?m trying to print a text in bold. For example:
> 
> def main():
>     name=input("Enter your name:")
>     print("You entered for name a value of",name)
> 
> I want whatever the user inputs as his/her name to be printed in Bold

The solution to this is rather complex. Python reads and writes to
stdin/out on  the host computer. Python does not know anything about
what stdin/out are other than that it can send text to them or read text
from them. It could be an old style teleprinter, a VDT, a window within
a GUI(the most common these days) or a speech unit for the visually
impaired.

So python has no way of making text bold or otherwise - indeed in the
text reader case it is a meaningless concept, unless it shouted the bold
bits perhaps?

So how is bold text handled? It's down to the device and if that is a
typical text console in a GUI window then it will have a set of control
codes that affect how text is displayed. The three most common sets of
control codes are the VT100(Unix land), the 3270 (IBM mainframes) and
the ANSI terminal (from MS DOS). Once you know which terminal you are
using you can write those codes out. Let's assume you've looked up the
reference material and stored their values in some variables: BOLD and
NORMAL

Then you can do something like:

print(NORMAL, "Enter your name: ", BOLD)
name = input()
print(NORMAL)

That will switch the terminal between BOLD and NORMAL as required.
But its all a bit tedious and the minute your user switches
terminal then it breaks!

[ Note: It is slightly easier to do this in a GUI environment
because you can control the fonts used for the various parts
of the screen. So you could have the label asking for the name
use normal font and the entry box into which you type the reply
use a bold font. but then you have all the extra complexity
of building a GUI!]

As a response to this difficulty the curses library was created
in the 1980's(?) and it has been ported to most environments so
that you can use different font styles and even colours in a
non GUI terminal. It still requires writing out specific text
settings like the BOLD and NORMAL above but at least the codes
are standard and it will work across terminal types without
change. curses is a standard module with Python on MacOS and
Unix but not on Windows. (You need to download a third party
version for Windows, or use the cygwin version of Python).

Most of us just learn to live with not having bold/underline etc when
working in a terminal. It makes life much easier!

-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos



From cs at cskk.id.au  Fri Jan 31 21:05:21 2020
From: cs at cskk.id.au (Cameron Simpson)
Date: Sat, 1 Feb 2020 13:05:21 +1100
Subject: [Tutor] Corrupt file(s) likelihood and prevention?
In-Reply-To: <r12g85$gq9$1@ciao.gmane.io>
References: <r12g85$gq9$1@ciao.gmane.io>
Message-ID: <20200201020521.GA6289@cskk.homeip.net>

On 01Feb2020 00:20, Alan Gauld <alan.gauld at yahoo.co.uk> wrote:
>On 01/02/2020 00:04, Adam Slowley wrote:
>> What is this ? I never asked about corrupt files
>> ________________________________
>> From: Tutor <tutor-bounces+adam_slow=hotmail.com at python.org> on behalf of DL Neil via Tutor <tutor at python.org>
>
>You are subscribed to the list which means you get all of the
>tutor emails, not just the ones you send/receive. That's how
>we learn from each other - by being exposed to issues we may
>not even have considered before.
>
>If the traffic is too high for you then you have the option
>of choosing to receive the digest instead if individual messages.
>All of the same material but in a single message instead of
>a stream.

BTW, I discourage this approach. Far better to have your mailer filter 
the tutor messages off into their own folder. Replying to digests brings 
much pain for all, because replies are not direct replies to a specific 
message.

Cheers,
Cameron Simpson <cs at cskk.id.au>