Hello community,

here is the log from the commit of package python-pylibacl for openSUSE:Factory 
checked in at 2020-01-09 22:52:48
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-pylibacl (Old)
 and      /work/SRC/openSUSE:Factory/.python-pylibacl.new.6675 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-pylibacl"

Thu Jan  9 22:52:48 2020 rev:3 rq:762227 version:0.5.4

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-pylibacl/python-pylibacl.changes  
2019-10-16 09:15:31.459430610 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-pylibacl.new.6675/python-pylibacl.changes    
    2020-01-09 22:53:25.710794377 +0100
@@ -1,0 +2,8 @@
+Thu Jan  9 14:06:28 UTC 2020 - Tomáš Chvátal <[email protected]>
+
+- Update to 0.5.4:
+  * Switch to python3 interpreter
+  * minor documentation improvements
+- Switch to singlespec
+
+-------------------------------------------------------------------

Old:
----
  pylibacl-0.5.3.tar.gz

New:
----
  pylibacl-0.5.4.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-pylibacl.spec ++++++
--- /var/tmp/diff_new_pack.p7uaBC/_old  2020-01-09 22:53:27.730795388 +0100
+++ /var/tmp/diff_new_pack.p7uaBC/_new  2020-01-09 22:53:27.754795401 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package python-pylibacl
 #
-# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2020 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -16,54 +16,44 @@
 #
 
 
+%{?!python_module:%define python_module() python-%{**} python3-%{**}}
 Name:           python-pylibacl
-Version:        0.5.3
+Version:        0.5.4
 Release:        0
-Summary:        Python POSIX.1e ACL module
+Summary:        POSIX1e ACLs for python
 License:        LGPL-2.1-or-later
 URL:            https://pylibacl.k1024.org/
-Source:         
https://github.com/iustin/pylibacl/releases/download/pylibacl-v%{version}/pylibacl-%{version}.tar.gz
+Source:         
https://files.pythonhosted.org/packages/source/p/pylibacl/pylibacl-%{version}.tar.gz
+BuildRequires:  %{python_module devel}
+BuildRequires:  %{python_module pytest}
+BuildRequires:  %{python_module setuptools}
 BuildRequires:  fdupes
-BuildRequires:  libacl-devel
-# Documentation requirements:
-BuildRequires:  python-Sphinx
-BuildRequires:  python-devel
-BuildRequires:  python-setuptools
+BuildRequires:  pkgconfig
+BuildRequires:  python-rpm-macros
+BuildRequires:  pkgconfig(libacl)
+%python_subpackages
 
 %description
-This Python 2.4+ extension module allows you to manipulate the POSIX.1e Access
-Control Lists present in some OS/file-systems combinations. It is a wrapper on
-top of the systems's acl C library - see acl(5).
-
-%package doc
-Summary:        Python POSIX.1e ACL module
-Requires:       %{name} = %{version}
-
-%description doc
-This Python 2.4+ extension module allows you to manipulate the POSIX.1e Access
-Control Lists present in some OS/file-systems combinations. It is a wrapper on
-top of the systems's acl C library - see acl(5).
+This is a C extension module for Python which
+implements POSIX ACLs manipulation. It is a wrapper on top
+of the systems's acl C library - see acl(5).
 
 %prep
 %setup -q -n pylibacl-%{version}
 
 %build
-CFLAGS="%{optflags} -fno-strict-aliasing" python setup.py build
-python setup.py build_sphinx
+%python_build
 
 %install
-python setup.py install --prefix=%{_prefix} --root=%{buildroot}
-%fdupes %{buildroot}/%{_prefix}
+%python_install
+%python_expand %fdupes %{buildroot}%{$python_sitearch}
 
 %check
-python setup.py test
+%pytest_arch
 
-%files
+%files %{python_files}
 %license COPYING
