22
22
# NOTE: docstring needed for `cylc help all` output
23
23
# (if editing check this still comes out as expected)
24
24
25
+ LINT_SECTIONS = ['cylc-lint' , 'cylclint' , 'cylc_lint' ]
26
+
25
27
COP_DOC = """cylc lint [OPTIONS] ARGS
26
28
27
29
Check .cylc and .rc files for code style, deprecated syntax and other issues.
33
35
34
36
A non-zero return code will be returned if any issues are identified.
35
37
This can be overridden by providing the "--exit-zero" flag.
38
+ """
36
39
37
- Configurations for Cylc lint can also be set in a pyproject.toml file.
38
-
40
+ TOMLDOC = """
41
+ pyproject.toml configuration:{}
42
+ [cylc-lint] # any of {}
43
+ ignore = ['S001', 'S002] # List of rules to ignore
44
+ exclude = ['etc/foo.cylc'] # List of files to ignore
45
+ rulesets = ['style', '728'] # Sets default rulesets to check
46
+ max-line-length = 130 # Max line length for linting
39
47
"""
40
48
from colorama import Fore
41
49
import functools
42
- from optparse import Values
43
50
from pathlib import Path
44
51
import re
45
52
import sys
59
66
loads as toml_loads ,
60
67
TOMLDecodeError ,
61
68
)
62
- from typing import Callable , Dict , Iterator , List , Union
69
+ from typing import TYPE_CHECKING , Callable , Dict , Iterator , List , Union
63
70
64
71
from cylc .flow import LOG
65
72
from cylc .flow .exceptions import CylcError
73
80
from cylc .flow .scripts .cylc import DEAD_ENDS
74
81
from cylc .flow .terminal import cli_function
75
82
83
+ if TYPE_CHECKING :
84
+ from optparse import Values
85
+
86
+
76
87
DEPRECATED_ENV_VARS = {
77
88
'CYLC_SUITE_HOST' : 'CYLC_WORKFLOW_HOST' ,
78
89
'CYLC_SUITE_OWNER' : 'CYLC_WORKFLOW_OWNER' ,
@@ -222,13 +233,44 @@ def check_for_obsolete_environment_variables(line: str) -> List[str]:
222
233
return [i for i in OBSOLETE_ENV_VARS if i in line ]
223
234
224
235
236
+ INDENTATION = re .compile (r'^(\s*)(.*)' )
237
+
238
+
239
+ def check_indentation (line : str ) -> bool :
240
+ """The key value pair is not indented 4*X spaces
241
+
242
+ n.b. We test for trailing whitespace and incorrect section indenting
243
+ elsewhere
244
+
245
+ Examples:
246
+
247
+ >>> check_indentation('')
248
+ False
249
+ >>> check_indentation(' ')
250
+ False
251
+ >>> check_indentation(' [')
252
+ False
253
+ >>> check_indentation('baz')
254
+ False
255
+ >>> check_indentation(' qux')
256
+ False
257
+ >>> check_indentation(' foo')
258
+ True
259
+ >>> check_indentation(' bar')
260
+ True
261
+ """
262
+ match = INDENTATION .findall (line )[0 ]
263
+ if not match [0 ] or not match [1 ] or match [1 ].startswith ('[' ):
264
+ return False
265
+ return bool (len (match [0 ]) % 4 != 0 )
266
+
267
+
225
268
FUNCTION = 'function'
226
269
227
270
STYLE_GUIDE = (
228
271
'https://cylc.github.io/cylc-doc/stable/html/workflow-design-guide/'
229
272
'style-guide.html#'
230
273
)
231
- URL_STUB = "https://cylc.github.io/cylc-doc/stable/html/7-to-8/"
232
274
SECTION2 = r'\[\[\s*{}\s*\]\]'
233
275
SECTION3 = r'\[\[\[\s*{}\s*\]\]\]'
234
276
FILEGLOBS = ['*.rc' , '*.cylc' ]
@@ -268,7 +310,6 @@ def check_for_obsolete_environment_variables(line: str) -> List[str]:
268
310
# - short: A short description of the issue.
269
311
# - url: A link to a fuller description.
270
312
# - function: A function to use to run the check.
271
- # - fallback: A second function(The first function might want to call this?)
272
313
# - kwargs: We want to pass a set of common kwargs to the check function.
273
314
# - evaluate commented lines: Run this check on commented lines.
274
315
# - rst: An rst description, for use in the Cylc docs.
@@ -398,21 +439,32 @@ def check_for_obsolete_environment_variables(line: str) -> List[str]:
398
439
check_if_jinja2 ,
399
440
function = re .compile (r'(?<!{)#.*?{[{%]' ).findall
400
441
)
442
+ },
443
+ 'S012' : {
444
+ 'short' : 'This number is reserved for line length checks' ,
445
+ },
446
+ 'S013' : {
447
+ 'short' : 'Items should be indented in 4 space blocks.' ,
448
+ FUNCTION : check_indentation
401
449
}
402
450
}
403
451
# Subset of deprecations which are tricky (impossible?) to scrape from the
404
452
# upgrader.
405
453
MANUAL_DEPRECATIONS = {
406
454
"U001" : {
407
- 'short' : DEPENDENCY_SECTION_MSG ['text' ],
455
+ 'short' : (
456
+ DEPENDENCY_SECTION_MSG ['text' ] + ' (``[dependencies]`` detected)'
457
+ ),
408
458
'url' : '' ,
409
- 'rst' : DEPENDENCY_SECTION_MSG ['rst' ],
459
+ 'rst' : (
460
+ DEPENDENCY_SECTION_MSG ['rst' ] + ' (``[dependencies]`` detected)'
461
+ ),
410
462
FUNCTION : re .compile (SECTION2 .format ('dependencies' )).findall ,
411
463
},
412
464
"U002" : {
413
- 'short' : DEPENDENCY_SECTION_MSG ['text' ],
465
+ 'short' : DEPENDENCY_SECTION_MSG ['text' ] + ' (``graph =`` detected)' ,
414
466
'url' : '' ,
415
- 'rst' : DEPENDENCY_SECTION_MSG ['rst' ],
467
+ 'rst' : DEPENDENCY_SECTION_MSG ['rst' ] + ' (``graph =`` detected)' ,
416
468
FUNCTION : re .compile (r'graph\s*=\s*' ).findall ,
417
469
},
418
470
"U003" : {
@@ -541,6 +593,31 @@ def check_for_obsolete_environment_variables(line: str) -> List[str]:
541
593
}
542
594
543
595
596
+ def get_url (check_meta : Dict ) -> str :
597
+ """Get URL from check data.
598
+
599
+ If the URL doesn't start with http then prepend with address
600
+ of the 7-to-8 upgrade guide.
601
+
602
+ Examples:
603
+ >>> get_url({'no': 'url key'})
604
+ ''
605
+ >>> get_url({'url': ''})
606
+ ''
607
+ >>> get_url({'url': 'https://www.h2g2.com/'})
608
+ 'https://www.h2g2.com/'
609
+ >>> get_url({'url': 'cheat-sheet.html'})
610
+ 'https://cylc.github.io/cylc-doc/stable/html/7-to-8/cheat-sheet.html'
611
+ """
612
+ url = check_meta .get ('url' , '' )
613
+ if url and not url .startswith ('http' ):
614
+ url = (
615
+ "https://cylc.github.io/cylc-doc/stable/html/7-to-8/"
616
+ + check_meta ['url' ]
617
+ )
618
+ return url
619
+
620
+
544
621
def validate_toml_items (tomldata ):
545
622
"""Check that all tomldata items are lists of strings
546
623
@@ -590,7 +667,7 @@ def get_pyproject_toml(dir_):
590
667
raise CylcError (f'pyproject.toml did not load: { exc } ' )
591
668
592
669
if any (
593
- i in loadeddata for i in [ 'cylc-lint' , 'cylclint' , 'cylc_lint' ]
670
+ i in loadeddata for i in LINT_SECTIONS
594
671
):
595
672
for key in keys :
596
673
tomldata [key ] = loadeddata .get ('cylc-lint' ).get (key , [])
@@ -906,10 +983,7 @@ def lint(
906
983
counter [check_meta ['purpose' ]] += 1
907
984
if modify :
908
985
# insert a command to help the user
909
- if check_meta ['url' ].startswith ('http' ):
910
- url = check_meta ['url' ]
911
- else :
912
- url = URL_STUB + check_meta ['url' ]
986
+ url = get_url (check_meta )
913
987
914
988
yield (
915
989
f'# [{ get_index_str (check_meta , index )} ]: '
@@ -983,10 +1057,7 @@ def get_reference_rst(checks):
983
1057
template = (
984
1058
'{check}\n ^^^^\n {summary}\n \n '
985
1059
)
986
- if meta ['url' ].startswith ('http' ):
987
- url = meta ['url' ]
988
- else :
989
- url = URL_STUB + meta ['url' ]
1060
+ url = get_url (meta )
990
1061
summary = meta .get ("rst" , meta ['short' ])
991
1062
msg = template .format (
992
1063
check = get_index_str (meta , index ),
@@ -1027,10 +1098,7 @@ def get_reference_text(checks):
1027
1098
template = (
1028
1099
'{check}:\n {summary}\n \n '
1029
1100
)
1030
- if meta ['url' ].startswith ('http' ):
1031
- url = meta ['url' ]
1032
- else :
1033
- url = URL_STUB + meta ['url' ]
1101
+ url = get_url (meta )
1034
1102
msg = template .format (
1035
1103
title = index ,
1036
1104
check = get_index_str (meta , index ),
@@ -1044,7 +1112,7 @@ def get_reference_text(checks):
1044
1112
1045
1113
def get_option_parser () -> COP :
1046
1114
parser = COP (
1047
- COP_DOC ,
1115
+ COP_DOC + TOMLDOC . format ( '' , str ( LINT_SECTIONS )) ,
1048
1116
argdoc = [
1049
1117
COP .optional (WORKFLOW_ID_OR_PATH_ARG_DOC )
1050
1118
],
@@ -1086,7 +1154,7 @@ def get_option_parser() -> COP:
1086
1154
default = [],
1087
1155
dest = 'ignores' ,
1088
1156
metavar = "CODE" ,
1089
- choices = tuple (STYLE_CHECKS )
1157
+ choices = list (STYLE_CHECKS . keys ()) + [ LINE_LEN_NO ]
1090
1158
)
1091
1159
parser .add_option (
1092
1160
'--exit-zero' ,
@@ -1204,4 +1272,6 @@ def main(parser: COP, options: 'Values', target=None) -> None:
1204
1272
1205
1273
# NOTE: use += so that this works with __import__
1206
1274
# (docstring needed for `cylc help all` output)
1207
- __doc__ += get_reference_rst (parse_checks (['728' , 'style' ], reference = True ))
1275
+ __doc__ += TOMLDOC .format (
1276
+ '\n \n .. code-block:: toml\n ' , str (LINT_SECTIONS )) + get_reference_rst (
1277
+ parse_checks (['728' , 'style' ], reference = True ))
0 commit comments