Skip to content

migrate from fuse-python to pyfuse3#4

Draft
obbardc wants to merge 4 commits intobrgl:mainfrom
obbardc:wip/obbardc/migrate-to-fusepy
Draft

migrate from fuse-python to pyfuse3#4
obbardc wants to merge 4 commits intobrgl:mainfrom
obbardc:wip/obbardc/migrate-to-fusepy

Conversation

@obbardc
Copy link
Copy Markdown

@obbardc obbardc commented Apr 12, 2026

fuse-python depends on libfuse2 which is being phased out from most
distros because FUSE 3 has been the stable upstream for nearly a decade
and distros don't want to ship two major versions of the same library
indefinitely. Because of this fuse-python is no longer packaged in
Debian.

Replace the usage of fuse-python with pyfuse3 which uses an inode-based
async API backed by trio.

Link: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1125204

@obbardc
Copy link
Copy Markdown
Author

obbardc commented Apr 12, 2026

Draft as untested and possibly a lot of nonsense... :-)

@obbardc
Copy link
Copy Markdown
Author

obbardc commented Apr 12, 2026

Actually, fusepy has been removed from debian too. Not sure what to do to get it into debian now :-).

@obbardc
Copy link
Copy Markdown
Author

obbardc commented Apr 12, 2026

closing in favour of #5

@obbardc obbardc closed this Apr 12, 2026
@obbardc obbardc reopened this Apr 20, 2026
@obbardc obbardc force-pushed the wip/obbardc/migrate-to-fusepy branch from 3523fb4 to 9e986c3 Compare April 20, 2026 21:23
@obbardc obbardc changed the title Migrate from python3-fuse to python3-fusepy migrate from fuse-python to pyfuse3 Apr 20, 2026
@obbardc
Copy link
Copy Markdown
Author

obbardc commented Apr 20, 2026

@brgl I have an initial implementation, can you review and test ? It may be a lot of nonsense too ;-)

@brgl
Copy link
Copy Markdown
Owner

brgl commented Apr 21, 2026

How did you test it? The following command-line ExecStart=/usr/bin/gpiod-sysfs-proxy /sys/class/gpio -f -o nonempty -o allow_other -o default_permissions -o entry_timeout=0 -o attr_timeout=0 is givine me: gpiod-sysfs-proxy: error: unrecognized arguments: -f. I suppose the command-line arguments in fuse3 changed?

@obbardc
Copy link
Copy Markdown
Author

obbardc commented Apr 21, 2026

How did you test it?

I didn't test it. Oops.

The following command-line ExecStart=/usr/bin/gpiod-sysfs-proxy /sys/class/gpio -f -o nonempty -o allow_other -o default_permissions -o entry_timeout=0 -o attr_timeout=0 is givine me: gpiod-sysfs-proxy: error: unrecognized arguments: -f. I suppose the command-line arguments in fuse3 changed?

Yeah, I added a commit to fix that. I guess we can squash them eventually once all the problems are ironed out.

obbardc added 2 commits April 21, 2026 12:53
fuse-python depends on libfuse2 which is being phased out from most
distros because FUSE 3 has been the stable upstream for nearly a decade
and distros don't want to ship two major versions of the same library
indefinitely. Because of this fuse-python is no longer packaged in
Debian.

Replace the usage of fuse-python with pyfuse3 which uses an inode-based
async API backed by trio.

Fixes: brgl#5
Signed-off-by: Christopher Obbard <christopher.obbard@linaro.org>
- Accept and ignore -f/--foreground: pyfuse3 always runs in the
  foreground since the event loop is managed by the caller via trio
- Silently drop 'nonempty': FUSE 3 removed this option; mounting over
  a non-empty directory is unconditionally allowed
- Intercept entry_timeout=N and attr_timeout=N: these are no longer
  FUSE mount options in FUSE 3; they are per-entry fields in
  EntryAttributes, so parse them into globals used at entry creation
  time instead of forwarding them to pyfuse3.init()

This makes the existing systemd ExecStart line work unchanged:
  gpiod-sysfs-proxy /sys/class/gpio -f -o nonempty -o allow_other \
    -o default_permissions -o entry_timeout=0 -o attr_timeout=0