-%doc NEWS README
+%doc NEWS README.rst
 %{python_sitearch}/*
 
-%files doc
-%doc build/sphinx/html
-
 %changelog

++++++ pylibacl-0.5.3.tar.gz -> pylibacl-0.5.4.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pylibacl-0.5.3/MANIFEST.in 
new/pylibacl-0.5.4/MANIFEST.in
--- old/pylibacl-0.5.3/MANIFEST.in      2012-05-17 04:49:28.000000000 +0200
+++ new/pylibacl-0.5.4/MANIFEST.in      2015-05-01 21:56:38.000000000 +0200
@@ -1,7 +1,7 @@
 include COPYING
 include Makefile
 include NEWS
-include README
+include README.rst
 include acl.c
 include setup.cfg
 include doc/conf.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pylibacl-0.5.3/Makefile new/pylibacl-0.5.4/Makefile
--- old/pylibacl-0.5.3/Makefile 2015-04-30 22:11:29.000000000 +0200
+++ new/pylibacl-0.5.4/Makefile 2019-11-14 11:37:56.000000000 +0100
@@ -1,38 +1,49 @@
+PYTHON        = python3
 SPHINXOPTS    = -W
-SPHINXBUILD   = sphinx-build
+SPHINXBUILD   = $(PYTHON) -m sphinx
 DOCDIR        = doc
 DOCHTML       = $(DOCDIR)/html
 DOCTREES      = $(DOCDIR)/doctrees
 ALLSPHINXOPTS = -d $(DOCTREES) $(SPHINXOPTS) $(DOCDIR)
 
 MODNAME = posix1e.so
-RSTFILES = doc/index.rst doc/module.rst NEWS README doc/conf.py
+RSTFILES = doc/index.rst doc/module.rst NEWS README.rst doc/conf.py
 
 all: doc test
 
 $(MODNAME): acl.c
-       ./setup.py build_ext --inplace
+       $(PYTHON) ./setup.py build_ext --inplace
 
-$(DOCHTML)/index.html: $(MODNAME) $(RSTFILES)
+$(DOCHTML)/index.html: $(MODNAME) $(RSTFILES) acl.c
        $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(DOCHTML)
        touch $@
 
 doc: $(DOCHTML)/index.html
 
 dist:
-       fakeroot ./setup.py sdist
+       fakeroot $(PYTHON) ./setup.py sdist
 
 test:
-       @for ver in 2.4 2.5 2.6 2.7 3.0 3.1 3.2 3.3 3.4; do \
-         if type python$$ver >/dev/null; then \
-           echo Testing with python$$ver; \
-           python$$ver ./setup.py test -q; \
+       @for ver in 2.7 3.0 3.1 3.2 3.3 3.4 3.5 3.6 3.7; do \
+         for flavour in "" "-dbg"; do \
+           if type python$$ver$$flavour >/dev/null; then \
+             echo Testing with python$$ver$$flavour; \
+             python$$ver$$flavour ./setup.py test -q; \
+           fi; \
+         done; \
+       done; \
+       for pp in pypy pypy3; do \
+         if type $$pp >/dev/null; then \
+           echo Testing with $$pp; \
+           $$pp ./setup.py test -q; \
          fi; \
        done
-       @if type pypy >/dev/null; then \
-         echo Testing with pypy; \
-         pypy ./setup.py test -q; \
-       fi
+
+coverage:
+       $(MAKE) clean
+       $(MAKE) test CFLAGS="-coverage"
+       lcov --capture --directory . --output-file coverage.info
+       genhtml coverage.info --output-directory out
 
 clean:
        rm -rf $(DOCHTML) $(DOCTREES)
@@ -40,4 +51,4 @@
        rm -f *.so
        rm -rf build
 
-.PHONY: doc test clean dist
+.PHONY: doc test clean dist coverage
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pylibacl-0.5.3/NEWS new/pylibacl-0.5.4/NEWS
--- old/pylibacl-0.5.3/NEWS     2015-04-30 22:20:00.000000000 +0200
+++ new/pylibacl-0.5.4/NEWS     2019-11-14 11:57:12.000000000 +0100
@@ -1,9 +1,28 @@
 News
 ====
 
+Version 0.5.4
+-------------
+
+*released Thu, 14 Nov 2019*
+
+Maintenance release:
+
+- Switch build system to Python 3 by default (can be overridden if
+  needed).
+- Internal improvements for better cpychecker support.
+- Fix compatibility with PyPy.
+- Test improvements (both local and on Travis), testing more variations
+  (debug, PyPy).
+- Improve test coverage, and allow gathering test coverage results.
+- Drop support (well, drop testing) for Python lower than 2.7.
+- Minor documentation improvements (closes #9, #12).
+
 Version 0.5.3
 -------------
 
+*released Thu, 30 Apr 2015*
+
 FreeBSD fixes:
 
 - Enable all FreeBSD versions after 7.x at level 2 (thanks to Garrett
@@ -15,11 +34,15 @@
 Version 0.5.2
 -------------
 
+*released Sat, 24 May 2014*
+
 No visible changes release: just fix tests when running under pypy.
 
 Version 0.5.1
 -------------
 
+*released Sun, 13 May 2012*
+
 A bug-fix only release. Critical bugs (memory leaks and possible
 segmentation faults) have been fixed thanks to Dave Malcolm and his
 ``cpychecker`` tool. Additionally, some compatibility issues with Python
@@ -36,16 +59,20 @@
 Version 0.5
 -----------
 
+*released Sun, 27 Dec 2009*
+
 Added support for Python 3.x and improved support for Unicode filenames.
 
 Version 0.4
 -----------
 
+*released Sat, 28 Jun 2008*
+
 License
 ~~~~~~~
 
 Starting with this version, pylibacl is licensed under LGPL 2.1,
-Febryary 1999 or any later versions (see README and COPYING).
+Febryary 1999 or any later versions (see README.rst and COPYING).
 
 Linux support
 ~~~~~~~~~~~~~
@@ -97,6 +124,8 @@
 Version 0.3
 -----------
 
+*released Sun, 21 Oct 2007*
+
 Linux support
 ~~~~~~~~~~~~~
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pylibacl-0.5.3/PKG-INFO new/pylibacl-0.5.4/PKG-INFO
--- old/pylibacl-0.5.3/PKG-INFO 2015-04-30 22:22:25.000000000 +0200
+++ new/pylibacl-0.5.4/PKG-INFO 2019-11-14 12:03:24.000000000 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 1.0
 Name: pylibacl
-Version: 0.5.3
+Version: 0.5.4
 Summary: POSIX.1e ACLs for python
 Home-page: http://pylibacl.k1024.org/
 Author: Iustin Pop
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pylibacl-0.5.3/README new/pylibacl-0.5.4/README
--- old/pylibacl-0.5.3/README   2015-04-30 22:18:19.000000000 +0200
+++ new/pylibacl-0.5.4/README   1970-01-01 01:00:00.000000000 +0100
@@ -1,41 +0,0 @@
-pylibacl
-========
-
-This is a Python 2.4+ extension module allows you to manipulate the
-POSIX.1e Access Control Lists present in some OS/file-systems
-combinations.
-
-Downloads: go to http://pylibacl.k1024.org/downloads. Latest
-version is 0.5.3. The source repository is either
-at `<git://git.k1024.org/pylibacl.git>`_ or
-at https://github.com/iustin/pylibacl.
-
-For any issues, please file bugs at
-https://github.com/iustin/pylibacl/issues.
-
-Requirements
-------------
-
-pylibacl has been written and tested on Linux, kernel v2.4 or newer,
-with XFS filesystems; ext2/ext3 should also work. Since release 0.4.0,
-FreeBSD 7 also has quite good support. If any other platform
-implements the POSIX.1e draft, pylibacl can be used. I heard that
-Solaris does, but I can't test it.
-
-- Python 2.4 or newer
-- operating system:
-    - Linux, kernel v2.4 or newer, and the libacl library and
-      development packages (all modern distributions should have this,
-      under various names); also the file-systems you use must have
-      ACLs turned on, either as a compile or mount option
-    - FreeBSD 7.0 or newer
-
-License
--------
-
-pylibacl is Copyright (C) 2002-2009, 2012, 2014, 2015 Iustin Pop.
-
-pylibacl 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.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pylibacl-0.5.3/README.rst 
new/pylibacl-0.5.4/README.rst
--- old/pylibacl-0.5.3/README.rst       1970-01-01 01:00:00.000000000 +0100
+++ new/pylibacl-0.5.4/README.rst       2019-11-14 11:57:57.000000000 +0100
@@ -0,0 +1,60 @@
+pylibacl
+========
+
+This is a Python 2.7+ extension module allows you to manipulate the
+POSIX.1e Access Control Lists present in some OS/file-systems
+combinations.
+
+Downloads: go to http://pylibacl.k1024.org/downloads. Latest version
+is 0.5.4. The source repository is either at
+https://git.k1024.org/pylibacl.git or at
+https://github.com/iustin/pylibacl.
+
+For any issues, please file bugs at
+https://github.com/iustin/pylibacl/issues.
+
+Requirements
+------------
+
+pylibacl has been written and tested on Linux, kernel v2.4 or newer,
+with XFS filesystems; ext2/ext3 should also work. Since release 0.4.0,
+FreeBSD 7 also has quite good support. If any other platform
+implements the POSIX.1e draft, pylibacl can be used. I heard that
+Solaris does, but I can't test it.
+
+- Python 2.7 or newer.
+- Operating system:
+    - Linux, kernel v2.4 or newer, and the libacl library and
+      development packages (all modern distributions should have this,
+      under various names); also the file-systems you use must have
+      ACLs turned on, either as a compile or mount option.
+    - FreeBSD 7.0 or newer.
+- The sphinx python module, for your python version, if building the
+  documentation.
+
+Note: to build from source, by default, Python 3 is needed. It can
+still be built with Python 2, by calling `make PYTHON=python2`.
+
+FreeBSD
++++++++
+
+Note that on FreeBSD, ACLs are not enabled by default (at least on UFS
+file systems). To enable them, run `tunefs -a enabled` on the file
+system in question (after mounting it read-only). Then install:
+
+- pkg install py36-setuptools py36-sphinx
+
+or:
+
+- pkg install py37-setuptools
+
+
+License
+-------
+
+pylibacl is Copyright (C) 2002-2009, 2012, 2014, 2015 Iustin Pop.
+
+pylibacl 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.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pylibacl-0.5.3/acl.c new/pylibacl-0.5.4/acl.c
--- old/pylibacl-0.5.3/acl.c    2015-04-30 22:14:27.000000000 +0200
+++ new/pylibacl-0.5.4/acl.c    2019-11-14 11:45:22.000000000 +0100
@@ -1,7 +1,7 @@
 /*
     posix1e - a python module exposing the posix acl functions
 
-    Copyright (C) 2002-2009, 2012, 2014 Iustin Pop <[email protected]>
+    Copyright (C) 2002-2009, 2012, 2014, 2015 Iustin Pop <[email protected]>
 
     This library is free software; you can redistribute it and/or
     modify it under the terms of the GNU Lesser General Public
@@ -45,7 +45,6 @@
 #define PyInt_AsUnsignedLongMask PyLong_AsUnsignedLongMask
 #define PyInt_AsUnsignedLongLongMask PyLong_AsUnsignedLongLongMask
 #define PyInt_AS_LONG PyLong_AS_LONG
-#define MyString_ConcatAndDel PyUnicode_AppendAndDel
 #define MyString_FromFormat PyUnicode_FromFormat
 #define MyString_FromString PyUnicode_FromString
 #define MyString_FromStringAndSize PyUnicode_FromStringAndSize
@@ -55,19 +54,34 @@
 #define PyBytes_FromStringAndSize PyString_FromStringAndSize
 #define PyBytes_FromString PyString_FromString
 #define PyBytes_FromFormat PyString_FromFormat
-#define PyBytes_ConcatAndDel PyString_ConcatAndDel
-#define MyString_ConcatAndDel PyBytes_ConcatAndDel
 #define MyString_FromFormat PyBytes_FromFormat
 #define MyString_FromString PyBytes_FromString
 #define MyString_FromStringAndSize PyBytes_FromStringAndSize
+#endif
 
-/* Python 2.6 already defines Py_TYPE */
-#ifndef Py_TYPE
-#define Py_TYPE(o)    (((PyObject*)(o))->ob_type)
+/* Used for cpychecker: */
+/* The checker automatically defines this preprocessor name when creating
+   the custom attribute: */
+#if defined(WITH_CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF_ATTRIBUTE)
+#define CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF(typename) \
+  __attribute__((cpychecker_type_object_for_typedef(typename)))
+#else
+/* This handles the case where we're compiling with a "vanilla"
+   compiler that doesn't supply this attribute: */
+#define CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF(typename)
 #endif
