Hello community, here is the log from the commit of package python-pyxattr for openSUSE:Factory checked in at 2020-12-04 21:27:43 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-pyxattr (Old) and /work/SRC/openSUSE:Factory/.python-pyxattr.new.5913 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-pyxattr" Fri Dec 4 21:27:43 2020 rev:4 rq:852915 version:0.7.2 Changes: -------- --- /work/SRC/openSUSE:Factory/python-pyxattr/python-pyxattr.changes 2020-11-23 19:01:10.962009758 +0100 +++ /work/SRC/openSUSE:Factory/.python-pyxattr.new.5913/python-pyxattr.changes 2020-12-04 21:27:46.954064096 +0100 @@ -1,0 +2,11 @@ +Mon Nov 30 12:13:40 UTC 2020 - Dan Čermák <dcer...@suse.com> + +- New upstream release 0.7.2 + + Minor release: + + * Expand testing by adding better mixed-access checks (e.g. set via symlink and read on file) and by not leaking resources during tests. + * Enable testing with Python 3.9 and confirm compatibility with it. + * Fix documentation building with Sphinx 3.0+. + +------------------------------------------------------------------- Old: ---- pyxattr-0.7.1.tar.gz pyxattr-0.7.1.tar.gz.asc New: ---- pyxattr-0.7.2.tar.gz pyxattr-0.7.2.tar.gz.asc ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-pyxattr.spec ++++++ --- /var/tmp/diff_new_pack.LQSvvX/_old 2020-12-04 21:27:47.766065262 +0100 +++ /var/tmp/diff_new_pack.LQSvvX/_new 2020-12-04 21:27:47.766065262 +0100 @@ -21,7 +21,7 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} %define github_url https://github.com/iustin/%{mod_name}/releases/download Name: python-%{mod_name} -Version: 0.7.1 +Version: 0.7.2 Release: 0 Summary: Filesystem extended attributes for python License: LGPL-2.1-or-later @@ -30,12 +30,12 @@ Source1: %{github_url}/v%{version}/%{mod_name}-%{version}.tar.gz.asc Source2: https://k1024.org/files/key.asc#/%{name}.keyring BuildRequires: %{python_module devel} +BuildRequires: %{python_module pytest} BuildRequires: %{python_module setuptools} BuildRequires: fdupes BuildRequires: gcc BuildRequires: libattr-devel BuildRequires: python-rpm-macros -BuildRequires: %{python_module pytest} %python_subpackages %description @@ -50,7 +50,7 @@ %python_build %check -%pytest_arch test +%pytest_arch tests %install %python_install ++++++ pyxattr-0.7.1.tar.gz -> pyxattr-0.7.2.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyxattr-0.7.1/MANIFEST.in new/pyxattr-0.7.2/MANIFEST.in --- old/pyxattr-0.7.1/MANIFEST.in 2019-11-23 22:22:42.000000000 +0100 +++ new/pyxattr-0.7.2/MANIFEST.in 2019-11-26 22:18:15.000000000 +0100 @@ -6,6 +6,6 @@ include doc/index.rst include doc/module.rst include setup.cfg -include test/test_xattr.py -include test/__init__.py +include tests/test_xattr.py +include tests/__init__.py include xattr.c diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyxattr-0.7.1/Makefile new/pyxattr-0.7.2/Makefile --- old/pyxattr-0.7.1/Makefile 2019-11-26 04:36:34.000000000 +0100 +++ new/pyxattr-0.7.2/Makefile 2020-11-29 20:39:34.000000000 +0100 @@ -5,13 +5,13 @@ DOCHTML = $(DOCDIR)/html DOCTREES = $(DOCDIR)/doctrees ALLSPHINXOPTS = -d $(DOCTREES) $(SPHINXOPTS) $(DOCDIR) -VERSION = 0.7.1 +VERSION = 0.7.2 FULLVER = pyxattr-$(VERSION) DISTFILE = $(FULLVER).tar.gz MODNAME = xattr.so RSTFILES = doc/index.rst doc/module.rst doc/news.rst doc/readme.md doc/conf.py -PYVERS = 3.4 3.5 3.6 3.7 3.8 +PYVERS = 3.4 3.5 3.6 3.7 3.8 3.9 REPS = 5 all: doc test @@ -48,19 +48,19 @@ if type python$$ver$$flavour >/dev/null; then \ echo Testing with python$$ver$$flavour; \ python$$ver$$flavour setup.py build_ext -i; \ - python$$ver$$flavour -m pytest test; \ + python$$ver$$flavour -m pytest tests; \ fi; \ done; \ done; @if type pypy3 >/dev/null; then \ echo Testing with pypy3; \ pypy3 setup.py build_ext -i; \ - pypy3 -m pytest test; \ + pypy3 -m pytest tests; \ fi fast-test: python3 setup.py build_ext -i - python3 -m pytest test -v + python3 -m pytest tests -v benchmark: $(MODNAME) @set -e; \ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyxattr-0.7.1/NEWS new/pyxattr-0.7.2/NEWS --- old/pyxattr-0.7.1/NEWS 2019-11-26 04:36:13.000000000 +0100 +++ new/pyxattr-0.7.2/NEWS 2020-11-29 20:39:51.000000000 +0100 @@ -1,6 +1,18 @@ News ==== +Version 0.7.2 +------------- + +*Sun, 29 Nov 2020* + +Minor release: + +* Expand testing by adding better mixed-access checks (e.g. set via + symlink and read on file) and by not leaking resources during tests. +* Enable testing with Python 3.9 and confirm compatibility with it. +* Fix documentation building with Sphinx 3.0+. + Version 0.7.1 ------------- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyxattr-0.7.1/PKG-INFO new/pyxattr-0.7.2/PKG-INFO --- old/pyxattr-0.7.1/PKG-INFO 2019-11-26 04:37:49.000000000 +0100 +++ new/pyxattr-0.7.2/PKG-INFO 2020-11-29 20:41:06.882087700 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 1.2 Name: pyxattr -Version: 0.7.1 +Version: 0.7.2 Summary: Filesystem extended attributes for python Home-page: http://pyxattr.k1024.org/ Author: Iustin Pop @@ -20,5 +20,6 @@ Classifier: Programming Language :: Python :: Implementation :: PyPy Classifier: Operating System :: MacOS :: MacOS X Classifier: Operating System :: POSIX :: Linux +Classifier: Topic :: Software Development :: Libraries :: Python Modules Classifier: Topic :: System :: Filesystems Requires-Python: >=3.4 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyxattr-0.7.1/README.md new/pyxattr-0.7.2/README.md --- old/pyxattr-0.7.1/README.md 2019-11-26 04:24:59.000000000 +0100 +++ new/pyxattr-0.7.2/README.md 2020-11-29 20:39:34.000000000 +0100 @@ -23,7 +23,7 @@ ## Requirements -The current supported Python versions are 3.4+. +The current supported Python versions are 3.4+ (tested up to 3.9). The library has been written and tested on Linux, kernel v2.4 or later, with XFS and ext2/ext3/ext3 file systems. If any other platform @@ -39,7 +39,7 @@ Or from your distribution, e.g. in Debian: - $ sudo install python3-pyxattr + $ sudo apt install python3-pyxattr ## Basic example diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyxattr-0.7.1/doc/conf.py new/pyxattr-0.7.2/doc/conf.py --- old/pyxattr-0.7.1/doc/conf.py 2019-11-26 04:36:43.000000000 +0100 +++ new/pyxattr-0.7.2/doc/conf.py 2020-11-29 20:39:34.000000000 +0100 @@ -25,7 +25,7 @@ # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['sphinx.ext.autodoc', 'sphinx.ext.todo'] +extensions = ['sphinx.ext.autodoc', 'sphinx.ext.todo', 'recommonmark'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -48,9 +48,9 @@ # built documents. # # The short X.Y version. -version = '0.7.1' +version = '0.7.2' # The full version, including alpha/beta/rc tags. -release = '0.7.1' +release = '0.7.2' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyxattr-0.7.1/pyxattr.egg-info/PKG-INFO new/pyxattr-0.7.2/pyxattr.egg-info/PKG-INFO --- old/pyxattr-0.7.1/pyxattr.egg-info/PKG-INFO 2019-11-26 04:37:49.000000000 +0100 +++ new/pyxattr-0.7.2/pyxattr.egg-info/PKG-INFO 2020-11-29 20:41:06.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 1.2 Name: pyxattr -Version: 0.7.1 +Version: 0.7.2 Summary: Filesystem extended attributes for python Home-page: http://pyxattr.k1024.org/ Author: Iustin Pop @@ -20,5 +20,6 @@ Classifier: Programming Language :: Python :: Implementation :: PyPy Classifier: Operating System :: MacOS :: MacOS X Classifier: Operating System :: POSIX :: Linux +Classifier: Topic :: Software Development :: Libraries :: Python Modules Classifier: Topic :: System :: Filesystems Requires-Python: >=3.4 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyxattr-0.7.1/pyxattr.egg-info/SOURCES.txt new/pyxattr-0.7.2/pyxattr.egg-info/SOURCES.txt --- old/pyxattr-0.7.1/pyxattr.egg-info/SOURCES.txt 2019-11-26 04:37:49.000000000 +0100 +++ new/pyxattr-0.7.2/pyxattr.egg-info/SOURCES.txt 2020-11-29 20:41:06.000000000 +0100 @@ -13,5 +13,5 @@ pyxattr.egg-info/SOURCES.txt pyxattr.egg-info/dependency_links.txt pyxattr.egg-info/top_level.txt -test/__init__.py -test/test_xattr.py \ No newline at end of file +tests/__init__.py +tests/test_xattr.py \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyxattr-0.7.1/setup.py new/pyxattr-0.7.2/setup.py --- old/pyxattr-0.7.1/setup.py 2019-11-26 04:36:54.000000000 +0100 +++ new/pyxattr-0.7.2/setup.py 2020-11-29 20:39:34.000000000 +0100 @@ -10,7 +10,7 @@ long_desc = """This is a C extension module for Python which implements extended attributes manipulation. It is a wrapper on top of the attr C library - see attr(5).""" -version = "0.7.1" +version = "0.7.2" author = "Iustin Pop" author_email = "ius...@k1024.org" libraries = [] @@ -33,7 +33,6 @@ define_macros=macros, extra_compile_args=["-Wall", "-Werror", "-Wsign-compare"], )], - test_suite = "test", platforms = ["Linux"], python_requires = ">=3.4", project_urls={ @@ -48,6 +47,7 @@ "Programming Language :: Python :: Implementation :: PyPy", "Operating System :: MacOS :: MacOS X", "Operating System :: POSIX :: Linux", + "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: System :: Filesystems", ] ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyxattr-0.7.1/test/test_xattr.py new/pyxattr-0.7.2/test/test_xattr.py --- old/pyxattr-0.7.1/test/test_xattr.py 2019-11-26 04:03:43.000000000 +0100 +++ new/pyxattr-0.7.2/test/test_xattr.py 1970-01-01 01:00:00.000000000 +0100 @@ -1,456 +0,0 @@ -# -# - -import sys -import tempfile -import os -import errno -import pytest -import pathlib -import platform -import io - -import xattr -from xattr import NS_USER, XATTR_CREATE, XATTR_REPLACE - -NAMESPACE = os.environ.get("NAMESPACE", NS_USER) - -EMPTY_NS = bytes() - -TEST_DIR = os.environ.get("TEST_DIR", ".") -TEST_IGNORE_XATTRS = os.environ.get("TEST_IGNORE_XATTRS", "") -if TEST_IGNORE_XATTRS == "": - TEST_IGNORE_XATTRS = [] -else: - TEST_IGNORE_XATTRS = TEST_IGNORE_XATTRS.split(",") - # The following has to be a list comprehension, not a generator, to - # avoid weird consequences of lazy evaluation. - TEST_IGNORE_XATTRS.extend([a.encode() for a in TEST_IGNORE_XATTRS]) - -USER_NN = "test" -USER_ATTR = NAMESPACE.decode() + "." + USER_NN -USER_VAL = "abc" -EMPTY_VAL = "" -LARGE_VAL = "x" * 2048 -MANYOPS_COUNT = 16384 - -USER_NN = USER_NN.encode() -USER_VAL = USER_VAL.encode() -USER_ATTR = USER_ATTR.encode() -EMPTY_VAL = EMPTY_VAL.encode() -LARGE_VAL = LARGE_VAL.encode() - -# Helper functions - -def ignore_tuples(attrs): - """Remove ignored attributes from the output of xattr.get_all.""" - return [attr for attr in attrs - if attr[0] not in TEST_IGNORE_XATTRS] - -def ignore(attrs): - """Remove ignored attributes from the output of xattr.list""" - return [attr for attr in attrs - if attr not in TEST_IGNORE_XATTRS] - -def lists_equal(attrs, value): - """Helper to check list equivalence, skipping TEST_IGNORE_XATTRS.""" - assert ignore(attrs) == value - -def tuples_equal(attrs, value): - """Helper to check list equivalence, skipping TEST_IGNORE_XATTRS.""" - assert ignore_tuples(attrs) == value - -# Fixtures and helpers - -@pytest.fixture -def testdir(): - """per-test temp dir based in TEST_DIR""" - with tempfile.TemporaryDirectory(dir=TEST_DIR) as dname: - yield dname - -def get_file(path): - fh, fname = tempfile.mkstemp(".test", "xattr-", path) - return fh, fname - -def get_file_name(path): - fh, fname = get_file(path) - os.close(fh) - return fname - -def get_file_fd(path): - return get_file(path)[0] - -def get_file_object(path): - fd = get_file(path)[0] - return os.fdopen(fd) - -def get_dir(path): - return tempfile.mkdtemp(".test", "xattr-", path) - -def get_symlink(path, dangling=True): - """create a symlink""" - fh, fname = get_file(path) - os.close(fh) - if dangling: - os.unlink(fname) - sname = fname + ".symlink" - os.symlink(fname, sname) - return fname, sname - -def get_valid_symlink(path): - return get_symlink(path, dangling=False)[1] - -def get_dangling_symlink(path): - return get_symlink(path, dangling=True)[1] - -def as_bytes(call): - def f(path): - return call(path).encode() - return f - -def as_fspath(call): - def f(path): - return pathlib.PurePath(call(path)) - return f - -def as_iostream(call): - def f(path): - return io.open(call(path), "r") - return f - -NOT_BEFORE_36 = pytest.mark.xfail(condition="sys.version_info < (3,6)", - strict=True) -NOT_PYPY = pytest.mark.xfail(condition="platform.python_implementation() == 'PyPy'", - strict=False) - -# Note: user attributes are only allowed on files and directories, so -# we have to skip the symlinks here. See xattr(7). -ITEMS_P = [ - (get_file_name, False), - (as_bytes(get_file_name), False), - pytest.param((as_fspath(get_file_name), False), - marks=[NOT_BEFORE_36, NOT_PYPY]), - (get_file_fd, False), - (get_file_object, False), - (as_iostream(get_file_name), False), - (get_dir, False), - (as_bytes(get_dir), False), - pytest.param((as_fspath(get_dir), False), - marks=[NOT_BEFORE_36, NOT_PYPY]), - (get_valid_symlink, False), - (as_bytes(get_valid_symlink), False), - pytest.param((as_fspath(get_valid_symlink), False), - marks=[NOT_BEFORE_36, NOT_PYPY]), -] - -ITEMS_D = [ - "file name", - "file name (bytes)", - "file name (path)", - "file FD", - "file object", - "file io stream", - "directory", - "directory (bytes)", - "directory (path)", - "file via symlink", - "file via symlink (bytes)", - "file via symlink (path)", -] - -ALL_ITEMS_P = ITEMS_P + [ - (get_valid_symlink, True), - (as_bytes(get_valid_symlink), True), - (get_dangling_symlink, True), - (as_bytes(get_dangling_symlink), True), -] - -ALL_ITEMS_D = ITEMS_D + [ - "valid symlink", - "valid symlink (bytes)", - "dangling symlink", - "dangling symlink (bytes)" -] - -@pytest.fixture(params=ITEMS_P, ids=ITEMS_D) -def subject(testdir, request): - return request.param[0](testdir), request.param[1] - -@pytest.fixture(params=ALL_ITEMS_P, ids=ALL_ITEMS_D) -def any_subject(testdir, request): - return request.param[0](testdir), request.param[1] - -@pytest.fixture(params=[True, False], ids=["with namespace", "no namespace"]) -def use_ns(request): - return request.param - -@pytest.fixture(params=[True, False], ids=["dangling", "valid"]) -def use_dangling(request): - return request.param - -### Test functions - -def test_empty_value(subject): - item, nofollow = subject - xattr.set(item, USER_ATTR, EMPTY_VAL, nofollow=nofollow) - assert xattr.get(item, USER_ATTR, nofollow=nofollow) == EMPTY_VAL - -def test_large_value(subject): - item, nofollow = subject - xattr.set(item, USER_ATTR, LARGE_VAL) - assert xattr.get(item, USER_ATTR, nofollow=nofollow) == LARGE_VAL - - -def test_file_mixed_access_deprecated(testdir): - """test mixed access to file (deprecated functions)""" - fh, fname = get_file(testdir) - with os.fdopen(fh) as fo: - lists_equal(xattr.listxattr(fname), []) - xattr.setxattr(fname, USER_ATTR, USER_VAL) - lists_equal(xattr.listxattr(fh), [USER_ATTR]) - assert xattr.getxattr(fo, USER_ATTR) == USER_VAL - tuples_equal(xattr.get_all(fo), [(USER_ATTR, USER_VAL)]) - tuples_equal(xattr.get_all(fname), - [(USER_ATTR, USER_VAL)]) - -def test_file_mixed_access(testdir): - """test mixed access to file""" - fh, fname = get_file(testdir) - with os.fdopen(fh) as fo: - lists_equal(xattr.list(fname), []) - xattr.set(fname, USER_ATTR, USER_VAL) - lists_equal(xattr.list(fh), [USER_ATTR]) - assert xattr.list(fh, namespace=NAMESPACE) == [USER_NN] - assert xattr.get(fo, USER_ATTR) == USER_VAL - assert xattr.get(fo, USER_NN, namespace=NAMESPACE) == USER_VAL - tuples_equal(xattr.get_all(fo), - [(USER_ATTR, USER_VAL)]) - assert xattr.get_all(fo, namespace=NAMESPACE) == \ - [(USER_NN, USER_VAL)] - tuples_equal(xattr.get_all(fname), [(USER_ATTR, USER_VAL)]) - assert xattr.get_all(fname, namespace=NAMESPACE) == \ - [(USER_NN, USER_VAL)] - -def test_replace_on_missing(subject, use_ns): - item = subject[0] - lists_equal(xattr.list(item), []) - with pytest.raises(EnvironmentError): - if use_ns: - xattr.set(item, USER_NN, USER_VAL, flags=XATTR_REPLACE, - namespace=NAMESPACE) - else: - xattr.set(item, USER_ATTR, USER_VAL, flags=XATTR_REPLACE) - -def test_create_on_existing(subject, use_ns): - item = subject[0] - lists_equal(xattr.list(item), []) - if use_ns: - xattr.set(item, USER_NN, USER_VAL, - namespace=NAMESPACE) - else: - xattr.set(item, USER_ATTR, USER_VAL) - with pytest.raises(EnvironmentError): - if use_ns: - xattr.set(item, USER_NN, USER_VAL, - flags=XATTR_CREATE, namespace=NAMESPACE) - else: - xattr.set(item, USER_ATTR, USER_VAL, flags=XATTR_CREATE) - -def test_remove_on_missing(any_subject, use_ns): - item, nofollow = any_subject - lists_equal(xattr.list(item, nofollow=nofollow), []) - with pytest.raises(EnvironmentError): - if use_ns: - xattr.remove(item, USER_NN, namespace=NAMESPACE, - nofollow=nofollow) - else: - xattr.remove(item, USER_ATTR, nofollow=nofollow) - -def test_set_get_remove(subject, use_ns): - item = subject[0] - lists_equal(xattr.list(item), []) - if use_ns: - xattr.set(item, USER_NN, USER_VAL, - namespace=NAMESPACE) - else: - xattr.set(item, USER_ATTR, USER_VAL) - if use_ns: - assert xattr.list(item, namespace=NAMESPACE) == [USER_NN] - else: - lists_equal(xattr.list(item), [USER_ATTR]) - lists_equal(xattr.list(item, namespace=EMPTY_NS), - [USER_ATTR]) - if use_ns: - assert xattr.get(item, USER_NN, namespace=NAMESPACE) == USER_VAL - else: - assert xattr.get(item, USER_ATTR) == USER_VAL - if use_ns: - assert xattr.get_all(item, namespace=NAMESPACE) == \ - [(USER_NN, USER_VAL)] - else: - tuples_equal(xattr.get_all(item), - [(USER_ATTR, USER_VAL)]) - if use_ns: - xattr.remove(item, USER_NN, namespace=NAMESPACE) - else: - xattr.remove(item, USER_ATTR) - lists_equal(xattr.list(item), []) - tuples_equal(xattr.get_all(item), []) - -def test_replace_on_missing_deprecated(subject): - item = subject[0] - lists_equal(xattr.listxattr(item), []) - with pytest.raises(EnvironmentError): - xattr.setxattr(item, USER_ATTR, USER_VAL, XATTR_REPLACE) - -def test_create_on_existing_deprecated(subject): - item = subject[0] - lists_equal(xattr.listxattr(item), []) - xattr.setxattr(item, USER_ATTR, USER_VAL, 0) - with pytest.raises(EnvironmentError): - xattr.setxattr(item, USER_ATTR, USER_VAL, XATTR_CREATE) - -def test_remove_on_missing_deprecated(any_subject): - """check deprecated list, set, get operations against an item""" - item, nofollow = any_subject - lists_equal(xattr.listxattr(item, nofollow), []) - with pytest.raises(EnvironmentError): - xattr.removexattr(item, USER_ATTR) - -def test_set_get_remove_deprecated(subject): - """check deprecated list, set, get operations against an item""" - item = subject[0] - lists_equal(xattr.listxattr(item), []) - xattr.setxattr(item, USER_ATTR, USER_VAL, 0) - lists_equal(xattr.listxattr(item), [USER_ATTR]) - assert xattr.getxattr(item, USER_ATTR) == USER_VAL - tuples_equal(xattr.get_all(item), [(USER_ATTR, USER_VAL)]) - xattr.removexattr(item, USER_ATTR) - lists_equal(xattr.listxattr(item), []) - tuples_equal(xattr.get_all(item), []) - -def test_many_ops(subject): - """test many ops""" - item = subject[0] - xattr.set(item, USER_ATTR, USER_VAL) - VL = [USER_ATTR] - VN = [USER_NN] - for i in range(MANYOPS_COUNT): - lists_equal(xattr.list(item), VL) - lists_equal(xattr.list(item, namespace=EMPTY_NS), VL) - assert xattr.list(item, namespace=NAMESPACE) == VN - for i in range(MANYOPS_COUNT): - assert xattr.get(item, USER_ATTR) == USER_VAL - assert xattr.get(item, USER_NN, namespace=NAMESPACE) == USER_VAL - for i in range(MANYOPS_COUNT): - tuples_equal(xattr.get_all(item), - [(USER_ATTR, USER_VAL)]) - assert xattr.get_all(item, namespace=NAMESPACE) == \ - [(USER_NN, USER_VAL)] - -def test_many_ops_deprecated(subject): - """test many ops (deprecated functions)""" - item = subject[0] - xattr.setxattr(item, USER_ATTR, USER_VAL) - VL = [USER_ATTR] - for i in range(MANYOPS_COUNT): - lists_equal(xattr.listxattr(item), VL) - for i in range(MANYOPS_COUNT): - assert xattr.getxattr(item, USER_ATTR) == USER_VAL - for i in range(MANYOPS_COUNT): - tuples_equal(xattr.get_all(item), - [(USER_ATTR, USER_VAL)]) - -def test_no_attributes_deprecated(any_subject): - """test no attributes (deprecated functions)""" - item, nofollow = any_subject - lists_equal(xattr.listxattr(item, True), []) - tuples_equal(xattr.get_all(item, True), []) - with pytest.raises(EnvironmentError): - xattr.getxattr(item, USER_ATTR, True) - -def test_no_attributes(any_subject): - """test no attributes""" - item, nofollow = any_subject - lists_equal(xattr.list(item, nofollow=nofollow), []) - assert xattr.list(item, nofollow=nofollow, - namespace=NAMESPACE) == [] - tuples_equal(xattr.get_all(item, nofollow=nofollow), []) - assert xattr.get_all(item, nofollow=nofollow, - namespace=NAMESPACE) == [] - with pytest.raises(EnvironmentError): - xattr.get(item, USER_NN, nofollow=nofollow, - namespace=NAMESPACE) - -def test_binary_payload_deprecated(subject): - """test binary values (deprecated functions)""" - item = subject[0] - BINVAL = b"abc\0def" - xattr.setxattr(item, USER_ATTR, BINVAL) - lists_equal(xattr.listxattr(item), [USER_ATTR]) - assert xattr.getxattr(item, USER_ATTR) == BINVAL - tuples_equal(xattr.get_all(item), [(USER_ATTR, BINVAL)]) - xattr.removexattr(item, USER_ATTR) - -def test_binary_payload(subject): - """test binary values""" - item = subject[0] - BINVAL = b"abc\0def" - xattr.set(item, USER_ATTR, BINVAL) - lists_equal(xattr.list(item), [USER_ATTR]) - assert xattr.list(item, namespace=NAMESPACE) == [USER_NN] - assert xattr.get(item, USER_ATTR) == BINVAL - assert xattr.get(item, USER_NN, namespace=NAMESPACE) == BINVAL - tuples_equal(xattr.get_all(item), [(USER_ATTR, BINVAL)]) - assert xattr.get_all(item, namespace=NAMESPACE) == [(USER_NN, BINVAL)] - xattr.remove(item, USER_ATTR) - -def test_symlinks_user_fail(testdir, use_dangling): - _, sname = get_symlink(testdir, dangling=use_dangling) - with pytest.raises(IOError): - xattr.set(sname, USER_ATTR, USER_VAL, nofollow=True) - with pytest.raises(IOError): - xattr.set(sname, USER_NN, USER_VAL, namespace=NAMESPACE, - nofollow=True) - with pytest.raises(IOError): - xattr.setxattr(sname, USER_ATTR, USER_VAL, XATTR_CREATE, True) - -@pytest.mark.parametrize( - "call, args", [(xattr.get, [USER_ATTR]), - (xattr.list, []), - (xattr.remove, [USER_ATTR]), - (xattr.get, [USER_ATTR]), - (xattr.set, [USER_ATTR, USER_VAL])]) -def test_none_namespace(testdir, call, args): - # Don't want to use subject, since that would prevent xfail test - # on path objects (due to hiding the exception here). - f = get_file_name(testdir) - with pytest.raises(TypeError): - call(f, *args, namespace=None) - fd = get_file_fd(testdir) - with pytest.raises(TypeError): - call(fd, *args, namespace=None) - -@pytest.mark.parametrize( - "call", - [xattr.get, xattr.list, xattr.listxattr, - xattr.remove, xattr.removexattr, - xattr.set, xattr.setxattr, - xattr.get, xattr.getxattr]) -def test_wrong_call(call): - with pytest.raises(TypeError): - call() - -@pytest.mark.parametrize( - "call, args", [(xattr.get, [USER_ATTR]), - (xattr.listxattr, []), - (xattr.list, []), - (xattr.remove, [USER_ATTR]), - (xattr.removexattr, [USER_ATTR]), - (xattr.get, [USER_ATTR]), - (xattr.getxattr, [USER_ATTR]), - (xattr.set, [USER_ATTR, USER_VAL]), - (xattr.setxattr, [USER_ATTR, USER_VAL])]) -def test_wrong_argument_type(call, args): - with pytest.raises(TypeError): - call(object(), *args) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyxattr-0.7.1/tests/test_xattr.py new/pyxattr-0.7.2/tests/test_xattr.py --- old/pyxattr-0.7.1/tests/test_xattr.py 1970-01-01 01:00:00.000000000 +0100 +++ new/pyxattr-0.7.2/tests/test_xattr.py 2019-11-26 22:12:39.000000000 +0100 @@ -0,0 +1,489 @@ +# +# + +import sys +import tempfile +import os +import errno +import pytest +import pathlib +import platform +import io +import contextlib + +import xattr +from xattr import NS_USER, XATTR_CREATE, XATTR_REPLACE + +NAMESPACE = os.environ.get("NAMESPACE", NS_USER) + +EMPTY_NS = bytes() + +TEST_DIR = os.environ.get("TEST_DIR", ".") +TEST_IGNORE_XATTRS = os.environ.get("TEST_IGNORE_XATTRS", "") +if TEST_IGNORE_XATTRS == "": + TEST_IGNORE_XATTRS = [] +else: + TEST_IGNORE_XATTRS = TEST_IGNORE_XATTRS.split(",") + # The following has to be a list comprehension, not a generator, to + # avoid weird consequences of lazy evaluation. + TEST_IGNORE_XATTRS.extend([a.encode() for a in TEST_IGNORE_XATTRS]) + +USER_NN = "test" +USER_ATTR = NAMESPACE.decode() + "." + USER_NN +USER_VAL = "abc" +EMPTY_VAL = "" +LARGE_VAL = "x" * 2048 +MANYOPS_COUNT = 16384 + +USER_NN = USER_NN.encode() +USER_VAL = USER_VAL.encode() +USER_ATTR = USER_ATTR.encode() +EMPTY_VAL = EMPTY_VAL.encode() +LARGE_VAL = LARGE_VAL.encode() + +# Helper functions + +def ignore_tuples(attrs): + """Remove ignored attributes from the output of xattr.get_all.""" + return [attr for attr in attrs + if attr[0] not in TEST_IGNORE_XATTRS] + +def ignore(attrs): + """Remove ignored attributes from the output of xattr.list""" + return [attr for attr in attrs + if attr not in TEST_IGNORE_XATTRS] + +def lists_equal(attrs, value): + """Helper to check list equivalence, skipping TEST_IGNORE_XATTRS.""" + assert ignore(attrs) == value + +def tuples_equal(attrs, value): + """Helper to check list equivalence, skipping TEST_IGNORE_XATTRS.""" + assert ignore_tuples(attrs) == value + +# Fixtures and helpers + +@pytest.fixture +def testdir(): + """per-test temp dir based in TEST_DIR""" + with tempfile.TemporaryDirectory(dir=TEST_DIR) as dname: + yield dname + +def get_file(path): + fh, fname = tempfile.mkstemp(".test", "xattr-", path) + return fh, fname + +@contextlib.contextmanager +def get_file_name(path): + fh, fname = get_file(path) + os.close(fh) + yield fname + +@contextlib.contextmanager +def get_file_fd(path): + fd = get_file(path)[0] + yield fd + os.close(fd) + +@contextlib.contextmanager +def get_file_object(path): + fd = get_file(path)[0] + with os.fdopen(fd) as f: + yield f + +@contextlib.contextmanager +def get_dir(path): + yield tempfile.mkdtemp(".test", "xattr-", path) + +def get_symlink(path, dangling=True): + """create a symlink""" + fh, fname = get_file(path) + os.close(fh) + if dangling: + os.unlink(fname) + sname = fname + ".symlink" + os.symlink(fname, sname) + return fname, sname + +@contextlib.contextmanager +def get_valid_symlink(path): + yield get_symlink(path, dangling=False)[1] + +@contextlib.contextmanager +def get_dangling_symlink(path): + yield get_symlink(path, dangling=True)[1] + +@contextlib.contextmanager +def get_file_and_symlink(path): + yield get_symlink(path, dangling=False) + +@contextlib.contextmanager +def get_file_and_fobject(path): + fh, fname = get_file(path) + with os.fdopen(fh) as fo: + yield fname, fo + +# Wrappers that build upon existing values + +def as_wrapper(call, fn, closer=None): + @contextlib.contextmanager + def f(path): + with call(path) as r: + val = fn(r) + yield val + if closer is not None: + closer(val) + return f + +def as_bytes(call): + return as_wrapper(call, lambda r: r.encode()) + +def as_fspath(call): + return as_wrapper(call, pathlib.PurePath) + +def as_iostream(call): + opener = lambda f: io.open(f, "r") + closer = lambda r: r.close() + return as_wrapper(call, opener, closer) + +NOT_BEFORE_36 = pytest.mark.xfail(condition="sys.version_info < (3,6)", + strict=True) +NOT_PYPY = pytest.mark.xfail(condition="platform.python_implementation() == 'PyPy'", + strict=False) + +# Note: user attributes are only allowed on files and directories, so +# we have to skip the symlinks here. See xattr(7). +ITEMS_P = [ + (get_file_name, False), + (as_bytes(get_file_name), False), + pytest.param((as_fspath(get_file_name), False), + marks=[NOT_BEFORE_36, NOT_PYPY]), + (get_file_fd, False), + (get_file_object, False), + (as_iostream(get_file_name), False), + (get_dir, False), + (as_bytes(get_dir), False), + pytest.param((as_fspath(get_dir), False), + marks=[NOT_BEFORE_36, NOT_PYPY]), + (get_valid_symlink, False), + (as_bytes(get_valid_symlink), False), + pytest.param((as_fspath(get_valid_symlink), False), + marks=[NOT_BEFORE_36, NOT_PYPY]), +] + +ITEMS_D = [ + "file name", + "file name (bytes)", + "file name (path)", + "file FD", + "file object", + "file io stream", + "directory", + "directory (bytes)", + "directory (path)", + "file via symlink", + "file via symlink (bytes)", + "file via symlink (path)", +] + +ALL_ITEMS_P = ITEMS_P + [ + (get_valid_symlink, True), + (as_bytes(get_valid_symlink), True), + (get_dangling_symlink, True), + (as_bytes(get_dangling_symlink), True), +] + +ALL_ITEMS_D = ITEMS_D + [ + "valid symlink", + "valid symlink (bytes)", + "dangling symlink", + "dangling symlink (bytes)" +] + +@pytest.fixture(params=ITEMS_P, ids=ITEMS_D) +def subject(testdir, request): + with request.param[0](testdir) as value: + yield value, request.param[1] + +@pytest.fixture(params=ALL_ITEMS_P, ids=ALL_ITEMS_D) +def any_subject(testdir, request): + with request.param[0](testdir) as value: + yield value, request.param[1] + +@pytest.fixture(params=[True, False], ids=["with namespace", "no namespace"]) +def use_ns(request): + return request.param + +@pytest.fixture(params=[True, False], ids=["dangling", "valid"]) +def use_dangling(request): + return request.param + +### Test functions + +def test_empty_value(subject): + item, nofollow = subject + xattr.set(item, USER_ATTR, EMPTY_VAL, nofollow=nofollow) + assert xattr.get(item, USER_ATTR, nofollow=nofollow) == EMPTY_VAL + +def test_large_value(subject): + item, nofollow = subject + xattr.set(item, USER_ATTR, LARGE_VAL) + assert xattr.get(item, USER_ATTR, nofollow=nofollow) == LARGE_VAL + +@pytest.mark.parametrize( + "gen", [ get_file_and_symlink, get_file_and_fobject ]) +def test_mixed_access(testdir, gen): + """test mixed access to file""" + with gen(testdir) as (a, b): + # Check empty + lists_equal(xattr.list(a), []) + lists_equal(xattr.listxattr(b), []) + + # Check value + xattr.set(a, USER_ATTR, USER_VAL) + for i in [a, b]: + # Deprecated functions + lists_equal(xattr.listxattr(i), [USER_ATTR]) + assert xattr.getxattr(i, USER_ATTR) == USER_VAL + tuples_equal(xattr.get_all(i), [(USER_ATTR, USER_VAL)]) + # Current functions + lists_equal(xattr.list(i), [USER_ATTR]) + assert xattr.list(i, namespace=NAMESPACE) == [USER_NN] + assert xattr.get(i, USER_ATTR) == USER_VAL + assert xattr.get(i, USER_NN, namespace=NAMESPACE) == USER_VAL + tuples_equal(xattr.get_all(i), + [(USER_ATTR, USER_VAL)]) + assert xattr.get_all(i, namespace=NAMESPACE) == \ + [(USER_NN, USER_VAL)] + + # Overwrite + xattr.set(b, USER_ATTR, LARGE_VAL, flags=xattr.XATTR_REPLACE) + assert xattr.get(a, USER_ATTR) == LARGE_VAL + assert xattr.getxattr(a, USER_ATTR) == LARGE_VAL + xattr.removexattr(b, USER_ATTR) + assert xattr.get_all(a, namespace=NAMESPACE) == [] + assert xattr.get_all(b, namespace=NAMESPACE) == [] + +def test_replace_on_missing(subject, use_ns): + item = subject[0] + lists_equal(xattr.list(item), []) + with pytest.raises(EnvironmentError): + if use_ns: + xattr.set(item, USER_NN, USER_VAL, flags=XATTR_REPLACE, + namespace=NAMESPACE) + else: + xattr.set(item, USER_ATTR, USER_VAL, flags=XATTR_REPLACE) + +def test_create_on_existing(subject, use_ns): + item = subject[0] + lists_equal(xattr.list(item), []) + if use_ns: + xattr.set(item, USER_NN, USER_VAL, + namespace=NAMESPACE) + else: + xattr.set(item, USER_ATTR, USER_VAL) + with pytest.raises(EnvironmentError): + if use_ns: + xattr.set(item, USER_NN, USER_VAL, + flags=XATTR_CREATE, namespace=NAMESPACE) + else: + xattr.set(item, USER_ATTR, USER_VAL, flags=XATTR_CREATE) + +def test_remove_on_missing(any_subject, use_ns): + item, nofollow = any_subject + lists_equal(xattr.list(item, nofollow=nofollow), []) + with pytest.raises(EnvironmentError): + if use_ns: + xattr.remove(item, USER_NN, namespace=NAMESPACE, + nofollow=nofollow) + else: + xattr.remove(item, USER_ATTR, nofollow=nofollow) + +def test_set_get_remove(subject, use_ns): + item = subject[0] + lists_equal(xattr.list(item), []) + if use_ns: + xattr.set(item, USER_NN, USER_VAL, + namespace=NAMESPACE) + else: + xattr.set(item, USER_ATTR, USER_VAL) + if use_ns: + assert xattr.list(item, namespace=NAMESPACE) == [USER_NN] + else: + lists_equal(xattr.list(item), [USER_ATTR]) + lists_equal(xattr.list(item, namespace=EMPTY_NS), + [USER_ATTR]) + if use_ns: + assert xattr.get(item, USER_NN, namespace=NAMESPACE) == USER_VAL + else: + assert xattr.get(item, USER_ATTR) == USER_VAL + if use_ns: + assert xattr.get_all(item, namespace=NAMESPACE) == \ + [(USER_NN, USER_VAL)] + else: + tuples_equal(xattr.get_all(item), + [(USER_ATTR, USER_VAL)]) + if use_ns: + xattr.remove(item, USER_NN, namespace=NAMESPACE) + else: + xattr.remove(item, USER_ATTR) + lists_equal(xattr.list(item), []) + tuples_equal(xattr.get_all(item), []) + +def test_replace_on_missing_deprecated(subject): + item = subject[0] + lists_equal(xattr.listxattr(item), []) + with pytest.raises(EnvironmentError): + xattr.setxattr(item, USER_ATTR, USER_VAL, XATTR_REPLACE) + +def test_create_on_existing_deprecated(subject): + item = subject[0] + lists_equal(xattr.listxattr(item), []) + xattr.setxattr(item, USER_ATTR, USER_VAL, 0) + with pytest.raises(EnvironmentError): + xattr.setxattr(item, USER_ATTR, USER_VAL, XATTR_CREATE) + +def test_remove_on_missing_deprecated(any_subject): + """check deprecated list, set, get operations against an item""" + item, nofollow = any_subject + lists_equal(xattr.listxattr(item, nofollow), []) + with pytest.raises(EnvironmentError): + xattr.removexattr(item, USER_ATTR) + +def test_set_get_remove_deprecated(subject): + """check deprecated list, set, get operations against an item""" + item = subject[0] + lists_equal(xattr.listxattr(item), []) + xattr.setxattr(item, USER_ATTR, USER_VAL, 0) + lists_equal(xattr.listxattr(item), [USER_ATTR]) + assert xattr.getxattr(item, USER_ATTR) == USER_VAL + tuples_equal(xattr.get_all(item), [(USER_ATTR, USER_VAL)]) + xattr.removexattr(item, USER_ATTR) + lists_equal(xattr.listxattr(item), []) + tuples_equal(xattr.get_all(item), []) + +def test_many_ops(subject): + """test many ops""" + item = subject[0] + xattr.set(item, USER_ATTR, USER_VAL) + VL = [USER_ATTR] + VN = [USER_NN] + for i in range(MANYOPS_COUNT): + lists_equal(xattr.list(item), VL) + lists_equal(xattr.list(item, namespace=EMPTY_NS), VL) + assert xattr.list(item, namespace=NAMESPACE) == VN + for i in range(MANYOPS_COUNT): + assert xattr.get(item, USER_ATTR) == USER_VAL + assert xattr.get(item, USER_NN, namespace=NAMESPACE) == USER_VAL + for i in range(MANYOPS_COUNT): + tuples_equal(xattr.get_all(item), + [(USER_ATTR, USER_VAL)]) + assert xattr.get_all(item, namespace=NAMESPACE) == \ + [(USER_NN, USER_VAL)] + +def test_many_ops_deprecated(subject): + """test many ops (deprecated functions)""" + item = subject[0] + xattr.setxattr(item, USER_ATTR, USER_VAL) + VL = [USER_ATTR] + for i in range(MANYOPS_COUNT): + lists_equal(xattr.listxattr(item), VL) + for i in range(MANYOPS_COUNT): + assert xattr.getxattr(item, USER_ATTR) == USER_VAL + for i in range(MANYOPS_COUNT): + tuples_equal(xattr.get_all(item), + [(USER_ATTR, USER_VAL)]) + +def test_no_attributes_deprecated(any_subject): + """test no attributes (deprecated functions)""" + item, nofollow = any_subject + lists_equal(xattr.listxattr(item, True), []) + tuples_equal(xattr.get_all(item, True), []) + with pytest.raises(EnvironmentError): + xattr.getxattr(item, USER_ATTR, True) + +def test_no_attributes(any_subject): + """test no attributes""" + item, nofollow = any_subject + lists_equal(xattr.list(item, nofollow=nofollow), []) + assert xattr.list(item, nofollow=nofollow, + namespace=NAMESPACE) == [] + tuples_equal(xattr.get_all(item, nofollow=nofollow), []) + assert xattr.get_all(item, nofollow=nofollow, + namespace=NAMESPACE) == [] + with pytest.raises(EnvironmentError): + xattr.get(item, USER_NN, nofollow=nofollow, + namespace=NAMESPACE) + +def test_binary_payload_deprecated(subject): + """test binary values (deprecated functions)""" + item = subject[0] + BINVAL = b"abc\0def" + xattr.setxattr(item, USER_ATTR, BINVAL) + lists_equal(xattr.listxattr(item), [USER_ATTR]) + assert xattr.getxattr(item, USER_ATTR) == BINVAL + tuples_equal(xattr.get_all(item), [(USER_ATTR, BINVAL)]) + xattr.removexattr(item, USER_ATTR) + +def test_binary_payload(subject): + """test binary values""" + item = subject[0] + BINVAL = b"abc\0def" + xattr.set(item, USER_ATTR, BINVAL) + lists_equal(xattr.list(item), [USER_ATTR]) + assert xattr.list(item, namespace=NAMESPACE) == [USER_NN] + assert xattr.get(item, USER_ATTR) == BINVAL + assert xattr.get(item, USER_NN, namespace=NAMESPACE) == BINVAL + tuples_equal(xattr.get_all(item), [(USER_ATTR, BINVAL)]) + assert xattr.get_all(item, namespace=NAMESPACE) == [(USER_NN, BINVAL)] + xattr.remove(item, USER_ATTR) + +def test_symlinks_user_fail(testdir, use_dangling): + _, sname = get_symlink(testdir, dangling=use_dangling) + with pytest.raises(IOError): + xattr.set(sname, USER_ATTR, USER_VAL, nofollow=True) + with pytest.raises(IOError): + xattr.set(sname, USER_NN, USER_VAL, namespace=NAMESPACE, + nofollow=True) + with pytest.raises(IOError): + xattr.setxattr(sname, USER_ATTR, USER_VAL, XATTR_CREATE, True) + +@pytest.mark.parametrize( + "call, args", [(xattr.get, [USER_ATTR]), + (xattr.list, []), + (xattr.remove, [USER_ATTR]), + (xattr.get, [USER_ATTR]), + (xattr.set, [USER_ATTR, USER_VAL])]) +def test_none_namespace(testdir, call, args): + # Don't want to use subject, since that would prevent xfail test + # on path objects (due to hiding the exception here). + f = get_file_name(testdir) + with pytest.raises(TypeError): + call(f, *args, namespace=None) + fd = get_file_fd(testdir) + with pytest.raises(TypeError): + call(fd, *args, namespace=None) + +@pytest.mark.parametrize( + "call", + [xattr.get, xattr.list, xattr.listxattr, + xattr.remove, xattr.removexattr, + xattr.set, xattr.setxattr, + xattr.get, xattr.getxattr]) +def test_wrong_call(call): + with pytest.raises(TypeError): + call() + +@pytest.mark.parametrize( + "call, args", [(xattr.get, [USER_ATTR]), + (xattr.listxattr, []), + (xattr.list, []), + (xattr.remove, [USER_ATTR]), + (xattr.removexattr, [USER_ATTR]), + (xattr.get, [USER_ATTR]), + (xattr.getxattr, [USER_ATTR]), + (xattr.set, [USER_ATTR, USER_VAL]), + (xattr.setxattr, [USER_ATTR, USER_VAL])]) +def test_wrong_argument_type(call, args): + with pytest.raises(TypeError): + call(object(), *args) _______________________________________________ openSUSE Commits mailing list -- commit@lists.opensuse.org To unsubscribe, email commit-le...@lists.opensuse.org List Netiquette: https://en.opensuse.org/openSUSE:Mailing_list_netiquette List Archives: https://lists.opensuse.org/archives/list/commit@lists.opensuse.org