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

Identifying routines internally by id instead of name #100

Merged
merged 12 commits into from
Oct 28, 2024

Conversation

shamin-slac
Copy link
Collaborator

  • Added an optional id field to the Routine class
  • When a new routine is saved, the id is created in the save_routine() method in db.py
  • Changed all database methods to reference routines by id instead of name
  • Updated the rest of the gui functionality accordingly
  • Updated tests accordingly
  • Now multiple routines can have the same name
  • If a routine has no runs, changes to the routine will simply update the routine
  • If a routine has runs and the only change is name and/or description, it will simply update the routine
  • If a routine has runs and there are changes that are not name and/or description, a new routine will be created

Copy link
Collaborator

@roussel-ryan roussel-ryan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good so far, I added some comments and I think we need some testing to make sure the ID behavior is as advertised.


con.commit()
con.close()


@maybe_create_routines_db
def load_routine(name: str):
def load_routine(id: str):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you said that the routine ID is optional? How is that handled in this function?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function just takes an id, not a whole routine. In principle, the only place where there is a routine without an id is when a routine is composed from the routine editor (this is the main motivation to have id as an optional and not required field in the Routine class). Then in the save_routine() function, the id is generated and stored in that routine which is then saved in the database (and then it is subsequently retrieved for use in Badger). That being said, there are a couple places where I can imagine it's not impossible that there is no id, so I've modified the function to handle this possibility.

src/badger/db.py Outdated
@@ -20,7 +21,6 @@
logger.info(
f'Badger database root {BADGER_DB_ROOT} created')


def maybe_create_routines_db(func):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this isn't a change from this PR but could be come up with a better name for this @zhe-slac @shamin-slac

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe ensure_routines_db_exists or require_routines_db?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so what is the purpose of this decorator?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To create the routines database if it doesn't already exist.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In that case I'm liking the ensure_routines_db_exists name and I would add a small docstring to the decorator that describes what it does

@@ -36,7 +36,7 @@ def test_home_page_run_routine(qtbot, init_multiprocessing):
]

for ele in routines:
save_routine(ele)
ele.id = save_routine(ele)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we do some additional testing here to make sure the ID generation is correct? Should also probably do a standalone file

