Skip to content
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

Relax the yamllint rules on spaces inside braces for flow mappings #2077

Merged

Conversation

ziegenberg
Copy link
Contributor

@ziegenberg ziegenberg commented Apr 27, 2022

This allows zero or one space inside braces for flow mappings.

Fixes: #2076

@ziegenberg
Copy link
Contributor Author

I'd need a hint on where to put tests for testing this change. I see that test_formatted_yaml_loader_dumper tests for changes done by prettier vs ruamel.yaml. But after formatting, those changes are not fed into yamllint again.

@cognifloyd
Copy link
Member

Let's see.

This is where we add the extra space:

def write_indicator(
self,
indicator: str, # ruamel.yaml typehint is wrong. This is a string.
need_whitespace: bool,
whitespace: bool = False,
indention: bool = False, # (sic) ruamel.yaml has this typo in their API
) -> None:
"""Make sure that flow maps get whitespace by the curly braces."""
# If this is the end of the flow mapping that isn't on a new line:
if (
indicator == "}"
and (self.column or 0) > (self.indent or 0)
and not self._in_empty_flow_map
):
indicator = " }"
super().write_indicator(indicator, need_whitespace, whitespace, indention)
# if it is the start of a flow mapping, and it's not time
# to wrap the lines, insert a space.
if indicator == "{" and self.column < self.best_width:
if self.check_empty_mapping():
self._in_empty_flow_map = True
else:
self.column += 1
self.stream.write(" ")
self._in_empty_flow_map = False

We would need to add a case for braces here:

def _defaults_from_yamllint_config() -> Dict[str, Union[bool, int, str]]:
"""Extract FormattedYAML-relevant settings from yamllint config if possible."""
config = {
"explicit_start": True,
"explicit_end": False,
"width": 160,
"indent_sequences": True,
"preferred_quote": '"',
}
for rule, rule_config in load_yamllint_config().rules.items():
if not rule_config:
# rule disabled
continue
if rule == "document-start":
config["explicit_start"] = rule_config["present"]
elif rule == "document-end":
config["explicit_end"] = rule_config["present"]
elif rule == "line-length":
config["width"] = rule_config["max"]
elif rule == "indentation":
indent_sequences = rule_config["indent-sequences"]
# one of: bool, "whatever", "consistent"
# so, we use True for "whatever" and "consistent"
config["indent_sequences"] = bool(indent_sequences)
elif rule == "quoted-strings":
quote_type = rule_config["quote-type"]
# one of: single, double, any
if quote_type == "single":
config["preferred_quote"] = "'"
elif quote_type == "double":
config["preferred_quote"] = '"'
return cast(Dict[str, Union[bool, int, str]], config)

And then save the braces setting somewhere here:

config = self._defaults_from_yamllint_config()
# these settings are derived from yamllint config
self.explicit_start: bool = config["explicit_start"] # type: ignore[assignment]
self.explicit_end: bool = config["explicit_end"] # type: ignore[assignment]
self.width: int = config["width"] # type: ignore[assignment]
indent_sequences: bool = cast(bool, config["indent_sequences"])
preferred_quote: str = cast(str, config["preferred_quote"]) # either ' or "

And pass that setting into the FormattedEmitter here ish:

# ignore invalid preferred_quote setting
if preferred_quote in ['"', "'"]:
FormattedEmitter.preferred_quote = preferred_quote
# NB: default_style affects preferred_quote as well.
# self.default_style ∈ None (default), '', '"', "'", '|', '>'

So we can access it in FormattedEmitter.write_indicator (where we're adding the space) to determine whether or not to add the space.

Our default config needs to be compatible with prettier's default (add the space in flow-style maps), but I'm happy to respect the (potentially custom) yamllint config in more cases.

@cognifloyd
Copy link
Member

This is the test for the FormattedEmitter:

def test_custom_ruamel_yaml_emitter(

So we might need additional test cases or an additional test function here to make sure we're respecting the yamllint config.

@cognifloyd
Copy link
Member

This is the test that actually calls prettier to regenerate the fixtures:
https://github.com/ansible/ansible-lint/blob/main/test/fixtures/test_regenerate_formatting_fixtures.py

We might want to add a call in there to also run yamllint on the files and make sure our yamllint config is also compatible with prettier.

That might mean adding something to one or more of the test fixture files (or adding a new fixture file) that has flow maps with too many + too few spaces.

@cognifloyd
Copy link
Member

Thank you for working on this!

I've been a little swamped and unable to get back to finishing the --write stuff (jinja reformatting is my next on my plate #2066, and then I can finally add rule transforms to automatically address fixing some of the issues identified by our rules).

I will review whatever you do as quickly as I can however, because I hate holding up people's PRs.

@cognifloyd cognifloyd added the bug label Apr 27, 2022
@ziegenberg
Copy link
Contributor Author

That might mean adding something to one or more of the test fixture files (or adding a new fixture file) that has flow maps with too many + too few spaces.

There's already a case here for too few spaces and I will add one more with too many spaces.

inline-dictionary:
- {foo: bar} # should add some spacing between curly braces and content

@ziegenberg ziegenberg force-pushed the relax-yamllint-space-inside-rule branch from 5cca796 to 0530c90 Compare April 28, 2022 21:04
@ziegenberg
Copy link
Contributor Author

ziegenberg commented Apr 28, 2022

@cognifloyd I got a first version that basically works. Also the tests were extended to test with yamllint after ruaml.yaml did it's thing.

What is missing? Extending FormattedEmitter.write_indicatorto honor the new settings. I'll probably get that done tomorrow.

Do you see anything completely horrible for now?

If you remove the new settings around this lines, the extended test fails.
https://github.com/ansible/ansible-lint/blob/main/src/ansiblelint/yaml_utils.py#L61-64

@ssbarnea ssbarnea requested review from a team as code owners April 29, 2022 08:58
@ssbarnea ssbarnea changed the title relax the yamllint rules on spaces inside braces for flow mappings Relax the yamllint rules on spaces inside braces for flow mappings Apr 29, 2022
@ziegenberg ziegenberg force-pushed the relax-yamllint-space-inside-rule branch 2 times, most recently from 239f8ad to 82108aa Compare April 29, 2022 13:27
@ziegenberg
Copy link
Contributor Author

@cognifloyd I think, this is now ready for review.

@ziegenberg
Copy link
Contributor Author

I'm looking at the src/ansiblelint/yaml_utils.py:850:5: C901 'FormattedYAML._defaults_from_yamllint_config' is too complex (11) warning right now. I'll add a comment about rewriting this using match - case once py310 is mandatory. And silence the flake8 grumbling about complexity.

Fixes: ansible#2076

Signed-off-by: Daniel Ziegenberg <daniel@ziegenberg.at>
Signed-off-by: Daniel Ziegenberg <daniel@ziegenberg.at>
Signed-off-by: Daniel Ziegenberg <daniel@ziegenberg.at>
@ziegenberg ziegenberg force-pushed the relax-yamllint-space-inside-rule branch from 0437aae to ffaaa71 Compare April 29, 2022 16:14
@cognifloyd cognifloyd merged commit 752f838 into ansible:main May 2, 2022
@ziegenberg ziegenberg deleted the relax-yamllint-space-inside-rule branch May 2, 2022 22:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

Write mode introduces too many spaces inside braces
3 participants