Skip to content

chore(ci)(deps): bump softprops/action-gh-release from 1 to 2 - #9

Open
dependabot[bot] wants to merge 1 commit into
mainfrom
dependabot/github_actions/softprops/action-gh-release-2
Open

chore(ci)(deps): bump softprops/action-gh-release from 1 to 2#9
dependabot[bot] wants to merge 1 commit into
mainfrom
dependabot/github_actions/softprops/action-gh-release-2

Conversation

@dependabot

@dependabot dependabot Bot commented on behalf of github Jul 15, 2025

Copy link
Copy Markdown

Bumps softprops/action-gh-release from 1 to 2.

Release notes

Sourced from softprops/action-gh-release's releases.

v2.0.0

  • update actions.yml declaration to node20 to address warnings
Changelog

Sourced from softprops/action-gh-release's changelog.

0.1.12

  • fix bug leading to empty strings subsituted for inputs users don't provide breaking api calls #144
Commits

Dependabot compatibility score

You can trigger a rebase of this PR by commenting @dependabot rebase.


Dependabot commands and options

You can trigger Dependabot actions by commenting on this PR:

  • @dependabot rebase will rebase this PR
  • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
  • @dependabot merge will merge this PR after your CI passes on it
  • @dependabot squash and merge will squash and merge this PR after your CI passes on it
  • @dependabot cancel merge will cancel a previously requested merge and block automerging
  • @dependabot reopen will reopen this PR if it is closed
  • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
  • @dependabot show <dependency name> ignore conditions will show all of the ignore conditions of the specified dependency
  • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)

Note
Automatic rebases have been disabled on this pull request as it has been open for over 30 days.

Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 1 to 2.
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](softprops/action-gh-release@v1...v2)

---
updated-dependencies:
- dependency-name: softprops/action-gh-release
  dependency-version: '2'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
@dependabot @github

dependabot Bot commented on behalf of github Jul 15, 2025

Copy link
Copy Markdown
Author

Reviewers

The following users could not be added as reviewers: maintainer-username. Either the username does not exist or it does not have the correct permissions to be added as a reviewer.

Assignees

The following users could not be added as assignees: maintainer-username. Either the username does not exist or it does not have the correct permissions to be added as an assignee.

Labels

The following labels could not be found: automated, dependencies, github-actions. Please create them before Dependabot can add them to a pull request.

Please fix the above issues or remove invalid values from dependabot.yml.

@dependabot @github

dependabot Bot commented on behalf of github Jul 15, 2025

Copy link
Copy Markdown
Author

The reviewers field in the dependabot.yml file will be removed soon. Please use the code owners file to specify reviewers for Dependabot PRs. For more information, see this blog post.

@github-actions

Copy link
Copy Markdown

[ANALYSIS] Code Quality Summary

Generated on: Tue Jul 15 09:34:39 UTC 2025

Code Quality Reports

Code Complexity Report

Cyclomatic Complexity

