[Python-modules-commits] [python-llfuse] 01/01: Import python-llfuse_1.1.1+dfsg.orig.tar.xz

Nikolaus Rath nikratio-guest at moszumanska.debian.org
Wed Jul 27 18:26:33 UTC 2016


This is an automated email from the git hooks/post-receive script.

nikratio-guest pushed a commit to branch upstream
in repository python-llfuse.

commit df84cf8d74324f750f847be2f6fb0bcb39e571ce
Author: Nikolaus Rath <Nikolaus at rath.org>
Date:   Wed Jul 27 10:17:23 2016 -0700

    Import python-llfuse_1.1.1+dfsg.orig.tar.xz
---
 Changes.rst                     |  14 +++++
 PKG-INFO                        |   2 +-
 rst/install.rst                 |   4 +-
 setup.py                        |   5 +-
 src/llfuse.c                    |  14 ++---
 src/llfuse.egg-info/PKG-INFO    |   2 +-
 src/llfuse.egg-info/SOURCES.txt |   2 +-
 src/misc.pxi                    |   4 +-
 src/operations.pxi              |   2 +-
 src/xattr.h                     |  21 ++++++-
 test/.cache/v/cache/lastfailed  | Bin 7 -> 0 bytes
 test/conftest.py                |  75 +++++++++++++----------
 test/pytest_checklogs.py        | 130 ++++++++++++++++++++++++++++++++++++++++
 test/test_fs.py                 |  18 +++++-
 14 files changed, 243 insertions(+), 50 deletions(-)

diff --git a/Changes.rst b/Changes.rst
index 08ccb9d..7e4e869 100644
--- a/Changes.rst
+++ b/Changes.rst
@@ -4,6 +4,20 @@
 
 .. currentmodule:: llfuse
 
+Release 1.1.1 (2016-07-27)
+==========================
+
+* Fixed the description of the `~Operations.lookup` handler (should
+  return zero if there is no such entry, not a negative value).
+* Fixed the description of the `EntryAttributes` structure
+  (descriptions of `~EntryAttributes.attr_timeout` and
+  `~EntryAttributes.entry_timeout` were switched).
+
+Release 1.1 (2016-05-23)
+========================
+
+* Added support for nanosecond resolution time-stamps in GNU/kFreeBSD.
+* Fixed another set of build issues on FreeBSD.
 
 Release 1.0 (2016-03-08)
 ========================
diff --git a/PKG-INFO b/PKG-INFO
index bc25431..d17145e 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: llfuse
-Version: 1.0
+Version: 1.1.1
 Summary: Python bindings for the low-level FUSE API
 Home-page: https://bitbucket.org/nikratio/python-llfuse/
 Author: Nikolaus Rath
diff --git a/rst/install.rst b/rst/install.rst
index a7c6c7e..bab2354 100644
--- a/rst/install.rst
+++ b/rst/install.rst
@@ -22,7 +22,9 @@ In order to build and run Python-LLFUSE you need the following software:
 
 To run the unit tests, you will need
 
-* The `py.test`_ module.
+* The `py.test`_ module, version 2.8.0 or newer
+* The `pytest-catchlog
+  <https://github.com/eisensheng/pytest-catchlog>`_ module
 
 When using Linux, you also need:
 
diff --git a/setup.py b/setup.py
index 185ab31..353c05c 100755
--- a/setup.py
+++ b/setup.py
@@ -59,7 +59,7 @@ if DEVELOPER_MODE:
 # to work properly
 sys.path.insert(0, os.path.join(basedir, 'src'))
 
-LLFUSE_VERSION = '1.0'
+LLFUSE_VERSION = '1.1.1'
 
 def main():
 
@@ -111,10 +111,9 @@ def main():
     link_args.append('-lpthread')
     c_sources = ['src/llfuse.c', 'src/lock.c']
 
-    if os.uname()[0] == 'Linux':
+    if os.uname()[0] in ('Linux', 'GNU/kFreeBSD'):
         link_args.append('-lrt')
         compile_args.append('-DHAVE_STRUCT_STAT_ST_ATIM')
-
     elif os.uname()[0] == 'Darwin':
         compile_args.append('-DHAVE_STRUCT_STAT_ST_ATIMESPEC')
         c_sources.append('src/darwin_compat.c')
