Skip to content

Commit 127086d

Browse files
HugoCLSCdependabot[bot]Robert0MartRobertogmmcosta15
authored
Update (#197)
* Build(deps): Bump requests from 2.32.3 to 2.32.4 in /scripts (#105) Bumps [requests](https://github.com/psf/requests) from 2.32.3 to 2.32.4. - [Release notes](https://github.com/psf/requests/releases) - [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md) - [Commits](psf/requests@v2.32.3...v2.32.4) --- updated-dependencies: - dependency-name: requests dependency-version: 2.32.4 dependency-type: direct:production ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Hugoclsc/feature/GitHub actions (#107) * initial actions * Update CodeQL workflow to ignore certain paths Ignore specific paths for CodeQL analysis on push and pull request events. * experimenting workflows * Add pylintrc configuration file, configure dev test code workflow * split into multiple jobs * Fail job on error * pylint rc file, jobs refactores for dev workflow * Remove upload artifacts for now, move pylintrc file to root dir * Added upload artifacts with different files * Rem: branch naming workflow, enviroment handles this * Added fail-fast to false * Run only on PR to dev * Change file name * Hugoclsc/feature/GitHub actions (#113) * initial actions * Update CodeQL workflow to ignore certain paths Ignore specific paths for CodeQL analysis on push and pull request events. * experimenting workflows * Add pylintrc configuration file, configure dev test code workflow * split into multiple jobs * Fail job on error * pylint rc file, jobs refactores for dev workflow * Remove upload artifacts for now, move pylintrc file to root dir * Added upload artifacts with different files * Rem: branch naming workflow, enviroment handles this * Added fail-fast to false * Run only on PR to dev * Change file name * Initial stage-ci workflow configuration * Changed worflow name, added docstr-coverage tool to the workflow * Added dependencies cache, reduces redundant installations, fixes incorrect pytest file * Exclude F403 ruff error * Added docstr-coverage dependency * Fix incorrect requirements installation command * bugfix on cli command for docstr-coverage * Uncomment artifact upload * Update pyproject.toml * Added bandig config, bump requests version * Bump requests version * Bump requirement versions * Add dev, stage requirements, bump all requirements * Migrate pylint config options to pyproject.toml file * Deleted pylintrc.dev file * Remove unused dependencie * uncomment upload artifacts * Added bandit security tests * Standardize bandit output to json * Add environment --------- Signed-off-by: Hugo Costa <hugo.santos.costa@gmail.com> * Hugoclsc/feature/GitHub actions (#114) * initial actions * Update CodeQL workflow to ignore certain paths Ignore specific paths for CodeQL analysis on push and pull request events. * experimenting workflows * Add pylintrc configuration file, configure dev test code workflow * split into multiple jobs * Fail job on error * pylint rc file, jobs refactores for dev workflow * Remove upload artifacts for now, move pylintrc file to root dir * Added upload artifacts with different files * Rem: branch naming workflow, enviroment handles this * Added fail-fast to false * Run only on PR to dev * Change file name * Initial stage-ci workflow configuration * Changed worflow name, added docstr-coverage tool to the workflow * Added dependencies cache, reduces redundant installations, fixes incorrect pytest file * Exclude F403 ruff error * Added docstr-coverage dependency * Fix incorrect requirements installation command * bugfix on cli command for docstr-coverage * Uncomment artifact upload * Update pyproject.toml * Added bandig config, bump requests version * Bump requests version * Bump requirement versions * Add dev, stage requirements, bump all requirements * Migrate pylint config options to pyproject.toml file * Deleted pylintrc.dev file * Remove unused dependencie * uncomment upload artifacts * Added bandit security tests * Standardize bandit output to json * Add environment * Fix incorrect file extension for bandit --------- Signed-off-by: Hugo Costa <hugo.santos.costa@gmail.com> * Hugoclsc/feature/GitHub actions (#115) * initial actions * Update CodeQL workflow to ignore certain paths Ignore specific paths for CodeQL analysis on push and pull request events. * experimenting workflows * Add pylintrc configuration file, configure dev test code workflow * split into multiple jobs * Fail job on error * pylint rc file, jobs refactores for dev workflow * Remove upload artifacts for now, move pylintrc file to root dir * Added upload artifacts with different files * Rem: branch naming workflow, enviroment handles this * Added fail-fast to false * Run only on PR to dev * Change file name * Initial stage-ci workflow configuration * Changed worflow name, added docstr-coverage tool to the workflow * Added dependencies cache, reduces redundant installations, fixes incorrect pytest file * Exclude F403 ruff error * Added docstr-coverage dependency * Fix incorrect requirements installation command * bugfix on cli command for docstr-coverage * Uncomment artifact upload * Update pyproject.toml * Added bandig config, bump requests version * Bump requests version * Bump requirement versions * Add dev, stage requirements, bump all requirements * Migrate pylint config options to pyproject.toml file * Deleted pylintrc.dev file * Remove unused dependencie * uncomment upload artifacts * Added bandit security tests * Standardize bandit output to json * Add environment * Fix incorrect file extension for bandit * Add exclude section to ruff config * Fix docstr-converage exclude regex --------- Signed-off-by: Hugo Costa <hugo.santos.costa@gmail.com> * Hugoclsc/feature/GitHub actions (#116) * initial actions * Update CodeQL workflow to ignore certain paths Ignore specific paths for CodeQL analysis on push and pull request events. * experimenting workflows * Add pylintrc configuration file, configure dev test code workflow * split into multiple jobs * Fail job on error * pylint rc file, jobs refactores for dev workflow * Remove upload artifacts for now, move pylintrc file to root dir * Added upload artifacts with different files * Rem: branch naming workflow, enviroment handles this * Added fail-fast to false * Run only on PR to dev * Change file name * Initial stage-ci workflow configuration * Changed worflow name, added docstr-coverage tool to the workflow * Added dependencies cache, reduces redundant installations, fixes incorrect pytest file * Exclude F403 ruff error * Added docstr-coverage dependency * Fix incorrect requirements installation command * bugfix on cli command for docstr-coverage * Uncomment artifact upload * Update pyproject.toml * Added bandig config, bump requests version * Bump requests version * Bump requirement versions * Add dev, stage requirements, bump all requirements * Migrate pylint config options to pyproject.toml file * Deleted pylintrc.dev file * Remove unused dependencie * uncomment upload artifacts * Added bandit security tests * Standardize bandit output to json * Add environment * Fix incorrect file extension for bandit * Add exclude section to ruff config * Fix docstr-converage exclude regex * Separate CI from CD --------- Signed-off-by: Hugo Costa <hugo.santos.costa@gmail.com> * Refactor/tests compliance (#117) * Build(deps): Bump requests from 2.32.3 to 2.32.4 in /scripts (#112) Bumps [requests](https://github.com/psf/requests) from 2.32.3 to 2.32.4. - [Release notes](https://github.com/psf/requests/releases) - [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md) - [Commits](psf/requests@v2.32.3...v2.32.4) --- updated-dependencies: - dependency-name: requests dependency-version: 2.32.4 dependency-type: direct:production ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Removed unused method * Remove unused imports * Remove unused import, f-string without placeholders * Remove unused import * Removed unused module * Removed f-string without placeholder * Removed unused code on method * Removed placeholder file for new module * Removed assigned variable but never used * Removed unused import * Comment unused variable * Removed unused code line * Removed unused file * Explicity re-raise with from * Removed unused code line * Refactor text box painting * Removed unused import * Removed unused code line * Removed unused module * Removed unused module placeholder * Added docstrings * Add docstrings to methods * Add docstring to methods and class * Add docstring to methods * Removed unused module * Added docstrings * Added docstrings * Added docstrings, deleted commented code * Added docstrings, deleted commented code * Added docstrings, deleted commented code * Added docstrings, deleted commented code * deleted commented code * Added docstrings, deleted commented code * Deleted code from unused window * Added docstring to methods, deleted unused code * Added docstring to methods, deleted unused code * Add docsctring, delete commented code * Add docsctring * Add docsctring, delete unused code * Add docstring, change method name * Add docstring, change method name, delete unused code * Add docstring, delete unused code * Add docstring, delete unused code, changed method name * Add docstring, changed method name * Add docstring, changed method name * Add docstring, changed method name * Add docstring, changed method name * Add docstring, changed method name * Formatting * Add docstring * Add docstring, delete unused code, changed method name * Add docstring, delete unused code, changed method name * Add docstring, changed method name * Add docstring, changed method name * Add docstring, delete commented code, change method name * Add docstring, delete commented code, change method name * Let troubleshoot page decide where it wants to go * Add docstring, change method name * Add docstring, delete unused and untested code * Add docstring * Add docstring * Add docstring, delete unused code * Add docstring * Add docstring * Add docstring * Add docstring * Add docstring * Add docstrings * Add docstring, change method name * Add docstring * Add docstring, delete unused code * Add docstring, delete unused code * Add docstring * Change list item docstring * Add docstring * Add docstring * Deleted unused module * Add docstring * Deleted unused method * Deleted unused code line * Delete unused code line * Delete unused code line * Security patch subprocess shell = True, security issue * Remove argument from method * Ruff formatting * Ruff formatting * Surpress Reviewed security issues * Formatting --------- Signed-off-by: dependabot[bot] <support@github.com> Signed-off-by: Hugo Costa <hugo.santos.costa@gmail.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * ADD: added overriedCursor to blank cursor (#118) * ADD: added overriedCursor to blank cursor * Refactor: ran ruff formater --------- Co-authored-by: Roberto <roberto.martins@blockstec.com> * ADD: color degrade when ON/OFF (#120) * Bugfix label overlap (#121) * bugfix: label overlapping when stoped * Upd: rollback some parts * ADD: added delay to marquee effect * bugfix: text when marquee wasnt needed and glow effect * Refactor: Ran ruff formatter * Remove unecessary lambda expression * Add docstring to paintEvent method --------- Co-authored-by: Roberto <roberto.martins@blockstec.com> Co-authored-by: Hugo Costa <hugo.santos.costa@gmail.com> * Bugfix: Delete file handling and QDialog class refactoring (#128) * Refactor: Ran ruff formatter * Remove unecessary lambda expression * Add docstring to paintEvent method * Refactor back signal from reject to request_back * Change delete file button from reject to delete_file_button * Make setupUI method private * Change request back signal name * Make setupUI the last method on file * Separate logic, created get mainwindow widget method * Set dialog modal, add class vars, x and y dialog offsets * Use accept and reject signals for dialog result * implement open method, calculate dialog position relative to window * Refactor cancel print dialog * Simplify print cancel signal emition * Refactor delete file logic * Change delete file signal name * Fix empty directory * Fix directory handling for file deletion operationsFix empty directory * Dev debt --------- Co-authored-by: Roberto Martins <robertomicael.martins@gmail.com> Co-authored-by: Roberto <roberto.martins@blockstec.com> * Work fan page (#119) * ADD: added fans page * add: added fans into fans page * ADD: added line to fans page * Refacotr: changed layout type * UPD: updated options card to have 2 text . added cards into controltab fans * Rev: removed line from fans page * Refactor: refactor on_fan_object_update * Refactor: Ran ruff formatter * Fix incorrect method name * Fix incorrect method name * bugfix: option card clicklable area * Ran: ruff formatter * Bugfix: names being wrong and slider spaming gcodes on change * ADD: color degrade when ON/OFF (#120) * Del: deleted some prints * Bugfix: fan not updating when slider updates * Bugfix: label size * Bugfix: Delete file handling and QDialog class refactoring (#128) * Refactor: Ran ruff formatter * Remove unecessary lambda expression * Add docstring to paintEvent method * Refactor back signal from reject to request_back * Change delete file button from reject to delete_file_button * Make setupUI method private * Change request back signal name * Make setupUI the last method on file * Separate logic, created get mainwindow widget method * Set dialog modal, add class vars, x and y dialog offsets * Use accept and reject signals for dialog result * implement open method, calculate dialog position relative to window * Refactor cancel print dialog * Simplify print cancel signal emition * Refactor delete file logic * Change delete file signal name * Fix empty directory * Fix directory handling for file deletion operationsFix empty directory * Dev debt --------- Co-authored-by: Roberto Martins <robertomicael.martins@gmail.com> Co-authored-by: Roberto <roberto.martins@blockstec.com> * bugfix: option card centering --------- Co-authored-by: Roberto <roberto.martins@blockstec.com> Co-authored-by: Hugo Costa <hugo.santos.costa@gmail.com> * Fix issues intruduced in Bugfix label overlap #121 (#129) * ADD: added fans page * add: added fans into fans page * ADD: added line to fans page * Refacotr: changed layout type * UPD: updated options card to have 2 text . added cards into controltab fans * Rev: removed line from fans page * Refactor: refactor on_fan_object_update * Refactor: Ran ruff formatter * Fix incorrect method name * Fix incorrect method name * bugfix: option card clicklable area * Ran: ruff formatter * Bugfix: names being wrong and slider spaming gcodes on change * ADD: color degrade when ON/OFF (#120) * Del: deleted some prints * Bugfix: fan not updating when slider updates * Bugfix: label size * Fix integration problems #121 fix * Refactor variable into local method variable --------- Signed-off-by: Hugo Costa <hugo.santos.costa@gmail.com> Co-authored-by: Roberto Martins <robertomicael.martins@gmail.com> Co-authored-by: Roberto <roberto.martins@blockstec.com> * Fix Merge problems introduced on the previous pull requests (#131) * Add 'flat' visual property, seperate methods to their own methods * Delete attribute set, BlocksLabel does not have that attribute * Refactor: reorder methods * Fix missing slot for klippy signal, now reacts to klippy connected signal * Delete: touch handlers, will be implemented in the future * Added standard pull request template (#133) * Bugfix: fixed white dot on list_model.py (#130) Fix: white dot on widget lists built using **EntryDelegate** by deleting unused code * Bugfix thumbnail not working (#123) * Refactor: reafactor how thumbnail are painted * Refactor: Ran ruff formatter * Refactor: resolved issues on the code * Adhere to snake casing * Adhere to snake casing * Return event handled * Requests files on websocket open Instead of only requesting the available files when Klippy is ready request them when websocket opens. Moonraker handles the files, so there is no need to wait until klippy is connected. This also ensures that when the screen connects with moonraker and klipper the information about all available print files are ready to be handled by the GUI. This stems from a problem loading the thumbnails. There were many instances of initializing the application mid print, when this happened a request for the available thumbnails is made, because the files are loaded after receiving the klippy ready event, the moment when asking about the current job thumbnail there are not files nor metadata loaded onto the GUI, so no thumbnail is fetched. Now with this change the same situation doesn't occur. * Change on_accept signal types. There is no need to add list type to the signal. The thumbnails were passed there before, we will load the print thumbnails when we get the metadata from the file. Passing the thumbnails here was unnecessary. * Add inner progress bar icon The progress bar fills a circumference until the print is complete, the inner part of the widget is blank and is suposed to have a thumbnail of the current print, before a QGraphicsView overlaped with the progress bar widget. Now we add the functionality to add a pixmap on the progress bar itself. It calculates the scaling for the pixmap to fill the inner part of the progress bar widget without overlaping anything. There are some bugs still, such as what happens when resizeEvent is emitted, the automatic scaling is not working properly yet. * Refactor Thumnail painting and widget building The solution provided by @Robert0Mart showed us that the thumbnail building needed some work, this commit intends to extend that effort to rewrite this feature. We will simplify thumbnail building, less widgets for this feature to work. We will also let the progress bar widget handle the small widget painting, and propagate the click to expand to a bigger thumbnail painting that fills the entire screen. * Final progress bar refactor, send signal on thumbnail click Refactored class method positions to add some structure to the class. Privatised some class variables, should add @Property decorator with getter and setter for these variables since they are actually properties. Captured MousePressEvent of the widget and filtered the events only to those inside the inner rect of the widget, when triggered, send an event `thumbnail_clicked` to signal that the thumbnail was actually clicked. * Refactor `setValue`method Added type for argument, refactored method body readability * Added thumbnail expansion Added initial thumbnail expansion, it works, but it needs to be worked on. We need to hide all widgets so that the thumbnail doesn't have anything on the background while its expanded. this requires us to hide all widgets used one by one. it's not incorrect per-se but it's not the best. The thumbnail is loaded once when the thumbnail is received, so it just paints once and stays in memory until `.show()` and `.hide()` methods are called. Once the print stops for whatever reason. Since the widget is built when the thumbnail comes, the QGraphicsView and its childs are deleted, freeing memory. It'll be built again when a new print job is selected. * Added type for arguments, refactored `setValue` and `set_bar_color` methods. * Reduced conditional branching, added docstring to class Reduced branching on printer object handlers, Added simple docstring to the `jobStatusPage` class. * Conditional logic when thumbnail pixmaps are Null When the provided thumbnails are Null Pixmaps, the should not build the QGraphicsView Widget. Before , even when pixmaps were null, it whould be built, the user could click the progress widget and the scene whould expand, only without anything to show. Now the widget simply does not build anything when all pixmaps are Null. The click signal connections are now done inside the `_load_thumbnails` method, the progress widget pixmap is also set inside that method. Everything related to thumbnails (except the eventFilter method) is now handled inside the `_load_thumbnails` method. The next step, filtering the provided Null Pixmaps. Only load not Null pixmaps * Refactor filter null pixmaps during thumbnail loading Simplified thumbnail filtering. Now i can have any number of Null pixmaps, if no pixmap is usable, cancels thumbnail loading, if there is at least one usable pixmap. It'll load the thumbnails on the progress widget and on the QGraphicsView. This means that if only the smallest resolution is available (48x48) it'll paint with low resolution --------- Co-authored-by: Roberto <roberto.martins@blockstec.com> Co-authored-by: Hugo Costa <hugo.santos.costa@gmail.com> * Bugfix uninitilized variable access introduced on #123 (#141) * Del: reference to uninitialized QGraphicsView variable When there is no thumbnail for the current print, we shouldn't referece `self.thumbnail_view` since it hasn't been initialized. When the print stops for whatever reason we want to delete the object, but if it hasn't been initilialized there is nothing to delete. So we must only delete when the print stops if the class has been attributed. * Added clear thumbnail object on print stop * Small refactor, exit method when page is not visible * Calculate and scale thumbnail pixmap on set When setting the pixmap on the progress bar, the image was not scaled and the inner rect was not calculated. This resulted in the pixmap not showing. Now when setting the progressbar thumbnail this is calculated so that the pixmap can be shown in the middle of the progress bar circumference. * Del forgotten print() * Refactor and handle show event Refactored some methods, including accessing values in dicts, by using .get(). Now the slot `on_fileinfo` only runs when the `jobStatusPage` is visible this is because the request for file information is done on `file.py` and the confirmation page. This whould result in the slot triggering multiple times before it was actually necessary and on asking for imformation for all files, while we only want information on one file. Now the request for file information is done when the `jobStatusPage` is actually visible. The `showEvent` method requests the file information when that event is triggered on the class. * Split print state logic into seperate method Split the state logic in a seperate method (`_handle_print_state(state: str))` just so it's more readable than handling all `print_status` object updates in a single method. It was getting to big of a method. * Change print state event dispatch logic * Refactor `SensorPanel`: replace `QListWidgetItem` with `EntryListModel` (#125) * refactor: migrated sensorsPanel.py sensor list from a QtWidgets.QListWidgetItem to a ListModelView Arq with some bugfixes Signed-off-by: Guilherme Costa <guiherme.costa@blockstec.com> * sensors: resolve bugs and some cleanup Signed-off-by: Guilherme Costa <guiherme.costa@blockstec.com> * sensors: add cutter sensor handling and visual update for list item Signed-off-by: Guilherme Costa <guiherme.costa@blockstec.com> * code cleanup and formatting Signed-off-by: Guilherme Costa <guiherme.costa@blockstec.com> * sensorwidget bugfix Signed-off-by: Guilherme Costa <guiherme.costa@blockstec.com> * sensorsPanel.py: ensure first item is checked on startup sensorWidget.py: lock toggle_button until action succeeds and replace repaint() with update() for proper refresh Signed-off-by: Guilherme Costa <guiherme.costa@blockstec.com> * sensorsPanel.py: reformat code to be complient with ruff guidelines Signed-off-by: Guilherme Costa <guiherme.costa@blockstec.com> --------- Signed-off-by: Guilherme Costa <guiherme.costa@blockstec.com> Co-authored-by: Guilherme Costa <guiherme.costa@blockstec.com> Co-authored-by: HugoCLSC <hugo.santos.costa@gmail.com> * Refactor `filesPage.py`: Changed Files List `QtWidgets.QListWidgetItem` to our custom `EntryListModel` (#126) * FilesPage: Refactor almost complete missing passing the directory by itemclick helper_methods: updated the get_file_loc method to return always the filename instead of the full path Signed-off-by: Guilherme Costa <guiherme.costa@blockstec.com> * filesPage.py: refactor concluded, scrollbar bugfix Signed-off-by: Guilherme Costa <guiherme.costa@blockstec.com> * helper_method.py: Change naming of a method from get_file_loc to get_file_name Signed-off-by: Guilherme Costa <guiherme.costa@blockstec.com> * filesPage.py: code cleanup, small docstring generation and add missing commented lines Signed-off-by: Guilherme Costa <guiherme.costa@blockstec.com> * filesPage.py: remove unused lines of code Signed-off-by: Guilherme Costa <guiherme.costa@blockstec.com> * filesPage.py - fix rebase conflits Signed-off-by: Guilherme Costa <guiherme.costa@blockstec.com> * formatting fix Signed-off-by: Guilherme Costa <guiherme.costa@blockstec.com> * filesPage.py: Add sync timeout and change click behavior in files page Set file list to refresh after 1.5s to improve UI responsiveness. Clicks are now handled in the _on_item_selected slot instead of inline callbacks to separate logic and unify behavior. --------- Signed-off-by: Guilherme Costa <guiherme.costa@blockstec.com> Signed-off-by: gmmcosta15 <guilherme.costa@blockstec.com> Co-authored-by: Guilherme Costa <guiherme.costa@blockstec.com> Co-authored-by: HugoCLSC <hugo.santos.costa@gmail.com> * Work group button refactor (#137) * Refactor: optimized group button and renamed to check button * Refactor: updated button import to the newer file name and class * Refactor: ran ruff formatter --------- Co-authored-by: Roberto <roberto.martins@blockstec.com> * Bugfix `tunePage`: Add clickability and distinct icons to controllable fans (#138) * update fan icons and show only user-controllable fans Signed-off-by: Guilherme Costa <guiherme.costa@blockstec.com> * tunePage.py: improve icon management and add regex to display the correct icon for each fan type * networkWindow.py: reorganize imports and refactor icons management condition * Test signed commit --------- Signed-off-by: Guilherme Costa <guiherme.costa@blockstec.com> Co-authored-by: Guilherme Costa <guiherme.costa@blockstec.com> Co-authored-by: Hugo Costa <hugo.santos.costa@gmail.com> * Work display info UI (#140) * Bugfix: fixed total layer/current layer fallback * Add: added font size and family * bugfix: where the fallback was allways active * Refactor: ran ruff formatter --------- Signed-off-by: Hugo Costa <hugo.santos.costa@gmail.com> Co-authored-by: Roberto <roberto.martins@blockstec.com> Co-authored-by: Hugo Costa <hugo.santos.costa@gmail.com> * Work input shapper rework (#134) * ADD: added input shaper page * bugfix: button blocking clicks * ADD: added input shapper logic * ADD: added input shapper page to .ui * Add: basepopup.py Refactor: loadwidget to have similar logic to loadpage Removed: dialog page and loadPage * Refactor: change popup to Basepopup or/with loadwidget * Rev: removed misstype --------- Co-authored-by: Roberto <roberto.martins@blockstec.com> * Work connnectivity update page (#139) * ADD: added update page to connection page * ADD: added reload button to updatepage Refactor : evertime it reload shows loadwidget Refactor: info frame layout * Refactor: when update page gets refreshed * Added: icon_button pressed state Refactor: resized icon buttons on connectionwindow * Rev: removed updatepage instances * Fix: fixed loadwidget not hiding * add: added update page instance * Refactor: ran ruff formatter * refactor: removed unused import * Refactor: ran ruff formatter --------- Co-authored-by: Roberto <roberto.martins@blockstec.com> * Bugfix/tab unlocking (#147) * bugfix: fixed event config * Rev: removed on_cancel_print from handle cancel print --------- Co-authored-by: Roberto <roberto.martins@blockstec.com> * jobStatusPage: only load filedata when printer is printing (#150) Authored-by: Guilherme Costa <guiherme.costa@blockstec.com> * Bugfix/inputshaper page (#148) * bugfix: multiple connects signals * bugifx: loadcreen having button * bugfix: fixed input shaper after merge * Bugfix: being able to click behind the popup * Refactor: ran ruff formatter --------- Authored-by: Roberto <roberto.martins@blockstec.com> * work popup features (#144) * Fix: fixed wrong if check for popups * feat: first version of userinput for popup * feat: added new error and info icons * feat: added ClearPixmap to icon_button * Refactor: finished popup userInput feat * Refactor: formated _handle_error_message message ignored unknow type popup * Refactor: popups only shows error messages and added popup whitelist * Refactor:run ruff formater * Rev: removed prints * refactor: removed bare except * bugfix: fixed wordwrap * Refactor: ran ruff formatter --------- Authored-by: Roberto <roberto.martins@blockstec.com> * Improvement/Apply Z‑offset changes immediately, with an option to save permanently (#149) * babystepPage: make buttons update instantly and respond to all Z-offset changes * babystepPage and printTab: bugfix showing the current saved z-offset * printTab: change save message * add missing icons from merge --------- Co-authored-by: Guilherme Costa <guiherme.costa@blockstec.com> * Work network priority (#122) * ADD: added priority to 'get_saved_networks' * ADD: added priority buttons ADD: added details page to saved network Refacotr: refactor how edit on saved is made * ADD: added option to set an Tittle * UPD: changed some text * Refactor: Ran Ruff formatter * Refactor: some butttons text and group name --------- Co-authored-by: Roberto <roberto.martins@blockstec.com> Co-authored-by: Hugo Costa <hugo.santos.costa@gmail.com> * Bugfix: fixed loadwidget default being placeholder (gif) (#145) Co-authored-by: Roberto <roberto.martins@blockstec.com> Co-authored-by: Hugo Costa <hugo.santos.costa@gmail.com> * Bugfix/after merge fix (#151) * bugfix: fixed wrong imports * bugfix: wrong button name --------- Co-authored-by: Roberto <roberto.martins@blockstec.com> * Fans controlling UI wasnt working (#153) Co-authored-by: Guilherme Costa <guiherme.costa@blockstec.com> * Bugfix/update page & Popup logic (#154) * add: added popup cap * bugfix: made update page hide * bugfix: fixed broken popup logic --------- Co-authored-by: Roberto <roberto.martins@blockstec.com> * bugfix: ipv4 ip command error fix (#155) Co-authored-by: Guilherme Costa <guiherme.costa@blockstec.com> * bugfix: fans_widget on tunepage are stacked (#156) Co-authored-by: Guilherme Costa <guiherme.costa@blockstec.com> * bugfix ztilt loadscreen (#158) * Add z_tilt object update handler and corresponding signal * bugfix: fixed ztilt hiding on wrong moment * Refactor: ran ruff formatter --------- Co-authored-by: HugoCLSC <hugo.santos.costa@gmail.com> Co-authored-by: Roberto <roberto.martins@blockstec.com> * bugfix: inputshaper load not hiding (#161) Co-authored-by: Roberto <roberto.martins@blockstec.com> * bugfix/popup show right arrow (#163) Co-authored-by: Guilherme Costa <guiherme.costa@blockstec.com> * swap lower and raise nozzle icons (#164) Co-authored-by: Guilherme Costa <guiherme.costa@blockstec.com> * Refactor loadscreen on the project (#165) * Refactor: added single instance of loadScreen on all project bugfix fixed conenctionpage below load page * Refactor: ran ruff formatter --------- Signed-off-by: Hugo Costa <hugo.santos.costa@gmail.com> Co-authored-by: Roberto <roberto.martins@blockstec.com> * Deleted Unused `ztilt_state` variable from control tab (#166) The variable `ztilt_state` was left behing during another PR, it should have been deleted. Now it is * ADD: Additional load messages (#169) Co-authored-by: Roberto <roberto.martins@blockstec.com> * Refactor `NetworkWindow` (#174) * refactor: change network list to listview * Refactor: Refac to MVC view with Controller being runnables on a threadpoll * UPD: Regenerated icon_resources_rc * networkWindow.py: refactor to include listview wifiConnectivityWindow.ui: change horizontalLayout to a vertical layout with a listview and a vertical scrollbar wifiConnectivityWindow.py: generated file from QtDesigner with some optimizations Signed-off-by: Guilherme Costa <guiherme.costa@blockstec.com> * networkWindow: rebase merge conflits fix and cleanup Signed-off-by: Guilherme Costa <guiherme.costa@blockstec.com> * networkWindow.py: added missing right icon Signed-off-by: Guilherme Costa <guiherme.costa@blockstec.com> * Fix typo * networkWindow.py: optimize and bugfix on self.paths Signed-off-by: Guilherme Costa <guiherme.costa@blockstec.com> * networkWindow.py: comments cleanup * networkWindow.py: fix missing formatting * Revert accidental changes to requirements.txt * networkwindo.py: between 5 and 25 show only one bar icon * bugfix: fixed wrong imports * bugfix: wrong button name * resolve merge conflits * add missing docstrings * add missing docstrings * separation between saved and unsaved network and update code * refactor network window file * Add hidden network page, fix scrollbar behaviour at borders remove the need to use wificonnectivitywindow_ui * cleanup of unused code * fix code formatation * changed QtWidgets.QApplication.processEvents for repaint * delete unused files * fix formatting issues and logic to parse sensors * fix code formatation --------- Signed-off-by: Guilherme Costa <guiherme.costa@blockstec.com> Co-authored-by: Roberto Martins <robertomicael.martins@gmail.com> Co-authored-by: Guilherme Costa <guiherme.costa@blockstec.com> Co-authored-by: HugoCLSC <hugo.santos.costa@gmail.com> Co-authored-by: Roberto <roberto.martins@blockstec.com> * Fix incorrect file removal (#177) * uild: overhaul Makefile, and expand dev deps (#183) * bugfix: fixed missing home before ztilt (#180) Co-authored-by: Roberto <roberto.martins@blockstec.com> * Feat/cancel page (#170) * Feat: added cancel page * Rev: removed back button * add: hides cancel page * Refactor: removed cancel page connection to printtab * ADD: added logic to cancelPage * refactor: ran ruff formatter --------- Co-authored-by: Roberto <roberto.martins@blockstec.com> Co-authored-by: Hugo Costa <hugo.santos.costa@gmail.com> * Refactor the Logging System (#172) * bugfix: logger works with each module and handles stdout/stderr * fix code formatation * Catch segmentation faults and log crash details --------- Signed-off-by: Hugo Costa <hugo.santos.costa@gmail.com> Co-authored-by: Guilherme Costa <guiherme.costa@blockstec.com> Co-authored-by: Hugo Costa <hugo.santos.costa@gmail.com> * Revert "Refactor the Logging System (#172)" This reverts commit cc33f7b. * Refactor the File Management System (#171) * refactor files list behaviour, added USB icons and handling when the current_dir is deleted * bugfix: generation of new .code files and handling of new files introduced, in case of not loading the thumbnail of a file always shows the blocksthumbnail file * fix bug about the scrollbar not showing when screen started on the filespage * fix: correct USB dir detection, logger name, time unit, and error coupling - files.py: replace fragile single-string USB preload tracker with a FIFO deque, fixing "No files found" shown on USB-prefixed dir creation; replace os.path with pathlib.Path - filesPage.py: fix _format_print_time returning label as seconds instead of minutes for durations under 60s; fix logger using file path as name instead of __name__; clarify retry debug log labels - mainWindow.py: replace back_btn.click() with on_directory_error() to avoid reaching through abstraction layers into nested widget internals --------- Co-authored-by: Guilherme Costa <guiherme.costa@blockstec.com> * Bugfix/filament loadscreen (#179) * ADD: reset variable on show * Bugfix: fixed loadpage showing --------- Co-authored-by: Roberto <roberto.martins@blockstec.com> Co-authored-by: Hugo Costa <hugo.santos.costa@gmail.com> * feat(network): NetworkManager refactor and NetworkControlWindow rewrite (#182) * feat(network): network window refactor and manager architecture * fixed icons generated file * Feat/notification tab (#160) * ADD: added a first version of notication page * ADD: added notifaction button * Refactor: refactor notification page * ADD: added notification page access * Refactor: refactor paint ,sizeHint . ADD: added delete duplicates , delete item added expand flag , color and cache (stores width&heigh ) * Refactor: use notification page instead of sending popup * Refactor: ran ruff formatter * bugfix: initalized variable * ADD: added popup flag * Refactor: updated show_notifications signal * Rev: removed unused variable * Refactor: ran ruff formatter * bugfix: fixed logic after rebase * Bugfix: re added variable * Ran : ruff formatter * ADD: added flag to paint icon * Refactor: delete unused import * ADD: added new icons and updated old ones * UPD: changed import to pyqt6 --------- Co-authored-by: Roberto <roberto.martins@blockstec.com> * Del extras directory not needed * Feat/eddy calibration panel (#188) * ADD: added eddy calibration logic * Rev: removed gcode movement --------- Co-authored-by: Roberto <roberto.martins@blockstec.com> * feat(logger): overhaul logging system with module-aware names and c… (#186) * feat(logger): overhaul logging system with module-aware names and crash handling - Replace AsyncFileHandler with ThreadedFileHandler (queue + background thread wrapping TimedRotatingFileHandler; "async" was a misnomer) - Add LogManager singleton: configures root logger, optional StreamToLogger capture of stderr/stdout, handler deduplication - Add CrashHandler: installs sys.excepthook, threading.excepthook, and faulthandler for C-level crashes; supports exit_on_crash flag - Expose setup_logging() and get_logger() as the public API - Suppress noisy third-party loggers (urllib3, websocket, PIL) to WARNING - Fix all modules to use logging.getLogger(__name__) instead of the old named-file pattern (logs/BlocksScreen.log): BlocksScreen.py, configfile.py, lib/machine.py, lib/moonrest.py, lib/printer.py, lib/panels/mainWindow.py, lib/panels/widgets/connectionPage.py - Replace manual logger-iteration loop in MainWindow.closeEvent with LogManager.shutdown(); remove erroneous recursive self.close() call - Fix create_hotspot password param: str | None = None, raise ValueError instead of silently accepting empty/hardcoded default (bandit B107) - Replace all bare except/pass blocks with typed exception handling that writes to sys.__stderr__ when the logger itself may be unavailable (bandit B110) EOF )" * fix formatting * fix merge problems * add missing logger changes and remove double-formatting in QueueHandler → ThreadedFileHandler chain * fix(makefile): align clean, lint and format-check with CI (#187) * Bugfix/nozzle calli hide (#189) * Bugfix: hide screen when not active * Refactor : optimzied code --------- Co-authored-by: Roberto <roberto.martins@blockstec.com> * feat(network): remove ethernet DHCP, require static IP for VLANs (#190) * feat(network): remove DHCP support for ethernet/VLAN connections * fix formatting * Bugfix/eddy current calibration home (#191) * bugfix: home before eddy current paper-test * refactor : ran ruff formatter * refactor(keyboard): delete unused keys, always show . in all screens, simplify the code and added unit tests (#192) * USB tools (#193) * Udisks2 dbus interfaces for File system and dev Block * Add Udisks2 Drive interface * Finalize UDisks2 Interfaces * Finished blocking udisks2 dbus interfaces and manager * Add initial async UDisks2 Dbus interfaces and manager * Added parallel monitoring for added/removed interfaces for Udisks2 signals, new properties on interfaces * WIP (switching laptops) * WIP Udev monitoring * WIP: Add UDisks2 Partition Interface, properties changed signal handling The properties of a device although uncommon may change, so a handler for the signal UDisks2 manager `properties_changed` was added. The logic is still missing here. The initial representation of a Device is added but not finished * Created a module for this usb storage devices Since code can be added in the future to increase the functionality of the usb storage devices communication, the different parts of the feature were seperated into different files in order to create a module that can later be called to handle all usb storage devices. This will make code additions and refactors cleaner in the future. The commit seperates the previous `usb_manager.py` into six different files: seperate wrappers for the sdbus UDisks2 service (blocking and async), usb storage asynchronous manager, and a WIP udev monitor that may be deleted in the future. This is still a work in progress so don't pay to much attention to what is done * Moved to module * WIP * Seperated Device definition * Rplaced string literals with Enum members, added new property to interface * WIP All phases are now in place, mounting and symlink creation next * WIP version and type checking * WIP print to udisks2 signals * Add symlink traking * WIP, mounting, symlink creation and removal, input validation, exception handling * WIP: changing laptops * Finish static typing for arguments * Finish static typing for arguments for blocking * Wip: remove comments and prints * add: added banner popup for usb * Del: debug prints * Remove useless comments * Finish available module signals * Make banner popup adhere to the same file naming * Format, remove deprecated typing.Deque, change var name * Changed var name for something more explicit * Fix typo from the prior commit * Del prints from debugging * Change method names, auto restart when usb monitor stops * Add active control flag, incomplete * Add new signals, finish restart logic * Finish restart logic, handle restart type * Finish restart type logic * gcodes_dir can also be none now * Add as a requirement * Instantiate USBManager * Add slot for .aboutToQuit the app, start transition to this cleanup * Fix bug TYPE_CHECKING = True, this broke everything * return fallback on no section * Call usb_manager, fetch gcode dir from configfile if available * Cleanup * Add default usb-manager config section * Call banner on hardware signals * Remove unused experiment * Add docstrings * Add docstrings to FileSystem async interface * Midway adding docstrings to Block device async interface * Finish Block method docstrings * Finish Drive interface methods docstrings * Finish adding documentation * Correctly import the storage package * Pass device name or id_label as the symlink name * Fix device initialization * Del dead code * Typo fix * Del unused var type * Add return types * Typo fixes * Rem unused imports * Add doctring to fire_n_forget * Fix banner parent, pass signals correctly * Only pass the parent if it exists * bugfix: black background * Add a 'USB' prefix to the symlink name so that the screen can assign a usb icon to the symlink * Del accidental import --------- Co-authored-by: Roberto <roberto.martins@blockstec.com> * Fix merge issues * Fix pyqt version * Add '-' to label prefix * bugfix(logger): starts logger before the mainwindow (#196) * bugfix(logger): starts logger before the mainwindow * fix formatting --------- Co-authored-by: Hugo Costa <hugo.santos.costa@gmail.com> * Add legacy dir cleanup on start * Replace pillow dependency with pure PyQt6 --------- Signed-off-by: dependabot[bot] <support@github.com> Signed-off-by: Hugo Costa <hugo.santos.costa@gmail.com> Signed-off-by: Guilherme Costa <guiherme.costa@blockstec.com> Signed-off-by: gmmcosta15 <guilherme.costa@blockstec.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Roberto Martins <robertomicael.martins@gmail.com> Co-authored-by: Roberto <roberto.martins@blockstec.com> Co-authored-by: Guilherme Costa <guilherme.costa@blockstec.com> Co-authored-by: Guilherme Costa <guiherme.costa@blockstec.com>
1 parent 7ecd8f1 commit 127086d

93 files changed

Lines changed: 24564 additions & 13249 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/dev-ci.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ jobs:
2828
cache: pip
2929
cache-dependency-path: scripts/requirements-dev.txt
3030

31+
- name: Install system dependencies
32+
if: matrix.test-type == 'pytest'
33+
run: sudo apt-get install -y libgl1 libglib2.0-0 libegl1
34+
3135
- name: Install dependencies
3236
run: |
3337
echo "Installing dependencies"

BlocksScreen.cfg

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,7 @@ host: localhost
33
port: 7125
44

55
[screensaver]
6-
timeout: 5000
6+
timeout: 5000
7+
8+
[usb_manager]
9+
gcodes_dir: ~/printer_data/gcodes/

BlocksScreen/BlocksScreen.py

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,28 @@
22
import sys
33
import typing
44

5-
import logger
6-
from lib.panels.mainWindow import MainWindow
7-
from PyQt6 import QtCore, QtGui, QtWidgets
5+
from logger import CrashHandler, LogManager, install_crash_handler, setup_logging
6+
7+
install_crash_handler()
8+
9+
from lib.panels.mainWindow import MainWindow # noqa: E402
10+
from PyQt6 import QtCore, QtGui, QtWidgets # noqa: E402
11+
12+
13+
class BlocksScreenApp(QtWidgets.QApplication):
14+
"""QApplication subclass that routes unhandled slot exceptions to CrashHandler."""
15+
16+
def notify(self, a0: QtCore.QObject, a1: QtCore.QEvent) -> bool: # type: ignore[override]
17+
try:
18+
return super().notify(a0, a1)
19+
except Exception:
20+
exc_type, exc_value, exc_tb = sys.exc_info()
21+
handler = CrashHandler._instance
22+
if handler is not None and exc_type is not None and exc_value is not None:
23+
handler._exception_hook(exc_type, exc_value, exc_tb)
24+
return False
25+
826

9-
_logger = logging.getLogger(name="logs/BlocksScreen.log")
1027
QtGui.QGuiApplication.setAttribute(
1128
QtCore.Qt.ApplicationAttribute.AA_SynthesizeMouseForUnhandledTouchEvents,
1229
True,
@@ -22,13 +39,6 @@
2239
RESET = "\033[0m"
2340

2441

25-
def setup_app_loggers():
26-
"""Setup logger"""
27-
_ = logger.create_logger(name="logs/BlocksScreen.log", level=logging.DEBUG)
28-
_logger = logging.getLogger(name="logs/BlocksScreen.log")
29-
_logger.info("============ BlocksScreen Initializing ============")
30-
31-
3242
def show_splash(window: typing.Optional[QtWidgets.QWidget] = None):
3343
"""Show splash screen on app initialization"""
3444
logo = QtGui.QPixmap("BlocksScreen/BlocksScreen/lib/ui/resources/logoblocks.png")
@@ -38,13 +48,28 @@ def show_splash(window: typing.Optional[QtWidgets.QWidget] = None):
3848
splash.finish(window)
3949

4050

51+
def on_quit() -> None:
52+
logging.info("Final exit cleanup")
53+
LogManager.shutdown()
54+
55+
4156
if __name__ == "__main__":
42-
setup_app_loggers()
43-
BlocksScreen = QtWidgets.QApplication([])
57+
setup_logging(
58+
filename="logs/BlocksScreen.log",
59+
level=logging.DEBUG,
60+
console_output=True,
61+
console_level=logging.DEBUG,
62+
capture_stderr=True,
63+
capture_stdout=False,
64+
)
65+
_logger = logging.getLogger(__name__)
66+
_logger.info("============ BlocksScreen Initializing ============")
67+
BlocksScreen = BlocksScreenApp([])
4468
BlocksScreen.setApplicationName("BlocksScreen")
4569
BlocksScreen.setApplicationDisplayName("BlocksScreen")
4670
BlocksScreen.setDesktopFileName("BlocksScreen")
4771
main_window = MainWindow()
4872
BlocksScreen.processEvents()
73+
BlocksScreen.aboutToQuit.connect(on_quit)
4974
main_window.show()
5075
sys.exit(BlocksScreen.exec())

BlocksScreen/configfile.py

Lines changed: 71 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@
3737

3838
from helper_methods import check_file_on_path
3939

40+
logger = logging.getLogger(__name__)
41+
4042
HOME_DIR = os.path.expanduser("~/")
4143
WORKING_DIR = os.getcwd()
4244
DEFAULT_CONFIGFILE_PATH = pathlib.Path(HOME_DIR, "printer_data", "config")
@@ -56,11 +58,19 @@ class ConfigError(Exception):
5658
"""Exception raised when Configfile errors exist"""
5759

5860
def __init__(self, msg) -> None:
61+
"""Store the error message on both the exception and the ``msg`` attribute."""
5962
super().__init__(msg)
6063
self.msg = msg
6164

6265

6366
class BlocksScreenConfig:
67+
"""Thread-safe wrapper around :class:`configparser.ConfigParser` with raw-text tracking.
68+
69+
Maintains a ``raw_config`` list that mirrors the on-disk file so that
70+
``add_section``, ``add_option``, and ``update_option`` can write back
71+
changes without losing comments or formatting.
72+
"""
73+
6474
config = configparser.ConfigParser(
6575
allow_no_value=True,
6676
)
@@ -70,16 +80,19 @@ class BlocksScreenConfig:
7080
def __init__(
7181
self, configfile: typing.Union[str, pathlib.Path], section: str
7282
) -> None:
83+
"""Initialise with the path to the config file and the default section name."""
7384
self.configfile = pathlib.Path(configfile)
7485
self.section = section
7586
self.raw_config: typing.List[str] = []
7687
self.raw_dict_config: typing.Dict = {}
7788
self.file_lock = threading.Lock() # Thread safety for future work
7889

7990
def __getitem__(self, key: str) -> BlocksScreenConfig:
91+
"""Return a :class:`BlocksScreenConfig` for *key* section (same as ``get_section``)."""
8092
return self.get_section(key)
8193

8294
def __contains__(self, key):
95+
"""Return True if *key* is a section in the underlying ConfigParser."""
8396
return key in self.config
8497

8598
def sections(self) -> typing.List[str]:
@@ -91,7 +104,7 @@ def get_section(
91104
) -> BlocksScreenConfig:
92105
"""Get configfile section"""
93106
if not self.config.has_section(section):
94-
raise configparser.NoSectionError(f"No section with name: {section}")
107+
return fallback
95108
return BlocksScreenConfig(self.configfile, section)
96109

97110
def get_options(self) -> list:
@@ -193,12 +206,14 @@ def getboolean(
193206
)
194207

195208
def _find_section_index(self, section: str) -> int:
209+
"""Return the index of the ``[section]`` header line in ``raw_config``."""
196210
try:
197211
return self.raw_config.index("[" + section + "]")
198212
except ValueError as e:
199213
raise configparser.Error(f'Section "{section}" does not exist: {e}')
200214

201215
def _find_section_limits(self, section: str) -> typing.Tuple:
216+
"""Return ``(start_index, end_index)`` of *section* in ``raw_config``."""
202217
try:
203218
section_start = self._find_section_index(section)
204219
buffer = self.raw_config[section_start:]
@@ -212,6 +227,7 @@ def _find_section_limits(self, section: str) -> typing.Tuple:
212227
def _find_option_index(
213228
self, section: str, option: str
214229
) -> typing.Union[Sentinel, int, None]:
230+
"""Return the index of the *option* line within *section* in ``raw_config``."""
215231
try:
216232
start, end = self._find_section_limits(section)
217233
section_buffer = self.raw_config[start:][:end]
@@ -253,9 +269,9 @@ def add_section(self, section: str) -> None:
253269
self.config.add_section(section)
254270
self.update_pending = True
255271
except configparser.DuplicateSectionError as e:
256-
logging.error(f'Section "{section}" already exists. {e}')
272+
logger.error(f'Section "{section}" already exists. {e}')
257273
except configparser.Error as e:
258-
logging.error(f'Unable to add "{section}" section to configuration: {e}')
274+
logger.error(f'Unable to add "{section}" section to configuration: {e}')
259275

260276
def add_option(
261277
self,
@@ -283,12 +299,46 @@ def add_option(
283299
self.config.set(section, option, value)
284300
self.update_pending = True
285301
except configparser.DuplicateOptionError as e:
286-
logging.error(f"Option {option} already present on {section}: {e}")
302+
logger.error(f"Option {option} already present on {section}: {e}")
287303
except configparser.Error as e:
288-
logging.error(
304+
logger.error(
289305
f'Unable to add "{option}" option to section "{section}": {e} '
290306
)
291307

308+
def update_option(
309+
self,
310+
section: str,
311+
option: str,
312+
value: typing.Any,
313+
) -> None:
314+
"""Update an existing option's value in both raw tracking and configparser."""
315+
try:
316+
with self.file_lock:
317+
if not self.config.has_section(section):
318+
self.add_section(section)
319+
320+
if not self.config.has_option(section, option):
321+
self.add_option(section, option, str(value))
322+
return
323+
324+
line_idx = self._find_option_line_index(section, option)
325+
self.raw_config[line_idx] = f"{option}: {value}"
326+
self.config.set(section, option, str(value))
327+
self.update_pending = True
328+
except Exception as e:
329+
logger.error(
330+
f'Unable to update option "{option}" in section "{section}": {e}'
331+
)
332+
333+
def _find_option_line_index(self, section: str, option: str) -> int:
334+
"""Find the index of an option line within a specific section."""
335+
start, end = self._find_section_limits(section)
336+
opt_regex = re.compile(rf"^\s*{re.escape(option)}\s*[:=]")
337+
for i in range(start + 1, end):
338+
if opt_regex.match(self.raw_config[i]):
339+
return i
340+
raise configparser.Error(f'Option "{option}" not found in section "{section}"')
341+
292342
def save_configuration(self) -> None:
293343
"""Save teh configuration to file"""
294344
try:
@@ -301,7 +351,7 @@ def save_configuration(self) -> None:
301351
self.config.write(sio)
302352
sio.close()
303353
except Exception as e:
304-
logging.error(
354+
logger.error(
305355
f"ERROR: Unable to save new configuration, something went wrong while saving updated configuration. {e}"
306356
)
307357
finally:
@@ -319,6 +369,14 @@ def load_config(self):
319369
raise configparser.Error(f"Error loading configuration file: {e}")
320370

321371
def _parse_file(self) -> typing.Tuple[typing.List[str], typing.Dict]:
372+
"""Read and normalise the config file into a raw line list and a nested dict.
373+
374+
Strips comments, normalises ``=`` to ``:`` separators, deduplicates
375+
sections/options, and ensures the buffer ends with an empty line.
376+
377+
Returns:
378+
A tuple of (raw_lines, dict_representation).
379+
"""
322380
buffer = []
323381
dict_buff: typing.Dict = {}
324382
curr_sec: typing.Union[Sentinel, str] = Sentinel.MISSING
@@ -336,17 +394,18 @@ def _parse_file(self) -> typing.Tuple[typing.List[str], typing.Dict]:
336394
if not line:
337395
continue
338396
# remove leading and trailing white spaces
339-
line = re.sub(r"\s*([:=])\s*", r"\1", line)
397+
line = re.sub(r"\s*([:=])\s*", r"\1 ", line)
340398
line = re.sub(r"=", r":", line)
341399
# find the beginning of sections
342400
section_match = re.compile(r"[^\s]*\[([^]]+)\]")
343401
match_sec = re.match(section_match, line) #
344402
if match_sec:
345403
sec_name = re.sub(r"[\[*\]]", r"", line)
346404
if sec_name not in dict_buff.keys():
347-
buffer.extend(
348-
[""]
349-
) # REFACTOR: Just add some line separation between sections
405+
if buffer:
406+
buffer.extend(
407+
[""]
408+
) # REFACTOR: Just add some line separation between sections
350409
dict_buff.update({sec_name: {}})
351410
curr_sec = sec_name
352411
else:
@@ -386,6 +445,6 @@ def get_configparser() -> BlocksScreenConfig:
386445
config_object = BlocksScreenConfig(configfile=configfile, section="server")
387446
config_object.load_config()
388447
if not config_object.has_section("server"):
389-
logging.error("Error loading configuration file for the application.")
448+
logger.error("Error loading configuration file for the application.")
390449
raise ConfigError("Section [server] is missing from configuration")
391-
return BlocksScreenConfig(configfile=configfile, section="server")
450+
return config_object
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
from .usb_controller import USBManager
2+
3+
__doc__ = """
4+
5+
The storage package contains a tool that monitors
6+
pluggable usb devices via python-sdbus library.
7+
While offering an automounting option.
8+
The package is also capable of creating a symlink that
9+
points directly to the mounted usb drive on the gcodes
10+
directory.
11+
12+
13+
There is still a lot of functionality missing, that may
14+
be added in the future, but for now it just automounts,
15+
creates symlinks, cleans up broken symlinks on the
16+
gcodes directory.
17+
18+
19+
All tools related to storage devices should be contained
20+
in this package directory.
21+
"""
22+
__version__ = "0.0.1"
23+
__all__ = ["USBManager"]
24+
__name__ = "storage"

0 commit comments

Comments
 (0)