Skip to content

Commit b246418

Browse files
bhirszmnojek
andauthored
Add ReplaceEmptyValues transformer (#489)
* Add ReplaceEmptyValues transformer * Fix invalid name in the docs * Apply suggestions from code review Co-authored-by: Mateusz Nojek <matnojek@gmail.com>
1 parent 5934ca9 commit b246418

File tree

9 files changed

+212
-13
lines changed

9 files changed

+212
-13
lines changed

docs/releasenotes/4.0.0.rst

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,8 @@ list in the ``__init__.py``::
8484
"TransformerB"
8585
]
8686

87-
New skip option: --skip-sections #388 #475
88-
-------------------------------------------
87+
New skip option: --skip-sections (#388 #475)
88+
--------------------------------------------
8989

9090
It is now possible to skip formatting of whole sections with new ``--skip-sections`` option.
9191

@@ -97,6 +97,7 @@ Currently supported in::
9797
NormalizeNewLines
9898
NormalizeSectionHeaderName
9999
NormalizeSeparators
100+
ReplaceEmptyValues
100101
SplitTooLongLine
101102

102103
Support for other transformers can be added if needed.
@@ -117,9 +118,35 @@ Is now equivalent of::
117118

118119
> robotidy -c NormalizeSeparators:skip_sections=keywords
119120

121+
New transformer ReplaceEmptyValues (#474)
122+
------------------------------------------
120123

121-
Group comments with settings in OrderSettings #468
122-
---------------------------------------------------
124+
This new, enabled by default transformer replaces empty values with ``${EMPTY}`` variable.
125+
126+
Empty variables, lists or elements in the list can be defined in the following way::
127+
128+
*** Variables ***
129+
${EMPTY_VALUE}
130+
@{EMPTY_LIST}
131+
&{EMPTY_DICT}
132+
@{LIST_WITH_EMPTY}
133+
... value
134+
...
135+
... value3
136+
137+
To be more explicit, this transformer replace such values with ``${EMPTY}`` variables::
138+
139+
*** Variables ***
140+
${EMPTY_VALUE} ${EMPTY}
141+
@{EMPTY_LIST} @{EMPTY}
142+
&{EMPTY_DICT} &{EMPTY}
143+
@{LIST_WITH_EMPTY}
144+
... value
145+
... ${EMPTY}
146+
... value3
147+
148+
Group comments with settings in OrderSettings (#468)
149+
----------------------------------------------------
123150

124151
``OrderSettings`` transformer adjusts the order of the settings such as ``[Arguments]`` or ``[Teardown]`` inside test,
125152
task or keyword. Previously, it only ordered the settings and comments were not moved. Following code::
@@ -151,8 +178,8 @@ together with settings::
151178
# comment about step
152179
Step
153180

154-
SplitTooLongLine and splitting single values #436
155-
--------------------------------------------------
181+
SplitTooLongLine and splitting single values (#436)
182+
---------------------------------------------------
156183

157184
``SplitTooLongLine`` splits all too long values including single values (not lists)::
158185

docs/source/configuration/skip_formatting.rst

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,6 @@ Skip formatting
55
.. rubric:: Skip formatting
66

77
It is possible to skip formatting on code that matches given criteria.
8-
Following transformers provide support for skip option:
9-
10-
- :ref:`AlignKeywordsSection`
11-
- :ref:`AlignTestCasesSection`
12-
- :ref:`NormalizeSeparators`
13-
- :ref:`SplitTooLongLine`
148

159
To see what types are possible to skip, see ``Skip formatting`` sections in each transformer documentation.
1610

@@ -236,7 +230,7 @@ Both options are configurable using configuration file (:ref:`config-file`).
236230
Skip sections
237231
---------------
238232

239-
Option that disables formatting of the selected settings. Example usage::
233+
Option that disables formatting of the selected sections. Example usage::
240234

241235
robotidy -c NormalizeSeparators:skip_sections=variables src
242236

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
.. _ReplaceEmptyValues:
2+
3+
ReplaceEmptyValues
4+
===================
5+
6+
Replace empty values with ``${EMPTY}`` variable.
7+
8+
.. |TRANSFORMERNAME| replace:: ReplaceEmptyValues
9+
.. include:: enabled_hint.txt
10+
11+
12+
Empty variables, lists or elements in the list can be defined in a way that omits the value.
13+
To be more explicit, this transformer replace such values with ``${EMPTY}`` variables:
14+
15+
.. tab-set::
16+
17+
.. tab-item:: Before
18+
19+
.. code:: robotframework
20+
21+
*** Variables ***
22+
${EMPTY_VALUE}
23+
@{EMPTY_LIST}
24+
&{EMPTY_DICT}
25+
@{LIST_WITH_EMPTY}
26+
... value
27+
...
28+
... value3
29+
30+
.. tab-item:: After
31+
32+
.. code:: robotframework
33+
34+
*** Variables ***
35+
${EMPTY_VALUE} ${EMPTY}
36+
@{EMPTY_LIST} @{EMPTY}
37+
&{EMPTY_DICT} &{EMPTY}
38+
@{LIST_WITH_EMPTY}
39+
... value
40+
... ${EMPTY}
41+
... value3
42+
43+
Skip formatting
44+
----------------
45+
46+
It is possible to use the following arguments to skip formatting of the code:
47+
48+
- :ref:`skip sections`
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
from robot.api.parsing import Token
2+
3+
from robotidy.disablers import skip_if_disabled, skip_section_if_disabled
4+
from robotidy.skip import Skip
5+
from robotidy.transformers import Transformer
6+
7+
8+
class ReplaceEmptyValues(Transformer):
9+
"""
10+
Replace empty values with ``${EMPTY}`` variable.
11+
12+
Empty variables, lists or elements in the list can be defined in the following way:
13+
14+
```robotframework
15+
*** Variables ***
16+
${EMPTY_VALUE}
17+
@{EMPTY_LIST}
18+
&{EMPTY_DICT}
19+
@{LIST_WITH_EMPTY}
20+
... value
21+
...
22+
... value3
23+
```
24+
25+
To be more explicit, this transformer replace such values with ``${EMPTY}`` variables:
26+
27+
```robotframework
28+
*** Variables ***
29+
${EMPTY_VALUE} ${EMPTY}
30+
@{EMPTY_LIST} @{EMPTY}
31+
&{EMPTY_DICT} &{EMPTY}
32+
@{LIST_WITH_EMPTY}
33+
... value
34+
... ${EMPTY}
35+
... value3
36+
```
37+
"""
38+
HANDLES_SKIP = frozenset({"skip_sections"})
39+
40+
def __init__(self, skip: Skip = None):
41+
super().__init__(skip)
42+
43+
@skip_section_if_disabled
44+
def visit_VariableSection(self, node): # noqa
45+
return self.generic_visit(node)
46+
47+
@skip_if_disabled
48+
def visit_Variable(self, node): # noqa
49+
if node.errors or not node.name:
50+
return node
51+
args = node.get_tokens(Token.ARGUMENT)
52+
sep = Token(Token.SEPARATOR, self.formatting_config.separator)
53+
new_line_sep = Token(Token.SEPARATOR, self.formatting_config.continuation_indent)
54+
if args:
55+
tokens = []
56+
prev_token = None
57+
for token in node.tokens:
58+
if token.type == Token.ARGUMENT and not token.value:
59+
if not prev_token or prev_token.type != Token.SEPARATOR:
60+
tokens.append(new_line_sep)
61+
tokens.append(Token(Token.ARGUMENT, "${EMPTY}"))
62+
else:
63+
if token.type == Token.EOL:
64+
token.value = token.value.lstrip(" ")
65+
tokens.append(token)
66+
prev_token = token
67+
else:
68+
tokens = [node.tokens[0], sep, Token(Token.ARGUMENT, node.name[0] + "{EMPTY}"), *node.tokens[1:]]
69+
node.tokens = tokens
70+
return node

robotidy/transformers/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
"DiscardEmptySections",
3535
"MergeAndOrderSections",
3636
"RemoveEmptySettings",
37+
"ReplaceEmptyValues",
3738
"NormalizeAssignments",
3839
"OrderSettings",
3940
"OrderSettingsSection",

tests/atest/transformers/ReplaceEmptyValues/__init__.py

Whitespace-only changes.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
*** Variables ***
2+
${EMPTY_SCALAR} ${EMPTY}
3+
${MULTILINE_SCALAR}
4+
... ${EMPTY}
5+
... value2
6+
${EMPTY_SCALAR_WITH_COMMENT} ${EMPTY} # comment
7+
${SCALAR} value
8+
@{EMPTY_LIST} @{EMPTY}
9+
@{MULTILINE_LIST}
10+
... ${EMPTY}
11+
... ${EMPTY}
12+
... value2
13+
@{LIST_WITH_COMMENT} # comment
14+
... ${EMPTY} # comment
15+
... value # comment
16+
@{ONELINE_LIST} value1 value2
17+
&{EMPTY_DICT} &{EMPTY}
18+
&{MULTILINE_DICT}
19+
...
20+
... key=value
21+
&{DICT_WITH_COMMENT} &{EMPTY} # comment
22+
&{DICT}
23+
... key=value
24+
... key2=value
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
*** Variables ***
2+
${EMPTY_SCALAR}
3+
${MULTILINE_SCALAR}
4+
...
5+
... value2
6+
${EMPTY_SCALAR_WITH_COMMENT} # comment
7+
${SCALAR} value
8+
@{EMPTY_LIST}
9+
@{MULTILINE_LIST}
10+
...
11+
...
12+
... value2
13+
@{LIST_WITH_COMMENT} # comment
14+
... # comment
15+
... value # comment
16+
@{ONELINE_LIST} value1 value2
17+
&{EMPTY_DICT}
18+
&{MULTILINE_DICT}
19+
...
20+
... key=value
21+
&{DICT_WITH_COMMENT} # comment
22+
&{DICT}
23+
... key=value
24+
... key2=value
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from .. import TransformerAcceptanceTest
2+
3+
4+
class TestReplaceEmptyValues(TransformerAcceptanceTest):
5+
TRANSFORMER_NAME = "ReplaceEmptyValues"
6+
7+
def test_transformer(self):
8+
self.compare(source="test.robot", expected="test.robot")
9+
10+
def test_skip_section(self):
11+
self.compare(source="test.robot", config=" --skip-sections=variables", not_modified=True)

0 commit comments

Comments
 (0)