fuse4dbricks 0.7.0__tar.gz → 0.7.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. {fuse4dbricks-0.7.0 → fuse4dbricks-0.7.1}/CHANGELOG.md +8 -0
  2. {fuse4dbricks-0.7.0 → fuse4dbricks-0.7.1}/PKG-INFO +12 -1
  3. {fuse4dbricks-0.7.0 → fuse4dbricks-0.7.1}/README.md +11 -0
  4. {fuse4dbricks-0.7.0 → fuse4dbricks-0.7.1}/fuse4dbricks/main.py +23 -1
  5. {fuse4dbricks-0.7.0 → fuse4dbricks-0.7.1}/pyproject.toml +1 -1
  6. {fuse4dbricks-0.7.0 → fuse4dbricks-0.7.1}/uv.lock +1 -1
  7. {fuse4dbricks-0.7.0 → fuse4dbricks-0.7.1}/.env.example +0 -0
  8. {fuse4dbricks-0.7.0 → fuse4dbricks-0.7.1}/.github/workflows/test.yml +0 -0
  9. {fuse4dbricks-0.7.0 → fuse4dbricks-0.7.1}/.gitignore +0 -0
  10. {fuse4dbricks-0.7.0 → fuse4dbricks-0.7.1}/fuse4dbricks/__init__.py +0 -0
  11. {fuse4dbricks-0.7.0 → fuse4dbricks-0.7.1}/fuse4dbricks/api/__init__.py +0 -0
  12. {fuse4dbricks-0.7.0 → fuse4dbricks-0.7.1}/fuse4dbricks/api/errors.py +0 -0
  13. {fuse4dbricks-0.7.0 → fuse4dbricks-0.7.1}/fuse4dbricks/api/uc_client.py +0 -0
  14. {fuse4dbricks-0.7.0 → fuse4dbricks-0.7.1}/fuse4dbricks/auth/__init__.py +0 -0
  15. {fuse4dbricks-0.7.0 → fuse4dbricks-0.7.1}/fuse4dbricks/auth/provider.py +0 -0
  16. {fuse4dbricks-0.7.0 → fuse4dbricks-0.7.1}/fuse4dbricks/fs/__init__.py +0 -0
  17. {fuse4dbricks-0.7.0 → fuse4dbricks-0.7.1}/fuse4dbricks/fs/auth_manager.py +0 -0
  18. {fuse4dbricks-0.7.0 → fuse4dbricks-0.7.1}/fuse4dbricks/fs/data_manager.py +0 -0
  19. {fuse4dbricks-0.7.0 → fuse4dbricks-0.7.1}/fuse4dbricks/fs/inode_manager.py +0 -0
  20. {fuse4dbricks-0.7.0 → fuse4dbricks-0.7.1}/fuse4dbricks/fs/metadata_manager.py +0 -0
  21. {fuse4dbricks-0.7.0 → fuse4dbricks-0.7.1}/fuse4dbricks/fs/operations.py +0 -0
  22. {fuse4dbricks-0.7.0 → fuse4dbricks-0.7.1}/fuse4dbricks/fs/ram_cache.py +0 -0
  23. {fuse4dbricks-0.7.0 → fuse4dbricks-0.7.1}/fuse4dbricks/fs/securable_filter.py +0 -0
  24. {fuse4dbricks-0.7.0 → fuse4dbricks-0.7.1}/fuse4dbricks/fs/utils.py +0 -0
  25. {fuse4dbricks-0.7.0 → fuse4dbricks-0.7.1}/fuse4dbricks/fs/write_buffer.py +0 -0
  26. {fuse4dbricks-0.7.0 → fuse4dbricks-0.7.1}/fuse4dbricks/storage/__init__.py +0 -0
  27. {fuse4dbricks-0.7.0 → fuse4dbricks-0.7.1}/fuse4dbricks/storage/persistence.py +0 -0
  28. {fuse4dbricks-0.7.0 → fuse4dbricks-0.7.1}/tests/test_auth_manager.py +0 -0
  29. {fuse4dbricks-0.7.0 → fuse4dbricks-0.7.1}/tests/test_auth_provider.py +0 -0
  30. {fuse4dbricks-0.7.0 → fuse4dbricks-0.7.1}/tests/test_data_manager.py +0 -0
  31. {fuse4dbricks-0.7.0 → fuse4dbricks-0.7.1}/tests/test_e2e_mount.py +0 -0
  32. {fuse4dbricks-0.7.0 → fuse4dbricks-0.7.1}/tests/test_inode_manager.py +0 -0
  33. {fuse4dbricks-0.7.0 → fuse4dbricks-0.7.1}/tests/test_main.py +0 -0
  34. {fuse4dbricks-0.7.0 → fuse4dbricks-0.7.1}/tests/test_metadata_manager.py +0 -0
  35. {fuse4dbricks-0.7.0 → fuse4dbricks-0.7.1}/tests/test_operations.py +0 -0
  36. {fuse4dbricks-0.7.0 → fuse4dbricks-0.7.1}/tests/test_persistence.py +0 -0
  37. {fuse4dbricks-0.7.0 → fuse4dbricks-0.7.1}/tests/test_securable_filter.py +0 -0
  38. {fuse4dbricks-0.7.0 → fuse4dbricks-0.7.1}/tests/test_uc_client.py +0 -0
  39. {fuse4dbricks-0.7.0 → fuse4dbricks-0.7.1}/tests/test_uc_client_consistency.py +0 -0
  40. {fuse4dbricks-0.7.0 → fuse4dbricks-0.7.1}/tests/test_uc_client_live.py +0 -0
  41. {fuse4dbricks-0.7.0 → fuse4dbricks-0.7.1}/tests/test_utils.py +0 -0
  42. {fuse4dbricks-0.7.0 → fuse4dbricks-0.7.1}/tests/test_write_buffer.py +0 -0