Signed-off-by: Christopher Obbard <christopher.obbard@linaro.org>
@obbardc obbardc force-pushed the wip/obbardc/migrate-to-fusepy branch from 71b307d to 4ecf1f9 Compare April 21, 2026 11:53
@brgl
Copy link
Copy Markdown
Owner

brgl commented Apr 21, 2026

Most tests pass, there are a couple issues:

test_chown_export_unexport (__main__.TestChangeOwner.test_chown_export_unexport) ... ok
test_cannot_remove_chip_dir (__main__.TestChipDir.test_cannot_remove_chip_dir) ... FAIL
test_chip_attributes (__main__.TestChipDir.test_chip_attributes) ... ok
test_chip_base (__main__.TestChipDir.test_chip_base) ... ok
test_chip_label (__main__.TestChipDir.test_chip_label) ... ok
test_chip_ngpio (__main__.TestChipDir.test_chip_ngpio) ... ok
test_chip_write_to_attrs (__main__.TestChipDir.test_chip_write_to_attrs) ... ok
test_cannot_create_new_file_in_class (__main__.TestClassLayout.test_cannot_create_new_file_in_class) ... ok
test_cannot_mkdir_in_class (__main__.TestClassLayout.test_cannot_mkdir_in_class) ... ok
test_cannot_remove_export_unexport (__main__.TestClassLayout.test_cannot_remove_export_unexport) ... ok
test_export_unexport_exist_and_writeable (__main__.TestClassLayout.test_export_unexport_exist_and_writeable) ... ok
test_export_unexport_mode (__main__.TestClassLayout.test_export_unexport_mode) ... ok
test_remove_chip_before_unexporting_its_gpio (__main__.TestCornerCases.test_remove_chip_before_unexporting_its_gpio) ... ok
test_chip_dir_really_disappears (__main__.TestExportUnexport.test_chip_dir_really_disappears) ... ok
test_export_unexport (__main__.TestExportUnexport.test_export_unexport) ... ok
test_export_unexport_invalid_values (__main__.TestExportUnexport.test_export_unexport_invalid_values) ... ok
test_gpio_dir_really_disappears (__main__.TestExportUnexport.test_gpio_dir_really_disappears) ... ok
test_active_low (__main__.TestGpioDir.test_active_low) ... ok
test_active_low_invalid_value (__main__.TestGpioDir.test_active_low_invalid_value) ... ok
test_cannot_remove_gpio_dir (__main__.TestGpioDir.test_cannot_remove_gpio_dir) ... FAIL
test_direction (__main__.TestGpioDir.test_direction) ... ok
test_direction_invalid_value (__main__.TestGpioDir.test_direction_invalid_value) ... ok
test_edge_good_values (__main__.TestGpioDir.test_edge_good_values) ... ok
test_edge_invalid_value (__main__.TestGpioDir.test_edge_invalid_value) ... ok
test_gpio_attributes (__main__.TestGpioDir.test_gpio_attributes) ... ok
test_gpio_get_value (__main__.TestGpioDir.test_gpio_get_value) ... ok
test_gpio_set_value (__main__.TestGpioDir.test_gpio_set_value) ... ok
test_gpio_set_value_input_fails (__main__.TestGpioDir.test_gpio_set_value_input_fails) ... FAIL
test_gpio_set_value_invalid (__main__.TestGpioDir.test_gpio_set_value_invalid) ... ok
test_poll_edge_both (__main__.TestGpioDir.test_poll_edge_both) ... ok
test_poll_edge_falling (__main__.TestGpioDir.test_poll_edge_falling) ... FAIL
test_poll_edge_none (__main__.TestGpioDir.test_poll_edge_none) ... ok
test_poll_edge_rising (__main__.TestGpioDir.test_poll_edge_rising) ... FAIL
test_chip_write_uevent_invalid_value (__main__.TestUeventAttr.test_chip_write_uevent_invalid_value) ... ok
test_chip_write_uevent_synth_uevent (__main__.TestUeventAttr.test_chip_write_uevent_synth_uevent) ... ok
test_uevent_read (__main__.TestUeventAttr.test_uevent_read) ... ok

