Add flake8 checks in tox and Python 3.8 in supported versions
diff --git a/.travis.yml b/.travis.yml
index ba42c72..a282485 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -15,7 +15,10 @@
python: "3.7"
env: TOXENV=py37
dist: xenial
- sudo: true
+ - os: linux
+ python: "3.8-dev"
+ env: TOXENV=py38
+ dist: xenial
- os: linux
python: "pypy"
env: TOXENV=pypy
@@ -30,8 +33,8 @@
- os: osx
language: generic
env:
- - PYTHON_VERSION=3.6
- - TOXENV=py36
+ - PYTHON_VERSION=3.7
+ - TOXENV=py37
before_install:
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then chmod +x .travis/install.sh && .travis/install.sh; fi
@@ -44,4 +47,4 @@
- tox
notifications:
- email: false
+ email: false
diff --git a/docs/source/conf.py b/docs/source/conf.py
index efe7ca2..101c7ab 100644
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
@@ -17,9 +17,9 @@
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
-TOP_DIR_PATH = os.path.abspath('../../')
-SRC_DIR_PATH = os.path.join(TOP_DIR_PATH, 'src')
-sys.path.insert(0, SRC_DIR_PATH)
+TOP_DIR_PATH = os.path.abspath('../../') # noqa
+SRC_DIR_PATH = os.path.join(TOP_DIR_PATH, 'src') # noqa
+sys.path.insert(0, SRC_DIR_PATH) # noqa
import watchdog.version
@@ -30,12 +30,15 @@
# -- General configuration -----------------------------------------------------
-# If your documentation needs a minimal Sphinx version, state it here.
-#needs_sphinx = '1.0'
-
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
-extensions = ['sphinx.ext.autodoc', 'sphinx.ext.todo', 'sphinx.ext.coverage', 'sphinx.ext.ifconfig', 'sphinx.ext.viewcode']
+extensions = [
+ 'sphinx.ext.autodoc',
+ 'sphinx.ext.todo',
+ 'sphinx.ext.coverage',
+ 'sphinx.ext.ifconfig',
+ 'sphinx.ext.viewcode'
+]
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
@@ -43,9 +46,6 @@
# The suffix of source filenames.
source_suffix = '.rst'
-# The encoding of source files.
-#source_encoding = 'utf-8-sig'
-
# The master toctree document.
master_doc = 'index'
@@ -62,161 +62,33 @@
# The full version, including alpha/beta/rc tags.
release = version
-# The language for content autogenerated by Sphinx. Refer to documentation
-# for a list of supported languages.
-#language = None
-
-# There are two options for replacing |today|: either, you set today to some
-# non-false value, then it is used:
-#today = ''
-# Else, today_fmt is used as the format for a strftime call.
-#today_fmt = '%B %d, %Y'
-
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = []
-# The reST default role (used for this markup: `text`) to use for all documents.
-#default_role = None
-
-# If true, '()' will be appended to :func: etc. cross-reference text.
-#add_function_parentheses = True
-
-# If true, the current module name will be prepended to all description
-# unit titles (such as .. function::).
-#add_module_names = True
-
-# If true, sectionauthor and moduleauthor directives will be shown in the
-# output. They are ignored by default.
-#show_authors = False
-
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
-# A list of ignored prefixes for module index sorting.
-#modindex_common_prefix = []
-
# -- Options for HTML output ---------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
-#html_theme = 'default'
html_theme = 'pyramid'
-# Theme options are theme-specific and customize the look and feel of a theme
-# further. For a list of options available for each theme, see the
-# documentation.
-#html_theme_options = {}
-
-# Add any paths that contain custom themes here, relative to this directory.
-#html_theme_path = []
-
-# The name for this set of Sphinx documents. If None, it defaults to
-# "<project> v<release> documentation".
-#html_title = None
-
-# A shorter title for the navigation bar. Default is the same as html_title.
-#html_short_title = None
-
-# The name of an image file (relative to this directory) to place at the top
-# of the sidebar.
-#html_logo = None
-
-# The name of an image file (within the static path) to use as favicon of the
-# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
-# pixels large.
-#html_favicon = None
-
-# Add any paths that contain custom static files (such as style sheets) here,
-# relative to this directory. They are copied after the builtin static files,
-# so a file named "default.css" will overwrite the builtin "default.css".
-#html_static_path = []
-
-# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
-# using the given strftime format.
-#html_last_updated_fmt = '%b %d, %Y'
-
-# If true, SmartyPants will be used to convert quotes and dashes to
-# typographically correct entities.
-#html_use_smartypants = True
-
-# Custom sidebar templates, maps document names to template names.
-#html_sidebars = {}
-
-# Additional templates that should be rendered to pages, maps page names to
-# template names.
-#html_additional_pages = {}
-
-# If false, no module index is generated.
-#html_domain_indices = True
-
-# If false, no index is generated.
-#html_use_index = True
-
-# If true, the index is split into individual pages for each letter.
-#html_split_index = False
-
-# If true, links to the reST sources are added to the pages.
-#html_show_sourcelink = True
-
-# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
-#html_show_sphinx = True
-
-# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
-#html_show_copyright = True
-
-# If true, an OpenSearch description file will be output, and all pages will
-# contain a <link> tag referring to it. The value of this option must be the
-# base URL from which the finished HTML is served.
-#html_use_opensearch = ''
-
-# This is the file name suffix for HTML files (e.g. ".xhtml").
-#html_file_suffix = None
-
# Output file base name for HTML help builder.
htmlhelp_basename = '%sdoc' % PROJECT_NAME
# -- Options for LaTeX output --------------------------------------------------
-# The paper size ('letter' or 'a4').
-#latex_paper_size = 'letter'
-
-# The font size ('10pt', '11pt' or '12pt').
-#latex_font_size = '10pt'
-
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
- ('index', '%s.tex' % PROJECT_NAME, '%s Documentation' % PROJECT_NAME,
- AUTHOR_NAME, 'manual'),
+ ('index', '%s.tex' % PROJECT_NAME, '%s Documentation' % PROJECT_NAME,
+ AUTHOR_NAME, 'manual'),
]
-# The name of an image file (relative to this directory) to place at the top of
-# the title page.
-#latex_logo = None
-
-# For "manual" documents, if this is true, then toplevel headings are parts,
-# not chapters.
-#latex_use_parts = False
-
-# If true, show page references after internal links.
-#latex_show_pagerefs = False
-
-# If true, show URL addresses after external links.
-#latex_show_urls = False
-
-# Additional stuff for the LaTeX preamble.
-#latex_preamble = ''
-
-# Documents to append as an appendix to all manuals.
-#latex_appendices = []
-
-# If false, no module index is generated.
-#latex_domain_indices = True
-
-
# -- Options for manual page output --------------------------------------------
# One entry per manual page. List of tuples
@@ -234,34 +106,3 @@
epub_author = AUTHOR_NAME
epub_publisher = AUTHOR_NAME
epub_copyright = COPYRIGHT
-
-# The language of the text. It defaults to the language option
-# or en if the language is not set.
-#epub_language = ''
-
-# The scheme of the identifier. Typical schemes are ISBN or URL.
-#epub_scheme = ''
-
-# The unique identifier of the text. This can be a ISBN number
-# or the project homepage.
-#epub_identifier = ''
-
-# A unique identification for the text.
-#epub_uid = ''
-
-# HTML files that should be inserted before the pages created by sphinx.
-# The format is a list of tuples containing the path and title.
-#epub_pre_files = []
-
-# HTML files shat should be inserted after the pages created by sphinx.
-# The format is a list of tuples containing the path and title.
-#epub_post_files = []
-
-# A list of files that should not be packed into the epub file.
-#epub_exclude_files = []
-
-# The depth of the table of contents in toc.ncx.
-#epub_tocdepth = 3
-
-# Allow duplicate toc entries.
-#epub_tocdup = True
diff --git a/docs/source/examples/logger.py b/docs/source/examples/logger.py
index 3337e93..577ab01 100644
--- a/docs/source/examples/logger.py
+++ b/docs/source/examples/logger.py
@@ -17,4 +17,3 @@
except KeyboardInterrupt:
observer.stop()
observer.join()
-
diff --git a/docs/source/examples/patterns.py b/docs/source/examples/patterns.py
index b8c271a..bb750b5 100644
--- a/docs/source/examples/patterns.py
+++ b/docs/source/examples/patterns.py
@@ -10,13 +10,15 @@
import logging
logging.basicConfig(level=logging.DEBUG)
+
class MyEventHandler(PatternMatchingEventHandler):
def on_any_event(self, event):
logging.debug(event)
+
event_handler = MyEventHandler(patterns=['*.py', '*.pyc'],
- ignore_patterns=['version.py'],
- ignore_directories=True)
+ ignore_patterns=['version.py'],
+ ignore_directories=True)
observer = Observer()
observer.schedule(event_handler, sys.argv[1], recursive=True)
observer.start()
@@ -26,4 +28,3 @@
except KeyboardInterrupt:
observer.stop()
observer.join()
-
diff --git a/docs/source/examples/simple.py b/docs/source/examples/simple.py
index eb46959..fe60e19 100644
--- a/docs/source/examples/simple.py
+++ b/docs/source/examples/simple.py
@@ -10,6 +10,7 @@
logging.basicConfig(level=logging.DEBUG)
+
class MyEventHandler(FileSystemEventHandler):
def catch_all_handler(self, event):
logging.debug(event)
@@ -26,6 +27,7 @@
def on_modified(self, event):
self.catch_all_handler(event)
+
path = sys.argv[1]
event_handler = MyEventHandler()
diff --git a/setup.cfg b/setup.cfg
index 669bb6a..e3cfc2f 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -3,6 +3,14 @@
build-dir = docs/build
all_files = 1
+[flake8]
+ignore =
+ # E203 whitespace before ':', but E203 is not PEP 8 compliant
+ E203
+ # W503 line break before binary operator, but W503 is not PEP 8 compliant
+ W503
+max-line-length = 120
+
[upload_sphinx]
# Requires sphinx-pypi-upload to work.
upload-dir = docs/build/html
diff --git a/setup.py b/setup.py
index 81a746c..59f54f3 100644
--- a/setup.py
+++ b/setup.py
@@ -124,6 +124,7 @@
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
+ 'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: Implementation :: PyPy',
'Programming Language :: C',
'Topic :: Software Development :: Libraries',
diff --git a/src/watchdog/observers/__init__.py b/src/watchdog/observers/__init__.py
index b03ff68..7ba6d3d 100644
--- a/src/watchdog/observers/__init__.py
+++ b/src/watchdog/observers/__init__.py
@@ -28,7 +28,7 @@
:members:
:show-inheritance:
:inherited-members:
-
+
Observer thread that schedules watching directories and dispatches
calls to event handlers.
diff --git a/src/watchdog/observers/fsevents.py b/src/watchdog/observers/fsevents.py
index 42900ec..b7e4b0e 100644
--- a/src/watchdog/observers/fsevents.py
+++ b/src/watchdog/observers/fsevents.py
@@ -80,8 +80,8 @@
def queue_events(self, timeout):
with self._lock:
- if not self.watch.is_recursive\
- and self.watch.path not in self.pathnames:
+ if (not self.watch.is_recursive
+ and self.watch.path not in self.pathnames):
return
new_snapshot = DirectorySnapshot(self.watch.path,
self.watch.is_recursive)
@@ -126,7 +126,7 @@
# INFO: FSEvents reports directory notifications recursively
# by default, so we do not need to add subdirectory paths.
- #pathnames = set([self.watch.path])
+ # pathnames = set([self.watch.path])
# if self.watch.is_recursive:
# for root, directory_names, _ in os.walk(self.watch.path):
# for directory_name in directory_names:
@@ -159,7 +159,7 @@
# Fix for issue #26: Trace/BPT error when given a unicode path
# string. https://github.com/gorakhargosh/watchdog/issues#issue/26
if isinstance(path, str_class):
- #path = unicode(path, 'utf-8')
+ # path = unicode(path, 'utf-8')
path = unicodedata.normalize('NFC', path)
# We only encode the path in Python 2 for backwards compatibility.
# On Python 3 we want the path to stay as unicode if possible for
diff --git a/src/watchdog/observers/fsevents2.py b/src/watchdog/observers/fsevents2.py
index b42b5b6..9f48d7e 100644
--- a/src/watchdog/observers/fsevents2.py
+++ b/src/watchdog/observers/fsevents2.py
@@ -157,17 +157,23 @@
@property
def _event_type(self):
- if self.is_created: return "Created"
- if self.is_removed: return "Removed"
- if self.is_renamed: return "Renamed"
- if self.is_modified: return "Modified"
- if self.is_inode_meta_mod: return "InodeMetaMod"
- if self.is_xattr_mod: return "XattrMod"
+ if self.is_created:
+ return "Created"
+ if self.is_removed:
+ return "Removed"
+ if self.is_renamed:
+ return "Renamed"
+ if self.is_modified:
+ return "Modified"
+ if self.is_inode_meta_mod:
+ return "InodeMetaMod"
+ if self.is_xattr_mod:
+ return "XattrMod"
return "Unknown"
def __repr__(self):
- s ="<%s: path=%s, type=%s, is_dir=%s, flags=%s, id=%s>"
- return s % (type(self).__name__, repr(self.path),self._event_type,
+ s = "<%s: path=%s, type=%s, is_dir=%s, flags=%s, id=%s>"
+ return s % (type(self).__name__, repr(self.path), self._event_type,
self.is_directory, hex(self.flags), self.event_id)
@@ -201,13 +207,13 @@
# don't) making it possible to pair up the two events coming
# from a singe move operation. (None of this is documented!)
# Otherwise, guess whether file was moved in or out.
- #TODO: handle id wrapping
- if (i+1 < len(events) and events[i+1].is_renamed and
- events[i+1].event_id == event.event_id + 1):
+ # TODO: handle id wrapping
+ if (i + 1 < len(events) and events[i + 1].is_renamed
+ and events[i + 1].event_id == event.event_id + 1):
cls = DirMovedEvent if event.is_directory else FileMovedEvent
- self.queue_event(cls(event.path, events[i+1].path))
+ self.queue_event(cls(event.path, events[i + 1].path))
self.queue_event(DirModifiedEvent(os.path.dirname(event.path)))
- self.queue_event(DirModifiedEvent(os.path.dirname(events[i+1].path)))
+ self.queue_event(DirModifiedEvent(os.path.dirname(events[i + 1].path)))
i += 1
elif os.path.exists(event.path):
cls = DirCreatedEvent if event.is_directory else FileCreatedEvent
@@ -217,7 +223,7 @@
cls = DirDeletedEvent if event.is_directory else FileDeletedEvent
self.queue_event(cls(event.path))
self.queue_event(DirModifiedEvent(os.path.dirname(event.path)))
- #TODO: generate events for tree
+ # TODO: generate events for tree
elif event.is_modified or event.is_inode_meta_mod or event.is_xattr_mod :
cls = DirModifiedEvent if event.is_directory else FileModifiedEvent
diff --git a/src/watchdog/observers/inotify.py b/src/watchdog/observers/inotify.py
index e26a6a6..6e56052 100644
--- a/src/watchdog/observers/inotify.py
+++ b/src/watchdog/observers/inotify.py
@@ -200,10 +200,11 @@
"""
def __init__(self, event_queue, watch, timeout=DEFAULT_EMITTER_TIMEOUT):
InotifyEmitter.__init__(self, event_queue, watch, timeout)
-
+
def queue_events(self, timeout, events=True):
InotifyEmitter.queue_events(self, timeout, full_events=events)
+
class InotifyObserver(BaseObserver):
"""
Observer thread that schedules watching directories and dispatches
@@ -215,4 +216,4 @@
BaseObserver.__init__(self, emitter_class=InotifyFullEmitter, timeout=timeout)
else:
BaseObserver.__init__(self, emitter_class=InotifyEmitter,
- timeout=timeout)
+ timeout=timeout)
diff --git a/src/watchdog/observers/inotify_buffer.py b/src/watchdog/observers/inotify_buffer.py
index a8d2ba0..de0802f 100644
--- a/src/watchdog/observers/inotify_buffer.py
+++ b/src/watchdog/observers/inotify_buffer.py
@@ -55,6 +55,7 @@
grouped = []
for inotify_event in event_list:
logger.debug("in-event %s", inotify_event)
+
def matching_from_event(event):
return (not isinstance(event, tuple) and event.is_moved_from
and event.cookie == inotify_event.cookie)
diff --git a/src/watchdog/observers/inotify_c.py b/src/watchdog/observers/inotify_c.py
index d6db4f4..c9c1b5c 100644
--- a/src/watchdog/observers/inotify_c.py
+++ b/src/watchdog/observers/inotify_c.py
@@ -320,7 +320,7 @@
if wd == -1:
continue
wd_path = self._path_for_wd[wd]
- src_path = os.path.join(wd_path, name) if name else wd_path #avoid trailing slash
+ src_path = os.path.join(wd_path, name) if name else wd_path # avoid trailing slash
inotify_event = InotifyEvent(wd, mask, cookie, name, src_path)
if inotify_event.is_moved_from:
@@ -344,8 +344,8 @@
event_list.append(inotify_event)
- if (self.is_recursive and inotify_event.is_directory and
- inotify_event.is_create):
+ if (self.is_recursive and inotify_event.is_directory
+ and inotify_event.is_create):
# TODO: When a directory from another part of the
# filesystem is moved into a watched directory, this
@@ -543,8 +543,8 @@
# It looks like the kernel does not provide this information for
# IN_DELETE_SELF and IN_MOVE_SELF. In this case, assume it's a dir.
# See also: https://github.com/seb-m/pyinotify/blob/2c7e8f8/python2/pyinotify.py#L897
- return (self.is_delete_self or self.is_move_self or
- self._mask & InotifyConstants.IN_ISDIR > 0)
+ return (self.is_delete_self or self.is_move_self
+ or self._mask & InotifyConstants.IN_ISDIR > 0)
@property
def key(self):
diff --git a/src/watchdog/observers/kqueue.py b/src/watchdog/observers/kqueue.py
index 458dbd0..490d64f 100644
--- a/src/watchdog/observers/kqueue.py
+++ b/src/watchdog/observers/kqueue.py
@@ -62,7 +62,8 @@
:members:
:show-inheritance:
-.. _Mac OS X File System Performance Guidelines: http://developer.apple.com/library/ios/#documentation/Performance/Conceptual/FileSystem/Articles/TrackingChanges.html#//apple_ref/doc/uid/20001993-CJBJFIDD
+.. _Mac OS X File System Performance Guidelines:
+ http://developer.apple.com/library/ios/#documentation/Performance/Conceptual/FileSystem/Articles/TrackingChanges.html#//apple_ref/doc/uid/20001993-CJBJFIDD
"""
@@ -114,13 +115,13 @@
WATCHDOG_KQ_FILTER = select.KQ_FILTER_VNODE
WATCHDOG_KQ_EV_FLAGS = select.KQ_EV_ADD | select.KQ_EV_ENABLE | select.KQ_EV_CLEAR
WATCHDOG_KQ_FFLAGS = (
- select.KQ_NOTE_DELETE |
- select.KQ_NOTE_WRITE |
- select.KQ_NOTE_EXTEND |
- select.KQ_NOTE_ATTRIB |
- select.KQ_NOTE_LINK |
- select.KQ_NOTE_RENAME |
- select.KQ_NOTE_REVOKE
+ select.KQ_NOTE_DELETE
+ | select.KQ_NOTE_WRITE
+ | select.KQ_NOTE_EXTEND
+ | select.KQ_NOTE_ATTRIB
+ | select.KQ_NOTE_LINK
+ | select.KQ_NOTE_RENAME
+ | select.KQ_NOTE_REVOKE
)
# Flag tests.
@@ -460,7 +461,7 @@
# and then quickly deleted before we could open
# a descriptor for it. Therefore, simply queue a sequence
# of created and deleted events for the path.
- #path = absolute_path(path)
+ # path = absolute_path(path)
# if is_directory:
# self.queue_event(DirCreatedEvent(path))
# self.queue_event(DirDeletedEvent(path))
diff --git a/src/watchdog/observers/winapi.py b/src/watchdog/observers/winapi.py
index 6eaa7f6..8a17370 100644
--- a/src/watchdog/observers/winapi.py
+++ b/src/watchdog/observers/winapi.py
@@ -223,9 +223,10 @@
_fields_ = [("NextEntryOffset", ctypes.wintypes.DWORD),
("Action", ctypes.wintypes.DWORD),
("FileNameLength", ctypes.wintypes.DWORD),
- #("FileName", (ctypes.wintypes.WCHAR * 1))]
+ # ("FileName", (ctypes.wintypes.WCHAR * 1))]
("FileName", (ctypes.c_char * 1))]
+
LPFNI = ctypes.POINTER(FILE_NOTIFY_INFORMATION)
@@ -258,7 +259,7 @@
while nBytes > 0:
fni = ctypes.cast(readBuffer, LPFNI)[0]
ptr = ctypes.addressof(fni) + FILE_NOTIFY_INFORMATION.FileName.offset
- #filename = ctypes.wstring_at(ptr, fni.FileNameLength)
+ # filename = ctypes.wstring_at(ptr, fni.FileNameLength)
filename = ctypes.string_at(ptr, fni.FileNameLength)
results.append((fni.Action, filename.decode('utf-16')))
numToSkip = fni.NextEntryOffset
diff --git a/src/watchdog/utils/bricks.py b/src/watchdog/utils/bricks.py
index 843f15c..8d68745 100644
--- a/src/watchdog/utils/bricks.py
+++ b/src/watchdog/utils/bricks.py
@@ -38,6 +38,7 @@
from .compat import queue
+
class SkipRepeatsQueue(queue.Queue):
"""Thread-safe implementation of an special queue where a
diff --git a/src/watchdog/utils/dirsnapshot.py b/src/watchdog/utils/dirsnapshot.py
index ee04438..abf0604 100644
--- a/src/watchdog/utils/dirsnapshot.py
+++ b/src/watchdog/utils/dirsnapshot.py
@@ -69,17 +69,17 @@
:type snapshot:
:class:`DirectorySnapshot`
"""
-
+
def __init__(self, ref, snapshot):
created = snapshot.paths - ref.paths
deleted = ref.paths - snapshot.paths
-
+
# check that all unchanged paths have the same inode
for path in ref.paths & snapshot.paths:
if ref.inode(path) != snapshot.inode(path):
created.add(path)
deleted.add(path)
-
+
# find moved paths
moved = set()
for path in set(deleted):
@@ -89,14 +89,14 @@
# file is not deleted but moved
deleted.remove(path)
moved.add((path, new_path))
-
+
for path in set(created):
inode = snapshot.inode(path)
old_path = ref.path(inode)
if old_path:
created.remove(path)
moved.add((old_path, path))
-
+
# find modified paths
# first check paths that have not moved
modified = set()
@@ -104,21 +104,21 @@
if ref.inode(path) == snapshot.inode(path):
if ref.mtime(path) != snapshot.mtime(path) or ref.size(path) != snapshot.size(path):
modified.add(path)
-
+
for (old_path, new_path) in moved:
if ref.mtime(old_path) != snapshot.mtime(new_path) or ref.size(old_path) != snapshot.size(new_path):
modified.add(old_path)
-
+
self._dirs_created = [path for path in created if snapshot.isdir(path)]
self._dirs_deleted = [path for path in deleted if ref.isdir(path)]
self._dirs_modified = [path for path in modified if ref.isdir(path)]
self._dirs_moved = [(frm, to) for (frm, to) in moved if ref.isdir(frm)]
-
+
self._files_created = list(created - set(self._dirs_created))
self._files_deleted = list(deleted - set(self._dirs_deleted))
self._files_modified = list(modified - set(self._dirs_modified))
self._files_moved = list(moved - set(self._dirs_moved))
-
+
@property
def files_created(self):
"""List of files that were created."""
@@ -175,6 +175,7 @@
"""
return self._dirs_created
+
class DirectorySnapshot(object):
"""
A snapshot of stat information of files in a directory.
@@ -193,20 +194,20 @@
:param stat:
Use custom stat function that returns a stat structure for path.
Currently only st_dev, st_ino, st_mode and st_mtime are needed.
-
+
A function with the signature ``walker_callback(path, stat_info)``
which will be called for every entry in the directory tree.
:param listdir:
Use custom listdir function. For details see ``os.scandir`` if available, else ``os.listdir``.
"""
-
+
def __init__(self, path, recursive=True,
walker_callback=(lambda p, s: None),
stat=default_stat,
listdir=scandir):
self._stat_info = {}
self._inode_to_path = {}
-
+
st = stat(path)
self._stat_info[path] = st
self._inode_to_path[(st.st_ino, st.st_dev)] = path
@@ -250,27 +251,27 @@
Set of file/directory paths in the snapshot.
"""
return set(self._stat_info.keys())
-
+
def path(self, id):
"""
Returns path for id. None if id is unknown to this snapshot.
"""
return self._inode_to_path.get(id)
-
+
def inode(self, path):
""" Returns an id for path. """
st = self._stat_info[path]
return (st.st_ino, st.st_dev)
-
+
def isdir(self, path):
return S_ISDIR(self._stat_info[path].st_mode)
-
+
def mtime(self, path):
return self._stat_info[path].st_mtime
def size(self, path):
return self._stat_info[path].st_size
-
+
def stat_info(self, path):
"""
Returns a stat information object for the specified path from
@@ -294,9 +295,9 @@
A :class:`DirectorySnapshotDiff` object.
"""
return DirectorySnapshotDiff(previous_dirsnap, self)
-
+
def __str__(self):
return self.__repr__()
-
+
def __repr__(self):
return str(self._stat_info)
diff --git a/src/watchdog/utils/echo.py b/src/watchdog/utils/echo.py
index 12803e0..28b6038 100644
--- a/src/watchdog/utils/echo.py
+++ b/src/watchdog/utils/echo.py
@@ -45,6 +45,7 @@
" Determine if an instancemethod is a classmethod. "
return inspect.ismethod(instancemethod) and instancemethod.__self__ is klass
+
def is_static_method(method, klass):
"""Returns True if method is an instance method of klass."""
for c in klass.mro():
@@ -53,6 +54,7 @@
else:
return False
+
def is_class_private_name(name):
" Determine if a name is a class private name. "
# Exclude system defined names such as __init__, __add__ etc
@@ -127,20 +129,22 @@
else:
setattr(klass, mname, echo(method, write))
+
def echo_class(klass, write=sys.stdout.write):
""" Echo calls to class methods and static functions
"""
for _, method in inspect.getmembers(klass, inspect.ismethod):
- #In python 3 only class methods are returned here, but in python2 instance methods are too.
+ # In python 3 only class methods are returned here, but in python2 instance methods are too.
echo_instancemethod(klass, method, write)
for _, fn in inspect.getmembers(klass, inspect.isfunction):
if is_static_method(fn, klass):
setattr(klass, name(fn), staticmethod(echo(fn, write)))
else:
- #It's not a class or a static method, so it must be an instance method.
- #This should only be called in python 3, because in python 3 instance methods are considered functions.
+ # It's not a class or a static method, so it must be an instance method.
+ # This should only be called in python 3, because in python 3 instance methods are considered functions.
echo_instancemethod(klass, fn, write)
+
def echo_module(mod, write=sys.stdout.write):
""" Echo calls to functions and methods in a module.
"""
@@ -149,6 +153,7 @@
for _, klass in inspect.getmembers(mod, inspect.isclass):
echo_class(klass, write)
+
if __name__ == "__main__":
import doctest
diff --git a/src/watchdog/utils/platform.py b/src/watchdog/utils/platform.py
index 84a3efa..55bda3e 100644
--- a/src/watchdog/utils/platform.py
+++ b/src/watchdog/utils/platform.py
@@ -38,6 +38,7 @@
else:
return PLATFORM_UNKNOWN
+
__platform__ = get_platform_name()
diff --git a/src/watchdog/utils/win32stat.py b/src/watchdog/utils/win32stat.py
index 4f6bb84..41da772 100644
--- a/src/watchdog/utils/win32stat.py
+++ b/src/watchdog/utils/win32stat.py
@@ -87,6 +87,7 @@
StatResult = namedtuple('StatResult', 'st_dev st_ino st_mode st_mtime st_size')
+
def _to_mode(attr):
m = 0
if (attr & FILE_ATTRIBUTE_DIRECTORY):
@@ -99,18 +100,22 @@
m |= 0o666
return m
+
def _to_unix_time(ft):
t = (ft.dwHighDateTime) << 32 | ft.dwLowDateTime
return (t / 10000000) - 11644473600
+
def stat(path):
hfile = CreateFile(path,
- FILE_READ_ATTRIBUTES,
- 0,
- None,
- OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
- None)
+ FILE_READ_ATTRIBUTES,
+ 0,
+ None,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL
+ | FILE_FLAG_BACKUP_SEMANTICS
+ | FILE_FLAG_OPEN_REPARSE_POINT,
+ None)
if hfile == INVALID_HANDLE_VALUE:
raise ctypes.WinError()
info = BY_HANDLE_FILE_INFORMATION()
diff --git a/src/watchdog/watchmedo.py b/src/watchdog/watchmedo.py
index 4f76914..da893d9 100755
--- a/src/watchdog/watchmedo.py
+++ b/src/watchdog/watchmedo.py
@@ -343,8 +343,8 @@
elif args.debug_force_fsevents:
from watchdog.observers.fsevents import FSEventsObserver as Observer
else:
- # Automatically picks the most appropriate observer for the platform
- # on which it is running.
+ # Automatically picks the most appropriate observer for the platform
+ # on which it is running.
from watchdog.observers import Observer
observer = Observer(timeout=args.timeout)
observe_with(observer, handler, args.directories, args.recursive)
@@ -412,7 +412,7 @@
dest='drop_during_process',
action='store_true',
default=False,
- help="Ignore events that occur while command is still being executed " \
+ help="Ignore events that occur while command is still being executed "
"to avoid multiple simultaneous instances")
@arg('--debug-force-polling',
default=False,
diff --git a/tests/test_delayed_queue.py b/tests/test_delayed_queue.py
index 387e170..a62b3bd 100644
--- a/tests/test_delayed_queue.py
+++ b/tests/test_delayed_queue.py
@@ -27,6 +27,7 @@
# 2.10 instead of 2.05 for slow macOS slaves on Travis
assert 2.10 > elapsed > 1.99
+
def test_nondelayed_get():
q = DelayedQueue(2)
q.put("", False)
diff --git a/tests/test_fsevents.py b/tests/test_fsevents.py
index fd044c2..27fa6dd 100644
--- a/tests/test_fsevents.py
+++ b/tests/test_fsevents.py
@@ -3,7 +3,7 @@
import pytest
from watchdog.utils import platform
-if not platform.is_darwin():
+if not platform.is_darwin(): # noqa
pytest.skip("macOS only.", allow_module_level=True)
import logging
diff --git a/tests/test_inotify_buffer.py b/tests/test_inotify_buffer.py
index 0c69f38..24d467e 100644
--- a/tests/test_inotify_buffer.py
+++ b/tests/test_inotify_buffer.py
@@ -19,8 +19,8 @@
import pytest
from watchdog.utils import platform
-if not platform.is_linux():
- pytest.skip("GNU/Linux only.", allow_module_level=True)
+if not platform.is_linux(): # noqa
+ pytest.skip("GNU/Linux only.", allow_module_level=True) # noqa
import os
import random
diff --git a/tests/test_inotify_c.py b/tests/test_inotify_c.py
index 912195a..3de1853 100644
--- a/tests/test_inotify_c.py
+++ b/tests/test_inotify_c.py
@@ -3,7 +3,7 @@
import pytest
from watchdog.utils import platform
-if not platform.is_linux():
+if not platform.is_linux(): # noqa
pytest.skip("GNU/Linux only.", allow_module_level=True)
import contextlib
@@ -54,27 +54,27 @@
def test_late_double_deletion(monkeypatch):
- inotify_fd = type(str("FD"), (object,), {})() # Empty object
+ inotify_fd = type(str("FD"), (object,), {})() # Empty object
inotify_fd.last = 0
inotify_fd.wds = []
# CREATE DELETE CREATE DELETE DELETE_SELF IGNORE DELETE_SELF IGNORE
inotify_fd.buf = (
- # IN_CREATE|IS_DIR (wd = 1, path = subdir1)
- b"\x01\x00\x00\x00\x00\x01\x00\x40\x00\x00\x00\x00\x10\x00\x00\x00"
- b"\x73\x75\x62\x64\x69\x72\x31\x00\x00\x00\x00\x00\x00\x00\x00\x00"
- # IN_DELETE|IS_DIR (wd = 1, path = subdir1)
- b"\x01\x00\x00\x00\x00\x02\x00\x40\x00\x00\x00\x00\x10\x00\x00\x00"
- b"\x73\x75\x62\x64\x69\x72\x31\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ # IN_CREATE|IS_DIR (wd = 1, path = subdir1)
+ b"\x01\x00\x00\x00\x00\x01\x00\x40\x00\x00\x00\x00\x10\x00\x00\x00"
+ b"\x73\x75\x62\x64\x69\x72\x31\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ # IN_DELETE|IS_DIR (wd = 1, path = subdir1)
+ b"\x01\x00\x00\x00\x00\x02\x00\x40\x00\x00\x00\x00\x10\x00\x00\x00"
+ b"\x73\x75\x62\x64\x69\x72\x31\x00\x00\x00\x00\x00\x00\x00\x00\x00"
) * 2 + (
- # IN_DELETE_SELF (wd = 2)
- b"\x02\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
- # IN_IGNORE (wd = 2)
- b"\x02\x00\x00\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
- # IN_DELETE_SELF (wd = 3)
- b"\x03\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
- # IN_IGNORE (wd = 3)
- b"\x03\x00\x00\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ # IN_DELETE_SELF (wd = 2)
+ b"\x02\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ # IN_IGNORE (wd = 2)
+ b"\x02\x00\x00\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ # IN_DELETE_SELF (wd = 3)
+ b"\x03\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ # IN_IGNORE (wd = 3)
+ b"\x03\x00\x00\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
)
os_read_bkp = os.read
diff --git a/tests/test_observer.py b/tests/test_observer.py
index f40570d..4d3e967 100644
--- a/tests/test_observer.py
+++ b/tests/test_observer.py
@@ -32,6 +32,7 @@
except RuntimeError:
pass
+
@pytest.fixture
def observer2():
obs = BaseObserver(EventEmitter)
diff --git a/tests/test_observers_winapi.py b/tests/test_observers_winapi.py
index a08e10d..5bc4977 100644
--- a/tests/test_observers_winapi.py
+++ b/tests/test_observers_winapi.py
@@ -19,7 +19,7 @@
import pytest
from watchdog.utils import platform
-if not platform.is_windows():
+if not platform.is_windows(): # noqa
pytest.skip("Windows only.", allow_module_level=True)
import os.path
diff --git a/tests/test_snapshot_diff.py b/tests/test_snapshot_diff.py
index 00e08f8..1f8dbe5 100644
--- a/tests/test_snapshot_diff.py
+++ b/tests/test_snapshot_diff.py
@@ -78,6 +78,7 @@
assert diff.files_deleted == [p('dir2', 'b')]
assert diff.files_created == []
+
def test_dir_modify_on_create(p):
ref = DirectorySnapshot(p(''))
wait()
diff --git a/tests/test_watchmedo.py b/tests/test_watchmedo.py
index a4ecd7d..e865ea8 100644
--- a/tests/test_watchmedo.py
+++ b/tests/test_watchmedo.py
@@ -2,10 +2,11 @@
from __future__ import unicode_literals
import pytest
+
# Skip if import PyYAML failed. PyYAML missing possible because
-# watchdog installed without watchmedo. See Installation section
+# watchdog installed without watchmedo. See Installation section
# in README.rst
-yaml = pytest.importorskip('yaml')
+yaml = pytest.importorskip('yaml') # noqa
import os
diff --git a/tools/dump_fsevents_constants.py b/tools/dump_fsevents_constants.py
index 3d27459..a8c4ebf 100755
--- a/tools/dump_fsevents_constants.py
+++ b/tools/dump_fsevents_constants.py
@@ -39,6 +39,7 @@
with open(filename, 'wb') as f:
f.write(content)
+
if __name__ == "__main__":
if len(sys.argv) > 1:
output_file = sys.argv[1]
diff --git a/tox.ini b/tox.ini
index 5c85d45..4abe32d 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,10 +1,13 @@
[tox]
-envlist = py{37,36,35,27,py3,py}
+envlist = py{38,37,36,35,27,py3,py}
+skip_missing_interpreters = True
[testenv]
deps =
- py{37,36,35,27,py3,py}: pytest-cov
- py{37,36,35,27,py3,py}: pytest-timeout
+ flake8
+ pytest-cov
+ pytest-timeout
extras = watchmedo
commands =
+ python -m flake8 docs tools src tests
python -bb -m pytest {posargs}