Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GUI: Embedded doc #54

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions constrain/api/data_processing.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ def __init__(
"""Instantiate a data processing object to load datasets and manipulate data before feeding it to the verification process.

Args:
data (str): Path to the data (CSV format) to be loaded for processing.
data_source (str): Data source name. Use `EnergyPlus` or `Other`.
timestamp_column_name (str): Name of the column header that contains the time series timestamps.
data (str, optional): Path to the data (CSV format) to be loaded for processing.
data_source (str, optional): Data source name. Use `EnergyPlus` or `Other`.
timestamp_column_name (str, optional): Name of the column header that contains the time series timestamps.
"""
self.data = None

Expand Down
6 changes: 3 additions & 3 deletions constrain/api/reporting.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ def __init__(
) -> None:
"""
Args:
verification_json (str): Path to the result json files after verifications to be loaded for reporting. It can be one JSON file or wildcard for multiple JSON files (e.g., *_md.json).
result_md_name (str): Name of the report summary markdown to be saved. All md reports will be created in the same directory as the verification result json files.
report_format (str): File format to be output. For now, only `markdown` format is available. More formats (e.g., html, pdf, csv, etc.) will be added in future releases.
verification_json (str, optional): Path to the result json files after verifications to be loaded for reporting. It can be one JSON file or wildcard for multiple JSON files (e.g., *_md.json).
result_md_name (str, optional): Name of the report summary markdown to be saved. All md reports will be created in the same directory as the verification result json files.
report_format (str, optional): File format to be output. For now, only `markdown` format is available. More formats (e.g., html, pdf, csv, etc.) will be added in future releases.
"""

# TODO:
Expand Down
7 changes: 6 additions & 1 deletion constrain/api/verification.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@

class Verification:
def __init__(self, verifications: VerificationCase = None):
"""Instantiate a Verification object.

Args:
verficiations (VerificationCase, optional): a VerificationCase
"""
self.lib_classes_py_file = None
self.preprocessed_data = None
self.cases = None
Expand Down Expand Up @@ -147,7 +152,7 @@ def run_single_verification(self, case: dict = None) -> None:
"""Run a single verification and generate a json file containing markdown report string and other results info.

Args:
case (dict): Verification case dictionary.
case (Dict): Verification case dictionary.
"""
# Input validation
if case is None:
Expand Down
84 changes: 69 additions & 15 deletions constrain/api/verification_case.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ def __init__(self, cases: List = None, json_case_path: str = None) -> None:
"""Instantiate a verification case class object and load verification case(s) in `self.case_suite` as a Dict. keys are automatically generated unique id of cases, values are the fully defined verification case Dict. If any argument is invalid, the object instantion will report an error message.

Args:
cases: (optional) A list of Dict. dictionary that includes verification case(s).
json_case_path: (optional) str. path to the verification case file. If the path ends with `*.json`, then the items in the JSON file are loaded. If the path points to a directory, then verification cases JSON files are loaded.
cases (List, optional): A list of Dict. dictionary that includes verification case(s).
json_case_path (str, optional): Path to the verification case file. If the path ends with `*.json`, then the items in the JSON file are loaded. If the path points to a directory, then verification cases JSON files are loaded.
"""
self.case_suite = {}

Expand Down Expand Up @@ -56,10 +56,10 @@ def load_verification_cases_from_json(
"""Add verification cases from specified json file into self.case_suite. Cases that have already been loaded are ignored.

Args:
json_case_path: str, path to the json file containing fully defined verification cases.
json_case_path (str): path to the json file containing fully defined verification cases.

Returns:
List, unique ids of verification cases loaded in self.case_suite
List: unique ids of verification cases loaded in self.case_suite
"""

# check `json_case_path` type
Expand All @@ -80,8 +80,8 @@ def save_case_suite_to_json(
"""Save verification cases to a dedicated file. If the `case_ids` argument is empty, all the cases in `self.case_suite` is saved. If `case_ids` includes specific cases' hash, only the hashes in the list are saved.

Args:
json_path: str. path to the json file to save the cases.
case_ids: (optional) List. Unique ids of verification cases to save. By default, save all cases in `self.case_suite`. Default to an empty list.
json_path (str): Path to the json file to save the cases.
case_ids (List, optional): Unique ids of verification cases to save. By default, save all cases in `self.case_suite`. Default to an empty list.
"""

if case_ids is None:
Expand Down Expand Up @@ -118,12 +118,12 @@ def create_verification_case_suite_from_base_case(
"""Create slightly different multiple verification cases by changing keys and values as specified in `update_key_value`. if `keep_base_case` is set to True, the `base_case` is added to the first element in the returned list.

Args:
base_case: Dict. base verification input information.
update_key_value: Dict. the same format as the `base_case` arg, but the updating fields consist of a list of values to be populated with.
keep_base_case: (optional) bool. whether to keep the base case in returned list of verification cases. Default to False.
base_case (Dict): base verification input information.
update_key_value (Dict): the same format as the `base_case` arg, but the updating fields consist of a list of values to be populated with.
keep_base_case (bool, optional): whether to keep the base case in returned list of verification cases. Default to False.

Returns:
List, A list of Dict, each dict is a generated case from the base case.
List: A list of Dict, each dict is a generated case from the base case.
"""

# return all the updating value lists' length
Expand Down Expand Up @@ -221,11 +221,11 @@ def validate_verification_case_structure(
"""Validate verification case structure (e.g., check whether `run_simulation`, `simulation_IO`, etc. exist or not). Check if required key / values pairs exist in the case. check if datatype of values are appropriate, e.g. file path is str.

Args:
case: dict. case information that will be validated.
verbose: bool. whether to output verbose information. Default to False.
case (Dict): case information that will be validated.
verbose (bool): whether to output verbose information. Default to False.

Returns:
Bool, indicating whether the case structure is valid or not.
bool: indicating whether the case structure is valid or not.
"""

def _validate_case_structure_helper(schema, instance, verbose) -> Union[bool]:
Expand Down Expand Up @@ -320,8 +320,8 @@ def save_verification_cases_to_json(
"""Save verification cases to a dedicated file. The cases list consists of verification case dicts.

Args:
json_path: str. json file path to save the cases.
cases: List. List of complete verification cases Dictionary to save.
json_path (str): json file path to save the cases.
cases (List): List of complete verification cases Dictionary to save.
"""
# check `json_path` type
if not isinstance(json_path, str):
Expand Down Expand Up @@ -350,6 +350,14 @@ def save_verification_cases_to_json(
json.dump(case_suite_in_template_format, fw, indent=4)

def read_case(self, file_name: str) -> List:
"""Reads cases from file

Args:
file_name (str): file name to read from

Returns:
List: cases
"""
# load the cases from file_path
with open(file_name, "r") as f:
loaded_cases = json.load(f)
Expand All @@ -367,26 +375,63 @@ def read_case(self, file_name: str) -> List:

@staticmethod
def same_case(case_a: {}, case_b: {}, ignored_keys=["case_id_in_suite"]) -> bool:
"""Returns whether two cases have the same items, ignoring a given list of keys

Args:
case_a (Dict): First case in check
case_b (Dict): Second case in check
ignored_keys (List, optional): keys to ignore, defaults to ["case_id_in_suite"]

Returns:
bool: True if cases are the same, False otherwise
"""
case_a_new = {k: v for k, v in case_a.items() if k not in ignored_keys}
case_b_new = {k: v for k, v in case_b.items() if k not in ignored_keys}
return case_a_new == case_b_new

def case_already_in_suite(
self, case: {}, ignored_keys=["case_id_in_suite"]
) -> bool:
"""Returns whether or not case is already in case suite, ignoring a given list of keys

Args:
case (Dict): case in question
ignored_keys (List, optional): keys to ignore, defaults to ["case_id_in_suite"]

Returns:
bool: True if case is in suite, False otherwise
"""
for k, v in self.case_suite.items():
if self.same_case(case, v, ignored_keys=ignored_keys):
return True
return False

@staticmethod
def check_json_path_type(json_path: str) -> bool:
"""Checks whether path is a json file

Args:
json_path (str): path to check

Returns:
bool: True if path is a .json, False otherwise
"""
return True if json_path[-5:] == ".json" else False

@staticmethod
def check_type(
var_name: str, var_value: Union[str, list, dict], var_type: type
) -> bool:
"""Returns whether value is of a given type

Args:
var_name (str): name of variable
var_value (str, List, Dict): value of variable
var_type (type): type of variable

Returns:
bool: True if value is of given type, False otherwise
"""
if var_value is None:
# no error msg if None
return False
Expand All @@ -400,6 +445,15 @@ def check_type(

@staticmethod
def check_file(file_path_name: str, file_path: str) -> bool:
"""Checks whether file exists

Args:
file_path_name (str): name of file path
file_path (str): file path

Returns:
bool: True if file path exists, False otherwise
"""
if os.path.isfile(file_path):
return True
else:
Expand Down
16 changes: 8 additions & 8 deletions constrain/api/verification_library.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,10 +120,10 @@ def validate_library(self, items: List[str] = None) -> Dict:
"""Check the validity of library items definition. This validity check includes checking the completeness of json specification (against library json schema) and Python verification class definition (against library class interface) and the match between the json and python implementation.

Args:
items: list of str, default []. Library items to validate. `items` must be filled with valid verification item(s). If not, an error occurs.
items (List): Library items to validate. `items` must be filled with valid verification item(s). If not, an error occurs. Defaults to empty list.

Returns:
Dict that contains validity information of library items.
Dict: Dict that contains validity information of library items.
"""

# check `items` type
Expand Down Expand Up @@ -191,10 +191,10 @@ def get_library_items(self, items: List[str] = []) -> Union[List, None]:
"""Get the json definition and meta information of a list of specific library items.

Args:
items: list of str, default []. Library items to get. By default, get all library items loaded at instantiation.
items (List, optional): Library items to get. By default, get all library items loaded at instantiation. Defaults to empty list.

Returns:
list of `Dict` with four specific keys:
List: list of `Dict` with four specific keys:
- `library_item_name`: unique str name of the library item.
- `library_json`: library item json definition in the library json file.
- `library_json_path`: path of the library json file that contains this library item.
Expand Down Expand Up @@ -226,10 +226,10 @@ def get_applicable_library_items_by_datapoints(
"""Based on provided datapoints lists, identify potentially applicable library items from all loaded items. Use this function with caution as it 1) requires aligned data points naming across all library items; 2) does not check the topological relationships between datapoints.

Args:
datapoints: list of str datapoints names.
datapoints (List): Datapoints names.

Returns:
Dict with keys being the library item names and values being the required datapoints for the corresponding keys.
Dict: Dict with keys being the library item names and values being the required datapoints for the corresponding keys.
"""

# check `datapoints` type
Expand Down Expand Up @@ -271,10 +271,10 @@ def get_required_datapoints_by_library_items(
"""Summarize datapoints that need to be used to support specified library items. Use this function with caution as it 1) requires aligned data points naming across all library items; 2) does not check the topological relationships between datapoints.

Args:
items: list of str, default []. Library items to summarize datapoints from. By default, summarize all library items loaded at instantiation.
items (List): Library items to summarize datapoints from. By default, summarize all library items loaded at instantiation. Defaults to empty list.

Returns:
Dict with keys being the datapoint name and values being a sub Dict with the following keys:
Dict: Dict with keys being the datapoint name and values being a sub Dict with the following keys:
- number_of_items_using_this_datapoint: int, number of library items that use this datapoint.
- library_items_list: List, of library item names that use this datapoint.
"""
Expand Down
33 changes: 31 additions & 2 deletions constrain/app/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
QFileDialog,
QMessageBox,
)
from PyQt6.QtCore import Qt, QRectF
from PyQt6.QtGui import QAction, QPixmap, QPainter, QColor
from PyQt6.QtCore import Qt, QRectF, QUrl
from PyQt6.QtGui import QAction, QPixmap, QPainter, QColor, QDesktopServices

from constrain.app.import_form import ImportForm
from constrain.app.meta_form import MetaForm
Expand Down Expand Up @@ -52,6 +52,17 @@ def initialize_ui(self):
)
self.column_list.setCurrentItem(self.column_list.item(0))

meta_item = self.column_list.item(0)
meta_item.setToolTip("Metadata about the workflow")

import_item = self.column_list.item(1)
import_item.setToolTip("Python package import needed to run the workflow")

state_item = self.column_list.item(2)
state_item.setToolTip(
"Sequential steps to follow to perform the verification; 'states' can either be 'MethodCall' which represent a method call to one of ConStrain’s APIs or a 'Choice' which can be used to help define alternative steps in a workflow based on the result (referred to as payloads in a workflow)."
)

# make and reposition frame containing meta, imports, and state
self.column_frame = QFrame()
self.column_frame.setFrameStyle(QFrame.Shape.NoFrame)
Expand Down Expand Up @@ -140,8 +151,26 @@ def initialize_toolbar(self):

settings_menu.addMenu(popup_settings_menu)

help_menu = QMenu("Help", self)

open_github_action = QAction("GitHub Repository", self)
open_github_action.triggered.connect(self.open_github)

open_docs_action = QAction("Documentation", self)
open_docs_action.triggered.connect(self.open_docs)

help_menu.addAction(open_github_action)
help_menu.addAction(open_docs_action)

toolbar.addAction(file_menu.menuAction())
toolbar.addAction(settings_menu.menuAction())
toolbar.addAction(help_menu.menuAction())

def open_docs(self):
QDesktopServices.openUrl(QUrl("https://pnnl.github.io/ConStrain/index.html"))

def open_github(self):
QDesktopServices.openUrl(QUrl("https://github.com/pnnl/ConStrain"))

def basicPopupSetting(self):
self.states_form.setting = "basic"
Expand Down
Loading
Loading