syspilot/main.py
F 24:0 main - B (10)
syspilot/widgets/charts.py
M 246:4 ThermometerWidget.update_data - C (13)
C 238:0 ThermometerWidget - B (8)
C 135:0 BarChartWidget - A (4)
M 142:4 BarChartWidget.update_data - A (4)
C 52:0 PieChartWidget - A (3)
C 91:0 LineChartWidget - A (3)
C 183:0 GaugeWidget - A (3)
M 190:4 GaugeWidget.update_data - A (3)
C 390:0 SystemMonitoringWidget - A (3)
M 439:4 SystemMonitoringWidget.update_data - A (3)
C 25:0 BaseChartWidget - A (2)
M 55:4 PieChartWidget.init - A (2)
M 99:4 LineChartWidget.add_data_point - A (2)
M 109:4 LineChartWidget.update_chart - A (2)
M 138:4 BarChartWidget.init - A (2)
C 479:0 TrendMonitoringWidget - A (2)
M 498:4 TrendMonitoringWidget.update_data - A (2)
M 28:4 BaseChartWidget.init - A (1)
M 33:4 BaseChartWidget.setup_ui - A (1)
M 59:4 PieChartWidget.update_data - A (1)
M 94:4 LineChartWidget.init - A (1)
M 186:4 GaugeWidget.init - A (1)
M 241:4 ThermometerWidget.init - A (1)
M 393:4 SystemMonitoringWidget.init - A (1)
M 397:4 SystemMonitoringWidget.setup_ui - A (1)
M 482:4 TrendMonitoringWidget.init - A (1)
M 486:4 TrendMonitoringWidget.setup_ui - A (1)
syspilot/core/app.py
M 786:4 SysPilotApp.update_monitoring_data - C (18)
M 1045:4 SysPilotApp.update_schedules_list - B (6)
M 215:4 ScheduleDialog.get_schedule_data - A (5)
M 282:4 SysPilotApp.run - A (5)
M 103:4 MonitoringWorker.run - A (4)
C 236:0 SysPilotApp - A (4)
M 239:4 SysPilotApp.init - A (4)
M 647:4 SysPilotApp.setup_system_tray - A (4)
M 841:4 SysPilotApp.enable_autostart - A (4)
M 874:4 SysPilotApp.disable_autostart - A (4)
M 933:4 SysPilotApp.remove_selected_schedule - A (4)
M 1014:4 SysPilotApp.update_settings_ui - A (4)
M 1110:4 SysPilotApp.closeEvent - A (4)
C 66:0 CleanupWorker - A (3)
C 93:0 MonitoringWorker - A (3)
C 129:0 ScheduleDialog - A (3)
M 411:4 SysPilotApp.create_monitoring_tab - A (3)
M 620:4 SysPilotApp.find_icon_path - A (3)
M 701:4 SysPilotApp.start_cleanup - A (3)
M 777:4 SysPilotApp.manual_monitoring_update - A (3)
M 905:4 SysPilotApp.add_schedule_dialog - A (3)
M 961:4 SysPilotApp.create_default_schedules - A (3)
M 79:4 CleanupWorker.run - A (2)
M 690:4 SysPilotApp.tray_icon_activated - A (2)
M 727:4 SysPilotApp.cleanup_finished - A (2)
M 988:4 SysPilotApp.apply_settings - A (2)
M 1081:4 SysPilotApp.toggle_auto_start - A (2)
M 74:4 CleanupWorker.init - A (1)
M 98:4 MonitoringWorker.init - A (1)
M 123:4 MonitoringWorker.stop - A (1)
M 132:4 ScheduleDialog.init - A (1)
M 139:4 ScheduleDialog.setup_ui - A (1)
M 210:4 ScheduleDialog.on_type_changed - A (1)
M 328:4 SysPilotApp.setup_ui - A (1)
M 359:4 SysPilotApp.create_cleanup_tab - A (1)
M 498:4 SysPilotApp.create_settings_tab - A (1)
M 695:4 SysPilotApp.show_main_window - A (1)
M 719:4 SysPilotApp.update_progress - A (1)
M 723:4 SysPilotApp.update_status - A (1)
M 752:4 SysPilotApp.cleanup_error - A (1)
M 762:4 SysPilotApp.start_monitoring - A (1)
M 1077:4 SysPilotApp.setup_scheduled_cleanup - A (1)
M 1088:4 SysPilotApp.show_about - A (1)
syspilot/core/daemon.py
M 52:4 SysPilotDaemon.run - A (5)
M 97:4 SysPilotDaemon.stop - A (5)
M 159:4 SysPilotDaemon._schedule_cleanup_tasks - A (5)
M 193:4 SysPilotDaemon._monitoring_loop - A (5)
C 22:0 SysPilotDaemon - A (4)
M 115:4 SysPilotDaemon._is_daemon_running - A (4)
M 221:4 SysPilotDaemon._scheduler_loop - A (4)
M 273:4 SysPilotDaemon.is_running - A (4)
M 295:4 SysPilotDaemon.stop_daemon - A (4)
M 146:4 SysPilotDaemon._cleanup_daemon - A (3)
M 248:4 SysPilotDaemon.get_daemon_status - A (3)
M 136:4 SysPilotDaemon._create_pid_file - A (2)
M 181:4 SysPilotDaemon._scheduled_cleanup - A (2)
M 238:4 SysPilotDaemon._send_alert_notification - A (2)
M 25:4 SysPilotDaemon.init - A (1)
M 154:4 SysPilotDaemon._signal_handler - A (1)
syspilot/core/cli.py
M 313:4 SysPilotCLI.show_cleanup_preview - B (9)
M 34:4 SysPilotCLI.run - B (8)
M 66:4 SysPilotCLI.cleanup_menu - B (7)
M 176:4 SysPilotCLI.monitoring_menu - B (6)
M 200:4 SysPilotCLI.show_current_stats - B (6)
M 349:4 SysPilotCLI.settings_menu - B (6)
C 16:0 SysPilotCLI - A (4)
M 93:4 SysPilotCLI.run_full_cleanup - A (4)
M 232:4 SysPilotCLI.show_top_processes - A (4)
M 258:4 SysPilotCLI.show_disk_usage - A (4)
M 289:4 SysPilotCLI.show_network_info - A (4)
M 147:4 SysPilotCLI.show_system_info - A (3)
M 410:4 SysPilotCLI._format_bytes - A (3)
M 399:4 SysPilotCLI.reset_settings - A (2)
M 19:4 SysPilotCLI.init - A (1)
M 123:4 SysPilotCLI.clean_temp - A (1)
M 129:4 SysPilotCLI.clean_cache - A (1)
M 135:4 SysPilotCLI.clean_logs - A (1)
M 141:4 SysPilotCLI.clean_package_cache - A (1)
M 373:4 SysPilotCLI.show_current_settings - A (1)
M 389:4 SysPilotCLI.modify_cleanup_settings - A (1)
M 394:4 SysPilotCLI.modify_monitoring_settings - A (1)
syspilot/utils/logger.py
F 12:0 setup_logging - A (3)
F 59:0 get_logger - A (1)
syspilot/utils/config.py
M 131:4 ConfigManager._validate_config - B (9)
M 113:4 ConfigManager._merge_config - A (5)
C 14:0 ConfigManager - A (3)
M 98:4 ConfigManager._load_config - A (3)
M 74:4 ConfigManager.init - A (2)
M 160:4 ConfigManager.save_config - A (2)
M 169:4 ConfigManager.get - A (2)
M 188:4 ConfigManager.set - A (2)
M 203:4 ConfigManager.get_temp_dirs - A (2)
M 208:4 ConfigManager.get_cache_dirs - A (2)
M 213:4 ConfigManager.get_log_files - A (2)
M 218:4 ConfigManager.get_package_cache - A (2)
M 223:4 ConfigManager.get_exclude_patterns - A (1)
M 227:4 ConfigManager.get_max_age_days - A (1)
M 231:4 ConfigManager.get_min_free_space_mb - A (1)
M 235:4 ConfigManager.get_monitoring_interval - A (1)
M 239:4 ConfigManager.get_alert_thresholds - A (1)
M 243:4 ConfigManager.is_debug_mode - A (1)
M 247:4 ConfigManager.should_backup_before_cleanup - A (1)
M 251:4 ConfigManager.should_minimize_to_tray - A (1)
M 255:4 ConfigManager.should_show_notifications - A (1)
syspilot/platforms/init.py
F 29:0 get_platform_module - A (5)
F 10:0 get_platform - A (4)
F 83:0 is_platform_supported - A (1)
syspilot/platforms/factory.py
C 9:0 PlatformFactory - A (4)
M 13:4 PlatformFactory.create_cleanup_service - A (4)
M 33:4 PlatformFactory.create_monitoring_service - A (4)
M 53:4 PlatformFactory.create_system_info_service - A (4)
M 73:4 PlatformFactory.get_supported_platforms - A (1)
M 78:4 PlatformFactory.is_current_platform_supported - A (1)
syspilot/platforms/macos/monitoring_service.py
M 71:4 MonitoringService.get_top_processes - A (4)
C 13:0 MonitoringService - A (2)
M 19:4 MonitoringService.init - A (1)
M 23:4 MonitoringService.get_cpu_usage - A (1)
M 28:4 MonitoringService.get_memory_usage - A (1)
M 40:4 MonitoringService.get_disk_usage - A (1)
M 51:4 MonitoringService.get_cpu_temperature - A (1)
M 60:4 MonitoringService.get_network_io - A (1)
M 94:4 MonitoringService.get_system_stats - A (1)
syspilot/platforms/macos/system_info_service.py
M 59:4 SystemInfoService.get_disk_info - A (4)
C 13:0 SystemInfoService - A (3)
M 44:4 SystemInfoService.get_hardware_info - A (2)
M 19:4 SystemInfoService.init - A (1)
M 22:4 SystemInfoService.get_system_info - A (1)
syspilot/platforms/macos/cleanup_service.py
C 13:0 CleanupService - A (2)
M 19:4 CleanupService.init - A (1)
M 23:4 CleanupService.clean_temp_files - A (1)
M 35:4 CleanupService.clean_cache_files - A (1)
M 47:4 CleanupService.clean_logs - A (1)
M 59:4 CleanupService.run_cleanup - A (1)
syspilot/platforms/windows/monitoring_service.py
M 74:4 MonitoringService.get_top_processes - A (4)
C 13:0 MonitoringService - A (2)
M 40:4 MonitoringService.get_disk_usage - A (2)
M 19:4 MonitoringService.init - A (1)
M 23:4 MonitoringService.get_cpu_usage - A (1)
M 28:4 MonitoringService.get_memory_usage - A (1)
M 54:4 MonitoringService.get_cpu_temperature - A (1)
M 63:4 MonitoringService.get_network_io - A (1)
M 97:4 MonitoringService.get_system_stats - A (1)
syspilot/platforms/windows/system_info_service.py
M 59:4 SystemInfoService.get_disk_info - A (5)
C 13:0 SystemInfoService - A (3)
M 44:4 SystemInfoService.get_hardware_info - A (2)
M 19:4 SystemInfoService.init - A (1)
M 22:4 SystemInfoService.get_system_info - A (1)
syspilot/platforms/windows/cleanup_service.py
C 13:0 CleanupService - A (2)
M 19:4 CleanupService.init - A (1)
M 23:4 CleanupService.clean_temp_files - A (1)
M 35:4 CleanupService.clean_cache_files - A (1)
M 47:4 CleanupService.clean_logs - A (1)
M 59:4 CleanupService.run_cleanup - A (1)
syspilot/platforms/linux/monitoring_service.py
M 92:4 MonitoringService._get_cpu_temperature - C (15)
M 221:4 MonitoringService._get_network_io - B (6)
C 17:0 MonitoringService - A (5)
M 269:4 MonitoringService._get_top_processes - A (5)
M 308:4 MonitoringService._get_system_load - A (5)
M 352:4 MonitoringService._check_alerts - A (5)
M 431:4 MonitoringService.get_history - A (4)
M 464:4 MonitoringService.get_process_info - A (4)
M 20:4 MonitoringService.init - A (3)
M 193:4 MonitoringService._get_disk_info - A (3)
M 499:4 MonitoringService.get_system_info - A (3)
M 52:4 MonitoringService.get_system_stats - A (2)
M 84:4 MonitoringService._get_cpu_percent - A (2)
M 156:4 MonitoringService._get_memory_percent - A (2)
M 164:4 MonitoringService._get_memory_info - A (2)
M 185:4 MonitoringService._get_disk_percent - A (2)
M 333:4 MonitoringService._get_boot_time - A (2)
M 402:4 MonitoringService._update_history - A (2)
syspilot/platforms/linux/system_info_service.py
M 273:4 SystemInfoService._get_graphics_info - B (9)
M 118:4 SystemInfoService._get_cpu_info - B (7)
M 151:4 SystemInfoService._get_desktop_environment - B (7)
M 196:4 SystemInfoService._get_disk_partitions - B (7)
M 355:4 SystemInfoService.get_largest_files - B (6)
C 14:0 SystemInfoService - A (5)
M 306:4 SystemInfoService._get_system_services_count - A (5)
M 324:4 SystemInfoService.get_disk_usage_by_directory - A (5)
M 53:4 SystemInfoService._get_os_name - A (4)
M 64:4 SystemInfoService._get_os_version - A (4)
M 96:4 SystemInfoService._get_total_memory - A (4)
M 243:4 SystemInfoService._get_network_interfaces - A (4)
M 183:4 SystemInfoService._get_package_count - A (3)
M 404:4 SystemInfoService._format_bytes - A (3)
M 21:4 SystemInfoService.get_system_info - A (2)
M 75:4 SystemInfoService._get_kernel_version - A (2)
M 82:4 SystemInfoService._get_architecture - A (2)
M 89:4 SystemInfoService._get_hostname - A (2)
M 109:4 SystemInfoService._get_available_disk - A (2)
M 176:4 SystemInfoService._get_python_version - A (2)
M 17:4 SystemInfoService.init - A (1)
syspilot/platforms/linux/cleanup_service.py
M 238:4 CleanupService._clean_directory - B (10)
M 344:4 CleanupService.get_cleanup_preview - B (8)
M 37:4 CleanupService.full_cleanup - B (7)
M 394:4 CleanupService._get_files_to_clean - B (7)
M 203:4 CleanupService._clean_browser_cache - B (6)
C 18:0 CleanupService - A (5)
M 150:4 CleanupService._clean_log_files - A (5)
M 124:4 CleanupService._clean_temp_files - A (3)
M 137:4 CleanupService._clean_cache_files - A (3)
M 166:4 CleanupService._clean_package_cache - A (3)
M 191:4 CleanupService._clean_trash - A (3)
M 224:4 CleanupService._clean_system_cache - A (3)
M 281:4 CleanupService._should_exclude - A (3)
M 324:4 CleanupService._update_package_database - A (3)
M 336:4 CleanupService._format_bytes - A (3)
M 288:4 CleanupService._is_file_old - A (2)
M 297:4 CleanupService._is_directory_empty - A (2)
M 304:4 CleanupService._remove_file - A (2)
M 315:4 CleanupService._remove_directory - A (2)
M 21:4 CleanupService.init - A (1)
syspilot/services/system_info.py
M 273:4 SystemInfoService._get_graphics_info - B (9)
M 118:4 SystemInfoService._get_cpu_info - B (7)
M 151:4 SystemInfoService._get_desktop_environment - B (7)
M 196:4 SystemInfoService._get_disk_partitions - B (7)
M 355:4 SystemInfoService.get_largest_files - B (6)
C 14:0 SystemInfoService - A (5)
M 306:4 SystemInfoService._get_system_services_count - A (5)
M 324:4 SystemInfoService.get_disk_usage_by_directory - A (5)
M 53:4 SystemInfoService._get_os_name - A (4)
M 64:4 SystemInfoService._get_os_version - A (4)
M 96:4 SystemInfoService._get_total_memory - A (4)
M 243:4 SystemInfoService._get_network_interfaces - A (4)
M 183:4 SystemInfoService._get_package_count - A (3)
M 404:4 SystemInfoService._format_bytes - A (3)
M 21:4 SystemInfoService.get_system_info - A (2)
M 75:4 SystemInfoService._get_kernel_version - A (2)
M 82:4 SystemInfoService._get_architecture - A (2)
M 89:4 SystemInfoService._get_hostname - A (2)
M 109:4 SystemInfoService._get_available_disk - A (2)
M 176:4 SystemInfoService._get_python_version - A (2)
M 17:4 SystemInfoService.init - A (1)
syspilot/services/monitoring_service.py
M 86:4 MonitoringService._get_cpu_temperature - C (15)
M 215:4 MonitoringService._get_network_io - B (6)
M 263:4 MonitoringService._get_top_processes - A (5)
M 302:4 MonitoringService._get_system_load - A (5)
M 346:4 MonitoringService._check_alerts - A (5)
C 17:0 MonitoringService - A (4)
M 425:4 MonitoringService.get_history - A (4)
M 458:4 MonitoringService.get_process_info - A (4)
M 187:4 MonitoringService._get_disk_info - A (3)
M 493:4 MonitoringService.get_system_info - A (3)
M 46:4 MonitoringService.get_system_stats - A (2)
M 78:4 MonitoringService._get_cpu_percent - A (2)
M 150:4 MonitoringService._get_memory_percent - A (2)
M 158:4 MonitoringService._get_memory_info - A (2)
M 179:4 MonitoringService._get_disk_percent - A (2)
M 327:4 MonitoringService._get_boot_time - A (2)
M 396:4 MonitoringService._update_history - A (2)
M 20:4 MonitoringService.init - A (1)
syspilot/services/autostart_service.py
M 184:4 AutoStartService._get_syspilot_path - A (5)
C 13:0 AutoStartService - A (4)
M 29:4 AutoStartService.enable_autostart - A (4)
M 51:4 AutoStartService.disable_autostart - A (4)
M 128:4 AutoStartService._enable_systemd_autostart - A (4)
M 84:4 AutoStartService._enable_desktop_autostart - A (3)
M 25:4 AutoStartService.is_autostart_enabled - A (2)
M 16:4 AutoStartService.init - A (1)
M 206:4 AutoStartService.get_autostart_status - A (1)
syspilot/services/cleanup_service.py
M 238:4 CleanupService._clean_directory - B (10)
M 344:4 CleanupService.get_cleanup_preview - B (8)
M 37:4 CleanupService.full_cleanup - B (7)
M 394:4 CleanupService._get_files_to_clean - B (7)
M 203:4 CleanupService._clean_browser_cache - B (6)
C 18:0 CleanupService - A (5)
M 150:4 CleanupService._clean_log_files - A (5)
M 124:4 CleanupService._clean_temp_files - A (3)
M 137:4 CleanupService._clean_cache_files - A (3)
M 166:4 CleanupService._clean_package_cache - A (3)
M 191:4 CleanupService._clean_trash - A (3)
M 224:4 CleanupService._clean_system_cache - A (3)
M 281:4 CleanupService._should_exclude - A (3)
M 324:4 CleanupService._update_package_database - A (3)
M 336:4 CleanupService._format_bytes - A (3)
M 288:4 CleanupService._is_file_old - A (2)
M 297:4 CleanupService._is_directory_empty - A (2)
M 304:4 CleanupService._remove_file - A (2)
M 315:4 CleanupService._remove_directory - A (2)
M 21:4 CleanupService.init - A (1)
syspilot/services/scheduling_service.py
M 186:4 SchedulingService._run_scheduled_cleanup - B (7)
M 110:4 SchedulingService.remove_schedule - B (6)
M 158:4 SchedulingService._add_to_scheduler - B (6)
M 142:4 SchedulingService.disable_schedule - A (5)
M 213:4 SchedulingService.start_scheduler - A (5)
C 18:0 SchedulingService - A (4)
M 57:4 SchedulingService.add_schedule - A (4)
M 240:4 SchedulingService.stop_scheduler - A (4)
M 260:4 SchedulingService._scheduler_loop - A (4)
M 33:4 SchedulingService._load_schedules - A (3)
M 130:4 SchedulingService.enable_schedule - A (3)
M 274:4 SchedulingService.get_next_run_times - A (3)
M 44:4 SchedulingService._save_schedules - A (2)
M 288:4 SchedulingService.create_default_schedules - A (2)
M 21:4 SchedulingService.init - A (1)
M 270:4 SchedulingService.get_schedules - A (1)

324 blocks (classes, functions, methods) analyzed.
Average complexity: A (3.2098765432098766)

Maintainability Index

syspilot/core/app.py - A (22.49)
syspilot/core/cli.py - A (27.95)
syspilot/platforms/linux/system_info_service.py - A (38.71)
syspilot/services/system_info.py - A (38.71)
syspilot/platforms/linux/cleanup_service.py - A (40.11)
syspilot/services/cleanup_service.py - A (40.11)
syspilot/platforms/linux/monitoring_service.py - A (40.13)
syspilot/services/monitoring_service.py - A (40.80)
syspilot/widgets/charts.py - A (42.13)
syspilot/services/scheduling_service.py - A (46.53)
syspilot/core/daemon.py - A (49.77)
syspilot/utils/config.py - A (54.66)
syspilot/services/autostart_service.py - A (59.11)
syspilot/platforms/factory.py - A (61.85)
syspilot/main.py - A (75.54)
syspilot/platforms/init.py - A (76.23)
syspilot/platforms/windows/monitoring_service.py - A (78.60)
syspilot/platforms/windows/system_info_service.py - A (79.06)
syspilot/platforms/macos/monitoring_service.py - A (79.18)
syspilot/platforms/macos/system_info_service.py - A (79.95)
syspilot/utils/logger.py - A (82.21)
syspilot/services/init.py - A (88.53)
syspilot/init.py - A (100.00)
syspilot/widgets/init.py - A (100.00)
syspilot/core/init.py - A (100.00)
syspilot/utils/init.py - A (100.00)
syspilot/platforms/macos/init.py - A (100.00)
syspilot/platforms/macos/cleanup_service.py - A (100.00)
syspilot/platforms/windows/init.py - A (100.00)
syspilot/platforms/windows/cleanup_service.py - A (100.00)
syspilot/platforms/linux/init.py - A (100.00)

Raw Metrics

syspilot/init.py
LOC: 9
LLOC: 5
SLOC: 4
Comments: 0
Single comments: 0
Multi: 4
Blank: 1
- Comment Stats
(C % L): 0%
(C % S): 0%
(C + M % L): 44%
syspilot/main.py
LOC: 75
LLOC: 48
SLOC: 54
Comments: 6
Single comments: 7
Multi: 4
Blank: 10
- Comment Stats
(C % L): 8%
(C % S): 11%
(C + M % L): 13%
syspilot/widgets/init.py
LOC: 27
LLOC: 6
SLOC: 19
Comments: 2
Single comments: 2
Multi: 4
Blank: 2
- Comment Stats
(C % L): 7%
(C % S): 11%
(C + M % L): 22%
syspilot/widgets/charts.py
LOC: 519
LLOC: 266
SLOC: 336
Comments: 62
Single comments: 71
Multi: 4
Blank: 108
- Comment Stats
(C % L): 12%
(C % S): 18%
(C + M % L): 13%
syspilot/core/init.py
LOC: 3
LLOC: 1
SLOC: 0
Comments: 0
Single comments: 0
Multi: 3
Blank: 0
- Comment Stats
(C % L): 0%
(C % S): 0%
(C + M % L): 100%
syspilot/core/app.py
LOC: 1118
LLOC: 632
SLOC: 798
Comments: 90
Single comments: 114
Multi: 3
Blank: 203
- Comment Stats
(C % L): 8%
(C % S): 11%
(C + M % L): 8%
syspilot/core/daemon.py
LOC: 314
LLOC: 200
SLOC: 197
Comments: 31
Single comments: 41
Multi: 8
Blank: 68
- Comment Stats
(C % L): 10%
(C % S): 16%
(C + M % L): 12%
syspilot/core/cli.py
LOC: 416
LLOC: 308
SLOC: 308
Comments: 8
Single comments: 26
Multi: 8
Blank: 74
- Comment Stats
(C % L): 2%
(C % S): 3%
(C + M % L): 4%
syspilot/utils/init.py
LOC: 3
LLOC: 1
SLOC: 0
Comments: 0
Single comments: 0
Multi: 3
Blank: 0
- Comment Stats
(C % L): 0%
(C % S): 0%
(C + M % L): 100%
syspilot/utils/logger.py
LOC: 69
LLOC: 30
SLOC: 31
Comments: 8
Single comments: 7
Multi: 16
Blank: 15
- Comment Stats
(C % L): 12%
(C % S): 26%
(C + M % L): 35%
syspilot/utils/config.py
LOC: 257
LLOC: 128
SLOC: 166
Comments: 7
Single comments: 24
Multi: 24
Blank: 43
- Comment Stats
(C % L): 3%
(C % S): 4%
(C + M % L): 12%
syspilot/platforms/init.py
LOC: 85
LLOC: 45
SLOC: 50
Comments: 0
Single comments: 1
Multi: 15
Blank: 19
- Comment Stats
(C % L): 0%
(C % S): 0%
(C + M % L): 18%
syspilot/platforms/factory.py
LOC: 80
LLOC: 57
SLOC: 50
Comments: 0
Single comments: 6
Multi: 4
Blank: 20
- Comment Stats
(C % L): 0%
(C % S): 0%
(C + M % L): 5%
syspilot/platforms/macos/init.py
LOC: 7
LLOC: 1
SLOC: 0
Comments: 2
Single comments: 2
Multi: 4
Blank: 1
- Comment Stats
(C % L): 29%
(C % S): 200%
(C + M % L): 86%
syspilot/platforms/macos/monitoring_service.py
LOC: 109
LLOC: 48
SLOC: 67
Comments: 8
Single comments: 13
Multi: 16
Blank: 13
- Comment Stats
(C % L): 7%
(C % S): 12%
(C + M % L): 22%
syspilot/platforms/macos/system_info_service.py
LOC: 83
LLOC: 33
SLOC: 50
Comments: 3
Single comments: 3
Multi: 20
Blank: 10
- Comment Stats
(C % L): 4%
(C % S): 6%
(C + M % L): 28%
syspilot/platforms/macos/cleanup_service.py
LOC: 72
LLOC: 27
SLOC: 36
Comments: 4
Single comments: 4
Multi: 24
Blank: 8
- Comment Stats
(C % L): 6%
(C % S): 11%
(C + M % L): 39%
syspilot/platforms/windows/init.py
LOC: 7
LLOC: 1
SLOC: 0
Comments: 2
Single comments: 2
Multi: 4
Blank: 1
- Comment Stats
(C % L): 29%
(C % S): 200%
(C + M % L): 86%
syspilot/platforms/windows/monitoring_service.py
LOC: 112
LLOC: 48
SLOC: 67
Comments: 8
Single comments: 12
Multi: 20
Blank: 13
- Comment Stats
(C % L): 7%
(C % S): 12%
(C + M % L): 25%
syspilot/platforms/windows/system_info_service.py
LOC: 83
LLOC: 34
SLOC: 50
Comments: 3
Single comments: 3
Multi: 20
Blank: 10
- Comment Stats
(C % L): 4%
(C % S): 6%
(C + M % L): 28%
syspilot/platforms/windows/cleanup_service.py
LOC: 72
LLOC: 27
SLOC: 36
Comments: 4
Single comments: 4
Multi: 24
Blank: 8
- Comment Stats
(C % L): 6%
(C % S): 11%
(C + M % L): 39%
syspilot/platforms/linux/init.py
LOC: 6
LLOC: 1
SLOC: 0
Comments: 2
Single comments: 2
Multi: 3
Blank: 1
- Comment Stats
(C % L): 33%
(C % S): 200%
(C + M % L): 83%
syspilot/platforms/linux/monitoring_service.py
LOC: 513
LLOC: 253
SLOC: 372
Comments: 23
Single comments: 29
Multi: 35
Blank: 77
- Comment Stats
(C % L): 4%
(C % S): 6%
(C + M % L): 11%
syspilot/platforms/linux/system_info_service.py
LOC: 410
LLOC: 256
SLOC: 290
Comments: 17
Single comments: 34
Multi: 23
Blank: 63
- Comment Stats
(C % L): 4%
(C % S): 6%
(C + M % L): 10%
syspilot/platforms/linux/cleanup_service.py
LOC: 418
LLOC: 242
SLOC: 287
Comments: 16
Single comments: 31
Multi: 28
Blank: 72
- Comment Stats
(C % L): 4%
(C % S): 6%
(C + M % L): 11%
syspilot/services/init.py
LOC: 32
LLOC: 15
SLOC: 22
Comments: 1
Single comments: 1
Multi: 3
Blank: 6
- Comment Stats
(C % L): 3%
(C % S): 5%
(C + M % L): 12%
syspilot/services/system_info.py
LOC: 410
LLOC: 256
SLOC: 290
Comments: 17
Single comments: 34
Multi: 23
Blank: 63
- Comment Stats
(C % L): 4%
(C % S): 6%
(C + M % L): 10%
syspilot/services/monitoring_service.py
LOC: 507
LLOC: 246
SLOC: 366
Comments: 23
Single comments: 29
Multi: 35
Blank: 77
- Comment Stats
(C % L): 5%
(C % S): 6%
(C + M % L): 11%
syspilot/services/autostart_service.py
LOC: 214
LLOC: 97
SLOC: 147
Comments: 15
Single comments: 22
Multi: 11
Blank: 34
- Comment Stats
(C % L): 7%
(C % S): 10%
(C + M % L): 12%
syspilot/services/cleanup_service.py
LOC: 418
LLOC: 242
SLOC: 287
Comments: 16
Single comments: 31
Multi: 28
Blank: 72
- Comment Stats
(C % L): 4%
(C % S): 6%
(C + M % L): 11%
syspilot/services/scheduling_service.py
LOC: 310
LLOC: 200
SLOC: 212
Comments: 19
Single comments: 32
Multi: 15
Blank: 51
- Comment Stats
(C % L): 6%
(C % S): 9%
(C + M % L): 11%