======================================================================
FAIL: test_cannot_remove_chip_dir (__main__.TestChipDir.test_cannot_remove_chip_dir)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/lib/gpiod-sysfs-proxy/ptest/tests/./gpio-sysfs-compat-tests", line 291, in test_cannot_remove_chip_dir
    self.assertEqual(raised.exception.errno, errno.ENOTDIR)
    ~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError: 1 != 20

======================================================================
FAIL: test_cannot_remove_gpio_dir (__main__.TestGpioDir.test_cannot_remove_gpio_dir)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/lib/gpiod-sysfs-proxy/ptest/tests/./gpio-sysfs-compat-tests", line 426, in test_cannot_remove_gpio_dir
    self.assertEqual(raised.exception.errno, errno.ENOTDIR)
    ~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError: 1 != 20

======================================================================
FAIL: test_gpio_set_value_input_fails (__main__.TestGpioDir.test_gpio_set_value_input_fails)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/lib/gpiod-sysfs-proxy/ptest/tests/./gpio-sysfs-compat-tests", line 450, in test_gpio_set_value_input_fails
    self.assertEqual(raised.exception.errno, errno.EPERM)
    ~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError: 107 != 1

======================================================================
FAIL: test_poll_edge_falling (__main__.TestGpioDir.test_poll_edge_falling)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/lib/gpiod-sysfs-proxy/ptest/tests/./gpio-sysfs-compat-tests", line 547, in test_poll_edge_falling
    self.assertTrue(got_falling)
    ~~~~~~~~~~~~~~~^^^^^^^^^^^^^
AssertionError: False is not true

======================================================================
FAIL: test_poll_edge_rising (__main__.TestGpioDir.test_poll_edge_rising)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/lib/gpiod-sysfs-proxy/ptest/tests/./gpio-sysfs-compat-tests", line 541, in test_poll_edge_rising
    self.assertTrue(got_rising)
    ~~~~~~~~~~~~~~~^^^^^^^^^^^^
AssertionError: False is not true

----------------------------------------------------------------------
Ran 36 tests in 10.062s

FAILED (failures=5)

@obbardc
Copy link
Copy Markdown
Author

obbardc commented Apr 21, 2026

sidenote, how do you run these tests ? I wonder if it would be possible for us to add them into GitHub actions CI.

@brgl
Copy link
Copy Markdown
Owner

brgl commented Apr 21, 2026

With yocto ptests. Use current meta-openembedded master and the following options:

MACHINE = "qemux86-64"
DISTRO = "poky"

EXTRA_IMAGE_FEATURES = "allow-empty-password empty-root-password allow-root-login"
EXTRA_IMAGE_FEATURES += "ptest-pkgs"

DISTRO_FEATURES = "ipv4 xattr zeroconf ldconfig"

DISTRO_FEATURES:append = " ptest"

INIT_MANAGER = "systemd"

IMAGE_INSTALL:append = " \
    kernel-module-gpio-sim \
    kernel-module-gpio-mockup \
    kernel-module-configfs \
"

IMAGE_INSTALL:append = " libgpiod"
IMAGE_INSTALL:append = " libgpiodcxx"
IMAGE_INSTALL:append = " libgpiod-tools"
IMAGE_INSTALL:append = " libgpiod-manager libgpiod-cli"

PACKAGECONFIG:append:pn-libgpiod = " glib"
PACKAGECONFIG:append:pn-libgpiod = " dbus"

IMAGE_INSTALL:append = " python3-gpiod"

IMAGE_INSTALL:append = " gpiod-sysfs-proxy"
PACKAGECONFIG:append:pn-gpiod-sysfs-proxy = " sys-class-mount"

KERNEL_FEATURES:append = " \
    features/gpio/sim.scc \
    features/gpio/mockup.scc \
    features/gpio/sysfs.scc \
    features/overlayfs/overlayfs.scc \
"

And the following layers:

