-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add spreadsheet generation for templates (#260)
* add generate_spreadsheet method to templates; * add test for spreadsheet generation from templates * Add csv_generation; adjust csv/template generation to emit buffer or write to file * Parameterize tests, add testing of inmem + file based Move template generation tests to their own file * setup tables during template generation test * use fixtures properly to avoid shared state * remove unneeded inline arg from generate_ functions
- Loading branch information
Showing
2 changed files
with
250 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
import csv | ||
from io import StringIO | ||
from pathlib import Path | ||
from tempfile import NamedTemporaryFile | ||
|
||
import openpyxl | ||
from rdflib import Namespace | ||
from rdflib.compare import isomorphic | ||
|
||
from buildingmotif.dataclasses import Library | ||
from buildingmotif.ingresses.csv import CSVIngress | ||
from buildingmotif.ingresses.template import TemplateIngress | ||
from buildingmotif.ingresses.xlsx import XLSXIngress | ||
|
||
BLDG = Namespace("urn:bldg/") | ||
|
||
|
||
# utility function for spreadsheet tests | ||
def _add_spreadsheet_row(sheet, bindings): | ||
num_columns = sheet.max_column | ||
for column in range(1, num_columns + 1): | ||
param = sheet.cell(row=1, column=column).value | ||
sheet.cell(row=2, column=column).value = bindings[param][len(BLDG) :] | ||
|
||
|
||
def _add_csv_row(params, tempfile, bindings): | ||
params = [param.strip() for param in params] | ||
if isinstance(tempfile, StringIO): | ||
w = csv.writer(tempfile) | ||
w.writerow([bindings[param][len(BLDG) :] for param in params]) | ||
tempfile.flush() | ||
else: | ||
with open(Path(tempfile.name), "a") as f: | ||
w = csv.writer(f) | ||
w.writerow([bindings[param][len(BLDG) :] for param in params]) | ||
|
||
|
||
def pytest_generate_tests(metafunc): | ||
if metafunc.fixturenames == [ | ||
"clean_building_motif", | ||
"template_name", | ||
"include_optional", | ||
"inline_dependencies", | ||
]: | ||
test_cases = { | ||
"NOdep-NOoptional-NOinline": ("supply-fan", False, False), | ||
"NOdep-WITHoptional-NOinline": ("outside-air-damper", True, False), | ||
"WITHdep-WITHoptional-NOinline": ("single-zone-vav-ahu", True, False), | ||
"WITHdep-WITHoptional-WITHinline": ("single-zone-vav-ahu", True, True), | ||
} | ||
metafunc.parametrize( | ||
"template_name,include_optional,inline_dependencies", | ||
test_cases.values(), | ||
ids=test_cases.keys(), | ||
) | ||
|
||
|
||
def test_template_generation_inmemory( | ||
clean_building_motif, template_name, include_optional, inline_dependencies | ||
): | ||
fixture_lib = Library.load(directory="tests/unit/fixtures/templates") | ||
template = fixture_lib.get_template_by_name(template_name) | ||
template = fixture_lib.get_template_by_name(template_name) | ||
if inline_dependencies: | ||
template = template.inline_dependencies() | ||
bindings, filled = template.fill(BLDG, include_optional=include_optional) | ||
|
||
with NamedTemporaryFile(suffix=".xlsx") as dest: | ||
output = template.generate_spreadsheet() | ||
assert output is not None | ||
dest.write(output.getbuffer()) | ||
|
||
w = openpyxl.load_workbook(dest.name) | ||
_add_spreadsheet_row(w.active, bindings) | ||
w.save(Path(dest.name)) | ||
|
||
reader = XLSXIngress(Path(dest.name)) | ||
ing = TemplateIngress(template, None, reader) | ||
g = ing.graph(BLDG) | ||
|
||
assert isomorphic( | ||
g, filled | ||
), f"Template -> spreadsheet -> ingress -> graph path did not generate a result isomorphic to just filling the template {template.name}" | ||
|
||
|
||
def test_template_generation_file( | ||
clean_building_motif, template_name, include_optional, inline_dependencies | ||
): | ||
fixture_lib = Library.load(directory="tests/unit/fixtures/templates") | ||
template = fixture_lib.get_template_by_name(template_name) | ||
if inline_dependencies: | ||
template = template.inline_dependencies() | ||
bindings, filled = template.fill(BLDG, include_optional=include_optional) | ||
|
||
with NamedTemporaryFile(suffix=".xlsx") as dest: | ||
output = template.generate_spreadsheet(Path(dest.name)) | ||
assert output is None | ||
|
||
w = openpyxl.load_workbook(dest.name) | ||
_add_spreadsheet_row(w.active, bindings) | ||
w.save(Path(dest.name)) | ||
|
||
reader = XLSXIngress(Path(dest.name)) | ||
ing = TemplateIngress(template, None, reader) | ||
g = ing.graph(BLDG) | ||
|
||
assert isomorphic( | ||
g, filled | ||
), f"Template -> spreadsheet -> ingress -> graph path did not generate a result isomorphic to just filling the template {template.name}" | ||
|
||
|
||
def test_csv_generation_inmemory( | ||
clean_building_motif, template_name, include_optional, inline_dependencies | ||
): | ||
fixture_lib = Library.load(directory="tests/unit/fixtures/templates") | ||
template = fixture_lib.get_template_by_name(template_name) | ||
if inline_dependencies: | ||
template = template.inline_dependencies() | ||
bindings, filled = template.fill(BLDG, include_optional=include_optional) | ||
|
||
with NamedTemporaryFile(mode="w", suffix=".csv") as dest: | ||
output = template.generate_csv() | ||
assert output is not None | ||
dest.writelines([output.getvalue()]) | ||
dest.flush() | ||
|
||
params = output.getvalue().split(",") | ||
_add_csv_row(params, dest, bindings) | ||
|
||
reader = CSVIngress(Path(dest.name)) | ||
ing = TemplateIngress(template, None, reader) | ||
g = ing.graph(BLDG) | ||
|
||
assert isomorphic( | ||
g, filled | ||
), f"Template -> csv -> ingress -> graph path did not generate a result isomorphic to just filling the template {template.name}\n{(filled - g).serialize()}" | ||
|
||
|
||
def test_csv_generation_file( | ||
clean_building_motif, template_name, include_optional, inline_dependencies | ||
): | ||
fixture_lib = Library.load(directory="tests/unit/fixtures/templates") | ||
template = fixture_lib.get_template_by_name(template_name) | ||
if inline_dependencies: | ||
template = template.inline_dependencies() | ||
bindings, filled = template.fill(BLDG, include_optional=include_optional) | ||
|
||
with NamedTemporaryFile(mode="w", suffix=".csv") as dest: | ||
output = template.generate_csv(Path(dest.name)) | ||
assert output is None | ||
|
||
with open(Path(dest.name)) as f: | ||
params = f.read().strip().split(",") | ||
_add_csv_row(params, dest, bindings) | ||
|
||
reader = CSVIngress(Path(dest.name)) | ||
ing = TemplateIngress(template, None, reader) | ||
g = ing.graph(BLDG) | ||
|
||
assert isomorphic( | ||
g, filled | ||
), f"Template -> csv -> ingress -> graph path did not generate a result isomorphic to just filling the template {template.name}\n{(filled - g).serialize()}" |