Skip to content

Commit 826e9bb

Browse files
committed
step7
1 parent c8d2a62 commit 826e9bb

File tree

9 files changed

+339
-61
lines changed

9 files changed

+339
-61
lines changed

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,4 +80,6 @@ The project uses GitHub Actions for automated testing and linting. You can see s
8080

8181
[![asciicast](https://asciinema.org/a/Pe196IZV1YWZEZojjxIbKHeU8.svg)](https://asciinema.org/a/Pe196IZV1YWZEZojjxIbKHeU8)
8282

83-
[![asciicast](https://asciinema.org/a/Hc7xhdtxCYwpHkDT0RCYTOhJ9.svg)](https://asciinema.org/a/Hc7xhdtxCYwpHkDT0RCYTOhJ9)
83+
[![asciicast](https://asciinema.org/a/Hc7xhdtxCYwpHkDT0RCYTOhJ9.svg)](https://asciinema.org/a/Hc7xhdtxCYwpHkDT0RCYTOhJ9)
84+
85+
[![asciicast](https://asciinema.org/a/W3OLlaIN5eQ1MMhkHUFwjiR6M.svg)](https://asciinema.org/a/W3OLlaIN5eQ1MMhkHUFwjiR6M)

demo3.cast

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
{"version": 2, "width": 192, "height": 15, "timestamp": 1741780328, "env": {"SHELL": "/bin/bash", "TERM": "xterm-256color"}}
2+
[3.47823, "o", "\u001b]0;nurzhan@localhost:~/Desktop/python-project-50\u0007"]
3+
[3.568615, "o", "[nurzhan@localhost python-project-50]$ "]
4+
[8.424893, "o", "gendiff gendiff/tests/file1.yaml gendiff/tests/file2.yaml"]
5+
[8.849617, "o", "\r\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[Cexit\u001b[K"]
6+
[9.310889, "o", "\b\b\b\bgendiff file1.yaml file2.yaml"]
7+
[10.222548, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[17Pmake install"]
8+
[12.834095, "o", "\b\b\b\b\b\b\b\b\b\b\b\bgendiff file1.yaml file2.yaml"]
9+
[15.729997, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[17Pmake install"]
10+
[15.996626, "o", "\b\b\b\b\b\b\b\b\b\b\b\bgendiff file1.yaml file2.yaml"]
11+
[16.884771, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[17Pmake install"]
12+
[17.068114, "o", "\b\b\b\b\b\b\b\b\b\b\b\bgendiff file1.yaml file2.yaml"]
13+
[17.253045, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\bexit\u001b[K"]
14+
[17.769981, "o", "\b\b\b\bgendiff gendiff/tests/file1.yaml gendiff/tests/file2.yaml"]
15+
[21.647681, "o", "\r\n"]
16+
[21.733744, "o", "{\r\n common: {\r\n + follow: false\r\n setting1: Value 1\r\n - setting2: 200\r\n - setting3: true\r\n + setting3: null\r\n + setting4: blah blah\r\n + setting5: {\r\n key5: value5\r\n }\r\n setting6: {\r\n doge: {\r\n - wow: \r\n + wow: so much\r\n }\r\n key: value\r\n + ops: vops\r\n }\r\n }\r\n group1: {\r\n - baz: bas\r\n + baz: bars\r\n foo: bar\r\n - nest: {\r\n key: value\r\n }\r\n + nest: str\r\n }\r\n - group2: {\r\n abc: 12345\r\n deep: {\r\n id: 45\r\n }\r\n }\r\n + group3: {\r\n deep: {\r\n id: {\r\n number: 45\r\n }\r\n }\r\n fee: 100500\r\n }\r\n}\r\nNone\r\n"]
17+
[21.7389, "o", "\u001b]0;nurzhan@localhost:~/Desktop/python-project-50\u0007[nurzhan@localhost python-project-50]$ "]
18+
[23.366386, "o", "gendiff gendiff/tests/file1.yaml gendiff/tests/file2.yaml"]
19+
[24.436943, "o", "\b"]
20+
[24.938548, "o", "\b"]
21+
[24.967969, "o", "\b"]
22+
[25.008874, "o", "\b"]
23+
[25.036755, "o", "\b"]
24+
[25.064186, "o", "\b"]
25+
[25.093036, "o", "\b"]
26+
[25.125074, "o", "\b"]
27+
[25.160087, "o", "\b"]
28+
[25.187289, "o", "\b"]
29+
[25.221381, "o", "\b"]
30+
[25.251318, "o", "\b"]
31+
[25.284844, "o", "\b"]
32+
[25.309205, "o", "\b"]
33+
[25.340176, "o", "\b"]
34+
[25.367074, "o", "\b"]
35+
[25.397324, "o", "\b"]
36+
[25.434682, "o", "\b"]
37+
[25.468296, "o", "\b"]
38+
[25.504362, "o", "\b"]
39+
[25.521678, "o", "\b"]
40+
[25.561856, "o", "\b"]
41+
[25.582103, "o", "\b"]
42+
[25.738938, "o", "\b"]
43+
[25.888035, "o", "\b"]
44+
[26.536587, "o", "\b\u001b[1P gendiff/tests/file2.yaml\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
45+
[26.673095, "o", "\b\u001b[1P gendiff/tests/file2.yaml\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
46+
[26.756587, "o", "\b\u001b[1P gendiff/tests/file2.yaml\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
47+
[27.080531, "o", "\b\u001b[1P gendiff/tests/file2.yaml\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
48+
[27.719043, "o", "j gendiff/tests/file2.yaml\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
49+
[28.07815, "o", "s gendiff/tests/file2.yaml\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
50+
[28.308081, "o", "o gendiff/tests/file2.yaml\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
51+
[28.63157, "o", "n gendiff/tests/file2.yaml\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"]
52+
[29.628122, "o", "\u001b[C"]
53+
[30.128778, "o", "\u001b[C"]
54+
[30.159195, "o", "\u001b[C"]
55+
[30.198309, "o", "\u001b[C"]
56+
[30.220587, "o", "\u001b[C"]
57+
[30.252925, "o", "\u001b[C"]
58+
[30.381706, "o", "\u001b[C"]
59+
[30.383397, "o", "\u001b[C"]
60+
[30.384559, "o", "\u001b[C"]
61+
[30.385684, "o", "\u001b[C"]
62+
[30.41638, "o", "\u001b[C"]
63+
[30.429516, "o", "\u001b[C"]
64+
[30.466543, "o", "\u001b[C"]
65+
[30.49559, "o", "\u001b[C"]
66+
[30.519316, "o", "\u001b[C"]
67+
[30.550746, "o", "\u001b[C"]
68+
[30.58523, "o", "\u001b[C"]
69+
[30.618192, "o", "\u001b[C"]
70+
[30.646204, "o", "\u001b[C"]
71+
[30.673276, "o", "\u001b[C"]
72+
[30.701229, "o", "\u001b[C"]
73+
[30.734937, "o", "\u001b[C"]
74+
[30.873867, "o", "\u001b[C"]
75+
[31.042638, "o", "\u001b[C"]
76+
[31.309449, "o", "\u001b[C"]
77+
[31.784886, "o", "\b\u001b[K"]
78+
[32.013098, "o", "\b\u001b[K"]
79+
[32.10693, "o", "\b\u001b[K"]
80+
[32.307099, "o", "\b\u001b[K"]
81+
[34.026058, "o", "j"]
82+
[34.277854, "o", "s"]
83+
[34.544279, "o", "o"]
84+
[34.778731, "o", "n"]
85+
[35.612398, "o", "\r\n"]
86+
[35.757652, "o", "{\r\n common: {\r\n + follow: false\r\n setting1: Value 1\r\n - setting2: 200\r\n - setting3: true\r\n + setting3: null\r\n + setting4: blah blah\r\n + setting5: {\r\n key5: value5\r\n }\r\n setting6: {\r\n doge: {\r\n - wow: \r\n + wow: so much\r\n }\r\n key: value\r\n + ops: vops\r\n }\r\n }\r\n group1: {\r\n - baz: bas\r\n + baz: bars\r\n foo: bar\r\n - nest: {\r\n key: value\r\n }\r\n + nest: str\r\n }\r\n - group2: {\r\n abc: 12345\r\n deep: {\r\n id: 45\r\n }\r\n }\r\n + group3: {\r\n deep: {\r\n id: {\r\n number: 45\r\n }\r\n }\r\n fee: 100500\r\n }\r\n}\r\nNone\r\n"]
87+
[35.765436, "o", "\u001b]0;nurzhan@localhost:~/Desktop/python-project-50\u0007"]
88+
[35.76551, "o", "[nurzhan@localhost python-project-50]$ "]
89+
[37.486524, "o", "gendiff gendiff/tests/file1.json gendiff/tests/file2.json"]
90+
[38.483804, "o", "\r\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[K"]
91+
[39.111932, "o", "gendiff gendiff/tests/file1.json gendiff/tests/file2.json"]
92+
[39.328918, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\byaml gendiff/tests/file2.yaml"]
93+
[39.844355, "o", "\r\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[Cexit\u001b[K"]
94+
[40.251797, "o", "\b\b\b\bgendiff file1.yaml file2.yaml"]
95+
[40.461118, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[17Pmake install"]
96+
[41.048146, "o", "\b\b\b\b\b\b\b\b\b\b\b\bgendiff file1.yaml file2.yaml"]
97+
[41.642793, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\bjson file2.json"]
98+
[41.910224, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\byaml file2.yaml"]
99+
[42.294957, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\bjson file2.json"]
100+
[42.678952, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[12Pcd gendiff/tests/"]
101+
[43.144105, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[5Pmake install"]
102+
[43.521867, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\u001b[7Pcd .."]
103+
[44.029385, "o", "\b\b\b\b\bmake install"]
104+
[44.261455, "o", "\b\b\b\b\b\b\b\b\b\b\b\bcd gendiff/tests/"]
105+
[44.412371, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\bgendiff file1.json file2.json"]
106+
[44.562589, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\byaml file2.yaml"]
107+
[44.712114, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\bjson file2.json"]
108+
[44.84907, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\byaml file2.yaml"]
109+
[44.979851, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\u001b[17Pmake install"]
110+
[45.113041, "o", "\b\b\b\b\b\b\b\b\b\b\b\bgendiff file1.yaml file2.yaml"]
111+
[45.245769, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\bexit\u001b[K"]
112+
[45.379866, "o", "\b\b\b\bgendiff gendiff/tests/file1.yaml gendiff/tests/file2.yaml"]
113+
[45.513205, "o", "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\bjson gendiff/tests/file2.json"]
114+
[45.895909, "o", "\r\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[C\u001b[K"]
115+
[48.837129, "o", "exit\r\n"]

gendiff/diff_generator.py

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,40 @@
11
from gendiff.read import read_file
22

33

4-
def format_diff(key, value, status):
5-
symbols = {'added': '+', 'removed': '-', 'unchanged': ' '}
6-
return f" {symbols[status]} {key}: {value}"
7-
8-
9-
def generate_diff(file_path1, file_path2):
10-
data1 = read_file(file_path1)
11-
data2 = read_file(file_path2)
12-
4+
def build_diff(data1, data2):
135
keys = sorted(set(data1.keys()) | set(data2.keys()))
14-
diff = []
6+
diff = {}
157

168
for key in keys:
179
if key not in data1:
18-
diff.append(format_diff(key, data2[key], 'added'))
10+
diff[key] = {"status": "added", "value": data2[key]}
1911
elif key not in data2:
20-
diff.append(format_diff(key, data1[key], 'removed'))
12+
diff[key] = {"status": "removed", "value": data1[key]}
13+
elif isinstance(data1[key], dict) and isinstance(data2[key], dict):
14+
diff[key] = {
15+
"status": "nested",
16+
"children": build_diff(
17+
data1[key],
18+
data2[key])}
2119
elif data1[key] == data2[key]:
22-
diff.append(format_diff(key, data1[key], 'unchanged'))
20+
diff[key] = {"status": "unchanged", "value": data1[key]}
2321
else:
24-
diff.append(format_diff(key, data1[key], 'removed'))
25-
diff.append(format_diff(key, data2[key], 'added'))
22+
diff[key] = {
23+
"status": "modified",
24+
"old_value": data1[key],
25+
"new_value": data2[key]}
26+
27+
return diff
28+
29+
30+
def generate_diff(file_path1, file_path2, format_name="stylish"):
31+
data1 = read_file(file_path1)
32+
data2 = read_file(file_path2)
33+
34+
diff = build_diff(data1, data2)
35+
36+
if format_name == "stylish":
37+
from gendiff.formaters.stylish import format_stylish
38+
return format_stylish(diff)
2639

27-
return "{\n" + "\n".join(diff) + "\n}"
40+
raise ValueError(f"Unsupported format: {format_name}")

gendiff/formaters/stylish.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
def format_value(value, depth):
2+
indent = " " * (depth * 4)
3+
4+
if isinstance(value, dict):
5+
formatted = ["{"]
6+
for k, v in value.items():
7+
formatted.append(f"{indent} {k}: {format_value(v, depth + 1)}")
8+
formatted.append(f"{indent}}}")
9+
return "\n".join(formatted)
10+
11+
if value is True:
12+
return "true"
13+
if value is False:
14+
return "false"
15+
if value is None:
16+
return "null"
17+
18+
return value
19+
20+
21+
def format_stylish(diff, depth=0):
22+
indent = " " * (depth * 4)
23+
lines = ["{"]
24+
25+
for key, info in diff.items():
26+
status = info["status"]
27+
28+
if status == "nested":
29+
children = format_stylish(info["children"], depth + 1)
30+
lines.append(f"{indent} {key}: {children}")
31+
elif status == "added":
32+
lines.append(
33+
f"{indent} + {key}: {format_value(info['value'], depth + 1)}"
34+
)
35+
elif status == "removed":
36+
lines.append(
37+
f"{indent} - {key}: {format_value(info['value'], depth + 1)}"
38+
)
39+
elif status == "modified":
40+
lines.append(
41+
f"{indent} - {key}:"
42+
f" {format_value(info['old_value'], depth + 1)}"
43+
)
44+
lines.append(
45+
f"{indent} + {key}:"
46+
f"{format_value(info['new_value'], depth + 1)}"
47+
)
48+
else: # unchanged
49+
lines.append(
50+
f"{indent} {key}: {format_value(info['value'], depth + 1)}"
51+
)
52+
53+
lines.append(indent + "}")
54+
return "\n".join(lines)

gendiff/tests/diff_generator_test.py

Lines changed: 45 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,32 +2,52 @@
22
from gendiff.diff_generator import generate_diff
33

44

5-
def normalize_indentation(text):
6-
return "\n".join(line.strip() for line in text.strip().splitlines())
7-
8-
95
@pytest.mark.parametrize("file1, file2, expected_result", [
106
("gendiff/tests/file1.json", "gendiff/tests/file2.json", """{
11-
- follow: False
12-
host: hexlet.io
13-
- proxy: 123.124.53.22
14-
- timeout: 50
15-
+ timeout: 20
16-
+ verbose: True
17-
}"""),
18-
("gendiff/tests/file1.yaml", "gendiff/tests/file2.yaml", """{
19-
- follow: False
20-
host: hexlet.io
21-
- proxy: 123.124.53.22
22-
- timeout: 50
23-
+ timeout: 20
24-
+ verbose: True
25-
}"""),
7+
common: {
8+
+ follow: false
9+
setting1: Value 1
10+
- setting2: 200
11+
- setting3: true
12+
+ setting3: null
13+
+ setting4: blah blah
14+
+ setting5: {
15+
key5: value5
16+
}
17+
setting6: {
18+
doge: {
19+
- wow:
20+
+ wow: so much
21+
}
22+
key: value
23+
+ ops: vops
24+
}
25+
}
26+
group1: {
27+
- baz: bas
28+
+ baz: bars
29+
foo: bar
30+
- nest: {
31+
key: value
32+
}
33+
+ nest: str
34+
}
35+
- group2: {
36+
abc: 12345
37+
deep: {
38+
id: 45
39+
}
40+
}
41+
+ group3: {
42+
deep: {
43+
id: {
44+
number: 45
45+
}
46+
}
47+
fee: 100500
48+
}
49+
}""")
2650
])
2751
def test_generate_diff(file1, file2, expected_result):
28-
actual_result = generate_diff(file1, file2)
29-
30-
normalized_expected = normalize_indentation(expected_result)
31-
normalized_actual = normalize_indentation(actual_result)
32-
33-
assert normalized_actual == normalized_expected
52+
actual_result = generate_diff(file1, file2, format_name="stylish")
53+
assert actual_result.strip() == expected_result.strip()

gendiff/tests/file1.json

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,26 @@
11
{
2-
"host": "hexlet.io",
3-
"timeout": 50,
4-
"proxy": "123.124.53.22",
5-
"follow": false
6-
7-
}
2+
"common": {
3+
"setting1": "Value 1",
4+
"setting2": 200,
5+
"setting3": true,
6+
"setting6": {
7+
"key": "value",
8+
"doge": {
9+
"wow": ""
10+
}
11+
}
12+
},
13+
"group1": {
14+
"baz": "bas",
15+
"foo": "bar",
16+
"nest": {
17+
"key": "value"
18+
}
19+
},
20+
"group2": {
21+
"abc": 12345,
22+
"deep": {
23+
"id": 45
24+
}
25+
}
26+
}

gendiff/tests/file1.yaml

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
1-
# file1.yaml
2-
follow: false
3-
host: hexlet.io
4-
proxy: 123.124.53.22
5-
timeout: 50
1+
common:
2+
setting1: Value 1
3+
setting2: 200
4+
setting3: true
5+
setting6:
6+
key: value
7+
doge:
8+
wow: ""
9+
group1:
10+
baz: bas
11+
foo: bar
12+
nest:
13+
key: value
14+
group2:
15+
abc: 12345
16+
deep:
17+
id: 45

0 commit comments

Comments
 (0)