A customizable linter: Flinter

(Sorry I already written this info in other posts)

We tried to make a customizable linter with Flinter, but we lack feedback. If some motivated guy want to try it out, the help (and critics) would be appreciated.

Note : To make this possible we extended Lizard to Fortran , so we have a new free Cyclomatic Complexity evaluation by func/subroutine for fortran too…


I just gave it a quick try. It deserves to be tested! The installation is so easy: $ pip install flinter

I guess I should customize the options because I don’t β€œagree” with all default formatting rules. But I have found some interesting things in the Fortran code I tested, for example:

| line_no | column | span |                                    line                                    |
|   211   |   73   |  1   |                 & "png"//c_null_char, c_null_ptr, c_null_ptr, c_null_ptr); |
|   348   |   59   |  1   |            box1 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 10_c_int);        |

Calling C GTK functions, it seems I sometimes put a ; at the end of line… :grin:

There are some false positives, especially when there is text in a string the regex get confused:

| line_no | column | span |                                       line                                       |
|   238   |   20   |  5   |                        & "In pause"//C_NEW_LINE//c_null_char, -1_c_int)          |
|   241   |   43   |  5   |                                              &"In pause..."//c_null_char)        |
|   251   |   38   |  5   |                             & "Not in pause"//C_NEW_LINE//c_null_char, -1_c_int) |

The flint tree is interesting. Is it possible to make the image bigger? (it’s rather small compared to current resolutions…) And the standard color scale is strange: OK, it follows the rainbow order, but green for high score would be more intuitive I think.

Thanks for that work, I will try to test it further.

Thanks a lot for the feedback

yeah, The string (and docstring) is somehow biasing the results. I hope we will find a clean solution soon.

Do tell me more about the rules you would prefer to see as a default (This probably the hardest part, finding a common linting standard…)

I agree the graphical output should be more customisable. We tried to follow Paul Tol rules to be colorblind friendly. The β€œIncandescent” scale might be a better fit.

We will keep you in touch.

1 Like

I think flinter would deserve its own thread in the Discourse, rather than discussing in β€œFortran goals for 2022”.

Concerning the default formatting rules, maybe a poll in the Discourse could help defining them.

Concerning colors, I am not familiar with colorblind friendly but β€œincandescent” scale could be more intuitive. For me, green means β€œeverything is OK”!

1 Like

3 posts were split to a new topic: (Intrinsic) equation parsing

I tested it for GitHub - tblite/tblite: Light-weight tight-binding framework and all its dependencies (150 KLOC). With fpm turns out to be quite easy by just using the dependencies subdir as starting point:

❯ git clone https://github.com/tblite/tblite
❯ cd tblite
❯ fpm update
❯ git clone . build/dependencies/tblite
❯ time flint score build/dependencies
Flinter global rating -->|3.90|<--  (150571 statements)
flint score build/dependencies  17.55s user 0.07s system 99% cpu 17.635 total

The tree view is really helpful for spotting files worth linting. The overall result looks quite well, since I’m not actually following the built-in style I’m loosing some score points there, especially for files with many comments, due to one-space-after-comment at the moment (!> Docstring style).

From the 8 projects only JSON Fortran is not really parsed correctly here due to cpp preprocessor usage.

I think I found a bug in the regex when it comes to select type statements, like in TOML Fortran at src/tomlf/type.f90:

