[Tutor] Debug help

Cameron Simpson cs at cskk.id.au
Sun Jul 19 19:57:46 EDT 2020


On 19Jul2020 15:25, jim <jf_byrnes at comcast.net> wrote:
[...]
>Here is the part of the code that generates the error, the remainder of 
>the script just manipulates the spreadsheet.
>
>    for stock in stocks:
>        # ~ count = 0
>        # ~ while count < total_num_of_stocks:
>        # ~ while count < 33:
>        while True:
>            # ~ count = count + 1
>            try:
>                # ~ print('Day = ' + day)
>                ticker = yf.Ticker(stock)
>                # ~ print('Ticker = ' + ticker)
>                hist = ticker.history(start=day)
>                # ~ print('History = ' + hist)
>                close_price = hist.loc[day]['Close']
>                # ~ print('Close = ' + close_price)
>                closing_prices.append(close_price)
>
>            except:
>                print ('yfinance JSONDecodeError DAILY, retyring')
>                # ~ print ('ticker: ' + hist)
>                continue
>            break
>
>    # Get stock values by multiplying the list elements by number of shares
>    # using zip()
>    value = [num_shares * stk for num_shares, stk in zip(shares, 
>closing_prices)]
>
>    # Put date in cell then go down one row
>    S(cell_loc).string = day
>    S().dispatch('GoDown')
>
>    # Fill column for MY100000 with stock values using the number of 
>stocks in MY100000
>    for stk in value[:total_num_MY100000]:
>        S().value = stk # Line 102
>        S().dispatch('GoDown')
>
>If I run the script with the print lines outside the except commented 
>out it will print the date in the spreadsheet, go down 1 cell and 
>throw the error and end. If I uncomment any of the print lines it 
>seems to go into a endless loop printing out the exception error msg.
>
>I wonder if anyone has an idea of how to figure out what Yahoo Finance 
>is doing to cause a problem and I am curious as to why uncommenting a 
>print seems to cause an endless loop.

I'm unfamiliar with Yahoo Finance, but I want to comment on your 
debugging issues.

Your code's control structure is like this:

    while True:
        try:
            [...]
            # ~ print('Close = ' + close_price)
            [...]
        except:
            print ('yfinance JSONDecodeError DAILY, retyring')
            # ~ print ('ticker: ' + hist)
            continue

First up, consider what happens when anything goes wrong inside the 
try/except: you print something and continue, restarting the loop. If 
that thing happens on every pass, you get an infinite loop.

See the commented out print(). Supposing close_price is not a string.  
The addition will raise a TypeError exception. And into the infinite 
loop you go.

Better, for debugging statements, to perform as few operations as 
possible. because if something is wrong, any operation might itself fail 
because things as not as you expect. So consider:

    print('Close = ', close_price)

Because print() converts all is arguments to strings, the form above 
does no addition and still produces a result.

However, the biggest problem here is what we call a "bare except": an 
except which catches _any_ exception. That's handy for reporting on 
_everything_ which explodes, but otherwise a bad practice.

The rule of thumb for catching excpetions is to _only_ catch what you 
expect and know how to handle _correctly_. Your code catches everything 
(again, great for reporting) but does not know what to do with it.

Because you do not print the exception or where it came from, you learn 
nothing about the underlying issue. Consider this:

    while True:
        try:
            [...]
            # ~ print('Close = ' + close_price)
            [...]
        except Exception as e:
            print("unexpection exception:", e)
            print ('yfinance JSONDecodeError DAILY, retyring')
            # ~ print ('ticker: ' + hist)
            continue

At least this will show you what is wrong. But better still is not to 
catch it at all. It is unexpected, so your print-and-continue action is 
probably inappropriate (because you do not know the context - _anything_ 
might be wrong). As a scarey example, consider:

    while True:
        try:
            x = closed_price
            [...]
            # ~ print('Close = ' + close_price)
            [...]
        except Exception as e:
            print("unexpection exception:", e)
            print ('yfinance JSONDecodeError DAILY, retyring')
            # ~ print ('ticker: ' + hist)
            continue

Here, "closed_price" is a misspelled variable name. Python will raise a 
NameError because it is an unknown name, and you won't have even printed 
out the exception, so you will be blind to a simple typo in the code.

The usual pattern with try/except is to catch exactly what you can 
handle, and let other exceptions out. That does abort your programme, 
but you get the raw exception _and_ a nice stacktrace showing where it 
came from:

    while True:
        try:
            x = closed_price
            [...]
            # ~ print('Close = ' + close_price)
            [...]
        except HTTPError as e:
            print("HTTP networking error", e)
            time.sleep(1)
            continue

Here we catch an expected failure (the network maybe went away, and the 
HTTP conencion did not work). We print that, and we sleep for 1 second 
to avoid a busy loop (spinning until the network works again). But this 
is an _expected_ exception with a well defined plan for accomodating it.  
So we catch it, report it, and continue.

Now, you may only know how to handle a specific type of an exception.  
Then the pattern is only slightly more elaborate:

    while True:
        try:
            x = closed_price
            [...]
            # ~ print('Close = ' + close_price)
            [...]
        except HTTPError as e:
            # I'm just making up some kind of test on the exception here
            if e.errno == errno.EIO:
                print("HTTP networking error", e)
                time.sleep(1)
                continue
            raise

Here, we know how to handle a specific type of HTTPError. Any others are 
just reraised, producing an error and a stack trace for you to examine.

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


More information about the Tutor mailing list