New upstream release.

This commit is contained in:
Vincent Bernat 2017-09-18 19:14:14 +02:00
parent cc3055ebc3
commit 506682a7c5
14 changed files with 495 additions and 146 deletions

View file

@ -1,14 +1,22 @@
language: python
python:
- "2.6"
- "2.7"
- "3.3"
- "3.4"
- "3.5"
- "3.6-dev"
- "3.6"
matrix:
include:
- python: '3.6'
env: TOXENV=linting
install:
- pip install tox coveralls
- pip install tox-travis coveralls
script:
- if [[ $TRAVIS_PYTHON_VERSION != 3.6-dev ]]; then tox; fi
- if [[ $TRAVIS_PYTHON_VERSION == 3.6-dev ]]; then tox -e py36-pytest28,py36-pytest29,py36-pytest30; fi
- tox
after_success:
- coveralls
@ -16,10 +24,11 @@ after_success:
deploy:
provider: pypi
user: nicoddemus
skip_upload_docs: true
distributions: sdist bdist_wheel
password:
secure: bB4adUZVIkt31cmNklskyIDNehujKToGnStnlunp7P8CBF6CGeNqkYU17emAPvfZbTb/ClUpiO9r6AD1ej32Uyr+I8qUyhuYtHG3JGp+WRR/tw+ytAZIJ9i+PMjBv1RAdyLENJ/Tx0LKHKsABr8dQIieLFqKZJuT77f/5ZkvI/U=
secure: OEWrbk09CZRrwFE6sBpRqQHu45zRu1S0Ly1ZeprkFCKxMd9tZOnrYM5qxCDQXxFHIvuyajuJ+qWTOgxUvurQMNsD6DbvJKTJ0R8upH1b1Q95KK8xiJFedhqBEUga5GrInK59oo0Sgblse2jtH5NnHXRUClSdT+iHdLY5sljCTRg=
on:
tags: true
distributions: sdist bdist_wheel
repo: pytest-dev/pytest-mock
condition: $TRAVIS_PYTHON_VERSION = 3.5
condition: $TRAVIS_PYTHON_VERSION = 3.6

View file

@ -1,5 +1,74 @@
1.3
---
1.6.3
-----
* Fix ``UnicodeDecodeError`` during assert introspection in ``assert_called_with`` in Python 2.
Thanks `@AndreasHogstrom`_ for the report (`#91`_).
.. _@AndreasHogstrom: https://github.com/AndreasHogstrom
.. _#91: https://github.com/pytest-dev/pytest-mock/issues/91
1.6.2
-----
* Provide source package in ``tar.gz`` format and remove obsolete ``MANIFEST.in``.
1.6.1
-----
* Fix ``mocker.resetall()`` by ignoring mocker objects which don't have a
``resetall`` method, like for example ``patch.dict``.
Thanks `@jdavisp3`_ for the PR (`#88`_).
.. _@jdavisp3: https://github.com/jdavisp3
.. _#88: https://github.com/pytest-dev/pytest-mock/pull/88
1.6.0
-----
* The original assertions raised by the various ``Mock.assert_*`` methods
now appear in the failure message, in addition to the message obtained from
pytest introspection.
Thanks `@quodlibetor`_ for the initial patch (`#79`_).
.. _@quodlibetor: https://github.com/quodlibetor
.. _#79: https://github.com/pytest-dev/pytest-mock/pull/79
1.5.0
-----
* New ``mocker.mock_module`` variable points to the underlying mock module being used
(``unittest.mock`` or ``mock``).
Thanks `@blueyed`_ for the request (`#71`_).
.. _#71: https://github.com/pytest-dev/pytest-mock/pull/71
1.4.0
-----
* New configuration variable, ``mock_use_standalone_module`` (defaults to ``False``). This forces
the plugin to import ``mock`` instead of ``unittest.mock`` on Python 3. This is useful to import
a newer version than the one available in the Python distribution.
* Previously the plugin would first try to import ``mock`` and fallback to ``unittest.mock``
in case of an ``ImportError``, but this behavior has been removed because it could hide
hard to debug import errors (`#68`_).
* Now ``mock`` (Python 2) and ``unittest.mock`` (Python 3) are lazy-loaded to make it possible to
implement the new ``mock_use_standlone_module`` configuration option. As a consequence of this
the undocumented ``pytest_mock.mock_module`` variable, which pointed to the actual mock module
being used by the plugin, has been removed.
* `DEFAULT <https://docs.python.org/3/library/unittest.mock.html#default>`_ is now available from
the ``mocker`` fixture.
.. _#68: https://github.com/pytest-dev/pytest-mock/issues/68
1.3.0
-----
* Add support for Python 3.6. Thanks `@hackebrot`_ for the report (`#59`_).

View file

@ -1,2 +0,0 @@
include README.md
include LICENSE

