def get_device_test_summary(devicetype=None, include_failed=False, session=None): projectfolder = projects.cards[devicetype] bomobj = import_pcb(cardfolder=projectfolder) bomobj.configure_motifs(devicetype) logger.info("Creating dummy test suites") dummy_suites = get_electronics_test_suites(None, devicetype, projectfolder, offline=True, dummy=True) collector = ResultCollector(dummy_suites, include_failed=include_failed) snos = sno_controller.get_serialnos_by_efield(efield=devicetype, session=session) for sno in snos: suites = get_test_suite_objects(serialno=sno.sno, session=session) if len(suites) > 0: collector.add_suites_set(suites) return collector
def gen_cobom_csv(projfolder, namebase, force=False): """ Generates a CSV file in the :mod:`tendril.boms.outputbase.CompositeOutputBom` format, including the BOMs of the all the defined configurations of the project. This function uses a :mod:`csv.writer` instead of rendering a jinja2 template. It also generates configdocs for all the defined configurations of the project, using :func:`gen_confpdf`. :param projfolder: The gEDA project folder. :type projfolder: str :param namebase: The project name. :type namebase: str :param force: Regenerate even if up-to-date. :type force: bool :return: The output file path. .. rubric:: Paths * Output Files : ``<project_doc_folder>/confdocs/conf_boms.csv`` * Also triggers : :func:`gen_confpdf` for all listed configurations. * Source Files : The project's schematic folder. """ gpf = projfile.GedaProjectFile(projfolder) configfile = conffile.ConfigsFile(projfolder) sch_mtime = fsutils.get_folder_mtime(gpf.configsfile.schfolder) docfolder = get_project_doc_folder(projfolder) cobom_csv_path = path.join(docfolder, 'confdocs', 'conf-boms.csv') outf_mtime = fsutils.get_file_mtime(cobom_csv_path, fs=refdoc_fs) if not force and outf_mtime is not None and outf_mtime > sch_mtime: logger.debug('Skipping up-to-date ' + cobom_csv_path) return cobom_csv_path logger.info('Regenerating ' + cobom_csv_path + os.linesep + 'Last modified : ' + str(sch_mtime) + '; Last Created : ' + str(outf_mtime)) bomlist = [] for cfn in configfile.configuration_names: gen_confpdf(projfolder, cfn, namebase, force=force) lbom = boms_electronics.import_pcb(projfolder) lobom = lbom.create_output_bom(cfn) bomlist.append(lobom) cobom = boms_outputbase.CompositeOutputBom(bomlist) with refdoc_fs.open(cobom_csv_path, 'wb') as f: writer = csv.writer(f) writer.writerow(['device'] + [x.configname for x in cobom.descriptors]) for line in cobom.lines: writer.writerow([line.ident] + line.columns)
def gen_cobom_csv(projfolder, namebase, force=False): """ Generates a CSV file in the :mod:`tendril.boms.outputbase.CompositeOutputBom` format, including the BOMs of the all the defined configurations of the project. This function uses a :mod:`csv.writer` instead of rendering a jinja2 template. It also generates configdocs for all the defined configurations of the project, using :func:`gen_confpdf`. :param projfolder: The gEDA project folder. :type projfolder: str :param namebase: The project name. :type namebase: str :param force: Regenerate even if up-to-date. :type force: bool :return: The output file path. .. rubric:: Paths * Output Files : ``<project_doc_folder>/confdocs/conf_boms.csv`` * Also triggers : :func:`gen_confpdf` for all listed configurations. * Source Files : The project's schematic folder. """ gpf = projfile.GedaProjectFile(projfolder) configfile = conffile.ConfigsFile(projfolder) sch_mtime = fsutils.get_folder_mtime(gpf.schfolder) docfolder = get_project_doc_folder(projfolder) cobom_csv_path = path.join(docfolder, 'confdocs', 'conf-boms.csv') outf_mtime = fsutils.get_file_mtime(cobom_csv_path, fs=refdoc_fs) if not force and outf_mtime is not None and outf_mtime > sch_mtime: logger.debug('Skipping up-to-date ' + cobom_csv_path) return cobom_csv_path logger.info('Regenerating ' + cobom_csv_path + os.linesep + 'Last modified : ' + str(sch_mtime) + '; Last Created : ' + str(outf_mtime)) bomlist = [] for cfn in configfile.configuration_names: gen_confpdf(projfolder, cfn, namebase, force=force) lbom = boms_electronics.import_pcb(projfolder) lobom = lbom.create_output_bom(cfn) bomlist.append(lobom) cobom = boms_outputbase.CompositeOutputBom(bomlist) with refdoc_fs.open(cobom_csv_path, 'wb') as f: writer = csv.writer(f) writer.writerow(['device'] + [x.configname for x in cobom.descriptors]) for line in cobom.lines: writer.writerow([line.ident] + line.columns)
def get_device_test_summary(devicetype=None, include_failed=False, session=None): projectfolder = projects.cards[devicetype] bomobj = import_pcb(cardfolder=projectfolder) bomobj.configure_motifs(devicetype) logger.info("Creating dummy test suites") dummy_suites = get_electronics_test_suites(None, devicetype, projectfolder, offline=True) for suite in dummy_suites: suite.dummy = True collector = ResultCollector(dummy_suites, include_failed=include_failed) snos = sno_controller.get_serialnos_by_efield(efield=devicetype, session=session) for sno in snos: suites = get_test_suite_objects(serialno=sno.sno, session=session) if len(suites) > 0: collector.add_suites_set(suites) return collector
def get_test_suite_objects(serialno=None, order_by='FILE_ORDER', session=None): # This reconstructs the test objects from the database. Using SQLAlchemy # as the ORM that it is, and letting it handle the object creation would # be infinitely better. It isn't done here since the models are separate # from the actual test objects, which in turn have other dependencies. # Integrating the models with the classes should be considered in the # future when there is time. # suite_names = controller.get_test_suite_names(serialno=serialno, # session=session) suite_descs = controller.get_test_suite_descs(serialno=serialno, session=session) devicetype = serialnos.get_serialno_efield(sno=serialno, session=session) projectfolder = projects.cards[devicetype] bomobj = import_pcb(cardfolder=projectfolder) # Perhaps this bomobject should not be recreated on the fly. bomobj.configure_motifs(devicetype) if order_by == 'FILE_ORDER': logger.info("Creating dummy test suites for file ordering") dummy_suites = get_electronics_test_suites(None, devicetype, projectfolder, offline=True) ldummy_suites = [] for suite in dummy_suites: suite.dummy = True ldummy_suites.append(suite) file_order = [(x.desc, [(y.desc, y.passfailonly) for y in x.tests]) for x in ldummy_suites] suite_order = [x[0] for x in file_order] test_order = {x[0]: x[1] for x in file_order} elif order_by == 'DONT_CARE': suite_order = [] test_order = {} else: raise ValueError('Unknown order_by heuristic : ' + order_by) suites = [] suite_descs = sort_by_order(suite_descs, suite_order) # for suite_name in suite_names: for desc, name in suite_descs: suite_db_obj = controller.get_latest_test_suite(serialno=serialno, suite_class=name, descr=desc, session=session) if suite_db_obj.suite_class == \ "<class 'tendril.testing.testbase.TestSuiteBase'>": suite_obj = TestSuiteBase() else: raise ValueError("Unrecognized suite_class : " + suite_db_obj.suite_class) suite_obj.desc = suite_db_obj.desc suite_obj.title = suite_db_obj.title suite_obj.ts = suite_db_obj.created_at suite_obj.serialno = serialno if order_by == 'FILE_ORDER': test_display_params = { x[0]: x[1] for x in test_order[suite_obj.desc] } for test_db_obj in suite_db_obj.tests: class_name = rex_class.match(test_db_obj.test_class).group('cl') test_obj = get_test_object(class_name, offline=True) test_obj.desc = test_db_obj.desc test_obj.title = test_db_obj.title test_obj.ts = test_db_obj.created_at test_obj.use_bom(bomobj) test_obj.load_result_from_obj(test_db_obj.result) if order_by == 'FILE_ORDER': test_obj.passfailonly = test_display_params[test_obj.desc] suite_obj.add_test(test_obj) # Crosscheck test passed? # Crosscheck suite passed? suites.append(suite_obj) return suites
def gen_schpdf(projfolder, namebase, configname=None, force=False): """ Generates a PDF file of all the project schematics listed in the gEDA project file. This function does not use jinja2 and latex. It relies on :func:`tendril.gedaif.gschem.conv_gsch2pdf` instead. :param projfolder: The gEDA project folder. :type projfolder: str :param namebase: The project name. :type namebase: str :param force: Regenerate even if up-to-date. :type force: bool :return: The output file path. .. rubric:: Paths * Output File : ``<project_doc_folder>/<namebase>-schematic.pdf`` * Source Files : The project's schematic folder. """ gpf = projfile.GedaProjectFile(projfolder) sch_mtime = fsutils.get_folder_mtime(gpf.schfolder) configfile = conffile.ConfigsFile(projfolder) docfolder = get_project_doc_folder(projfolder) # TODO Consider converting all configurations in one go instead? if configname is None: schpdfpath = path.join(docfolder, namebase + '-schematic.pdf') else: docfolder = path.join(docfolder, 'confdocs') pdfname = configname + '-conf-schematic.pdf' schpdfpath = path.join(docfolder, pdfname) outf_mtime = fsutils.get_file_mtime(schpdfpath, fs=refdoc_fs) if not force and outf_mtime is not None and outf_mtime > sch_mtime: logger.debug('Skipping up-to-date ' + schpdfpath) return schpdfpath logger.info('Regenerating ' + schpdfpath + os.linesep + 'Last modified : ' + str(sch_mtime) + '; Last Created : ' + str(outf_mtime)) if configfile.rawconfig is not None: workspace_outpath = workspace_fs.getsyspath(schpdfpath) workspace_folder = workspace_fs.getsyspath(docfolder) workspace_fs.makedir(docfolder, recursive=True, allow_recreate=True) pdffiles = [] obom = None if configname is not None: tfolder = path.join(docfolder, configname) workspace_tfolder = workspace_fs.getsyspath(tfolder) workspace_fs.makedir(tfolder, recursive=False, allow_recreate=True) bom = boms_electronics.import_pcb(projfolder) bom.configure_motifs(configname) obom = bom.create_output_bom(configname) for schematic in gpf.schfiles: schfile = os.path.normpath(projfolder + '/schematic/' + schematic) if configname is not None: tschfile = path.join(workspace_tfolder, schematic) gschem.rewrite_schematic(schfile, obom, gpf, tschfile) pdffile = gschem.conv_gsch2pdf(tschfile, workspace_tfolder) os.remove(tschfile) else: pdffile = gschem.conv_gsch2pdf(schfile, workspace_folder) pdffiles.append(pdffile) pdf.merge_pdf(pdffiles, workspace_outpath) for pdffile in pdffiles: os.remove(pdffile) copyfile(workspace_fs, schpdfpath, refdoc_fs, schpdfpath, overwrite=True) return schpdfpath
def gen_confdoc(projfolder, configname, force=False): """ Generate a PDF documenting a single configuration of the project. The document should include a reasonably thorough representation of the contents of the configuration related sections of the `tendril.gedaif.conffile.ConfigsFile``. :param projfolder: The gEDA project folder :type projfolder: str :param configname: The configuration name for which the BOM should be generated. :type configname: str :param force: Regenerate even if up-to-date. :type force: bool :return: The output file path. .. rubric:: Paths * Output File : ``<project_doc_folder>/confdocs/<configname>-doc.pdf`` * Source Files : The project's schematic folder. .. rubric:: Template Used ``tendril/dox/templates/projects/geda-conf-doc.tex`` (:download:`Included version <../../tendril/dox/templates/projects/geda-conf-doc.tex>`) .. rubric:: Stage Keys Provided .. list-table:: * - ``configname`` - The name of the configuration (a card or cable name). * - ``desc`` - The description of the configuration. * - ``pcbname`` - The name of the base PCB. * - ``obom`` - An :mod:`tendril.boms.outputbase.OutputBom` instance """ gpf = projfile.GedaProjectFile(projfolder) sch_mtime = fsutils.get_folder_mtime(gpf.schfolder) docfolder = get_project_doc_folder(projfolder) outpath = path.join(docfolder, 'confdocs', configname + '-doc.pdf') outf_mtime = fsutils.get_file_mtime(outpath, fs=refdoc_fs) if not force and outf_mtime is not None and outf_mtime > sch_mtime: logger.debug('Skipping up-to-date ' + outpath) return outpath logger.info('Regenerating ' + outpath + os.linesep + 'Last modified : ' + str(sch_mtime) + '; Last Created : ' + str(outf_mtime)) bom = boms_electronics.import_pcb(projfolder) obom = bom.create_output_bom(configname) group_oboms = bom.get_group_boms(configname) stage = { 'configname': obom.descriptor.configname, 'pcbname': obom.descriptor.pcbname, 'bom': bom, 'obom': obom, 'group_oboms': group_oboms } config = obom.descriptor.configurations.configuration(configname) stage['desc'] = config['desc'] template = 'projects/geda-conf-doc.tex' workspace_outpath = workspace_fs.getsyspath(outpath) workspace_fs.makedir(path.dirname(outpath), recursive=True, allow_recreate=True) render.render_pdf(stage, template, workspace_outpath) copyfile(workspace_fs, outpath, refdoc_fs, outpath, overwrite=True) return outpath
def gen_confdoc(projfolder, configname, force=False): """ Generate a PDF documenting a single configuration of the project. The document should include a reasonably thorough representation of the contents of the configuration related sections of the `tendril.gedaif.conffile.ConfigsFile``. :param projfolder: The gEDA project folder :type projfolder: str :param configname: The configuration name for which the BOM should be generated. :type configname: str :param force: Regenerate even if up-to-date. :type force: bool :return: The output file path. .. rubric:: Paths * Output File : ``<project_doc_folder>/confdocs/<configname>-doc.pdf`` * Source Files : The project's schematic folder. .. rubric:: Template Used ``tendril/dox/templates/projects/geda-conf-doc.tex`` (:download:`Included version <../../tendril/dox/templates/projects/geda-conf-doc.tex>`) .. rubric:: Stage Keys Provided .. list-table:: * - ``configname`` - The name of the configuration (a card or cable name). * - ``desc`` - The description of the configuration. * - ``pcbname`` - The name of the base PCB. * - ``obom`` - An :mod:`tendril.boms.outputbase.OutputBom` instance """ gpf = projfile.GedaProjectFile(projfolder) sch_mtime = fsutils.get_folder_mtime(gpf.schfolder) docfolder = get_project_doc_folder(projfolder) outpath = path.join(docfolder, 'confdocs', configname + '-doc.pdf') outf_mtime = fsutils.get_file_mtime(outpath, fs=refdoc_fs) if not force and outf_mtime is not None and outf_mtime > sch_mtime: logger.debug('Skipping up-to-date ' + outpath) return outpath logger.info('Regenerating ' + outpath + os.linesep + 'Last modified : ' + str(sch_mtime) + '; Last Created : ' + str(outf_mtime)) bom = boms_electronics.import_pcb(projfolder) obom = bom.create_output_bom(configname) group_oboms = bom.get_group_boms(configname) stage = {'configname': obom.descriptor.configname, 'pcbname': obom.descriptor.pcbname, 'bom': bom, 'obom': obom, 'group_oboms': group_oboms} config = obom.descriptor.configurations.configuration(configname) stage['desc'] = config['desc'] template = 'projects/geda-conf-doc.tex' workspace_outpath = workspace_fs.getsyspath(outpath) workspace_fs.makedir(path.dirname(outpath), recursive=True, allow_recreate=True) render.render_pdf(stage, template, workspace_outpath) copyfile(workspace_fs, outpath, refdoc_fs, outpath, overwrite=True) return outpath
def get_suiteobj_from_cnf_suite(cnf_suite, gcf, devicetype, offline=False): """ :param cnf_suite: :param gcf: :type gcf: tendril.gedaif.conffile.ConfigsFile :param devicetype: :param offline: :param dummy: :return: """ if len(cnf_suite.keys()) != 1: raise ValueError("Suite configurations are expected " "to have exactly one key at the top level") cnf_suite_name = cnf_suite.keys()[0] testvars = gcf.testvars(devicetype) bomobj = import_pcb(gcf.projectfolder) bomobj.configure_motifs(devicetype) cnf_grouplist = gcf.configuration_grouplist(devicetype) desc = None title = None if 'desc' in cnf_suite[cnf_suite.keys()[0]].keys(): logger.debug("Found Test Suite Description") desc = cnf_suite[cnf_suite.keys()[0]]['desc'] if 'title' in cnf_suite[cnf_suite.keys()[0]].keys(): logger.debug("Found Test Suite Title") title = cnf_suite[cnf_suite.keys()[0]]['title'] logger.debug("Creating test suite : " + cnf_suite_name) if cnf_suite_name == "TestSuiteBase": suite = [] suite_detail = cnf_suite[cnf_suite_name] if 'group-tests' in suite_detail.keys(): suite.append(TestSuiteBase()) if 'prep' in suite_detail.keys(): add_prep_steps_from_cnf_prep(suite[0], suite_detail['prep']) if desc is not None: suite[0].desc = desc if title is not None: suite[0].title = title cnf_groups = suite_detail['group-tests'] for cnf_group in cnf_groups: if len(cnf_suite.keys()) != 1: raise ValueError("Group test configurations are " "expected to have exactly one " "key at the top level") logger.debug("Creating group tests : " + cnf_group.keys()[0]) if cnf_group.keys()[0] in cnf_grouplist: cnf_test_list = cnf_group[cnf_group.keys()[0]] for cnf_test in cnf_test_list: suite[0].add_test( get_testobj_from_cnf_test( cnf_test, testvars, bomobj, offline=offline ) ) if 'channel-tests' in suite_detail.keys(): channel_defs = get_channel_defs_from_cnf_channels( suite_detail['channels'], cnf_grouplist ) lsuites = [] for channel_def in channel_defs: lsuite = TestSuiteBase() if 'prep' in suite_detail.keys(): add_prep_steps_from_cnf_prep( lsuite, replace_in_test_cnf_dict( suite_detail['prep'], '<CH>', channel_def.idx ) ) if desc is not None: lsuite.desc = replace_in_string( desc, '<CH>', channel_def.idx ) if title is not None: lsuite.title = replace_in_string( title, '<CH>', channel_def.idx ) for test in suite_detail['channel-tests']: if 'motif-map' in suite_detail.keys(): motifmap = suite_detail['motif-map'] else: motifmap = None cnf_test_dict = replace_in_test_cnf_dict( test, '<CH>', channel_def.idx, motifmap ) lsuite.add_test( get_testobj_from_cnf_test( cnf_test_dict, testvars, bomobj, offline=offline ) ) lsuites.append(lsuite) suite.extend(lsuites) else: suite = [get_test_object(cnf_suite)] return suite
def get_test_suite_objects(serialno=None, order_by='FILE_ORDER', session=None): # This reconstructs the test objects from the database. Using SQLAlchemy # as the ORM that it is, and letting it handle the object creation would # be infinitely better. It isn't done here since the models are separate # from the actual test objects, which in turn have other dependencies. # Integrating the models with the classes should be considered in the # future when there is time. # suite_names = controller.get_test_suite_names(serialno=serialno, # session=session) suite_descs = controller.get_test_suite_descs(serialno=serialno, session=session) devicetype = serialnos.get_serialno_efield(sno=serialno, session=session) projectfolder = projects.cards[devicetype] bomobj = import_pcb(cardfolder=projectfolder) # Perhaps this bomobject should not be recreated on the fly. bomobj.configure_motifs(devicetype) if order_by == 'FILE_ORDER': logger.info("Creating dummy test suites for file ordering") dummy_suites = get_electronics_test_suites(None, devicetype, projectfolder, offline=True) ldummy_suites = [] for suite in dummy_suites: suite.dummy = True ldummy_suites.append(suite) file_order = [(x.desc, [(y.desc, y.passfailonly) for y in x.tests]) for x in ldummy_suites] suite_order = [x[0] for x in file_order] test_order = {x[0]: x[1] for x in file_order} elif order_by == 'DONT_CARE': suite_order = [] test_order = {} else: raise ValueError('Unknown order_by heuristic : ' + order_by) suites = [] suite_descs = sort_by_order(suite_descs, suite_order) # for suite_name in suite_names: for desc, name in suite_descs: suite_db_obj = controller.get_latest_test_suite( serialno=serialno, suite_class=name, descr=desc, session=session ) if suite_db_obj.suite_class == \ "<class 'tendril.testing.testbase.TestSuiteBase'>": suite_obj = TestSuiteBase() else: raise ValueError("Unrecognized suite_class : " + suite_db_obj.suite_class) suite_obj.desc = suite_db_obj.desc suite_obj.title = suite_db_obj.title suite_obj.ts = suite_db_obj.created_at suite_obj.serialno = serialno if order_by == 'FILE_ORDER': test_display_params = {x[0]: x[1] for x in test_order[suite_obj.desc]} for test_db_obj in suite_db_obj.tests: class_name = rex_class.match(test_db_obj.test_class).group('cl') test_obj = get_test_object(class_name, offline=True) test_obj.desc = test_db_obj.desc test_obj.title = test_db_obj.title test_obj.ts = test_db_obj.created_at test_obj.use_bom(bomobj) test_obj.load_result_from_obj(test_db_obj.result) if order_by == 'FILE_ORDER': test_obj.passfailonly = test_display_params[test_obj.desc] suite_obj.add_test(test_obj) # Crosscheck test passed? # Crosscheck suite passed? suites.append(suite_obj) return suites
def get_suiteobj_from_cnf_suite(cnf_suite, gcf, devicetype, offline=False): """ :param cnf_suite: :param gcf: :type gcf: tendril.gedaif.conffile.ConfigsFile :param devicetype: :param offline: :return: """ if len(cnf_suite.keys()) != 1: raise ValueError("Suite configurations are expected " "to have exactly one key at the top level") cnf_suite_name = cnf_suite.keys()[0] testvars = gcf.testvars(devicetype) bomobj = import_pcb(gcf.projectfolder) bomobj.configure_motifs(devicetype) cnf_grouplist = gcf.configuration_grouplist(devicetype) desc = None title = None if "desc" in cnf_suite[cnf_suite.keys()[0]].keys(): logger.debug("Found Test Suite Description") desc = cnf_suite[cnf_suite.keys()[0]]["desc"] if "title" in cnf_suite[cnf_suite.keys()[0]].keys(): logger.debug("Found Test Suite Title") title = cnf_suite[cnf_suite.keys()[0]]["title"] logger.debug("Creating test suite : " + cnf_suite_name) if cnf_suite_name == "TestSuiteBase": suite = [] suite_detail = cnf_suite[cnf_suite_name] if "group-tests" in suite_detail.keys(): suite.append(TestSuiteBase()) if "prep" in suite_detail.keys(): add_prep_steps_from_cnf_prep(suite[0], suite_detail["prep"]) if desc is not None: suite[0].desc = desc if title is not None: suite[0].title = title cnf_groups = suite_detail["group-tests"] for cnf_group in cnf_groups: if len(cnf_suite.keys()) != 1: raise ValueError( "Group test configurations are " "expected to have exactly one " "key at the top level" ) logger.debug("Creating group tests : " + cnf_group.keys()[0]) if cnf_group.keys()[0] in cnf_grouplist: cnf_test_list = cnf_group[cnf_group.keys()[0]] for cnf_test in cnf_test_list: suite[0].add_test(get_testobj_from_cnf_test(cnf_test, testvars, bomobj, offline=offline)) if "channel-tests" in suite_detail.keys(): channel_defs = get_channel_defs_from_cnf_channels(suite_detail["channels"], cnf_grouplist) lsuites = [] for channel_def in channel_defs: lsuite = TestSuiteBase() if "prep" in suite_detail.keys(): add_prep_steps_from_cnf_prep( lsuite, replace_in_test_cnf_dict(suite_detail["prep"], "<CH>", channel_def.idx) ) if desc is not None: lsuite.desc = replace_in_string(desc, "<CH>", channel_def.idx) if title is not None: lsuite.title = replace_in_string(title, "<CH>", channel_def.idx) for test in suite_detail["channel-tests"]: if "motif-map" in suite_detail.keys(): motifmap = suite_detail["motif-map"] else: motifmap = None cnf_test_dict = replace_in_test_cnf_dict(test, "<CH>", channel_def.idx, motifmap) lsuite.add_test(get_testobj_from_cnf_test(cnf_test_dict, testvars, bomobj, offline=offline)) lsuites.append(lsuite) suite.extend(lsuites) else: suite = [get_test_object(cnf_suite)] return suite