Refactor scanners, add typed models, improve paths, and setup testing…#3
Conversation
…/coverage framework Completed first phase of codebase modernization: - Refactored plugin scanning logic into separate AUScanner and VST3Scanner classes within a new 'scanners' module. - Introduced dataclasses for PluginInfo and PluginParameter for improved type safety and data consistency. - Updated plugin cache loading/saving to use these new models. - Enhanced cross-platform support for cache paths (added Linux XDG). - Modernized resource loading to use importlib.resources. - Added initial unit tests for the new scanner modules and CLI operations. - Integrated Codecov for test coverage reporting in CI. - Began setup for Sphinx documentation.
Reviewer's GuideThis PR refactors the core scanning workflow by extracting platform-specific logic into dedicated AUScanner and VST3Scanner classes, introduces typed dataclasses for plugin metadata with robust JSON serialization and reconstruction, enhances cross-platform cache path resolution and resource loading, modernizes the CLI with structured logging and Fire commands, and establishes a first suite of unit tests plus CI coverage reporting. Entity relationship diagram for plugin cache and ignores dataerDiagram
PLUGIN_CACHE {
string id PK
string name
string path
string filename
string plugin_type
string manufacturer
string name_in_file
}
PLUGIN_PARAMETER {
string name
string value
}
PLUGIN_CACHE ||--o{ PLUGIN_PARAMETER : has
IGNORES {
string plugin_key PK
}
IGNORES ||..|| PLUGIN_CACHE : excludes
Class diagram for new and refactored scanner and model classesclassDiagram
class PedalboardScanner {
- plugins_path: Path
- plugins: Dict~str, PluginInfo~
- ignores_path: Path
- ignores: Set~str~
- safe_save: bool
- au_scanner: Optional~AUScanner~
- vst3_scanner: VST3Scanner
+ __init__()
+ ensure_ignores()
+ save_plugins()
+ get_plugin_params()
+ scan_single_plugin_file()
+ scan_typed_plugins()
+ scan_aufx_plugins()
+ scan_vst3_plugins()
+ scan_all_plugins()
+ full_scan()
+ rescan()
+ update_scan()
+ get_json()
}
class AUScanner {
- ignores: Set~str~
+ __init__(ignores)
+ find_plugin_files(plugin_paths)
}
class VST3Scanner {
- ignores: Set~str~
+ __init__(ignores)
+ find_plugin_files(extra_folders, plugin_paths)
}
class PluginInfo {
+ id: str
+ name: str
+ path: str
+ filename: str
+ plugin_type: str
+ parameters: Dict~str, PluginParameter~
+ manufacturer: Optional~str~
+ name_in_file: Optional~str~
}
class PluginParameter {
+ name: str
+ value: float|bool|str
}
PedalboardScanner --> AUScanner : uses
PedalboardScanner --> VST3Scanner : uses
PedalboardScanner --> PluginInfo : manages
PluginInfo --> PluginParameter : has
Class diagram for CLI and core entry pointsclassDiagram
class PedalboardPluginary {
- plugins_path: Path
- plugins: Dict~str, Any~
+ __init__()
+ load_data()
+ list_plugins()
}
class __main__ {
+ scan_plugins_cli(extra_folders, verbose)
+ update_plugins_cli(extra_folders, verbose)
+ list_json_cli(verbose)
+ list_yaml_cli(verbose)
+ main_cli()
}
PedalboardPluginary <.. __main__ : used by
Class diagram for data and utility helpersclassDiagram
class data {
+ get_cache_path(cache_name)
+ load_json_file(file_path)
+ save_json_file(data, file_path)
+ load_ignores(ignores_path)
+ save_ignores(ignores, ignores_path)
+ copy_default_ignores(destination_path)
}
class utils {
+ ensure_folder(path)
+ from_pb_param(data)
}
data ..> utils : uses
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
PR Reviewer Guide 🔍Here are some key observations to aid the review process:
|
There was a problem hiding this comment.
Hey @twardoch - I've reviewed your changes - here's some feedback:
Blocking issues:
- Found 'importlib.resources', which is a module only available on Python 3.7+. This does not work in lower versions, and therefore is not backwards compatible. Use importlib_resources instead for older Python versions. (link)
General comments:
- The entry-point in pyproject.toml still points to the old
clifunction but you renamed it tomain_cli—update the script reference (and any imports) to match the new name so the installedpbpluginarycommand actually runs. - In
load_json_file,save_json_file, andcopy_default_ignoresyou use plainprintcalls for warnings—replace those withlogger.warningorlogger.errorso all runtime diagnostics are captured through the logging framework. - You load each plugin twice (once in
get_plugin_paramsand again inscan_single_plugin_filejust to fetch metadata); consider refactoringget_plugin_paramsto return both the parameter dict and the plugin instance so you can reuse it and avoid the extra load.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The entry-point in pyproject.toml still points to the old `cli` function but you renamed it to `main_cli`—update the script reference (and any imports) to match the new name so the installed `pbpluginary` command actually runs.
- In `load_json_file`, `save_json_file`, and `copy_default_ignores` you use plain `print` calls for warnings—replace those with `logger.warning` or `logger.error` so all runtime diagnostics are captured through the logging framework.
- You load each plugin twice (once in `get_plugin_params` and again in `scan_single_plugin_file` just to fetch metadata); consider refactoring `get_plugin_params` to return both the parameter dict and the plugin instance so you can reuse it and avoid the extra load.
## Individual Comments
### Comment 1
<location> `src/pedalboard_pluginary/scanner.py:327` </location>
<code_context>
+ # or after each file if safe_save. If scan_typed_plugins wasn't called (no new plugins),
+ # an explicit save here might be redundant but harmless if state hasn't changed.
+ # However, if safe_save is False, it's crucial here.
+ if not self.safe_save and (new_vst3_paths_to_scan or (platform.system() == "Darwin" and 'new_aufx_paths_to_scan' in locals() and new_aufx_paths_to_scan)):
+ self.save_plugins()
+ elif not new_vst3_paths_to_scan and not (platform.system() == "Darwin" and 'new_aufx_paths_to_scan' in locals() and new_aufx_paths_to_scan):
</code_context>
<issue_to_address>
Use of 'locals()' to check for variable existence is fragile.
Initialize 'new_aufx_paths_to_scan' to None at the start of the function for clearer and more reliable logic.
Suggested implementation:
```python
if new_aufx_paths_to_scan:
logger.info(f"Found {len(new_aufx_paths_to_scan)} new AUFX plugin files to scan.")
self.scan_aufx_plugins(plugin_paths=new_aufx_paths_to_scan) # Scan only these
else:
logger.info("No new AUFX plugin files found.")
# self.save_plugins() is called within scan_typed_plugins if not safe_save,
# or after each file if safe_save. If scan_typed_plugins wasn't called (no new plugins),
# an explicit save here might be redundant but harmless if state hasn't changed.
# However, if safe_save is False, it's crucial here.
if not self.safe_save and (new_vst3_paths_to_scan or (platform.system() == "Darwin" and new_aufx_paths_to_scan)):
self.save_plugins()
elif not new_vst3_paths_to_scan and not (platform.system() == "Darwin" and new_aufx_paths_to_scan):
logger.info("No new plugins found in update scan. Cache remains unchanged.")
```
At the start of the function (before any assignment or use of `new_aufx_paths_to_scan`), add:
```python
new_aufx_paths_to_scan = None
```
This ensures the variable always exists and the logic is reliable.
</issue_to_address>
### Comment 2
<location> `src/pedalboard_pluginary/data.py:46` </location>
<code_context>
+def load_json_file(file_path: Path) -> Dict[Any, Any]: # Or more specific if structure is known
+ """ Load JSON data from a file. """
+ if file_path.exists():
+ with open(file_path, 'r', encoding='utf-8') as file:
+ try:
+ return json.load(file)
</code_context>
<issue_to_address>
No error handling for file I/O errors.
Catch OSError or IOError when opening files to handle unreadable files or permission issues.
</issue_to_address>
<suggested_fix>
<<<<<<< SEARCH
with open(file_path, 'r', encoding='utf-8') as file:
try:
raw_data = json.load(file)
except json.JSONDecodeError:
return {} # Return empty dict if JSON is corrupted
=======
try:
with open(file_path, 'r', encoding='utf-8') as file:
try:
raw_data = json.load(file)
except json.JSONDecodeError:
return {} # Return empty dict if JSON is corrupted
except OSError:
return {} # Return empty dict if file can't be opened/read
>>>>>>> REPLACE
</suggested_fix>
### Comment 3
<location> `src/pedalboard_pluginary/data.py:64` </location>
<code_context>
-def save_json_file(data, file_path):
+ # Check if this is the plugins cache file by its name
+ if file_path.name == f"{PLUGINS_CACHE_FILENAME_BASE}.json":
+ reconstructed_plugins: Dict[str, PluginInfo] = {}
+ for plugin_id, plugin_data_dict in raw_data.items():
</code_context>
<issue_to_address>
PluginInfo and PluginParameter reconstruction assumes all required fields are present.
Consider adding a warning or error log when skipping malformed entries to avoid silent data loss.
</issue_to_address>
### Comment 4
<location> `src/pedalboard_pluginary/data.py:111` </location>
<code_context>
+
+def save_json_file(data: Dict[Any, Any], file_path: Path) -> None: # Or list/Any for data
+ """ Save JSON data to a file. """
+ ensure_folder(file_path) # Ensures parent directory exists
+ with open(file_path, 'w', encoding='utf-8') as file:
+ json.dump(data, file, indent=4)
</code_context>
<issue_to_address>
ensure_folder is called with a file path, not a directory.
Consider renaming ensure_folder to ensure_parent_folder or updating its docstring to clarify that it creates the parent directory when given a file path.
Suggested implementation:
```python
def save_json_file(data: Dict[Any, Any], file_path: Path) -> None: # Or list/Any for data
""" Save JSON data to a file. """
ensure_parent_folder(file_path) # Ensures parent directory exists
with open(file_path, 'w', encoding='utf-8') as file:
json.dump(data, file, indent=4)
```
section.
Here are the code changes:
<file_operations>
<file_operation operation="edit" file_path="src/pedalboard_pluginary/data.py">
<<<<<<< SEARCH
def save_json_file(data: Dict[Any, Any], file_path: Path) -> None: # Or list/Any for data
""" Save JSON data to a file. """
ensure_folder(file_path) # Ensures parent directory exists
with open(file_path, 'w', encoding='utf-8') as file:
json.dump(data, file, indent=4)
=======
def save_json_file(data: Dict[Any, Any], file_path: Path) -> None: # Or list/Any for data
""" Save JSON data to a file. """
ensure_parent_folder(file_path) # Ensures parent directory exists
with open(file_path, 'w', encoding='utf-8') as file:
json.dump(data, file, indent=4)
>>>>>>> REPLACE
</file_operation>
</file_operations>
<additional_changes>
- If `ensure_folder` is defined in this file, rename its definition to `ensure_parent_folder` and update its docstring to clarify that it creates the parent directory for a file path.
- If `ensure_folder` is imported from another module, update the import statement to import `ensure_parent_folder` instead.
- Update any other usages of `ensure_folder` in the codebase to use `ensure_parent_folder` for consistency.
</issue_to_address>
## Security Issues
### Issue 1
<location> `src/pedalboard_pluginary/data.py:135` </location>
<issue_to_address>
**security (opengrep-rules.python.lang.compatibility.python37-compatibility-importlib2):** Found 'importlib.resources', which is a module only available on Python 3.7+. This does not work in lower versions, and therefore is not backwards compatible. Use importlib_resources instead for older Python versions.
*Source: opengrep*
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| # or after each file if safe_save. If scan_typed_plugins wasn't called (no new plugins), | ||
| # an explicit save here might be redundant but harmless if state hasn't changed. | ||
| # However, if safe_save is False, it's crucial here. | ||
| if not self.safe_save and (new_vst3_paths_to_scan or (platform.system() == "Darwin" and 'new_aufx_paths_to_scan' in locals() and new_aufx_paths_to_scan)): |
There was a problem hiding this comment.
suggestion: Use of 'locals()' to check for variable existence is fragile.
Initialize 'new_aufx_paths_to_scan' to None at the start of the function for clearer and more reliable logic.
Suggested implementation:
if new_aufx_paths_to_scan:
logger.info(f"Found {len(new_aufx_paths_to_scan)} new AUFX plugin files to scan.")
self.scan_aufx_plugins(plugin_paths=new_aufx_paths_to_scan) # Scan only these
else:
logger.info("No new AUFX plugin files found.")
# self.save_plugins() is called within scan_typed_plugins if not safe_save,
# or after each file if safe_save. If scan_typed_plugins wasn't called (no new plugins),
# an explicit save here might be redundant but harmless if state hasn't changed.
# However, if safe_save is False, it's crucial here.
if not self.safe_save and (new_vst3_paths_to_scan or (platform.system() == "Darwin" and new_aufx_paths_to_scan)):
self.save_plugins()
elif not new_vst3_paths_to_scan and not (platform.system() == "Darwin" and new_aufx_paths_to_scan):
logger.info("No new plugins found in update scan. Cache remains unchanged.")At the start of the function (before any assignment or use of new_aufx_paths_to_scan), add:
new_aufx_paths_to_scan = NoneThis ensures the variable always exists and the logic is reliable.
| with open(file_path, 'r', encoding='utf-8') as file: | ||
| try: | ||
| raw_data = json.load(file) | ||
| except json.JSONDecodeError: | ||
| return {} # Return empty dict if JSON is corrupted |
There was a problem hiding this comment.
suggestion: No error handling for file I/O errors.
Catch OSError or IOError when opening files to handle unreadable files or permission issues.
| with open(file_path, 'r', encoding='utf-8') as file: | |
| try: | |
| raw_data = json.load(file) | |
| except json.JSONDecodeError: | |
| return {} # Return empty dict if JSON is corrupted | |
| try: | |
| with open(file_path, 'r', encoding='utf-8') as file: | |
| try: | |
| raw_data = json.load(file) | |
| except json.JSONDecodeError: | |
| return {} # Return empty dict if JSON is corrupted | |
| except OSError: | |
| return {} # Return empty dict if file can't be opened/read |
|
|
||
| def save_json_file(data, file_path): | ||
| # Check if this is the plugins cache file by its name | ||
| if file_path.name == f"{PLUGINS_CACHE_FILENAME_BASE}.json": |
There was a problem hiding this comment.
suggestion (bug_risk): PluginInfo and PluginParameter reconstruction assumes all required fields are present.
Consider adding a warning or error log when skipping malformed entries to avoid silent data loss.
| """ Save JSON data to a file. """ | ||
| ensure_folder(file_path) | ||
| with open(file_path, 'w') as file: | ||
| ensure_folder(file_path) # Ensures parent directory exists |
There was a problem hiding this comment.
suggestion: ensure_folder is called with a file path, not a directory.
Consider renaming ensure_folder to ensure_parent_folder or updating its docstring to clarify that it creates the parent directory when given a file path.
Suggested implementation:
def save_json_file(data: Dict[Any, Any], file_path: Path) -> None: # Or list/Any for data
""" Save JSON data to a file. """
ensure_parent_folder(file_path) # Ensures parent directory exists
with open(file_path, 'w', encoding='utf-8') as file:
json.dump(data, file, indent=4)section.
Here are the code changes:
<file_operations>
<file_operation operation="edit" file_path="src/pedalboard_pluginary/data.py">
<<<<<<< SEARCH
def save_json_file(data: Dict[Any, Any], file_path: Path) -> None: # Or list/Any for data
""" Save JSON data to a file. """
ensure_folder(file_path) # Ensures parent directory exists
with open(file_path, 'w', encoding='utf-8') as file:
json.dump(data, file, indent=4)
def save_json_file(data: Dict[Any, Any], file_path: Path) -> None: # Or list/Any for data
""" Save JSON data to a file. """
ensure_parent_folder(file_path) # Ensures parent directory exists
with open(file_path, 'w', encoding='utf-8') as file:
json.dump(data, file, indent=4)
REPLACE
</file_operation>
</file_operations>
<additional_changes>
- If
ensure_folderis defined in this file, rename its definition toensure_parent_folderand update its docstring to clarify that it creates the parent directory for a file path. - If
ensure_folderis imported from another module, update the import statement to importensure_parent_folderinstead. - Update any other usages of
ensure_folderin the codebase to useensure_parent_folderfor consistency.
| # 'pedalboard_pluginary.resources' should be where the resources package is. | ||
| # Or, if 'resources' is a sub-package of 'data's package: from . import resources | ||
| # Assuming 'pedalboard_pluginary' is the top-level package for resources. | ||
| import importlib.resources |
There was a problem hiding this comment.
security (opengrep-rules.python.lang.compatibility.python37-compatibility-importlib2): Found 'importlib.resources', which is a module only available on Python 3.7+. This does not work in lower versions, and therefore is not backwards compatible. Use importlib_resources instead for older Python versions.
Source: opengrep
| logger.error(f"Error running auval (is it installed and in PATH?): {e}") | ||
| return [] | ||
|
|
||
| def find_plugin_files(self, plugin_paths: Optional[List[Path]] = None) -> List[Path]: |
There was a problem hiding this comment.
issue (code-quality): We've found these issues:
- Use named expression to simplify assignment and conditional (
use-named-expression) - Use set when checking membership of a collection of literals (
collection-into-set) - Low code quality found in AUScanner.find_plugin_files - 24% (
low-code-quality)
Explanation
The quality score for this function is below the quality threshold of 25%.
This score is a combination of the method length, cognitive complexity and working memory.
How can you solve this?
It might be worth refactoring this function to make it shorter and more readable.
- Reduce the function length by extracting pieces of functionality out into
their own functions. This is the most important thing you can do - ideally a
function should be less than 10 lines. - Reduce nesting, perhaps by introducing guard clauses to return early.
- Ensure that variables are tightly scoped, so that code using related concepts
sits together within the function rather than being scattered.
| if drep.lower() == "false": | ||
| return False | ||
| return drep |
There was a problem hiding this comment.
suggestion (code-quality): We've found these issues:
- Lift code into else after jump in control flow (
reintroduce-else) - Replace if statement with if expression (
assign-if-exp)
| if drep.lower() == "false": | |
| return False | |
| return drep | |
| return False if drep.lower() == "false" else drep |
| if path_arg == cache_file: | ||
| # Return raw dict, PedalboardPluginary.load_data will handle reconstruction | ||
| return MOCK_PLUGIN_DATA | ||
| return {} # Default for other calls |
There was a problem hiding this comment.
suggestion (code-quality): We've found these issues:
- Lift code into else after jump in control flow (
reintroduce-else) - Replace if statement with if expression (
assign-if-exp)
| if path_arg == cache_file: | |
| # Return raw dict, PedalboardPluginary.load_data will handle reconstruction | |
| return MOCK_PLUGIN_DATA | |
| return {} # Default for other calls | |
| return MOCK_PLUGIN_DATA if path_arg == cache_file else {} |
| if path_arg == cache_file: | ||
| return MOCK_PLUGIN_DATA | ||
| return {} |
There was a problem hiding this comment.
suggestion (code-quality): We've found these issues:
- Lift code into else after jump in control flow (
reintroduce-else) - Replace if statement with if expression (
assign-if-exp)
| if path_arg == cache_file: | |
| return MOCK_PLUGIN_DATA | |
| return {} | |
| return MOCK_PLUGIN_DATA if path_arg == cache_file else {} |
| if path_arg == cache_file: | ||
| return MOCK_PLUGIN_DATA | ||
| return {} |
There was a problem hiding this comment.
suggestion (code-quality): We've found these issues:
- Lift code into else after jump in control flow (
reintroduce-else) - Replace if statement with if expression (
assign-if-exp)
| if path_arg == cache_file: | |
| return MOCK_PLUGIN_DATA | |
| return {} | |
| return MOCK_PLUGIN_DATA if path_arg == cache_file else {} |
PR Code Suggestions ✨No code suggestions found for the PR. |
User description
…/coverage framework
Completed first phase of codebase modernization:
PR Type
Enhancement, Tests, Documentation
Description
• Major architectural refactor: Split monolithic scanner into modular
AUScannerandVST3Scannerclasses with improved separation of concerns• Enhanced type safety: Introduced
PluginInfoandPluginParameterdataclasses with comprehensive type annotations throughout codebase• Cross-platform improvements: Added Linux XDG cache directory support and modernized resource loading with
importlib.resources• Comprehensive testing suite: Added unit tests for CLI commands, scanner modules, and cross-platform functionality with mocked data
• CI/CD enhancements: Integrated Codecov for test coverage reporting and added mypy pre-commit hooks for static type checking
• Project modernization: Migrated from
setup.pyto modernpyproject.tomlconfiguration with updated dependencies• Documentation improvements: Added coverage badge and comprehensive codebase representation for AI analysis
Changes walkthrough 📝
8 files
scanner.py
Major refactor of scanner with typed models and modular architecturesrc/pedalboard_pluginary/scanner.py
• Refactored plugin scanning logic into separate AUScanner and
VST3Scanner classes
• Added type annotations throughout the module and
improved error handling
• Introduced PluginInfo and PluginParameter
dataclasses for better type safety
• Enhanced plugin parameter
extraction with more robust metadata handling
data.py
Enhanced data handling with cross-platform support and modern resourceloadingsrc/pedalboard_pluginary/data.py
• Enhanced cross-platform cache path support with Linux XDG compliance
• Modernized resource loading to use
importlib.resourceswithpkg_resourcesfallback• Added PluginInfo reconstruction logic for
loading cached plugin data
• Improved error handling and type
annotations throughout
vst3_scanner.py
New modular VST3 scanner implementationsrc/pedalboard_pluginary/scanners/vst3_scanner.py
• Created new VST3Scanner class with platform-specific folder
detection
• Implemented plugin discovery logic with ignore list
support
• Added comprehensive type annotations and logging
au_scanner.py
New modular Audio Unit scanner for macOSsrc/pedalboard_pluginary/scanners/au_scanner.py
• Created new AUScanner class for macOS Audio Unit plugin discovery
•
Implemented auval output parsing with regex pattern matching
• Added
bundle path resolution logic for AU component files
__main__.py
Enhanced CLI with verbose logging and type safetysrc/pedalboard_pluginary/main.py
• Enhanced CLI with verbose logging options and better argument
handling
• Added type annotations and improved function naming for
clarity
• Implemented proper logging configuration based on verbosity
levels
models.py
New typed dataclasses for plugin informationsrc/pedalboard_pluginary/models.py
• Added PluginInfo and PluginParameter dataclasses for type-safe
plugin representation
• Defined ParameterValue type alias for plugin
parameter values
• Included optional fields for manufacturer and
file-specific plugin names
core.py
Core module type safety improvementssrc/pedalboard_pluginary/core.py
• Added type annotations and improved error handling
• Enhanced plugin
data loading with better type checking
• Fixed method call to use
updated scanner interface
utils.py
Utility functions type safety and boolean parsing improvementssrc/pedalboard_pluginary/utils.py
• Added comprehensive type annotations for utility functions
•
Enhanced
from_pb_paramfunction with better boolean parsing logic•
Improved parameter value conversion with explicit type handling
5 files
test_cli.py
Complete CLI testing suite with mocked plugin datatests/test_cli.py
• Added comprehensive unit tests for CLI commands (scan, update, list,
json, yaml)
• Implemented mock data and fixtures for testing plugin
cache operations
• Created helper functions for subprocess-based CLI
testing with proper mocking
test_au_scanner.py
Unit tests for Audio Unit scanner functionalitytests/scanners/test_au_scanner.py
• Added unit tests for AUScanner class covering auval output parsing
•
Implemented tests for plugin path resolution and bundle detection
logic
• Added platform-specific tests and error condition handling
test_vst3_scanner.py
Cross-platform VST3 scanner testing suitetests/scanners/test_vst3_scanner.py
• Added comprehensive tests for VST3Scanner across different platforms
• Implemented tests for default folder detection on Windows, macOS,
and Linux
• Added tests for plugin discovery with extra folders and
ignore functionality
test_data.py
Cross-platform cache path testingtests/test_data.py
• Added tests for cross-platform cache path generation
• Implemented
platform-specific tests for Windows, macOS, and Linux
• Added XDG
cache directory support testing for Linux
__init__.py
Test package initialization for scannerstests/scanners/init.py
• Added package initialization file for scanner tests
• Created empty
init file to establish test package structure
2 files
__init__.py
Simplified imports removing legacy Python compatibilitysrc/pedalboard_pluginary/init.py
• Removed Python 3.7 compatibility code for
importlib_metadata•
Simplified imports to use standard library
importlib.metadatadirectly__init__.py
Package initialization for scanners modulesrc/pedalboard_pluginary/scanners/init.py
• Added package initialization file for scanners module
• Created
empty init file to establish scanners as a Python package
3 files
pyproject.toml
Complete project configuration modernizationpyproject.toml
• Complete project configuration overhaul with modern Python packaging
• Added comprehensive dependencies, testing configuration, and mypy
setup
• Configured pytest with coverage reporting and tool-specific
settings
.pre-commit-config.yaml
Added mypy pre-commit hook for type checking.pre-commit-config.yaml
• Added mypy pre-commit hook for static type checking
• Configured
additional dependencies for mypy to work with project dependencies
•
Added mypy configuration pointing to pyproject.toml
ci.yml
CI enhancement with coverage reporting integration.github/workflows/ci.yml
• Integrated pytest-cov for test coverage reporting
• Added Codecov
upload action for coverage reporting
• Enhanced CI pipeline with
coverage tracking
2 files
README.md
Documentation update with coverage badgeREADME.md
• Added Codecov badge for test coverage visibility
• Enhanced
documentation with coverage reporting information
llms.txt
Add complete codebase representation for AI analysisllms.txt
• Added a comprehensive merged representation of the entire codebase
in a single file
• Contains repository structure, file contents, and
metadata for AI analysis
• Includes all source files, tests,
configuration files, and documentation
• Organized with file
summaries, directory structure, and complete file contents
2 files