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

DRAFT Ruff: create config file and run auto format & fixes #716

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 16 additions & 3 deletions .github/workflows/unit-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,29 @@ on:
branches: [ main ]

jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install ruff
- name: Ruff linter
run: ruff check --output-format=github .
- name: Ruff formatter
run: ruff format --check --diff .
test:
strategy:
fail-fast: false
matrix:
include:
- os: 'windows-latest'
python-version: '3.9'
rf-version: 'rf5'
- os: 'ubuntu-latest'
python-version: '3.8'
rf-version: 'rf4'
- os: 'ubuntu-latest'
python-version: '3.9'
Expand Down
14 changes: 5 additions & 9 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
repos:
- repo: https://github.com/pycqa/isort
rev: 5.11.5
hooks:
- id: isort
name: isort (python)

- repo: https://github.com/psf/black
rev: 22.3.0
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.6.9
hooks:
- id: black
#- id: ruff
- id: ruff-format
58 changes: 54 additions & 4 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,55 @@
[tool.black]
[tool.ruff]
line-length = 120
[tool.isort]
profile = "black"
line_length = 120
show-fixes = true
target-version = "py39" # TODO verify min Python version

lint.select = [
"ALL", # include all the rules, including new ones
]
exclude = [
"tests/utest/testdata/"
]
lint.ignore = [
#### modules
"ANN", # flake8-annotations
"COM", # flake8-commas
"C90", # mccabe complexity
"DJ", # django
"EXE", # flake8-executable
"PTH", # flake8-use-pathlib
"T10", # debugger
"TID", # flake8-tidy-imports
#### specific rules
"D100", # ignore missing docs
"D101",
"D102",
"D103",
"D104",
"D105",
"D106",
"D107",
"D200",
"D203", # blank line before class body
"D205",
"D212",
"D400",
"D401",
"D415",
"E402", # false positives for local imports
"E722", # bare except
"B904", # Raise from None
"EM101", # No string-literal exceptions !?
"EM102", # No Exceptions with f-strings
"PLR0913", # too many arguments to function call
"TRY003", # external messages in exceptions are too verbose
"TD002",
"TD003",
"FIX002", # too verbose descriptions of todos
"PLE1205", # too many arguments for logging
"T201", # print in code
]

[tool.ruff.format]
quote-style = "double"
skip-magic-trailing-comma = false
line-ending = "auto"
4 changes: 3 additions & 1 deletion robotidy/api.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""
Methods for transforming Robot Framework ast model programmatically.
"""

from __future__ import annotations

from pathlib import Path
Expand All @@ -9,7 +10,7 @@
from robotidy.config import MainConfig, RawConfig


def get_robotidy(src: str, output: str | None, ignore_git_dir: bool = False, **kwargs):

Check failure on line 13 in robotidy/api.py

View workflow job for this annotation

GitHub Actions / lint

Ruff (FBT001)

robotidy/api.py:13:48: FBT001 Boolean-typed positional argument in function definition

Check failure on line 13 in robotidy/api.py

View workflow job for this annotation

GitHub Actions / lint

Ruff (FBT002)

robotidy/api.py:13:48: FBT002 Boolean default positional argument in function definition
config = RawConfig(**kwargs)
config_file = files.find_source_config_file(Path(src), ignore_git_dir)
if config_file:
Expand Down Expand Up @@ -37,7 +38,8 @@
"""
robotidy_class = get_robotidy(root_dir, output, **kwargs)
disabler_finder = disablers.RegisterDisablers(
robotidy_class.config.formatting.start_line, robotidy_class.config.formatting.end_line
robotidy_class.config.formatting.start_line,
robotidy_class.config.formatting.end_line,
)
disabler_finder.visit(model)
if disabler_finder.is_disabled_in_file(disablers.ALL_TRANSFORMERS):
Expand Down
17 changes: 12 additions & 5 deletions robotidy/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from robot.errors import DataError

from robotidy import disablers
from robotidy.config import MainConfig

Check failure on line 14 in robotidy/app.py

View workflow job for this annotation

GitHub Actions / lint

Ruff (TCH001)

robotidy/app.py:14:29: TCH001 Move application import `robotidy.config.MainConfig` into a type-checking block
from robotidy.rich_console import console
from robotidy.utils import misc

Expand Down Expand Up @@ -44,7 +44,7 @@
stdin = True
if self.config.verbose:
click.echo("Loading file from stdin")
source = self.load_from_stdin()

Check failure on line 47 in robotidy/app.py

View workflow job for this annotation

GitHub Actions / lint

Ruff (PLW2901)

robotidy/app.py:47:21: PLW2901 `for` loop variable `source` overwritten by assignment target
elif self.config.verbose:
click.echo(f"Found {source} file")
model = self.get_model(source)
Expand All @@ -61,12 +61,15 @@
self.output_diff(model_path, old_model, new_model)
changed_files += 1
except DataError as err:
click.echo(f"Failed to decode {source} with an error: {err}\nSkipping file", err=True)
click.echo(
f"Failed to decode {source} with an error: {err}\nSkipping file",
err=True,
)
changed_files = previous_changed_files
skipped_files += 1
return self.formatting_result(all_files, changed_files, skipped_files, stdin)

