-
Notifications
You must be signed in to change notification settings - Fork 29
Sophisticated component / lib handling #161
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
@coderabbitai full review |
✅ Actions performedFull review triggered. |
|
Caution Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted. Error details |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (6)
builder/frameworks/component_manager.py (6)
329-329: Rename unused loop variableThe loop control variable
dirsis not used within the loop body.-for root, dirs, files in os.walk(src_dir): +for root, _, files in os.walk(src_dir):
407-428: Consider externalizing component detection patternsThe component detection patterns are hardcoded within the method, making them harder to maintain and extend. Consider moving these patterns to a configuration file or class constant for better maintainability.
Example refactor:
class ProjectAnalyzer: # Class constant for easier maintenance COMPONENT_PATTERNS = { 'bt': ['bluetooth', 'ble', 'nimble', 'bt_', 'esp_bt', 'esp_ble'], 'esp_wifi': ['wifi', 'esp_wifi', 'tcpip_adapter'], # ... rest of patterns } def _extract_components_from_file(self, file_path: str) -> Set[str]: components = set() try: with open(file_path, 'r', encoding='utf-8', errors='ignore') as f: content = f.read().lower() for component, patterns in self.COMPONENT_PATTERNS.items(): if any(pattern in content for pattern in patterns): components.add(component) except Exception: pass return components
679-757: Consider externalizing library mappingsThe extensive library mapping dictionary is hardcoded, making it difficult to update without modifying the source code. Consider moving this to an external JSON or YAML configuration file.
This would allow:
- Easier updates to mappings without code changes
- Version-specific mapping configurations
- User-customizable mappings
- Reduced code complexity
Example approach:
# Load from external file with open('library_mappings.json', 'r') as f: extended_mapping = json.load(f)
962-962: Remove unnecessary f-string prefixThe string doesn't contain any placeholders, so the f-string prefix is unnecessary.
-self.logger.log_change(f"Cleaned up CPPPATH entries for removed components") +self.logger.log_change("Cleaned up CPPPATH entries for removed components")
1059-1059: Fix or remove commented codeThe commented line has improper formatting. Either remove it or fix the formatting if it's needed for reference.
-#self.arduino_libs_mcu = join(self.platform.get_package_dir("framework-arduinoespressif32-libs"), self.mcu) +# self.arduino_libs_mcu = join(self.platform.get_package_dir("framework-arduinoespressif32-libs"), self.mcu)Or simply remove the line if it's no longer needed.
996-1071: Consider decomposing the ComponentManager classThe
ComponentManagerclass has 15 instance attributes, which exceeds the recommended limit of 7. This suggests the class has too many responsibilities and could benefit from further decomposition.Consider extracting some responsibilities into separate classes:
- Configuration management (env, platform, config, board, mcu)
- Path management (project_src_dir, arduino_framework_dir, arduino_libs_mcu)
- State tracking (removed_components, ignored_libs)
This would improve maintainability and testability while adhering to the Single Responsibility Principle.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
builder/frameworks/component_manager.py(6 hunks)
🧰 Additional context used
🪛 Ruff (0.11.9)
builder/frameworks/component_manager.py
329-329: Loop control variable dirs not used within loop body
Rename unused dirs to _dirs
(B007)
962-962: f-string without any placeholders
Remove extraneous f prefix
(F541)
🪛 Pylint (3.3.7)
builder/frameworks/component_manager.py
[refactor] 485-485: Too few public methods (1/2)
(R0903)
[refactor] 996-996: Too many instance attributes (15/7)
(R0902)
🪛 Flake8 (7.2.0)
builder/frameworks/component_manager.py
[error] 962-962: f-string is missing placeholders
(F541)
[error] 1059-1059: block comment should start with '# '
(E265)
⏰ Context from checks skipped due to timeout of 90000ms (20)
- GitHub Check: build (macos-15, examples/espidf-ulp-riscv)
- GitHub Check: build (windows-latest, examples/espidf-hello-world)
- GitHub Check: build (macos-15, examples/espidf-blink)
- GitHub Check: build (windows-latest, examples/espidf-ulp)
- GitHub Check: build (windows-latest, examples/espidf-peripherals-uart)
- GitHub Check: build (windows-latest, examples/arduino-rmt-blink)
- GitHub Check: build (windows-latest, examples/arduino-usb-keyboard)
- GitHub Check: build (windows-latest, examples/espidf-ulp-riscv)
- GitHub Check: build (windows-latest, examples/espidf-peripherals-usb)
- GitHub Check: build (ubuntu-latest, examples/espidf-ulp-riscv)
- GitHub Check: build (windows-latest, examples/espidf-coap-server)
- GitHub Check: build (windows-latest, examples/arduino-blink)
- GitHub Check: build (windows-latest, examples/espidf-arduino-blink)
- GitHub Check: build (ubuntu-latest, examples/tasmota)
- GitHub Check: build (ubuntu-latest, examples/espidf-ulp)
- GitHub Check: build (ubuntu-latest, examples/espidf-peripherals-uart)
- GitHub Check: build (ubuntu-latest, examples/espidf-hello-world)
- GitHub Check: build (ubuntu-latest, examples/espidf-blink)
- GitHub Check: build (ubuntu-latest, examples/espidf-arduino-blink)
- GitHub Check: build (ubuntu-latest, examples/arduino-blink)
🔇 Additional comments (3)
builder/frameworks/component_manager.py (3)
113-270: Well-structured YAML handler implementationThe
ComponentYamlHandlerclass is well-designed with clear separation of concerns, proper error handling, and comprehensive documentation. The backup functionality provides good safety measures.
1-1413: Excellent modular refactor of the component management systemThis is a well-executed refactor that transforms a monolithic design into a modular system with clear separation of concerns. The code is well-documented with comprehensive docstrings and examples. The addition of specialized classes for logging, YAML handling, project analysis, library mapping, and build file management significantly improves maintainability and testability.
Key strengths:
- Clear class responsibilities following SOLID principles
- Comprehensive error handling and logging
- Extensive documentation with examples
- Safety measures (backups, validation, critical component protection)
The minor issues identified can be easily addressed in a follow-up commit.
1323-1323: ```shell
#!/bin/bash
echo "Searching for Python version specifiers in common project config files..."Check setup.py / setup.cfg / pyproject.toml for python_requires
rg -n "python_requires" --glob="setup.py" --glob="setup.cfg" --glob="pyproject.toml" || echo "-- no python_requires found"
Check pyproject.toml for requires-python field
rg -n "requires-python" --glob="pyproject.toml" || echo "-- no requires-python found"
Check tox.ini for basepython setting
rg -n "basepython" --glob="tox.ini" || echo "-- no basepython in tox.ini"
Check for a runtime.txt (Heroku) specifying Python version
if [ -f runtime.txt ]; then
echo "-- runtime.txt found:"
sed -n '1,5p' runtime.txt
else
echo "-- no runtime.txt"
fiCheck classifiers in setup.cfg for supported Python versions
rg -n "Programming Language :: Python :: 3.[0-9]" --glob="setup.cfg" || echo "-- no Python classifiers found in setup.cfg"
</details> </blockquote></details> </details> <!-- This is an auto-generated comment by CodeRabbit for review status -->
| def get_changes(self) -> List[str]: | ||
| """ | ||
| Get a copy of all changes made during the session. | ||
| Get all logged changes. | ||
| Returns a defensive copy of the change log to prevent external | ||
| modification while allowing access to the complete change history. | ||
| Returns a copy of all change messages that have been logged during | ||
| the current session. | ||
| Returns: | ||
| List of change messages in chronological order | ||
| """ | ||
| return self.component_changes.copy() | ||
| List[str]: List of all logged change messages | ||
| Example: | ||
| >>> logger = ComponentLogger() | ||
| >>> logger.log_change("First change") | ||
| >>> logger.log_change("Second change") | ||
| >>> changes = logger.get_changes() | ||
| >>> len(changes) | ||
| 2 | ||
| """ | ||
| return self.component_changes |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Return a copy to protect internal state
The get_changes method returns the internal list directly, which allows external modification of the logger's state. This violates encapsulation principles.
Apply this diff to return a copy:
def get_changes(self) -> List[str]:
"""
Get all logged changes.
Returns a copy of all change messages that have been logged during
the current session.
Returns:
List[str]: List of all logged change messages
Example:
>>> logger = ComponentLogger()
>>> logger.log_change("First change")
>>> logger.log_change("Second change")
>>> changes = logger.get_changes()
>>> len(changes)
2
"""
- return self.component_changes
+ return self.component_changes.copy()📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| def get_changes(self) -> List[str]: | |
| """ | |
| Get a copy of all changes made during the session. | |
| Get all logged changes. | |
| Returns a defensive copy of the change log to prevent external | |
| modification while allowing access to the complete change history. | |
| Returns a copy of all change messages that have been logged during | |
| the current session. | |
| Returns: | |
| List of change messages in chronological order | |
| """ | |
| return self.component_changes.copy() | |
| List[str]: List of all logged change messages | |
| Example: | |
| >>> logger = ComponentLogger() | |
| >>> logger.log_change("First change") | |
| >>> logger.log_change("Second change") | |
| >>> changes = logger.get_changes() | |
| >>> len(changes) | |
| 2 | |
| """ | |
| return self.component_changes | |
| def get_changes(self) -> List[str]: | |
| """ | |
| Get all logged changes. | |
| Returns a copy of all change messages that have been logged during | |
| the current session. | |
| Returns: | |
| List[str]: List of all logged change messages | |
| Example: | |
| >>> logger = ComponentLogger() | |
| >>> logger.log_change("First change") | |
| >>> logger.log_change("Second change") | |
| >>> changes = logger.get_changes() | |
| >>> len(changes) | |
| 2 | |
| """ | |
| - return self.component_changes | |
| + return self.component_changes.copy() |
🤖 Prompt for AI Agents
In builder/frameworks/component_manager.py around lines 74 to 92, the
get_changes method returns the internal list self.component_changes directly,
which exposes the internal state to external modification. To fix this, modify
the method to return a shallow copy of the list by returning
self.component_changes.copy() instead of the list itself, ensuring encapsulation
and protecting the internal state.
Summary by CodeRabbit
Refactor
New Features