Skip to content

Commit

Permalink
refactoring formats -> formatters, add documentation of functions
Browse files Browse the repository at this point in the history
  • Loading branch information
AntiViruS90 committed Sep 1, 2024
1 parent 7224e01 commit 024b5f8
Show file tree
Hide file tree
Showing 17 changed files with 315 additions and 173 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ dist/
__pycache__
.idea/
gendiff/scripts/__pycache__
gendiff/formats/__pycache__
gendiff/formatters/__pycache__
.coverage
cc-test-reporter
coverage.xml
Expand Down
33 changes: 21 additions & 12 deletions gendiff/cli.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,25 @@
import argparse

parser = argparse.ArgumentParser(
usage="gendiff [-h] [-f FORMAT] first_file second_file",
description="Compares two configuration files and shows a difference"
)

parser.add_argument("first_file")
parser.add_argument("second_file")
parser.add_argument(
'-f', '--format',
default="stylish",
help="set format of output"
)
def argparse_func():
"""
Parses command line arguments for the gendiff utility
:return: argparse.Namespace: An object that stores the command-line arguments
parsed by argparse
"""
parser = argparse.ArgumentParser(
usage="gendiff [-h] [-f FORMAT] first_file second_file",
description="Compares two configuration files and shows a difference"
)

args = parser.parse_args()
parser.add_argument("first_file")
parser.add_argument("second_file")
parser.add_argument(
'-f', '--format',
default="stylish",
help="set format of output"
)

args = parser.parse_args()

return args
Empty file removed gendiff/formats/__init__.py
Empty file.
15 changes: 0 additions & 15 deletions gendiff/formats/select_format.py

This file was deleted.

39 changes: 0 additions & 39 deletions gendiff/formats/stylish.py

This file was deleted.

22 changes: 22 additions & 0 deletions gendiff/formatters/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from gendiff.formatters.plain import plain_format
from gendiff.formatters.stylish import default_format
from gendiff.formatters.json import json_format


def select_format(output_format):
"""
Selects and returns a specific formatting function based
on the given output format
:param output_format: (str) The output format to select. Valid values
are 'stulish', 'plain', or 'json'
:return: (func) The formatting function corresponding to the output format
"""

if output_format == 'stylish':
return default_format

elif output_format == 'plain':
return plain_format

elif output_format == 'json':
return json_format
File renamed without changes.
20 changes: 20 additions & 0 deletions gendiff/formats/plain.py → gendiff/formatters/plain.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@ def complex_or_string(value):


def disassemble(list_of_diff):
"""
Iterates over a list of differences and disassembles them into a flat
list of lists containing information about the changes.
:param list_of_diff: (list) A list containing dictionaries representing
differences between objects.
:return: (list) A flat list containing information about changes in a
formatted way.
"""
def iter_(keys, path=''):
lines = []

Expand Down Expand Up @@ -49,12 +57,24 @@ def iter_(keys, path=''):


def assemble(list_of_keys, n=3):
"""
Divides a list of keys into sublists of size n.
:param list_of_keys: (list) A list of keys to be divided into sublists
:param n: (int) The size of each sublist
:return: (list) A list containing sublists of keys
"""
result = [list_of_keys[i:i + n] for i in range(0, len(list_of_keys), n)]

return result


def plain_format(list_of_diff):
"""
Formats the list of differences into a human-readable plain text format
:param list_of_diff: (list) A list containing dictionaries representing
differences between objects
:return: (str) A formatted plain text representing the differences
"""
disassembled_keys = disassemble(list_of_diff)
assembled_keys = assemble(disassembled_keys)

Expand Down
101 changes: 101 additions & 0 deletions gendiff/formatters/stylish.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import itertools

from gendiff.transform_func import trans_value


def iterate_nested_value(value, spaces_count, replacer=' '):
"""
Recursively iterates over a nested dictionary and formats it into in string
with specified indentation
Args:
:param value: (dict) The nested dictionary to iterate over
:param spaces_count: (int) The initial number of spaces for indentation
:param replacer: (str, optional) The character used for indentation.
Defaults to ' '
:return: (str) The formatted string representation of the nested dictionary
with appropriate indentation
"""
if not isinstance(value, dict):
return trans_value(value)

def iter_(nested_value, spaces_count_1):
lines = []

for key, value in nested_value.items():
if not isinstance(value, dict):
lines.append(
f"{replacer * spaces_count_1}{key}: "
f"{trans_value(value)}"
)
else:
lines.append(
f"{replacer * spaces_count_1}{key}: "
f"{iter_(value, spaces_count_1 + 4)}"
)
result = itertools.chain(
"{", lines, [(replacer * (spaces_count_1 - 4)) + "}"]
)

return '\n'.join(result)

return iter_(value, spaces_count)


def determine_type(type_of_key):
"""
Determine the representation character based on the type of key
:param type_of_key: (str) The type of key ('added', 'deleted' or any other)
:return: (str) The representation character ('+ ', '- ', or ' ')
"""
if type_of_key == 'added':
return '+ '
elif type_of_key == 'deleted':
return '- '
else:
return ' '


def default_format(list_of_diff, replacer=' '):
"""
Generate the default format representation of the list of differences
:param list_of_diff: (list) A list of difference objects.
:param replacer: (str, optional) The character used for indentation.
Defaults to ' '
:return: (str) The formatted representation of the differences
"""
def iter_(current_value, spaces_count):
lines = []

for key in current_value:
if key['type'] == 'nested':
lines.append(
f"{replacer * spaces_count} "
f"{key['key']}: "
f"{iter_(key['children'], spaces_count + 4)}"
)
elif key['type'] == 'updated':
lines.append(
f"{replacer * spaces_count}- "
f"{key['key']}: "
f"{iterate_nested_value(key['value_1'], spaces_count + 6)}"
)
lines.append(
f"{replacer * spaces_count}+ "
f"{key['key']}: "
f"{iterate_nested_value(key['value_2'], spaces_count + 6)}"
)
else:
lines.append(
f"{replacer * spaces_count}{determine_type(key['type'])}"
f"{key['key']}: "
f"{iterate_nested_value(key['value'], spaces_count + 6)}"
)
result = itertools.chain(
"{", lines, [(replacer * (spaces_count - 2)) + "}"]
)

return '\n'.join(result)

return iter_(list_of_diff, 2)
35 changes: 27 additions & 8 deletions gendiff/gen_diff.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,32 @@
from gendiff.generator import generate_list_of_diff
from gendiff.parser import parser, current_format
from gendiff.formats.select_format import select_format
from gendiff.parser import parse_file, get_file_extension
from gendiff.formatters import select_format


def read_and_parse(file):
"""
Read and parse the contents of a file based on its extension
:param file: (str) The path to the file
:return: (dict) Parsed content of the file
"""
file_format = get_file_extension(file)
with open(file, 'r') as data:
return parse_file(data, file_format)


def generate_diff(file_1, file_2, format_='stylish'):
with open(file_1, 'r') as data_1, open(file_2, 'r') as data_2:
parser_data_1 = parser(data_1, current_format(file_1))
parser_data_2 = parser(data_2, current_format(file_2))
output_format = select_format(format_)
diff = generate_list_of_diff(parser_data_1, parser_data_2)
"""
Generate the difference between two files in a specified format
:param file_1: (str) path to the first file
:param file_2: (str) path to the second file
:param format_: (str, optional) The format of the output diff
(default is 'stylish')
:return: (str) The formatted difference between the two files
"""
parser_data_1 = read_and_parse(file_1)
parser_data_2 = read_and_parse(file_2)
diff = generate_list_of_diff(parser_data_1, parser_data_2)

output_format = select_format(format_)

return output_format(diff)
return output_format(diff)
7 changes: 7 additions & 0 deletions gendiff/generator.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
def generate_list_of_diff(data_1, data_2):
"""
Generate the list of differences between two data dictionaries
:param data_1: (dict) First data dictionary
:param data_2: (dict) Second data dictionary
:return: (list) List of dictionaries representing the differences
between the two data dictionaries
"""
def run(curr_data_1, curr_data_2):
result = []

Expand Down
25 changes: 21 additions & 4 deletions gendiff/parser.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,34 @@
import json
import yaml
import os


def current_format(file):
if file[-4:] == 'json':
def get_file_extension(file_path):
"""
Get the file extension from the file path
:param file_path: (str) Path of the file
:return: (str) The file extension in lowercase
"""
_, extension = os.path.splitext(file_path)
extension = extension.lower().lstrip('.')

if extension == 'json':
return 'json'

elif file[-4:] in ['yaml', '.yml']:
elif extension in ['yaml', 'yml']:
return 'yaml'


def parser(data, file_format):
def parse_file(data, file_format):
"""
Parse the file data based on the specified file format
:param data: (object) Data read from the file
:param file_format: (str) Format of the file ('json' or 'yaml')
:return: (object) Parsed data object
"""
if file_format == 'json':
return json.load(data)
elif file_format == 'yaml':
return yaml.load(data, Loader=yaml.FullLoader)
else:
raise ValueError(f"Unsupported file format: {file_format}")
3 changes: 2 additions & 1 deletion gendiff/scripts/gendiff.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
#!/usr/bin/env python3

from gendiff.cli import args
from gendiff.cli import argparse_func
from gendiff.gen_diff import generate_diff


def main():
args = argparse_func()
diff = generate_diff(args.first_file, args.second_file, args.format)

print(diff)
Expand Down
Loading

0 comments on commit 024b5f8

Please sign in to comment.