BBLAYERS ?= " \
  /home/brgl/workspace/yocto/libgpiod-ptest/sources/openembedded-core/meta \
  /home/brgl/workspace/yocto/libgpiod-ptest/sources/meta-yocto/meta-poky \
  /home/brgl/workspace/yocto/libgpiod-ptest/sources/meta-openembedded/meta-oe \
  /home/brgl/workspace/yocto/libgpiod-ptest/sources/meta-openembedded/meta-python \
  /home/brgl/workspace/yocto/libgpiod-ptest/sources/meta-openembedded/meta-networking \
  /home/brgl/workspace/yocto/libgpiod-ptest/sources/meta-openembedded/meta-filesystems \
  "

Run with runqemu and call ptest-runner gpiod-sysfs-proxy.

Signed-off-by: Christopher Obbard <christopher.obbard@linaro.org>
@obbardc
Copy link
Copy Markdown
Author

obbardc commented Apr 21, 2026

@brgl I added a quick fix for the tests. Can you retry the test suite please and report back ? I haven't had the time to run it yet. I will do if there are many more issues.

@brgl
Copy link
Copy Markdown
Owner

brgl commented Apr 22, 2026

Some of them got fixed:

test_chown_export_unexport (__main__.TestChangeOwner.test_chown_export_unexport) ... ok
test_cannot_remove_chip_dir (__main__.TestChipDir.test_cannot_remove_chip_dir) ... ok
test_chip_attributes (__main__.TestChipDir.test_chip_attributes) ... ok
test_chip_base (__main__.TestChipDir.test_chip_base) ... ok
test_chip_label (__main__.TestChipDir.test_chip_label) ... ok
test_chip_ngpio (__main__.TestChipDir.test_chip_ngpio) ... ok
test_chip_write_to_attrs (__main__.TestChipDir.test_chip_write_to_attrs) ... ok
test_cannot_create_new_file_in_class (__main__.TestClassLayout.test_cannot_create_new_file_in_class) ... ok
test_cannot_mkdir_in_class (__main__.TestClassLayout.test_cannot_mkdir_in_class) ... ok
test_cannot_remove_export_unexport (__main__.TestClassLayout.test_cannot_remove_export_unexport) ... ok
test_export_unexport_exist_and_writeable (__main__.TestClassLayout.test_export_unexport_exist_and_writeable) ... ok
test_export_unexport_mode (__main__.TestClassLayout.test_export_unexport_mode) ... ok
test_remove_chip_before_unexporting_its_gpio (__main__.TestCornerCases.test_remove_chip_before_unexporting_its_gpio) ... ok
test_chip_dir_really_disappears (__main__.TestExportUnexport.test_chip_dir_really_disappears) ... ok
test_export_unexport (__main__.TestExportUnexport.test_export_unexport) ... ok
test_export_unexport_invalid_values (__main__.TestExportUnexport.test_export_unexport_invalid_values) ... ok
test_gpio_dir_really_disappears (__main__.TestExportUnexport.test_gpio_dir_really_disappears) ... ok
test_active_low (__main__.TestGpioDir.test_active_low) ... ok
test_active_low_invalid_value (__main__.TestGpioDir.test_active_low_invalid_value) ... ok
test_cannot_remove_gpio_dir (__main__.TestGpioDir.test_cannot_remove_gpio_dir) ... ok
test_direction (__main__.TestGpioDir.test_direction) ... ok
test_direction_invalid_value (__main__.TestGpioDir.test_direction_invalid_value) ... ok
test_edge_good_values (__main__.TestGpioDir.test_edge_good_values) ... ok
test_edge_invalid_value (__main__.TestGpioDir.test_edge_invalid_value) ... ok
test_gpio_attributes (__main__.TestGpioDir.test_gpio_attributes) ... ok
test_gpio_get_value (__main__.TestGpioDir.test_gpio_get_value) ... ok
test_gpio_set_value (__main__.TestGpioDir.test_gpio_set_value) ... ok
test_gpio_set_value_input_fails (__main__.TestGpioDir.test_gpio_set_value_input_fails) ... ok
test_gpio_set_value_invalid (__main__.TestGpioDir.test_gpio_set_value_invalid) ... ok
test_poll_edge_both (__main__.TestGpioDir.test_poll_edge_both) ... FAIL
test_poll_edge_falling (__main__.TestGpioDir.test_poll_edge_falling) ... FAIL
test_poll_edge_none (__main__.TestGpioDir.test_poll_edge_none) ... ok
test_poll_edge_rising (__main__.TestGpioDir.test_poll_edge_rising) ... FAIL
test_chip_write_uevent_invalid_value (__main__.TestUeventAttr.test_chip_write_uevent_invalid_value) ... ok
test_chip_write_uevent_synth_uevent (__main__.TestUeventAttr.test_chip_write_uevent_synth_uevent) ... ok
test_uevent_read (__main__.TestUeventAttr.test_uevent_read) ... ok