Code Quality Score

Code Duplication Analysis

************* Module syspilot.services.scheduling_service
syspilot/services/scheduling_service.py:1:0: R0801: Similar lines in 2 files
==syspilot.platforms.linux.monitoring_service:[49:513]
==syspilot.services.monitoring_service:[43:507]
self.logger.info("Monitoring service initialized")

def get_system_stats(self) -> Dict:
    """
    Get current system statistics

    Returns:
        Dictionary with system statistics
    """
    try:
        stats = {
            "timestamp": datetime.now().isoformat(),
            "cpu_percent": self._get_cpu_percent(),
            "cpu_temperature": self._get_cpu_temperature(),
            "memory_percent": self._get_memory_percent(),
            "memory_info": self._get_memory_info(),
            "disk_percent": self._get_disk_percent(),
            "disk_info": self._get_disk_info(),
            "network_io": self._get_network_io(),
            "top_processes": self._get_top_processes(),
            "system_load": self._get_system_load(),
            "boot_time": self._get_boot_time(),
            "alerts": self._check_alerts(),
        }

        # Update history
        self._update_history(stats)

        return stats

    except Exception as e:
        self.logger.error(f"Error getting system stats: {e}")
        return {}

def _get_cpu_percent(self) -> float:
    """Get CPU usage percentage"""
    try:
        return psutil.cpu_percent(interval=0.1)
    except Exception as e:
        self.logger.error(f"Error getting CPU percent: {e}")
        return 0.0

def _get_cpu_temperature(self) -> Optional[float]:
    """Get CPU temperature in Celsius"""
    try:
        # Try to get temperature from psutil sensors
        if hasattr(psutil, "sensors_temperatures"):
            temps = psutil.sensors_temperatures()

            # Look for common temperature sensor names
            temp_sources = [
                "coretemp",  # Intel processors
                "k10temp",  # AMD processors
                "cpu_thermal",  # ARM processors
                "acpi",  # ACPI thermal zones
            ]

            for source in temp_sources:
                if source in temps and temps[source]:
                    # Get the first (usually main) temperature sensor
                    temp_sensor = temps[source][0]
                    if hasattr(temp_sensor, "current"):
                        self.logger.debug(
                            f"CPU temperature from {source}: {temp_sensor.current}°C"
                        )
                        return round(temp_sensor.current, 1)

            # If specific sources not found, try the first available temperature
            for source_name, sensors in temps.items():
                if sensors and len(sensors) > 0:
                    temp_sensor = sensors[0]
                    if hasattr(temp_sensor, "current"):
                        self.logger.debug(
                            f"CPU temperature from {source_name}: {temp_sensor.current}°C"
                        )
                        return round(temp_sensor.current, 1)

        # Fallback: try to read from /sys/class/thermal directly
        try:
            thermal_zones = [
                "/sys/class/thermal/thermal_zone0/temp",
                "/sys/class/thermal/thermal_zone1/temp",
                "/sys/class/thermal/thermal_zone2/temp",
            ]

            for zone_path in thermal_zones:
                if os.path.exists(zone_path):
                    with open(zone_path, "r") as f:
                        temp_millidegrees = int(f.read().strip())
                        temp_celsius = temp_millidegrees / 1000.0
                        if 0 < temp_celsius < 150:  # Reasonable temperature range
                            self.logger.debug(
                                f"CPU temperature from {zone_path}: {temp_celsius}°C"
                            )
                            return round(temp_celsius, 1)
        except (OSError, ValueError, FileNotFoundError):
            pass

        # If all methods fail, return None
        self.logger.debug("CPU temperature not available")
        return None

    except Exception as e:
        self.logger.error(f"Error getting CPU temperature: {e}")
        return None

def _get_memory_percent(self) -> float:
    """Get memory usage percentage"""
    try:
        return psutil.virtual_memory().percent
    except Exception as e:
        self.logger.error(f"Error getting memory percent: {e}")
        return 0.0

def _get_memory_info(self) -> Dict:
    """Get detailed memory information"""
    try:
        mem = psutil.virtual_memory()
        swap = psutil.swap_memory()

        return {
            "total": mem.total,
            "available": mem.available,
            "used": mem.used,
            "free": mem.free,
            "percent": mem.percent,
            "swap_total": swap.total,
            "swap_used": swap.used,
            "swap_free": swap.free,
            "swap_percent": swap.percent,
        }
    except Exception as e:
        self.logger.error(f"Error getting memory info: {e}")
        return {}

def _get_disk_percent(self) -> float:
    """Get disk usage percentage for root partition"""
    try:
        return psutil.disk_usage("/").percent
    except Exception as e:
        self.logger.error(f"Error getting disk percent: {e}")
        return 0.0

def _get_disk_info(self) -> Dict:
    """Get detailed disk information"""
    try:
        disk_usage = psutil.disk_usage("/")
        disk_io = psutil.disk_io_counters()

        info = {
            "total": disk_usage.total,
            "used": disk_usage.used,
            "free": disk_usage.free,
            "percent": disk_usage.percent,
        }

        if disk_io:
            info.update(
                {
                    "read_bytes": disk_io.read_bytes,
                    "write_bytes": disk_io.write_bytes,
                    "read_count": disk_io.read_count,
                    "write_count": disk_io.write_count,
                }
            )

        return info
    except Exception as e:
        self.logger.error(f"Error getting disk info: {e}")
        return {}

def _get_network_io(self) -> Dict:
    """Get network I/O statistics"""
    try:
        current_time = time.time()
        network_io = psutil.net_io_counters()

        if network_io is None:
            return {}

        result = {
            "bytes_sent": network_io.bytes_sent,
            "bytes_recv": network_io.bytes_recv,
            "packets_sent": network_io.packets_sent,
            "packets_recv": network_io.packets_recv,
        }

        # Calculate rates if we have previous data
        if self.prev_network_io and self.prev_network_time:
            time_diff = current_time - self.prev_network_time
            if time_diff > 0:
                bytes_sent_rate = (
                    (network_io.bytes_sent - self.prev_network_io.bytes_sent)
                    / time_diff
                    / 1024
                )  # KB/s
                bytes_recv_rate = (
                    (network_io.bytes_recv - self.prev_network_io.bytes_recv)
                    / time_diff
                    / 1024
                )  # KB/s

                result.update(
                    {
                        "bytes_sent_rate": round(bytes_sent_rate, 2),
                        "bytes_recv_rate": round(bytes_recv_rate, 2),
                    }
                )

        # Update previous values
        self.prev_network_io = network_io
        self.prev_network_time = current_time

        return result

    except Exception as e:
        self.logger.error(f"Error getting network I/O: {e}")
        return {}

def _get_top_processes(self, limit: int = 10) -> List[Dict]:
    """
    Get top processes by CPU usage

    Args:
        limit: Maximum number of processes to return

    Returns:
        List of process information dictionaries
    """
    try:
        processes = []

        for proc in psutil.process_iter(
            ["pid", "name", "cpu_percent", "memory_percent", "username"]
        ):
            try:
                proc_info = proc.info
                if proc_info["cpu_percent"] is not None:
                    processes.append(
                        {
                            "pid": proc_info["pid"],
                            "name": proc_info["name"],
                            "cpu_percent": proc_info["cpu_percent"],
                            "memory_percent": proc_info["memory_percent"],
                            "username": proc_info["username"],
                        }
                    )
            except (psutil.NoSuchProcess, psutil.AccessDenied):
                pass

        # Sort by CPU usage and return top processes
        processes.sort(key=lambda x: x["cpu_percent"], reverse=True)
        return processes[:limit]

    except Exception as e:
        self.logger.error(f"Error getting top processes: {e}")
        return []

def _get_system_load(self) -> Dict:
    """Get system load averages"""
    try:
        load_avg = psutil.getloadavg()
        cpu_count = psutil.cpu_count()

        return {
            "load_1min": load_avg[0],
            "load_5min": load_avg[1],
            "load_15min": load_avg[2],
            "cpu_count": cpu_count,
            "load_1min_percent": (
                (load_avg[0] / cpu_count) * 100 if cpu_count > 0 else 0
            ),
            "load_5min_percent": (
                (load_avg[1] / cpu_count) * 100 if cpu_count > 0 else 0
            ),
            "load_15min_percent": (
                (load_avg[2] / cpu_count) * 100 if cpu_count > 0 else 0
            ),
        }
    except Exception as e:
        self.logger.error(f"Error getting system load: {e}")
        return {}

def _get_boot_time(self) -> Dict:
    """Get system boot time information"""
    try:
        boot_timestamp = psutil.boot_time()
        boot_time = datetime.fromtimestamp(boot_timestamp)
        current_time = datetime.now()
        uptime = current_time - boot_time

        return {
            "boot_time": boot_time.isoformat(),
            "uptime_seconds": uptime.total_seconds(),
            "uptime_days": uptime.days,
            "uptime_hours": uptime.seconds // 3600,
            "uptime_minutes": (uptime.seconds % 3600) // 60,
        }
    except Exception as e:
        self.logger.error(f"Error getting boot time: {e}")
        return {}

