Re: [gentoo-portage-dev] [PATCH v2] xattr: centralize the various shims in one place
2013-10-21 05:07 Mike Frysinger napisaĆ(a): > Rather than each module implementing its own shim around the various > methods for accessing extended attributes, start a dedicated module > that exports a consistent API. > --- > v2 > - passes unittests w/python 2.6 2.7 3.2 3.3 But portage.util._xattr._XattrSystemCommands does not work :) . >>> import portage.util._xattr >>> portage.util._xattr._XattrSystemCommands.list("/tmp") ... See below. > bin/xattr-helper.py | 11 +- > pym/portage/tests/util/test_xattr.py | 178 ++ > pym/portage/util/_xattr.py | 205 > +++ > pym/portage/util/movefile.py | 100 - > 4 files changed, 407 insertions(+), 87 deletions(-) > create mode 100644 pym/portage/tests/util/test_xattr.py > create mode 100644 pym/portage/util/_xattr.py > > diff --git a/bin/xattr-helper.py b/bin/xattr-helper.py > index 6d99521..69b83f7 100755 > --- a/bin/xattr-helper.py > +++ b/bin/xattr-helper.py > @@ -17,16 +17,7 @@ import re > import sys > > from portage.util._argparse import ArgumentParser > - > -if hasattr(os, "getxattr"): > - > - class xattr(object): > - get = os.getxattr > - set = os.setxattr > - list = os.listxattr > - > -else: > - import xattr > +from portage.util._xattr import xattr > > > _UNQUOTE_RE = re.compile(br'\\[0-7]{3}') > diff --git a/pym/portage/tests/util/test_xattr.py > b/pym/portage/tests/util/test_xattr.py > new file mode 100644 > index 000..e1f6ee8 > --- /dev/null > +++ b/pym/portage/tests/util/test_xattr.py > @@ -0,0 +1,178 @@ > +# Copyright 2010-2013 Gentoo Foundation > +# Distributed under the terms of the GNU General Public License v2 > + > +"""Tests for the portage.util._xattr module""" > + > +from __future__ import print_function > + > +try: > + # Try python-3.3 module first. > + from unittest import mock > +except ImportError: > + try: > + # Try standalone module. > + import mock > + except ImportError: > + mock = None > + > +import subprocess > + > +from portage.tests import TestCase > +from portage.util._xattr import (xattr as _xattr, _XattrSystemCommands, > + _XattrStub) > + > + > +orig_popen = subprocess.Popen > +def MockSubprocessPopen(stdin): > + """Helper to mock (closely) a subprocess.Popen call > + > + The module has minor tweaks in behavior when it comes to encoding and > + python versions, so use a real subprocess.Popen call to fake out the > + runtime behavior. This way we don't have to also implement different > + encodings as that gets ugly real fast. > + """ > + proc = orig_popen(['cat'], stdout=subprocess.PIPE, > stdin=subprocess.PIPE) > + try: > + proc.stdin.write(bytes(stdin)) > + except TypeError: > + proc.stdin.write(bytes(stdin, 'ascii')) It can fail with UnicodeEncodeError. Use proc.stdin.write(portage._unicode_encode(stdin), portage._encodings['stdio']) instead of above 4 lines. > + return proc > + > + > +class SystemCommandsTest(TestCase): > + """Test _XattrSystemCommands""" > + > + OUTPUT = '\n'.join([ > + '# file: /bin/ping', > + 'security.capability=0sAQAAAgAgAAA=', > + 'user.foo="asdf"', > + '', > + ]) > + > + def _setUp(self): > + if mock is None: > + self.skipTest('need mock for testing') > + > + return _XattrSystemCommands > + > + def _testGetBasic(self): > + """Verify the get() behavior""" > + xattr = self._setUp() > + with mock.patch.object(subprocess, 'Popen') as call_mock: > + # Verify basic behavior, and namespace arg works as > expected. > + xattr.get('/some/file', 'user.foo') > + xattr.get('/some/file', 'foo', namespace='user') > + self.assertEqual(call_mock.call_args_list[0], > call_mock.call_args_list[1]) > + > + # Verify nofollow behavior. > + call_mock.reset() > + xattr.get('/some/file', 'user.foo', nofollow=True) > + self.assertIn('-h', call_mock.call_args[0][0]) > + > + def testGetParsing(self): > + """Verify get() parses output sanely""" > + xattr = self._setUp() > + with mock.patch.object(subprocess, 'Popen') as call_mock: > + # Verify output parsing. > + call_mock.return_value = MockSubprocessPopen('\n'.join([ > + '# file: /some/file', > + 'user.foo="asdf"', > + '', > + ])) > + call_mock.reset() > + self.assertEqual(xattr.get('/some/file', 'user.foo'), > b
[gentoo-portage-dev] [PATCH v2] xattr: centralize the various shims in one place
Rather than each module implementing its own shim around the various methods for accessing extended attributes, start a dedicated module that exports a consistent API. --- v2 - passes unittests w/python 2.6 2.7 3.2 3.3 bin/xattr-helper.py | 11 +- pym/portage/tests/util/test_xattr.py | 178 ++ pym/portage/util/_xattr.py | 205 +++ pym/portage/util/movefile.py | 100 - 4 files changed, 407 insertions(+), 87 deletions(-) create mode 100644 pym/portage/tests/util/test_xattr.py create mode 100644 pym/portage/util/_xattr.py diff --git a/bin/xattr-helper.py b/bin/xattr-helper.py index 6d99521..69b83f7 100755 --- a/bin/xattr-helper.py +++ b/bin/xattr-helper.py @@ -17,16 +17,7 @@ import re import sys from portage.util._argparse import ArgumentParser - -if hasattr(os, "getxattr"): - - class xattr(object): - get = os.getxattr - set = os.setxattr - list = os.listxattr - -else: - import xattr +from portage.util._xattr import xattr _UNQUOTE_RE = re.compile(br'\\[0-7]{3}') diff --git a/pym/portage/tests/util/test_xattr.py b/pym/portage/tests/util/test_xattr.py new file mode 100644 index 000..e1f6ee8 --- /dev/null +++ b/pym/portage/tests/util/test_xattr.py @@ -0,0 +1,178 @@ +# Copyright 2010-2013 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 + +"""Tests for the portage.util._xattr module""" + +from __future__ import print_function + +try: + # Try python-3.3 module first. + from unittest import mock +except ImportError: + try: + # Try standalone module. + import mock + except ImportError: + mock = None + +import subprocess + +from portage.tests import TestCase +from portage.util._xattr import (xattr as _xattr, _XattrSystemCommands, + _XattrStub) + + +orig_popen = subprocess.Popen +def MockSubprocessPopen(stdin): + """Helper to mock (closely) a subprocess.Popen call + + The module has minor tweaks in behavior when it comes to encoding and + python versions, so use a real subprocess.Popen call to fake out the + runtime behavior. This way we don't have to also implement different + encodings as that gets ugly real fast. + """ + proc = orig_popen(['cat'], stdout=subprocess.PIPE, stdin=subprocess.PIPE) + try: + proc.stdin.write(bytes(stdin)) + except TypeError: + proc.stdin.write(bytes(stdin, 'ascii')) + return proc + + +class SystemCommandsTest(TestCase): + """Test _XattrSystemCommands""" + + OUTPUT = '\n'.join([ + '# file: /bin/ping', + 'security.capability=0sAQAAAgAgAAA=', + 'user.foo="asdf"', + '', + ]) + + def _setUp(self): + if mock is None: + self.skipTest('need mock for testing') + + return _XattrSystemCommands + + def _testGetBasic(self): + """Verify the get() behavior""" + xattr = self._setUp() + with mock.patch.object(subprocess, 'Popen') as call_mock: + # Verify basic behavior, and namespace arg works as expected. + xattr.get('/some/file', 'user.foo') + xattr.get('/some/file', 'foo', namespace='user') + self.assertEqual(call_mock.call_args_list[0], call_mock.call_args_list[1]) + + # Verify nofollow behavior. + call_mock.reset() + xattr.get('/some/file', 'user.foo', nofollow=True) + self.assertIn('-h', call_mock.call_args[0][0]) + + def testGetParsing(self): + """Verify get() parses output sanely""" + xattr = self._setUp() + with mock.patch.object(subprocess, 'Popen') as call_mock: + # Verify output parsing. + call_mock.return_value = MockSubprocessPopen('\n'.join([ + '# file: /some/file', + 'user.foo="asdf"', + '', + ])) + call_mock.reset() + self.assertEqual(xattr.get('/some/file', 'user.foo'), b'"asdf"') + + def testGetAllBasic(self): + """Verify the get_all() behavior""" + xattr = self._setUp() + with mock.patch.object(subprocess, 'Popen') as call_mock: + # Verify basic behavior. + xattr.get_all('/some/file') + + # Verify nofollow behavior. + call_mock.reset() + xattr.get_all('/some/file', nofollow=True) + self.as