OLD | NEW |
(Empty) | |
| 1 import warnings |
| 2 |
| 3 from rope.base import exceptions, resourceobserver |
| 4 from rope.base.oi import objectdb, memorydb, transform |
| 5 |
| 6 |
| 7 class ObjectInfoManager(object): |
| 8 """Stores object information |
| 9 |
| 10 It uses an instance of `objectdb.ObjectDB` for storing |
| 11 information. |
| 12 |
| 13 """ |
| 14 |
| 15 def __init__(self, project): |
| 16 self.project = project |
| 17 self.to_textual = transform.PyObjectToTextual(project) |
| 18 self.to_pyobject = transform.TextualToPyObject(project) |
| 19 self.doi_to_pyobject = transform.DOITextualToPyObject(project) |
| 20 self._init_objectdb() |
| 21 if project.prefs.get('validate_objectdb', False): |
| 22 self._init_validation() |
| 23 |
| 24 def _init_objectdb(self): |
| 25 dbtype = self.project.get_prefs().get('objectdb_type', None) |
| 26 persist = None |
| 27 if dbtype is not None: |
| 28 warnings.warn( |
| 29 '"objectdb_type" project config is deprecated;\n' |
| 30 'Use "save_objectdb" instead in your project ' |
| 31 'config file.\n(".ropeproject/config.py" by default)\n', |
| 32 DeprecationWarning) |
| 33 if dbtype != 'memory' and self.project.ropefolder is not None: |
| 34 persist = True |
| 35 self.validation = TextualValidation(self.to_pyobject) |
| 36 db = memorydb.MemoryDB(self.project, persist=persist) |
| 37 self.objectdb = objectdb.ObjectDB(db, self.validation) |
| 38 |
| 39 def _init_validation(self): |
| 40 self.objectdb.validate_files() |
| 41 observer = resourceobserver.ResourceObserver( |
| 42 changed=self._resource_changed, moved=self._resource_moved, |
| 43 removed=self._resource_moved) |
| 44 files = [] |
| 45 for path in self.objectdb.get_files(): |
| 46 resource = self.to_pyobject.path_to_resource(path) |
| 47 if resource is not None and resource.project == self.project: |
| 48 files.append(resource) |
| 49 self.observer = resourceobserver.FilteredResourceObserver(observer, |
| 50 files) |
| 51 self.objectdb.add_file_list_observer(_FileListObserver(self)) |
| 52 self.project.add_observer(self.observer) |
| 53 |
| 54 def _resource_changed(self, resource): |
| 55 try: |
| 56 self.objectdb.validate_file( |
| 57 self.to_textual.resource_to_path(resource)) |
| 58 except exceptions.ModuleSyntaxError: |
| 59 pass |
| 60 |
| 61 def _resource_moved(self, resource, new_resource=None): |
| 62 self.observer.remove_resource(resource) |
| 63 if new_resource is not None: |
| 64 old = self.to_textual.resource_to_path(resource) |
| 65 new = self.to_textual.resource_to_path(new_resource) |
| 66 self.objectdb.file_moved(old, new) |
| 67 self.observer.add_resource(new_resource) |
| 68 |
| 69 def get_returned(self, pyobject, args): |
| 70 result = self.get_exact_returned(pyobject, args) |
| 71 if result is not None: |
| 72 return result |
| 73 path, key = self._get_scope(pyobject) |
| 74 if path is None: |
| 75 return None |
| 76 for call_info in self.objectdb.get_callinfos(path, key): |
| 77 returned = call_info.get_returned() |
| 78 if returned and returned[0] not in ('unknown', 'none'): |
| 79 result = returned |
| 80 break |
| 81 if result is None: |
| 82 result = returned |
| 83 if result is not None: |
| 84 return self.to_pyobject(result) |
| 85 |
| 86 def get_exact_returned(self, pyobject, args): |
| 87 path, key = self._get_scope(pyobject) |
| 88 if path is not None: |
| 89 returned = self.objectdb.get_returned( |
| 90 path, key, self._args_to_textual(pyobject, args)) |
| 91 if returned is not None: |
| 92 return self.to_pyobject(returned) |
| 93 |
| 94 def _args_to_textual(self, pyfunction, args): |
| 95 parameters = list(pyfunction.get_param_names(special_args=False)) |
| 96 arguments = args.get_arguments(parameters)[:len(parameters)] |
| 97 textual_args = tuple([self.to_textual(arg) |
| 98 for arg in arguments]) |
| 99 return textual_args |
| 100 |
| 101 def get_parameter_objects(self, pyobject): |
| 102 path, key = self._get_scope(pyobject) |
| 103 if path is None: |
| 104 return None |
| 105 arg_count = len(pyobject.get_param_names(special_args=False)) |
| 106 unknowns = arg_count |
| 107 parameters = [None] * arg_count |
| 108 for call_info in self.objectdb.get_callinfos(path, key): |
| 109 args = call_info.get_parameters() |
| 110 for index, arg in enumerate(args[:arg_count]): |
| 111 old = parameters[index] |
| 112 if self.validation.is_more_valid(arg, old): |
| 113 parameters[index] = arg |
| 114 if self.validation.is_value_valid(arg): |
| 115 unknowns -= 1 |
| 116 if unknowns == 0: |
| 117 break |
| 118 if unknowns < arg_count: |
| 119 return [self.to_pyobject(parameter) |
| 120 for parameter in parameters] |
| 121 |
| 122 def get_passed_objects(self, pyfunction, parameter_index): |
| 123 path, key = self._get_scope(pyfunction) |
| 124 if path is None: |
| 125 return [] |
| 126 result = [] |
| 127 for call_info in self.objectdb.get_callinfos(path, key): |
| 128 args = call_info.get_parameters() |
| 129 if len(args) > parameter_index: |
| 130 parameter = self.to_pyobject(args[parameter_index]) |
| 131 if parameter is not None: |
| 132 result.append(parameter) |
| 133 return result |
| 134 |
| 135 def doa_data_received(self, data): |
| 136 def doi_to_normal(textual): |
| 137 pyobject = self.doi_to_pyobject(textual) |
| 138 return self.to_textual(pyobject) |
| 139 function = doi_to_normal(data[0]) |
| 140 args = tuple([doi_to_normal(textual) for textual in data[1]]) |
| 141 returned = doi_to_normal(data[2]) |
| 142 if function[0] == 'defined' and len(function) == 3: |
| 143 self._save_data(function, args, returned) |
| 144 |
| 145 def function_called(self, pyfunction, params, returned=None): |
| 146 function_text = self.to_textual(pyfunction) |
| 147 params_text = tuple([self.to_textual(param) |
| 148 for param in params]) |
| 149 returned_text = ('unknown',) |
| 150 if returned is not None: |
| 151 returned_text = self.to_textual(returned) |
| 152 self._save_data(function_text, params_text, returned_text) |
| 153 |
| 154 def save_per_name(self, scope, name, data): |
| 155 path, key = self._get_scope(scope.pyobject) |
| 156 if path is not None: |
| 157 self.objectdb.add_pername(path, key, name, self.to_textual(data)) |
| 158 |
| 159 def get_per_name(self, scope, name): |
| 160 path, key = self._get_scope(scope.pyobject) |
| 161 if path is not None: |
| 162 result = self.objectdb.get_pername(path, key, name) |
| 163 if result is not None: |
| 164 return self.to_pyobject(result) |
| 165 |
| 166 def _save_data(self, function, args, returned=('unknown',)): |
| 167 self.objectdb.add_callinfo(function[1], function[2], args, returned) |
| 168 |
| 169 def _get_scope(self, pyobject): |
| 170 resource = pyobject.get_module().get_resource() |
| 171 if resource is None: |
| 172 return None, None |
| 173 textual = self.to_textual(pyobject) |
| 174 if textual[0] == 'defined': |
| 175 path = textual[1] |
| 176 if len(textual) == 3: |
| 177 key = textual[2] |
| 178 else: |
| 179 key = '' |
| 180 return path, key |
| 181 return None, None |
| 182 |
| 183 def sync(self): |
| 184 self.objectdb.sync() |
| 185 |
| 186 def __str__(self): |
| 187 return str(self.objectdb) |
| 188 |
| 189 |
| 190 class TextualValidation(object): |
| 191 |
| 192 def __init__(self, to_pyobject): |
| 193 self.to_pyobject = to_pyobject |
| 194 |
| 195 def is_value_valid(self, value): |
| 196 # ???: Should none and unknown be considered valid? |
| 197 if value is None or value[0] in ('none', 'unknown'): |
| 198 return False |
| 199 return self.to_pyobject(value) is not None |
| 200 |
| 201 def is_more_valid(self, new, old): |
| 202 if old is None: |
| 203 return True |
| 204 return new[0] not in ('unknown', 'none') |
| 205 |
| 206 def is_file_valid(self, path): |
| 207 return self.to_pyobject.path_to_resource(path) is not None |
| 208 |
| 209 def is_scope_valid(self, path, key): |
| 210 if key == '': |
| 211 textual = ('defined', path) |
| 212 else: |
| 213 textual = ('defined', path, key) |
| 214 return self.to_pyobject(textual) is not None |
| 215 |
| 216 |
| 217 class _FileListObserver(object): |
| 218 |
| 219 def __init__(self, object_info): |
| 220 self.object_info = object_info |
| 221 self.observer = self.object_info.observer |
| 222 self.to_pyobject = self.object_info.to_pyobject |
| 223 |
| 224 def removed(self, path): |
| 225 resource = self.to_pyobject.path_to_resource(path) |
| 226 if resource is not None: |
| 227 self.observer.remove_resource(resource) |
| 228 |
| 229 def added(self, path): |
| 230 resource = self.to_pyobject.path_to_resource(path) |
| 231 if resource is not None: |
| 232 self.observer.add_resource(resource) |
OLD | NEW |