From phillor9 at gmail.com  Wed Dec  1 01:24:58 2021
From: phillor9 at gmail.com (Phil)
Date: Wed, 1 Dec 2021 17:24:58 +1100
Subject: [Tutor] pylint(too-many-nested-blocks)
In-Reply-To: <34dc6d5f-99f7-7826-95f3-1e5965ddfb87@DancesWithMice.info>
References: <2c34791d-dc21-4070-82d2-1c98d67616ce@gmail.com>
 <703ee90c-2d81-5ea3-91aa-7b2a399e4531@DancesWithMice.info>
 <c58dda6d-2da8-8993-787f-77b69314ecf4@gmail.com>
 <34dc6d5f-99f7-7826-95f3-1e5965ddfb87@DancesWithMice.info>
Message-ID: <2306a13a-99e0-39b6-dd10-29c3d2381f45@gmail.com>

Thank you again dn, Cameron and Alex for more useful information and links.


> OTOH, the non-practical pursuit of perfection leads to one never being
> 'finished'!

That's why I revisited this project. Indecently, I've reduced the 
complexity of the function that I posted by splitting it into two and, 
as a bonus, I cured a problem that prevented the code from breaking out 
of a nested loop. I do remember reading somewhere many years ago that a 
function should fit onto a screen without scrolling. That's about 20 
lines in my case.


> There are (apparently) employers who will look at your portfolio of work
> (should you ever be applying for such a job),

Not at my age, thankfully.


> Incidentally, there's an impression that you've adopted a 'grey gypsy'
> life-style.
That's correct. My wife and I first hit the road during May 2005.
>   However, if you can gain decent Internet access, perhaps an
> online course might confer similar additional/alternate benefit?

While I haven't enrolled in any on-line courses while travelling I have 
completed one rather lengthy course of Python exercises. I do have an 
extensive range of mostly dated on-line books, however, having them and 
reading them is not the same thing.


> I cheerfully blather-on about pytest and TDD.

I know of pytest, although I've never looked into it's use. Something 
else to study.


> Are you using an IDE such as PyCharm or Codium (the F/LOSS-y alternative
> to VS-Code)?

I've tried several IDEs over the years and have settled on VS Code. I 
only use a small fraction of it's capabilities and I do like it's 
debugger. I still use IDLE if I want to test something simple and I do 
find it's debugger to be useful.


> (https://www.youtube.com/watch?v=UANN2Eu6ZnM) Well worth the time - and
> maybe you have a YouTube downloader if Internet-reliability is an issue..
Two of my favourite down-loaders are Firefox plug-ins.
> Back to the earlier question about IDEs. I'm using PyCharm at the moment

I have used the community version but VS Code's all-in-one features won 
me over.

-- 

Regards,
Phil


From phillor9 at gmail.com  Wed Dec  1 01:32:10 2021
From: phillor9 at gmail.com (Phil)
Date: Wed, 1 Dec 2021 17:32:10 +1100
Subject: [Tutor] pylint(too-many-nested-blocks)
In-Reply-To: <YabbqlyAl9mGdPnG@cskk.homeip.net>
References: <c58dda6d-2da8-8993-787f-77b69314ecf4@gmail.com>
 <YabbqlyAl9mGdPnG@cskk.homeip.net>
Message-ID: <228d8097-c645-e85a-4de8-c80a7e2863d6@gmail.com>

Thanks Cameron.
> Doctest is pretty simple, though it lends itself mostly to pretty simple
> tests.

Simple is good and I see that there are lots of tutorials on it's use. 
That and reducing cylomatic complexity will keep me occupied for quite 
some time.

-- 

Regards,
Phil


From PyTutor at DancesWithMice.info  Wed Dec  1 03:38:52 2021
From: PyTutor at DancesWithMice.info (dn)
Date: Wed, 1 Dec 2021 21:38:52 +1300
Subject: [Tutor] OT:  pylint(too-many-nested-blocks)
In-Reply-To: <2306a13a-99e0-39b6-dd10-29c3d2381f45@gmail.com>
References: <2c34791d-dc21-4070-82d2-1c98d67616ce@gmail.com>
 <703ee90c-2d81-5ea3-91aa-7b2a399e4531@DancesWithMice.info>
 <c58dda6d-2da8-8993-787f-77b69314ecf4@gmail.com>
 <34dc6d5f-99f7-7826-95f3-1e5965ddfb87@DancesWithMice.info>
 <2306a13a-99e0-39b6-dd10-29c3d2381f45@gmail.com>
Message-ID: <1f6d0f42-7fdf-d8d4-8e9d-dc20df49bc28@DancesWithMice.info>

>> Incidentally, there's an impression that you've adopted a 'grey gypsy'
>> life-style.
> That's correct. My wife and I first hit the road during May 2005.
>> ? However, if you can gain decent Internet access, perhaps an
>> online course might confer similar additional/alternate benefit?


In case you speak Python better than "Oz" (or "Oztrarlian") the slang
term: "grey gypsy" (amongst others), refers to the significant number of
retirees/superannuitants/pensioners who have traded suburbia for a
mobile-home, camper-van, or caravan; and are enjoying their 'twilight
years' in travel, new experiences, meeting new people, ...

Something else which is likely to surprise, is that Australia (by
itself) offers a huge expanse in which to travel. The "How big is
Australia" web page
(https://www.virtualoceania.net/australia/maps/how-big-is-australia.shtml)
overlays maps of Europe and USA for direct-comparison.
-- 
Regards,
=dn

From joao.oliveira at ufob.edu.br  Wed Dec  1 09:23:48 2021
From: joao.oliveira at ufob.edu.br (Joao Carlos Silva de Oliveira Matos)
Date: Wed, 1 Dec 2021 11:23:48 -0300
Subject: [Tutor] Send SOAP to Proxy
In-Reply-To: <YaaaXYq3kE479ht1@cskk.homeip.net>
References: <CAN8ghrBK0Ri6yNGKtaxGD4+tOF7+c=kFZoL4Z-ep9Eji1ZBYFw@mail.gmail.com>
 <YaaaXYq3kE479ht1@cskk.homeip.net>
Message-ID: <CAN8ghrBKybfCBPCV_c6dJxeOEZ5Ek=pvGnioXLOKnk8tO40OgQ@mail.gmail.com>

It does, but I get the 200 message saying that my IP is not allowed. I'm
starting to think that's it's an issue with the VPN not allowing me to
request to the WebService. But I do need to pass through the proxy because
it's the only client that can receive the data.

Em ter., 30 de nov. de 2021 ?s 19:35, Cameron Simpson <cs at cskk.id.au>
escreveu:

> On 29Nov2021 18:59, Joao Carlos Silva de Oliveira Matos <
> joao.oliveira at ufob.edu.br> wrote:
> >I've been trying to access a WSDL Service via a SOAP protocol. But first I
> >need to get to a proxy in my University because the server will only
> accept
> >it as a client.
>
> Skipping the complexities of the library, if it is using the builtin
> Python libraries underneath I expect it to honour the normal environment
> variables $http_proxy and $https_proxy, meaning your code does not need
> to specify a proxy.
>
> If you set these in your environment and try your code with no proxy
> specification in it, do things work?
>
> Bourne shell syntax to set these:
>
>     http_proxy='http://proxy-ip-adress:8080'
>     https_proxy='http://proxy-ip-adress:8080'
>     export http_proxy https_proxy
>
> If you set them in your environment, do things work (provided you strip
> the settings out of the inline code itself i.e. comment out the
> "session.proxies" stuff?
>
> Cheers,Cameron Simpson <cs at cskk.id.au>
> _______________________________________________
> Tutor maillist  -  Tutor at python.org
> To unsubscribe or change subscription options:
> https://mail.python.org/mailman/listinfo/tutor
>


-- 
[image: Ficheiro:Bras?o da UFOB.png ? Wikip?dia, a enciclop?dia livre]
Jo?o Carlos Silva de Oliveira Matos
Bolsista de Inova??o e Tecnologia
PROFNIT - Centro das Humanidades - UFOB
Mat. 2020100150

From cs at cskk.id.au  Wed Dec  1 15:29:27 2021
From: cs at cskk.id.au (Cameron Simpson)
Date: Thu, 2 Dec 2021 07:29:27 +1100
Subject: [Tutor] Send SOAP to Proxy
In-Reply-To: <CAN8ghrBKybfCBPCV_c6dJxeOEZ5Ek=pvGnioXLOKnk8tO40OgQ@mail.gmail.com>
References: <CAN8ghrBKybfCBPCV_c6dJxeOEZ5Ek=pvGnioXLOKnk8tO40OgQ@mail.gmail.com>
Message-ID: <YafbJ/+/vcLUZ4T9@cskk.homeip.net>

On 01Dec2021 11:23, Joao Carlos Silva de Oliveira Matos <joao.oliveira at ufob.edu.br> wrote:
>It does, but I get the 200 message saying that my IP is not allowed.

Does it tell you which IP it thinks you have? If it is your own IP then 
the proxy settings are probably being ignored.

>I'm
>starting to think that's it's an issue with the VPN not allowing me to
>request to the WebService.

If you're gettings a 200 response then you're probably talking to the 
web service.

>But I do need to pass through the proxy because
>it's the only client that can receive the data.

I'd start with a little lower level testing first, maybe using wget or 
curl command line tools to manually do a single SOAP request. They both 
honour proxy setting environment variables and also accept command line 
arguments to specify it. That should let you see different behaviours 
with different settings.

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

From joao.oliveira at ufob.edu.br  Wed Dec  1 15:54:54 2021
From: joao.oliveira at ufob.edu.br (Joao Carlos Silva de Oliveira Matos)
Date: Wed, 1 Dec 2021 17:54:54 -0300
Subject: [Tutor] Send SOAP to Proxy
In-Reply-To: <YafbJ/+/vcLUZ4T9@cskk.homeip.net>
References: <CAN8ghrBKybfCBPCV_c6dJxeOEZ5Ek=pvGnioXLOKnk8tO40OgQ@mail.gmail.com>
 <YafbJ/+/vcLUZ4T9@cskk.homeip.net>
Message-ID: <CAN8ghrAmzme=oh_DGSwuPF7coAYnZauv++s3VRg5g_iZZ9XCKA@mail.gmail.com>

NIce tip, I'm gonna do it the next time.

Em qua., 1 de dez. de 2021 ?s 17:31, Cameron Simpson <cs at cskk.id.au>
escreveu:

> On 01Dec2021 11:23, Joao Carlos Silva de Oliveira Matos <
> joao.oliveira at ufob.edu.br> wrote:
> >It does, but I get the 200 message saying that my IP is not allowed.
>
> Does it tell you which IP it thinks you have? If it is your own IP then
> the proxy settings are probably being ignored.
>
> >I'm
> >starting to think that's it's an issue with the VPN not allowing me to
> >request to the WebService.
>
> If you're gettings a 200 response then you're probably talking to the
> web service.
>
> >But I do need to pass through the proxy because
> >it's the only client that can receive the data.
>
> I'd start with a little lower level testing first, maybe using wget or
> curl command line tools to manually do a single SOAP request. They both
> honour proxy setting environment variables and also accept command line
> arguments to specify it. That should let you see different behaviours
> with different settings.
>
> Cheers,
> Cameron Simpson <cs at cskk.id.au>
> _______________________________________________
> Tutor maillist  -  Tutor at python.org
> To unsubscribe or change subscription options:
> https://mail.python.org/mailman/listinfo/tutor
>


-- 
[image: Ficheiro:Bras?o da UFOB.png ? Wikip?dia, a enciclop?dia livre]
Jo?o Carlos Silva de Oliveira Matos
Bolsista de Inova??o e Tecnologia
PROFNIT - Centro das Humanidades - UFOB
Mat. 2020100150

From phillor9 at gmail.com  Wed Dec  1 19:24:57 2021
From: phillor9 at gmail.com (Phil)
Date: Thu, 2 Dec 2021 11:24:57 +1100
Subject: [Tutor] function return values
Message-ID: <82a53068-6e6d-2038-cf8c-f297a0419c19@gmail.com>

I was quite pleased with myself that I had reduced the complexity of a 
function until I tried to reuse the same code elsewhere. I had the 
return values set to some dummy values and that was good in this case. 
However, this idea failed when I tried to test if the pairs are in the 
same column. So, what is the correct way to handle a case where there 
isn't a valid pair, row or list value to return?

 ??? def boxPairsInSameRow(self, pairs, x, y):
 ??????? col_list = []

 ??????? for item, count in pairs.items():
 ??????????? if count == 2:? # then item is a pair candidate
 ??????????????? for row in range(x, x + 3):
 ??????????????????? col_list = []
 ??????????????????? for col in range(y, y + 3):
 ??????????????????????? if item in self.solution[row][col]:
 ??????????????????????????? col_list.append(col)
 ??????????????????? return item, row, col_list
 ??????? return None, None, None # item, row and col_list were 
originally dummy values

This is the calling function:

 ??????????? item, row, column_list = 
self.boxPairsInSameRow(candidate_pairs, x , y)
 ??????????? if item is not None and row is not None and column_list is 
not None:
 ??????????? ??? do this only if the returned values are valid. In other 
words, this is a pair in a row.

Maybe the boxPairsInSameRow function is still too complex? The aim is to 
feed in the pairs, from a counter dictionary, and the row and column 
starting coordinates and have it return the pairs.item, the row that the 
item is on and a list containing the two columns for that row position. 
Once the pairs have been found on a row then there is no need to search 
the remaining row or rows.

It all sounds simple, however, evidently it's not simple enough.

-- 
Regards,
Phil


From PyTutor at DancesWithMice.info  Wed Dec  1 22:34:52 2021
From: PyTutor at DancesWithMice.info (dn)
Date: Thu, 2 Dec 2021 16:34:52 +1300
Subject: [Tutor] function return values
In-Reply-To: <82a53068-6e6d-2038-cf8c-f297a0419c19@gmail.com>
References: <82a53068-6e6d-2038-cf8c-f297a0419c19@gmail.com>
Message-ID: <34ce759a-a45e-21cc-0705-c210cbacaa63@DancesWithMice.info>

On 02/12/2021 13.24, Phil wrote:
> I was quite pleased with myself that I had reduced the complexity of a
> function until I tried to reuse the same code elsewhere. I had the
> return values set to some dummy values and that was good in this case.
> However, this idea failed when I tried to test if the pairs are in the
> same column. So, what is the correct way to handle a case where there
> isn't a valid pair, row or list value to return?
> 
> ??? def boxPairsInSameRow(self, pairs, x, y):
> ??????? col_list = []
> 
> ??????? for item, count in pairs.items():
> ??????????? if count == 2:? # then item is a pair candidate
> ??????????????? for row in range(x, x + 3):
> ??????????????????? col_list = []
> ??????????????????? for col in range(y, y + 3):
> ??????????????????????? if item in self.solution[row][col]:
> ??????????????????????????? col_list.append(col)
> ??????????????????? return item, row, col_list
> ??????? return None, None, None # item, row and col_list were originally
> dummy values
> 
> This is the calling function:
> 
> ??????????? item, row, column_list =
> self.boxPairsInSameRow(candidate_pairs, x , y)
> ??????????? if item is not None and row is not None and column_list is
> not None:
> ??????????? ??? do this only if the returned values are valid. In other
> words, this is a pair in a row.
> 
> Maybe the boxPairsInSameRow function is still too complex? The aim is to
> feed in the pairs, from a counter dictionary, and the row and column
> starting coordinates and have it return the pairs.item, the row that the
> item is on and a list containing the two columns for that row position.
> Once the pairs have been found on a row then there is no need to search
> the remaining row or rows.
> 
> It all sounds simple, however, evidently it's not simple enough.


Suggest creating another function which returns a boolean. Then use that
to initiate (or not) the scan. Perhaps along these lines:

if is_pair_in_row( item, row, column_list ):
    ( item,
      row,
      column_list,
      ) = self.boxPairsInSameRow(candidate_pairs, x , y)


which requires:

def is_pair_in_row( item, row, column_list ):
    """Docstring."""
    return item and row and column_list

NB am not guaranteeing that I have understood which
argument/parameter/identifier goes where!

NBB asking "if xyz" is the same as "if xyz is not None" - a concept
known as "truthiness" (falsiness)

NBBB Python's PEP-008 (a guide (maybe) and not a "standard") for naming
identifiers and functions:

box_pairs_in_same_row()


-- 
Regards,
=dn

From wlfraed at ix.netcom.com  Thu Dec  2 00:00:05 2021
From: wlfraed at ix.netcom.com (Dennis Lee Bieber)
Date: Thu, 02 Dec 2021 00:00:05 -0500
Subject: [Tutor] Non sequitur -- Re: function return values
References: <82a53068-6e6d-2038-cf8c-f297a0419c19@gmail.com>
 <34ce759a-a45e-21cc-0705-c210cbacaa63@DancesWithMice.info>
Message-ID: <lekgqgpesvtvgrdshuokhjqdjs74ka2hqi@4ax.com>

On Thu, 2 Dec 2021 16:34:52 +1300, dn via Tutor <tutor at python.org>
declaimed the following:


>NB am not guaranteeing that I have understood which
>argument/parameter/identifier goes where!
>
>NBB asking "if xyz" is the same as "if xyz is not None" - a concept
>known as "truthiness" (falsiness)
>
>NBBB Python's PEP-008 (a guide (maybe) and not a "standard") for naming
>identifiers and functions:
>
>box_pairs_in_same_row()

	Since NB -> nota bene translates as "note well", NBB would be "note
well well" etc. Seems that "NNB" would be more correct for emphasis --
"note note well" <G>

	Though in truth, I doubt this follows the pattern of PS -> post script,
in which PPS -> post post script does make logical sense (vs PSS -> post
script script)


-- 
	Wulfraed                 Dennis Lee Bieber         AF6VN
	wlfraed at ix.netcom.com    http://wlfraed.microdiversity.freeddns.org/


From PyTutor at DancesWithMice.info  Thu Dec  2 00:57:39 2021
From: PyTutor at DancesWithMice.info (dn)
Date: Thu, 2 Dec 2021 18:57:39 +1300
Subject: [Tutor] Non sequitur -- Re: function return values
In-Reply-To: <lekgqgpesvtvgrdshuokhjqdjs74ka2hqi@4ax.com>
References: <82a53068-6e6d-2038-cf8c-f297a0419c19@gmail.com>
 <34ce759a-a45e-21cc-0705-c210cbacaa63@DancesWithMice.info>
 <lekgqgpesvtvgrdshuokhjqdjs74ka2hqi@4ax.com>
Message-ID: <0a8492a8-86d3-550b-702e-4edb16fbf5a8@DancesWithMice.info>



On 02/12/2021 18.00, Dennis Lee Bieber wrote:
> On Thu, 2 Dec 2021 16:34:52 +1300, dn via Tutor <tutor at python.org>
> declaimed the following:
> 
> 
>> NB am not guaranteeing that I have understood which
>> argument/parameter/identifier goes where!
>>
>> NBB asking "if xyz" is the same as "if xyz is not None" - a concept
>> known as "truthiness" (falsiness)
>>
>> NBBB Python's PEP-008 (a guide (maybe) and not a "standard") for naming
>> identifiers and functions:
>>
>> box_pairs_in_same_row()
> 
> 	Since NB -> nota bene translates as "note well", NBB would be "note
> well well" etc. Seems that "NNB" would be more correct for emphasis --
> "note note well" <G>
> 
> 	Though in truth, I doubt this follows the pattern of PS -> post script,
> in which PPS -> post post script does make logical sense (vs PSS -> post
> script script)


In many languages, repetition indicates a superior form. Also, in Linux,
as you likely know, -v requests a verbose output, and some systems offer
the opportunity to select -vv, ie an even more verbose/illustrative output.

Back to English, you may remember:

There was a little girl, Who had a little curl,
Right in the middle of her forehead.
And when she was good, She was very, very good.
But when she was bad, She was horrid.

(and here I'm likely to land into more trans-Atlantic dispute) but
whereas some Americans attribute it to Longfellow, it was likely a
British nursery rhyme more than 150-years ago.
- cue @Alan

Perhaps I'll sail close to the wind of the Python CofP when I say that I
prefer (the idea of meeting someone espousing) the Mae West variation:

?When I'm good, I'm very good, but when I'm bad, I'm better.?

This device was used to great effect in a British TV series (don't know
if it still runs) called "The Vicar of Dibley". One of the
aged-characters had a bad stutter, and it was a running-joke (repeated,
programme after programme - NB British spelling!!!) to have him say "no,
no, no, no, -pause-, yes" (or was it vice-versa?). At first, you would
interpret him to be emphatic in his negative expression, only to find
that he really means the exact opposite.


In Hindi, the famous imperious phrase was "chaldi, chaldi!" (EN:
quickly, quickly - or hurry, hurry).

In Tok Pisin, younger children could be "lik, lik" (EN: little, little -
or smaller than little).

In French we add emphasis or indicate enthusiasm with repetition, such
as "tr?s, tr?s bien" (EN: very, very, good), and a similar device exists
in other human-languages.

Further replies 'here' will likely form a catalog of such...


To bring us back to something remotely approaching 'the topic', and
given our habit of writing loops/iterating, can these be restated as:

"To err is human, but to really foul things up, you need a computer!"


Thus, aligning repetition to emphasis, I'd go with your pattern - repeat
the second letter/word.

As NB = Nota Bene; and taking "bene" as (still, after all the centuries)
"well" or "good" in modern Italian, I'd stick with NBB = Nota Bene Bene,
as 'note very well'.

However, the 'bottom line', or en-fin (EN: at the end), which appears in
EN:AU as "at the end of the day", should you prefer, the adding of "B"s
was only to distinguish each of a series of notes from one-another.


In future, I'll list them as NB1, NB2, etc.

Oh wait, won't that start you into a debate about zero-based indexing?


It doesn't take much to amuse my (small) mind!
-- 
-- 
Regards,
=dn

From cs at cskk.id.au  Thu Dec  2 02:16:46 2021
From: cs at cskk.id.au (Cameron Simpson)
Date: Thu, 2 Dec 2021 18:16:46 +1100
Subject: [Tutor] function return values
In-Reply-To: <82a53068-6e6d-2038-cf8c-f297a0419c19@gmail.com>
References: <82a53068-6e6d-2038-cf8c-f297a0419c19@gmail.com>
Message-ID: <Yahy3u9s3KAScEhe@cskk.homeip.net>

On 02Dec2021 11:24, Phil <phillor9 at gmail.com> wrote:
>I was quite pleased with myself that I had reduced the complexity of a 
>function until I tried to reuse the same code elsewhere. I had the 
>return values set to some dummy values and that was good in this case. 
>However, this idea failed when I tried to test if the pairs are in the 
>same column. So, what is the correct way to handle a case where there 
>isn't a valid pair, row or list value to return?
>
>??? def boxPairsInSameRow(self, pairs, x, y):
>??????? col_list = []
>??????? for item, count in pairs.items():
>??????????? if count == 2:? # then item is a pair candidate
>??????????????? for row in range(x, x + 3):
>??????????????????? col_list = []
>??????????????????? for col in range(y, y + 3):
>??????????????????????? if item in self.solution[row][col]:
>??????????????????????????? col_list.append(col)
>??????????????????? return item, row, col_list
>??????? return None, None, None # item, row and col_list were 
>originally dummy values
>
>This is the calling function:
>
>??????????? item, row, column_list = 
>self.boxPairsInSameRow(candidate_pairs, x , y)
>??????????? if item is not None and row is not None and column_list is 
>not None:
>??????????? ??? do this only if the returned values are valid. In 
>other words, this is a pair in a row.
>
>Maybe the boxPairsInSameRow function is still too complex? The aim is 
>to feed in the pairs, from a counter dictionary, and the row and 
>column starting coordinates and have it return the pairs.item, the row 
>that the item is on and a list containing the two columns for that row 
>position. Once the pairs have been found on a row then there is no need 
>to search the remaining row or rows.

For a function returning a valid result or no result you have two main 
approaches in Python:
- return the result or None (or None-ish, as you are doing)
- return the result or raise a ValueError("no solution found")

The former requires a test by the caller. The latter means you need to 
catch an exception for "no solution". Wordier, but it might mean you can 
defer that to more outer pieces of the code, or not catch it at all if 
this programme should always find a solution.

The exception approach means you would replace the last:

    return None, None, None

with:

    raise ValueError("no solution found") # better message needed

For the None-ish approach, you might:
- return None (or some other sentinel, but None is best if None is not 
  itself a valid return)
- return a (None,None,None) tuple as you have done to match the expected 
  result

The former requires code like this if you return None:

    solution = self.boxPairsInSameRow(candidate_pairs, x, y)
    if solution is None:
        ... no solution ...
    else:
        item, row, column_list = solution
        ... use the solution ...

or this for your None-ish approach:

    item, row, column_list =_ self.boxPairsInSameRow(candidate_pairs, x , y)
    if (item, row, column_list) == (None, None, None):
        ... no solution ...
    else:
        ... use the solution ...

The exception approach looks like this:

    try:
        item, row, column_list =_ self.boxPairsInSameRow(candidate_pairs, x , y)
    except ValueError as e:
        warning("no box pairs found: %s", e)
        ... handle no solution here ...
    else:
        ... use the solution ..

If you always expect a solution, this becomes:

    item, row, column_list = self.boxPairsInSameRow(candidate_pairs, x , y)
    ... use the solution ..

which is very simple. I suppose if that were the case you would not need 
your None-ish test in the first place.

A third alternative turns on your statement: "Once the pairs have been 
found on a row then there is no need to search the remaining row or 
rows". Is it _meaningful_ to search for more solutions, even if you 
_currently_ just want the first one?  If it is you might recast this as 
a generator:

??? def boxPairsInSameRow(self, pairs, x, y):
??????? col_list = []
??????? for item, count in pairs.items():
??????????? if count == 2:? # then item is a pair candidate
??????????????? for row in range(x, x + 3):
??????????????????? col_list = []
??????????????????? for col in range(y, y + 3):
??????????????????????? if item in self.solution[row][col]:
??????????????????????????? col_list.append(col)
??????????????????? yield item, row, col_list

This is a generator function, which walks your data structure and yields 
solutions as they are found. Note that because it will continue after 
the first solution you may need to clear some things after the "yield" 
statement, for example maybe "col_list" should be emptied before 
proceeding.

Then at the calling end you can iterate over the generator:

    solutions = list(self.boxPairsInSameRow(candidate_pairs, x , y))

which would get a list of all the solutions. In your scenario, you only 
want to search to the first solution:

    solution = None
    for solution in self.boxPairsInSameRow(candidate_pairs, x , y):
        # exit the loop on the first solution found
        break
    if solution is None:
        ... no solution yielded ...
    else:
        ... use the solution ...

This runs the generator to the first solution, but _does not_ continue 
executing it because you exit the for-loop. So no further iteration 
happens and the generator ceases execution (it stopped at the "yield", 
and here you never resume it).

In fact Pythons for-loop has a little used feature: an else-clause:

    for solution in self.boxPairsInSameRow(candidate_pairs, x , y):
        # exit the loop on the first solution found
        ... use the solution ...
        break
    else:
        ... no solution yielded ...

The "else" clause runs after the for-loop finishes, _unless_ you "break" 
out of the loop. So here we have the loop body handle the solution and 
the "else:" handle the no solution path (you can leave the "else:" off 
if there is nothing to do if there is no solution).

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

From alan.gauld at yahoo.co.uk  Thu Dec  2 13:37:47 2021
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Thu, 2 Dec 2021 18:37:47 +0000
Subject: [Tutor] function return values
In-Reply-To: <82a53068-6e6d-2038-cf8c-f297a0419c19@gmail.com>
References: <82a53068-6e6d-2038-cf8c-f297a0419c19@gmail.com>
Message-ID: <sob3pu$qvb$1@ciao.gmane.io>

On 02/12/2021 00:24, Phil wrote:

>  ??? def boxPairsInSameRow(self, pairs, x, y):
>  ??????? col_list = []

You don't need this since you set it below

> 
>  ??????? for item, count in pairs.items():
>  ??????????? if count == 2:? # then item is a pair candidate
>  ??????????????? for row in range(x, x + 3):
>  ??????????????????? col_list = []
>  ??????????????????? for col in range(y, y + 3):
>  ??????????????????????? if item in self.solution[row][col]:
>  ??????????????????????????? col_list.append(col)
>  ??????????????????? return item, row, col_list

This return will happen after the first row is processed,
you never process the other rows. I suspect that's not
what you intended?

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



From phillor9 at gmail.com  Thu Dec  2 23:11:37 2021
From: phillor9 at gmail.com (Phil)
Date: Fri, 3 Dec 2021 15:11:37 +1100
Subject: [Tutor] function return values
In-Reply-To: <sob3pu$qvb$1@ciao.gmane.io>
References: <82a53068-6e6d-2038-cf8c-f297a0419c19@gmail.com>
 <sob3pu$qvb$1@ciao.gmane.io>
Message-ID: <24fde022-ff82-bd86-4d52-2c3cb7f39ba2@gmail.com>


On 3/12/21 05:37, Alan Gauld via Tutor wrote:
> On 02/12/2021 00:24, Phil wrote:
>
>>   ??? def boxPairsInSameRow(self, pairs, x, y):
>>   ??????? col_list = []
> You don't need this since you set it below
>
>>   ??????? for item, count in pairs.items():
>>   ??????????? if count == 2:? # then item is a pair candidate
>>   ??????????????? for row in range(x, x + 3):
>>   ??????????????????? col_list = []
>>   ??????????????????? for col in range(y, y + 3):
>>   ??????????????????????? if item in self.solution[row][col]:
>>   ??????????????????????????? col_list.append(col)
>>   ??????????????????? return item, row, col_list
> This return will happen after the first row is processed,
> you never process the other rows. I suspect that's not
> what you intended?

You are correct Alan. The pair exists on row zero in my test case.

This function should return a valid result if two numbers are in the 
same row. So, if a number passes the "if count == 2" test then that 
number is a pair and if the pair is found in row zero then it cannot 
exist anywhere else so there is no need to keep searching. But, what if 
the pair is in row 1 or 2 and not in the first row? I think a "found" 
test is needed before the return statement and the first thing that 
comes to mind is:

if len(col_list) == 2:

 ??? return item, row, col_list

else:

 ??? continue

And, if the pair is not in the same row then return None, None, None.

I'll give this a test tomorrow.

-- 

Regards,
Phil


From phillor9 at gmail.com  Fri Dec  3 00:34:22 2021
From: phillor9 at gmail.com (Phil)
Date: Fri, 3 Dec 2021 16:34:22 +1100
Subject: [Tutor] function return values
In-Reply-To: <Yahy3u9s3KAScEhe@cskk.homeip.net>
References: <82a53068-6e6d-2038-cf8c-f297a0419c19@gmail.com>
 <Yahy3u9s3KAScEhe@cskk.homeip.net>
Message-ID: <2fffbd36-34d1-b47a-44bf-91d469117c8d@gmail.com>


On 2/12/21 18:16, Cameron Simpson wrote:
>
> For a function returning a valid result or no result you have two main
> approaches in Python:
> - return the result or None (or None-ish, as you are doing)
> - return the result or raise a ValueError("no solution found")

Thank you Cameron for your detailed reply which has given me something 
to think about.

I think the return of None, None, None is the simplest option. My 
calling function was originally only testing for a list of two elements 
and ignoring the other two variables. I think this is still correct, an 
empty list or a list containing 1 element is not valid. I'll experiment 
further with this.

Alan has pointed out an error: I do not need to keep searching after a 
pair has been found but I do need to search beyond the first row. The 
pair could be on row 2 or 3.

I've seldom ever used exceptions and I've never found a case where I 
could use the yield statement. I can see that it would be useful if I 
needed to return multiple values of the same variable from a function. 
I'll try to keep the yield statement in mind it could be useful 
somewhere and better than the use of a list.

> or this for your None-ish approach:
>
>      item, row, column_list =_ self.boxPairsInSameRow(candidate_pairs, x , y)
>      if (item, row, column_list) == (None, None, None):

Should the Nones be enclosed within brackets? I didn't do that. I know 
that "if (a + b) == 2" is C syntax.


> A third alternative turns on your statement: "Once the pairs have been
> found on a row then there is no need to search the remaining row or
> rows". Is it _meaningful_ to search for more solutions, even if you
> _currently_ just want the first one?

There can only be a pair and they must be on the same row, not 
necessarily on the first row. So what I wrote was not correct. I do not 
need to continue searching once a pair has been found on a row but I do 
need to search beyond the first row in case the pair is on row 1 or 2. I 
don't think the use of a generator is called for here.

-- 

Regards,
Phil


From phillor9 at gmail.com  Fri Dec  3 00:57:34 2021
From: phillor9 at gmail.com (Phil)
Date: Fri, 3 Dec 2021 16:57:34 +1100
Subject: [Tutor] function return values
In-Reply-To: <34ce759a-a45e-21cc-0705-c210cbacaa63@DancesWithMice.info>
References: <82a53068-6e6d-2038-cf8c-f297a0419c19@gmail.com>
 <34ce759a-a45e-21cc-0705-c210cbacaa63@DancesWithMice.info>
Message-ID: <72d79228-0924-5614-3a6f-aac928473dd8@gmail.com>


> Suggest creating another function which returns a boolean. Then use that
> to initiate (or not) the scan. Perhaps along these lines:
>
> if is_pair_in_row( item, row, column_list ):
>      ( item,
>        row,
>        column_list,
>        ) = self.boxPairsInSameRow(candidate_pairs, x , y)
>
That was exactly my first thought dn until I realised that I needed the 
function to return the item, row and a list of the columns where the 
pair was found.

Asking if a pair is on row 0 column 0 and if not then asking if the pair 
is on row 0 col 1 etc would not reduce the complexity of the calling 
function (unless I've misunderstood your reply, which is not unlikely) 
which is the aim of the current exercise.


> NBBB Python's PEP-008 (a guide (maybe) and not a "standard") for naming
> identifiers and functions:
>
> box_pairs_in_same_row()

This was originally isBoxPairsInSameRow, I just dropped the "is" (Pairs 
should have been Pair) since I'm not returning a boolean value. Coming 
up with descriptive names? for functions and variable is not one of my 
strong points and I must check if camel text is acceptable in Python.

-- 

Regards,
Phil


From cs at cskk.id.au  Fri Dec  3 02:04:54 2021
From: cs at cskk.id.au (Cameron Simpson)
Date: Fri, 3 Dec 2021 18:04:54 +1100
Subject: [Tutor] function return values
In-Reply-To: <2fffbd36-34d1-b47a-44bf-91d469117c8d@gmail.com>
References: <2fffbd36-34d1-b47a-44bf-91d469117c8d@gmail.com>
Message-ID: <YanBlj/UCUUABbDe@cskk.homeip.net>

On 03Dec2021 16:34, Phil <phillor9 at gmail.com> wrote:
>On 2/12/21 18:16, Cameron Simpson wrote:
>>For a function returning a valid result or no result you have two main
>>approaches in Python:
>>- return the result or None (or None-ish, as you are doing)
>>- return the result or raise a ValueError("no solution found")
>
>Thank you Cameron for your detailed reply which has given me something 
>to think about.
>
>I think the return of None, None, None is the simplest option.

That's fine.

>I've seldom ever used exceptions and I've never found a case where I 
>could use the yield statement. I can see that it would be useful if I 
>needed to return multiple values of the same variable from a function.  

Generators are good when:
- there's a series of values, sometimes unbounded (eg primes)
- the series is expensive to compute, either per item or in total ("all 
  the primes" has infinite cost)
because they compute until they yield a value. The code consuming/using 
those values can process that value. It can then resume the generator 
(which has simply paused at the "yield") or just cease using it, so the 
generator no longer runs. So they compute only what gets consumed, 
nothing more.

>I'll try to keep the yield statement in mind it could be useful 
>somewhere and better than the use of a list.

Not that generator functions (functions containing a "yield" statement) 
are used _differently_ to normal functions.

    def gen():
        x = 1
        while True:
            yield x
            x += 2

This generates odd numbers. The _return_ of the function is an iterable, 
the generator:

    g = gen()

At this point the function _has not run_. If you print(g) you'll see a 
generator object. It is iterable, and a common way to use it is to 
iterable with a for-loop:

    for n in g:
        print(n)

Each iteration of the loop rns the function until it yields, and you get 
what it yielded as the next value in the iteration. So the for-loop 
about assigns odd numbers to "n".

>>or this for your None-ish approach:
>>
>>     item, row, column_list =_ self.boxPairsInSameRow(candidate_pairs, x , y)
>>     if (item, row, column_list) == (None, None, None):
>
>Should the Nones be enclosed within brackets? I didn't do that. I know 
>that "if (a + b) == 2" is C syntax.

That's a precedence thing (and a readability thing, possibly). This is a 
3-tuple:

    None, None, None

You know you don't need the brackets - your return-statement used no 
brackets, and it returns a tuple. (All Python functions return exactly 
one object - your object just happens to be a tuple with 3 elements 
inside it).

_However_, the == operator binds more tightly that the , operator. So 
this:

    if item, row, column_list == None, None, None:

is actually a 5-tuple:

    item
    row
    column_list==None
    None
    None

Being a non-empty tuple, it is always true. Not what you wanted to test.

This:

    if (item, row, column_list) == (None, None, None):

is a Boolean expression comparing 2 3-tuples. Inside brackets to get the 
groups right. So "item, row, column_list" is the left hand 3-tuple, and 
it is in brackets to keep it together. No different to:

    (2 + 3) * 5

meaning 25 instead of:

    2 + 3 * 5

meaning 17, because arithmetic precedence groups the "*" tighter than 
the "+".  Brackets to override default operator precedence.

>>A third alternative turns on your statement: "Once the pairs have been
>>found on a row then there is no need to search the remaining row or
>>rows". Is it _meaningful_ to search for more solutions, even if you
>>_currently_ just want the first one?
>
>There can only be a pair and they must be on the same row, not 
>necessarily on the first row. So what I wrote was not correct. I do 
>not need to continue searching once a pair has been found on a row but 
>I do need to search beyond the first row in case the pair is on row 1 
>or 2. I don't think the use of a generator is called for here.

On that basis, I don't think so either.

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

From cs at cskk.id.au  Fri Dec  3 02:10:13 2021
From: cs at cskk.id.au (Cameron Simpson)
Date: Fri, 3 Dec 2021 18:10:13 +1100
Subject: [Tutor] function return values
In-Reply-To: <72d79228-0924-5614-3a6f-aac928473dd8@gmail.com>
References: <72d79228-0924-5614-3a6f-aac928473dd8@gmail.com>
Message-ID: <YanC1QbPWLV3xv8D@cskk.homeip.net>

On 03Dec2021 16:57, Phil <phillor9 at gmail.com> wrote:
>This was originally isBoxPairsInSameRow, I just dropped the "is" (Pairs 
>should have been Pair) since I'm not returning a boolean value.  Coming 
>up with descriptive names? for functions and variable is not one of my 
>strong points and I must check if camel text is acceptable in Python.

Functions starting with "is" usually return a Boolean because they 
usually test something ("is this blue?" etc). If your function actually 
returns the pair found (with some context information) you'd give it a 
nounlike name, naming the thing it returns somehow.

    def is_odd(n):
        return n % 2 != 0

    def square(n):
        return n * n

    # print the squares of the odd numbers < 100
    for n in range(100):
        if is_odd(n):
            print(square(n))

Anyway, it's your code. Do what you find easiest to read later. Having 
things sort-of-like English grammar helps me though. And don't stress 
about names too much. If you find a name confusing or not to your liking 
it is easy to fix with an editor later.

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

From __peter__ at web.de  Fri Dec  3 12:14:33 2021
From: __peter__ at web.de (Peter Otten)
Date: Fri, 3 Dec 2021 18:14:33 +0100
Subject: [Tutor] function return values
In-Reply-To: <YanBlj/UCUUABbDe@cskk.homeip.net>
References: <2fffbd36-34d1-b47a-44bf-91d469117c8d@gmail.com>
 <YanBlj/UCUUABbDe@cskk.homeip.net>
Message-ID: <af53971f-a385-13f4-5276-25a36b82f102@web.de>

On 03/12/2021 08:04, Cameron Simpson wrote:

> _However_, the == operator binds more tightly that the , operator. So
> this:
> 
>      if item, row, column_list == None, None, None:
> 
> is actually a 5-tuple:
> 
>      item
>      row
>      column_list==None
>      None
>      None
> 
> Being a non-empty tuple, it is always true. Not what you wanted to test.

I believed you, but something made me feed this to the interpreter:

 >>> 1, 2 == 3, 4
(1, False, 4)
 >>> if 1, 2 == 3, 4: print("equal")
SyntaxError: invalid syntax

So the unsuspecting writer gets one more chance to put the parens into 
the right places ;)


From cs at cskk.id.au  Fri Dec  3 15:46:57 2021
From: cs at cskk.id.au (Cameron Simpson)
Date: Sat, 4 Dec 2021 07:46:57 +1100
Subject: [Tutor] function return values
In-Reply-To: <af53971f-a385-13f4-5276-25a36b82f102@web.de>
References: <af53971f-a385-13f4-5276-25a36b82f102@web.de>
Message-ID: <YaqCQSAMJBEVGTno@cskk.homeip.net>

On 03Dec2021 18:14, Peter Otten <__peter__ at web.de> wrote:
>On 03/12/2021 08:04, Cameron Simpson wrote:
>>_However_, the == operator binds more tightly that the , operator. So
>>this:
>>
>>     if item, row, column_list == None, None, None:
>>
>>is actually a 5-tuple:
>>
>>     item
>>     row
>>     column_list==None
>>     None
>>     None
>>
>>Being a non-empty tuple, it is always true. Not what you wanted to test.
>
>I believed you, but something made me feed this to the interpreter:
>
>>>> 1, 2 == 3, 4
>(1, False, 4)
>>>> if 1, 2 == 3, 4: print("equal")
>SyntaxError: invalid syntax
>
>So the unsuspecting writer gets one more chance to put the parens into 
>the right places ;)

Fascinating. I did not expect this!

On consideration, this will only confuse people coming from C, who might 
think "oh I need brackets around the condition" and write:

    >>> if (1, 2 == 3, 4):
    ...   print(1)
    ...
    1

In Python 3.8 I get this:

    >>> if 1, 2 == 3, 4:
      File "<stdin>", line 1
          if 1, 2 == 3, 4:
              ^
      SyntaxError: invalid syntax

which does suggest the commas as the issue, not a missing opening 
bracket, but still...

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

From phillor9 at gmail.com  Fri Dec  3 17:46:06 2021
From: phillor9 at gmail.com (Phil)
Date: Sat, 4 Dec 2021 09:46:06 +1100
Subject: [Tutor] function return values
In-Reply-To: <YanBlj/UCUUABbDe@cskk.homeip.net>
References: <2fffbd36-34d1-b47a-44bf-91d469117c8d@gmail.com>
 <YanBlj/UCUUABbDe@cskk.homeip.net>
Message-ID: <6eb515c6-9294-89f0-e484-5beaed8fae17@gmail.com>


> Not that generator functions (functions containing a "yield" statement)
> are used _differently_ to normal functions.
>
>      def gen():
>          x = 1
>          while True:
>              yield x
>              x += 2
>
> This generates odd numbers. The _return_ of the function is an iterable,
> the generator:
>
>      g = gen()
>
> At this point the function _has not run_. If you print(g) you'll see a
> generator object. It is iterable, and a common way to use it is to
> iterable with a for-loop:
>
>      for n in g:
>          print(n)
>
> Each iteration of the loop rns the function until it yields, and you get
> what it yielded as the next value in the iteration. So the for-loop
> about assigns odd numbers to "n".
Thank Cameron for the extra generator information and the example that 
illustrates it's use well.
>      if (item, row, column_list) == (None, None, None):
>
> is a Boolean expression comparing 2 3-tuples.

Of course, and thank you for pointing that out.

-- 

Regards,
Phil


From nulla.epistola at web.de  Sat Dec  4 07:46:40 2021
From: nulla.epistola at web.de (Sibylle Koczian)
Date: Sat, 4 Dec 2021 13:46:40 +0100
Subject: [Tutor] function return values
In-Reply-To: <YaqCQSAMJBEVGTno@cskk.homeip.net>
References: <af53971f-a385-13f4-5276-25a36b82f102@web.de>
 <YaqCQSAMJBEVGTno@cskk.homeip.net>
Message-ID: <sofnvd$154r$1@ciao.gmane.io>

Am 03.12.2021 um 21:46 schrieb Cameron Simpson:
> 
> Fascinating. I did not expect this!
> 
> On consideration, this will only confuse people coming from C, who might
> think "oh I need brackets around the condition" and write:
> 
>      >>> if (1, 2 == 3, 4):
>      ...   print(1)
>      ...
>      1
> 
> In Python 3.8 I get this:
> 
>      >>> if 1, 2 == 3, 4:
>        File "<stdin>", line 1
>            if 1, 2 == 3, 4:
>                ^
>        SyntaxError: invalid syntax
> 
> which does suggest the commas as the issue, not a missing opening
> bracket, but still...
> 

Still shorter:

 >>> if 1, 2: print("ja")
   File "<stdin>", line 1
     if 1, 2: print("ja")
         ^
SyntaxError: invalid syntax
 >>> if (1, 2): print("ja")
...
ja

Python 3.10, that's probably unimportant.


From deshwill at iu.edu  Mon Dec  6 09:59:26 2021
From: deshwill at iu.edu (Deshaun Williams)
Date: Mon, 6 Dec 2021 09:59:26 -0500
Subject: [Tutor] SOS pleas help
Message-ID: <CAEoqJdftt58+0bYo343feUM2ZpD3W+qtw_vx4smkAuR5YPa4Qg@mail.gmail.com>

im trying to code a web application to use API but i cant get it to work
heres my current code. <%
import math, json
from bottle import request, route
url = "https://www.gamerpower.com/api/giveaways?platform=pc"
r = request.get(url)
request.forms.get("cosnole")
gamer = request.forms.get("cosnole")
pathstring =""
if gamer == "pc":
    pathstring = ('/pc.html')
elif gamer == "switch":
    pathstring == ('/switch.html')
end
response =  request.get("
https://www.gamerpower.com/api/giveaways?platform=pc")
data = json.load(response)
        # write the results in a csv file
%>
<html>
<html lang = "en-us">
<head></head>
<h1> nothing</h1>
<style>
<body>
<div>
{{data()}}
</div>
</body>



</style>
</html>
any help you can give would be grealy appreciated

From juliushamilton100 at gmail.com  Mon Dec  6 17:37:40 2021
From: juliushamilton100 at gmail.com (Julius Hamilton)
Date: Mon, 6 Dec 2021 23:37:40 +0100
Subject: [Tutor] urllib vs requests
Message-ID: <CAEsMKX0K5spUxLv6J8bjWHNcgGja8K1uaiR9PpfNkW_zwf=2nQ@mail.gmail.com>

Hey,

Could anyone please let me know why requests.get fetches the following url
effectively but urllib.request.urlopen returns ?403 Forbidden??

https://juno.sh/direct-connection-to-jupyter-server/

Is it because they make different types of requests so the web server
detects that urllib is something it doesn?t accept? Is there any way around
that?

By the way, is there any Python email group for slightly more advanced
questions than the tutor group? More like troubleshooting or something,
from package maintainers?

Thanks,
Julius

From learn2program at gmail.com  Mon Dec  6 18:25:30 2021
From: learn2program at gmail.com (Alan Gauld)
Date: Mon, 6 Dec 2021 23:25:30 +0000
Subject: [Tutor] urllib vs requests
In-Reply-To: <CAEsMKX0K5spUxLv6J8bjWHNcgGja8K1uaiR9PpfNkW_zwf=2nQ@mail.gmail.com>
References: <CAEsMKX0K5spUxLv6J8bjWHNcgGja8K1uaiR9PpfNkW_zwf=2nQ@mail.gmail.com>
Message-ID: <adf96bdc-7dfa-f2ea-7650-3ced097ee31f@yahoo.co.uk>


On 06/12/2021 22:37, Julius Hamilton wrote:

> By the way, is there any Python email group for slightly more advanced

Yes the main Python list is targetted at more experienced users and
especially
those working outside the standard library, or looking for new features or
packages to be added.


Sign up via the python.org site under mailing lists.


-- 

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


From alan.gauld at yahoo.co.uk  Mon Dec  6 18:26:29 2021
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Mon, 6 Dec 2021 23:26:29 +0000
Subject: [Tutor] SOS pleas help
In-Reply-To: <CAEoqJdftt58+0bYo343feUM2ZpD3W+qtw_vx4smkAuR5YPa4Qg@mail.gmail.com>
References: <CAEoqJdftt58+0bYo343feUM2ZpD3W+qtw_vx4smkAuR5YPa4Qg@mail.gmail.com>
Message-ID: <som675$av1$1@ciao.gmane.io>

On 06/12/2021 14:59, Deshaun Williams wrote:
> im trying to code a web application to use API but i cant get it to work
> heres my current code. <%
> import math, json
> from bottle import request, route
> url = "https://www.gamerpower.com/api/giveaways?platform=pc"
> r = request.get(url)
> request.forms.get("cosnole")
> gamer = request.forms.get("cosnole")

I suspect those two strings should be spelled "console" ?

-- 
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  Mon Dec  6 18:27:29 2021
From: mats at wichmann.us (Mats Wichmann)
Date: Mon, 6 Dec 2021 16:27:29 -0700
Subject: [Tutor] urllib vs requests
In-Reply-To: <CAEsMKX0K5spUxLv6J8bjWHNcgGja8K1uaiR9PpfNkW_zwf=2nQ@mail.gmail.com>
References: <CAEsMKX0K5spUxLv6J8bjWHNcgGja8K1uaiR9PpfNkW_zwf=2nQ@mail.gmail.com>
Message-ID: <4ec2b57b-5953-9dcf-3da3-6eee86ea2fdd@wichmann.us>

On 12/6/21 15:37, Julius Hamilton wrote:
> Hey,
> 
> Could anyone please let me know why requests.get fetches the following url
> effectively but urllib.request.urlopen returns ?403 Forbidden??
> 
> https://juno.sh/direct-connection-to-jupyter-server/
> 
> Is it because they make different types of requests so the web server
> detects that urllib is something it doesn?t accept? Is there any way around
> that?

If there's a proxy involved, that's probably the issue, last I knew it 
it didn't talk to https through a proxy without some further hacks.

also note that urllib docs themselves recommend using requests if it 
makes sense.

> 
> By the way, is there any Python email group for slightly more advanced
> questions than the tutor group? More like troubleshooting or something,
> from package maintainers?

python-list is one http://mail.python.org/mailman/listinfo/python-list

can also try https://discuss.python.org/ which is a board, but you can 
also access it via email.

Or the Python Discord: https://discord.com/invite/python



From cs at cskk.id.au  Mon Dec  6 18:32:14 2021
From: cs at cskk.id.au (Cameron Simpson)
Date: Tue, 7 Dec 2021 10:32:14 +1100
Subject: [Tutor] SOS pleas help
In-Reply-To: <CAEoqJdftt58+0bYo343feUM2ZpD3W+qtw_vx4smkAuR5YPa4Qg@mail.gmail.com>
References: <CAEoqJdftt58+0bYo343feUM2ZpD3W+qtw_vx4smkAuR5YPa4Qg@mail.gmail.com>
Message-ID: <Ya6dfpf7bN4nJ62g@cskk.homeip.net>

On 06Dec2021 09:59, Deshaun Williams <deshwill at iu.edu> wrote:
>im trying to code a web application to use API but i cant get it to work

Doesn't work is a little vague. Some remarks on the code inline below:

>import math, json
>from bottle import request, route
>url = "https://www.gamerpower.com/api/giveaways?platform=pc"
>r = request.get(url)
>request.forms.get("cosnole")

This does a GET but does nothing with the result.

>gamer = request.forms.get("cosnole")

Both this GET and the preceeding one might misspell "console".

GETs typically want an entire URL.

>pathstring =""
>if gamer == "pc":
>    pathstring = ('/pc.html')

You don't need the brackets here, though they do no harm.

>elif gamer == "switch":
>    pathstring == ('/switch.html')

This is an equality test ("=="), not an assigment ("=").

>end

"end"? This is not a Python keyword. As such, it is a variable 
reference, and you have no "end" variable. This will produce a NameError 
when you get here.

>response =  request.get("https://www.gamerpower.com/api/giveaways?platform=pc")

Looks like url from earlier. If so, just say url here, it will avoid 
accidentally not using the same URL string.

>data = json.load(response)

json.load() is for files. You probably want json.loads() (load from a 
string). You should also check that response is actually a string, and 
not a more complex "HTTP response" type object. A:

    print(type(response))

before this line will tel you that.

>        # write the results in a csv file

I don't see anycode to write a CSV file. See the "csv" module 
documentation: https://docs.python.org/3/library/csv.html#module-csv

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

From phillor9 at gmail.com  Tue Dec  7 02:19:51 2021
From: phillor9 at gmail.com (Phil)
Date: Tue, 7 Dec 2021 18:19:51 +1100
Subject: [Tutor] The Python way and two dimensional lists
In-Reply-To: <sneppr$ifj$1@ciao.gmane.io>
References: <dd686338-48ea-8114-190f-c9dc0a185073@gmail.com>
 <sneppr$ifj$1@ciao.gmane.io>
Message-ID: <ab220826-db5f-aa05-f1a3-fb60c81fd14d@gmail.com>


On 22/11/21 11:55, Alan Gauld via Tutor wrote:
>
> Also, using python "2D" lists there is no way to
> access the entire column (in your example) you can
> only access a whole row.
>
> You can build a copy of a column easily enough with:
>
> col6 = [row[5] for row in solution]
>
> But if you change any values you need to regenerate
> the copy so it's not exactly efficient.

I've used this idea to simplify a section of my otherwise complex code 
to access columns. I've spent the whole day trying to simplify another 
area of confusing code, the code is simpler but it doesn't do what I 
want and I can see why but I don't know how to proceed.

What I have is a 9 x 9 grid and there are three 3 x 3 boxes per line 
which means that I have nine 3 x 3 boxes in total. Each box is accessed 
by it's top left coordinates:

 ??????? box_start = [(0, 0), (0, 3), (0, 6),
 ??????????? (3, 0), (3, 3), (3, 6),
 ??????????? (6, 0), (6, 3), (6, 6)
 ??????????? ]

 ??????? for x, y in box_start:
 ??????????? ...

 ??????? for col in range(x, x + 3):
 ??????????? ...
 ??????????? for row in range(y, y + 3):
 ??????????????? print(f'self.solution[row][col] 
{self.solution[row][col]}')

This works but I know that it's not the correct method and I still find 
accessing columns within a 2D array confusing. I only got this working 
by trial and error by swapping the x and y coordinates. I think all I've 
done is turn the grid onto it's side.

So, by adapting Alan's suggestion I can print the top three boxes as 
columns:

 ??????? for c in range(y, y + 3):
 ??????????? col = [row[c] for row in self.solution[:3]]
 ??????????? print(col)

This does exactly what I want. The question is, how do I use the x 
variable to step down to the next row of boxes? The next row starts at 3 
instead of 0.

I hope this is less confusing to the reader than it is to me.

-- 

Regards,
Phil


From bouncingcats at gmail.com  Tue Dec  7 03:39:06 2021
From: bouncingcats at gmail.com (David)
Date: Tue, 7 Dec 2021 19:39:06 +1100
Subject: [Tutor] The Python way and two dimensional lists
In-Reply-To: <ab220826-db5f-aa05-f1a3-fb60c81fd14d@gmail.com>
References: <dd686338-48ea-8114-190f-c9dc0a185073@gmail.com>
 <sneppr$ifj$1@ciao.gmane.io> <ab220826-db5f-aa05-f1a3-fb60c81fd14d@gmail.com>
Message-ID: <CAMPXz=odOWbdekJvDk1_scLkQ1futJBh2-xkGTnzNn2ML46Rrw@mail.gmail.com>

On Tue, 7 Dec 2021 at 18:21, Phil <phillor9 at gmail.com> wrote:

>          box_start = [(0, 0), (0, 3), (0, 6),
>              (3, 0), (3, 3), (3, 6),
>              (6, 0), (6, 3), (6, 6)
>              ]
>
>          for x, y in box_start:
>              ...
>
>          for col in range(x, x + 3):
>              ...
>              for row in range(y, y + 3):
>                  print(f'self.solution[row][col]
> {self.solution[row][col]}')
>
> This works but I know that it's not the correct method and I still find
> accessing columns within a 2D array confusing. I only got this working
> by trial and error by swapping the x and y coordinates. I think all I've
> done is turn the grid onto it's side.

Hi, I'm not going to dig into your code at all.

But I am offering to help, just by making sure that you
understand the basic idea of 2D indexing of lists.

Also I suggest to stop using the word 'array' at this stage.
Python has both 'list' and 'array' and they are slightly
different. So just stick to 'list' for the time being, and
stop calling your lists 'arrays' because that's unclear.

> col = [row[c] for row in self.solution[:3]]

Also I suggest to stop using comprehensions at this
stage. Just use simple 'for' loops like I have, until they
make sense. After that, you can start to use
comprehensions and slicing.

I don't know what it is that you aren't understanding.
But you seem to be unclear so I have written a quick
demo of 2D list indexing below for you.

I suggest you have a look at *and* *run* the code below until you
have no trouble understanding it.

I think that being confident about this concept will make
your actual problem much clearer to you.

I have pasted the code below, but it might get mangled
or line-wrapped by the email system, so I have attached
a file copy of it also.

# have a look at this code, maybe it helps you understand

# i is row index
# j is column index

# lets use a list for each row, each row-list has 3 columns
row_0 = [0, 1, 2]
row_1 = [3, 4, 5]
row_2 = [6, 7, 8]

# how to print each column of row_0
for j in range(0, 3):
    print(f"row_0[{j}] = row_0, column {j} = {row_0[j]}")

# lets make box contain 3 rows, let box be a list of 3 rows
box = [row_0, row_1, row_2]
# note: box is a list, of three rows
# note: each row is a list, of three elements

# how to print each row of box
for i in range(0, 3):
    print(f"box[{i}] = row_{i} = {box[i]}")

# now combine the above two print ranges, to print the whole box, by rows
for i in range(0, 3):
    # get a row, which is one of the three lists in box
    row = box[i]
    # now print each column of the row
    for j in range(0, 3):
        # print each j of the box[i] row
        print(f"row[{j}] = {row[j]}")

# but we dont really need that variable 'row'
# because row = box[i]
# so instead of naming 'row', we can refer to 'box[i]'
# they are the same thing
# so for example row[2] can be written box[i][2]
# because box[i] is the row list, and then we ask for the [2] element of it
# and by the same thinking, any element can be accessed as box[i][j]
# where box[i] is the row, which is then indexed using [j]

# the below print statement is exactly the same as the previous one
for i in range(0, 3):
    for j in range(0, 3):
        print(f"box[{i}][{j}] = {box[i][j]}")
-------------- next part --------------
# have a look at this code, maybe it helps you understand

# i is row index
# j is column index

# lets use a list for each row, each row-list has 3 columns
row_0 = [0, 1, 2]
row_1 = [3, 4, 5]
row_2 = [6, 7, 8]

# how to print each column of row_0
for j in range(0, 3):
	print(f"row_0[{j}] = row_0, column {j} = {row_0[j]}")

# lets make box contain 3 rows, let box be a list of 3 rows
box = [row_0, row_1, row_2]
# note: box is a list, of three rows
# note: each row is a list, of three elements

# how to print each row of box
for i in range(0, 3):
	print(f"box[{i}] = row_{i} = {box[i]}")

# now combine the above two print ranges, to print the whole box, by rows
for i in range(0, 3):
	# get a row, which is one of the three lists in box
	row = box[i]
	# now print each column of the row
	for j in range(0, 3):
		# print each j of the box[i] row
		print(f"row[{j}] = {row[j]}")

# but we dont really need that variable 'row'
# because row = box[i]
# so instead of naming 'row', we can refer to 'box[i]'
# they are the same thing
# so for example row[2] can be written box[i][2]
# because box[i] is the row list, and then we ask for the [2] element of it
# and by the same thinking, any element can be accessed as box[i][j]
# where box[i] is the row, which is then indexed using [j]

# the below print statement is exactly the same as the previous one
for i in range(0, 3):
	for j in range(0, 3):
		print(f"box[{i}][{j}] = {box[i][j]}")

From phillor9 at gmail.com  Tue Dec  7 04:13:16 2021
From: phillor9 at gmail.com (Phil)
Date: Tue, 7 Dec 2021 20:13:16 +1100
Subject: [Tutor] The Python way and two dimensional lists
In-Reply-To: <CAMPXz=odOWbdekJvDk1_scLkQ1futJBh2-xkGTnzNn2ML46Rrw@mail.gmail.com>
References: <dd686338-48ea-8114-190f-c9dc0a185073@gmail.com>
 <sneppr$ifj$1@ciao.gmane.io> <ab220826-db5f-aa05-f1a3-fb60c81fd14d@gmail.com>
 <CAMPXz=odOWbdekJvDk1_scLkQ1futJBh2-xkGTnzNn2ML46Rrw@mail.gmail.com>
Message-ID: <cc9843d2-a7a0-d746-59d0-1f51d718f1b4@gmail.com>


On 7/12/21 19:39, David wrote:
>
> I don't know what it is that you aren't understanding.
> But you seem to be unclear so I have written a quick
> demo of 2D list indexing below for you.

Thank you David. I will study and run your code trough a debugger.

While I was typing my previous e-mail I thought of a solution.

col = [row[c] for row in self.solution] gives me the entire column. So 
what I need is to extract the first three rows for the top three boxes. 
Then for the next row of boxes I need the middle section of the column 
(rows 3, 4 and 5) and for the last row of boxes I need the last three 
rows of the column. At the moment I don't know how I might do this but 
that's a project for tomorrow.

-- 

Regards,
Phil


From alan.gauld at yahoo.co.uk  Tue Dec  7 04:34:46 2021
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Tue, 7 Dec 2021 09:34:46 +0000
Subject: [Tutor] The Python way and two dimensional lists
In-Reply-To: <ab220826-db5f-aa05-f1a3-fb60c81fd14d@gmail.com>
References: <dd686338-48ea-8114-190f-c9dc0a185073@gmail.com>
 <sneppr$ifj$1@ciao.gmane.io> <ab220826-db5f-aa05-f1a3-fb60c81fd14d@gmail.com>
Message-ID: <son9rn$omd$1@ciao.gmane.io>

On 07/12/2021 07:19, Phil wrote:

> What I have is a 9 x 9 grid and there are three 3 x 3 boxes per line 
> which means that I have nine 3 x 3 boxes in total. 

I believe you are building a model of a Sudoku game?
But from your description it's not clear what data
structure you are using. Please just show it!

For example, do you really have a 9x9 grid - that is,
a list with 81 single elements?

solution = [0,1,2....,79, 80]

Or is it a list with 9 sublists each of 9 elements?

solution = [[0...8],
            [9...17],
....
            [71...80]]

Or is it a list with 9 elements(boxes), each of which
is itself a list with 9 elements

solution = [[0,1,2,9,10,11,18,19,20],[3,4,5,12,13,14...],[6,7,8....]
            [...][...],[...]
            [...],[...],[...,78,79,80]]

or is each box a list with 3 sublists each with 3 elements?


solution = [[[0,1,2],
             [9,10,11],
             [18,19,20]
            ],
            [[3,4,5],....],
            ...
           ]

>From your description you could have any of these structures.

Each box is accessed
> by it's top left coordinates:
> 
>  ??????? box_start = [(0, 0), (0, 3), (0, 6),
>  ??????????? (3, 0), (3, 3), (3, 6),
>  ??????????? (6, 0), (6, 3), (6, 6)
>  ??????????? ]

This suggests to me you are using the second option above?
ie a list with 9 sub lists of 9 elements?

> This works but I know that it's not the correct method 

If it works it is "correct" for some definition of correct.

But personally here is how I would tackle your problem.

I'd just use a single list of 81 cells.

I'd then write helper functions to extract the sublists I needed:

def get_cell(table, row, col)

def get_row(table, row_num)

def get_col(table, col_num)

def get_box(table, row_num, col_num)  # or just box_num?

The next problem (based on previous posts) is that your
cells are sets which are immutable, so you need to:
1) create another set of functions for writing back changes
to a cell - tricky...
OR
2) use lists instead of sets because they are mutable.
OR
3) Use OOP and make your cells objects with methods
to add/remove values and using a set internally to
check uniqueness etc. This would be my choice.

Personally, I'd use OOP for the table too, and make the
functions above methods of the table. So you would have
a table object with 81 mutable cells.

But you haven't mentioned OOP up to now so that may be
an extra learning curve you don't want to deal with.

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



From wlfraed at ix.netcom.com  Tue Dec  7 12:46:11 2021
From: wlfraed at ix.netcom.com (Dennis Lee Bieber)
Date: Tue, 07 Dec 2021 12:46:11 -0500
Subject: [Tutor] The Python way and two dimensional lists
References: <dd686338-48ea-8114-190f-c9dc0a185073@gmail.com>
 <sneppr$ifj$1@ciao.gmane.io> <ab220826-db5f-aa05-f1a3-fb60c81fd14d@gmail.com>
 <CAMPXz=odOWbdekJvDk1_scLkQ1futJBh2-xkGTnzNn2ML46Rrw@mail.gmail.com>
 <cc9843d2-a7a0-d746-59d0-1f51d718f1b4@gmail.com>
Message-ID: <302vqgtro4a2dul5oa5pkghktdka5bara1@4ax.com>

On Tue, 7 Dec 2021 20:13:16 +1100, Phil <phillor9 at gmail.com> declaimed the
following:

	I'd also emphasize using Python names for the Python structures...

	A list is a dynamically allocated (automatically resizes if needed)
heterogeneous (mixed content) structure.

	An array is a specialized structure optimized for math operations --
mostly superceded by packages like NumPy/SciPy and/or Pandas. The standard
library array module only supports homogeneous arrays -- and essentially
limited to integer, float, and likely complex numbers (Nope: just checked
and complex are not listed: https://docs.python.org/3/library/array.html --
just byte, 16-bit int, 32-bit int, 64-bit int, 32-bit float, 64-bit
double). NumPy array apparently allows for heterogeneous content.

>While I was typing my previous e-mail I thought of a solution.
>
>col = [row[c] for row in self.solution] gives me the entire column. So 
>what I need is to extract the first three rows for the top three boxes. 
>Then for the next row of boxes I need the middle section of the column 
>(rows 3, 4 and 5) and for the last row of boxes I need the last three 
>rows of the column. At the moment I don't know how I might do this but 
>that's a project for tomorrow.

	As mentioned elsewhere, a linear list with a set of functions to
translate (row, col) into the linear index is probably going to be the
simplest route. That is what one would have used in assembly or other early
languages where one just has a chunk of memory (granted, Python lists are
not "just a chunk of memory", but the addressing scheme still works). For
zero-based addressing:

	cell_address = row * 9 + col

(or col * 9 + row depending on which you prefer -- row-major or
column-major)

	You could make that a short function and just use

	board[cell_address(row, col)]

where board is the 81 element list.

	Or, if the board is a class instance... (watch out for line wrap).
There is no error checking in the following. Coordinates should be checked
for range 0..8, values maybe should be checked to be set type.

-=-=-
"""
    Rudimentary class for accessing Sudoko board
    Dennis L Bieber         Dec 7 2021
"""

class Board(object):
    def __init__(self):
        self._cells = [{_} for _ in range(9 * 9)]
    def _cell_address(self, row, col):
        return row * 9 + col
    def get_cell(self, row, col):
        return self._cells[self._cell_address(row, col)]
    def set_cell(self, row, col, value):
        self._cells[self._cell_address(row, col)] = value
    def get_row(self, row):
        return [self._cells[self._cell_address(row, col)] for col in
range(9)]
    def set_row(self, row, values):
        self._cells[self._cell_address(row, 0):self._cell_address(row, 9)]
= values
    def get_col(self, col):
        return [self._cells[self._cell_address(row, col)] for row in
range(9)]
    def set_col(self, col, values):
        for row, value in enumerate(values):
            self._cells[self._cell_address(row, col)] = value
-=-=-

C:\Users\Wulfraed\Documents\_Hg-Repositories\Python Progs>python3
Python ActivePython 3.8.2 (ActiveState Software Inc.) based on
 on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import SudokuBoard as sb
>>> b = sb.Board()
>>> b._cells
[{0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, {9}, {10}, {11}, {12}, {13},
{14}, {15}, {16}, {17}, {18}, {19}, {20}, {21}, {22}, {23}, {24}, {25},
{26}, {27}, {28}, {29}, {30}, {31}, {32}, {33}, {34}, {35}, {36}, {37},
{38}, {39}, {40}, {41}, {42}, {43}, {44}, {45}, {46}, {47}, {48}, {49},
{50}, {51}, {52}, {53}, {54}, {55}, {56}, {57}, {58}, {59}, {60}, {61},
{62}, {63}, {64}, {65}, {66}, {67}, {68}, {69}, {70}, {71}, {72}, {73},
{74}, {75}, {76}, {77}, {78}, {79}, {80}]
>>> b.get_cell(1, 5)
{14}
>>> b.set_cell(1, 5, {2, 3})
>>> b.get_cell(1, 5)
{2, 3}
>>> b.get_row(1)
[{9}, {10}, {11}, {12}, {13}, {2, 3}, {15}, {16}, {17}]
>>> b.get_col(5)
[{5}, {2, 3}, {23}, {32}, {41}, {50}, {59}, {68}, {77}]
>>>

	I'd have preferred to make those get/set methods Python properties, but
I don't know how to manage a property that takes in multiple arguments
(need row, col, and value for setter).



-- 
	Wulfraed                 Dennis Lee Bieber         AF6VN
	wlfraed at ix.netcom.com    http://wlfraed.microdiversity.freeddns.org/


From PyTutor at DancesWithMice.info  Tue Dec  7 16:47:12 2021
From: PyTutor at DancesWithMice.info (dn)
Date: Wed, 8 Dec 2021 10:47:12 +1300
Subject: [Tutor] The Python way and two dimensional lists
In-Reply-To: <cc9843d2-a7a0-d746-59d0-1f51d718f1b4@gmail.com>
References: <dd686338-48ea-8114-190f-c9dc0a185073@gmail.com>
 <sneppr$ifj$1@ciao.gmane.io> <ab220826-db5f-aa05-f1a3-fb60c81fd14d@gmail.com>
 <CAMPXz=odOWbdekJvDk1_scLkQ1futJBh2-xkGTnzNn2ML46Rrw@mail.gmail.com>
 <cc9843d2-a7a0-d746-59d0-1f51d718f1b4@gmail.com>
Message-ID: <ea78d46d-2d51-0773-f7c4-e7d8b0b5f5b1@DancesWithMice.info>

On 07/12/2021 22.13, Phil wrote:
> 
> On 7/12/21 19:39, David wrote:
>>
>> I don't know what it is that you aren't understanding.
>> But you seem to be unclear so I have written a quick
>> demo of 2D list indexing below for you.
> 
> Thank you David. I will study and run your code trough a debugger.
> 
> While I was typing my previous e-mail I thought of a solution.
> 
> col = [row[c] for row in self.solution] gives me the entire column. So
> what I need is to extract the first three rows for the top three boxes.
> Then for the next row of boxes I need the middle section of the column
> (rows 3, 4 and 5) and for the last row of boxes I need the last three
> rows of the column. At the moment I don't know how I might do this but
> that's a project for tomorrow.


This may represent a significant break-through! You've started thinking
about how the data-structure and the algorithm must combine, in order to
produce an effective solution.


A random selection from a "Sudoku rules" web-search yields the
following: "The object of Sudoku is to fill the ... empty cells with
numbers between 1 and 9 (1 number only in each cell) according the
following guidelines: ... that a number should appear only once on each
row, column and a region." A "region" is what has been called a "box"
earlier in this thread.

Thinking about it, the first two "guidelines" obviate the third. When we
print/display a Sudoku tableau, it is easier on the eyes if the nine
regions are highlighted. However, do they add anything to the need to
check 'the rules' - indeed, is it an easy check?

So, when it comes to evaluating a Sudoku 'solution', each column in the
tableau must feature all of the nine digits, and each row of the
tableau, the same. QED(?) These rules are 1D in nature - taken in-turn.

However, shifting our view slightly, when we look at a Sudoku puzzle we
see the tableau as a matrix, and in two dimensions.

Notice how the evaluations (above) are 1D, but the visual 'picture' is
2D! Thus, if we can dispense with the 'region rule', the only 'use' we
have for regions is for back-end display formatting.

When you separate the two ways to look at a Sudoku, life becomes a lot
easier. We can look at it one 'way' when running the algorithm, and any
'way' when displaying the tableau (remember earlier advice about
"stepwise decomposition" - break large problem into multiple smaller ones!)


@Alan has made the suggestion of using a single list to represent the
tableau (I refer to this a "snake" - rather than a separate construct,
the second row becomes (something like) an extension of the first). The
2D complexity is reduced to 1D - however, keeping track of where rows
begin/end adds (some/different) complexity back in.

The algorithm has been partially-developed by @wulfraed. This is likely
to be a very storage-efficient method, but some may find the 'snake' a
little awkward to visualise, and having to manipulate the math
(especially zero-based) will challenge others.


Contrarily, your own first foray utilised a 2D approach, which is much
easier to visualise. Probably because that's the way Sudoku puzzles are
presented!

Because lists are (typically) built by appending, the techniques which
we may have applied in other languages where arrays are 'dimensioned' at
compile-time, can't be carried-across directly. This is why folk will
talk about writing Python 'pythonically', ie using a Python idiom,
rather than trying to literally translate from a previous-language to
Python, 'word for word'.

NB this is a little different from the confusion of which dimension
represents rows, and which 'holds' the columns (an issue of
"consistency") - from which apparently, you've been suffering/dug
yourself out.

For this reason, I would use 2D/nested dict[ionarie]s. This has the
added-advantage that the author may label each column/row, as-desired.
For whatever reason, these could run 1~9, rather than Python's 0~8 (even
'Row1', 'Row2', and thus distinct from 'Col1' - which may further dispel
earlier confusion/promote consistent use. Such may also assist
comprehension and/or building the logic.


I guess that if we really want to go 'mathematically-nuts' we could
consider the opening Sudoku tableau to be a "sparse matrix". Such
approaches typically store the data as a triplet - (row, column, value).
Thus, each time a row must be evaluated (eg to see if it obeys that
rule), the entire list of triplets must be scanned - similarly for each
column. Added to that, a completed tableau is the exact opposite of a
'sparse' matrix. So, I'll say no more about that idea, and claim its
consideration as 'making progress' - if only because we can concentrate
our investigations elsewhere!


There is another idea that you may like to consider - and perhaps as a
next step from yesterday's report mental-breakthrough/learning. There
are two 'rules'. Why not have two data-structures: one to facilitate the
checking of one rule, and the other, um, the other?

In the case of a Sudoku tableau, our 'data lake' is exactly 81 integers
in size. [pauses to wipe sweat from eyes] So, if we were to duplicate
the data, it's not particularly "expensive".

The idea here, is to maintain a list of nine lists which represent the
nine rows of the tableau. The second pile of nine lists represents the
columns. Yes, when you boil-it-down, the data is repeated - each 'cell'
appears once in a row list and again in a column list - and when a new
value is added to the tableau, it must be added in two places. Ouch!

Computer people will tell you that this 'repetition' is a "code smell" -
a recipe for future-faults (and that assessment is completely correct -
see "DRY = Do not Repeat Yourself Principle").

However, this 'separation' is another way to 'decompose' the problem of
dealing with the tableau into a single 'view' - think horizontally first
(your choice) and prove that, then switch... (after all, this is a
method many use to solve a puzzle!) It is an inefficient solution, but
offers a learning-path and an opportunity to figure-out a simpler
version of 2D lists, and builds upon your 'consistency' determination.
(maybe - YMMV!)


So, after theorising, it was time to 'have some fun'. To compare the
'snake' with a 2D dict solution, I prepared some code and sufficient
tests which progress from:

An initial tableau:

-------------------------------------
|   | 2 | 7 |   | 8 | 9 | 6 |   |   |
-------------------------------------
|   |   |   |   |   | 1 | 7 |   | 2 |
-------------------------------------
| 9 |   |   |   |   |   |   |   |   |
-------------------------------------
|   |   |   |   | 5 |   |   |   | 7 |
-------------------------------------
| 1 | 7 |   |   |   |   |   | 2 | 6 |
-------------------------------------
| 8 |   |   |   | 4 |   |   |   |   |
-------------------------------------
|   |   |   |   |   |   |   |   | 4 |
-------------------------------------
| 2 |   | 8 | 5 |   |   |   |   |   |
-------------------------------------
|   |   | 1 | 8 | 6 |   | 2 | 3 |   |
-------------------------------------

To 'proving' the first row and the first column, and assuring the
handling of data-entry errors:

-------------------------------------
| 3 | 2 | 7 | 4 | 8 | 9 | 6 | 5 | 1 |
-------------------------------------
| 5 |   |   |   |   | 1 | 7 |   | 2 |
-------------------------------------
| 9 |   |   |   |   |   |   |   |   |
-------------------------------------
| 4 |   |   |   | 5 |   |   |   | 7 |
-------------------------------------
| 1 | 7 |   |   |   |   |   | 2 | 6 |
-------------------------------------
| 8 |   |   |   | 4 |   |   |   |   |
-------------------------------------
| 6 |   |   |   |   |   |   |   | 4 |
-------------------------------------
| 2 |   | 8 | 5 |   |   |   |   |   |
-------------------------------------
| 7 |   | 1 | 8 | 6 |   | 2 | 3 |   |
-------------------------------------

NB due apologies - text-only email will not carry the visual information
that the puzzle-values, as-provided, are emboldened; whereas the
user-entries are not.
(which rather ruins the effect)

This emphasises another important question, which IIRC you have already
struck: the realisation that a cell must be in one of three 'states': no
value, an initial-tableau value (as forms the puzzle, and which may not
be changed), and a user-entered value (which may be changed). Thus the
question: how to represent the three 'states'?

Once again, I counsel that the needs/best way to implement the methods
and data-structures implementing the algorithm, may be quite different
from the way the puzzle is 'output'. That's OK - you can perform
necessary translation as part of the output-routine (eg at the same time
as the row and column delimiting lines are added - emboldened around
each box/region (which I didn't bother to do)).


After developing those two 'sample-solutions', I experimented with the
two-lists method, to see if (a) it would work, and (b) to attempt to
assess if it might be an easier learning-approach. So, there are now
three classes, identical in function but different in data-structure and
algorithm.

Each initialises the board/tableau, accepts input (either to set-up the
puzzle, or from the user attempting solution), checks that
entered-values are legal, checks that the board is legal, and displays a
rather Q&D board (as above).

It does not actually play a game (there's no front-end, at all), nor
will it start ringing the bells or flashing lights, once the tableau is
(correctly and completely) filled. Purely the mechanics/the algorithms!

The total weighs-in at about 400-lines. So, I wouldn't be thanked for
posting it to the list! If you (or you, gentle (and patient) reader)
would like to review the code, please contact me directly, and I'll
point you at a 'repo'...

(NB I recommend, if not expect, that you'll attempt your own solution(s)
first - because that's the best way to learn!)

Are the several descriptions sufficient to start you off?
-- 
Regards,
=dn

From phillor9 at gmail.com  Tue Dec  7 19:31:45 2021
From: phillor9 at gmail.com (Phil)
Date: Wed, 8 Dec 2021 11:31:45 +1100
Subject: [Tutor] The Python way and two dimensional lists
In-Reply-To: <son9rn$omd$1@ciao.gmane.io>
References: <dd686338-48ea-8114-190f-c9dc0a185073@gmail.com>
 <sneppr$ifj$1@ciao.gmane.io> <ab220826-db5f-aa05-f1a3-fb60c81fd14d@gmail.com>
 <son9rn$omd$1@ciao.gmane.io>
Message-ID: <a7a0ab0e-ff56-5017-26ca-1fb750a37760@gmail.com>


On 7/12/21 20:34, Alan Gauld via Tutor wrote:

Thank you Alan, Dennis and dn, now I have even more to think about!

I previously mentioned that this current sudoku solver project is one 
that I've translated from a C++ project that I wrote many years ago. It 
does, as it stands, solve all but the more difficult puzzles. I've added 
some extra solving strategies over the past couple of months and I'm 
attempting to make the code, even though it works, more understandable. 
Visualising and manipulating objects in space is one of my many failings 
and one that cost me a job at an IBM interview.

> I believe you are building a model of a Sudoku game?
> But from your description it's not clear what data
> structure you are using. Please just show it!
>
The first list of lists represents the board.

 ??????? self.solution = [[None] * self.num_cols for _ in 
range(self.num_rows)]

The second list of lists represents the Tkinter GUI where the user can 
enter a puzzle to be solved. The programme solves the puzzle, not the user.

 ??????? self.entry_grid = [[None] * self.num_cols for _ in 
range(self.num_rows)]
> If it works it is "correct" for some definition of correct.
Both working correctly and being understandable is the issue here.
> But personally here is how I would tackle your problem.
>
> I'd just use a single list of 81 cells.
I'll think about this. As dn pointed out, knowing where the line endings 
are could be a complication. I'll think about this and helper functions. 
I'm a little reluctant to move from the model that I have because I 
understand how it represents the board, I'm just having a problem with 
manipulating the board grid to extract the columns. I don't have a 
problem with the rows. I will experiment with the class methods provided 
by Dennis, it may persuade me to change from a list of lists to a snake 
list as dn calls it.
> I'd then write helper functions to extract the sublists I needed:
>
> def get_cell(table, row, col)
>
> def get_row(table, row_num)
>
> def get_col(table, col_num)
>
> def get_box(table, row_num, col_num)  # or just box_num?

I don't have a function that just gets a column. Column extraction is 
performed as part of other functions. I know that a function should do 
just one job, so I'll work on that. I have started a function that gets 
the box number but I cannot see, at the moment, how to integrate it with 
the rest of my programme.

> The next problem (based on previous posts) is that your
> cells are sets which are immutable, so you need to:
> 1) create another set of functions for writing back changes
> to a cell - tricky...

I'm not sure that I understand why this is difficult. This is how I 
update a cell:

self.solution[row][col] = set(num)

> OR
> 2) use lists instead of sets because they are mutable.
I had originally used lists instead of sets as a result of my 
translation from arrays to lists. The use of sets was an experiment that 
didn't cause any harm so it's use stayed.
> OR
> 3) Use OOP and make your cells objects with methods
> to add/remove values and using a set internally to
> check uniqueness etc. This would be my choice.
I'll give this some thought as well.
> Personally, I'd use OOP for the table too, and make the
> functions above methods of the table. So you would have
> a table object with 81 mutable cells.
>
> But you haven't mentioned OOP up to now so that may be
> an extra learning curve you don't want to deal with.

A grid class would probably be a good idea, more to think about.

-- 

Regards,
Phil


From phillor9 at gmail.com  Tue Dec  7 20:06:51 2021
From: phillor9 at gmail.com (Phil)
Date: Wed, 8 Dec 2021 12:06:51 +1100
Subject: [Tutor] The Python way and two dimensional lists
In-Reply-To: <ea78d46d-2d51-0773-f7c4-e7d8b0b5f5b1@DancesWithMice.info>
References: <dd686338-48ea-8114-190f-c9dc0a185073@gmail.com>
 <sneppr$ifj$1@ciao.gmane.io> <ab220826-db5f-aa05-f1a3-fb60c81fd14d@gmail.com>
 <CAMPXz=odOWbdekJvDk1_scLkQ1futJBh2-xkGTnzNn2ML46Rrw@mail.gmail.com>
 <cc9843d2-a7a0-d746-59d0-1f51d718f1b4@gmail.com>
 <ea78d46d-2d51-0773-f7c4-e7d8b0b5f5b1@DancesWithMice.info>
Message-ID: <ab9ac00a-abfc-71e4-3be6-756ae66e8f06@gmail.com>


On 8/12/21 08:47, dn via Tutor wrote:
>
> row, column and a region." A "region" is what has been called a "box"
> earlier in this thread.

To me a box is a 3 x 3 grid of cells.


> When you separate the two ways to look at a Sudoku, life becomes a lot
> easier.self.solution[row][found_col] = set(num)mpleted this project

I pride myself in not being a rigid thinker but I suppose I am, other 
wise I would have completed this project by now.


> For this reason, I would use 2D/nested dict[ionarie]s. This has the
> added-advantage that the author may label each column/row, as-desired.

Someone else also suggested the use of a list of dictionaries but I 
didn't see the point at the time. However, now that I've used the 
counter method from the collections module I can see that a dictionary 
might be useful after all.


> The idea here, is to maintain a list of nine lists which represent the
> nine rows of the tableau. The second pile of nine lists represents the
> columns. Yes, when you boil-it-down, the data is repeated - each 'cell'
> appears once in a row list and again in a column list - and when a new
> value is added to the tableau, it must be added in two places. Ouch!

I'm not sure about the idea of two tables, more complications perhaps?


> So, after theorising, it was time to 'have some fun'. To compare the
> 'snake' with a 2D dict solution, I prepared some code and sufficient
> tests which progress from:
>
> An initial tableau:
>
> -------------------------------------
> |   | 2 | 7 |   | 8 | 9 | 6 |   |   |
> -------------------------------------
> |   |   |   |   |   | 1 | 7 |   | 2 |
> -------------------------------------
> | 9 |   |   |   |   |   |   |   |   |
> -------------------------------------
> |   |   |   |   | 5 |   |   |   | 7 |
> -------------------------------------
> | 1 | 7 |   |   |   |   |   | 2 | 6 |
> -------------------------------------
> | 8 |   |   |   | 4 |   |   |   |   |
> -------------------------------------
> |   |   |   |   |   |   |   |   | 4 |
> -------------------------------------
> | 2 |   | 8 | 5 |   |   |   |   |   |
> -------------------------------------
> |   |   | 1 | 8 | 6 |   | 2 | 3 |   |
> -------------------------------------

This is a rather easy puzzle to solve, my programme solved it in 3 
passes. I'm not skiting, just pointing out that I have achieved something.

Are the several descriptions sufficient to start you off?

Yes, thank you and keep your code safe, I may contact you.

-- 

Regards,
Phil


From alan.gauld at yahoo.co.uk  Tue Dec  7 20:10:56 2021
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Wed, 8 Dec 2021 01:10:56 +0000
Subject: [Tutor] The Python way and two dimensional lists
In-Reply-To: <a7a0ab0e-ff56-5017-26ca-1fb750a37760@gmail.com>
References: <dd686338-48ea-8114-190f-c9dc0a185073@gmail.com>
 <sneppr$ifj$1@ciao.gmane.io> <ab220826-db5f-aa05-f1a3-fb60c81fd14d@gmail.com>
 <son9rn$omd$1@ciao.gmane.io> <a7a0ab0e-ff56-5017-26ca-1fb750a37760@gmail.com>
Message-ID: <sop0n0$7s4$1@ciao.gmane.io>

On 08/12/2021 00:31, Phil wrote:

> The second list of lists represents the Tkinter GUI where the user can 
> enter a puzzle to be solved. The programme solves the puzzle, not the user.

I try to keep the presentation logic as far away from
the game logic as possible. Usually drawing a user friendly
picture of algorithmic data is easier than forming algorithms
around user friendly layouts!

>> I'd just use a single list of 81 cells.

> I'll think about this. As dn pointed out, knowing where the line endings 
> are could be a complication.

That's why you need the helper function. It abstracts the
underlying data structure from the higher level concept
of solving the problem per row, column and box. This keeps
the game rules separate from the slicing and dicing of
data collection.

Each function (row/column/box returns the appropriate list
of cells. The validation is the exact same for each, you
just pass the list of 9 cells to the validator function

> I'm a little reluctant to move from the model that I have because I 
> understand how it represents the board, I'm just having a problem with 
> manipulating the board grid to extract the columns. 

Exactly, you are trying to separate rows/columns and boxes
all in one place while simultaneously trying to apply the
rules. That's a lot of mental concepts to juggle in one
piece of code.

> I'd then write helper functions to extract the sublists I needed:
>>
>> def get_cell(table, row, col)
>>
>> def get_row(table, row_num)
>>
>> def get_col(table, col_num)
>>
>> def get_box(table, row_num, col_num)  # or just box_num?
> 
> I don't have a function that just gets a column. Column extraction is 
> performed as part of other functions. I know that a function should do 
> just one job, so I'll work on that. I have started a function that gets 
> the box number but I cannot see, at the moment, how to integrate it with 
> the rest of my programme.

As I understand it you need to check rows columns and boxes.
If its an interactive game you might just need to check the
move for validity and completion of the puzzle - thats much
easier than actually solving the puzzle.

But if you are catering for interactive play rather than
purely solving the puzzle then you probably need helper
functions that can return the required items for any given
cell anyway, so those helpers get used both in checking
and in solving.

>> The next problem (based on previous posts) is that your
>> cells are sets which are immutable, so you need to:
>> 1) create another set of functions for writing back changes
>> to a cell - tricky...
> 
> I'm not sure that I understand why this is difficult. This is how I 
> update a cell:
> 
> self.solution[row][col] = set(num)

I'm not entirely sure what the set holds, I've assuming the set of
possible values, which reduces in size as other cells get completed?
The problem is you cannot easily edit a cell directly, you need to
extract the set, create a new set and then assign the new set back to
the cell. If you use a list instead you can address the cell list
directly and edit in place.

For example if you just use bare sets in a list:

sl = [{1,2},{3,4}]
for st in sl:
    sl = sl + 9  # uh uh, immutable set

Does not modify the original values in sl.
You need to use the index and replace the original list
with a new one.

But using a list:

ll = [[1,2],[3,4]]
for lst in ll:
    lst.append(9)   ## ok, mutable list

Does modify the original list. Much simpler code.

>> 3) Use OOP and make your cells objects with methods
>> Personally, I'd use OOP for the table too, and make the
>... 
> A grid class would probably be a good idea, more to think about.

I notice you said to dn that this originally was C++ so I'll
assume classes and objects are familiar even though you haven't
used them thus far. Classes could simplify the top level code
but will not make the overall code any shorter. But they
should hide the more murky details.

-- 
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  Tue Dec  7 23:43:33 2021
From: PyTutor at DancesWithMice.info (dn)
Date: Wed, 8 Dec 2021 17:43:33 +1300
Subject: [Tutor] The Python way and two dimensional lists
In-Reply-To: <a7a0ab0e-ff56-5017-26ca-1fb750a37760@gmail.com>
References: <dd686338-48ea-8114-190f-c9dc0a185073@gmail.com>
 <sneppr$ifj$1@ciao.gmane.io> <ab220826-db5f-aa05-f1a3-fb60c81fd14d@gmail.com>
 <son9rn$omd$1@ciao.gmane.io> <a7a0ab0e-ff56-5017-26ca-1fb750a37760@gmail.com>
Message-ID: <ef35e544-6ee7-12be-e020-00ef9de01ceb@DancesWithMice.info>

On 08/12/2021 13.31, Phil wrote:
> On 7/12/21 20:34, Alan Gauld via Tutor wrote:
> 
> I previously mentioned that this current sudoku solver project is one
> that I've translated from a C++ project that I wrote many years ago. It
> does, as it stands, solve all but the more difficult puzzles. I've added
> some extra solving strategies over the past couple of months and I'm
> attempting to make the code, even though it works, more understandable.

Which indicates I have 'fallen-down on the job' because the code I
threw-together only assures a 'move' - it doesn't 'design' the next
move/step towards solution!
(further comments, to follow)


> Visualising and manipulating objects in space is one of my many failings
> and one that cost me a job at an IBM interview.

This is a surprise, because back in the ?good, old, days (when our Stone
Age computers ran on dino-ary code), we spent a lot of time drawing
diagrams. In the beginning we were banned from writing code unless we
had first flowchart-ed a solution. Later we moved to DFDs (Data Flow
Diagrams) and DSDs (Data Structure Diagrams) etc.

Yes, the world has moved-on, and many don't feel they are 'working'
unless they're writing code. (wrong!) That doesn't mean that we 'silver
surfers' have moved with it! However, before some young-buck jumps-in to
prove superiority, it actually gives us an advantage, because we can
pick-and-choose between approaches and use the one which works best for
us - instead of 'the one' that 'everyone' uses! Suitability beats
'trending', all day long!

I laugh when people ask me to demonstrate problem-solving
("whiteboarding" a problem/solution), usually with the expectation that
this will present some sort of 'challenge' (like the fear of
public-speaking?); because that's exactly what I do, always, even
something 'small' like this, and even if I have to use the proverbial
paper-napkin or 'back of a post-card' ("no correspondence will be
entered into").

Cognitive Psychology, my research area (yes, that's two counts of
'weird' - at least), has shown that people who write notes, or even
doodle, during a lecture, will remember 'more'. An irony is that many
write notes and then don't need to refer to them later - which becomes
an error when 'logic' says: don't bother making the notes then!

Perhaps you might try sketching a few rows and columns to see if the
visual (and labelling!) helps, particularly when it comes to the problem
of extracting columnar information from what appears to be horizontal
data-structures.


>> I believe you are building a model of a Sudoku game?
>> But from your description it's not clear what data
>> structure you are using. Please just show it!
>>
> The first list of lists represents the board.
> 
> ??????? self.solution = [[None] * self.num_cols for _ in
> range(self.num_rows)]
> 
> The second list of lists represents the Tkinter GUI where the user can
> enter a puzzle to be solved. The programme solves the puzzle, not the user.
> 
> ??????? self.entry_grid = [[None] * self.num_cols for _ in
> range(self.num_rows)]

+1

(refer back to @Alan's advice about Separation of Concerns, and mine
about different ways of 'seeing'/handling the same information)


>> If it works it is "correct" for some definition of correct.
> Both working correctly and being understandable is the issue here.

You've had such a fire-hose of information thrown at you, it'll take
time - and much re-reading and 'reading around', to absorb it all.
Perhaps some slowing down to 'walk before we can run' is in-order?

Much of the advice is related to simplification and solving a series of
'lower-level' problems rather than trying to do 'too much' in one go.
(this echoed and echoing...)


>> But personally here is how I would tackle your problem.
>>
>> I'd just use a single list of 81 cells.
> I'll think about this. As dn pointed out, knowing where the line endings
> are could be a complication. I'll think about this and helper functions.
> I'm a little reluctant to move from the model that I have because I
> understand how it represents the board, I'm just having a problem with
> manipulating the board grid to extract the columns. I don't have a
> problem with the rows. I will experiment with the class methods provided
> by Dennis, it may persuade me to change from a list of lists to a snake
> list as dn calls it.
>> I'd then write helper functions to extract the sublists I needed:
>>
>> def get_cell(table, row, col)
>>
>> def get_row(table, row_num)
>>
>> def get_col(table, col_num)
>>
>> def get_box(table, row_num, col_num)? # or just box_num?
> 
> I don't have a function that just gets a column. Column extraction is
> performed as part of other functions. I know that a function should do
> just one job, so I'll work on that. I have started a function that gets
> the box number but I cannot see, at the moment, how to integrate it with
> the rest of my programme.

Neither could I, but then 'solving' wasn't in the spec.

With regard to these 'helper functions' (or methods), three of us have
now suggested the exact same thing. (I'll be billing both of them for
"stealing" my idea...)

Because selecting a column of data will be required at various stages
within the program[me], doesn't that SHOUT: "make me a function"? If
it's only a few lines of code (see below), that's not a problem. A
function (once tested and proven) is one less 'problem' to consider!

(conversely, a function with only one line of code is possibly NOT a
valid candidate) Thinking 'small' is probably a virtue, at this stage of
learning.


With the two-list idea, finding columnar-data is trivial - which column,
ie which list, do you want? EOJ!


With the 2D dicts (that is a dict of dicts, not a dict of lists, or
v-v!), what is required is to 'hold' the row-index fixed, and iterate
the column-index. I'd think this very familiar from the approaches
required/imposed/implemented in earlier languages, eg:

    def check_col( self, col: int, value: int, ) -> None:
        """Assure no duplicate values."""
        column = [ self.board[ row ][ col ]
                   for row in self.board_dimensions
                   ]
        if value in column:
            raise ValueError( "No duplicate values." )

Notice that because my partial-solution/illustration can enjoy the
relative-luxury of not needing a transition between algorithm
data-structures and GUI-structures, the only time column-data is needed
is during the duplicate-check.

In your situation, it would be better to split the above function into
halves, perhaps something like (untested):

    def get_column( self, col: int, ) -> list[ int ]:
        """Extract nominated column-data from the board."""
        return [ self.board[ row ][ col ]
                   for row in self.board_dimensions
                   ]

    def check_col( self, col: int, value: int, ) -> None:
        """Assure no duplicate values."""
        column = self.get_column( col )
        if value in column:
            raise ValueError( "No duplicate values." )

If the list-comprehension (in the return) is more complex than
preferred, 'unwind' it to a multi-line for-loop, appending one item per
loop, with preparatory list declaration, and use that list as the
return-value.

Now, get_column() can be used wherever needed, from multiple points in
the code, etc.



The solution for the 'snake' is to use slices (and 'striding') - by
definition all of the values which constitute one 'column' must be nine
cells apart from each-other in the 1D 'snake'. Thus, row = 0, column = 0
is the zero-th cell, and row = 1, column = 0 will have a snake-index of
9, ie 0 + 9. Proceeding: row = 2, column = 0 is nine cells further
'along', ie 0 + 9 + 9. Pretty soon, you'll notice that instead of adding
9 each time, we could multiply by the number of rows 'down'!

    def get_col( self, col_index: int, ) -> None:
        """Return single column from board."""
        first_cell_index = col_index % 9
        return [ self.board[ cell_index ]
                 for cell_index in range( first_cell_index, 81, 9 )
                 ]

The reasons for the "remainder", is the presumption that the column
could be defined as that above-and-below any cell on the board, cf a
column-number. Once the nominated-cell's column is ascertained, the
column-number becomes the start of the 'stride'.
(81 being the length of the snaking tableau, and 9 being the width of
each row)


As you can see, in both 'solutions', a 'get-column' "helper function"
furnishes utility!

Also, here's-hoping that one-or-the-other will help to make the
technique 'click' in your mind.
(no 'click' is perhaps not a snooty, cognitive-psych term - but who will
understand these days if I say "when the penny drops"? Maybe an "ahah
moment"!)


>> The next problem (based on previous posts) is that your
>> cells are sets which are immutable, so you need to:
>> 1) create another set of functions for writing back changes
>> to a cell - tricky...
> 
> I'm not sure that I understand why this is difficult. This is how I
> update a cell:
> 
> self.solution[row][col] = set(num)

Why a set?

How to be sure that the cell is not already 'occupied' by part of the
puzzle-definition?


>> OR
>> 2) use lists instead of sets because they are mutable.
> I had originally used lists instead of sets as a result of my
> translation from arrays to lists. The use of sets was an experiment that
> didn't cause any harm so it's use stayed.

Be careful! A set has no (guarantee of) sequence.

Sequence is important when it comes to the tableau.

Sets are useful when it comes to ensuring that a digit isn't used twice
in one row/column/region...

(as below)
= tools for the job


>> OR
>> 3) Use OOP and make your cells objects with methods
>> to add/remove values and using a set internally to
>> check uniqueness etc. This would be my choice.
> I'll give this some thought as well.
>> Personally, I'd use OOP for the table too, and make the
>> functions above methods of the table. So you would have
>> a table object with 81 mutable cells.
>>
>> But you haven't mentioned OOP up to now so that may be
>> an extra learning curve you don't want to deal with.
> 
> A grid class would probably be a good idea, more to think about.


> I pride myself in not being a rigid thinker but I suppose I am, other wise I would have completed this project by now.

You have been considering so many alternatives, started and re-started,
are learning Python, and trying to 'remember' old-code. Confusion reigns!


> I'm not sure about the idea of two tables, more complications perhaps?

"Two" sounds more complicated than "one'. However, it will have the
advantage of forcing you to concentrate on one (little) thing at a time.

If you take-to-heart the suggestion of 'helper functions', you can do
everything (easier) that needs to be done with rows first. Thereafter,
you can put such thoughts out of your mind, and concentrate on similar
for columns. Because the two function independently at all times, except
when data is (twice) added to the tableau - only one is necessary to
assess completeness/success/transfer to output, etc; it does not make
'the work' more complicated.


However, success at this is going to require the process of sitting-down
and planning/sketching/charting. When you know how to put individual
data-points into the row/column/snake/tableau, how to pull-out data from
specific cells, or entire row/column constructs, and such-like; then you
have the 'little problems' which can be individually solved, coded
one-at-a-time AND you can test each as you go, eg if column-n is
requested the value-returned will be of x-type and contain the following
values... This enables you to ensure that each helper function works
(properly!) BEFORE incorporating it/the columnar-data retrieved, into a
wider part of the algorithm!

eg if the final 'solution' is presented with whole rows of 1s and rows
of 2s, there is plainly a fault - but where? It is unlikely to be in the
GUI, or the solver. Almost certainly it will 'start' at a lower-level,
in - (wait for it) - a helper-function. So, testing each 'little bit'
first, is worthwhile, because it adds confidence as the snow-ball starts
to grow larger, and at the same time as that happens, reduces the number
of things to be kept in-mind...


> This is a rather easy puzzle to solve, my programme solved it in 3 passes. I'm not skiting, just pointing out that I have achieved something.

...and well done! Nothing succeeds like success!

Yes, I think it was described as a 'medium' or maybe 'hard' puzzle. No
matter, it was only needed to test those (dare I say it again?) 'helper
functions'.


> Are the several descriptions sufficient to start you off?
> 
> Yes, thank you and keep your code safe, I may contact you.

Because you are treating this as a learning exercise (and after
reviewing it again), I'm still comfortable recommending the two-list
approach. Once solved, you won't keep it (shouldn't keep it?) but it
might help with solving the non-Python problems you have outlined.

Once you have a 'model' straightened-out in your mind (confidence that
you know where to go and how to get there), then I'd suggest
using/expanding/amending that set of helper-functions to implement the
2D dictionary approach.

Once you're really feeling like you've 'earned your stripes', then have
a go at the 'snake'.


However, if you prefer the more mathematical type of problem/algorithm,
if the first step and/or diagramming/charting gives you confidence, then
maybe snake-second.

An algorithmic thinker will prefer the 'snake', because (s)he has
greater confidence in 'playing with numbers' and an ability to 'see the
patterns'.

The 2D approach has the advantage that one is more easily able to 'see'
what is what, and which is where.


That code is sitting in my GitLab instance - but remember, its purpose
is to illustrate 'the basics' and compare approaches. It does not 'do'
half of what your system apparently intends!

-- 
Regards =dn

-- 
Regards,
=dn

From wlfraed at ix.netcom.com  Wed Dec  8 00:56:38 2021
From: wlfraed at ix.netcom.com (Dennis Lee Bieber)
Date: Wed, 08 Dec 2021 00:56:38 -0500
Subject: [Tutor] The Python way and two dimensional lists
References: <dd686338-48ea-8114-190f-c9dc0a185073@gmail.com>
 <sneppr$ifj$1@ciao.gmane.io> <ab220826-db5f-aa05-f1a3-fb60c81fd14d@gmail.com>
 <CAMPXz=odOWbdekJvDk1_scLkQ1futJBh2-xkGTnzNn2ML46Rrw@mail.gmail.com>
 <cc9843d2-a7a0-d746-59d0-1f51d718f1b4@gmail.com>
 <ea78d46d-2d51-0773-f7c4-e7d8b0b5f5b1@DancesWithMice.info>
 <ab9ac00a-abfc-71e4-3be6-756ae66e8f06@gmail.com>
Message-ID: <sfh0rgdafoct2l1r8aop49jcjvadlg63mh@4ax.com>

On Wed, 8 Dec 2021 12:06:51 +1100, Phil <phillor9 at gmail.com> declaimed the
following:


>This is a rather easy puzzle to solve, my programme solved it in 3 
>passes. I'm not skiting, just pointing out that I have achieved something.
>
	How do you define "passes"?

	Just for giggles I took an old, unfinished solver I'd started over a
decade ago, and modified it for Python3.x (I think I'd already 2to3 over it
as the "print" statements were up-to-date -- but the change of  "int / int
=> float" killed it. Had to change the "/" to "//".

	I'm going to put it as text attachments to avoiding spamming too many
-- as I recall the group does allow plain text as an attachment. I'll also
include a run of the program with your data set. As you'll see, I only
manage to solve the simpler levels and reach deadlock for some cases.

	This code does NOT use the class I illustrated earlier. 1) Python2.x
hadn't introduced "sets" at the time I wrote it, so everything is lists; 2)
it uses three classes: Cell (one cell with flags for locked [provided start
value, and maybe solved value] along with a list of candidates); Grid (a
3x3 set of Cell -- your box/region); Table (a 3x3 set of Grid).


-- 
	Wulfraed                 Dennis Lee Bieber         AF6VN
	wlfraed at ix.netcom.com    http://wlfraed.microdiversity.freeddns.org/
-------------- next part --------------
#   Dec 8 2021 -- update to Python 3.x

import time


class Cell(object):
    def __init__(self):
        self.locked = False     #   final value found
        self.value = None
        self.candidates = [1, 2, 3, 4, 5, 6, 7, 8, 9]

    def set(self, value):
        self.locked = True
        self.value = value
        self.candidates = None

    def eliminate(self, value):
        if not self.locked:
            if value in self.candidates:
                self.candidates.remove(value)
                return True
        return False


class Grid(object):
    def __init__(self):
        self.cells = [ [Cell(), Cell(), Cell()],
                       [Cell(), Cell(), Cell()],
                       [Cell(), Cell(), Cell()] ]

    def completed(self):
        for r in range(3):
            for c in range(3):
                if not self.cells[r][c].locked:
                    return False
        return True

class Table(object):
    def __init__(self):
        self.grids = [ [Grid(), Grid(), Grid()],
                       [Grid(), Grid(), Grid()],
                       [Grid(), Grid(), Grid()] ]

        self.rows = [None] * 9
        for r in range(9):
            row = [None] * 9
            for c in range(9):
                row[c] = self.grids[r // 3][c // 3].cells[r % 3][c % 3]

    def set(self, row, col, value):
        self.grids[row // 3][col // 3].cells[row % 3][col % 3].set(value)

    def get(self, row, col):
        return self.grids[row // 3][col // 3].cells[row % 3][col % 3]

    def eliminate(self, row, col, value):
        changed = False
        for c in range(9):
            changed = (self.grids[row // 3][c // 3].cells[row % 3][c % 3].eliminate(value)
                       or changed)
                
        for r in range(9):
            changed = (self.grids[r // 3][col // 3].cells[r % 3][col % 3].eliminate(value)
                       or changed)

        grid = self.grids[row // 3][col // 3]
        for c in range(3):
            for r in range(3):
                changed = (grid.cells[r][c].eliminate(value) or changed)

        return changed                    

    def display(self):
        print("\n\n0 1 2 3 4 5 6 7 8\n==================")
        for r in range(9):
            for c in range(9):
                if self.get(r, c).value:
                    print("%s" % (self.get(r, c).value), end=' ')
                else:
                    print(" ", end=' ')
            print("|%s" % r)

    def completed(self):
        for r in range(3):
            for c in range(3):
                if not self.grids[r][c].completed():
                    return False
        return True
                    

if __name__ == "__main__":
    myTable = Table()
    print("\n\nEnter a value of 0 to exit setup")
    print("\tRow and Column range 0..8")

    while True:
        cin = input("Enter the cell Value Row Column (space separated): ")
        try:
            cv, cr, cc = cin.split()
            value = int(cv)
            if value == 0: break
            row = int(cr)
            col = int(cc)
            myTable.set(row, col, value)
            myTable.display()
            print()
        except:
            print("Error processing input: try again")
            pass

    print("\n\nBuilding table ", end=' ')
    for r in range(9):
        for c in range(9):
            if myTable.get(r, c).locked:
                myTable.eliminate(r, c, myTable.get(r, c).value)

    myTable.display()
    
    while True:
        print("Evaluating   ")
        change = False
        done = True
        for r in range(9):
            for c in range(9):
                print(".", end=' ')
                time.sleep(0.01)
                if not myTable.get(r, c).locked:
                    if len(myTable.get(r, c).candidates) == 1:
                           myTable.set(r, c, myTable.get(r, c).candidates[0])
                           change = myTable.eliminate(r, c,
                                                      myTable.get(r, c).value)
                           myTable.display()
                           if change: break
            if change: break
            
        print()

        #   check for completion
        if myTable.completed():
            print("Completed")
            break

        if not change:
            deadlock = True
            print("Resolving initial deadlock")
            for gr in range(3):
                for gc in range(3):
                    myGrid = myTable.grids[gr][gc]
                    count = [0] * 9
                    if deadlock:
                        for r in range(3):
                            for c in range(3):
                                if deadlock and myGrid.cells[r][c].candidates:
                                    for n in myGrid.cells[r][c].candidates:
                                        count[n-1] += 1
                                    
                        try:
                            n = count.index(1) + 1
                            deadlock = False
                            for r in range(3):
                                for c in range(3):
                                    if (myGrid.cells[r][c].candidates
                                        and n in myGrid.cells[r][c].candidates):
                                        myGrid.cells[r][c].set(n)
                                        myTable.eliminate(gr * 3 + r, gc * 3 + c, n)
                                        myTable.display()
                        except:
                            pass

            if deadlock:
                print("Deadlocked; must be resolved manually")
                cin = input("Enter value row column: ")
                cv, cr, cc = cin.split()
                value = int(cv)
                row = int(cr)
                col = int(cc)
                myTable.set(row, col, value)
                myTable.eliminate(row, col, value)
                myTable.display()
                cv, cr, cc = cin.split()
                value = int(cv)
                row = int(cr)
                col = int(cc)
                myTable.set(row, col, value)
                myTable.eliminate(row, col, value)
-------------- next part --------------
C:\Users\Wulfraed\Documents\_Hg-Repositories\Python Progs>sudoku.py


Enter a value of 0 to exit setup
        Row and Column range 0..8
Enter the cell Value Row Column (space separated): 2 0 1


0 1 2 3 4 5 6 7 8
==================
  2               |0
                  |1
                  |2
                  |3
                  |4
                  |5
                  |6
                  |7
                  |8

Enter the cell Value Row Column (space separated): 7 0 2


0 1 2 3 4 5 6 7 8
==================
  2 7             |0
                  |1
                  |2
                  |3
                  |4
                  |5
                  |6
                  |7
                  |8

Enter the cell Value Row Column (space separated): 8 0 4


0 1 2 3 4 5 6 7 8
==================
  2 7   8         |0
                  |1
                  |2
                  |3
                  |4
                  |5
                  |6
                  |7
                  |8

Enter the cell Value Row Column (space separated): 9 0 5


0 1 2 3 4 5 6 7 8
==================
  2 7   8 9       |0
                  |1
                  |2
                  |3
                  |4
                  |5
                  |6
                  |7
                  |8

Enter the cell Value Row Column (space separated): 6 0 6


0 1 2 3 4 5 6 7 8
==================
  2 7   8 9 6     |0
                  |1
                  |2
                  |3
                  |4
                  |5
                  |6
                  |7
                  |8

Enter the cell Value Row Column (space separated): 1 1 5


0 1 2 3 4 5 6 7 8
==================
  2 7   8 9 6     |0
          1       |1
                  |2
                  |3
                  |4
                  |5
                  |6
                  |7
                  |8

Enter the cell Value Row Column (space separated): 7 1 6


0 1 2 3 4 5 6 7 8
==================
  2 7   8 9 6     |0
          1 7     |1
                  |2
                  |3
                  |4
                  |5
                  |6
                  |7
                  |8

Enter the cell Value Row Column (space separated): 2 1 8


0 1 2 3 4 5 6 7 8
==================
  2 7   8 9 6     |0
          1 7   2 |1
                  |2
                  |3
                  |4
                  |5
                  |6
                  |7
                  |8

Enter the cell Value Row Column (space separated): 9 2 0


0 1 2 3 4 5 6 7 8
==================
  2 7   8 9 6     |0
          1 7   2 |1
9                 |2
                  |3
                  |4
                  |5
                  |6
                  |7
                  |8

Enter the cell Value Row Column (space separated): 5 3 4


0 1 2 3 4 5 6 7 8
==================
  2 7   8 9 6     |0
          1 7   2 |1
9                 |2
        5         |3
                  |4
                  |5
                  |6
                  |7
                  |8

Enter the cell Value Row Column (space separated): 7 3 8


0 1 2 3 4 5 6 7 8
==================
  2 7   8 9 6     |0
          1 7   2 |1
9                 |2
        5       7 |3
                  |4
                  |5
                  |6
                  |7
                  |8

Enter the cell Value Row Column (space separated): 1 4 0


0 1 2 3 4 5 6 7 8
==================
  2 7   8 9 6     |0
          1 7   2 |1
9                 |2
        5       7 |3
1                 |4
                  |5
                  |6
                  |7
                  |8

Enter the cell Value Row Column (space separated): 7 4 1


0 1 2 3 4 5 6 7 8
==================
  2 7   8 9 6     |0
          1 7   2 |1
9                 |2
        5       7 |3
1 7               |4
                  |5
                  |6
                  |7
                  |8

Enter the cell Value Row Column (space separated): 2 4 7


0 1 2 3 4 5 6 7 8
==================
  2 7   8 9 6     |0
          1 7   2 |1
9                 |2
        5       7 |3
1 7           2   |4
                  |5
                  |6
                  |7
                  |8

Enter the cell Value Row Column (space separated): 6 4 8


0 1 2 3 4 5 6 7 8
==================
  2 7   8 9 6     |0
          1 7   2 |1
9                 |2
        5       7 |3
1 7           2 6 |4
                  |5
                  |6
                  |7
                  |8

Enter the cell Value Row Column (space separated): 8 5 0


0 1 2 3 4 5 6 7 8
==================
  2 7   8 9 6     |0
          1 7   2 |1
9                 |2
        5       7 |3
1 7           2 6 |4
8                 |5
                  |6
                  |7
                  |8

Enter the cell Value Row Column (space separated): 4 5 4


0 1 2 3 4 5 6 7 8
==================
  2 7   8 9 6     |0
          1 7   2 |1
9                 |2
        5       7 |3
1 7           2 6 |4
8       4         |5
                  |6
                  |7
                  |8

Enter the cell Value Row Column (space separated): 4 6 8


0 1 2 3 4 5 6 7 8
==================
  2 7   8 9 6     |0
          1 7   2 |1
9                 |2
        5       7 |3
1 7           2 6 |4
8       4         |5
                4 |6
                  |7
                  |8

Enter the cell Value Row Column (space separated): 2 7 0


0 1 2 3 4 5 6 7 8
==================
  2 7   8 9 6     |0
          1 7   2 |1
9                 |2
        5       7 |3
1 7           2 6 |4
8       4         |5
                4 |6
2                 |7
                  |8

Enter the cell Value Row Column (space separated): 8 7 2


0 1 2 3 4 5 6 7 8
==================
  2 7   8 9 6     |0
          1 7   2 |1
9                 |2
        5       7 |3
1 7           2 6 |4
8       4         |5
                4 |6
2   8             |7
                  |8

Enter the cell Value Row Column (space separated): 5 7 3


0 1 2 3 4 5 6 7 8
==================
  2 7   8 9 6     |0
          1 7   2 |1
9                 |2
        5       7 |3
1 7           2 6 |4
8       4         |5
                4 |6
2   8 5           |7
                  |8

Enter the cell Value Row Column (space separated): 1 8 2


0 1 2 3 4 5 6 7 8
==================
  2 7   8 9 6     |0
          1 7   2 |1
9                 |2
        5       7 |3
1 7           2 6 |4
8       4         |5
                4 |6
2   8 5           |7
    1             |8

Enter the cell Value Row Column (space separated): 8 8 3


0 1 2 3 4 5 6 7 8
==================
  2 7   8 9 6     |0
          1 7   2 |1
9                 |2
        5       7 |3
1 7           2 6 |4
8       4         |5
                4 |6
2   8 5           |7
    1 8           |8

Enter the cell Value Row Column (space separated): 6 8 4


0 1 2 3 4 5 6 7 8
==================
  2 7   8 9 6     |0
          1 7   2 |1
9                 |2
        5       7 |3
1 7           2 6 |4
8       4         |5
                4 |6
2   8 5           |7
    1 8 6         |8

Enter the cell Value Row Column (space separated): 2 8 6


0 1 2 3 4 5 6 7 8
==================
  2 7   8 9 6     |0
          1 7   2 |1
9                 |2
        5       7 |3
1 7           2 6 |4
8       4         |5
                4 |6
2   8 5           |7
    1 8 6   2     |8

Enter the cell Value Row Column (space separated): 3 8 7


0 1 2 3 4 5 6 7 8
==================
  2 7   8 9 6     |0
          1 7   2 |1
9                 |2
        5       7 |3
1 7           2 6 |4
8       4         |5
                4 |6
2   8 5           |7
    1 8 6   2 3   |8

Enter the cell Value Row Column (space separated): 0 0 0


Building table

0 1 2 3 4 5 6 7 8
==================
  2 7   8 9 6     |0
          1 7   2 |1
9                 |2
        5       7 |3
1 7           2 6 |4
8       4         |5
                4 |6
2   8 5           |7
    1 8 6   2 3   |8
Evaluating
. . . . . . . . . . . . . .

0 1 2 3 4 5 6 7 8
==================
  2 7   8 9 6     |0
        3 1 7   2 |1
9                 |2
        5       7 |3
1 7           2 6 |4
8       4         |5
                4 |6
2   8 5           |7
    1 8 6   2 3   |8

Evaluating
. . . .

0 1 2 3 4 5 6 7 8
==================
  2 7 4 8 9 6     |0
        3 1 7   2 |1
9                 |2
        5       7 |3
1 7           2 6 |4
8       4         |5
                4 |6
2   8 5           |7
    1 8 6   2 3   |8

Evaluating
. . . . . . . . . . . . .

0 1 2 3 4 5 6 7 8
==================
  2 7 4 8 9 6     |0
      6 3 1 7   2 |1
9                 |2
        5       7 |3
1 7           2 6 |4
8       4         |5
                4 |6
2   8 5           |7
    1 8 6   2 3   |8

Evaluating
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

0 1 2 3 4 5 6 7 8
==================
  2 7 4 8 9 6     |0
      6 3 1 7   2 |1
9                 |2
        5       7 |3
1 7     9     2 6 |4
8       4         |5
                4 |6
2   8 5           |7
    1 8 6   2 3   |8

Evaluating
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

0 1 2 3 4 5 6 7 8
==================
  2 7 4 8 9 6     |0
      6 3 1 7   2 |1
9                 |2
        5       7 |3
1 7   3 9     2 6 |4
8       4         |5
                4 |6
2   8 5           |7
    1 8 6   2 3   |8

Evaluating
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

0 1 2 3 4 5 6 7 8
==================
  2 7 4 8 9 6     |0
      6 3 1 7   2 |1
9                 |2
        5       7 |3
1 7   3 9 8   2 6 |4
8       4         |5
                4 |6
2   8 5           |7
    1 8 6   2 3   |8

Evaluating
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Resolving initial deadlock


0 1 2 3 4 5 6 7 8
==================
  2 7 4 8 9 6     |0
      6 3 1 7   2 |1
9 1               |2
        5       7 |3
1 7   3 9 8   2 6 |4
8       4         |5
                4 |6
2   8 5           |7
    1 8 6   2 3   |8
Evaluating
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Resolving initial deadlock


0 1 2 3 4 5 6 7 8
==================
  2 7 4 8 9 6     |0
      6 3 1 7   2 |1
9 1 6             |2
        5       7 |3
1 7   3 9 8   2 6 |4
8       4         |5
                4 |6
2   8 5           |7
    1 8 6   2 3   |8
Evaluating
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Resolving initial deadlock


0 1 2 3 4 5 6 7 8
==================
3 2 7 4 8 9 6     |0
      6 3 1 7   2 |1
9 1 6             |2
        5       7 |3
1 7   3 9 8   2 6 |4
8       4         |5
                4 |6
2   8 5           |7
    1 8 6   2 3   |8
Evaluating
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Resolving initial deadlock


0 1 2 3 4 5 6 7 8
==================
3 2 7 4 8 9 6     |0
  8   6 3 1 7   2 |1
9 1 6             |2
        5       7 |3
1 7   3 9 8   2 6 |4
8       4         |5
                4 |6
2   8 5           |7
    1 8 6   2 3   |8
Evaluating
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Resolving initial deadlock


0 1 2 3 4 5 6 7 8
==================
3 2 7 4 8 9 6     |0
  8   6 3 1 7   2 |1
9 1 6     5       |2
        5       7 |3
1 7   3 9 8   2 6 |4
8       4         |5
                4 |6
2   8 5           |7
    1 8 6   2 3   |8
Evaluating
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Resolving initial deadlock


0 1 2 3 4 5 6 7 8
==================
3 2 7 4 8 9 6     |0
  8   6 3 1 7 9 2 |1
9 1 6     5       |2
        5       7 |3
1 7   3 9 8   2 6 |4
8       4         |5
                4 |6
2   8 5           |7
    1 8 6   2 3   |8
Evaluating
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Resolving initial deadlock


0 1 2 3 4 5 6 7 8
==================
3 2 7 4 8 9 6     |0
  8   6 3 1 7 9 2 |1
9 1 6     5       |2
        5       7 |3
1 7   3 9 8   2 6 |4
8       4         |5
      9         4 |6
2   8 5           |7
    1 8 6   2 3   |8
Evaluating
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Resolving initial deadlock
Deadlocked; must be resolved manually
Enter value row column:


From wlfraed at ix.netcom.com  Wed Dec  8 01:23:04 2021
From: wlfraed at ix.netcom.com (Dennis Lee Bieber)
Date: Wed, 08 Dec 2021 01:23:04 -0500
Subject: [Tutor] The Python way and two dimensional lists
References: <dd686338-48ea-8114-190f-c9dc0a185073@gmail.com>
 <sneppr$ifj$1@ciao.gmane.io> <ab220826-db5f-aa05-f1a3-fb60c81fd14d@gmail.com>
 <son9rn$omd$1@ciao.gmane.io> <a7a0ab0e-ff56-5017-26ca-1fb750a37760@gmail.com>
Message-ID: <e2j0rg9dl2octuk1nha4kf912hgbn4bchj@4ax.com>

On Wed, 8 Dec 2021 11:31:45 +1100, Phil <phillor9 at gmail.com> declaimed the
following:


>Visualising and manipulating objects in space is one of my many failings 
>and one that cost me a job at an IBM interview.
>
	You would have hated the ASVAB of the mid-70s... One section of the
test is: given a "flattened/unfolded" box pattern, which of the four boxes
(where you only see three sides) matches the FU pattern.

{I'm fairly certain I did well in that area... But I'm not sure which part
of the score it applied to... My worst score was in "Clerical" -- a 78 I
believe -- and that was still better than some of my class-mates best
sections. https://www.military.com/join-armed-forces/asvab Clerical doesn't
seem to be a category in the current ASVAB
https://www.military.com/join-armed-forces/asvab/versions-of-asvab.html --
there it is, on the page showing how the categories are summed to get final
results
https://www.military.com/join-armed-forces/asvab/asvab-and-army-jobs.html
At the time, the student ASVAB only reported on something like 6 final
groupings}



-- 
	Wulfraed                 Dennis Lee Bieber         AF6VN
	wlfraed at ix.netcom.com    http://wlfraed.microdiversity.freeddns.org/


From phillor9 at gmail.com  Wed Dec  8 03:14:05 2021
From: phillor9 at gmail.com (Phil)
Date: Wed, 8 Dec 2021 19:14:05 +1100
Subject: [Tutor] The Python way and two dimensional lists
In-Reply-To: <e2j0rg9dl2octuk1nha4kf912hgbn4bchj@4ax.com>
References: <dd686338-48ea-8114-190f-c9dc0a185073@gmail.com>
 <sneppr$ifj$1@ciao.gmane.io> <ab220826-db5f-aa05-f1a3-fb60c81fd14d@gmail.com>
 <son9rn$omd$1@ciao.gmane.io> <a7a0ab0e-ff56-5017-26ca-1fb750a37760@gmail.com>
 <e2j0rg9dl2octuk1nha4kf912hgbn4bchj@4ax.com>
Message-ID: <90b75927-a14c-1c95-451f-17e1ba597b29@gmail.com>


On 8/12/21 17:23, Dennis Lee Bieber wrote:
> On Wed, 8 Dec 2021 11:31:45 +1100, Phil <phillor9 at gmail.com> declaimed the
> following:
>
>
>> Visualising and manipulating objects in space is one of my many failings
>> and one that cost me a job at an IBM interview.
>>
> 	You would have hated the ASVAB of the mid-70s... One section of the
> test is: given a "flattened/unfolded" box pattern, which of the four boxes
> (where you only see three sides) matches the FU pattern.

That's exactly the test that I was referring to. I passed the phone 
interview but my spatial ability didn't measure up. Back in the olden 
days I could read a text book from cover to cover and remember enough to 
achieve a distinction, or better. Now, I cannot remember what I had for 
lunch.

-- 

Regards,
Phil


From DomainAdmin at DancesWithMice.info  Tue Dec  7 23:41:15 2021
From: DomainAdmin at DancesWithMice.info (David L Neil)
Date: Wed, 8 Dec 2021 17:41:15 +1300
Subject: [Tutor] The Python way and two dimensional lists
In-Reply-To: <a7a0ab0e-ff56-5017-26ca-1fb750a37760@gmail.com>
References: <dd686338-48ea-8114-190f-c9dc0a185073@gmail.com>
 <sneppr$ifj$1@ciao.gmane.io> <ab220826-db5f-aa05-f1a3-fb60c81fd14d@gmail.com>
 <son9rn$omd$1@ciao.gmane.io> <a7a0ab0e-ff56-5017-26ca-1fb750a37760@gmail.com>
Message-ID: <6e65603b-7704-79b9-0695-19337c9505ea@DancesWithMice.info>

On 08/12/2021 13.31, Phil wrote:
> On 7/12/21 20:34, Alan Gauld via Tutor wrote:
> 
> I previously mentioned that this current sudoku solver project is one
> that I've translated from a C++ project that I wrote many years ago. It
> does, as it stands, solve all but the more difficult puzzles. I've added
> some extra solving strategies over the past couple of months and I'm
> attempting to make the code, even though it works, more understandable.

Which indicates I have 'fallen-down on the job' because the code I
threw-together only assures a 'move' - it doesn't 'design' the next
move/step towards solution!
(further comments, to follow)


> Visualising and manipulating objects in space is one of my many failings
> and one that cost me a job at an IBM interview.

This is a surprise, because back in the ?good, old, days (when our Stone
Age computers ran on dino-ary code), we spent a lot of time drawing
diagrams. In the beginning we were banned from writing code unless we
had first flowchart-ed a solution. Later we moved to DFDs (Data Flow
Diagrams) and DSDs (Data Structure Diagrams) etc.

Yes, the world has moved-on, and many don't feel they are 'working'
unless they're writing code. (wrong!) That doesn't mean that we 'silver
surfers' have moved with it! However, before some young-buck jumps-in to
prove superiority, it actually gives us an advantage, because we can
pick-and-choose between approaches and use the one which works best for
us - instead of 'the one' that 'everyone' uses! Suitability beats
'trending', all day long!

I laugh when people ask me to demonstrate problem-solving
("whiteboarding" a problem/solution), usually with the expectation that
this will present some sort of 'challenge' (like the fear of
public-speaking?); because that's exactly what I do, always, even
something 'small' like this, and even if I have to use the proverbial
paper-napkin or 'back of a post-card' ("no correspondence will be
entered into").

Cognitive Psychology, my research area (yes, that's two counts of
'weird' - at least), has shown that people who write notes, or even
doodle, during a lecture, will remember 'more'. An irony is that many
write notes and then don't need to refer to them later - which becomes
an error when 'logic' says: don't bother making the notes then!

Perhaps you might try sketching a few rows and columns to see if the
visual (and labelling!) helps, particularly when it comes to the problem
of extracting columnar information from what appears to be horizontal
data-structures.


>> I believe you are building a model of a Sudoku game?
>> But from your description it's not clear what data
>> structure you are using. Please just show it!
>>
> The first list of lists represents the board.
> 
> ??????? self.solution = [[None] * self.num_cols for _ in
> range(self.num_rows)]
> 
> The second list of lists represents the Tkinter GUI where the user can
> enter a puzzle to be solved. The programme solves the puzzle, not the user.
> 
> ??????? self.entry_grid = [[None] * self.num_cols for _ in
> range(self.num_rows)]

+1

(refer back to @Alan's advice about Separation of Concerns, and mine
about different ways of 'seeing'/handling the same information)


>> If it works it is "correct" for some definition of correct.
> Both working correctly and being understandable is the issue here.

You've had such a fire-hose of information thrown at you, it'll take
time - and much re-reading and 'reading around', to absorb it all.
Perhaps some slowing down to 'walk before we can run' is in-order?

Much of the advice is related to simplification and solving a series of
'lower-level' problems rather than trying to do 'too much' in one go.
(this echoed and echoing...)


>> But personally here is how I would tackle your problem.
>>
>> I'd just use a single list of 81 cells.
> I'll think about this. As dn pointed out, knowing where the line endings
> are could be a complication. I'll think about this and helper functions.
> I'm a little reluctant to move from the model that I have because I
> understand how it represents the board, I'm just having a problem with
> manipulating the board grid to extract the columns. I don't have a
> problem with the rows. I will experiment with the class methods provided
> by Dennis, it may persuade me to change from a list of lists to a snake
> list as dn calls it.
>> I'd then write helper functions to extract the sublists I needed:
>>
>> def get_cell(table, row, col)
>>
>> def get_row(table, row_num)
>>
>> def get_col(table, col_num)
>>
>> def get_box(table, row_num, col_num)? # or just box_num?
> 
> I don't have a function that just gets a column. Column extraction is
> performed as part of other functions. I know that a function should do
> just one job, so I'll work on that. I have started a function that gets
> the box number but I cannot see, at the moment, how to integrate it with
> the rest of my programme.

Neither could I, but then 'solving' wasn't in the spec.

With regard to these 'helper functions' (or methods), three of us have
now suggested the exact same thing. (I'll be billing both of them for
"stealing" my idea...)

Because selecting a column of data will be required at various stages
within the program[me], doesn't that SHOUT: "make me a function"? If
it's only a few lines of code (see below), that's not a problem. A
function (once tested and proven) is one less 'problem' to consider!

(conversely, a function with only one line of code is possibly NOT a
valid candidate) Thinking 'small' is probably a virtue, at this stage of
learning.


With the two-list idea, finding columnar-data is trivial - which column,
ie which list, do you want? EOJ!


With the 2D dicts (that is a dict of dicts, not a dict of lists, or
v-v!), what is required is to 'hold' the row-index fixed, and iterate
the column-index. I'd think this very familiar from the approaches
required/imposed/implemented in earlier languages, eg:

    def check_col( self, col: int, value: int, ) -> None:
        """Assure no duplicate values."""
        column = [ self.board[ row ][ col ]
                   for row in self.board_dimensions
                   ]
        if value in column:
            raise ValueError( "No duplicate values." )

Notice that because my partial-solution/illustration can enjoy the
relative-luxury of not needing a transition between algorithm
data-structures and GUI-structures, the only time column-data is needed
is during the duplicate-check.

In your situation, it would be better to split the above function into
halves, perhaps something like (untested):

    def get_column( self, col: int, ) -> list[ int ]:
        """Extract nominated column-data from the board."""
        return [ self.board[ row ][ col ]
                   for row in self.board_dimensions
                   ]

    def check_col( self, col: int, value: int, ) -> None:
        """Assure no duplicate values."""
        column = self.get_column( col )
        if value in column:
            raise ValueError( "No duplicate values." )

If the list-comprehension (in the return) is more complex than
preferred, 'unwind' it to a multi-line for-loop, appending one item per
loop, with preparatory list declaration, and use that list as the
return-value.

Now, get_column() can be used wherever needed, from multiple points in
the code, etc.



The solution for the 'snake' is to use slices (and 'striding') - by
definition all of the values which constitute one 'column' must be nine
cells apart from each-other in the 1D 'snake'. Thus, row = 0, column = 0
is the zero-th cell, and row = 1, column = 0 will have a snake-index of
9, ie 0 + 9. Proceeding: row = 2, column = 0 is nine cells further
'along', ie 0 + 9 + 9. Pretty soon, you'll notice that instead of adding
9 each time, we could multiply by the number of rows 'down'!

    def get_col( self, col_index: int, ) -> None:
        """Return single column from board."""
        first_cell_index = col_index % 9
        return [ self.board[ cell_index ]
                 for cell_index in range( first_cell_index, 81, 9 )
                 ]

The reasons for the "remainder", is the presumption that the column
could be defined as that above-and-below any cell on the board, cf a
column-number. Once the nominated-cell's column is ascertained, the
column-number becomes the start of the 'stride'.
(81 being the length of the snaking tableau, and 9 being the width of
each row)


As you can see, in both 'solutions', a 'get-column' "helper function"
furnishes utility!

Also, here's-hoping that one-or-the-other will help to make the
technique 'click' in your mind.
(no 'click' is perhaps not a snooty, cognitive-psych term - but who will
understand these days if I say "when the penny drops"? Maybe an "ahah
moment"!)


>> The next problem (based on previous posts) is that your
>> cells are sets which are immutable, so you need to:
>> 1) create another set of functions for writing back changes
>> to a cell - tricky...
> 
> I'm not sure that I understand why this is difficult. This is how I
> update a cell:
> 
> self.solution[row][col] = set(num)

Why a set?

How to be sure that the cell is not already 'occupied' by part of the
puzzle-definition?


>> OR
>> 2) use lists instead of sets because they are mutable.
> I had originally used lists instead of sets as a result of my
> translation from arrays to lists. The use of sets was an experiment that
> didn't cause any harm so it's use stayed.

Be careful! A set has no (guarantee of) sequence.

Sequence is important when it comes to the tableau.

Sets are useful when it comes to ensuring that a digit isn't used twice
in one row/column/region...

(as below)
= tools for the job


>> OR
>> 3) Use OOP and make your cells objects with methods
>> to add/remove values and using a set internally to
>> check uniqueness etc. This would be my choice.
> I'll give this some thought as well.
>> Personally, I'd use OOP for the table too, and make the
>> functions above methods of the table. So you would have
>> a table object with 81 mutable cells.
>>
>> But you haven't mentioned OOP up to now so that may be
>> an extra learning curve you don't want to deal with.
> 
> A grid class would probably be a good idea, more to think about.


> I pride myself in not being a rigid thinker but I suppose I am, other wise I would have completed this project by now.

You have been considering so many alternatives, started and re-started,
are learning Python, and trying to 'remember' old-code. Confusion reigns!


> I'm not sure about the idea of two tables, more complications perhaps?

"Two" sounds more complicated than "one'. However, it will have the
advantage of forcing you to concentrate on one (little) thing at a time.

If you take-to-heart the suggestion of 'helper functions', you can do
everything (easier) that needs to be done with rows first. Thereafter,
you can put such thoughts out of your mind, and concentrate on similar
for columns. Because the two function independently at all times, except
when data is (twice) added to the tableau - only one is necessary to
assess completeness/success/transfer to output, etc; it does not make
'the work' more complicated.


However, success at this is going to require the process of sitting-down
and planning/sketching/charting. When you know how to put individual
data-points into the row/column/snake/tableau, how to pull-out data from
specific cells, or entire row/column constructs, and such-like; then you
have the 'little problems' which can be individually solved, coded
one-at-a-time AND you can test each as you go, eg if column-n is
requested the value-returned will be of x-type and contain the following
values... This enables you to ensure that each helper function works
(properly!) BEFORE incorporating it/the columnar-data retrieved, into a
wider part of the algorithm!

eg if the final 'solution' is presented with whole rows of 1s and rows
of 2s, there is plainly a fault - but where? It is unlikely to be in the
GUI, or the solver. Almost certainly it will 'start' at a lower-level,
in - (wait for it) - a helper-function. So, testing each 'little bit'
first, is worthwhile, because it adds confidence as the snow-ball starts
to grow larger, and at the same time as that happens, reduces the number
of things to be kept in-mind...


> This is a rather easy puzzle to solve, my programme solved it in 3 passes. I'm not skiting, just pointing out that I have achieved something.

...and well done! Nothing succeeds like success!

Yes, I think it was described as a 'medium' or maybe 'hard' puzzle. No
matter, it was only needed to test those (dare I say it again?) 'helper
functions'.


> Are the several descriptions sufficient to start you off?
> 
> Yes, thank you and keep your code safe, I may contact you.

Because you are treating this as a learning exercise (and after
reviewing it again), I'm still comfortable recommending the two-list
approach. Once solved, you won't keep it (shouldn't keep it?) but it
might help with solving the non-Python problems you have outlined.

Once you have a 'model' straightened-out in your mind (confidence that
you know where to go and how to get there), then I'd suggest
using/expanding/amending that set of helper-functions to implement the
2D dictionary approach.

Once you're really feeling like you've 'earned your stripes', then have
a go at the 'snake'.


However, if you prefer the more mathematical type of problem/algorithm,
if the first step and/or diagramming/charting gives you confidence, then
maybe snake-second.

An algorithmic thinker will prefer the 'snake', because (s)he has
greater confidence in 'playing with numbers' and an ability to 'see the
patterns'.

The 2D approach has the advantage that one is more easily able to 'see'
what is what, and which is where.


That code is sitting in my GitLab instance - but remember, its purpose
is to illustrate 'the basics' and compare approaches. It does not 'do'
half of what your system apparently intends!

-- 
Regards =dn

From mats at wichmann.us  Wed Dec  8 10:23:27 2021
From: mats at wichmann.us (Mats Wichmann)
Date: Wed, 8 Dec 2021 08:23:27 -0700
Subject: [Tutor] Error When Using CoolProp
In-Reply-To: <CAK6zEbhUDO1DZu3T4mhAaEG2Kx_o=Pg60giE4_28v=z64Vx4kw@mail.gmail.com>
References: <A6BACFB5-DEDD-47E4-8092-F42C1028A72B@gmail.com>
 <aa0f237d-5bbf-a545-7b22-52044e77fc31@wichmann.us>
 <F26446B2-9E53-4E8B-98DD-789D02969724@gmail.com>
 <CAK6zEbhUDO1DZu3T4mhAaEG2Kx_o=Pg60giE4_28v=z64Vx4kw@mail.gmail.com>
Message-ID: <77e9e881-cb51-93b7-e52e-c52a9698e446@wichmann.us>

On 12/8/21 08:18, Bernard Marjaba wrote:
> Kind reminder please
> 
> On Mon, Nov 29, 2021 at 7:01 PM Bernard Marjaba 
> <marjababernard at gmail.com <mailto:marjababernard at gmail.com>> wrote:
> 
>     Hello,
> 
>     Yeah sure I?m checking with them as well. Meanwhile, this is a
>     purely python related error following what you suggested to me about
>     installing the wheel package:
> 
>     I tried installing the wheel package using
> 
>     (venv) Bernards-MacBook-Pro:Python Bernard$ pip install
>     /Users/Bernard/Downloads/CoolProp-6.4.1-cp38-cp38-macosx_10_9_x86_64.whl
> 
>     but it gave me this error
> 
>     ERROR: CoolProp-6.4.1-cp38-cp38-macosx_10_9_x86_64.whl is not a
>     supported wheel on this platform.
> 
>     I assume this means that i need python 3.8 for this wheel to work,
>     which I have. I typed python3 in terminal it gave me 3.8.10, i typed
>     python3 in PyCharm and it gave me 3.9.5, how come? So i searched for
>     python 3.9 in my MacBook and i couldn?t find any traces of it,
>     except for in a project folder:
>     /Users/Bernard/PycharmProjects/Isentropic SUS Model/venv/lib/python3.9
> 
>     However, 3.8 exists in the Applications folder. Any idea how to
>     remove all traces of 3.9?
> 

you select the interpreter in PyCharm independently of what the system 
thinks the default is - it's a clickable field in the bottom of the 
screen. Probably you'll be okay when you select 3.8.  If you choose to 
make a virtualenv, remember you have to install your packages in that 
virtualenv for them to be picked up - from the path you show it looks 
like you ended up with a 3.9 virtualenv. you can do that through 
pycharm, if that's what you intend to use.  they have lots of docs on that.

From marjababernard at gmail.com  Wed Dec  8 10:18:33 2021
From: marjababernard at gmail.com (Bernard Marjaba)
Date: Wed, 8 Dec 2021 10:18:33 -0500
Subject: [Tutor] Error When Using CoolProp
In-Reply-To: <F26446B2-9E53-4E8B-98DD-789D02969724@gmail.com>
References: <A6BACFB5-DEDD-47E4-8092-F42C1028A72B@gmail.com>
 <aa0f237d-5bbf-a545-7b22-52044e77fc31@wichmann.us>
 <F26446B2-9E53-4E8B-98DD-789D02969724@gmail.com>
Message-ID: <CAK6zEbhUDO1DZu3T4mhAaEG2Kx_o=Pg60giE4_28v=z64Vx4kw@mail.gmail.com>

Kind reminder please

On Mon, Nov 29, 2021 at 7:01 PM Bernard Marjaba <marjababernard at gmail.com>
wrote:

> Hello,
>
> Yeah sure I?m checking with them as well. Meanwhile, this is a purely
> python related error following what you suggested to me about installing
> the wheel package:
>
> I tried installing the wheel package using
>
> (venv) Bernards-MacBook-Pro:Python Bernard$ pip install
> /Users/Bernard/Downloads/CoolProp-6.4.1-cp38-cp38-macosx_10_9_x86_64.whl
>
> but it gave me this error
>
> ERROR: CoolProp-6.4.1-cp38-cp38-macosx_10_9_x86_64.whl is not a supported
> wheel on this platform.
>
> I assume this means that i need python 3.8 for this wheel to work, which I
> have. I typed python3 in terminal it gave me 3.8.10, i typed python3 in
> PyCharm and it gave me 3.9.5, how come? So i searched for python 3.9 in my
> MacBook and i couldn?t find any traces of it, except for in a project
> folder: /Users/Bernard/PycharmProjects/Isentropic SUS
> Model/venv/lib/python3.9
>
> However, 3.8 exists in the Applications folder. Any idea how to remove all
> traces of 3.9?
>
>
>
> *Thanks and regards,Bernard Marjaba(514) 922-9807*
>
> On Nov 24, 2021, at 6:53 PM, Mats Wichmann <mats at wichmann.us> wrote:
>
> On 11/24/21 13:17, Bernard Marjaba wrote:
>
> Hello
> I am having trouble using CoolProp with python. I have macOS Big Sur
> 11.5.1 with python version 3.10.
> import CoolProp.CoolProp as CP
> is giving me the error ModuleNotFoundError: No module named
> ?CoolProp.CoolProp? because it is not installed. I am however using it with
> MATLAB with no issues. I assume each software has its own wrapper?
> So I tried installing CoolProp using pip install coolprop, and got the
> following error:
> Collecting coolprop
>   Using cached CoolProp-6.4.1.tar.gz (12.9 MB)
>   Preparing metadata (setup.py) ... done
> Using legacy 'setup.py install' for coolprop, since package 'wheel' is not
> installed.
> Installing collected packages: coolprop
>     Running setup.py install for coolprop ... error
>     ERROR: Command errored out with exit status 1:
>      command: '/Users/Bernard/PycharmProjects/Isentropic SUS
> Model/venv/bin/python' -u -c 'import io, os, sys, setuptools, tokenize;
> sys.argv[0] =
> '"'"'/private/var/folders/1j/jv39r0t12cb4dhscxkdz97740000gn/T/pip-install-z5afcrzx/coolprop_6739af7137474652994855ae32a03dd4/setup.py'"'"';
> __file__='"'"'/private/var/folders/1j/jv39r0t12cb4dhscxkdz97740000gn/T/pip-install-z5afcrzx/coolprop_6739af7137474652994855ae32a03dd4/setup.py'"'"';f
> = getattr(tokenize, '"'"'open'"'"', open)(__file__) if
> os.path.exists(__file__) else io.StringIO('"'"'from setuptools import
> setup; setup()'"'"');code = f.read().replace('"'"'\r\n'"'"',
> '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))'
> install --record
> /private/var/folders/1j/jv39r0t12cb4dhscxkdz97740000gn/T/pip-record-8453i4i7/install-record.txt
> --single-version-externally-managed --compile --install-headers
> '/Users/Bernard/PycharmProjects/Isentropic SUS
> Model/venv/include/site/python3.9/coolprop'
>          cwd:
> /private/var/folders/1j/jv39r0t12cb4dhscxkdz97740000gn/T/pip-install-z5afcrzx/coolprop_6739af7137474652994855ae32a03dd4/
>     Complete output (79 lines):
>     xcrun: error: invalid active developer path
> (/Library/Developer/CommandLineTools), missing xcrun at:
> /Library/Developer/CommandLineTools/usr/bin/xcrun
>     OSX build detected, targetting 10.9 using clang/gcc v0.0.
>     Cython will not be used; cy_ext is cpp
>     running install
>     /Users/Bernard/PycharmProjects/Isentropic SUS
> Model/venv/lib/python3.9/site-packages/setuptools/command/install.py:34:
> SetuptoolsDeprecationWarning: setup.py install is deprecated. Use build and
> pip and other standards-based tools.
>       warnings.warn(
>     running build
>     running build_py
>     creating build
>     creating build/lib.macosx-10.9-x86_64-3.9
>     creating build/lib.macosx-10.9-x86_64-3.9/CoolProp
>     copying CoolProp/constants.py ->
> build/lib.macosx-10.9-x86_64-3.9/CoolProp
>     copying CoolProp/__init__.py ->
> build/lib.macosx-10.9-x86_64-3.9/CoolProp
>     copying CoolProp/BibtexParser.py ->
> build/lib.macosx-10.9-x86_64-3.9/CoolProp
>     copying CoolProp/HumidAirProp.py ->
> build/lib.macosx-10.9-x86_64-3.9/CoolProp
>     copying CoolProp/State.py -> build/lib.macosx-10.9-x86_64-3.9/CoolProp
>     creating build/lib.macosx-10.9-x86_64-3.9/CoolProp/tests
>     copying CoolProp/tests/runner.py ->
> build/lib.macosx-10.9-x86_64-3.9/CoolProp/tests
>     copying CoolProp/tests/test_plots.py ->
> build/lib.macosx-10.9-x86_64-3.9/CoolProp/tests
>     copying CoolProp/tests/test_Props.py ->
> build/lib.macosx-10.9-x86_64-3.9/CoolProp/tests
>     copying CoolProp/tests/__init__.py ->
> build/lib.macosx-10.9-x86_64-3.9/CoolProp/tests
>     copying CoolProp/tests/test_CoolPropState.py ->
> build/lib.macosx-10.9-x86_64-3.9/CoolProp/tests
>     creating build/lib.macosx-10.9-x86_64-3.9/CoolProp/GUI
>     copying CoolProp/GUI/__init__.py ->
> build/lib.macosx-10.9-x86_64-3.9/CoolProp/GUI
>     copying CoolProp/GUI/CoolPropGUI.py ->
> build/lib.macosx-10.9-x86_64-3.9/CoolProp/GUI
>     copying CoolProp/GUI/PsychScript.py ->
> build/lib.macosx-10.9-x86_64-3.9/CoolProp/GUI
>     creating build/lib.macosx-10.9-x86_64-3.9/CoolProp/Plots
>     copying CoolProp/Plots/ConsistencyPlots_pcsaft.py ->
> build/lib.macosx-10.9-x86_64-3.9/CoolProp/Plots
>     copying CoolProp/Plots/PsychChart.py ->
> build/lib.macosx-10.9-x86_64-3.9/CoolProp/Plots
>     copying CoolProp/Plots/SimpleCycles.py ->
> build/lib.macosx-10.9-x86_64-3.9/CoolProp/Plots
>     copying CoolProp/Plots/__init__.py ->
> build/lib.macosx-10.9-x86_64-3.9/CoolProp/Plots
>     copying CoolProp/Plots/psy.py ->
> build/lib.macosx-10.9-x86_64-3.9/CoolProp/Plots
>     copying CoolProp/Plots/Plots.py ->
> build/lib.macosx-10.9-x86_64-3.9/CoolProp/Plots
>     copying CoolProp/Plots/Common.py ->
> build/lib.macosx-10.9-x86_64-3.9/CoolProp/Plots
>     copying CoolProp/Plots/SimpleCyclesCompression.py ->
> build/lib.macosx-10.9-x86_64-3.9/CoolProp/Plots
>     copying CoolProp/Plots/ConsistencyPlots.py ->
> build/lib.macosx-10.9-x86_64-3.9/CoolProp/Plots
>     copying CoolProp/Plots/PsychScript.py ->
> build/lib.macosx-10.9-x86_64-3.9/CoolProp/Plots
>     copying CoolProp/Plots/Tests.py ->
> build/lib.macosx-10.9-x86_64-3.9/CoolProp/Plots
>     copying CoolProp/Plots/SimpleCyclesExpansion.py ->
> build/lib.macosx-10.9-x86_64-3.9/CoolProp/Plots
>     copying CoolProp/typedefs.pxd ->
> build/lib.macosx-10.9-x86_64-3.9/CoolProp
>     copying CoolProp/CoolProp.pxd ->
> build/lib.macosx-10.9-x86_64-3.9/CoolProp
>     copying CoolProp/State.pxd -> build/lib.macosx-10.9-x86_64-3.9/CoolProp
>     copying CoolProp/cAbstractState.pxd ->
> build/lib.macosx-10.9-x86_64-3.9/CoolProp
>     copying CoolProp/constants_header.pxd ->
> build/lib.macosx-10.9-x86_64-3.9/CoolProp
>     copying CoolProp/AbstractState.pxd ->
> build/lib.macosx-10.9-x86_64-3.9/CoolProp
>     copying CoolProp/Plots/psyrc ->
> build/lib.macosx-10.9-x86_64-3.9/CoolProp/Plots
>     running build_ext
>     creating private
>     creating private/var
>     creating private/var/folders
>     creating private/var/folders/1j
>     creating private/var/folders/1j/jv39r0t12cb4dhscxkdz97740000gn
>     creating private/var/folders/1j/jv39r0t12cb4dhscxkdz97740000gn/T
>     creating
> private/var/folders/1j/jv39r0t12cb4dhscxkdz97740000gn/T/pip-install-z5afcrzx
>     creating
> private/var/folders/1j/jv39r0t12cb4dhscxkdz97740000gn/T/pip-install-z5afcrzx/coolprop_6739af7137474652994855ae32a03dd4
>     gcc -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common
> -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -arch x86_64 -g
> -I/Users/Bernard/PycharmProjects/Isentropic SUS Model/venv/include
> -I/Library/Frameworks/Python.framework/Versions/3.9/include/python3.9 -c
> /private/var/folders/1j/jv39r0t12cb4dhscxkdz97740000gn/T/pip-install-z5afcrzx/coolprop_6739af7137474652994855ae32a03dd4/tmp0hdk2tsu.cpp
> -o
> private/var/folders/1j/jv39r0t12cb4dhscxkdz97740000gn/T/pip-install-z5afcrzx/coolprop_6739af7137474652994855ae32a03dd4/tmp0hdk2tsu.o
>     xcrun: error: invalid active developer path
> (/Library/Developer/CommandLineTools), missing xcrun at:
> /Library/Developer/CommandLineTools/usr/bin/xcrun
>     gcc -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common
> -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -arch x86_64 -g
> -I/Users/Bernard/PycharmProjects/Isentropic SUS Model/venv/include
> -I/Library/Frameworks/Python.framework/Versions/3.9/include/python3.9 -c
> /private/var/folders/1j/jv39r0t12cb4dhscxkdz97740000gn/T/pip-install-z5afcrzx/coolprop_6739af7137474652994855ae32a03dd4/tmp0r3vfej0.cpp
> -o
> private/var/folders/1j/jv39r0t12cb4dhscxkdz97740000gn/T/pip-install-z5afcrzx/coolprop_6739af7137474652994855ae32a03dd4/tmp0r3vfej0.o
>     xcrun: error: invalid active developer path
> (/Library/Developer/CommandLineTools), missing xcrun at:
> /Library/Developer/CommandLineTools/usr/bin/xcrun
>     gcc -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common
> -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -arch x86_64 -g
> -I/Users/Bernard/PycharmProjects/Isentropic SUS Model/venv/include
> -I/Library/Frameworks/Python.framework/Versions/3.9/include/python3.9 -c
> /private/var/folders/1j/jv39r0t12cb4dhscxkdz97740000gn/T/pip-install-z5afcrzx/coolprop_6739af7137474652994855ae32a03dd4/tmp93394q_4.cpp
> -o
> private/var/folders/1j/jv39r0t12cb4dhscxkdz97740000gn/T/pip-install-z5afcrzx/coolprop_6739af7137474652994855ae32a03dd4/tmp93394q_4.o
>     xcrun: error: invalid active developer path
> (/Library/Developer/CommandLineTools), missing xcrun at:
> /Library/Developer/CommandLineTools/usr/bin/xcrun
>     Adding these shared_ptr compilation macros: []
>     building 'CoolProp.CoolProp' extension
>     creating build/temp.macosx-10.9-x86_64-3.9
>     creating build/temp.macosx-10.9-x86_64-3.9/CoolProp
>     creating build/temp.macosx-10.9-x86_64-3.9/src
>     creating build/temp.macosx-10.9-x86_64-3.9/src/Backends
>     creating build/temp.macosx-10.9-x86_64-3.9/src/Backends/Cubics
>     creating build/temp.macosx-10.9-x86_64-3.9/src/Backends/Helmholtz
>     creating
> build/temp.macosx-10.9-x86_64-3.9/src/Backends/Helmholtz/Fluids
>     creating build/temp.macosx-10.9-x86_64-3.9/src/Backends/IF97
>     creating build/temp.macosx-10.9-x86_64-3.9/src/Backends/Incompressible
>     creating build/temp.macosx-10.9-x86_64-3.9/src/Backends/PCSAFT
>     creating build/temp.macosx-10.9-x86_64-3.9/src/Backends/REFPROP
>     creating build/temp.macosx-10.9-x86_64-3.9/src/Backends/Tabular
>     creating build/temp.macosx-10.9-x86_64-3.9/src/Tests
>     gcc -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common
> -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -arch x86_64 -g -I. -I./include
> -I./src -I./externals/Eigen -I./externals/fmtlib
> -I./externals/msgpack-c/include -I/Users/Bernard/PycharmProjects/Isentropic
> SUS Model/venv/include
> -I/Library/Frameworks/Python.framework/Versions/3.9/include/python3.9 -c
> CoolProp/CoolProp.cpp -o
> build/temp.macosx-10.9-x86_64-3.9/CoolProp/CoolProp.o
>     xcrun: error: invalid active developer path
> (/Library/Developer/CommandLineTools), missing xcrun at:
> /Library/Developer/CommandLineTools/usr/bin/xcrun
>     error: command '/usr/bin/gcc' failed with exit code 1
>     ----------------------------------------
> ERROR: Command errored out with exit status 1:
> '/Users/Bernard/PycharmProjects/Isentropic SUS Model/venv/bin/python' -u -c
> 'import io, os, sys, setuptools, tokenize; sys.argv[0] =
> '"'"'/private/var/folders/1j/jv39r0t12cb4dhscxkdz97740000gn/T/pip-install-z5afcrzx/coolprop_6739af7137474652994855ae32a03dd4/setup.py'"'"';
> __file__='"'"'/private/var/folders/1j/jv39r0t12cb4dhscxkdz97740000gn/T/pip-install-z5afcrzx/coolprop_6739af7137474652994855ae32a03dd4/setup.py'"'"';f
> = getattr(tokenize, '"'"'open'"'"', open)(__file__) if
> os.path.exists(__file__) else io.StringIO('"'"'from setuptools import
> setup; setup()'"'"');code = f.read().replace('"'"'\r\n'"'"',
> '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))'
> install --record
> /private/var/folders/1j/jv39r0t12cb4dhscxkdz97740000gn/T/pip-record-8453i4i7/install-record.txt
> --single-version-externally-managed --compile --install-headers
> '/Users/Bernard/PycharmProjects/Isentropic SUS
> Model/venv/include/site/python3.9/coolprop' Check the logs for full command
> output.
>
>
>
> looks like you probably don't have the command-line developer tools
> installed - it's separate from the main xcode install on MacOS.
>
> also, you might be able to install without the effort to build if you
> installed the wheel package first - see this error from early on:
>
> > Using legacy 'setup.py install' for coolprop, since package 'wheel' is
> not installed.
>
> I have no idea what CoolProp is, never heard of it, but a check here:
>
> https://pypi.org/project/CoolProp/#files
>
> shows there *is* a macosx wheel available for installation - at least as
> long as you're using no newer than Python 3.8.  The project looks like it
> hasn't updated for a good long time so they haven't done anything for 3.9
> or 3.10. That's probably cause for some worry...
>
> You'd be far better asking this kind of thing directly to the project in
> question, we won't be able to answer any further stuff from here.
>
>
>

From marjababernard at gmail.com  Wed Dec  8 16:31:19 2021
From: marjababernard at gmail.com (Bernard Marjaba)
Date: Wed, 8 Dec 2021 16:31:19 -0500
Subject: [Tutor] Error When Using CoolProp
In-Reply-To: <77e9e881-cb51-93b7-e52e-c52a9698e446@wichmann.us>
References: <A6BACFB5-DEDD-47E4-8092-F42C1028A72B@gmail.com>
 <aa0f237d-5bbf-a545-7b22-52044e77fc31@wichmann.us>
 <F26446B2-9E53-4E8B-98DD-789D02969724@gmail.com>
 <CAK6zEbhUDO1DZu3T4mhAaEG2Kx_o=Pg60giE4_28v=z64Vx4kw@mail.gmail.com>
 <77e9e881-cb51-93b7-e52e-c52a9698e446@wichmann.us>
Message-ID: <9DDFF682-63D7-488E-8B44-9BB59C57CB6B@gmail.com>

ok thanks, i changed the environment to 3.8. but now when i try to run any command with pip in it, it is giving me this error


/Users/Bernard/PycharmProjects/Isentropic SUS Model/venv/bin/pip: line 2: /Users/Bernard/PycharmProjects/Isentropic SUS Model/venv/bin/python: No such file or directory
/Users/Bernard/PycharmProjects/Isentropic SUS Model/venv/bin/pip: line 2: exec: /Users/Bernard/PycharmProjects/Isentropic SUS Model/venv/bin/python: cannot execute: No such file or directory

I checked if this folder exists, and it does.

Thanks and regards,
Bernard Marjaba
(514) 922-9807

> On Dec 8, 2021, at 10:23 AM, Mats Wichmann <mats at wichmann.us> wrote:
> 
> On 12/8/21 08:18, Bernard Marjaba wrote:
>> Kind reminder please
>> On Mon, Nov 29, 2021 at 7:01 PM Bernard Marjaba <marjababernard at gmail.com <mailto:marjababernard at gmail.com>> wrote:
>>    Hello,
>>    Yeah sure I?m checking with them as well. Meanwhile, this is a
>>    purely python related error following what you suggested to me about
>>    installing the wheel package:
>>    I tried installing the wheel package using
>>    (venv) Bernards-MacBook-Pro:Python Bernard$ pip install
>>    /Users/Bernard/Downloads/CoolProp-6.4.1-cp38-cp38-macosx_10_9_x86_64.whl
>>    but it gave me this error
>>    ERROR: CoolProp-6.4.1-cp38-cp38-macosx_10_9_x86_64.whl is not a
>>    supported wheel on this platform.
>>    I assume this means that i need python 3.8 for this wheel to work,
>>    which I have. I typed python3 in terminal it gave me 3.8.10, i typed
>>    python3 in PyCharm and it gave me 3.9.5, how come? So i searched for
>>    python 3.9 in my MacBook and i couldn?t find any traces of it,
>>    except for in a project folder:
>>    /Users/Bernard/PycharmProjects/Isentropic SUS Model/venv/lib/python3.9
>>    However, 3.8 exists in the Applications folder. Any idea how to
>>    remove all traces of 3.9?
> 
> you select the interpreter in PyCharm independently of what the system thinks the default is - it's a clickable field in the bottom of the screen. Probably you'll be okay when you select 3.8.  If you choose to make a virtualenv, remember you have to install your packages in that virtualenv for them to be picked up - from the path you show it looks like you ended up with a 3.9 virtualenv. you can do that through pycharm, if that's what you intend to use.  they have lots of docs on that.


From acianci15 at gmail.com  Thu Dec  9 10:28:13 2021
From: acianci15 at gmail.com (Anthony Cianci)
Date: Thu, 9 Dec 2021 10:28:13 -0500
Subject: [Tutor] Plotting multiple lines on one graph with same X values
Message-ID: <CABdY6so-iQ=YsZcgAJyyjJAFQLGePeh9EZ6fVmpQv=ic_VFRpg@mail.gmail.com>

Hello,

I am looking to plot multiple lines (1,000+) from an excel file.
I am new to Python and have figured out how to graph one dataframe using
pandas, but I am not sure how to include the rest of the data without
writing a new line of code for each "tag".
[image: image.png]

[image: image.png]

Thank you,
Anthony

From mhedges21 at gmail.com  Thu Dec  9 05:07:48 2021
From: mhedges21 at gmail.com (Mike Hedges)
Date: Thu, 9 Dec 2021 11:07:48 +0100
Subject: [Tutor] Need help developing DSP within GUI.
Message-ID: <CAL+uqr7THuF3=aOroNC6CDm0Kby9hK0uhVZjQHvDA6GsVxF2Kw@mail.gmail.com>

Hey Tutors!

This is my first time attempting this, so I hope I'm doing it accurately. I
just need a few pointers on how to get multiple elements to function within
the same space. I'm working on an interface that displays a comparison of
different pitch tracking methods. I have the YIN and CREPE methods [mostly]
scripted out, now I'm trying to build an interface that displays their
values as real-time audio is being inputted. Would someone be able to help
me wrap my mind around getting this to work together? Maybe we could have a
one-on-one session or something? I'm pretty novice with Python, but I have
some understanding of how it works. Thanks!

Also, my timezone is UTC +01:00.

Best Regards,
Mike

From wlfraed at ix.netcom.com  Thu Dec  9 19:29:55 2021
From: wlfraed at ix.netcom.com (Dennis Lee Bieber)
Date: Thu, 09 Dec 2021 19:29:55 -0500
Subject: [Tutor] Plotting multiple lines on one graph with same X values
References: <CABdY6so-iQ=YsZcgAJyyjJAFQLGePeh9EZ6fVmpQv=ic_VFRpg@mail.gmail.com>
Message-ID: <ni75rgdakbhbchkbobt29vn1p6supd8pu5@4ax.com>

On Thu, 9 Dec 2021 10:28:13 -0500, Anthony Cianci <acianci15 at gmail.com>
declaimed the following:

>Hello,
>
>I am looking to plot multiple lines (1,000+) from an excel file.
>I am new to Python and have figured out how to graph one dataframe using
>pandas, but I am not sure how to include the rest of the data without
>writing a new line of code for each "tag".
>[image: image.png]
>

	Text attachments only on this forum -- anything else gets stripped.

	If you must reference an image, you will have to find some image
hosting provider, and include URLs to the images one that provider. I
recommend you do not use a provider that creates cryptic URLs -- I, for
one, will not click on any URL that does not have a definable target (eg:
.../image1.png is okay,  .../8374917ds87374lf could be anything including
trojans and will not be clicked).

	As for your subject -- does matplotlib have anything that may help?
Otherwise you may be down to scripting something that extracts the "tags",
and loops over them executing a suitable plot call.


-- 
	Wulfraed                 Dennis Lee Bieber         AF6VN
	wlfraed at ix.netcom.com    http://wlfraed.microdiversity.freeddns.org/


From mats at wichmann.us  Fri Dec 10 16:51:11 2021
From: mats at wichmann.us (Mats Wichmann)
Date: Fri, 10 Dec 2021 14:51:11 -0700
Subject: [Tutor] Error When Using CoolProp
In-Reply-To: <E723CDA8-74D5-4AE5-842D-8770635AA881@gmail.com>
References: <A6BACFB5-DEDD-47E4-8092-F42C1028A72B@gmail.com>
 <aa0f237d-5bbf-a545-7b22-52044e77fc31@wichmann.us>
 <F26446B2-9E53-4E8B-98DD-789D02969724@gmail.com>
 <CAK6zEbhUDO1DZu3T4mhAaEG2Kx_o=Pg60giE4_28v=z64Vx4kw@mail.gmail.com>
 <77e9e881-cb51-93b7-e52e-c52a9698e446@wichmann.us>
 <E723CDA8-74D5-4AE5-842D-8770635AA881@gmail.com>
Message-ID: <29300e4e-4bcf-24be-73ba-5a0c31134e54@wichmann.us>

On 12/10/21 13:49, Bernard Marjaba wrote:
> Ok I changed the version like you said, and coolprop is successfully 
> installed. Now I?m getting this error when trying to install matplotlib. 
> I already installed pip for python 3.8, but i think the issue here is 
> accessing the right path, because here it shows its accessing 2.7 
> instead of 3.8. How do I fix this issue?

Use the python for installing that you intend to use for running.

if "python" is 2.7 and "python3" is 3.8, then the install should be

python3 -m pip install -U matplotlib

From marjababernard at gmail.com  Fri Dec 10 15:49:32 2021
From: marjababernard at gmail.com (Bernard Marjaba)
Date: Fri, 10 Dec 2021 15:49:32 -0500
Subject: [Tutor] Error When Using CoolProp
In-Reply-To: <77e9e881-cb51-93b7-e52e-c52a9698e446@wichmann.us>
References: <A6BACFB5-DEDD-47E4-8092-F42C1028A72B@gmail.com>
 <aa0f237d-5bbf-a545-7b22-52044e77fc31@wichmann.us>
 <F26446B2-9E53-4E8B-98DD-789D02969724@gmail.com>
 <CAK6zEbhUDO1DZu3T4mhAaEG2Kx_o=Pg60giE4_28v=z64Vx4kw@mail.gmail.com>
 <77e9e881-cb51-93b7-e52e-c52a9698e446@wichmann.us>
Message-ID: <E723CDA8-74D5-4AE5-842D-8770635AA881@gmail.com>

Ok I changed the version like you said, and coolprop is successfully installed. Now I?m getting this error when trying to install matplotlib. I already installed pip for python 3.8, but i think the issue here is accessing the right path, because here it shows its accessing 2.7 instead of 3.8. How do I fix this issue?

Bernards-MacBook-Pro:Python Bernard$ python -m pip install -U matplotlib
/System/Library/Frameworks/Python.framework/Versions/2.7/Resources/Python.app/Contents/MacOS/Python: No module named pip

Thanks and regards,
Bernard Marjaba
(514) 922-9807

> On Dec 8, 2021, at 10:23 AM, Mats Wichmann <mats at wichmann.us> wrote:
> 
> On 12/8/21 08:18, Bernard Marjaba wrote:
>> Kind reminder please
>> On Mon, Nov 29, 2021 at 7:01 PM Bernard Marjaba <marjababernard at gmail.com <mailto:marjababernard at gmail.com>> wrote:
>>    Hello,
>>    Yeah sure I?m checking with them as well. Meanwhile, this is a
>>    purely python related error following what you suggested to me about
>>    installing the wheel package:
>>    I tried installing the wheel package using
>>    (venv) Bernards-MacBook-Pro:Python Bernard$ pip install
>>    /Users/Bernard/Downloads/CoolProp-6.4.1-cp38-cp38-macosx_10_9_x86_64.whl
>>    but it gave me this error
>>    ERROR: CoolProp-6.4.1-cp38-cp38-macosx_10_9_x86_64.whl is not a
>>    supported wheel on this platform.
>>    I assume this means that i need python 3.8 for this wheel to work,
>>    which I have. I typed python3 in terminal it gave me 3.8.10, i typed
>>    python3 in PyCharm and it gave me 3.9.5, how come? So i searched for
>>    python 3.9 in my MacBook and i couldn?t find any traces of it,
>>    except for in a project folder:
>>    /Users/Bernard/PycharmProjects/Isentropic SUS Model/venv/lib/python3.9
>>    However, 3.8 exists in the Applications folder. Any idea how to
>>    remove all traces of 3.9?
> 
> you select the interpreter in PyCharm independently of what the system thinks the default is - it's a clickable field in the bottom of the screen. Probably you'll be okay when you select 3.8.  If you choose to make a virtualenv, remember you have to install your packages in that virtualenv for them to be picked up - from the path you show it looks like you ended up with a 3.9 virtualenv. you can do that through pycharm, if that's what you intend to use.  they have lots of docs on that.


From leamhall at gmail.com  Fri Dec 10 21:32:31 2021
From: leamhall at gmail.com (Leam Hall)
Date: Fri, 10 Dec 2021 20:32:31 -0600
Subject: [Tutor] Using Python for the job search
Message-ID: <2f95293a-bd59-b83b-9918-1d83ea2c85bf@gmail.com>

Found out that the job I'm on is going away shortly, and I'm enjoying a wonderful job search. Keeping the same resume in multiple formats gets tiring, so I started to convert some old code to Python to make things easier. I could use some feedback on how to improve the code.

	https://github.com/LeamHall/resume_writer

If you want to play with it, move "sample_data" to "data", and then go through the README.

Thanks!

Leam
-- 
Site Reliability Engineer  (reuel.net/resume)
Scribe: The Domici War     (domiciwar.net)
General Ne'er-do-well      (github.com/LeamHall)

From juliushamilton100 at gmail.com  Sat Dec 11 06:47:01 2021
From: juliushamilton100 at gmail.com (Julius Hamilton)
Date: Sat, 11 Dec 2021 12:47:01 +0100
Subject: [Tutor] Packaging questions
Message-ID: <CAEsMKX0DM6grQR64y-TMdgmqyXwS9BobVnjgMbTVtj8=Rf+5pg@mail.gmail.com>

Hey,

I just went through the pip packaging tutorial. It seemed to be mainly for
making importable modules, i.e. files of functions you can access via

import library

I was hoping to package a command line application that can be used by
invoking its name on the command line.

The tutorial had me (basically) make an outermost project directory and put
the actual project code in a subdirectory, ?src?, and specify that was the
?root? directory in the config file.

As far as I could tell, the only other essential file was either a
?setup.cfg? file or a ?setup.py? file, (and a blank ?__init__? file in src
as well). Could anyone let me know why I would choose the one over the
other, and if some people choose to have both?

Which information in the config file is mandatory? I entered name,
description, long_description, project_urls, license and much else. What?s
the bare minimum possible?

What should I do if I want my pip installation to be a command line
application instead of an importable library of functions? Do I need a more
sophisticated setup.py file which installs an executable in usr/bin or
something?

Thanks very much,
Julius

From juliushamilton100 at gmail.com  Sat Dec 11 08:05:24 2021
From: juliushamilton100 at gmail.com (Julius Hamilton)
Date: Sat, 11 Dec 2021 14:05:24 +0100
Subject: [Tutor] Publish Python web application
Message-ID: <CAEsMKX0gMgNUxMHjk3TrmL2LgqxgcYBs7gU88RmdJVkLhY+Q3A@mail.gmail.com>

Hey,

I would like to make a web application available publicly on the internet,
likely written in Python.

Is there a standard way to host it?

Amazon web services or GitHub pages?

Thanks,
Julius

From alan.gauld at yahoo.co.uk  Sun Dec 12 06:17:59 2021
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Sun, 12 Dec 2021 11:17:59 +0000
Subject: [Tutor] Packaging questions
In-Reply-To: <CAEsMKX0DM6grQR64y-TMdgmqyXwS9BobVnjgMbTVtj8=Rf+5pg@mail.gmail.com>
References: <CAEsMKX0DM6grQR64y-TMdgmqyXwS9BobVnjgMbTVtj8=Rf+5pg@mail.gmail.com>
Message-ID: <D16B7AAB-F290-48D6-B2F0-8ABCD88FE7FB@yahoo.co.uk>



Sent from my iPad

> What should I do if I want my pip installation to be a command line
> application instead of an importable library of functions? Do I need a more
> sophisticated setup.py file which installs an executable in usr/bin or
> something?

You do know about the 

if __name__ == ?__main__?:

Idiom for making a module executable, right?

That means an executable script and a module are the same thing.
The only other requirement is that the user has a compatible python installed.

If you are looking at installing python as well then you might be better off looking at tools like py2exe for windows, or similar tools for other OS?

From alan.gauld at yahoo.co.uk  Sun Dec 12 06:21:50 2021
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Sun, 12 Dec 2021 11:21:50 +0000
Subject: [Tutor] Publish Python web application
In-Reply-To: <CAEsMKX0gMgNUxMHjk3TrmL2LgqxgcYBs7gU88RmdJVkLhY+Q3A@mail.gmail.com>
References: <CAEsMKX0gMgNUxMHjk3TrmL2LgqxgcYBs7gU88RmdJVkLhY+Q3A@mail.gmail.com>
Message-ID: <0C402679-6E1A-48F2-B432-A7A30952137D@yahoo.co.uk>



Sent from my iPad

> On 12 Dec 2021, at 00:44, Julius Hamilton <juliushamilton100 at gmail.com> wrote:
> 
> ?Hey,
> 
> I would like to make a web application available publicly on the internet,
> likely written in Python.

Do you mean make the code available so that others can set up their own version of it? Or do you simply want to make your application available to all internet users?

> 
> Is there a standard way to host it?

If the former then GitHub or pypi.
If the latter then any web hosting service.

> 
> Amazon web services or GitHub pages?

Amazon might be appropriate depending on the app but my guess is it would be overkill.

Alan g.

From alexkleider at gmail.com  Sun Dec 12 19:35:47 2021
From: alexkleider at gmail.com (Alex Kleider)
Date: Sun, 12 Dec 2021 16:35:47 -0800
Subject: [Tutor] class attributes
Message-ID: <CAMCEyD5mWOE7SBU7k-2zN1_zo4y7v5UZjBQaNecTwT8Rf6yakg@mail.gmail.com>

I'm trying to write a __repr__ method that can be easily changed to
show only the attributes in which I'm currently interested and want to
be able to easily change the attributes of interest.
My attempted solution is as follows:

    def __repr__(self):
        attrs = ['SECRETARY',  # an easy to modify listing
                 'PATTERN',    # of attributes of interest
                 ]
        ret = []
        for attr in attrs:
            if hasattr(self, attr):
                ret.append("{}::{}".format(attr, self.attr))
            else:
                ret.append("{}::unassigned".format(attr))
        return ','.join(ret)

Not surprisingly, I get the following error:
"""
    ret.append("{}::{}".format(attr, self.attr))
AttributeError: 'Club' object has no attribute 'attr'
"""

I'd be grateful if anyone could suggest a way to get around the
problem. The built in method 'hasattr' is able to do the introspection
necessary to do its work so it seems what I want should be "doable".

Thanks in advance,
Alex

From bouncingcats at gmail.com  Sun Dec 12 20:23:47 2021
From: bouncingcats at gmail.com (David)
Date: Mon, 13 Dec 2021 12:23:47 +1100
Subject: [Tutor] class attributes
In-Reply-To: <CAMCEyD5mWOE7SBU7k-2zN1_zo4y7v5UZjBQaNecTwT8Rf6yakg@mail.gmail.com>
References: <CAMCEyD5mWOE7SBU7k-2zN1_zo4y7v5UZjBQaNecTwT8Rf6yakg@mail.gmail.com>
Message-ID: <CAMPXz=pXOFp-sZdxr3GjFzkVAtbyQFsQPu2ixse_ZxQjd-eM0Q@mail.gmail.com>

On Mon, 13 Dec 2021 at 11:37, Alex Kleider <alexkleider at gmail.com> wrote:

> I'm trying to write a __repr__ method that can be easily changed to
> show only the attributes in which I'm currently interested and want to
> be able to easily change the attributes of interest.
> My attempted solution is as follows:
>
>     def __repr__(self):
>         attrs = ['SECRETARY',  # an easy to modify listing
>                  'PATTERN',    # of attributes of interest
>                  ]
>         ret = []
>         for attr in attrs:
>             if hasattr(self, attr):
>                 ret.append("{}::{}".format(attr, self.attr))
>             else:
>                 ret.append("{}::unassigned".format(attr))
>         return ','.join(ret)
>
> Not surprisingly, I get the following error:
> """
>     ret.append("{}::{}".format(attr, self.attr))
> AttributeError: 'Club' object has no attribute 'attr'
> """
>
> I'd be grateful if anyone could suggest a way to get around the
> problem. The built in method 'hasattr' is able to do the introspection
> necessary to do its work so it seems what I want should be "doable".

Python has builtin functions getattr() and setattr() which take a
string argument for the attribute name, in the same way such
information is passed to hasattr().

From cs at cskk.id.au  Sun Dec 12 19:56:10 2021
From: cs at cskk.id.au (Cameron Simpson)
Date: Mon, 13 Dec 2021 11:56:10 +1100
Subject: [Tutor] class attributes
In-Reply-To: <CAMCEyD5mWOE7SBU7k-2zN1_zo4y7v5UZjBQaNecTwT8Rf6yakg@mail.gmail.com>
References: <CAMCEyD5mWOE7SBU7k-2zN1_zo4y7v5UZjBQaNecTwT8Rf6yakg@mail.gmail.com>
Message-ID: <YbaaKhcK+nC3dgcM@cskk.homeip.net>

On 12Dec2021 16:35, Alex Kleider <alexkleider at gmail.com> wrote:
>I'm trying to write a __repr__ method that can be easily changed to
>show only the attributes in which I'm currently interested and want to
>be able to easily change the attributes of interest.
>My attempted solution is as follows:
>
>    def __repr__(self):
>        attrs = ['SECRETARY',  # an easy to modify listing
>                 'PATTERN',    # of attributes of interest
>                 ]
>        ret = []
>        for attr in attrs:
>            if hasattr(self, attr):
>                ret.append("{}::{}".format(attr, self.attr))
>            else:
>                ret.append("{}::unassigned".format(attr))
>        return ','.join(ret)
>
>Not surprisingly, I get the following error:
>"""
>    ret.append("{}::{}".format(attr, self.attr))
>AttributeError: 'Club' object has no attribute 'attr'
>"""
>
>I'd be grateful if anyone could suggest a way to get around the
>problem. The built in method 'hasattr' is able to do the introspection
>necessary to do its work so it seems what I want should be "doable".

getattr(self, attr_name)

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

From alexkleider at gmail.com  Sun Dec 12 21:06:28 2021
From: alexkleider at gmail.com (Alex Kleider)
Date: Sun, 12 Dec 2021 18:06:28 -0800
Subject: [Tutor] class attributes
In-Reply-To: <YbaaKhcK+nC3dgcM@cskk.homeip.net>
References: <CAMCEyD5mWOE7SBU7k-2zN1_zo4y7v5UZjBQaNecTwT8Rf6yakg@mail.gmail.com>
 <YbaaKhcK+nC3dgcM@cskk.homeip.net>
Message-ID: <CAMCEyD5B-LJkahiPZxSxhah4gpGVt24C9Pb_v1gPCV4pOGF3fQ@mail.gmail.com>

Problem solved (and so easily!)
A sincere thank you to both (Cameron & David) of you (and to the list in
general.)
Alex

On Sun, Dec 12, 2021 at 5:35 PM Cameron Simpson <cs at cskk.id.au> wrote:

> On 12Dec2021 16:35, Alex Kleider <alexkleider at gmail.com> wrote:
> >I'm trying to write a __repr__ method that can be easily changed to
> >show only the attributes in which I'm currently interested and want to
> >be able to easily change the attributes of interest.
> >My attempted solution is as follows:
> >
> >    def __repr__(self):
> >        attrs = ['SECRETARY',  # an easy to modify listing
> >                 'PATTERN',    # of attributes of interest
> >                 ]
> >        ret = []
> >        for attr in attrs:
> >            if hasattr(self, attr):
> >                ret.append("{}::{}".format(attr, self.attr))
> >            else:
> >                ret.append("{}::unassigned".format(attr))
> >        return ','.join(ret)
> >
> >Not surprisingly, I get the following error:
> >"""
> >    ret.append("{}::{}".format(attr, self.attr))
> >AttributeError: 'Club' object has no attribute 'attr'
> >"""
> >
> >I'd be grateful if anyone could suggest a way to get around the
> >problem. The built in method 'hasattr' is able to do the introspection
> >necessary to do its work so it seems what I want should be "doable".
>
> getattr(self, attr_name)
>
> Cheers,
> Cameron Simpson <cs at cskk.id.au>
> _______________________________________________
> 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 Dec 12 18:03:45 2021
From: cs at cskk.id.au (Cameron Simpson)
Date: Mon, 13 Dec 2021 10:03:45 +1100
Subject: [Tutor] Packaging questions
In-Reply-To: <D16B7AAB-F290-48D6-B2F0-8ABCD88FE7FB@yahoo.co.uk>
References: <D16B7AAB-F290-48D6-B2F0-8ABCD88FE7FB@yahoo.co.uk>
Message-ID: <YbZ/0Yl8NST/VCP1@cskk.homeip.net>

On 12Dec2021 11:17, Alan Gauld <alan.gauld at yahoo.co.uk> wrote:
>> What should I do if I want my pip installation to be a command line
>> application instead of an importable library of functions? Do I need a more
>> sophisticated setup.py file which installs an executable in usr/bin or
>> something?
>
>You do know about the
>
>    if __name__ == ?__main__?:
>
>Idiom for making a module executable, right?
>
>That means an executable script and a module are the same thing.

Just to follow on, you don't even need that (though you probably want 
it). The dictionary you supply with the module package can contain an 
entry like this:

    'entry_points': {
        'console_scripts': [
            'your_command_name = your.module.name:command_function',
        ],
    },

which makes a command line script which calls a function of your choice.  
The example above would create a script called "your_command_name" which 
called the "command_function" function in the module "your.module.name" 
when it is invoked.

Remember that you're installing into a shared area and make sure that 
both your module names and the command name itself are not too generic 
and thus unlikely to collide with other installed things. An end user 
can always make an alias for a long command if they use it a lot and 
start finding the typing tedious.

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

From marisesea at gmail.com  Sun Dec 12 17:16:18 2021
From: marisesea at gmail.com (Marise Miville)
Date: Sun, 12 Dec 2021 14:16:18 -0800
Subject: [Tutor] File I/O Help please!!
Message-ID: <CAM7fjZmDzd6WLnNEpHo-mwKQYdhQyhv2ivKFt6D65XNAwHN3wg@mail.gmail.com>

[image: Tutor help 1.png]

[image: image.png]
I am very new at this and I am trying to write 2 short programs.

*Program 1: Prepare a list of the primes less than 1500. Save them in
binary form to a file named 'SmallPrimes.dat'*

*Program 2: Open the file 'SmallPrimes.dat' and read them into a list.
Print them 5 at a time until the list is exhausted.*

This is how far I could get without success. What am I doing wrong? Can
anyone help me correct my codes?

Thank you everyone!!!

MM

From juliushamilton100 at gmail.com  Mon Dec 13 03:43:39 2021
From: juliushamilton100 at gmail.com (Julius Hamilton)
Date: Mon, 13 Dec 2021 09:43:39 +0100
Subject: [Tutor] Packaging questions
In-Reply-To: <YbZ/0Yl8NST/VCP1@cskk.homeip.net>
References: <D16B7AAB-F290-48D6-B2F0-8ABCD88FE7FB@yahoo.co.uk>
 <YbZ/0Yl8NST/VCP1@cskk.homeip.net>
Message-ID: <CAEsMKX3R++=OTsFLyrCMwXch34tDQEvw-t3ZpYLhwxMR5y2+NA@mail.gmail.com>

Thanks.

It seems like there are many ways to do this. I did one tutorial that I
didn?t quite fully understand but they put a script called ?module-run.py?
in the directory, which was the command line execution version. I don?t
remember what they did to make it easy to execute though.

Do you know which documentation page covers this topic?

I might read this next seeing as it goes over many different ?options?:

https://packaging.python.org/en/latest/overview/


Thanks,
Julius

On Mon 13. Dec 2021 at 05:11, Cameron Simpson <cs at cskk.id.au> wrote:

> On 12Dec2021 11:17, Alan Gauld <alan.gauld at yahoo.co.uk> wrote:
> >> What should I do if I want my pip installation to be a command line
> >> application instead of an importable library of functions? Do I need a
> more
> >> sophisticated setup.py file which installs an executable in usr/bin or
> >> something?
> >
> >You do know about the
> >
> >    if __name__ == ?__main__?:
> >
> >Idiom for making a module executable, right?
> >
> >That means an executable script and a module are the same thing.
>
> Just to follow on, you don't even need that (though you probably want
> it). The dictionary you supply with the module package can contain an
> entry like this:
>
>     'entry_points': {
>         'console_scripts': [
>             'your_command_name = your.module.name:command_function',
>         ],
>     },
>
> which makes a command line script which calls a function of your choice.
> The example above would create a script called "your_command_name" which
> called the "command_function" function in the module "your.module.name"
> when it is invoked.
>
> Remember that you're installing into a shared area and make sure that
> both your module names and the command name itself are not too generic
> and thus unlikely to collide with other installed things. An end user
> can always make an alias for a long command if they use it a lot and
> start finding the typing tedious.
>
> Cheers,
> Cameron Simpson <cs at cskk.id.au>
> _______________________________________________
> Tutor maillist  -  Tutor at python.org
> To unsubscribe or change subscription options:
> https://mail.python.org/mailman/listinfo/tutor
>

From david at graniteweb.com  Mon Dec 13 09:35:18 2021
From: david at graniteweb.com (David Rock)
Date: Mon, 13 Dec 2021 08:35:18 -0600
Subject: [Tutor] File I/O Help please!!
In-Reply-To: <CAM7fjZmDzd6WLnNEpHo-mwKQYdhQyhv2ivKFt6D65XNAwHN3wg@mail.gmail.com>
References: <CAM7fjZmDzd6WLnNEpHo-mwKQYdhQyhv2ivKFt6D65XNAwHN3wg@mail.gmail.com>
Message-ID: <20211213143518.GP18857@graniteweb.com>

* Marise Miville <marisesea at gmail.com> [2021-12-12 14:16]:
> 
> I am very new at this and I am trying to write 2 short programs.
> 
> *Program 1: Prepare a list of the primes less than 1500. Save them in
> binary form to a file named 'SmallPrimes.dat'*
> 
> *Program 2: Open the file 'SmallPrimes.dat' and read them into a list.
> Print them 5 at a time until the list is exhausted.*
> 
> This is how far I could get without success. What am I doing wrong? Can
> anyone help me correct my codes?

Two problems:

1. This mailing list strips attachments.  Please copy/paste your code as text
so we can see it instead of attaching an image.

2. we won't do homework for you. We will give suggestions
about where to look, but that will depend on what the code you've done looks
like.

-- 
David Rock
david at graniteweb.com

From wlfraed at ix.netcom.com  Mon Dec 13 10:01:30 2021
From: wlfraed at ix.netcom.com (Dennis Lee Bieber)
Date: Mon, 13 Dec 2021 10:01:30 -0500
Subject: [Tutor] File I/O Help please!!
References: <CAM7fjZmDzd6WLnNEpHo-mwKQYdhQyhv2ivKFt6D65XNAwHN3wg@mail.gmail.com>
Message-ID: <l2lergd4p8tvje04m9adb5nc4md71atmg7@4ax.com>

On Sun, 12 Dec 2021 14:16:18 -0800, Marise Miville <marisesea at gmail.com>
declaimed the following:

>[image: Tutor help 1.png]
>
>[image: image.png]

	This is a TEXT-ONLY forum. If possible, cut&paste the TEXT from a
console window, do not do image captures. If you must use an image (which
would mostly be required if having problems with layout of a GUI interface
-- unlikely for a beginner), you will have to acquire some hosting site and
post a link (URL) to the image on that site. Preferably use a site that
does not obscure the contents under some random/hash sequence, but instead
displays the actual file name(s) -- there are those of us who will not open
URLs that are a string of hex-digits; only those with known file types
shown.

>I am very new at this and I am trying to write 2 short programs.
>
>*Program 1: Prepare a list of the primes less than 1500. Save them in
>binary form to a file named 'SmallPrimes.dat'*
>

	Given the two part descriptions these sound a lot like homework. I'm
surprised a beginner's exercise for Python specifies "binary-form" --
that's a somewhat advanced module. Common Python I/O works in
"human-readable" text form.

	This program requires two things: a function/procedure for generating
prime numbers -- with a limit of <1500 even the Sieve of Eratosthenes (sp?)
only has to examine factors up to 750.; and logic to handle the I/O. The
binary requirement means using the	struct	module (you don't mention which
version of Python you are using, but the module hasn't changed that much
over the decades so https://docs.python.org/3.9/library/struct.html should
be usable).

>*Program 2: Open the file 'SmallPrimes.dat' and read them into a list.
>Print them 5 at a time until the list is exhausted.*
>

	Again... the struct module would be needed to read the file if it was
used when writing it. Printing "5 at a time" is probably easiest handled by
printing them one-at-a-time WITHOUT LINE-FEEDS and using counter to
indicate when a line-feed needs to be printed to start the next line. With
a suitable format, you can even get the columns to line up <G>

>This is how far I could get without success. What am I doing wrong? Can
>anyone help me correct my codes?

	Without seeing the code or error messages, there is not much we can
deduce.


-- 
	Wulfraed                 Dennis Lee Bieber         AF6VN
	wlfraed at ix.netcom.com    http://wlfraed.microdiversity.freeddns.org/


From cs at cskk.id.au  Mon Dec 13 18:10:20 2021
From: cs at cskk.id.au (Cameron Simpson)
Date: Tue, 14 Dec 2021 10:10:20 +1100
Subject: [Tutor] Packaging questions
In-Reply-To: <CAEsMKX3R++=OTsFLyrCMwXch34tDQEvw-t3ZpYLhwxMR5y2+NA@mail.gmail.com>
References: <CAEsMKX3R++=OTsFLyrCMwXch34tDQEvw-t3ZpYLhwxMR5y2+NA@mail.gmail.com>
Message-ID: <YbfS3EE/ZLS+OOgN@cskk.homeip.net>

On 13Dec2021 09:43, Julius Hamilton <juliushamilton100 at gmail.com> wrote:
>It seems like there are many ways to do this.

I think Alan and I have outlined the 2 main ways.

Alan's suggestion is standard for modules which can themselves be 
meaningfully run as a command. I do it all the time. Even if I haven't 
made a command line mode, the __main__ thing might run some tests.

The entry_points thing is the standard way to have the package install 
(run by "pip install") create a command script in the environment where 
the install is happening, typically a virtualenv.

>I did one tutorial that I
>didn?t quite fully understand but they put a script called ?module-run.py?
>in the directory, which was the command line execution version.

That's fiddly, unless they expect you to modify "module-run.py" in some 
way. Do Alan's __main__ thing, then you can just go:

    python -m your_module command line args here ...

to run it.

>I don?t
>remember what they did to make it easy to execute though.

Well, you could just go:

    python module-run.py command line args here ...

with no special actions. If you want "module-run.py" as a command (a) it 
needs execute permission and (b) it needs to be in your $PATH (on 
UNIXlike systems).

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

From wlfraed at ix.netcom.com  Mon Dec 13 20:52:23 2021
From: wlfraed at ix.netcom.com (Dennis Lee Bieber)
Date: Mon, 13 Dec 2021 20:52:23 -0500
Subject: [Tutor] Packaging questions
References: <CAEsMKX3R++=OTsFLyrCMwXch34tDQEvw-t3ZpYLhwxMR5y2+NA@mail.gmail.com>
 <YbfS3EE/ZLS+OOgN@cskk.homeip.net>
Message-ID: <bmtfrgt2oeis6u4f992jt56mk46g6vvbu3@4ax.com>

On Tue, 14 Dec 2021 10:10:20 +1100, Cameron Simpson <cs at cskk.id.au>
declaimed the following:

>with no special actions. If you want "module-run.py" as a command (a) it 
>needs execute permission and (b) it needs to be in your $PATH (on 
>UNIXlike systems).
>
	And just to provide the dark side... On Windows one needs suitable
FTYPE and ASSOC assignments -- eg:

C:\Users\Wulfraed>assoc .py
.py=Python.File

C:\Users\Wulfraed>ftype python.file
python.file="C:\WINDOWS\py.exe" "%L" %*

C:\Users\Wulfraed>py
Python ActivePython 3.8.2 (ActiveState Software Inc.) based on
 on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>

	Going further, if one doesn't want to provide the .py suffix and just
use "module-run", one needs to add it to the PATHEXT variable (hmm, I need
to clean mine up -- looks like updating Visual Studio added some...)

C:\Users\Wulfraed>set pathext
PATHEXT=.PY;.PY3;.PYC;.PYO;.PYW;.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC;.py;.pyw;.rexx;.rex;.rx

C:\Users\Wulfraed>


-- 
	Wulfraed                 Dennis Lee Bieber         AF6VN
	wlfraed at ix.netcom.com    http://wlfraed.microdiversity.freeddns.org/


From phillor9 at gmail.com  Tue Dec 14 00:43:18 2021
From: phillor9 at gmail.com (Phil)
Date: Tue, 14 Dec 2021 16:43:18 +1100
Subject: [Tutor] Tkinter frame background colour
Message-ID: <644f93ba-3935-1f0b-a780-0338ffb4dfa6@gmail.com>

My original GUI worked but it was a bit of a mess so I've spent most of 
the day building a new interface to my sudoku solver. However, there is 
one problem. I used to have a red line after the third and sixth column 
of boxes, the same with the rows. I achieved this by setting the frame's 
background to red and placing some padding after the third and sixth 
group of cells so that the red background would show through and show a 
red line between the 3 x 3 boxes. Otherwise, I'm happy with the result.

import tkinter as tk

class Root(tk.Tk):
 ??? def __init__(self):
 ??????? super().__init__()

 ??????? self.title('Sudoku Solver')
 ??????? self.geometry('300x300')

 ??????? self.frame = tk.Frame()
 ??????? self.frame.pack(expand=True)
 ??????? self.frame.bg="red"

 ??????? self.entry = [None] * 81
 ??????? for i in range(81):
 ??????????? r, c = divmod(i, 9)
 ??????????? self.entry[i] = tk.Entry(self.frame, width=2, 
justify=tk.CENTER, fg="red")
 ??????????? #if i == i % 3:
 ??????????? pad_x = (4, 0)
 ??????????? self.entry[i].grid(row=r, column=c, padx=pad_x)

 ??????? self.control_frame = tk.Frame()
 ??????? self.control_frame.pack(side=tk.TOP, pady=5)
 ??????? self.b_quit = tk.Button(self.control_frame, text='Quit',
 ??????????? command=self.quit)
 ??????? self.b_quit.pack(side=tk.LEFT)

 ??????? self.b_solve = tk.Button(self.control_frame, text='Solve',
 ??????????? command=self.solve)
 ??????? self.b_solve.pack(side=tk.RIGHT)

 ??? def quit(self):
 ??????? self.destroy()

 ??? def solve(self):
 ??????? self.entry[2].insert(0, '9')
 ??????? print(self.entry[2].get())


if __name__ == '__main__':
 ??? root = Root()
 ??? root.mainloop()

-- 
Regards,
Phil


From alan.gauld at yahoo.co.uk  Tue Dec 14 03:53:34 2021
From: alan.gauld at yahoo.co.uk (alan.gauld at yahoo.co.uk)
Date: Tue, 14 Dec 2021 08:53:34 +0000
Subject: [Tutor] Tkinter frame background colour
In-Reply-To: <644f93ba-3935-1f0b-a780-0338ffb4dfa6@gmail.com>
References: <2578db48-b904-4003-bb2a-7b8e99bbf936.ref@email.android.com>
Message-ID: <2578db48-b904-4003-bb2a-7b8e99bbf936@email.android.com>

   You are building a grid so why use the pack manager? it would all be so
   much easier if you use the grid manager.
   For the red lines I'd consider setting the borders of the entry widgets as
   a possibility. But I haven't tried it....
   Alan g
   From my phone
   On 14 Dec 2021 05:43, Phil <phillor9 at gmail.com> wrote:

     My original GUI worked but it was a bit of a mess so I've spent most of
     the day building a new interface to my sudoku solver. However, there is
     one problem. I used to have a red line after the third and sixth column
     of boxes, the same with the rows. I achieved this by setting the frame's
     background to red and placing some padding after the third and sixth
     group of cells so that the red background would show through and show a
     red line between the 3 x 3 boxes. Otherwise, I'm happy with the result.

     import tkinter as tk

     class Root(tk.Tk):
     ??? def __init__(self):
     ??????? super().__init__()

     ??????? self.title('Sudoku Solver')
     ??????? self.geometry('300x300')

     ??????? self.frame = tk.Frame()
     ??????? self.frame.pack(expand=True)
     ??????? self.frame.bg="red"

     ??????? self.entry = [None] * 81
     ??????? for i in range(81):
     ??????????? r, c = divmod(i, 9)
     ??????????? self.entry[i] = tk.Entry(self.frame, width=2,
     justify=tk.CENTER, fg="red")
     ??????????? #if i == i % 3:
     ??????????? pad_x = (4, 0)
     ??????????? self.entry[i].grid(row=r, column=c, padx=pad_x)

     ??????? self.control_frame = tk.Frame()
     ??????? self.control_frame.pack(side=tk.TOP, pady=5)
     ??????? self.b_quit = tk.Button(self.control_frame, text='Quit',
     ??????????? command=self.quit)
     ??????? self.b_quit.pack(side=tk.LEFT)

     ??????? self.b_solve = tk.Button(self.control_frame, text='Solve',
     ??????????? command=self.solve)
     ??????? self.b_solve.pack(side=tk.RIGHT)

     ??? def quit(self):
     ??????? self.destroy()

     ??? def solve(self):
     ??????? self.entry[2].insert(0, '9')
     ??????? print(self.entry[2].get())

     if __name__ == '__main__':
     ??? root = Root()
     ??? root.mainloop()

     --
     Regards,
     Phil

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

From phillor9 at gmail.com  Tue Dec 14 17:51:06 2021
From: phillor9 at gmail.com (Phil)
Date: Wed, 15 Dec 2021 09:51:06 +1100
Subject: [Tutor] Tkinter frame background colour
In-Reply-To: <2578db48-b904-4003-bb2a-7b8e99bbf936@email.android.com>
References: <2578db48-b904-4003-bb2a-7b8e99bbf936.ref@email.android.com>
 <2578db48-b904-4003-bb2a-7b8e99bbf936@email.android.com>
Message-ID: <07783092-25ae-3559-f496-6bf3e12879c2@gmail.com>

Problem solved, I wasn't setting the frame background colour correctly. 
This is correct:

 ??????? self.frame.configure(background="red")

-- 

Regards,
Phil


From mats at wichmann.us  Wed Dec 15 12:56:48 2021
From: mats at wichmann.us (Mats Wichmann)
Date: Wed, 15 Dec 2021 10:56:48 -0700
Subject: [Tutor] Packaging questions
In-Reply-To: <bmtfrgt2oeis6u4f992jt56mk46g6vvbu3@4ax.com>
References: <CAEsMKX3R++=OTsFLyrCMwXch34tDQEvw-t3ZpYLhwxMR5y2+NA@mail.gmail.com>
 <YbfS3EE/ZLS+OOgN@cskk.homeip.net>
 <bmtfrgt2oeis6u4f992jt56mk46g6vvbu3@4ax.com>
Message-ID: <D88579EE-EE6E-4597-94B9-C65B3DB24B12@wichmann.us>

On December 13, 2021 6:52:23 PM MST, Dennis Lee Bieber <wlfraed at ix.netcom.com> wrote:
>On Tue, 14 Dec 2021 10:10:20 +1100, Cameron Simpson <cs at cskk.id.au>
>declaimed the following:
>
>>with no special actions. If you want "module-run.py" as a command (a) it 
>>needs execute permission and (b) it needs to be in your $PATH (on 
>>UNIXlike systems).
>>
>	And just to provide the dark side... On Windows one needs suitable
>FTYPE and ASSOC assignments -- eg:
>
>C:\Users\Wulfraed>assoc .py
>.py=Python.File
>
>C:\Users\Wulfraed>ftype python.file
>python.file="C:\WINDOWS\py.exe" "%L" %*

As I've just found out, the value of ftype is fairly useless now, you need to look a lot deeper.



>C:\Users\Wulfraed>py
>Python ActivePython 3.8.2 (ActiveState Software Inc.) based on
> on win32
>Type "help", "copyright", "credits" or "license" for more information.
>>>>
>
>	Going further, if one doesn't want to provide the .py suffix and just
>use "module-run", one needs to add it to the PATHEXT variable (hmm, I need
>to clean mine up -- looks like updating Visual Studio added some...)
>
>C:\Users\Wulfraed>set pathext
>PATHEXT=.PY;.PY3;.PYC;.PYO;.PYW;.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC;.py;.pyw;.rexx;.rex;.rx
>
>C:\Users\Wulfraed>
>
>


-- 
Sent from my Android device with K-9 Mail. Please excuse my brevity.

From hemfaume at gmail.com  Thu Dec 16 07:52:41 2021
From: hemfaume at gmail.com (Henry Mfaume)
Date: Thu, 16 Dec 2021 14:52:41 +0200
Subject: [Tutor] I need help please
Message-ID: <CALfYTfVV9-Gd00UyX44Bpm2h3_vfhyBsDu7CA_6=hdFcKPnd4Q@mail.gmail.com>

HI There.
i installed anaconda on my pc, and through anaconda installed python,
pandas and other programs. i created an environment, but if i want to
import from the environment i created, i get the module not found error.

someone please help me.

Thank you.

Henry.

From alan.gauld at yahoo.co.uk  Fri Dec 17 03:45:12 2021
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Fri, 17 Dec 2021 08:45:12 +0000
Subject: [Tutor] I need help please
In-Reply-To: <CALfYTfVV9-Gd00UyX44Bpm2h3_vfhyBsDu7CA_6=hdFcKPnd4Q@mail.gmail.com>
References: <CALfYTfVV9-Gd00UyX44Bpm2h3_vfhyBsDu7CA_6=hdFcKPnd4Q@mail.gmail.com>
Message-ID: <sphimp$66s$1@ciao.gmane.io>

On 16/12/2021 12:52, Henry Mfaume wrote:
> HI There.
> i installed anaconda on my pc, and through anaconda installed python,
> pandas and other programs. i created an environment, but if i want to
> import from the environment i created, i get the module not found error.

Caveat:
I've never used anaconda and rarely use environments but...

I think that's the correct behaviour. The whole point of
virtual environments is to isolate the user from other
installations on the computer. So you need to install
everything into each environment.
It would defeat the purpose of having an environment
if they could see and use each others modules.

-- 
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  Fri Dec 17 13:21:11 2021
From: mats at wichmann.us (Mats Wichmann)
Date: Fri, 17 Dec 2021 11:21:11 -0700
Subject: [Tutor] I need help please
In-Reply-To: <sphimp$66s$1@ciao.gmane.io>
References: <CALfYTfVV9-Gd00UyX44Bpm2h3_vfhyBsDu7CA_6=hdFcKPnd4Q@mail.gmail.com>
 <sphimp$66s$1@ciao.gmane.io>
Message-ID: <FE2F56C9-6486-48A4-9130-3A0CC1AD8C3A@wichmann.us>

On December 17, 2021 1:45:12 AM MST, Alan Gauld via Tutor <tutor at python.org> wrote:
>On 16/12/2021 12:52, Henry Mfaume wrote:
>> HI There.
>> i installed anaconda on my pc, and through anaconda installed python,
>> pandas and other programs. i created an environment, but if i want to
>> import from the environment i created, i get the module not found error.
>
>Caveat:
>I've never used anaconda and rarely use environments but...
>
>I think that's the correct behaviour. The whole point of
>virtual environments is to isolate the user from other
>installations on the computer. So you need to install
>everything into each environment.
>It would defeat the purpose of having an environment
>if they could see and use each others modules.
>

Do your conda install from inside the active virtualenv
-- 
Sent from my Android device with K-9 Mail. Please excuse my brevity.

From phillor9 at gmail.com  Wed Dec 22 19:59:37 2021
From: phillor9 at gmail.com (Phil)
Date: Thu, 23 Dec 2021 11:59:37 +1100
Subject: [Tutor] method could be a function warning
Message-ID: <6306a283-372d-8406-7021-136e96f8ec5b@gmail.com>

I've been in the habit of mixing methods and functions within the GUI 
class and to get the functions to work I've had to prefix the call to 
the function with .self and add self as a function argument. The 
function dummy in the following code is an an example of this.

It makes more sense to me, and I think it's correct, to define and call 
the functions outside the GUI class as I've done with my_function below. 
Also, I'm thinking that the GUI class should be in a file of it's own 
because the total number of lines of code exceeds 500 thus making 
scrolling tedious.

I ask because I'm in the process of tidying up a Conway's Game of Life 
project that I wrote 3 years ago.

import tkinter as tk

class Root(tk.Tk):
 ??? def __init__(self):
 ??????? super().__init__()

 ??????? self.title('test')
 ??????? self.geometry('300x300')

 ??????? self.frame = tk.Frame()

 ??????? self.dummy()

 ??? def dummy(self):
 ??????? print('hello')

def my_function():
 ??? print('my function')

my_function()

if __name__ == '__main__':
 ??? root = Root()
 ??? root.mainloop()

-- 

Regards,
Phil


From alan.gauld at yahoo.co.uk  Wed Dec 22 20:29:16 2021
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Thu, 23 Dec 2021 01:29:16 +0000
Subject: [Tutor] method could be a function warning
In-Reply-To: <6306a283-372d-8406-7021-136e96f8ec5b@gmail.com>
References: <6306a283-372d-8406-7021-136e96f8ec5b@gmail.com>
Message-ID: <sq0jdv$oij$1@ciao.gmane.io>

On 23/12/2021 00:59, Phil wrote:
> I've been in the habit of mixing methods and functions within the GUI 
> class and to get the functions to work I've had to prefix the call to 
> the function with .self and add self as a function argument. The 
> function dummy in the following code is an an example of this.

The function dummy is a method not a function.
A method in OOP is how an object responds to a message.
In this case the message is Rootinstance.dummy() and
the method for handling that message is Root.dummy

In practical terms (in Python) a function defined inside
a class which takes as its firs parameter an instance of the
same class is a method.

The function my_function() is not a method since it is
defined outside the class and does not take an instance
as its first parameter.

> It makes more sense to me, and I think it's correct, to define and call 
> the functions outside the GUI class as I've done with my_function below. 

Functions are defined outside the class, methods are
defined inside. Functions or methods can be called
from inside or outside the class.


> Also, I'm thinking that the GUI class should be in a file of it's own 
> because the total number of lines of code exceeds 500 thus making 
> scrolling tedious.

That's a style issue but once you get beyond a few hundred
lines it's usually better to split it into a module.

However, your Root class is probably only ever going to
have a single instance which represents the application itself.
As such I don't know what you are going to put in any higher level
file. Won't it just consist of an import and instantiation of Root?
(essentially just the last 3 lines below) which seems a bit pointless.

> I ask because I'm in the process of tidying up a Conway's Game of Life 
> project that I wrote 3 years ago.

I wouldn't expect that to even take 500 lines in total.
I did a (mostly non-OOP*) curses version of life for my recent
book and it was only 98 lines in total, a GUI shouldn't
be much bigger! Even if you add an interactive start screen
which mine didn't have, it shouldn't be more than 200
lines tops.

What is making up all that code?

(*)It had a Cell class with a few attributes only and
5 functions including a main().

> import tkinter as tk
> 
> class Root(tk.Tk):
>  ??? def __init__(self):
>  ??????? super().__init__()
> 
>  ??????? self.title('test')
>  ??????? self.geometry('300x300')
> 
>  ??????? self.frame = tk.Frame()
> 
>  ??????? self.dummy()
> 
>  ??? def dummy(self):
>  ??????? print('hello')
> 
> def my_function():
>  ??? print('my function')
> 
> my_function()
> 
> if __name__ == '__main__':
>  ??? root = Root()
>  ??? root.mainloop()
> 


-- 
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  Wed Dec 22 20:22:30 2021
From: cs at cskk.id.au (Cameron Simpson)
Date: Thu, 23 Dec 2021 12:22:30 +1100
Subject: [Tutor] method could be a function warning
In-Reply-To: <6306a283-372d-8406-7021-136e96f8ec5b@gmail.com>
References: <6306a283-372d-8406-7021-136e96f8ec5b@gmail.com>
Message-ID: <YcPPVuBPEAv62NnP@cskk.homeip.net>

First: "method could be a function warning" looks like a linter warning.  
Is it?

On 23Dec2021 11:59, Phil <phillor9 at gmail.com> wrote:
>I've been in the habit of mixing methods and functions within the GUI 
>class and to get the functions to work I've had to prefix the call to 
>the function with .self and add self as a function argument. The 
>function dummy in the following code is an an example of this.

Yes. If your linter's complaining, that is because the method does not 
use self. So it does not need to be a method. That does not not mean it 
_should _not_ be a method. A function which is tightly associated with a 
class conceptually does belong in the class. For example, perhaps you've 
got a method which constructs a string in a way specificly for use with 
this class. That would naturally be a method.

Python has a couple of decorators for methods which don't use self: 
@classmethod and @staticmethod. You would define dummy() like this and 
_still_ call it via self.

    @staticmethod
??? def dummy():
??????? print('hello')

and linters will know you don't expect to use self. These have to do 
with the context needed for the method. _Mostly_ methods need self 
because they utilise the object state. Some might just need the class 
(for example to use some constants defined by the class) - they would 
need a classmethod:

    @classmethod
    def dummy2(cls):
        return cls.SOMETHING + 1

where SOMETHING is a class attribute. A staticmethod is just a function, 
and does not need the class or instance for context.

>It makes more sense to me, and I think it's correct, to define and 
>call the functions outside the GUI class as I've done with my_function 
>below.

A function outside a class is a general purpose utility function. I 
don't have many static methods, but those which are are conceptually 
related to the class. Here's an example from my Tag class:

    @staticmethod
    def is_valid_name(name):
        ''' Test whether a tag name is valid: a dotted identifier.
        '''
        return is_dotted_identifier(name)

So there's a Tag.is_valid_name(name) method for checking that a tag name 
is valid. It doesn't use the class or instance, but how it is 
implemented is a direct feature of the class. So it is a static method.

>Also, I'm thinking that the GUI class should be in a file of it's own 
>because the total number of lines of code exceeds 500 thus making 
>scrolling tedious.

You want a tags file, or whatever the equivalent is for your editor.  
Most code editors have a facility to jump to a symbol definition in your 
code. This reduces the concern with file size.

I prefer to break things up based on their conceptual structure. But 
there does come a size related time for breaking things up.

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

From mats at wichmann.us  Wed Dec 22 20:38:36 2021
From: mats at wichmann.us (Mats Wichmann)
Date: Wed, 22 Dec 2021 18:38:36 -0700
Subject: [Tutor] method could be a function warning
In-Reply-To: <6306a283-372d-8406-7021-136e96f8ec5b@gmail.com>
References: <6306a283-372d-8406-7021-136e96f8ec5b@gmail.com>
Message-ID: <fee03b4d-18f4-a7e2-10bc-0aae01d0eda3@wichmann.us>

On 12/22/21 17:59, Phil wrote:
> I've been in the habit of mixing methods and functions within the GUI
> class and to get the functions to work I've had to prefix the call to
> the function with .self and add self as a function argument. The
> function dummy in the following code is an an example of this.

The suggestion (as I recall it's not a "warning" but a "recommendation",
but my memory isn't that great) is that because the method doesn't make
any use of "self", why have it be a method that takes "self" as an
argument? But it's up to you... it's okay to put something that _could_
have been a global function inside the class because it's logically
connected to the things the class does, and not interesting otherwise.
You're certainly allowed to add indications (in the form of comments) to
tell the checker to shut up about this.
> 
> It makes more sense to me, and I think it's correct, to define and call
> the functions outside the GUI class as I've done with my_function below.
> Also, I'm thinking that the GUI class should be in a file of it's own
> because the total number of lines of code exceeds 500 thus making
> scrolling tedious.
> 
> I ask because I'm in the process of tidying up a Conway's Game of Life
> project that I wrote 3 years ago.
> 
> import tkinter as tk
> 
> class Root(tk.Tk):
> ??? def __init__(self):
> ??????? super().__init__()
> 
> ??????? self.title('test')
> ??????? self.geometry('300x300')
> 
> ??????? self.frame = tk.Frame()
> 
> ??????? self.dummy()
> 
> ??? def dummy(self):
> ??????? print('hello')
> 
> def my_function():
> ??? print('my function')
> 
> my_function()
> 
> if __name__ == '__main__':
> ??? root = Root()
> ??? root.mainloop()
> 


From cs at cskk.id.au  Wed Dec 22 20:46:09 2021
From: cs at cskk.id.au (Cameron Simpson)
Date: Thu, 23 Dec 2021 12:46:09 +1100
Subject: [Tutor] method could be a function warning
In-Reply-To: <YcPPVuBPEAv62NnP@cskk.homeip.net>
References: <YcPPVuBPEAv62NnP@cskk.homeip.net>
Message-ID: <YcPU4TQDTHHPNxB5@cskk.homeip.net>

Just to follow up to myself:

On 23Dec2021 12:22, Cameron Simpson <cs at cskk.id.au> wrote:
>A function outside a class is a general purpose utility function. I
>don't have many static methods, but those which are are conceptually
>related to the class. Here's an example from my Tag class:
>
>    @staticmethod
>    def is_valid_name(name):
>        ''' Test whether a tag name is valid: a dotted identifier.
>        '''
>        return is_dotted_identifier(name)
>
>So there's a Tag.is_valid_name(name) method for checking that a tag name
>is valid. It doesn't use the class or instance, but how it is
>implemented is a direct feature of the class. So it is a static method.

So what we're getting from a class staticmethod is that the class name 
is effectively part of the the function name. Instead of maybe making an 
external function like:

    def is_valid_tag_name(name):

I've defined a function effectively named "Tag.is_valid_name". Which is 
quite explicit about what kind of validity it is testing.

Also, if you've subclasses, or are writing something else which works on 
"tag-like" things, you can call:

    if tag_like_thing.is_valid_name(some_name):

and it will get the appropriate is_valid_name() method from the class 
which implements tag_like_thing, which might not be my "Tag" class but 
something which works like it.

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

From phillor9 at gmail.com  Wed Dec 22 23:07:36 2021
From: phillor9 at gmail.com (Phil)
Date: Thu, 23 Dec 2021 15:07:36 +1100
Subject: [Tutor] method could be a function warning
In-Reply-To: <YcPPVuBPEAv62NnP@cskk.homeip.net>
References: <6306a283-372d-8406-7021-136e96f8ec5b@gmail.com>
 <YcPPVuBPEAv62NnP@cskk.homeip.net>
Message-ID: <c7097d03-6ca0-49c3-7674-edb4b9b389f4@gmail.com>


On 23/12/21 12:22, Cameron Simpson wrote:
> First: "method could be a function warning" looks like a linter warning.
> Is it?
>
>
> Yes. If your linter's complaining, that is because the method does not
> use self. So it does not need to be a method. That does not not mean it
> _should _not_ be a method.

Thank you Cameron, Alan and Mats.

I didn't mention in my initial message that I had tried:

 ??????? self.dummy()

 ??? @staticmethod
 ??? def dummy():
 ??????? print('hello')

This quietened pylint but since I still need to prefix the call to 
dummy() with self. I presumed that what I was doing still wasn't quite 
correct.

Dummy(), not it's real name, doesn't access anything from the gui class. 
It's used as a helper function, and it's called by several methods that 
do access a gui widget. So I suppose, based on what you have said, I 
should us the @staticmethod and leave it at that.

-- 

Regards,
Phil


From cs at cskk.id.au  Wed Dec 22 23:11:03 2021
From: cs at cskk.id.au (Cameron Simpson)
Date: Thu, 23 Dec 2021 15:11:03 +1100
Subject: [Tutor] method could be a function warning
In-Reply-To: <c7097d03-6ca0-49c3-7674-edb4b9b389f4@gmail.com>
References: <c7097d03-6ca0-49c3-7674-edb4b9b389f4@gmail.com>
Message-ID: <YcP21122B4hCVu76@cskk.homeip.net>

On 23Dec2021 15:07, Phil <phillor9 at gmail.com> wrote:
>Dummy(), not it's real name, doesn't access anything from the gui 
>class. It's used as a helper function, and it's called by several 
>methods that do access a gui widget. So I suppose, based on what you 
>have said, I should us the @staticmethod and leave it at that.

If it is conceptually for the purposes of the class, then yes.

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

From Richard at Damon-Family.org  Thu Dec 23 00:19:41 2021
From: Richard at Damon-Family.org (Richard Damon)
Date: Thu, 23 Dec 2021 00:19:41 -0500
Subject: [Tutor] method could be a function warning
In-Reply-To: <YcP21122B4hCVu76@cskk.homeip.net>
References: <c7097d03-6ca0-49c3-7674-edb4b9b389f4@gmail.com>
 <YcP21122B4hCVu76@cskk.homeip.net>
Message-ID: <b952667a-890c-a5f0-f903-dd89e17549d5@Damon-Family.org>

On 12/22/21 11:11 PM, Cameron Simpson wrote:
> On 23Dec2021 15:07, Phil <phillor9 at gmail.com> wrote:
>> Dummy(), not it's real name, doesn't access anything from the gui
>> class. It's used as a helper function, and it's called by several
>> methods that do access a gui widget. So I suppose, based on what you
>> have said, I should us the @staticmethod and leave it at that.
> If it is conceptually for the purposes of the class, then yes.
>
> Cheers,
> Cameron Simpson <cs at cskk.id.au>

As a static method, you call call it with self.dummy() or Root.dummy() 
(i.e. either on an instance of the class or the class itself) as by 
makeing it a (static) method, the name is put into the namespace of the 
class.

If you don't want to need to prefix it with anything, you need to make 
it not a member of the class, and then it is just a global.

Unlike some languages, just because you are inside a method of a class, 
Python doesn't automatically assume to start looking in that class for 
names, but all accesses need to be prefixed with the space to look in. 
(This may be your confusion, it isn't like C++ for instance which will 
try to assume the 'this' or 'class' added to the call.)

-- 
Richard Damon


From phillor9 at gmail.com  Thu Dec 23 03:15:10 2021
From: phillor9 at gmail.com (Phil)
Date: Thu, 23 Dec 2021 19:15:10 +1100
Subject: [Tutor] method could be a function warning
In-Reply-To: <b952667a-890c-a5f0-f903-dd89e17549d5@Damon-Family.org>
References: <c7097d03-6ca0-49c3-7674-edb4b9b389f4@gmail.com>
 <YcP21122B4hCVu76@cskk.homeip.net>
 <b952667a-890c-a5f0-f903-dd89e17549d5@Damon-Family.org>
Message-ID: <1c5f0cac-7b77-73fa-973d-993c46b5834f@gmail.com>


On 23/12/21 16:19, Richard Damon wrote:
>
> (This may be your confusion, it isn't like C++ for instance which will 
> try to assume the 'this' or 'class' added to the call.)
Thanks Richard, I do find the differences between Python and C++ 
confusing. I have this difference sorted out now.

-- 
Regards,
Phil


From chamblissjames51 at gmail.com  Fri Dec 24 23:02:56 2021
From: chamblissjames51 at gmail.com (James Chambliss)
Date: Fri, 24 Dec 2021 21:02:56 -0700
Subject: [Tutor] (no subject)
Message-ID: <CAGQx4PfZoKGNCspNaW2nWVACQki0saW-3zY3qs2yx-b_FfWF+A@mail.gmail.com>

Need help understanding how to use class decorated......

From alan.gauld at yahoo.co.uk  Sat Dec 25 03:53:24 2021
From: alan.gauld at yahoo.co.uk (Alan Gauld)
Date: Sat, 25 Dec 2021 08:53:24 +0000
Subject: [Tutor] class decorated was: (no subject)
In-Reply-To: <CAGQx4PfZoKGNCspNaW2nWVACQki0saW-3zY3qs2yx-b_FfWF+A@mail.gmail.com>
References: <CAGQx4PfZoKGNCspNaW2nWVACQki0saW-3zY3qs2yx-b_FfWF+A@mail.gmail.com>
Message-ID: <sq6m64$1662$1@ciao.gmane.io>

Please always add a meaningful subject line it helps
find things in the archive.

On 25/12/2021 04:02, James Chambliss wrote:
> Need help understanding how to use class decorated......

You need to be more specific. Are you trying to decorate
a class using the standard decorators? Are you trying
to write a decorator of your own?

Are you trying to decorate the whole class? Or just
methods or attributes within the class?

Do you have a specific task in mind for this decorator?
Or are you just asking out of general interest and curiosity?

The more specific the question the more specific the answer.

Also, it usually helps if you tell us which Python version
and OS you are using.

-- 
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 juliushamilton100 at gmail.com  Sat Dec 25 12:11:26 2021
From: juliushamilton100 at gmail.com (Julius Hamilton)
Date: Sat, 25 Dec 2021 18:11:26 +0100
Subject: [Tutor] Break element into list while iterating
Message-ID: <CAEsMKX0=7r6sHOm2i6FPOEiOqtnjPzpAN34o3BZihv3CYfE9oQ@mail.gmail.com>

Hey,

I would like to do some kind of list comprehension where elements meeting
certain conditions get split on a delimiter. They don?t become lists nested
in one element in the previous list; the new elements just get inserted
where the old one was.

Like this:

[?apple?, ?pear?]

->

[?a?, ?p?, ?p?, ?l?, ?e?, ?pear?]

Is there a list comprehension syntax where if I split an element with
e.split(), I can ?insert? those elements at the element they came from?

Thanks very much,
Julius

From juliushamilton100 at gmail.com  Sat Dec 25 15:46:02 2021
From: juliushamilton100 at gmail.com (Julius Hamilton)
Date: Sat, 25 Dec 2021 21:46:02 +0100
Subject: [Tutor] Segmenting bash help docs
Message-ID: <CAEsMKX00RUNo=xAoT7tatJxBOJfUWZ2e1D3V=13y8M5qyJ96iA@mail.gmail.com>

Hey,

I am pretty close to pulling this off and I thought I?d reach out to fill
in a few gaps.

I can imagine writing a Bash function which takes the help page and
displays it sentence by sentence.

If we consider code for doing this step by step:

$ help wait > wait.txt

$ python3

>>> import spacy, requests

>>> f = open(?wait.txt?).read()

>>> sen = spacy.load(?en_core_web_sm?)(f)

The sentences are pretty well segmented. There is a thread that fascinates
me about separating on an even more fine-grained level (
https://stackoverflow.com/questions/65227103/clause-extraction-long-sentence-segmentation-in-python),
but I won?t venture there yet.

What I can do is first split the current list on any newline regions
greater than one newline.

>>> sen = [s.text.strip() for s in sen]

Then I can compress broken sentences into single lines by replacing
extended whitespace with a single whitespace:

>>> sen = [re.sub(?[\s]+?, ? ?, s) for s in sen]

Not sure if anybody has any opinions on this, or ways they?d improve it.
It?d be cool to find a single simple, elegant way to clean, strip and
conjoin the sentences/lines in one line of code, and also not to use the
?re? module if not necessary.

Thanks,
Julius

From mats at wichmann.us  Sun Dec 26 10:50:32 2021
From: mats at wichmann.us (Mats Wichmann)
Date: Sun, 26 Dec 2021 08:50:32 -0700
Subject: [Tutor] Segmenting bash help docs
In-Reply-To: <CAEsMKX00RUNo=xAoT7tatJxBOJfUWZ2e1D3V=13y8M5qyJ96iA@mail.gmail.com>
References: <CAEsMKX00RUNo=xAoT7tatJxBOJfUWZ2e1D3V=13y8M5qyJ96iA@mail.gmail.com>
Message-ID: <4cc909cb-c1ac-6185-0ddc-bfd66e5eba93@wichmann.us>

On 12/25/21 13:46, Julius Hamilton wrote:

> Not sure if anybody has any opinions on this, or ways they?d improve it.
> It?d be cool to find a single simple, elegant way to clean, strip and
> conjoin the sentences/lines in one line of code, and also not to use the
> ?re? module if not necessary.

This is the kind of problem regular expressions were invented for, so
don't be shy about using them...

If you want to get really carried away, consider the natural language
toolkit (nltk): https://www.nltk.org/


From learn2program at gmail.com  Sun Dec 26 13:33:14 2021
From: learn2program at gmail.com (Alan Gauld)
Date: Sun, 26 Dec 2021 18:33:14 +0000
Subject: [Tutor] Break element into list while iterating
In-Reply-To: <CAEsMKX0=7r6sHOm2i6FPOEiOqtnjPzpAN34o3BZihv3CYfE9oQ@mail.gmail.com>
References: <CAEsMKX0=7r6sHOm2i6FPOEiOqtnjPzpAN34o3BZihv3CYfE9oQ@mail.gmail.com>
Message-ID: <90eeacde-f765-7891-1567-4e795815f197@yahoo.co.uk>


On 25/12/2021 17:11, Julius Hamilton wrote:
> Hey,
>
> I would like to do some kind of list comprehension where elements meeting
> certain conditions get split on a delimiter. They don?t become lists nested
> in one element in the previous list; the new elements just get inserted
> where the old one was.


Not a LC as such but I did get this:


>>> L = ['apple', 'pear', 'grape']
>>> def splitInListAt(L,idx):
??? return L[:idx] + [n for n in L[idx]] + L[idx+1:]

>>> splitInListAt(L,0)
['a', 'p', 'p', 'l', 'e', 'pear', 'grape']
>>> splitInListAt(L,1)
['apple', 'p', 'e', 'a', 'r', 'grape']
>>> splitInListAt(L,2)
['apple', 'pear', 'g', 'r', 'a', 'p', 'e']
>>>

Which is generic to any kind of sequence not just strings:

>>> L = [[1,2,3],(4,5,6),{7,8,9}]
>>> splitInListAt(L,0)
[1, 2, 3, (4, 5, 6), {8, 9, 7}]
>>> splitInListAt(L,1)
[[1, 2, 3], 4, 5, 6, {8, 9, 7}]
>>> splitInListAt(L,2)
[[1, 2, 3], (4, 5, 6), 8, 9, 7]
>>>

-- 
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