+
+/* The checker automatically defines this preprocessor name when creating
+   the custom attribute: */
+#if defined(WITH_CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION_ATTRIBUTE)
+   #define CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION \
+__attribute__((cpychecker_negative_result_sets_exception))
+   #else
+   #define CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
 #endif
 
-static PyTypeObject ACL_Type;
+static PyTypeObject ACL_Type
+  CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF("ACL_Object");
 static PyObject* ACL_applyto(PyObject* obj, PyObject* args);
 static PyObject* ACL_valid(PyObject* obj, PyObject* args);
 
@@ -77,8 +91,10 @@
 #endif
 
 #ifdef HAVE_LEVEL2
-static PyTypeObject Entry_Type;
-static PyTypeObject Permset_Type;
+static PyTypeObject Entry_Type
+  CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF("Entry_Object");
+static PyTypeObject Permset_Type
+  CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF("Permset_Object");
 static PyObject* Permset_new(PyTypeObject* type, PyObject* args,
                              PyObject *keywds);
 #endif
@@ -134,8 +150,8 @@
 #ifdef HAVE_LINUX
     static char *kwlist[] = { "file", "fd", "text", "acl", "filedef",
                               "mode", NULL };
-    char *format = "|etisO!sH";
-    mode_t mode = 0;
+    char *format = "|etisO!si";
+    int mode = -1;
 #else
     static char *kwlist[] = { "file", "fd", "text", "acl", "filedef", NULL };
     char *format = "|etisO!s";
@@ -177,7 +193,7 @@
     else if(filedef != NULL)
         self->acl = acl_get_file(filedef, ACL_TYPE_DEFAULT);
 #ifdef HAVE_LINUX
-    else if(PyMapping_HasKeyString(keywds, kwlist[5]))
+    else if(mode != -1)
         self->acl = acl_from_mode(mode);
 #endif
     else
@@ -343,7 +359,8 @@
         ret = n == 1 ? Py_True : Py_False;
         break;
     default:
-        ret = Py_NotImplemented;
+        PyErr_SetString(PyExc_TypeError, "ACLs are not orderable");
+        return NULL;
     }
     Py_INCREF(ret);
     return ret;
@@ -371,12 +388,14 @@
 }
 #endif
 
+#ifndef IS_PY3K
 /* Implementation of the compare for ACLs */
 static int ACL_nocmp(PyObject* o1, PyObject* o2) {
 
     PyErr_SetString(PyExc_TypeError, "cannot compare ACLs using cmp()");
     return -1;
 }
+#endif
 
 /* Custom methods */
 static char __applyto_doc__[] =
@@ -680,27 +699,31 @@
     };
 } tag_qual;
 
+/* Pre-declaring the function is more friendly to cpychecker, sigh. */
+static int get_tag_qualifier(acl_entry_t entry, tag_qual *tq)
+  CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
+
 /* Helper function to get the tag and qualifier of an Entry at the
    same time. This is "needed" because the acl_get_qualifier function
    returns a pointer to different types, based on the tag value, and
    thus it's not straightforward to get the right type.
 
-   It sets a Python exception if an error occurs, and return 0 in this
-   case. If successful, the tag is set to the tag type, and the
+   It sets a Python exception if an error occurs, and returns -1 in
+   this case. If successful, the tag is set to the tag type, the
    qualifier (if any) to either the uid or the gid entry in the
-   tag_qual structure.
+   tag_qual structure, and the return value is 0.
 */
