Commit b65bfd89 authored by Grant Paton-Simpson's avatar Grant Paton-Simpson

Misc:

* Fix bug falsely detecting open func call without cm
* Add ability to ignore specified lint rules
* Refine rules for showing overall snippet in displayers
parent 20b1306a
......@@ -92,7 +92,7 @@ def get_open_cm_msg():
WITH_XPATH = 'descendant-or-self::With'
def is_using_open(with_el):
def with_is_using_open(with_el):
func_name_els = with_el.xpath(
'descendant::items/withitem/context_expr/Call/func/Name')
if len(func_name_els) != 1:
......@@ -107,7 +107,7 @@ def content_manager_overview(block_dets, *, repeat=False):
Explain context managers.
"""
with_els = block_dets.element.xpath(WITH_XPATH)
using_open_cm = any([is_using_open(with_el) for with_el in with_els])
using_open_cm = any([with_is_using_open(with_el) for with_el in with_els])
if not with_els:
return None
......@@ -156,16 +156,37 @@ def content_manager_overview(block_dets, *, repeat=False):
}
return message
ASSIGN_OPEN_XPATH = 'descendant-or-self::Assign/value/Call/func/Name'
def has_with_ancestor(open_el):
with_els = open_el.xpath('ancestor::With')
if not with_els:
return False
with_el = with_els[-1]
func_name_els = with_el.xpath('items/withitem/context_expr/Call/func/Name')
if len(func_name_els) != 1:
return False
func_name_el_under_with = func_name_els[0]
return open_el == func_name_el_under_with
@filt_block_advisor(xpath=ASSIGN_OPEN_XPATH, warning=True)
FUNC_NAME_XPATH = 'descendant-or-self::Call/func/Name'
@filt_block_advisor(xpath=FUNC_NAME_XPATH, warning=True)
def file_cm_needed(block_dets, *, repeat=False):
"""
Look for opening of file without a context managers - recommend use of the
"with open" context manager.
"""
assign_open_els = block_dets.element.xpath(ASSIGN_OPEN_XPATH)
if not assign_open_els:
func_name_els = block_dets.element.xpath(FUNC_NAME_XPATH)
if not func_name_els:
return None
open_els = []
for func_name_el in func_name_els:
func_name = func_name_el.get('id')
if func_name == 'open':
open_els.append(func_name_el)
if not open_els:
return None
missing_cm = not all([has_with_ancestor(open_el) for open_el in open_els])
if not missing_cm:
return None
title = layout("""\
......
......@@ -28,7 +28,7 @@ def _get_flake8_fpath():
if os_platform == conf.WINDOWS:
"""
The Joys of Where
The "where" statement won't always point to an actual executable -
sometimes it finds a stub which, when executed, opens up an MS app store
LOL FAIL. Sometimes refers to two places - one on a C: drive and another
......@@ -37,8 +37,8 @@ def _get_flake8_fpath():
which_statement = 'where'
else:
which_statement = 'which'
cmd = [which_statement, 'flake8']
res = run(args=cmd, stdout=PIPE)
args = [which_statement, 'flake8']
res = run(args=args, stdout=PIPE)
flake8_fpath = str(res.stdout, encoding='utf-8').strip()
if not flake8_fpath:
flake8_fpath = _get_env_flake8_fpath()
......@@ -46,8 +46,11 @@ def _get_flake8_fpath():
def _get_flake8_results(fpath):
flake8_fpath = _get_flake8_fpath()
cmd = [flake8_fpath, str(fpath)]
res = run(args=cmd, stdout=PIPE)
args = [flake8_fpath, str(fpath)]
if conf.IGNORED_LINT_RULES:
ignored = ','.join(conf.IGNORED_LINT_RULES)
args.append(f"--extend-ignore={ignored}")
res = run(args=args, stdout=PIPE)
return res
@snippet_str_advisor(warning=True)
......@@ -79,7 +82,9 @@ def lint_snippet(snippet):
spending all their time restyling each other's code and arguing about
"standards".
Here is what the linter reported about your snippet:
Here is what the linter reported about your snippet. Note - if your
snippet is taken from a broader context the linter might be concerned
about names it doesn't know about - i.e. some unavoidable false alarms.
""")
lint_lines = [line.strip()
......
......@@ -27,7 +27,19 @@ else:
## When testing user-supplied snippets watch out for the BOM MS inserts via Notepad. AST chokes on it.
TEST_SNIPPET = """\
home = 'super volcano'
try:
from .. import conf # @UnresolvedImport @UnusedImport
## importing from superhelp only works properly after I've installed superhelp as a pip package (albeit as a link to this code using python3 -m pip install --user -e <path_to_proj_folder>)
## Using this as a library etc works with . instead of superhelp but I want to be be able to run the helper module from within my IDE
from . import advisors, messages # @UnusedImport
from .displayers import cli_displayer, html_displayer # @UnusedImport
except (ImportError, ValueError):
from pathlib import Path
import sys
parent = str(Path.cwd().parent)
sys.path.insert(0, parent)
from superhelp import conf, advisors, messages # @Reimport
from superhelp.displayers import cli_displayer, html_displayer # @Reimport
"""
DEMO_SNIPPET = """\
......@@ -244,6 +256,11 @@ SNIPPET_FNAME = 'snippet.py'
LINT_MSG_TYPE = 'msg_type'
LINT_MSG = 'msg'
LINT_LINE_NO = 'line_no'
## https://pycodestyle.pycqa.org/en/latest/intro.html#error-codes
## https://flake8.pycqa.org/en/latest/user/error-codes.html
IGNORED_LINT_RULES = [
'E128', ## flake8 wants visual alignment on line continuation - I don't - I want standardised alignment on indent multiples of 4
]
LINE_FEED = '&#10;'
......
......@@ -27,15 +27,17 @@ def get_message(message_dets, message_level):
message = md2cli.main(md=message.replace('`', '')) ## They create problems in formatting
return message
def _need_snippet_displayed(block_messages_dets, *, multi_block=False):
def _need_snippet_displayed(overall_messages_dets, block_messages_dets, *,
multi_block=False):
"""
Don't need to see the code snippet displayed when it is already visible:
* because there is only one block in snippet and there is a block message
for it (which will display the block i.e. the entire snippet)
for it (which will display the block i.e. the entire snippet) UNLESS there
is an overall message separating them
Otherwise we need it displayed.
"""
mono_block_snippet = not multi_block
if mono_block_snippet and block_messages_dets:
if mono_block_snippet and block_messages_dets and not overall_messages_dets:
return False
return True
......@@ -61,7 +63,7 @@ def display(snippet, messages_dets, *,
]
overall_messages_dets, block_messages_dets = messages_dets
display_snippet = _need_snippet_displayed(
block_messages_dets, multi_block=multi_block)
overall_messages_dets, block_messages_dets, multi_block=multi_block)
if display_snippet:
text.append(md2cli.main(dedent(
"## Overall Snippet"
......
......@@ -571,19 +571,21 @@ def repeat_overall_snippet(snippet):
html_strs.append(overall_code_str_highlighted)
return html_strs
def _need_snippet_displayed(block_messages_dets, *,
def _need_snippet_displayed(overall_messages_dets, block_messages_dets, *,
in_notebook=False, multi_block=False):
"""
Don't need to see the code snippet displayed when it is already visible:
Don't need to see the code snippet displayed when it is already visible
right next to it:
* because in notebook (it is already in the cell straight above)
* because there is only one block in snippet and there is a block message
for it (which will display the block i.e. the entire snippet)
for it (which will display the block i.e. the entire snippet) UNLESS there
is an overall message separating them
Otherwise we need it displayed.
"""
if in_notebook:
return False
mono_block_snippet = not multi_block
if mono_block_snippet and block_messages_dets:
if mono_block_snippet and block_messages_dets and not overall_messages_dets:
return False
return True
......@@ -599,7 +601,8 @@ def _get_all_html_strs(snippet, overall_messages_dets, block_messages_dets, *,
all_html_strs = []
## overall snippet display
display_snippet = _need_snippet_displayed(block_messages_dets,
display_snippet = _need_snippet_displayed(
overall_messages_dets, block_messages_dets,
in_notebook=in_notebook, multi_block=multi_block)
if display_snippet:
overall_snippet_html_strs = repeat_overall_snippet(snippet)
......
......@@ -91,6 +91,16 @@ def test_misc():
ROOT + 'file_cm_needed': 1,
}
),
(
dedent("""\
def test():
pass
"""),
{
ROOT + 'content_manager_overview': 0,
ROOT + 'file_cm_needed': 0,
}
),
]
check_as_expected(test_conf)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment