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

Add Xopt and Badger version into routine #101

Merged
merged 19 commits into from
Oct 22, 2024
Merged
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
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ __pycache__
*.pickle
*.db
.vscode
src/badger/_version.py
src/badger/_version.py
.coverage*
4 changes: 4 additions & 0 deletions src/badger/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,10 @@ def get_generator_docs(name):
return generators[name].__doc__


def get_env_docs(name):
return load_docs(BADGER_PLUGIN_ROOT, name, 'environment')


def get_intf(name):
return get_plug(BADGER_PLUGIN_ROOT, name, 'interface')

Expand Down
3 changes: 3 additions & 0 deletions src/badger/gui/default/components/env_cbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,12 @@ def init_ui(self):
btn_env_play.setFixedSize(128, 24)
if not strtobool(read_value('BADGER_ENABLE_ADVANCED')):
btn_env_play.hide()
self.btn_docs = btn_docs = QPushButton('Open Docs')
btn_docs.setFixedSize(128, 24)
hbox_name.addWidget(lbl)
hbox_name.addWidget(cb, 1)
hbox_name.addWidget(btn_env_play)
hbox_name.addWidget(btn_docs)
vbox.addWidget(name)

params = QWidget()
Expand Down
18 changes: 16 additions & 2 deletions src/badger/gui/default/components/routine_page.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@
from .filter_cbox import BadgerFilterBox
from .state_item import state_item
from ..windows.docs_window import BadgerDocsWindow
from ..windows.env_docs_window import BadgerEnvDocsWindow
from ..windows.edit_script_dialog import BadgerEditScriptDialog
from ..windows.lim_vrange_dialog import BadgerLimitVariableRangeDialog
from ..windows.review_dialog import BadgerReviewDialog
from ..windows.var_dialog import BadgerVariableDialog
from ..windows.add_random_dialog import BadgerAddRandomDialog
from ..windows.message_dialog import BadgerScrollableMessageBox
from ..windows.expandable_message_box import ExpandableMessageBox
Expand All @@ -45,7 +45,10 @@
from ....factory import list_generators, list_env, get_env
from ....routine import Routine
from ....settings import read_value
from ....utils import get_yaml_string, load_config, strtobool
from ....utils import (
get_yaml_string, load_config, strtobool,
get_badger_version, get_xopt_version
)