@@ -1,3 +1,11 @@
1
+ # 0.7.1 (2026-06-17)
2
+
3
+ - Unmount cleanly on `SIGTERM`/`SIGHUP` (e.g. `systemctl stop`). trio only turns
4
+ `SIGINT` (Ctrl-C) into a clean shutdown; other termination signals killed the
5
+ process before `pyfuse3.close()` ran, leaving the kernel with a stale mount
6
+ that showed up as `d?????????` in `ls`/`df`. All termination signals now run
7
+ the same orderly unwind that unmounts the filesystem.
8
+
1
9
  # 0.7.0 (2026-06-17)
2
10
 
3
11
  - Fix files written from a Windows application through WSL being uploaded at
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fuse4dbricks
3
- Version: 0.7.0
3
+ Version: 0.7.1
4
4
  Summary: FUSE driver for Databricks Unity Catalog Volumes.
5
5
  Project-URL: Homepage, https://github.com/zeehio/fuse4dbricks
6
6
  Author-email: Sergio Oller <sergioller@gmail.com>
@@ -261,6 +261,13 @@ user has to provide its own access token.
261
261
  User=root
262
262
  WorkingDirectory=/opt/fuse4dbricks
263
263
  ExecStart=/opt/fuse4dbricks/fuse4dbricks_start.sh
264
+ # On stop, fuse4dbricks catches SIGTERM and unmounts itself. Give it time
265
+ # to finish before systemd escalates to SIGKILL (which cannot be caught
266
+ # and would leave a stale mount).
267
+ TimeoutStopSec=30
268
+ # Belt-and-suspenders: if the process was hard-killed and left a stale
269
+ # mount, force-unmount it. '-' ignores failure when nothing is mounted.
270
+ ExecStopPost=-/bin/fusermount3 -uz /Volumes
264
271
  Restart=on-failure
265
272
  RestartSec=5
266
273
 
@@ -268,6 +275,10 @@ user has to provide its own access token.
268
275
  WantedBy=multi-user.target
269
276
  EOF
270
277
 
278
+ If your mountpoint is not `/Volumes`, update it in `ExecStopPost` to match.
279
+ On systems that ship FUSE 2 rather than FUSE 3, use the absolute path to
280
+ `fusermount` (e.g. `/usr/bin/fusermount`) instead of `fusermount3`.
281
+
271
282
 
272
283
  - Reload the daemon lists
273
284
 
@@ -238,6 +238,13 @@ user has to provide its own access token.
238
238
  User=root
239
239
  WorkingDirectory=/opt/fuse4dbricks
240
240
  ExecStart=/opt/fuse4dbricks/fuse4dbricks_start.sh
