summaryrefslogtreecommitdiff
blob: 3a33ebbfe844a44c0d5727e8864cd96cb93b1703 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
Index: pychecker/pychecker/checker.py
===================================================================
--- pychecker.orig/pychecker/checker.py
+++ pychecker/pychecker/checker.py
@@ -99,7 +99,7 @@ def _flattenList(list) :
     return new_list
 
 def getModules(arg_list) :
-    "Returns a list of module names that can be imported"
+    "Returns a list of (module names, dirPath) that can be imported"
 
     new_arguments = []
     for arg in arg_list :
@@ -116,6 +116,7 @@ def getModules(arg_list) :
         
     modules = []
     for arg in _flattenList(new_arguments) :
+        arg_dir = None # actual modules will not give us a dir to load from
         # is it a .py file?
         for suf, suflen in zip(PY_SUFFIXES, PY_SUFFIX_LENS):
             if len(arg) > suflen and arg[-suflen:] == suf:
@@ -125,10 +126,12 @@ def getModules(arg_list) :
                     continue
 
                 module_name = os.path.basename(arg)[:-suflen]
-                if arg_dir not in sys.path :
-                    sys.path.insert(0, arg_dir)
+                # THOMAS: this breaks loading two .py files with same name
+                # from different dirs; we would always get the first one
+                #if arg_dir not in sys.path :
+                #    sys.path.insert(0, arg_dir)
                 arg = module_name
-        modules.append(arg)
+        modules.append((arg, arg_dir))
 
     return modules
 
@@ -161,11 +164,13 @@ def _q_find_module(p, path):
                 if os.path.exists(f):
                     return _q_file(file(f)), f, ('.ptl', 'U', 1)
 
-def _findModule(name) :
+def _findModule(name, moduleDir=None) :
     """Returns the result of an imp.find_module(), ie, (file, filename, smt)
        name can be a module or a package name.  It is *not* a filename."""
 
     path = sys.path[:]
+    if moduleDir:
+        path.insert(0, moduleDir)
     packages = string.split(name, '.')
     for p in packages :
         # smt = (suffix, mode, type)
@@ -235,8 +240,9 @@ def _getClassTokens(c) :
 class Class :
     "Class to hold all information about a class"
 
-    def __init__(self, name, module) :
+    def __init__(self, name, pcmodule) :
         self.name = name
+        module = pcmodule.module
         self.classObject = getattr(module, name)
 
         modname = getattr(self.classObject, '__module__', None)
@@ -260,7 +266,9 @@ class Class :
             self.classObject__name__ = name
 
         self.module = sys.modules.get(modname)
-        if not self.module:
+        # if the pcmodule has moduleDir, it means we processed it before,
+        # and deleted it from sys.modules
+        if not self.module and not pcmodule.moduleDir:
             self.module = module
             if modname not in cfg().blacklist:
                 sys.stderr.write("warning: couldn't find real module "
@@ -497,8 +505,13 @@ def _getPyFile(filename):
 class PyCheckerModule :
     "Class to hold all information for a module"
 
-    def __init__(self, moduleName, check = 1) :
+    def __init__(self, moduleName, check = 1, moduleDir=None) :
+        """
+        @param moduleDir: if specified, the directory where the module can
+                          be loaded from
+        """
         self.moduleName = moduleName
+        self.moduleDir = moduleDir
         self.variables = {}
         self.functions = {}
         self.classes = {}
@@ -508,7 +521,12 @@ class PyCheckerModule :
         self.main_code = None
         self.module = None
         self.check = check
-        _allModules[moduleName] = self
+        # FIXME: to make sure we have separate dict entries for different files
+        # with the same module name, we fudge in the moduleDir
+        __name = moduleName
+        if moduleDir:
+            __name = moduleName + moduleDir
+        _allModules[__name] = self
 
     def __str__(self) :
         return self.moduleName
@@ -528,7 +546,9 @@ class PyCheckerModule :
         c.addMembers(classObject)
 
     def addClass(self, name) :
-        self.classes[name] = c = Class(name, self.module)
+        #self.classes[name] = c = Class(name, self.module)
+        # give ourselves, so Class has more context
+        self.classes[name] = c = Class(name, self)
         try:
             objName = utils.safestr(c.classObject)
         except TypeError:
@@ -558,16 +578,19 @@ class PyCheckerModule :
             filename = self.module.__file__
         except AttributeError :
             filename = self.moduleName
+            if self.moduleDir:
+                filename = self.moduleDir + ': ' + filename
         return _getPyFile(filename)
 
     def load(self):
         try :
-            # there's no need to reload modules we already have
-            module = sys.modules.get(self.moduleName)
-            if module :
-                if not _allModules[self.moduleName].module :
-                    return self._initModule(module)
-                return 1
+            # there's no need to reload modules we already have if no moduleDir
+            if not self.moduleDir:
+                module = sys.modules.get(self.moduleName)
+                if module :
+                    if not _allModules[self.moduleName].module :
+                        return self._initModule(module)
+                    return 1
 
             return self._initModule(self.setupMainCode())
         except (SystemExit, KeyboardInterrupt) :
@@ -627,9 +650,19 @@ class PyCheckerModule :
         return 1
 
     def setupMainCode(self) :
-        file, filename, smt = _findModule(self.moduleName)
+        file, filename, smt = _findModule(self.moduleName, self.moduleDir)
         # FIXME: if the smt[-1] == imp.PKG_DIRECTORY : load __all__
+        # HACK: to make sibling imports work, we add self.moduleDir to sys.path
+        # temporarily, and remove it later
+        if self.moduleDir:
+            oldsyspath = sys.path[:]
+            sys.path.insert(0, self.moduleDir)
         module = imp.load_module(self.moduleName, file, filename, smt)
+        if self.moduleDir:
+            sys.path = oldsyspath
+            # to make sure that subsequent modules with the same moduleName
+            # do not persist, and getting their namespace clobbered, delete it
+            del sys.modules[self.moduleName]
         self._setupMainCode(file, filename, module)
         return module
 
@@ -736,10 +769,10 @@ def processFiles(files, cfg = None, pre_
 
     warnings = []
     utils.initConfig(_cfg)
-    for moduleName in getModules(files) :
+    for file, (moduleName, moduleDir) in zip(files, getModules(files)) :
         if callable(pre_process_cb) :
-            pre_process_cb(moduleName)
-        module = PyCheckerModule(moduleName)
+            pre_process_cb("%s (%s)" % (moduleName, file))
+        module = PyCheckerModule(moduleName, moduleDir=moduleDir)
         if not module.load() :
             w = Warning(module.filename(), 1,
                         msgs.Internal("NOT PROCESSED UNABLE TO IMPORT"))