Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Changed errors default to 'backslashreplace'.
  • Loading branch information
vsajip committed Jun 15, 2019
commit e2dc53ba69c8f203db97b03ce3ad5f08671e845b
7 changes: 6 additions & 1 deletion Doc/library/logging.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1204,7 +1204,12 @@ functions.
| *errors* | If this keyword argument is specified along |
| | with *filename*, its value is used when the |
| | FileHandler is created, and thus used when |
| | opening the output file. |
| | opening the output file. If not specified, |
| | the value 'backslashreplace' is used. Note |
| | that if ``None`` is specified, it will be |
| | passed as such to func:`open`, which means |
| | that it will be treated the same as passing |
| | 'errors'. |
+--------------+---------------------------------------------+

.. versionchanged:: 3.2
Expand Down
7 changes: 5 additions & 2 deletions Lib/logging/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1935,7 +1935,8 @@ def basicConfig(**kwargs):
opened.
errors If specified together with a filename, this value is passed to the
created FileHandler, causing it to be used when the file is
opened.
opened in text mode. If not specified, the default value is
`backslashreplace`.

Note that you could specify a stream created using open(filename, mode)
rather than passing the filename and mode in. However, it should be
Expand Down Expand Up @@ -1965,7 +1966,7 @@ def basicConfig(**kwargs):
try:
force = kwargs.pop('force', False)
encoding = kwargs.pop('encoding', None)
errors = kwargs.pop('errors', None)
errors = kwargs.pop('errors', 'backslashreplace')
if force:
for h in root.handlers[:]:
root.removeHandler(h)
Expand All @@ -1984,6 +1985,8 @@ def basicConfig(**kwargs):
filename = kwargs.pop("filename", None)
mode = kwargs.pop("filemode", 'a')
if filename:
if 'b'in mode:
errors = None
h = FileHandler(filename, mode,
encoding=encoding, errors=errors)
else:
Expand Down
54 changes: 54 additions & 0 deletions Lib/test/test_logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -4484,6 +4484,60 @@ def test_encoding_errors(self):
os.remove('test.log')
self.assertEqual(data, 'The resund Bridge joins Copenhagen to Malm')

def test_encoding_errors_default(self):
try:
encoding = 'ascii'
logging.basicConfig(filename='test.log', encoding=encoding,
format='%(message)s', level=logging.DEBUG)

self.assertEqual(len(logging.root.handlers), 1)
handler = logging.root.handlers[0]
self.assertIsInstance(handler, logging.FileHandler)
self.assertEqual(handler.encoding, encoding)
self.assertEqual(handler.errors, 'backslashreplace')
logging.debug('😂: ☃️: The Øresund Bridge joins Copenhagen to Malmö')
finally:
handler.close()
with open('test.log', encoding='utf-8') as f:
data = f.read().strip()
os.remove('test.log')
self.assertEqual(data, r'\U0001f602: \u2603\ufe0f: The \xd8resund '
r'Bridge joins Copenhagen to Malm\xf6')

def test_encoding_errors_none(self):
# Specifying None should behave as 'strict'
try:
encoding = 'ascii'
logging.basicConfig(filename='test.log', encoding=encoding,
errors=None,
format='%(message)s', level=logging.DEBUG)

self.assertEqual(len(logging.root.handlers), 1)
handler = logging.root.handlers[0]
self.assertIsInstance(handler, logging.FileHandler)
self.assertEqual(handler.encoding, encoding)
self.assertIsNone(handler.errors)

message = []

def dummy_handle_error(record):
_, v, _ = sys.exc_info()
message.append(str(v))

handler.handleError = dummy_handle_error
logging.debug('The Øresund Bridge joins Copenhagen to Malmö')
self.assertTrue(message)
self.assertIn("'ascii' codec can't encode "
"character '\\xd8' in position 4:", message[0])
finally:
handler.close()
with open('test.log', encoding='utf-8') as f:
data = f.read().strip()
os.remove('test.log')
# didn't write anything due to the encoding error
self.assertEqual(data, r'')


def _test_log(self, method, level=None):
# logging.root has no handlers so basicConfig should be called
called = []
Expand Down