# HG changeset patch # User Paul Boddie # Date 1481842331 -3600 # Node ID 70d826ac75105374975e9f2cb0e64e4eaec37619 # Parent 79f5d2c374424b2bc29a6eae6faa357668ac36d2 Added a method to test whether an inter-module dependency applies. Expanded and formatted the dependency report when modules cannot be ordered. Reorganised testing for callable references. diff -r 79f5d2c37442 -r 70d826ac7510 deducer.py --- a/deducer.py Thu Dec 15 23:50:05 2016 +0100 +++ b/deducer.py Thu Dec 15 23:52:11 2016 +0100 @@ -671,12 +671,12 @@ else: raise DeduceError("Cannot find module for path %s." % path) - # Identify usage of callables employing dynamic defaults. + # Identify references providing dependencies. for attrtype, objtype, attr in referenced_attrs: - if self.importer.uses_dynamic_callable(attr): + if not attr.unresolved(): provider = self.importer.get_module_provider(attr) - self.importer.add_provider(path, provider) + self.importer.test_dependency(attr, path, provider) def get_referenced_attrs(self, location): diff -r 79f5d2c37442 -r 70d826ac7510 importer.py --- a/importer.py Thu Dec 15 23:50:05 2016 +0100 +++ b/importer.py Thu Dec 15 23:52:11 2016 +0100 @@ -445,18 +445,19 @@ if module.name not in self.required: init_item(self.waiting, module.name, set) self.waiting[module.name].add(provider) + if self.verbose: + print >>sys.stderr, "Noting", provider, "for", ref, "from", module.name # Make this module required in the accessing module. elif provider not in self.required: self.required.add(provider) if self.verbose: - print >>sys.stderr, "Requiring", provider, "for", ref + print >>sys.stderr, "Requiring", provider, "for", ref, "from", module.name # Record a module ordering dependency. - if not found.static() or self.uses_dynamic_callable(found): - self.add_provider(module.name, provider) + self.test_dependency(found, module.name, provider) module.deferred = original_deferred @@ -466,6 +467,16 @@ for module_name in self.waiting.keys(): self.require_providers(module_name) + def test_dependency(self, ref, module_name, provider): + + """ + Test 'ref' for establishing a dependency from 'module_name' to + 'provider'. + """ + + if not ref.static() or self.uses_dynamic_callable(ref): + self.add_provider(module_name, provider) + def add_provider(self, module_name, provider): "Add a dependency for 'module_name' of 'provider'." @@ -488,6 +499,19 @@ print >>sys.stderr, "Requiring", provider self.require_providers(provider) + def uses_callable(self, ref): + + "Return whether 'ref' refers to a callable." + + # Find the function or method associated with the reference. + + if ref.has_kind(""): + return ref.get_origin() + elif ref.has_kind(""): + return "%s.__init__" % ref.get_origin() + else: + return False + def uses_dynamic_callable(self, ref): """ @@ -495,14 +519,12 @@ need initialising before the callable can be used. """ - # Find the function or method associated with the reference. + origin = self.uses_callable(ref) + if not origin: + return False - if ref.has_kind(""): - origin = ref.get_origin() - elif ref.has_kind(""): - origin = "%s.__init__" % ref.get_origin() - else: - return False + if ref.has_kind(""): + return True # Find any defaults for the function or method. @@ -566,10 +588,35 @@ "Check the ordering dependencies." + mutual = set() + + # Get dependency relationships for each module. + for module_name, modules in self.depends.items(): + + # Find the reverse relationship. + for provider in modules: if self.depends.has_key(provider) and module_name in self.depends[provider]: - raise ProgramError, "Modules %s and %s may not depend on each other for non-static objects." % (module_name, provider) + + # Record the module names in order. + + mutual.add((module_name < provider and module_name or provider, + module_name > provider and module_name or provider)) + + if not mutual: + return + + # Format the dependencies. + + mutual = list(mutual) + mutual.sort() + l = [] + + for module_name, provider in mutual: + l.append("(%s <-> %s)" % (module_name, provider)) + + raise ProgramError, "Modules may not depend on each other for non-static objects:\n%s" % "\n".join(l) def find_dependency(self, ref):