]> git.madduck.net Git - etc/vim.git/blob - .vim/bundle/ale/ale_linters/python/pylama.vim

madduck's git repository

Every one of the projects in this repository is available at the canonical URL git://git.madduck.net/madduck/pub/<projectpath> — see each project's metadata for the exact URL.

All patches and comments are welcome. Please squash your changes to logical commits before using git-format-patch and git-send-email to patches@git.madduck.net. If you'd read over the Git project's submission guidelines and adhered to them, I'd be especially grateful.

SSH access, as well as push access can be individually arranged.

If you use my repositories frequently, consider adding the following snippet to ~/.gitconfig and using the third clone URL listed for each project:

[url "git://git.madduck.net/madduck/"]
  insteadOf = madduck:

Merge commit 'a39f715c13be3352193ffd9c5b7536b8786eff64' as '.vim/bundle/vim-lsp'
[etc/vim.git] / .vim / bundle / ale / ale_linters / python / pylama.vim
1 " Author: Kevin Locke <kevin@kevinlocke.name>
2 " Description: pylama for python files
3
4 call ale#Set('python_pylama_executable', 'pylama')
5 call ale#Set('python_pylama_options', '')
6 call ale#Set('python_pylama_use_global', get(g:, 'ale_use_global_executables', 0))
7 call ale#Set('python_pylama_auto_pipenv', 0)
8 call ale#Set('python_pylama_auto_poetry', 0)
9 call ale#Set('python_pylama_auto_uv', 0)
10 call ale#Set('python_pylama_change_directory', 1)
11
12 function! ale_linters#python#pylama#GetExecutable(buffer) abort
13     if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'python_pylama_auto_pipenv'))
14     \ && ale#python#PipenvPresent(a:buffer)
15         return 'pipenv'
16     endif
17
18     if (ale#Var(a:buffer, 'python_auto_poetry') || ale#Var(a:buffer, 'python_pylama_auto_poetry'))
19     \ && ale#python#PoetryPresent(a:buffer)
20         return 'poetry'
21     endif
22
23     if (ale#Var(a:buffer, 'python_auto_uv') || ale#Var(a:buffer, 'python_pylama_auto_uv'))
24     \ && ale#python#UvPresent(a:buffer)
25         return 'uv'
26     endif
27
28     return ale#python#FindExecutable(a:buffer, 'python_pylama', ['pylama'])
29 endfunction
30
31 function! ale_linters#python#pylama#RunWithVersionCheck(buffer) abort
32     let l:executable = ale_linters#python#pylama#GetExecutable(a:buffer)
33     let l:exec_args = l:executable =~? '\(pipenv\|poetry\|uv\)$'
34     \   ? ' run pylama'
35     \   : ''
36
37     let l:command = ale#Escape(l:executable) . l:exec_args . ' --version'
38
39     return ale#semver#RunWithVersionCheck(
40     \   a:buffer,
41     \   l:executable,
42     \   l:command,
43     \   function('ale_linters#python#pylama#GetCommand'),
44     \)
45 endfunction
46
47 function! ale_linters#python#pylama#GetCwd(buffer) abort
48     if ale#Var(a:buffer, 'python_pylama_change_directory')
49         " Pylama loads its configuration from the current directory only, and
50         " applies file masks using paths relative to the current directory.
51         " Run from project root, if found, otherwise buffer dir.
52         let l:project_root = ale#python#FindProjectRoot(a:buffer)
53
54         return !empty(l:project_root) ? l:project_root : '%s:h'
55     endif
56
57     return ''
58 endfunction
59
60 function! ale_linters#python#pylama#GetCommand(buffer, version) abort
61     let l:executable = ale_linters#python#pylama#GetExecutable(a:buffer)
62     let l:exec_args = l:executable =~? '\(pipenv\|poetry\|uv\)$'
63     \   ? ' run pylama'
64     \   : ''
65
66     " json format is added in version 8.1.4
67     " https://github.com/klen/pylama/blob/develop/Changelog
68     let l:format_json_args = ale#semver#GTE(a:version, [8, 1, 4])
69     \   ? ' --format json'
70     \   : ''
71
72     " Note: Using %t to lint changes would be preferable, but many pylama
73     " checks use surrounding paths (e.g. C0103 module name, E0402 relative
74     " import beyond top, etc.).  Neither is ideal.
75     return ale#Escape(l:executable) . l:exec_args
76     \   . ale#Pad(ale#Var(a:buffer, 'python_pylama_options'))
77     \   . l:format_json_args
78     \   . ' %s'
79 endfunction
80
81 function! ale_linters#python#pylama#Handle(buffer, version, lines) abort
82     if empty(a:lines)
83         return []
84     endif
85
86     let l:output = ale#python#HandleTraceback(a:lines, 1)
87
88     " First letter of error code is a pylint-compatible message type
89     " http://pylint.pycqa.org/en/latest/user_guide/output.html#source-code-analysis-section
90     " D is for Documentation (pydocstyle)
91     let l:pylint_type_to_ale_type = {
92     \   'I': 'I',
93     \   'R': 'W',
94     \   'C': 'W',
95     \   'W': 'W',
96     \   'E': 'E',
97     \   'F': 'E',
98     \   'D': 'W',
99     \}
100     let l:pylint_type_to_ale_sub_type = {
101     \   'R': 'style',
102     \   'C': 'style',
103     \   'D': 'style',
104     \}
105
106     if ale#semver#GTE(a:version, [8, 1, 4])
107         try
108             let l:errors = json_decode(join(a:lines, ''))
109         catch
110             return l:output
111         endtry
112
113         if empty(l:errors)
114             return l:output
115         endif
116
117         for l:error in l:errors
118             call add(l:output, {
119             \   'lnum': l:error['lnum'],
120             \   'col': l:error['col'],
121             \   'code': l:error['number'],
122             \   'type': get(l:pylint_type_to_ale_type, l:error['etype'], 'W'),
123             \   'sub_type': get(l:pylint_type_to_ale_sub_type, l:error['etype'], ''),
124             \   'text': printf('%s [%s]', l:error['message'], l:error['source']),
125             \})
126         endfor
127     else
128         let l:pattern = '\v^.{-}:([0-9]+):([0-9]+): +%(([A-Z][0-9]+):? +)?(.*)$'
129
130         for l:match in ale#util#GetMatches(a:lines, l:pattern)
131             call add(l:output, {
132             \   'lnum': str2nr(l:match[1]),
133             \   'col': str2nr(l:match[2]),
134             \   'code': l:match[3],
135             \   'type': get(l:pylint_type_to_ale_type, l:match[3][0], 'W'),
136             \   'sub_type': get(l:pylint_type_to_ale_sub_type, l:match[3][0], ''),
137             \   'text': l:match[4],
138             \})
139         endfor
140     endif
141
142     return l:output
143 endfunction
144
145 call ale#linter#Define('python', {
146 \   'name': 'pylama',
147 \   'executable': function('ale_linters#python#pylama#GetExecutable'),
148 \   'cwd': function('ale_linters#python#pylama#GetCwd'),
149 \   'command': function('ale_linters#python#pylama#RunWithVersionCheck'),
150 \   'callback': {buffer, lines -> ale#semver#RunWithVersionCheck(
151 \       buffer,
152 \       ale_linters#python#pylama#GetExecutable(buffer),
153 \       '%e --version',
154 \       {buffer, version -> ale_linters#python#pylama#Handle(
155 \           buffer,
156 \           l:version,
157 \           lines)},
158 \   )},
159 \   'lint_file': 1,
160 \})