def report(verbose, user, password, base_url, report_file, output_file, format, serialization_roundtrip, orca_server_url): """ Make a report. See API documentation's POST reports section for REPORT_FILE requirements. """ set_log_level(verbose) token = cli_access_token(user, password) with open(report_file) as f: metadata = json.load(f) session = APISession(token, base_url=base_url) report = session.process_report_dict(metadata) if orca_server_url is not None: import plotly.io as pio pio.orca.config.server_url = orca_server_url if serialization_roundtrip: with mock_raw_report_endpoints(base_url): session.create_report(report) reports.compute_report(token, 'no_id', base_url) full_report = session.get_report('no_id') else: data = reports.get_data_for_report(session, report) raw_report = reports.create_raw_report_from_data(report, data) full_report = report.replace(raw_report=raw_report, status='complete') # assumed dashboard url based on api url dash_url = base_url.replace('api', 'dashboard') if ((format == 'detect' and output_file.endswith('.html')) or format == 'html'): html_report = template.render_html(full_report, dash_url, with_timeseries=True, body_only=False) with open(output_file, 'w') as f: f.write(html_report) elif ((format == 'detect' and output_file.endswith('.pdf')) or format == 'pdf'): pdf_report = template.render_pdf(full_report, dash_url) with open(output_file, 'wb') as f: f.write(pdf_report) else: raise ValueError("Unable to detect format")
def get(self, uuid): try: self.set_metadata(uuid) except DataRequestException as e: errors = {'errors': e.errors} return ReportView().get(uuid, errors=errors) exclude_timeseries = 'exclude_timeseries' in request.args # don't do the work of making a report if the format is incorrect if self.format_ not in ('html', 'pdf'): raise ValueError( 'Only html and pdf report downloads are currently supported') fname = self.metadata['report_parameters']['name'].replace( ' ', '_') report_object = build_report(self.metadata) # render to right format if self.format_ == 'html': bytes_out = render_html( report_object, request.url_root.rstrip('/'), with_timeseries=not exclude_timeseries, body_only=False ).encode('utf-8') elif self.format_ == 'pdf': bytes_out = render_pdf( report_object, request.url_root.rstrip('/'), ) out = check_sign_zip(bytes_out, fname + f'.{self.format_}', current_app.config['GPG_KEY_ID'], current_app.config['GPG_PASSPHRASE_FILE']) return send_file( out, 'application/zip', as_attachment=True, attachment_filename=fname + '.zip', add_etags=False)
def test_render_pdf_process_error(report_with_raw, dash_url, mocker): mocker.patch('solarforecastarbiter.reports.template.subprocess.run', side_effect=subprocess.CalledProcessError( cmd='', returncode=1)) with pytest.raises(subprocess.CalledProcessError): template.render_pdf(report_with_raw, dash_url)
def test_render_pdf_not_settled(report_with_raw, dash_url): if shutil.which('pdflatex') is None: # pragma: no cover pytest.skip('pdflatex must be on PATH to generate PDF reports') with pytest.raises(RuntimeError): template.render_pdf(report_with_raw, dash_url, 1)
def test_render_pdf_special_chars( ac_power_observation_metadata, ac_power_forecast_metadata, dash_url, fail_pdf, preprocessing_result_types, report_metrics): if shutil.which('pdflatex') is None: # pragma: no cover pytest.skip('pdflatex must be on PATH to generate PDF reports') quality_flag_filter = datamodel.QualityFlagFilter( ( "USER FLAGGED", ) ) forecast = ac_power_forecast_metadata.replace( name="ac_power forecast (why,) ()'-_,") observation = ac_power_observation_metadata.replace( name="ac_power observations ()'-_,") fxobs = datamodel.ForecastObservation(forecast, observation) tz = 'America/Phoenix' start = pd.Timestamp('20190401 0000', tz=tz) end = pd.Timestamp('20190404 2359', tz=tz) report_params = datamodel.ReportParameters( name="NREL MIDC OASIS GHI Forecast Analysis ()'-_,", start=start, end=end, object_pairs=(fxobs,), metrics=("mae", "rmse", "mbe", "s"), categories=("total", "date", "hour"), filters=(quality_flag_filter,) ) report = datamodel.Report( report_id="56c67770-9832-11e9-a535-f4939feddd83", report_parameters=report_params ) qflags = list( f.quality_flags for f in report.report_parameters.filters if isinstance(f, datamodel.QualityFlagFilter) ) qflags = list(qflags[0]) ser_index = pd.date_range( start, end, freq=to_offset(forecast.interval_length), name='timestamp') ser = pd.Series( np.repeat(100, len(ser_index)), name='value', index=ser_index) pfxobs = datamodel.ProcessedForecastObservation( forecast.name, fxobs, forecast.interval_value_type, forecast.interval_length, forecast.interval_label, valid_point_count=len(ser), validation_results=tuple(datamodel.ValidationResult( flag=f, count=0) for f in qflags), preprocessing_results=tuple(datamodel.PreprocessingResult( name=t, count=0) for t in preprocessing_result_types), forecast_values=ser, observation_values=ser ) figs = datamodel.RawReportPlots( ( datamodel.PlotlyReportFigure.from_dict( { 'name': 'mae tucson ac_power', 'spec': '{"data":[{"x":[1],"y":[1],"type":"bar"}]}', 'pdf': fail_pdf, 'figure_type': 'bar', 'category': 'total', 'metric': 'mae', 'figure_class': 'plotly', } ),), '4.5.3', ) raw = datamodel.RawReport( generated_at=report.report_parameters.end, timezone=tz, plots=figs, metrics=report_metrics(report), processed_forecasts_observations=(pfxobs,), versions=(('test', 'test_with_underscore?'),), messages=(datamodel.ReportMessage( message="Failed to make metrics for ac_power forecast ()'-_,", step='', level='', function=''),)) rr = report.replace(raw_report=raw) rendered = template.render_pdf(rr, dash_url) assert rendered.startswith(b'%PDF')
def test_render_pdf(report_with_raw, dash_url): if shutil.which('pdflatex') is None: # pragma: no cover pytest.skip('pdflatex must be on PATH to generate PDF reports') rendered = template.render_pdf(report_with_raw, dash_url) assert rendered.startswith(b'%PDF')