diff --git a/py-scripts/lf_report.py b/py-scripts/lf_report.py index 717cd63d..12d98e40 100755 --- a/py-scripts/lf_report.py +++ b/py-scripts/lf_report.py @@ -1,20 +1,20 @@ #!/usr/bin/env python3 -''' +""" NAME: lf_report.py -PURPOSE: +PURPOSE: This program is a helper class for reporting results for a lanforge python script. -The class will generate an output directory based on date and time in the /home/lanforge/html-reports/ . +The class will generate an output directory based on date and time in the /home/lanforge/html-reports/ . If the reports-data is not present then the date and time directory will be created in the current directory. -The banner and Candela Technology logo will be copied in the results directory. -The results directory may be over written and many of the other paramaters during construction. +The banner and Candela Technology logo will be copied in the results directory. +The results directory may be over written and many of the other paramaters during construction. Creating the date time directory on construction was a design choice. -EXAMPLE: +EXAMPLE: -This is a helper class, a unit test is included at the bottom of the file. +This is a helper class, a unit test is included at the bottom of the file. To test lf_report.py and lf_graph.py together use the lf_report_test.py file LICENSE: @@ -23,7 +23,7 @@ LICENSE: INCLUDE_IN_README -''' +""" # CAUTION: adding imports to this file which are not in update_dependencies.py is not advised import os import shutil @@ -33,145 +33,148 @@ import pandas as pd import pdfkit import argparse + # internal candela references included during intial phases, to be deleted at future date # https://candelatech.atlassian.net/wiki/spaces/LANFORGE/pages/372703360/Scripting+Data+Collection+March+2021 # base report class -class lf_report(): + +class lf_report: def __init__(self, - #_path the report directory under which the report directories will be created. - _path = "/home/lanforge/html-reports", - _alt_path = "", - _date = "", - _title="LANForge Unit Test Run Heading", - _table_title="LANForge Table Heading", - _graph_title="LANForge Graph Title", - _obj = "", - _obj_title = "", - _output_html="outfile.html", - _output_pdf="outfile.pdf", - _results_dir_name = "LANforge_Test_Results_Unit_Test", - _output_format = 'html', # pass in on the write functionality, current not used - _dataframe="", - _path_date_time="", + # _path the report directory under which the report directories will be created. + _path="/home/lanforge/html-reports", + _alt_path="", + _date="", + _title="LANForge Unit Test Run Heading", + _table_title="LANForge Table Heading", + _graph_title="LANForge Graph Title", + _obj="", + _obj_title="", + _output_html="outfile.html", + _output_pdf="outfile.pdf", + _results_dir_name="LANforge_Test_Results_Unit_Test", + _output_format='html', # pass in on the write functionality, current not used + _dataframe="", + _path_date_time="", _custom_css='custom-example.css'): # this is where the final report is placed. - #other report paths, + # other report paths, - # _path is where the directory with the data time will be created - if _path == "local" or _path == "here": - self.path = os.path.abspath(__file__) - print("path set to file path: {}".format(self.path)) - elif _alt_path != "": - self.path = _alt_path - print("path set to alt path: {}".format(self.path)) - else: - self.path = _path - print("path set: {}".format(self.path)) - - self.dataframe=_dataframe - self.text = "" - self.title=_title - self.table_title=_table_title - self.graph_title=_graph_title - self.date=_date - self.output_html=_output_html - self.path_date_time = _path_date_time - self.write_output_html = "" - self.write_output_index_html = "" - self.output_pdf=_output_pdf - self.write_output_pdf = "" - self.banner_html = "" - self.footer_html = "" - self.graph_titles="" - self.graph_image="" - self.csv_file_name="" - self.html = "" - self.custom_html = "" - self.pdf_link_html = "" - self.objective = _obj - self.obj_title = _obj_title - #self.systeminfopath = "" - self.date_time_directory = "" - self.log_directory = "" - - self.banner_directory = "artifacts" - self.banner_file_name = "banner.png" # does this need to be configurable - self.logo_directory = "artifacts" - self.logo_file_name = "CandelaLogo2-90dpi-200x90-trans.png" # does this need to be configurable. - self.logo_footer_file_name = "candela_swirl_small-72h.png" # does this need to be configurable. - self.current_path = os.path.dirname(os.path.abspath(__file__)) - self.custom_css = _custom_css - # note: the following 3 calls must be in order - self.set_date_time_directory(_date,_results_dir_name) - self.build_date_time_directory() - self.build_log_directory() + # _path is where the directory with the data time will be created + if _path == "local" or _path == "here": + self.path = os.path.abspath(__file__) + print("path set to file path: {}".format(self.path)) + elif _alt_path != "": + self.path = _alt_path + print("path set to alt path: {}".format(self.path)) + else: + self.path = _path + print("path set: {}".format(self.path)) + + self.dataframe = _dataframe + self.text = "" + self.title = _title + self.table_title = _table_title + self.graph_title = _graph_title + self.date = _date + self.output_html = _output_html + self.path_date_time = _path_date_time + self.write_output_html = "" + self.write_output_index_html = "" + self.output_pdf = _output_pdf + self.write_output_pdf = "" + self.banner_html = "" + self.footer_html = "" + self.graph_titles = "" + self.graph_image = "" + self.csv_file_name = "" + self.html = "" + self.custom_html = "" + self.pdf_link_html = "" + self.objective = _obj + self.obj_title = _obj_title + # self.systeminfopath = "" + self.date_time_directory = "" + self.log_directory = "" + + self.banner_directory = "artifacts" + self.banner_file_name = "banner.png" # does this need to be configurable + self.logo_directory = "artifacts" + self.logo_file_name = "CandelaLogo2-90dpi-200x90-trans.png" # does this need to be configurable. + self.logo_footer_file_name = "candela_swirl_small-72h.png" # does this need to be configurable. + self.current_path = os.path.dirname(os.path.abspath(__file__)) + self.custom_css = _custom_css + # note: the following 3 calls must be in order + self.set_date_time_directory(_date, _results_dir_name) + self.build_date_time_directory() + self.build_log_directory() + + self.font_file = "CenturyGothic.woff" + # move the banners and candela images to report path + self.copy_banner() + self.copy_css() + self.copy_logo() + self.copy_logo_footer() - self.font_file = "CenturyGothic.woff" - # move the banners and candela images to report path - self.copy_banner() - self.copy_css() - self.copy_logo() - self.copy_logo_footer() - def copy_banner(self): - banner_src_file = str(self.current_path)+'/'+str(self.banner_directory)+'/'+str(self.banner_file_name) - banner_dst_file = str(self.path_date_time)+'/'+ str(self.banner_file_name) - #print("banner src_file: {}".format(banner_src_file)) - #print("dst_file: {}".format(banner_dst_file)) + banner_src_file = str(self.current_path) + '/' + str(self.banner_directory) + '/' + str(self.banner_file_name) + banner_dst_file = str(self.path_date_time) + '/' + str(self.banner_file_name) + # print("banner src_file: {}".format(banner_src_file)) + # print("dst_file: {}".format(banner_dst_file)) shutil.copy(banner_src_file, banner_dst_file) def copy_css(self): - reportcss_src_file = str(self.current_path)+'/'+str(self.banner_directory)+'/report.css' + reportcss_src_file = str(self.current_path) + '/' + str(self.banner_directory) + '/report.css' # print("copy_css: source file is: "+reportcss_src_file) - reportcss_dest_file = str(self.path_date_time)+'/report.css' + reportcss_dest_file = str(self.path_date_time) + '/report.css' - customcss_src_file = str(self.current_path)+'/'+str(self.banner_directory)+'/'+str(self.custom_css) - customcss_dest_file = str(self.path_date_time)+'/custom.css' + customcss_src_file = str(self.current_path) + '/' + str(self.banner_directory) + '/' + str(self.custom_css) + customcss_dest_file = str(self.path_date_time) + '/custom.css' - font_src_file = str(self.current_path)+'/'+str(self.banner_directory)+'/'+str(self.font_file) - font_dest_file = str(self.path_date_time)+'/'+str(self.font_file) + font_src_file = str(self.current_path) + '/' + str(self.banner_directory) + '/' + str(self.font_file) + font_dest_file = str(self.path_date_time) + '/' + str(self.font_file) shutil.copy(reportcss_src_file, reportcss_dest_file) shutil.copy(customcss_src_file, customcss_dest_file) shutil.copy(font_src_file, font_dest_file) def copy_logo(self): - logo_src_file = str(self.current_path)+'/'+str(self.logo_directory)+'/'+str(self.logo_file_name) - logo_dst_file = str(self.path_date_time)+'/'+ str(self.logo_file_name) - #print("logo_src_file: {}".format(logo_src_file)) - #print("logo_dst_file: {}".format(logo_dst_file)) + logo_src_file = str(self.current_path) + '/' + str(self.logo_directory) + '/' + str(self.logo_file_name) + logo_dst_file = str(self.path_date_time) + '/' + str(self.logo_file_name) + # print("logo_src_file: {}".format(logo_src_file)) + # print("logo_dst_file: {}".format(logo_dst_file)) shutil.copy(logo_src_file, logo_dst_file) def copy_logo_footer(self): - logo_footer_src_file = str(self.current_path)+'/'+str(self.logo_directory)+'/'+str(self.logo_footer_file_name) - logo_footer_dst_file = str(self.path_date_time)+'/'+ str(self.logo_footer_file_name) - #print("logo_footer_src_file: {}".format(logo_footer_src_file)) - #print("logo_footer_dst_file: {}".format(logo_footer_dst_file)) + logo_footer_src_file = str(self.current_path) + '/' + str(self.logo_directory) + '/' + str( + self.logo_footer_file_name) + logo_footer_dst_file = str(self.path_date_time) + '/' + str(self.logo_footer_file_name) + # print("logo_footer_src_file: {}".format(logo_footer_src_file)) + # print("logo_footer_dst_file: {}".format(logo_footer_dst_file)) shutil.copy(logo_footer_src_file, logo_footer_dst_file) - def move_graph_image(self,): + def move_graph_image(self, ): graph_src_file = str(self.graph_image) - graph_dst_file = str(self.path_date_time)+'/'+ str(self.graph_image) + graph_dst_file = str(self.path_date_time) + '/' + str(self.graph_image) print("graph_src_file: {}".format(graph_src_file)) print("graph_dst_file: {}".format(graph_dst_file)) shutil.move(graph_src_file, graph_dst_file) def move_csv_file(self): csv_src_file = str(self.csv_file_name) - csv_dst_file = str(self.path_date_time)+'/'+str(self.csv_file_name) + csv_dst_file = str(self.path_date_time) + '/' + str(self.csv_file_name) print("csv_src_file: {}".format(csv_src_file)) print("csv_dst_file: {}".format(csv_dst_file)) shutil.move(csv_src_file, csv_dst_file) - def set_path(self,_path): + def set_path(self, _path): self.path = _path - def set_date_time_directory(self,_date,_results_dir_name): + def set_date_time_directory(self, _date, _results_dir_name): self.date = _date self.results_dir_name = _results_dir_name if self.date != "": self.date_time_directory = str(self.date) + str("_") + str(self.results_dir_name) else: - self.date = str(datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S")).replace(':','-') + self.date = str(datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S")).replace(':', '-') self.date_time_directory = self.date + str("_") + str(self.results_dir_name) def build_date_time_directory(self): @@ -179,18 +182,18 @@ class lf_report(): self.set_date_time_directory() self.path_date_time = os.path.join(self.path, self.date_time_directory) print("path_date_time {}".format(self.path_date_time)) - try: + try: if not os.path.exists(self.path_date_time): os.mkdir(self.path_date_time) except: self.path_date_time = os.path.join(self.current_path, self.date_time_directory) if not os.path.exists(self.path_date_time): os.mkdir(self.path_date_time) - print("report path : {}".format(self.path_date_time)) + print("report path : {}".format(self.path_date_time)) def build_log_directory(self): - if self.log_directory =="": - self.log_directory = os.path.join(self.path_date_time,"log") + if self.log_directory == "": + self.log_directory = os.path.join(self.path_date_time, "log") try: if not os.path.exists(self.log_directory): os.mkdir(self.log_directory) @@ -198,16 +201,16 @@ class lf_report(): print("exception making {}".format(self.log_directory)) exit(1) - def set_text(self,_text): + def set_text(self, _text): self.text = _text - def set_title(self,_title): + def set_title(self, _title): self.title = _title - def set_table_title(self,_table_title): + def set_table_title(self, _table_title): self.table_title = _table_title - def set_graph_title(self,_graph_title): + def set_graph_title(self, _graph_title): self.graph_title = _graph_title # sets the csv file name as graph title @@ -216,23 +219,23 @@ class lf_report(): self.csv_file_name = fname + ".csv" # The _date is set when class is enstanciated / created so this set_date should be used with caution, used to synchronize results - def set_date(self,_date): + def set_date(self, _date): self.date = _date - def set_table_dataframe(self,_dataframe): + def set_table_dataframe(self, _dataframe): self.dataframe = _dataframe - def set_table_dataframe_from_csv(self,_csv): + def set_table_dataframe_from_csv(self, _csv): self.dataframe = pd.read_csv(_csv) - def set_custom_html(self,_custom_html): + def set_custom_html(self, _custom_html): self.custom_html = _custom_html - def set_obj_html(self,_obj_title, _obj ): + def set_obj_html(self, _obj_title, _obj): self.objective = _obj self.obj_title = _obj_title - def set_graph_image(self,_graph_image): + def set_graph_image(self, _graph_image): self.graph_image = _graph_image def get_date(self): @@ -256,12 +259,12 @@ class lf_report(): return self.log_directory def file_add_path(self, file): - output_file = str(self.path_date_time)+'/'+ str(file) + output_file = str(self.path_date_time) + '/' + str(file) print("output file {}".format(output_file)) return output_file - def write_html(self): - self.write_output_html = str(self.path_date_time)+'/'+ str(self.output_html) + def write_html(self): + self.write_output_html = str(self.path_date_time) + '/' + str(self.output_html) print("write_output_html: {}".format(self.write_output_html)) try: test_file = open(self.write_output_html, "w") @@ -271,8 +274,8 @@ class lf_report(): print("write_html failed") return self.write_output_html - def write_index_html(self): - self.write_output_index_html = str(self.path_date_time)+'/'+ str("index.html") + def write_index_html(self): + self.write_output_index_html = str(self.path_date_time) + '/' + str("index.html") print("write_output_index_html: {}".format(self.write_output_index_html)) try: test_file = open(self.write_output_index_html, "w") @@ -282,9 +285,8 @@ class lf_report(): print("write_index_html failed") return self.write_output_index_html - - def write_html_with_timestamp(self): - self.write_output_html = "{}/{}-{}".format(self.path_date_time,self.date,self.output_html) + def write_html_with_timestamp(self): + self.write_output_html = "{}/{}-{}".format(self.path_date_time, self.date, self.output_html) print("write_output_html: {}".format(self.write_output_html)) try: test_file = open(self.write_output_html, "w") @@ -294,57 +296,56 @@ class lf_report(): print("write_html failed") return self.write_output_html + # https://wkhtmltopdf.org/usage/wkhtmltopdf.txt + # page_size A4, A3, Letter, Legal + # orientation Portrait , Landscape + def write_pdf(self, _page_size='A4', _orientation='Portrait'): + # write logic to generate pdf here + # wget https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6-1/wkhtmltox_0.12.6-1.focal_amd64.deb + # sudo apt install ./wkhtmltox_0.12.6-1.focal_amd64.deb + + options = {"enable-local-file-access": None, + 'orientation': _orientation, + 'page-size': _page_size} # prevent error Blocked access to file + self.write_output_pdf = str(self.path_date_time) + '/' + str(self.output_pdf) + pdfkit.from_file(self.write_output_html, self.write_output_pdf, options=options) # https://wkhtmltopdf.org/usage/wkhtmltopdf.txt # page_size A4, A3, Letter, Legal # orientation Portrait , Landscape - def write_pdf(self, _page_size = 'A4', _orientation = 'Portrait'): - # write logic to generate pdf here - # wget https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6-1/wkhtmltox_0.12.6-1.focal_amd64.deb - # sudo apt install ./wkhtmltox_0.12.6-1.focal_amd64.deb - - options = {"enable-local-file-access" : None, - 'orientation': _orientation, - 'page-size': _page_size} # prevent error Blocked access to file - self.write_output_pdf = str(self.path_date_time)+'/'+ str(self.output_pdf) - pdfkit.from_file(self.write_output_html, self.write_output_pdf, options=options) + def write_pdf_with_timestamp(self, _page_size='A4', _orientation='Portrait'): + # write logic to generate pdf here + # wget https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6-1/wkhtmltox_0.12.6-1.focal_amd64.deb + # sudo apt install ./wkhtmltox_0.12.6-1.focal_amd64.deb - # https://wkhtmltopdf.org/usage/wkhtmltopdf.txt - # page_size A4, A3, Letter, Legal - # orientation Portrait , Landscape - def write_pdf_with_timestamp(self, _page_size = 'A4', _orientation = 'Portrait'): - # write logic to generate pdf here - # wget https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6-1/wkhtmltox_0.12.6-1.focal_amd64.deb - # sudo apt install ./wkhtmltox_0.12.6-1.focal_amd64.deb - - options = {"enable-local-file-access" : None, - 'orientation': _orientation, - 'page-size': _page_size} # prevent error Blocked access to file - self.write_output_pdf = "{}/{}-{}".format(self.path_date_time,self.date,self.output_pdf) - pdfkit.from_file(self.write_output_html, self.write_output_pdf, options=options) + options = {"enable-local-file-access": None, + 'orientation': _orientation, + 'page-size': _page_size} # prevent error Blocked access to file + self.write_output_pdf = "{}/{}-{}".format(self.path_date_time, self.date, self.output_pdf) + pdfkit.from_file(self.write_output_html, self.write_output_pdf, options=options) def get_pdf_path(self): pdf_link_path = "{}/{}-{}".format(self.path_date_time, self.date, self.output_pdf) return pdf_link_path - - def build_pdf_link(self,_pdf_link_name,_pdf_link_path): + + def build_pdf_link(self, _pdf_link_name, _pdf_link_path): self.pdf_link_html = """ {pdf_link_name}
- """.format(pdf_link_path=_pdf_link_path,pdf_link_name=_pdf_link_name) + """.format(pdf_link_path=_pdf_link_path, pdf_link_name=_pdf_link_name) self.html += self.pdf_link_html - def build_link(self,_link_name,_link_path): + def build_link(self, _link_name, _link_path): self.link = """ {link_name}
- """.format(link_path=_link_path,link_name=_link_name) + """.format(link_path=_link_path, link_name=_link_name) self.html += self.link def generate_report(self): - self.write_html() + self.write_html() self.write_pdf() def build_all(self): @@ -419,7 +420,6 @@ class lf_report(): ) self.html += self.banner_html - def build_table_title(self): self.table_title_html = """ @@ -442,23 +442,24 @@ class lf_report(): self.html += self.text_html def build_date_time(self): - self.date_time = str(datetime.datetime.now().strftime("%Y-%m-%d-%H-h-%m-m-%S-s")).replace(':','-') + self.date_time = str(datetime.datetime.now().strftime("%Y-%m-%d-%H-h-%m-m-%S-s")).replace(':', '-') return self.date_time def build_path_date_time(self): - try: - self.path_date_time = os.path.join(self.path,self.date_time) + try: + self.path_date_time = os.path.join(self.path, self.date_time) os.mkdir(self.path_date_time) except: - curr_dir_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) - self.path_date_time = os.path.join(curr_dir_path,self.date_time) - os.mkdir(self.path_date_time) + curr_dir_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + self.path_date_time = os.path.join(curr_dir_path, self.date_time) + os.mkdir(self.path_date_time) def build_table(self): - self.dataframe_html = self.dataframe.to_html(index=False, justify='center') # have the index be able to be passed in. + self.dataframe_html = self.dataframe.to_html(index=False, + justify='center') # have the index be able to be passed in. self.html += self.dataframe_html - def test_setup_table(self,test_setup_data, value): + def test_setup_table(self, test_setup_data, value): if test_setup_data is None: return None else: @@ -471,7 +472,7 @@ class lf_report(): - +
"""+ str(value) + """""" + str(value) + """ """ + var + """ @@ -571,34 +572,35 @@ function copyTextToClipboard(ele) { def end_content_div(self): self.html += "\n\n" + # Unit Test if __name__ == "__main__": parser = argparse.ArgumentParser( prog="lf_report.py", formatter_class=argparse.RawTextHelpFormatter, description="Reporting library Unit Test") - parser.add_argument('--lfmgr', help='sample argument: where LANforge GUI is running', default='localhost') + parser.add_argument('--lfmgr', help='sample argument: where LANforge GUI is running', default='localhost') # the args parser is not really used , this is so the report is not generated when testing # the imports with --help args = parser.parse_args() print("LANforge manager {lfmgr}".format(lfmgr=args.lfmgr)) - - # Testing: generate data frame + # Testing: generate data frame dataframe = pd.DataFrame({ - 'product':['CT521a-264-1ac-1n','CT521a-1ac-1ax','CT522-264-1ac2-1n','CT523c-2ac2-db-10g-cu','CT523c-3ac2-db-10g-cu','CT523c-8ax-ac10g-cu','CT523c-192-2ac2-1ac-10g'], - 'radios':[1,1,2,2,6,9,3], - 'MIMO':['N','N','N','Y','Y','Y','Y'], - 'stations':[200,64,200,128,384,72,192], - 'mbps':[300,300,300,10000,10000,10000,10000] + 'product': ['CT521a-264-1ac-1n', 'CT521a-1ac-1ax', 'CT522-264-1ac2-1n', 'CT523c-2ac2-db-10g-cu', + 'CT523c-3ac2-db-10g-cu', 'CT523c-8ax-ac10g-cu', 'CT523c-192-2ac2-1ac-10g'], + 'radios': [1, 1, 2, 2, 6, 9, 3], + 'MIMO': ['N', 'N', 'N', 'Y', 'Y', 'Y', 'Y'], + 'stations': [200, 64, 200, 128, 384, 72, 192], + 'mbps': [300, 300, 300, 10000, 10000, 10000, 10000] }) print(dataframe) # Testing: generate data frame dataframe2 = pd.DataFrame({ - 'station':[1,2,3,4,5,6,7], - 'time_seconds':[23,78,22,19,45,22,25] + 'station': [1, 2, 3, 4, 5, 6, 7], + 'time_seconds': [23, 78, 22, 19, 45, 22, 25] }) report = lf_report() @@ -617,14 +619,13 @@ if __name__ == "__main__": report.set_table_dataframe(dataframe2) report.build_table() - #report.build_all() - #report.build_footer() + # report.build_all() + # report.build_footer() report.build_footer_no_png() - html_file = report.write_html() + html_file = report.write_html() print("returned file ") print(html_file) report.write_pdf() print("report path {}".format(report.get_path())) -