Re: [gentoo-portage-dev] [PATCH v2] xattr: centralize the various shims in one place

2013-10-22 Thread Arfrever Frehtes Taifersar Arahesis
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

2013-10-20 Thread Mike Frysinger
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