def _check_alerts(self) -> List[Dict]:
    """Check for system alerts based on thresholds"""
    alerts = []

    try:
        # CPU alert
        cpu_percent = self._get_cpu_percent()
        if cpu_percent > self.alert_thresholds.get("cpu_percent", 80):
            alerts.append(
                {
                    "type": "cpu",
                    "level": "warning",
                    "message": f"High CPU usage: {cpu_percent:.1f}%",
                    "value": cpu_percent,
                    "threshold": self.alert_thresholds.get("cpu_percent", 80),
                }
            )

        # Memory alert
        memory_percent = self._get_memory_percent()
        if memory_percent > self.alert_thresholds.get("memory_percent", 85):
            alerts.append(
                {
                    "type": "memory",
                    "level": "warning",
                    "message": f"High memory usage: {memory_percent:.1f}%",
                    "value": memory_percent,
                    "threshold": self.alert_thresholds.get("memory_percent", 85),
                }
            )

        # Disk alert
        disk_percent = self._get_disk_percent()
        if disk_percent > self.alert_thresholds.get("disk_percent", 90):
            alerts.append(
                {
                    "type": "disk",
                    "level": "critical",
                    "message": f"High disk usage: {disk_percent:.1f}%",
                    "value": disk_percent,
                    "threshold": self.alert_thresholds.get("disk_percent", 90),
                }
            )

        return alerts

    except Exception as e:
        self.logger.error(f"Error checking alerts: {e}")
        return []

def _update_history(self, stats: Dict):
    """Update historical data"""
    try:
        timestamp = stats.get("timestamp", datetime.now().isoformat())

        self.cpu_history.append(
            {"timestamp": timestamp, "value": stats.get("cpu_percent", 0)}
        )

        self.memory_history.append(
            {"timestamp": timestamp, "value": stats.get("memory_percent", 0)}
        )

        self.disk_history.append(
            {"timestamp": timestamp, "value": stats.get("disk_percent", 0)}
        )

        network_io = stats.get("network_io", {})
        self.network_history.append(
            {
                "timestamp": timestamp,
                "bytes_sent": network_io.get("bytes_sent", 0),
                "bytes_recv": network_io.get("bytes_recv", 0),
            }
        )

    except Exception as e:
        self.logger.error(f"Error updating history: {e}")

def get_history(self, metric: str, limit: Optional[int] = None) -> List[Dict]:
    """
    Get historical data for a specific metric

    Args:
        metric: Metric name (cpu, memory, disk, network)
        limit: Maximum number of entries to return

    Returns:
        List of historical data points
    """
    try:
        history_map = {
            "cpu": self.cpu_history,
            "memory": self.memory_history,
            "disk": self.disk_history,
            "network": self.network_history,
        }

        if metric not in history_map:
            return []

        history = list(history_map[metric])

        if limit:
            history = history[-limit:]

        return history

    except Exception as e:
        self.logger.error(f"Error getting history for {metric}: {e}")
        return []

def get_process_info(self, pid: int) -> Dict:
    """
    Get detailed information about a specific process

    Args:
        pid: Process ID

    Returns:
        Dictionary with process information
    """
    try:
        proc = psutil.Process(pid)

        return {
            "pid": proc.pid,
            "name": proc.name(),
            "cmdline": proc.cmdline(),
            "cpu_percent": proc.cpu_percent(),
            "memory_percent": proc.memory_percent(),
            "memory_info": proc.memory_info()._asdict(),
            "status": proc.status(),
            "create_time": proc.create_time(),
            "username": proc.username(),
            "num_threads": proc.num_threads(),
            "connections": (
                len(proc.connections()) if hasattr(proc, "connections") else 0
            ),
        }

    except psutil.NoSuchProcess:
        return {}
    except Exception as e:
        self.logger.error(f"Error getting process info for PID {pid}: {e}")
        return {}

def get_system_info(self) -> Dict:
    """Get general system information"""
    try:
        return {
            "cpu_count": psutil.cpu_count(),
            "cpu_count_logical": psutil.cpu_count(logical=True),
            "cpu_freq": psutil.cpu_freq()._asdict() if psutil.cpu_freq() else {},
            "memory_total": psutil.virtual_memory().total,
            "disk_total": psutil.disk_usage("/").total,
            "platform": psutil.LINUX,
            "python_version": psutil.version_info,
        }
    except Exception as e:
        self.logger.error(f"Error getting system info: {e}")
        return {} (duplicate-code)

syspilot/services/scheduling_service.py:1:0: R0801: Similar lines in 2 files
==syspilot.platforms.linux.system_info_service:[13:410]
==syspilot.services.system_info:[13:410]
class SystemInfoService:
"""Service for gathering system information"""

def __init__(self):
    """Initialize system info service"""
    self.logger = get_logger(__name__)

def get_system_info(self) -> Dict:
    """
    Get comprehensive system information

    Returns:
        Dictionary with system information
    """
    try:
        info = {
            "os_name": self._get_os_name(),
            "os_version": self._get_os_version(),
            "kernel_version": self._get_kernel_version(),
            "architecture": self._get_architecture(),
            "hostname": self._get_hostname(),
            "total_memory": self._get_total_memory(),
            "available_disk": self._get_available_disk(),
            "cpu_info": self._get_cpu_info(),
            "desktop_environment": self._get_desktop_environment(),
            "python_version": self._get_python_version(),
            "installed_packages": self._get_package_count(),
            "disk_partitions": self._get_disk_partitions(),
            "network_interfaces": self._get_network_interfaces(),
            "graphics_info": self._get_graphics_info(),
            "system_services": self._get_system_services_count(),
        }

        return info

    except Exception as e:
        self.logger.error(f"Error getting system info: {e}")
        return {}

def _get_os_name(self) -> str:
    """Get operating system name"""
    try:
        with open("/etc/os-release", "r") as f:
            for line in f:
                if line.startswith("PRETTY_NAME="):
                    return line.split("=")[1].strip('"')
        return platform.system()
    except Exception:
        return platform.system()

def _get_os_version(self) -> str:
    """Get operating system version"""
    try:
        with open("/etc/os-release", "r") as f:
            for line in f:
                if line.startswith("VERSION="):
                    return line.split("=")[1].strip('"')
        return platform.release()
    except Exception:
        return platform.release()

def _get_kernel_version(self) -> str:
    """Get kernel version"""
    try:
        return platform.release()
    except Exception:
        return "Unknown"

def _get_architecture(self) -> str:
    """Get system architecture"""
    try:
        return platform.machine()
    except Exception:
        return "Unknown"

def _get_hostname(self) -> str:
    """Get system hostname"""
    try:
        return platform.node()
    except Exception:
        return "Unknown"

def _get_total_memory(self) -> str:
    """Get total system memory"""
    try:
        with open("/proc/meminfo", "r") as f:
            for line in f:
                if line.startswith("MemTotal:"):
                    mem_kb = int(line.split()[1])
                    mem_gb = mem_kb / (1024 * 1024)
                    return f"{mem_gb:.2f} GB"
        return "Unknown"
    except Exception:
        return "Unknown"

def _get_available_disk(self) -> str:
    """Get available disk space"""
    try:
        total, used, free = shutil.disk_usage("/")
        free_gb = free / (1024 * 1024 * 1024)
        return f"{free_gb:.2f} GB"
    except Exception:
        return "Unknown"

def _get_cpu_info(self) -> Dict:
    """Get CPU information"""
    try:
        cpu_info = {}

        # Get CPU model name
        with open("/proc/cpuinfo", "r") as f:
            for line in f:
                if line.startswith("model name"):
                    cpu_info["model"] = line.split(":")[1].strip()
                    break

        # Get CPU count
        cpu_info["cores"] = os.cpu_count()

        # Get CPU frequency
        try:
            with open("/proc/cpuinfo", "r") as f:
                for line in f:
                    if line.startswith("cpu MHz"):
                        cpu_info["frequency"] = (
                            f"{float(line.split(':')[1].strip()):.0f} MHz"
                        )
                        break
        except Exception:
            pass

        return cpu_info

    except Exception as e:
        self.logger.error(f"Error getting CPU info: {e}")
        return {}

def _get_desktop_environment(self) -> str:
    """Get desktop environment"""
    try:
        # Check common desktop environment variables
        desktop_env = os.environ.get("XDG_CURRENT_DESKTOP", "")
        if desktop_env:
            return desktop_env

        desktop_env = os.environ.get("DESKTOP_SESSION", "")
        if desktop_env:
            return desktop_env

        # Check for specific desktop environments
        if os.environ.get("GNOME_DESKTOP_SESSION_ID"):
            return "GNOME"
        elif os.environ.get("KDE_FULL_SESSION"):
            return "KDE"
        elif os.environ.get("XFCE4_SESSION"):
            return "XFCE"

        return "Unknown"

    except Exception:
        return "Unknown"

def _get_python_version(self) -> str:
    """Get Python version"""
    try:
        return platform.python_version()
    except Exception:
        return "Unknown"

def _get_package_count(self) -> int:
    """Get number of installed packages"""
    try:
        # Count APT packages
        result = subprocess.run(
            ["dpkg", "--get-selections"], capture_output=True, text=True
        )
        if result.returncode == 0:
            return len(result.stdout.strip().split("\n"))
        return 0
    except Exception:
        return 0

def _get_disk_partitions(self) -> List[Dict]:
    """Get disk partition information"""
    try:
        partitions = []

        # Read from /proc/mounts
        with open("/proc/mounts", "r") as f:
            for line in f:
                parts = line.strip().split()
                if len(parts) >= 3:
                    device, mountpoint, fstype = parts[0], parts[1], parts[2]

                    # Filter out non-disk filesystems
                    if fstype in [
                        "ext4",
                        "ext3",
                        "ext2",
                        "btrfs",
                        "xfs",
                        "ntfs",
                        "fat32",
                        "vfat",
                    ]:
                        try:
                            total, used, free = shutil.disk_usage(mountpoint)
                            partitions.append(
                                {
                                    "device": device,
                                    "mountpoint": mountpoint,
                                    "fstype": fstype,
                                    "total": total,
                                    "used": used,
                                    "free": free,
                                    "percent": (
                                        (used / total) * 100 if total > 0 else 0
                                    ),
                                }
                            )
                        except Exception:
                            pass

        return partitions

    except Exception as e:
        self.logger.error(f"Error getting disk partitions: {e}")
        return []

