def _determine_clashing_namespaces(self, py_namespaces_by_target): """Check for any overlapping namespaces.""" namespaces_by_files = defaultdict(list) for target, all_namespaces in py_namespaces_by_target.items(): for (path, namespace) in all_namespaces: namespaces_by_files[namespace].append((target, path)) clashing_namespaces = { namespace: all_paths for namespace, all_paths in namespaces_by_files.items() if len(all_paths) > 1 } if clashing_namespaces: pretty_printed_clashing = '\n'.join( '{}: [{}]'.format( namespace, ', '.join( '({}, {})'.format(t.address.spec, path) for (t, path) in all_paths)) for namespace, all_paths in clashing_namespaces.items()) error = self.ClashingNamespaceError("""\ Clashing namespaces for python thrift library sources detected in build graph. This will silently overwrite previously generated python sources with generated sources from thrift files declaring the same python namespace. This is an upstream WONTFIX in thrift, see: https://issues.apache.org/jira/browse/THRIFT-515 Errors: {} """.format(pretty_printed_clashing)) if self.get_options().strict: raise error else: self.context.log.warn(str(error)) return namespaces_by_files
def _extract_all_python_namespaces(self, thrift_file_sources_by_target): """Extract the python namespace from each thrift source file.""" py_namespaces_by_target = OrderedDict() failing_py_thrift_by_target = defaultdict(list) for t, all_content in thrift_file_sources_by_target.items(): py_namespaces_by_target[t] = [] for (path, content) in all_content: try: py_namespaces_by_target[t].append( # File content is provided as a binary string, so we have to decode it. (path, self._extract_py_namespace_from_content( t, path, content.decode('utf-8')))) except self.NamespaceParseFailure: failing_py_thrift_by_target[t].append(path) if failing_py_thrift_by_target: # We dump the output to a file here because the output can be very long in some repos. no_py_namespace_output_file = os.path.join( self.workdir, 'no-python-namespace-output.txt') pretty_printed_failures = '\n'.join( '{}: [{}]'.format(t.address.spec, ', '.join(paths)) for t, paths in failing_py_thrift_by_target.items()) error = self.NamespaceExtractionError( no_py_namespace_output_file, """\ Python namespaces could not be extracted from some thrift sources. Declaring a `namespace py` in thrift sources for python thrift library targets will soon become required. {} python library target(s) contained thrift sources not declaring a python namespace. The targets and/or files which need to be edited will be dumped to: {} """.format(len(failing_py_thrift_by_target), no_py_namespace_output_file)) safe_file_dump(no_py_namespace_output_file, '{}\n'.format(pretty_printed_failures), mode='w') if self.get_options().strict: raise error else: self.context.log.warn(error) return py_namespaces_by_target