Skip to content

Commit d678350

Browse files
committed
Add linter to all source files
1 parent f6a1821 commit d678350

2 files changed

Lines changed: 66 additions & 63 deletions

File tree

manager/manager/lint/linter.py

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1+
import glob
12
import re
23
import os
34
import subprocess
4-
5+
import tempfile
56

67
class Lint:
78

@@ -103,3 +104,51 @@ def evaluate_code(
103104
return final_result.strip()
104105
except Exception as ex:
105106
print(ex)
107+
108+
def evaluate_source_code(self, files):
109+
all_files = []
110+
for f in files:
111+
glob_files = glob.glob(os.path.join("/workspace/code", f))
112+
for g in glob_files:
113+
all_files.append(g)
114+
115+
output = []
116+
117+
linter_env = os.environ.copy()
118+
linter_env["PYTHONPATH"] = f"{linter_env['PYTHONPATH']}:/workspace/code"
119+
120+
try:
121+
122+
for file in all_files:
123+
if file.endswith(".py"):
124+
with open(file) as f:
125+
python_code = f.read()
126+
127+
# Create temp file
128+
code_file = tempfile.NamedTemporaryFile(delete=False)
129+
code_file.write(python_code.encode())
130+
code_file.seek(0)
131+
code_file.close()
132+
133+
options = f"{code_file.name} --enable=similarities --disable=C0114,C0116"
134+
135+
# Run pylint using subprocess
136+
result = subprocess.run(
137+
["pylint"] + options.split(), capture_output=True, text=True, env=linter_env
138+
)
139+
140+
# Process pylint exit
141+
stdout = result.stdout
142+
143+
# Clean temp files
144+
if os.path.exists(code_file.name):
145+
os.remove(code_file.name)
146+
147+
raw_output = stdout + "\n"
148+
cleaned_result = self.clean_pylint_output(raw_output)
149+
final_result = self.append_rating_if_missing(cleaned_result)
150+
output.append(final_result.strip())
151+
152+
return output
153+
except Exception as ex:
154+
return ex

manager/manager/manager.py

Lines changed: 16 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -354,36 +354,6 @@ def on_prepare_tools(self, event):
354354
self.tools_launcher.run(self.consumer)
355355
LogManager.logger.info("Tools transition finished")
356356

357-
def add_frequency_control(self, code):
358-
frequency_control_code_imports = """
359-
import time
360-
from datetime import datetime
361-
ideal_cycle = 20
362-
"""
363-
code = frequency_control_code_imports + code
364-
infinite_loop = re.search(
365-
r"[^ ]while\s*\(\s*True\s*\)\s*:|[^ ]while\s*True\s*:|[^ ]while\s*1\s*:|[^ ]while\s*\(\s*1\s*\)\s*:",
366-
code,
367-
)
368-
frequency_control_code_pre = """
369-
start_time_internal_freq_control = datetime.now()
370-
"""
371-
code = (
372-
code[: infinite_loop.end()]
373-
+ frequency_control_code_pre
374-
+ code[infinite_loop.end() :]
375-
)
376-
frequency_control_code_post = """
377-
finish_time_internal_freq_control = datetime.now()
378-
dt = finish_time_internal_freq_control - start_time_internal_freq_control
379-
ms = (dt.days * 24 * 60 * 60 + dt.seconds) * 1000 + dt.microseconds / 1000.0
380-
381-
if (ms < ideal_cycle):
382-
time.sleep((ideal_cycle - ms) / 1000.0)
383-
"""
384-
code = code + frequency_control_code_post
385-
return code
386-
387357
def on_style_check_application(self, event):
388358
"""
389359
Handles the 'style_check' event, does not change the state and returns the current state.
@@ -616,33 +586,6 @@ def find_docker_console():
616586
# raise Exception("No active console other than /dev/pts/0")
617587
return consoles
618588

619-
def prepare_RA_code(code_path):
620-
f = open(code_path, "r")
621-
code = f.read()
622-
f.close()
623-
624-
# Make code backwards compatible
625-
code = code.replace("from GUI import GUI", "import GUI")
626-
code = code.replace("from HAL import HAL", "import HAL")
627-
628-
# Create executable app
629-
errors = self.linter.evaluate_code(code, self.ros_version)
630-
if errors == "":
631-
632-
# code = self.add_frequency_control(code)
633-
# f = open(code_path, "w")
634-
# f.write(code)
635-
# f.close()
636-
pass
637-
638-
else:
639-
console_path = find_docker_console()
640-
for i in console_path:
641-
with open(i, "w") as console:
642-
console.write(errors + "\n\n")
643-
644-
raise Exception(errors)
645-
646589
# Kill already running code
647590
try:
648591
proc = psutil.Process(self.application_process.pid)
@@ -659,6 +602,7 @@ def prepare_RA_code(code_path):
659602
# Extract app config
660603
app_cfg = event.kwargs.get("data", {})
661604
entrypoint = app_cfg["entrypoint"]
605+
to_lint = app_cfg["linter"]
662606

663607
# Unzip the app
664608
if app_cfg["code"].startswith("data:"):
@@ -668,17 +612,27 @@ def prepare_RA_code(code_path):
668612
zip_ref = zipfile.ZipFile("/workspace/code/app.zip", "r")
669613
zip_ref.extractall("/workspace/code")
670614
zip_ref.close()
671-
print("Here")
672615

673616
if not os.path.isfile(entrypoint):
674617
LogManager.logger.info("User code not found")
675618
raise Exception("User code not found")
676619

677-
try:
678-
# if entrypoint == "/workspace/code/academy.py":
679-
# # TODO: temporal
680-
# prepare_RA_code(entrypoint)
620+
# Pass the linter
621+
errors = self.linter.evaluate_source_code(to_lint)
622+
failed_linter = False
623+
624+
for error in errors:
625+
if error != "":
626+
failed_linter = True
627+
console_path = find_docker_console()
628+
for i in console_path:
629+
with open(i, "w") as console:
630+
console.write(errors + "\n\n")
631+
632+
if failed_linter:
633+
raise Exception(errors)
681634

635+
try:
682636
fds = os.listdir("/dev/pts/")
683637
console_fd = str(max(map(int, fds[:-1])))
684638

0 commit comments

Comments
 (0)