lintr icon indicating copy to clipboard operation
lintr copied to clipboard

Unhelpful Error Message for linting

Open franperic opened this issue 1 year ago • 5 comments

With the update to lintr 3.0.1 I receive the following error message:

Error in if (allow_cascading_assign) "" else "[text() = '<-']" : 
  argument is not interpretable as logical
In addition: Warning message:
In if (allow_cascading_assign) "" else "[text() = '<-']" :
  the condition has length > 1 and only the first element will be used

Unfortunately, the error message is not very helpful and I didn´t find any information online. Is this a problem with lintr 3.0.1 or is my .lintr file badly specified.

Here my .lintr file:

linters: linters_with_defaults(
  line_length_linter               = line_length_linter(100),
  T_and_F_symbol_linter            = lintr::T_and_F_symbol_linter,
  assignment_linter                = lintr::assignment_linter,
  closed_curly_linter              = lintr::brace_linter(allow_single_line = FALSE),
  commas_linter                    = lintr::commas_linter,
  commented_code_linter            = lintr::commented_code_linter,
  cyclocomp_linter                 = lintr::cyclocomp_linter(complexity_limit = 25),
  object_name_linter               = lintr::object_name_linter(styles = c("snake_case", "camelCase", "CamelCase", "SNAKE_CASE")),
  object_length_linter             = lintr::object_length_linter(length = 30L),
  equals_na_linter                 = lintr::equals_na_linter,
  function_left_parentheses_linter = lintr::function_left_parentheses_linter,
  infix_spaces_linter              = lintr::infix_spaces_linter,
  no_tab_linter                    = lintr::no_tab_linter,
  paren_brace_linter               = lintr::paren_brace_linter,
  absolute_path_linter             = lintr::absolute_path_linter(lax = TRUE),
  nonportable_path_linter          = lintr::nonportable_path_linter(lax = TRUE),
  pipe_continuation_linter         = lintr::pipe_continuation_linter,
  semicolon_terminator_linter      = lintr::semicolon_linter(allow_compound = FALSE, allow_trailing = FALSE),
  seq_linter                       = lintr::seq_linter,
  single_quotes_linter             = lintr::single_quotes_linter,
  spaces_inside_linter             = lintr::spaces_inside_linter,
  spaces_left_parentheses_linter   = lintr::spaces_left_parentheses_linter,
  undesirable_function_linter      = lintr::undesirable_function_linter(fun = lintr::default_undesirable_functions),
  undesirable_operator_linter      = lintr::undesirable_operator_linter(op = lintr::default_undesirable_operators),
  unneeded_concatenation_linter    = lintr::unneeded_concatenation_linter
  )
exclusions: list("file_to_exclude.R", "another_file_to_exclude.R")
exclude: "# Exclude Linting"
exclude_start: "# Begin Exclude Linting"
exclude_end: "# End Exclude Linting"

franperic avatar Oct 17 '22 15:10 franperic

that message is certainly no good :)

FWIW, all linters' are factories since 3.0.0 -- that means all your entries should be converted to function calls, e.g.

-assignment_linter                = lintr::assignment_linter
+assignment_linter                = lintr::assignment_linter()

see if that makes your error go away

MichaelChirico avatar Oct 17 '22 16:10 MichaelChirico

I reproduce the issue:

cd /tmp
echo "linters: linters_with_defaults(assignment_linter = lintr::assignment_linter)" > .lintr
echo "a = 1" > file.R
Rscript -e "lintr::lint_dir()"
# Error: Linter 'assignment_linter' failed in /tmp/file.R: argument is not interpretable as logical
# In addition: Warning message:
# In if (allow_cascading_assign) "" else "[text() = '<-']" :
#   the condition has length > 1 and only the first element will be used
# Execution halted

as well as confirming assignment_linter = lintr::assignment_linter() fixes the issue

MichaelChirico avatar Oct 17 '22 20:10 MichaelChirico

Somehow, the factory is not being evaluated, assignment_linter is being run on the expression, i.e., the error is essentially:

assignment_linter(get_source_expressions("file.R")$expressions[[1L]])
# Error in if (allow_cascading_assign) "" else "[text() = '<-']" : 
#   argument is not interpretable as logical
# In addition: Warning message:
# In if (allow_cascading_assign) "" else "[text() = '<-']" :
#   the condition has length > 1 and only the first element will be used

The correct code should instead be:

assignment_linter()(get_source_expressions("file.R")$expressions[[1L]])
# file.R:1:3: style: [NA] Use <-, not =, for assignment.
# a = 1
#   ^

MichaelChirico avatar Oct 17 '22 21:10 MichaelChirico

Great - that did the job! Thank you @MichaelChirico!

franperic avatar Oct 18 '22 06:10 franperic

Great! Glad to un-break you.

Leaving the issue open because it should fail in a much friendlier way for you to unstick yourself.

MichaelChirico avatar Oct 18 '22 06:10 MichaelChirico

Smaller reprex, showing that linters_with_defaults() is necessary to trigger the problem:

lintr::lint(text = "a = 1", linters = list(assignment_linter = lintr::assignment_linter))
#> Warning: Passing linters as variables was deprecated in lintr version 3.0.0. Use
#> a call to the linters (see ?linters) instead.
#> <text>:1:3: style: [assignment_linter] Use <-, not =, for assignment.
#> a = 1
#>   ^
lintr::lint(text = "a = 1", linters = lintr::linters_with_defaults(assignment_linter = lintr::assignment_linter))
#> Error: Linter 'assignment_linter' failed in /tmp/RtmpHSaTXh/filec155373c23d6: the condition has length > 1

Created on 2022-12-03 with reprex v2.0.2

waldo::compare(lintr::linters_with_defaults(assignment_linter = lintr::assignment_linter)["assignment_linter"], list(assignment_linter = lintr::assignment_linter))
#> `old$assignment_linter` is an S3 object of class <linter/function>, a function
#> `new$assignment_linter` is a function

Created on 2022-12-03 with reprex v2.0.2

AshesITR avatar Dec 03 '22 12:12 AshesITR