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

Add check for use of mutable default arguments; misc

* Add check for use of mutable default arguments
* Add nice_pairs function
* Improve feedback to user if unable to identify source script
* Improve docs for choosing advisor decorator
* Bump version
parent 466049fe
Pipeline #581 failed with stages
# https://git.nzoss.org.nz/pyGrant/superhelp
0# https://git.nzoss.org.nz/pyGrant/superhelp
version number: 0.9.19
version number: 0.9.20
author: Grant Paton-Simpson
## Overview
......
......@@ -2,7 +2,7 @@ from setuptools import setup, find_packages # @UnresolvedImport
from codecs import open
from os import path
__version__ = '0.9.19'
__version__ = '0.9.20'
here = path.abspath(path.dirname(__file__))
......
......@@ -6,6 +6,17 @@ modules with the @..._advisor decorators :-). Make sure the first paragraph of
the docstring is a good, user-facing description of its purpose so it can be
automatically processed into lists of available advice in SuperHELP.
So which advisor decorator to use?
Is the advice for the snippet as a whole? If so, are you processing the raw
snippet string or the XML code block elements? If processing the snippet string
e.g. passing into flake8 linter use snippet_str_advisor; if processing XML use
all_blocks_advisor.
If looking at individual code blocks, are you prefiltering or looking at every
sort? If prefiltering use filt_block_advisor; if not use any_block_advisor.
Simple really :-)
The basic pattern within an advisor function is:
* Get the correct elements and see if the target pattern is found e.g. a value
......@@ -124,6 +135,9 @@ def any_block_advisor(*, warning=False):
def all_blocks_advisor(*, warning=False):
"""
Use when processing XML for all blocks at once. Probably looking for first
instance of something rather than processing code block by code block.
Simple decorator that registers an unchanged advisor function in the list of
ALL_BLOCKS_ADVISORS.
......@@ -142,6 +156,8 @@ def all_blocks_advisor(*, warning=False):
def snippet_str_advisor(*, warning=False):
"""
Use when processing the snippet string e.g. passing into flake8 linter.
Simple decorator that registers an unchanged advisor function in the list of
SNIPPET_STR_ADVISORS.
......
This diff is collapsed.
......@@ -30,13 +30,9 @@ else:
## When testing user-supplied snippets watch out for the BOM MS inserts via Notepad. AST chokes on it.
## All snippets here should be raw strings (see https://stackoverflow.com/questions/53636723/python-parsing-code-with-new-line-character-in-them-using-ast)
TEST_SNIPPET = r"""
## https://www.mnn.com/earth-matters/animals/stories/21-animals-with-completely-ridiculous-names
words = ['Spiny lumpsucker', 'Wunderpus photogenicus', 'Pleasing fungus beetle']
for word in words:
if len(word) > 16:
break
else:
print("Never found any long words")
def multifunc(posonly_arg1=1, posonly_arg2=[], /,
arg1=2, arg2=3, arg3=[], *, kwonly_arg1={}):
pass
"""
PY3_6 = '3.6'
......
......@@ -118,8 +118,9 @@ def _get_introspected_file_path():
break
else: ## didn't break for-loop
raise Exception('Unable to identify calling script through '
'introspection so file_path=__file__ will need to be explicitly '
'supplied e.g. superhelp.this(file_path=__file__)')
"introspection. Did you rename 'superhelp' or 'this'? "
"If that isn't the problem try explicitly supplying "
"file_path e.g. superhelp.this(file_path=__file__)'")
file_path = calling_item.filename
return file_path
......
......@@ -66,6 +66,11 @@ def get_nice_str_list(items, *, quoter='`'):
nice_str_list += f"{quoter}{items[-1]}{quoter}"
return nice_str_list
def get_nice_pairs(pairs, *, left_quoter='`', right_quoter='`'):
return '; '.join(
f"{left_quoter}{left}{left_quoter}: {right_quoter}{right}{right_quoter}"
for left, right in pairs)
def int2nice(num):
"""
:return: nicer version of number ready for use in sentences
......
......@@ -18,6 +18,7 @@ def test_misc():
ROOT + 'func_excess_parameters': 0,
ROOT + 'positional_boolean': 0,
ROOT + 'docstring_issues': 0,
ROOT + 'mutable_default': 0,
}
),
(
......@@ -31,6 +32,7 @@ def test_misc():
ROOT + 'func_excess_parameters': 0,
ROOT + 'positional_boolean': 0,
ROOT + 'docstring_issues': 1,
ROOT + 'mutable_default': 0,
}
),
(
......@@ -45,6 +47,7 @@ def test_misc():
ROOT + 'func_excess_parameters': 0,
ROOT + 'positional_boolean': 0,
ROOT + 'docstring_issues': 1,
ROOT + 'mutable_default': 0,
}
),
(
......@@ -59,6 +62,7 @@ def test_misc():
ROOT + 'func_excess_parameters': 0,
ROOT + 'positional_boolean': 0,
ROOT + 'docstring_issues': 1,
ROOT + 'mutable_default': 0,
}
),
(
......@@ -72,6 +76,7 @@ def test_misc():
ROOT + 'func_excess_parameters': 1,
ROOT + 'positional_boolean': 0,
ROOT + 'docstring_issues': 1,
ROOT + 'mutable_default': 0,
}
),
(
......@@ -85,6 +90,7 @@ def test_misc():
ROOT + 'func_excess_parameters': 1,
ROOT + 'positional_boolean': 1,
ROOT + 'docstring_issues': 1,
ROOT + 'mutable_default': 0,
}
),
(
......@@ -98,6 +104,7 @@ def test_misc():
ROOT + 'func_excess_parameters': 0,
ROOT + 'positional_boolean': 1,
ROOT + 'docstring_issues': 1,
ROOT + 'mutable_default': 0,
}
),
(
......@@ -114,6 +121,7 @@ def test_misc():
ROOT + 'func_excess_parameters': 0,
ROOT + 'positional_boolean': 0,
ROOT + 'docstring_issues': 1,
ROOT + 'mutable_default': 0,
}
),
(
......@@ -132,6 +140,7 @@ def test_misc():
ROOT + 'func_excess_parameters': 0,
ROOT + 'positional_boolean': 0,
ROOT + 'docstring_issues': 0, ## Just squeaks through
ROOT + 'mutable_default': 0,
}
),
(
......@@ -147,6 +156,7 @@ def test_misc():
ROOT + 'func_excess_parameters': 0,
ROOT + 'positional_boolean': 0,
ROOT + 'docstring_issues': 1,
ROOT + 'mutable_default': 0,
}
),
(
......@@ -164,6 +174,7 @@ def test_misc():
ROOT + 'func_excess_parameters': 0,
ROOT + 'positional_boolean': 0,
ROOT + 'docstring_issues': 1,
ROOT + 'mutable_default': 0,
}
),
(
......@@ -183,6 +194,36 @@ def test_misc():
ROOT + 'func_excess_parameters': 0,
ROOT + 'positional_boolean': 0,
ROOT + 'docstring_issues': 1,
ROOT + 'mutable_default': 0,
}
),
(
dedent(f"""\
def demo(items=[]):
pass
"""),
{
ROOT + 'func_overview': 1,
ROOT + 'func_len_check': 0,
ROOT + 'func_excess_parameters': 0,
ROOT + 'positional_boolean': 0,
ROOT + 'docstring_issues': 1,
ROOT + 'mutable_default': 1,
}
),
(
dedent(f"""\
class Demo:
def demo(self, items=[]):
pass
"""),
{
ROOT + 'func_overview': 1,
ROOT + 'func_len_check': 0,
ROOT + 'func_excess_parameters': 0,
ROOT + 'positional_boolean': 0,
ROOT + 'docstring_issues': 1,
ROOT + 'mutable_default': 1,
}
),
]
......
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