coalib.results package

Submodules

coalib.results.AbsolutePosition module

class coalib.results.AbsolutePosition.AbsolutePosition(text: (<class 'tuple'>, <class 'list'>, None) = None, position: (<class 'int'>, None) = None)[source]

Bases: coalib.results.TextPosition.TextPosition

position
coalib.results.AbsolutePosition.calc_line_col(text, position)[source]

Creates a tuple containing (line, column) by calculating line number and column in the text, from position.

The position represents the index of a character. In the following example ‘a’ is at position ‘0’ and it’s corresponding line and column are:

>>> calc_line_col(('a\n',), 0)
(1, 1)

All special characters(including the newline character) belong in the same line, and have their own position. A line is an item in the tuple:

>>> calc_line_col(('a\n', 'b\n'), 1)
(1, 2)
>>> calc_line_col(('a\n', 'b\n'), 2)
(2, 1)
Parameters:
  • text – A tuple/list of lines in which position is to be calculated.
  • position – Position (starting from 0) of character to be found in the (line, column) form.
Returns:

A tuple of the form (line, column), where both line and column start from 1.

coalib.results.Diff module

class coalib.results.Diff.Diff(file_list, rename=False, delete=False)[source]

Bases: object

A Diff result represents a difference for one file.

add_line(line_nr_before, line)[source]

Adds line after the given line number.

Parameters:
  • line_nr_before – Line number of the line before the addition. Use 0 to insert line before everything.
  • line – Line to add.
add_lines(line_nr_before, lines)[source]

Adds lines after the given line number.

Parameters:
  • line_nr_before – Line number of the line before the additions. Use 0 for insert lines before everything.
  • lines – A list of lines to add.
affected_code(filename)[source]

Creates a list of SourceRange objects which point to the related code. Changes on continuous lines will be put into one SourceRange.

Parameters:filename – The filename to associate the SourceRange’s to.
Returns:A list of all related SourceRange objects.
change_line(line_nr, original_line, replacement)[source]
delete
Returns:True if file is set to be deleted.
delete_line(line_nr)[source]

Mark the given line nr as deleted. The first line is line number 1.

Raises an exception if line number doesn’t exist in the diff.

delete_lines(line_nr_start, line_nr_end)[source]

Delete lines in a specified range, inclusively.

The range must be valid, i.e. lines must exist in diff, else an exception is raised.

classmethod from_string_arrays(file_array_1, file_array_2, rename=False)[source]

Creates a Diff object from two arrays containing strings.

If this Diff is applied to the original array, the second array will be created.

Parameters:
  • file_array_1 – Original array
  • file_array_2 – Array to compare
  • rename – False or str containing new name of file.
classmethod from_unified_diff(unified_diff, original_file)[source]

Creates a Diff object from given unified diff.

If the provided unified diff does not contain any patch, the Diff object initialized from the original file is returned.

Parameters:
  • unified_diff – Unified diff string.
  • original_file – The contents of the original file (line-splitted).
Raises:

RuntimeError – Raised when the context lines or the lines to be removed do not match in the original file and the unified diff.

insert(position, text)[source]

Inserts (multiline) text at arbitrary position.

>>> from coalib.results.TextPosition import TextPosition
>>> test_text = ['123\n', '456\n', '789\n']
>>> def insert(position, text):
...     diff = Diff(test_text)
...     diff.insert(position, text)
...     return diff.modified
>>> insert(TextPosition(2, 3), 'woopy doopy')
['123\n', '45woopy doopy6\n', '789\n']
>>> insert(TextPosition(1, 1), 'woopy\ndoopy')
['woopy\n', 'doopy123\n', '456\n', '789\n']
>>> insert(TextPosition(2, 4), '\nwoopy\ndoopy\n')
['123\n', '456\n', 'woopy\n', 'doopy\n', '\n', '789\n']
Parameters:
  • position – The TextPosition where to insert text.
  • text – The text to insert.
modified

Calculates the modified file, after applying the Diff to the original.

This property also adds linebreaks at the end of each line. If no newline was present at the end of file before, this state will be preserved, except if the last line is deleted.

modify_line(line_nr, replacement)[source]

Changes the given line with the given line number. The replacement will be there instead.

Given an empty diff object:

>>> diff = Diff(['Hey there! Gorgeous.\n',
...              "It's nice that we're here.\n"])

We can change a line easily:

>>> diff.modify_line(1,
...                  'Hey there! This is sad.\n')
>>> diff.modified
['Hey there! This is sad.\n', "It's nice that we're here.\n"]

We can even merge changes within one line:

>>> diff.modify_line(1,
...                  'Hello. :( Gorgeous.\n')
>>> diff.modified
['Hello. :( This is sad.\n', "It's nice that we're here.\n"]

However, if we change something that has been changed before, we’ll get a conflict:

>>> diff.modify_line(1, 'Hello. This is not ok. Gorgeous.\n')
Traceback (most recent call last):
 ...
coalib.results.LineDiff.ConflictError: ...
original

Retrieves the original file.

range(filename)[source]

Calculates a SourceRange spanning over the whole Diff. If something is added after the 0th line (i.e. before the first line) the first line will be included in the SourceRange.

The range of an empty diff will only affect the filename:

>>> range = Diff([]).range("file")
>>> range.file is None
False
>>> print(range.start.line)
None
Parameters:filename – The filename to associate the SourceRange with.
Returns:A SourceRange object.
remove(range)[source]

Removes a piece of text in a given range.

>>> from coalib.results.TextRange import TextRange
>>> test_text = ['nice\n', 'try\n', 'bro\n']
>>> def remove(range):
...     diff = Diff(test_text)
...     diff.remove(range)
...     return diff.modified
>>> remove(TextRange.from_values(1, 1, 1, 4))
['e\n', 'try\n', 'bro\n']
>>> remove(TextRange.from_values(1, 5, 2, 1))
['nicetry\n', 'bro\n']
>>> remove(TextRange.from_values(1, 3, 3, 2))
['niro\n']
>>> remove(TextRange.from_values(2, 1, 2, 1))
['nice\n', 'try\n', 'bro\n']
Parameters:range – The range to delete.
rename
Returns:string containing new name of the file.
replace(range, replacement)[source]

Replaces a part of text. Allows to span multiple lines.

This function uses add_lines and delete_lines accordingly, so calls of those functions on lines given range affects after usage or vice versa lead to ConflictError.

>>> from coalib.results.TextRange import TextRange
>>> test_text = ['hello\n', 'world\n', '4lines\n', 'done\n']
>>> def replace(range, text):
...     diff = Diff(test_text)
...     diff.replace(range, text)
...     return diff.modified
>>> replace(TextRange.from_values(1, 5, 4, 3), '\nyeah\ncool\nno')
['hell\n', 'yeah\n', 'cool\n', 'none\n']
>>> replace(TextRange.from_values(2, 1, 3, 5), 'b')
['hello\n', 'bes\n', 'done\n']
>>> replace(TextRange.from_values(1, 6, 4, 3), '')
['hellone\n']
Parameters:
  • range – The TextRange that gets replaced.
  • replacement – The replacement string. Can be multiline.
split_diff(distance=1)[source]

Splits this diff into small pieces, such that several continuously altered lines are still together in one diff. All subdiffs will be yielded.

A diff like this with changes being together closely won’t be splitted:

>>> diff = Diff.from_string_arrays([     'b', 'c', 'e'],
...                                ['a', 'b', 'd', 'f'])
>>> len(list(diff.split_diff()))
1

If we set the distance to 0, it will be splitted:

>>> len(list(diff.split_diff(distance=0)))
2

If a negative distance is given, every change will be yielded as an own diff, even if they are right beneath each other:

>>> len(list(diff.split_diff(distance=-1)))
3

If a file gets renamed or deleted only, it will be yielded as is:

>>> len(list(Diff([], rename='test').split_diff()))
1

An empty diff will not yield any diffs:

>>> len(list(Diff([]).split_diff()))
0
Parameters:distance – Number of unchanged lines that are allowed in between two changed lines so they get yielded as one diff.
stats()[source]

Returns tuple containing number of additions and deletions in the diff.

unified_diff

Generates a unified diff corresponding to this patch.

Each change will be displayed on its own line. Additionally, the unified diff preserves the EOF-state of the original file. This means that the Diff will only have a linebreak on the last line, if that was also present in the original file.

Note that the unified diff is not deterministic and thus not suitable for equality comparison.

coalib.results.HiddenResult module

class coalib.results.HiddenResult.HiddenResult(origin, contents, message: str = '', affected_code: (<class 'tuple'>, <class 'list'>) = (), severity: int = 1, additional_info: str = '', debug_msg='', diffs: (<class 'dict'>, None) = None, confidence: int = 100, aspect: (<class 'coalib.bearlib.aspects.base.aspectbase'>, None) = None, message_arguments: dict = {}, applied_actions: dict = {})[source]

Bases: coalib.results.Result.Result

This is a result that is not meant to be shown to the user. It can be used to transfer any data from a dependent bear to others.

coalib.results.LineDiff module

exception coalib.results.LineDiff.ConflictError[source]

Bases: Exception

class coalib.results.LineDiff.LineDiff(change=False, delete=False, add_after=False)[source]

Bases: object

A LineDiff holds the difference between two strings.

add_after
change
delete

coalib.results.RESULT_SEVERITY module

coalib.results.Result module

class coalib.results.Result.Result(origin, message: str, affected_code: (<class 'tuple'>, <class 'list'>) = (), severity: int = 1, additional_info: str = '', debug_msg='', diffs: (<class 'dict'>, None) = None, confidence: int = 100, aspect: (<class 'coalib.bearlib.aspects.base.aspectbase'>, None) = None, message_arguments: dict = {}, applied_actions: dict = {})[source]

Bases: object

A result is anything that has an origin and a message.

Optionally it might affect a file.

Result messages can also have arguments. The message is python style formatted with these arguments.

>>> r = Result('origin','{arg1} and {arg2}',            message_arguments={'arg1': 'foo', 'arg2': 'bar'})
>>> r.message
'foo and bar'

Message arguments may be changed later. The result message will also reflect these changes.

>>> r.message_arguments = {'arg1': 'spam', 'arg2': 'eggs'}
>>> r.message
'spam and eggs'
apply(file_dict: dict)[source]

Applies all contained diffs to the given file_dict. This operation will be done in-place.

Parameters:file_dict – A dictionary containing all files with filename as key and all lines a value. Will be modified.
classmethod from_values(origin, message: str, file: str, line: (<class 'int'>, None) = None, column: (<class 'int'>, None) = None, end_line: (<class 'int'>, None) = None, end_column: (<class 'int'>, None) = None, severity: int = 1, additional_info: str = '', debug_msg='', diffs: (<class 'dict'>, None) = None, confidence: int = 100, aspect: (<class 'coalib.bearlib.aspects.base.aspectbase'>, None) = None, message_arguments: dict = {})[source]

Creates a result with only one SourceRange with the given start and end locations.

Parameters:
  • origin – Class name or creator object of this object.
  • message – Base message to show with this result.
  • message_arguments – Arguments to be provided to the base message
  • file – The related file.
  • line – The first related line in the file. (First line is 1)
  • column – The column indicating the first character. (First character is 1)
  • end_line – The last related line in the file.
  • end_column – The column indicating the last character.
  • severity – Severity of this result.
  • additional_info – A long description holding additional information about the issue and/or how to fix it. You can use this like a manual entry for a category of issues.
  • debug_msg – A message which may help the user find out why this result was yielded.
  • diffs – A dictionary with filename as key and Diff object associated with it as value.
  • confidence – A number between 0 and 100 describing the likelihood of this result being a real issue.
  • aspect – An Aspect object which this result is associated to. Note that this should be a leaf of the aspect tree! (If you have a node, spend some time figuring out which of the leafs exactly your result belongs to.)
get_applied_actions()[source]
location_repr()[source]

Retrieves a string, that briefly represents the affected code of the result.

Returns:A string containing all of the affected files separated by a comma.
message
overlaps(ranges)[source]

Determines if the result overlaps with source ranges provided.

Parameters:ranges – A list SourceRange objects to check for overlap.
Returns:True if the ranges overlap with the result.
set_applied_actions(applied_actions)[source]
to_string_dict()[source]

Makes a dictionary which has all keys and values as strings and contains all the data that the base Result has.

FIXME: diffs are not serialized ATM. FIXME: Only the first SourceRange of affected_code is serialized. If there are more, this data is currently missing.

Returns:Dictionary with keys and values as string.

coalib.results.ResultFilter module

coalib.results.ResultFilter.basics_match(original_result, modified_result)[source]

Checks whether the following properties of two results match: * origin * message * severity * debug_msg

Parameters:
  • original_result – A result of the old files
  • modified_result – A result of the new files
Returns:

Boolean value whether or not the properties match

coalib.results.ResultFilter.ensure_files_present(original_file_dict, modified_file_dict)[source]

Ensures that all files are available as keys in both dicts.

Parameters:
  • original_file_dict – Dict of lists of file contents before changes
  • modified_file_dict – Dict of lists of file contents after changes
Returns:

Return a dictionary of renamed files.

coalib.results.ResultFilter.filter_results(original_file_dict, modified_file_dict, original_results, modified_results)[source]

Filters results for such ones that are unique across file changes

Parameters:
  • original_file_dict – Dict of lists of file contents before changes
  • modified_file_dict – Dict of lists of file contents after changes
  • original_results – List of results of the old files
  • modified_results – List of results of the new files
Returns:

List of results from new files that are unique from all those that existed in the old changes

coalib.results.ResultFilter.remove_range(file_contents, source_range)[source]

removes the chars covered by the sourceRange from the file

Parameters:
  • file_contents – list of lines in the file
  • source_range – Source Range
Returns:

list of file contents without specified chars removed

coalib.results.ResultFilter.remove_result_ranges_diffs(result_list, file_dict)[source]

Calculates the diffs to all files in file_dict that describe the removal of each respective result’s affected code.

Parameters:
  • result_list – list of results
  • file_dict – dict of file contents
Returns:

returnvalue[result][file] is a diff of the changes the removal of this result’s affected code would cause for the file.

coalib.results.ResultFilter.source_ranges_match(original_file_dict, diff_dict, original_result_diff_dict, modified_result_diff_dict, renamed_files)[source]

Checks whether the SourceRanges of two results match

Parameters:
  • original_file_dict – Dict of lists of file contents before changes
  • diff_dict – Dict of diffs describing the changes per file
  • original_result_diff_dict – diff for each file for this result
  • modified_result_diff_dict – guess
  • renamed_files – A dictionary containing file renamings across runs
Returns:

Boolean value whether the SourceRanges match

coalib.results.SourcePosition module

class coalib.results.SourcePosition.SourcePosition(file: str, line=None, column=None)[source]

Bases: coalib.results.TextPosition.TextPosition

file

coalib.results.SourceRange module

class coalib.results.SourceRange.SourceRange(start: coalib.results.SourcePosition.SourcePosition, end: (<class 'coalib.results.SourcePosition.SourcePosition'>, None) = None)[source]

Bases: coalib.results.TextRange.TextRange

affected_source(file_dict: dict)[source]

Tells which lines are affected in a specified file within a given range.

>>> from os.path import abspath
>>> sr = SourceRange.from_values('file_name', start_line=2, end_line=2)
>>> sr.affected_source({
...     abspath('file_name'): ('def fun():\n', '    x = 2  \n')
... })
('    x = 2  \n',)

If more than one line is affected.

>>> sr = SourceRange.from_values('file_name', start_line=2, end_line=3)
>>> sr.affected_source({
...     abspath('file_name'): ('def fun():\n',
...                            '    x = 2  \n', '    print(x)  \n')
... })
('    x = 2  \n', '    print(x)  \n')

If the file indicated at the source range is not in the file_dict or the lines are not given, this will return None:

>>> sr = SourceRange.from_values('file_name_not_present',
...     start_line=2, end_line=2)
>>> sr.affected_source({abspath('file_name'):
...     ('def fun():\n', '    x = 2  \n')})
Parameters:file_dict – It is a dictionary where the file names are the keys and the contents of the files are the values(which is of type tuple).
Returns:A tuple of affected lines in the specified file. If the file is not affected or the file is not present in file_dict return None.
expand(file_contents)[source]

Passes a new SourceRange that covers the same area of a file as this one would. All values of None get replaced with absolute values.

values of None will be interpreted as follows: self.start.line is None: -> 1 self.start.column is None: -> 1 self.end.line is None: -> last line of file self.end.column is None: -> last column of self.end.line

Parameters:file_contents – File contents of the applicable file
Returns:TextRange with absolute values
file
classmethod from_absolute_position(file: str, position_start: coalib.results.AbsolutePosition.AbsolutePosition, position_end: (<class 'coalib.results.AbsolutePosition.AbsolutePosition'>, None) = None)[source]

Creates a SourceRange from a start and end positions.

Parameters:
  • file – Name of the file.
  • position_start – Start of range given by AbsolutePosition.
  • position_end – End of range given by AbsolutePosition or None.
classmethod from_values(file, start_line=None, start_column=None, end_line=None, end_column=None)[source]
overlaps(other)[source]
renamed_file(file_diff_dict: dict)[source]

Retrieves the filename this source range refers to while taking the possible file renamings in the given file_diff_dict into account:

Parameters:file_diff_dict – A dictionary with filenames as key and their associated Diff objects as values.

coalib.results.TextPosition module

class coalib.results.TextPosition.TextPosition(line: (<class 'int'>, None) = None, column: (<class 'int'>, None) = None)[source]

Bases: object

column
line
exception coalib.results.TextPosition.ZeroOffsetError[source]

Bases: ValueError

coalib.results.TextRange module

class coalib.results.TextRange.TextRange(start: coalib.results.TextPosition.TextPosition, end: (<class 'coalib.results.TextPosition.TextPosition'>, None) = None)[source]

Bases: object

end
expand(text_lines)[source]

Passes a new TextRange that covers the same area of a file as this one would. All values of None get replaced with absolute values.

values of None will be interpreted as follows: self.start.line is None: -> 1 self.start.column is None: -> 1 self.end.line is None: -> last line of file self.end.column is None: -> last column of self.end.line

Parameters:text_lines – File contents of the applicable file
Returns:TextRange with absolute values
classmethod from_values(start_line=None, start_column=None, end_line=None, end_column=None)[source]

Creates a new TextRange.

Parameters:
  • start_line – The line number of the start position. The first line is 1.
  • start_column – The column number of the start position. The first column is 1.
  • end_line – The line number of the end position. If this parameter is None, then the end position is set the same like start position and end_column gets ignored.
  • end_column – The column number of the end position.
Returns:

A TextRange.

classmethod join(a, b)[source]

Creates a new TextRange that covers the area of two overlapping ones

Parameters:
  • a – TextRange (needs to overlap b)
  • b – TextRange (needs to overlap a)
Returns:

A new TextRange covering the union of the Area of a and b

overlaps(other)[source]
start

Module contents