======================================================================
FAIL: test_poll_edge_both (__main__.TestGpioDir.test_poll_edge_both)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/lib/gpiod-sysfs-proxy/ptest/tests/./gpio-sysfs-compat-tests", line 537, in test_poll_edge_both
    self.assertTrue(got_rising and got_falling)
    ~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError: False is not true

======================================================================
FAIL: test_poll_edge_falling (__main__.TestGpioDir.test_poll_edge_falling)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/lib/gpiod-sysfs-proxy/ptest/tests/./gpio-sysfs-compat-tests", line 547, in test_poll_edge_falling
    self.assertTrue(got_falling)
    ~~~~~~~~~~~~~~~^^^^^^^^^^^^^
AssertionError: False is not true

======================================================================
FAIL: test_poll_edge_rising (__main__.TestGpioDir.test_poll_edge_rising)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/lib/gpiod-sysfs-proxy/ptest/tests/./gpio-sysfs-compat-tests", line 541, in test_poll_edge_rising
    self.assertTrue(got_rising)
    ~~~~~~~~~~~~~~~^^^^^^^^^^^^
AssertionError: False is not true

----------------------------------------------------------------------
Ran 36 tests in 11.176s

FAILED (failures=3)

Signed-off-by: Christopher Obbard <christopher.obbard@linaro.org>
@obbardc
Copy link
Copy Markdown
Author

obbardc commented Apr 24, 2026

@brgl I pushed another change. I didn't get the test setup created yet. I'll have another go at that shortly.

@brgl
Copy link
Copy Markdown
Owner

brgl commented Apr 27, 2026

@brgl I pushed another change. I didn't get the test setup created yet. I'll have another go at that shortly.

Something's still missing. :/ Sorry I can't assist you more than that but I'm really swamped with work ATM. I probably won't make time for debugging it anytime soon. It would be best if you could create a VM with the options I posted above, that makes testing super easy. The results are in /usr/lib/gpiod-sysfs-proxy/ptest/tests/gpio-sysfs-compat-tests.out.

