Skip to content
10 changes: 10 additions & 0 deletions src/mdformat/_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,16 @@ def make_arg_parser(
plugin.add_cli_argument_group(group)
for action in group._group_actions:
action.dest = f"plugin.{plugin_id}.{action.dest}"
if action.default not in {None, argparse.SUPPRESS}:
import warnings

plugin_file, plugin_line = get_source_file_and_line(plugin)
warnings.warn_explicit(
f"The `default` ({action.default}) for {action.option_strings} from the '{plugin_id}' plugin, will always override any value configured in TOML. The only supported CLI defaults are `None` or `argparse.SUPPRESS`. To resolve, consider refactoring to `.add_argument(..., default=None)` ", # noqa: E501
UserWarning,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's use DeprecationWarning to avoid the visibility issue mentioned here #507 (comment)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The risk with a deprecation warning is that developers may never see it because the test code needs to exercise run() or the plugin author needs to modify the warning level, which when tested with my prior release of mdformat-mkdocs wouldn't have been visible to me

I think a UserWarning might be appropriate because ultimately users will be the ones experiencing unexpected behavior. The impact should be small because only plugins that have migrated to the new groups and have arguments with defaults will need to make any changes. For examples mdformat-tables=1.0.0 won't error and I don't see other examples on GitHub: https://github.com/search?q=add_cli_argument_group+language%3APython+NOT+repo%3Ahukkin%2Fmdformat+NOT+repo%3Ajamesquilty%2Fmdformat+NOT+repo%3Aantazoey%2Fmdformat+NOT+repo%3Ajamesquilty%2Fmdformat-tables+NOT+repo%3Ahukkin%2Fmdformat-tables+NOT+repo%3AKyleKing%2Fmdformat&type=code&l=Python

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Besides potential unexpected behavior, the user is also the one experiencing the annoying warning message. But unlike the developer, the user cannot do anything about it. There can be plugins that decide not to read from the configuration file, and options where TOML configuration makes no sense. Mdformat would show a warning to users, though working exactly as intended.

If it's later decided that a hard error here is better, a DeprecationWarning is more accurate at signaling future removal.

So I'd say let's keep the DeprecationWarning. That, to my knowledge, is visible by default in pytest and unittest. I encourage plugin developers to test with mdformat._cli.run.

filename=plugin_file,
lineno=plugin_line,
)
return parser


Expand Down
29 changes: 29 additions & 0 deletions tests/test_plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,35 @@ def test_cli_options_group(monkeypatch, tmp_path):
)


def test_plugin_argument_warnings(monkeypatch, tmp_path):
"""Test for warnings of plugin arguments that conflict with TOML."""

class ExamplePluginWithStoreTrue:
@staticmethod
def update_mdit(mdit: MarkdownIt):
pass

@staticmethod
def add_cli_argument_group(group: argparse._ArgumentGroup) -> None:
group.add_argument("--store-true", action="store_true")
group.add_argument("--store-false", action="store_false")
group.add_argument("--store-zero", default=0)
group.add_argument("--store-const", action="store_const", const=True)

monkeypatch.setitem(PARSER_EXTENSIONS, "table", ExamplePluginWithStoreTrue)
file_path = tmp_path / "test_markdown.md"
file_path.touch()

with patch.object(MDRenderer, "render", return_value=""):
with pytest.warns(UserWarning) as warnings:
assert run([str(file_path)]) == 0

assert "--store-true" in str(warnings.pop().message)
assert "--store-false" in str(warnings.pop().message)
assert "--store-zero" in str(warnings.pop().message)
assert len(warnings) == 0


def test_cli_options_group__no_toml(monkeypatch, tmp_path):
"""Test add_cli_argument_group plugin API with configuration only from
CLI."""
Expand Down