With a little care, you can implement a PyFilesystem interface for any filesystem, which will allow it to work interchangeably with any of the built-in FS classes and tools.
Take care to copy the method signatures exactly, including default values. It is also essential that you follow the same logic with regards to exceptions, and only raise exceptions in :mod:`~fs.errors`.
There are no particular requirements regarding how a PyFilesystem class is constructed, but be sure to call the base class
__init__ method with no parameters.
All Filesystems should be thread-safe. The simplest way to achieve that is by using the
_lock attribute supplied by the :class:`~fs.base.FS` constructor. This is a
RLock object from the standard library, which you can use as a context manager, so methods you implement will start something like this:
with self._lock: do_something()
You aren't required to use
_lock. Just as long as calling methods on the FS object from multiple threads doesn't break anything.
PyFilesystem supports Python2.7 and Python3.X. The differences between the two major Python versions are largely managed by the
You aren't obligated to support the same versions of Python that PyFilesystem itself supports, but it is recommended if your project is for general use.
To test your implementation, you can borrow the test suite used to test the built in filesystems. If your code passes these tests, then you can be confident your implementation will work seamlessly.
Here's the simplest possible example to test a filesystem class called
import unittest from fs.test import FSTestCases class TestMyFS(FSTestCases, unittest.TestCase): def make_fs(self): # Return an instance of your FS object here return MyFS()
You may also want to override some of the methods in the test suite for more targeted testing:
.. autoclass:: fs.test.FSTestCases :members:
As of version 2.4.11 this project uses pytest to run its tests.
While it's completely compatible with
unittest-style tests, it's much more powerful and
feature-rich. We suggest you take advantage of it and its plugins in new tests you write, rather
than sticking to strict
unittest features. For benefits and limitations, see here.
The following methods MUST be implemented in a PyFilesystem interface.
- :meth:`~fs.base.FS.getinfo` Get info regarding a file or directory.
- :meth:`~fs.base.FS.listdir` Get a list of resources in a directory.
- :meth:`~fs.base.FS.makedir` Make a directory.
- :meth:`~fs.base.FS.openbin` Open a binary file.
- :meth:`~fs.base.FS.remove` Remove a file.
- :meth:`~fs.base.FS.removedir` Remove a directory.
- :meth:`~fs.base.FS.setinfo` Set resource information.
Non - Essential Methods
The following methods MAY be implemented in a PyFilesystem interface.
These methods have a default implementation in the base class, but may be overridden if you can supply a more optimal version.
Exactly which methods you should implement depends on how and where the data is stored. For network filesystems, a good candidate to implement, is the
scandir method which would otherwise call a combination of
getinfo for each file.
In the general case, it is a good idea to look at how these methods are implemented in :class:`~fs.base.FS`, and only write a custom version if it would be more efficient than the default.
These methods SHOULD NOT be implemented.
Implementing these is highly unlikely to be worthwhile.