Skip to content

Commit

Permalink
Bears.py: Ask users for capabilities
Browse files Browse the repository at this point in the history
Adds functionality for users to provide their
preferences for bears capabilities to use instead
of the `DEFAULT_CAPABILITIES` to filter bears by
capabilties. Also adds a command line argument
--no-filter-by-capabilties to disable filtering of
bears by capapbilities.

Related to #131
  • Loading branch information
satwikkansal committed Jul 23, 2017
1 parent 88f6996 commit 02369a9
Show file tree
Hide file tree
Showing 5 changed files with 177 additions and 34 deletions.
21 changes: 21 additions & 0 deletions coala_quickstart/Constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,27 @@
"Java": {"JavaPMD", "CheckstyleBear"},
"Python": {"PycodestyleBear"}}

ALL_CAPABILITIES = {
'Code Simplification',
'Commented Code',
'Complexity',
'Documentation',
'Duplication',
'Formatting',
'Grammar',
'Memory Leak',
'Missing Import',
'Redundancy',
'Security',
'Smell',
'Spelling',
'Syntax',
'Undefined Element',
'Unreachable Code',
'Unused Code',
'Variable Misuse'
}

DEFAULT_CAPABILTIES = {
"Syntax",
"Formatting",
Expand Down
5 changes: 5 additions & 0 deletions coala_quickstart/coala_quickstart.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ def _get_arg_parser():
dest='incomplete_sections', const=True,
help='generate coafile with only `bears` and `files` field in sections')

arg_parser.add_argument(
'--no-filter-by-capabilities', action='store_const',
dest='no_filter_by_capabilities', const=True,
help='disable filtering of bears by their capabilties.')

return arg_parser


Expand Down
130 changes: 97 additions & 33 deletions coala_quickstart/generation/Bears.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@

from pyprint.NullPrinter import NullPrinter

