# HG changeset patch # User Paul Boddie # Date 1473003879 -7200 # Node ID 7a0fcff254e81a6ca6a704963a338942b1fbb398 # Parent e359ffe6c3fcf02a88e085c42ceac59a1c4073ff Track required modules, either explicitly imported or providing dependencies, as opposed to those providing objects defined elsewhere. diff -r e359ffe6c3fc -r 7a0fcff254e8 importer.py --- a/importer.py Sun Sep 04 00:08:11 2016 +0200 +++ b/importer.py Sun Sep 04 17:44:39 2016 +0200 @@ -51,6 +51,7 @@ self.verbose = verbose self.to_import = set() + self.required = set(["__main__"]) self.modules = {} self.accessing_modules = {} @@ -230,18 +231,22 @@ # Module management. - def queue_module(self, name, module): + def queue_module(self, name, accessor, required=False): """ Queue the module with the given 'name' for import from the given - 'module'. + 'accessor' module. If 'required' is true (it is false by default), the + module will be required in the final program. """ if not self.modules.has_key(name): self.to_import.add(name) + if required: + self.required.add(name) + init_item(self.accessing_modules, name, set) - self.accessing_modules[name].add(module.name) + self.accessing_modules[name].add(accessor.name) def get_modules(self): @@ -285,11 +290,24 @@ self.resolve() + # Record the type of all classes. + + self.type_ref = self.get_object("__builtins__.type") + # Resolve dependencies within the program. for module in self.modules.values(): module.complete() + # Remove unneeded modules. + + all_modules = self.modules.items() + + for name, module in all_modules: + if name not in self.required: + module.unpropagate() + del self.modules[name] + return m def finalise(self): @@ -318,9 +336,15 @@ else: print >>sys.stderr, "Name %s references an unknown object: %s" % (name, ref.get_origin()) + # Record the resolved names and identify required modules. + for name, ref in resolved.items(): self.objects[name] = ref + module_name = self.get_module_provider(ref) + if module_name: + self.required.add(module_name) + def find_dependency(self, ref): "Find the ultimate dependency for 'ref'." @@ -331,6 +355,15 @@ ref = self.objects.get(ref.get_origin()) return ref + def get_module_provider(self, ref): + + "Identify the provider of the given 'ref'." + + for ancestor in ref.ancestors(): + if self.modules.has_key(ancestor): + return ancestor + return None + def finalise_classes(self): "Finalise the class relationships and attributes." @@ -425,9 +458,8 @@ "Set the type of each class." - ref = self.get_object("__builtins__.type") for attrs in self.all_class_attrs.values(): - attrs["__class__"] = ref.get_origin() + attrs["__class__"] = self.type_ref.get_origin() def define_instantiators(self): diff -r e359ffe6c3fc -r 7a0fcff254e8 inspector.py --- a/inspector.py Sun Sep 04 00:08:11 2016 +0200 +++ b/inspector.py Sun Sep 04 17:44:39 2016 +0200 @@ -645,7 +645,7 @@ raise InspectError("Imported modules must be aliased unless a simple module is imported.", path, n) self.set_module(alias or name.split(".")[-1], name) - self.importer.queue_module(name, self) + self.importer.queue_module(name, self, True) def process_invocation_node(self, n): diff -r e359ffe6c3fc -r 7a0fcff254e8 modules.py --- a/modules.py Sun Sep 04 00:08:11 2016 +0200 +++ b/modules.py Sun Sep 04 17:44:39 2016 +0200 @@ -20,7 +20,7 @@ this program. If not, see . """ -from common import init_item, CommonModule +from common import init_item, remove_items, CommonModule from encoders import decode_modifier_term, encode_modifiers, encode_usage from referencing import decode_reference, Reference from results import ResolvedNameRef @@ -119,7 +119,6 @@ for name in self.classes.keys(): del self.importer.all_class_attrs[name] del self.importer.all_instance_attrs[name] - del self.importer.all_combined_attrs[name] del self.importer.all_instance_attr_constants[name] for name, bases in self.classes.items(): @@ -147,9 +146,7 @@ # automatically propagated when defined. for name, ref in self.objects.items(): - if ref.provided_by_module(self.name) or name in self.importer.hidden: - if ref.get_kind() != "": - del self.importer.objects[name] + del self.importer.objects[name] def propagate_attrs(self): diff -r e359ffe6c3fc -r 7a0fcff254e8 referencing.py --- a/referencing.py Sun Sep 04 00:08:11 2016 +0200 +++ b/referencing.py Sun Sep 04 17:44:39 2016 +0200 @@ -131,19 +131,30 @@ return Reference("", None, self.name) - def provided_by_module(self, module_name): - - "Return whether the reference is provided by 'module_name'." - - path = self.origin - return not path or path.rsplit(".", 1)[0] == module_name - def alias(self, name): "Alias this reference employing 'name'." return Reference(self.get_kind(), self.get_origin(), name) + def ancestors(self): + + """ + Return ancestors of this reference's origin in order of decreasing + depth. + """ + + if not self.origin: + return None + + parts = self.get_origin().split(".") + ancestors = [] + + for i in range(len(parts) - 1, 0, -1): + ancestors.append(".".join(parts[:i])) + + return ancestors + def decode_reference(s, name=None): "Decode 's', making a reference."