cannect 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cannect/__init__.py +30 -0
- cannect/api/__init__.py +0 -0
- cannect/config.py +114 -0
- cannect/core/__init__.py +0 -0
- cannect/core/ascet/__init__.py +3 -0
- cannect/core/ascet/amd.py +698 -0
- cannect/core/ascet/formula.py +33 -0
- cannect/core/ascet/oid.py +29 -0
- cannect/core/ascet/ws.py +154 -0
- cannect/core/can/__init__.py +2 -0
- cannect/core/can/ascet/__init__.py +3 -0
- cannect/core/can/ascet/_db2code.py +344 -0
- cannect/core/can/ascet/_db2elem.py +399 -0
- cannect/core/can/ascet/comdef.py +256 -0
- cannect/core/can/ascet/comrx.py +139 -0
- cannect/core/can/ascet/diag.py +691 -0
- cannect/core/can/db/__init__.py +4 -0
- cannect/core/can/db/reader.py +148 -0
- cannect/core/can/db/schema.py +269 -0
- cannect/core/can/db/specification/__init__.py +0 -0
- cannect/core/can/db/specification/message.py +230 -0
- cannect/core/can/db/specification/styles.py +81 -0
- cannect/core/can/db/specification/wrapper.py +161 -0
- cannect/core/can/db/vcs.py +104 -0
- cannect/core/can/rule.py +229 -0
- cannect/core/can/testcase/__init__.py +0 -0
- cannect/core/can/testcase/unitcase/__init__.py +0 -0
- cannect/core/can/testcase/unitcase/asw2can.py +48 -0
- cannect/core/can/testcase/unitcase/decode.py +63 -0
- cannect/core/can/testcase/unitcase/diagnosis.py +479 -0
- cannect/core/can/testcase/unitcase/encode.py +60 -0
- cannect/core/ir/__init__.py +2 -0
- cannect/core/ir/changehistory.py +310 -0
- cannect/core/ir/delivereables.py +71 -0
- cannect/core/ir/diff.py +97 -0
- cannect/core/ir/ir.py +581 -0
- cannect/core/ir/sdd.py +148 -0
- cannect/core/mdf.py +66 -0
- cannect/core/subversion.py +136 -0
- cannect/core/testcase/__init__.py +3 -0
- cannect/core/testcase/plotter.py +181 -0
- cannect/core/testcase/style.py +981 -0
- cannect/core/testcase/testcase.py +160 -0
- cannect/core/testcase/unitcase.py +227 -0
- cannect/errors.py +20 -0
- cannect/schema/__init__.py +5 -0
- cannect/schema/candb.py +226 -0
- cannect/schema/datadictionary.py +60 -0
- cannect/utils/__init__.py +3 -0
- cannect/utils/excel.py +29 -0
- cannect/utils/logger.py +81 -0
- cannect/utils/ppt.py +236 -0
- cannect/utils/tools.py +207 -0
- cannect-1.0.0.dist-info/METADATA +214 -0
- cannect-1.0.0.dist-info/RECORD +58 -0
- cannect-1.0.0.dist-info/WHEEL +5 -0
- cannect-1.0.0.dist-info/licenses/LICENSE +21 -0
- cannect-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
from cannect.utils.ppt import PptRW
|
|
2
|
+
from pandas import DataFrame
|
|
3
|
+
from typing import Iterable, List
|
|
4
|
+
import pygetwindow as gw
|
|
5
|
+
import pyautogui as gui
|
|
6
|
+
import time
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ChangeHistoryManager(PptRW):
|
|
10
|
+
|
|
11
|
+
@classmethod
|
|
12
|
+
def routine_capture(cls, ppt:str='', size:int=26, *hotkey):
|
|
13
|
+
"""
|
|
14
|
+
최초 픽픽 또는 기타 툴로 최초 캡쳐가 되어 있어야 함.
|
|
15
|
+
반복 캡쳐는 단축키로 수행이 가능해야 함
|
|
16
|
+
@param ppt : 변경내역서 파일명
|
|
17
|
+
@param size :
|
|
18
|
+
"""
|
|
19
|
+
windows = gw.getAllTitles()
|
|
20
|
+
ascet_diff = None
|
|
21
|
+
pptx = []
|
|
22
|
+
for title in windows:
|
|
23
|
+
if title and title == "ASCET-DIFF":
|
|
24
|
+
ascet_diff = title
|
|
25
|
+
if title and '.pptx' in title:
|
|
26
|
+
pptx.append(title)
|
|
27
|
+
|
|
28
|
+
if ascet_diff is None:
|
|
29
|
+
raise OSError('ASCET-DIFF 를 찾을 수 없습니다')
|
|
30
|
+
if not pptx:
|
|
31
|
+
raise OSError('변경내역서를 찾을 수 없습니다')
|
|
32
|
+
if len(pptx) >= 2 and not ppt:
|
|
33
|
+
raise OSError('열려있는 pptx가 2개 이상이며 변경내역서를 특정할 수 없습니다. @ppt = ""')
|
|
34
|
+
pptx = [_ppt for _ppt in pptx if _ppt.startswith(ppt)][0]
|
|
35
|
+
|
|
36
|
+
window = gw.getWindowsWithTitle(ascet_diff)[0]
|
|
37
|
+
window.activate()
|
|
38
|
+
|
|
39
|
+
if not hotkey:
|
|
40
|
+
hotkey = 'shift', 'ctrl', 'd'
|
|
41
|
+
gui.hotkey(*hotkey)
|
|
42
|
+
time.sleep(0.5)
|
|
43
|
+
|
|
44
|
+
report = gw.getWindowsWithTitle(pptx)[0]
|
|
45
|
+
report.activate()
|
|
46
|
+
gui.hotkey('ctrl', 'v')
|
|
47
|
+
time.sleep(0.5)
|
|
48
|
+
|
|
49
|
+
gui.hotkey('alt', '6')
|
|
50
|
+
time.sleep(0.2)
|
|
51
|
+
|
|
52
|
+
gui.write(str(size))
|
|
53
|
+
gui.press('enter')
|
|
54
|
+
time.sleep(0.2)
|
|
55
|
+
|
|
56
|
+
return
|
|
57
|
+
|
|
58
|
+
def resize_cover(self):
|
|
59
|
+
"""
|
|
60
|
+
| n == 7 | n == 3 |
|
|
61
|
+
| n == 8 | n == 4 |
|
|
62
|
+
| n == 9 | n == 5 |
|
|
63
|
+
| n == 10 | n == 6 |
|
|
64
|
+
:return:
|
|
65
|
+
"""
|
|
66
|
+
for n, shape in enumerate(self.ppt.Slides.Item(1).Shapes, start=1):
|
|
67
|
+
if shape.HasTable:
|
|
68
|
+
if n in [7, 8, 9, 10]:
|
|
69
|
+
shape.Left = 0.76 * 28.346
|
|
70
|
+
shape.Top = {7:2.77, 8:8.1, 9:11.86, 10:15.53}[n] * 28.346
|
|
71
|
+
if n in [3, 4, 5, 6]:
|
|
72
|
+
shape.Width = 22.4 * 28.346
|
|
73
|
+
shape.Left = 4.36 * 28.346
|
|
74
|
+
shape.Top = {3: 2.77, 4: 8.1, 5: 11.86, 6: 15.53}[n] * 28.346
|
|
75
|
+
if n == 3:
|
|
76
|
+
shape.Table.Rows(5).Height = 1.69 * 28.346
|
|
77
|
+
else:
|
|
78
|
+
shape.Height = {4:3.6, 5:3.5, 6:2.36}[n] * 28.346
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
@property
|
|
82
|
+
def title(self) -> str:
|
|
83
|
+
return self.__dict__.get('_title', '')
|
|
84
|
+
|
|
85
|
+
@title.setter
|
|
86
|
+
def title(self, title:str):
|
|
87
|
+
self.__dict__['_title'] = title
|
|
88
|
+
self.set_text(n_slide=1, n_shape=1, text=title, pos='new')
|
|
89
|
+
self.set_text_font(n_slide=1, n_shape=1, size=24)
|
|
90
|
+
n_regulation = self.get_slide_n('법규 정합성')
|
|
91
|
+
if n_regulation:
|
|
92
|
+
self.set_text_in_table(n_slide=n_regulation[0], n_table=1, cell=(1, 2), text=title, pos='new')
|
|
93
|
+
n_checklist = self.get_slide_n('SW변경내역서 Check List')
|
|
94
|
+
if n_checklist:
|
|
95
|
+
self.set_text_in_table(n_slide=n_checklist[0], n_table=1, cell=(1, 2), text=title, pos='new')
|
|
96
|
+
|
|
97
|
+
@property
|
|
98
|
+
def developer(self) -> str:
|
|
99
|
+
return self.__dict__.get('_developer', '')
|
|
100
|
+
|
|
101
|
+
@developer.setter
|
|
102
|
+
def developer(self, developer:str):
|
|
103
|
+
self.__dict__['_developer'] = developer
|
|
104
|
+
self.set_text_in_table(n_slide=1, n_table=1, cell=(2, 1), text=developer, pos='new')
|
|
105
|
+
self.set_table_font(n_slide=1, n_table=1, cell=(2, 1), size=10)
|
|
106
|
+
|
|
107
|
+
@property
|
|
108
|
+
def function(self) -> str:
|
|
109
|
+
return self.__dict__.get('_function', '')
|
|
110
|
+
|
|
111
|
+
@function.setter
|
|
112
|
+
def function(self, functions:Iterable):
|
|
113
|
+
self.set_text_in_table(n_slide=1, n_table=2, cell=(3, 2), text=", ".join(functions), pos='new')
|
|
114
|
+
self.set_table_font(n_slide=1, n_table=2, cell=(3, 2), size=10)
|
|
115
|
+
|
|
116
|
+
@property
|
|
117
|
+
def issue(self) -> str:
|
|
118
|
+
return self.__dict__.get('_issue', '')
|
|
119
|
+
|
|
120
|
+
@issue.setter
|
|
121
|
+
def issue(self, issue:str):
|
|
122
|
+
self.__dict__['_issue'] = issue
|
|
123
|
+
self.set_table_font(n_slide=1, n_table=2, cell=(3, 8), name="현대하모니 L")
|
|
124
|
+
self.set_text_in_table(n_slide=1, n_table=2, cell=(3, 8), text=issue, pos='new')
|
|
125
|
+
|
|
126
|
+
@property
|
|
127
|
+
def lcr(self) -> str:
|
|
128
|
+
return self.__dict__.get('_lcr', '')
|
|
129
|
+
|
|
130
|
+
@lcr.setter
|
|
131
|
+
def lcr(self, lcr:str):
|
|
132
|
+
self.__dict__['_lcr'] = lcr
|
|
133
|
+
self.set_text_in_table(n_slide=1, n_table=2, cell=(4, 8), text=lcr, pos='before')
|
|
134
|
+
n_regulation = self.get_slide_n('법규 정합성')
|
|
135
|
+
if n_regulation:
|
|
136
|
+
self.set_text_in_table(n_slide=n_regulation[0], n_table=1, cell=(1, 4), text=lcr, pos='new')
|
|
137
|
+
n_checklist = self.get_slide_n('SW변경내역서 Check List')
|
|
138
|
+
if n_checklist:
|
|
139
|
+
self.set_text_in_table(n_slide=n_checklist[0], n_table=1, cell=(1, 4), text=lcr, pos='new')
|
|
140
|
+
|
|
141
|
+
@property
|
|
142
|
+
def problem(self) -> str:
|
|
143
|
+
return self.__dict__.get('_problem', '')
|
|
144
|
+
|
|
145
|
+
@problem.setter
|
|
146
|
+
def problem(self, problem:str):
|
|
147
|
+
self.set_text_in_table(n_slide=1, n_table=2, cell=(5, 1), text=problem, pos='new')
|
|
148
|
+
|
|
149
|
+
@property
|
|
150
|
+
def prev_model_description(self) -> str:
|
|
151
|
+
return self.__dict__.get('_prev_model_description', '')
|
|
152
|
+
|
|
153
|
+
@prev_model_description.setter
|
|
154
|
+
def prev_model_description(self, models:DataFrame):
|
|
155
|
+
text = ''
|
|
156
|
+
for n in models.index:
|
|
157
|
+
text += f'%{models.loc[n, "FunctionName"]} <r.{models.loc[n, "SCMRev"]}>\x0b\x0b\n'
|
|
158
|
+
text = text[:-1]
|
|
159
|
+
self.set_text_in_table(n_slide=2, n_table=1, cell=(2, 1), text=text, pos='new')
|
|
160
|
+
|
|
161
|
+
@property
|
|
162
|
+
def post_model_description(self) -> str:
|
|
163
|
+
return self.__dict__.get('_post_model_description', '')
|
|
164
|
+
|
|
165
|
+
@post_model_description.setter
|
|
166
|
+
def post_model_description(self, models: DataFrame):
|
|
167
|
+
text = ''
|
|
168
|
+
for n in models.index:
|
|
169
|
+
text += f'%{models.loc[n, "FunctionName"]} <r.{models.loc[n, "SCMRev"]}>\x0b-\x0b\n'
|
|
170
|
+
text = text[:-1]
|
|
171
|
+
self.set_text_in_table(n_slide=2, n_table=1, cell=(2, 2), text=text, pos='new')
|
|
172
|
+
|
|
173
|
+
def set_model_slides(self, ir:DataFrame):
|
|
174
|
+
if self.log is not None:
|
|
175
|
+
self.log('>>> GENERATING MODEL SLIDES...')
|
|
176
|
+
self.set_shape(n_slide=3, n_shape=1, width=26.1 * 28.346, left=0.8 * 28.346)
|
|
177
|
+
self.set_text_font(n_slide=3, n_shape=1, name="현대하모니 M", size=20)
|
|
178
|
+
self.set_table_height(n_slide=3, n_table=1, row=2, height=11 * 28.346)
|
|
179
|
+
self.set_table_height(n_slide=3, n_table=1, row=3, height=3 * 28.346)
|
|
180
|
+
self.set_table_text_align(n_slide=3, n_table=1, cell=(3, 1))
|
|
181
|
+
self.set_table_text_align(n_slide=3, n_table=1, cell=(3, 2))
|
|
182
|
+
self.set_table_font(n_slide=3, n_table=1, cell=(3, 1), size=12)
|
|
183
|
+
self.set_table_font(n_slide=3, n_table=1, cell=(3, 2), size=12)
|
|
184
|
+
for n in range(3 * len(ir) - 1):
|
|
185
|
+
self.ppt.Slides(3).Duplicate()
|
|
186
|
+
|
|
187
|
+
# if self.ppt.SectionProperties.Count == 0:
|
|
188
|
+
# self.ppt.SectionProperties.AddSection(1, f'기본 구역')
|
|
189
|
+
for n, i in enumerate(ir.index, start=1):
|
|
190
|
+
n_default = 3 * i + 3
|
|
191
|
+
n_element = 3 * i + 4
|
|
192
|
+
n_formula = 3 * i + 5
|
|
193
|
+
name = ir.loc[i]["FunctionName"]
|
|
194
|
+
self.ppt.SectionProperties.AddBeforeSlide(n_default, f'%{name}')
|
|
195
|
+
self.set_text(n_slide=n_default, n_shape=1, text=f'SW 변경 내용 상세: %{name} /', pos='new')
|
|
196
|
+
self.set_text(n_slide=n_element, n_shape=1, text=f'SW 변경 내용 상세: %{name} / Element', pos='new')
|
|
197
|
+
self.set_text(n_slide=n_formula, n_shape=1, text=f'SW 변경 내용 상세: %{name} / Implementation', pos='new')
|
|
198
|
+
self.set_text_in_table(n_slide=n_element, n_table=1, cell=(3, 1), text="Element 삭제\x0b", pos="new")
|
|
199
|
+
self.set_text_in_table(n_slide=n_element, n_table=1, cell=(3, 2), text="Element 추가\x0b", pos="new")
|
|
200
|
+
self.set_text_in_table(n_slide=n_formula, n_table=1, cell=(3, 1), text="Impl. 삭제\x0b", pos="new")
|
|
201
|
+
self.set_text_in_table(n_slide=n_formula, n_table=1, cell=(3, 2), text="Impl. 추가\x0b", pos="new")
|
|
202
|
+
self.ppt.SectionProperties.AddBeforeSlide(self.get_slide_n('Calibration')[0], 'Calibration Guide')
|
|
203
|
+
return
|
|
204
|
+
|
|
205
|
+
@property
|
|
206
|
+
def prev_model_details(self):
|
|
207
|
+
return self.__dict__.get('_prev_model_details', '')
|
|
208
|
+
|
|
209
|
+
@prev_model_details.setter
|
|
210
|
+
def prev_model_details(self, models:DataFrame):
|
|
211
|
+
if self.log is not None:
|
|
212
|
+
self.log('>>> WRITING PREVIOUS MODEL DETAILS...')
|
|
213
|
+
for n in models.index:
|
|
214
|
+
name, rev = models.loc[n, "FunctionName"], models.loc[n, "SCMRev"]
|
|
215
|
+
if self.log is not None:
|
|
216
|
+
self.log(f'>>> ... {name} @{rev}')
|
|
217
|
+
slides = self.get_slide_n(f'{name} ')
|
|
218
|
+
for slide in slides:
|
|
219
|
+
self.replace_text_in_table(
|
|
220
|
+
n_slide=slide,
|
|
221
|
+
n_table=1,
|
|
222
|
+
cell=(1, 1),
|
|
223
|
+
prev="Rev.",
|
|
224
|
+
post=f"Rev.{rev}"
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
@property
|
|
228
|
+
def post_model_details(self):
|
|
229
|
+
return self.__dict__.get('_post_model_details', '')
|
|
230
|
+
|
|
231
|
+
@post_model_details.setter
|
|
232
|
+
def post_model_details(self, models:DataFrame):
|
|
233
|
+
if self.log is not None:
|
|
234
|
+
self.log('>>> WRITING POST MODEL DETAILS...')
|
|
235
|
+
for n in models.index:
|
|
236
|
+
name, rev = models.loc[n, "FunctionName"], models.loc[n, "SCMRev"]
|
|
237
|
+
if self.log is not None:
|
|
238
|
+
self.log(f'>>> ... {name} @{rev}')
|
|
239
|
+
slides = self.get_slide_n(f'{name} ')
|
|
240
|
+
for slide in slides:
|
|
241
|
+
self.replace_text_in_table(
|
|
242
|
+
n_slide=slide,
|
|
243
|
+
n_table=1,
|
|
244
|
+
cell=(1, 2),
|
|
245
|
+
prev="Rev.",
|
|
246
|
+
post=f"Rev.{rev}"
|
|
247
|
+
)
|
|
248
|
+
slides = self.get_slide_n(f'{name} / Element')
|
|
249
|
+
for slide in slides:
|
|
250
|
+
self.set_text_in_table(
|
|
251
|
+
n_slide=slide,
|
|
252
|
+
n_table=1,
|
|
253
|
+
cell=(3, 1),
|
|
254
|
+
text='Element 삭제\x0b' + models.loc[n, "ElementDeleted"],
|
|
255
|
+
pos="new"
|
|
256
|
+
)
|
|
257
|
+
self.set_text_in_table(
|
|
258
|
+
n_slide=slide,
|
|
259
|
+
n_table=1,
|
|
260
|
+
cell=(3, 2),
|
|
261
|
+
text='Element 추가\x0b' + models.loc[n, "ElementAdded"],
|
|
262
|
+
pos="new"
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
@property
|
|
266
|
+
def parameters(self) -> List[DataFrame]:
|
|
267
|
+
return self.__dict__.get('_parameters', [])
|
|
268
|
+
|
|
269
|
+
@parameters.setter
|
|
270
|
+
def parameters(self, parameters: List[DataFrame]):
|
|
271
|
+
if len(parameters) == 0:
|
|
272
|
+
return
|
|
273
|
+
self.__dict__['_parameters'] = parameters
|
|
274
|
+
if self.log is not None:
|
|
275
|
+
self.log('>>> WRITING CALIBRATION PARAMETERS...')
|
|
276
|
+
|
|
277
|
+
n_param = self.get_slide_n('Calibration')[0]
|
|
278
|
+
for n in range(len(parameters) - 1):
|
|
279
|
+
self.ppt.Slides(n_param).Duplicate()
|
|
280
|
+
|
|
281
|
+
for n, param in enumerate(parameters):
|
|
282
|
+
table = self._get_table(n_param + n, 1)
|
|
283
|
+
if len(param) > 3:
|
|
284
|
+
for _ in range(len(param) - 3):
|
|
285
|
+
table.Rows.Add()
|
|
286
|
+
table.Columns(1).Width = 5.0 * 28.346
|
|
287
|
+
table.Columns(2).Width = 7.0 * 28.346
|
|
288
|
+
table.Columns(3).Width = 4.0 * 28.346
|
|
289
|
+
table.Columns(5).Width = 2.0 * 28.346
|
|
290
|
+
table.Columns(6).Width = 2.0 * 28.346
|
|
291
|
+
table.Columns(7).Width = 2.0 * 28.346
|
|
292
|
+
for r, index in enumerate(param.index, start=1):
|
|
293
|
+
row = param.loc[index]
|
|
294
|
+
for c, val in enumerate(row.values, start=1):
|
|
295
|
+
cell = table.Cell(r + 1, c).Shape
|
|
296
|
+
cell.TextFrame.TextRange.Text = str(val)
|
|
297
|
+
cell.TextFrame.TextRange.Font.Name = "현대하모니 L"
|
|
298
|
+
cell.TextFrame.TextRange.Font.Size = 10
|
|
299
|
+
|
|
300
|
+
cell.TextFrame.TextRange.ParagraphFormat.Alignment = 1 if c == 2 else 2
|
|
301
|
+
cell.TextFrame.VerticalAnchor = 3
|
|
302
|
+
return
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
if __name__ == "__main__":
|
|
306
|
+
# ChangeHistoryManager.routine_capture('0000_CNGPIO_통신_인터페이스_개발.pptx', 13)
|
|
307
|
+
chm = ChangeHistoryManager(
|
|
308
|
+
path = r"D:\Archive\00_프로젝트\2017 통신개발-\2026\DS0127 CR10787035 DTC별 IUMPR 표출 조건 변경 ICE\0000_CAN_ICE_IUMPR표출_DEM조건_추가.pptx"
|
|
309
|
+
)
|
|
310
|
+
chm.resize_cover()
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
from cannect.config import env
|
|
2
|
+
from cannect.utils import tools
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
import os
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Deliverables:
|
|
9
|
+
|
|
10
|
+
# Resources = { U | Formula, Conf-Data, BSW-Auxiliary, SDD-Note, OS-Task-Info }
|
|
11
|
+
__slots__ = (
|
|
12
|
+
"Root",
|
|
13
|
+
"Requirement", "BuildEnv", "Workspace", "Model",
|
|
14
|
+
"Resources", "CGen", "ROM", "Test", "Others"
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
def __init__(self, base_path: str=''):
|
|
18
|
+
"""
|
|
19
|
+
IR 산출물 관리 폴더 생성,
|
|
20
|
+
@base_path 경로 입력 시 하위에 @sub_path 이름으로 폴더 생성
|
|
21
|
+
@base_path 미 입력 시, "다운로드"폴더 하위에 "{생성 날짜}_IR_산출물" 이름으로 자동 폴더
|
|
22
|
+
생성 후 @sub_paths 이름의 하위 폴더 생성
|
|
23
|
+
@sub_paths 하위 폴더 리스트 미 지정 시 디폴트 값 자동 할당
|
|
24
|
+
|
|
25
|
+
@base_path : [str] 산출물 관리 경로
|
|
26
|
+
"""
|
|
27
|
+
if base_path:
|
|
28
|
+
self.Root = Path(base_path)
|
|
29
|
+
else:
|
|
30
|
+
self.Root = Path(env.DOWNLOADS / f'{datetime.now().strftime("%Y%m%d")}_IR_산출물')
|
|
31
|
+
root = self.Root
|
|
32
|
+
|
|
33
|
+
os.makedirs(root, exist_ok=True)
|
|
34
|
+
for n, path in enumerate(self.__slots__, start=0):
|
|
35
|
+
if path == "Root":
|
|
36
|
+
continue
|
|
37
|
+
full_path = Path(os.path.join(root, f'{str(n).zfill(2)}_{path}'))
|
|
38
|
+
setattr(self, path, full_path)
|
|
39
|
+
|
|
40
|
+
os.makedirs(full_path, exist_ok=True)
|
|
41
|
+
if path == "Model":
|
|
42
|
+
os.makedirs(os.path.join(full_path, f'Prev'), exist_ok=True)
|
|
43
|
+
os.makedirs(os.path.join(full_path, f'Post'), exist_ok=True)
|
|
44
|
+
|
|
45
|
+
if not any(file.endswith('.xlsm') for file in os.listdir(root)):
|
|
46
|
+
try:
|
|
47
|
+
tools.copy_to(env.SVN_IR / '0000_HNB_SW_IR_.xlsm', root)
|
|
48
|
+
except PermissionError:
|
|
49
|
+
pass
|
|
50
|
+
|
|
51
|
+
if not any(file.endswith('.pptx') for file in os.listdir(root)):
|
|
52
|
+
try:
|
|
53
|
+
tools.copy_to(env.SVN_HISTORY / '0000_변경내역서 양식.pptx', root)
|
|
54
|
+
except PermissionError:
|
|
55
|
+
pass
|
|
56
|
+
return
|
|
57
|
+
|
|
58
|
+
def __getitem__(self, item):
|
|
59
|
+
return self.Root / item
|
|
60
|
+
|
|
61
|
+
def __str__(self) -> str:
|
|
62
|
+
indent = max(len(path) for path in self.__slots__)
|
|
63
|
+
return "\n".join(f'{path:>{indent}}: {self.__getattribute__(path)}' for path in self.__slots__)
|
|
64
|
+
|
|
65
|
+
@property
|
|
66
|
+
def change_history(self) -> str:
|
|
67
|
+
for file in os.listdir(self.Root):
|
|
68
|
+
if file.endswith('.pptx'):
|
|
69
|
+
return os.path.join(self.Root, file)
|
|
70
|
+
raise FileExistsError('변경 내역서 없음')
|
|
71
|
+
|
cannect/core/ir/diff.py
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
from cannect.core.ascet import Amd
|
|
2
|
+
from pandas import DataFrame
|
|
3
|
+
from typing import List
|
|
4
|
+
import os, hashlib
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class AmdDiff:
|
|
8
|
+
|
|
9
|
+
@classmethod
|
|
10
|
+
def parameters2table(cls, elem:DataFrame, value:DataFrame):
|
|
11
|
+
elem = elem[
|
|
12
|
+
(elem['kind'] == 'parameter') &
|
|
13
|
+
(elem['scope'] != 'imported')
|
|
14
|
+
]
|
|
15
|
+
elem.set_index(keys='OID', inplace=True)
|
|
16
|
+
|
|
17
|
+
data = value[value['elementName'].isin(elem['name'])]
|
|
18
|
+
data.set_index(keys='elementOID', inplace=True)
|
|
19
|
+
elem = elem.join(data[['value']], how='left')
|
|
20
|
+
elem = elem[["name", "comment", "model", "value"]]
|
|
21
|
+
elem.columns = ['Name', 'Description', 'Module', 'Recommendation Cal']
|
|
22
|
+
elem['Default Cal'] = elem['Recommendation Cal']
|
|
23
|
+
elem['Disable Cal'] = '-'
|
|
24
|
+
elem['Remark'] = '-'
|
|
25
|
+
return elem
|
|
26
|
+
|
|
27
|
+
def __init__(
|
|
28
|
+
self,
|
|
29
|
+
prev:str,
|
|
30
|
+
post:str,
|
|
31
|
+
exclude_imported:bool=True
|
|
32
|
+
):
|
|
33
|
+
self.prev = prev = Amd(prev)
|
|
34
|
+
self.post = post = Amd(post)
|
|
35
|
+
self.prev_elem = prev.main.dataframe('Element')
|
|
36
|
+
self.post_elem = post.main.dataframe('Element')
|
|
37
|
+
if exclude_imported:
|
|
38
|
+
self.prev_elem = self.prev_elem[self.prev_elem['scope'] != 'imported']
|
|
39
|
+
self.post_elem = self.post_elem[self.post_elem['scope'] != 'imported']
|
|
40
|
+
|
|
41
|
+
self.prev_data = prev.data.dataframe('DataEntry')
|
|
42
|
+
self.post_data = post.data.dataframe('DataEntry')
|
|
43
|
+
return
|
|
44
|
+
|
|
45
|
+
@property
|
|
46
|
+
def is_equal(self) -> bool:
|
|
47
|
+
def _hash(file):
|
|
48
|
+
_md5 = hashlib.md5()
|
|
49
|
+
with open(file, "rb") as f:
|
|
50
|
+
for chunk in iter(lambda: f.read(4096), b""):
|
|
51
|
+
_md5.update(chunk)
|
|
52
|
+
return _md5.hexdigest()
|
|
53
|
+
if os.path.getsize(self.prev.main.path) != os.path.getsize(self.post.main.path):
|
|
54
|
+
return False
|
|
55
|
+
return _hash(self.prev.main.path) == _hash(self.post.main.path)
|
|
56
|
+
|
|
57
|
+
@property
|
|
58
|
+
def deleted(self) -> List[str]:
|
|
59
|
+
return list(set(self.prev_elem['name']) - set(self.post_elem['name']))
|
|
60
|
+
|
|
61
|
+
@property
|
|
62
|
+
def added(self) -> List[str]:
|
|
63
|
+
if self.is_equal:
|
|
64
|
+
return self.post_elem['name'].tolist()
|
|
65
|
+
return list(set(self.post_elem['name']) - set(self.prev_elem['name']))
|
|
66
|
+
|
|
67
|
+
@property
|
|
68
|
+
def added_parameters(self) -> DataFrame:
|
|
69
|
+
elem = self.post_elem[self.post_elem['name'].isin(self.added)]
|
|
70
|
+
data = self.post_data[self.post_data['elementName'].isin(elem['name'])]
|
|
71
|
+
return self.parameters2table(elem, data)
|
|
72
|
+
# elem = self.post_elem[
|
|
73
|
+
# self.post_elem['name'].isin(self.added) &
|
|
74
|
+
# (self.post_elem['kind'] == 'parameter') &
|
|
75
|
+
# (self.post_elem['scope'] != 'imported')
|
|
76
|
+
# ]
|
|
77
|
+
# elem.set_index(keys='OID', inplace=True)
|
|
78
|
+
# data = self.post_data[self.post_data['elementName'].isin(elem['name'])]
|
|
79
|
+
# data.set_index(keys='elementOID', inplace=True)
|
|
80
|
+
# elem = elem.join(data[['value']], how='left')
|
|
81
|
+
# elem = elem[["name", "comment", "model", "value"]]
|
|
82
|
+
# elem.columns = ['Name', 'Description', 'Module', 'Recommendation Cal']
|
|
83
|
+
# elem['Default Cal'] = elem['Recommendation Cal']
|
|
84
|
+
# elem['Disable Cal'] = '-'
|
|
85
|
+
# elem['Remark'] = '-'
|
|
86
|
+
# return elem
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
if __name__ == "__main__":
|
|
90
|
+
from pandas import set_option
|
|
91
|
+
set_option('display.expand_frame_repr', False)
|
|
92
|
+
|
|
93
|
+
diff = AmdDiff(
|
|
94
|
+
r"D:\Archive\00_프로젝트\2017 통신개발-\2025\DS1201 IUMPR 미표출 ICE CANFD\02_Model\Prev\CanBMSD_48V.main.amd",
|
|
95
|
+
r"D:\Archive\00_프로젝트\2017 통신개발-\2025\DS1201 IUMPR 미표출 ICE CANFD\02_Model\Post\CanBMSD_48V\CanBMSD_48V.main.amd",
|
|
96
|
+
)
|
|
97
|
+
print(diff.added_parameters)
|