Skip to content

Commit

Permalink
move LinterState to it's own directory
Browse files Browse the repository at this point in the history
  • Loading branch information
wxtim committed Jan 13, 2025
1 parent b3c2ab7 commit b784135
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 87 deletions.
110 changes: 110 additions & 0 deletions cylc/flow/lint/state.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
#!/usr/bin/env python3
# THIS FILE IS PART OF THE CYLC WORKFLOW ENGINE.
# Copyright (C) NIWA & British Crown (Met Office) & Contributors.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""Cylc Linter state store object.
"""

from dataclasses import dataclass
import re


@dataclass
class LinterState:
"""A place to keep linter state"""
TRIPLE_QUOTES = re.compile(r'\'{3}|\"{3}')
JINJA2_START = re.compile(r'{%')
JINJA2_END = re.compile(r'%}')
NEW_SECTION_START = re.compile(r'^[^\[]*\[[^\[]')
is_metadata_section: bool = False
is_multiline_chunk: bool = False
is_jinja2_block: bool = False
jinja2_shebang: bool = False
line_no: int = 1

def skip_line(self, line):
"""Is this a line we should skip, according to state we are holding
and the line content?
TODO: Testme
"""
return any((
self.skip_metatadata_desc(line),
self.skip_jinja2_block(line)
))

def skip_metatadata_desc(self, line):
"""Should we skip this line because it's part of a metadata multiline
description section.
TODO: Testme
"""
if '[meta]' in line:
self.is_metadata_section = True
elif self.is_metadata_section and self.is_end_of_meta_section(line):
self.is_metadata_section = False

if self.is_metadata_section:
if self.TRIPLE_QUOTES.findall(line):
self.is_multiline_chunk = not self.is_multiline_chunk
if self.is_multiline_chunk:
return True

return False

def skip_jinja2_block(self, line):
"""Is this line part of a jinja2 block?
TODO: Testme
"""
if self.jinja2_shebang:
if (
self.JINJA2_START.findall(line)
and not self.JINJA2_END.findall(line)
):
self.is_jinja2_block = True
elif self.is_jinja2_block and self.JINJA2_END.findall(line):
self.is_jinja2_block = False
return True

return self.is_jinja2_block

@staticmethod
def is_end_of_meta_section(line):
"""Best tests I can think of for end of metadata section.
Exists as separate function to improve documentation of what we
look for as the end of the meta section.
Examples:
>>> this = LinterState.is_end_of_meta_section
>>> this('[scheduler]') # Likely right answer
True
>>> this('[garbage]') # Unreasonable, not worth guarding against
True
>>> this('')
False
>>> this(' ')
False
>>> this('{{NAME}}')
False
>>> this(' [[custom metadata subsection]]')
False
>>> this('[[custom metadata subsection]]')
False
>>> this('arbitrary crud')
False
"""
return bool(line and LinterState.NEW_SECTION_START.findall(line))
88 changes: 1 addition & 87 deletions cylc/flow/scripts/lint.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@
max-line-length = 130 # Max line length for linting
"""

from dataclasses import dataclass
import functools
import pkgutil
import re
Expand Down Expand Up @@ -91,6 +90,7 @@
from cylc.flow.exceptions import CylcError
from cylc.flow.id_cli import parse_id
from cylc.flow.job_runner_mgr import JobRunnerManager
from cylc.flow.lint.state import LinterState
from cylc.flow.loggingutil import set_timestamps
from cylc.flow.option_parsers import (
WORKFLOW_ID_OR_PATH_ARG_DOC,
Expand Down Expand Up @@ -1253,92 +1253,6 @@ def no_qa(line: str, index: str):
return False


@dataclass
class LinterState:
"""A place to keep linter state"""
TRIPLE_QUOTES = re.compile(r'\'{3}|\"{3}')
JINJA2_START = re.compile(r'{%')
JINJA2_END = re.compile(r'%}')
NEW_SECTION_START = re.compile(r'^[^\[]*\[[^\[]')
is_metadata_section: bool = False
is_multiline_chunk: bool = False
is_jinja2_block: bool = False
jinja2_shebang: bool = False
line_no: int = 1

def skip_line(self, line):
"""Is this a line we should skip, according to state we are holding
and the line content?
TODO: Testme
"""
return any((
self.skip_metatadata_desc(line),
self.skip_jinja2_block(line)
))

def skip_metatadata_desc(self, line):
"""Should we skip this line because it's part of a metadata multiline
description section.
TODO: Testme
"""
if '[meta]' in line:
self.is_metadata_section = True
elif self.is_metadata_section and self.is_end_of_meta_section(line):
self.is_metadata_section = False

if self.is_metadata_section:
if self.TRIPLE_QUOTES.findall(line):
self.is_multiline_chunk = not self.is_multiline_chunk
if self.is_multiline_chunk:
return True

return False

def skip_jinja2_block(self, line):
"""Is this line part of a jinja2 block?
TODO: Testme
"""
if self.jinja2_shebang:
if (
self.JINJA2_START.findall(line)
and not self.JINJA2_END.findall(line)
):
self.is_jinja2_block = True
elif self.is_jinja2_block and self.JINJA2_END.findall(line):
self.is_jinja2_block = False
return True

return self.is_jinja2_block

@staticmethod
def is_end_of_meta_section(line):
"""Best tests I can think of for end of metadata section.
Examples:
>>> this = LinterState.is_end_of_meta_section
>>> this('[scheduler]') # Likely right answer
True
>>> this('[garbage]') # Unreasonable, not worth guarding against
True
>>> this('')
False
>>> this(' ')
False
>>> this('{{NAME}}')
False
>>> this(' [[custom metadata subsection]]')
False
>>> this('[[custom metadata subsection]]')
False
>>> this('arbitrary crud')
False
"""
return line and LinterState.NEW_SECTION_START.findall(line)


def lint(
file_rel: Path,
lines: Iterator[str],
Expand Down

0 comments on commit b784135

Please sign in to comment.