1.1 --- a/deducer.py Thu Dec 15 23:50:05 2016 +0100
1.2 +++ b/deducer.py Thu Dec 15 23:52:11 2016 +0100
1.3 @@ -671,12 +671,12 @@
1.4 else:
1.5 raise DeduceError("Cannot find module for path %s." % path)
1.6
1.7 - # Identify usage of callables employing dynamic defaults.
1.8 + # Identify references providing dependencies.
1.9
1.10 for attrtype, objtype, attr in referenced_attrs:
1.11 - if self.importer.uses_dynamic_callable(attr):
1.12 + if not attr.unresolved():
1.13 provider = self.importer.get_module_provider(attr)
1.14 - self.importer.add_provider(path, provider)
1.15 + self.importer.test_dependency(attr, path, provider)
1.16
1.17 def get_referenced_attrs(self, location):
1.18
2.1 --- a/importer.py Thu Dec 15 23:50:05 2016 +0100
2.2 +++ b/importer.py Thu Dec 15 23:52:11 2016 +0100
2.3 @@ -445,18 +445,19 @@
2.4 if module.name not in self.required:
2.5 init_item(self.waiting, module.name, set)
2.6 self.waiting[module.name].add(provider)
2.7 + if self.verbose:
2.8 + print >>sys.stderr, "Noting", provider, "for", ref, "from", module.name
2.9
2.10 # Make this module required in the accessing module.
2.11
2.12 elif provider not in self.required:
2.13 self.required.add(provider)
2.14 if self.verbose:
2.15 - print >>sys.stderr, "Requiring", provider, "for", ref
2.16 + print >>sys.stderr, "Requiring", provider, "for", ref, "from", module.name
2.17
2.18 # Record a module ordering dependency.
2.19
2.20 - if not found.static() or self.uses_dynamic_callable(found):
2.21 - self.add_provider(module.name, provider)
2.22 + self.test_dependency(found, module.name, provider)
2.23
2.24 module.deferred = original_deferred
2.25
2.26 @@ -466,6 +467,16 @@
2.27 for module_name in self.waiting.keys():
2.28 self.require_providers(module_name)
2.29
2.30 + def test_dependency(self, ref, module_name, provider):
2.31 +
2.32 + """
2.33 + Test 'ref' for establishing a dependency from 'module_name' to
2.34 + 'provider'.
2.35 + """
2.36 +
2.37 + if not ref.static() or self.uses_dynamic_callable(ref):
2.38 + self.add_provider(module_name, provider)
2.39 +
2.40 def add_provider(self, module_name, provider):
2.41
2.42 "Add a dependency for 'module_name' of 'provider'."
2.43 @@ -488,6 +499,19 @@
2.44 print >>sys.stderr, "Requiring", provider
2.45 self.require_providers(provider)
2.46
2.47 + def uses_callable(self, ref):
2.48 +
2.49 + "Return whether 'ref' refers to a callable."
2.50 +
2.51 + # Find the function or method associated with the reference.
2.52 +
2.53 + if ref.has_kind("<function>"):
2.54 + return ref.get_origin()
2.55 + elif ref.has_kind("<class>"):
2.56 + return "%s.__init__" % ref.get_origin()
2.57 + else:
2.58 + return False
2.59 +
2.60 def uses_dynamic_callable(self, ref):
2.61
2.62 """
2.63 @@ -495,14 +519,12 @@
2.64 need initialising before the callable can be used.
2.65 """
2.66
2.67 - # Find the function or method associated with the reference.
2.68 + origin = self.uses_callable(ref)
2.69 + if not origin:
2.70 + return False
2.71
2.72 - if ref.has_kind("<function>"):
2.73 - origin = ref.get_origin()
2.74 - elif ref.has_kind("<class>"):
2.75 - origin = "%s.__init__" % ref.get_origin()
2.76 - else:
2.77 - return False
2.78 + if ref.has_kind("<class>"):
2.79 + return True
2.80
2.81 # Find any defaults for the function or method.
2.82
2.83 @@ -566,10 +588,35 @@
2.84
2.85 "Check the ordering dependencies."
2.86
2.87 + mutual = set()
2.88 +
2.89 + # Get dependency relationships for each module.
2.90 +
2.91 for module_name, modules in self.depends.items():
2.92 +
2.93 + # Find the reverse relationship.
2.94 +
2.95 for provider in modules:
2.96 if self.depends.has_key(provider) and module_name in self.depends[provider]:
2.97 - raise ProgramError, "Modules %s and %s may not depend on each other for non-static objects." % (module_name, provider)
2.98 +
2.99 + # Record the module names in order.
2.100 +
2.101 + mutual.add((module_name < provider and module_name or provider,
2.102 + module_name > provider and module_name or provider))
2.103 +
2.104 + if not mutual:
2.105 + return
2.106 +
2.107 + # Format the dependencies.
2.108 +
2.109 + mutual = list(mutual)
2.110 + mutual.sort()
2.111 + l = []
2.112 +
2.113 + for module_name, provider in mutual:
2.114 + l.append("(%s <-> %s)" % (module_name, provider))
2.115 +
2.116 + raise ProgramError, "Modules may not depend on each other for non-static objects:\n%s" % "\n".join(l)
2.117
2.118 def find_dependency(self, ref):
2.119