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

Test PathFinder/FileFinder/*Loaders as an API #47

Open
asmodehn opened this issue Jun 3, 2018 · 1 comment
Open

Test PathFinder/FileFinder/*Loaders as an API #47

asmodehn opened this issue Jun 3, 2018 · 1 comment

Comments

@asmodehn
Copy link
Owner

asmodehn commented Jun 3, 2018

The simplest way to make your custom importer, should also be the easiest : reusing existing classes directly should not come with surprises.

We should integrate the pattern I use in most FileFinder even if I they dont do much, only to integrate with existing python and work around some pitfalls :

class MyFileFinder(FileFinder):

    def __init__(self, path, *loader_details):
        super(MyFileFinder, self).__init__(path, *loader_details)

    def __repr__(self):
        return 'MyFileFinder({!r})'.format(self.path)

    @classmethod
    def path_hook(cls, *loader_details):
        """A class method which returns a closure to use on sys.path_hook
        which will return an instance using the specified loaders and the path
        called on the closure.

        If the path called on the closure is not a directory, or doesnt contain
         any files with the supported extension, ImportError is raised.

         This is different from default python behavior
         but prevent polluting the cache with custom finders
        """
        def path_hook_for_MyFileFinder(path):
            """Path hook for importlib.machinery.FileFinder."""

            if not (os.path.isdir(path)):
                raise ImportError('only directories are supported')

            exts = [x for ld in loader_details for x in ld[1]]
            if not any(fname.endswith(ext) for fname in os.listdir(path) for ext in exts):
                raise ImportError(
                    'only directories containing {ext} files are supported'.format(ext=", ".join(exts)))
            return cls(path, *loader_details)
        return path_hook_for_MyFileFinder

    def find_spec(self, fullname, target=None):
        """
        Try to find a spec for the specified module.
        :param fullname: the name of the package we are trying to import
        :return: the matching spec, or None if not found.
        """

        # We attempt to load a .my file as a module
        tail_module = fullname.rpartition('.')[2]
        base_path = os.path.join(self.path, tail_module)
        for suffix, loader_class in self._loaders:
            full_path = base_path + suffix
            if os.path.isfile(full_path):  # maybe we need more checks here (importlib filefinder checks its cache...)
                return self._get_spec(loader_class, fullname, full_path, None, target)

        # Otherwise, we try find python modules
        return super(MyFileFinder, self).find_spec(fullname=fullname, target=target)

[...]

There are probably similar changes that would be useful in PathFinder. I haven't used it enough yet to know which ones would be useful.

@asmodehn
Copy link
Owner Author

asmodehn commented Jun 3, 2018

For clarity : This issue is about testing the behavior when one makes a custom importer (without defining his own class).
It is important, especially in this case, to add tests before starting to change existing behavior.

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

No branches or pull requests

1 participant