nathanhi / pyfatfs

Python based FAT12/FAT16/FAT32 implementation with VFAT support
https://pypi.org/project/pyfatfs/
MIT License
31 stars 14 forks source link

PyFilesystem2 dependency causes pkg_resources ImportError with Python 3.12 #41

Open mxmlnkn opened 2 months ago

mxmlnkn commented 2 months ago

Hello,

this project looks really cool and I wanted to integrate it as a backend into ratarmount, if you are not opposed to that. However, while looking into it, I saw that the dependency PyFilesystem2 seems to not have received updates since 2 years ago.

In the ReadMe, a low-level API is mentioned, which I assume is the PyFat.py file as opposed to the PyFatFS file / PyFilesystem2 URI opening. I would like to use those without have fs as a dependency. Would that be possible?

PyFilesystem2 would have to be taken out of the pyproject somehow. But, having it as an optional dependency also seems clunky, ... I guess one could split the project into two subprojects on PyPI to avoid that, e.g. pyfatfs and pyfatfs_ll. But even then, PyFatIO.py imports fs.mode. This also would have to be abstracted to get rid of the dependency. This seems to be the only import of fs, so it might be easier than thought to use it without fs.

mxmlnkn commented 2 months ago

I have now encountered this issue: https://github.com/PyFilesystem/pyfilesystem2/issues/577 in a Python 3.12 environment, which is the default in Ubuntu 24.04.

Traceback (most recent call last):
  File "squashfs-root/opt/python3.12/lib/python3.12/site-packages/ratarmountcore/FATMountSource.py", line 13, in <module>
    from pyfatfs import PyFatFS
  File "squashfs-root/opt/python3.12/lib/python3.12/site-packages/pyfatfs/PyFatFS.py", line 11, in <module>
    from fs.base import FS
  File "squashfs-root/opt/python3.12/lib/python3.12/site-packages/fs/__init__.py", line 4, in <module>
    __import__("pkg_resources").declare_namespace(__name__)  # type: ignore
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^
ModuleNotFoundError: No module named 'pkg_resources'

I refactored to avoid usage of PyFatFS and use PyFat directly, but now I get this error when importing FatIO because it imports fs.mode.Mode.

If it was not for the default argument, then this import would not even be necessary and we could simply rubber-type! Therefore, a quick fix could look like this:

--- FatIO.py    2024-09-15 20:21:04.000000000 +0200
+++ FatIO.py    2024-09-15 21:45:27.968480300 +0200
@@ -6,18 +6,25 @@
 import threading
 from typing import Union, Optional

-from fs.mode import Mode
 from pyfatfs import PyFATException

 from pyfatfs.PyFat import PyFat

+class DefaultModeReadOnly:
+    def __init__(self):
+        self.truncate = False
+        self.appending = False
+        self.reading = True
+        self.writing = False
+
+
 class FatIO(io.RawIOBase):
     """Wrap basic I/O operations for PyFat."""

     def __init__(self, fs: PyFat,
                  path: str,
-                 mode: Mode = Mode('r')) -> None:
+                 mode = DefaultModeReadOnly()) -> None:
         """Wrap basic I/O operations for PyFat. **Currently read-only**.

         :param fs: `PyFat`: Instance of opened filesystem

It works for me.