-int get_tag_qualifier(acl_entry_t entry, tag_qual *tq) {
+static int get_tag_qualifier(acl_entry_t entry, tag_qual *tq) {
     void *p;
 
     if(acl_get_tag_type(entry, &tq->tag) == -1) {
         PyErr_SetFromErrno(PyExc_IOError);
-        return 0;
+        return -1;
     }
     if (tq->tag == ACL_USER || tq->tag == ACL_GROUP) {
         if((p = acl_get_qualifier(entry)) == NULL) {
             PyErr_SetFromErrno(PyExc_IOError);
-            return 0;
+            return -1;
         }
         if (tq->tag == ACL_USER) {
             tq->uid = *(uid_t*)p;
@@ -709,7 +732,7 @@
         }
         acl_free(p);
     }
-    return 1;
+    return 0;
 }
 
 /* Creation of a new Entry instance */
@@ -769,7 +792,7 @@
     Entry_Object *self = (Entry_Object*) obj;
     tag_qual tq;
 
-    if(!get_tag_qualifier(self->entry, &tq)) {
+    if(get_tag_qualifier(self->entry, &tq) < 0) {
         return NULL;
     }
 
@@ -810,8 +833,15 @@
         Py_DECREF(format);
         return NULL;
     }
-    MyString_ConcatAndDel(&format, kind);
+#ifdef IS_PY3K
+    PyObject *ret = PyUnicode_Concat(format, kind);
+    Py_DECREF(format);
+    Py_DECREF(kind);
+    return ret;
+#else
+    PyString_ConcatAndDel(&format, kind);
     return format;
+#endif
 }
 
 /* Sets the tag type of the entry */
@@ -930,7 +960,7 @@
         PyErr_SetString(PyExc_AttributeError, "entry attribute");
         return NULL;
     }
