Add ability to update custom Function module in-place#1516
Conversation
Co-authored-by: kizniche <838427+kizniche@users.noreply.github.com>
Co-authored-by: kizniche <838427+kizniche@users.noreply.github.com>
|
@copilot In utils.settings.py, you set "controller_device_name = form.controller_id.data" and then compare "controller_info.FUNCTION_INFORMATION['function_name_unique'].lower() != controller_device_name.lower()", however, this appears to be initially setting the function name to the filename of the uploaded file? The unique function name is contained within the module file, in the FUNCTION_INFORMATION dict, key function_name_unique. To compare the existing unique name to the uploaded file unique name, you will need to get the dict form the new file. Check the import code for how the file is validated, as there are several sanity checks before an uploaded file can be accepted. For this replacement, the unique name must be the same. |
…estart when activated; add tests Co-authored-by: kizniche <838427+kizniche@users.noreply.github.com>
Co-authored-by: kizniche <838427+kizniche@users.noreply.github.com>
Fixed in commit Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
There was a problem hiding this comment.
Pull request overview
Adds an in-place “update/overwrite” flow for custom Function modules on the Settings → Function page, reducing the need to delete/recreate dependent Function instances during iterative development.
Changes:
- Add a new
ControllerModform and POST handling to update an existing custom Function module by uploading a replacement file. - Implement
settings_function_update()to validateFUNCTION_INFORMATION['function_name_unique']matches the existing module, overwrite the on-disk module, reload frontend, and optionally restart the daemon if any dependent Functions are activated. - Add unit tests for update success/failure scenarios; update
.gitignoreand changelog accordingly.
Reviewed changes
Copilot reviewed 6 out of 7 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
mycodo/mycodo_flask/utils/utils_settings.py |
Adds settings_function_update() implementation for module replacement + reload/restart logic. |
mycodo/mycodo_flask/forms/forms_settings.py |
Introduces ControllerMod (hidden controller_id + upload field + submit). |
mycodo/mycodo_flask/routes_settings.py |
Wires new form + POST dispatch and passes form to template. |
mycodo/mycodo_flask/templates/settings/function.html |
Adds per-row file picker + “Replace” button next to Delete. |
mycodo/tests/software_tests/test_mycodo_flask/test_utils_settings.py |
Adds unit tests covering update behavior and edge cases. |
.gitignore / CHANGELOG.md |
Ignores session artifacts, ensures tests are tracked, and documents the feature. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…oller_id in update handler Co-authored-by: kizniche <838427+kizniche@users.noreply.github.com>
|
Just as a heads up, I was blocked by some firewall rules while working on your feedback. Expand below for details. Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
Updating a custom Function module required deleting all dependent Function instances, removing the module, re-uploading, and recreating everything — making iterative development painful.
Changes
ControllerModform (forms_settings.py): New form withFileFieldfor the replacement file and a submit button.controller_idis no longer duplicated here — it is supplied byControllerDelwhich shares the same<form>tag per row.settings_function_update(form_del, form)(utils_settings.py): New handler that readscontroller_idfromform_del(the sharedControllerDelform) and the replacement file fromform. Validates by loading both the existing on-disk module and the uploaded module, extractingfunction_name_uniquefrom each file'sFUNCTION_INFORMATIONdict, and comparing them. The uploaded file's filename is irrelevant — only the dict value determines a match. On success, overwrites the existing module file, triggers a frontend reload, and restarts the backend daemon only if at least oneCustomControllerusing this module is currently activated.Route (
routes_settings.py): Instantiatesform_controller_update, dispatches tosettings_function_update(form_controller_delete, form_controller_update)on POST, passes both forms to the template.Template (
function.html): Each row in the Imported Function Modules table renders a singlecontroller_idhidden field (fromform_controller_delete), a file-picker, and an "Update Controller Module" button alongside the existing Delete button, inside a singleenctype="multipart/form-data"form with a JS confirmation dialog.CHANGELOG.md: Feature entry added under 8.17.0.test_utils_settings.py(new): 8 unit tests using splitmake_del_form/make_mod_formhelpers matching the two-argument signature — covering success with no activated functions (frontend reload only), success with an activated function (frontend reload + daemon restart), overwrite of existing file content, no file submitted, empty filename submitted, different upload filename with matching dict unique name (succeeds), different upload filename with mismatched dict unique name (fails), and invalid Python file. Amock_mycodo_userfixture patchespwd.getpwnam/grp.getgrnaminsystem_pito return the current process UID/GID soos.chownexercises its real code path without requiring amycodosystem account in CI..gitignore: Added/mycodo/flask_session/to exclude test-generated session files; added!mycodo/tests/negation so the new test file is tracked.Original prompt
💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.