Skip to content

Commit

Permalink
Merge pull request #48 from malthe/modernize-repo
Browse files Browse the repository at this point in the history
Modernize repo
  • Loading branch information
malthe authored Apr 19, 2024
2 parents 027079b + cd11299 commit 90721d7
Show file tree
Hide file tree
Showing 8 changed files with 417 additions and 179 deletions.
57 changes: 57 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
on:
push:
pull_request:
# Allow to run this workflow manually from the Actions tab
workflow_dispatch:

jobs:
build:
runs-on: macos-latest
steps:
- uses: actions/checkout@v3
- run: python -m pip install setuptools wheel
- run: python setup.py sdist
- run: python setup.py bdist_wheel
- uses: actions/upload-artifact@v4
with:
name: MacFSEvents
path: ./dist/
test:
strategy:
# We want to see all failures:
fail-fast: false
matrix:
config:
- ["3.8", "py38", "macos-12"]
- ["3.9", "py38", "macos-12"]
- ["3.9", "lint", "macos-12"]
- ["3.9", "py39", "macos-12"]
- ["3.10", "py310", "macos-12"]
- ["3.11", "py311", "macos-12"]
- ["3.12", "py312", "macos-12"]
- ["3.12", "py312", "macos-13"]
- ["3.12", "py312", "macos-14"]
runs-on: ${{ matrix.config[2] }}
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name
name: ${{ matrix.config[0] }}-${{ matrix.config[1] }}-${{ matrix.config[2] }}
steps:
- run: git config --global core.autocrlf false
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.config[0] }}
- name: Pip cache
uses: actions/cache@v3
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ matrix.config[0] }}-${{ hashFiles('setup.*', 'tox.ini') }}
restore-keys: |
${{ runner.os }}-pip-${{ matrix.config[0] }}-
${{ runner.os }}-pip-
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install tox
- name: Test
run: tox -e ${{ matrix.config[1] }}
18 changes: 0 additions & 18 deletions .travis.yml

This file was deleted.

2 changes: 2 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
include *.py
include tox.ini
175 changes: 106 additions & 69 deletions fsevents.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,66 +4,57 @@
import unicodedata

from _fsevents import (
loop,
stop,
schedule,
unschedule,
CF_POLLIN,
CF_POLLOUT,
FS_IGNORESELF,
FS_FILEEVENTS,
FS_ITEMCREATED,
FS_ITEMREMOVED,
FS_ITEMINODEMETAMOD,
FS_ITEMRENAMED,
FS_ITEMMODIFIED,
FS_ITEMFINDERINFOMOD,
FS_ITEMCHANGEOWNER,
FS_ITEMXATTRMOD,
FS_ITEMISFILE,
FS_ITEMISDIR,
FS_ITEMISSYMLINK,
FS_CFLAGFILEEVENTS,
FS_CFLAGNONE,
FS_EVENTIDSINCENOW,
FS_FLAGEVENTIDSWRAPPED,
FS_FLAGNONE,
FS_FLAGHISTORYDONE,
FS_FLAGROOTCHANGED,
FS_FLAGKERNELDROPPED,
FS_FLAGUNMOUNT,
FS_FLAGMOUNT,
FS_FLAGUSERDROPPED,
FS_FLAGMUSTSCANSUBDIRS,
FS_CFLAGFILEEVENTS,
FS_CFLAGNONE,
FS_CFLAGIGNORESELF,
FS_CFLAGUSECFTYPES,
FS_CFLAGNODEFER,
FS_CFLAGWATCHROOT,
FS_FLAGROOTCHANGED,
FS_FLAGUNMOUNT,
FS_FLAGUSERDROPPED,
FS_ITEMCHANGEOWNER,
FS_ITEMCREATED,
FS_ITEMFINDERINFOMOD,
FS_ITEMINODEMETAMOD,
FS_ITEMISDIR,
FS_ITEMISFILE,
FS_ITEMISSYMLINK,
FS_ITEMMODIFIED,
FS_ITEMREMOVED,
FS_ITEMRENAMED,
FS_ITEMXATTRMOD,
loop,
schedule,
stop,
unschedule
)


