4

It appears that one cannot resume the execution of test once you hit the raise the user defined exception in Python. But in my scenario I want to check error occurred for different input values. But Current implementation is restricting to continue the check error for the different input vectors.

However, before coming up with some sort of convoluted solution to my problem, I figured I would ask the experts and see if there is something I'm missing. Unfortunately, I cannot change this paradigm easily without significant re-factoring.

My application looks similar to this:

  • Input will be given as numGen function. This numGen function add the input to the random number. In my example I am checking for 10 different random number.
  • Note Input is also will be varying as well as the range of random number generation

Problem statement:

  • I want to check for each input whether error is occurred and if any error occurred raise exception and store the information of which input

  • Continue the program execution for other input as well, But In my implementation it I'm not able to continue further execution.

Questions:

  • How to raise the exceptions later, without using unittest module?

from random import randint

class RND_ERROR(Exception):
    def __init__(self, ErrNum, *arg, **kwargs):
        self.RND_ERR_NR = int(ErrNum)
        self.RND_ERR_MSG = ""         
        if self.RND_ERR_NR == 0x00000000:
            self.RND_ERR_MSG = "NO ERROR"
        elif self.RND_ERR_NR == 0x00000001:
            self.RND_ERR_MSG = "RANDOM NUMBER IS ONE"
        elif self.RND_ERR_NR == 0x00000002:
            self.RND_ERR_MSG = "RANDOM NUMBER IS TWO"
        elif self.RND_ERR_NR == 0x00000003:
            self.RND_ERR_MSG = "RANDOM NUMBER IS THREE"
        else:
            self.RND_ERR_MSG = "RANDOM NUMBER GREATER THAN THREE"
    def __str__(self):
        return "RND ERROR (0x%08X): %s" % (self.RND_ERR_NR,self.RND_ERR_MSG)

    def __repr__(self):
       return self.__str__()

def check_error(b):
    print "dict",b
    count = 0

    for i, error_nr in b.items():

        error_nr = error_nr % 2
        print "key:val",i, error_nr
        if error_nr ==0:
            count = count +1
            # print count
        elif error_nr > 0:

            # print error_nr
            raise RND_ERROR(error_nr)

def numGen(input):
    from random import randint
    result= {}
    for i in range(9):
        j = (randint(0,4))
        result[i] = input+j
        result.update()
    check_error(result)

if __name__ == '__main__':
    try:
        numGen(3)
    except BaseException as e:
        print e

Output1: # Since at the 6th input error occurred and execution stopped **(Some what Best case)**  
dict {0: 6, 1: 6, 2: 6, 3: 6, 4: 4, 5: 6, 6: 3, 7: 3, 8: 7}
key:val 0 0
key:val 1 0
key:val 2 0
key:val 3 0
key:val 4 0
key:val 5 0
key:val 6 1
RND ERROR (0x00000001): RANDOM NUMBER IS ONE

**Output2:**
dict {0: 7, 1: 6, 2: 4, 3: 3, 4: 6, 5: 6, 6: 7, 7: 5, 8: 4}
key:val 0 1

RND ERROR (0x00000001): RANDOM NUMBER IS ONE

Expected Output:

Input1 - Pass
Input2 - Pass
Input3 - Pass
Input4 - Pass
Input5 - Pass
Input6 - RANDOM IS TWO (exception occurred)
Input7 - Pass  # execution continued for next input check
Input8 - Pass
Input9 - RANDOM IS ONE (exception occurred)
Input10 - Pass  # execution continued for next input check

I found link, which looks similar to my requirement. Difference is instead of checking error in file reading and stack up the error if found. In my case it is checking for inputs.

Similar requirement

Thanks in advance!!

Community
  • 1
  • 1

2 Answers2

2

What you've defined is a logical contradiction: you want to raise an exception and continue normal execution. The common meaning of raise exception in a 4th-generation language means that you do not want to continue normal execution. Make up your mind.

You are welcome to print a message, not raise an exception, and continue normal operation. If you want to raise the exception later, you are welcome to do that.

If you want to check for an error on each input, then you cannot make the error check itself an exception condition. I'm guessing a little here: you want to report every discrepancy, but then not raise an exception until you've gone through all the input cases. Try this: it splits the error handling into a non-exception routine. I've left a lot of your exception-handling stuff intact, in case you want to fill it in with other code.

class RND_ERROR(Exception):
    def __init__(self, ErrNum, *arg, **kwargs):
        self.RND_ERR_NR = int(ErrNum)
        self.RND_ERR_MSG = ""

    def __str__(self):
        return "RND ERROR (0x%08X): %s" % (self.RND_ERR_NR,self.RND_ERR_MSG)

    def __repr__(self):
        return self.__str__()


