[Tutor] Looking for some comments on my code segment...

dn PythonList at DancesWithMice.info
Fri Feb 24 22:09:31 EST 2023


On 25/02/2023 10.13, Dave (NK7Z) wrote:
> I tend to drop in with both feet into anything I try hence, the hello 
> world to telnet move...

As long as you don't drive yourself into over-load and right over a 
cliff into de-motivation...


> Tests to prove code:
> 
> The entire program is around 800 lines long at this point, and I did not 
> want to drop that into an email...

Quite right. If the code exhibits an error, the first thing to do is 
extract the minimum example which will illustrate/demonstrate the error, 
and post that. (assuming such process doesn't make the solution leap-out)


> An overview of what I am doing:
> I have an amateur radio license, and there are telnet servers on the net 
> called clusters, these clusters aggregate incoming spots, (little notes 
> amateurs send to the cluster servers), to tell other amateur radio 
> operators, they have seen a station, on such and such a frequency, using 
> such and such a mode, at such and such a time.  The cluster spots are 
> highly formatted, and are designed to be parsed by software.  This 
> software is written for two reasons, one to teach me Python, and the 
> other to alert me to selected stations from a list in a file, that 
> changes from time to time.
> The software logs into one of these clusters, parses the incoming telnet 
> feed stream, and then verbally announces stations I am interested in, as 
> defined in a separate file I populate.

I've never been a 'ham' operator. Almost 32-years to the day, I hung-up 
my three 'radios', amongst other electronic (and other) items: one would 
now be called a sat-phone - for talking to "Central Command" (I never 
did figure-out where), an FM/VHF and FA unit for talking with the pilots 
flying CAP close-by in case we needed them (and when we did, we did - 
and they did...), and another at some longer wave for talking with Fleet 
and the grey tin-cans bobbing about in the Gulf.

That said, we've just endured a series of natural disasters, and 'this 
modern generation' have realised that relying upon cell-phones and 'the 
Internet' is a superficial layer of banality, sorry, security, which 
separates 'civilisation' from 'breakdown'. Hams + generators have 
certainly been needed to provide vital comms. Interestingly, (lesson not 
learned?) a 'solution' has been to fly-in pairs of StarLink + gen-set to 
separated communities.


> Code Proof:
> The code proof is that it is working, it logs into the clusters, and 
> announces what I expect.  All the code works, as far as I can tell, the 
> software logs in, IDs my by callsign to the server, configures the 
> server stream, then looks at the incoming stream of data, and parses it 
> looking at my want list from that other file.  A day can have as many as 
> a million spots in it across a 24 hour period.
> 
> My question is motivated by the far end dropping telnet connection every 
> few days, (reset server, update the server software, etc, does not 
> happen often). I want to be able to trap that drop and gracefully leave 
> the script.  Or perhaps relog in after I gain some confidence in my 
> programming ability ion Python.

You can test this by removing the Ethernet cable from your computer!

To solve the bigger 'problem', break it down into smaller, sub-problems, 
eg "grabbing data from the server" can be split into connecting, 
logging-in, call-sign, establish stream, examine ...

Try working 'bottom-up'. Take each of these in-turn, and split it off 
into its own function. What result(s) do you expect from this function? 
What will it do to create such output? What input will it need?

NB "results" because an error-occurring will be a different result from 
a successful-execution (etc).

Now, you can write other code which calls that function, purely with the 
intent of testing what happens if you give it certain input(s) - and can 
check to see if the output(s) is/are exactly as-designed.

By doing this, breaking the 800-line entirety into smaller "units", you 
can concentrate on the proverbial one-thing-at-a-time, gain confidence 
(in yourself, and the code), and test for only relevant issues 
(undistracted by what else happens at other stages in the process).

(there's more to be said about this process, but (hah!) one step at a 
time cf 'overload'...)

Once you have completed a daisy-chain of such units (perhaps as 
loosely-outlined, above) you can (going bottom-up) work on a 
'higher-level' function which will call each of the smaller units, in 
sequence - feeding them needed data, and controlling the returned-results.

(and so-on, until reach the 'mainline')


> Globals:
> I am using globals, because in some cases, the variable(s) I use is/are 
> not passed to/from the function.

Why not then, pass them into the function? (etc)
(see also @Cameron's comments)


> Where are these constants coming from:
> 
> They are defined very early on in the software.  I could drop thej 
> software here, but it is around 800 lines long, so I decided to not as 
> my first post...  :)

Consider that combinations such as "HOST, PORT, TIMEOUT" could be 
presented as a "collection", eg a tuple. Then there'd only be one 
identifier to pass-around. You can also select a name which communicates 
its use/purpose!

The point to the question though, was to point-out that these 
'magic-constants' just 'appear', whereas tn and failcode are explicitly 
identified. Don't make me think! (it hurts)

Agreed, one lot are 'read-only' and the others read-write, thus 
appropriate mechanisms must be chosen. However, if you combine thoughts 
from (above), eg what is the output from this unit of code, they you 
realise that the telnet object is output from one unit which will become 
input to another. Thus, no need for it to be a 'global'. (see also 
@Cameron's comment, aka avoid globals as much as possible - on the 
grounds that such techniques, whilst perfectly legal, have a nasty habit 
of coming back to bite you)


> Failcode:
> I write a log file of my own making, and add the fail codes in the event 
> something dies, I know where...
> 
> Logging:
> Not using logging library, I ran across that a few days ago, and will be 
> switching to that method later, after things are running as I want.

ToDo: See above. Smaller units make 'location' easier.

Backlog: read-up about the logging library.


> exitscript:
> Yes the main calling loop could leave with a try/except, but for now, I 
> am exiting this way, that will guarantee a clean exit.  exitscript() is 
> just a routine to kill things, in a way I KNOW will things get killed as 
>   I want then to be killed.

Complement your development using try...except with raise and Custom 
Exceptions. In short, defining your own means that you can use 
try-except at the 'higher level' to achieve exactly what you are 
currently rolling-by-hand.

In short, now that you have learned this new technique, go 'back' and 
refactor (improve) earlier code to take advantage. (no shame, 
refactoring is 'best practice')


> Because I am interacting with someone else's server, and because this is 
> the first telnet script in Python I have written, I want to INSURE 
> without a doubt I have closed the connection in case of a fail of some 
> sort in my code.

Good thinking - we should all be 'good citizens', aka 'the Boy Scout Rule'.

There is a time-out on every telnet transaction (not only the logging-in 
process). You do not need to fear for the remote server!

Another powerful technique you might like to add to the 'Backlog' is 
Python's Context Manager protocol. The philosophy exactly matches your 
intent. Three tasks:

- task commencement
- the doing of the task
- cleaning-up afterwards

Context-managers will guarantee that the last will be completed 
regardless of the success/state of earlier stages!


> As I said, I am VERY new to Python...  I just learned how try/except 
> worked a few weeks ago, so I did not put that in my main calling loop, I 
> directed things to a function designed to kill things no matter what 
> happened...  I am now using try/except and understand it, and at some 
> point will correct things in the main caller.

Recommend sooner rather than later. Let the power of Python (in this 
case try-except) save you unnecessary work (blood, sweat, or tears).


> There will be many changes to the script over time, right now I am 
> working on the telnet portion, and that is why I am asking about that.

...and we're back to "units"!

We develop a unit at a time, and in relative isolation - get it right, 
and move-on.


> This entire script is a learning experience for me, and that is why I 
> decided to write it in Python, never wrote in Python before, and for 
> that I am sad...  Things seem to just come together in Python.  I am 
> having a blast with it!

That's why we like it too!


> I can't seem to get my head around how to trap the telnet errors though...

Which one(s)?
Where is current code failing?


> Again, thanks for your help in all of this, and sorry the questions are 
> so basic.

That's why this Discussion List exists!

"There's no such thing as a stupid-question, only stupid answers".
(that said, there are ways of asking a question which will promote the 
receipt of a good/better/best answer...)

-- 
Regards,
=dn


More information about the Tutor mailing list