Skip to content

Commit 3da34f3

Browse files
authored
add configure option (#98)
1 parent 3fec199 commit 3da34f3

File tree

7 files changed

+83
-55
lines changed

7 files changed

+83
-55
lines changed

CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
-
1616

1717
### Features
18+
- New option ``--configure`` or ``-c`` for configuring transformer parameters. It works the same way configuring through ``--transform`` works. The benefit of using ``--configure`` is that you can configure selected transformers and still run all transformers [#96](https://github.com/MarketSquare/robotframework-tidy/issues/96)
1819
- Transformers can now be disabled by default if you add ``ENABLED = False`` class attribute to your class. Those transformers will be only run when selected explictly with ``--transform`` option [#10](https://github.com/MarketSquare/robotframework-tidy/issues/10)
1920
- Support for ``pyproject.toml`` configuration files. Because of the required changes there are backward incompatible changes done to ``robotidy.toml`` syntax. See example from [README](https://github.com/MarketSquare/robotframework-tidy/blob/main/README.rst#configuration-file) [#66](https://github.com/MarketSquare/robotframework-tidy/issues/66)
2021
- ``--list-transformers`` output is now ordered. Also transformers themselves will always run in the same predefined order [#69](https://github.com/MarketSquare/robotframework-tidy/issues/69)

README.rst

Lines changed: 11 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,14 @@ You can run robotidy with selected transformers. Use ``--transform`` argument fo
4343

4444
robotidy --transform ReplaceRunKeywordIf src
4545

46-
Some transformers provide configurable parameters. You can modify them by adding `:` after transformer name::
46+
Some transformers provide configurable parameters. You can pass your own values using --config/-c TRANSFORMER_NAME:param=value syntax::
4747

48-
robotidy --transform DiscardEmptySections:allow_only_comments=True src
48+
robotidy --configure DiscardEmptySections:allow_only_comments=True src
49+
50+
It is also possible to supply parameters using ``--transform`` option. The main difference is that ``--transform`` works like
51+
include option in Robot Framework while ``--configure`` allows you to configure selected transformers and still run all of them::
52+
53+
robotidy --transform DiscardEmptySections:allow_only_comments=True src
4954

5055
It is possible to develop your own transformers. You can use module name (if it is installed in your env) or path to
5156
file with class::
@@ -54,44 +59,7 @@ file with class::
5459

5560
Command line options
5661
--------------------
57-
You can list available options by running ``robotidy --help``::
58-
59-
Usage: robotidy [OPTIONS] [PATH(S)]
60-
61-
Options:
62-
--transform TRANSFORMER_NAME Transform files from [PATH(S)] with given
63-
transformer
64-
65-
--overwrite / --no-overwrite Overwrite source files.
66-
--diff Output diff of each processed file.
67-
-s, --spacecount INTEGER The number of spaces between cells in the
68-
plain text format. Default is 4.
69-
70-
-l, --lineseparator [native|windows|unix]
71-
Line separator to use in outputs. The
72-
default is 'native'.
73-
native: use operating system's native line separators
74-
windows: use Windows line separators (CRLF)
75-
unix: use Unix line separators (LF)
76-
77-
-p, --usepipes Use pipe ('|') as a column separator in the
78-
plain text format.
79-
80-
-sl, --startline INTEGER Limit robotidy only to selected area. If
81-
--endline is not provided, format text only
82-
at --startline. Line numbers start from 1.
83-
84-
-el, --endline INTEGER Limit robotidy only to selected area. Line
85-
numbers start from 1.
86-
87-
-v, --verbose
88-
--config FILE Read configuration from FILE path.
89-
--list-transformers List available transformers and exit.
90-
--describe-transformer TRANSFORMER_NAME
91-
Show documentation for selected transformer.
92-
--version Show the version and exit.
93-
--help Show this message and exit.
94-
62+
You can list available options by running ``robotidy --help``
9563

9664
Configuration file
9765
-------------------
@@ -117,6 +85,9 @@ Example configuration file::
11785
"DiscardEmptySections:allow_only_comments=True",
11886
"ReplaceRunKeywordIf"
11987
]
88+
configure = [
89+
"DiscardEmptySections:allow_only_comments=False"
90+
]
12091

12192
.. Badges links
12293

robotidy/app.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import List, Tuple, Dict, Set
1+
from typing import List, Tuple, Dict, Set, Any
22
from difflib import unified_diff
33

44
import click
@@ -15,7 +15,8 @@
1515

1616
class Robotidy:
1717
def __init__(self,
18-
transformers: List[Tuple[str, Dict]],
18+
transformers: List[Tuple[str, List]],
19+
transformers_config: Dict[str, List],
1920
src: Set,
2021
overwrite: bool,
2122
show_diff: bool,
@@ -29,7 +30,7 @@ def __init__(self,
2930
self.check = check
3031
self.verbose = verbose
3132
self.formatting_config = formatting_config
32-
self.transformers = load_transformers(transformers)
33+
self.transformers = load_transformers(transformers, transformers_config)
3334

3435
def transform_files(self):
3536
changed_files = 0

robotidy/cli.py

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from pathlib import Path
1111
import click
1212
import toml
13+
from collections import defaultdict
1314

1415
from robotidy.version import __version__
1516
from robotidy.app import Robotidy
@@ -38,10 +39,10 @@
3839
$ robotidy dir_name
3940
4041
# List available transformers:
41-
$ robotidy --list-transformers
42+
$ robotidy --list
4243
4344
# Display transformer documentation
44-
$ robotidy --describe-transformer <TRANSFORMER_NAME>
45+
$ robotidy --desc <TRANSFORMER_NAME>
4546
4647
# Format `src.robot` file using `SplitTooLongLine` transformer only
4748
$ robotidy --transform SplitTooLongLine src.robot
@@ -80,6 +81,13 @@ def convert(self, value, param, ctx):
8081
return name, args
8182

8283

84+
def convert_configure(configure: List[Tuple[str, List]]) -> Dict[str, List]:
85+
config_map = defaultdict(list)
86+
for transformer, args in configure:
87+
config_map[transformer].extend(args)
88+
return config_map
89+
90+
8391
def find_project_root(srcs: Iterable[str]) -> Path:
8492
"""Return a directory containing .git, or robotidy.toml.
8593
That directory will be a common parent of all files and directories
@@ -205,6 +213,14 @@ def get_paths(src: Tuple[str, ...]):
205213
metavar='TRANSFORMER_NAME',
206214
help="Transform files from [PATH(S)] with given transformer"
207215
)
216+
@click.option(
217+
'--configure',
218+
'-c',
219+
type=TransformType(),
220+
multiple=True,
221+
metavar='TRANSFORMER_NAME:PARAM=VALUE',
222+
help='Configure transformers'
223+
)
208224
@click.argument(
209225
"src",
210226
nargs=-1,
@@ -310,7 +326,8 @@ def get_paths(src: Tuple[str, ...]):
310326
@click.pass_context
311327
def cli(
312328
ctx: click.Context,
313-
transform: List[Tuple[str, Dict]],
329+
transform: List[Tuple[str, List]],
330+
configure: List[Tuple[str, List]],
314331
src: Tuple[str, ...],
315332
overwrite: bool,
316333
diff: bool,
@@ -325,13 +342,13 @@ def cli(
325342
describe_transformer: Optional[str]
326343
):
327344
if list_transformers:
328-
transformers = load_transformers(None)
345+
transformers = load_transformers(None, {})
329346
click.echo('Run --desc <transformer_name> to get more details. Transformers:')
330347
for transformer in transformers:
331348
click.echo(transformer.__class__.__name__)
332349
ctx.exit(0)
333350
if describe_transformer is not None:
334-
transformers = load_transformers(None)
351+
transformers = load_transformers(None, {})
335352
transformer_by_names = {transformer.__class__.__name__: transformer for transformer in transformers}
336353
if describe_transformer in transformer_by_names:
337354
click.echo(f"Transformer {describe_transformer}:")
@@ -350,8 +367,10 @@ def cli(
350367
end_line=endline
351368
)
352369
sources = get_paths(src)
370+
configure_transform = convert_configure(configure)
353371
tidy = Robotidy(
354372
transformers=transform,
373+
transformers_config=configure_transform,
355374
src=sources,
356375
overwrite=overwrite,
357376
show_diff=diff,

robotidy/transformers/__init__.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
If you don't want to run your transformer by default and only when calling robotidy with --transform YourTransformer
99
then add ``ENABLED = False`` class attribute inside.
1010
"""
11+
from itertools import chain
1112
from robot.utils.importer import Importer
1213

1314

@@ -28,20 +29,29 @@
2829
]
2930

3031

31-
def load_transformers(allowed_transformers):
32+
def load_transformers(allowed_transformers, config):
3233
""" Dynamically load all classes from this file with attribute `name` defined in allowed_transformers """
3334
loaded_transformers = []
3435
if allowed_transformers:
35-
3636
for name, args in allowed_transformers:
37+
# if we are configure the same param from both --transform and --configure we need to overwrite it
38+
# it is done by converting to dict and back to list in format of key=value
39+
temp_args = {}
40+
for arg in chain(args, config.get(name, ())):
41+
param, value = arg.split('=', maxsplit=1)
42+
temp_args[param] = value
43+
args = [f'{key}={value}' for key, value in temp_args.items()]
3744
import_name = f'robotidy.transformers.{name}' if name in TRANSFORMERS else name
3845
loaded_transformers.append(Importer().import_class_or_module(
3946
import_name,
4047
instantiate_with_args=args
4148
))
4249
else:
4350
for name in TRANSFORMERS:
44-
imported_class = Importer().import_class_or_module(f'robotidy.transformers.{name}', instantiate_with_args=())
51+
imported_class = Importer().import_class_or_module(
52+
f'robotidy.transformers.{name}',
53+
instantiate_with_args=config.get(name, ())
54+
)
4555
if getattr(imported_class, 'ENABLED', True):
4656
loaded_transformers.append(imported_class)
4757
return loaded_transformers

tests/utest/test_cli.py

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,7 @@ def test_invalid_configurable_usage(self):
5252
assert expected_output in str(result.exception)
5353

5454
def test_too_many_arguments_for_transform(self):
55-
expected_output = "Importing 'robotidy.transformers.DiscardEmptySections' failed: " \
56-
"'DiscardEmptySections' expected 0 to 1 arguments, got 2."
55+
expected_output = "not enough values to unpack (expected 2, got 1)"
5756
args = '--transform DiscardEmptySections:allow_only_comments:False'.split()
5857
result = run_tidy(args, exit_code=1)
5958
assert expected_output == str(result.exception)
@@ -91,6 +90,9 @@ def test_read_pyproject_config(self):
9190
'transform': [
9291
'DiscardEmptySections:allow_only_comments=True',
9392
'SplitTooLongLine'
93+
],
94+
'configure': [
95+
'DiscardEmptySections:allow_only_comments=False'
9496
]
9597
}
9698
config_path = str(Path(Path(__file__).parent, 'testdata', 'only_pyproject', 'pyproject.toml'))
@@ -105,6 +107,9 @@ def test_read_pyproject_config_e2e(self):
105107
'transform': [
106108
'DiscardEmptySections:allow_only_comments=True',
107109
'SplitTooLongLine'
110+
],
111+
'configure': [
112+
'DiscardEmptySections:allow_only_comments=False'
108113
]
109114
}
110115
config_path = str(Path(Path(__file__).parent, 'testdata', 'only_pyproject'))
@@ -206,9 +211,27 @@ def test_diff(self):
206211
assert "*** Settings ***" in result.output
207212

208213
def test_disabled_transformer(self):
209-
transformers = load_transformers(None)
214+
transformers = load_transformers(None, {})
210215
assert all(transformer.__class__.__name__ != 'SmartSortKeywords' for transformer in transformers)
211216

212217
def test_enable_disable_transformer(self):
213-
transformers = load_transformers([('SmartSortKeywords', [])])
218+
transformers = load_transformers([('SmartSortKeywords', [])], {})
214219
assert transformers[0].__class__.__name__ == 'SmartSortKeywords'
220+
221+
def test_configure_transformer(self):
222+
transformers = load_transformers(
223+
None,
224+
{'AlignVariablesSection': ['up_to_column=4']}
225+
)
226+
transformers_not_configured = load_transformers(None, {})
227+
assert len(transformers) == len(transformers_not_configured)
228+
for transformer in transformers:
229+
if transformer.__class__.__name__ == 'AlignVariablesSection':
230+
assert transformer.up_to_column + 1 == 4
231+
232+
def test_configure_transformer_overwrite(self):
233+
transformers = load_transformers(
234+
[('AlignVariablesSection', ['up_to_column=3'])],
235+
{'AlignVariablesSection': ['up_to_column=4']}
236+
)
237+
assert transformers[0].up_to_column + 1 == 4

tests/utest/testdata/only_pyproject/pyproject.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,7 @@ startline = 10
55
transform = [
66
"DiscardEmptySections:allow_only_comments=True",
77
"SplitTooLongLine"
8+
]
9+
configure = [
10+
"DiscardEmptySections:allow_only_comments=False"
811
]

0 commit comments

Comments
 (0)