❯ time flint struct build/dependencies/toml-f/src/tomlf/type.f90
β”œ type: file
β”œ path: build/dependencies/toml-f/src/tomlf/type.f90
β”œ size: 435
β”œ start_line: 0
β”œ end_line: 435
β”” tomlf_type
  β”œ type: module
  β”œ path: build/dependencies/toml-f/src/tomlf/type.f90/tomlf_type
  β”œ size: 406
  β”œ start_line: 29
  β”œ end_line: 435
  β”” add_table_to_table
    β”œ type: subroutine
    β”œ path: build/dependencies/toml-f/src/tomlf/type.f90/tomlf_type/add_table_to_table
    β”œ size: 361
    β”œ start_line: 74
    β”œ end_line: 435
    β”œ is
    β”‚ β”œ type: program
    β”‚ β”œ path: build/dependencies/toml-f/src/tomlf/type.f90/tomlf_type/add_table_to_table/is
    β”‚ β”œ size: 4
    β”‚ β”œ start_line: 108
    β”‚ β”” end_line: 112
    β”” add_table_to_table.add_array_to_table
      β”œ type: subroutine
      β”œ path: build/dependencies/toml-f/src/tomlf/type.f90/tomlf_type/add_table_to_table/add_table_to_table.add_array_to_table
      β”œ size: 311
      β”œ start_line: 124
      β”œ end_line: 435
      β”œ is
      β”‚ β”œ type: program
      β”‚ β”œ path: build/dependencies/toml-f/src/tomlf/type.f90/tomlf_type/add_table_to_table/add_table_to_table.add_array_to_table/is
      β”‚ β”œ size: 4
      β”‚ β”œ start_line: 158
      β”‚ β”” end_line: 162
      β”” add_table_to_table.add_array_to_table.add_keyval_to_table
        β”œ type: subroutine
        β”œ path: build/dependencies/toml-f/src/tomlf/type.f90/tomlf_type/add_table_to_table/add_table_to_table.add_array_to_table/add_table_to_table.add_array_to_table.add_keyval_to_table
        β”œ size: 261
        β”œ start_line: 174
        β”œ end_line: 435
        β”œ is
        β”‚ β”œ type: program
        β”‚ β”œ path: build/dependencies/toml-f/src/tomlf/type.f90/tomlf_type/add_table_to_table/add_table_to_table.add_array_to_table/add_table_to_table.add_array_to_table.add_keyval_to_table/is
        β”‚ β”œ size: 4
        β”‚ β”œ start_line: 208
        β”‚ β”” end_line: 212
        β”” add_table_to_table.add_array_to_table.add_keyval_to_table.add_table_to_array
          β”œ type: subroutine
          β”œ path: build/dependencies/toml-f/src/tomlf/type.f90/tomlf_type/add_table_to_table/add_table_to_table.add_array_to_table/add_table_to_table.add_array_to_table.add_keyval_to_table/add_table_to_table.add_array_to_table.add_keyval_to_table.add_table_to_array
          β”œ size: 211
          β”œ start_line: 224
          β”œ end_line: 435
          β”œ is
          β”‚ β”œ type: program
          β”‚ β”œ path: build/dependencies/toml-f/src/tomlf/type.f90/tomlf_type/add_table_to_table/add_table_to_table.add_array_to_table/add_table_to_table.add_array_to_table.add_keyval_to_table/add_table_to_table.add_array_to_table.add_keyval_to_table.add_table_to_array/is
          β”‚ β”œ size: 4
          β”‚ β”œ start_line: 254
          β”‚ β”” end_line: 258
          β”” add_table_to_table.add_array_to_table.add_keyval_to_table.add_table_to_array.add_array_to_array
            β”œ type: subroutine
            β”œ path: build/dependencies/toml-f/src/tomlf/type.f90/tomlf_type/add_table_to_table/add_table_to_table.add_array_to_table/add_table_to_table.add_array_to_table.add_keyval_to_table/add_table_to_table.add_array_to_table.add_keyval_to_table.add_table_to_array/add_table_to_table.add_array_to_table.add_keyval_to_table.add_table_to_array.add_array_to_array
            β”œ size: 165
            β”œ start_line: 270
            β”œ end_line: 435
            β”œ is
            β”‚ β”œ type: program
            β”‚ β”œ path: build/dependencies/toml-f/src/tomlf/type.f90/tomlf_type/add_table_to_table/add_table_to_table.add_array_to_table/add_table_to_table.add_array_to_table.add_keyval_to_table/add_table_to_table.add_array_to_table.add_keyval_to_table.add_table_to_array/add_table_to_table.add_array_to_table.add_keyval_to_table.add_table_to_array.add_array_to_array/is
            β”‚ β”œ size: 4
            β”‚ β”œ start_line: 301
            β”‚ β”” end_line: 305
            β”” add_table_to_table.add_array_to_table.add_keyval_to_table.add_table_to_array.add_array_to_array.add_keyval_to_array
              β”œ type: subroutine
              β”œ path: build/dependencies/toml-f/src/tomlf/type.f90/tomlf_type/add_table_to_table/add_table_to_table.add_array_to_table/add_table_to_table.add_array_to_table.add_keyval_to_table/add_table_to_table.add_array_to_table.add_keyval_to_table.add_table_to_array/add_table_to_table.add_array_to_table.add_keyval_to_table.add_table_to_array.add_array_to_array/add_table_to_table.add_array_to_table.add_keyval_to_table.add_table_to_array.add_array_to_array.add_keyval_to_array
              β”œ size: 118
              β”œ start_line: 317
              β”œ end_line: 435
              β”œ is
              β”‚ β”œ type: program
              β”‚ β”œ path: build/dependencies/toml-f/src/tomlf/type.f90/tomlf_type/add_table_to_table/add_table_to_table.add_array_to_table/add_table_to_table.add_array_to_table.add_keyval_to_table/add_table_to_table.add_array_to_table.add_keyval_to_table.add_table_to_array/add_table_to_table.add_array_to_table.add_keyval_to_table.add_table_to_array.add_array_to_array/add_table_to_table.add_array_to_table.add_keyval_to_table.add_table_to_array.add_array_to_array.add_keyval_to_array/is
              β”‚ β”œ size: 4
              β”‚ β”œ start_line: 347
              β”‚ β”” end_line: 351
              β”œ add_table_to_table.add_array_to_table.add_keyval_to_table.add_table_to_array.add_array_to_array.add_keyval_to_array.new_table_
              β”‚ β”œ type: subroutine
              β”‚ β”œ path: build/dependencies/toml-f/src/tomlf/type.f90/tomlf_type/add_table_to_table/add_table_to_table.add_array_to_table/add_table_to_table.add_array_to_table.add_keyval_to_table/add_table_to_table.add_array_to_table.add_keyval_to_table.add_table_to_array/add_table_to_table.add_array_to_table.add_keyval_to_table.add_table_to_array.add_array_to_array/add_table_to_table.add_array_to_table.add_keyval_to_table.add_table_to_array.add_array_to_array.add_keyval_to_array/add_table_to_table.add_array_to_table.add_keyval_to_table.add_table_to_array.add_array_to_array.add_keyval_to_array.new_table_
              β”‚ β”œ size: 8
              β”‚ β”œ start_line: 363
              β”‚ β”” end_line: 371
              β”œ add_table_to_table.add_array_to_table.add_keyval_to_table.add_table_to_array.add_array_to_array.add_keyval_to_array.new_array_
              β”‚ β”œ type: subroutine
              β”‚ β”œ path: build/dependencies/toml-f/src/tomlf/type.f90/tomlf_type/add_table_to_table/add_table_to_table.add_array_to_table/add_table_to_table.add_array_to_table.add_keyval_to_table/add_table_to_table.add_array_to_table.add_keyval_to_table.add_table_to_array/add_table_to_table.add_array_to_table.add_keyval_to_table.add_table_to_array.add_array_to_array/add_table_to_table.add_array_to_table.add_keyval_to_table.add_table_to_array.add_array_to_array.add_keyval_to_array/add_table_to_table.add_array_to_table.add_keyval_to_table.add_table_to_array.add_array_to_array.add_keyval_to_array.new_array_
              β”‚ β”œ size: 8
              β”‚ β”œ start_line: 378
              β”‚ β”” end_line: 386
              β”œ add_table_to_table.add_array_to_table.add_keyval_to_table.add_table_to_array.add_array_to_array.add_keyval_to_array.new_keyval_
              β”‚ β”œ type: subroutine
              β”‚ β”œ path: build/dependencies/toml-f/src/tomlf/type.f90/tomlf_type/add_table_to_table/add_table_to_table.add_array_to_table/add_table_to_table.add_array_to_table.add_keyval_to_table/add_table_to_table.add_array_to_table.add_keyval_to_table.add_table_to_array/add_table_to_table.add_array_to_table.add_keyval_to_table.add_table_to_array.add_array_to_array/add_table_to_table.add_array_to_table.add_keyval_to_table.add_table_to_array.add_array_to_array.add_keyval_to_array/add_table_to_table.add_array_to_table.add_keyval_to_table.add_table_to_array.add_array_to_array.add_keyval_to_array.new_keyval_
              β”‚ β”œ size: 8
              β”‚ β”œ start_line: 393
              β”‚ β”” end_line: 401
              β”” add_table_to_table.add_array_to_table.add_keyval_to_table.add_table_to_array.add_array_to_array.add_keyval_to_array.is_array_of_tables
                β”œ type: function
                β”œ path: build/dependencies/toml-f/src/tomlf/type.f90/tomlf_type/add_table_to_table/add_table_to_table.add_array_to_table/add_table_to_table.add_array_to_table.add_keyval_to_table/add_table_to_table.add_array_to_table.add_keyval_to_table.add_table_to_array/add_table_to_table.add_array_to_table.add_keyval_to_table.add_table_to_array.add_array_to_array/add_table_to_table.add_array_to_table.add_keyval_to_table.add_table_to_array.add_array_to_array.add_keyval_to_array/add_table_to_table.add_array_to_table.add_keyval_to_table.add_table_to_array.add_array_to_array.add_keyval_to_array.is_array_of_tables
                β”œ size: 29
                β”œ start_line: 405
                β”œ end_line: 434
                β”” is
                  β”œ type: program
                  β”œ path: build/dependencies/toml-f/src/tomlf/type.f90/tomlf_type/add_table_to_table/add_table_to_table.add_array_to_table/add_table_to_table.add_array_to_table.add_keyval_to_table/add_table_to_table.add_array_to_table.add_keyval_to_table.add_table_to_array/add_table_to_table.add_array_to_table.add_keyval_to_table.add_table_to_array.add_array_to_array/add_table_to_table.add_array_to_table.add_keyval_to_table.add_table_to_array.add_array_to_array.add_keyval_to_array/add_table_to_table.add_array_to_table.add_keyval_to_table.add_table_to_array.add_array_to_array.add_keyval_to_array.is_array_of_tables/is
                  β”œ size: 5
                  β”œ start_line: 423
                  β”” end_line: 428
