Fixed #23930 -- Added copies of captured_std* managers from CPython's test.support.

StringIO import was adapted for compatibility with Python 2.
This commit is contained in:
wrwrwr 2014-11-28 23:47:53 +01:00 committed by Tim Graham
parent c8dcded930
commit 6dbe979b4d
7 changed files with 76 additions and 60 deletions

View File

@ -493,3 +493,51 @@ def extend_sys_path(*paths):
yield yield
finally: finally:
sys.path = _orig_sys_path sys.path = _orig_sys_path
@contextmanager
def captured_output(stream_name):
"""Return a context manager used by captured_stdout/stdin/stderr
that temporarily replaces the sys stream *stream_name* with a StringIO.
Note: This function and the following ``captured_std*`` are copied
from CPython's ``test.support`` module."""
orig_stdout = getattr(sys, stream_name)
setattr(sys, stream_name, six.StringIO())
try:
yield getattr(sys, stream_name)
finally:
setattr(sys, stream_name, orig_stdout)
def captured_stdout():
"""Capture the output of sys.stdout:
with captured_stdout() as stdout:
print("hello")
self.assertEqual(stdout.getvalue(), "hello\n")
"""
return captured_output("stdout")
def captured_stderr():
"""Capture the output of sys.stderr:
with captured_stderr() as stderr:
print("hello", file=sys.stderr)
self.assertEqual(stderr.getvalue(), "hello\n")
"""
return captured_output("stderr")
def captured_stdin():
"""Capture the input to sys.stdin:
with captured_stdin() as stdin:
stdin.write('hello\n')
stdin.seek(0)
# call test code that consumes from sys.stdin
captured = input()
self.assertEqual(captured, "hello")
"""
return captured_output("stdin")

View File

@ -7,7 +7,7 @@ import unittest
from django.apps import apps from django.apps import apps
from django.core.management import ManagementUtility from django.core.management import ManagementUtility
from django.utils.six import StringIO from django.test.utils import captured_stdout
class BashCompletionTests(unittest.TestCase): class BashCompletionTests(unittest.TestCase):
@ -20,12 +20,8 @@ class BashCompletionTests(unittest.TestCase):
def setUp(self): def setUp(self):
self.old_DJANGO_AUTO_COMPLETE = os.environ.get('DJANGO_AUTO_COMPLETE') self.old_DJANGO_AUTO_COMPLETE = os.environ.get('DJANGO_AUTO_COMPLETE')
os.environ['DJANGO_AUTO_COMPLETE'] = '1' os.environ['DJANGO_AUTO_COMPLETE'] = '1'
self.output = StringIO()
self.old_stdout = sys.stdout
sys.stdout = self.output
def tearDown(self): def tearDown(self):
sys.stdout = self.old_stdout
if self.old_DJANGO_AUTO_COMPLETE: if self.old_DJANGO_AUTO_COMPLETE:
os.environ['DJANGO_AUTO_COMPLETE'] = self.old_DJANGO_AUTO_COMPLETE os.environ['DJANGO_AUTO_COMPLETE'] = self.old_DJANGO_AUTO_COMPLETE
else: else:
@ -53,11 +49,12 @@ class BashCompletionTests(unittest.TestCase):
def _run_autocomplete(self): def _run_autocomplete(self):
util = ManagementUtility(argv=sys.argv) util = ManagementUtility(argv=sys.argv)
try: with captured_stdout() as stdout:
util.autocomplete() try:
except SystemExit: util.autocomplete()
pass except SystemExit:
return self.output.getvalue().strip().split('\n') pass
return stdout.getvalue().strip().split('\n')
def test_django_admin_py(self): def test_django_admin_py(self):
"django_admin.py will autocomplete option flags" "django_admin.py will autocomplete option flags"

View File