CONS_RELATION_DICT = {
'>': 'GREATER_THAN',
Expand All @@ -67,6 +70,7 @@ def __init__(self):
self.routine = None
self.script = ''
self.window_docs = BadgerDocsWindow(self, '')
self.window_env_docs = BadgerEnvDocsWindow(self, '')
self.vars_env = None # needed for passing env vars to the var table

# Limit variable ranges
Expand Down Expand Up @@ -183,6 +187,7 @@ def config_logic(self):
self.generator_box.btn_edit_script.clicked.connect(self.edit_script)
self.env_box.cb.currentIndexChanged.connect(self.select_env)
self.env_box.btn_env_play.clicked.connect(self.open_playground)
self.env_box.btn_docs.clicked.connect(self.open_environment_docs)
self.env_box.btn_add_var.clicked.connect(self.add_var)
self.env_box.btn_lim_vrange.clicked.connect(self.limit_variable_ranges)
self.env_box.btn_add_con.clicked.connect(self.add_constraint)
Expand Down Expand Up @@ -518,6 +523,9 @@ def select_env(self, i):

self.env_box.update_stylesheets(env.name)

# Update the docs
self.window_env_docs.update_docs(env.name)

def get_init_table_header(self):
table = self.env_box.init_table
header_list = []
Expand Down Expand Up @@ -634,6 +642,9 @@ def open_playground(self):
def open_generator_docs(self):
self.window_docs.show()

def open_environment_docs(self):
self.window_env_docs.show()

def add_var(self):
# TODO: Use a cached env
env_params = load_config(self.env_box.edit.toPlainText())
Expand Down Expand Up @@ -925,6 +936,9 @@ def _compose_routine(self) -> Routine:

with warnings.catch_warnings(record=True) as caught_warnings:
routine = Routine(
# Metadata
badger_version=get_badger_version(),
xopt_version=get_xopt_version(),
# Xopt part
vocs=vocs,
generator={"name": generator_name} | generator_params,
Expand Down
61 changes: 61 additions & 0 deletions src/badger/gui/default/windows/env_docs_window.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
from PyQt5.QtWidgets import QTextEdit, QHBoxLayout, QVBoxLayout, QCheckBox, QWidget, QMainWindow
from ....factory import get_env_docs


class BadgerEnvDocsWindow(QMainWindow):
def __init__(self, parent, env_name):
super().__init__(parent=parent)

self.env_name = env_name
self.render_md = True
self.docs = None

self.init_ui()
self.config_logic()
self.load_docs()

def init_ui(self):
self.setWindowTitle(f'Docs for environment {self.env_name}')
self.resize(640, 640)

doc_panel = QWidget(self)
vbox = QVBoxLayout(doc_panel)

# Toolbar
toolbar = QWidget()
hbox_tool = QHBoxLayout(toolbar)
hbox_tool.setContentsMargins(0, 0, 0, 0)
self.cb_md = cb_md = QCheckBox('Render as Markdown')
cb_md.setChecked(True)
hbox_tool.addStretch()
hbox_tool.addWidget(cb_md)
vbox.addWidget(toolbar)

self.markdown_viewer = QTextEdit()
self.markdown_viewer.setReadOnly(True)
vbox.addWidget(self.markdown_viewer)

self.setCentralWidget(doc_panel)

def config_logic(self):
self.cb_md.stateChanged.connect(self.switch_render_mode)

def load_docs(self):
try:
self.docs = docs = get_env_docs(self.env_name)
except Exception as e:
self.docs = docs = str(e)

if self.render_md:
self.markdown_viewer.setMarkdown(docs)
else:
self.markdown_viewer.setText(docs)

def update_docs(self, env_name):
self.env_name = env_name
self.setWindowTitle(f'Docs for environment {env_name}')
self.load_docs()

def switch_render_mode(self):
self.render_md = self.cb_md.isChecked()
self.load_docs()
12 changes: 5 additions & 7 deletions src/badger/routine.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,9 @@ class Routine(Xopt):
vrange_limit_options: Optional[dict] = Field(None)
initial_point_actions: Optional[List] = Field(None)
additional_variables: Optional[List[str]] = Field([])
# Store relative to current params
relative_to_current: Optional[bool] = Field(False)
vrange_limit_options: Optional[dict] = Field(None)
initial_point_actions: Optional[List] = Field(None)
additional_variables: Optional[List[str]] = Field([])
# Other meta data
badger_version: Optional[str] = Field(None)
xopt_version: Optional[str] = Field(None)

model_config = ConfigDict(arbitrary_types_allowed=True)

Expand Down Expand Up @@ -164,7 +162,7 @@ def json(self, **kwargs) -> str:
except AttributeError:
pass

return json.dumps(dict_result)
return json.dumps(dict_result)

def __eq__(self, routine):
if not isinstance(routine, Routine):
Expand All @@ -174,7 +172,7 @@ def __eq__(self, routine):
routine_dict = json.loads(routine.json())
routine_dict.pop('data')
return self_dict == routine_dict

def __hash__(self):
self_dict = json.loads(self.json())
self_dict.pop('data')
Expand Down
4 changes: 4 additions & 0 deletions src/badger/tests/test_db.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,8 @@ def test_load_routine(self):
assert new_routine.generator == routine.generator
assert new_routine.vocs == routine.vocs

# Test if xopt and badger version are defined in the routine
assert hasattr(new_routine, 'xopt_version')
assert hasattr(new_routine, 'badger_version')

remove_routine("test")
5 changes: 5 additions & 0 deletions src/badger/tests/test_routine_page.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ def test_routine_page_init(qtbot):

def test_routine_generation(qtbot):
from badger.errors import BadgerRoutineError
from badger.utils import get_badger_version, get_xopt_version

# test if a simple routine can be created
from badger.gui.default.components.routine_page import BadgerRoutinePage
Expand Down Expand Up @@ -48,6 +49,10 @@ def test_routine_generation(qtbot):
assert routine.vocs.objectives == {"f": "MINIMIZE"}
assert routine.initial_points.empty

# Test if badger and xopt version match with the current version
assert routine.badger_version == get_badger_version()
assert routine.xopt_version == get_xopt_version()


def test_add_additional_vars(qtbot):
from badger.db import load_routine, remove_routine
Expand Down
9 changes: 9 additions & 0 deletions src/badger/utils.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from importlib import metadata
import json
import logging
import os
Expand Down Expand Up @@ -314,3 +315,11 @@ def get_datadir() -> pathlib.Path:
return home / ".local/share"
elif sys.platform == "darwin":
return home / "Library/Application Support"


def get_badger_version():
return metadata.version('badger-opt')


def get_xopt_version():
return metadata.version('xopt')