-    if(!get_tag_qualifier(self->entry, &tq)) {
+    if(get_tag_qualifier(self->entry, &tq) < 0) {
         return NULL;
     }
     if (tq.tag == ACL_USER) {
@@ -1116,8 +1146,8 @@
     int nerr;
 
     if(!PyInt_Check(value)) {
-        PyErr_SetString(PyExc_ValueError, "a maximum of one argument must"
-                        " be passed");
+        PyErr_SetString(PyExc_ValueError, "invalid argument, an integer"
+                        " is expected");
         return -1;
     }
     on = PyInt_AsLong(value);
@@ -1230,17 +1260,20 @@
     ".. note:: only one keyword parameter should be provided\n"
     "\n"
     ":param string file: creates an ACL representing\n"
-    "    the access ACL of the specified file\n"
+    "    the access ACL of the specified file.\n"
     ":param string filedef: creates an ACL representing\n"
-    "    the default ACL of the given directory\n"
+    "    the default ACL of the given directory.\n"
     ":param int fd: creates an ACL representing\n"
-    "    the access ACL of the given file descriptor\n"
+    "    the access ACL of the given file descriptor.\n"
     ":param string text: creates an ACL from a \n"
-    "    textual description\n"
-    ":param ACL acl: creates a copy of an existing ACL instance\n"
+    "    textual description; note the ACL must be valid, which\n"
+    "    means including a mask for extended ACLs, similar to\n"
+    "    ``setfacl --no-mask``\n"
+    ":param ACL acl: creates a copy of an existing ACL instance.\n"
     ":param int mode: creates an ACL from a numeric mode\n"
-    "    (e.g. mode=0644) (this is valid only when the C library\n"
-    "    provides the acl_from_mode call)\n"
+    "    (e.g. ``mode=0644``); this is valid only when the C library\n"
+    "    provides the ``acl_from_mode call``, and\n"
+    "    note that no validation is done on the given value.\n"
     "\n"
     "If no parameters are passed, an empty ACL will be created; this\n"
     "makes sense only when your OS supports ACL modification\n"
@@ -1288,7 +1321,12 @@
     0,                  /* tp_print */
     0,                  /* tp_getattr */
     0,                  /* tp_setattr */
+#ifdef IS_PY3K
+    0,                  /* formerly tp_compare, in 3.0 deprecated, in
+                           3.5 tp_as_async */
+#else
     ACL_nocmp,          /* tp_compare */
+#endif
     0,                  /* tp_repr */
     0,                  /* tp_as_number */
     0,                  /* tp_as_sequence */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pylibacl-0.5.3/doc/conf.py 
new/pylibacl-0.5.4/doc/conf.py
--- old/pylibacl-0.5.3/doc/conf.py      2015-04-30 22:18:44.000000000 +0200
+++ new/pylibacl-0.5.4/doc/conf.py      2019-11-14 11:58:24.000000000 +0100
@@ -48,9 +48,9 @@
 # built documents.
 #
 # The short X.Y version.
-version = '0.5.3'
+version = '0.5.4'
 # The full version, including alpha/beta/rc tags.
-release = '0.5.3'
+release = '0.5.4'
 
 # 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/pylibacl-0.5.3/doc/index.rst 
new/pylibacl-0.5.4/doc/index.rst
--- old/pylibacl-0.5.3/doc/index.rst    2012-05-13 06:13:49.000000000 +0200
+++ new/pylibacl-0.5.4/doc/index.rst    2019-11-14 11:47:30.000000000 +0100
@@ -2,7 +2,7 @@
  Welcome to pylibacl's documentation!
 ======================================
 
-.. include:: ../README
+.. include:: ../README.rst
    :start-line: 2
 
 Contents
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pylibacl-0.5.3/doc/news.rst 
new/pylibacl-0.5.4/doc/news.rst
--- old/pylibacl-0.5.3/doc/news.rst     2020-01-09 22:53:28.006795527 +0100
+++ new/pylibacl-0.5.4/doc/news.rst     2019-11-14 11:57:12.000000000 +0100
@@ -1 +1,142 @@
-symbolic link to ../NEWS
+News
+====
+
+Version 0.5.4
+-------------
+
+*released Thu, 14 Nov 2019*
+
+Maintenance release:
+
+- Switch build system to Python 3 by default (can be overridden if
+  needed).
+- Internal improvements for better cpychecker support.
+- Fix compatibility with PyPy.
+- Test improvements (both local and on Travis), testing more variations
+  (debug, PyPy).
+- Improve test coverage, and allow gathering test coverage results.
+- Drop support (well, drop testing) for Python lower than 2.7.
+- Minor documentation improvements (closes #9, #12).
+
+Version 0.5.3
+-------------
+
+*released Thu, 30 Apr 2015*
+
+FreeBSD fixes:
+
+- Enable all FreeBSD versions after 7.x at level 2 (thanks to Garrett
+  Cooper).
+- Make test suite pass under FreeBSD, which has a stricter behaviour
+  with regards to invalid ACLs (which we do exercise in the test suite),
+  thanks again to Garret for the bug reports.
+
+Version 0.5.2
+-------------
+
+*released Sat, 24 May 2014*
+
+No visible changes release: just fix tests when running under pypy.
+
+Version 0.5.1
+-------------
+
+*released Sun, 13 May 2012*
+
+A bug-fix only release. Critical bugs (memory leaks and possible
+segmentation faults) have been fixed thanks to Dave Malcolm and his
+``cpychecker`` tool. Additionally, some compatibility issues with Python
+3.x have been fixed (str() methods returning bytes).
+
+The documentation has been improved and changed from epydoc to sphinx;
+note however that the documentation is still auto-generated from the
+docstrings.
+
+Project reorganisation: the project home page has been moved from
+SourceForge to GitHub.
+
+
+Version 0.5
+-----------
+
+*released Sun, 27 Dec 2009*
+
+Added support for Python 3.x and improved support for Unicode filenames.
+
+Version 0.4
+-----------
+
+*released Sat, 28 Jun 2008*
+
+License
+~~~~~~~
+
+Starting with this version, pylibacl is licensed under LGPL 2.1,
+Febryary 1999 or any later versions (see README.rst and COPYING).
+
+Linux support
+~~~~~~~~~~~~~
+
+A few more Linux-specific functions:
+
+- add the ACL.equiv_mode() method, which will return the equivalent
+  octal mode if this is a basic ACL and raise an IOError exception
+  otherwise
+
+- add the acl_extended(...) function, which will check if an fd or path
+  has an extended ACL
+
+FreeBSD support
+~~~~~~~~~~~~~~~
+
+FreeBSD 7.x will have almost all the acl manipulation functions that
+Linux has, with the exception of __getstate__/__setstate__. As a
+workaround, use the str() and ACL(text=...) methods to pass around
+textual representations.
+
+Interface
+~~~~~~~~~
+
+At module level there are now a few constants exported for easy-checking
+at runtime what features have been compiled in:
+
+- HAS_ACL_FROM_MODE, denoting whether the ACL constructor supports the
+  mode=0xxx parameter
+
+- HAS_ACL_CHECK, denoting whether ACL instances support the check()
+  method
+
+- HAS_ACL_ENTRY, denoting whether ACL manipulation is possible and the
+  Entry and Permset classes are available
+
+- HAS_EXTENEDED_CHECK, denoting whether the acl_extended function is
+  supported
+
+- HAS_EQUIV_MODE, denoting whether ACL instances support the
+  equiv_mode() method
+
+Internals
+~~~~~~~~~
+
+Many functions have now unittests, which is a good thing.
+
+
+Version 0.3
+-----------
+
+*released Sun, 21 Oct 2007*
+
+Linux support
+~~~~~~~~~~~~~
+
+Under Linux, implement more functions from libacl:
+
+- add ACL(mode=...), implementing acl_from_mode
+- add ACL().to_any_text, implementing acl_to_any_text
+- add ACL comparison, using acl_cmp
+- add ACL().check, which is a more descriptive function than validate
+
+.. Local Variables:
+.. mode: rst
+.. fill-column: 72
+.. End:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pylibacl-0.5.3/pylibacl.egg-info/PKG-INFO 
new/pylibacl-0.5.4/pylibacl.egg-info/PKG-INFO
--- old/pylibacl-0.5.3/pylibacl.egg-info/PKG-INFO       2015-04-30 
22:22:25.000000000 +0200
+++ new/pylibacl-0.5.4/pylibacl.egg-info/PKG-INFO       2019-11-14 
12:03:23.000000000 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 1.0
 Name: pylibacl
-Version: 0.5.3
+Version: 0.5.4
 Summary: POSIX.1e ACLs for python
 Home-page: http://pylibacl.k1024.org/
 Author: Iustin Pop
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pylibacl-0.5.3/pylibacl.egg-info/SOURCES.txt 
new/pylibacl-0.5.4/pylibacl.egg-info/SOURCES.txt
--- old/pylibacl-0.5.3/pylibacl.egg-info/SOURCES.txt    2015-04-30 
22:22:25.000000000 +0200
+++ new/pylibacl-0.5.4/pylibacl.egg-info/SOURCES.txt    2019-11-14 
12:03:23.000000000 +0100
@@ -2,7 +2,7 @@
 MANIFEST.in
 Makefile
 NEWS
-README
+README.rst
 acl.c
 setup.cfg
 setup.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pylibacl-0.5.3/setup.cfg new/pylibacl-0.5.4/setup.cfg
--- old/pylibacl-0.5.3/setup.cfg        2015-04-30 22:22:25.000000000 +0200
+++ new/pylibacl-0.5.4/setup.cfg        2019-11-14 12:03:24.000000000 +0100
@@ -5,5 +5,4 @@
 [egg_info]
 tag_build = 
 tag_date = 0
-tag_svn_revision = 0
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pylibacl-0.5.3/setup.py new/pylibacl-0.5.4/setup.py
--- old/pylibacl-0.5.3/setup.py 2015-04-30 22:18:52.000000000 +0200
+++ new/pylibacl-0.5.4/setup.py 2019-11-14 11:58:31.000000000 +0100
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 
 import os
 from setuptools import setup, Extension
@@ -30,7 +30,7 @@
 implements POSIX ACLs manipulation. It is a wrapper on top
 of the systems's acl C library - see acl(5)."""
 
-version = "0.5.3"
+version = "0.5.4"
 
 setup(name="pylibacl",
       version=version,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pylibacl-0.5.3/test/test_acls.py 
new/pylibacl-0.5.4/test/test_acls.py
--- old/pylibacl-0.5.3/test/test_acls.py        2015-04-30 22:14:44.000000000 
+0200
+++ new/pylibacl-0.5.4/test/test_acls.py        2019-03-03 12:47:04.000000000 
+0100
@@ -28,10 +28,16 @@
 import platform
 import re
 import errno
+import operator
 
 import posix1e
 from posix1e import *
 
+try:
+  import __pypy__
+except ImportError:
+  __pypy__ = None
+
 TEST_DIR = os.environ.get("TEST_DIR", ".")
 
 BASIC_ACL_TEXT = "u::rw,g::r,o::-"
@@ -42,22 +48,16 @@
 M0644 = 420 # octal 0644
 M0755 = 493 # octal 755
 
-# Check if running under Python 3
-IS_PY_3K = sys.hexversion >= 0x03000000
-
-def _skip_test(fn):
-    """Wrapper to skip a test"""
-    new_fn = lambda x: None
-    new_fn.__doc__ = "SKIPPED %s" % fn.__doc__
-    return new_fn
+# Permset permission information
+PERMSETS = {
+  posix1e.ACL_READ: ("read", posix1e.Permset.read),
+  posix1e.ACL_WRITE: ("write", posix1e.Permset.write),
+  posix1e.ACL_EXECUTE: ("execute", posix1e.Permset.execute),
+  }
 
 
-def has_ext(extension):
-    """Decorator to skip tests based on platform support"""
-    if not extension:
-        return _skip_test
-    else:
-        return lambda x: x
+# Check if running under Python 3
+IS_PY_3K = sys.hexversion >= 0x03000000
 
 def ignore_ioerror(errnum, fn, *args, **kwargs):
     """Call a function while ignoring some IOErrors.
@@ -74,6 +74,14 @@
             return
         raise
 
+def encode(s):
+    """Encode a string if needed (under Python 3)"""
+    if IS_PY_3K:
+        return s.encode()
+    else:
+        return s
+
+
 class aclTest:
     """Support functions ACLs"""
 
@@ -145,17 +153,38 @@
         self.assertTrue(acl1.valid(),
                         "ACL based on standard description should be valid")
 
+    def testFromACL(self):
+        """Test creating an ACL from an existing ACL"""
+        acl1 = posix1e.ACL()
+        acl2 = posix1e.ACL(acl=acl1)
+
+    def testInvalidCreationParams(self):
+        """Test that creating an ACL from multiple objects fails"""
+        fd, _ = self._getfile()
+        self.assertRaises(ValueError, posix1e.ACL, text=BASIC_ACL_TEXT, fd=fd)
+
+    def testInvalidValueCreation(self):
+        """Test that creating an ACL from wrong specification fails"""
+        self.assertRaises(EnvironmentError, posix1e.ACL, text="foobar")
+        self.assertRaises(TypeError, posix1e.ACL, foo="bar")
+
+    def testDoubleInit(self):
+        acl1 = posix1e.ACL(text=BASIC_ACL_TEXT)
+        self.assertTrue(acl1.valid())
+        acl1.__init__(text=BASIC_ACL_TEXT)
+        self.assertTrue(acl1.valid())
+
 class AclExtensions(aclTest, unittest.TestCase):
     """ACL extensions checks"""
 
-    @has_ext(HAS_ACL_FROM_MODE)
+    @unittest.skipUnless(HAS_ACL_FROM_MODE, "Missing HAS_ACL_FROM_MODE")
     def testFromMode(self):
         """Test loading ACLs from an octal mode"""
         acl1 = posix1e.ACL(mode=M0644)
         self.assertTrue(acl1.valid(),
                         "ACL created via octal mode shoule be valid")
 
-    @has_ext(HAS_ACL_CHECK)
+    @unittest.skipUnless(HAS_ACL_CHECK, "ACL check not supported")
     def testAclCheck(self):
         """Test the acl_check method"""
         acl1 = posix1e.ACL(text=BASIC_ACL_TEXT)
@@ -163,7 +192,7 @@
         acl2 = posix1e.ACL()
         self.assertTrue(acl2.check(), "Empty ACL should not be valid")
 
-    @has_ext(HAS_EXTENDED_CHECK)
+    @unittest.skipUnless(HAS_EXTENDED_CHECK, "Extended ACL check not 
supported")
     def testExtended(self):
         """Test the acl_extended function"""
         fd, fname = self._getfile()
@@ -180,7 +209,12 @@
             self.assertTrue(has_extended(item),
                             "An extended ACL should be reported as such")
 
-    @has_ext(HAS_EQUIV_MODE)
+    @unittest.skipUnless(HAS_EXTENDED_CHECK, "Extended ACL check not 
supported")
+    def testExtendedArgHandling(self):
+      self.assertRaises(TypeError, has_extended)
+      self.assertRaises(TypeError, has_extended, object())
+
+    @unittest.skipUnless(HAS_EQUIV_MODE, "equiv_mode not supported")
     def testEquivMode(self):
         """Test the equiv_mode function"""
         if HAS_ACL_FROM_MODE:
@@ -192,6 +226,51 @@
         acl = posix1e.ACL(text="u::rx,g::-,o::-")
         self.assertEqual(acl.equiv_mode(), M0500)
 
+    @unittest.skipUnless(HAS_ACL_CHECK, "ACL check not supported")
+    def testToAnyText(self):
+        acl = posix1e.ACL(text=BASIC_ACL_TEXT)
+        self.assertIn(encode("u::"),
+                          acl.to_any_text(options=posix1e.TEXT_ABBREVIATE))
+        self.assertIn(encode("user::"), acl.to_any_text())
+
+    @unittest.skipUnless(HAS_ACL_CHECK, "ACL check not supported")
+    def testToAnyTextWrongArgs(self):
+        acl = posix1e.ACL(text=BASIC_ACL_TEXT)
+        self.assertRaises(TypeError, acl.to_any_text, foo="bar")
+
+
+    @unittest.skipUnless(HAS_ACL_CHECK, "ACL check not supported")
+    def testRichCompare(self):
+        acl1 = posix1e.ACL(text="u::rw,g::r,o::r")
+        acl2 = posix1e.ACL(acl=acl1)
+        acl3 = posix1e.ACL(text="u::rw,g::rw,o::r")
+        self.assertEqual(acl1, acl2)
+        self.assertNotEqual(acl1, acl3)
+        self.assertRaises(TypeError, operator.lt, acl1, acl2)
+        self.assertRaises(TypeError, operator.ge, acl1, acl3)
+        self.assertTrue(acl1 != True)
+        self.assertFalse(acl1 == 1)
+        self.assertRaises(TypeError, operator.gt, acl1, True)
+
+    @unittest.skipUnless(hasattr(posix1e.ACL, "__cmp__"), "__cmp__ is missing")
+    @unittest.skipUnless(__pypy__ is None, "Disabled under pypy")
+    def testCmp(self):
+        acl1 = posix1e.ACL()
+        self.assertRaises(TypeError, acl1.__cmp__, acl1)
+
+    def testApplyToWithWrongObject(self):
+        acl1 = posix1e.ACL(text=BASIC_ACL_TEXT)
+        self.assertTrue(acl1.valid())
+        self.assertRaises(TypeError, acl1.applyto, object())
+        self.assertRaises(TypeError, acl1.applyto, object(), object())
+
+    @unittest.skipUnless(HAS_ACL_ENTRY, "ACL entries not supported")
+    def testAclIterator(self):
+        acl = posix1e.ACL(text=BASIC_ACL_TEXT)
+        #self.assertEqual(len(acl), 3)
+        for entry in acl:
+            self.assertIs(entry.parent, acl)
+
 
 class WriteTests(aclTest, unittest.TestCase):
     """Write tests"""
@@ -201,6 +280,10 @@
         dname = self._getdir()
         posix1e.delete_default(dname)
 
+    @unittest.skipUnless(__pypy__ is None, "Disabled under pypy")
+    def testDeleteDefaultWrongArg(self):
+        self.assertRaises(TypeError, posix1e.delete_default, object())
+
     def testReapply(self):
         """Test re-applying an ACL"""
         fd, fname = self._getfile()
@@ -212,6 +295,7 @@
         acl2.applyto(dname)
 
 
[email protected](HAS_ACL_ENTRY, "ACL entries not supported")
 class ModificationTests(aclTest, unittest.TestCase):
     """ACL modification tests"""
 
@@ -233,7 +317,6 @@
         str_acl = str(acl)
         self.checkRef(str_acl)
 
-    @has_ext(HAS_ACL_ENTRY)
     def testAppend(self):
         """Test append a new Entry to the ACL"""
         acl = posix1e.ACL()
@@ -242,8 +325,27 @@
         ignore_ioerror(errno.EINVAL, acl.calc_mask)
         str_format = str(e)
         self.checkRef(str_format)
+        e2 = acl.append(e)
+        ignore_ioerror(errno.EINVAL, acl.calc_mask)
+        self.assertFalse(acl.valid())
+
+    def testWrongAppend(self):
+        """Test append a new Entry to the ACL based on wrong object type"""
+        acl = posix1e.ACL()
+        self.assertRaises(TypeError, acl.append, object())
+
+    def testEntryCreation(self):
+        acl = posix1e.ACL()
+        e = posix1e.Entry(acl)
+        ignore_ioerror(errno.EINVAL, acl.calc_mask)
+        str_format = str(e)
+        self.checkRef(str_format)
+
+    def testEntryFailedCreation(self):
+        # Checks for partial initialisation and deletion on error
+        # path.
+        self.assertRaises(TypeError, posix1e.Entry, object())
 
-    @has_ext(HAS_ACL_ENTRY)
     def testDelete(self):
         """Test delete Entry from the ACL"""
         acl = posix1e.ACL()
@@ -253,7 +355,36 @@
         acl.delete_entry(e)
         ignore_ioerror(errno.EINVAL, acl.calc_mask)
 
-    @has_ext(HAS_ACL_ENTRY)
+    def testDoubleDelete(self):
+        """Test delete Entry from the ACL"""
+        # This is not entirely valid/correct, since the entry object
+        # itself is invalid after the first deletion, so we're
+        # actually testing deleting an invalid object, not a
+        # non-existing entry...
+        acl = posix1e.ACL()
+        e = acl.append()
+        e.tag_type = posix1e.ACL_OTHER
+        ignore_ioerror(errno.EINVAL, acl.calc_mask)
+        acl.delete_entry(e)
+        ignore_ioerror(errno.EINVAL, acl.calc_mask)
+        self.assertRaises(EnvironmentError, acl.delete_entry, e)
+
+    # This currently fails as this deletion seems to be accepted :/
+    @unittest.skip("Entry deletion is unreliable")
+    def testDeleteInvalidEntry(self):
+        """Test delete foreign Entry from the ACL"""
+        acl1 = posix1e.ACL()
+        acl2 = posix1e.ACL()
+        e = acl1.append()
+        e.tag_type = posix1e.ACL_OTHER
+        ignore_ioerror(errno.EINVAL, acl1.calc_mask)
+        self.assertRaises(EnvironmentError, acl2.delete_entry, e)
+
+    def testDeleteInvalidObject(self):
+        """Test delete a non-Entry from the ACL"""
+        acl = posix1e.ACL()
+        self.assertRaises(TypeError, acl.delete_entry, object())
+
     def testDoubleEntries(self):
         """Test double entries"""
         acl = posix1e.ACL(text=BASIC_ACL_TEXT)
@@ -268,7 +399,6 @@
                 " should not be valid")
             acl.delete_entry(e)
 
-    @has_ext(HAS_ACL_ENTRY)
     def testMultipleGoodEntries(self):
         """Test multiple valid entries"""
         acl = posix1e.ACL(text=BASIC_ACL_TEXT)
@@ -285,7 +415,6 @@
                     "ACL should be able to hold multiple"
                     " user/group entries")
 
-    @has_ext(HAS_ACL_ENTRY)
     def testMultipleBadEntries(self):
         """Test multiple invalid entries"""
         for tag_type in (posix1e.ACL_USER,
@@ -312,7 +441,64 @@
             # entry, even though it still exists.
             ignore_ioerror(errno.EINVAL, acl.delete_entry, e2)
 
-    @has_ext(HAS_ACL_ENTRY)
+    def testCopy(self):
+        acl = ACL()
+        e1 = acl.append()
+        e1.tag_type = ACL_USER
+        p1 = e1.permset
+        p1.clear()
+        p1.read = True
+        p1.write = True
+        e2 = acl.append()
+        e2.tag_type = ACL_GROUP
+        p2 = e2.permset
+        p2.clear()
+        p2.read = True
+        self.assertFalse(p2.write)
+        e2.copy(e1)
+        self.assertTrue(p2.write)
+        self.assertEqual(e1.tag_type, e2.tag_type)
+
+    def testCopyWrongArg(self):
+        acl = ACL()
+        e = acl.append()
+        self.assertRaises(TypeError, e.copy, object())
+
+    def testSetPermset(self):
+        acl = ACL()
+        e1 = acl.append()
+        e1.tag_type = ACL_USER
+        p1 = e1.permset
+        p1.clear()
+        p1.read = True
+        p1.write = True
+        e2 = acl.append()
+        e2.tag_type = ACL_GROUP
+        p2 = e2.permset
+        p2.clear()
+        p2.read = True
+        self.assertFalse(p2.write)
+        e2.permset = p1
+        self.assertTrue(e2.permset.write)
+        self.assertEqual(e2.tag_type, ACL_GROUP)
+
+    def testSetPermsetWrongArg(self):
+        acl = ACL()
+        e = acl.append()
+        def setter(v):
+            e.permset = v
+        self.assertRaises(TypeError, setter, object())
+
+    def testPermsetCreation(self):
+        acl = ACL()
+        e = acl.append()
+        p1 = e.permset
+        p2 = Permset(e)
+        #self.assertEqual(p1, p2)
+
+    def testPermsetCreationWrongArg(self):
+        self.assertRaises(TypeError, Permset, object())
+
     def testPermset(self):
         """Test permissions"""
         acl = posix1e.ACL()
@@ -321,27 +507,65 @@
         ps.clear()
         str_ps = str(ps)
         self.checkRef(str_ps)
-        pmap = {
-            posix1e.ACL_READ: "read",
-            posix1e.ACL_WRITE: "write",
-            posix1e.ACL_EXECUTE: "execute",
-            }
-        for perm in pmap:
+        for perm in PERMSETS:
             str_ps = str(ps)
+            txt = PERMSETS[perm][0]
             self.checkRef(str_ps)
             self.assertFalse(ps.test(perm), "Empty permission set should not"
-                " have permission '%s'" % pmap[perm])
+                " have permission '%s'" % txt)
             ps.add(perm)
             self.assertTrue(ps.test(perm), "Permission '%s' should exist"
-                " after addition" % pmap[perm])
+                " after addition" % txt)
             str_ps = str(ps)
             self.checkRef(str_ps)
             ps.delete(perm)
             self.assertFalse(ps.test(perm), "Permission '%s' should not exist"
-                " after deletion" % pmap[perm])
+                " after deletion" % txt)
 
+    def testPermsetViaAccessors(self):
+        """Test permissions"""
+        acl = posix1e.ACL()
+        e = acl.append()
+        ps = e.permset
+        ps.clear()
+        str_ps = str(ps)
+        self.checkRef(str_ps)
+        def getter(perm):
+            return PERMSETS[perm][1].__get__(ps)
+        def setter(parm, value):
+            return PERMSETS[perm][1].__set__(ps, value)
+        for perm in PERMSETS:
+            str_ps = str(ps)
+            self.checkRef(str_ps)
+            txt = PERMSETS[perm][0]
+            self.assertFalse(getter(perm), "Empty permission set should not"
+                " have permission '%s'" % txt)
+            setter(perm, True)
+            self.assertTrue(ps.test(perm), "Permission '%s' should exist"
+                " after addition" % txt)
+            self.assertTrue(getter(perm), "Permission '%s' should exist"
+                " after addition" % txt)
+            str_ps = str(ps)
+            self.checkRef(str_ps)
+            setter(perm, False)
+            self.assertFalse(ps.test(perm), "Permission '%s' should not exist"
+                " after deletion" % txt)
+            self.assertFalse(getter(perm), "Permission '%s' should not exist"
+                " after deletion" % txt)
+
+    def testPermsetInvalidType(self):
+        acl = posix1e.ACL()
+        e = acl.append()
+        ps = e.permset
+        ps.clear()
+        def setter():
+            ps.write = object()
+        self.assertRaises(TypeError, ps.add, "foobar")
+        self.assertRaises(TypeError, ps.delete, "foobar")
+        self.assertRaises(TypeError, ps.test, "foobar")
+        self.assertRaises(ValueError, setter)
 
-    @has_ext(HAS_ACL_ENTRY and IS_PY_3K)
+    @unittest.skipUnless(IS_PY_3K, "Only supported under Python 3")
     def testQualifierValues(self):
         """Tests qualifier correct store/retrieval"""
         acl = posix1e.ACL()
@@ -368,7 +592,7 @@
                 fn(str(e), regex)
                 qualifier *= 2
 
-    @has_ext(HAS_ACL_ENTRY and IS_PY_3K)
+    @unittest.skipUnless(IS_PY_3K, "Only supported under Python 3")
     def testQualifierOverflow(self):
         """Tests qualifier overflow handling"""
         acl = posix1e.ACL()
@@ -379,7 +603,7 @@
             with self.assertRaises(OverflowError):
                 e.qualifier = qualifier
 
-    @has_ext(HAS_ACL_ENTRY and IS_PY_3K)
+    @unittest.skipUnless(IS_PY_3K, "Only supported under Python 3")
     def testNegativeQualifier(self):
         """Tests negative qualifier handling"""
         # Note: this presumes that uid_t/gid_t in C are unsigned...
@@ -391,6 +615,61 @@
                 with self.assertRaises(OverflowError):
                     e.qualifier = qualifier
 
+    def testInvalidQualifier(self):
+        """Tests invalid qualifier handling"""
+        acl = posix1e.ACL()
+        e = acl.append()
+        def set_qual(x):
+            e.qualifier = x
+        def del_qual():
+            del e.qualifier
+        self.assertRaises(TypeError, set_qual, object())
+        self.assertRaises((TypeError, AttributeError), del_qual)
+
+    def testQualifierOnWrongTag(self):
+        """Tests qualifier setting on wrong tag"""
+        acl = posix1e.ACL()
+        e = acl.append()
+        e.tag_type = posix1e.ACL_OTHER
+        def set_qual(x):
+            e.qualifier = x
+        def get_qual():
+            return e.qualifier
+        self.assertRaises(TypeError, set_qual, 1)
+        self.assertRaises(TypeError, get_qual)
+
+
+    def testTagTypes(self):
+        """Tests tag type correct set/get"""
+        acl = posix1e.ACL()
+        e = acl.append()
+        for tag in [posix1e.ACL_USER, posix1e.ACL_GROUP, posix1e.ACL_USER_OBJ,
+                    posix1e.ACL_GROUP_OBJ, posix1e.ACL_MASK,
+                    posix1e.ACL_OTHER]:
+            e.tag_type = tag
+            self.assertEqual(e.tag_type, tag)
+            # check we can show all tag types without breaking
+            self.assertTrue(str(e))
+
+    def testInvalidTags(self):
+        """Tests tag type incorrect set/get"""
+        acl = posix1e.ACL()
+        e = acl.append()
+        def set_tag(x):
+          e.tag_type = x
+        self.assertRaises(TypeError, set_tag, object())
+        def delete_tag():
+          del e.tag_type
+        # For some reason, PyPy raises AttributeError. Strange...
+        self.assertRaises((TypeError, AttributeError), delete_tag)
+
+        e.tag_type = posix1e.ACL_USER_OBJ
+        tag = max([posix1e.ACL_USER, posix1e.ACL_GROUP, posix1e.ACL_USER_OBJ,
+                   posix1e.ACL_GROUP_OBJ, posix1e.ACL_MASK,
+                   posix1e.ACL_OTHER]) + 1
+        self.assertRaises(EnvironmentError, set_tag, tag)
+        # Check tag is still valid.
+        self.assertEqual(e.tag_type, posix1e.ACL_USER_OBJ)
 
 if __name__ == "__main__":
     unittest.main()


Reply via email to