flint struct build/dependencies/toml-f/src/tomlf/type.f90  0.24s user 0.02s system 98% cpu 0.271 total

Personally, I would deactivate that one because I generally put a space after ! when writing a sentence but not when using a comment as a delimiter like:

1 Like

Maybe the linter can be improved to expect a space after !, except if it is several * or -.

1 Like

Yes, we could for example expect a space if it begins with an alphanumeric character.

I think it’s important to define general rules that are accepted by a majority of people. If the user feels there are two many false positive warnings (from his point of view), he may finally not use flinter (the user may be too lazy to define its own rules).


I will have a play with it during the weekend and get back to you. From the looks of it there might be some potential collaboration with our VS Code Modern Fortran extension.

I would be keen on learning more about the underlying parser(s) that you are using, maybe we can start another thread about this.

@Dauptain Observation: Flinter/flint hosted on GitLab is not flint as hosted on GitHub; though, once installed, actually both launch by $ flint [parameters] easy to recall (analogue to e.g., pylint for Python).*

Question: Is there an intent to join the forces on what looks like a partially overlapping target of hint the user to the line better revised while the provision of the maps by flint(GitLab) obviously advance much further?

*) I’m aware setting an alias in .bashrc may remove the ambiguity between the two.

I agree, the homonym btw github and gitlab is a mistake from us. All apologies @marshallward :confounded:. Story is as usual, we started a project, got a minimal satisfied user base in the lab, then decided to put the stuff open source. We forgot the check on github. I will add disclaimers and redirection ASAP in the README.