diff --git a/src/llfuse.c b/src/llfuse.c
index 6ce8c4b..b92ed5e 100644
--- a/src/llfuse.c
+++ b/src/llfuse.c
@@ -2363,7 +2363,7 @@ static PyObject *__pyx_pf_6llfuse_10Operations_2destroy(CYTHON_UNUSED PyObject *
 
 /* Python wrapper */
 static PyObject *__pyx_pw_6llfuse_10Operations_5lookup(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
-static char __pyx_doc_6llfuse_10Operations_4lookup[] = "Operations.lookup(self, parent_inode, name, ctx)\nLook up a directory entry by name and get its attributes.\n\n        This method should return an `EntryAttributes` instance for the\n        directory entry *name* in the directory with inode *parent_inode*.\n\n        If there is no such entry, the method should either return an\n        `EntryAttributes` instance with negative ``st_ino`` value (in which case\n        the negative  [...]
+static char __pyx_doc_6llfuse_10Operations_4lookup[] = "Operations.lookup(self, parent_inode, name, ctx)\nLook up a directory entry by name and get its attributes.\n\n        This method should return an `EntryAttributes` instance for the\n        directory entry *name* in the directory with inode *parent_inode*.\n\n        If there is no such entry, the method should either return an\n        `EntryAttributes` instance with zero ``st_ino`` value (in which case\n        the negative look [...]
 static PyMethodDef __pyx_mdef_6llfuse_10Operations_5lookup = {"lookup", (PyCFunction)__pyx_pw_6llfuse_10Operations_5lookup, METH_VARARGS|METH_KEYWORDS, __pyx_doc_6llfuse_10Operations_4lookup};
 static PyObject *__pyx_pw_6llfuse_10Operations_5lookup(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
   CYTHON_UNUSED PyObject *__pyx_v_self = 0;
@@ -29315,7 +29315,7 @@ static int __pyx_pf_6llfuse_15EntryAttributes_10generation_2__set__(struct __pyx
  * 
  *     @property
  *     def attr_timeout(self):             # <<<<<<<<<<<<<<
- *         '''Validity timeout for the name of the directory entry
+ *         '''Validity timeout for the attributes of the directory entry
  * 
  */
 
@@ -29356,7 +29356,7 @@ static PyObject *__pyx_pf_6llfuse_15EntryAttributes_12attr_timeout___get__(struc
  * 
  *     @property
  *     def attr_timeout(self):             # <<<<<<<<<<<<<<
- *         '''Validity timeout for the name of the directory entry
+ *         '''Validity timeout for the attributes of the directory entry
  * 
  */
 
@@ -29431,7 +29431,7 @@ static int __pyx_pf_6llfuse_15EntryAttributes_12attr_timeout_2__set__(struct __p
  * 
  *     @property
  *     def entry_timeout(self):             # <<<<<<<<<<<<<<
- *         '''Validity timeout for the attributes of the directory entry
+ *         '''Validity timeout for the name/existence of the directory entry
  * 
  */
 
@@ -29472,7 +29472,7 @@ static PyObject *__pyx_pf_6llfuse_15EntryAttributes_13entry_timeout___get__(stru
  * 
  *     @property
  *     def entry_timeout(self):             # <<<<<<<<<<<<<<
- *         '''Validity timeout for the attributes of the directory entry
+ *         '''Validity timeout for the name/existence of the directory entry
  * 
  */
 
@@ -40262,8 +40262,8 @@ static PyMethodDef __pyx_methods_6llfuse_EntryAttributes[] = {
 static struct PyGetSetDef __pyx_getsets_6llfuse_EntryAttributes[] = {
   {(char *)"st_ino", __pyx_getprop_6llfuse_15EntryAttributes_st_ino, __pyx_setprop_6llfuse_15EntryAttributes_st_ino, (char *)0, 0},
   {(char *)"generation", __pyx_getprop_6llfuse_15EntryAttributes_generation, __pyx_setprop_6llfuse_15EntryAttributes_generation, (char *)"The inode generation number", 0},
-  {(char *)"attr_timeout", __pyx_getprop_6llfuse_15EntryAttributes_attr_timeout, __pyx_setprop_6llfuse_15EntryAttributes_attr_timeout, (char *)"Validity timeout for the name of the directory entry\n\n        Floating point numbers may be used. Units are seconds.\n        ", 0},
-  {(char *)"entry_timeout", __pyx_getprop_6llfuse_15EntryAttributes_entry_timeout, __pyx_setprop_6llfuse_15EntryAttributes_entry_timeout, (char *)"Validity timeout for the attributes of the directory entry\n\n        Floating point numbers may be used. Units are seconds.\n        ", 0},
+  {(char *)"attr_timeout", __pyx_getprop_6llfuse_15EntryAttributes_attr_timeout, __pyx_setprop_6llfuse_15EntryAttributes_attr_timeout, (char *)"Validity timeout for the attributes of the directory entry\n\n        Floating point numbers may be used. Units are seconds.\n        ", 0},
+  {(char *)"entry_timeout", __pyx_getprop_6llfuse_15EntryAttributes_entry_timeout, __pyx_setprop_6llfuse_15EntryAttributes_entry_timeout, (char *)"Validity timeout for the name/existence of the directory entry\n\n        Floating point numbers may be used. Units are seconds.\n        ", 0},
   {(char *)"st_mode", __pyx_getprop_6llfuse_15EntryAttributes_st_mode, __pyx_setprop_6llfuse_15EntryAttributes_st_mode, (char *)0, 0},
   {(char *)"st_nlink", __pyx_getprop_6llfuse_15EntryAttributes_st_nlink, __pyx_setprop_6llfuse_15EntryAttributes_st_nlink, (char *)0, 0},
   {(char *)"st_uid", __pyx_getprop_6llfuse_15EntryAttributes_st_uid, __pyx_setprop_6llfuse_15EntryAttributes_st_uid, (char *)0, 0},
diff --git a/src/llfuse.egg-info/PKG-INFO b/src/llfuse.egg-info/PKG-INFO
index bc25431..d17145e 100644
--- a/src/llfuse.egg-info/PKG-INFO
+++ b/src/llfuse.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: llfuse
-Version: 1.0
+Version: 1.1.1
 Summary: Python bindings for the low-level FUSE API
 Home-page: https://bitbucket.org/nikratio/python-llfuse/
 Author: Nikolaus Rath
diff --git a/src/llfuse.egg-info/SOURCES.txt b/src/llfuse.egg-info/SOURCES.txt
index 3d5a9b0..3b729be 100644
--- a/src/llfuse.egg-info/SOURCES.txt
+++ b/src/llfuse.egg-info/SOURCES.txt
@@ -100,9 +100,9 @@ src/llfuse.egg-info/top_level.txt
 src/llfuse.egg-info/zip-safe
 test/conftest.py
 test/pytest.ini
+test/pytest_checklogs.py
 test/test_api.py
 test/test_examples.py
 test/test_fs.py
 test/util.py
-test/.cache/v/cache/lastfailed
 util/sphinx_cython.py
\ No newline at end of file
diff --git a/src/misc.pxi b/src/misc.pxi
index 17bf16a..c9498df 100644
--- a/src/misc.pxi
+++ b/src/misc.pxi
@@ -386,7 +386,7 @@ cdef class EntryAttributes:
 
     @property
     def attr_timeout(self):
-        '''Validity timeout for the name of the directory entry
+        '''Validity timeout for the attributes of the directory entry
 
         Floating point numbers may be used. Units are seconds.
         '''
@@ -397,7 +397,7 @@ cdef class EntryAttributes:
 
     @property
     def entry_timeout(self):
-        '''Validity timeout for the attributes of the directory entry
+        '''Validity timeout for the name/existence of the directory entry
 
         Floating point numbers may be used. Units are seconds.
         '''
diff --git a/src/operations.pxi b/src/operations.pxi
index 2caa8d4..8f2daa3 100644
--- a/src/operations.pxi
+++ b/src/operations.pxi
@@ -54,7 +54,7 @@ class Operations(object):
         directory entry *name* in the directory with inode *parent_inode*.
 
         If there is no such entry, the method should either return an
-        `EntryAttributes` instance with negative ``st_ino`` value (in which case
+        `EntryAttributes` instance with zero ``st_ino`` value (in which case
         the negative lookup will be cached as specified by ``entry_timeout``),
         or it should raise `FUSEError` with an errno of `errno.ENOENT` (in this
         case the negative result will not be cached).
diff --git a/src/xattr.h b/src/xattr.h
index 4dcee01..182040a 100644
--- a/src/xattr.h
+++ b/src/xattr.h
@@ -83,7 +83,26 @@ static ssize_t getxattr_p (char *path, char *name, void *value, size_t size,
 
 static int setxattr_p (char *path, char *name, void *value, size_t size,
                        int namespace) {
-    return extattr_set_file(path, namespace, name, value, size);
+    if (size >= SSIZE_MAX) {
+        errno = EINVAL;
+        return -1;
+    }
+
+    ssize_t ret;
+    ret = extattr_set_file(path, namespace, name, value, size);
+    if (ret < 0) {
+        /* Errno values really ought to fit into int, but better safe
+           than sorry */
+        if (ret < INT_MIN)
+            return -EOVERFLOW;
+        else
+            return (int) ret;
+    }
+    if ((size_t)ret != size) {
+        errno = ENOSPC;
+        return -1;
+    }
+    return 0;
 }
 
 
diff --git a/test/.cache/v/cache/lastfailed b/test/.cache/v/cache/lastfailed
deleted file mode 100644
index 17f7165..0000000
Binary files a/test/.cache/v/cache/lastfailed and /dev/null differ
diff --git a/test/conftest.py b/test/conftest.py
index d079c82..fa19c6a 100644
--- a/test/conftest.py
+++ b/test/conftest.py
@@ -2,23 +2,24 @@ import sys
 import os.path
 import logging
 import pytest
+import time
 import gc
 
-# Converted to autouse fixture below if capture is activated
-def check_test_output(request, capfd):
-    request.capfd = capfd
-    def raise_on_exception_in_out():
-        # Peek at captured output
-        (stdout, stderr) = capfd.readouterr()
-        sys.stdout.write(stdout)
-        sys.stderr.write(stderr)
+# Enable output checks
+pytest_plugins = ('pytest_checklogs')
 
-        if ('exception' in stderr.lower()
-            or 'exception' in stdout.lower()):
-            raise AssertionError('Suspicious output to stderr')
+# Register false positives
+ at pytest.fixture(autouse=True)
+def register_false_checklog_pos(reg_output):
 
-    request.addfinalizer(raise_on_exception_in_out)
+    # DeprecationWarnings are unfortunately quite often a result of indirect
+    # imports via third party modules, so we can't actually fix them.
+    reg_output(r'(Pending)?DeprecationWarning', count=0)
 
+    # Valgrind output
+    reg_output(r'^==\d+== Memcheck, a memory error detector$')
+    reg_output(r'^==\d+== For counts of detected and suppressed errors, rerun with: -v')
+    reg_output(r'^==\d+== ERROR SUMMARY: 0 errors from 0 contexts')
 
 def pytest_addoption(parser):
     group = parser.getgroup("general")
@@ -26,15 +27,25 @@ def pytest_addoption(parser):
                      help="Test the installed package.")
 
     group = parser.getgroup("terminal reporting")
-    group._addoption("--logdebug", action="store_true", default=False,
-                     help="Activate debugging output.")
+    group._addoption("--logdebug", action="append", metavar='<module>',
+                     help="Activate debugging output from <module> for tests. Use `all` "
+                          "to get debug messages from all modules. This option can be "
+                          "specified multiple times.")
 
-def pytest_configure(config):
-    # Enable stdout and stderr analysis, unless output capture is disabled
-    if config.getoption('capture') != 'no':
-        global check_test_output
-        check_test_output = pytest.fixture(autouse=True)(check_test_output)
+# If a test fails, wait a moment before retrieving the captured
+# stdout/stderr. When using a server process, this makes sure that we capture
+# any potential output of the server that comes *after* a test has failed. For
+# example, if a request handler raises an exception, the server first signals an
+# error to FUSE (causing the test to fail), and then logs the exception. Without
+# the extra delay, the exception will go into nowhere.
+ at pytest.mark.hookwrapper
+def pytest_pyfunc_call(pyfuncitem):
+    outcome = yield
+    failed = outcome.excinfo is not None
+    if failed:
+        time.sleep(1)
 
+def pytest_configure(config):
     # If we are running from the source directory, make sure that we load
     # modules from here
     basedir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
@@ -63,19 +74,23 @@ def pytest_configure(config):
     if os.path.exists(os.path.join(basedir, 'MANIFEST.in')):
         import warnings
         warnings.resetwarnings()
-        warnings.simplefilter('error')
+        warnings.simplefilter('default')
 
+    # Configure logging. We don't set a default handler but rely on
+    # the catchlog pytest plugin.
     logdebug = config.getoption('logdebug')
-    if logdebug:
-        root_logger = logging.getLogger()
-        formatter = logging.Formatter('%(asctime)s.%(msecs)03d %(threadName)s '
-                                      '%(funcName)s: %(message)s',
-                                      datefmt="%H:%M:%S")
-        handler = logging.StreamHandler(sys.stdout)
-        handler.setLevel(logging.DEBUG)
-        handler.setFormatter(formatter)
-        root_logger.addHandler(handler)
-        root_logger.setLevel(logging.DEBUG)
+    root_logger = logging.getLogger()
+    if logdebug is not None:
+        logging.disable(logging.NOTSET)
+        if 'all' in logdebug:
+            root_logger.setLevel(logging.DEBUG)
+        else:
+            for module in logdebug:
+                logging.getLogger(module).setLevel(logging.DEBUG)
+    else:
+        root_logger.setLevel(logging.INFO)
+        logging.disable(logging.DEBUG)
+    logging.captureWarnings(capture=True)
 
 # Run gc.collect() at the end of every test, so that we get ResourceWarnings
 # as early as possible.
diff --git a/test/pytest_checklogs.py b/test/pytest_checklogs.py
new file mode 100644
index 0000000..046df20
--- /dev/null
+++ b/test/pytest_checklogs.py
@@ -0,0 +1,130 @@
+#!/usr/bin/env python3
+'''
+py.test plugin to look for suspicious phrases in messages
+emitted on stdout/stderr or via the logging module.
+
+False positives can be registered via a new `reg_output`
+fixture (for messages to stdout/stderr), and a `assert_logs`
+function (for logging messages).
+'''
+
+import pytest
+import re
+import functools
+import sys
+import logging
+from contextlib import contextmanager
+
+def pytest_configure(config):
+    if not config.pluginmanager.hasplugin('pytest_catchlog'):
+        raise ImportError('pytest catchlog plugin not found')
+
+# Fail tests if they result in log messages of severity WARNING or more.
+def check_test_log(caplog):
+    for record in caplog.records:
+        if (record.levelno >= logging.WARNING and
+            not getattr(record, 'checklogs_ignore', False)):
+            raise AssertionError('Logger received warning messages')
+
+class CountMessagesHandler(logging.Handler):
+    def __init__(self, level=logging.NOTSET):
+        super().__init__(level)
+        self.count = 0
+
+    def emit(self, record):
+        self.count += 1
+
+ at contextmanager
+def assert_logs(pattern, level=logging.WARNING, count=None):
+    '''Assert that suite emits specified log message
+
+    *pattern* is matched against the *unformatted* log message, i.e. before any
+    arguments are merged.
+
+    If *count* is not None, raise an exception unless exactly *count* matching
+    messages are caught.
+
+    Matched log records will also be flagged so that the caplog fixture
+    does not generate exceptions for them (no matter their severity).
+    '''
+
+    def filter(record):
+        if (record.levelno == level and
+            re.search(pattern, record.msg)):
+            record.checklogs_ignore = True
+            return True
+        return False
+
+    handler = CountMessagesHandler()
+    handler.setLevel(level)
+    handler.addFilter(filter)
+    logger = logging.getLogger()
+    logger.addHandler(handler)
+    try:
+        yield
+
+    finally:
+        logger.removeHandler(handler)
+
+        if count is not None and handler.count != count:
+            raise AssertionError('Expected to catch %d %r messages, but got only %d'
+                                 % (count, pattern, handler.count))
+
+def check_test_output(capfd, item):
+    (stdout, stderr) = capfd.readouterr()
+
+    # Write back what we've read (so that it will still be printed)
+    sys.stdout.write(stdout)
+    sys.stderr.write(stderr)
+
+    # Strip out false positives
+    try:
+        false_pos = item.checklogs_fp
+    except AttributeError:
+        false_pos = ()
+    for (pattern, flags, count) in false_pos:
+        cp = re.compile(pattern, flags)
+        (stdout, cnt) = cp.subn('', stdout, count=count)
+        if count == 0 or count - cnt > 0:
+            stderr = cp.sub('', stderr, count=count - cnt)
+
+    for pattern in ('exception', 'error', 'warning', 'fatal', 'traceback',
+                    'fault', 'crash(?:ed)?', 'abort(?:ed)', 'fishy'):
+        cp = re.compile(r'\b{}\b'.format(pattern), re.IGNORECASE | re.MULTILINE)
+        hit = cp.search(stderr)
+        if hit:
+            raise AssertionError('Suspicious output to stderr (matched "%s")' % hit.group(0))
+        hit = cp.search(stdout)
+        if hit:
+            raise AssertionError('Suspicious output to stdout (matched "%s")' % hit.group(0))
+
+def register_output(item, pattern, count=1, flags=re.MULTILINE):
+    '''Register *pattern* as false positive for output checking
+
+    This prevents the test from failing because the output otherwise
+    appears suspicious.
+    '''
+
+    item.checklogs_fp.append((pattern, flags, count))
+
+ at pytest.fixture()
+def reg_output(request):
+    assert not hasattr(request.node, 'checklogs_fp')
+    request.node.checklogs_fp = []
+    return functools.partial(register_output, request.node)
+
+def check_output(item):
+    pm = item.config.pluginmanager
+    cm = pm.getplugin('capturemanager')
+    check_test_output(cm._capturing, item)
+    check_test_log(item.catch_log_handler)
+
+ at pytest.hookimpl(trylast=True)
+def pytest_runtest_setup(item):
+    check_output(item)
+ at pytest.hookimpl(trylast=True)
+def pytest_runtest_call(item):
+    check_output(item)
+ at pytest.hookimpl(trylast=True)
+def pytest_runtest_teardown(item, nextitem):
+    check_output(item)
diff --git a/test/test_fs.py b/test/test_fs.py
index 61512f5..b6c2511 100755
--- a/test/test_fs.py
+++ b/test/test_fs.py
@@ -23,6 +23,7 @@ import os
 import errno
 import stat
 import time
+import logging
 import threading
 from util import skip_if_no_fuse, wait_for_mount, umount, cleanup, wait_for
 
@@ -32,8 +33,9 @@ skip_if_no_fuse()
 @pytest.yield_fixture()
 def testfs(tmpdir):
 
-    # We can't use forkserver or spawn because of
-    # https://github.com/pytest-dev/pytest/issues/958.
+    # We can't use forkserver because we have to make sure
+    # that the server inherits the per-test stdout/stderr file
+    # descriptors.
     if hasattr(multiprocessing, 'get_context'):
         mp = multiprocessing.get_context('fork')
     else:
@@ -231,6 +233,18 @@ class Fs(llfuse.Operations):
             raise FUSEError(errno.EINVAL)
 
 def run_fs(mountpoint, cross_process):
+    # Logging (note that we run in a new process, so we can't
+    # rely on direct log capture and instead print to stdout)
+    root_logger = logging.getLogger()
+    formatter = logging.Formatter('%(asctime)s.%(msecs)03d %(levelname)s '
+                                  '%(funcName)s(%(threadName)s): %(message)s',
+                                   datefmt="%M:%S")
+    handler = logging.StreamHandler(sys.stdout)
+    handler.setLevel(logging.DEBUG)
+    handler.setFormatter(formatter)
+    root_logger.addHandler(handler)
+    root_logger.setLevel(logging.DEBUG)
+
     testfs = Fs(cross_process)
     fuse_options = set(llfuse.default_options)
     fuse_options.add('fsname=llfuse_testfs')

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/python-llfuse.git



More information about the Python-modules-commits mailing list