Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,18 @@ jobs:
- name: Build
run: uv sync --locked

- name: Lint (ruff)
run: uv run ruff check

- name: Lint (format)
run: uv run ruff format --diff

- name: Type check (mypy)
run: uv run mypy .

- name: Type check (pyright)
run: uv run pyright

- name: Run tests
run: uv run pytest -v -rs test/

Expand Down
13 changes: 9 additions & 4 deletions developer-notes/FUSEError Performance.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,10 @@
" except FUSEErrorExt as exc:\n",
" a += exc.errno\n",
" except:\n",
" print('This should not happen')\n",
" print(\"This should not happen\")\n",
" return a\n",
"\n",
"\n",
"def test_int():\n",
" a = 0\n",
" for i in range(100):\n",
Expand All @@ -101,7 +102,7 @@
" except FUSEErrorInt as exc:\n",
" a += exc.errno\n",
" except:\n",
" print('This should not happen')\n",
" print(\"This should not happen\")\n",
" return a"
]
},
Expand Down Expand Up @@ -151,13 +152,16 @@
"outputs": [],
"source": [
"cache = dict()\n",
"\n",
"\n",
"def getError(errno):\n",
" try:\n",
" return cache[errno]\n",
" except KeyError:\n",
" cache[errno] = FUSEErrorExt(errno)\n",
" return cache[errno]\n",
" \n",
"\n",
"\n",
"def test_ext_cached():\n",
" a = 0\n",
" for i in range(100):\n",
Expand All @@ -166,7 +170,7 @@
" except FUSEErrorExt as exc:\n",
" a += exc.errno\n",
" except:\n",
" print('This should not happen')\n",
" print(\"This should not happen\")\n",
" return a"
]
},
Expand Down Expand Up @@ -210,6 +214,7 @@
"def handler(i):\n",
" return getError(i)\n",
"\n",
"\n",
"def test_ext_direct():\n",
" a = 0\n",
" for i in range(100):\n",
Expand Down
3 changes: 2 additions & 1 deletion developer-notes/Namedtuple.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@
"outputs": [],
"source": [
"from collections import namedtuple\n",
"InvalRequestTup = namedtuple('InvalRequestTup', [ 'inode', 'attr_only' ])"
"\n",
"InvalRequestTup = namedtuple(\"InvalRequestTup\", [\"inode\", \"attr_only\"])"
]
},
{
Expand Down
58 changes: 30 additions & 28 deletions examples/hello.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,22 +22,17 @@
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
'''

import errno
import logging
import os
import sys
import stat
from argparse import ArgumentParser
from typing import cast

# If we are running from the pyfuse3 source directory, try
# to load the module from there first.
basedir = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), '..'))
if (os.path.exists(os.path.join(basedir, 'setup.py')) and
os.path.exists(os.path.join(basedir, 'src', 'pyfuse3', '__init__.pyx'))):
sys.path.insert(0, os.path.join(basedir, 'src'))
import trio

from argparse import ArgumentParser
import stat
import logging
import errno
import pyfuse3
Copy link

Copilot AI Jan 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Module 'pyfuse3' is imported with both 'import' and 'import from'.

Copilot uses AI. Check for mistakes.
import trio
from pyfuse3 import FileHandleT, FileInfo, InodeT

try:
import faulthandler
Expand All @@ -48,20 +43,21 @@

log = logging.getLogger(__name__)


class TestFs(pyfuse3.Operations):
def __init__(self):
super(TestFs, self).__init__()
self.hello_name = b"message"
self.hello_inode = pyfuse3.ROOT_INODE+1
self.hello_inode = cast(InodeT, pyfuse3.ROOT_INODE + 1)
self.hello_data = b"hello world\n"

async def getattr(self, inode, ctx=None):
entry = pyfuse3.EntryAttributes()
if inode == pyfuse3.ROOT_INODE:
entry.st_mode = (stat.S_IFDIR | 0o755)
entry.st_mode = stat.S_IFDIR | 0o755
entry.st_size = 0
elif inode == self.hello_inode:
entry.st_mode = (stat.S_IFREG | 0o644)
entry.st_mode = stat.S_IFREG | 0o644
entry.st_size = len(self.hello_data)
else:
raise pyfuse3.FUSEError(errno.ENOENT)
Expand All @@ -84,31 +80,35 @@ async def lookup(self, parent_inode, name, ctx=None):
async def opendir(self, inode, ctx):
if inode != pyfuse3.ROOT_INODE:
raise pyfuse3.FUSEError(errno.ENOENT)
return inode
# For simplicity, we use the inode as file handle
return FileHandleT(inode)

async def readdir(self, fh, start_id, token):
assert fh == pyfuse3.ROOT_INODE

# only one entry
if start_id == 0:
pyfuse3.readdir_reply(
token, self.hello_name, await self.getattr(self.hello_inode), 1)
pyfuse3.readdir_reply(token, self.hello_name, await self.getattr(self.hello_inode), 1)
return

async def open(self, inode, flags, ctx):
if inode != self.hello_inode:
raise pyfuse3.FUSEError(errno.ENOENT)
if flags & os.O_RDWR or flags & os.O_WRONLY:
raise pyfuse3.FUSEError(errno.EACCES)
return pyfuse3.FileInfo(fh=inode)
# For simplicity, we use the inode as file handle
return FileInfo(fh=FileHandleT(inode))

async def read(self, fh, off, size):
assert fh == self.hello_inode
return self.hello_data[off:off+size]
return self.hello_data[off : off + size]


def init_logging(debug=False):
formatter = logging.Formatter('%(asctime)s.%(msecs)03d %(threadName)s: '
'[%(name)s] %(message)s', datefmt="%Y-%m-%d %H:%M:%S")
formatter = logging.Formatter(
'%(asctime)s.%(msecs)03d %(threadName)s: [%(name)s] %(message)s',
datefmt="%Y-%m-%d %H:%M:%S",
)
handler = logging.StreamHandler()
handler.setFormatter(formatter)
root_logger = logging.getLogger()
Expand All @@ -120,17 +120,19 @@ def init_logging(debug=False):
root_logger.setLevel(logging.INFO)
root_logger.addHandler(handler)


def parse_args():
'''Parse command line'''

parser = ArgumentParser()

parser.add_argument('mountpoint', type=str,
help='Where to mount the file system')
parser.add_argument('--debug', action='store_true', default=False,
help='Enable debugging output')
parser.add_argument('--debug-fuse', action='store_true', default=False,
help='Enable FUSE debugging output')
parser.add_argument('mountpoint', type=str, help='Where to mount the file system')
parser.add_argument(
'--debug', action='store_true', default=False, help='Enable debugging output'
)
parser.add_argument(
'--debug-fuse', action='store_true', default=False, help='Enable FUSE debugging output'
)
return parser.parse_args()


Expand Down
59 changes: 30 additions & 29 deletions examples/hello_asyncio.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,23 +22,17 @@
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
'''

import os
import sys

# If we are running from the pyfuse3 source directory, try
# to load the module from there first.
basedir = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), '..'))
if (os.path.exists(os.path.join(basedir, 'setup.py')) and
os.path.exists(os.path.join(basedir, 'src', 'pyfuse3', '__init__.pyx'))):
sys.path.insert(0, os.path.join(basedir, 'src'))

