* you can define tests as free functions (you don't have to, it also supports classes and even regular unittest cases, you can use pytest to run your existing suite)
* exceptions aside it uses the standard `assert` statement
* fixtures are DI'd, independent from tests and much more flexible than the setUp/tearDown dance
* tests are configured and fixtures are defined using decorators & generators
* excellent support for data-driven tests (parametrized tests and fixtures)
* there is a wealth of reusable third-party plugins[0] ranging from framework helpers[1] to test parallelisation and distribution[2]
[0] http://plugincompat.herokuapp.com
If this were the only difference, it'd still be enough. Inevitably I end up with a unittest.TestCase with 30 tests, all of which mock out some resource. Except for 1. That one wants to mock out a different resource while leaving the first intact.
* With unittest: either split that test out into its own TestCase (duplicating most of the original, except for the part I don't want, or coming up with an inheritance tree with is always ugly with unittest), or
* Remove all the unwanted mocks inside that test.
* With pytest: don't pass the mocking fixture into that test.
Combined with flexible scopes and the ability to mark and select/deselect tests based on name and marks it makes for genuinely great stuff e.g. some of your tests depend on the database, you can have a session-scoped fixture handling a connection, then a function-scoped one depending on it and getting a cursor, and if you don't select any test depending on the latter no connection will be created at any point.
Pytest fixtures are also quite a bit more flexible than unittest's setUp and tearDown methods, although they take a little while to really understand (at least they did for me) since they use some magic.
You can define the lifetime of each parameter (just the test, the class or the whole testing session). This makes it very flexible.
The use of "assert" is magic in the sense that in case of failure, you get helpful values. "assert a == b" will show you the values of "a" and "b" in case of failure.