Skip to content

Commit

Permalink
Add green_mode.py
Browse files Browse the repository at this point in the history
This file is the center of --green-mode and contains the underlying
core of this mode of coala-quickstart.

* green_mode(): The master method which calls all the underlying
  methods in this file and many others. Some broad actions that it
  performs:
  * Creates `.project_data.yaml` to store the directory and file
    structure of the project, deletes it in the end. Further commits
    may change this behaviour and add code to reuse this data
    generated.
  * Calls the QuickstartBear to traverse the file_dict and guess some
  	setting values on its own.
  * Calls the methods to provide some other information about settings
  	of some bears which can't be detected by traversing the file_dict
  	eg. settings based on the names of files.
  * Calls the methods to test each bear for each file for all the
    values for each setting until a green setting is found for a bear.
  * Will call the methods to create section object and write `.coafile`
  	in further commits.

* bear_test_fun(): Calls the methods to get all possible combinations
  of values to bear settings and supply these to other underlying
  methods to test them for each bear.

* run_test_on_each_bear(): Prints a message about which bear, the tests
  are running on and calls local_bear_test() or global_bear_test()
  depending on the type of bear to guess the green setting values
  from the combination of all values.

* local_bear_test(), global_bear_test(): Run coala repetitively on the
  bear in a multiprocessing environment and return the green settings
  found.

* check_bear_results(): Checks whether the result objects returned by
  the bear are 0 or if they lie in the ignore scope of the code to
  testify whether the current bear settings are green.

* get_kwargs(): Produces combinations of all setting values for the
  bears which are given one by one to the bear to run upon.

* get_setting_type(): Detects the type of a bear argument, i.e.
  whether it accepts boolean values or something like int which falls
  under the category of infinite set of values, whether some setting
  requires a config file of a specific linter or whether an argument
  accepts some discrete set of values.

* run_quickstartbear(): Runs QuickstartBear to guess some setting
  values from the file_dict and write the results to
  `.project_data.yaml`.

* find_min_of_setting()/find_max_of_setting(): Are helper functions
  for bear settings that run in coordination with per file results of
  QuickstartBear to get the project minima/maxima value of that
  particular setting.

* generate_complete_filename_list(): From the file/directory structure
  written to the `.project_data.yaml` gets only the list of files.

* initialize_project_data(): Initializes the `.project_data.yaml` by
  writing to the file/directory structure of the project with file
  names as items of a list but directories as dicts again as sub items
  of a list.

* Some other helper methods for some basic operations are also created.

Apart from the changes to green_mode.py a method that is added to
Utilities.py is:

contained_in(): Detects whether the first argument which must be
a SourceRange object is contained absolutely inside the
other SourceRange object with closed boundaries.

Tests are added for each method except the final green_mode() method.

coala_quickstart.py: The arguments:
* MAX_NUM_OF_OPTIONAL_ARGS_ALLOWED_FOR_GREEN_MODE
* MAX_NUM_OF_VALUES_OF_OPTIONAL_ARGS_ALLOWED_FOR_GREEN_MODE
are introduced.
  • Loading branch information
ishanSrt committed Aug 12, 2018
1 parent 6f96574 commit eb133e6
Show file tree
Hide file tree
Showing 14 changed files with 1,198 additions and 3 deletions.
1 change: 1 addition & 0 deletions .nocover.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ nocover_file_globs:
- coala_quickstart/info_extractors/EditorconfigParsing.py
- coala_quickstart/info_extractors/GemfileInfoExtractor.py
- coala_quickstart/info_extractors/GruntfileInfoExtractor.py
- coala_quickstart/green_mode/green_mode_core.py

nocover_regexes:
# coala_quickstart.py
Expand Down
11 changes: 10 additions & 1 deletion coala_quickstart/coala_quickstart.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@
generate_settings, write_coafile)
from coala_quickstart.generation.SettingsClass import (
collect_bear_settings)
from coala_quickstart.green_mode.green_mode_core import green_mode

MAX_NUM_OF_OPTIONAL_ARGS_ALLOWED_FOR_GREEN_MODE = 5
MAX_NUM_OF_VALUES_OF_OPTIONAL_ARGS_ALLOWED_FOR_GREEN_MODE = 5


def _get_arg_parser():
Expand Down Expand Up @@ -110,7 +114,12 @@ def main():
used_languages, printer, arg_parser, extracted_information)

if args.green_mode:
collect_bear_settings(relevant_bears)
bear_settings_obj = collect_bear_settings(relevant_bears)
green_mode(
project_dir, ignore_globs, relevant_bears, bear_settings_obj,
MAX_NUM_OF_OPTIONAL_ARGS_ALLOWED_FOR_GREEN_MODE,
MAX_NUM_OF_VALUES_OF_OPTIONAL_ARGS_ALLOWED_FOR_GREEN_MODE,
printer)

print_relevant_bears(printer, relevant_bears)

Expand Down
123 changes: 123 additions & 0 deletions coala_quickstart/generation/Utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import os
from collections import defaultdict
import re
import yaml

from coala_utils.Extensions import exts
from coala_utils.string_processing import unescaped_search_for
Expand Down Expand Up @@ -236,3 +237,125 @@ def peek(iterable):
except StopIteration:
return None
return first, itertools.chain([first], iterable)