def formatting_result(self, all_files: int, changed_files: int, skipped_files: int, stdin: bool):

Check failure on line 72 in robotidy/app.py

View workflow job for this annotation

GitHub Actions / lint

Ruff (FBT001)

robotidy/app.py:72:89: FBT001 Boolean-typed positional argument in function definition
"""
Print formatting summary and return status code.
"""
Expand All @@ -86,7 +89,7 @@
return 0
return 1

def log_formatted_source(self, source: str, stdin: bool):

Check failure on line 92 in robotidy/app.py

View workflow job for this annotation

GitHub Actions / lint

Ruff (FBT001)

robotidy/app.py:92:49: FBT001 Boolean-typed positional argument in function definition
if stdin:
return
if not self.config.overwrite:
Expand All @@ -109,7 +112,7 @@
def transform(self, model, disablers):
old_model = misc.StatementLinesCollector(model)
for transformer in self.config.transformers:
setattr(transformer, "disablers", disablers) # set dynamically to allow using external transformers
transformer.disablers = disablers # set dynamically to allow using external transformers
if disablers.is_disabled_in_file(transformer.__class__.__name__):
continue
transformer.visit(model)
Expand Down Expand Up @@ -137,11 +140,15 @@
return os.linesep
if isinstance(f.newlines, str):
return f.newlines
else:
return f.newlines[0]
return f.newlines[0]
return self.config.formatting.line_sep

def output_diff(self, path: str, old_model: misc.StatementLinesCollector, new_model: misc.StatementLinesCollector):
def output_diff(
self,
path: str,
old_model: misc.StatementLinesCollector,
new_model: misc.StatementLinesCollector,
):
if not self.config.show_diff:
return
old = [l + "\n" for l in old_model.text.splitlines()]
Expand Down
34 changes: 26 additions & 8 deletions robotidy/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import sys
from pathlib import Path
from typing import Pattern
from re import Pattern

try:
import rich_click as click
Expand All @@ -13,12 +13,15 @@

RICH_PRESENT = False

from robotidy import app
from robotidy import app, decorators, exceptions, files, skip, version
from robotidy import config as config_module
from robotidy import decorators, exceptions, files, skip, version
from robotidy.config import RawConfig, csv_list_type, validate_target_version
from robotidy.rich_console import console
from robotidy.transformers import TransformConfigMap, TransformConfigParameter, load_transformers
from robotidy.transformers import (
TransformConfigMap,
TransformConfigParameter,
load_transformers,
)
from robotidy.utils import misc