When we will have some new manpower on this, I plan to divide instead 1) Try to contribute directly to Flint(Github) if we are up to the task 2) and specialize FLint>Gitlab into FlintMap, extending it with some visual greps, mapping of complexities, etc…

However, Manpower in France is scarce this year , the ETA of this division is expected for 2023.


The parser is an extension we added in Lizard, the fortran specific file is here.

No need to apologize, I’m glad to hear about this project. And I think we can all agree that PyPI could use better namespacing :sweat_smile:.

Although the internals are rather different, I think there are a lot of common goals here. Let’s stay in touch and see how things evolve once we both have the resources to come back to these respective projects.

1 Like

True, homonyms one may encounter in business (Merck/Germany vs. Merck & Co in the U.S.; though actually a split [fork] for political reasons), or in computation. Like OpenBabel for the transformation of chemical data which faced a similar situation when transitioning to Python 3:

# OB 2.x
import openbabel as ob
import pybel

# OB 3.0
from openbabel import openbabel as ob
from openbabel import pybel

with the remaining reminder of

Β« While more verbose, the new arrangement is in line with standard practice and helps avoid conflict with a different Python project, PyBEL. Β»

with pyBEL as in Biological Expression Language about handling biological networks e.g., in epigenetics (reference). Or of course the many Β«babelΒ» outside CTAN – including Babel of OpenBabel itself …

