Is there a way to override default assert in pytest (python)? - python

I'd like to a log some information to a file/database every time assert is invoked. Is there a way to override assert or register some sort of callback function to do this, every time assert is invoked?
Regards
Sharad

Try overload the AssertionError instead of assert. The original assertion error is available in exceptions module in python2 and builtins module in python3.
import exceptions
class AssertionError:
def __init__(self, *args, **kwargs):
print("Log me!")
raise exceptions.AssertionError

I don't think that would be possible. assert is a statement (and not a function) in Python and has a predefined behavior. It's a language element and cannot just be modified. Changing the language cannot be the solution to a problem. Problem has to be solved using what is provided by the language
There is one thing you can do though. Assert will raise AssertionError exception on failure. This can be exploited to get the job done. Place the assert statement in Try-expect block and do your callbacks inside that block. It isn't as good a solution as you are looking for. You have to do this with every assert. Modifying a statement's behavior is something one won't do.

It is possible, because pytest is actually re-writing assert expressions in some cases. I do not know how to do it or how easy it is, but here is the documentation explaining when assert re-writing occurs in pytest:
https://docs.pytest.org/en/latest/assert.html
By default, if the Python version is greater than or equal to 2.6, py.test rewrites assert statements in test modules.
...
py.test rewrites test modules on import. It does this by using an
import hook to write a new pyc files.
Theoretically, you could look at the pytest code to see how they do it, and perhaps do something similar.
For further information, Benjamin Peterson wrote up Behind the scenes of py.test’s new assertion rewriting [ at http://pybites.blogspot.com/2011/07/behind-scenes-of-pytests-new-assertion.html ]

I suggest to use pyhamcrest. It has very beatiful matchers which can be simply reimplemented. Also you can write your own.

Related

Is there a way to mark a python function as incomplete / unimplemented in VSCode / pylance?

I'm relatively new to python, using VSCode for python development. As far as I can tell VSCode is using an extension called "pylance" to handle python support features, such as detecting errors in code as you write.
In the last language I spent time with (Scala), there was a great little expression ??? that could be used to mark a method as incomplete / unimplemented, so that it would not generate any errors in the compiler or IDE, and would just throw an exception if encountered at runtime.
Is there any equivalent in python, specifically that would be understood by pylance? The idea would be that there is an unimplemented function, or one with a return type hint that isn't satisfied because it is incomplete, but this wouldn't throw up any errors that would make it harder to find the problems with the part I'm actually working on.
Obviously this isn't critical, just a matter of preferences, but it would be nice to keep the signal-to-noise ratio down! Thank you
You can use use pass inside of a function definition to avoid having to give a function a body, this will not raise exceptions on its own. Alternatively you can use raise(NotImplementedError()) to raise an error when a function is called.
def foo():
pass
def baz():
raise NotImplementedError
EDIT With Update---
Similar to pass in Python 3+ an ellipsis can be used to indicate code that has not yet been written e.g.
def foo(): ...
If you want it to throw an exception at runtime, the standard thing is to just raise NotImplementedError:
def some_fn():
raise NotImplementedError

Does Python provide support for Assumptions as pre-conditions?

Assumptions in Python unit tests
Does Python provide support for Assumptions to be used as pre-conditions for tests similar to those provided by JUnit with assumeThat(...) methods for Java.
This is important, because of the application of Hoare Logic, to quote JUnit:
A set of methods useful for stating assumptions about the conditions in which a test is meaningful. A failed assumption does not mean the code is broken, but that the test provides no useful information. Assume basically means "don't run this test if these conditions don't apply". The default JUnit runner skips tests with failing assumptions. Custom runners may behave differently.
It seems that Python doesn't provide these out of the box in its unittest framework. I've tentatively POC my own approach by extending unittest.TestCase.
class LoggingTestCase(unittest.TestCase):
def assumeTrue(self, expr: Any, msg: Any = ...) -> None:
try:
super().assertTrue(expr, msg)
self.test_result = TestResult.PASSED
except AssertionError as e:
self.test_result = TestResult.SKIPPED
raise InvalidAssumption(e)
With this unittest of behaviour:
class TestLoggingTestCase(LoggingTestCase):
def test_assumeTrue(self):
self.assertRaises(InvalidAssumption, self.assumeTrue, False) # Passes as expected.
self.assertRaises(InvalidAssumption, self.assumeTrue, True) # Fails as expected.
This approach seems to exhibit the correct behaviour I want, is this the best approach, is there better way to do this, or 3rd party library to use? I'm looking for a better way than wrapping all the base assertions this way to make my own assumptions.
I use pytest skipif for this purpose.
http://doc.pytest.org/en/latest/skipping.html

Pylint complains about method 'data_received' not overridden, for RequestHandler

For example:
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.render('data.html', items = [])
It yields the following Pylint error:
warning (W0223, abstract-method, MainHandler) Method 'data_received' is abstract in class 'RequestHandler' but is not overridden
I understand that somehow it wants me to override this data_received method, but I do not understand why, and what it is for?
This is actually a problem with Pylint that's sort of unavoidable with the nature of Python.
The RequestHandler class has a lot of methods that act as hooks you can override in order to do different things, but only some of those hooks may actually be called, depending on your application's code. To make sure you're implementing everything you're supposed to when you're using certain functionality, the default data_received implementation throws a NotImplementedError that will get triggered when you do something that expects your class to have a custom implementation.
Normally this isn't any kind of issue because Python lets you have code paths that fail and doesn't throw any errors. Because Pylint tries to "help" make sure you've done everything you're supposed to, it's seeing that NotImplementedError throw and is warning you that you could trigger it depending on what you do.
The real problem is that because Python is an interpreted language, it's hard for a tool like Pylint to look at your code and make sure it's "safe". Python gives you a lot of flexibility and power, but in turn you bear the burden of keeping your program's logic straight in your head and knowing what possible problems are actually problems, and what aren't.
Luckily, Pylint is aware of its own limitations and gives you nice tools to disable extraneous warnings. Add the comment line
# pylint: disable=W0223
right before your class definition and the warning should stop popping up for this instance while leaving everything else alone.
I am running into the same issue as the OP, except my PyCharm (2018.3.4) seems not to be using Pylint, but its own inspection engine. I managed to solve a similar issue with the similar trick as R Phillip Castagna suggested:
# noinspection PyAbstractClass
class XyzRequestHandler(tornado.web.RequestHandler):
def prepare(self):
print('-' * 100)
self.set_header('Access-Control-Allow-Origin', '*')
def print_n_respond(self, result):
response = json.dumps(result)
print('responding with:\n', response)
print()
self.write(response)
Here is a list of PyCharm's inspections.

python 2.6. unittest framework, asserts: help required

I am writing a test suite in python 2.6 using the unittest framework, and I want to use asserts in my code. I know that asserts got a complete overhaul and are much nicer in 2.7+ but I am confined to using 2.6 for now.
I am having problems using asserts. I want to be able to use the assertIn(a,b) feature, but alas, that is only in 2.7+. So I realized I must use the assertTrue(x) which is also in 2.6, but that didn't work. Then, I looked at this document which says that in previous versions assertTrue(x) used to be failUnless(x), so I used that in my code, and still no results.
I get the message:
NameError: global name 'failUnless' is not defined
which is the same thing I got for assertIn(a,b) and for assertTrue(x).
So I am totally at a loss for what I should do.
shorter version of my problem:
I want to be able to implement assertIn(a,b) in python 2.6.
Anyone have any solutions to this?
my code:
import unittest
class test_base(unittest.TestCase):
# some functions that are used by many tests
class test_01(test_base):
def setUp(self):
#set up code
def tearDown(self):
#tear down code
def test_01001_something(self):
#gets a return value of a function
ret = do_something()
#here i want to check if foo is in ret
failUnless("foo" in ret)
edit: Seems I am an idiot. All I needed to do was add self.assert.... and it worked.
import unittest
class MyTest(unittest.TestCase):
def test_example(self):
self.assertTrue(x)
This should work, based on the docs for unittest from Python 2.6. Be sure to use it as TestCase.assertTrue().
edit: In your example, set it as self.failUnless("foo" in ret) and it should work.
assertTrue should work just fine for an in test:
self.assertTrue('a' in somesequence)
All assertIn does is run the same test as above and set a helpful message if the test fails.
Your code for test case really helped.
Your problem is that you're trying to use assert[Something] as functions, while they're methods of TestCase class.
So you can solve your problem with, e.g. assertTrue:
self.assertTrue(element in list_object)
Actually implementing assertIn is pretty trivial. This is what I've used in my unit tests:
class MyTestCase(unittest.TestCase)
def assertIn(self, item, iterable):
self.assertTrue(item in iterable,
msg="{item} not found in {iterable}"
.format(item=item,
iterable=iterable))
You can then base all your testcases on this class instead unittest.TestCase and safely use assertIn even on python 2.6 and the error message will be much better than pure assertTrue. For comparison actual implementation of assertIn from Python 2.7:
def assertIn(self, member, container, msg=None):
"""Just like self.assertTrue(a in b), but with a nicer default message."""
if member not in container:
standardMsg = '%s not found in %s' % (safe_repr(member),
safe_repr(container))
self.fail(self._formatMessage(msg, standardMsg))

How do I raise a custom exception from a package __init__?

I have a package __init__.py that looks something like this:
import sys
__required_python_version = (2,6, 0)
if sys.version_info < __required_python_version:
this_version = '.'.join([str(x) for x in sys.version_info[0:3]])
required_version = '.'.join([str(x) for x in __required_python_version])
raise PythonVersionError(this_version, required_version)
class PythonVersionError(Exception):
def __init__(self, this_version, required_version):
self.this_version = this_version
self.required_version = required_version
def __str__(self):
return 'Python version %s is invalid. Must be at least %s' % (self.this_ver, self.required_ver)
While I'm certain there is a more elegant way to format those version strings and I could probably get by using a standard exception, my real question is how would I do something like this? Would the best approach be to move my custom exception into a separate file and import it? Or should I wrap the version check in a function that executes when the __init__ is run? I'm just looking for recommendations on the preferred approach.
Thanks
Since it looks like you won't have any user for that exception --
unless this module is to be used by other modules you are impleemnting as part of a larger system, I say you don't need a custom exception here.
There is very little to gain from it, apart from the error message given. Ay module trying to import yours would have to be aware of it, to catch the exception, or just let the program stop witha backtrace. Since be aware of it , it would need to import your module, it would just crash to a backtrace anyway -- wher ethe user can then read the error message.
For one to read the error message,a plain "Exception" stating it is the incorrect PythonVersin is as good as any custom exception.
On the technical side, Python would need to know about PythonVersionError before raising it: you need to put that code before you try to raise it inside the if block.
And finally, if you are building a larger system, and other parts of the system might try to catch PythonVersionError, the coorect thing to do is to put it in its own file/module, so that it becomes available to this module that will raise it, and any other modules that are importing this.
There seems to be something awkward here.
Is it really usefull to create a custom Exception class when it won't be reused anywhere else in other modules ? If everyone did this we would end up with every module defining it's own different (and probably incompatible) PythonVersionError class.
Why don't you use a standard existing exception ? For this one I would probably go for a standard RuntimeError exception.
OK, I know you don't want this answer, but anyway.
If I really wanted to do this at least I would define PythonVersionException class as a local instance of checking code to avoid polluting module namespace or any global namespace of other files of the module.

Categories