@ -1,8 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
import sys
from django.apps.registry import Apps, apps from django.apps.registry import Apps, apps
from django.contrib.contenttypes.fields import ( from django.contrib.contenttypes.fields import (
GenericForeignKey, GenericRelation GenericForeignKey, GenericRelation
@ -12,9 +10,8 @@ from django.contrib.contenttypes.models import ContentType
from django.core import checks from django.core import checks
from django.db import connections, models, router from django.db import connections, models, router
from django.test import TestCase from django.test import TestCase
from django.test.utils import override_settings from django.test.utils import captured_stdout, override_settings
from django.utils.encoding import force_str from django.utils.encoding import force_str
from django.utils.six import StringIO
from .models import Author, Article, SchemeIncludedURL from .models import Author, Article, SchemeIncludedURL
@ -369,11 +366,6 @@ class UpdateContentTypesTests(TestCase):
self.before_count = ContentType.objects.count() self.before_count = ContentType.objects.count()
ContentType.objects.create(name='fake', app_label='contenttypes_tests', model='Fake') ContentType.objects.create(name='fake', app_label='contenttypes_tests', model='Fake')
self.app_config = apps.get_app_config('contenttypes_tests') self.app_config = apps.get_app_config('contenttypes_tests')
self.old_stdout = sys.stdout
sys.stdout = StringIO()
def tearDown(self):
sys.stdout = self.old_stdout
def test_interactive_true(self): def test_interactive_true(self):
""" """
@ -381,8 +373,9 @@ class UpdateContentTypesTests(TestCase):
stale contenttypes. stale contenttypes.
""" """
management.input = lambda x: force_str("yes") management.input = lambda x: force_str("yes")
management.update_contenttypes(self.app_config) with captured_stdout() as stdout:
self.assertIn("Deleting stale content type", sys.stdout.getvalue()) management.update_contenttypes(self.app_config)
self.assertIn("Deleting stale content type", stdout.getvalue())
self.assertEqual(ContentType.objects.count(), self.before_count) self.assertEqual(ContentType.objects.count(), self.before_count)
def test_interactive_false(self): def test_interactive_false(self):
@ -390,8 +383,9 @@ class UpdateContentTypesTests(TestCase):
non-interactive mode of update_contenttypes() shouldn't delete stale non-interactive mode of update_contenttypes() shouldn't delete stale
content types. content types.
""" """
management.update_contenttypes(self.app_config, interactive=False) with captured_stdout() as stdout:
self.assertIn("Stale content types remain.", sys.stdout.getvalue()) management.update_contenttypes(self.app_config, interactive=False)
self.assertIn("Stale content types remain.", stdout.getvalue())
self.assertEqual(ContentType.objects.count(), self.before_count + 1) self.assertEqual(ContentType.objects.count(), self.before_count + 1)

View File

@ -3,7 +3,6 @@
import os import os
import shutil import shutil
import stat import stat
import sys
import unittest import unittest
import gettext as gettext_module import gettext as gettext_module
@ -11,6 +10,7 @@ from django.core.management import call_command, CommandError, execute_from_comm
from django.core.management.utils import find_command from django.core.management.utils import find_command
from django.test import SimpleTestCase from django.test import SimpleTestCase
from django.test import override_settings from django.test import override_settings
from django.test.utils import captured_stderr, captured_stdout
from django.utils import translation from django.utils import translation
from django.utils.translation import ugettext from django.utils.translation import ugettext
from django.utils.encoding import force_text from django.utils.encoding import force_text
@ -145,15 +145,11 @@ class ExcludedLocaleCompilationTests(MessageCompilationTests):
self.addCleanup(self._rmrf, os.path.join(self.test_dir, 'locale')) self.addCleanup(self._rmrf, os.path.join(self.test_dir, 'locale'))
def test_command_help(self): def test_command_help(self):
old_stdout, old_stderr = sys.stdout, sys.stderr with captured_stdout(), captured_stderr():
sys.stdout, sys.stderr = StringIO(), StringIO()
try:
# `call_command` bypasses the parser; by calling # `call_command` bypasses the parser; by calling
# `execute_from_command_line` with the help subcommand we # `execute_from_command_line` with the help subcommand we
# ensure that there are no issues with the parser itself. # ensure that there are no issues with the parser itself.
execute_from_command_line(['django-admin', 'help', 'compilemessages']) execute_from_command_line(['django-admin', 'help', 'compilemessages'])
finally:
sys.stdout, sys.stderr = old_stdout, old_stderr
def test_one_locale_excluded(self): def test_one_locale_excluded(self):
call_command('compilemessages', exclude=['it'], stdout=StringIO()) call_command('compilemessages', exclude=['it'], stdout=StringIO())

View File

@ -5,7 +5,6 @@ import io
import os import os
import re import re
import shutil import shutil
import sys
import time import time
from unittest import SkipTest, skipUnless from unittest import SkipTest, skipUnless
import warnings import warnings
@ -16,6 +15,7 @@ from django.core.management import execute_from_command_line
from django.core.management.utils import find_command from django.core.management.utils import find_command
from django.test import SimpleTestCase from django.test import SimpleTestCase
from django.test import override_settings from django.test import override_settings
from django.test.utils import captured_stderr, captured_stdout
from django.utils.encoding import force_text from django.utils.encoding import force_text
from django.utils._os import upath from django.utils._os import upath
from django.utils import six from django.utils import six
@ -632,15 +632,11 @@ class ExcludedLocaleExtractionTests(ExtractorTests):
self.addCleanup(self._rmrf, os.path.join(self.test_dir, 'locale')) self.addCleanup(self._rmrf, os.path.join(self.test_dir, 'locale'))
def test_command_help(self): def test_command_help(self):
old_stdout, old_stderr = sys.stdout, sys.stderr with captured_stdout(), captured_stderr():
sys.stdout, sys.stderr = StringIO(), StringIO()
try:
# `call_command` bypasses the parser; by calling # `call_command` bypasses the parser; by calling
# `execute_from_command_line` with the help subcommand we # `execute_from_command_line` with the help subcommand we
# ensure that there are no issues with the parser itself. # ensure that there are no issues with the parser itself.
execute_from_command_line(['django-admin', 'help', 'makemessages']) execute_from_command_line(['django-admin', 'help', 'makemessages'])
finally:
sys.stdout, sys.stderr = old_stdout, old_stderr
def test_one_locale_excluded(self): def test_one_locale_excluded(self):
management.call_command('makemessages', exclude=['it'], stdout=StringIO()) management.call_command('makemessages', exclude=['it'], stdout=StringIO())

View File

@ -1,10 +1,9 @@
import sys
from django.core.handlers.wsgi import WSGIRequest from django.core.handlers.wsgi import WSGIRequest
from django.core.servers.basehttp import WSGIRequestHandler from django.core.servers.basehttp import WSGIRequestHandler
from django.test import TestCase from django.test import TestCase
from django.test.client import RequestFactory from django.test.client import RequestFactory
from django.utils.six import BytesIO, StringIO from django.test.utils import captured_stderr
from django.utils.six import BytesIO
class WSGIRequestHandlerTestCase(TestCase): class WSGIRequestHandlerTestCase(TestCase):
@ -14,14 +13,10 @@ class WSGIRequestHandlerTestCase(TestCase):
handler = WSGIRequestHandler(request, '192.168.0.2', None) handler = WSGIRequestHandler(request, '192.168.0.2', None)
_stderr = sys.stderr with captured_stderr() as stderr:
sys.stderr = StringIO()
try:
handler.log_message("GET %s %s", str('\x16\x03'), "4") handler.log_message("GET %s %s", str('\x16\x03'), "4")
self.assertIn( self.assertIn(
"You're accessing the developement server over HTTPS, " "You're accessing the developement server over HTTPS, "
"but it only supports HTTP.", "but it only supports HTTP.",
sys.stderr.getvalue() stderr.getvalue()
) )
finally:
sys.stderr = _stderr

View File

@ -1,5 +1,4 @@
import os import os
import sys
import warnings import warnings
from django.db import connection from django.db import connection
@ -7,6 +6,7 @@ from django.core import management
from django.core.management import BaseCommand, CommandError from django.core.management import BaseCommand, CommandError
from django.core.management.utils import find_command, popen_wrapper from django.core.management.utils import find_command, popen_wrapper
from django.test import SimpleTestCase from django.test import SimpleTestCase
from django.test.utils import captured_stderr, captured_stdout
from django.utils import translation from django.utils import translation
from django.utils.deprecation import RemovedInDjango20Warning from django.utils.deprecation import RemovedInDjango20Warning
from django.utils.six import StringIO from django.utils.six import StringIO
@ -42,14 +42,9 @@ class CommandTests(SimpleTestCase):
""" """
with self.assertRaises(CommandError): with self.assertRaises(CommandError):
management.call_command('dance', example="raise") management.call_command('dance', example="raise")
old_stderr = sys.stderr with captured_stderr() as stderr, self.assertRaises(SystemExit):
sys.stderr = err = StringIO() management.ManagementUtility(['manage.py', 'dance', '--example=raise']).execute()
try: self.assertIn("CommandError", stderr.getvalue())
with self.assertRaises(SystemExit):
management.ManagementUtility(['manage.py', 'dance', '--example=raise']).execute()
finally:
sys.stderr = old_stderr
self.assertIn("CommandError", err.getvalue())
def test_default_en_us_locale_set(self): def test_default_en_us_locale_set(self):
# Forces en_us when set to true # Forces en_us when set to true
@ -100,14 +95,9 @@ class CommandTests(SimpleTestCase):
self.assertEqual(out.getvalue(), "All right, let's dance Rock'n'Roll.\n") self.assertEqual(out.getvalue(), "All right, let's dance Rock'n'Roll.\n")
# Simulate command line execution # Simulate command line execution
old_stdout, old_stderr = sys.stdout, sys.stderr with captured_stdout() as stdout, captured_stderr():
sys.stdout, sys.stderr = StringIO(), StringIO()
try:
management.execute_from_command_line(['django-admin', 'optparse_cmd']) management.execute_from_command_line(['django-admin', 'optparse_cmd'])
finally: self.assertEqual(stdout.getvalue(), "All right, let's dance Rock'n'Roll.\n")
output = sys.stdout.getvalue()
sys.stdout, sys.stderr = old_stdout, old_stderr
self.assertEqual(output, "All right, let's dance Rock'n'Roll.\n")
def test_calling_a_command_with_only_empty_parameter_should_ends_gracefully(self): def test_calling_a_command_with_only_empty_parameter_should_ends_gracefully(self):
out = StringIO() out = StringIO()