Skip to content
This repository was archived by the owner on Apr 2, 2019. It is now read-only.

Commit 5f3a1c9

Browse files
committed
Include support for external Python interpreters
1 parent 4232381 commit 5f3a1c9

8 files changed

+115
-43
lines changed

README.md

+16
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,19 @@ Installation
1313
------------
1414

1515
Use [Package Control](https://sublime.wbond.net/).
16+
17+
Python version
18+
--------------
19+
20+
By default Python Checker will use the version of Python that came with Sublime Text 3. This currently means Python 3 and can result in problems like `undefined name 'unicode'` being reported. If you want to use a different version, set the `python_interpreter_path` option in your project settings:
21+
22+
```json
23+
# <project name>.sublime-project
24+
{
25+
"settings": {
26+
"python_interpreter_path": "/usr/bin/python"
27+
}
28+
}
29+
```
30+
31+
This is compatible with other plugins including [SublimeJEDI](https://github.com/srusskih/SublimeJEDI).

checker.py

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import ast
2+
from collections import namedtuple
3+
import sys
4+
import tempfile
5+
6+
try:
7+
# as plugin
8+
from .pep8 import pep8
9+
from .pyflakes import checker
10+
except (SystemError, ValueError):
11+
# external process
12+
from pep8 import pep8
13+
from pyflakes import checker
14+
15+
PEP8_IGNORED = {'E501', 'W191'}
16+
17+
Problem = namedtuple('Problem', 'level lineno offset message')
18+
19+
20+
class Pep8Report(pep8.BaseReport):
21+
22+
def __init__(self, *args, **kwargs):
23+
self.problems = []
24+
if sys.version_info[0] >= 3:
25+
super().__init__(*args, **kwargs)
26+
else:
27+
super(Pep8Report, self).__init__(*args, **kwargs)
28+
29+
def error(self, line_number, offset, text, check):
30+
level = 'error' if text.startswith('E') else 'warn'
31+
self.problems.append(Problem(level, line_number, offset, text))
32+
33+
34+
def get_problems(source, filename):
35+
flakes = get_flakes(source, filename)
36+
style_problems = get_style_problems(source, filename)
37+
return list(flakes) + list(style_problems)
38+
39+
40+
def get_flakes(source, filename):
41+
try:
42+
tree = ast.parse(source, filename, "exec")
43+
except SyntaxError:
44+
value = sys.exc_info()[1]
45+
msg = value.args[0]
46+
yield Problem('error', value.lineno, value.offset, msg)
47+
else:
48+
results = checker.Checker(tree, filename)
49+
for m in results.messages:
50+
yield Problem('warn', m.lineno, m.col,
51+
m.message % m.message_args)
52+
53+
54+
def get_style_problems(source, filename):
55+
guide = pep8.StyleGuide(reporter=Pep8Report, ignore=PEP8_IGNORED)
56+
lines = source.splitlines(True)
57+
checker = pep8.Checker(filename, lines, guide.options)
58+
checker.check_all()
59+
return checker.report.problems
60+
61+
62+
def get_external(source, filename, executable):
63+
import json
64+
import subprocess
65+
with tempfile.NamedTemporaryFile() as tf:
66+
tf.write(source.encode('utf-8'))
67+
output = subprocess.check_output([executable, __file__, tf.name])
68+
problems = json.loads(output.decode('utf-8'))
69+
problems = [Problem(*p) for p in problems]
70+
return problems
71+
72+
73+
def main(filename):
74+
import json
75+
with open(filename, 'rb') as f:
76+
source = f.read()
77+
if sys.version_info[0] >= 3:
78+
source = source.decode('utf-8')
79+
problems = get_problems(source, filename)
80+
json.dump(problems, sys.stdout)
81+
82+
83+
if __name__ == '__main__':
84+
if len(sys.argv) == 2:
85+
main(sys.argv[1])
86+
else:
87+
print('Usage: %s %s <filename>' % (sys.executable, sys.argv[0],))

plugin.py

+12-43
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,7 @@
1-
import ast
2-
from collections import namedtuple
3-
import sys
4-
51
import sublime
62
import sublime_plugin
73

8-
from .pep8 import pep8
9-
from .pyflakes import checker
10-
11-
Problem = namedtuple('Problem', 'level lineno offset message')
12-
13-
14-
class Pep8Report(pep8.BaseReport):
15-
16-
def __init__(self, *args, **kwargs):
17-
self.problems = []
18-
super().__init__(*args, **kwargs)
19-
20-
def error(self, line_number, offset, text, check):
21-
self.problems.append(Problem('warn', line_number, offset, text))
4+
from . import checker
225

236

247
class Validator(sublime_plugin.EventListener):
@@ -74,35 +57,21 @@ def get_selected_line(self, view):
7457
def revalidate(self, view):
7558
if view.settings().get("syntax") not in self.KNOWN_SYNTAXES:
7659
return
60+
problems = self.get_problems(view)
61+
self.highlight_problems(view, problems)
62+
self.update_statusbar(view, force=True)
63+
64+
def get_problems(self, view):
7765
filename = view.file_name()
7866
if not filename:
7967
filename = '<unsaved>'
8068
source = view.substr(sublime.Region(0, view.size()))
81-
flakes = self.get_flakes(source, filename)
82-
style_problems = self.get_style_problems(source, filename)
83-
problems = list(flakes) + list(style_problems)
84-
self.highlight_problems(view, problems)
85-
self.update_statusbar(view, force=True)
86-
87-
def get_flakes(self, source, filename):
88-
try:
89-
tree = ast.parse(source, filename, "exec")
90-
except SyntaxError:
91-
value = sys.exc_info()[1]
92-
msg = value.args[0]
93-
yield Problem('error', value.lineno, value.offset, msg)
94-
else:
95-
results = checker.Checker(tree, filename)
96-
for m in results.messages:
97-
yield Problem('warn', m.lineno, m.col,
98-
m.message % m.message_args)
99-
100-
def get_style_problems(self, source, filename):
101-
guide = pep8.StyleGuide(reporter=Pep8Report, ignore=self.PEP8_IGNORED)
102-
lines = source.splitlines(True)
103-
checker = pep8.Checker(filename, lines, guide.options)
104-
checker.check_all()
105-
return checker.report.problems
69+
settings = view.settings()
70+
python_executable = settings.get('python_interpreter_path', None)
71+
if python_executable:
72+
return checker.get_external(source, filename,
73+
executable=python_executable)
74+
return checker.get_problems(source, filename)
10675

10776
def highlight_problems(self, view, problems):
10877
view.erase_regions('python-checker-problem')
-149 Bytes
Binary file not shown.
-4.67 KB
Binary file not shown.
-36.6 KB
Binary file not shown.
-9.19 KB
Binary file not shown.
-3.41 KB
Binary file not shown.

0 commit comments

Comments
 (0)