from coala_quickstart.Constants import IMPORTANT_BEAR_LIST, DEFAULT_CAPABILTIES
from coala_quickstart.Constants import (
IMPORTANT_BEAR_LIST, ALL_CAPABILITIES, DEFAULT_CAPABILTIES)
from coala_quickstart.Strings import BEAR_HELP
from coala_quickstart.generation.SettingsFilling import is_autofill_possible
from coalib.settings.ConfigurationGathering import get_filtered_bears
Expand Down Expand Up @@ -34,7 +35,7 @@ def filter_relevant_bears(used_languages,
:return:
A dict with language name as key and bear classes as value.
"""
args = arg_parser.parse_args()
args = arg_parser.parse_args() if arg_parser else None
log_printer = LogPrinter(NullPrinter())
used_languages.append(("All", 100))

Expand Down Expand Up @@ -71,14 +72,23 @@ def filter_relevant_bears(used_languages,
if lang in selected_bears and
bear not in selected_bears[lang]])

# Filter bears based on default capabilties
capable_candidates = {}
desired_capabilities = DEFAULT_CAPABILTIES
for lang, lang_bears in candidate_bears.items():
# Eliminate bears which doesn't contain the desired capabilites
capable_bears = get_bears_with_given_capabilities(
lang_bears, desired_capabilities)
capable_candidates[lang] = capable_bears
if not args.no_filter_by_capabilities:
# Ask user for capablities
user_selected_capabilities = set()
if not args.non_interactive:
user_selected_capabilities = ask_to_select_capabilties(
list(ALL_CAPABILITIES), list(DEFAULT_CAPABILTIES), printer)

desired_capabilities = (
user_selected_capabilities if user_selected_capabilities
else DEFAULT_CAPABILTIES)

# Filter bears based on capabilties
for lang, lang_bears in candidate_bears.items():
# Eliminate bears which doesn't contain the desired capabilites
capable_bears = get_bears_with_given_capabilities(
lang_bears, desired_capabilities)
candidate_bears[lang] = capable_bears

project_dependency_info = extracted_info.get("ProjectDependencyInfo")

Expand All @@ -103,7 +113,7 @@ def filter_relevant_bears(used_languages,

if user_input_reqd:
# Ask user to activate the bear
if (not args.non_interactive and
if (args and not args.non_interactive and
prompt_to_activate(bear, printer)):
selected_bears[lang].add(bear)
else:
Expand All @@ -113,28 +123,30 @@ def filter_relevant_bears(used_languages,
# no non-optional setting, select it right away!
selected_bears[lang].add(bear)

# capabilities satisfied till now
satisfied_capabilities = get_bears_capabilties(selected_bears)
remaining_capabilities = {
lang: [cap for cap in desired_capabilities
if satisfied_capabilities.get(lang) and
cap not in satisfied_capabilities[lang]]
for lang in candidate_bears}

filtered_bears = {}
for lang, lang_bears in capable_candidates.items():
filtered_bears[lang] = get_bears_with_given_capabilities(
lang_bears, remaining_capabilities[lang])

# Remove overlapping capabilty bears
filtered_bears = remove_bears_with_conflicting_capabilties(
filtered_bears)
# Add to the selectecd_bears
for lang, lang_bears in filtered_bears.items():
if not selected_bears.get(lang):
selected_bears[lang] = lang_bears
else:
selected_bears[lang].update(lang_bears)
if not args.no_filter_by_capabilities:
# capabilities satisfied till now
satisfied_capabilities = get_bears_capabilties(selected_bears)
remaining_capabilities = {
lang: [cap for cap in desired_capabilities
if lang in satisfied_capabilities and
cap not in satisfied_capabilities[lang]]
for lang in candidate_bears}

filtered_bears = {}
for lang, lang_bears in candidate_bears.items():
filtered_bears[lang] = get_bears_with_given_capabilities(
lang_bears, remaining_capabilities[lang])

# Remove overlapping capabilty bears
filtered_bears = remove_bears_with_conflicting_capabilties(
filtered_bears)

# Add to the selectecd_bears
for lang, lang_bears in filtered_bears.items():
if not selected_bears.get(lang):
selected_bears[lang] = lang_bears
else:
selected_bears[lang].update(lang_bears)

return selected_bears

Expand Down Expand Up @@ -436,3 +448,55 @@ def prompt_to_activate(bear, printer):
return False
else:
return prompt_to_activate(bear, printer)


def ask_to_select_capabilties(all_capabilities,
default_capabilities,
console_printer):
"""
Asks the users to select capabilties out of all_capabilities.
"""
all_capabilities = sorted(all_capabilities)
PROMPT_QUESTION = ("What would you like the bears to detect or fix? "
"Please select some bear capabilities using "
"their numbers or just press 'Enter' to select"
"default capabilities (highlighted in green)")
console_printer.print(PROMPT_QUESTION, color="yellow")

default_options = []
total_options = len(all_capabilities) + 1

for idx, cap in enumerate(all_capabilities):
color = 'cyan'
if cap in default_capabilities:
color = 'green'
default_options.append(idx)
console_printer.print(
" {}. {}".format(idx + 1, cap), color=color)
console_printer.print(
" {}. Select all default capabilities.".format(
total_options), color="cyan")

selected_numbers = []
try:
selected_numbers = list(map(int, re.split("\D+", input())))
except Exception:
# Parsing failed, choose all the default capabilities
selected_numbers = [total_options]

selected_capabilties = []

for num in selected_numbers:
if num >= 0 and num < total_options:
selected_capabilties.append(all_capabilities[int(num) - 1])
elif num == total_options:
selected_capabilties += default_capabilities
else:
console_printer.print(
"{} is not a valid option. Please choose the right"
" option numbers".format(str(num)))
ask_to_select_capabilties(all_capabilities,
default_capabilities,
console_printer)

return set(selected_capabilties)
46 changes: 45 additions & 1 deletion tests/generation/Bears.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import unittest
from copy import deepcopy


from pyprint.ConsolePrinter import ConsolePrinter
from coalib.output.printers.LogPrinter import LogPrinter
from coala_utils.ContextManagers import (
Expand All @@ -11,6 +12,8 @@
filter_relevant_bears, print_relevant_bears)
from coala_quickstart.coala_quickstart import main
from coala_quickstart.coala_quickstart import _get_arg_parser
from coala_quickstart.Constants import (
IMPORTANT_BEAR_LIST, ALL_CAPABILITIES)
from coala_quickstart.generation.InfoCollector import collect_info
from tests.TestUtilities import bear_test_module, generate_files

Expand Down Expand Up @@ -117,7 +120,7 @@ def test_filter_relevant_bears_with_extracted_info(self):
self.assertIn(bear, additional_bears)

def test_filter_relevant_bears_with_non_optional_settings(self):

sys.argv.append('--no-filter-by-capabilities')
with bear_test_module():
languages = []
res_1 = filter_relevant_bears(
Expand Down Expand Up @@ -171,6 +174,33 @@ def test_filter_relevant_bears_with_non_optional_settings(self):
for bear in additional_bears_by_lang[lang]:
self.assertIn(bear, additional_bears)

def test_filter_relevant_bears_with_capabilities(self):
# Clear the IMPORTANT_BEARS_LIST
import coala_quickstart.generation.Bears as Bears
Bears.IMPORTANT_BEARS_LIST = {}

with bear_test_module():
languages = []
capability_to_select = 'Smell'
cap_number = (
sorted(ALL_CAPABILITIES).index(capability_to_select) + 1)
res = []
with simulate_console_inputs('1000', str(cap_number)) as generator:
res = filter_relevant_bears(languages,
self.printer,
self.arg_parser,
{})
# 1000 was not a valid option, so there will be two prompts
self.assertEqual(generator.last_input, 1)

expected_results = {
"All": set(["SmellCapabilityBear"])
}
for lang, lang_bears in expected_results.items():
for bear in lang_bears:
res_bears = [b.name for b in res[lang]]
self.assertIn(bear, res_bears)

def test_print_relevant_bears(self):
with retrieve_stdout() as custom_stdout:
print_relevant_bears(self.printer, filter_relevant_bears(
Expand Down Expand Up @@ -203,6 +233,20 @@ def test_bears_ci_mode(self):
os.remove('.coafile')
os.chdir(orig_cwd)

def test_bears_no_filter_by_capability_mode(self):
languages = []
with bear_test_module():
# Results without filtering
sys.argv.append('--no-filter-by-capabilities')
res = []
with simulate_console_inputs() as generator:
res = filter_relevant_bears(languages,
self.printer,
self.arg_parser,
{})
self.assertEqual(generator.last_input, -1)
self.assertEqual(res, {"All": set()})

def test_filter_bears_ci_mode(self):
sys.argv.append('--ci')
with bear_test_module():
Expand Down
9 changes: 9 additions & 0 deletions tests/test_bears/SmellCapabilityBear.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from coalib.bears.LocalBear import LocalBear


class SmellCapabilityBear(LocalBear):
CAN_FIX = {"Smell"}
LANGUAGES = {"All"}

def run(self, filename, file):
pass

0 comments on commit 02369a9

Please sign in to comment.