def contained_in(smaller, bigger):
"""
Takes in two SourceRange objects and checks whether
the first one lies inside the other one.
:param smaller:
The SourceRange object that needs to be checked whether
it is inside the other one.
:param bigger:
The SourceRange object that needs to be checked whether
it contains the other one.
:return:
True if smaller is inside the bigger else false.
"""
smaller_file = smaller.start.file
bigger_file = bigger.start.file

smaller_start_line = smaller.start.line
smaller_start_column = smaller.start.column
smaller_end_line = smaller.end.line
smaller_end_column = smaller.end.column

bigger_start_line = bigger.start.line
bigger_start_column = bigger.start.column
bigger_end_line = bigger.end.line
bigger_end_column = bigger.end.column

if None in [smaller_start_line, smaller_start_column,
smaller_end_line, smaller_end_column,
bigger_start_line, bigger_start_column,
bigger_end_line, bigger_end_column]:
return False

if not smaller_file == bigger_file:
return False

if smaller_start_line < bigger_start_line:
return False

if smaller_end_line > bigger_end_line:
return False

if smaller_start_line > bigger_start_line and (
smaller_end_line < bigger_end_line):
return True

same_start_line = (smaller_start_line == bigger_start_line)

same_end_line = (smaller_end_line == bigger_end_line)

if same_start_line and same_end_line:
if smaller_start_column < bigger_start_column:
return False
if smaller_end_column > bigger_end_column:
return False
return True

if same_start_line:
if smaller_start_column < bigger_start_column:
return False
return True

assert same_end_line
if smaller_end_column > bigger_end_column:
return False
return True


def get_yaml_contents(project_data):
"""
Reads a YAML file and returns the data.
:param project_data:
The file path from which to read data.
:return:
The YAML data as python objects.
"""
with open(project_data, 'r') as stream:
return yaml.load(stream)


def dump_yaml_to_file(file, contents):
"""
Writes YAML data to a file.
:param file:
The file to write YAML data to.
:param contents:
The python objects to be written as YAML data.
"""
with open(file, 'w+') as outfile:
yaml.dump(contents, outfile,
default_flow_style=False)


def append_to_contents(contents, key, values, settings_key):
"""
Appends data to a dict, adding the received values
to the list of values at a given key or creating
the key if it does not exist.
:param contents:
The dict to append data to.
:param key:
The key needed to be appended to the dict.
:param values:
The list of values needed to be appended to the
values at a key in the dict.
:param settings_key:
The key to which data has to be appended to.
:return:
The dict with appended key and values.
"""
found = False
if settings_key not in contents:
contents[settings_key] = []
for index, obj in enumerate(contents[settings_key]):
if isinstance(obj, dict) and key in obj.keys():
found = True
contents[settings_key][index][key] += values
if not found:
contents[settings_key].append({key: values})

return contents
68 changes: 68 additions & 0 deletions coala_quickstart/green_mode/Setting.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
settings_key = 'green_mode_infinite_value_settings'


def find_max_of_setting(setting, value, contents):
"""
Generates max value of a setting where this
function is called upon for every value generated for
every file in the project (excluding ignored files).
:param setting:
The setting for which to find the max value of.
:param value:
The current value to be compared against the
supposedly max value stored in contents.
:param contents:
The python object to be written to 'PROJECT_DATA'
which contains the max value of the setting which was
encountered uptil now.
:return:
The contents with the max value of the setting encountered
uptil now after comparing it with the current value recieved
by the function.
"""
found = False
position = None
for index, item in enumerate(contents[settings_key]):
if isinstance(item, dict) and setting in item:
found = True
position = index
if not found:
contents[settings_key].append({setting: value})
return contents
current_val = contents[settings_key][position][setting]
if value > current_val:
contents[settings_key][position][setting] = value
return contents


def find_min_of_setting(setting, value, contents):
"""
Generates min value of a setting where this
function is called upon for every value generated for
every file in the project (excluding ignored files).
:param setting:
The setting for which to find the min value of.
:param value:
The current value to be compared against the
supposedly min value stored in contents.
:param contents:
The python object to be written to 'PROJECT_DATA'
which contains the min value of the setting which was
encountered uptil now.
:return:
The contents with the min value of the setting encountered
uptil now after comparing it with the current value recieved
by the function.
"""
found = False
for index, item in enumerate(contents[settings_key]):
if isinstance(item, dict) and setting in item:
found = True
position = index
if not found:
contents[settings_key].append({setting: value})
return contents
current_val = contents[settings_key][position][setting]
if value < current_val:
contents[settings_key][position][setting] = value
return contents
4 changes: 2 additions & 2 deletions coala_quickstart/green_mode/filename_operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def insert(self, string, idx):
self.children[ch].count += 1
else:
self.children[ch] = Node(string[idx], self)
self.children[ch].insert(string, idx+1)
self.children[ch].insert(string, idx + 1)


class Trie:
Expand Down Expand Up @@ -70,7 +70,7 @@ def _discover_prefixes(self, node, prefix, min_length, len, min_files):
for ch, ch_node in node.children.items():
prefix.append(node.character)
if (not ch_node.count < node.count) or orig_prefix == []:
self._discover_prefixes(ch_node, prefix, min_length, len+1,
self._discover_prefixes(ch_node, prefix, min_length, len + 1,
min_files)
prefix.pop()

Expand Down
Loading

0 comments on commit eb133e6

Please sign in to comment.