1"""ImportSpy
2
3Keeps track of modules not imported directly by Webware for Python.
4
5This module helps save the filepath of every module which is imported.
6This is used by the `AutoReloadingAppServer` (see doc strings for more
7information) to restart the server if any source files change.
8
9Other than keeping track of the filepaths, the behaviour of this module
10loader is identical to Python's default behaviour.
11
12If the system supports FAM (file alteration monitor) and python-fam is
13installed, then the need for reloading can be monitored very effectively
14with the use of ImportSpy. Otherwise, ImportSpy will not have much benefit.
15
16Note that ImportSpy is based on the new import hooks of Python described
17in PEP 302. It is possible to suppress the use of ImportSpy by setting
18`UseImportSpy` in AppServer.config to False.
19"""
20
21from os.path import isdir
22from sys import path_hooks, path_importer_cache
23
24
25class ImportSpy(object):
26    """New style import tracker."""
27
28    _imp = None
29
30    def __init__(self, path=None):
31        """Create importer."""
32        assert self._imp
33        if path and isdir(path):
34            self.path = path
35        else:
36            raise ImportError
37
38    def find_module(self, fullname):
39        """Replaces imp.find_module."""
40        try:
41            self.file, self.filename, self.info = self._imp.find_module(
42                fullname.rsplit('.', 1)[-1], [self.path])
43        except ImportError:
44            pass
45        else:
46            return self
47
48    def load_module(self, fullname):
49        """Replaces imp.load_module."""
50        mod = self._imp.load_module(fullname, self.file, self.filename, self.info)
51        if mod:
52            mod.__loader__ = self
53        return mod
54
55
56def activate(impManager):
57    """Activate ImportSpy."""
58    assert not ImportSpy._imp
59    ImportSpy._imp = impManager
60    path_hooks.append(ImportSpy)
61    path_importer_cache.clear()
62    impManager.recordModules()
63