def _get_network_interfaces(self) -> List[Dict]:
    """Get network interface information"""
    try:
        interfaces = []

        # Read from /proc/net/dev
        with open("/proc/net/dev", "r") as f:
            lines = f.readlines()[2:]  # Skip header lines

            for line in lines:
                parts = line.strip().split()
                if len(parts) >= 10:
                    interface = parts[0].rstrip(":")
                    rx_bytes = int(parts[1])
                    tx_bytes = int(parts[9])

                    interfaces.append(
                        {
                            "name": interface,
                            "rx_bytes": rx_bytes,
                            "tx_bytes": tx_bytes,
                        }
                    )

        return interfaces

    except Exception as e:
        self.logger.error(f"Error getting network interfaces: {e}")
        return []

def _get_graphics_info(self) -> Dict:
    """Get graphics card information"""
    try:
        graphics_info = {}

        # Try to get GPU info using lspci
        try:
            result = subprocess.run(["lspci", "-v"], capture_output=True, text=True)
            if result.returncode == 0:
                lines = result.stdout.split("\n")
                for line in lines:
                    if "VGA compatible controller" in line:
                        graphics_info["gpu"] = (
                            line.split(": ")[1] if ": " in line else line
                        )
                        break
        except Exception:
            pass

        # Try to get display info
        try:
            display = os.environ.get("DISPLAY", "")
            if display:
                graphics_info["display"] = display
        except Exception:
            pass

        return graphics_info

    except Exception as e:
        self.logger.error(f"Error getting graphics info: {e}")
        return {}

def _get_system_services_count(self) -> int:
    """Get number of system services"""
    try:
        # Count systemd services
        result = subprocess.run(
            ["systemctl", "list-units", "--type=service"],
            capture_output=True,
            text=True,
        )
        if result.returncode == 0:
            lines = result.stdout.strip().split("\n")
            # Filter out header and footer lines
            service_lines = [line for line in lines if ".service" in line]
            return len(service_lines)
        return 0
    except Exception:
        return 0

def get_disk_usage_by_directory(self, directory: str = "/") -> List[Dict]:
    """
    Get disk usage by directory

    Args:
        directory: Directory to analyze

    Returns:
        List of directories with their sizes
    """
    try:
        directories = []

        # Use du command to get directory sizes
        result = subprocess.run(
            ["du", "-h", "--max-depth=1", directory], capture_output=True, text=True
        )

        if result.returncode == 0:
            lines = result.stdout.strip().split("\n")
            for line in lines:
                if "\t" in line:
                    size, path = line.split("\t")
                    directories.append({"path": path, "size": size})

        return directories

    except Exception as e:
        self.logger.error(f"Error getting disk usage by directory: {e}")
        return []

def get_largest_files(self, directory: str = "/", limit: int = 10) -> List[Dict]:
    """
    Get largest files in a directory

    Args:
        directory: Directory to search
        limit: Maximum number of files to return

    Returns:
        List of largest files
    """
    try:
        files = []

        # Use find command to get largest files
        result = subprocess.run(
            ["find", directory, "-type", "f", "-exec", "ls", "-la", "{}", "+"],
            capture_output=True,
            text=True,
        )

        if result.returncode == 0:
            lines = result.stdout.strip().split("\n")
            file_info = []

            for line in lines:
                if line.strip():
                    parts = line.split()
                    if len(parts) >= 9:
                        size = int(parts[4])
                        filename = " ".join(parts[8:])
                        file_info.append(
                            {
                                "filename": filename,
                                "size": size,
                                "size_human": self._format_bytes(size),
                            }
                        )

            # Sort by size and return top files
            file_info.sort(key=lambda x: x["size"], reverse=True)
            files = file_info[:limit]

        return files

    except Exception as e:
        self.logger.error(f"Error getting largest files: {e}")
        return []

def _format_bytes(self, bytes_count: int) -> str:
    """Format bytes count to human readable string"""
    for unit in ["B", "KB", "MB", "GB", "TB"]:
        if bytes_count < 1024.0:
            return f"{bytes_count:.2f} {unit}"
        bytes_count /= 1024.0
    return f"{bytes_count:.2f} PB" (duplicate-code)

syspilot/services/scheduling_service.py:1:0: R0801: Similar lines in 2 files
==syspilot.platforms.linux.cleanup_service:[17:418]
==syspilot.services.cleanup_service:[17:418]
class CleanupService:
"""Service for system cleanup operations"""

def __init__(self, config: ConfigManager):
    """
    Initialize cleanup service

    Args:
        config: Configuration manager instance
    """
    self.config = config
    self.logger = get_logger(__name__)
    self.stats = {
        "files_cleaned": 0,
        "directories_cleaned": 0,
        "space_freed": 0,
        "errors": [],
    }

def full_cleanup(
    self,
    progress_callback: Optional[Callable[[int], None]] = None,
    status_callback: Optional[Callable[[str], None]] = None,
) -> Dict:
    """
    Perform full system cleanup

    Args:
        progress_callback: Progress update callback
        status_callback: Status update callback

    Returns:
        Dictionary with cleanup results
    """
    start_time = time.time()
    self.stats = {
        "files_cleaned": 0,
        "directories_cleaned": 0,
        "space_freed": 0,
        "errors": [],
    }

    try:
        self.logger.info("Starting full system cleanup")

        # Define cleanup tasks
        cleanup_tasks = [
            ("Cleaning temporary files", self._clean_temp_files),
            ("Cleaning cache files", self._clean_cache_files),
            ("Cleaning log files", self._clean_log_files),
            ("Cleaning package cache", self._clean_package_cache),
            ("Cleaning trash", self._clean_trash),
            ("Cleaning browser cache", self._clean_browser_cache),
            ("Cleaning system cache", self._clean_system_cache),
        ]

        total_tasks = len(cleanup_tasks)

        for i, (task_name, task_func) in enumerate(cleanup_tasks):
            if status_callback:
                status_callback(task_name)

            self.logger.info(f"Executing task: {task_name}")

            try:
                task_func()
            except Exception as e:
                error_msg = f"Error in {task_name}: {str(e)}"
                self.logger.error(error_msg)
                self.stats["errors"].append(error_msg)

            # Update progress
            if progress_callback:
                progress = int((i + 1) / total_tasks * 100)
                progress_callback(progress)

        # Final cleanup tasks
        if status_callback:
            status_callback("Finalizing cleanup")

        self._update_package_database()

        # Calculate results
        end_time = time.time()
        time_taken = end_time - start_time

        results = {
            "temp_files_cleaned": self.stats["files_cleaned"],
            "cache_files_cleaned": self.stats["directories_cleaned"],
            "space_freed": self._format_bytes(self.stats["space_freed"]),
            "time_taken": f"{time_taken:.2f} seconds",
            "errors": self.stats["errors"],
        }

        self.logger.info(f"Cleanup completed in {time_taken:.2f} seconds")
        self.logger.info(f"Files cleaned: {self.stats['files_cleaned']}")
        self.logger.info(
            f"Space freed: {self._format_bytes(self.stats['space_freed'])}"
        )

        return results

    except Exception as e:
        self.logger.error(f"Full cleanup failed: {e}")
        raise

def _clean_temp_files(self):
    """Clean temporary files"""
    temp_dirs = self.config.get_temp_dirs()
    max_age_days = self.config.get_max_age_days()
    exclude_patterns = self.config.get_exclude_patterns()

    for temp_dir in temp_dirs:
        if not os.path.exists(temp_dir):
            continue

        self.logger.debug(f"Cleaning temp directory: {temp_dir}")
        self._clean_directory(temp_dir, max_age_days, exclude_patterns)

def _clean_cache_files(self):
    """Clean cache files"""
    cache_dirs = self.config.get_cache_dirs()
    max_age_days = self.config.get_max_age_days()
    exclude_patterns = self.config.get_exclude_patterns()

    for cache_dir in cache_dirs:
        if not os.path.exists(cache_dir):
            continue

        self.logger.debug(f"Cleaning cache directory: {cache_dir}")
        self._clean_directory(cache_dir, max_age_days, exclude_patterns)

def _clean_log_files(self):
    """Clean log files"""
    log_patterns = self.config.get_log_files()
    max_age_days = self.config.get_max_age_days()

    for pattern in log_patterns:
        try:
            files = glob.glob(pattern)
            for file_path in files:
                if self._is_file_old(file_path, max_age_days):
                    self._remove_file(file_path)
        except Exception as e:
            self.logger.error(
                f"Error cleaning log files with pattern {pattern}: {e}"
            )

def _clean_package_cache(self):
    """Clean package cache"""
    try:
        # Clean apt cache
        self.logger.debug("Cleaning apt cache")
        subprocess.run(
            ["sudo", "apt-get", "clean"], check=True, capture_output=True
        )

        # Clean apt auto-remove
        subprocess.run(
            ["sudo", "apt-get", "autoremove", "-y"], check=True, capture_output=True
        )

        # Clean apt auto-clean
        subprocess.run(
            ["sudo", "apt-get", "autoclean"], check=True, capture_output=True
        )

        self.logger.info("Package cache cleaned successfully")
    except subprocess.CalledProcessError as e:
        self.logger.error(f"Error cleaning package cache: {e}")
    except Exception as e:
        self.logger.error(f"Unexpected error cleaning package cache: {e}")

def _clean_trash(self):
    """Clean trash directories"""
    trash_dirs = [
        os.path.expanduser("~/.local/share/Trash"),
        os.path.expanduser("~/.Trash"),
    ]

    for trash_dir in trash_dirs:
        if os.path.exists(trash_dir):
            self.logger.debug(f"Cleaning trash directory: {trash_dir}")
            self._clean_directory(trash_dir, 0, [])  # Clean all trash

def _clean_browser_cache(self):
    """Clean browser cache files"""
    browser_cache_dirs = [
        os.path.expanduser("~/.cache/google-chrome"),
        os.path.expanduser("~/.cache/chromium"),
        os.path.expanduser("~/.cache/mozilla"),
        os.path.expanduser("~/.mozilla/firefox/*/Cache"),
    ]

    for cache_dir in browser_cache_dirs:
        if "*" in cache_dir:
            # Handle glob patterns
            for expanded_dir in glob.glob(cache_dir):
                if os.path.exists(expanded_dir):
                    self.logger.debug(f"Cleaning browser cache: {expanded_dir}")
                    self._clean_directory(expanded_dir, 7, [])
        else:
            if os.path.exists(cache_dir):
                self.logger.debug(f"Cleaning browser cache: {cache_dir}")
                self._clean_directory(cache_dir, 7, [])

