<jupyter_start><jupyter_text>Python [conda env:PY27_Test] Python Warning and Exception Handling Basics  TOC- Working with Warnings:  Immediately Below- [Exception Handling: try-except-finally and raise](except) Working With WarningsThis example shows integration of warnings with object code.  The following topics were useful in researching this code:- [Simple warn example on Stack Overflow](http://stackoverflow.com/questions/3891804/how-to-raise-a-warning-in-python-without-stopping-interrupting-the-program)- [Python warnings Documentation](https://docs.python.org/3/library/warnings.htmlwarnings.warn)<jupyter_code># Note how warnings in this sample are held until after code is run and then output at the end ...

from warnings import warn
from warnings import resetwarnings

class myClass(object):        
    def __init__(self, numberArg):

        if numberArg > 1000:
            self._tmpTxt = "That's a really big number for this code." + \
                           "Code may take a while to run..."
            warn("\n%s %s" %(numberArg, self._tmpTxt), stacklevel=0, category=RuntimeWarning)
                                                       # possible categories (some of them):
                                                       # UserWarning, Warning, RunTimeWarning, ResourceWarning
                                                       # stacklevel was a experiment w/ no visible effect
                                                       # in this instance
            
            resetwarnings()                            # tried putting this before and after the warn()
            print("If this were real code:")
            print("Actions code takes because this is a big number would happen here.")
        
        print("If this were real code, it would be doing more stuff here ...")
        
mc1 = myClass(1001)
# In this case, we want the warning to come before code execution.  This is easily fixed as shown below.
# note: removed some extraneous useless stuff, the line to look for is sys.stderr.flush()

from warnings import warn
from warnings import resetwarnings

class myClass(object):        
    def __init__(self, numberArg):

        if numberArg > 1000:
            self._tmpTxt = "That's a really big number for this code." + \
                           "Code may take a while to run..."
            warn("\n%s %s" %(numberArg, self._tmpTxt), category=Warning)            
            sys.stderr.flush()                         # put this after each warn() to make it output more immediately
            print("If this were real code:")
            print("Actions code takes because this is a big number would happen here.")
        
        print("If this were real code, it would be doing more stuff here ...")
        
mc1 = myClass(1001)  
# note the warning from this output example to compare it to the next cell ...
# multiple identical warnings are issued and all are output

from warnings import warn

class myClass(object):        
    def __init__(self, numberArg):
        
        for i in [1,2]:

            if numberArg > 1000:
                print("loop count %d:" %(i))
                self._tmpTxt = "That's a really big number for this code." + \
                               "Code may take a while to run..."
                warn("\n%s %s" %(numberArg, self._tmpTxt), stacklevel=1, category=RuntimeWarning)
                sys.stderr.flush() # this provides warning ahead of the output instead of after it
                print("If this were real code:")
                print("Actions taken because this is a big number would happen here.")
                warn("\n%s %s" %(numberArg, self._tmpTxt), stacklevel=1, category=RuntimeWarning)
                sys.stderr.flush()
                
            if numberArg > 20000:
                self._tmpTxt = "That's a really really really big number for this code." + \
                               "Code may take a while to run..."                
                warn("\n%s %s" %(numberArg, self._tmpTxt), stacklevel=1)
                sys.stderr.flush() # this provides warning ahead of the output instead of after it

                warn("\n%s %s" %(numberArg, self._tmpTxt), stacklevel=1)
                sys.stderr.flush()
                print("If this were real code:")
                print("Actions taken because this is an even bigger number would happen here.")

                
            print("loop count %d:" %(i))    
            print("If this were real code, it would be doing more stuff here ...")

mc1 = myClass(1001)
print("====================")
mc2 = myClass(20001)
# code provided as an experiment ... may be updated later with a more useful example ...
# in theory, filterwarnings should help shake out repeat warnings if used with right arguments
#   * note how our loop causes the content to print twice, and in theory, the 3 instances of warnings
#   * occur twice each for 6 possible output warnings
#   * each new occurance (3 of them) still outputs, but when the same ones come up again, they don't
#   * we get 3 instead of 6 warnings ... this should be the effect of filterwarning("once", ...)
#     in this instance

# help on this: https://docs.python.org/3/library/warnings.html#warning-filter
#               in this example:
#                  "once" arg = print only the first occurrence of matching warnings, regardless of location

from warnings import warn
from warnings import resetwarnings
from warnings import filterwarnings

class myClass(object):        
    def __init__(self, numberArg):
        for i in [1,2]:            
            if numberArg > 1000:
                print("loop count %d:" %(i))
                self._tmpTxt = "That's a really big number for this code." + \
                               "Code may take a while to run..."
                filterwarnings("once")    
                warn("\n%s %s" %(numberArg, self._tmpTxt), stacklevel=1, category=RuntimeWarning)
                sys.stderr.flush() # this provides warning ahead of the output instead of after it
                # resetwarnings()  # no noticeable effect on the code
                print("If this were real code:")
                print("Actions taken because this is a big number would happen here.")
                warn("\n%s %s" %(numberArg, self._tmpTxt), stacklevel=1, category=RuntimeWarning)
                sys.stderr.flush()
                # resetwarnings()  # no noticeable effect on the code
                
            if numberArg > 20000:
                self._tmpTxt = "That's a really really really big number for this code." + \
                               "Code may take a while to run..."
                filterwarnings("once")    
                warn("\n%s %s" %(numberArg, self._tmpTxt), stacklevel=1)
                sys.stderr.flush() # this provides warning ahead of the output instead of after it
                # resetwarnings()  # no noticeable effect on the code

                warn("\n%s %s" %(numberArg, self._tmpTxt), stacklevel=1)
                sys.stderr.flush()
                # resetwarnings()  # no noticeable effect on the code
                print("If this were real code:")
                print("Actions taken because this is an even bigger number would happen here.")

            print("loop count %d:" %(i))    
            print("If this were real code, it would be doing more stuff here ...")

mc1 = myClass(1001)
print("====================")
mc2 = myClass(20001)
# Notice the impact of putting the filter statement in only once at the start of the code:
# intermittent symptom:  repeat executions:
#                        sometimes produces output shown in this notebook
#                        sometimes produces identical output to the cell above

from warnings import warn
from warnings import resetwarnings
from warnings import filterwarnings

class myClass(object):        
    def __init__(self, numberArg):
        filterwarnings("once")    # note: message argument is regEx to filter by
                                  # in this case, we want it to filter all warnings
        
        for i in [1,2]:            
            if numberArg > 1000:
                print("loop count %d:" %(i))
                self._tmpTxt = "That's a really big number for this code." + \
                               "Code may take a while to run..."
                warn("\n%s %s" %(numberArg, self._tmpTxt), stacklevel=1, category=RuntimeWarning)
                sys.stderr.flush() # this provides warning ahead of the output instead of after it
                # resetwarnings()  # no noticeable effect on the code
                print("If this were real code:")
                print("Actions taken because this is a big number would happen here.")
                warn("\n%s %s" %(numberArg, self._tmpTxt), stacklevel=1, category=RuntimeWarning)
                sys.stderr.flush()
                # resetwarnings()  # no noticeable effect on the code
                
            if numberArg > 20000:
                self._tmpTxt = "That's a really really really big number for this code." + \
                               "Code may take a while to run..."
                warn("\n%s %s" %(numberArg, self._tmpTxt), stacklevel=1)
                sys.stderr.flush() # this provides warning ahead of the output instead of after it
                # resetwarnings()  # no noticeable effect on the code

                warn("\n%s %s" %(numberArg, self._tmpTxt), stacklevel=1)
                sys.stderr.flush()
                # resetwarnings()  # no noticeable effect on the code
                print("If this were real code:")
                print("Actions taken because this is an even bigger number would happen here.")

            print("loop count %d:" %(i))    
            print("If this were real code, it would be doing more stuff here ...")

mc1 = myClass(1001)
print("====================")
mc2 = myClass(20001)<jupyter_output>C:\ProgramFilesCoders\Anaconda2\envs\PY27_Test\lib\site-packages\ipykernel\__main__.py:16: RuntimeWarning: 
1001 That's a really big number for this code.Code may take a while to run...<jupyter_text>Final note:  in earlier tests, we tried storing the return value from `warn()` but the return value is just None.  Exception HandlingThis section tests out different try-except-finally blocks followed by tests of their functionality to illustrate different things.<jupyter_code># this code is designed to illustrate the try-except-finally concept and general exception handling.
# it is not written for the real world:

class InvaidNegNumberError(Exception):
    # create own error type
    # source: https://www.codementor.io/sheena/how-to-write-python-custom-exceptions-du107ufv9
    def __init__(self,*args,**kwargs):
        Exception.__init__(self,*args,**kwargs)

def ex_4(a,b):
    try:
        if a < 0 or b < 0:
            rtnVal = abs(float(a)/b)    # moved here to head off error flagged in testing section
            raise InvaidNegNumberError("You entered a Negative number. " + 
                                       "This function or code is desinged for positive inputs.")
                                        # ths isn't realy an error, just assuming this function will
                                        # always return positive values to try something
        else:
            rtnVal = float(a)/b         # note: if we return here, a return in finally would 
                                        #       superced it somehow (tested this)

    except TypeError as te:
        print("You appear to have entered the wrong type of data.  Please input 2 numbers only")
        rtnVal = None
    except ZeroDivisionError as ze:
        print(ze)
        print("Please Enter b greater than 0 only: ex_4(a,b)")
        rtnVal = None
    except InvaidNegNumberError as ine:
        print(ine)
        print("Your numbers will be treated as positive and an answer will be returned.")
        # rtnVal assignment moved to try to debug an error
    except Exception as e:
        # catch all ... errors that I can't predict yet:
        print e
        print "Please revisit your inputs and try again."
        rtnVal = None
    else:
        print("You follow instructions well.  Good job.  Here is your answer:")
    finally:
        # executes regardless of whether there is an error or not
        print("Finally!  The end of the try-except block ...")
        
    print("This line is regular code in the program that executes after the try-except test is complete.")
    return rtnVal<jupyter_output><empty_output><jupyter_text>Tests Of Different Asects of the Try-Except Block<jupyter_code>ex_4(5,6)  # no error to catch ... falls to else, then finally
ex_4(9, 'x')  # string = TypeError
ex_4(9,0)   # ZeroDivisionError
print(round(ex_4(-5, 45),2))   # code raises this exception and then catches it
print(round(ex_4(-5, -45),2))  # exception is custom class:  InvaidNegNumberError
print(round(ex_4(5, -45),2))
# ex_4(0)
# ex_4(1/5)
# what this illustrates:
#    error occurs during function call so code is unable to catch it
#    would need try/except block around ex_4() to catch this error situation
#    we could do something like this ...
#    but as this is a programmer's error, this is really just for illustration
#    this type of error should be corrected in the code, not w/ try/except

try:
    ex_4(0/4)
except TypeError as te:
    print(te)
    print("Please enter 2 arguments of form:  ex_4(a, b)")
# getting a better handle on finally ... note this StackOverflow Post:
#   http://stackoverflow.com/questions/547791/why-use-finally-in-c
# although written for C, the explanation probably cuts across all languages using try-catch-finally or try-except-finally

# here's a test to show it in action

def myTestFun(someNum):
    try:
        x = 1000 / someNum
    except Exception as e:
        print(type(e))
        print(e)
        return someNum
    finally:
        print("This message needs to always display (it is presented under 'finally')")
    
    print("This message lives in the code but not under Finally.")
    return x
myTestFun(10)
myTestFun(0)<jupyter_output><type 'exceptions.ZeroDivisionError'>
integer division or modulo by zero
This message needs to always display (it is presented under 'finally')<jupyter_text>Note: if try-except block throws an exception from within its processing, or returns from a function, then code after the try-except block never executes.  Finally always executes.<jupyter_code># This example may be useful when tinkering with files:

def openfile(filename, mode):
    try:
        f = open(filename, mode)
        # do stuff
        f.close()
        
    except ValueError:
        print 'Likely to be wrong mode in this case.'
    except TypeError:
        print 'Parameter entered is wrong type: string for int, int for string, etc.'
    except IOError:
        print 'File doesn\'t exist in this case.'
    except Exception as e:
        print 'Some other error.'
        print 'System says: ', e
    else:
        # if no exceptions ...
        print 'No error'
    finally:
        # do last no matter what happens above (with or without errors does not matter):
        print 'Do this regardless of errors being encountered or not ...'
def testOpenFileTryExceptFun(fileNameString, mode):
    print("openfile('%s', '%s')" %(fileNameString, mode))
    print('-'*50)
    openfile(fileNameString, mode)
    print('\n')

testOpenFileTryExceptFun('nonexistent.txt', 'r')
testOpenFileTryExceptFun('data\existent.txt', 'no_such_mode')
testOpenFileTryExceptFun('data\existent.txt', 123)
testOpenFileTryExceptFun('data\existent.txt', 'r')<jupyter_output>openfile('nonexistent.txt', 'r')
--------------------------------------------------
File doesn't exist in this case.
Do this regardless of errors being encountered or not ...


openfile('data\existent.txt', 'no_such_mode')
--------------------------------------------------
Likely to be wrong mode in this case.
Do this regardless of errors being encountered or not ...


openfile('data\existent.txt', '123')
--------------------------------------------------
Parameter entered is wrong type: string for int, int for string, etc.
Do this regardless of errors being encountered or not ...


openfile('data\existent.txt', 'r')
--------------------------------------------------
No error
Do this regardless of errors being encountered or not ...
{'fraction_non_alphanumeric': 0.10021244309559939, 'fraction_numerical': 0.011350531107738999, 'mean_word_length': 2.134703196347032, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 23, 'https://': 3, 'lorem ipsum': 0, 'www.': 1, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 17, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '4', 'dir': 'jupyter-structured-clean-dedup', 'id': '237543', 'license': 'MIT', 'n_tokens_mistral': 4376, 'n_tokens_neox': 4121, 'n_words': 1728, 'path': 'PY_Basics/TMWP_Warn-and-ExceptHandling_PY.ipynb', 'repo_name': 'TheMitchWorksPro/DataTech_Playground', 'size': '16475'}