View file

@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: pytest-mock
Version: 1.3.0
Version: 1.6.3
Summary: Thin-wrapper around the mock package for easier use with py.test
Home-page: https://github.com/pytest-dev/pytest-mock/
Author: Bruno Oliveira
@ -17,7 +17,14 @@ Description: ===========
.. code-block:: python
import os
class UnixFS:
@staticmethod
def rm(filename):
os.remove(filename)
def test_unix_fs(mocker):
mocker.patch('os.remove')
UnixFS.rm('file')
@ -26,21 +33,21 @@ Description: ===========
.. Using PNG badges because PyPI doesn't support SVG
|python| |version| |downloads| |ci| |appveyor| |coverage|
|python| |version| |anaconda| |ci| |appveyor| |coverage|
.. |version| image:: http://img.shields.io/pypi/v/pytest-mock.png
.. |version| image:: http://img.shields.io/pypi/v/pytest-mock.svg
:target: https://pypi.python.org/pypi/pytest-mock
.. |downloads| image:: http://img.shields.io/pypi/dm/pytest-mock.png
:target: https://pypi.python.org/pypi/pytest-mock
.. |anaconda| image:: https://anaconda.org/conda-forge/pytest-mock/badges/version.svg
:target: https://anaconda.org/conda-forge/pytest-mock
.. |ci| image:: http://img.shields.io/travis/pytest-dev/pytest-mock.png
.. |ci| image:: http://img.shields.io/travis/pytest-dev/pytest-mock.svg
:target: https://travis-ci.org/pytest-dev/pytest-mock
.. |appveyor| image:: https://ci.appveyor.com/api/projects/status/pid1t7iuwhkm9eh6/branch/master?svg=true
:target: https://ci.appveyor.com/project/pytestbot/pytest-mock
.. |coverage| image:: http://img.shields.io/coveralls/pytest-dev/pytest-mock.png
.. |coverage| image:: http://img.shields.io/coveralls/pytest-dev/pytest-mock.svg
:target: https://coveralls.io/r/pytest-dev/pytest-mock
.. |python| image:: https://img.shields.io/pypi/pyversions/pytest-mock.svg
@ -76,6 +83,7 @@ Description: ===========
* `MagicMock <https://docs.python.org/3/library/unittest.mock.html#unittest.mock.MagicMock>`_
* `PropertyMock <https://docs.python.org/3/library/unittest.mock.html#unittest.mock.PropertyMock>`_
* `ANY <https://docs.python.org/3/library/unittest.mock.html#any>`_
* `DEFAULT <https://docs.python.org/3/library/unittest.mock.html#default>`_ *(Version 1.4)*
* `call <https://docs.python.org/3/library/unittest.mock.html#call>`_ *(Version 1.1)*
* `sentinel <https://docs.python.org/3/library/unittest.mock.html#sentinel>`_ *(Version 1.2)*
* `mock_open <https://docs.python.org/3/library/unittest.mock.html#mock-open>`_
@ -133,14 +141,30 @@ Description: ===========
diff::
m = mocker.patch.object(DS, 'create_char')
DS().create_char('Raistlin', class_='mag', gift=12)
> m.assert_called_once_with('Raistlin', class_='mage', gift=12)
E assert {'class_': 'mag', 'gift': 12} == {'class_': 'mage', 'gift': 12}
E Omitting 1 identical items, use -v to show
E Differing items:
E {'class_': 'mag'} != {'class_': 'mage'}
mocker = <pytest_mock.MockFixture object at 0x0381E2D0>
def test(mocker):
m = mocker.Mock()
m('fo')
> m.assert_called_once_with('', bar=4)
E AssertionError: Expected call: mock('', bar=4)
E Actual call: mock('fo')
E
E pytest introspection follows:
E
E Args:
E assert ('fo',) == ('',)
E At index 0 diff: 'fo' != ''
E Use -v to get the full diff
E Kwargs:
E assert {} == {'bar': 4}
E Right contains more items:
E {'bar': 4}
E Use -v to get the full diff
test_foo.py:6: AssertionError
========================== 1 failed in 0.03 seconds ===========================
This is useful when asserting mock calls with many/nested arguments and trying
@ -158,7 +182,25 @@ Description: ===========
mechanism used to suppress traceback entries from ``mock`` module does not work with that option
anyway plus it generates confusing messages on Python 3.5 due to exception chaining
.. _advanced assertions: https://pytest.org/latest/assert.html
.. _advanced assertions: http://pytest.org/latest/assert.html
Use standalone "mock" package
-----------------------------
*New in version 1.4.0.*
Python 3 users might want to use a newest version of the ``mock`` package as published on PyPI
than the one that comes with the Python distribution.
.. code-block:: ini
[pytest]
mock_use_standalone_module = true
This will force the plugin to import ``mock`` instead of the ``unittest.mock`` module bundled with
Python 3.3+. Note that this option is only used in Python 3+, as Python 2 users only have the option
to use the ``mock`` package from PyPI anyway.
Requirements
@ -240,9 +282,13 @@ Description: ===========
- you can't easily undo the mocking during the test execution;
**Note**
**Note about usage as context manager**
Although mocker's API is intentionally the same as ``mock.patch``'s, its uses as context managers and function decorators are **not** supported. The purpose of this plugin is to make the use of context managers and function decorators for mocking unnecessary. Indeed, trying to use the functionality in ``mocker`` in this manner can lead to non-intuitive errors:
Although mocker's API is intentionally the same as ``mock.patch``'s, its use
as context manager and function decorator is **not** supported through the
fixture. The purpose of this plugin is to make the use of context managers and
function decorators for mocking unnecessary. Indeed, trying to use the
functionality in ``mocker`` in this manner can lead to non-intuitive errors:
.. code-block:: python
@ -259,6 +305,23 @@ Description: ===========
with mocker.patch.object(a, 'doIt', return_value=True, autospec=True):
E AttributeError: __exit__
You can however use ``mocker.mock_module`` to access the underlying ``mock``
module, e.g. to return a context manager in a fixture that mocks something
temporarily:
.. code-block:: python
@pytest.fixture
def fixture_cm(mocker):
@contextlib.contextmanager
def my_cm():
def mocked():
pass
with mocker.mock_module.patch.object(SomeClass, 'method', mocked):
yield
return my_cm
License
=======