def handle_error(ErrNum):
    RND_ERR_NR = int(ErrNum)
    RND_ERR_MSG = ""
    if RND_ERR_NR == 0x00000000:
        RND_ERR_MSG = "NO ERROR"
    elif RND_ERR_NR == 0x00000001:
        RND_ERR_MSG = "RANDOM NUMBER IS ONE"
    elif RND_ERR_NR == 0x00000002:
        RND_ERR_MSG = "RANDOM NUMBER IS TWO"
    elif RND_ERR_NR == 0x00000003:
        RND_ERR_MSG = "RANDOM NUMBER IS THREE"
    else:
        RND_ERR_MSG = "RANDOM NUMBER GREATER THAN THREE"

    print "RND ERROR (0x%08X): %s" % (RND_ERR_NR, RND_ERR_MSG)

def check_error(b):
    print "dict",b
    count = 0
    need_exception = False

    for i, error_nr in b.items():

        error_nr = error_nr % 2
        print "key:val",i, error_nr
        if error_nr ==0:
            count = count +1
            # print count
        elif error_nr > 0:
            # print error_nr
            handle_error(error_nr)
            need_exception = True

    if need_exception:
        raise RND_ERROR(49374)


def numGen(input):
    from random import randint
    result= {}
    for i in range(9):
        j = (randint(0, 4))
        result[i] = input+j
        result.update()
        # print "iteration", i, j
    check_error(result)

try:
    numGen(3)
except BaseException as e:
    print e
finally:
    print "Finished"

output:

dict {0: 6, 1: 4, 2: 6, 3: 5, 4: 4, 5: 4, 6: 5, 7: 6, 8: 3}
key:val 0 0
key:val 1 0
key:val 2 0
key:val 3 1
RND ERROR (0x00000001): RANDOM NUMBER IS ONE
key:val 4 0
key:val 5 0
key:val 6 1
RND ERROR (0x00000001): RANDOM NUMBER IS ONE
key:val 7 0
key:val 8 1
RND ERROR (0x00000001): RANDOM NUMBER IS ONE
RND ERROR (0x0000C0DE): 
Finished
Prune
  • 76,765
  • 14
  • 60
  • 81
  • Tons of Thanks Prune. Looks promising!!! "You are welcome to print a message, not raise an exception, and continue normal operation. **If you want to raise the exception later, you are welcome to do that**", How do I raise an exception in Later stage. This what exactly wanted. Request you to edit the answer for raise an exception later stage. –  Jan 30 '16 at 02:26
  • I've done exactly that: set a flag within the loop, testing it after we're all done checking input. – Prune Jan 31 '16 at 02:43
  • Yes. But you have done raise RND_ERROR(49374)? not Like raise RND_ERROR(error_nr) right? –  Jan 31 '16 at 03:16
  • The value 49374 is for illustration only. Note that it shows up as the word "code" in hexadecimal. I didn't use **error_nr**, because you can have a variety of error numbers; if you want a single exception to stand for all errors, you need to alter your reporting to match what you actually want. You haven't detailed that yet. – Prune Feb 01 '16 at 18:08
  • **If you want a single exception to stand for all errors, you need to alter your reporting to match what you actually want.** could you please explain? –  Feb 02 '16 at 03:55
  • In your original code, you try to raise an exception for each **error_nr** value. This is not viable: you can raise only one fatal exception. The semantics of your reporting have to change, since you have only this one chance. You can put them in a list, report them as simple messages as you encounter them, etc., but you cannot continue to propagate upward a personalized exception for each input error. – Prune Feb 02 '16 at 18:08
  • could please the code snippet accordingly. I m confused with **This is not viable: you can raise only one fatal exception.** and **You can put them in a list, report them as simple messages as you encounter them, etc** statement. How both is possible? –  Feb 03 '16 at 03:40
  • Your first sentence has no verb; I'm not sure what you're asking about the code snippet. If you're asking how to write the code (1) you're supposed to try that yourself before asking here; (2) knite gave you such code. – Prune Feb 03 '16 at 20:28
  • I'm not sure where you're confused. I didn't say that *both* of something is possible. I suggested an alternative to the original contradiction in your design. You have basically two choices when you hit an error condition: (1) propagate an exception and exit the routine; (2) handle the condition and continue. Handling can include reporting. You can handle an exception (which may include keeping evidence of its existence), discard the control-flow condition (don't reraise it), and continue. – Prune Feb 03 '16 at 20:32
1

You can catch the errors as they occur and process them later:

def numGen(input):
    from random import randint
    result= {}
    errors = []
    for i in range(9):
        j = (randint(0,4))
        result[i] = input+j
        result.update()    # This line does nothing...
        try:
            check_error(result)
        except RND_ERROR as e:
            errors.append((i, e))

    for i, error in errors:
        print(i, error)
knite
  • 6,033
  • 6
  • 38
  • 54