From 0f4520d987f353af96e19dbad61743a7a1f4edfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Wirtel?= Date: Thu, 11 Oct 2018 10:09:43 +0200 Subject: [PATCH 01/33] wip: fix doctest --- Doc/Makefile | 2 +- Doc/library/re.rst | 14 ++++++-------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/Doc/Makefile b/Doc/Makefile index 042f960b93e7fff..1885b9784e14e05 100644 --- a/Doc/Makefile +++ b/Doc/Makefile @@ -4,7 +4,7 @@ # # You can set these variables from the command line. -PYTHON = python3 +PYTHON = ../python VENVDIR = ./venv SPHINXBUILD = PATH=$(VENVDIR)/bin:$$PATH sphinx-build BLURB = PATH=$(VENVDIR)/bin:$$PATH blurb diff --git a/Doc/library/re.rst b/Doc/library/re.rst index e90840d9acc1755..0e3fd0e764d2472 100644 --- a/Doc/library/re.rst +++ b/Doc/library/re.rst @@ -825,6 +825,7 @@ form. This is useful if you want to match an arbitrary literal string that may have regular expression metacharacters in it. For example:: + >>> import string >>> print(re.escape('python.exe')) python\.exe @@ -1236,12 +1237,10 @@ Checking for a Pair In this example, we'll use the following helper function to display match objects a little more gracefully: -.. testcode:: - - def displaymatch(match): - if match is None: - return None - return '' % (match.group(), match.groups()) + >>> def displaymatch(match): + ... if match is None: + ... return None + ... return '' % (match.group(), match.groups()) Suppose you are writing a poker program where a player's hand is represented as a 5-character string with each character representing a card, "a" for ace, "k" @@ -1271,8 +1270,7 @@ To match this with a regular expression, one could use backreferences as such:: To find out what card the pair consists of, one could use the :meth:`~Match.group` method of the match object in the following manner: -.. doctest:: - + >>> pair = re.compile(r".*(.).*\1") >>> pair.match("717ak").group(1) '7' From 36ed172cf9b988f71069bf8d38fd86b23aa74958 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Wirtel?= Date: Thu, 11 Oct 2018 10:46:08 +0200 Subject: [PATCH 02/33] fix doctest for library/re.rst --- Doc/library/re.rst | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/Doc/library/re.rst b/Doc/library/re.rst index 0e3fd0e764d2472..f10867b4e5675bc 100644 --- a/Doc/library/re.rst +++ b/Doc/library/re.rst @@ -825,7 +825,6 @@ form. This is useful if you want to match an arbitrary literal string that may have regular expression metacharacters in it. For example:: - >>> import string >>> print(re.escape('python.exe')) python\.exe @@ -1375,15 +1374,14 @@ easily read and modified by Python as demonstrated in the following example that creates a phonebook. First, here is the input. Normally it may come from a file, here we are using -triple-quoted string syntax:: - - >>> text = """Ross McFluff: 834.345.1254 155 Elm Street - ... - ... Ronald Heathmore: 892.345.3428 436 Finley Avenue - ... Frank Burger: 925.541.7625 662 South Dogwood Way - ... - ... - ... Heather Albrecht: 548.326.4584 919 Park Place""" +triple-quoted string syntax + +.. testcode:: + + text = """Ross McFluff: 834.345.1254 155 Elm Street + Ronald Heathmore: 892.345.3428 436 Finley Avenue + Frank Burger: 925.541.7625 662 South Dogwood Way + Heather Albrecht: 548.326.4584 919 Park Place""" The entries are separated by one or more newlines. Now we convert the string into a list with each nonempty line having its own entry: From cc14274bd7ad913c7d9e69e3c7a106893b03952c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Wirtel?= Date: Thu, 11 Oct 2018 11:02:49 +0200 Subject: [PATCH 03/33] use .. doctest:: instead of .. testcode:: because we need to keep the presentation --- Doc/library/re.rst | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Doc/library/re.rst b/Doc/library/re.rst index f10867b4e5675bc..5313da2b797ab8b 100644 --- a/Doc/library/re.rst +++ b/Doc/library/re.rst @@ -1376,12 +1376,15 @@ creates a phonebook. First, here is the input. Normally it may come from a file, here we are using triple-quoted string syntax -.. testcode:: +.. doctest:: - text = """Ross McFluff: 834.345.1254 155 Elm Street - Ronald Heathmore: 892.345.3428 436 Finley Avenue - Frank Burger: 925.541.7625 662 South Dogwood Way - Heather Albrecht: 548.326.4584 919 Park Place""" + >>> text = """Ross McFluff: 834.345.1254 155 Elm Street + ... + ... Ronald Heathmore: 892.345.3428 436 Finley Avenue + ... Frank Burger: 925.541.7625 662 South Dogwood Way + ... + ... + ... Heather Albrecht: 548.326.4584 919 Park Place""" The entries are separated by one or more newlines. Now we convert the string into a list with each nonempty line having its own entry: From 01dea04c26c07aea2b56045f29bd97ccb1281895 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Wirtel?= Date: Thu, 11 Oct 2018 11:03:10 +0200 Subject: [PATCH 04/33] Add testsetup --- Doc/library/unittest.mock.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Doc/library/unittest.mock.rst b/Doc/library/unittest.mock.rst index 06009e4a09716e9..3df5565998615e6 100644 --- a/Doc/library/unittest.mock.rst +++ b/Doc/library/unittest.mock.rst @@ -41,6 +41,12 @@ available as `mock on PyPI `_. Quick Guide ----------- +.. testsetup:: + + class ProductionClass: + def method(self, a, b, c): + pass + :class:`Mock` and :class:`MagicMock` objects create all attributes and methods as you access them and store details of how they have been used. You can configure them, to specify return values or limit what attributes are @@ -183,6 +189,9 @@ the ``__call__`` method. The Mock Class -------------- +.. testsetup:: + + from unittest.mock import Mock :class:`Mock` is a flexible mock object intended to replace the use of stubs and test doubles throughout your code. Mocks are callable and create attributes as From 068485a39753ac16922045c3820866808a5f96b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Wirtel?= Date: Thu, 11 Oct 2018 11:13:46 +0200 Subject: [PATCH 05/33] pass from 258 to 240 --- Doc/library/unittest.mock.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/unittest.mock.rst b/Doc/library/unittest.mock.rst index 3df5565998615e6..5066e800e24809e 100644 --- a/Doc/library/unittest.mock.rst +++ b/Doc/library/unittest.mock.rst @@ -191,7 +191,7 @@ The Mock Class .. testsetup:: - from unittest.mock import Mock + from unittest.mock import Mock, call, sentinel, DEFAULT :class:`Mock` is a flexible mock object intended to replace the use of stubs and test doubles throughout your code. Mocks are callable and create attributes as From cd14acb7a5b3b51ddea28de2696233014840c5a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Wirtel?= Date: Thu, 11 Oct 2018 11:16:11 +0200 Subject: [PATCH 06/33] add SomeClass in testsetup -> 235 tests failed --- Doc/library/unittest.mock.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Doc/library/unittest.mock.rst b/Doc/library/unittest.mock.rst index 5066e800e24809e..9b00568730c7147 100644 --- a/Doc/library/unittest.mock.rst +++ b/Doc/library/unittest.mock.rst @@ -47,6 +47,9 @@ Quick Guide def method(self, a, b, c): pass + class SomeClass: + pass + :class:`Mock` and :class:`MagicMock` objects create all attributes and methods as you access them and store details of how they have been used. You can configure them, to specify return values or limit what attributes are From 940724753dd8f4d027a78e347bb9554017972f5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Wirtel?= Date: Thu, 11 Oct 2018 13:33:57 +0200 Subject: [PATCH 07/33] update --- Doc/library/unittest.mock-examples.rst | 130 ++++++++++++++----------- Doc/library/unittest.mock.rst | 102 ++++++++++++------- 2 files changed, 138 insertions(+), 94 deletions(-) diff --git a/Doc/library/unittest.mock-examples.rst b/Doc/library/unittest.mock-examples.rst index 65dee7c0eb2d72c..31ae6e286675223 100644 --- a/Doc/library/unittest.mock-examples.rst +++ b/Doc/library/unittest.mock-examples.rst @@ -9,6 +9,19 @@ .. _getting-started: + +.. testsetup:: + + import unittest + from unittest.mock import Mock, MagicMock, patch, call, sentinel + + class SomeClass: + attribute = 'this is a doctest' + + @staticmethod + def static_method(): + pass + Using Mock ---------- @@ -99,17 +112,17 @@ by looking at the return value of the mocked class. In the example below we have a function ``some_function`` that instantiates ``Foo`` and calls a method on it. The call to :func:`patch` replaces the class ``Foo`` with a mock. The ``Foo`` instance is the result of calling the mock, so it is configured -by modifying the mock :attr:`~Mock.return_value`. +by modifying the mock :attr:`~Mock.return_value`.:: - >>> def some_function(): - ... instance = module.Foo() - ... return instance.method() - ... - >>> with patch('module.Foo') as mock: - ... instance = mock.return_value - ... instance.method.return_value = 'the result' - ... result = some_function() - ... assert result == 'the result' + def some_function(): + instance = module.Foo() + return instance.method() + + with patch('module.Foo') as mock: + instance = mock.return_value + instance.method.return_value = 'the result' + result = some_function() + assert result == 'the result' Naming your mocks @@ -321,7 +334,7 @@ whatever) to be replaced with. 'patch.object' takes an object and the name of the attribute you would like patched, plus optionally the value to patch it with. -``patch.object``: +``patch.object``: :: >>> original = SomeClass.attribute >>> @patch.object(SomeClass, 'attribute', sentinel.attribute) @@ -348,7 +361,7 @@ instead of :func:`patch.object`: >>> mock.assert_called_with('filename', 'r') >>> assert handle == sentinel.file_handle, "incorrect file handle returned" -The module name can be 'dotted', in the form ``package.module`` if needed: +The module name can be 'dotted', in the form ``package.module`` if needed: :: >>> @patch('package.module.ClassName.attribute', sentinel.attribute) ... def test(): @@ -380,7 +393,7 @@ passed into the test function / method: ... >>> MyTest('test_something').test_something() -You can stack up multiple patch decorators using this pattern: +You can stack up multiple patch decorators using this pattern: :: >>> class MyTest(unittest.TestCase): ... @patch('package.module.ClassName1') @@ -485,28 +498,28 @@ response object for it. To set the response as the return value for that final mock_backend.get_endpoint.return_value.create_call.return_value.start_call.return_value = mock_response We can do that in a slightly nicer way using the :meth:`~Mock.configure_mock` -method to directly set the return value for us: +method to directly set the return value for us:: - >>> something = Something() - >>> mock_response = Mock(spec=open) - >>> mock_backend = Mock() - >>> config = {'get_endpoint.return_value.create_call.return_value.start_call.return_value': mock_response} - >>> mock_backend.configure_mock(**config) + something = Something() + mock_response = Mock(spec=open) + mock_backend = Mock() + config = {'get_endpoint.return_value.create_call.return_value.start_call.return_value': mock_response} + mock_backend.configure_mock(**config) With these we monkey patch the "mock backend" in place and can make the real -call: +call: :: - >>> something.backend = mock_backend - >>> something.method() + something.backend = mock_backend + something.method() Using :attr:`~Mock.mock_calls` we can check the chained call with a single assert. A chained call is several calls in one line of code, so there will be several entries in ``mock_calls``. We can use :meth:`call.call_list` to create -this list of calls for us: +this list of calls for us: :: - >>> chained = call.get_endpoint('foobar').create_call('spam', 'eggs').start_call() - >>> call_list = chained.call_list() - >>> assert mock_backend.mock_calls == call_list + chained = call.get_endpoint('foobar').create_call('spam', 'eggs').start_call() + call_list = chained.call_list() + assert mock_backend.mock_calls == call_list Partial mocking @@ -525,16 +538,15 @@ The :func:`patch decorator ` is used here to mock out the ``date`` class in the module under test. The :attr:`side_effect` attribute on the mock date class is then set to a lambda function that returns a real date. When the mock date class is called a real date will be -constructed and returned by ``side_effect``. +constructed and returned by ``side_effect``. :: - >>> from datetime import date - >>> with patch('mymodule.date') as mock_date: - ... mock_date.today.return_value = date(2010, 10, 8) - ... mock_date.side_effect = lambda *args, **kw: date(*args, **kw) - ... - ... assert mymodule.date.today() == date(2010, 10, 8) - ... assert mymodule.date(2009, 6, 8) == date(2009, 6, 8) - ... + from datetime import date + with patch('mymodule.date') as mock_date: + mock_date.today.return_value = date(2010, 10, 8) + mock_date.side_effect = lambda *args, **kw: date(*args, **kw) + + assert mymodule.date.today() == date(2010, 10, 8) + assert mymodule.date(2009, 6, 8) == date(2009, 6, 8) Note that we don't patch :class:`datetime.date` globally, we patch ``date`` in the module that *uses* it. See :ref:`where to patch `. @@ -600,10 +612,10 @@ is to apply the patch decorators to every method. This can feel like unnecessary repetition. For Python 2.6 or more recent you can use :func:`patch` (in all its various forms) as a class decorator. This applies the patches to all test methods on the class. A test method is identified by methods whose names start -with ``test``: +with ``test``: :: >>> @patch('mymodule.SomeClass') - ... class MyTest(TestCase): + ... class MyTest(unittest.TestCase): ... ... def test_one(self, MockSomeClass): ... self.assertIs(mymodule.SomeClass, MockSomeClass) @@ -620,9 +632,10 @@ with ``test``: 'something' An alternative way of managing patches is to use the :ref:`start-and-stop`. -These allow you to move the patching into your ``setUp`` and ``tearDown`` methods. +These allow you to move the patching into your ``setUp`` and ``tearDown`` methods. +:: - >>> class MyTest(TestCase): + >>> class MyTest(unittest.TestCase): ... def setUp(self): ... self.patcher = patch('mymodule.foo') ... self.mock_foo = self.patcher.start() @@ -638,9 +651,9 @@ These allow you to move the patching into your ``setUp`` and ``tearDown`` method If you use this technique you must ensure that the patching is "undone" by calling ``stop``. This can be fiddlier than you might think, because if an exception is raised in the setUp then tearDown is not called. -:meth:`unittest.TestCase.addCleanup` makes this easier: +:meth:`unittest.TestCase.addCleanup` makes this easier: :: - >>> class MyTest(TestCase): + >>> class MyTest(unittest.TestCase): ... def setUp(self): ... patcher = patch('mymodule.foo') ... self.addCleanup(patcher.stop) @@ -753,7 +766,7 @@ defined in 'mymodule':: val.clear() When we try to test that ``grob`` calls ``frob`` with the correct argument look -what happens: +what happens: :: >>> with patch('mymodule.frob') as mock_frob: ... val = {6} @@ -777,7 +790,7 @@ functionality. If you provide a ``side_effect`` function for a mock then opportunity to copy the arguments and store them for later assertions. In this example I'm using *another* mock to store the arguments so that I can use the mock methods for doing the assertion. Again a helper function sets this up for -me. +me. :: >>> from copy import deepcopy >>> from unittest.mock import Mock, patch, DEFAULT @@ -854,9 +867,9 @@ Nesting Patches Using patch as a context manager is nice, but if you do multiple patches you can end up with nested with statements indenting further and further to the -right: +right: :: - >>> class MyTest(TestCase): + >>> class MyTest(unittest.TestCase): ... ... def test_foo(self): ... with patch('mymodule.Foo') as mock_foo: @@ -873,9 +886,9 @@ right: With unittest ``cleanup`` functions and the :ref:`start-and-stop` we can achieve the same effect without the nested indentation. A simple helper method, ``create_patch``, puts the patch in place and returns the created mock -for us: +for us: :: - >>> class MyTest(TestCase): + >>> class MyTest(unittest.TestCase): ... ... def create_patch(self, name): ... patcher = patch(name) @@ -969,7 +982,7 @@ mock methods and attributes: >>> mock.__setitem__.call_args_list [call('b', 'fish'), call('d', 'eggs')] >>> my_dict - {'a': 1, 'c': 3, 'b': 'fish', 'd': 'eggs'} + {'a': 1, 'b': 'fish', 'c': 3, 'd': 'eggs'} Mock subclasses and their attributes @@ -1064,6 +1077,7 @@ previously will be restored safely. Here's an example that mocks out the 'fooble' module. + >>> import sys >>> mock = Mock() >>> with patch.dict('sys.modules', {'fooble': mock}): ... import fooble @@ -1132,16 +1146,16 @@ the ``mock_calls`` attribute on the manager mock: If ``patch`` is creating, and putting in place, your mocks then you can attach them to a manager mock using the :meth:`~Mock.attach_mock` method. After -attaching calls will be recorded in ``mock_calls`` of the manager. - - >>> manager = MagicMock() - >>> with patch('mymodule.Class1') as MockClass1: - ... with patch('mymodule.Class2') as MockClass2: - ... manager.attach_mock(MockClass1, 'MockClass1') - ... manager.attach_mock(MockClass2, 'MockClass2') - ... MockClass1().foo() - ... MockClass2().bar() - ... +attaching calls will be recorded in ``mock_calls`` of the manager. :: + + manager = MagicMock() + with patch('mymodule.Class1') as MockClass1: + with patch('mymodule.Class2') as MockClass2: + manager.attach_mock(MockClass1, 'MockClass1') + manager.attach_mock(MockClass2, 'MockClass2') + MockClass1().foo() + MockClass2().bar() + >>> manager.mock_calls diff --git a/Doc/library/unittest.mock.rst b/Doc/library/unittest.mock.rst index 9b00568730c7147..0660118ae3cc474 100644 --- a/Doc/library/unittest.mock.rst +++ b/Doc/library/unittest.mock.rst @@ -48,7 +48,14 @@ Quick Guide pass class SomeClass: - pass + @staticmethod + def static_method(args): + return args + + @classmethod + def class_method(cls, args): + return args + :class:`Mock` and :class:`MagicMock` objects create all attributes and methods as you access them and store details of how they have been used. You @@ -89,7 +96,7 @@ that don't exist on the spec will fail with an :exc:`AttributeError`. The :func:`patch` decorator / context manager makes it easy to mock classes or objects in a module under test. The object you specify will be replaced with a -mock (or other object) during the test and restored when the test ends: +mock (or other object) during the test and restored when the test ends: :: >>> from unittest.mock import patch >>> @patch('module.ClassName2') @@ -194,7 +201,10 @@ The Mock Class .. testsetup:: - from unittest.mock import Mock, call, sentinel, DEFAULT + import unittest + from unittest.mock import sentinel, DEFAULT, ANY + from unittest.mock import patch, call, Mock, MagicMock, PropertyMock + from unittest.mock import mock_open :class:`Mock` is a flexible mock object intended to replace the use of stubs and test doubles throughout your code. Mocks are callable and create attributes as @@ -786,7 +796,7 @@ apply to method calls on the mock object. so you can specify a return value when it is fetched. Fetching a :class:`PropertyMock` instance from an object calls the mock, with - no args. Setting it calls the mock with the value being set. + no args. Setting it calls the mock with the value being set. :: >>> class Foo: ... @property @@ -1013,7 +1023,7 @@ the "parenting" if for some reason you don't want it to happen. Mocks created for you by :func:`patch` are automatically given names. To attach mocks that have names to a parent you use the :meth:`~Mock.attach_mock` -method: +method: :: >>> thing1 = object() >>> thing2 = object() @@ -1129,7 +1139,7 @@ patch available for alternate use-cases. :func:`patch` as function decorator, creating the mock for you and passing it into -the decorated function: +the decorated function: :: >>> @patch('__main__.SomeClass') ... def function(normal_argument, mock_class): @@ -1147,7 +1157,7 @@ If the class is instantiated multiple times you could use can set the *return_value* to be anything you want. To configure return values on methods of *instances* on the patched class -you must do this on the :attr:`return_value`. For example: +you must do this on the :attr:`return_value`. For example: :: >>> class Class: ... def method(self): @@ -1161,7 +1171,7 @@ you must do this on the :attr:`return_value`. For example: ... If you use *spec* or *spec_set* and :func:`patch` is replacing a *class*, then the -return value of the created mock will have the same spec. +return value of the created mock will have the same spec. :: >>> Original = Class >>> patcher = patch('__main__.Class', spec=True) @@ -1172,7 +1182,7 @@ return value of the created mock will have the same spec. The *new_callable* argument is useful where you want to use an alternative class to the default :class:`MagicMock` for the created mock. For example, if -you wanted a :class:`NonCallableMock` to be used: +you wanted a :class:`NonCallableMock` to be used: :: >>> thing = object() >>> with patch('__main__.thing', new_callable=NonCallableMock) as mock_thing: @@ -1183,7 +1193,7 @@ you wanted a :class:`NonCallableMock` to be used: ... TypeError: 'NonCallableMock' object is not callable -Another use case might be to replace an object with an :class:`io.StringIO` instance: +Another use case might be to replace an object with an :class:`io.StringIO` instance: :: >>> from io import StringIO >>> def foo(): @@ -1199,7 +1209,7 @@ Another use case might be to replace an object with an :class:`io.StringIO` inst When :func:`patch` is creating a mock for you, it is common that the first thing you need to do is to configure the mock. Some of that configuration can be done in the call to patch. Any arbitrary keywords you pass into the call will be -used to set attributes on the created mock: +used to set attributes on the created mock: :: >>> patcher = patch('__main__.thing', first='one', second='two') >>> mock_thing = patcher.start() @@ -1212,7 +1222,7 @@ As well as attributes on the created mock attributes, like the :attr:`~Mock.return_value` and :attr:`~Mock.side_effect`, of child mocks can also be configured. These aren't syntactically valid to pass in directly as keyword arguments, but a dictionary with these as keys can still be expanded -into a :func:`patch` call using ``**``: +into a :func:`patch` call using ``**``: :: >>> config = {'method.return_value': 3, 'other.side_effect': KeyError} >>> patcher = patch('__main__.thing', **config) @@ -1371,7 +1381,7 @@ patch.multiple If you want :func:`patch.multiple` to create mocks for you, then you can use :data:`DEFAULT` as the value. If you use :func:`patch.multiple` as a decorator -then the created mocks are passed into the decorated function by keyword. +then the created mocks are passed into the decorated function by keyword. :: >>> thing = object() >>> other = object() @@ -1384,7 +1394,7 @@ then the created mocks are passed into the decorated function by keyword. >>> test_function() :func:`patch.multiple` can be nested with other ``patch`` decorators, but put arguments -passed by keyword *after* any of the standard arguments created by :func:`patch`: +passed by keyword *after* any of the standard arguments created by :func:`patch`: :: >>> @patch('sys.exit') ... @patch.multiple('__main__', thing=DEFAULT, other=DEFAULT) @@ -1396,7 +1406,7 @@ passed by keyword *after* any of the standard arguments created by :func:`patch` >>> test_function() If :func:`patch.multiple` is used as a context manager, the value returned by the -context manger is a dictionary where created mocks are keyed by name: +context manger is a dictionary where created mocks are keyed by name: :: >>> with patch.multiple('__main__', thing=DEFAULT, other=DEFAULT) as values: ... assert 'other' in repr(values['other']) @@ -1420,7 +1430,7 @@ normal and keep a reference to the returned ``patcher`` object. You can then call :meth:`start` to put the patch in place and :meth:`stop` to undo it. If you are using :func:`patch` to create a mock for you then it will be returned by -the call to ``patcher.start``. +the call to ``patcher.start``. :: >>> patcher = patch('package.module.ClassName') >>> from package import module @@ -1434,9 +1444,9 @@ the call to ``patcher.start``. A typical use case for this might be for doing multiple patches in the ``setUp`` -method of a :class:`TestCase`: +method of a :class:`TestCase`: :: - >>> class MyTest(TestCase): + >>> class MyTest(unittest.TestCase): ... def setUp(self): ... self.patcher1 = patch('package.module.Class1') ... self.patcher2 = patch('package.module.Class2') @@ -1458,9 +1468,9 @@ method of a :class:`TestCase`: If you use this technique you must ensure that the patching is "undone" by calling ``stop``. This can be fiddlier than you might think, because if an exception is raised in the ``setUp`` then ``tearDown`` is not called. - :meth:`unittest.TestCase.addCleanup` makes this easier: + :meth:`unittest.TestCase.addCleanup` makes this easier: :: - >>> class MyTest(TestCase): + >>> class MyTest(unittest.TestCase): ... def setUp(self): ... patcher = patch('package.module.Class') ... self.MockClass = patcher.start() @@ -1486,7 +1496,7 @@ It is also possible to stop all patches which have been started by using patch builtins ~~~~~~~~~~~~~~ You can patch any builtins within a module. The following example patches -builtin :func:`ord`: +builtin :func:`ord`: :: >>> @patch('__main__.ord') ... def test(mock_ord): @@ -1506,7 +1516,7 @@ start with ``'test'`` as being test methods. This is the same way that the :class:`unittest.TestLoader` finds test methods by default. It is possible that you want to use a different prefix for your tests. You can -inform the patchers of the different prefix by setting ``patch.TEST_PREFIX``: +inform the patchers of the different prefix by setting ``patch.TEST_PREFIX``: :: >>> patch.TEST_PREFIX = 'foo' >>> value = 3 @@ -1943,7 +1953,7 @@ arguments are a dictionary: >>> args (1, 2, 3) >>> kwargs - {'arg2': 'two', 'arg': 'one'} + {'arg': 'one', 'arg2': 'two'} >>> args is kall[0] True >>> kwargs is kall[1] @@ -1959,7 +1969,7 @@ arguments are a dictionary: >>> args (4, 5, 6) >>> kwargs - {'arg2': 'three', 'arg': 'two'} + {'arg': 'two', 'arg2': 'three'} >>> name is m.mock_calls[0][0] True @@ -2039,11 +2049,17 @@ If the mock was created with a *spec* (or *autospec* of course) then all the attributes from the original are shown, even if they haven't been accessed yet: +.. doctest:: + :options: +ELLIPSIS,+NORMALIZE_WHITESPACE + >>> dir(Mock()) ['assert_any_call', + 'assert_called', + 'assert_called_once', 'assert_called_once_with', 'assert_called_with', 'assert_has_calls', + 'assert_not_called', 'attach_mock', ... >>> from urllib import request @@ -2060,6 +2076,9 @@ filtered from the result of calling :func:`dir` on a :class:`Mock`. If you disli behaviour you can switch it off by setting the module level switch :data:`FILTER_DIR`: +.. doctest:: + :options: +ELLIPSIS,+NORMALIZE_WHITESPACE + >>> from unittest import mock >>> mock.FILTER_DIR = False >>> dir(mock.Mock()) @@ -2122,7 +2141,7 @@ The issue is that even if you mock out the call to :func:`open` it is the :meth:`__exit__` called). Mocking context managers with a :class:`MagicMock` is common enough and fiddly -enough that a helper function is useful. +enough that a helper function is useful. :: >>> m = mock_open() >>> with patch('__main__.open', m): @@ -2138,7 +2157,7 @@ enough that a helper function is useful. >>> handle = m() >>> handle.write.assert_called_once_with('some stuff') -And for reading files: +And for reading files: :: >>> with patch('__main__.open', mock_open(read_data='bibble')) as m: ... with open('foo') as h: @@ -2231,7 +2250,7 @@ accessed) you can use it with very complex or deeply nested objects (like modules that import modules that import modules) without a big performance hit. -Here's an example of it in use: +Here's an example of it in use: :: >>> from urllib import request >>> patcher = patch('__main__.request', autospec=True) @@ -2243,7 +2262,7 @@ Here's an example of it in use: You can see that :class:`request.Request` has a spec. :class:`request.Request` takes two arguments in the constructor (one of which is *self*). Here's what happens if -we try to call it incorrectly: +we try to call it incorrectly: :: >>> req = request.Request() Traceback (most recent call last): @@ -2251,7 +2270,7 @@ we try to call it incorrectly: TypeError: () takes at least 2 arguments (1 given) The spec also applies to instantiated classes (i.e. the return value of -specced mocks): +specced mocks): :: >>> req = request.Request('foo') >>> req @@ -2259,7 +2278,7 @@ specced mocks): :class:`Request` objects are not callable, so the return value of instantiating our mocked out :class:`request.Request` is a non-callable mock. With the spec in place -any typos in our asserts will raise the correct error: +any typos in our asserts will raise the correct error: :: >>> req.add_header('spam', 'eggs') @@ -2293,7 +2312,7 @@ objects so that introspection is safe [#]_. A more serious problem is that it is common for instance attributes to be created in the :meth:`__init__` method and not to exist on the class at all. *autospec* can't know about any dynamically created attributes and restricts -the api to visible attributes. +the api to visible attributes. :: >>> class Something: ... def __init__(self): @@ -2311,7 +2330,7 @@ There are a few different ways of resolving this problem. The easiest, but not necessarily the least annoying, way is to simply set the required attributes on the mock after creation. Just because *autospec* doesn't allow you to fetch attributes that don't exist on the spec it doesn't prevent you -setting them: +setting them: :: >>> with patch('__main__.Something', autospec=True): ... thing = Something() @@ -2362,7 +2381,7 @@ spec rather than the class. The other is to create a subclass of the production class and add the defaults to the subclass without affecting the production class. Both of these require you to use an alternative object as the spec. Thankfully :func:`patch` supports this - you can simply pass the -alternative object as the *autospec* argument: +alternative object as the *autospec* argument: :: >>> class Something: ... def __init__(self): @@ -2384,6 +2403,11 @@ alternative object as the *autospec* argument: Sealing mocks ~~~~~~~~~~~~~ + +.. testsetup:: + + from unittest.mock import seal + .. function:: seal(mock) Seal will disable the creation of mock children by preventing getting or setting @@ -2391,13 +2415,19 @@ Sealing mocks If a mock instance is assigned to an attribute instead of being dynamically created it won't be considered in the sealing chain. This allows one to prevent seal from - fixing part of the mock object. + fixing part of the mock object. :: >>> mock = Mock() >>> mock.submock.attribute1 = 2 >>> mock.not_submock = mock.Mock() >>> seal(mock) - >>> mock.submock.attribute2 # This will raise AttributeError. - >>> mock.not_submock.attribute2 # This won't raise. + >>> mock.submock.attribute2 + Traceback (most recent call last): + ... + AttributeError: mock.submock.attribute2 + >>> mock.not_submock.attribute2 + Traceback (most recent call last): + ... + AttributeError: mock.Mock().attribute2 .. versionadded:: 3.7 From 249ff3db47d5a17ac4a396864917d939928c89b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Wirtel?= Date: Thu, 11 Oct 2018 13:48:18 +0200 Subject: [PATCH 08/33] update --- Doc/library/unittest.mock.rst | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/Doc/library/unittest.mock.rst b/Doc/library/unittest.mock.rst index 0660118ae3cc474..fc1daf2331dfceb 100644 --- a/Doc/library/unittest.mock.rst +++ b/Doc/library/unittest.mock.rst @@ -2421,13 +2421,7 @@ Sealing mocks >>> mock.submock.attribute1 = 2 >>> mock.not_submock = mock.Mock() >>> seal(mock) - >>> mock.submock.attribute2 - Traceback (most recent call last): - ... - AttributeError: mock.submock.attribute2 - >>> mock.not_submock.attribute2 - Traceback (most recent call last): - ... - AttributeError: mock.Mock().attribute2 + >>> mock.submock.attribute2 # This will raise AttributeError + >>> mock.not_submock.attribute2 # This won't raise .. versionadded:: 3.7 From c9d6175063770b7e702fb780ef7eabe74592d5c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Wirtel?= Date: Thu, 11 Oct 2018 14:34:12 +0200 Subject: [PATCH 09/33] add new target in travis --- .travis.yml | 11 ++++++++++- Doc/Makefile | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index d1a6da70e508b36..bdebaa3ed17a171 100644 --- a/.travis.yml +++ b/.travis.yml @@ -54,9 +54,18 @@ matrix: # Sphinx is pinned so that new versions that introduce new warnings won't suddenly cause build failures. # (Updating the version is fine as long as no warnings are raised by doing so.) # The theme used by the docs is stored seperately, so we need to install that as well. - - python -m pip install sphinx~=1.6.1 blurb python-docs-theme + - python -m pip install sphinx blurb python-docs-theme script: - make check suspicious html SPHINXOPTS="-q -W -j4" + - os: linux + language: python + python: 3.7 + env: TESTING=docs + before_script: + - cd Doc + - python -m pip install sphinx blurb python-docs-theme + script: + - xvfb-run make doctest SPHINXOPTS="-q -W -j4" - os: osx language: c compiler: clang diff --git a/Doc/Makefile b/Doc/Makefile index 1885b9784e14e05..042f960b93e7fff 100644 --- a/Doc/Makefile +++ b/Doc/Makefile @@ -4,7 +4,7 @@ # # You can set these variables from the command line. -PYTHON = ../python +PYTHON = python3 VENVDIR = ./venv SPHINXBUILD = PATH=$(VENVDIR)/bin:$$PATH sphinx-build BLURB = PATH=$(VENVDIR)/bin:$$PATH blurb From 1fa950989d1b7d151fa76f154cdf6c38065065e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Wirtel?= Date: Thu, 11 Oct 2018 14:44:39 +0200 Subject: [PATCH 10/33] fix the whitespace --- Doc/library/unittest.mock-examples.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/unittest.mock-examples.rst b/Doc/library/unittest.mock-examples.rst index 31ae6e286675223..4b300c6f32e630f 100644 --- a/Doc/library/unittest.mock-examples.rst +++ b/Doc/library/unittest.mock-examples.rst @@ -632,7 +632,7 @@ with ``test``: :: 'something' An alternative way of managing patches is to use the :ref:`start-and-stop`. -These allow you to move the patching into your ``setUp`` and ``tearDown`` methods. +These allow you to move the patching into your ``setUp`` and ``tearDown`` methods. :: >>> class MyTest(unittest.TestCase): From 305ee743ea2f826eb4c5c72f6d928a0e9156024e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Wirtel?= Date: Thu, 11 Oct 2018 14:48:31 +0200 Subject: [PATCH 11/33] try to use 3.7 --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index bdebaa3ed17a171..434c30dca1f8be7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -60,6 +60,8 @@ matrix: - os: linux language: python python: 3.7 + dist: xenial + sudo: true env: TESTING=docs before_script: - cd Doc From 1517a37b70bb41d83cf30596621493854ba6fe6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Wirtel?= Date: Thu, 11 Oct 2018 15:11:56 +0200 Subject: [PATCH 12/33] disable the warnings into errors --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 434c30dca1f8be7..ff24041d935c82e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -67,7 +67,7 @@ matrix: - cd Doc - python -m pip install sphinx blurb python-docs-theme script: - - xvfb-run make doctest SPHINXOPTS="-q -W -j4" + - xvfb-run make doctest SPHINXOPTS="-q -j4" - os: osx language: c compiler: clang From 7c03c41f963db4f4620719a84d190ad606ef1ca9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Wirtel?= Date: Thu, 11 Oct 2018 15:22:34 +0200 Subject: [PATCH 13/33] use a block code instead of doctest --- Doc/library/re.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Doc/library/re.rst b/Doc/library/re.rst index 5313da2b797ab8b..65acc8b9e9c4846 100644 --- a/Doc/library/re.rst +++ b/Doc/library/re.rst @@ -1234,12 +1234,12 @@ Checking for a Pair ^^^^^^^^^^^^^^^^^^^ In this example, we'll use the following helper function to display match -objects a little more gracefully: +objects a little more gracefully: :: - >>> def displaymatch(match): - ... if match is None: - ... return None - ... return '' % (match.group(), match.groups()) + def displaymatch(match): + if match is None: + return None + return '' % (match.group(), match.groups()) Suppose you are writing a poker program where a player's hand is represented as a 5-character string with each character representing a card, "a" for ace, "k" @@ -1267,7 +1267,7 @@ To match this with a regular expression, one could use backreferences as such:: "" To find out what card the pair consists of, one could use the -:meth:`~Match.group` method of the match object in the following manner: +:meth:`~Match.group` method of the match object in the following manner: :: >>> pair = re.compile(r".*(.).*\1") >>> pair.match("717ak").group(1) From 2e1db29d0924201271e8048bdf73c8eada3a72e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Wirtel?= Date: Thu, 11 Oct 2018 15:25:20 +0200 Subject: [PATCH 14/33] Disable some builds --- .travis.yml | 114 ++++++++++++++++++++++++++-------------------------- 1 file changed, 57 insertions(+), 57 deletions(-) diff --git a/.travis.yml b/.travis.yml index ff24041d935c82e..d62d0cbb2729ed4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,30 +33,30 @@ matrix: allow_failures: - env: OPTIONAL=true include: - - os: linux - language: c - compiler: clang - # gcc also works, but to keep the # of concurrent builds down, we use one C - # compiler here and the other to run the coverage build. Clang is preferred - # in this instance for its better error messages. - env: TESTING=cpython - addons: - apt: - packages: - - xvfb - - os: linux - language: python - # Build the docs against a stable version of Python so code bugs don't hold up doc-related PRs. - python: 3.6 - env: TESTING=docs - before_script: - - cd Doc - # Sphinx is pinned so that new versions that introduce new warnings won't suddenly cause build failures. - # (Updating the version is fine as long as no warnings are raised by doing so.) - # The theme used by the docs is stored seperately, so we need to install that as well. - - python -m pip install sphinx blurb python-docs-theme - script: - - make check suspicious html SPHINXOPTS="-q -W -j4" + #- os: linux + # language: c + # compiler: clang + # # gcc also works, but to keep the # of concurrent builds down, we use one C + # # compiler here and the other to run the coverage build. Clang is preferred + # # in this instance for its better error messages. + # env: TESTING=cpython + # addons: + # apt: + # packages: + # - xvfb + #- os: linux + # language: python + # # Build the docs against a stable version of Python so code bugs don't hold up doc-related PRs. + # python: 3.6 + # env: TESTING=docs + # before_script: + # - cd Doc + # # Sphinx is pinned so that new versions that introduce new warnings won't suddenly cause build failures. + # # (Updating the version is fine as long as no warnings are raised by doing so.) + # # The theme used by the docs is stored seperately, so we need to install that as well. + # - python -m pip install sphinx blurb python-docs-theme + # script: + # - make check suspicious html SPHINXOPTS="-q -W -j4" - os: linux language: python python: 3.7 @@ -68,39 +68,39 @@ matrix: - python -m pip install sphinx blurb python-docs-theme script: - xvfb-run make doctest SPHINXOPTS="-q -j4" - - os: osx - language: c - compiler: clang - # Testing under macOS is optional until testing stability has been demonstrated. - env: OPTIONAL=true - before_install: - # Python 3 is needed for Argument Clinic and multissl - - HOMEBREW_NO_AUTO_UPDATE=1 brew install xz python3 - - export PATH=$(brew --prefix)/bin:$(brew --prefix)/sbin:$PATH - - os: linux - language: c - compiler: gcc - env: OPTIONAL=true - addons: - apt: - packages: - - lcov - - xvfb - before_script: - - ./configure - - make coverage -s -j4 - # Need a venv that can parse covered code. - - ./python -m venv venv - - ./venv/bin/python -m pip install -U coverage - - ./venv/bin/python -m test.pythoninfo - script: - # Skip tests that re-run the entire test suite. - - xvfb-run ./venv/bin/python -m coverage run --pylib -m test --fail-env-changed -uall,-cpu -x test_multiprocessing_fork -x test_multiprocessing_forkserver -x test_multiprocessing_spawn -x test_concurrent_futures - after_script: # Probably should be after_success once test suite updated to run under coverage.py. - # Make the `coverage` command available to Codecov w/ a version of Python that can parse all source files. - - source ./venv/bin/activate - - make coverage-lcov - - bash <(curl -s https://codecov.io/bash) + #- os: osx + # language: c + # compiler: clang + # # Testing under macOS is optional until testing stability has been demonstrated. + # env: OPTIONAL=true + # before_install: + # # Python 3 is needed for Argument Clinic and multissl + # - HOMEBREW_NO_AUTO_UPDATE=1 brew install xz python3 + # - export PATH=$(brew --prefix)/bin:$(brew --prefix)/sbin:$PATH + #- os: linux + # language: c + # compiler: gcc + # env: OPTIONAL=true + # addons: + # apt: + # packages: + # - lcov + # - xvfb + # before_script: + # - ./configure + # - make coverage -s -j4 + # # Need a venv that can parse covered code. + # - ./python -m venv venv + # - ./venv/bin/python -m pip install -U coverage + # - ./venv/bin/python -m test.pythoninfo + # script: + # # Skip tests that re-run the entire test suite. + # - xvfb-run ./venv/bin/python -m coverage run --pylib -m test --fail-env-changed -uall,-cpu -x test_multiprocessing_fork -x test_multiprocessing_forkserver -x test_multiprocessing_spawn -x test_concurrent_futures + # after_script: # Probably should be after_success once test suite updated to run under coverage.py. + # # Make the `coverage` command available to Codecov w/ a version of Python that can parse all source files. + # - source ./venv/bin/activate + # - make coverage-lcov + # - bash <(curl -s https://codecov.io/bash) before_install: From 21b3db012d963b8bbf1f0dbcbe22b1bd886a0cc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Wirtel?= Date: Thu, 11 Oct 2018 15:44:23 +0200 Subject: [PATCH 15/33] Fix with ellipsis --- Doc/library/multiprocessing.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst index a7d26f9b4554d7a..8402370d98f60a4 100644 --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -621,18 +621,19 @@ The :mod:`multiprocessing` package mostly replicates the API of the Example usage of some of the methods of :class:`Process`: .. doctest:: + :options: +ELLIPSIS >>> import multiprocessing, time, signal >>> p = multiprocessing.Process(target=time.sleep, args=(1000,)) >>> print(p, p.is_alive()) - False + False >>> p.start() >>> print(p, p.is_alive()) - True + True >>> p.terminate() >>> time.sleep(0.1) >>> print(p, p.is_alive()) - False + False >>> p.exitcode == -signal.SIGTERM True From 526f366217582b80c9ffc220648f66c671a23ca4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Wirtel?= Date: Thu, 11 Oct 2018 15:48:50 +0200 Subject: [PATCH 16/33] Disable the quiet flag of sphinx --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index d62d0cbb2729ed4..eb24b735cfcb2d8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -67,7 +67,7 @@ matrix: - cd Doc - python -m pip install sphinx blurb python-docs-theme script: - - xvfb-run make doctest SPHINXOPTS="-q -j4" + - xvfb-run make doctest SPHINXOPTS="-j4" #- os: osx # language: c # compiler: clang From 5764cdb0d4c3ad63e2bd7fe935dd33a87dd33152 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Wirtel?= Date: Thu, 11 Oct 2018 16:05:55 +0200 Subject: [PATCH 17/33] Merge the tests and execute doctests just after the build --- .travis.yml | 38 ++++++++++++++++---------------------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/.travis.yml b/.travis.yml index eb24b735cfcb2d8..c24e3049218af59 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,17 +33,22 @@ matrix: allow_failures: - env: OPTIONAL=true include: - #- os: linux - # language: c - # compiler: clang - # # gcc also works, but to keep the # of concurrent builds down, we use one C - # # compiler here and the other to run the coverage build. Clang is preferred - # # in this instance for its better error messages. - # env: TESTING=cpython - # addons: - # apt: - # packages: - # - xvfb + - os: linux + language: c + compiler: clang + # gcc also works, but to keep the # of concurrent builds down, we use one C + # compiler here and the other to run the coverage build. Clang is preferred + # in this instance for its better error messages. + env: TESTING=cpython + addons: + apt: + packages: + - xvfb + script: + - make + - cd Doc + - xvfb-run make PYTHON=../python SPHINXOPTS="-j4" venv doctest + #- os: linux # language: python # # Build the docs against a stable version of Python so code bugs don't hold up doc-related PRs. @@ -57,17 +62,6 @@ matrix: # - python -m pip install sphinx blurb python-docs-theme # script: # - make check suspicious html SPHINXOPTS="-q -W -j4" - - os: linux - language: python - python: 3.7 - dist: xenial - sudo: true - env: TESTING=docs - before_script: - - cd Doc - - python -m pip install sphinx blurb python-docs-theme - script: - - xvfb-run make doctest SPHINXOPTS="-j4" #- os: osx # language: c # compiler: clang From e500b599f68bd7c60cf7d950029ae2eae3d0f188 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Wirtel?= Date: Thu, 11 Oct 2018 16:23:07 +0200 Subject: [PATCH 18/33] Execute the doctests with the tests --- .travis.yml | 97 ++++++++++++++++++++++++++--------------------------- 1 file changed, 47 insertions(+), 50 deletions(-) diff --git a/.travis.yml b/.travis.yml index c24e3049218af59..c4125104ad3febd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -44,57 +44,54 @@ matrix: apt: packages: - xvfb - script: - - make + - os: linux + language: python + # Build the docs against a stable version of Python so code bugs don't hold up doc-related PRs. + python: 3.6 + env: TESTING=docs + before_script: - cd Doc - - xvfb-run make PYTHON=../python SPHINXOPTS="-j4" venv doctest - - #- os: linux - # language: python - # # Build the docs against a stable version of Python so code bugs don't hold up doc-related PRs. - # python: 3.6 - # env: TESTING=docs - # before_script: - # - cd Doc - # # Sphinx is pinned so that new versions that introduce new warnings won't suddenly cause build failures. - # # (Updating the version is fine as long as no warnings are raised by doing so.) - # # The theme used by the docs is stored seperately, so we need to install that as well. - # - python -m pip install sphinx blurb python-docs-theme - # script: - # - make check suspicious html SPHINXOPTS="-q -W -j4" - #- os: osx - # language: c - # compiler: clang - # # Testing under macOS is optional until testing stability has been demonstrated. - # env: OPTIONAL=true - # before_install: - # # Python 3 is needed for Argument Clinic and multissl - # - HOMEBREW_NO_AUTO_UPDATE=1 brew install xz python3 - # - export PATH=$(brew --prefix)/bin:$(brew --prefix)/sbin:$PATH - #- os: linux - # language: c - # compiler: gcc - # env: OPTIONAL=true - # addons: - # apt: - # packages: - # - lcov - # - xvfb - # before_script: - # - ./configure - # - make coverage -s -j4 - # # Need a venv that can parse covered code. - # - ./python -m venv venv - # - ./venv/bin/python -m pip install -U coverage - # - ./venv/bin/python -m test.pythoninfo - # script: - # # Skip tests that re-run the entire test suite. - # - xvfb-run ./venv/bin/python -m coverage run --pylib -m test --fail-env-changed -uall,-cpu -x test_multiprocessing_fork -x test_multiprocessing_forkserver -x test_multiprocessing_spawn -x test_concurrent_futures - # after_script: # Probably should be after_success once test suite updated to run under coverage.py. - # # Make the `coverage` command available to Codecov w/ a version of Python that can parse all source files. - # - source ./venv/bin/activate - # - make coverage-lcov - # - bash <(curl -s https://codecov.io/bash) + # Sphinx is pinned so that new versions that introduce new warnings won't suddenly cause build failures. + # (Updating the version is fine as long as no warnings are raised by doing so.) + # The theme used by the docs is stored seperately, so we need to install that as well. + - python -m pip install sphinx blurb python-docs-theme + script: + - make check suspicious html SPHINXOPTS="-q -W -j4" + - os: osx + language: c + compiler: clang + # Testing under macOS is optional until testing stability has been demonstrated. + env: OPTIONAL=true + before_install: + # Python 3 is needed for Argument Clinic and multissl + - HOMEBREW_NO_AUTO_UPDATE=1 brew install xz python3 + - export PATH=$(brew --prefix)/bin:$(brew --prefix)/sbin:$PATH + - os: linux + language: c + compiler: gcc + env: OPTIONAL=true + addons: + apt: + packages: + - lcov + - xvfb + before_script: + - ./configure + - make coverage -s -j4 + # Need a venv that can parse covered code. + - ./python -m venv venv + - ./venv/bin/python -m pip install -U coverage + - ./venv/bin/python -m test.pythoninfo + script: + # Skip tests that re-run the entire test suite. + - xvfb-run ./venv/bin/python -m coverage run --pylib -m test --fail-env-changed -uall,-cpu -x test_multiprocessing_fork -x test_multiprocessing_forkserver -x test_multiprocessing_spawn -x test_concurrent_futures + - xvfb-run make PYTHON=../python SPHINXOPTS="-j4" -C Doc/ venv doctest + + after_script: # Probably should be after_success once test suite updated to run under coverage.py. + # Make the `coverage` command available to Codecov w/ a version of Python that can parse all source files. + - source ./venv/bin/activate + - make coverage-lcov + - bash <(curl -s https://codecov.io/bash) before_install: From 1312c42a6ebbd7ccc0b6455a54701e120d5791c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Wirtel?= Date: Thu, 11 Oct 2018 16:41:54 +0200 Subject: [PATCH 19/33] reset --- .travis.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index c4125104ad3febd..d1a6da70e508b36 100644 --- a/.travis.yml +++ b/.travis.yml @@ -54,7 +54,7 @@ matrix: # Sphinx is pinned so that new versions that introduce new warnings won't suddenly cause build failures. # (Updating the version is fine as long as no warnings are raised by doing so.) # The theme used by the docs is stored seperately, so we need to install that as well. - - python -m pip install sphinx blurb python-docs-theme + - python -m pip install sphinx~=1.6.1 blurb python-docs-theme script: - make check suspicious html SPHINXOPTS="-q -W -j4" - os: osx @@ -85,8 +85,6 @@ matrix: script: # Skip tests that re-run the entire test suite. - xvfb-run ./venv/bin/python -m coverage run --pylib -m test --fail-env-changed -uall,-cpu -x test_multiprocessing_fork -x test_multiprocessing_forkserver -x test_multiprocessing_spawn -x test_concurrent_futures - - xvfb-run make PYTHON=../python SPHINXOPTS="-j4" -C Doc/ venv doctest - after_script: # Probably should be after_success once test suite updated to run under coverage.py. # Make the `coverage` command available to Codecov w/ a version of Python that can parse all source files. - source ./venv/bin/activate From a12dbe7342ffdf1f8e918e6c7eed10aef6f11731 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Wirtel?= Date: Thu, 11 Oct 2018 16:42:23 +0200 Subject: [PATCH 20/33] execute doctest --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index d1a6da70e508b36..c4125104ad3febd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -54,7 +54,7 @@ matrix: # Sphinx is pinned so that new versions that introduce new warnings won't suddenly cause build failures. # (Updating the version is fine as long as no warnings are raised by doing so.) # The theme used by the docs is stored seperately, so we need to install that as well. - - python -m pip install sphinx~=1.6.1 blurb python-docs-theme + - python -m pip install sphinx blurb python-docs-theme script: - make check suspicious html SPHINXOPTS="-q -W -j4" - os: osx @@ -85,6 +85,8 @@ matrix: script: # Skip tests that re-run the entire test suite. - xvfb-run ./venv/bin/python -m coverage run --pylib -m test --fail-env-changed -uall,-cpu -x test_multiprocessing_fork -x test_multiprocessing_forkserver -x test_multiprocessing_spawn -x test_concurrent_futures + - xvfb-run make PYTHON=../python SPHINXOPTS="-j4" -C Doc/ venv doctest + after_script: # Probably should be after_success once test suite updated to run under coverage.py. # Make the `coverage` command available to Codecov w/ a version of Python that can parse all source files. - source ./venv/bin/activate From 0ed453b1682517dd3c748a5dd3c883f171b2cbf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Wirtel?= Date: Thu, 11 Oct 2018 17:05:11 +0200 Subject: [PATCH 21/33] Execute doctest just after the tests --- .travis.yml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index c4125104ad3febd..a2e877368c4fbd7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -85,7 +85,6 @@ matrix: script: # Skip tests that re-run the entire test suite. - xvfb-run ./venv/bin/python -m coverage run --pylib -m test --fail-env-changed -uall,-cpu -x test_multiprocessing_fork -x test_multiprocessing_forkserver -x test_multiprocessing_spawn -x test_concurrent_futures - - xvfb-run make PYTHON=../python SPHINXOPTS="-j4" -C Doc/ venv doctest after_script: # Probably should be after_success once test suite updated to run under coverage.py. # Make the `coverage` command available to Codecov w/ a version of Python that can parse all source files. @@ -157,8 +156,14 @@ script: # Check that all symbols exported by libpython start with "Py" or "_Py" - make smelly # `-r -w` implicitly provided through `make buildbottest`. - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then XVFB_RUN=xvfb-run; fi; $XVFB_RUN make buildbottest TESTOPTS="-j4 -uall,-cpu" - + - | + if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then + XVFB_RUN=xvfb-run; + fi + $XVFB_RUN make buildbottest TESTOPTS="-j4 -uall,-cpu" + if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then + $XVFB_RUN make PYTHON=../python SPHINXOPTS="-q -W -j4" -C Doc/ venv doctest + fi notifications: email: false webhooks: From be41d1c37961c600075cfd1e78cc6c21acb4367f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Wirtel?= Date: Thu, 11 Oct 2018 17:09:07 +0200 Subject: [PATCH 22/33] pin the version of sphinx --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a2e877368c4fbd7..e0233dd233caefa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -54,7 +54,7 @@ matrix: # Sphinx is pinned so that new versions that introduce new warnings won't suddenly cause build failures. # (Updating the version is fine as long as no warnings are raised by doing so.) # The theme used by the docs is stored seperately, so we need to install that as well. - - python -m pip install sphinx blurb python-docs-theme + - python -m pip install sphinx~=1.6.1 blurb python-docs-theme script: - make check suspicious html SPHINXOPTS="-q -W -j4" - os: osx From f8238a4219762ff94d2f20b72ad038950e77521c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Wirtel?= Date: Thu, 11 Oct 2018 17:29:18 +0200 Subject: [PATCH 23/33] Reuse >>> for the doctests --- Doc/library/unittest.mock-examples.rst | 107 ++++++++++++------------- 1 file changed, 53 insertions(+), 54 deletions(-) diff --git a/Doc/library/unittest.mock-examples.rst b/Doc/library/unittest.mock-examples.rst index 4b300c6f32e630f..4588b2d8929e36e 100644 --- a/Doc/library/unittest.mock-examples.rst +++ b/Doc/library/unittest.mock-examples.rst @@ -112,17 +112,17 @@ by looking at the return value of the mocked class. In the example below we have a function ``some_function`` that instantiates ``Foo`` and calls a method on it. The call to :func:`patch` replaces the class ``Foo`` with a mock. The ``Foo`` instance is the result of calling the mock, so it is configured -by modifying the mock :attr:`~Mock.return_value`.:: +by modifying the mock :attr:`~Mock.return_value`. :: - def some_function(): - instance = module.Foo() - return instance.method() - - with patch('module.Foo') as mock: - instance = mock.return_value - instance.method.return_value = 'the result' - result = some_function() - assert result == 'the result' + >>> def some_function(): + ... instance = module.Foo() + ... return instance.method() + ... + >>> with patch('module.Foo') as mock: + ... instance = mock.return_value + ... instance.method.return_value = 'the result' + ... result = some_function() + ... assert result == 'the result' Naming your mocks @@ -500,26 +500,26 @@ response object for it. To set the response as the return value for that final We can do that in a slightly nicer way using the :meth:`~Mock.configure_mock` method to directly set the return value for us:: - something = Something() - mock_response = Mock(spec=open) - mock_backend = Mock() - config = {'get_endpoint.return_value.create_call.return_value.start_call.return_value': mock_response} - mock_backend.configure_mock(**config) + >>> something = Something() + >>> mock_response = Mock(spec=open) + >>> mock_backend = Mock() + >>> config = {'get_endpoint.return_value.create_call.return_value.start_call.return_value': mock_response} + >>> mock_backend.configure_mock(**config) With these we monkey patch the "mock backend" in place and can make the real call: :: - something.backend = mock_backend - something.method() + >>> something.backend = mock_backend + >>> something.method() Using :attr:`~Mock.mock_calls` we can check the chained call with a single assert. A chained call is several calls in one line of code, so there will be several entries in ``mock_calls``. We can use :meth:`call.call_list` to create this list of calls for us: :: - chained = call.get_endpoint('foobar').create_call('spam', 'eggs').start_call() - call_list = chained.call_list() - assert mock_backend.mock_calls == call_list + >>> chained = call.get_endpoint('foobar').create_call('spam', 'eggs').start_call() + >>> call_list = chained.call_list() + >>> assert mock_backend.mock_calls == call_list Partial mocking @@ -540,13 +540,13 @@ attribute on the mock date class is then set to a lambda function that returns a real date. When the mock date class is called a real date will be constructed and returned by ``side_effect``. :: - from datetime import date - with patch('mymodule.date') as mock_date: - mock_date.today.return_value = date(2010, 10, 8) - mock_date.side_effect = lambda *args, **kw: date(*args, **kw) - - assert mymodule.date.today() == date(2010, 10, 8) - assert mymodule.date(2009, 6, 8) == date(2009, 6, 8) + >>> from datetime import date + >>> with patch('mymodule.date') as mock_date: + ... mock_date.today.return_value = date(2010, 10, 8) + ... mock_date.side_effect = lambda *args, **kw: date(*args, **kw) + ... + ... assert mymodule.date.today() == date(2010, 10, 8) + ... assert mymodule.date(2009, 6, 8) == date(2009, 6, 8) Note that we don't patch :class:`datetime.date` globally, we patch ``date`` in the module that *uses* it. See :ref:`where to patch `. @@ -1125,44 +1125,43 @@ arbitrary attribute of a mock creates a child mock, we can create our separate mocks from a parent one. Calls to those child mock will then all be recorded, in order, in the ``mock_calls`` of the parent: - >>> manager = Mock() - >>> mock_foo = manager.foo - >>> mock_bar = manager.bar + >>> manager = Mock() + >>> mock_foo = manager.foo + >>> mock_bar = manager.bar - >>> mock_foo.something() - - >>> mock_bar.other.thing() - + >>> mock_foo.something() + + >>> mock_bar.other.thing() + - >>> manager.mock_calls - [call.foo.something(), call.bar.other.thing()] + >>> manager.mock_calls + [call.foo.something(), call.bar.other.thing()] We can then assert about the calls, including the order, by comparing with the ``mock_calls`` attribute on the manager mock: - >>> expected_calls = [call.foo.something(), call.bar.other.thing()] - >>> manager.mock_calls == expected_calls - True + >>> expected_calls = [call.foo.something(), call.bar.other.thing()] + >>> manager.mock_calls == expected_calls + True If ``patch`` is creating, and putting in place, your mocks then you can attach them to a manager mock using the :meth:`~Mock.attach_mock` method. After attaching calls will be recorded in ``mock_calls`` of the manager. :: - manager = MagicMock() - with patch('mymodule.Class1') as MockClass1: - with patch('mymodule.Class2') as MockClass2: - manager.attach_mock(MockClass1, 'MockClass1') - manager.attach_mock(MockClass2, 'MockClass2') - MockClass1().foo() - MockClass2().bar() - - - - >>> manager.mock_calls - [call.MockClass1(), - call.MockClass1().foo(), - call.MockClass2(), - call.MockClass2().bar()] + >>> manager = MagicMock() + >>> with patch('mymodule.Class1') as MockClass1: + ... with patch('mymodule.Class2') as MockClass2: + ... manager.attach_mock(MockClass1, 'MockClass1') + ... manager.attach_mock(MockClass2, 'MockClass2') + ... MockClass1().foo() + ... MockClass2().bar() + + + >>> manager.mock_calls + [call.MockClass1(), + call.MockClass1().foo(), + call.MockClass2(), + call.MockClass2().bar()] If many calls have been made, but you're only interested in a particular sequence of them then an alternative is to use the From e5f6478d9975f393e27c4338c137273edb1c738c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Wirtel?= Date: Thu, 11 Oct 2018 21:36:52 +0200 Subject: [PATCH 24/33] Pass the tests if tkinter is not installed --- Doc/conf.py | 7 ++++ Doc/library/turtle.rst | 82 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+) diff --git a/Doc/conf.py b/Doc/conf.py index 7f720ce3832de26..6060ac176c95f3e 100644 --- a/Doc/conf.py +++ b/Doc/conf.py @@ -16,6 +16,13 @@ extensions = ['sphinx.ext.coverage', 'sphinx.ext.doctest', 'pyspecific', 'c_annotations', 'escape4chm'] + +doctest_global_setup = ''' +try: + import _tkinter +except ImportError: + _tkinter = None +''' # General substitutions. project = 'Python' copyright = '2001-%s, Python Software Foundation' % time.strftime('%Y') diff --git a/Doc/library/turtle.rst b/Doc/library/turtle.rst index 595a244342c44bb..83903648b4274c1 100644 --- a/Doc/library/turtle.rst +++ b/Doc/library/turtle.rst @@ -250,6 +250,7 @@ Turtle motion turtle is headed. .. doctest:: + :skipif: _tkinter is None >>> turtle.position() (0.00,0.00) @@ -276,6 +277,7 @@ Turtle motion >>> turtle.goto(0, 0) .. doctest:: + :skipif: _tkinter is None >>> turtle.position() (0.00,0.00) @@ -294,11 +296,13 @@ Turtle motion orientation depends on the turtle mode, see :func:`mode`. .. doctest:: + :skipif: _tkinter is None :hide: >>> turtle.setheading(22) .. doctest:: + :skipif: _tkinter is None >>> turtle.heading() 22.0 @@ -317,11 +321,13 @@ Turtle motion orientation depends on the turtle mode, see :func:`mode`. .. doctest:: + :skipif: _tkinter is None :hide: >>> turtle.setheading(22) .. doctest:: + :skipif: _tkinter is None >>> turtle.heading() 22.0 @@ -344,11 +350,13 @@ Turtle motion not change the turtle's orientation. .. doctest:: + :skipif: _tkinter is None :hide: >>> turtle.goto(0, 0) .. doctest:: + :skipif: _tkinter is None >>> tp = turtle.pos() >>> tp @@ -372,11 +380,13 @@ Turtle motion unchanged. .. doctest:: + :skipif: _tkinter is None :hide: >>> turtle.goto(0, 240) .. doctest:: + :skipif: _tkinter is None >>> turtle.position() (0.00,240.00) @@ -392,11 +402,13 @@ Turtle motion Set the turtle's second coordinate to *y*, leave first coordinate unchanged. .. doctest:: + :skipif: _tkinter is None :hide: >>> turtle.goto(0, 40) .. doctest:: + :skipif: _tkinter is None >>> turtle.position() (0.00,40.00) @@ -423,6 +435,7 @@ Turtle motion =================== ==================== .. doctest:: + :skipif: _tkinter is None >>> turtle.setheading(90) >>> turtle.heading() @@ -435,12 +448,14 @@ Turtle motion its start-orientation (which depends on the mode, see :func:`mode`). .. doctest:: + :skipif: _tkinter is None :hide: >>> turtle.setheading(90) >>> turtle.goto(0, -10) .. doctest:: + :skipif: _tkinter is None >>> turtle.heading() 90.0 @@ -472,6 +487,7 @@ Turtle motion calculated automatically. May be used to draw regular polygons. .. doctest:: + :skipif: _tkinter is None >>> turtle.home() >>> turtle.position() @@ -500,6 +516,7 @@ Turtle motion .. doctest:: + :skipif: _tkinter is None >>> turtle.home() >>> turtle.dot() @@ -517,6 +534,7 @@ Turtle motion it by calling ``clearstamp(stamp_id)``. .. doctest:: + :skipif: _tkinter is None >>> turtle.color("blue") >>> turtle.stamp() @@ -532,6 +550,7 @@ Turtle motion Delete stamp with given *stampid*. .. doctest:: + :skipif: _tkinter is None >>> turtle.position() (150.00,-0.00) @@ -576,6 +595,7 @@ Turtle motion undo actions is determined by the size of the undobuffer. .. doctest:: + :skipif: _tkinter is None >>> for i in range(4): ... turtle.fd(50); turtle.lt(80) @@ -608,6 +628,7 @@ Turtle motion turtle turn instantly. .. doctest:: + :skipif: _tkinter is None >>> turtle.speed() 3 @@ -628,6 +649,7 @@ Tell Turtle's state Return the turtle's current location (x,y) (as a :class:`Vec2D` vector). .. doctest:: + :skipif: _tkinter is None >>> turtle.pos() (440.00,-0.00) @@ -643,6 +665,7 @@ Tell Turtle's state orientation which depends on the mode - "standard"/"world" or "logo"). .. doctest:: + :skipif: _tkinter is None >>> turtle.goto(10, 10) >>> turtle.towards(0,0) @@ -654,6 +677,7 @@ Tell Turtle's state Return the turtle's x coordinate. .. doctest:: + :skipif: _tkinter is None >>> turtle.home() >>> turtle.left(50) @@ -669,6 +693,7 @@ Tell Turtle's state Return the turtle's y coordinate. .. doctest:: + :skipif: _tkinter is None >>> turtle.home() >>> turtle.left(60) @@ -685,6 +710,7 @@ Tell Turtle's state :func:`mode`). .. doctest:: + :skipif: _tkinter is None >>> turtle.home() >>> turtle.left(67) @@ -701,6 +727,7 @@ Tell Turtle's state other turtle, in turtle step units. .. doctest:: + :skipif: _tkinter is None >>> turtle.home() >>> turtle.distance(30,40) @@ -724,6 +751,7 @@ Settings for measurement Default value is 360 degrees. .. doctest:: + :skipif: _tkinter is None >>> turtle.home() >>> turtle.left(90) @@ -746,6 +774,7 @@ Settings for measurement ``degrees(2*math.pi)``. .. doctest:: + :skipif: _tkinter is None >>> turtle.home() >>> turtle.left(90) @@ -756,6 +785,7 @@ Settings for measurement 1.5707963267948966 .. doctest:: + :skipif: _tkinter is None :hide: >>> turtle.degrees(360) @@ -791,6 +821,7 @@ Drawing state thickness. If no argument is given, the current pensize is returned. .. doctest:: + :skipif: _tkinter is None >>> turtle.pensize() 1 @@ -822,6 +853,7 @@ Drawing state attributes in one statement. .. doctest:: + :skipif: _tkinter is None :options: +NORMALIZE_WHITESPACE >>> turtle.pen(fillcolor="black", pencolor="red", pensize=10) @@ -844,6 +876,7 @@ Drawing state Return ``True`` if pen is down, ``False`` if it's up. .. doctest:: + :skipif: _tkinter is None >>> turtle.penup() >>> turtle.isdown() @@ -884,6 +917,7 @@ Color control newly set pencolor. .. doctest:: + :skipif: _tkinter is None >>> colormode() 1.0 @@ -932,6 +966,7 @@ Color control with the newly set fillcolor. .. doctest:: + :skipif: _tkinter is None >>> turtle.fillcolor("violet") >>> turtle.fillcolor() @@ -970,6 +1005,7 @@ Color control with the newly set colors. .. doctest:: + :skipif: _tkinter is None >>> turtle.color("red", "green") >>> turtle.color() @@ -986,6 +1022,7 @@ Filling ~~~~~~~ .. doctest:: + :skipif: _tkinter is None :hide: >>> turtle.home() @@ -995,6 +1032,7 @@ Filling Return fillstate (``True`` if filling, ``False`` else). .. doctest:: + :skipif: _tkinter is None >>> turtle.begin_fill() >>> if turtle.filling(): @@ -1014,6 +1052,7 @@ Filling Fill the shape drawn after the last call to :func:`begin_fill`. .. doctest:: + :skipif: _tkinter is None >>> turtle.color("black", "red") >>> turtle.begin_fill() @@ -1030,6 +1069,7 @@ More drawing control variables to the default values. .. doctest:: + :skipif: _tkinter is None >>> turtle.goto(0,-22) >>> turtle.left(100) @@ -1080,6 +1120,7 @@ Visibility drawing observably. .. doctest:: + :skipif: _tkinter is None >>> turtle.hideturtle() @@ -1090,6 +1131,7 @@ Visibility Make the turtle visible. .. doctest:: + :skipif: _tkinter is None >>> turtle.showturtle() @@ -1120,6 +1162,7 @@ Appearance deal with shapes see Screen method :func:`register_shape`. .. doctest:: + :skipif: _tkinter is None >>> turtle.shape() 'classic' @@ -1145,6 +1188,7 @@ Appearance resizemode("user") is called by :func:`shapesize` when used with arguments. .. doctest:: + :skipif: _tkinter is None >>> turtle.resizemode() 'noresize' @@ -1168,6 +1212,7 @@ Appearance of the shapes's outline. .. doctest:: + :skipif: _tkinter is None >>> turtle.shapesize() (1.0, 1.0, 1) @@ -1192,6 +1237,7 @@ Appearance heading of the turtle are sheared. .. doctest:: + :skipif: _tkinter is None >>> turtle.shape("circle") >>> turtle.shapesize(5,2) @@ -1208,6 +1254,7 @@ Appearance change the turtle's heading (direction of movement). .. doctest:: + :skipif: _tkinter is None >>> turtle.reset() >>> turtle.shape("circle") @@ -1227,6 +1274,7 @@ Appearance (direction of movement). .. doctest:: + :skipif: _tkinter is None >>> turtle.reset() >>> turtle.shape("circle") @@ -1252,6 +1300,7 @@ Appearance turtle (its direction of movement). .. doctest:: + :skipif: _tkinter is None >>> turtle.reset() >>> turtle.shape("circle") @@ -1280,6 +1329,7 @@ Appearance given matrix. .. doctest:: + :skipif: _tkinter is None >>> turtle = Turtle() >>> turtle.shape("square") @@ -1295,6 +1345,7 @@ Appearance can be used to define a new shape or components of a compound shape. .. doctest:: + :skipif: _tkinter is None >>> turtle.shape("square") >>> turtle.shapetransform(4, -1, 0, 2) @@ -1318,6 +1369,7 @@ Using events procedural way: .. doctest:: + :skipif: _tkinter is None >>> def turn(x, y): ... left(180) @@ -1338,6 +1390,7 @@ Using events ``None``, existing bindings are removed. .. doctest:: + :skipif: _tkinter is None >>> class MyTurtle(Turtle): ... def glow(self,x,y): @@ -1365,6 +1418,7 @@ Using events mouse-click event on that turtle. .. doctest:: + :skipif: _tkinter is None >>> turtle.ondrag(turtle.goto) @@ -1392,6 +1446,7 @@ Special Turtle methods Return the last recorded polygon. .. doctest:: + :skipif: _tkinter is None >>> turtle.home() >>> turtle.begin_poly() @@ -1411,6 +1466,7 @@ Special Turtle methods turtle properties. .. doctest:: + :skipif: _tkinter is None >>> mick = Turtle() >>> joe = mick.clone() @@ -1423,6 +1479,7 @@ Special Turtle methods return the "anonymous turtle": .. doctest:: + :skipif: _tkinter is None >>> pet = getturtle() >>> pet.fd(50) @@ -1436,6 +1493,7 @@ Special Turtle methods TurtleScreen methods can then be called for that object. .. doctest:: + :skipif: _tkinter is None >>> ts = turtle.getscreen() >>> ts @@ -1453,6 +1511,7 @@ Special Turtle methods ``None``, the undobuffer is disabled. .. doctest:: + :skipif: _tkinter is None >>> turtle.setundobuffer(42) @@ -1462,6 +1521,7 @@ Special Turtle methods Return number of entries in the undobuffer. .. doctest:: + :skipif: _tkinter is None >>> while undobufferentries(): ... undo() @@ -1484,6 +1544,7 @@ below: For example: .. doctest:: + :skipif: _tkinter is None >>> s = Shape("compound") >>> poly1 = ((0,0),(10,-5),(0,10),(-10,-5)) @@ -1494,6 +1555,7 @@ below: 3. Now add the Shape to the Screen's shapelist and use it: .. doctest:: + :skipif: _tkinter is None >>> register_shape("myshape", s) >>> shape("myshape") @@ -1513,6 +1575,7 @@ Most of the examples in this section refer to a TurtleScreen instance called ``screen``. .. doctest:: + :skipif: _tkinter is None :hide: >>> screen = Screen() @@ -1529,6 +1592,7 @@ Window control Set or return background color of the TurtleScreen. .. doctest:: + :skipif: _tkinter is None >>> screen.bgcolor("orange") >>> screen.bgcolor() @@ -1614,6 +1678,7 @@ Window control distorted. .. doctest:: + :skipif: _tkinter is None >>> screen.reset() >>> screen.setworldcoordinates(-50,-7.5,50,7.5) @@ -1624,6 +1689,7 @@ Window control ... left(45); fd(2) # a regular octagon .. doctest:: + :skipif: _tkinter is None :hide: >>> screen.reset() @@ -1645,6 +1711,7 @@ Animation control Optional argument: .. doctest:: + :skipif: _tkinter is None >>> screen.delay() 10 @@ -1666,6 +1733,7 @@ Animation control :func:`delay`). .. doctest:: + :skipif: _tkinter is None >>> screen.tracer(8, 25) >>> dist = 2 @@ -1702,6 +1770,7 @@ Using screen events must have the focus. (See method :func:`listen`.) .. doctest:: + :skipif: _tkinter is None >>> def f(): ... fd(50) @@ -1722,6 +1791,7 @@ Using screen events must have focus. (See method :func:`listen`.) .. doctest:: + :skipif: _tkinter is None >>> def f(): ... fd(50) @@ -1746,6 +1816,7 @@ Using screen events named turtle: .. doctest:: + :skipif: _tkinter is None >>> screen.onclick(turtle.goto) # Subsequently clicking into the TurtleScreen will >>> # make the turtle move to the clicked point. @@ -1765,6 +1836,7 @@ Using screen events Install a timer that calls *fun* after *t* milliseconds. .. doctest:: + :skipif: _tkinter is None >>> running = True >>> def f(): @@ -1846,6 +1918,7 @@ Settings and special methods ============ ========================= =================== .. doctest:: + :skipif: _tkinter is None >>> mode("logo") # resets turtle heading to north >>> mode() @@ -1860,6 +1933,7 @@ Settings and special methods values of color triples have to be in the range 0..\ *cmode*. .. doctest:: + :skipif: _tkinter is None >>> screen.colormode(1) >>> turtle.pencolor(240, 160, 80) @@ -1880,6 +1954,7 @@ Settings and special methods do with a Tkinter Canvas. .. doctest:: + :skipif: _tkinter is None >>> cv = screen.getcanvas() >>> cv @@ -1891,6 +1966,7 @@ Settings and special methods Return a list of names of all currently available turtle shapes. .. doctest:: + :skipif: _tkinter is None >>> screen.getshapes() ['arrow', 'blank', 'circle', ..., 'turtle'] @@ -1914,6 +1990,7 @@ Settings and special methods coordinates: Install the corresponding polygon shape. .. doctest:: + :skipif: _tkinter is None >>> screen.register_shape("triangle", ((5,-3), (0,5), (-5,-3))) @@ -1929,6 +2006,7 @@ Settings and special methods Return the list of turtles on the screen. .. doctest:: + :skipif: _tkinter is None >>> for turtle in screen.turtles(): ... turtle.color("red") @@ -1990,6 +2068,7 @@ Methods specific to Screen, not inherited from TurtleScreen center window vertically .. doctest:: + :skipif: _tkinter is None >>> screen.setup (width=200, height=200, startx=0, starty=0) >>> # sets window to 200x200 pixels, in upper left of screen @@ -2005,6 +2084,7 @@ Methods specific to Screen, not inherited from TurtleScreen Set title of turtle window to *titlestring*. .. doctest:: + :skipif: _tkinter is None >>> screen.title("Welcome to the turtle zoo!") @@ -2075,6 +2155,7 @@ Public classes Example: .. doctest:: + :skipif: _tkinter is None >>> poly = ((0,0),(10,-5),(0,10),(-10,-5)) >>> s = Shape("compound") @@ -2421,6 +2502,7 @@ Changes since Python 3.0 .. doctest:: + :skipif: _tkinter is None :hide: >>> for turtle in turtles(): From 9d14da29e65294f30bdfac079b286670b166b2c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Wirtel?= Date: Thu, 11 Oct 2018 22:07:14 +0200 Subject: [PATCH 25/33] Rename duplicated ref to a new ref --- Doc/distutils/examples.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/distutils/examples.rst b/Doc/distutils/examples.rst index 4e2761d8a7d0460..f81e06b5e60578a 100644 --- a/Doc/distutils/examples.rst +++ b/Doc/distutils/examples.rst @@ -1,4 +1,4 @@ -.. _examples: +.. _distutils_examples: ******** Examples From bece51b5e2ee6f8cd2f1ba13f68c8b9ac272124d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Wirtel?= Date: Thu, 11 Oct 2018 22:07:53 +0200 Subject: [PATCH 26/33] Use the last version of sphinx --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index e0233dd233caefa..a2e877368c4fbd7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -54,7 +54,7 @@ matrix: # Sphinx is pinned so that new versions that introduce new warnings won't suddenly cause build failures. # (Updating the version is fine as long as no warnings are raised by doing so.) # The theme used by the docs is stored seperately, so we need to install that as well. - - python -m pip install sphinx~=1.6.1 blurb python-docs-theme + - python -m pip install sphinx blurb python-docs-theme script: - make check suspicious html SPHINXOPTS="-q -W -j4" - os: osx From 8263dee8f069810a12339fcd9e35e599aee72550 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Wirtel?= Date: Thu, 11 Oct 2018 22:34:49 +0200 Subject: [PATCH 27/33] Add News entry --- Misc/NEWS.d/next/Tests/2018-10-11-22-34-27.bpo-34962.0PLBi8.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Tests/2018-10-11-22-34-27.bpo-34962.0PLBi8.rst diff --git a/Misc/NEWS.d/next/Tests/2018-10-11-22-34-27.bpo-34962.0PLBi8.rst b/Misc/NEWS.d/next/Tests/2018-10-11-22-34-27.bpo-34962.0PLBi8.rst new file mode 100644 index 000000000000000..0d0f6a1ff77e526 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2018-10-11-22-34-27.bpo-34962.0PLBi8.rst @@ -0,0 +1 @@ +make docstest in Doc now passes., and is enforced in CI From e47a624ef979ab47356590f4cbb81952fa3e3039 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Wirtel?= Date: Thu, 11 Oct 2018 23:58:27 +0200 Subject: [PATCH 28/33] fix typo: seperately -> separately --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a2e877368c4fbd7..d210f200d8fcafb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -53,7 +53,7 @@ matrix: - cd Doc # Sphinx is pinned so that new versions that introduce new warnings won't suddenly cause build failures. # (Updating the version is fine as long as no warnings are raised by doing so.) - # The theme used by the docs is stored seperately, so we need to install that as well. + # The theme used by the docs is stored separately, so we need to install that as well. - python -m pip install sphinx blurb python-docs-theme script: - make check suspicious html SPHINXOPTS="-q -W -j4" From 40f850cebcb444a92646e4e15e26009c4c984caf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Wirtel?= Date: Fri, 12 Oct 2018 00:01:47 +0200 Subject: [PATCH 29/33] fix ': ::' to '::' --- Doc/library/re.rst | 4 +-- Doc/library/unittest.mock-examples.rst | 20 ++++++------ Doc/library/unittest.mock.rst | 42 +++++++++++++------------- 3 files changed, 33 insertions(+), 33 deletions(-) diff --git a/Doc/library/re.rst b/Doc/library/re.rst index 65acc8b9e9c4846..67f85705169beda 100644 --- a/Doc/library/re.rst +++ b/Doc/library/re.rst @@ -1234,7 +1234,7 @@ Checking for a Pair ^^^^^^^^^^^^^^^^^^^ In this example, we'll use the following helper function to display match -objects a little more gracefully: :: +objects a little more gracefully:: def displaymatch(match): if match is None: @@ -1267,7 +1267,7 @@ To match this with a regular expression, one could use backreferences as such:: "" To find out what card the pair consists of, one could use the -:meth:`~Match.group` method of the match object in the following manner: :: +:meth:`~Match.group` method of the match object in the following manner:: >>> pair = re.compile(r".*(.).*\1") >>> pair.match("717ak").group(1) diff --git a/Doc/library/unittest.mock-examples.rst b/Doc/library/unittest.mock-examples.rst index 4588b2d8929e36e..7f454ac0730a86e 100644 --- a/Doc/library/unittest.mock-examples.rst +++ b/Doc/library/unittest.mock-examples.rst @@ -334,7 +334,7 @@ whatever) to be replaced with. 'patch.object' takes an object and the name of the attribute you would like patched, plus optionally the value to patch it with. -``patch.object``: :: +``patch.object``:: >>> original = SomeClass.attribute >>> @patch.object(SomeClass, 'attribute', sentinel.attribute) @@ -361,7 +361,7 @@ instead of :func:`patch.object`: >>> mock.assert_called_with('filename', 'r') >>> assert handle == sentinel.file_handle, "incorrect file handle returned" -The module name can be 'dotted', in the form ``package.module`` if needed: :: +The module name can be 'dotted', in the form ``package.module`` if needed:: >>> @patch('package.module.ClassName.attribute', sentinel.attribute) ... def test(): @@ -393,7 +393,7 @@ passed into the test function / method: ... >>> MyTest('test_something').test_something() -You can stack up multiple patch decorators using this pattern: :: +You can stack up multiple patch decorators using this pattern:: >>> class MyTest(unittest.TestCase): ... @patch('package.module.ClassName1') @@ -507,7 +507,7 @@ method to directly set the return value for us:: >>> mock_backend.configure_mock(**config) With these we monkey patch the "mock backend" in place and can make the real -call: :: +call:: >>> something.backend = mock_backend >>> something.method() @@ -515,7 +515,7 @@ call: :: Using :attr:`~Mock.mock_calls` we can check the chained call with a single assert. A chained call is several calls in one line of code, so there will be several entries in ``mock_calls``. We can use :meth:`call.call_list` to create -this list of calls for us: :: +this list of calls for us:: >>> chained = call.get_endpoint('foobar').create_call('spam', 'eggs').start_call() >>> call_list = chained.call_list() @@ -612,7 +612,7 @@ is to apply the patch decorators to every method. This can feel like unnecessary repetition. For Python 2.6 or more recent you can use :func:`patch` (in all its various forms) as a class decorator. This applies the patches to all test methods on the class. A test method is identified by methods whose names start -with ``test``: :: +with ``test``:: >>> @patch('mymodule.SomeClass') ... class MyTest(unittest.TestCase): @@ -651,7 +651,7 @@ These allow you to move the patching into your ``setUp`` and ``tearDown`` method If you use this technique you must ensure that the patching is "undone" by calling ``stop``. This can be fiddlier than you might think, because if an exception is raised in the setUp then tearDown is not called. -:meth:`unittest.TestCase.addCleanup` makes this easier: :: +:meth:`unittest.TestCase.addCleanup` makes this easier:: >>> class MyTest(unittest.TestCase): ... def setUp(self): @@ -766,7 +766,7 @@ defined in 'mymodule':: val.clear() When we try to test that ``grob`` calls ``frob`` with the correct argument look -what happens: :: +what happens:: >>> with patch('mymodule.frob') as mock_frob: ... val = {6} @@ -867,7 +867,7 @@ Nesting Patches Using patch as a context manager is nice, but if you do multiple patches you can end up with nested with statements indenting further and further to the -right: :: +right:: >>> class MyTest(unittest.TestCase): ... @@ -886,7 +886,7 @@ right: :: With unittest ``cleanup`` functions and the :ref:`start-and-stop` we can achieve the same effect without the nested indentation. A simple helper method, ``create_patch``, puts the patch in place and returns the created mock -for us: :: +for us:: >>> class MyTest(unittest.TestCase): ... diff --git a/Doc/library/unittest.mock.rst b/Doc/library/unittest.mock.rst index fc1daf2331dfceb..f99b7c44e743fa6 100644 --- a/Doc/library/unittest.mock.rst +++ b/Doc/library/unittest.mock.rst @@ -96,7 +96,7 @@ that don't exist on the spec will fail with an :exc:`AttributeError`. The :func:`patch` decorator / context manager makes it easy to mock classes or objects in a module under test. The object you specify will be replaced with a -mock (or other object) during the test and restored when the test ends: :: +mock (or other object) during the test and restored when the test ends:: >>> from unittest.mock import patch >>> @patch('module.ClassName2') @@ -1023,7 +1023,7 @@ the "parenting" if for some reason you don't want it to happen. Mocks created for you by :func:`patch` are automatically given names. To attach mocks that have names to a parent you use the :meth:`~Mock.attach_mock` -method: :: +method:: >>> thing1 = object() >>> thing2 = object() @@ -1139,7 +1139,7 @@ patch available for alternate use-cases. :func:`patch` as function decorator, creating the mock for you and passing it into -the decorated function: :: +the decorated function:: >>> @patch('__main__.SomeClass') ... def function(normal_argument, mock_class): @@ -1157,7 +1157,7 @@ If the class is instantiated multiple times you could use can set the *return_value* to be anything you want. To configure return values on methods of *instances* on the patched class -you must do this on the :attr:`return_value`. For example: :: +you must do this on the :attr:`return_value`. For example:: >>> class Class: ... def method(self): @@ -1182,7 +1182,7 @@ return value of the created mock will have the same spec. :: The *new_callable* argument is useful where you want to use an alternative class to the default :class:`MagicMock` for the created mock. For example, if -you wanted a :class:`NonCallableMock` to be used: :: +you wanted a :class:`NonCallableMock` to be used:: >>> thing = object() >>> with patch('__main__.thing', new_callable=NonCallableMock) as mock_thing: @@ -1193,7 +1193,7 @@ you wanted a :class:`NonCallableMock` to be used: :: ... TypeError: 'NonCallableMock' object is not callable -Another use case might be to replace an object with an :class:`io.StringIO` instance: :: +Another use case might be to replace an object with an :class:`io.StringIO` instance:: >>> from io import StringIO >>> def foo(): @@ -1209,7 +1209,7 @@ Another use case might be to replace an object with an :class:`io.StringIO` inst When :func:`patch` is creating a mock for you, it is common that the first thing you need to do is to configure the mock. Some of that configuration can be done in the call to patch. Any arbitrary keywords you pass into the call will be -used to set attributes on the created mock: :: +used to set attributes on the created mock:: >>> patcher = patch('__main__.thing', first='one', second='two') >>> mock_thing = patcher.start() @@ -1222,7 +1222,7 @@ As well as attributes on the created mock attributes, like the :attr:`~Mock.return_value` and :attr:`~Mock.side_effect`, of child mocks can also be configured. These aren't syntactically valid to pass in directly as keyword arguments, but a dictionary with these as keys can still be expanded -into a :func:`patch` call using ``**``: :: +into a :func:`patch` call using ``**``:: >>> config = {'method.return_value': 3, 'other.side_effect': KeyError} >>> patcher = patch('__main__.thing', **config) @@ -1394,7 +1394,7 @@ then the created mocks are passed into the decorated function by keyword. :: >>> test_function() :func:`patch.multiple` can be nested with other ``patch`` decorators, but put arguments -passed by keyword *after* any of the standard arguments created by :func:`patch`: :: +passed by keyword *after* any of the standard arguments created by :func:`patch`:: >>> @patch('sys.exit') ... @patch.multiple('__main__', thing=DEFAULT, other=DEFAULT) @@ -1406,7 +1406,7 @@ passed by keyword *after* any of the standard arguments created by :func:`patch` >>> test_function() If :func:`patch.multiple` is used as a context manager, the value returned by the -context manger is a dictionary where created mocks are keyed by name: :: +context manger is a dictionary where created mocks are keyed by name:: >>> with patch.multiple('__main__', thing=DEFAULT, other=DEFAULT) as values: ... assert 'other' in repr(values['other']) @@ -1444,7 +1444,7 @@ the call to ``patcher.start``. :: A typical use case for this might be for doing multiple patches in the ``setUp`` -method of a :class:`TestCase`: :: +method of a :class:`TestCase`:: >>> class MyTest(unittest.TestCase): ... def setUp(self): @@ -1468,7 +1468,7 @@ method of a :class:`TestCase`: :: If you use this technique you must ensure that the patching is "undone" by calling ``stop``. This can be fiddlier than you might think, because if an exception is raised in the ``setUp`` then ``tearDown`` is not called. - :meth:`unittest.TestCase.addCleanup` makes this easier: :: + :meth:`unittest.TestCase.addCleanup` makes this easier:: >>> class MyTest(unittest.TestCase): ... def setUp(self): @@ -1496,7 +1496,7 @@ It is also possible to stop all patches which have been started by using patch builtins ~~~~~~~~~~~~~~ You can patch any builtins within a module. The following example patches -builtin :func:`ord`: :: +builtin :func:`ord`:: >>> @patch('__main__.ord') ... def test(mock_ord): @@ -1516,7 +1516,7 @@ start with ``'test'`` as being test methods. This is the same way that the :class:`unittest.TestLoader` finds test methods by default. It is possible that you want to use a different prefix for your tests. You can -inform the patchers of the different prefix by setting ``patch.TEST_PREFIX``: :: +inform the patchers of the different prefix by setting ``patch.TEST_PREFIX``:: >>> patch.TEST_PREFIX = 'foo' >>> value = 3 @@ -2157,7 +2157,7 @@ enough that a helper function is useful. :: >>> handle = m() >>> handle.write.assert_called_once_with('some stuff') -And for reading files: :: +And for reading files:: >>> with patch('__main__.open', mock_open(read_data='bibble')) as m: ... with open('foo') as h: @@ -2250,7 +2250,7 @@ accessed) you can use it with very complex or deeply nested objects (like modules that import modules that import modules) without a big performance hit. -Here's an example of it in use: :: +Here's an example of it in use:: >>> from urllib import request >>> patcher = patch('__main__.request', autospec=True) @@ -2262,7 +2262,7 @@ Here's an example of it in use: :: You can see that :class:`request.Request` has a spec. :class:`request.Request` takes two arguments in the constructor (one of which is *self*). Here's what happens if -we try to call it incorrectly: :: +we try to call it incorrectly:: >>> req = request.Request() Traceback (most recent call last): @@ -2270,7 +2270,7 @@ we try to call it incorrectly: :: TypeError: () takes at least 2 arguments (1 given) The spec also applies to instantiated classes (i.e. the return value of -specced mocks): :: +specced mocks):: >>> req = request.Request('foo') >>> req @@ -2278,7 +2278,7 @@ specced mocks): :: :class:`Request` objects are not callable, so the return value of instantiating our mocked out :class:`request.Request` is a non-callable mock. With the spec in place -any typos in our asserts will raise the correct error: :: +any typos in our asserts will raise the correct error:: >>> req.add_header('spam', 'eggs') @@ -2330,7 +2330,7 @@ There are a few different ways of resolving this problem. The easiest, but not necessarily the least annoying, way is to simply set the required attributes on the mock after creation. Just because *autospec* doesn't allow you to fetch attributes that don't exist on the spec it doesn't prevent you -setting them: :: +setting them:: >>> with patch('__main__.Something', autospec=True): ... thing = Something() @@ -2381,7 +2381,7 @@ spec rather than the class. The other is to create a subclass of the production class and add the defaults to the subclass without affecting the production class. Both of these require you to use an alternative object as the spec. Thankfully :func:`patch` supports this - you can simply pass the -alternative object as the *autospec* argument: :: +alternative object as the *autospec* argument:: >>> class Something: ... def __init__(self): From 9505f06ebba16f7c19bfbe22d3bbcdaea99ea4af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Wirtel?= Date: Fri, 12 Oct 2018 00:04:37 +0200 Subject: [PATCH 30/33] fix the indentation of a function --- Doc/library/unittest.mock-examples.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Doc/library/unittest.mock-examples.rst b/Doc/library/unittest.mock-examples.rst index 7f454ac0730a86e..271e9bcb2cd1584 100644 --- a/Doc/library/unittest.mock-examples.rst +++ b/Doc/library/unittest.mock-examples.rst @@ -115,14 +115,14 @@ mock. The ``Foo`` instance is the result of calling the mock, so it is configure by modifying the mock :attr:`~Mock.return_value`. :: >>> def some_function(): - ... instance = module.Foo() - ... return instance.method() + ... instance = module.Foo() + ... return instance.method() ... >>> with patch('module.Foo') as mock: - ... instance = mock.return_value - ... instance.method.return_value = 'the result' - ... result = some_function() - ... assert result == 'the result' + ... instance = mock.return_value + ... instance.method.return_value = 'the result' + ... result = some_function() + ... assert result == 'the result' Naming your mocks From 7d76ead87145f1872e959dcf097577fb936e10b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Wirtel?= Date: Fri, 12 Oct 2018 00:09:05 +0200 Subject: [PATCH 31/33] reindent with the previous indentation, tab 4 --- Doc/library/unittest.mock-examples.rst | 104 ++++++++++++------------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/Doc/library/unittest.mock-examples.rst b/Doc/library/unittest.mock-examples.rst index 271e9bcb2cd1584..60db4c2ba4dacdf 100644 --- a/Doc/library/unittest.mock-examples.rst +++ b/Doc/library/unittest.mock-examples.rst @@ -114,15 +114,15 @@ and calls a method on it. The call to :func:`patch` replaces the class ``Foo`` w mock. The ``Foo`` instance is the result of calling the mock, so it is configured by modifying the mock :attr:`~Mock.return_value`. :: - >>> def some_function(): - ... instance = module.Foo() - ... return instance.method() - ... - >>> with patch('module.Foo') as mock: - ... instance = mock.return_value - ... instance.method.return_value = 'the result' - ... result = some_function() - ... assert result == 'the result' + >>> def some_function(): + ... instance = module.Foo() + ... return instance.method() + ... + >>> with patch('module.Foo') as mock: + ... instance = mock.return_value + ... instance.method.return_value = 'the result' + ... result = some_function() + ... assert result == 'the result' Naming your mocks @@ -500,26 +500,26 @@ response object for it. To set the response as the return value for that final We can do that in a slightly nicer way using the :meth:`~Mock.configure_mock` method to directly set the return value for us:: - >>> something = Something() - >>> mock_response = Mock(spec=open) - >>> mock_backend = Mock() - >>> config = {'get_endpoint.return_value.create_call.return_value.start_call.return_value': mock_response} - >>> mock_backend.configure_mock(**config) + >>> something = Something() + >>> mock_response = Mock(spec=open) + >>> mock_backend = Mock() + >>> config = {'get_endpoint.return_value.create_call.return_value.start_call.return_value': mock_response} + >>> mock_backend.configure_mock(**config) With these we monkey patch the "mock backend" in place and can make the real call:: - >>> something.backend = mock_backend - >>> something.method() + >>> something.backend = mock_backend + >>> something.method() Using :attr:`~Mock.mock_calls` we can check the chained call with a single assert. A chained call is several calls in one line of code, so there will be several entries in ``mock_calls``. We can use :meth:`call.call_list` to create this list of calls for us:: - >>> chained = call.get_endpoint('foobar').create_call('spam', 'eggs').start_call() - >>> call_list = chained.call_list() - >>> assert mock_backend.mock_calls == call_list + >>> chained = call.get_endpoint('foobar').create_call('spam', 'eggs').start_call() + >>> call_list = chained.call_list() + >>> assert mock_backend.mock_calls == call_list Partial mocking @@ -540,13 +540,13 @@ attribute on the mock date class is then set to a lambda function that returns a real date. When the mock date class is called a real date will be constructed and returned by ``side_effect``. :: - >>> from datetime import date - >>> with patch('mymodule.date') as mock_date: - ... mock_date.today.return_value = date(2010, 10, 8) - ... mock_date.side_effect = lambda *args, **kw: date(*args, **kw) - ... - ... assert mymodule.date.today() == date(2010, 10, 8) - ... assert mymodule.date(2009, 6, 8) == date(2009, 6, 8) + >>> from datetime import date + >>> with patch('mymodule.date') as mock_date: + ... mock_date.today.return_value = date(2010, 10, 8) + ... mock_date.side_effect = lambda *args, **kw: date(*args, **kw) + ... + ... assert mymodule.date.today() == date(2010, 10, 8) + ... assert mymodule.date(2009, 6, 8) == date(2009, 6, 8) Note that we don't patch :class:`datetime.date` globally, we patch ``date`` in the module that *uses* it. See :ref:`where to patch `. @@ -1125,43 +1125,43 @@ arbitrary attribute of a mock creates a child mock, we can create our separate mocks from a parent one. Calls to those child mock will then all be recorded, in order, in the ``mock_calls`` of the parent: - >>> manager = Mock() - >>> mock_foo = manager.foo - >>> mock_bar = manager.bar + >>> manager = Mock() + >>> mock_foo = manager.foo + >>> mock_bar = manager.bar - >>> mock_foo.something() - - >>> mock_bar.other.thing() - + >>> mock_foo.something() + + >>> mock_bar.other.thing() + - >>> manager.mock_calls - [call.foo.something(), call.bar.other.thing()] + >>> manager.mock_calls + [call.foo.something(), call.bar.other.thing()] We can then assert about the calls, including the order, by comparing with the ``mock_calls`` attribute on the manager mock: - >>> expected_calls = [call.foo.something(), call.bar.other.thing()] - >>> manager.mock_calls == expected_calls - True + >>> expected_calls = [call.foo.something(), call.bar.other.thing()] + >>> manager.mock_calls == expected_calls + True If ``patch`` is creating, and putting in place, your mocks then you can attach them to a manager mock using the :meth:`~Mock.attach_mock` method. After attaching calls will be recorded in ``mock_calls`` of the manager. :: - >>> manager = MagicMock() - >>> with patch('mymodule.Class1') as MockClass1: - ... with patch('mymodule.Class2') as MockClass2: - ... manager.attach_mock(MockClass1, 'MockClass1') - ... manager.attach_mock(MockClass2, 'MockClass2') - ... MockClass1().foo() - ... MockClass2().bar() - - - >>> manager.mock_calls - [call.MockClass1(), - call.MockClass1().foo(), - call.MockClass2(), - call.MockClass2().bar()] + >>> manager = MagicMock() + >>> with patch('mymodule.Class1') as MockClass1: + ... with patch('mymodule.Class2') as MockClass2: + ... manager.attach_mock(MockClass1, 'MockClass1') + ... manager.attach_mock(MockClass2, 'MockClass2') + ... MockClass1().foo() + ... MockClass2().bar() + + + >>> manager.mock_calls + [call.MockClass1(), + call.MockClass1().foo(), + call.MockClass2(), + call.MockClass2().bar()] If many calls have been made, but you're only interested in a particular sequence of them then an alternative is to use the From 93734d8b4961f5175adf4bf3c46ea288413eb312 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Wirtel?= Date: Fri, 12 Oct 2018 00:10:06 +0200 Subject: [PATCH 32/33] supress a useless diff --- Doc/library/unittest.mock.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/unittest.mock.rst b/Doc/library/unittest.mock.rst index f99b7c44e743fa6..edafca0c674ed2b 100644 --- a/Doc/library/unittest.mock.rst +++ b/Doc/library/unittest.mock.rst @@ -2421,7 +2421,7 @@ Sealing mocks >>> mock.submock.attribute1 = 2 >>> mock.not_submock = mock.Mock() >>> seal(mock) - >>> mock.submock.attribute2 # This will raise AttributeError - >>> mock.not_submock.attribute2 # This won't raise + >>> mock.submock.attribute2 # This will raise AttributeError. + >>> mock.not_submock.attribute2 # This won't raise. .. versionadded:: 3.7 From 0511ae17b6638aecd036628976904f90793e7fec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Wirtel?= Date: Fri, 12 Oct 2018 00:10:56 +0200 Subject: [PATCH 33/33] supress a useless diff --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index d210f200d8fcafb..19be17e2f25ed46 100644 --- a/.travis.yml +++ b/.travis.yml @@ -85,7 +85,6 @@ matrix: script: # Skip tests that re-run the entire test suite. - xvfb-run ./venv/bin/python -m coverage run --pylib -m test --fail-env-changed -uall,-cpu -x test_multiprocessing_fork -x test_multiprocessing_forkserver -x test_multiprocessing_spawn -x test_concurrent_futures - after_script: # Probably should be after_success once test suite updated to run under coverage.py. # Make the `coverage` command available to Codecov w/ a version of Python that can parse all source files. - source ./venv/bin/activate