CLI_OPTIONS_LIST = [
Expand Down Expand Up @@ -55,7 +58,10 @@
"--endline",
],
},
{"name": "File exclusion", "options": ["--exclude", "--extend-exclude", "--skip-gitignore"]},
{
"name": "File exclusion",
"options": ["--exclude", "--extend-exclude", "--skip-gitignore"],
},
skip.option_group,
{
"name": "Other",
Expand Down Expand Up @@ -124,7 +130,11 @@ def print_transformer_docs(transformer):
@decorators.optional_rich
def print_description(name: str, target_version: int):
# TODO: --desc works only for default transformers, it should also print custom transformer desc
transformers = load_transformers(TransformConfigMap([], [], []), allow_disabled=True, target_version=target_version)
transformers = load_transformers(
TransformConfigMap([], [], []),
allow_disabled=True,
target_version=target_version,
)
transformer_by_names = {transformer.name: transformer for transformer in transformers}
if name == "all":
for transformer in transformers:
Expand Down Expand Up @@ -159,7 +169,11 @@ def print_transformers_list(global_config: config_module.MainConfig):
table = Table(title="Transformers", header_style="bold red")
table.add_column("Name", justify="left", no_wrap=True)
table.add_column("Enabled")
transformers = load_transformers(TransformConfigMap([], [], []), allow_disabled=True, target_version=target_version)
transformers = load_transformers(
TransformConfigMap([], [], []),
allow_disabled=True,
target_version=target_version,
)
transformers.extend(_load_external_transformers(transformers, config.transformers_config, target_version))

for transformer in transformers:
Expand Down Expand Up @@ -194,7 +208,11 @@ def generate_config(global_config: config_module.MainConfig):
raise exceptions.MissingOptionalTomliWDependencyError()
target_version = global_config.default.target_version
config = global_config.default_loaded
transformers = load_transformers(TransformConfigMap([], [], []), allow_disabled=True, target_version=target_version)
transformers = load_transformers(
TransformConfigMap([], [], []),
allow_disabled=True,
target_version=target_version,
)
transformers.extend(_load_external_transformers(transformers, config.transformers_config, target_version))

toml_config = {
Expand Down
59 changes: 40 additions & 19 deletions robotidy/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from collections import namedtuple
from dataclasses import dataclass, field
from pathlib import Path
from typing import Pattern
from re import Pattern

try:
from robot.api import Languages # RF 6.0
Expand All @@ -19,7 +19,12 @@
from click.core import ParameterSource

from robotidy import exceptions, files, skip
from robotidy.transformers import TransformConfig, TransformConfigMap, convert_transform_config, load_transformers
from robotidy.transformers import (
TransformConfig,
TransformConfigMap,
convert_transform_config,
load_transformers,
)
from robotidy.utils import misc


Expand Down Expand Up @@ -60,12 +65,11 @@ def __init__(
def get_line_sep(line_sep):
if line_sep == "windows":
return "\r\n"
elif line_sep == "unix":
if line_sep == "unix":
return "\n"
elif line_sep == "auto":
if line_sep == "auto":
return "auto"
else:
return os.linesep
return os.linesep


def validate_target_version(value: str | None) -> int | None:
Expand Down Expand Up @@ -98,7 +102,12 @@ def convert_transformers_config(
is_config: bool = False,
) -> list[TransformConfig]:
return [
TransformConfig(tr, force_include=force_included, custom_transformer=custom_transformer, is_config=is_config)
TransformConfig(
tr,
force_include=force_included,
custom_transformer=custom_transformer,
is_config=is_config,
)
for tr in config.get(param_name, ())
]

Expand Down Expand Up @@ -180,13 +189,17 @@ def from_cli(cls, ctx: click.Context, **kwargs):
defined_in_cli.add(option)
return cls(**kwargs, defined_in_cli=defined_in_cli)

def from_config_file(self, config: dict, config_path: Path) -> "RawConfig":
"""Creates new RawConfig instance from dictionary.
def from_config_file(self, config: dict, config_path: Path) -> RawConfig:
"""
Creates new RawConfig instance from dictionary.

Dictionary key:values needs to be normalized and parsed to correct types.
"""
options_map = map_class_fields_with_their_types(self)
parsed_config = {"defined_in_config": {"defined_in_config", "config_path"}, "config_path": config_path}
parsed_config = {
"defined_in_config": {"defined_in_config", "config_path"},
"config_path": config_path,
}
for key, value in config.items():
# workaround to be able to use two option names for same action - backward compatibility change
if key == "load_transformers":
Expand All @@ -206,16 +219,20 @@ def from_config_file(self, config: dict, config_path: Path) -> "RawConfig":
parsed_config[key] = [convert_transform_config(val, key) for val in value]
elif key == "src":
parsed_config[key] = tuple(value)
elif value_type in ("Pattern", Pattern): # future typing for 3.8 provides type as str
elif value_type in (
"Pattern",
Pattern,
): # future typing for 3.8 provides type as str
parsed_config[key] = misc.validate_regex(value)
else:
parsed_config[key] = value
parsed_config["defined_in_config"].add(key)
from_config = RawConfig(**parsed_config)
return self.merge_with_config_file(from_config)

def merge_with_config_file(self, config: "RawConfig") -> "RawConfig":
"""Merge cli config with the configuration file config.
def merge_with_config_file(self, config: RawConfig) -> RawConfig:
"""
Merge cli config with the configuration file config.

Use configuration file parameter value only if it was not defined in the cli already.
"""
Expand Down Expand Up @@ -253,7 +270,8 @@ def load_config_from_option(cli_config: RawConfig) -> RawConfig:
return cli_config

def get_sources(self, sources: tuple[str, ...]) -> tuple[str, ...] | None:
"""Get list of sources to be transformed by Robotidy.
"""
Get list of sources to be transformed by Robotidy.

If the sources tuple is empty, look for most common configuration file and load sources from there.
"""
Expand All @@ -273,7 +291,10 @@ def get_sources(self, sources: tuple[str, ...]) -> tuple[str, ...] | None:

def get_sources_with_configs(self):
sources = files.get_paths(
self.sources, self.default.exclude, self.default.extend_exclude, self.default.skip_gitignore
self.sources,
self.default.exclude,
self.default.extend_exclude,
self.default.skip_gitignore,
)
for source in sources:
if self.default.config:
Expand Down Expand Up @@ -350,7 +371,7 @@ def set_color_mode(color: bool) -> bool:
return "NO_COLOR" not in os.environ

@classmethod
def from_raw_config(cls, raw_config: "RawConfig"):
def from_raw_config(cls, raw_config: RawConfig):
skip_config = skip.SkipConfig(
documentation=raw_config.skip_documentation,
return_values=raw_config.skip_return_values,
Expand Down Expand Up @@ -416,8 +437,8 @@ def load_transformers(self, transformers_config: TransformConfigMap, force_order
)
for transformer in transformers:
# inject global settings TODO: handle it better
setattr(transformer.instance, "formatting_config", self.formatting)
setattr(transformer.instance, "transformers", self.transformers_lookup)
setattr(transformer.instance, "languages", self.language)
transformer.instance.formatting_config = self.formatting
transformer.instance.transformers = self.transformers_lookup
transformer.instance.languages = self.language
self.transformers.append(transformer.instance)
self.transformers_lookup[transformer.name] = transformer.instance
Loading
Loading