Or perhaps issue a note when attempting to deposit a new project in tune of Β«there already is a project of identical/similar enough name on PyPi and GitHub, GitLab, Gitea, BitBucket, … Β».

I am trying to use flint in my project. But I obtain a false result. Consider the following lines for example:

  subroutine activate
    call gtk_widget_show(window)
  end subroutine activate

There is no trailing spaces, but the subroutine is indented with two spaces. This is the result:

$ flint lint try.f90 -r my_flint_rules.yaml

| line_no | column | span | line |
|    3    |   0    |  2   |      |

Note that I have not modified the trailing-whitespaces rule. And the regex seems OK : ([ \t])+$. If I remove the two spaces at the beginning of the third line, no trailing spaces are found. :thinking:

This is weird, indeed
Could you tell me what is the flint version please?

Many thanks
(pip show flinter)

1 Like

I have just installed Flinter on another machine, and I have the same problem with my three lines example. You can copy/paste and try.

$ pip show flinter
Name: flinter
Version: 0.7.1
Summary: Flinter, a multi-language code linter.
Home-page: https://gitlab.com/cerfacs/flint
Author: CoopTeam-CERFACS
Author-email: coop@cerfacs.com
License: UNKNOWN
Location: /home/vmagnin/.local/lib/python3.10/site-packages
Requires: click, lizard, nobvisual, prettytable, pyyaml

With the default configuration file, I obtain:

$ flint lint try.f90

| line_no | column | span |               line               |
|    2    |   9    |  16  |     call gtk_widget_show(window) |

| line_no | column | span |               line               |
|    2    |   9    |  17  |     call gtk_widget_show(window) |

| line_no | column | span |               line               |
|    2    |   9    |  23  |     call gtk_widget_show(window) |

| line_no | column | span | line |
|    3    |   0    |  2   |      |

I have even verified that there is no trailing spaces or strange characters with an hexadecimal dump:

$ hexdump -C try.f90
00000000  20 20 73 75 62 72 6f 75  74 69 6e 65 20 61 63 74  |  subroutine act|
00000010  69 76 61 74 65 0a 20 20  20 20 63 61 6c 6c 20 67  |ivate.    call g|
00000020  74 6b 5f 77 69 64 67 65  74 5f 73 68 6f 77 28 77  |tk_widget_show(w|
00000030  69 6e 64 6f 77 29 0a 20  20 65 6e 64 20 73 75 62  |indow).  end sub|
00000040  72 6f 75 74 69 6e 65 20  61 63 74 69 76 61 74 65  |routine activate|
00000050  0a                                                |.|

We can see that each line is ended by an ASCII &h0a Line Feed, and there is no space &h20 before the Line Feeds.

In my programs, each time I have an end subroutine indented by spaces, Flinter is telling me there is trailing spaces. Strange. :face_with_raised_eyebrow:

Another false detection occurs with =>:

| line_no | column | span |                          line                         |
|    28   |   44   |  3   |   use, intrinsic :: iso_fortran_env, only: wp=>real64 |

It could be fixed by adding > at the end of the regex:

regexp: ([^\s=])(?<!kind|.len)=([^\s=>])

And we could add a regex for =>:

    message: Missing space around "=>"
    regexp: ([^\s=])=>([^\s=])
    replacement: \1 => \2