[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