test_chown_export_unexport (__main__.TestChangeOwner.test_chown_export_unexport) ... ok
test_cannot_remove_chip_dir (__main__.TestChipDir.test_cannot_remove_chip_dir) ... ok
test_chip_attributes (__main__.TestChipDir.test_chip_attributes) ... ok
test_chip_base (__main__.TestChipDir.test_chip_base) ... ok
test_chip_label (__main__.TestChipDir.test_chip_label) ... ok
test_chip_ngpio (__main__.TestChipDir.test_chip_ngpio) ... ok
test_chip_write_to_attrs (__main__.TestChipDir.test_chip_write_to_attrs) ... ok
test_cannot_create_new_file_in_class (__main__.TestClassLayout.test_cannot_create_new_file_in_class) ... ok
test_cannot_mkdir_in_class (__main__.TestClassLayout.test_cannot_mkdir_in_class) ... ok
test_cannot_remove_export_unexport (__main__.TestClassLayout.test_cannot_remove_export_unexport) ... ok
test_export_unexport_exist_and_writeable (__main__.TestClassLayout.test_export_unexport_exist_and_writeable) ... ok
test_export_unexport_mode (__main__.TestClassLayout.test_export_unexport_mode) ... ok
test_remove_chip_before_unexporting_its_gpio (__main__.TestCornerCases.test_remove_chip_before_unexporting_its_gpio) ... ok
test_chip_dir_really_disappears (__main__.TestExportUnexport.test_chip_dir_really_disappears) ... ok
test_export_unexport (__main__.TestExportUnexport.test_export_unexport) ... ok
test_export_unexport_invalid_values (__main__.TestExportUnexport.test_export_unexport_invalid_values) ... ok
test_gpio_dir_really_disappears (__main__.TestExportUnexport.test_gpio_dir_really_disappears) ... ok
test_active_low (__main__.TestGpioDir.test_active_low) ... ERROR
test_active_low_invalid_value (__main__.TestGpioDir.test_active_low_invalid_value) ... ok
test_cannot_remove_gpio_dir (__main__.TestGpioDir.test_cannot_remove_gpio_dir) ... ok
test_direction (__main__.TestGpioDir.test_direction) ... ok
test_direction_invalid_value (__main__.TestGpioDir.test_direction_invalid_value) ... ok
test_edge_good_values (__main__.TestGpioDir.test_edge_good_values) ... ok
test_edge_invalid_value (__main__.TestGpioDir.test_edge_invalid_value) ... ok
test_gpio_attributes (__main__.TestGpioDir.test_gpio_attributes) ... ok
test_gpio_get_value (__main__.TestGpioDir.test_gpio_get_value) ... ok
test_gpio_set_value (__main__.TestGpioDir.test_gpio_set_value) ... ok
test_gpio_set_value_input_fails (__main__.TestGpioDir.test_gpio_set_value_input_fails) ... ok
test_gpio_set_value_invalid (__main__.TestGpioDir.test_gpio_set_value_invalid) ... ok
test_poll_edge_both (__main__.TestGpioDir.test_poll_edge_both) ... ok
test_poll_edge_falling (__main__.TestGpioDir.test_poll_edge_falling) ... ERROR
test_poll_edge_none (__main__.TestGpioDir.test_poll_edge_none) ... ok
test_poll_edge_rising (__main__.TestGpioDir.test_poll_edge_rising) ... ERROR
test_chip_write_uevent_invalid_value (__main__.TestUeventAttr.test_chip_write_uevent_invalid_value) ... ok
test_chip_write_uevent_synth_uevent (__main__.TestUeventAttr.test_chip_write_uevent_synth_uevent) ... ok
test_uevent_read (__main__.TestUeventAttr.test_uevent_read) ... ok

======================================================================
ERROR: test_active_low (__main__.TestGpioDir.test_active_low)
----------------------------------------------------------------------
ConnectionAbortedError: [Errno 103] Software caused connection abort

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/lib/gpiod-sysfs-proxy/ptest/tests/./gpio-sysfs-compat-tests", line 464, in test_active_low
    self.gpio.write_attr("active_low", "1")
    ~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/gpiod-sysfs-proxy/ptest/tests/./gpio-sysfs-compat-tests", line 388, in write_attr
    write_kern_attr(f"{self.dir}/{attr}", val)
    ~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/gpiod-sysfs-proxy/ptest/tests/./gpio-sysfs-compat-tests", line 46, in write_kern_attr
    with open(os.path.normpath(path), "w") as fd:
         ~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
OSError: [Errno 107] Transport endpoint is not connected

======================================================================
ERROR: test_poll_edge_falling (__main__.TestGpioDir.test_poll_edge_falling)
----------------------------------------------------------------------
ConnectionAbortedError: [Errno 103] Software caused connection abort

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/lib/gpiod-sysfs-proxy/ptest/tests/./gpio-sysfs-compat-tests", line 545, in test_poll_edge_falling
    got_rising, got_falling = self.check_edges("falling")
                              ~~~~~~~~~~~~~~~~^^^^^^^^^^^
  File "/usr/lib/gpiod-sysfs-proxy/ptest/tests/./gpio-sysfs-compat-tests", line 506, in check_edges
    self.gpio.write_attr("direction", "in")
    ~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/gpiod-sysfs-proxy/ptest/tests/./gpio-sysfs-compat-tests", line 388, in write_attr
    write_kern_attr(f"{self.dir}/{attr}", val)
    ~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/gpiod-sysfs-proxy/ptest/tests/./gpio-sysfs-compat-tests", line 46, in write_kern_attr
    with open(os.path.normpath(path), "w") as fd:
         ~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