View file

@ -9,7 +9,14 @@ of a test:
.. code-block:: python
import os
class UnixFS:
@staticmethod
def rm(filename):
os.remove(filename)
def test_unix_fs(mocker):
mocker.patch('os.remove')
UnixFS.rm('file')
@ -18,21 +25,21 @@ of a test:
.. Using PNG badges because PyPI doesn't support SVG
|python| |version| |downloads| |ci| |appveyor| |coverage|
|python| |version| |anaconda| |ci| |appveyor| |coverage|
.. |version| image:: http://img.shields.io/pypi/v/pytest-mock.png
.. |version| image:: http://img.shields.io/pypi/v/pytest-mock.svg
:target: https://pypi.python.org/pypi/pytest-mock
.. |downloads| image:: http://img.shields.io/pypi/dm/pytest-mock.png
:target: https://pypi.python.org/pypi/pytest-mock
.. |anaconda| image:: https://anaconda.org/conda-forge/pytest-mock/badges/version.svg
:target: https://anaconda.org/conda-forge/pytest-mock
.. |ci| image:: http://img.shields.io/travis/pytest-dev/pytest-mock.png
.. |ci| image:: http://img.shields.io/travis/pytest-dev/pytest-mock.svg
:target: https://travis-ci.org/pytest-dev/pytest-mock
.. |appveyor| image:: https://ci.appveyor.com/api/projects/status/pid1t7iuwhkm9eh6/branch/master?svg=true
:target: https://ci.appveyor.com/project/pytestbot/pytest-mock
.. |coverage| image:: http://img.shields.io/coveralls/pytest-dev/pytest-mock.png
.. |coverage| image:: http://img.shields.io/coveralls/pytest-dev/pytest-mock.svg
:target: https://coveralls.io/r/pytest-dev/pytest-mock
.. |python| image:: https://img.shields.io/pypi/pyversions/pytest-mock.svg
@ -68,6 +75,7 @@ Some objects from the ``mock`` module are accessible directly from ``mocker`` fo
* `MagicMock <https://docs.python.org/3/library/unittest.mock.html#unittest.mock.MagicMock>`_
* `PropertyMock <https://docs.python.org/3/library/unittest.mock.html#unittest.mock.PropertyMock>`_
* `ANY <https://docs.python.org/3/library/unittest.mock.html#any>`_
* `DEFAULT <https://docs.python.org/3/library/unittest.mock.html#default>`_ *(Version 1.4)*
* `call <https://docs.python.org/3/library/unittest.mock.html#call>`_ *(Version 1.1)*
* `sentinel <https://docs.python.org/3/library/unittest.mock.html#sentinel>`_ *(Version 1.2)*
* `mock_open <https://docs.python.org/3/library/unittest.mock.html#mock-open>`_
@ -125,14 +133,30 @@ the method, and uses py.test's own `advanced assertions`_ to return a better
diff::
m = mocker.patch.object(DS, 'create_char')
DS().create_char('Raistlin', class_='mag', gift=12)
> m.assert_called_once_with('Raistlin', class_='mage', gift=12)
E assert {'class_': 'mag', 'gift': 12} == {'class_': 'mage', 'gift': 12}
E Omitting 1 identical items, use -v to show
E Differing items:
E {'class_': 'mag'} != {'class_': 'mage'}
mocker = <pytest_mock.MockFixture object at 0x0381E2D0>
def test(mocker):
m = mocker.Mock()
m('fo')
> m.assert_called_once_with('', bar=4)
E AssertionError: Expected call: mock('', bar=4)
E Actual call: mock('fo')
E
E pytest introspection follows:
E
E Args:
E assert ('fo',) == ('',)
E At index 0 diff: 'fo' != ''
E Use -v to get the full diff
E Kwargs:
E assert {} == {'bar': 4}
E Right contains more items:
E {'bar': 4}
E Use -v to get the full diff
test_foo.py:6: AssertionError
========================== 1 failed in 0.03 seconds ===========================
This is useful when asserting mock calls with many/nested arguments and trying
@ -150,7 +174,25 @@ Note that this feature is automatically disabled with the ``--tb=native`` option
mechanism used to suppress traceback entries from ``mock`` module does not work with that option
anyway plus it generates confusing messages on Python 3.5 due to exception chaining
.. _advanced assertions: https://pytest.org/latest/assert.html
.. _advanced assertions: http://pytest.org/latest/assert.html
Use standalone "mock" package
-----------------------------
*New in version 1.4.0.*
Python 3 users might want to use a newest version of the ``mock`` package as published on PyPI
than the one that comes with the Python distribution.
.. code-block:: ini
[pytest]
mock_use_standalone_module = true
This will force the plugin to import ``mock`` instead of the ``unittest.mock`` module bundled with
Python 3.3+. Note that this option is only used in Python 3+, as Python 2 users only have the option
to use the ``mock`` package from PyPI anyway.
Requirements
@ -232,9 +274,13 @@ But this poses a few disadvantages:
- you can't easily undo the mocking during the test execution;
**Note**
**Note about usage as context manager**
Although mocker's API is intentionally the same as ``mock.patch``'s, its uses as context managers and function decorators are **not** supported. The purpose of this plugin is to make the use of context managers and function decorators for mocking unnecessary. Indeed, trying to use the functionality in ``mocker`` in this manner can lead to non-intuitive errors:
Although mocker's API is intentionally the same as ``mock.patch``'s, its use
as context manager and function decorator is **not** supported through the
fixture. The purpose of this plugin is to make the use of context managers and
function decorators for mocking unnecessary. Indeed, trying to use the
functionality in ``mocker`` in this manner can lead to non-intuitive errors:
.. code-block:: python
@ -251,6 +297,23 @@ Although mocker's API is intentionally the same as ``mock.patch``'s, its uses as
with mocker.patch.object(a, 'doIt', return_value=True, autospec=True):
E AttributeError: __exit__
You can however use ``mocker.mock_module`` to access the underlying ``mock``
module, e.g. to return a context manager in a fixture that mocks something
temporarily:
.. code-block:: python
@pytest.fixture
def fixture_cm(mocker):
@contextlib.contextmanager
def my_cm():
def mocked():
pass
with mocker.mock_module.patch.object(SomeClass, 'method', mocked):
yield
return my_cm
License
=======