def _clean_system_cache(self):
    """Clean system cache"""
    system_cache_dirs = [
        "/var/cache/fontconfig",
        "/var/cache/man",
        os.path.expanduser("~/.cache/fontconfig"),
        os.path.expanduser("~/.cache/thumbnails"),
    ]

    for cache_dir in system_cache_dirs:
        if os.path.exists(cache_dir):
            self.logger.debug(f"Cleaning system cache: {cache_dir}")
            self._clean_directory(cache_dir, 30, [])

def _clean_directory(
    self, directory: str, max_age_days: int, exclude_patterns: List[str]
):
    """
    Clean files in a directory

    Args:
        directory: Directory path to clean
        max_age_days: Maximum age of files to keep
        exclude_patterns: Patterns to exclude from cleaning
    """
    try:
        if not os.path.exists(directory):
            return

        cutoff_date = datetime.now() - timedelta(days=max_age_days)

        for root, dirs, files in os.walk(directory):
            # Clean files
            for file in files:
                file_path = os.path.join(root, file)

                # Check exclude patterns
                if self._should_exclude(file, exclude_patterns):
                    continue

                # Check file age
                if max_age_days > 0 and not self._is_file_old(
                    file_path, max_age_days
                ):
                    continue

                self._remove_file(file_path)

            # Clean empty directories
            for dir_name in dirs:
                dir_path = os.path.join(root, dir_name)
                if self._is_directory_empty(dir_path):
                    self._remove_directory(dir_path)

    except Exception as e:
        self.logger.error(f"Error cleaning directory {directory}: {e}")

def _should_exclude(self, filename: str, exclude_patterns: List[str]) -> bool:
    """Check if file should be excluded based on patterns"""
    for pattern in exclude_patterns:
        if pattern.lower() in filename.lower():
            return True
    return False

def _is_file_old(self, file_path: str, max_age_days: int) -> bool:
    """Check if file is older than max_age_days"""
    try:
        file_mtime = os.path.getmtime(file_path)
        cutoff_time = time.time() - (max_age_days * 24 * 60 * 60)
        return file_mtime < cutoff_time
    except OSError:
        return False

def _is_directory_empty(self, directory: str) -> bool:
    """Check if directory is empty"""
    try:
        return not os.listdir(directory)
    except OSError:
        return False

def _remove_file(self, file_path: str):
    """Remove a file and update statistics"""
    try:
        file_size = os.path.getsize(file_path)
        os.remove(file_path)
        self.stats["files_cleaned"] += 1
        self.stats["space_freed"] += file_size
        self.logger.debug(f"Removed file: {file_path}")
    except OSError as e:
        self.logger.debug(f"Could not remove file {file_path}: {e}")

def _remove_directory(self, dir_path: str):
    """Remove a directory and update statistics"""
    try:
        shutil.rmtree(dir_path)
        self.stats["directories_cleaned"] += 1
        self.logger.debug(f"Removed directory: {dir_path}")
    except OSError as e:
        self.logger.debug(f"Could not remove directory {dir_path}: {e}")

def _update_package_database(self):
    """Update package database"""
    try:
        self.logger.debug("Updating package database")
        subprocess.run(["sudo", "updatedb"], check=True, capture_output=True)
    except subprocess.CalledProcessError:
        self.logger.debug(
            "Could not update package database (updatedb not available)"
        )
    except Exception as e:
        self.logger.error(f"Error updating package database: {e}")

def _format_bytes(self, bytes_count: int) -> str:
    """Format bytes count to human readable string"""
    for unit in ["B", "KB", "MB", "GB", "TB"]:
        if bytes_count < 1024.0:
            return f"{bytes_count:.2f} {unit}"
        bytes_count /= 1024.0
    return f"{bytes_count:.2f} PB"

def get_cleanup_preview(self) -> Dict:
    """
    Get preview of what would be cleaned without actually cleaning

    Returns:
        Dictionary with preview information
    """
    preview = {
        "temp_files": [],
        "cache_files": [],
        "log_files": [],
        "estimated_space": 0,
    }

    try:
        # Preview temp files
        temp_dirs = self.config.get_temp_dirs()
        max_age_days = self.config.get_max_age_days()
        exclude_patterns = self.config.get_exclude_patterns()

        for temp_dir in temp_dirs:
            if os.path.exists(temp_dir):
                files = self._get_files_to_clean(
                    temp_dir, max_age_days, exclude_patterns
                )
                preview["temp_files"].extend(files)

        # Preview cache files
        cache_dirs = self.config.get_cache_dirs()
        for cache_dir in cache_dirs:
            if os.path.exists(cache_dir):
                files = self._get_files_to_clean(
                    cache_dir, max_age_days, exclude_patterns
                )
                preview["cache_files"].extend(files)

        # Calculate estimated space
        all_files = preview["temp_files"] + preview["cache_files"]
        for file_path in all_files:
            try:
                preview["estimated_space"] += os.path.getsize(file_path)
            except OSError:
                pass

        return preview

    except Exception as e:
        self.logger.error(f"Error getting cleanup preview: {e}")
        return preview

def _get_files_to_clean(
    self, directory: str, max_age_days: int, exclude_patterns: List[str]
) -> List[str]:
    """Get list of files that would be cleaned"""
    files_to_clean = []

    try:
        for root, dirs, files in os.walk(directory):
            for file in files:
                file_path = os.path.join(root, file)

                if self._should_exclude(file, exclude_patterns):
                    continue

                if max_age_days > 0 and not self._is_file_old(
                    file_path, max_age_days
                ):
                    continue

                files_to_clean.append(file_path)

    except Exception as e:
        self.logger.error(f"Error getting files to clean from {directory}: {e}")

    return files_to_clean (duplicate-code)

syspilot/services/scheduling_service.py:1:0: R0801: Similar lines in 2 files
==syspilot.platforms.macos.monitoring_service:[43:107]
==syspilot.platforms.windows.monitoring_service:[46:110]
return {
"total": disk.total,
"used": disk.used,
"free": disk.free,
"percent": (disk.used / disk.total) * 100,
}

def get_cpu_temperature(self) -> Optional[float]:
    """
    Get macOS CPU temperature
    TODO: Implement macOS temperature monitoring using IOKit or system_profiler
    """
    # macOS temperature monitoring requires specific implementations
    # Placeholder - return None for now
    return None

def get_network_io(self) -> Dict:
    """Get macOS network I/O statistics"""
    # Basic implementation using psutil (works cross-platform)
    net_io = psutil.net_io_counters()
    return {
        "bytes_sent": net_io.bytes_sent,
        "bytes_recv": net_io.bytes_recv,
        "packets_sent": net_io.packets_sent,
        "packets_recv": net_io.packets_recv,
    }

def get_top_processes(self, limit: int = 5) -> List[Dict]:
    """Get top macOS processes by CPU usage"""
    # Basic implementation using psutil (works cross-platform)
    processes = []
    for proc in psutil.process_iter(
        ["pid", "name", "cpu_percent", "memory_percent"]
    ):
        try:
            processes.append(
                {
                    "pid": proc.info["pid"],
                    "name": proc.info["name"],
                    "cpu_percent": proc.info["cpu_percent"],
                    "memory_percent": proc.info["memory_percent"],
                }
            )
        except (psutil.NoSuchProcess, psutil.AccessDenied):
            pass

    # Sort by CPU usage and return top processes
    processes.sort(key=lambda x: x["cpu_percent"] or 0, reverse=True)
    return processes[:limit]

def get_system_stats(self) -> Dict:
    """
    Get comprehensive macOS system statistics
    TODO: Add macOS-specific monitoring features
    """
    return {
        "cpu_percent": self.get_cpu_usage(),
        "memory": self.get_memory_usage(),
        "memory_percent": self.get_memory_usage()["percent"],
        "disk": self.get_disk_usage(),
        "disk_percent": self.get_disk_usage()["percent"],
        "cpu_temperature": self.get_cpu_temperature(),
        "network_io": self.get_network_io(),
        "top_processes": self.get_top_processes(), (duplicate-code)

syspilot/services/scheduling_service.py:1:0: R0801: Similar lines in 2 files
==syspilot.platforms.macos.monitoring_service:[12:42]
==syspilot.platforms.windows.monitoring_service:[12:45]
class MonitoringService:
"""
macOS-specific monitoring service
TODO: Implement macOS-specific monitoring using system frameworks
"""

def __init__(self, config=None):
    self.config = config
    self.logger = None

def get_cpu_usage(self) -> float:
    """Get macOS CPU usage"""
    # Basic implementation using psutil (works cross-platform)
    return psutil.cpu_percent(interval=1)

def get_memory_usage(self) -> Dict:
    """Get macOS memory usage"""
    # Basic implementation using psutil (works cross-platform)
    memory = psutil.virtual_memory()
    return {
        "total": memory.total,
        "available": memory.available,
        "percent": memory.percent,
        "used": memory.used,
        "free": memory.free,
    }

def get_disk_usage(self) -> Dict:
    """Get macOS disk usage"""
    # Basic implementation using psutil (works cross-platform) (duplicate-code)

syspilot/services/scheduling_service.py:1:0: R0801: Similar lines in 2 files
==syspilot.platforms.linux.cleanup_service:[400:412]
==syspilot.services.cleanup_service:[254:269]
for root, dirs, files in os.walk(directory):
# Clean files
for file in files:
file_path = os.path.join(root, file)

                # Check exclude patterns
                if self._should_exclude(file, exclude_patterns):
                    continue

                # Check file age
                if max_age_days > 0 and not self._is_file_old(
                    file_path, max_age_days
                ):
                    continue

(duplicate-code)
syspilot/services/scheduling_service.py:1:0: R0801: Similar lines in 2 files
==syspilot.platforms.linux.cleanup_service:[254:269]
==syspilot.services.cleanup_service:[400:412]
for root, dirs, files in os.walk(directory):
for file in files:
file_path = os.path.join(root, file)

                if self._should_exclude(file, exclude_patterns):
                    continue

                if max_age_days > 0 and not self._is_file_old(
                    file_path, max_age_days
                ):
                    continue

(duplicate-code)
syspilot/services/scheduling_service.py:1:0: R0801: Similar lines in 2 files
==syspilot.platforms.macos.system_info_service:[67:75]
==syspilot.platforms.windows.system_info_service:[68:76]
try:
usage = psutil.disk_usage(partition.mountpoint)
disks[partition.device] = {
"total": usage.total,
"used": usage.used,
"free": usage.free,
"percent": (usage.used / usage.total) * 100,
"filesystem": partition.fstype, (duplicate-code)
syspilot/services/scheduling_service.py:1:0: R0801: Similar lines in 2 files
==syspilot.platforms.macos.system_info_service:[32:40]
==syspilot.platforms.windows.system_info_service:[32:40]
"os_version": platform.platform(),
"architecture": platform.architecture()[0],
"processor": platform.processor(),
"total_memory": f"{memory.total / (10243):.1f} GB",
"available_memory": f"{memory.available / (1024
3):.1f} GB",
"total_disk": f"{disk.total / (10243):.1f} GB",
"available_disk": f"{disk.free / (1024
3):.1f} GB",
"python_version": platform.python_version(), (duplicate-code)
syspilot/services/scheduling_service.py:1:0: R0801: Similar lines in 2 files
==syspilot.platforms.macos.cleanup_service:[56:70]
==syspilot.platforms.windows.cleanup_service:[56:70]
}

