1

Is there any way in Python2.7, we can capture and log the assert statements in general python scripting despite of assert is True or False Suppose I assert following line in code:

assert len(lst) ==4

So is any way can log what statement is passed, at what line and it is true or false. I do not want to use a wrapper function, looking for something inbuilt in python .

Note: What I want to achieve is , suppose I have legacy code having 1000's of assert statements , without changing the code, I should be able to log which assert statement is executed and what is the output, Is its achievable in python 2.7.

5
  • Sorry -- what do you mean "any way can log what statement is passed"? It seems like you want to log something rather than assert it. Commented Nov 4, 2016 at 0:00
  • Do you want to log at exception? Commented Nov 4, 2016 at 0:02
  • No I want to know if it's possible, somehow interpreter see if its an assert statement during execution, it should tell what line its executed and is it True or False.And also what was the assert statement. Commented Nov 4, 2016 at 0:05
  • you can catch assert exception just like other exceptions with except keyword. except AssertionError Commented Nov 4, 2016 at 0:09
  • @sudhanshu -- It seems like you're asking for an assert to behave like something that isn't an assert. It's like asking if there's a way to make a dict behave like a list... the only way that I can think that you might be able to accomplish this is by registering an import hook which changes all of the assert statements into appropriate logging statements... Commented Nov 4, 2016 at 0:15

4 Answers 4

4
try:
    assert len(lst) == 4    
    print "True"
except AssertionError as e:
    print "False"
Sign up to request clarification or add additional context in comments.

8 Comments

While this seems correct to accomplish the requested goal, I do wonder how it's different from an if statement (why use the assert to begin with?)
it's not different from if, but OP has asserts, so i just showed simple example from the top of my head
I clearly mentioned Sir, No wrapper. Is any default feature in python 2.7 and as well how the condition can be logged. in generic way in this case "assert len(lst) == 4"
It's not a wrapper, it's built in functionality in python to catch exceptions
FWIW, you can optimize away assert statements in which case you might print True no matter what. Plus, this doesn't show the line number, etc...
|
3

Yes, you can define a custom excepthook to log some extra information:

import sys
import logging
def excepthook(*args):
  logging.getLogger().error('Uncaught exception:', exc_info=args)

sys.excepthook = excepthook

assert 1==2

EDIT: Whoops I forgot you wanted to log even if it's true :) oh well I'll leave this for a little bit in case it informs you or someone else...

5 Comments

Thanks this is helpful , but yes I am also looking for some how if true can be captured as well can log the statement and the line.
I think a wrapper function is your best bet, but you said you didn't want that. I'll update the answer anyway to include an example, in case you change your mind :)
Ok Even if I use the wrapper function have you realised, the statement in your code will give True or False, not statement .Right?
@sudhanshu good catch, I didn't run that. You could make something more complicated that would actually work, but after reading your note (you don't want to change the assert statement at all, because it's a lot of legacy code), I don't have a good solution.
Thanks @rofls , I created the wrapper function now, this is what best I found could do.check my answer I posted.
1

This is what I could achieve closet, as does not seem it is possible in Python2.7 . I created a wrapper function.

import inspect

def assertit(condition,message):
    # The caller method
    (frame, filename, line_number,function_name, lines, index) = inspect.getouterframes(inspect.currentframe())[1]


    detailed_message=" => {message} [  {filename} : {line_number}]".format(message=message,line_number=line_number,
                                                                         filename=filename)

    if condition:
        print "True  %s"%detailed_message
        return
    raise AssertionError("False: %s"%detailed_message)
assertit(1==1,"Check if 1 equal 1")
assertit(1==2,"Check if 1 equal 2")

### HERE IS THE OUTPUT
True   => Check if 1 equal 1 [  test_cases.py : 20]
Traceback (most recent call last):
  File "test_cases.py", line 21, in <module>
    assertit(1==2,"Check if 1 equal 2")
  File "test_cases.py", line 19, in assertit
    raise AssertionError("False: %s"%detailed_message)
AssertionError: False:  => Check if 1 equal 2 [  test_cases.py : 21]

Comments

0

This is a proof of concept. So please downvote, or I will delete it... The idea is to replace the assert statement with print statement at the execution.

import ast
import inspect

from your_module import main

def my_assert(test_result, msg):
    assert test_result, msg
    # if test_result is True, just print the msg
    return "assert: {}, {}".format(test_result, msg)

class Transformer(ast.NodeTransformer):
    def visit_Assert(self, node):
        f = ast.Name(id='my_assert', ctx=ast.Load())
        c = ast.Call(func=f, args=[node.test, node.msg], keywords=[])
        p = ast.Print(values=[c], nl=True)

        # set line#, column offset same as the original assert statement
        f.lineno = c.lineno = p.lineno = node.lineno
        f.col_offset =c.col_offset = p.col_offset = node.col_offset

        return p


def replace_assert_with_print(func):
    source = inspect.getsource(func)
    ast_tree = ast.parse(source)
    Transformer().visit(ast_tree)
    return compile(ast_tree, filename="<ast>", mode="exec")

if __name__ == '__main__':
    exec(replace_assert_with_print(main))
    main(4)

And here is your_module.py

def main(x):
    assert x == 4, "hey {} is not 4".format(x)
    return x

4 Comments

Thanks have a look at my solution seems we are doing same, I am also passing a message and from inspect getting callee method's module and line number.
oh....i guess i can just wrap the assert statement with try-except rather than replacing with print statement
@sundhanshu I was trying to satisfy the requirement: without changing the code :-)
Yes I understand but I think the exec statement is causing some issue on mac, getting error popup 'Python quit unexpectidely'. Thanks

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.