def testGetTypeIncludedRef(self): manager = CppTypeGenerator('', self.windows, self.windows.unix_name) manager.AddNamespace(self.tabs, self.tabs.unix_name) self.assertEquals( 'std::vector<linked_ptr<tabs::Tab> >', manager.GetType( self.windows.types['windows.Window'].properties['tabs']))
def testGenerateIncludesAndForwardDeclarationsMultipleTypes(self): m = model.Model() self.tabs_json[0]['types'].append(self.permissions_json[0]['types'][0]) self.windows_json[0]['functions'].append( self.permissions_json[0]['functions'][1]) # Insert 'windows' before 'tabs' in order to test that they are sorted # properly. windows = m.AddNamespace(self.windows_json[0], 'path/to/windows.json') tabs_namespace = m.AddNamespace(self.tabs_json[0], 'path/to/tabs.json') manager = CppTypeGenerator('', windows, self.windows.unix_name) manager.AddNamespace(tabs_namespace, self.tabs.unix_name) self.assertEquals('#include "path/to/tabs.h"\n' '#include "base/string_number_conversions.h"\n' '#include "base/json/json_writer.h"', manager.GenerateIncludes().Render()) self.assertEquals('namespace tabs {\n' 'struct Permissions;\n' 'struct Tab;\n' '}\n' 'namespace windows {\n' 'struct Window;\n' '} // windows', manager.GenerateForwardDeclarations().Render())
def testStringAsType(self): manager = CppTypeGenerator('', self.font_settings, self.font_settings.unix_name) self.assertEquals( 'std::string', manager.GetType( self.font_settings.types['fontSettings.FakeStringType']))
def testGetCppTypeLocalRef(self): manager = CppTypeGenerator(self.models.get('tabs'), _FakeSchemaLoader(None)) self.assertEquals( 'Tab', manager.GetCppType( self.tabs.functions['get'].callback.params[0].type_))
def testArrayAsType(self): manager = CppTypeGenerator('', self.browser_action, self.browser_action.unix_name) self.assertEquals( 'std::vector<int>', manager.GetType( self.browser_action.types['browserAction.ColorArray']))
def testExpandParams(self): manager = CppTypeGenerator('extensions', self.tabs, self.tabs.unix_name) props = self.tabs.functions['move'].params self.assertEquals(2, len(props)) self.assertEquals(['move_properties', 'tab_ids_array', 'tab_ids_integer'], sorted([x.unix_name for x in manager.ExpandParams(props)]) )
def testChoicesEnum(self): manager = CppTypeGenerator('', self.tabs, self.tabs.unix_name) prop = self.tabs.functions['move'].params[0] self.assertEquals('TAB_IDS_ARRAY', manager.GetEnumValue(prop, model.PropertyType.ARRAY.name)) self.assertEquals('TAB_IDS_INTEGER', manager.GetEnumValue(prop, model.PropertyType.INTEGER.name)) self.assertEquals('TabIdsType', manager.GetChoicesEnumType(prop))
def testGetCppTypeIncludedRef(self): m = model.Model() m.AddNamespace(self.windows_json[0], 'path/to/windows.json') m.AddNamespace(self.tabs_json[0], 'path/to/tabs.json') manager = CppTypeGenerator(m, _FakeSchemaLoader(m)) self.assertEquals( 'std::vector<linked_ptr<tabs::Tab> >', manager.GetCppType( self.windows.types['Window'].properties['tabs'].type_))
def testGetTypeSimple(self): manager = CppTypeGenerator('', self.tabs, self.tabs.unix_name) self.assertEquals( 'int', manager.GetType(self.tabs.types['Tab'].properties['id'])) self.assertEquals( 'std::string', manager.GetType(self.tabs.types['Tab'].properties['status'])) self.assertEquals( 'bool', manager.GetType(self.tabs.types['Tab'].properties['selected']))
def testGetTypeWithPadForGeneric(self): manager = CppTypeGenerator('', self.permissions, self.permissions.unix_name) self.assertEquals('std::vector<std::string> ', manager.GetType( self.permissions.types['Permissions'].properties['origins'], pad_for_generics=True)) self.assertEquals('bool', manager.GetType( self.permissions.functions['contains'].callback.params[0], pad_for_generics=True))
def testGetCppTypeSimple(self): manager = CppTypeGenerator(self.models.get('tabs'), _FakeSchemaLoader(None)) self.assertEquals( 'int', manager.GetCppType(self.tabs.types['Tab'].properties['id'].type_)) self.assertEquals( 'std::string', manager.GetCppType(self.tabs.types['Tab'].properties['status'].type_)) self.assertEquals( 'bool', manager.GetCppType(self.tabs.types['Tab'].properties['selected'].type_))
def testGetCppTypeIncludedRef(self): m = model.Model() m.AddNamespace(self.windows_json[0], 'path/to/windows.json', environment=CppNamespaceEnvironment('%(namespace)s')) m.AddNamespace(self.tabs_json[0], 'path/to/tabs.json', environment=CppNamespaceEnvironment('%(namespace)s')) manager = CppTypeGenerator(m, _FakeSchemaLoader(m)) self.assertEqual( 'std::vector<tabs::Tab>', manager.GetCppType( self.windows.types['Window'].properties['tabs'].type_))
def testGetCppTypeWithPadForGeneric(self): manager = CppTypeGenerator(self.models.get('permissions'), _FakeSchemaLoader(None)) self.assertEquals('std::vector<std::string>', manager.GetCppType( self.permissions.types['Permissions'].properties['origins'].type_, is_in_container=False)) self.assertEquals('linked_ptr<std::vector<std::string> >', manager.GetCppType( self.permissions.types['Permissions'].properties['origins'].type_, is_in_container=True)) self.assertEquals('bool', manager.GetCppType( self.permissions.functions['contains'].callback.params[0].type_, is_in_container=True))
def testGenerateIncludesAndForwardDeclarationsDependencies(self): m = model.Model() # Insert 'font_settings' before 'browser_action' in order to test that # CppTypeGenerator sorts them properly. m.AddNamespace(self.font_settings_json[0], 'path/to/font_settings.json') m.AddNamespace(self.browser_action_json[0], 'path/to/browser_action.json') dependency_tester = m.AddNamespace(self.dependency_tester_json[0], 'path/to/dependency_tester.json') manager = CppTypeGenerator(m, _FakeSchemaLoader(m), default_namespace=dependency_tester) self.assertEquals('#include "path/to/browser_action.h"\n' '#include "path/to/font_settings.h"', manager.GenerateIncludes().Render()) self.assertEquals('', manager.GenerateForwardDeclarations().Render())
def testHardIncludesForEnumArrays(self): """Tests that enums in arrays generate hard includes. Note that it's important to use a separate file (cross_enums_array) here to isolate the test case so that other types don't cause the hard-dependency. """ m = model.Model() m.AddNamespace(self.crossref_enums_json[0], 'path/to/crossref_enums_array.json', environment=CppNamespaceEnvironment('%(namespace)s')) m.AddNamespace(self.simple_api_json[0], 'path/to/simple_api.json', environment=CppNamespaceEnvironment('%(namespace)s')) manager = CppTypeGenerator(self.models.get('crossref_enums_array'), _FakeSchemaLoader(m)) self.assertEquals('#include "path/to/simple_api.h"', manager.GenerateIncludes().Render())
def testGetAllPossibleParameterLists(self): manager = CppTypeGenerator('extensions', self.tabs, self.tabs.unix_name) props = self.forbidden.functions['forbiddenParameters'].params self.assertEquals(4, len(props)) param_lists = manager.GetAllPossibleParameterLists(props) expected_lists = [ ['first_choice_array', 'first_string', 'second_choice_array', 'second_string'], ['first_choice_array', 'first_string', 'second_choice_integer', 'second_string'], ['first_choice_integer', 'first_string', 'second_choice_array', 'second_string'], ['first_choice_integer', 'first_string', 'second_choice_integer', 'second_string']] result_lists = sorted([[param.unix_name for param in param_list] for param_list in param_lists]) self.assertEquals(expected_lists, result_lists)
def testGenerateIncludesAndForwardDeclarationsMultipleTypes(self): m = model.Model() self.tabs_json[0]['types'].append(self.permissions_json[0]['types'][0]) tabs_namespace = m.AddNamespace(self.tabs_json[0], 'path/to/tabs.json') self.windows_json[0]['functions'].append( self.permissions_json[0]['functions'][1]) windows = m.AddNamespace(self.windows_json[0], 'path/to/windows.json') manager = CppTypeGenerator('', windows, self.windows.unix_name) manager.AddNamespace(tabs_namespace, self.tabs.unix_name) self.assertEquals('#include "path/to/tabs.h"', manager.GenerateIncludes().Render()) self.assertEquals( 'namespace tabs {\n' 'struct Tab;\n' 'struct Permissions;\n' '}\n' 'namespace windows {\n' 'struct Window;\n' '} // windows', manager.GenerateForwardDeclarations().Render())
def testGenerateIncludesAndForwardDeclarationsDependencies(self): m = model.Model() browser_action_namespace = m.AddNamespace( self.browser_action_json[0], 'path/to/browserAction.json') font_settings_namespace = m.AddNamespace(self.font_settings_json[0], 'path/to/fontSettings.json') manager = CppTypeGenerator('', self.dependency_tester, self.dependency_tester.unix_name) manager.AddNamespace(browser_action_namespace, self.browser_action.unix_name) manager.AddNamespace(font_settings_namespace, self.font_settings.unix_name) self.assertEquals( '#include "path/to/browser_action.h"\n' '#include "path/to/font_settings.h"', manager.GenerateIncludes().Render()) self.assertEquals( 'namespace browserAction {\n' 'typedef std::vector<int> ColorArray;\n' '}\n' 'namespace fontSettings {\n' 'typedef std::string ScriptCode;\n' '}\n' 'namespace dependency_tester {\n' '} // dependency_tester', manager.GenerateForwardDeclarations().Render())
def testGenerateIncludesAndForwardDeclarationsDependencies(self): m = model.Model() # Insert 'font_settings' before 'browser_action' in order to test that # CppTypeGenerator sorts them properly. font_settings_namespace = m.AddNamespace(self.font_settings_json[0], 'path/to/font_settings.json') browser_action_namespace = m.AddNamespace(self.browser_action_json[0], 'path/to/browser_action.json') manager = CppTypeGenerator('', self.dependency_tester, self.dependency_tester.unix_name) manager.AddNamespace(font_settings_namespace, self.font_settings.unix_name) manager.AddNamespace(browser_action_namespace, self.browser_action.unix_name) self.assertEquals('#include "path/to/browser_action.h"\n' '#include "path/to/font_settings.h"\n' '#include "base/string_number_conversions.h"', manager.GenerateIncludes().Render()) self.assertEquals('namespace browserAction {\n' 'typedef std::vector<int> ColorArray;\n' '}\n' 'namespace fontSettings {\n' 'typedef std::string FakeStringType;\n' '}\n' 'namespace dependency_tester {\n' '} // dependency_tester', manager.GenerateForwardDeclarations().Render())
def testGetTypeArray(self): manager = CppTypeGenerator('', self.windows, self.windows.unix_name) self.assertEquals( 'std::vector<linked_ptr<Window> >', manager.GetType(self.windows.functions['getAll'].callback.params[0])) manager = CppTypeGenerator('', self.permissions, self.permissions.unix_name) self.assertEquals('std::vector<std::string>', manager.GetType( self.permissions.types['permissions.Permissions'].properties['origins']))
def testGenerateIncludesAndForwardDeclarations(self): manager = CppTypeGenerator('', self.windows, self.windows.unix_name) manager.AddNamespace(self.tabs, self.tabs.unix_name) self.assertEquals('#include "path/to/tabs.h"', manager.GenerateIncludes().Render()) self.assertEquals( 'namespace tabs {\n' 'struct Tab;\n' '}\n' 'namespace windows {\n' 'struct Window;\n' '} // windows', manager.GenerateForwardDeclarations().Render()) manager = CppTypeGenerator('', self.permissions, self.permissions.unix_name) self.assertEquals('', manager.GenerateIncludes().Render()) self.assertEquals('namespace permissions {\n' 'struct Permissions;\n' '} // permissions', manager.GenerateForwardDeclarations().Render())
def testNamespaceDeclaration(self): manager = CppTypeGenerator('extensions', self.permissions, self.permissions.unix_name) self.assertEquals('namespace extensions {', manager.GetRootNamespaceStart().Render()) manager = CppTypeGenerator('extensions::gen::api', self.permissions, self.permissions.unix_name) self.assertEquals('namespace permissions {', manager.GetNamespaceStart().Render()) self.assertEquals('} // permissions', manager.GetNamespaceEnd().Render()) self.assertEquals('namespace extensions {\n' 'namespace gen {\n' 'namespace api {', manager.GetRootNamespaceStart().Render()) self.assertEquals('} // api\n' '} // gen\n' '} // extensions', manager.GetRootNamespaceEnd().Render())
def testGetCppTypeArray(self): manager = CppTypeGenerator(self.models.get('windows'), _FakeSchemaLoader(None)) self.assertEquals( 'std::vector<Window>', manager.GetCppType( self.windows.functions['getAll'].callback.params[0].type_)) manager = CppTypeGenerator(self.models.get('permissions'), _FakeSchemaLoader(None)) self.assertEquals( 'std::vector<std::string>', manager.GetCppType(self.permissions.types['Permissions']. properties['origins'].type_)) manager = CppTypeGenerator(self.models.get('objects_movable'), _FakeSchemaLoader(None)) self.assertEquals( 'std::vector<MovablePod>', manager.GetCppType(self.objects_movable.types['MovableParent']. properties['pods'].type_))
def testGenerateIncludesAndForwardDeclarations(self): m = model.Model() m.AddNamespace(self.windows_json[0], 'path/to/windows.json', environment=CppNamespaceEnvironment('%(namespace)s')) m.AddNamespace(self.tabs_json[0], 'path/to/tabs.json', environment=CppNamespaceEnvironment('%(namespace)s')) manager = CppTypeGenerator(m, _FakeSchemaLoader(m)) self.assertEquals('', manager.GenerateIncludes().Render()) self.assertEquals('#include "path/to/tabs.h"', manager.GenerateIncludes(include_soft=True).Render()) self.assertEquals( 'namespace tabs {\n' 'struct Tab;\n' '} // namespace tabs', manager.GenerateForwardDeclarations().Render()) m = model.Model() m.AddNamespace( self.windows_json[0], 'path/to/windows.json', environment=CppNamespaceEnvironment('foo::bar::%(namespace)s')) m.AddNamespace( self.tabs_json[0], 'path/to/tabs.json', environment=CppNamespaceEnvironment('foo::bar::%(namespace)s')) manager = CppTypeGenerator(m, _FakeSchemaLoader(m)) self.assertEquals( 'namespace foo {\n' 'namespace bar {\n' 'namespace tabs {\n' 'struct Tab;\n' '} // namespace tabs\n' '} // namespace bar\n' '} // namespace foo', manager.GenerateForwardDeclarations().Render()) manager = CppTypeGenerator(self.models.get('permissions'), _FakeSchemaLoader(m)) self.assertEquals('', manager.GenerateIncludes().Render()) self.assertEquals('', manager.GenerateIncludes().Render()) self.assertEquals('', manager.GenerateForwardDeclarations().Render()) manager = CppTypeGenerator(self.models.get('content_settings'), _FakeSchemaLoader(m)) self.assertEquals('', manager.GenerateIncludes().Render())
def testGetTypeNotimplemented(self): prop = self.windows.types['Window'].properties['tabs'].item_type prop.type_ = 10 manager = CppTypeGenerator('', self.windows, self.windows.unix_name) self.assertRaises(NotImplementedError, manager.GetType, prop)
def testArrayAsType(self): manager = CppTypeGenerator(self.models.get('browser_action'), _FakeSchemaLoader(None)) self.assertEquals( 'std::vector<int>', manager.GetCppType(self.browser_action.types['ColorArray']))
def testStringAsType(self): manager = CppTypeGenerator(self.models.get('font_settings'), _FakeSchemaLoader(None)) self.assertEquals( 'std::string', manager.GetCppType(self.font_settings.types['FakeStringType']))
def GenerateSchema(generator, filenames, root, destdir, root_namespace, dart_overrides_dir, impl_dir): # Merge the source files into a single list of schemas. api_defs = [] for filename in filenames: schema = os.path.normpath(filename) schema_loader = SchemaLoader( os.path.dirname(os.path.relpath(os.path.normpath(filename), root)), os.path.dirname(filename)) api_def = schema_loader.LoadSchema(os.path.split(schema)[1]) # If compiling the C++ model code, delete 'nocompile' nodes. if generator == 'cpp': api_def = json_schema.DeleteNodes(api_def, 'nocompile') api_defs.extend(api_def) api_model = Model() # For single-schema compilation make sure that the first (i.e. only) schema # is the default one. default_namespace = None # If we have files from multiple source paths, we'll use the common parent # path as the source directory. src_path = None # Load the actual namespaces into the model. for target_namespace, schema_filename in zip(api_defs, filenames): relpath = os.path.relpath(os.path.normpath(schema_filename), root) namespace = api_model.AddNamespace(target_namespace, relpath, include_compiler_options=True) if default_namespace is None: default_namespace = namespace if src_path is None: src_path = namespace.source_file_dir else: src_path = os.path.commonprefix( (src_path, namespace.source_file_dir)) path, filename = os.path.split(schema_filename) short_filename, extension = os.path.splitext(filename) # Construct the type generator with all the namespaces in this model. type_generator = CppTypeGenerator(api_model, schema_loader, default_namespace=default_namespace) if generator == 'cpp-bundle': cpp_bundle_generator = CppBundleGenerator(root, api_model, api_defs, type_generator, root_namespace, src_path, impl_dir) generators = [ ('generated_api.cc', cpp_bundle_generator.api_cc_generator), ('generated_api.h', cpp_bundle_generator.api_h_generator), ('generated_schemas.cc', cpp_bundle_generator.schemas_cc_generator), ('generated_schemas.h', cpp_bundle_generator.schemas_h_generator) ] elif generator == 'cpp': cpp_generator = CppGenerator(type_generator, root_namespace) generators = [('%s.h' % short_filename, cpp_generator.h_generator), ('%s.cc' % short_filename, cpp_generator.cc_generator)] elif generator == 'dart': generators = [('%s.dart' % namespace.unix_name, DartGenerator(dart_overrides_dir))] elif generator == 'ppapi': generator = PpapiGenerator() generators = [ (os.path.join('api', 'ppb_%s.idl' % namespace.unix_name), generator.idl_generator), ] else: raise Exception('Unrecognised generator %s' % generator) output_code = [] for filename, generator in generators: code = generator.Generate(namespace).Render() if destdir: output_dir = os.path.join(destdir, src_path) if not os.path.exists(output_dir): os.makedirs(output_dir) with open(os.path.join(output_dir, filename), 'w') as f: f.write(code) output_code += [filename, '', code, ''] return '\n'.join(output_code)
def GenerateSchema(generator, filenames, root, destdir, root_namespace, dart_overrides_dir): schema_loader = SchemaLoader( os.path.dirname(os.path.relpath(os.path.normpath(filenames[0]), root)), os.path.dirname(filenames[0])) # Merge the source files into a single list of schemas. api_defs = [] for filename in filenames: schema = os.path.normpath(filename) api_def = schema_loader.LoadSchema(os.path.split(schema)[1]) # If compiling the C++ model code, delete 'nocompile' nodes. if generator == 'cpp': api_def = json_schema.DeleteNodes(api_def, 'nocompile') api_defs.extend(api_def) api_model = Model() # For single-schema compilation make sure that the first (i.e. only) schema # is the default one. default_namespace = None # Load the actual namespaces into the model. for target_namespace, schema_filename in zip(api_defs, filenames): relpath = os.path.relpath(os.path.normpath(schema_filename), root) namespace = api_model.AddNamespace(target_namespace, relpath, include_compiler_options=True) if default_namespace is None: default_namespace = namespace path, filename = os.path.split(schema_filename) short_filename, extension = os.path.splitext(filename) # Filenames are checked against the unix_names of the namespaces they # generate because the gyp uses the names of the JSON files to generate # the names of the .cc and .h files. We want these to be using unix_names. if namespace.unix_name != short_filename: sys.exit( "Filename %s is illegal. Name files using unix_hacker style." % schema_filename) # Construct the type generator with all the namespaces in this model. type_generator = CppTypeGenerator(api_model, schema_loader, default_namespace=default_namespace) if generator == 'cpp-bundle': cpp_bundle_generator = CppBundleGenerator(root, api_model, api_defs, type_generator, root_namespace) generators = [ ('generated_api.cc', cpp_bundle_generator.api_cc_generator), ('generated_api.h', cpp_bundle_generator.api_h_generator), ('generated_schemas.cc', cpp_bundle_generator.schemas_cc_generator), ('generated_schemas.h', cpp_bundle_generator.schemas_h_generator) ] elif generator == 'cpp': cpp_generator = CppGenerator(type_generator, root_namespace) generators = [ ('%s.h' % namespace.unix_name, cpp_generator.h_generator), ('%s.cc' % namespace.unix_name, cpp_generator.cc_generator) ] elif generator == 'dart': generators = [('%s.dart' % namespace.unix_name, DartGenerator(dart_overrides_dir))] else: raise Exception('Unrecognised generator %s' % generator) output_code = [] for filename, generator in generators: code = generator.Generate(namespace).Render() if destdir: with open( os.path.join(destdir, namespace.source_file_dir, filename), 'w') as f: f.write(code) output_code += [filename, '', code, ''] return '\n'.join(output_code)
def GenerateSchema(generator_name, file_paths, root, destdir, cpp_namespace_pattern, bundle_name, impl_dir, include_rules): # Merge the source files into a single list of schemas. api_defs = [] for file_path in file_paths: schema = os.path.relpath(file_path, root) api_def = SchemaLoader(root).LoadSchema(schema) # If compiling the C++ model code, delete 'nocompile' nodes. if generator_name == 'cpp': api_def = json_schema.DeleteNodes(api_def, 'nocompile') # Delete all 'nodefine' nodes. They are only for documentation. api_def = json_schema.DeleteNodes(api_def, 'nodefine') api_defs.extend(api_def) api_model = Model(allow_inline_enums=False) # For single-schema compilation make sure that the first (i.e. only) schema # is the default one. default_namespace = None # If we have files from multiple source paths, we'll use the common parent # path as the source directory. src_path = None # Load the actual namespaces into the model. for target_namespace, file_path in zip(api_defs, file_paths): relpath = os.path.relpath(os.path.normpath(file_path), root) namespace = api_model.AddNamespace(target_namespace, relpath, include_compiler_options=True, environment=CppNamespaceEnvironment( cpp_namespace_pattern)) if default_namespace is None: default_namespace = namespace if src_path is None: src_path = namespace.source_file_dir else: src_path = os.path.commonprefix((src_path, namespace.source_file_dir)) _, filename = os.path.split(file_path) filename_base, _ = os.path.splitext(filename) # Construct the type generator with all the namespaces in this model. schema_dir = os.path.dirname(os.path.relpath(file_paths[0], root)) namespace_resolver = NamespaceResolver(root, schema_dir, include_rules, cpp_namespace_pattern) type_generator = CppTypeGenerator(api_model, namespace_resolver, default_namespace) if generator_name in ('cpp-bundle-registration', 'cpp-bundle-schema'): cpp_bundle_generator = CppBundleGenerator(root, api_model, api_defs, type_generator, cpp_namespace_pattern, bundle_name, src_path, impl_dir) if generator_name == 'cpp-bundle-registration': generators = [ ('generated_api_registration.cc', cpp_bundle_generator.api_cc_generator), ('generated_api_registration.h', cpp_bundle_generator.api_h_generator), ] elif generator_name == 'cpp-bundle-schema': generators = [ ('generated_schemas.cc', cpp_bundle_generator.schemas_cc_generator), ('generated_schemas.h', cpp_bundle_generator.schemas_h_generator) ] elif generator_name == 'cpp': cpp_generator = CppGenerator(type_generator) generators = [ ('%s.h' % filename_base, cpp_generator.h_generator), ('%s.cc' % filename_base, cpp_generator.cc_generator) ] elif generator_name == 'externs': generators = [ ('%s_externs.js' % namespace.unix_name, JsExternsGenerator()) ] elif generator_name == 'interface': generators = [ ('%s_interface.js' % namespace.unix_name, JsInterfaceGenerator()) ] else: raise Exception('Unrecognised generator %s' % generator_name) output_code = [] for filename, generator in generators: code = generator.Generate(namespace).Render() if destdir: if generator_name == 'cpp-bundle-registration': # Function registrations must be output to impl_dir, since they link in # API implementations. output_dir = os.path.join(destdir, impl_dir) else: output_dir = os.path.join(destdir, src_path) if not os.path.exists(output_dir): os.makedirs(output_dir) with open(os.path.join(output_dir, filename), 'w') as f: f.write(code) # If multiple files are being output, add the filename for each file. if len(generators) > 1: output_code += [filename, '', code, ''] else: output_code += [code] return '\n'.join(output_code)