from argparse import ArgumentParser
import asyncio
import stat
import logging
import errno
import logging
import os
import stat
from argparse import ArgumentParser
from typing import cast

import pyfuse3
import pyfuse3.asyncio
from pyfuse3 import FileHandleT, FileInfo, InodeT

try:
import faulthandler
Expand All @@ -50,20 +44,21 @@
log = logging.getLogger(__name__)
pyfuse3.asyncio.enable()


class TestFs(pyfuse3.Operations):
def __init__(self):
super(TestFs, self).__init__()
self.hello_name = b"message"
self.hello_inode = pyfuse3.ROOT_INODE+1
self.hello_inode = cast(InodeT, pyfuse3.ROOT_INODE + 1)
self.hello_data = b"hello world\n"

async def getattr(self, inode, ctx=None):
entry = pyfuse3.EntryAttributes()
if inode == pyfuse3.ROOT_INODE:
entry.st_mode = (stat.S_IFDIR | 0o755)
entry.st_mode = stat.S_IFDIR | 0o755
entry.st_size = 0
elif inode == self.hello_inode:
entry.st_mode = (stat.S_IFREG | 0o644)
entry.st_mode = stat.S_IFREG | 0o644
entry.st_size = len(self.hello_data)
else:
raise pyfuse3.FUSEError(errno.ENOENT)
Expand All @@ -86,15 +81,15 @@ async def lookup(self, parent_inode, name, ctx=None):
async def opendir(self, inode, ctx):
if inode != pyfuse3.ROOT_INODE:
raise pyfuse3.FUSEError(errno.ENOENT)
return inode
# For simplicity, we use the inode as file handle
return FileHandleT(inode)

async def readdir(self, fh, start_id, token):
assert fh == pyfuse3.ROOT_INODE

# only one entry
if start_id == 0:
pyfuse3.readdir_reply(
token, self.hello_name, await self.getattr(self.hello_inode), 1)
pyfuse3.readdir_reply(token, self.hello_name, await self.getattr(self.hello_inode), 1)
return

async def setxattr(self, inode, name, value, ctx):
Expand All @@ -111,15 +106,19 @@ async def open(self, inode, flags, ctx):
raise pyfuse3.FUSEError(errno.ENOENT)
if flags & os.O_RDWR or flags & os.O_WRONLY:
raise pyfuse3.FUSEError(errno.EACCES)
return pyfuse3.FileInfo(fh=inode)
# For simplicity, we use the inode as file handle
return FileInfo(fh=FileHandleT(inode))

async def read(self, fh, off, size):
assert fh == self.hello_inode
return self.hello_data[off:off+size]
return self.hello_data[off : off + size]


def init_logging(debug=False):
formatter = logging.Formatter('%(asctime)s.%(msecs)03d %(threadName)s: '
'[%(name)s] %(message)s', datefmt="%Y-%m-%d %H:%M:%S")
formatter = logging.Formatter(
'%(asctime)s.%(msecs)03d %(threadName)s: [%(name)s] %(message)s',
datefmt="%Y-%m-%d %H:%M:%S",
)
handler = logging.StreamHandler()
handler.setFormatter(formatter)
root_logger = logging.getLogger()
Expand All @@ -131,17 +130,19 @@ def init_logging(debug=False):
root_logger.setLevel(logging.INFO)
root_logger.addHandler(handler)


def parse_args():
'''Parse command line'''

parser = ArgumentParser()

parser.add_argument('mountpoint', type=str,
help='Where to mount the file system')
parser.add_argument('--debug', action='store_true', default=False,
help='Enable debugging output')
parser.add_argument('--debug-fuse', action='store_true', default=False,
help='Enable FUSE debugging output')
parser.add_argument('mountpoint', type=str, help='Where to mount the file system')
parser.add_argument(
'--debug', action='store_true', default=False, help='Enable debugging output'
)
parser.add_argument(
'--debug-fuse', action='store_true', default=False, help='Enable FUSE debugging output'
)
return parser.parse_args()


Expand Down
Loading