@@ -67,7 +67,7 @@ def test_run_routine_subprocess(

self.routine = create_routine()
time.sleep(1)
save_routine(self.routine)
self.routine.id = save_routine(self.routine)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should save_routine be setting the routine ID in place instead of what is done here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that's my bad! I forgot that I was already setting the id of the routine object inside the save_routine() function itself haha. I've edited out these separate id assignments.

@shamin-slac
Copy link
Collaborator Author

Looks good so far, I added some comments and I think we need some testing to make sure the ID behavior is as advertised.

I've added some tests for the routine id behavior. It should be good to go, but let me know what you think.

@roussel-ryan
Copy link
Collaborator

roussel-ryan commented Oct 23, 2024

@shamin-slac I tried running badger from your fork with a fresh install (which has an empty badger database I think) and ran into the following issue. I would suggest that you try to recreate this issue in your tests (which may involve clearing out the run database before running the tests) and then implement a fix to solve the issue

Traceback (most recent call last):
  File "/home/rroussel/miniforge3/envs/badger/bin/badger", line 8, in <module>
    sys.exit(main())
             ~~~~^^
  File "/home/rroussel/Badger/src/badger/__main__.py", line 108, in main
    args.func(args)
    ~~~~~~~~~^^^^^^
  File "/home/rroussel/Badger/src/badger/actions/__init__.py", line 15, in show_info
    launch_gui()
    ~~~~~~~~~~^^
  File "/home/rroussel/Badger/src/badger/gui/default/__init__.py", line 75, in launch_gui
    window = BadgerMainWindow()
  File "/home/rroussel/Badger/src/badger/gui/default/windows/main_window.py", line 22, in __init__
    self.init_ui()
    ~~~~~~~~~~~~^^
  File "/home/rroussel/Badger/src/badger/gui/default/windows/main_window.py", line 80, in init_ui
    self.home_page = BadgerHomePage(self.process_manager)
                     ~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
  File "/home/rroussel/Badger/src/badger/gui/default/pages/home_page.py", line 93, in __init__
    self.init_ui()
    ~~~~~~~~~~~~^^
  File "/home/rroussel/Badger/src/badger/gui/default/pages/home_page.py", line 152, in init_ui
    self.refresh_routine_list()
    ~~~~~~~~~~~~~~~~~~~~~~~~~^^
  File "/home/rroussel/Badger/src/badger/gui/default/pages/home_page.py", line 390, in refresh_routine_list
    routine_ids, routine_names, timestamps, environments, descriptions = self.get_current_routines()
                                                                         ~~~~~~~~~~~~~~~~~~~~~~~~~^^
  File "/home/rroussel/Badger/src/badger/gui/default/pages/home_page.py", line 385, in get_current_routines
    routine_ids, routine_names, timestamps, environments, descriptions = list_routine(keyword, tags)
                                                                         ~~~~~~~~~~~~^^^^^^^^^^^^^^^
  File "/home/rroussel/Badger/src/badger/db.py", line 37, in func_safe
    return func(*args, **kwargs)
  File "/home/rroussel/Badger/src/badger/db.py", line 196, in list_routine
    cur.execute(f'select id, name, config, savedAt from routine where name like "%{keyword}%" order by savedAt desc')
    ~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
sqlite3.OperationalError: no such column: id

@shamin-slac
Copy link
Collaborator Author

shamin-slac commented Oct 23, 2024

@shamin-slac I tried running badger from your fork with a fresh install (which has an empty badger database I think) and ran into the following issue. I would suggest that you try to recreate this issue in your tests (which may involve clearing out the run database before running the tests) and then implement a fix to solve the issue

Traceback (most recent call last):
  File "/home/rroussel/miniforge3/envs/badger/bin/badger", line 8, in <module>
    sys.exit(main())
             ~~~~^^
  File "/home/rroussel/Badger/src/badger/__main__.py", line 108, in main
    args.func(args)
    ~~~~~~~~~^^^^^^
  File "/home/rroussel/Badger/src/badger/actions/__init__.py", line 15, in show_info
    launch_gui()
    ~~~~~~~~~~^^
  File "/home/rroussel/Badger/src/badger/gui/default/__init__.py", line 75, in launch_gui
    window = BadgerMainWindow()
  File "/home/rroussel/Badger/src/badger/gui/default/windows/main_window.py", line 22, in __init__
    self.init_ui()
    ~~~~~~~~~~~~^^
  File "/home/rroussel/Badger/src/badger/gui/default/windows/main_window.py", line 80, in init_ui
    self.home_page = BadgerHomePage(self.process_manager)
                     ~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
  File "/home/rroussel/Badger/src/badger/gui/default/pages/home_page.py", line 93, in __init__
    self.init_ui()
    ~~~~~~~~~~~~^^
  File "/home/rroussel/Badger/src/badger/gui/default/pages/home_page.py", line 152, in init_ui
    self.refresh_routine_list()
    ~~~~~~~~~~~~~~~~~~~~~~~~~^^
  File "/home/rroussel/Badger/src/badger/gui/default/pages/home_page.py", line 390, in refresh_routine_list
    routine_ids, routine_names, timestamps, environments, descriptions = self.get_current_routines()
                                                                         ~~~~~~~~~~~~~~~~~~~~~~~~~^^
  File "/home/rroussel/Badger/src/badger/gui/default/pages/home_page.py", line 385, in get_current_routines
    routine_ids, routine_names, timestamps, environments, descriptions = list_routine(keyword, tags)
                                                                         ~~~~~~~~~~~~^^^^^^^^^^^^^^^
  File "/home/rroussel/Badger/src/badger/db.py", line 37, in func_safe
    return func(*args, **kwargs)
  File "/home/rroussel/Badger/src/badger/db.py", line 196, in list_routine
    cur.execute(f'select id, name, config, savedAt from routine where name like "%{keyword}%" order by savedAt desc')
    ~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
sqlite3.OperationalError: no such column: id

@roussel-ryan I think this is because you already have a routine table in the routines.db file in BADGER_DB_ROOT (which by default is ~/.local/share/Badger/db) from an old install of Badger, which is why it doesn't have the id column. So I would say this is a backwards compatibility issue.

@roussel-ryan
Copy link
Collaborator

roussel-ryan commented Oct 24, 2024

Got it, thanks. Can we add some code to handle this and other issues when loading old routines? I think we discussed adding some kind of warning triangle to routines that failed to load in the GUI instead of raising errors during startup. We can also discuss this tomorrow

Copy link
Collaborator

@roussel-ryan roussel-ryan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm, thanks for the great work @shamin-slac

@roussel-ryan roussel-ryan merged commit 6514fec into xopt-org:main Oct 28, 2024
5 checks passed
@shamin-slac shamin-slac deleted the id branch October 28, 2024 17:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants