pyfemtet 1.1.4__py3-none-any.whl → 1.1.6__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.
Potentially problematic release.
This version of pyfemtet might be problematic. Click here for more details.
- pyfemtet/logger/_impl.py +26 -1
- pyfemtet/opt/interface/_base_interface.py +4 -4
- pyfemtet/opt/interface/_solidworks_interface/solidworks_interface.py +193 -70
- pyfemtet/opt/interface/_solidworks_interface/sw_const.py +32 -0
- pyfemtet/opt/optimizer/_base_optimizer.py +5 -0
- pyfemtet/opt/optimizer/optuna_optimizer/_optuna_optimizer.py +40 -2
- pyfemtet/opt/problem/variable_manager/_variable_manager.py +1 -0
- pyfemtet/opt/visualization/history_viewer/_complex_components/pm_graph.py +4 -3
- {pyfemtet-1.1.4.dist-info → pyfemtet-1.1.6.dist-info}/METADATA +1 -1
- {pyfemtet-1.1.4.dist-info → pyfemtet-1.1.6.dist-info}/RECORD +14 -13
- {pyfemtet-1.1.4.dist-info → pyfemtet-1.1.6.dist-info}/WHEEL +1 -1
- {pyfemtet-1.1.4.dist-info → pyfemtet-1.1.6.dist-info}/entry_points.txt +0 -0
- {pyfemtet-1.1.4.dist-info → pyfemtet-1.1.6.dist-info}/licenses/LICENSE +0 -0
- {pyfemtet-1.1.4.dist-info → pyfemtet-1.1.6.dist-info}/licenses/LICENSE_THIRD_PARTY.txt +0 -0
pyfemtet/logger/_impl.py
CHANGED
|
@@ -81,6 +81,7 @@ def __create_formatter(colored=True):
|
|
|
81
81
|
# ===== handler config =====
|
|
82
82
|
|
|
83
83
|
STDOUT_HANDLER_NAME = 'stdout-handler'
|
|
84
|
+
STDERR_HANDLER_NAME = 'stderr-handler'
|
|
84
85
|
|
|
85
86
|
|
|
86
87
|
def __get_stdout_handler():
|
|
@@ -94,6 +95,17 @@ def __has_stdout_handler(logger):
|
|
|
94
95
|
return any([handler.get_name() != STDOUT_HANDLER_NAME for handler in logger.handlers])
|
|
95
96
|
|
|
96
97
|
|
|
98
|
+
def __get_stderr_handler():
|
|
99
|
+
stderr_handler = logging.StreamHandler(sys.stderr)
|
|
100
|
+
stderr_handler.set_name(STDERR_HANDLER_NAME)
|
|
101
|
+
stderr_handler.setFormatter(__create_formatter(colored=True))
|
|
102
|
+
return stderr_handler
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def __has_stderr_handler(logger):
|
|
106
|
+
return any([handler.get_name() != STDERR_HANDLER_NAME for handler in logger.handlers])
|
|
107
|
+
|
|
108
|
+
|
|
97
109
|
def set_stdout_output(logger, level=logging.INFO):
|
|
98
110
|
|
|
99
111
|
if not __has_stdout_handler(logger):
|
|
@@ -107,6 +119,19 @@ def remove_stdout_output(logger):
|
|
|
107
119
|
logger.removeHandler(__get_stdout_handler())
|
|
108
120
|
|
|
109
121
|
|
|
122
|
+
def set_stderr_output(logger, level=logging.INFO):
|
|
123
|
+
|
|
124
|
+
if not __has_stderr_handler(logger):
|
|
125
|
+
logger.addHandler(__get_stderr_handler())
|
|
126
|
+
|
|
127
|
+
logger.setLevel(level)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def remove_stderr_output(logger):
|
|
131
|
+
if __has_stderr_handler(logger):
|
|
132
|
+
logger.removeHandler(__get_stderr_handler())
|
|
133
|
+
|
|
134
|
+
|
|
110
135
|
def add_file_output(logger, filepath=None, level=logging.INFO) -> str:
|
|
111
136
|
"""Add FileHandler to the logger.
|
|
112
137
|
|
|
@@ -165,7 +190,7 @@ def setup_package_root_logger(package_name):
|
|
|
165
190
|
with __lock:
|
|
166
191
|
logger = logging.getLogger(package_name)
|
|
167
192
|
logger.propagate = True
|
|
168
|
-
|
|
193
|
+
set_stderr_output(logger)
|
|
169
194
|
logger.setLevel(logging.INFO)
|
|
170
195
|
__initialized_root_packages.append(package_name)
|
|
171
196
|
else:
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
-
from typing import TYPE_CHECKING
|
|
2
|
+
from typing import TYPE_CHECKING, Callable, Any
|
|
3
3
|
|
|
4
4
|
import os
|
|
5
5
|
import tempfile
|
|
@@ -105,7 +105,7 @@ class AbstractFEMInterface:
|
|
|
105
105
|
|
|
106
106
|
return dst_path_
|
|
107
107
|
|
|
108
|
-
def _get_worker_space(self) -> str
|
|
108
|
+
def _get_worker_space(self) -> str:
|
|
109
109
|
worker = get_worker()
|
|
110
110
|
if worker is None:
|
|
111
111
|
assert hasattr(self, '_tmp_dir'), 'Internal Error! Run _distribute_files() first!'
|
|
@@ -176,12 +176,12 @@ class AbstractFEMInterface:
|
|
|
176
176
|
pass
|
|
177
177
|
|
|
178
178
|
# noinspection PyMethodMayBeStatic,PyUnusedLocal
|
|
179
|
-
def _check_using_fem(self, fun:
|
|
179
|
+
def _check_using_fem(self, fun: Callable) -> bool:
|
|
180
180
|
return False
|
|
181
181
|
|
|
182
182
|
# ===== postprocessing after recording =====
|
|
183
183
|
|
|
184
|
-
def _create_postprocess_args(self) -> dict[str,
|
|
184
|
+
def _create_postprocess_args(self) -> dict[str, Any]:
|
|
185
185
|
return {}
|
|
186
186
|
|
|
187
187
|
@staticmethod
|
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from time import sleep
|
|
4
|
-
from typing import TYPE_CHECKING
|
|
5
|
-
|
|
4
|
+
from typing import TYPE_CHECKING, Any
|
|
6
5
|
import os
|
|
7
|
-
import re
|
|
8
6
|
|
|
9
|
-
from win32com.client import
|
|
10
|
-
|
|
11
|
-
from pythoncom import CoInitialize, CoUninitialize, com_error
|
|
7
|
+
from win32com.client import Dispatch, DispatchEx
|
|
8
|
+
from pythoncom import com_error, CoInitialize
|
|
12
9
|
|
|
13
10
|
from pyfemtet._util.dask_util import *
|
|
14
11
|
from pyfemtet.opt.exceptions import *
|
|
@@ -20,9 +17,8 @@ from pyfemtet.logger import get_module_logger
|
|
|
20
17
|
if TYPE_CHECKING:
|
|
21
18
|
from pyfemtet.opt.optimizer import AbstractOptimizer
|
|
22
19
|
|
|
23
|
-
|
|
24
20
|
logger = get_module_logger('opt.interface', False)
|
|
25
|
-
|
|
21
|
+
asm_logger = get_module_logger('opt.interface.sldasm', False)
|
|
26
22
|
|
|
27
23
|
# 定数の宣言
|
|
28
24
|
swThisConfiguration = 1 # https://help.solidworks.com/2023/english/api/swconst/SOLIDWORKS.Interop.swconst~SOLIDWORKS.Interop.swconst.swInConfigurationOpts_e.html
|
|
@@ -33,12 +29,50 @@ swSaveAsOptions_Copy = 2 #
|
|
|
33
29
|
swSaveAsOptions_Silent = 1 # https://help.solidworks.com/2021/english/api/swconst/solidworks.interop.swconst~solidworks.interop.swconst.swsaveasoptions_e.html
|
|
34
30
|
swSaveWithReferencesOptions_None = 0 # https://help-solidworks-com.translate.goog/2023/english/api/swconst/SolidWorks.Interop.swconst~SolidWorks.Interop.swconst.swSaveWithReferencesOptions_e.html?_x_tr_sl=auto&_x_tr_tl=ja&_x_tr_hl=ja&_x_tr_pto=wapp
|
|
35
31
|
swDocPART = 1 # https://help.solidworks.com/2023/english/api/swconst/SOLIDWORKS.Interop.swconst~SOLIDWORKS.Interop.swconst.swDocumentTypes_e.html
|
|
32
|
+
swDocASSEMBLY = 2
|
|
36
33
|
|
|
37
34
|
|
|
38
35
|
class FileNotOpenedError(Exception):
|
|
39
36
|
pass
|
|
40
37
|
|
|
41
38
|
|
|
39
|
+
class EquationContext:
|
|
40
|
+
def __init__(self, swModel) -> None:
|
|
41
|
+
self.swModel = swModel
|
|
42
|
+
self.swEqnMgr = None
|
|
43
|
+
|
|
44
|
+
def __enter__(self):
|
|
45
|
+
# プロパティを退避
|
|
46
|
+
self.swEqnMgr = self.swModel.GetEquationMgr
|
|
47
|
+
self.buffer_aso = self.swEqnMgr.AutomaticSolveOrder
|
|
48
|
+
self.buffer_ar = self.swEqnMgr.AutomaticRebuild
|
|
49
|
+
self.swEqnMgr.AutomaticSolveOrder = False
|
|
50
|
+
self.swEqnMgr.AutomaticRebuild = False
|
|
51
|
+
return self.swEqnMgr
|
|
52
|
+
|
|
53
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
54
|
+
# プロパティをもとに戻す
|
|
55
|
+
assert self.swEqnMgr is not None
|
|
56
|
+
self.swEqnMgr.AutomaticSolveOrder = self.buffer_aso
|
|
57
|
+
self.swEqnMgr.AutomaticRebuild = self.buffer_ar
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class EditPartContext:
|
|
61
|
+
def __init__(self, swModel, component) -> None:
|
|
62
|
+
self.swModel = swModel
|
|
63
|
+
self.component = component
|
|
64
|
+
|
|
65
|
+
def __enter__(self):
|
|
66
|
+
swSelMgr = self.swModel.SelectionManager
|
|
67
|
+
swSelData = swSelMgr.CreateSelectData
|
|
68
|
+
swSelMgr.AddSelectionListObject(self.component, swSelData)
|
|
69
|
+
# self.swModel.EditPart() # 対象がアセンブリの場合動作しない
|
|
70
|
+
self.swModel.AssemblyPartToggle() # Obsolete だが代わりにこれを使う
|
|
71
|
+
|
|
72
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
73
|
+
self.swModel.EditAssembly()
|
|
74
|
+
|
|
75
|
+
|
|
42
76
|
# noinspection PyPep8Naming
|
|
43
77
|
class SolidworksInterface(COMInterface):
|
|
44
78
|
"""
|
|
@@ -63,7 +97,7 @@ class SolidworksInterface(COMInterface):
|
|
|
63
97
|
AssertionError: If the specified part file does not exist.
|
|
64
98
|
"""
|
|
65
99
|
|
|
66
|
-
swApp:
|
|
100
|
+
swApp: Any
|
|
67
101
|
com_members = {'swApp': 'SLDWORKS.Application'}
|
|
68
102
|
_access_sw_lock_name = 'access_sw'
|
|
69
103
|
|
|
@@ -77,7 +111,8 @@ class SolidworksInterface(COMInterface):
|
|
|
77
111
|
self.quit_solidworks_on_terminate = close_solidworks_on_terminate
|
|
78
112
|
self.solidworks_visible = visible
|
|
79
113
|
|
|
80
|
-
|
|
114
|
+
if not os.path.isfile(self.sldprt_path):
|
|
115
|
+
raise FileNotFoundError(self.sldprt_path)
|
|
81
116
|
self._original_sldprt_path = self.sldprt_path
|
|
82
117
|
|
|
83
118
|
def connect_sw(self):
|
|
@@ -86,9 +121,9 @@ class SolidworksInterface(COMInterface):
|
|
|
86
121
|
jp_message='Solidworks に接続しています...'
|
|
87
122
|
))
|
|
88
123
|
try:
|
|
89
|
-
self.swApp =
|
|
124
|
+
self.swApp = Dispatch('SLDWORKS.Application')
|
|
90
125
|
except com_error:
|
|
91
|
-
raise
|
|
126
|
+
raise RuntimeError(_(
|
|
92
127
|
en_message='Failed to instantiate Solidworks. '
|
|
93
128
|
'Please check installation and enabling macro.',
|
|
94
129
|
jp_message='Solidworks のインスタンス化に失敗しました。'
|
|
@@ -97,18 +132,32 @@ class SolidworksInterface(COMInterface):
|
|
|
97
132
|
self.swApp.Visible = self.solidworks_visible
|
|
98
133
|
|
|
99
134
|
def _setup_before_parallel(self, scheduler_address=None):
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
135
|
+
if not _is_assembly(self.sldprt_path):
|
|
136
|
+
self._distribute_files([self.sldprt_path], scheduler_address)
|
|
137
|
+
|
|
138
|
+
def _setup_after_parallel(self, opt: AbstractOptimizer):
|
|
139
|
+
|
|
140
|
+
# validation
|
|
141
|
+
if _is_assembly(self.sldprt_path) and get_worker() is not None:
|
|
142
|
+
# 現在の仕様だと sldprt_path だけが
|
|
143
|
+
# worker_space に保存される。
|
|
144
|
+
# 並列処理に対応するためには
|
|
145
|
+
# すべてのファイルを distribute したうえで
|
|
146
|
+
# 構成部品の置換を実行する必要がある。
|
|
147
|
+
raise RuntimeError(_(
|
|
148
|
+
en_message='Parallel processing is not supported when handling assembly parts with SolidworksInterface.',
|
|
149
|
+
jp_message='SolidworksInterfaceでアセンブリパーツを対象とする場合、並列処理はサポートされていません。'
|
|
150
|
+
))
|
|
103
151
|
|
|
104
|
-
|
|
105
|
-
|
|
152
|
+
if not _is_assembly(self.sldprt_path):
|
|
153
|
+
# get suffix
|
|
154
|
+
suffix = self._get_file_suffix(opt)
|
|
106
155
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
156
|
+
# rename and get worker path
|
|
157
|
+
self.sldprt_path = self._rename_and_get_path_on_worker_space(
|
|
158
|
+
self._original_sldprt_path,
|
|
159
|
+
suffix,
|
|
160
|
+
)
|
|
112
161
|
|
|
113
162
|
# connect solidworks
|
|
114
163
|
CoInitialize()
|
|
@@ -116,10 +165,13 @@ class SolidworksInterface(COMInterface):
|
|
|
116
165
|
self.connect_sw()
|
|
117
166
|
|
|
118
167
|
# open it
|
|
119
|
-
|
|
168
|
+
if _is_assembly(self.sldprt_path):
|
|
169
|
+
self.swApp.OpenDoc(self.sldprt_path, swDocASSEMBLY)
|
|
170
|
+
else:
|
|
171
|
+
self.swApp.OpenDoc(self.sldprt_path, swDocPART)
|
|
120
172
|
|
|
121
173
|
@property
|
|
122
|
-
def swModel(self)
|
|
174
|
+
def swModel(self):
|
|
123
175
|
return _get_model_by_basename(self.swApp, os.path.basename(self.sldprt_path))
|
|
124
176
|
|
|
125
177
|
def update(self) -> None:
|
|
@@ -131,54 +183,19 @@ class SolidworksInterface(COMInterface):
|
|
|
131
183
|
|
|
132
184
|
# sw はプロセスが一つなので Lock
|
|
133
185
|
with Lock(self._access_sw_lock_name):
|
|
134
|
-
|
|
135
186
|
sleep(0.2)
|
|
136
|
-
|
|
137
|
-
# ===== model を取得 =====
|
|
138
187
|
swModel = self.swModel
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
swEqnMgr = swModel.GetEquationMgr
|
|
142
|
-
nEquation = swEqnMgr.GetCount
|
|
143
|
-
|
|
144
|
-
# プロパティを退避
|
|
145
|
-
buffer_aso = swEqnMgr.AutomaticSolveOrder
|
|
146
|
-
buffer_ar = swEqnMgr.AutomaticRebuild
|
|
147
|
-
swEqnMgr.AutomaticSolveOrder = False
|
|
148
|
-
swEqnMgr.AutomaticRebuild = False
|
|
149
|
-
|
|
150
|
-
# 値を更新
|
|
151
|
-
for i in range(nEquation):
|
|
152
|
-
# name, equation の取得
|
|
153
|
-
eq = swEqnMgr.Equation(i)
|
|
154
|
-
prm_name = _get_name_from_equation(eq)
|
|
155
|
-
# 対象なら処理
|
|
156
|
-
if prm_name in self.current_prm_values:
|
|
157
|
-
prm = self.current_prm_values[prm_name]
|
|
158
|
-
right = str(prm.value) + prm.properties.get('unit', '')
|
|
159
|
-
new_equation = f'"{prm_name}" = {right}'
|
|
160
|
-
swEqnMgr.Equation(i, new_equation)
|
|
161
|
-
|
|
162
|
-
# 式の計算
|
|
163
|
-
# noinspection PyStatementEffect
|
|
164
|
-
swEqnMgr.EvaluateAll # always returns -1
|
|
165
|
-
|
|
166
|
-
# プロパティをもとに戻す
|
|
167
|
-
swEqnMgr.AutomaticSolveOrder = buffer_aso
|
|
168
|
-
swEqnMgr.AutomaticRebuild = buffer_ar
|
|
188
|
+
mgr = _UpdateVariableManager()
|
|
189
|
+
mgr._update_global_variables(swModel, self.current_prm_values)
|
|
169
190
|
|
|
170
191
|
def update_model(self):
|
|
171
192
|
"""Update .sldprt"""
|
|
172
193
|
|
|
173
194
|
# sw はプロセスが一つなので Lock
|
|
174
195
|
with Lock(self._access_sw_lock_name):
|
|
175
|
-
|
|
176
196
|
sleep(0.2)
|
|
177
197
|
|
|
178
|
-
# ===== model を取得 =====
|
|
179
198
|
swModel = self.swModel
|
|
180
|
-
|
|
181
|
-
# モデル再構築
|
|
182
199
|
result = swModel.EditRebuild3 # モデル再構築
|
|
183
200
|
if not result:
|
|
184
201
|
raise ModelError(_(
|
|
@@ -212,18 +229,124 @@ class SolidworksInterface(COMInterface):
|
|
|
212
229
|
sleep(3)
|
|
213
230
|
|
|
214
231
|
|
|
232
|
+
def _is_assembly(swModel_or_name):
|
|
233
|
+
if isinstance(swModel_or_name, str):
|
|
234
|
+
return swModel_or_name.lower().endswith('.sldasm')
|
|
235
|
+
else:
|
|
236
|
+
return swModel_or_name.GetPathName.lower().endswith('.sldasm')
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
def _iter_parts(swModel):
|
|
240
|
+
components = swModel.GetComponents(
|
|
241
|
+
False # TopOnly
|
|
242
|
+
)
|
|
243
|
+
return components
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
class _UpdateVariableManager:
|
|
247
|
+
|
|
248
|
+
def __init__(self):
|
|
249
|
+
self.updated_variables = set()
|
|
250
|
+
|
|
251
|
+
def _update_global_variables(self, swModel, x: TrialInput):
|
|
252
|
+
# まず自身のパラメータを更新
|
|
253
|
+
asm_logger.debug(f'Processing `{swModel.GetPathName}`')
|
|
254
|
+
self._update_global_variables_core(swModel, x)
|
|
255
|
+
|
|
256
|
+
# アセンブリならば、構成部品のパラメータを更新
|
|
257
|
+
if _is_assembly(swModel):
|
|
258
|
+
components = _iter_parts(swModel)
|
|
259
|
+
for component in components:
|
|
260
|
+
swPartModel = component.GetModelDoc2
|
|
261
|
+
asm_logger.debug(f'Checking `{swPartModel.GetPathName}`')
|
|
262
|
+
if swPartModel.GetPathName.lower() not in self.updated_variables:
|
|
263
|
+
asm_logger.debug(f'Processing `{swPartModel.GetPathName}`')
|
|
264
|
+
with EditPartContext(swModel, component):
|
|
265
|
+
self._update_global_variables_core(swPartModel, x)
|
|
266
|
+
self.updated_variables.add(swPartModel.GetPathName.lower())
|
|
267
|
+
|
|
268
|
+
def _update_global_variables_core(self, swModel, x: TrialInput):
|
|
269
|
+
with EquationContext(swModel) as swEqnMgr:
|
|
270
|
+
# txt にリンクされている場合は txt を更新
|
|
271
|
+
if swEqnMgr.LinkToFile:
|
|
272
|
+
self._update_global_variables_linked_txt(swEqnMgr, x)
|
|
273
|
+
self._update_global_variables_simple(swEqnMgr, x)
|
|
274
|
+
# noinspection PyStatementEffect
|
|
275
|
+
swEqnMgr.EvaluateAll
|
|
276
|
+
|
|
277
|
+
def _update_global_variables_linked_txt(self, swEqnMgr, x: TrialInput):
|
|
278
|
+
txt_path = swEqnMgr.FilePath
|
|
279
|
+
if txt_path in self.updated_variables:
|
|
280
|
+
return
|
|
281
|
+
with open(txt_path, 'r', encoding='utf_8_sig') as f:
|
|
282
|
+
equations = [line.strip() for line in f.readlines() if line.strip() != '']
|
|
283
|
+
for i, eq in enumerate(equations):
|
|
284
|
+
equations[i] = self._update_equation(eq, x)
|
|
285
|
+
with open(txt_path, 'w', encoding='utf_8_sig') as f:
|
|
286
|
+
f.writelines([eq + '\n' for eq in equations])
|
|
287
|
+
asm_logger.debug(f'`{txt_path}` is updated.')
|
|
288
|
+
self.updated_variables.add(txt_path)
|
|
289
|
+
|
|
290
|
+
def _update_global_variables_simple(self, swEqnMgr, x: TrialInput):
|
|
291
|
+
nEquation = swEqnMgr.GetCount
|
|
292
|
+
|
|
293
|
+
# equation を列挙
|
|
294
|
+
asm_logger.debug(f'{nEquation} equations detected.')
|
|
295
|
+
for i in range(nEquation):
|
|
296
|
+
# name, equation の取得
|
|
297
|
+
eq = swEqnMgr.Equation(i)
|
|
298
|
+
prm_name = self._get_left(eq)
|
|
299
|
+
# COM 経由なので必要な時以外は触らない
|
|
300
|
+
asm_logger.debug(f'Checking `{prm_name}`')
|
|
301
|
+
if (prm_name in x) and (prm_name not in self.updated_variables):
|
|
302
|
+
asm_logger.debug(f'Processing `{prm_name}`')
|
|
303
|
+
# 特定の Equation がテキストリンク有効か
|
|
304
|
+
# どうかを判定する術がないので、一旦更新する
|
|
305
|
+
new_eq = self._update_equation(eq, x)
|
|
306
|
+
swEqnMgr.Equation(i, new_eq)
|
|
307
|
+
# テキストリンクの場合、COM インスタンスに
|
|
308
|
+
# 更新された値が残ってしまうのでテキストを再読み込み
|
|
309
|
+
if swEqnMgr.LinkToFile:
|
|
310
|
+
# noinspection PyStatementEffect
|
|
311
|
+
swEqnMgr.UpdateValuesFromExternalEquationFile
|
|
312
|
+
self.updated_variables.add(prm_name)
|
|
313
|
+
|
|
314
|
+
def _update_equation(self, equation: str, x: TrialInput):
|
|
315
|
+
prm_name = self._get_left(equation)
|
|
316
|
+
if prm_name not in x:
|
|
317
|
+
return equation
|
|
318
|
+
prm = x[prm_name]
|
|
319
|
+
right = str(prm.value) + prm.properties.get('unit', '')
|
|
320
|
+
new_eq = f'"{prm_name}" = {right}'
|
|
321
|
+
asm_logger.debug(f'New eq.: `{new_eq}`')
|
|
322
|
+
return new_eq
|
|
323
|
+
|
|
324
|
+
@staticmethod
|
|
325
|
+
def _get_left(equation: str):
|
|
326
|
+
return equation.split('=')[0].strip('" ')
|
|
327
|
+
|
|
328
|
+
@staticmethod
|
|
329
|
+
def _load(swModel):
|
|
330
|
+
# テスト用関数
|
|
331
|
+
out = set()
|
|
332
|
+
swEqnMgr = swModel.GetEquationMgr
|
|
333
|
+
for i in range(swEqnMgr.GetCount):
|
|
334
|
+
eq = swEqnMgr.Equation(i)
|
|
335
|
+
out.add(eq)
|
|
336
|
+
if _is_assembly(swModel):
|
|
337
|
+
components = _iter_parts(swModel)
|
|
338
|
+
for component in components:
|
|
339
|
+
swPartModel = component.GetModelDoc2
|
|
340
|
+
swEqnMgr = swPartModel.GetEquationMgr
|
|
341
|
+
for i in range(swEqnMgr.GetCount):
|
|
342
|
+
eq = swEqnMgr.Equation(i)
|
|
343
|
+
out.add(eq)
|
|
344
|
+
return out
|
|
345
|
+
|
|
346
|
+
|
|
215
347
|
# noinspection PyPep8Naming
|
|
216
348
|
def _get_model_by_basename(swApp, basename):
|
|
217
349
|
swModel = swApp.ActivateDoc(basename)
|
|
218
350
|
if swModel is None:
|
|
219
351
|
raise FileNotOpenedError(f'Model {basename} is not opened.')
|
|
220
352
|
return swModel
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
def _get_name_from_equation(equation: str):
|
|
224
|
-
pattern = r'^\s*"(.+?)"\s*$'
|
|
225
|
-
matched = re.match(pattern, equation.split('=')[0])
|
|
226
|
-
if matched:
|
|
227
|
-
return matched.group(1)
|
|
228
|
-
else:
|
|
229
|
-
return None
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# https://help.solidworks.com/2026/English/api/swconst/SOLIDWORKS.Interop.swconst~SOLIDWORKS.Interop.swconst.swDocumentTypes_e.html
|
|
2
|
+
swDocASSEMBLY = 2
|
|
3
|
+
swDocDRAWING = 3
|
|
4
|
+
swDocIMPORTED_ASSEMBLY = 7
|
|
5
|
+
swDocIMPORTED_PART = 6
|
|
6
|
+
swDocLAYOUT = 5
|
|
7
|
+
swDocNONE = 0
|
|
8
|
+
swDocPART = 1
|
|
9
|
+
swDocSDM = 4
|
|
10
|
+
|
|
11
|
+
# https://help.solidworks.com/2026/English/api/swconst/SOLIDWORKS.Interop.swconst~SOLIDWORKS.Interop.swconst.swOpenDocOptions_e.html
|
|
12
|
+
swOpenDocOptions_AdvancedConfig = 8192 or 0x2000 # Open assembly using an advanced configuration
|
|
13
|
+
swOpenDocOptions_AutoMissingConfig = 32 or 0x20 # Obsolete # do not use
|
|
14
|
+
# The software automatically uses the last-used configuration of a model when it discovers missing configurations or component references as it silently opens drawings and assemblies.
|
|
15
|
+
|
|
16
|
+
swOpenDocOptions_DontLoadHiddenComponents = 256 or 0x100 # By default, hidden components are loaded when you open an assembly document. Set swOpenDocOptions_DontLoadHiddenComponents to not load hidden components when opening an assembly document
|
|
17
|
+
swOpenDocOptions_LDR_EditAssembly = 2048 or 0x800 # Open in Large Design Review (resolved) mode with edit assembly enabled # use in combination with swOpenDocOptions_ViewOnly
|
|
18
|
+
swOpenDocOptions_LoadExternalReferencesInMemory = 512 or 0x200 # Open external references in memory only # this setting is valid only if swUserPreferenceIntegerValue_e.swLoadExternalReferences is not set to swLoadExternalReferences_e.swLoadExternalReferences_None
|
|
19
|
+
# swUserPreferenceToggle_e.swExtRefLoadRefDocsInMemory (System Options > External References > Load documents in memory only) is ignored when opening documents through the API because IDocumentSpecification::LoadExternalReferencesInMemory and ISldWorks::OpenDoc6 (swOpenDocOptions_e.swOpenDocOptions_LoadExternalReferencesInMemory) have sole control of reference loading
|
|
20
|
+
|
|
21
|
+
swOpenDocOptions_LoadLightweight = 128 or 0x80 # Open assembly document as lightweight
|
|
22
|
+
# NOTE: The default for whether an assembly document is opened lightweight is based on a registry setting accessed via Tools, Options, Assemblies or with the user preference setting swAutoLoadPartsLightweight
|
|
23
|
+
# To override the default and specify a value with ISldWorks::OpenDoc6, set swOpenDocOptions_OverrideDefaultLoadLightweight. If set, then you can set swOpenDocOptions_LoadLightweight to open an assembly document as lightweight
|
|
24
|
+
|
|
25
|
+
swOpenDocOptions_LoadModel = 16 or 0x10 # Load Detached model upon opening document (drawings only)
|
|
26
|
+
swOpenDocOptions_OpenDetailingMode = 1024 or 0x400 # Open document in detailing mode
|
|
27
|
+
swOpenDocOptions_OverrideDefaultLoadLightweight = 64 or 0x40 # Override default setting whether to open an assembly document as lightweight
|
|
28
|
+
swOpenDocOptions_RapidDraft = 8 or 0x8 # Convert document to Detached format (drawings only)
|
|
29
|
+
swOpenDocOptions_ReadOnly = 2 or 0x2 # Open document read only
|
|
30
|
+
swOpenDocOptions_Silent = 1 or 0x1 # Open document silently
|
|
31
|
+
swOpenDocOptions_SpeedPak = 4096 or 0x1000 # Open document using the SpeedPak option
|
|
32
|
+
swOpenDocOptions_ViewOnly = 4 or 0x4 # Open document in Large Design Review mode (assemblies only)
|
|
@@ -4,6 +4,7 @@ import datetime
|
|
|
4
4
|
from typing import Callable, TypeAlias, Sequence, Literal
|
|
5
5
|
from numbers import Real # マイナーなので型ヒントでは使わず、isinstance で使う
|
|
6
6
|
from time import sleep
|
|
7
|
+
import os
|
|
7
8
|
|
|
8
9
|
import sympy
|
|
9
10
|
|
|
@@ -871,6 +872,10 @@ class AbstractOptimizer:
|
|
|
871
872
|
|
|
872
873
|
self.worker_status.value = WorkerStatus.running
|
|
873
874
|
|
|
875
|
+
if os.environ.get('DEBUG_FEMOPT_PARALLEL'):
|
|
876
|
+
if isinstance(worker_idx, int):
|
|
877
|
+
sleep(worker_idx)
|
|
878
|
+
|
|
874
879
|
self.run()
|
|
875
880
|
|
|
876
881
|
logger.info(_(
|
|
@@ -43,6 +43,20 @@ warnings.filterwarnings('ignore', 'Argument ``constraints_func`` is an experimen
|
|
|
43
43
|
_MESSAGE_ENQUEUED = 'Enqueued trial.'
|
|
44
44
|
|
|
45
45
|
|
|
46
|
+
def check_float_and_raise(value, check_target):
|
|
47
|
+
if isinstance(value, int | float):
|
|
48
|
+
if np.isnan(value):
|
|
49
|
+
raise ValueError(_(
|
|
50
|
+
en_message=f'{check_target} is NaN.',
|
|
51
|
+
jp_message=f'{check_target} は NaN です。',
|
|
52
|
+
))
|
|
53
|
+
else:
|
|
54
|
+
raise ValueError(_(
|
|
55
|
+
en_message=f'{check_target} should be a number, but {value} ({type(value)}) passed.',
|
|
56
|
+
jp_message=f'{check_target} は数値でなくてはなりませんが、{value} ({type(value)}) が与えられました。',
|
|
57
|
+
))
|
|
58
|
+
|
|
59
|
+
|
|
46
60
|
class MaxTrialsCallbackExcludingEnqueued(MaxTrialsCallback):
|
|
47
61
|
def __call__(self, study: Study, trial: FrozenTrial) -> None:
|
|
48
62
|
"""
|
|
@@ -167,14 +181,31 @@ class OptunaOptimizer(AbstractOptimizer):
|
|
|
167
181
|
self,
|
|
168
182
|
name: str,
|
|
169
183
|
initial_value: float,
|
|
170
|
-
lower_bound: float,
|
|
171
|
-
upper_bound: float,
|
|
184
|
+
lower_bound: float | None = None,
|
|
185
|
+
upper_bound: float | None = None,
|
|
172
186
|
step: float | None = None,
|
|
173
187
|
properties: dict[str, ...] | None = None,
|
|
174
188
|
*,
|
|
175
189
|
pass_to_fem: bool = True,
|
|
176
190
|
fix: bool = False,
|
|
177
191
|
) -> None:
|
|
192
|
+
|
|
193
|
+
if lower_bound is None or upper_bound is None:
|
|
194
|
+
properties = properties or {}
|
|
195
|
+
if properties.get('dynamic_bounds_fun') is None:
|
|
196
|
+
raise ValueError(_(
|
|
197
|
+
en_message='When using `OptunaOptimizer`, you must either specify `lower_bound` and `upper_bound`, ' \
|
|
198
|
+
'or include `dynamic_bounds_fun` (Callable[[AbstractOptimizer], float]) in `properties`.',
|
|
199
|
+
jp_message='OptunaOptimizer では、lower_bound と upper_bound を両方指定するか、' \
|
|
200
|
+
'または properties に dynamic_bounds_fun (Callable[[AbstractOptimizer], float]) ' \
|
|
201
|
+
'を含めなければなりません。'
|
|
202
|
+
))
|
|
203
|
+
else:
|
|
204
|
+
logger.warning(_(
|
|
205
|
+
en_message='`dynamic_bounds_fun` is under development. The functionally can be changed without any announcement.',
|
|
206
|
+
jp_message='dynamic_bounds_fun は開発中の機能です。機能は予告なく変更されることがあります。',
|
|
207
|
+
))
|
|
208
|
+
|
|
178
209
|
AbstractOptimizer.add_parameter(self, name, initial_value, lower_bound, upper_bound, step, properties,
|
|
179
210
|
pass_to_fem=pass_to_fem, fix=fix)
|
|
180
211
|
|
|
@@ -271,6 +302,13 @@ class OptunaOptimizer(AbstractOptimizer):
|
|
|
271
302
|
continue
|
|
272
303
|
|
|
273
304
|
if isinstance(prm, NumericParameter):
|
|
305
|
+
dynamic_bounds_fun = prm.properties.get('dynamic_bounds_fun')
|
|
306
|
+
if dynamic_bounds_fun:
|
|
307
|
+
lb, ub = dynamic_bounds_fun(self)
|
|
308
|
+
check_float_and_raise(lb, _(f'lower_bound of {prm.name}', f'{prm.name} の lower_bound'))
|
|
309
|
+
check_float_and_raise(ub, _(f'upper_bound of {prm.name}', f'{prm.name} の upper_bound'))
|
|
310
|
+
prm.lower_bound = lb
|
|
311
|
+
prm.upper_bound = ub
|
|
274
312
|
prm.value = trial.suggest_float(
|
|
275
313
|
name,
|
|
276
314
|
prm.lower_bound,
|
|
@@ -428,9 +428,10 @@ class PredictionModelGraph(AbstractPage):
|
|
|
428
428
|
self.CommandState.ready.value,
|
|
429
429
|
self.alert_region.create_alerts(
|
|
430
430
|
_(
|
|
431
|
-
en_message='Cannot draw the graph because
|
|
432
|
-
'
|
|
433
|
-
|
|
431
|
+
en_message='Cannot draw the graph because '
|
|
432
|
+
'the bounds of selected parameter '
|
|
433
|
+
'are not given.',
|
|
434
|
+
jp_message='選択された変数は上下限が与えられていないため、'
|
|
434
435
|
'グラフを描画できません。',
|
|
435
436
|
),
|
|
436
437
|
color='danger',
|
|
@@ -26,7 +26,7 @@ pyfemtet/core.py,sha256=t5tvWGrBNzCL9cP-91hbTR8q5lzULPsVeIEybeslhxQ,936
|
|
|
26
26
|
pyfemtet/dispatch_extensions/__init__.py,sha256=BzxYq3x8YdkdClq4VvH4G5HTGxu5nyAhN7xlFsnTv8c,159
|
|
27
27
|
pyfemtet/dispatch_extensions/_impl.py,sha256=Sgp350ioKcNVslXv9xRdtRjaQGRQM-BwbJYXjeildtw,11107
|
|
28
28
|
pyfemtet/logger/__init__.py,sha256=lofBrZHr0P1hsxPUiPG1SQqKxCuSBk8zGnR7vUfCHYw,516
|
|
29
|
-
pyfemtet/logger/_impl.py,sha256=
|
|
29
|
+
pyfemtet/logger/_impl.py,sha256=tR71WZbjUvnZqULzxD4Y8Vhq8eBnJhMm360-JXxB5Dc,7012
|
|
30
30
|
pyfemtet/opt/__init__.py,sha256=1LcwTddtoi8plemxkzmX0YEKiNpAZvKn9OoNQysyDLE,339
|
|
31
31
|
pyfemtet/opt/exceptions.py,sha256=M_O7jm20Y4e_QxsKF6tnEl-OrAtErUOj6hNT7eEXCO4,1327
|
|
32
32
|
pyfemtet/opt/femopt.py,sha256=Zht_H_eaTUwUcA7XFlzod0mGoJzTOZckqRK3VuwjaHM,23716
|
|
@@ -35,7 +35,7 @@ pyfemtet/opt/history/_history.py,sha256=K1k-iOSFoowqKPVZgvWEhdysO9ZsMuqEQ-P_kvO-
|
|
|
35
35
|
pyfemtet/opt/history/_hypervolume.py,sha256=_IvGH71ZNreWvDQCG815Q2hS1OEvPFPQhUnNXf1UxRQ,4449
|
|
36
36
|
pyfemtet/opt/history/_optimality.py,sha256=6vLySZmrrklr04Qir0hGethTykf8NYFod88NDGrBrG0,2407
|
|
37
37
|
pyfemtet/opt/interface/__init__.py,sha256=b2lfkBL-UPbzJppIqSgtUqHSHitPLQa6DRuH91nDZK8,1905
|
|
38
|
-
pyfemtet/opt/interface/_base_interface.py,sha256=
|
|
38
|
+
pyfemtet/opt/interface/_base_interface.py,sha256=iWJmJ8kxRH-Cztfhy3QKfRhSKRMytBtjGqgVjVavoPw,6689
|
|
39
39
|
pyfemtet/opt/interface/_dummy_classes.py,sha256=847zs3SwetMpRsGtivhvST_z2UKavKvTfUBZvkYfqB0,505
|
|
40
40
|
pyfemtet/opt/interface/_excel_interface/__init__.py,sha256=bFOmY18-j4RJc_dHQMe62GsxFwQSj7RWdvi6jxWuqyg,74
|
|
41
41
|
pyfemtet/opt/interface/_excel_interface/debug-excel-interface.xlsm,sha256=TM1CEOC5XtU7qYKNnHScO02kdtXT-gc5y29m2hatsm0,114259
|
|
@@ -51,7 +51,8 @@ pyfemtet/opt/interface/_femtet_with_nx_interface/update_model.py,sha256=2U5SJWnG
|
|
|
51
51
|
pyfemtet/opt/interface/_femtet_with_solidworks/__init__.py,sha256=5McSpy2uTmJNBylCrKt4xMSq90hlSpqyXYsjwZT3yGA,128
|
|
52
52
|
pyfemtet/opt/interface/_femtet_with_solidworks/femtet_with_solidworks_interface.py,sha256=xBAmHbzNrmHI6zzwUMX_mdjUkhRfyqzmYQN2_QNZcfE,5897
|
|
53
53
|
pyfemtet/opt/interface/_solidworks_interface/__init__.py,sha256=2c52Hfme1xdJepewRGVkPT4yhrZMQgzlCuqvHzEZPVk,95
|
|
54
|
-
pyfemtet/opt/interface/_solidworks_interface/solidworks_interface.py,sha256=
|
|
54
|
+
pyfemtet/opt/interface/_solidworks_interface/solidworks_interface.py,sha256=2SaUI5Lh1gVGqTNcSgqn0Ay1e0tZQHIXFOyYquwVvPw,14127
|
|
55
|
+
pyfemtet/opt/interface/_solidworks_interface/sw_const.py,sha256=M6KV0KmRiSOofW4ydV-3Zxqzofz4ij13CsM3Ggw6HS4,3085
|
|
55
56
|
pyfemtet/opt/interface/_surrogate_model_interface/__init__.py,sha256=9sjzQjJsMLdpBSpURyl8x4VQHEO_PGYgAshCHoycAPI,252
|
|
56
57
|
pyfemtet/opt/interface/_surrogate_model_interface/base_surrogate_interface.py,sha256=48mUOPgOVi_SRs_VnElgh6BMUJHQG9jzWpCocK_gjiY,6355
|
|
57
58
|
pyfemtet/opt/interface/_surrogate_model_interface/botorch_interface.py,sha256=JsFDs5GzlsstpyXjTYpUi_ctWlcEKliX3qMr4HBPj_E,10570
|
|
@@ -64,11 +65,11 @@ pyfemtet/opt/meta_script/__main__.py,sha256=9-QM6eZOLpZ_CxERpRu3RAMqpudorSJdPCiK
|
|
|
64
65
|
pyfemtet/opt/meta_script/sample/sample.bas,sha256=2iuSYMgPDyAdiSDVGxRu3avjcZYnULz0l8e25YBa7SQ,27966
|
|
65
66
|
pyfemtet/opt/meta_script/sample/sample.femprj,sha256=6_0ywhgXxZjdzZzQFog8mgMUEjKNCFVNlEgAWoptovk,292885
|
|
66
67
|
pyfemtet/opt/optimizer/__init__.py,sha256=A4QYeF0KHEFdwoxLfkDND7ikDQ186Ryy3oXEGdakFSg,463
|
|
67
|
-
pyfemtet/opt/optimizer/_base_optimizer.py,sha256=
|
|
68
|
+
pyfemtet/opt/optimizer/_base_optimizer.py,sha256=9vwrB7ER-Qfh0tGdP5Fg7mP459WXFGSc-yMlyYdZ4sY,37598
|
|
68
69
|
pyfemtet/opt/optimizer/_trial_queue.py,sha256=Yv6JlfVCYOiCukllfxk79xU4_utmxwRA3gcCWpdyG9k,2919
|
|
69
70
|
pyfemtet/opt/optimizer/optuna_optimizer/__init__.py,sha256=u2Bwc79tkZTU5dMbhzzrPQi0RlFg22UgXc-m9K9G6wQ,242
|
|
70
71
|
pyfemtet/opt/optimizer/optuna_optimizer/_optuna_attribute.py,sha256=7eZsruVCGgMlcnf3a9Vf55FOEE-D7V777MJQajI12Cw,1842
|
|
71
|
-
pyfemtet/opt/optimizer/optuna_optimizer/_optuna_optimizer.py,sha256=
|
|
72
|
+
pyfemtet/opt/optimizer/optuna_optimizer/_optuna_optimizer.py,sha256=mlp4jnjK78lV7hiw_SYrIc8k1CuE28z9hxHSfeefTIk,35078
|
|
72
73
|
pyfemtet/opt/optimizer/optuna_optimizer/_pof_botorch/__init__.py,sha256=BFbMNvdXqV9kl1h340pW2sq0-cwNFV5dfTo6UnNnX2M,179
|
|
73
74
|
pyfemtet/opt/optimizer/optuna_optimizer/_pof_botorch/debug-pof-botorch.reccsv,sha256=K6oI9jPi_5yayhBrI9Tm1RX3PoWWKo74TOdqnaPsIy8,1746
|
|
74
75
|
pyfemtet/opt/optimizer/optuna_optimizer/_pof_botorch/enable_nonlinear_constraint.py,sha256=jq8cfkZuEkdd8Gvlr3Do4dl48bKSm9Uu7AcEy1dAf6U,9901
|
|
@@ -85,7 +86,7 @@ pyfemtet/opt/problem/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hS
|
|
|
85
86
|
pyfemtet/opt/problem/problem.py,sha256=X9mro2yVJ6Uw9ck0F0OjG-0M2ReKtuWltu-JUEFIkzQ,10025
|
|
86
87
|
pyfemtet/opt/problem/variable_manager/__init__.py,sha256=uzuraWUZfLzB3uZHIQHFL7uMxWvv7Oaf940zEozXtNY,476
|
|
87
88
|
pyfemtet/opt/problem/variable_manager/_string_as_expression.py,sha256=aTJ9W9Gs6BS0Z_OsxWByJs9dAt32opD2_9913MCggPg,3626
|
|
88
|
-
pyfemtet/opt/problem/variable_manager/_variable_manager.py,sha256=
|
|
89
|
+
pyfemtet/opt/problem/variable_manager/_variable_manager.py,sha256=jtIHFWgVP2jhA3c5uSD388VZHuShR25ZZ8SYz5-6Rro,12785
|
|
89
90
|
pyfemtet/opt/visualization/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
90
91
|
pyfemtet/opt/visualization/_create_wrapped_components.py,sha256=9AltJHr1DM6imZfpNp867rC-uAYqQ-emdgTLChKDrl8,2513
|
|
91
92
|
pyfemtet/opt/visualization/history_viewer/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -97,7 +98,7 @@ pyfemtet/opt/visualization/history_viewer/_complex_components/alert_region.py,sh
|
|
|
97
98
|
pyfemtet/opt/visualization/history_viewer/_complex_components/control_femtet.py,sha256=FQUR9bYtMoj_3bvHXfzAhYMoYpbIWcDP8j7M2EwnYQM,6253
|
|
98
99
|
pyfemtet/opt/visualization/history_viewer/_complex_components/detail_graphs.py,sha256=friaHAJOG5BEUAkoy7ukpO-vUhJ0DlJFwMB2ayNJ4so,19134
|
|
99
100
|
pyfemtet/opt/visualization/history_viewer/_complex_components/main_graph.py,sha256=dMphOHbSV2R3oQvPlIQj7GwtV0phPiBwKniblxTAxMY,25978
|
|
100
|
-
pyfemtet/opt/visualization/history_viewer/_complex_components/pm_graph.py,sha256
|
|
101
|
+
pyfemtet/opt/visualization/history_viewer/_complex_components/pm_graph.py,sha256=y3FSZGIdaWcJQdbACbfIkjuAumW6pXxQ89Wkafnp4pA,29854
|
|
101
102
|
pyfemtet/opt/visualization/history_viewer/_detail_page.py,sha256=2LdCFSCcxZkAH6QMa9q6QX-KLYhVrRf-iTh7jNPrnnA,3406
|
|
102
103
|
pyfemtet/opt/visualization/history_viewer/_helper.py,sha256=276488eouQEo-haK4XXCVM1Vy8_28Vyp5g0l7zt4Sfc,1009
|
|
103
104
|
pyfemtet/opt/visualization/history_viewer/_process_monitor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -171,9 +172,9 @@ pyfemtet/opt/visualization/plotter/parallel_plot_creator.py,sha256=VRhT0CUG1mCHD
|
|
|
171
172
|
pyfemtet/opt/visualization/plotter/pm_graph_creator.py,sha256=7EwmoJlnHwDrpw65NchiA63FIjgGTLq6vTcpTzrSnJo,11841
|
|
172
173
|
pyfemtet/opt/wat_ex14_parametric_jp.femprj,sha256=dMwQMt6yok_PbZLyxPYdmg5wJQwgQDZ4RhS76zdGLGk,177944
|
|
173
174
|
pyfemtet/opt/worker_status.py,sha256=simvPa1AkO1idmPXrF5WjYVEBx3tO7hLhbM3J1rFjdo,3824
|
|
174
|
-
pyfemtet-1.1.
|
|
175
|
-
pyfemtet-1.1.
|
|
176
|
-
pyfemtet-1.1.
|
|
177
|
-
pyfemtet-1.1.
|
|
178
|
-
pyfemtet-1.1.
|
|
179
|
-
pyfemtet-1.1.
|
|
175
|
+
pyfemtet-1.1.6.dist-info/METADATA,sha256=d9ONd4nzpIoizIL5ZFjQ3v_9RJ5vm_eElDuZFwaw7A4,3410
|
|
176
|
+
pyfemtet-1.1.6.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
|
|
177
|
+
pyfemtet-1.1.6.dist-info/entry_points.txt,sha256=Tsb_l_8Z6pyyq2tRfuKiwfJUV3nq_cHoLS61foALtsg,134
|
|
178
|
+
pyfemtet-1.1.6.dist-info/licenses/LICENSE,sha256=LWUL5LlMGjSRTvsalS8_fFuwS4VMw18fJSNWFwDK8pc,1060
|
|
179
|
+
pyfemtet-1.1.6.dist-info/licenses/LICENSE_THIRD_PARTY.txt,sha256=8_9-cgzTpmeuCqItPZb9-lyAZcH2Qp9sZTU_hYuOZIQ,191
|
|
180
|
+
pyfemtet-1.1.6.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|