class Mask(int):
stringmap = {
FS_FLAGMUSTSCANSUBDIRS: 'MustScanSubDirs',
FS_FLAGUSERDROPPED: 'UserDropped',
FS_FLAGKERNELDROPPED: 'KernelDropped',
FS_FLAGEVENTIDSWRAPPED: 'EventIDsWrapped',
FS_FLAGHISTORYDONE: 'HistoryDone',
FS_FLAGROOTCHANGED: 'RootChanged',
FS_FLAGMOUNT: 'Mount',
FS_FLAGUNMOUNT: 'Unmount',

FS_FLAGMUSTSCANSUBDIRS: "MustScanSubDirs",
FS_FLAGUSERDROPPED: "UserDropped",
FS_FLAGKERNELDROPPED: "KernelDropped",
FS_FLAGEVENTIDSWRAPPED: "EventIDsWrapped",
FS_FLAGHISTORYDONE: "HistoryDone",
FS_FLAGROOTCHANGED: "RootChanged",
FS_FLAGMOUNT: "Mount",
FS_FLAGUNMOUNT: "Unmount",
# Flags when creating the stream.
FS_ITEMCREATED: 'ItemCreated',
FS_ITEMREMOVED: 'ItemRemoved',
FS_ITEMINODEMETAMOD: 'ItemInodeMetaMod',
FS_ITEMRENAMED: 'ItemRenamed',
FS_ITEMMODIFIED: 'ItemModified',
FS_ITEMFINDERINFOMOD: 'ItemFinderInfoMod',
FS_ITEMCHANGEOWNER: 'ItemChangedOwner',
FS_ITEMXATTRMOD: 'ItemXAttrMod',
FS_ITEMISFILE: 'ItemIsFile',
FS_ITEMISDIR: 'ItemIsDir',
FS_ITEMISSYMLINK: 'ItemIsSymlink'
FS_ITEMCREATED: "ItemCreated",
FS_ITEMREMOVED: "ItemRemoved",
FS_ITEMINODEMETAMOD: "ItemInodeMetaMod",
FS_ITEMRENAMED: "ItemRenamed",
FS_ITEMMODIFIED: "ItemModified",
FS_ITEMFINDERINFOMOD: "ItemFinderInfoMod",
FS_ITEMCHANGEOWNER: "ItemChangedOwner",
FS_ITEMXATTRMOD: "ItemXAttrMod",
FS_ITEMISFILE: "ItemIsFile",
FS_ITEMISDIR: "ItemIsDir",
FS_ITEMISSYMLINK: "ItemIsSymlink",
}

_svals = list(stringmap.items())
Expand Down Expand Up @@ -96,7 +87,8 @@ def check_path_string_type(*paths):
for path in paths:
if not isinstance(path, str):
raise TypeError(
"Path must be string, not '%s'." % type(path).__name__)
"Path must be string, not '%s'." % type(path).__name__
)


class Observer(threading.Thread):
Expand Down Expand Up @@ -138,16 +130,25 @@ def _schedule(self, stream):
if stream.file_events:
callback = FileEventCallback(stream.callback, stream.raw_paths)
else:

def callback(paths, masks, ids):
for path, mask, id in zip(paths, masks, ids):
if sys.version_info[0] >= 3:
path = path.decode('utf-8')
path = path.decode("utf-8")
if stream.ids is False:
stream.callback(path, mask)
elif stream.ids is True:
stream.callback(path, mask, id)

schedule(self, stream, callback, stream.paths, stream.since, stream.latency, stream.cflags)

schedule(
self,
stream,
callback,
stream.paths,
stream.since,
stream.latency,
stream.cflags,
)

def schedule(self, stream):
self.lock.acquire()
Expand Down Expand Up @@ -181,23 +182,26 @@ def stop(self):
self.event = None
event.set()


