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.
Files changed (58) hide show
  1. cannect/__init__.py +30 -0
  2. cannect/api/__init__.py +0 -0
  3. cannect/config.py +114 -0
  4. cannect/core/__init__.py +0 -0
  5. cannect/core/ascet/__init__.py +3 -0
  6. cannect/core/ascet/amd.py +698 -0
  7. cannect/core/ascet/formula.py +33 -0
  8. cannect/core/ascet/oid.py +29 -0
  9. cannect/core/ascet/ws.py +154 -0
  10. cannect/core/can/__init__.py +2 -0
  11. cannect/core/can/ascet/__init__.py +3 -0
  12. cannect/core/can/ascet/_db2code.py +344 -0
  13. cannect/core/can/ascet/_db2elem.py +399 -0
  14. cannect/core/can/ascet/comdef.py +256 -0
  15. cannect/core/can/ascet/comrx.py +139 -0
  16. cannect/core/can/ascet/diag.py +691 -0
  17. cannect/core/can/db/__init__.py +4 -0
  18. cannect/core/can/db/reader.py +148 -0
  19. cannect/core/can/db/schema.py +269 -0
  20. cannect/core/can/db/specification/__init__.py +0 -0
  21. cannect/core/can/db/specification/message.py +230 -0
  22. cannect/core/can/db/specification/styles.py +81 -0
  23. cannect/core/can/db/specification/wrapper.py +161 -0
  24. cannect/core/can/db/vcs.py +104 -0
  25. cannect/core/can/rule.py +229 -0
  26. cannect/core/can/testcase/__init__.py +0 -0
  27. cannect/core/can/testcase/unitcase/__init__.py +0 -0
  28. cannect/core/can/testcase/unitcase/asw2can.py +48 -0
  29. cannect/core/can/testcase/unitcase/decode.py +63 -0
  30. cannect/core/can/testcase/unitcase/diagnosis.py +479 -0
  31. cannect/core/can/testcase/unitcase/encode.py +60 -0
  32. cannect/core/ir/__init__.py +2 -0
  33. cannect/core/ir/changehistory.py +310 -0
  34. cannect/core/ir/delivereables.py +71 -0
  35. cannect/core/ir/diff.py +97 -0
  36. cannect/core/ir/ir.py +581 -0
  37. cannect/core/ir/sdd.py +148 -0
  38. cannect/core/mdf.py +66 -0
  39. cannect/core/subversion.py +136 -0
  40. cannect/core/testcase/__init__.py +3 -0
  41. cannect/core/testcase/plotter.py +181 -0
  42. cannect/core/testcase/style.py +981 -0
  43. cannect/core/testcase/testcase.py +160 -0
  44. cannect/core/testcase/unitcase.py +227 -0
  45. cannect/errors.py +20 -0
  46. cannect/schema/__init__.py +5 -0
  47. cannect/schema/candb.py +226 -0
  48. cannect/schema/datadictionary.py +60 -0
  49. cannect/utils/__init__.py +3 -0
  50. cannect/utils/excel.py +29 -0
  51. cannect/utils/logger.py +81 -0
  52. cannect/utils/ppt.py +236 -0
  53. cannect/utils/tools.py +207 -0
  54. cannect-1.0.0.dist-info/METADATA +214 -0
  55. cannect-1.0.0.dist-info/RECORD +58 -0
  56. cannect-1.0.0.dist-info/WHEEL +5 -0
  57. cannect-1.0.0.dist-info/licenses/LICENSE +21 -0
  58. cannect-1.0.0.dist-info/top_level.txt +1 -0