View file

@ -1,4 +1,4 @@
# coding: utf-8
# file generated by setuptools_scm
# don't change, don't track in version control
version = '1.3.0'
version = '1.6.3'

View file

@ -1,7 +1,7 @@
install:
- C:\Python35\python -m pip install tox
- C:\Python36\python -m pip install tox
build: false # Not a C# project
test_script:
- C:\Python35\scripts\tox
- C:\Python36\scripts\tox

View file

@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: pytest-mock
Version: 1.3.0
Version: 1.6.3
Summary: Thin-wrapper around the mock package for easier use with py.test
Home-page: https://github.com/pytest-dev/pytest-mock/
Author: Bruno Oliveira
@ -17,7 +17,14 @@ Description: ===========
.. code-block:: python
import os
class UnixFS:
@staticmethod
def rm(filename):
os.remove(filename)
def test_unix_fs(mocker):
mocker.patch('os.remove')
UnixFS.rm('file')
@ -26,21 +33,21 @@ Description: ===========
.. Using PNG badges because PyPI doesn't support SVG
|python| |version| |downloads| |ci| |appveyor| |coverage|
|python| |version| |anaconda| |ci| |appveyor| |coverage|
.. |version| image:: http://img.shields.io/pypi/v/pytest-mock.png
.. |version| image:: http://img.shields.io/pypi/v/pytest-mock.svg
:target: https://pypi.python.org/pypi/pytest-mock
.. |downloads| image:: http://img.shields.io/pypi/dm/pytest-mock.png
:target: https://pypi.python.org/pypi/pytest-mock
.. |anaconda| image:: https://anaconda.org/conda-forge/pytest-mock/badges/version.svg
:target: https://anaconda.org/conda-forge/pytest-mock
.. |ci| image:: http://img.shields.io/travis/pytest-dev/pytest-mock.png
.. |ci| image:: http://img.shields.io/travis/pytest-dev/pytest-mock.svg
:target: https://travis-ci.org/pytest-dev/pytest-mock
.. |appveyor| image:: https://ci.appveyor.com/api/projects/status/pid1t7iuwhkm9eh6/branch/master?svg=true
:target: https://ci.appveyor.com/project/pytestbot/pytest-mock
.. |coverage| image:: http://img.shields.io/coveralls/pytest-dev/pytest-mock.png
.. |coverage| image:: http://img.shields.io/coveralls/pytest-dev/pytest-mock.svg
:target: https://coveralls.io/r/pytest-dev/pytest-mock
.. |python| image:: https://img.shields.io/pypi/pyversions/pytest-mock.svg
@ -76,6 +83,7 @@ Description: ===========
* `MagicMock <https://docs.python.org/3/library/unittest.mock.html#unittest.mock.MagicMock>`_
* `PropertyMock <https://docs.python.org/3/library/unittest.mock.html#unittest.mock.PropertyMock>`_
* `ANY <https://docs.python.org/3/library/unittest.mock.html#any>`_
* `DEFAULT <https://docs.python.org/3/library/unittest.mock.html#default>`_ *(Version 1.4)*
* `call <https://docs.python.org/3/library/unittest.mock.html#call>`_ *(Version 1.1)*
* `sentinel <https://docs.python.org/3/library/unittest.mock.html#sentinel>`_ *(Version 1.2)*
* `mock_open <https://docs.python.org/3/library/unittest.mock.html#mock-open>`_
@ -133,14 +141,30 @@ Description: ===========
diff::
m = mocker.patch.object(DS, 'create_char')
DS().create_char('Raistlin', class_='mag', gift=12)
> m.assert_called_once_with('Raistlin', class_='mage', gift=12)
E assert {'class_': 'mag', 'gift': 12} == {'class_': 'mage', 'gift': 12}
E Omitting 1 identical items, use -v to show
E Differing items:
E {'class_': 'mag'} != {'class_': 'mage'}
mocker = <pytest_mock.MockFixture object at 0x0381E2D0>
def test(mocker):
m = mocker.Mock()
m('fo')
> m.assert_called_once_with('', bar=4)
E AssertionError: Expected call: mock('', bar=4)
E Actual call: mock('fo')
E
E pytest introspection follows:
E
E Args:
E assert ('fo',) == ('',)
E At index 0 diff: 'fo' != ''
E Use -v to get the full diff
E Kwargs:
E assert {} == {'bar': 4}
E Right contains more items:
E {'bar': 4}
E Use -v to get the full diff
test_foo.py:6: AssertionError
========================== 1 failed in 0.03 seconds ===========================
This is useful when asserting mock calls with many/nested arguments and trying
@ -158,7 +182,25 @@ Description: ===========
mechanism used to suppress traceback entries from ``mock`` module does not work with that option
anyway plus it generates confusing messages on Python 3.5 due to exception chaining
.. _advanced assertions: https://pytest.org/latest/assert.html
.. _advanced assertions: http://pytest.org/latest/assert.html
Use standalone "mock" package
-----------------------------
*New in version 1.4.0.*
Python 3 users might want to use a newest version of the ``mock`` package as published on PyPI
than the one that comes with the Python distribution.
.. code-block:: ini
[pytest]
mock_use_standalone_module = true
This will force the plugin to import ``mock`` instead of the ``unittest.mock`` module bundled with
Python 3.3+. Note that this option is only used in Python 3+, as Python 2 users only have the option
to use the ``mock`` package from PyPI anyway.
Requirements
@ -240,9 +282,13 @@ Description: ===========
- you can't easily undo the mocking during the test execution;
**Note**
**Note about usage as context manager**
Although mocker's API is intentionally the same as ``mock.patch``'s, its uses as context managers and function decorators are **not** supported. The purpose of this plugin is to make the use of context managers and function decorators for mocking unnecessary. Indeed, trying to use the functionality in ``mocker`` in this manner can lead to non-intuitive errors:
Although mocker's API is intentionally the same as ``mock.patch``'s, its use
as context manager and function decorator is **not** supported through the
fixture. The purpose of this plugin is to make the use of context managers and
function decorators for mocking unnecessary. Indeed, trying to use the
functionality in ``mocker`` in this manner can lead to non-intuitive errors:
.. code-block:: python
@ -259,6 +305,23 @@ Description: ===========
with mocker.patch.object(a, 'doIt', return_value=True, autospec=True):
E AttributeError: __exit__
You can however use ``mocker.mock_module`` to access the underlying ``mock``
module, e.g. to return a context manager in a fixture that mocks something
temporarily:
.. code-block:: python
@pytest.fixture
def fixture_cm(mocker):
@contextlib.contextmanager
def my_cm():
def mocked():
pass
with mocker.mock_module.patch.object(SomeClass, 'method', mocked):
yield
return my_cm
License
=======

