Cura/printer-linter/printer-linter.py
jspijker 49305474ea Added a diagnose flag
Allowing the user to opt-in or out of diagnosing the file
2022-11-20 10:46:21 +01:00

131 lines
4.9 KiB
Python

import configparser
import json
import re
from argparse import ArgumentParser
from collections import OrderedDict
from os import getcwd
from pathlib import Path
import yaml
from tidy import create
def examineFile(file, settings):
patient = create(file, settings)
if patient is None:
return {}
full_body_check = {f"{file.as_posix()}": []}
for diagnostic in patient.check():
if diagnostic:
full_body_check[f"{file.as_posix()}"].append(diagnostic.toDict())
if len(full_body_check[f"{file.as_posix()}"]) == 0:
del full_body_check[f"{file.as_posix()}"]
return full_body_check
def fixFile(file, settings, full_body_check):
if not file.exists():
return
ext = ".".join(file.name.split(".")[-2:])
if ext == "def.json":
issues = full_body_check[f"{file.as_posix()}"]
for issue in issues:
if issue["diagnostic"] == "diagnostic-definition-redundant-override" and settings["fixes"].get(
"diagnostic-definition-redundant-override", True):
pass
def formatFile(file: Path, settings):
if not file.exists():
return
ext = ".".join(file.name.split(".")[-2:])
if ext == "def.json":
definition = json.loads(file.read_text())
content = json.dumps(definition, indent=settings["format"].get("format-definition-indent", 4),
sort_keys=settings["format"].get("format-definition-sort-keys", True))
if settings["format"].get("format-definition-bracket-newline", True):
newline = re.compile(r"(\B\s+)(\"[\w\"]+)(\:\s\{)")
content = newline.sub(r"\1\2:\1{", content)
if settings["format"].get("format-definition-paired-coordinate-array", True):
paired_coordinates = re.compile(r"(\[)\s+(-?\d*),\s*(-?\d*)\s*(\])")
content = paired_coordinates.sub(r"\1 \2, \3 \4", content)
file.write_text(content)
if ext == "inst.cfg":
config = configparser.ConfigParser()
config.read(file)
if settings["format"].get("format-profile-sort-keys", True):
for section in config._sections:
config._sections[section] = OrderedDict(sorted(config._sections[section].items(), key=lambda t: t[0]))
config._sections = OrderedDict(sorted(config._sections.items(), key=lambda t: t[0]))
with open(file, "w") as f:
config.write(f, space_around_delimiters=settings["format"].get("format-profile-space-around-delimiters", True))
def main(files, setting_path, to_format, to_fix, to_diagnose, report):
if not setting_path:
setting_path = Path(getcwd(), ".printer-linter")
if not setting_path.exists():
print(f"Can't find the settings: {setting_path}")
return
with open(setting_path, "r") as f:
settings = yaml.load(f, yaml.FullLoader)
if to_fix or to_diagnose:
full_body_check = {}
for file in files:
if file.is_dir():
for fp in file.rglob("**/*"):
full_body_check |= examineFile(fp, settings)
else:
full_body_check |= examineFile(file, settings)
results = yaml.dump(full_body_check, default_flow_style=False, indent=4, width=240)
if report:
report.write_text(results)
else:
print(results)
if to_fix:
for file in files:
if file.is_dir():
for fp in file.rglob("**/*"):
if f"{file.as_posix()}" in full_body_check:
fixFile(fp, settings, full_body_check)
else:
if f"{file.as_posix()}" in full_body_check:
fixFile(file, settings, full_body_check)
if to_format:
for file in files:
if file.is_dir():
for fp in file.rglob("**/*"):
formatFile(fp, settings)
else:
formatFile(file, settings)
if __name__ == "__main__":
parser = ArgumentParser(
description="UltiMaker Cura printer linting, static analysis and formatting of Cura printer definitions and other resources")
parser.add_argument("--setting", required=False, type=Path, help="Path to the `.printer-linter` setting file")
parser.add_argument("--report", required=False, type=Path, help="Path where the diagnostic report should be stored")
parser.add_argument("--format", action="store_true", help="Format the files")
parser.add_argument("--diagnose", action="store_true", help="Diagnose the files")
parser.add_argument("--fix", action="store_true", help="Attempt to apply the suggested fixes on the files")
parser.add_argument("Files", metavar="F", type=Path, nargs="+", help="Files or directories to format")
args = parser.parse_args()
main(args.Files, args.setting, args.format, args.fix, args.diagnose, args.report)