-
Notifications
You must be signed in to change notification settings - Fork 22
Description
Prerequisites
- Are you running the latest version of this application?
- Have you checked the Frequently Asked Questions document?
- Have you simplified the bug report to the essential details?
- Do you have a distinct command line to report?
- Can you clearly state the configuration for this bug report?
- Do you have a minimal document that highlights this bug?
- Are any required files (configuration or Markdown document) attached to the issue?
- Did you perform a cursory search of other issues to look for related issues?
Bug Report
Please replace any of [these areas] in the paragraphs below with the requested information.
Bug Type
- Assertion Failure
- Documentation
- Scan/Rule not working as expected
- Fix/Rule not working as expected
- Other
[Other reason]
Description
PyMarkdown's --config flag fails to apply pyproject TOML configuration due to a key mapping mismatch in plugin configuration lookup, causing the tool to fall back to default values instead of using the specified configuration.
Specifics
- PyMarkdown version: 0.9.32
- Python version: 3.13
- application-properties: 0.9.0
Behavior
When using --config with TOML configuration files that use the pyproject.toml format (with [tool.pymarkdown] sections), pymarkdown ignores the specified configuration and uses default values instead. This occurs because pyproject.toml-style TOML configurations create keys with full dot-notation paths (tool.pymarkdown.plugins.md013.line_length), but the plugin lookup mechanism searches for shortened keys (plugins.md013.line_length), resulting in a key mismatch.
Note: TOML files using direct [plugins] sections work correctly - this bug only affects the pyproject.toml format with [tool.pymarkdown] sections.
Root Cause
The issue is in PluginManager.__find_configuration_for_plugin() method when processing pyproject.toml-format TOML files:
- Pyproject.toml-style TOML configs via --config: Create properties with full keys like
tool.pymarkdown.plugins.md013.line_length(note:md013.line_lengthis used as an example here, but this affects all plugin settings) - Plugin facade creation: Creates
ApplicationPropertiesFacadewith prefixplugins.md013. - Property lookup: Searches for
plugins.md013.line_length(prefix + property name) - Key mismatch: Cannot find
plugins.md013.line_lengthbecause onlytool.pymarkdown.plugins.md013.line_lengthexists - Fallback: Plugin uses hardcoded default values for all settings (e.g.,
line_length=80)
Comparison: TOML files with direct [plugins] sections create keys like plugins.md013.line_length which match the expected lookup pattern and work correctly.
Reproduction Steps
Step 1: Create pyproject.toml-style TOML configuration file
echo '[tool.pymarkdown]
plugins.md013.enabled = true
plugins.md013.line_length = 50' > pyproject.tomlStep 2: Create test markdown file (longer than 50 characters)
echo 'This line is definitely longer than 50 characters and should trigger MD013.' > test.mdStep 3: Run pymarkdown with pyproject.toml-style config
pymarkdown --config pyproject.toml scan test.mdExpected Result
test.md:1:1: MD013: Line length [Expected: 50, Actual: 78] (line-length)
Actual Result
test.md:1:1: MD013: Line length [Expected: 80, Actual: 78] (line-length)
Evidence: The violation shows Expected: 80 (default value) instead of Expected: 50 (configured value), proving the TOML configuration is ignored.
Technical Analysis
Configuration Loading Evidence
When debugging with ApplicationProperties, pyproject.toml-style TOML configs show:
Properties loaded: tool.pymarkdown.plugins.md013.line_length = 50
Plugin searches for: plugins.md013.line_length
Result: Not found → falls back to default (80)For comparison, direct [plugins] TOML configs work correctly:
Properties loaded: plugins.md013.line_length = 50
Plugin searches for: plugins.md013.line_length
Result: Found → uses configured value (50)Key Mapping Issue
The problem occurs in PluginManager.__find_configuration_for_plugin():
# Current code creates prefix: "plugins.md013."
plugin_section_title = (
f"{PluginManager.__plugin_prefix}{properties.separator}"
+ f"{next_key_name}{properties.separator}"
)
# Results in: "plugins.md013."
# But pyproject.toml-style TOML configs have keys like: "tool.pymarkdown.plugins.md013.line_length"
# So lookup for "plugins.md013.line_length" failsImpact
--configflag with pyproject.toml-style TOML files is completely non-functional- Users cannot use pyproject.toml format for pymarkdown configuration via
--config - Affects pyproject.toml-based configuration workflows (the standard for modern Python projects)
- No error message indicates the configuration is being ignored
- TOML files using direct
[plugins]sections continue to work correctly
Suggested Fix
Code Change Required
File: pymarkdown/plugin_manager/plugin_manager.py
Method: PluginManager.__find_configuration_for_plugin()
Location: Around line 918
@classmethod
def __find_configuration_for_plugin(
cls,
next_plugin: FoundPlugin,
properties: ApplicationProperties,
always_return_facade: bool = False,
) -> Optional[ApplicationPropertiesFacade]:
plugin_specific_facade, first_facade = None, None
for next_key_name in next_plugin.plugin_identifiers:
# Try standard plugin prefix (for JSON configs and auto-discovered TOML)
plugin_section_title = (
f"{PluginManager.__plugin_prefix}{properties.separator}"
+ f"{next_key_name}{properties.separator}"
)
section_facade_candidate = ApplicationPropertiesFacade(
properties, plugin_section_title
)
if not first_facade:
first_facade = section_facade_candidate
if section_facade_candidate.property_names:
plugin_specific_facade = section_facade_candidate
break
# Try pyproject.toml-style prefix (for --config pyproject.toml files)
toml_section_title = (
f"tool{properties.separator}pymarkdown{properties.separator}"
+ f"{PluginManager.__plugin_prefix}{properties.separator}"
+ f"{next_key_name}{properties.separator}"
)
toml_section_facade_candidate = ApplicationPropertiesFacade(
properties, toml_section_title
)
if toml_section_facade_candidate.property_names:
plugin_specific_facade = toml_section_facade_candidate
break
if always_return_facade and not plugin_specific_facade:
plugin_specific_facade = first_facade
return plugin_specific_facade(The code block at "Try pyproject.toml-style prefix" is the only new code.)
Fix Description
The fix adds a second lookup attempt with the pyproject.toml-style prefix (tool.pymarkdown.plugins.md013.) when the standard prefix fails. This maintains backward compatibility while enabling pyproject.toml configuration support via --config.
Workarounds
- Use JSON format for configuration (different code path, works correctly)
- Use auto-discovered TOML files (pyproject.toml in project root) instead of
--config - Use TOML files with direct
[plugins]sections instead of[tool.pymarkdown]sections - Use individual
--setflags instead of configuration files
Verification
Test Case for Fix Validation
After applying the fix, the same reproduction steps should show:
pymarkdown --config pyproject.toml scan test.mdExpected Result (after fix):
test.md:1:1: MD013: Line length [Expected: 50, Actual: 78] (line-length)
Backward Compatibility
The fix maintains full backward compatibility:
- JSON configurations continue to work unchanged
- Auto-discovered TOML configurations (pyproject.toml in project root) continue to work unchanged
- Direct
[plugins]TOML configurations continue to work unchanged - Only adds support for previously broken
--configpyproject.toml functionality
I'll create a PR based on the suggested fix later today.