class Stream(object):
def __init__(self, callback, *paths, **options):
file_events = options.pop('file_events', False)
since = options.pop('since',FS_EVENTIDSINCENOW)
cflags = options.pop('flags', FS_CFLAGNONE)
latency = options.pop('latency', 0.01)
ids = options.pop('ids', False)
assert len(options) == 0, "Invalid option(s): %s" % repr(options.keys())
file_events = options.pop("file_events", False)
since = options.pop("since", FS_EVENTIDSINCENOW)
cflags = options.pop("flags", FS_CFLAGNONE)
latency = options.pop("latency", 0.01)
ids = options.pop("ids", False)
assert len(options) == 0, "Invalid option(s): %s" % repr(
options.keys()
)
check_path_string_type(*paths)

self.callback = callback
self.raw_paths = paths

# The C-extension needs the path in 8-bit form.
self.paths = [
path if isinstance(path, bytes)
else path.encode('utf-8') for path in paths
path if isinstance(path, bytes) else path.encode("utf-8")
for path in paths
]

self.file_events = file_events
Expand All @@ -206,8 +210,9 @@ def __init__(self, callback, *paths, **options):
self.latency = latency
self.ids = ids


class FileEvent(object):
__slots__ = 'mask', 'cookie', 'name'
__slots__ = "mask", "cookie", "name"

def __init__(self, mask, cookie, name):
self.mask = mask
Expand All @@ -217,6 +222,7 @@ def __init__(self, mask, cookie, name):
def __repr__(self):
return repr((self.mask, self.cookie, self.name))


class FileEventCallback(object):
def __init__(self, callback, paths):
self.snapshots = {}
Expand All @@ -234,13 +240,13 @@ def __call__(self, paths, masks, ids):
for path in sorted(paths):
# supports UTF-8-MAC(NFD)
if not isinstance(path, unicode):
path = path.decode('utf-8')
path = unicodedata.normalize('NFD', path).encode('utf-8')
path = path.decode("utf-8")
path = unicodedata.normalize("NFD", path).encode("utf-8")

if sys.version_info[0] >= 3:
path = path.decode('utf-8')
path = path.rstrip('/')
path = path.decode("utf-8")

path = path.rstrip("/")
snapshot = self.snapshots[path]
current = {}
try:
Expand All @@ -265,13 +271,15 @@ def __call__(self, paths, masks, ids):
observed.discard(name)
else:
event = created.get(snap_stat.st_ino)
if (event is not None):
if event is not None:
self.cookie += 1
event.mask = IN_MOVED_FROM
event.cookie = self.cookie
tmp_filename = event.name
event.name = filename
events.append(FileEvent(IN_MOVED_TO, self.cookie, tmp_filename))
events.append(
FileEvent(IN_MOVED_TO, self.cookie, tmp_filename)
)
else:
event = FileEvent(IN_DELETE, None, filename)
deleted[snap_stat.st_ino] = event
Expand Down Expand Up @@ -313,3 +321,32 @@ def snapshot(self, path):
entry[obj] = os.lstat(os.path.join(root, obj))
except OSError:
continue


__all__ = (
FS_CFLAGFILEEVENTS,
FS_CFLAGNONE,
FS_EVENTIDSINCENOW,
FS_FLAGEVENTIDSWRAPPED,
FS_FLAGHISTORYDONE,
FS_FLAGKERNELDROPPED,
FS_FLAGMOUNT,
FS_FLAGMUSTSCANSUBDIRS,
FS_FLAGROOTCHANGED,
FS_FLAGUNMOUNT,
FS_FLAGUSERDROPPED,
FS_ITEMCHANGEOWNER,
FS_ITEMCREATED,
FS_ITEMFINDERINFOMOD,
FS_ITEMINODEMETAMOD,
FS_ITEMISDIR,
FS_ITEMISFILE,
FS_ITEMISSYMLINK,
FS_ITEMMODIFIED,
FS_ITEMREMOVED,
FS_ITEMRENAMED,
FS_ITEMXATTRMOD,
FileEvent,
Stream,
Observer,
)
5 changes: 5 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[tool.black]
line-length = 79

[tool.isort]
multi_line_output=3
Loading

0 comments on commit 90721d7

Please sign in to comment.