Index: Python-3.3.0/Lib/platform.py =================================================================== --- Python-3.3.0.orig/Lib/platform.py +++ Python-3.3.0/Lib/platform.py @@ -290,6 +290,23 @@ def _parse_release_file(firstline): id = l[1] return '', version, id +def _find_linux_release_file(supported_dists): + '''Select a file that may hold release information on a linux distribution + + :raises os.error: if the /etc/ directory does not exist + :returns: the complete path to the file + ''' + # Can throw os.error which is caught in the caller + etc = os.listdir('/etc') + etc.sort() + for file in etc: + m = _release_filename.match(file) + if m is not None: + _distname,dummy = m.groups() + if _distname in supported_dists: + return _distname, os.path.join('/etc', file) + return None, None + def linux_distribution(distname='', version='', id='', supported_dists=_supported_dists, @@ -315,23 +332,15 @@ def linux_distribution(distname='', vers """ try: - etc = os.listdir('/etc') + distname, file = _find_linux_release_file(supported_dists) except os.error: # Probably not a Unix system - return distname,version,id - etc.sort() - for file in etc: - m = _release_filename.match(file) - if m is not None: - _distname,dummy = m.groups() - if _distname in supported_dists: - distname = _distname - break - else: + return distname, version, id + if not file: return _dist_try_harder(distname,version,id) # Read the first line - with open('/etc/'+file, 'r') as f: + with open(file, 'r', encoding='utf-8', errors='surrogateescape') as f: firstline = f.readline() _distname, _version, _id = _parse_release_file(firstline) Index: Python-3.3.0/Lib/test/test_platform.py =================================================================== --- Python-3.3.0.orig/Lib/test/test_platform.py +++ Python-3.3.0/Lib/test/test_platform.py @@ -2,9 +2,12 @@ import os import platform import subprocess import sys +import tempfile import unittest import warnings +from unittest.mock import MagicMock, patch + from test import support class PlatformTest(unittest.TestCase): @@ -37,6 +40,60 @@ class PlatformTest(unittest.TestCase): for terse in (False, True): res = platform.platform(aliased, terse) + def test_dist_with_unicode(self): + # Test reading the platform information with a variety of "odd" locale + # settings and odd encodings of the files. (Want to catch tracebacks + # in unicode handling and unknown encodings of that file) + + # Expectations: + # utf8_data will come out as utf8 + # latin1_data will be mangled with some surrogateescapes + # locale will have no effect on the outcome + + # data + release_string = "Fedora release 19 (Schrödinger's Cat)\n" + parsed_release_string = ("fedora", "19", "Schrödinger's Cat") + parsed_mangled_latin1_release_as_utf8 = ("fedora", "19", "Schr\udcf6dinger's_Cat") + + # UTF-8 test + with tempfile.NamedTemporaryFile() as f: + utf8_data_filename = f.name + f.write(release_string.encode('utf-8')) + f.flush() + + find_utf8_file = MagicMock() + find_utf8_file.return_value = ('fedora', utf8_data_filename) + + # The linux_distribution function reads from a file so we have to + # mock out the file that will be found by that + with patch('platform._find_linux_release_file', find_utf8_file): + old_locale = os.environ.get('LC_ALL', None) + + for locale in ('C', 'pt_BR.UTF8', 'pt_BR.ISO8859-1'): + os.environ['LC_ALL'] = locale + self.assertEqual(platform.dist(), parsed_release_string) + + os.environ['LC_ALL'] = old_locale + + with tempfile.NamedTemporaryFile() as f: + latin1_data_filename = f.name + f.write(release_string.encode('latin-1')) + f.flush() + + find_latin1_file = MagicMock() + find_latin1_file.return_value = ('fedora', latin1_data_filename) + + # The linux_distribution function reads from a file so we have to + # mock out the file that will be found by that + with patch('platform._find_linux_release_file', find_latin1_file): + old_locale = os.environ.get('LC_ALL', None) + + for locale in ('C', 'pt_BR.UTF8', 'pt_BR.ISO8859-1'): + os.environ['LC_ALL'] = locale + self.assertTrue(platform.dist(), parsed_mangled_latin1_release_as_utf8) + + os.environ['LC_ALL'] = old_locale + def test_system(self): res = platform.system()