Repository navigation
Expand file tree
/
Copy pathutils.py
More file actions
129 lines (85 loc) · 3.6 KB
/
Copy pathutils.py
File metadata and controls
129 lines (85 loc) · 3.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
"""Общие функции ввода/вывода."""
from __future__ import annotations
from pathlib import Path
from openpyxl import Workbook, load_workbook
from models import CrossReferenceRecord
EXCEL_HEADERS = [
"Бренд Noitech",
"Артикул Noitech",
"Бренд Аналога",
"Артикул Аналога",
]
ARTICLE_COLUMN = "Артикул Аналога"
BRAND_COLUMN = "Бренд Аналога"
DEFAULT_SOURCE_BRAND = "Noitech"
def _normalize_article(value: object) -> str:
"""Приводит артикул из Excel к строке без лишних символов.
Числа вида 93621514 превращаются в "93621514",
числа с плавающей точкой 9056011.0 — в "9056011",
строки "LE 10002" — в "LE 10002".
"""
if value is None:
return ""
text = str(value).strip()
if text.endswith(".0"):
text = text[:-2]
return text
def load_articles(filename: str | Path) -> list[str]:
"""Загружает список артикулов из текстового файла."""
with open(filename, "r", encoding="utf-8") as file:
return [
line.strip()
for line in file
if line.strip()
]
def _load_input_excel(filename: str | Path) -> list[tuple[str, str]]:
"""Читает пары (бренд, артикул) из Excel-файла.
Ожидаются заголовки «Артикул Аналога» и «Бренд Аналога».
Пропускаются пустые артикулы.
"""
workbook = load_workbook(filename, read_only=True, data_only=True)
sheet = workbook.active
records: list[tuple[str, str]] = []
for index, row in enumerate(sheet.iter_rows(values_only=True), start=1):
if index == 1:
continue # строка заголовков
article = _normalize_article(row[0])
brand = str(row[1]).strip() if row[1] is not None else ""
if not article:
continue
records.append((brand or DEFAULT_SOURCE_BRAND, article))
workbook.close()
return records
def load_input_records(filename: str | Path) -> list[tuple[str, str]]:
"""Загружает пары (бренд, артикул) для поиска.
- Для .xlsx читает столбцы «Артикул Аналога» и «Бренд Аналога».
- Для текстовых файлов возвращает пары (Noitech, артикул).
"""
path = Path(filename)
if path.suffix.lower() == ".xlsx":
return _load_input_excel(path)
return [(DEFAULT_SOURCE_BRAND, article) for article in load_articles(path)]
def save_to_excel(data: list[CrossReferenceRecord], filename: str | Path) -> None:
"""Сохраняет найденные аналоги в Excel (без дубликатов)."""
workbook = Workbook()
sheet = workbook.active
sheet.title = "Cross Reference"
sheet.append(EXCEL_HEADERS)
seen: set[tuple[str, str, str, str]] = set()
for record in data:
row = record.as_row()
if row not in seen:
seen.add(row)
sheet.append(row)
workbook.save(filename)
def save_errors(
errors: list[tuple[str, str]],
filename: str | Path,
) -> None:
"""Сохраняет список ошибок."""
with open(filename, "w", encoding="utf-8") as file:
if not errors:
file.write("Ошибок нет.\n")
return
for article, message in errors:
file.write(f"{article} - {message}\n")