View file

@ -2,7 +2,6 @@
.travis.yml
CHANGELOG.rst
LICENSE
MANIFEST.in
README.rst
_pytest_mock_version.py
appveyor.yml

View file

@ -1,15 +1,38 @@
from __future__ import unicode_literals
import inspect
import sys
import pytest
try:
import mock as mock_module
except ImportError:
import unittest.mock as mock_module
from _pytest_mock_version import version
__version__ = version
# pseudo-six; if this starts to require more than this, depend on six already
if sys.version_info[0] == 2: # pragma: no cover
text_type = unicode # noqa
else:
text_type = str
def _get_mock_module(config):
"""
Import and return the actual "mock" module. By default this is "mock" for Python 2 and
"unittest.mock" for Python 3, but the user can force to always use "mock" on Python 3 using
the mock_use_standalone_module ini option.
"""
if not hasattr(_get_mock_module, '_module'):
use_standalone_module = parse_ini_boolean(config.getini('mock_use_standalone_module'))
if sys.version_info[0] == 2 or use_standalone_module:
import mock
_get_mock_module._module = mock
else:
import unittest.mock
_get_mock_module._module = unittest.mock
return _get_mock_module._module
class MockFixture(object):
"""
@ -17,20 +40,18 @@ class MockFixture(object):
ensuring that they are uninstalled at the end of each test.
"""
Mock = mock_module.Mock
MagicMock = mock_module.MagicMock
PropertyMock = mock_module.PropertyMock
call = mock_module.call
ANY = mock_module.ANY
sentinel = mock_module.sentinel
mock_open = mock_module.mock_open
def __init__(self):
def __init__(self, config):
self._patches = [] # list of mock._patch objects
self._mocks = [] # list of MagicMock objects
self.patch = self._Patcher(self._patches, self._mocks)
# temporary fix: this should be at class level, but is blowing
# up in Python 3.6
self.mock_module = mock_module = _get_mock_module(config)
self.patch = self._Patcher(self._patches, self._mocks, mock_module)
# aliases for convenience
self.Mock = mock_module.Mock
self.MagicMock = mock_module.MagicMock
self.PropertyMock = mock_module.PropertyMock
self.call = mock_module.call
self.ANY = mock_module.ANY
self.DEFAULT = mock_module.DEFAULT
self.sentinel = mock_module.sentinel
self.mock_open = mock_module.mock_open
@ -90,7 +111,7 @@ class MockFixture(object):
:rtype: mock.MagicMock
:return: Stub object.
"""
return mock_module.MagicMock(spec=lambda *args, **kwargs: None, name=name)
return self.mock_module.MagicMock(spec=lambda *args, **kwargs: None, name=name)
class _Patcher(object):
"""
@ -98,9 +119,10 @@ class MockFixture(object):
etc. We need this indirection to keep the same API of the mock package.
"""
def __init__(self, patches, mocks):
def __init__(self, patches, mocks, mock_module):
self._patches = patches
self._mocks = mocks
self.mock_module = mock_module
def _start_patch(self, mock_func, *args, **kwargs):
"""Patches something by calling the given function from the mock
@ -110,34 +132,35 @@ class MockFixture(object):
p = mock_func(*args, **kwargs)
mocked = p.start()
self._patches.append(p)
self._mocks.append(mocked)
if hasattr(mocked, 'reset_mock'):
self._mocks.append(mocked)
return mocked
def object(self, *args, **kwargs):
"""API to mock.patch.object"""
return self._start_patch(mock_module.patch.object, *args, **kwargs)
return self._start_patch(self.mock_module.patch.object, *args, **kwargs)
def multiple(self, *args, **kwargs):
"""API to mock.patch.multiple"""
return self._start_patch(mock_module.patch.multiple, *args,
return self._start_patch(self.mock_module.patch.multiple, *args,
**kwargs)
def dict(self, *args, **kwargs):
"""API to mock.patch.dict"""
return self._start_patch(mock_module.patch.dict, *args, **kwargs)
return self._start_patch(self.mock_module.patch.dict, *args, **kwargs)
def __call__(self, *args, **kwargs):
"""API to mock.patch"""
return self._start_patch(mock_module.patch, *args, **kwargs)
return self._start_patch(self.mock_module.patch, *args, **kwargs)
@pytest.yield_fixture
def mocker():
def mocker(pytestconfig):
"""
return an object that has the same interface to the `mock` module, but
takes care of automatically undoing all patches after each test method.
"""
result = MockFixture()
result = MockFixture(pytestconfig)
yield result
result.stopall()
@ -161,13 +184,27 @@ def assert_wrapper(__wrapped_mock_method__, *args, **kwargs):
__tracebackhide__ = True
try:
__wrapped_mock_method__(*args, **kwargs)
return
except AssertionError as e:
__mock_self = args[0]
if __mock_self.call_args is not None:
actual_args, actual_kwargs = __mock_self.call_args
assert actual_args == args[1:]
assert actual_kwargs == kwargs
raise AssertionError(*e.args)
if getattr(e, '_mock_introspection_applied', 0):
msg = text_type(e)
else:
__mock_self = args[0]
msg = text_type(e)
if __mock_self.call_args is not None:
actual_args, actual_kwargs = __mock_self.call_args
msg += '\n\npytest introspection follows:\n'
try:
assert actual_args == args[1:]
except AssertionError as e:
msg += '\nArgs:\n' + text_type(e)
try:
assert actual_kwargs == kwargs
except AssertionError as e:
msg += '\nKwargs:\n' + text_type(e)
e = AssertionError(msg)
e._mock_introspection_applied = True
raise e
def wrap_assert_not_called(*args, **kwargs):
@ -209,6 +246,8 @@ def wrap_assert_methods(config):
if _mock_module_originals:
return
mock_module = _get_mock_module(config)
wrappers = {
'assert_not_called': wrap_assert_not_called,
'assert_called_with': wrap_assert_called_with,
@ -247,6 +286,10 @@ def pytest_addoption(parser):
'Monkeypatch the mock library to improve reporting of the '
'assert_called_... methods',
default=True)
parser.addini('mock_use_standalone_module',
'Use standalone "mock" (from PyPI) instead of builtin "unittest.mock" '
'on Python 3',
default=False)
def parse_ini_boolean(value):

View file

@ -4,5 +4,4 @@ universal = 1
[egg_info]
tag_build =
tag_date = 0
tag_svn_revision = 0

View file

@ -1,5 +1,3 @@
import re
from setuptools import setup

View file

@ -4,7 +4,6 @@ import sys
from contextlib import contextmanager
import py.code
import pytest
pytest_plugins = 'pytester'
@ -69,10 +68,8 @@ def mock_using_patch(mocker):
def mock_using_patch_multiple(mocker):
from pytest_mock import mock_module
r = mocker.patch.multiple('os', remove=mock_module.DEFAULT,
listdir=mock_module.DEFAULT)
r = mocker.patch.multiple('os', remove=mocker.DEFAULT,
listdir=mocker.DEFAULT)
return r['remove'], r['listdir']
@ -89,6 +86,8 @@ def test_mock_patches(mock_fs, mocker, check_unix_fs_mocked):
mock_fs(mocker)
mocked_rm, mocked_ls = mock_fs(mocker)
check_unix_fs_mocked(mocked_rm, mocked_ls)
mocker.resetall()
mocker.stopall()
def test_mock_patch_dict(mocker):
@ -103,23 +102,16 @@ def test_mock_patch_dict(mocker):
assert x == {'original': 1}
def test_mock_fixture_is_deprecated(testdir):
def test_mock_patch_dict_resetall(mocker):
"""
Test that a warning emitted when using deprecated "mock" fixture.
We can call resetall after patching a dict.
:param mock:
"""
testdir.makepyfile('''
import warnings
import os
warnings.simplefilter('always')
def test_foo(mock, tmpdir):
mock.patch('os.listdir', return_value=['mocked'])
assert os.listdir(str(tmpdir)) == ['mocked']
mock.stopall()
assert os.listdir(str(tmpdir)) == []
''')
result = testdir.runpytest('-s')
result.stderr.fnmatch_lines(['*"mock" fixture has been deprecated*'])
x = {'original': 1}
mocker.patch.dict(x, values=[('new', 10)], clear=True)
assert x == {'new': 10}
mocker.resetall()
assert x == {'new': 10}
def test_deprecated_mock(mock, tmpdir):
@ -133,10 +125,12 @@ def test_deprecated_mock(mock, tmpdir):
@pytest.mark.parametrize('name', ['MagicMock', 'PropertyMock', 'Mock', 'call', 'ANY', 'sentinel', 'mock_open'])
def test_mocker_aliases(name):
from pytest_mock import mock_module, MockFixture
def test_mocker_aliases(name, pytestconfig):
from pytest_mock import _get_mock_module, MockFixture
mocker = MockFixture()
mock_module = _get_mock_module(pytestconfig)
mocker = MockFixture(pytestconfig)
assert getattr(mocker, name) is getattr(mock_module, name)
@ -203,8 +197,6 @@ def test_instance_method_spy(mocker):
@skip_pypy
def test_instance_method_by_class_spy(mocker):
from pytest_mock import mock_module
class Foo(object):
def bar(self, arg):
@ -215,13 +207,12 @@ def test_instance_method_by_class_spy(mocker):
other = Foo()
assert foo.bar(arg=10) == 20
assert other.bar(arg=10) == 20
calls = [mock_module.call(foo, arg=10), mock_module.call(other, arg=10)]
calls = [mocker.call(foo, arg=10), mocker.call(other, arg=10)]
assert spy.call_args_list == calls
@skip_pypy
def test_instance_method_by_subclass_spy(mocker):
from pytest_mock import mock_module
class Base(object):
@ -236,7 +227,7 @@ def test_instance_method_by_subclass_spy(mocker):
other = Foo()
assert foo.bar(arg=10) == 20
assert other.bar(arg=10) == 20
calls = [mock_module.call(foo, arg=10), mock_module.call(other, arg=10)]
calls = [mocker.call(foo, arg=10), mocker.call(other, arg=10)]
assert spy.call_args_list == calls
@ -424,12 +415,11 @@ def test_assert_any_call_wrapper(mocker):
def test_assert_has_calls(mocker):
from pytest_mock import mock_module
stub = mocker.stub()
stub("foo")
stub.assert_has_calls([mock_module.call("foo")])
stub.assert_has_calls([mocker.call("foo")])
with assert_traceback():
stub.assert_has_calls([mock_module.call("bar")])
stub.assert_has_calls([mocker.call("bar")])
def test_monkeypatch_ini(mocker, testdir):
@ -447,11 +437,7 @@ def test_monkeypatch_ini(mocker, testdir):
[pytest]
mock_traceback_monkeypatch = false
""")
if hasattr(testdir, 'runpytest_subprocess'):
result = testdir.runpytest_subprocess()
else:
# pytest 2.7.X
result = testdir.runpytest()
result = runpytest_subprocess(testdir)
assert result.ret == 0
@ -487,14 +473,74 @@ def test_monkeypatch_native(testdir):
stub(1, greet='hello')
stub.assert_called_once_with(1, greet='hey')
""")
if hasattr(testdir, 'runpytest_subprocess'):
result = testdir.runpytest_subprocess('--tb=native')
else:
# pytest 2.7.X
result = testdir.runpytest('--tb=native')
result = runpytest_subprocess(testdir, '--tb=native')
assert result.ret == 1
assert 'During handling of the above exception' not in result.stdout.str()
assert 'Differing items:' not in result.stdout.str()
traceback_lines = [x for x in result.stdout.str().splitlines()
if 'Traceback (most recent call last)' in x]
assert len(traceback_lines) == 1 # make sure there are no duplicated tracebacks (#44)
@pytest.mark.skipif(sys.version_info[0] < 3, reason='Py3 only')
def test_standalone_mock(testdir):
"""Check that the "mock_use_standalone" is being used.
"""
testdir.makepyfile("""
def test_foo(mocker):
pass
""")
testdir.makeini("""
[pytest]
mock_use_standalone_module = true
""")
result = runpytest_subprocess(testdir)
assert result.ret == 3
result.stderr.fnmatch_lines([
"*No module named 'mock'*",
])
def runpytest_subprocess(testdir, *args):
"""Testdir.runpytest_subprocess only available in pytest-2.8+"""
if hasattr(testdir, 'runpytest_subprocess'):
return testdir.runpytest_subprocess(*args)
else:
# pytest 2.7.X
return testdir.runpytest(*args)
def test_detailed_introspection(testdir):
"""Check that the "mock_use_standalone" is being used.
"""
testdir.makepyfile("""
def test(mocker):
m = mocker.Mock()
m('fo')
m.assert_called_once_with('', bar=4)
""")
result = testdir.runpytest('-s')
result.stdout.fnmatch_lines([
"*AssertionError: Expected call: mock('', bar=4)*",
"*Actual call: mock('fo')*",
"*pytest introspection follows:*",
'*Args:',
"*assert ('fo',) == ('',)",
"*At index 0 diff: 'fo' != ''*",
"*Use -v to get the full diff*",
"*Kwargs:*",
"*assert {} == {'bar': 4}*",
"*Right contains more items:*",
"*{'bar': 4}*",
"*Use -v to get the full diff*",
])
def test_assert_called_with_unicode_arguments(mocker):
"""Test bug in assert_call_with called with non-ascii unicode string (#91)"""
stub = mocker.stub()
stub(b'l\xc3\xb6k'.decode('UTF-8'))
with pytest.raises(AssertionError):
stub.assert_called_with(u'lak')

View file

@ -1,5 +1,5 @@
[tox]
envlist = py{26,27,33,34,35}-pytest{27,28,29,30},linting
envlist = py{26,27,33,34,35,36}-pytest{27,28,29,30},linting
[testenv]
passenv = USER USERNAME
@ -13,7 +13,6 @@ commands =
coverage run --append --source=pytest_mock.py -m pytest test_pytest_mock.py
[testenv:linting]
basepython = python3.5
skip_install=True
deps =
pytest-flakes