Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make scandir an optional dependency #44

Merged
merged 6 commits into from
May 19, 2017
Merged

Make scandir an optional dependency #44

merged 6 commits into from
May 19, 2017

Conversation

althonos
Copy link
Member

@althonos althonos commented May 8, 2017

Hi,
I just noticed while trying to install fs on the alpine-python Docker image that it had scandir as a hard requirement. Since scandir is a C extension, this meant that 1. implementations other than CPython couldn't use Pyfilesystem2, and that 2. it required C compilation, so minimal builds needed to have both a C compiler and Python headers installed, both of which can weigh a lot.

With the edits in that PR, the scandir module will be used if it can be found (either scandir is installed or the version is superior to 3.5). In other cases, plain os.listdir module will be used.

@coveralls
Copy link

coveralls commented May 8, 2017

Coverage Status

Coverage decreased (-0.5%) to 99.232% when pulling f66b1cc on althonos:feat-purepython into 11b4867 on PyFilesystem:master.

@coveralls
Copy link

coveralls commented May 8, 2017

Coverage Status

Coverage decreased (-0.5%) to 99.319% when pulling a2e8d3c on althonos:feat-purepython into 11b4867 on PyFilesystem:master.

@coveralls
Copy link

coveralls commented May 8, 2017

Coverage Status

Coverage decreased (-0.4%) to 99.384% when pulling e4be206 on althonos:feat-purepython into 11b4867 on PyFilesystem:master.

@coveralls
Copy link

coveralls commented May 9, 2017

Coverage Status

Coverage increased (+0.001%) to 99.78% when pulling 80706d6 on althonos:feat-purepython into 11b4867 on PyFilesystem:master.

@coveralls
Copy link

coveralls commented May 10, 2017

Coverage Status

Coverage increased (+0.001%) to 99.78% when pulling 1af4182 on althonos:feat-purepython into 11b4867 on PyFilesystem:master.

fs/osfs.py Outdated
}
}
if 'details' in namespaces:
stat_result = os.stat(entry_path)
Copy link
Member

Choose a reason for hiding this comment

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

Could you cache this os.stat call? It could potentially be called several time. And perhaps you can use the stat structure rather than isdir on L412, because that will do a stat under the hood.

fs/osfs.py Outdated
def _scandir(self, path, namespaces=None):


def _scandir_c(self, path, namespaces=None):
Copy link
Member

Choose a reason for hiding this comment

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

I'd like to suggest a slightly different way of doing the conditional.

try:
    import scandir
except ImportError:
    scandir = None

class OSFS:
    if scandir:
        def _scandir(self, path, namespaces=None, page=None):
            # with scandir implementation
    else:
        def _scandir(self, path, namespaces=None, page=None):
            # without scandir implementation

I think that's a little tidier than having separate _scandir_c and scandir_py functions. What do you think?

Copy link
Member Author

Choose a reason for hiding this comment

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

At first that's what I wanted to do, but for the sake of testing it's easier to have the two methods accessible at all times, since your way involves reloading the module while mocking an import to be able to access the other implementation. But I'll give it a shot anyway.

setup.py Outdated
@@ -37,7 +37,7 @@
description="Python's filesystem abstraction layer",
install_requires=REQUIREMENTS,
extras_require={
":python_version<'3.5'": ['scandir~=1.5'],
"scandir : python_version < '3.5'": ['scandir~=1.5'],
Copy link
Member

@willmcgugan willmcgugan May 13, 2017

Choose a reason for hiding this comment

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

I just merges a PR that might conflict with this. You might have to resolve it.

class TestOSFSScandir(OSFSTestBase, unittest.TestCase):

def test_scandir_purepython(self):
with mock.patch.object(self.fs, '_scandir', self.fs._scandir_py):
Copy link
Member

Choose a reason for hiding this comment

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

I think I see why you have the 2 functions defined now. I think you can modif tox.ini file to have separate environments for with and without the scandir module. Otherwise its not going to include this in coverage.

@willmcgugan
Copy link
Member

Thanks! I concur. Only thing that concerns me is that scandir won't be installed on automatically in environments that it would easily install on. I guess that would just need to be documented.

@althonos
Copy link
Member Author

I'll try to resolve the conflicts shortly.

For the automatic installation of scandir, I tried to search if there was a way to specify "default-but-not-mandatory" requirements, but no luck with that. At some point I thought restricting the installation of scandir to sys_implementation == "cpython", but that would fail for CPython systems without Python headers.

The setup.py could also throw a warning if the version is scandir friendly, like:

# setup.py

import sys
import warnings

if sys.implementation.name == "cpython" and sys.version < "3.5":
    try:
        import scandir
    except ImportError:
        warnings.warn("Consider installing scandir blah blah blah...")

@coveralls
Copy link

coveralls commented May 16, 2017

Coverage Status

Coverage increased (+0.001%) to 99.78% when pulling 77e4858 on althonos:feat-purepython into 51b8034 on PyFilesystem:master.

@althonos
Copy link
Member Author

Done, you can merge when you want. I added another environment to tox.ini, and rolled back to defining OSFS._scandir directly depending on the availability of scandir.

@willmcgugan
Copy link
Member

Brilliant. Thanks.

@willmcgugan willmcgugan merged commit 9990a1e into PyFilesystem:master May 19, 2017
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.

None yet

3 participants