diff --git a/tornado/test/autoreload_test.py b/tornado/test/autoreload_test.py index be481e10..fff60281 100644 --- a/tornado/test/autoreload_test.py +++ b/tornado/test/autoreload_test.py @@ -43,8 +43,12 @@ if 'TESTAPP_STARTED' not in os.environ: # Create temporary test application os.mkdir(os.path.join(self.path, "testapp")) - open(os.path.join(self.path, "testapp/__init__.py"), "w").close() - with open(os.path.join(self.path, "testapp/__main__.py"), "w") as f: + open( + os.path.join(self.path, "testapp/__init__.py"), "w", encoding="utf-8" + ).close() + with open( + os.path.join(self.path, "testapp/__main__.py"), "w", encoding="utf-8" + ) as f: f.write(main) # Make sure the tornado module under test is available to the test @@ -59,6 +63,7 @@ if 'TESTAPP_STARTED' not in os.environ: cwd=self.path, env=dict(os.environ, PYTHONPATH=pythonpath), universal_newlines=True, + encoding="utf-8", ) out = p.communicate()[0] self.assertEqual(out, "Starting\nStarting\n") @@ -94,9 +99,9 @@ else: # Create temporary test application os.mkdir(os.path.join(self.path, "testapp")) init_file = os.path.join(self.path, "testapp", "__init__.py") - open(init_file, "w").close() + open(init_file, "w", encoding="utf-8").close() main_file = os.path.join(self.path, "testapp", "__main__.py") - with open(main_file, "w") as f: + with open(main_file, "w", encoding="utf-8") as f: f.write(main) # Make sure the tornado module under test is available to the test @@ -111,6 +116,7 @@ else: cwd=self.path, env=dict(os.environ, PYTHONPATH=pythonpath), universal_newlines=True, + encoding="utf-8", ) # This timeout needs to be fairly generous for pypy due to jit diff --git a/tornado/test/log_test.py b/tornado/test/log_test.py index 9130ae7e..fec4c389 100644 --- a/tornado/test/log_test.py +++ b/tornado/test/log_test.py @@ -66,11 +66,7 @@ class LogFormatterTest(unittest.TestCase): os.rmdir(self.tempdir) def make_handler(self, filename): - # Base case: default setup without explicit encoding. - # In python 2, supports arbitrary byte strings and unicode objects - # that contain only ascii. In python 3, supports ascii-only unicode - # strings (but byte strings will be repr'd automatically). - return logging.FileHandler(filename) + return logging.FileHandler(filename, encoding="utf-8") def get_output(self): with open(self.filename, "rb") as f: @@ -116,14 +112,6 @@ class LogFormatterTest(unittest.TestCase): # The traceback contains newlines, which should not have been escaped. self.assertNotIn(rb"\n", output) - -class UnicodeLogFormatterTest(LogFormatterTest): - def make_handler(self, filename): - # Adding an explicit encoding configuration allows non-ascii unicode - # strings in both python 2 and 3, without changing the behavior - # for byte strings. - return logging.FileHandler(filename, encoding="utf8") - def test_unicode_logging(self): self.logger.error("\u00e9") self.assertEqual(self.get_output(), utf8("\u00e9")) @@ -147,7 +135,7 @@ class EnablePrettyLoggingTest(unittest.TestCase): self.logger.handlers[0].flush() filenames = glob.glob(tmpdir + "/test_log*") self.assertEqual(1, len(filenames)) - with open(filenames[0]) as f: + with open(filenames[0], encoding="utf-8") as f: self.assertRegex(f.read(), r"^\[E [^]]*\] hello$") finally: for handler in self.logger.handlers: @@ -167,7 +155,7 @@ class EnablePrettyLoggingTest(unittest.TestCase): self.logger.handlers[0].flush() filenames = glob.glob(tmpdir + "/test_log*") self.assertEqual(1, len(filenames)) - with open(filenames[0]) as f: + with open(filenames[0], encoding="utf-8") as f: self.assertRegex(f.read(), r"^\[E [^]]*\] hello$") finally: for handler in self.logger.handlers: diff --git a/tornado/test/runtests.py b/tornado/test/runtests.py index 6075b1e2..58cecd38 100644 --- a/tornado/test/runtests.py +++ b/tornado/test/runtests.py @@ -128,37 +128,6 @@ def main(): warnings.filterwarnings( "error", category=PendingDeprecationWarning, module=r"tornado\..*" ) - # The unittest module is aggressive about deprecating redundant methods, - # leaving some without non-deprecated spellings that work on both - # 2.7 and 3.2 - warnings.filterwarnings( - "ignore", category=DeprecationWarning, message="Please use assert.* instead" - ) - warnings.filterwarnings( - "ignore", - category=PendingDeprecationWarning, - message="Please use assert.* instead", - ) - # Twisted 15.0.0 triggers some warnings on py3 with -bb. - warnings.filterwarnings("ignore", category=BytesWarning, module=r"twisted\..*") - if (3,) < sys.version_info < (3, 6): - # Prior to 3.6, async ResourceWarnings were rather noisy - # and even - # `python3.4 -W error -c 'import asyncio; asyncio.get_event_loop()'` - # would generate a warning. - warnings.filterwarnings( - "ignore", category=ResourceWarning, module=r"asyncio\..*" - ) - # This deprecation warning is introduced in Python 3.8 and is - # triggered by pycurl. Unforunately, because it is raised in the C - # layer it can't be filtered by module and we must match the - # message text instead (Tornado's C module uses PY_SSIZE_T_CLEAN - # so it's not at risk of running into this issue). - warnings.filterwarnings( - "ignore", - category=DeprecationWarning, - message="PY_SSIZE_T_CLEAN will be required", - ) logging.getLogger("tornado.access").setLevel(logging.CRITICAL) diff --git a/tornado/test/web_test.py b/tornado/test/web_test.py index c2d057c5..56900d9a 100644 --- a/tornado/test/web_test.py +++ b/tornado/test/web_test.py @@ -1271,7 +1271,7 @@ class StaticFileTest(WebTestCase): # to ``Range: bytes=0-`` :( self.assertEqual(response.code, 200) robots_file_path = os.path.join(self.static_dir, "robots.txt") - with open(robots_file_path) as f: + with open(robots_file_path, encoding="utf-8") as f: self.assertEqual(response.body, utf8(f.read())) self.assertEqual(response.headers.get("Content-Length"), "26") self.assertEqual(response.headers.get("Content-Range"), None) @@ -1282,7 +1282,7 @@ class StaticFileTest(WebTestCase): ) self.assertEqual(response.code, 200) robots_file_path = os.path.join(self.static_dir, "robots.txt") - with open(robots_file_path) as f: + with open(robots_file_path, encoding="utf-8") as f: self.assertEqual(response.body, utf8(f.read())) self.assertEqual(response.headers.get("Content-Length"), "26") self.assertEqual(response.headers.get("Content-Range"), None) @@ -1293,7 +1293,7 @@ class StaticFileTest(WebTestCase): ) self.assertEqual(response.code, 206) robots_file_path = os.path.join(self.static_dir, "robots.txt") - with open(robots_file_path) as f: + with open(robots_file_path, encoding="utf-8") as f: self.assertEqual(response.body, utf8(f.read()[1:])) self.assertEqual(response.headers.get("Content-Length"), "25") self.assertEqual(response.headers.get("Content-Range"), "bytes 1-25/26") @@ -1320,7 +1320,7 @@ class StaticFileTest(WebTestCase): ) self.assertEqual(response.code, 200) robots_file_path = os.path.join(self.static_dir, "robots.txt") - with open(robots_file_path) as f: + with open(robots_file_path, encoding="utf-8") as f: self.assertEqual(response.body, utf8(f.read())) self.assertEqual(response.headers.get("Content-Length"), "26") self.assertEqual(response.headers.get("Content-Range"), None) diff --git a/tox.ini b/tox.ini index f7b5bd38..73a14a7f 100644 --- a/tox.ini +++ b/tox.ini @@ -47,7 +47,7 @@ deps = setenv = # Treat the extension as mandatory in testing (but not on pypy) - {py3,py38,py39,py310,py311}: TORNADO_EXTENSION=1 + {py3,py38,py39,py310,py311,py312}: TORNADO_EXTENSION=1 # CI workers are often overloaded and can cause our tests to exceed # the default timeout of 5s. ASYNC_TEST_TIMEOUT=25 @@ -60,7 +60,10 @@ setenv = # possible to set environment variables during that phase of # tox). {py3,py38,py39,py310,py311,pypy3}: PYTHONWARNINGS=error:::tornado - + # Warn if we try to open a file with an unspecified encoding. + # (New in python 3.10, becomes obsolete when utf8 becomes the + # default in 3.15) + PYTHONWARNDEFAULTENCODING=1 # Allow shell commands in tests allowlist_externals = sh @@ -77,33 +80,17 @@ commands = # the trap of relying on an assertion's side effects or using # them for things that should be runtime errors. full: python -O -m tornado.test - # In python 3, opening files in text mode uses a - # system-dependent encoding by default. Run the tests with "C" - # (ascii) and "utf-8" locales to ensure we don't have hidden - # dependencies on this setting. - full: sh -c 'LANG=C python -m tornado.test' - full: sh -c 'LANG=en_US.utf-8 python -m tornado.test' # Note that httpclient_test is always run with both client # implementations; this flag controls which client all the # other tests use. full: python -m tornado.test --httpclient=tornado.curl_httpclient.CurlAsyncHTTPClient full: python -m tornado.test --resolver=tornado.platform.caresresolver.CaresResolver - # Run the tests once from the source directory to detect issues - # involving relative __file__ paths; see - # https://github.com/tornadoweb/tornado/issues/1780 - full: sh -c '(cd {toxinidir} && unset TORNADO_EXTENSION && python -m tornado.test)' - # python will import relative to the current working directory by default, # so cd into the tox working directory to avoid picking up the working # copy of the files (especially important for the speedups module). changedir = {toxworkdir} -# tox 1.6 passes --pre to pip by default, which currently has problems -# installing pycurl (https://github.com/pypa/pip/issues/1405). -# Remove it (it's not a part of {opts}) to only install real releases. -install_command = pip install {opts} {packages} - [testenv:docs] changedir = docs # For some reason the extension fails to load in this configuration,