OSError: [Errno 107] Transport endpoint is not connected

======================================================================
ERROR: test_poll_edge_rising (__main__.TestGpioDir.test_poll_edge_rising)
----------------------------------------------------------------------
ConnectionAbortedError: [Errno 103] Software caused connection abort

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/lib/gpiod-sysfs-proxy/ptest/tests/./gpio-sysfs-compat-tests", line 540, in test_poll_edge_rising
    got_rising, got_falling = self.check_edges("rising")
                              ~~~~~~~~~~~~~~~~^^^^^^^^^^
  File "/usr/lib/gpiod-sysfs-proxy/ptest/tests/./gpio-sysfs-compat-tests", line 506, in check_edges
    self.gpio.write_attr("direction", "in")
    ~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/gpiod-sysfs-proxy/ptest/tests/./gpio-sysfs-compat-tests", line 388, in write_attr
    write_kern_attr(f"{self.dir}/{attr}", val)
    ~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/gpiod-sysfs-proxy/ptest/tests/./gpio-sysfs-compat-tests", line 46, in write_kern_attr
    with open(os.path.normpath(path), "w") as fd:
         ~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
OSError: [Errno 107] Transport endpoint is not connected

----------------------------------------------------------------------
Ran 36 tests in 4.514s

FAILED (errors=3)

@brgl
Copy link
Copy Markdown
Owner

brgl commented May 4, 2026

I tried to get claude to fix the problem and it says that pyfuse3 does not implement the poll notify mechanism fuse-python has. Is this correct? FWIW you call pyfuse3.notify_poll() which indeed seems to not exist in the pyfuse3 tree.

@obbardc
Copy link
Copy Markdown
Author

obbardc commented May 5, 2026

I tried to get claude to fix the problem and it says that pyfuse3 does not implement the poll notify mechanism fuse-python has. Is this correct? FWIW you call pyfuse3.notify_poll() which indeed seems to not exist in the pyfuse3 tree.

Yes, I think that is correct :/. I didn't really check this code much, it's untested from my side since I couldn't yet run the test suite (see #7)

fuse-python exposes that through Fuse.NotifyPoll() but pyfuse3 does not appear to expose either a poll request handler or a notify_poll equivalent.

I think we need add this functionality to pyfuse3 upstream. I will try to open a PR/issue upstream: https://github.com/libfuse/pyfuse3

Comment thread gpiod-sysfs-proxy
self._event = True
self.parent.parent.notify_poll(self._pollhandle)
self._pollhandle = None
pyfuse3.notify_poll(self._poll_handle)
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

This function doesn't exist in pyfuse3. See #4 (comment)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

@brgl I opened libfuse/pyfuse3#139 to discuss it upstream.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

created initial PR libfuse/pyfuse3#140

@brgl
Copy link
Copy Markdown
Owner

brgl commented May 5, 2026

FYI Claude offered to implement this as a solution to the above, does pyfuse3 accept AI-assisted contributions? I can't really spend time doing it myself but if it can do a good enough job, I can send it for review.

@obbardc
Copy link
Copy Markdown
Author

obbardc commented May 5, 2026

FYI Claude offered to implement this as a solution to the above, does pyfuse3 accept AI-assisted contributions? I can't really spend time doing it myself but if it can do a good enough job, I can send it for review.

I am happy to implement this as long as you can review the changes here and don;t mind waiting for me to have some "free time" :-)

@brgl
Copy link
Copy Markdown
Owner

brgl commented May 5, 2026

FYI Claude offered to implement this as a solution to the above, does pyfuse3 accept AI-assisted contributions? I can't really spend time doing it myself but if it can do a good enough job, I can send it for review.

I am happy to implement this as long as you can review the changes here and don;t mind waiting for me to have some "free time" :-)

Sounds good!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants