Skip to content

Commit 8c6003f

Browse files
committed
add: eighth step, format plain
1 parent 23d471c commit 8c6003f

File tree

7 files changed

+213
-144
lines changed

7 files changed

+213
-144
lines changed

gendiff/gendiff.py

Lines changed: 45 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
import yaml
44

55
from gendiff.cli import parse_args
6-
from gendiff.views import make_str_from_list
6+
from gendiff.views.plain import format_output_plain
7+
from gendiff.views.stylish import format_output_stylish
78

89

910
def read_file(path: str):
@@ -25,57 +26,56 @@ def read_file(path: str):
2526
return None
2627

2728

28-
def sort_list(items: list):
29-
def sort_by_rule(item: dict) -> tuple:
30-
"""The sign -> digit for correctly sort items with the same key."""
31-
sign_order = {'-': 0, '+': 1, ' ': 2}
32-
return (item['key'], sign_order[item['sign']])
33-
items.sort(key=sort_by_rule)
34-
return items
35-
36-
37-
def get_list_of_dict(data1, data2) -> list:
29+
def get_diff(data1, data2) -> list:
3830
if data1 == data2:
3931
return data1
40-
result = [
41-
{
42-
'key': key,
43-
'sign': ' ',
44-
'value': get_list_of_dict(value, data2[key])
45-
}
46-
if key in data2 and (
47-
(value == data2[key]) or
48-
(value != data2[key]) and
49-
(isinstance(value, dict) and isinstance(data2[key], dict))
50-
)
51-
else {
52-
'key': key,
53-
'sign': '-',
54-
'value': value
55-
}
56-
for key, value in data1.items()
57-
]
58-
result.extend([
59-
{
60-
'key': key,
61-
'sign': '+',
62-
'value': value
63-
}
64-
for key, value in data2.items()
65-
if (
66-
(key not in data1) or
67-
(key in data1 and value != data1[key]) and
68-
(not isinstance(value, dict) or not isinstance(data2[key], dict))
69-
)
70-
])
71-
return sort_list(result)
32+
diff = []
33+
keys = sorted(set(data1.keys()) | set(data2.keys()))
34+
for key in keys:
35+
if key not in data2:
36+
diff.append({
37+
'key': key,
38+
'status': 'removed',
39+
'value': data1[key],
40+
})
41+
elif key not in data1:
42+
diff.append({
43+
'key': key,
44+
'status': 'added',
45+
'value': data2[key],
46+
})
47+
elif data1[key] == data2[key]:
48+
diff.append({
49+
'key': key,
50+
'status': 'unchanged',
51+
'value': data1[key],
52+
})
53+
elif isinstance(data1[key], dict) and isinstance(data2[key], dict):
54+
diff.append({
55+
'key': key,
56+
'status': 'nested',
57+
'value': get_diff(data1[key], data2[key]),
58+
})
59+
else:
60+
diff.append({
61+
'key': key,
62+
'status': 'changed',
63+
'value': data1[key],
64+
'new_value': data2[key],
65+
})
66+
67+
diff.sort(key=lambda item: item['key'])
68+
return diff
7269

7370

7471
def generate_diff(path1, path2, format_name='stylish') -> str:
7572
dict_data1 = read_file(path1)
7673
dict_data2 = read_file(path2)
77-
sorted_list_of_dict = get_list_of_dict(dict_data1, dict_data2)
78-
return make_str_from_list(sorted_list_of_dict, format_name)
74+
sorted_diff = get_diff(dict_data1, dict_data2)
75+
if format_name == 'stylish':
76+
return format_output_stylish(sorted_diff)
77+
elif format_name == 'plain':
78+
return format_output_plain(sorted_diff)
7979

8080

8181
def main() -> None:

gendiff/views.py

Lines changed: 0 additions & 51 deletions
This file was deleted.

gendiff/views/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from gendiff.views.stylish import format_output_stylish
2+
3+
__all__ = [
4+
'format_output_stylish'
5+
]

gendiff/views/plain.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import json
2+
3+
4+
def get_value(value):
5+
if isinstance(value, (dict, list)):
6+
value = "[complex value]"
7+
elif isinstance(value, str):
8+
value = f"'{value}'"
9+
else:
10+
value = json.dumps(value)
11+
return value
12+
13+
14+
def format_output_plain(diff: list, accum=None, result=None):
15+
if result is None:
16+
result = []
17+
if accum is None:
18+
accum = ["Property '"]
19+
for item in diff:
20+
value = get_value(item['value'])
21+
22+
match item['status']:
23+
case 'unchanged':
24+
continue
25+
case 'nested':
26+
accum.append(f"{item['key']}.")
27+
format_output_plain(item['value'], accum, result)
28+
case 'removed':
29+
accum.append(f"{item['key']}' was removed")
30+
result.append(''.join(accum))
31+
case 'added':
32+
accum.append(f"{item['key']}' was added with value: {value}")
33+
result.append(''.join(accum))
34+
case 'changed':
35+
new_value = get_value(item['new_value'])
36+
accum.append(
37+
f"{item['key']}' was updated. From {value} to {new_value}"
38+
)
39+
result.append(''.join(accum))
40+
accum.pop()
41+
42+
return '\n'.join(result)

gendiff/views/stylish.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import json
2+
3+
4+
def make_str_from_dict(items: dict, indent=0) -> str:
5+
indent_str = ' ' * indent
6+
list_of_str = ['{']
7+
for key, value in items.items():
8+
if not isinstance(key, str):
9+
key = json.dumps(key)
10+
11+
if isinstance(value, dict):
12+
value = make_str_from_dict(value, indent + 4)
13+
14+
if not isinstance(value, str):
15+
value = json.dumps(value)
16+
17+
list_of_str.append(f"{indent_str} {key}: {value}")
18+
list_of_str.append(f"{indent_str}}}")
19+
return '\n'.join(list_of_str)
20+
21+
22+
def get_key(item_key):
23+
if isinstance(item_key, str):
24+
key = item_key
25+
else:
26+
key = json.dumps(item_key)
27+
return key
28+
29+
30+
def get_value(value, status, indent):
31+
if status == 'nested':
32+
result = format_output_stylish(value, indent + 4)
33+
elif isinstance(value, dict):
34+
result = make_str_from_dict(value, indent + 4)
35+
elif isinstance(value, str):
36+
result = value
37+
else:
38+
result = json.dumps(value)
39+
return result
40+
41+
42+
def format_output_stylish(diff: list, indent=0) -> str:
43+
"""
44+
Type checking for the output of strings without quotes,
45+
and for the correct output of True, False in the form of true, false.
46+
Doesn't matter for .yaml.
47+
"""
48+
indent_str = ' ' * indent
49+
sign = {
50+
'removed': '-',
51+
'added': '+',
52+
'unchanged': ' ',
53+
'nested': ' ',
54+
'changed': '-',
55+
}
56+
list_of_str = ['{']
57+
for item in diff:
58+
status = item['status']
59+
key = get_key(item['key'])
60+
value = get_value(item['value'], status, indent)
61+
list_of_str.append(f"{indent_str} {sign[status]} {key}: {value}")
62+
if status == 'changed':
63+
new_value = get_value(item['new_value'], status, indent)
64+
list_of_str.append(
65+
f"{indent_str} {sign['added']} {key}: {new_value}"
66+
)
67+
68+
list_of_str.append(f"{indent_str}}}")
69+
return '\n'.join(list_of_str)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
Property 'common.follow' was added with value: false
2+
Property 'common.setting2' was removed
3+
Property 'common.setting3' was updated. From true to null
4+
Property 'common.setting4' was added with value: 'blah blah'
5+
Property 'common.setting5' was added with value: [complex value]
6+
Property 'common.setting6.doge.wow' was updated. From '' to 'so much'
7+
Property 'common.setting6.ops' was added with value: 'vops'
8+
Property 'group1.baz' was updated. From 'bas' to 'bars'
9+
Property 'group1.nest' was updated. From [complex value] to 'str'
10+
Property 'group2' was removed
11+
Property 'group3' was added with value: [complex value]

0 commit comments

Comments
 (0)