From dcf8335648cf7b368c8230e1e71b9b1ecf5762ac Mon Sep 17 00:00:00 2001 From: Iustin Pop Date: Tue, 24 Jul 2018 23:45:55 +0200 Subject: [PATCH 01/16] Travis: add python 3.5 and 3.6 to build matrix Tests pass locally, so all seems good. --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 8d07539..35caa0d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,8 @@ python: - "2.7" - "3.3" - "3.4" + - "3.5" + - "3.6" - "nightly" # we don't need any python dependencies: -- 2.39.5 From bd7e8b3b3f53eee8bc53c4e7f7b7779c8b66c024 Mon Sep 17 00:00:00 2001 From: Iustin Pop Date: Sat, 2 Mar 2019 21:14:41 +0100 Subject: [PATCH 02/16] Travis: remove "sudo:false" Per the deprecation of container-based builds (https://blog.travis-ci.com/2018-11-19-required-linux-infrastructure-migration), remove the sudo:false setting. --- .travis.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 35caa0d..de545e8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,9 +16,6 @@ install: true # the test command: script: python ./setup.py test -# no need for sudo access, silence notice: -sudo: false - # enable OSX support, with only system python: matrix: include: -- 2.39.5 From 92d90564683495ae3f1ec23326198373cd81f529 Mon Sep 17 00:00:00 2001 From: Iustin Pop Date: Sun, 13 Oct 2019 17:57:04 +0200 Subject: [PATCH 03/16] Travis: remove obsolete python versions Some of them, at least. --- .travis.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index de545e8..b051ea0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,9 +2,7 @@ language: python # let's test as many versions as we can! python: - - "2.6" - "2.7" - - "3.3" - "3.4" - "3.5" - "3.6" -- 2.39.5 From 3cc4894fe04a6e776e1fdc60f5c01d2de733a26d Mon Sep 17 00:00:00 2001 From: Iustin Pop Date: Sat, 23 Nov 2019 00:00:48 +0100 Subject: [PATCH 04/16] Update Travis config to export coverage information Also enable newer Python (3.7, so not so new) under Linux. --- .travis.yml | 47 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 38 insertions(+), 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index b051ea0..5184af8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,15 +8,44 @@ python: - "3.6" - "nightly" -# we don't need any python dependencies: -install: true +# enable OSX support, with only system Python, and newer Python on Linux: +matrix: + include: + - os: osx + # specify a reasonably newer xcode so that brew works + osx_image: xcode11 + language: generic + python: + include: + - python: "3.7" + dist: xenial + +# install coverage helper: +install: gem install coveralls-lcov # the test command: -script: python ./setup.py test +script: + - python ./setup.py test + - make clean + - CFLAGS="-coverage" python ./setup.py test + +# install lcov, platform-specific but clean: +addons: + apt: + packages: + - lcov + homebrew: + packages: + - lcov + +# coverage settings from here: +env: + - COVERALLS_PARALLEL=true + +after_success: + - lcov --capture --no-external --directory . --output-file coverage.info + - coveralls-lcov coverage.info + +notifications: + webhooks: https://coveralls.io/webhook -# enable OSX support, with only system python: -matrix: - include: - - os: osx - language: generic - python: -- 2.39.5 From f0e724b620effc68f828086240832a6dde9aa444 Mon Sep 17 00:00:00 2001 From: Iustin Pop Date: Sat, 23 Nov 2019 21:08:17 +0100 Subject: [PATCH 05/16] Switch build system to Python 3 But still allow easy override (make ... PYTHON=python2). --- Makefile | 7 ++++--- setup.py | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 141685f..7515457 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,6 @@ +PYTHON = python3 SPHINXOPTS = -W -SPHINXBUILD = sphinx-build +SPHINXBUILD = $(PYTHON) -m sphinx DOCDIR = doc DOCHTML = $(DOCDIR)/html DOCTREES = $(DOCDIR)/doctrees @@ -13,7 +14,7 @@ REPS = 5 all: doc test $(MODNAME): xattr.c - ./setup.py build_ext --inplace + $(PYTHON) ./setup.py build_ext --inplace $(DOCHTML)/index.html: $(MODNAME) $(RSTFILES) $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(DOCHTML) @@ -22,7 +23,7 @@ $(DOCHTML)/index.html: $(MODNAME) $(RSTFILES) doc: $(DOCHTML)/index.html dist: - fakeroot ./setup.py sdist + fakeroot $(PYTHON) ./setup.py sdist test: @for ver in $(PYVERS); do \ diff --git a/setup.py b/setup.py index 4cd944b..26df53c 100755 --- a/setup.py +++ b/setup.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python3 import distutils import platform -- 2.39.5 From 75e8952e788f4081e10498563acd4626c378bfe1 Mon Sep 17 00:00:00 2001 From: Iustin Pop Date: Sat, 23 Nov 2019 21:53:37 +0100 Subject: [PATCH 06/16] Fix a docstring formatting issue This resulted in Sphinx altering the layout significantly. --- xattr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xattr.c b/xattr.c index 0087b7e..16b6876 100644 --- a/xattr.c +++ b/xattr.c @@ -1184,7 +1184,7 @@ static char __xattr_doc__[] = \ " a :exc:`EnvironmentError`; under\n" " Linux, the following ``errno`` values are used:\n" "\n" - " - ``ENODATA`` means that the attribute name is\n invalid\n" + " - ``ENODATA`` means that the attribute name is invalid\n" " - ``ENOTSUP`` and ``EOPNOTSUPP`` mean that the filesystem does not\n" " support extended attributes, or that the namespace is invalid\n" " - ``E2BIG`` mean that the attribute value is too big\n" -- 2.39.5 From d44999864280f9ecfe2e28c3ab75b11a704e43fd Mon Sep 17 00:00:00 2001 From: Iustin Pop Date: Sat, 23 Nov 2019 22:33:36 +0100 Subject: [PATCH 07/16] Switch README file to Markdown and expand it Let's get a bit more up with the times. --- MANIFEST.in | 5 ++-- Makefile | 9 ++++++- README.md | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++ README.rst | 41 -------------------------------- doc/conf.py | 7 +++++- doc/index.rst | 5 ++-- doc/news.rst | 1 - 7 files changed, 86 insertions(+), 48 deletions(-) create mode 100644 README.md delete mode 100644 README.rst delete mode 120000 doc/news.rst diff --git a/MANIFEST.in b/MANIFEST.in index 6c709af..e59fd38 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,9 +1,10 @@ include COPYING include NEWS -include README.rst +include README.md include Makefile include doc/conf.py -include doc/*.rst +include doc/index.rst +include doc/module.rst include setup.cfg include test/test_xattr.py include test/__init__.py diff --git a/Makefile b/Makefile index 7515457..bafcd44 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ DOCTREES = $(DOCDIR)/doctrees ALLSPHINXOPTS = -d $(DOCTREES) $(SPHINXOPTS) $(DOCDIR) MODNAME = xattr.so -RSTFILES = doc/index.rst doc/module.rst NEWS README.rst doc/conf.py +RSTFILES = doc/index.rst doc/module.rst doc/news.rst doc/readme.md doc/conf.py PYVERS = 2.4 2.5 2.6 2.7 3.0 3.1 3.2 3.3 3.4 3.5 3.6 3.7 REPS = 5 @@ -22,6 +22,12 @@ $(DOCHTML)/index.html: $(MODNAME) $(RSTFILES) doc: $(DOCHTML)/index.html +doc/readme.md: README.md + ln -s ../README.md doc/readme.md + +doc/news.rst: NEWS + ln -s ../NEWS doc/news.rst + dist: fakeroot $(PYTHON) ./setup.py sdist @@ -66,6 +72,7 @@ coverage: clean: rm -rf $(DOCHTML) $(DOCTREES) + rm -f doc/readme.md doc/news.rst rm -f $(MODNAME) rm -f *.so rm -rf build diff --git a/README.md b/README.md new file mode 100644 index 0000000..e63ac8f --- /dev/null +++ b/README.md @@ -0,0 +1,66 @@ +# pyxattr + +This is the pyxattr module, a Python extension module which gives access +to the extended attributes for filesystem objects available in some +operating systems. + +[![Travis](https://img.shields.io/travis/iustin/pyxattr)](https://travis-ci.org/iustin/pyxattr) +[![Coveralls github](https://img.shields.io/coveralls/github/iustin/pyxattr)](https://coveralls.io/github/iustin/pyxattr) +[![Read the Docs](https://img.shields.io/readthedocs/pyxattr)](http://pyxattr.readthedocs.io/en/latest/?badge=latest) +[![GitHub issues](https://img.shields.io/github/issues/iustin/pyxattr)](https://github.com/iustin/pyxattr/issues) +![GitHub tag (latest by date)](https://img.shields.io/github/v/tag/iustin/pyxattr) +[![GitHub release (latest by date)](https://img.shields.io/github/v/release/iustin/pyxattr)](https://github.com/iustin/pyxattr/releases) +[![PyPI](https://img.shields.io/pypi/v/pyxattr)](https://pypi.org/project/pyxattr/) +![Debian package](https://img.shields.io/debian/v/python-pyxattr) +![Ubuntu package](https://img.shields.io/ubuntu/v/python-pyxattr) +![GitHub Release Date](https://img.shields.io/github/release-date/iustin/pyxattr) +![GitHub commits since latest release](https://img.shields.io/github/commits-since/iustin/pyxattr/latest) +![GitHub last commit](https://img.shields.io/github/last-commit/iustin/pyxattr) + +Downloads: go to . The source +repository is either at or at +. + +## Requirements + +pyxattr has been written and tested on Linux, kernel v2.4 or later, +with XFS and ext2/ext3/ext3 file systems. If any other platform +implements the same behaviour, pyxattr could be used. + +You need to have the setuptools tool installed in order to build and +install the module, and for building the documentation you need to +have Sphinx installed. + +Alternatively, you can install directly from pip: + + $ pip install pyxattr + +Or from your distribution, e.g. in Debian: + + $ sudo install python3-pyxattr + +## Basic example + + >>> import xattr + >>> xattr.listxattr("file.txt") + ['user.mime_type'] + >>> xattr.getxattr("file.txt", "user.mime_type") + 'text/plain' + >>> xattr.setxattr("file.txt", "user.comment", "Simple text file") + >>> xattr.listxattr("file.txt") + ['user.mime_type', 'user.comment'] + >>> xattr.removexattr ("file.txt", "user.comment") + +## License + +pyxattr is Copyright 2002-2008, 2012-2015 Iustin Pop. + +pyxattr is free software; you can redistribute it and/or modify it under the +terms of the GNU Lesser General Public License as published by the Free +Software Foundation; either version 2.1 of the License, or (at your option) any +later version. See the COPYING file for the full license terms. + +Note that previous versions had different licenses: version 0.3 was licensed +under LGPL version 3 (which, I realized later, is not compatible with GPLv2, +hence the change to LGPL 2.1), and even older versions were licensed under GPL +v2 or later. diff --git a/README.rst b/README.rst deleted file mode 100644 index 033d597..0000000 --- a/README.rst +++ /dev/null @@ -1,41 +0,0 @@ -pyxattr -======= - -This is the pyxattr module, a Python extension module which gives access -to the extended attributes for filesystem objects available in some -operating systems. - -Downloads: go to https://pyxattr.k1024.org/downloads/. Latest -version is 0.6.1. The source repository is either at -http://git.k1024.org/pyxattr.git or at -https://github.com/iustin/pyxattr. - -Requirements ------------- - -pyxattr has been written and tested on Linux, kernel v2.4 or later, with -XFS filesystems; ext2/ext3 should work also. If any other platform -implements the same behavior, pyxattr could be used. - -You need to have the setuptools tool installed in order to build and -install the module. - -License -------- - -pyxattr is Copyright 2002-2008, 2012-2015 Iustin Pop. - -pyxattr is free software; you can redistribute it and/or modify it under the -terms of the GNU Lesser General Public License as published by the Free -Software Foundation; either version 2.1 of the License, or (at your option) any -later version. See the COPYING file for the full license terms. - -Note that previous versions had different licenses: version 0.3 was licensed -under LGPL version 3 (which, I realized later, is not compatible with GPLv2, -hence the change to LGPL 2.1), and even older versions were licensed under GPL -v2 or later. - -.. Local Variables: -.. mode: rst -.. fill-column: 72 -.. End: diff --git a/doc/conf.py b/doc/conf.py index a2ac56a..374cd19 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -31,7 +31,7 @@ extensions = ['sphinx.ext.autodoc', 'sphinx.ext.todo'] templates_path = ['_templates'] # The suffix of source filenames. -source_suffix = '.rst' +source_suffix = ['.rst', '.md'] # The encoding of source files. #source_encoding = 'utf-8-sig' @@ -90,6 +90,11 @@ pygments_style = 'sphinx' keep_warnings = True +# Note: this is still needed in Sphinx 1.8 with recommonmark 0.4.0 +# (https://github.com/readthedocs/recommonmark/issues/119): +source_parsers = { + '.md': 'recommonmark.parser.CommonMarkParser', +} # -- Options for HTML output --------------------------------------------------- diff --git a/doc/index.rst b/doc/index.rst index 6032182..a918c2e 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -2,8 +2,8 @@ Welcome to pyxattr's documentation! ====================================== -.. include:: ../README.rst - :start-line: 2 +See the :doc:`README ` for start, or the detailed :doc:`module +` information. Contents -------- @@ -11,6 +11,7 @@ Contents .. toctree:: :maxdepth: 2 + readme.md module.rst news.rst diff --git a/doc/news.rst b/doc/news.rst deleted file mode 120000 index 0fae0f8..0000000 --- a/doc/news.rst +++ /dev/null @@ -1 +0,0 @@ -../NEWS \ No newline at end of file -- 2.39.5 From 8f815e1628af4b1aa960202f2b05101b99c297bb Mon Sep 17 00:00:00 2001 From: Iustin Pop Date: Sat, 23 Nov 2019 22:34:29 +0100 Subject: [PATCH 08/16] Add a distcheck Makefile target MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Too bad setuptools doesn't have it built-in… --- Makefile | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index bafcd44..6761bff 100644 --- a/Makefile +++ b/Makefile @@ -5,6 +5,9 @@ DOCDIR = doc DOCHTML = $(DOCDIR)/html DOCTREES = $(DOCDIR)/doctrees ALLSPHINXOPTS = -d $(DOCTREES) $(SPHINXOPTS) $(DOCDIR) +VERSION = 0.6.1 +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 @@ -31,6 +34,14 @@ doc/news.rst: NEWS dist: fakeroot $(PYTHON) ./setup.py sdist +distcheck: dist + set -e; \ + TDIR=$$(mktemp -d) && \ + trap "rm -rf $$TDIR" EXIT; \ + tar xzf dist/$(DISTFILE) -C $$TDIR && \ + (cd $$TDIR/$(FULLVER) && make doc && make test && make dist) && \ + echo "All good, you can upload $(DISTFILE)!" + test: @for ver in $(PYVERS); do \ for flavour in "" "-dbg"; do \ @@ -77,4 +88,4 @@ clean: rm -f *.so rm -rf build -.PHONY: doc test clean dist coverage +.PHONY: doc test clean dist distcheck coverage -- 2.39.5 From 5cda87bbc14fb77362b8a6b9acf579e822edf52f Mon Sep 17 00:00:00 2001 From: Iustin Pop Date: Sun, 24 Nov 2019 14:53:12 +0100 Subject: [PATCH 09/16] Also export coverage results to codecov Will have to decide which to keep, but codecov at least supports partial line coverage (while missing nicer overall dashboard :/). --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 5184af8..19009c6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -45,6 +45,8 @@ env: after_success: - lcov --capture --no-external --directory . --output-file coverage.info - coveralls-lcov coverage.info + - pip install codecov + - codecov notifications: webhooks: https://coveralls.io/webhook -- 2.39.5 From 682c9505bab31ec3dfae5ab777b93ebe931c1cad Mon Sep 17 00:00:00 2001 From: Iustin Pop Date: Sun, 24 Nov 2019 14:53:57 +0100 Subject: [PATCH 10/16] Travis: test on py3.7 and 3.8 too --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 19009c6..2684c18 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,8 @@ python: - "3.4" - "3.5" - "3.6" + - "3.7" + - "3.8" - "nightly" # enable OSX support, with only system Python, and newer Python on Linux: @@ -50,4 +52,3 @@ after_success: notifications: webhooks: https://coveralls.io/webhook - -- 2.39.5 From e59b0db839c9f8b6e76ffe03f30c74a940ee9f4e Mon Sep 17 00:00:00 2001 From: Iustin Pop Date: Sun, 24 Nov 2019 14:54:56 +0100 Subject: [PATCH 11/16] Only export COVERALLS_PARALLEL in coveralls upload Having it shown as per-job env makes things more confusing. --- .travis.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2684c18..1f547c5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -40,13 +40,9 @@ addons: packages: - lcov -# coverage settings from here: -env: - - COVERALLS_PARALLEL=true - after_success: - lcov --capture --no-external --directory . --output-file coverage.info - - coveralls-lcov coverage.info + - COVERALLS_PARALLEL=true coveralls-lcov coverage.info - pip install codecov - codecov -- 2.39.5 From 73bb3f4bfe41ebe5d1d03bdb206858a3a710f641 Mon Sep 17 00:00:00 2001 From: Iustin Pop Date: Sun, 24 Nov 2019 15:41:02 +0100 Subject: [PATCH 12/16] Travis: remove hack for Python 3.7 test Current config was testing 3.7 twice :/ --- .travis.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1f547c5..e035a72 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,9 +18,6 @@ matrix: osx_image: xcode11 language: generic python: - include: - - python: "3.7" - dist: xenial # install coverage helper: install: gem install coveralls-lcov -- 2.39.5 From 579a5181f5aa67c98318e74888f6565a752396ee Mon Sep 17 00:00:00 2001 From: Iustin Pop Date: Mon, 25 Nov 2019 01:26:49 +0100 Subject: [PATCH 13/16] tests: move constants outside the class In preparation for pytest conversion. --- test/test_xattr.py | 219 +++++++++++++++++++++++---------------------- 1 file changed, 110 insertions(+), 109 deletions(-) diff --git a/test/test_xattr.py b/test/test_xattr.py index 7b14eec..09d685f 100644 --- a/test/test_xattr.py +++ b/test/test_xattr.py @@ -29,20 +29,21 @@ else: # 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 = 131072 + +if PY3K: + 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() + class xattrTest(unittest.TestCase): - USER_NN = "test" - USER_ATTR = NAMESPACE.decode() + "." + USER_NN - USER_VAL = "abc" - EMPTY_VAL = "" - LARGE_VAL = "x" * 2048 - MANYOPS_COUNT = 131072 - - if PY3K: - 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() @staticmethod def _ignore_tuples(attrs): @@ -109,10 +110,10 @@ class xattrTest(unittest.TestCase): """check deprecated list, set, get operations against an item""" self.checkList(xattr.listxattr(item, symlink), []) self.assertRaises(EnvironmentError, xattr.setxattr, item, - self.USER_ATTR, self.USER_VAL, + USER_ATTR, USER_VAL, XATTR_REPLACE, symlink) try: - xattr.setxattr(item, self.USER_ATTR, self.USER_VAL, 0, symlink) + xattr.setxattr(item, USER_ATTR, USER_VAL, 0, symlink) except IOError: err = sys.exc_info()[1] if symlink and (err.errno == errno.EPERM or @@ -123,38 +124,38 @@ class xattrTest(unittest.TestCase): return raise self.assertRaises(EnvironmentError, xattr.setxattr, item, - self.USER_ATTR, self.USER_VAL, XATTR_CREATE, symlink) - self.checkList(xattr.listxattr(item, symlink), [self.USER_ATTR]) - self.assertEqual(xattr.getxattr(item, self.USER_ATTR, symlink), - self.USER_VAL) + USER_ATTR, USER_VAL, XATTR_CREATE, symlink) + self.checkList(xattr.listxattr(item, symlink), [USER_ATTR]) + self.assertEqual(xattr.getxattr(item, USER_ATTR, symlink), + USER_VAL) self.checkTuples(xattr.get_all(item, nofollow=symlink), - [(self.USER_ATTR, self.USER_VAL)]) - xattr.removexattr(item, self.USER_ATTR, symlink) + [(USER_ATTR, USER_VAL)]) + xattr.removexattr(item, USER_ATTR, symlink) self.checkList(xattr.listxattr(item, symlink), []) self.checkTuples(xattr.get_all(item, nofollow=symlink), []) self.assertRaises(EnvironmentError, xattr.removexattr, - item, self.USER_ATTR, symlink) + item, USER_ATTR, symlink) def _checkListSetGet(self, item, symlink=False, use_ns=False): """check list, set, get operations against an item""" self.checkList(xattr.list(item, symlink), []) self.assertRaises(EnvironmentError, xattr.set, item, - self.USER_ATTR, self.USER_VAL, + USER_ATTR, USER_VAL, flags=XATTR_REPLACE, nofollow=symlink) self.assertRaises(EnvironmentError, xattr.set, item, - self.USER_NN, self.USER_VAL, + USER_NN, USER_VAL, flags=XATTR_REPLACE, namespace=NAMESPACE, nofollow=symlink) try: if use_ns: - xattr.set(item, self.USER_NN, self.USER_VAL, + xattr.set(item, USER_NN, USER_VAL, namespace=NAMESPACE, nofollow=symlink) else: - xattr.set(item, self.USER_ATTR, self.USER_VAL, + xattr.set(item, USER_ATTR, USER_VAL, nofollow=symlink) except IOError: err = sys.exc_info()[1] @@ -166,40 +167,40 @@ class xattrTest(unittest.TestCase): return raise self.assertRaises(EnvironmentError, xattr.set, item, - self.USER_ATTR, self.USER_VAL, + USER_ATTR, USER_VAL, flags=XATTR_CREATE, nofollow=symlink) self.assertRaises(EnvironmentError, xattr.set, item, - self.USER_NN, self.USER_VAL, + USER_NN, USER_VAL, flags=XATTR_CREATE, namespace=NAMESPACE, nofollow=symlink) - self.checkList(xattr.list(item, nofollow=symlink), [self.USER_ATTR]) + self.checkList(xattr.list(item, nofollow=symlink), [USER_ATTR]) self.checkList(xattr.list(item, nofollow=symlink, namespace=EMPTY_NS), - [self.USER_ATTR]) + [USER_ATTR]) self.assertEqual(xattr.list(item, namespace=NAMESPACE, nofollow=symlink), - [self.USER_NN]) - self.assertEqual(xattr.get(item, self.USER_ATTR, nofollow=symlink), - self.USER_VAL) - self.assertEqual(xattr.get(item, self.USER_NN, nofollow=symlink, - namespace=NAMESPACE), self.USER_VAL) + [USER_NN]) + self.assertEqual(xattr.get(item, USER_ATTR, nofollow=symlink), + USER_VAL) + self.assertEqual(xattr.get(item, USER_NN, nofollow=symlink, + namespace=NAMESPACE), USER_VAL) self.checkTuples(xattr.get_all(item, nofollow=symlink), - [(self.USER_ATTR, self.USER_VAL)]) + [(USER_ATTR, USER_VAL)]) self.assertEqual(xattr.get_all(item, nofollow=symlink, namespace=NAMESPACE), - [(self.USER_NN, self.USER_VAL)]) + [(USER_NN, USER_VAL)]) if use_ns: - xattr.remove(item, self.USER_NN, namespace=NAMESPACE, nofollow=symlink) + xattr.remove(item, USER_NN, namespace=NAMESPACE, nofollow=symlink) else: - xattr.remove(item, self.USER_ATTR, nofollow=symlink) + xattr.remove(item, USER_ATTR, nofollow=symlink) self.checkList(xattr.list(item, nofollow=symlink), []) self.checkTuples(xattr.get_all(item, nofollow=symlink), []) self.assertRaises(EnvironmentError, xattr.remove, - item, self.USER_ATTR, nofollow=symlink) + item, USER_ATTR, nofollow=symlink) self.assertRaises(EnvironmentError, xattr.remove, item, - self.USER_NN, namespace=NAMESPACE, nofollow=symlink) + USER_NN, namespace=NAMESPACE, nofollow=symlink) def testNoXattrDeprecated(self): """test no attributes (deprecated functions)""" @@ -207,17 +208,17 @@ class xattrTest(unittest.TestCase): self.checkList(xattr.listxattr(fname), []) self.checkTuples(xattr.get_all(fname), []) self.assertRaises(EnvironmentError, xattr.getxattr, fname, - self.USER_ATTR) + USER_ATTR) dname = self._getdir() self.checkList(xattr.listxattr(dname), []) self.checkTuples(xattr.get_all(dname), []) self.assertRaises(EnvironmentError, xattr.getxattr, dname, - self.USER_ATTR) + USER_ATTR) _, sname = self._getsymlink() self.checkList(xattr.listxattr(sname, True), []) self.checkTuples(xattr.get_all(sname, nofollow=True), []) self.assertRaises(EnvironmentError, xattr.getxattr, fname, - self.USER_ATTR, True) + USER_ATTR, True) def testNoXattr(self): @@ -228,14 +229,14 @@ class xattrTest(unittest.TestCase): self.checkTuples(xattr.get_all(fname), []) self.assertEqual(xattr.get_all(fname, namespace=NAMESPACE), []) self.assertRaises(EnvironmentError, xattr.get, fname, - self.USER_NN, namespace=NAMESPACE) + USER_NN, namespace=NAMESPACE) dname = self._getdir() self.checkList(xattr.list(dname), []) self.assertEqual(xattr.list(dname, namespace=NAMESPACE), []) self.checkTuples(xattr.get_all(dname), []) self.assertEqual(xattr.get_all(dname, namespace=NAMESPACE), []) self.assertRaises(EnvironmentError, xattr.get, dname, - self.USER_NN, namespace=NAMESPACE) + USER_NN, namespace=NAMESPACE) _, sname = self._getsymlink() self.checkList(xattr.list(sname, nofollow=True), []) self.assertEqual(xattr.list(sname, nofollow=True, @@ -244,7 +245,7 @@ class xattrTest(unittest.TestCase): self.assertEqual(xattr.get_all(sname, nofollow=True, namespace=NAMESPACE), []) self.assertRaises(EnvironmentError, xattr.get, sname, - self.USER_NN, namespace=NAMESPACE, nofollow=True) + USER_NN, namespace=NAMESPACE, nofollow=True) def testFileByNameDeprecated(self): """test set and retrieve one attribute by file name (deprecated)""" @@ -292,12 +293,12 @@ class xattrTest(unittest.TestCase): fh, fname = self._getfile() fo = os.fdopen(fh) self.checkList(xattr.listxattr(fname), []) - xattr.setxattr(fname, self.USER_ATTR, self.USER_VAL) - self.checkList(xattr.listxattr(fh), [self.USER_ATTR]) - self.assertEqual(xattr.getxattr(fo, self.USER_ATTR), self.USER_VAL) - self.checkTuples(xattr.get_all(fo), [(self.USER_ATTR, self.USER_VAL)]) + xattr.setxattr(fname, USER_ATTR, USER_VAL) + self.checkList(xattr.listxattr(fh), [USER_ATTR]) + self.assertEqual(xattr.getxattr(fo, USER_ATTR), USER_VAL) + self.checkTuples(xattr.get_all(fo), [(USER_ATTR, USER_VAL)]) self.checkTuples(xattr.get_all(fname), - [(self.USER_ATTR, self.USER_VAL)]) + [(USER_ATTR, USER_VAL)]) fo.close() def testMixedAccess(self): @@ -305,20 +306,20 @@ class xattrTest(unittest.TestCase): fh, fname = self._getfile() fo = os.fdopen(fh) self.checkList(xattr.list(fname), []) - xattr.set(fname, self.USER_ATTR, self.USER_VAL) - self.checkList(xattr.list(fh), [self.USER_ATTR]) - self.assertEqual(xattr.list(fh, namespace=NAMESPACE), [self.USER_NN]) - self.assertEqual(xattr.get(fo, self.USER_ATTR), self.USER_VAL) - self.assertEqual(xattr.get(fo, self.USER_NN, namespace=NAMESPACE), - self.USER_VAL) + xattr.set(fname, USER_ATTR, USER_VAL) + self.checkList(xattr.list(fh), [USER_ATTR]) + self.assertEqual(xattr.list(fh, namespace=NAMESPACE), [USER_NN]) + self.assertEqual(xattr.get(fo, USER_ATTR), USER_VAL) + self.assertEqual(xattr.get(fo, USER_NN, namespace=NAMESPACE), + USER_VAL) self.checkTuples(xattr.get_all(fo), - [(self.USER_ATTR, self.USER_VAL)]) + [(USER_ATTR, USER_VAL)]) self.assertEqual(xattr.get_all(fo, namespace=NAMESPACE), - [(self.USER_NN, self.USER_VAL)]) + [(USER_NN, USER_VAL)]) self.checkTuples(xattr.get_all(fname), - [(self.USER_ATTR, self.USER_VAL)]) + [(USER_ATTR, USER_VAL)]) self.assertEqual(xattr.get_all(fname, namespace=NAMESPACE), - [(self.USER_NN, self.USER_VAL)]) + [(USER_NN, USER_VAL)]) fo.close() def testDirOpsDeprecated(self): @@ -338,12 +339,12 @@ class xattrTest(unittest.TestCase): self.assertRaises(EnvironmentError, xattr.listxattr, sname) self._checkDeprecated(sname, symlink=True) target, sname = self._getsymlink(dangling=False) - xattr.setxattr(target, self.USER_ATTR, self.USER_VAL) - self.checkList(xattr.listxattr(target), [self.USER_ATTR]) + xattr.setxattr(target, USER_ATTR, USER_VAL) + self.checkList(xattr.listxattr(target), [USER_ATTR]) self.checkList(xattr.listxattr(sname, True), []) self.assertRaises(EnvironmentError, xattr.removexattr, sname, - self.USER_ATTR, True) - xattr.removexattr(sname, self.USER_ATTR, False) + USER_ATTR, True) + xattr.removexattr(sname, USER_ATTR, False) def testSymlinkOps(self): """test symlink operations""" @@ -352,12 +353,12 @@ class xattrTest(unittest.TestCase): self._checkListSetGet(sname, symlink=True) self._checkListSetGet(sname, symlink=True, use_ns=True) target, sname = self._getsymlink(dangling=False) - xattr.set(target, self.USER_ATTR, self.USER_VAL) - self.checkList(xattr.list(target), [self.USER_ATTR]) + xattr.set(target, USER_ATTR, USER_VAL) + self.checkList(xattr.list(target), [USER_ATTR]) self.checkList(xattr.list(sname, nofollow=True), []) self.assertRaises(EnvironmentError, xattr.remove, sname, - self.USER_ATTR, nofollow=True) - xattr.remove(sname, self.USER_ATTR, nofollow=False) + USER_ATTR, nofollow=True) + xattr.remove(sname, USER_ATTR, nofollow=False) def testBinaryPayloadDeprecated(self): """test binary values (deprecated functions)""" @@ -366,11 +367,11 @@ class xattrTest(unittest.TestCase): BINVAL = "abc" + '\0' + "def" if PY3K: BINVAL = BINVAL.encode() - xattr.setxattr(fname, self.USER_ATTR, BINVAL) - self.checkList(xattr.listxattr(fname), [self.USER_ATTR]) - self.assertEqual(xattr.getxattr(fname, self.USER_ATTR), BINVAL) - self.checkTuples(xattr.get_all(fname), [(self.USER_ATTR, BINVAL)]) - xattr.removexattr(fname, self.USER_ATTR) + xattr.setxattr(fname, USER_ATTR, BINVAL) + self.checkList(xattr.listxattr(fname), [USER_ATTR]) + self.assertEqual(xattr.getxattr(fname, USER_ATTR), BINVAL) + self.checkTuples(xattr.get_all(fname), [(USER_ATTR, BINVAL)]) + xattr.removexattr(fname, USER_ATTR) def testBinaryPayload(self): """test binary values""" @@ -379,59 +380,59 @@ class xattrTest(unittest.TestCase): BINVAL = "abc" + '\0' + "def" if PY3K: BINVAL = BINVAL.encode() - xattr.set(fname, self.USER_ATTR, BINVAL) - self.checkList(xattr.list(fname), [self.USER_ATTR]) - self.assertEqual(xattr.list(fname, namespace=NAMESPACE), [self.USER_NN]) - self.assertEqual(xattr.get(fname, self.USER_ATTR), BINVAL) - self.assertEqual(xattr.get(fname, self.USER_NN, + xattr.set(fname, USER_ATTR, BINVAL) + self.checkList(xattr.list(fname), [USER_ATTR]) + self.assertEqual(xattr.list(fname, namespace=NAMESPACE), [USER_NN]) + self.assertEqual(xattr.get(fname, USER_ATTR), BINVAL) + self.assertEqual(xattr.get(fname, USER_NN, namespace=NAMESPACE), BINVAL) - self.checkTuples(xattr.get_all(fname), [(self.USER_ATTR, BINVAL)]) + self.checkTuples(xattr.get_all(fname), [(USER_ATTR, BINVAL)]) self.assertEqual(xattr.get_all(fname, namespace=NAMESPACE), - [(self.USER_NN, BINVAL)]) - xattr.remove(fname, self.USER_ATTR) + [(USER_NN, BINVAL)]) + xattr.remove(fname, USER_ATTR) def testManyOpsDeprecated(self): """test many ops (deprecated functions)""" fh, fname = self._getfile() - xattr.setxattr(fh, self.USER_ATTR, self.USER_VAL) - VL = [self.USER_ATTR] - for i in range(self.MANYOPS_COUNT): + xattr.setxattr(fh, USER_ATTR, USER_VAL) + VL = [USER_ATTR] + for i in range(MANYOPS_COUNT): self.checkList(xattr.listxattr(fh), VL) - for i in range(self.MANYOPS_COUNT): - self.assertEqual(xattr.getxattr(fh, self.USER_ATTR), self.USER_VAL) - for i in range(self.MANYOPS_COUNT): + for i in range(MANYOPS_COUNT): + self.assertEqual(xattr.getxattr(fh, USER_ATTR), USER_VAL) + for i in range(MANYOPS_COUNT): self.checkTuples(xattr.get_all(fh), - [(self.USER_ATTR, self.USER_VAL)]) + [(USER_ATTR, USER_VAL)]) def testManyOps(self): """test many ops""" fh, fname = self._getfile() - xattr.set(fh, self.USER_ATTR, self.USER_VAL) - VL = [self.USER_ATTR] - VN = [self.USER_NN] - for i in range(self.MANYOPS_COUNT): + xattr.set(fh, USER_ATTR, USER_VAL) + VL = [USER_ATTR] + VN = [USER_NN] + for i in range(MANYOPS_COUNT): self.checkList(xattr.list(fh), VL) self.checkList(xattr.list(fh, namespace=EMPTY_NS), VL) self.assertEqual(xattr.list(fh, namespace=NAMESPACE), VN) - for i in range(self.MANYOPS_COUNT): - self.assertEqual(xattr.get(fh, self.USER_ATTR), self.USER_VAL) - self.assertEqual(xattr.get(fh, self.USER_NN, namespace=NAMESPACE), - self.USER_VAL) - for i in range(self.MANYOPS_COUNT): + for i in range(MANYOPS_COUNT): + self.assertEqual(xattr.get(fh, USER_ATTR), USER_VAL) + self.assertEqual(xattr.get(fh, USER_NN, namespace=NAMESPACE), + USER_VAL) + for i in range(MANYOPS_COUNT): self.checkTuples(xattr.get_all(fh), - [(self.USER_ATTR, self.USER_VAL)]) + [(USER_ATTR, USER_VAL)]) self.assertEqual(xattr.get_all(fh, namespace=NAMESPACE), - [(self.USER_NN, self.USER_VAL)]) + [(USER_NN, USER_VAL)]) def testNoneNamespace(self): fh, fname = self._getfile() - self.assertRaises(TypeError, xattr.get, fh, self.USER_ATTR, + self.assertRaises(TypeError, xattr.get, fh, USER_ATTR, namespace=None) def testEmptyValue(self): fh, fname = self._getfile() - xattr.set(fh, self.USER_ATTR, self.EMPTY_VAL) - self.assertEqual(xattr.get(fh, self.USER_ATTR), self.EMPTY_VAL) + xattr.set(fh, USER_ATTR, EMPTY_VAL) + self.assertEqual(xattr.get(fh, USER_ATTR), EMPTY_VAL) def testWrongCall(self): for call in [xattr.get, @@ -442,21 +443,21 @@ class xattrTest(unittest.TestCase): self.assertRaises(TypeError, call) def testWrongType(self): - self.assertRaises(TypeError, xattr.get, object(), self.USER_ATTR) + self.assertRaises(TypeError, xattr.get, object(), USER_ATTR) for call in [xattr.listxattr, xattr.list]: self.assertRaises(TypeError, call, object()) for call in [xattr.remove, xattr.removexattr, xattr.get, xattr.getxattr]: - self.assertRaises(TypeError, call, object(), self.USER_ATTR) + self.assertRaises(TypeError, call, object(), USER_ATTR) for call in [xattr.set, xattr.setxattr]: - self.assertRaises(TypeError, call, object(), self.USER_ATTR, self.USER_VAL) + self.assertRaises(TypeError, call, object(), USER_ATTR, USER_VAL) def testLargeAttribute(self): fh, fname = self._getfile() - xattr.set(fh, self.USER_ATTR, self.LARGE_VAL) - self.assertEqual(xattr.get(fh, self.USER_ATTR), self.LARGE_VAL) + xattr.set(fh, USER_ATTR, LARGE_VAL) + self.assertEqual(xattr.get(fh, USER_ATTR), LARGE_VAL) if __name__ == "__main__": -- 2.39.5 From 1a589c89e33dbb579ccb1799b862120b23d85b2c Mon Sep 17 00:00:00 2001 From: Iustin Pop Date: Mon, 25 Nov 2019 01:37:05 +0100 Subject: [PATCH 14/16] tests: move helper function outside the test class MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Not sure why these were there in the first place… --- test/test_xattr.py | 120 ++++++++++++++++++++++----------------------- 1 file changed, 59 insertions(+), 61 deletions(-) diff --git a/test/test_xattr.py b/test/test_xattr.py index 09d685f..eab0822 100644 --- a/test/test_xattr.py +++ b/test/test_xattr.py @@ -43,28 +43,26 @@ if PY3K: EMPTY_VAL = EMPTY_VAL.encode() LARGE_VAL = LARGE_VAL.encode() -class xattrTest(unittest.TestCase): +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] - @staticmethod - 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] - @staticmethod - 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 checkList(self, attrs, value): - """Helper to check list equivalence, skipping TEST_IGNORE_XATTRS.""" - self.assertEqual(self._ignore(attrs), value) +def tuples_equal(attrs, value): + """Helper to check list equivalence, skipping TEST_IGNORE_XATTRS.""" + assert ignore_tuples(attrs) == value - def checkTuples(self, attrs, value): - """Helper to check list equivalence, skipping TEST_IGNORE_XATTRS.""" - self.assertEqual(self._ignore_tuples(attrs), value) +class xattrTest(unittest.TestCase): def setUp(self): """set up function""" self.rmfiles = [] @@ -108,7 +106,7 @@ class xattrTest(unittest.TestCase): def _checkDeprecated(self, item, symlink=False): """check deprecated list, set, get operations against an item""" - self.checkList(xattr.listxattr(item, symlink), []) + lists_equal(xattr.listxattr(item, symlink), []) self.assertRaises(EnvironmentError, xattr.setxattr, item, USER_ATTR, USER_VAL, XATTR_REPLACE, symlink) @@ -125,21 +123,21 @@ class xattrTest(unittest.TestCase): raise self.assertRaises(EnvironmentError, xattr.setxattr, item, USER_ATTR, USER_VAL, XATTR_CREATE, symlink) - self.checkList(xattr.listxattr(item, symlink), [USER_ATTR]) + lists_equal(xattr.listxattr(item, symlink), [USER_ATTR]) self.assertEqual(xattr.getxattr(item, USER_ATTR, symlink), USER_VAL) - self.checkTuples(xattr.get_all(item, nofollow=symlink), + tuples_equal(xattr.get_all(item, nofollow=symlink), [(USER_ATTR, USER_VAL)]) xattr.removexattr(item, USER_ATTR, symlink) - self.checkList(xattr.listxattr(item, symlink), []) - self.checkTuples(xattr.get_all(item, nofollow=symlink), + lists_equal(xattr.listxattr(item, symlink), []) + tuples_equal(xattr.get_all(item, nofollow=symlink), []) self.assertRaises(EnvironmentError, xattr.removexattr, item, USER_ATTR, symlink) def _checkListSetGet(self, item, symlink=False, use_ns=False): """check list, set, get operations against an item""" - self.checkList(xattr.list(item, symlink), []) + lists_equal(xattr.list(item, symlink), []) self.assertRaises(EnvironmentError, xattr.set, item, USER_ATTR, USER_VAL, flags=XATTR_REPLACE, @@ -175,8 +173,8 @@ class xattrTest(unittest.TestCase): flags=XATTR_CREATE, namespace=NAMESPACE, nofollow=symlink) - self.checkList(xattr.list(item, nofollow=symlink), [USER_ATTR]) - self.checkList(xattr.list(item, nofollow=symlink, + lists_equal(xattr.list(item, nofollow=symlink), [USER_ATTR]) + lists_equal(xattr.list(item, nofollow=symlink, namespace=EMPTY_NS), [USER_ATTR]) self.assertEqual(xattr.list(item, namespace=NAMESPACE, nofollow=symlink), @@ -185,7 +183,7 @@ class xattrTest(unittest.TestCase): USER_VAL) self.assertEqual(xattr.get(item, USER_NN, nofollow=symlink, namespace=NAMESPACE), USER_VAL) - self.checkTuples(xattr.get_all(item, nofollow=symlink), + tuples_equal(xattr.get_all(item, nofollow=symlink), [(USER_ATTR, USER_VAL)]) self.assertEqual(xattr.get_all(item, nofollow=symlink, namespace=NAMESPACE), @@ -194,8 +192,8 @@ class xattrTest(unittest.TestCase): xattr.remove(item, USER_NN, namespace=NAMESPACE, nofollow=symlink) else: xattr.remove(item, USER_ATTR, nofollow=symlink) - self.checkList(xattr.list(item, nofollow=symlink), []) - self.checkTuples(xattr.get_all(item, nofollow=symlink), + lists_equal(xattr.list(item, nofollow=symlink), []) + tuples_equal(xattr.get_all(item, nofollow=symlink), []) self.assertRaises(EnvironmentError, xattr.remove, item, USER_ATTR, nofollow=symlink) @@ -205,18 +203,18 @@ class xattrTest(unittest.TestCase): def testNoXattrDeprecated(self): """test no attributes (deprecated functions)""" fh, fname = self._getfile() - self.checkList(xattr.listxattr(fname), []) - self.checkTuples(xattr.get_all(fname), []) + lists_equal(xattr.listxattr(fname), []) + tuples_equal(xattr.get_all(fname), []) self.assertRaises(EnvironmentError, xattr.getxattr, fname, USER_ATTR) dname = self._getdir() - self.checkList(xattr.listxattr(dname), []) - self.checkTuples(xattr.get_all(dname), []) + lists_equal(xattr.listxattr(dname), []) + tuples_equal(xattr.get_all(dname), []) self.assertRaises(EnvironmentError, xattr.getxattr, dname, USER_ATTR) _, sname = self._getsymlink() - self.checkList(xattr.listxattr(sname, True), []) - self.checkTuples(xattr.get_all(sname, nofollow=True), []) + lists_equal(xattr.listxattr(sname, True), []) + tuples_equal(xattr.get_all(sname, nofollow=True), []) self.assertRaises(EnvironmentError, xattr.getxattr, fname, USER_ATTR, True) @@ -224,24 +222,24 @@ class xattrTest(unittest.TestCase): def testNoXattr(self): """test no attributes""" fh, fname = self._getfile() - self.checkList(xattr.list(fname), []) + lists_equal(xattr.list(fname), []) self.assertEqual(xattr.list(fname, namespace=NAMESPACE), []) - self.checkTuples(xattr.get_all(fname), []) + tuples_equal(xattr.get_all(fname), []) self.assertEqual(xattr.get_all(fname, namespace=NAMESPACE), []) self.assertRaises(EnvironmentError, xattr.get, fname, USER_NN, namespace=NAMESPACE) dname = self._getdir() - self.checkList(xattr.list(dname), []) + lists_equal(xattr.list(dname), []) self.assertEqual(xattr.list(dname, namespace=NAMESPACE), []) - self.checkTuples(xattr.get_all(dname), []) + tuples_equal(xattr.get_all(dname), []) self.assertEqual(xattr.get_all(dname, namespace=NAMESPACE), []) self.assertRaises(EnvironmentError, xattr.get, dname, USER_NN, namespace=NAMESPACE) _, sname = self._getsymlink() - self.checkList(xattr.list(sname, nofollow=True), []) + lists_equal(xattr.list(sname, nofollow=True), []) self.assertEqual(xattr.list(sname, nofollow=True, namespace=NAMESPACE), []) - self.checkTuples(xattr.get_all(sname, nofollow=True), []) + tuples_equal(xattr.get_all(sname, nofollow=True), []) self.assertEqual(xattr.get_all(sname, nofollow=True, namespace=NAMESPACE), []) self.assertRaises(EnvironmentError, xattr.get, sname, @@ -292,12 +290,12 @@ class xattrTest(unittest.TestCase): """test mixed access to file (deprecated functions)""" fh, fname = self._getfile() fo = os.fdopen(fh) - self.checkList(xattr.listxattr(fname), []) + lists_equal(xattr.listxattr(fname), []) xattr.setxattr(fname, USER_ATTR, USER_VAL) - self.checkList(xattr.listxattr(fh), [USER_ATTR]) + lists_equal(xattr.listxattr(fh), [USER_ATTR]) self.assertEqual(xattr.getxattr(fo, USER_ATTR), USER_VAL) - self.checkTuples(xattr.get_all(fo), [(USER_ATTR, USER_VAL)]) - self.checkTuples(xattr.get_all(fname), + tuples_equal(xattr.get_all(fo), [(USER_ATTR, USER_VAL)]) + tuples_equal(xattr.get_all(fname), [(USER_ATTR, USER_VAL)]) fo.close() @@ -305,18 +303,18 @@ class xattrTest(unittest.TestCase): """test mixed access to file""" fh, fname = self._getfile() fo = os.fdopen(fh) - self.checkList(xattr.list(fname), []) + lists_equal(xattr.list(fname), []) xattr.set(fname, USER_ATTR, USER_VAL) - self.checkList(xattr.list(fh), [USER_ATTR]) + lists_equal(xattr.list(fh), [USER_ATTR]) self.assertEqual(xattr.list(fh, namespace=NAMESPACE), [USER_NN]) self.assertEqual(xattr.get(fo, USER_ATTR), USER_VAL) self.assertEqual(xattr.get(fo, USER_NN, namespace=NAMESPACE), USER_VAL) - self.checkTuples(xattr.get_all(fo), + tuples_equal(xattr.get_all(fo), [(USER_ATTR, USER_VAL)]) self.assertEqual(xattr.get_all(fo, namespace=NAMESPACE), [(USER_NN, USER_VAL)]) - self.checkTuples(xattr.get_all(fname), + tuples_equal(xattr.get_all(fname), [(USER_ATTR, USER_VAL)]) self.assertEqual(xattr.get_all(fname, namespace=NAMESPACE), [(USER_NN, USER_VAL)]) @@ -340,8 +338,8 @@ class xattrTest(unittest.TestCase): self._checkDeprecated(sname, symlink=True) target, sname = self._getsymlink(dangling=False) xattr.setxattr(target, USER_ATTR, USER_VAL) - self.checkList(xattr.listxattr(target), [USER_ATTR]) - self.checkList(xattr.listxattr(sname, True), []) + lists_equal(xattr.listxattr(target), [USER_ATTR]) + lists_equal(xattr.listxattr(sname, True), []) self.assertRaises(EnvironmentError, xattr.removexattr, sname, USER_ATTR, True) xattr.removexattr(sname, USER_ATTR, False) @@ -354,8 +352,8 @@ class xattrTest(unittest.TestCase): self._checkListSetGet(sname, symlink=True, use_ns=True) target, sname = self._getsymlink(dangling=False) xattr.set(target, USER_ATTR, USER_VAL) - self.checkList(xattr.list(target), [USER_ATTR]) - self.checkList(xattr.list(sname, nofollow=True), []) + lists_equal(xattr.list(target), [USER_ATTR]) + lists_equal(xattr.list(sname, nofollow=True), []) self.assertRaises(EnvironmentError, xattr.remove, sname, USER_ATTR, nofollow=True) xattr.remove(sname, USER_ATTR, nofollow=False) @@ -368,9 +366,9 @@ class xattrTest(unittest.TestCase): if PY3K: BINVAL = BINVAL.encode() xattr.setxattr(fname, USER_ATTR, BINVAL) - self.checkList(xattr.listxattr(fname), [USER_ATTR]) + lists_equal(xattr.listxattr(fname), [USER_ATTR]) self.assertEqual(xattr.getxattr(fname, USER_ATTR), BINVAL) - self.checkTuples(xattr.get_all(fname), [(USER_ATTR, BINVAL)]) + tuples_equal(xattr.get_all(fname), [(USER_ATTR, BINVAL)]) xattr.removexattr(fname, USER_ATTR) def testBinaryPayload(self): @@ -381,12 +379,12 @@ class xattrTest(unittest.TestCase): if PY3K: BINVAL = BINVAL.encode() xattr.set(fname, USER_ATTR, BINVAL) - self.checkList(xattr.list(fname), [USER_ATTR]) + lists_equal(xattr.list(fname), [USER_ATTR]) self.assertEqual(xattr.list(fname, namespace=NAMESPACE), [USER_NN]) self.assertEqual(xattr.get(fname, USER_ATTR), BINVAL) self.assertEqual(xattr.get(fname, USER_NN, namespace=NAMESPACE), BINVAL) - self.checkTuples(xattr.get_all(fname), [(USER_ATTR, BINVAL)]) + tuples_equal(xattr.get_all(fname), [(USER_ATTR, BINVAL)]) self.assertEqual(xattr.get_all(fname, namespace=NAMESPACE), [(USER_NN, BINVAL)]) xattr.remove(fname, USER_ATTR) @@ -397,11 +395,11 @@ class xattrTest(unittest.TestCase): xattr.setxattr(fh, USER_ATTR, USER_VAL) VL = [USER_ATTR] for i in range(MANYOPS_COUNT): - self.checkList(xattr.listxattr(fh), VL) + lists_equal(xattr.listxattr(fh), VL) for i in range(MANYOPS_COUNT): self.assertEqual(xattr.getxattr(fh, USER_ATTR), USER_VAL) for i in range(MANYOPS_COUNT): - self.checkTuples(xattr.get_all(fh), + tuples_equal(xattr.get_all(fh), [(USER_ATTR, USER_VAL)]) def testManyOps(self): @@ -411,15 +409,15 @@ class xattrTest(unittest.TestCase): VL = [USER_ATTR] VN = [USER_NN] for i in range(MANYOPS_COUNT): - self.checkList(xattr.list(fh), VL) - self.checkList(xattr.list(fh, namespace=EMPTY_NS), VL) + lists_equal(xattr.list(fh), VL) + lists_equal(xattr.list(fh, namespace=EMPTY_NS), VL) self.assertEqual(xattr.list(fh, namespace=NAMESPACE), VN) for i in range(MANYOPS_COUNT): self.assertEqual(xattr.get(fh, USER_ATTR), USER_VAL) self.assertEqual(xattr.get(fh, USER_NN, namespace=NAMESPACE), USER_VAL) for i in range(MANYOPS_COUNT): - self.checkTuples(xattr.get_all(fh), + tuples_equal(xattr.get_all(fh), [(USER_ATTR, USER_VAL)]) self.assertEqual(xattr.get_all(fh, namespace=NAMESPACE), [(USER_NN, USER_VAL)]) -- 2.39.5 From f288f888023f1c90db245f34fc5aef04973e9484 Mon Sep 17 00:00:00 2001 From: Iustin Pop Date: Mon, 25 Nov 2019 02:03:38 +0100 Subject: [PATCH 15/16] Stop supporting Python 2 Bump minimum Python version to 3.4, which covers e.g. in Debian even old-old-stable (Jessie), which is good enough. This will allow code simplification and supporting new features (e.g. to implement #20). --- .travis.yml | 1 - Makefile | 2 +- README.md | 6 ++++-- setup.py | 1 + 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index e035a72..df6c50d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,6 @@ language: python # let's test as many versions as we can! python: - - "2.7" - "3.4" - "3.5" - "3.6" diff --git a/Makefile b/Makefile index 6761bff..e8e685a 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ DISTFILE = $(FULLVER).tar.gz MODNAME = xattr.so RSTFILES = doc/index.rst doc/module.rst doc/news.rst doc/readme.md doc/conf.py -PYVERS = 2.4 2.5 2.6 2.7 3.0 3.1 3.2 3.3 3.4 3.5 3.6 3.7 +PYVERS = 3.4 3.5 3.6 3.7 3.8 REPS = 5 all: doc test diff --git a/README.md b/README.md index e63ac8f..d4fd58c 100644 --- a/README.md +++ b/README.md @@ -23,8 +23,10 @@ repository is either at or at ## Requirements -pyxattr has been written and tested on Linux, kernel v2.4 or later, -with XFS and ext2/ext3/ext3 file systems. If any other platform +The current supported Python versions are 3.4+. + +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 implements the same behaviour, pyxattr could be used. You need to have the setuptools tool installed in order to build and diff --git a/setup.py b/setup.py index 26df53c..e8b045c 100755 --- a/setup.py +++ b/setup.py @@ -35,4 +35,5 @@ setup(name = "pyxattr", )], test_suite = "test", platforms = ["Linux"], + python_requires = ">=3.4", ) -- 2.39.5 From 81cc7f32be0ec4acc073a211e1c8a5b2196494ef Mon Sep 17 00:00:00 2001 From: Iustin Pop Date: Mon, 25 Nov 2019 03:07:51 +0100 Subject: [PATCH 16/16] tests: stop trying to set user attributes on symlinks According to xattr(7), by design setting/modifying user attributes on symlinks is not allowed, due to the way access control works, so stop trying to test it. --- test/test_xattr.py | 63 ++++++---------------------------------------- 1 file changed, 8 insertions(+), 55 deletions(-) diff --git a/test/test_xattr.py b/test/test_xattr.py index eab0822..b477aa2 100644 --- a/test/test_xattr.py +++ b/test/test_xattr.py @@ -110,17 +110,7 @@ class xattrTest(unittest.TestCase): self.assertRaises(EnvironmentError, xattr.setxattr, item, USER_ATTR, USER_VAL, XATTR_REPLACE, symlink) - try: - xattr.setxattr(item, USER_ATTR, USER_VAL, 0, symlink) - except IOError: - err = sys.exc_info()[1] - if symlink and (err.errno == errno.EPERM or - err.errno == errno.ENOENT): - # symlinks may fail, in which case we abort the rest - # of the test for this case (Linux returns EPERM; OS X - # returns ENOENT) - return - raise + xattr.setxattr(item, USER_ATTR, USER_VAL, 0, symlink) self.assertRaises(EnvironmentError, xattr.setxattr, item, USER_ATTR, USER_VAL, XATTR_CREATE, symlink) lists_equal(xattr.listxattr(item, symlink), [USER_ATTR]) @@ -147,23 +137,13 @@ class xattrTest(unittest.TestCase): flags=XATTR_REPLACE, namespace=NAMESPACE, nofollow=symlink) - try: - if use_ns: - xattr.set(item, USER_NN, USER_VAL, - namespace=NAMESPACE, - nofollow=symlink) - else: - xattr.set(item, USER_ATTR, USER_VAL, - nofollow=symlink) - except IOError: - err = sys.exc_info()[1] - if symlink and (err.errno == errno.EPERM or - err.errno == errno.ENOENT): - # symlinks may fail, in which case we abort the rest - # of the test for this case (Linux returns EPERM; OS X - # returns ENOENT) - return - raise + if use_ns: + xattr.set(item, USER_NN, USER_VAL, + namespace=NAMESPACE, + nofollow=symlink) + else: + xattr.set(item, USER_ATTR, USER_VAL, + nofollow=symlink) self.assertRaises(EnvironmentError, xattr.set, item, USER_ATTR, USER_VAL, flags=XATTR_CREATE, @@ -331,33 +311,6 @@ class xattrTest(unittest.TestCase): self._checkListSetGet(dname) self._checkListSetGet(dname, use_ns=True) - def testSymlinkOpsDeprecated(self): - """test symlink operations (deprecated functions)""" - _, sname = self._getsymlink() - self.assertRaises(EnvironmentError, xattr.listxattr, sname) - self._checkDeprecated(sname, symlink=True) - target, sname = self._getsymlink(dangling=False) - xattr.setxattr(target, USER_ATTR, USER_VAL) - lists_equal(xattr.listxattr(target), [USER_ATTR]) - lists_equal(xattr.listxattr(sname, True), []) - self.assertRaises(EnvironmentError, xattr.removexattr, sname, - USER_ATTR, True) - xattr.removexattr(sname, USER_ATTR, False) - - def testSymlinkOps(self): - """test symlink operations""" - _, sname = self._getsymlink() - self.assertRaises(EnvironmentError, xattr.list, sname) - self._checkListSetGet(sname, symlink=True) - self._checkListSetGet(sname, symlink=True, use_ns=True) - target, sname = self._getsymlink(dangling=False) - xattr.set(target, USER_ATTR, USER_VAL) - lists_equal(xattr.list(target), [USER_ATTR]) - lists_equal(xattr.list(sname, nofollow=True), []) - self.assertRaises(EnvironmentError, xattr.remove, sname, - USER_ATTR, nofollow=True) - xattr.remove(sname, USER_ATTR, nofollow=False) - def testBinaryPayloadDeprecated(self): """test binary values (deprecated functions)""" fh, fname = self._getfile() -- 2.39.5