cannect/core/ir/ir.py ADDED
@@ -0,0 +1,581 @@
1
+ from cannect.config import env
2
+ from cannect.core.ascet import Amd, WorkspaceIO
3
+ from cannect.core.ir.delivereables import Deliverables
4
+ from cannect.core.ir.sdd import SddRW
5
+ from cannect.core.ir.diff import AmdDiff
6
+ from cannect.core.subversion import Subversion
7
+ from cannect.errors import SVNError
8
+ from cannect.utils import tools
9
+ from cannect.utils.logger import Logger
10
+
11
+ from datetime import datetime
12
+ from pandas import DataFrame, Series
13
+ from typing import List, Iterator
14
+ import pandas as pd
15
+ import warnings, os, time, stat
16
+
17
+ warnings.filterwarnings("ignore")
18
+ SCHEMA: List[str] = [
19
+ "FunctionName", "FunctionVersion", "SCMName", "SCMRev",
20
+ "DSMName", "DSMRev",
21
+ "BSWName", "BSWRev",
22
+ "SDDName", "SDDRev",
23
+ "ChangeHistoryName", "ChangeHistoryRev",
24
+ "ElementDeleted", "ElementAdded",
25
+ "User", "Date", "Comment",
26
+ "Empty",
27
+ "PolyspaceName", "PolyspaceRev"
28
+ ]
29
+
30
+
31
+ class IntegrationRequest:
32
+ logger: Logger = Logger()
33
+ _space: int = 0
34
+
35
+ def __new__(cls, *models):
36
+ for model in models:
37
+ if os.path.isfile(model):
38
+ cls._space = max(cls._space, len(os.path.basename(model).replace(".main.amd", "").replace(".zip", "")))
39
+ else:
40
+ cls._space = max(cls._space, len(model))
41
+ # SVN 최신화
42
+ Subversion.logger = cls.logger
43
+ Subversion.update(env.SVN_MODEL)
44
+ Subversion.update(env.SVN_SDD)
45
+ Subversion.update(env.SVN_CONF)
46
+ Subversion.update(env.SVN_UNECE)
47
+ return super().__new__(cls)
48
+
49
+ def __init__(self, *models):
50
+
51
+ # Attributes
52
+ self._change_history = ''
53
+ self._comment = ''
54
+ self._date = datetime.today().strftime('%Y-%m-%d')
55
+ self._user = ''
56
+ self._parameters = []
57
+ self._deliverables = None
58
+
59
+ # 기본 테이블 생성
60
+ self.ws = ws = WorkspaceIO()
61
+ # self._models = models = model_path(*models, logger=self.logger)
62
+ self.table = DataFrame(columns=SCHEMA)
63
+
64
+ self.logger(f'[INITIALIZE]')
65
+ for n, name in enumerate(models):
66
+ self.resolve_model(ws[name])
67
+ self.table["Date"] = self._date
68
+ self.p_table = self.table.copy()
69
+ return
70
+
71
+ def __iter__(self) -> Iterator[Series]:
72
+ for n in self.table.index:
73
+ yield self.table.loc[n]
74
+
75
+ def __str__(self) -> str:
76
+ return str(self.table[SCHEMA])
77
+
78
+ def __repr__(self):
79
+ return repr(self.table[SCHEMA])
80
+
81
+ def _repr_html_(self):
82
+ return getattr(self.table, '_repr_html_')()
83
+
84
+ @property
85
+ def deliverables(self) -> Deliverables:
86
+ """
87
+ 산출물 경로
88
+ """
89
+ return self._deliverables
90
+
91
+ @deliverables.setter
92
+ def deliverables(self, path: str):
93
+ """
94
+ 산출물 경로 설정
95
+ """
96
+ self._deliverables = Deliverables(path)
97
+
98
+ @property
99
+ def parameters(self) -> List[DataFrame]:
100
+ return self._parameters
101
+
102
+ @property
103
+ def Comment(self) -> str:
104
+ return self._comment
105
+
106
+ @Comment.setter
107
+ def Comment(self, comment: str):
108
+ self.table["Comment"] = comment
109
+ self._comment = comment
110
+
111
+ @property
112
+ def User(self) -> str:
113
+ return self._user
114
+
115
+ @User.setter
116
+ def User(self, user: str):
117
+ self.table["User"] = user
118
+ self._user = user
119
+
120
+ @property
121
+ def ChangeHistory(self) -> str:
122
+ return self._change_history
123
+
124
+ @ChangeHistory.setter
125
+ def ChangeHistory(self, change: str):
126
+ self.table["ChangeHistoryName"] = change
127
+ self._change_history = change
128
+
129
+ @staticmethod
130
+ def _column_selector(key: str) -> str:
131
+ """
132
+ keyword @key 입력 시 자동 column 이름(*Name) 식별 기능
133
+
134
+ @key: [str] 선택하고자 하는 column의 키워드
135
+ """
136
+ if key == '':
137
+ return key
138
+ if "func" in key.lower():
139
+ key = "SCMName"
140
+ for schema in SCHEMA:
141
+ if key.lower() in schema.lower():
142
+ if schema.endswith("Rev") and schema.replace("Rev", "Name") in SCHEMA:
143
+ return schema.replace("Rev", "Name")
144
+ return schema
145
+ raise KeyError
146
+
147
+ def commit_all(self, message:str):
148
+ if not message:
149
+ raise SVNError('COMMIT MESSAGE NOT SPECIFIED')
150
+ for row in self:
151
+ name = row['FunctionName']
152
+ self.logger.hold(f">>> %{name: <{self._space}}: ")
153
+ Subversion.commit(self.ws[f'{name}.zip'], message)
154
+ return
155
+
156
+ def compare_model(self, prev: str = '', post: str = '', exclude_imported: bool = True):
157
+ self.logger("[COMPARE ELEMENTS]")
158
+ if not prev:
159
+ prev = self.deliverables.Model / "Prev"
160
+ if not post:
161
+ post = self.deliverables.Model / "Post"
162
+ for n, row in enumerate(self):
163
+ name = row['FunctionName']
164
+ prev_amd = tools.find_file(prev, f'{name}.main.amd')
165
+ post_amd = tools.find_file(post, f'{name}.main.amd')
166
+ if not os.path.exists(post_amd):
167
+ continue
168
+ if not os.path.exists(prev_amd):
169
+ amd = Amd(post_amd).main.dataframe('Element')
170
+ dat = Amd(post_amd).data.dataframe('DataEntry')
171
+ self.table.loc[n, 'ElementAdded'] = ", ".join(amd["name"])
172
+ self.logger(
173
+ f">>> %{name: <{self._space}}: NEW ELEMENT / ADDED ={len(amd): >3}")
174
+ params = AmdDiff.parameters2table(amd, dat)
175
+ if not params.empty:
176
+ self._parameters.append(params)
177
+ continue
178
+ diff = AmdDiff(prev_amd, post_amd, exclude_imported=exclude_imported)
179
+ self.table.loc[n, 'ElementDeleted'] = ', '.join(diff.deleted)
180
+ self.table.loc[n, 'ElementAdded'] = ", ".join(diff.added)
181
+ params = diff.added_parameters
182
+ if not params.empty:
183
+ self._parameters.append(params)
184
+
185
+ self.logger(f">>> %{name: <{self._space}}: DELETED ={len(diff.deleted): >3} / ADDED ={len(diff.added): >3}")
186
+ return
187
+
188
+ def copy_model_to_svn(
189
+ self,
190
+ src_path:str='',
191
+ ):
192
+ """
193
+ SVN 경로 상 모델(.zip)을 동일 경로에 압축 해제 후 압축 파일 삭제
194
+ @local_path에 개발된 모델(*.amd) 파일을 SVN 경로로 복사(덮어쓰기) 후 압축
195
+
196
+ ASCET-SCM 미사용, 직접 commit 시 *.amd 파일 덮어쓰기 목적
197
+
198
+ @param local_path: svn으로 복사(commit)할 모델이 있는 경로
199
+ """
200
+ if not src_path:
201
+ src_path = self.deliverables.Model / "Post"
202
+
203
+ self.logger(f'[COPY MODELS FROM "{tools.path_abbreviate(src_path)}" TO SVN]')
204
+ for row in self:
205
+ name = row['FunctionName']
206
+ self.logger.hold(f">>> %{name: <{self._space}}: UNZIP -> ")
207
+
208
+ model = self.ws[f'{name}.zip']
209
+ mpath = os.path.dirname(model)
210
+ tools.unzip(model, mpath)
211
+ try:
212
+ os.chmod(model, stat.S_IWRITE)
213
+ os.remove(model)
214
+ self.logger.hold("SUCCESS | ")
215
+ except Exception as e:
216
+ self.logger.log("FAILED")
217
+ continue
218
+
219
+ self.logger.hold("OVERWRITE -> ")
220
+ try:
221
+ local_md = tools.find_file(str(src_path), f'{name}.main.amd')
222
+ tools.copy_to(local_md, mpath)
223
+ tools.copy_to(local_md.replace(".main", ".implementation"), mpath)
224
+ tools.copy_to(local_md.replace(".main", ".data"), mpath)
225
+ tools.copy_to(local_md.replace(".main", ".specification"), mpath)
226
+ self.logger.hold("SUCCESS | ")
227
+ except Exception as e:
228
+ self.logger.log("FAILED")
229
+ continue
230
+
231
+ self.logger.hold("ZIP -> ")
232
+ try:
233
+ tools.zip(mpath)
234
+ self.logger.hold("SUCCESS")
235
+ except Exception as e:
236
+ self.logger.log("FAILED")
237
+ continue
238
+
239
+ try:
240
+ for f in os.listdir(mpath):
241
+ if f.endswith('.amd'):
242
+ os.remove(os.path.join(mpath, f))
243
+ time.sleep(1)
244
+ self.logger.log("")
245
+ except Exception as e:
246
+ self.logger.log(" | FAILED WHILE CLEAN-UP")
247
+ continue
248
+ return
249
+
250
+ def copy_resource(self, key: str, dst: str, versioning: bool = True, unzip: bool = True):
251
+ col = self._column_selector(key)
252
+
253
+ self.logger(f'[COPY "{col[:-4]}" RESOURCE FROM SVN -> {self._path_abbr(dst)}]')
254
+ if col.startswith("SCM"):
255
+ path = env["MODEL"]
256
+ elif col.startswith("DSM"):
257
+ path = env["CONF"]
258
+ elif col.startswith("SDD"):
259
+ path = env["SDD"]
260
+ elif col.startswith("Poly"):
261
+ path = env["POLYSPACE"]
262
+ else:
263
+ raise KeyError()
264
+
265
+ for row in self:
266
+ self.logger.hold(f'>>> {row["FunctionName"]: <{self._space}} ')
267
+ file = path[f'{row[col]}.zip' if col.startswith("SCM") else row[col]]
268
+ if not os.path.exists(file):
269
+ self.logger.log(f'| NOT FOUND IN SVN')
270
+ continue
271
+
272
+ try:
273
+ tools.copy_to(file, dst)
274
+ self.logger.hold(f'| "{os.path.basename(file)}" COPIED')
275
+ except (Exception, FileNotFoundError, OSError):
276
+ self.logger.hold(f'| "{os.path.basename(file)}" FAILED TO COPY')
277
+
278
+ copied = os.path.join(dst, os.path.basename(file))
279
+ os.chmod(copied, stat.S_IWRITE)
280
+ if unzip:
281
+ tools.unzip(file, dst)
282
+ if versioning:
283
+ try:
284
+ ver = row[col.replace("Name", "Rev")]
285
+ os.rename(copied, copied.replace(".zip", f"-{ver}.zip").replace(".7z", f"-{ver}.7z"))
286
+ except (Exception, FileExistsError, FileNotFoundError):
287
+ pass
288
+ self.logger.log()
289
+ return
290
+
291
+ def exclude(self, *funcs):
292
+ self.table = self.table[~self.table["FunctionName"].isin(funcs)]
293
+ self.p_table = self.p_table[~self.p_table["FunctionName"].isin(funcs)]
294
+ self.table.reset_index(inplace=True)
295
+ self.p_table.reset_index(inplace=True)
296
+ return
297
+
298
+ def resolve_model(self, model: str):
299
+ """
300
+ 모델 정보를 @self.table에 추가 (SVN Revision 제외)
301
+ 추가 항목: FunctionName, SCMName, DSMName, SDDName, PolyspaceName
302
+
303
+ @model : [str] ASCET 모델 경로(*.main.amd 또는 *.amd 파일이 포함된 *.zip)
304
+ """
305
+ if not os.path.isfile(model):
306
+ model = self.ws[model]
307
+ amd = Amd(model)
308
+ # self.logger.hold(f'>>> %{amd.name: <{self._space}} ')
309
+
310
+ data = dict(zip(SCHEMA, [''] * len(SCHEMA)))
311
+ data["FunctionName"] = name = amd.name
312
+ data["SCMName"] = "\\".join(amd.main["nameSpace"][1:].split("/") + [name])
313
+
314
+ elements = amd.main.dataframe('Element')
315
+ if not elements[
316
+ elements['name'].str.contains('DEve') |
317
+ elements['name'].str.contains('Fid')
318
+ ].empty:
319
+ data["DSMName"] = conf = f'{name.lower()}_confdata.xml'
320
+ # self.logger.hold(f'| {conf: <{self._space + 13}} ')
321
+ else:
322
+ # self.logger.hold(f'| {"DSM NO USE": <{self._space + 13}} ')
323
+ pass
324
+
325
+ data["SDDName"] = sdd = f'{amd.main["OID"][1:]}.zip'
326
+ # self.logger.hold(f'| {sdd} ')
327
+
328
+ data["PolyspaceName"] = poly = f"BF_Result_{name}.7z"
329
+ # self.logger.hold(f'| {poly}')
330
+
331
+ if self._user:
332
+ data["User"] = self._user
333
+ if self._date:
334
+ data["Date"] = self._date
335
+ if self._comment:
336
+ data["Comment"] = self._comment
337
+
338
+ self.table = pd.concat([self.table, DataFrame(data=data, index=[0])], ignore_index=True)
339
+ self.p_table = self.table.copy()
340
+ # self.logger.log()
341
+ return
342
+
343
+ def resolve_svn_version(self, col: str = ''):
344
+ def _get_log(_file: str) -> str:
345
+ try:
346
+ _ver = Subversion.log(str(_file)).iloc[0, 0][1:]
347
+ self.logger.hold(f"-> {_ver} ")
348
+ return _ver
349
+ except (OSError, Exception):
350
+ self.logger.hold(f"-> ERROR ")
351
+ return ''
352
+
353
+ col = self._column_selector(col)
354
+ self.logger(f'[RESOLVE SVN VERSION]{f": {col}" if col else ""}')
355
+ for n, row in enumerate(self):
356
+ self.logger.hold(f">>> %{row['FunctionName']: <{self._space}} ")
357
+ if col == '' or col == 'SCMName':
358
+ self.table.loc[n, 'SCMRev'] = _get_log(env.SVN_MODEL / f'{row["SCMName"]}.zip')
359
+ if col == '' or col == 'DSMName':
360
+ if pd.isna(row["DSMName"]) or (row["DSMName"] == ''):
361
+ self.logger.hold(f'|{" " * (self._space + 13 + 11)}')
362
+ else:
363
+ self.logger.hold(f'| {row["DSMName"]: <{self._space + 13}} ')
364
+ self.table.loc[n, 'DSMRev'] = _get_log(env.SVN_CONF / f'{row["DSMName"]}')
365
+ if col == '' or col == 'SDDName':
366
+ self.logger.hold(f'| {row["SDDName"]} ')
367
+ self.table.loc[n, 'SDDRev'] = _get_log(env.SVN_SDD / f'{row["SDDName"]}')
368
+ if col == '' or col == 'PolyspaceName':
369
+ self.logger.hold(f'| {row["PolyspaceName"]: <{self._space + 13}} ')
370
+ self.table.loc[n, 'PolyspaceRev'] = _get_log(env.SVN_UNECE / f'{row["PolyspaceName"]}')
371
+ self.logger.log()
372
+ return
373
+
374
+ def resolve_sdd_version(self):
375
+ temp = os.path.join(env.TEMP, '~cannect')
376
+ os.makedirs(temp, exist_ok=True)
377
+
378
+ self.logger(f'[RESOLVE SDD VERSION]')
379
+ for n, row in enumerate(self):
380
+ self.logger.hold(f'>>> {row["FunctionName"]: <{self._space}} @{row["SDDName"]} ')
381
+ file = env.SVN_SDD / row["SDDName"]
382
+ if not os.path.exists(file):
383
+ self.logger.log('-> NOT FOUND IN SVN')
384
+ continue
385
+ tools.unzip(file, temp)
386
+
387
+ sdd = SddRW(os.path.join(temp, row["SDDName"].replace(".zip", "")))
388
+ ver = sdd.version_doc
389
+ self.table.loc[n, 'FunctionVersion'] = ver
390
+ self.logger.hold(f"-> {ver}")
391
+ if sdd.version_doc != sdd.version_log:
392
+ self.logger.hold(f'(version mismatch on sdd)')
393
+ self.logger.log()
394
+
395
+ if temp.endswith('~cannect'):
396
+ tools.clear(temp, leave_path=True)
397
+ return
398
+
399
+ def select_previous_svn_version(self, mode: str = 'auto'):
400
+ """
401
+ @mode: [str] {'auto', 'latest', 'select'}
402
+ """
403
+ # 산출물 경로가 존재하는 경우 모델 과거 버전 조회 이력 확인 후 재 사용
404
+ if self.deliverables is not None and os.listdir(self.deliverables.Model / "Prev"):
405
+ prev = self.deliverables.Model / "Prev"
406
+ models = self.p_table["FunctionName"].tolist()
407
+ for model in os.listdir(prev):
408
+ if not model.endswith('.zip'):
409
+ continue
410
+ name, rev = model.split('-')
411
+ rev = rev.replace('.zip', '')
412
+ if name in models:
413
+ self.p_table.loc[models.index(name), "SCMRev"] = rev
414
+ for n, row in enumerate(self):
415
+ if self.p_table.loc[n, "SCMRev"] == '' or pd.isna(self.p_table.loc[n, "SCMRev"]):
416
+ self.p_table.loc[n, "SCMRev"] = '-'
417
+ return
418
+
419
+ if not mode.lower() in ['auto', 'latest']:
420
+ self.logger(f'[SELECT PREVIOUS MODEL VERSION]')
421
+ for n, row in enumerate(self):
422
+ file = self.ws[row["FunctionName"]]
423
+ history = Subversion.log(file)
424
+ if mode.lower() in ['auto', 'latest']:
425
+ try:
426
+ i = 1 if mode.lower() == 'auto' else 0
427
+ self.p_table.loc[n, "SCMRev"] = rev = history["revision"].values[i][1:]
428
+ if self.deliverables is not None:
429
+ Subversion.save_revision_to(file, rev, self.deliverables.Model / "Prev")
430
+ except IndexError:
431
+ self.p_table.loc[n, "SCMRev"] = '-'
432
+ continue
433
+
434
+ self.logger.hold(f'>>> SELECT VERSION FOR %{row["FunctionName"]}\n')
435
+ self.logger.log(str(history))
436
+ time.sleep(0.5)
437
+ selected = str(input(">>> (select revision): "))
438
+ if not selected or (selected == '-'):
439
+ self.p_table.loc[n, "SCMRev"] = '-'
440
+ continue
441
+ if not selected.startswith('r'):
442
+ selected = f'r{selected}'
443
+ if not selected in history["revision"].values:
444
+ raise KeyError(f'{selected} NOT FOUND')
445
+ self.p_table.loc[n, "SCMRev"] = rev = selected[1:]
446
+ if self.deliverables is not None:
447
+ Subversion.save_revision(file, rev, self.deliverables.Model / "Prev")
448
+ for file in os.listdir(self.deliverables.Model / "Prev"):
449
+ path = os.path.join(self.deliverables.Model / "Prev", file)
450
+ tools.unzip(path, self.deliverables.Model / "Prev")
451
+ return
452
+
453
+ def update_sdd(self, comment: str = ''):
454
+ """
455
+ @self.table의 "SDDName" 항목을 @path에서 찾아 자동 업데이트,
456
+ 파일이 없는 경우 신규로 간주, 00.00.001 버전으로 신규 생성
457
+
458
+ @param comment: [str] SDD 노트 기입 내용
459
+ """
460
+ if self.deliverables is None:
461
+ path = env.DOWNLOADS
462
+ else:
463
+ path = self.deliverables.Resources / "SDD"
464
+ path.mkdir(parents=True, exist_ok=True)
465
+
466
+ if not comment:
467
+ comment = self.Comment
468
+
469
+ temp = os.path.join(env.TEMP, '~cannect')
470
+ os.makedirs(temp, exist_ok=True)
471
+
472
+ self.logger(f"[UPDATE SDD NOTE AND SAVE TO'{tools.path_abbreviate(path)}']")
473
+ for n, row in enumerate(self):
474
+ name = row['FunctionName']
475
+ self.logger.hold(f">>> %{name: <{self._space}}: ")
476
+ if row["SDDName"].replace(".zip", "") in os.listdir(path):
477
+ self.logger.log('ALREADY UPDATED')
478
+ continue
479
+ try:
480
+ tools.unzip(env.SVN_SDD / row["SDDName"], temp)
481
+ except (Exception, FileExistsError, FileNotFoundError):
482
+ self.logger.log('NOT FOUND IN SVN')
483
+ continue
484
+
485
+ file = os.path.join(temp, row['SDDName'].replace('.zip', ''))
486
+ os.chmod(file, stat.S_IWRITE)
487
+
488
+ sdd = SddRW(file)
489
+ self.logger.hold(f"v{sdd.version_doc}")
490
+ if sdd.version_doc != sdd.version_log:
491
+ self.logger.hold(f'(version mismatch on sdd)')
492
+
493
+ status = sdd.update(log=comment)
494
+ if status:
495
+ self.logger.log(f' -> v{status}')
496
+ else:
497
+ self.logger.log(f' -> v{sdd.version_doc}')
498
+ tools.copy_to(file, path)
499
+ tools.clear(temp, leave_path=True)
500
+ return
501
+
502
+ # def copy_sdd_to_svn(
503
+ # self,
504
+ # local_path:str='',
505
+ # ):
506
+ # # TODO
507
+ # path = local_path if local_path else os.path.join(self.root_path, r"09_Others\SDD")
508
+ # path_name = path if len(path) < 50 else f'{path[:20]} ... {path[-20:]}'
509
+ #
510
+ # tic = time.perf_counter()
511
+ # self.logger(f">>> COPY SDD NOTE FROM '{path_name}' TO SVN: ")
512
+ # for n, row in enumerate(self):
513
+ # name = row['FunctionName']
514
+ # sdd = row['SDDName']
515
+ # try:
516
+ # file = os.path.join(path, sdd)
517
+ # except (FileExistsError, FileNotFoundError):
518
+ # self.logger(f">>> ... %{name: <{self._space}} -> NOT EXIST")
519
+ # continue
520
+ # def commit_sdd(self, log:str):
521
+ # # TODO
522
+ # return
523
+
524
+ def to_clipboard(self, **kwargs):
525
+ return self.table[SCHEMA].to_clipboard(**kwargs)
526
+
527
+
528
+ if __name__ == "__main__":
529
+ from pandas import set_option
530
+
531
+ set_option('display.expand_frame_repr', False)
532
+
533
+
534
+
535
+ ir = IntegrationRequest(
536
+ # r"E:\TEMP\CanCNG\CanCNG.main.amd", # 신규 모델은 전체 경로 사용
537
+ # r"E:\TEMP\CanEMS_CNG\CanEMS_CNG.main.amd", # 신규 모델은 전체 경로 사용
538
+ # r"E:\TEMP\CanEMSM_CNG\CanEMSM_CNG.main.amd", # 신규 모델은 전체 경로 사용
539
+ "CanCVVDD",
540
+ "CanNOXD"
541
+ )
542
+ ir.deliverables = r'D:\Archive\00_프로젝트\2017 통신개발-\2026\DS0119 CR10787034 DTC별 IUMPR 표출 조건 변경 HEV'
543
+ ir.User = "이제혁"
544
+ ir.Comment = "VCDM CR10787034 HEV/CANFD DTC별 IUMPR 표출 조건 변경"
545
+ # ir.select_previous_svn_version(mode='select')
546
+ # ir.select_previous_svn_version(mode='latest')
547
+
548
+ # POST-ACTION
549
+ # ir.update_sdd(comment=ir.Comment)
550
+
551
+ # COMMIT
552
+ # ir.copy_model_to_svn(local_path='')
553
+ # ir.commit_model(log=f'[{env["NAME"]}] CR10785930 IUMPR Exception') # 반드시 영문 표기, "[", "]" 외 특수문자 불가
554
+ # ir.copy_sdd_to_svn(local_path='') # TODO
555
+ # ir.commit_sdd(log='') # TODO
556
+
557
+ # ir.resolve_svn_version('POLYSPACE')
558
+ # ir.resolve_svn_version()
559
+ # ir.resolve_sdd_version()
560
+ # ir.compare_model(prev='', post='', exclude_imported=False)
561
+
562
+ # 변경내역서 작성
563
+ # ppt = ChangeHistoryManager(
564
+ # path=ir.deliverables["0000_CNGPIO_통신_인터페이스_개발_CANFD"],
565
+ # logger=ir.logger
566
+ # )
567
+ # ppt.title = "[CAN] 송출 신호 음수 범위 미표출 오류 개선"
568
+ # ppt.developer = "이제혁"
569
+ # ppt.function = ir.table["FunctionName"]
570
+ # ppt.issue = "VCDM CR10787115"
571
+ # ppt.lcr = "자체 개선"
572
+ # ppt.problem = "CF_Ems_DecelReq_Can 신호 음수 범위 표출 불가"
573
+ # ppt.prev_model_description = ir.p_table # .select_previous_svn_version() 후행
574
+ # ppt.post_model_description = ir.table
575
+ # ppt.set_model_slides(ir.table)
576
+ # ppt.prev_model_details = ir.p_table # .select_previous_svn_version() 후행
577
+ # ppt.post_model_details = ir.table
578
+ # ppt.parameters = ir.parameters # .compare_model()의 후행
579
+
580
+ print(ir)
581
+ # ir.to_clipboard(index=False)