def run_cleanup(self) -> Dict:
    """
    Run comprehensive macOS cleanup
    TODO: Implement full macOS system cleanup
    """
    # Placeholder implementation
    return {
        "temp_files_cleaned": 0,
        "cache_files_cleaned": 0,
        "log_files_cleaned": 0,
        "space_freed": "0 MB",
        "time_taken": "0 seconds", (duplicate-code)

syspilot/services/scheduling_service.py:1:0: R0801: Similar lines in 2 files
==syspilot.platforms.macos.system_info_service:[41:55]
==syspilot.platforms.windows.system_info_service:[41:55]
}

def get_hardware_info(self) -> Dict:
    """
    Get Windows hardware information
    TODO: Implement Windows hardware detection using WMI
    """
    # Placeholder implementation
    return {
        "cpu_cores": psutil.cpu_count(logical=False),
        "cpu_threads": psutil.cpu_count(logical=True),
        "cpu_frequency": (
            psutil.cpu_freq().current if psutil.cpu_freq() else "Unknown"
        ), (duplicate-code)

syspilot/services/scheduling_service.py:1:0: R0801: Similar lines in 2 files
==syspilot.platforms.linux.cleanup_service:[52:59]
==syspilot.services.cleanup_service:[29:51]
self.stats = {
"files_cleaned": 0,
"directories_cleaned": 0,
"space_freed": 0,
"errors": [],
}

def full_cleanup(
    self,
    progress_callback: Optional[Callable[[int], None]] = None,
    status_callback: Optional[Callable[[str], None]] = None,
) -> Dict:
    """
    Perform full system cleanup

    Args:
        progress_callback: Progress update callback
        status_callback: Status update callback

    Returns:
        Dictionary with cleanup results
    """ (duplicate-code)

syspilot/services/scheduling_service.py:1:0: R0801: Similar lines in 2 files
==syspilot.platforms.linux.cleanup_service:[29:51]
==syspilot.services.cleanup_service:[52:59]
self.stats = {
"files_cleaned": 0,
"directories_cleaned": 0,
"space_freed": 0,
"errors": [],
}

def full_cleanup(
    self,
    progress_callback: Optional[Callable[[int], None]] = None,
    status_callback: Optional[Callable[[str], None]] = None,
) -> Dict:
    """
    Perform full system cleanup

    Args:
        progress_callback: Progress update callback
        status_callback: Status update callback

    Returns:
        Dictionary with cleanup results
    """ (duplicate-code)

syspilot/services/scheduling_service.py:1:0: R0801: Similar lines in 2 files
==syspilot.platforms.linux.monitoring_service:[34:44]
==syspilot.services.monitoring_service:[31:41]
self.cpu_history = deque(maxlen=self.history_size)
self.memory_history = deque(maxlen=self.history_size)
self.disk_history = deque(maxlen=self.history_size)
self.network_history = deque(maxlen=self.history_size)

    # Network counters for rate calculation
    self.prev_network_io = None
    self.prev_network_time = None

    # Alert thresholds (duplicate-code)

syspilot/services/scheduling_service.py:1:0: R0801: Similar lines in 2 files
==syspilot.platforms.macos.cleanup_service:[12:31]
==syspilot.platforms.windows.cleanup_service:[12:31]
class CleanupService:
"""
Windows-specific cleanup service
TODO: Implement Windows temp files, cache, and registry cleanup
"""

def __init__(self, config=None):
    self.config = config
    self.logger = None

def clean_temp_files(self) -> Dict:
    """
    Clean Windows temporary files
    TODO: Implement Windows %TEMP%, %TMP%, and Windows Temp cleanup
    """
    # Placeholder implementation
    return {
        "files_cleaned": 0,
        "space_freed": "0 MB", (duplicate-code)

syspilot/services/scheduling_service.py:1:0: R0801: Similar lines in 2 files
==syspilot.platforms.macos.system_info_service:[76:83]
==syspilot.platforms.windows.system_info_service:[76:83]
}
except PermissionError:
continue
except:
pass

    return disks (duplicate-code)

syspilot/services/scheduling_service.py:1:0: R0801: Similar lines in 2 files
==syspilot.platforms.linux.cleanup_service:[337:350]
==syspilot.services.system_info:[405:410]
for unit in ["B", "KB", "MB", "GB", "TB"]:
if bytes_count < 1024.0:
return f"{bytes_count:.2f} {unit}"
bytes_count /= 1024.0
return f"{bytes_count:.2f} PB" (duplicate-code)
syspilot/services/scheduling_service.py:1:0: R0801: Similar lines in 2 files
==syspilot.core.cli:[411:416]
==syspilot.platforms.linux.system_info_service:[405:410]
for unit in ["B", "KB", "MB", "GB", "TB"]:
if bytes_count < 1024.0:
return f"{bytes_count:.2f} {unit}"
bytes_count /= 1024.0
return f"{bytes_count:.2f} PB" (duplicate-code)

Report

3260 statements analysed.

Statistics by type

+---------+-------+-----------+-----------+------------+---------+
|type |number |old number |difference |%documented |%badname |
+=========+=======+===========+===========+============+=========+
|module |31 |NC |NC |100.00 |0.00 |
+---------+-------+-----------+-----------+------------+---------+
|class |30 |NC |NC |100.00 |0.00 |
+---------+-------+-----------+-----------+------------+---------+
|method |0 |NC |NC |0 |0 |
+---------+-------+-----------+-----------+------------+---------+
|function |0 |NC |NC |0 |0 |
+---------+-------+-----------+-----------+------------+---------+

External dependencies

::

PyQt5 
  \-QtCore (syspilot.core.app,syspilot.widgets.charts)
  \-QtGui (syspilot.core.app,syspilot.widgets.charts)
  \-QtWidgets (syspilot.core.app,syspilot.widgets.charts)
matplotlib 
  \-backends 
  | \-backend_qt5agg (syspilot.widgets.charts)
  \-figure (syspilot.widgets.charts)
  \-patches (syspilot.widgets.charts)
  \-pyplot (syspilot.widgets.charts)
numpy (syspilot.widgets.charts)
psutil (syspilot.platforms.linux.monitoring_service,syspilot.platforms.macos.monitoring_service,syspilot.platforms.macos.system_info_service,syspilot.platforms.windows.monitoring_service,syspilot.platforms.windows.system_info_service,syspilot.services.monitoring_service)
schedule (syspilot.core.daemon,syspilot.services.scheduling_service)
syspilot 
  \-platforms (syspilot.core.app)
  | \-factory (syspilot.core.app)
  \-services 
  | \-autostart_service (syspilot.core.app)
  | \-cleanup_service (syspilot.core.cli,syspilot.core.daemon)
  | \-monitoring_service (syspilot.core.cli,syspilot.core.daemon)
  | \-scheduling_service (syspilot.core.app,syspilot.core.daemon)
  | \-system_info (syspilot.core.cli)
  \-utils 
  | \-config (syspilot.core.app,syspilot.core.cli,syspilot.core.daemon,syspilot.platforms.linux.cleanup_service,syspilot.platforms.linux.monitoring_service,syspilot.services.cleanup_service,syspilot.services.monitoring_service)
  | \-logger (syspilot.core.app,syspilot.core.cli,syspilot.core.daemon,syspilot.platforms.linux.cleanup_service,syspilot.platforms.linux.monitoring_service,syspilot.platforms.linux.system_info_service,syspilot.services.cleanup_service,syspilot.services.monitoring_service,syspilot.services.system_info)
  \-widgets 
    \-charts (syspilot.core.app)

6821 lines have been analyzed

Raw metrics

+----------+-------+------+---------+-----------+
|type |number |% |previous |difference |
+==========+=======+======+=========+===========+
|code |4009 |58.77 |NC |NC |
+----------+-------+------+---------+-----------+
|docstring |1372 |20.11 |NC |NC |
+----------+-------+------+---------+-----------+
|comment |347 |5.09 |NC |NC |
+----------+-------+------+---------+-----------+
|empty |1093 |16.02 |NC |NC |
+----------+-------+------+---------+-----------+

Duplication

+-------------------------+------+---------+-----------+
| |now |previous |difference |
+=========================+======+=========+===========+
|nb duplicated lines |0 |NC |NC |
+-------------------------+------+---------+-----------+
|percent duplicated lines |0.000 |NC |NC |
+-------------------------+------+---------+-----------+

Messages by category

+-----------+-------+---------+-----------+
|type |number |previous |difference |
+===========+=======+=========+===========+
|convention |0 |NC |NC |
+-----------+-------+---------+-----------+
|refactor |18 |NC |NC |
+-----------+-------+---------+-----------+
|warning |0 |NC |NC |
+-----------+-------+---------+-----------+
|error |0 |NC |NC |
+-----------+-------+---------+-----------+

% errors / warnings by module

+-------------------------------------+------+--------+---------+-----------+
|module |error |warning |refactor |convention |
+=====================================+======+========+=========+===========+
|syspilot.services.scheduling_service |0.00 |0.00 |100.00 |0.00 |
+-------------------------------------+------+--------+---------+-----------+

Messages

+---------------+------------+
|message id |occurrences |
+===============+============+
|duplicate-code |18 |
+---------------+------------+


Your code has been rated at 9.94/10

License Compliance

Documentation Reports

Documentation Coverage Report

Docstring Coverage

  • Total functions/classes: 327
  • Documented: 304
  • Coverage: 93.0%

README Quality

  • Lines: 159
  • Sections: 21
    [SUCCESS] README.md exists

Performance Reports

Memory Profile Report

Application Startup Memory Usage

Memory profile completed

Import Time Analysis

Job Status

  • Code Quality: success
  • Performance Analysis: success
  • Documentation Quality: success

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.

0 participants