241
+ # On stop, fuse4dbricks catches SIGTERM and unmounts itself. Give it time
242
+ # to finish before systemd escalates to SIGKILL (which cannot be caught
243
+ # and would leave a stale mount).
244
+ TimeoutStopSec=30
245
+ # Belt-and-suspenders: if the process was hard-killed and left a stale
246
+ # mount, force-unmount it. '-' ignores failure when nothing is mounted.
247
+ ExecStopPost=-/bin/fusermount3 -uz /Volumes
241
248
  Restart=on-failure
242
249
  RestartSec=5
243
250
 
@@ -245,6 +252,10 @@ user has to provide its own access token.
245
252
  WantedBy=multi-user.target
246
253
  EOF
247
254
 
255
+ If your mountpoint is not `/Volumes`, update it in `ExecStopPost` to match.
256
+ On systems that ship FUSE 2 rather than FUSE 3, use the absolute path to
257
+ `fusermount` (e.g. `/usr/bin/fusermount`) instead of `fusermount3`.
258
+
248
259
 
249
260
  - Reload the daemon lists
250
261
 
@@ -2,6 +2,7 @@
2
2
  import argparse
3
3
  import logging
4
4
  import os
5
+ import signal
5
6
  import traceback
6
7
  import sys
7
8
 
@@ -145,6 +146,26 @@ def setup_logging(debug_mode):
145
146
  logging.getLogger("pyfuse3").setLevel(logging.INFO)
146
147
 
147
148
 
149
+ async def _shutdown_on_signal(cancel_scope: trio.CancelScope):
150
+ """Translate termination signals into a clean trio shutdown.
151
+
152
+ Without this, trio only converts SIGINT (Ctrl-C) into a KeyboardInterrupt;
153
+ SIGTERM (e.g. ``systemctl stop``) and SIGHUP kill the process outright, so
154
+ ``start_fuse``'s ``finally`` never runs and ``pyfuse3.close()`` never gets
155
+ a chance to unmount. The kernel is then left with a stale mount that shows
156
+ up as ``d?????????`` in ``ls``/``df``. Cancelling the nursery here makes
157
+ every signal follow the same orderly unwind that unmounts the filesystem.
158
+ """
159
+ with trio.open_signal_receiver(signal.SIGTERM, signal.SIGINT, signal.SIGHUP) as signals:
160
+ async for signum in signals:
161
+ logging.info(
162
+ "Received %s, unmounting and shutting down...",
163
+ signal.Signals(signum).name,
164
+ )
165
+ cancel_scope.cancel()
166
+ return
167
+
168
+
148
169
  async def start_fuse(ops, mountpoint, allow_other, debug_mode, stopped_evt: trio.Event | None = None):
149
170
  mount_options = ["fsname=fuse4dbricks", "noatime"]
150
171
  if allow_other:
@@ -165,7 +186,7 @@ async def start_fuse(ops, mountpoint, allow_other, debug_mode, stopped_evt: trio
165
186
  pass
166
187
  finally:
167
188
  try:
168
- pyfuse3.close()
189
+ pyfuse3.close(unmount=True)
169
190
  finally:
170
191
  if stopped_evt is not None:
171
192
  stopped_evt.set()
@@ -251,6 +272,7 @@ async def async_main():
251
272
  async with trio.open_nursery() as nursery:
252
273
  persistence.run_services(nursery)
253
274
  data_manager.run_services(nursery)
275
+ nursery.start_soon(_shutdown_on_signal, nursery.cancel_scope)
254
276
  nursery.start_soon(start_fuse, operations, mountpoint, args.allow_other, args.debug, stopped_evt)
255
277
 
256
278
  await stopped_evt.wait()
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "fuse4dbricks"
7
- version = "0.7.0"
7
+ version = "0.7.1"
8
8
  description = "FUSE driver for Databricks Unity Catalog Volumes."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -353,7 +353,7 @@ wheels = [
353
353
 
354
354
  [[package]]
355
355
  name = "fuse4dbricks"
356
- version = "0.6.2"
356
+ version = "0.7.1"
357
357
  source = { editable = "." }
358
358
  dependencies = [
359
359
  { name = "databricks-sdk" },
File without changes
File without changes