osis-python 0.5.1__tar.gz → 0.5.3__tar.gz

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 (116) hide show
  1. {osis_python-0.5.1/src/osis_python.egg-info → osis_python-0.5.3}/PKG-INFO +1 -1
  2. {osis_python-0.5.1 → osis_python-0.5.3/src/osis_python.egg-info}/PKG-INFO +1 -1
  3. {osis_python-0.5.1 → osis_python-0.5.3}/src/osis_python.egg-info/SOURCES.txt +8 -1
  4. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/__init__.py +1 -1
  5. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/boundary/manager.py +13 -1
  6. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/core/__init__.py +2 -0
  7. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/core/all_func.py +2 -1
  8. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/core/client.py +11 -2
  9. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/core/command.py +11 -2
  10. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/core/engine.py +32 -7
  11. osis_python-0.5.3/src/pyosis/core/exceptions.py +32 -0
  12. osis_python-0.5.3/src/pyosis/core/references.py +87 -0
  13. osis_python-0.5.3/src/pyosis/display/__init__.py +8 -0
  14. osis_python-0.5.3/src/pyosis/display/interface.py +103 -0
  15. osis_python-0.5.3/src/pyosis/display/manager.py +115 -0
  16. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/dynamic/manager.py +2 -2
  17. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/element/manager.py +13 -1
  18. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/general/interface.py +15 -19
  19. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/geometry/manager.py +8 -0
  20. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/live/manager.py +15 -0
  21. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/load/manager.py +34 -0
  22. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/load/tendon.py +18 -0
  23. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/material/manager.py +8 -1
  24. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/node/manager.py +8 -0
  25. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/project/interface.py +12 -1
  26. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/project/manager.py +30 -6
  27. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/property/manager.py +49 -4
  28. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/section/manager.py +36 -7
  29. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/section/param.py +17 -8
  30. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/thickness/manager.py +8 -0
  31. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/transfer/generator.py +3 -2
  32. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/transfer/out_to_python.py +99 -5
  33. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/transfer/routes.py +6 -0
  34. osis_python-0.5.3/tests/test_delete_occupied.py +432 -0
  35. osis_python-0.5.3/tests/test_project_manager.py +135 -0
  36. {osis_python-0.5.1 → osis_python-0.5.3}/LICENSE +0 -0
  37. {osis_python-0.5.1 → osis_python-0.5.3}/README.md +0 -0
  38. {osis_python-0.5.1 → osis_python-0.5.3}/pyproject.toml +0 -0
  39. {osis_python-0.5.1 → osis_python-0.5.3}/setup.cfg +0 -0
  40. {osis_python-0.5.1 → osis_python-0.5.3}/src/osis_python.egg-info/dependency_links.txt +0 -0
  41. {osis_python-0.5.1 → osis_python-0.5.3}/src/osis_python.egg-info/requires.txt +0 -0
  42. {osis_python-0.5.1 → osis_python-0.5.3}/src/osis_python.egg-info/top_level.txt +0 -0
  43. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/boundary/__init__.py +0 -0
  44. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/boundary/interface.py +0 -0
  45. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/control/__init__.py +0 -0
  46. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/control/control.py +0 -0
  47. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/control/io.py +0 -0
  48. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/control/manager.py +0 -0
  49. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/control/nonlinear.py +0 -0
  50. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/core/apdl_sync.py +0 -0
  51. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/core/basic_manager.py +0 -0
  52. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/core/build.py +0 -0
  53. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/core/sync_apdl_cli.py +0 -0
  54. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/dynamic/__init__.py +0 -0
  55. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/dynamic/load_to_mass.py +0 -0
  56. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/dynamic/modal.py +0 -0
  57. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/dynamic/seismic.py +0 -0
  58. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/element/__init__.py +0 -0
  59. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/element/interface.py +0 -0
  60. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/general/__init__.py +0 -0
  61. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/geometry/__init__.py +0 -0
  62. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/geometry/interface.py +0 -0
  63. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/live/__init__.py +0 -0
  64. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/live/analysis.py +0 -0
  65. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/live/grade.py +0 -0
  66. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/live/lane.py +0 -0
  67. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/load/__init__.py +0 -0
  68. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/load/loadcase.py +0 -0
  69. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/load/static.py +0 -0
  70. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/material/__init__.py +0 -0
  71. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/material/interface.py +0 -0
  72. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/node/__init__.py +0 -0
  73. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/node/interface.py +0 -0
  74. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/post/__init__.py +0 -0
  75. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/post/combine.py +0 -0
  76. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/post/design_check.py +0 -0
  77. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/post/display.py +0 -0
  78. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/post/manager.py +0 -0
  79. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/project/__init__.py +0 -0
  80. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/property/__init__.py +0 -0
  81. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/property/component_thickness.py +0 -0
  82. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/property/coordinate.py +0 -0
  83. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/property/creep_shrink.py +0 -0
  84. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/property/damping.py +0 -0
  85. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/property/pu_curve.py +0 -0
  86. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/quick_building/__init__.py +0 -0
  87. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/quick_building/interface.py +0 -0
  88. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/result/__init__.py +0 -0
  89. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/result/check.py +0 -0
  90. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/result/env.py +0 -0
  91. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/result/loadcase.py +0 -0
  92. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/result/manager.py +0 -0
  93. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/result/result.py +0 -0
  94. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/section/__init__.py +0 -0
  95. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/section/common.py +0 -0
  96. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/section/composite.py +0 -0
  97. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/section/numeric.py +0 -0
  98. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/section/rebar.py +0 -0
  99. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/section/rib.py +0 -0
  100. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/section/steel.py +0 -0
  101. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/settlement/__init__.py +0 -0
  102. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/settlement/interface.py +0 -0
  103. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/settlement/manager.py +0 -0
  104. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/stability/__init__.py +0 -0
  105. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/stability/buckling.py +0 -0
  106. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/stability/manager.py +0 -0
  107. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/stage/__init__.py +0 -0
  108. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/stage/define.py +0 -0
  109. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/stage/manager.py +0 -0
  110. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/stage/overall.py +0 -0
  111. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/thickness/__init__.py +0 -0
  112. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/thickness/interface.py +0 -0
  113. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/transfer/__init__.py +0 -0
  114. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/transfer/matrix.py +0 -0
  115. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/transfer/parser.py +0 -0
  116. {osis_python-0.5.1 → osis_python-0.5.3}/src/pyosis/transfer/split.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: osis-python
3
- Version: 0.5.1
3
+ Version: 0.5.3
4
4
  Summary: A Python client library for Osis APDL
5
5
  Author-email: "CCCC Highway Consultant Co. Ltd." <support@osisbim.com>
6
6
  License-Expression: MIT
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: osis-python
3
- Version: 0.5.1
3
+ Version: 0.5.3
4
4
  Summary: A Python client library for Osis APDL
5
5
  Author-email: "CCCC Highway Consultant Co. Ltd." <support@osisbim.com>
6
6
  License-Expression: MIT
@@ -23,7 +23,12 @@ src/pyosis/core/build.py
23
23
  src/pyosis/core/client.py
24
24
  src/pyosis/core/command.py
25
25
  src/pyosis/core/engine.py
26
+ src/pyosis/core/exceptions.py
27
+ src/pyosis/core/references.py
26
28
  src/pyosis/core/sync_apdl_cli.py
29
+ src/pyosis/display/__init__.py
30
+ src/pyosis/display/interface.py
31
+ src/pyosis/display/manager.py
27
32
  src/pyosis/dynamic/__init__.py
28
33
  src/pyosis/dynamic/load_to_mass.py
29
34
  src/pyosis/dynamic/manager.py
@@ -104,4 +109,6 @@ src/pyosis/transfer/matrix.py
104
109
  src/pyosis/transfer/out_to_python.py
105
110
  src/pyosis/transfer/parser.py
106
111
  src/pyosis/transfer/routes.py
107
- src/pyosis/transfer/split.py
112
+ src/pyosis/transfer/split.py
113
+ tests/test_delete_occupied.py
114
+ tests/test_project_manager.py
@@ -7,7 +7,7 @@ A library for extending OSIS functionality.
7
7
  A library that allows users to use CAE with great flexibility.
8
8
  """
9
9
 
10
- __version__ = "0.5.1"
10
+ __version__ = "0.5.3"
11
11
  __author__ = "CCCC Highway Consultant Co. Ltd." # 中交公路规划设计院 - 工程技术研究中心 - lzh - wjh - myf
12
12
 
13
13
  from .core.engine import OSISEngine
@@ -23,6 +23,7 @@ from typing import Any, Literal
23
23
  from enum import IntEnum
24
24
 
25
25
  from ..core.client import osis_client
26
+ from ..core import get_references, raise_if_occupied
26
27
  from .interface import (
27
28
  osis_boundary_general,
28
29
  osis_boundary_elstcspt,
@@ -638,6 +639,10 @@ class BoundaryManager:
638
639
  return 1
639
640
  return max(bd.no for bd in boundaries) + 1
640
641
 
642
+ def get_dependencies(self, no: int) -> dict[str, list]:
643
+ """查询边界被谁引用"""
644
+ return get_references("Boundary", no=no)
645
+
641
646
  # ── 增删改 ────────────────────────────────
642
647
  def create(self, no: int | None, type: str, *args: Any, **kwargs: Any) -> Boundary:
643
648
  """创建边界(便捷入口,内部转发到对应 create_* 方法)
@@ -846,7 +851,14 @@ class BoundaryManager:
846
851
  return self.get(no) # type: ignore[return-value]
847
852
 
848
853
  def delete(self, no: int) -> None:
849
- """删除边界"""
854
+ """删除边界
855
+
856
+ Raises:
857
+ DependencyError: 存在依赖项时
858
+ RuntimeError: 删除失败时抛出异常
859
+ """
860
+ deps = self.get_dependencies(no)
861
+ raise_if_occupied("Boundary", deps, no=no)
850
862
  ok, err = osis_boundary_del(no)
851
863
  if not ok:
852
864
  raise RuntimeError(f"删除边界 {no} 失败: {err}")
@@ -10,3 +10,5 @@ OSISEngine中的函数,将会分发到各个模块,被再次封装,意图
10
10
 
11
11
  from .command import REGISTRY, osis_run, set_run_mode
12
12
  from .client import set_osis_port, set_osis_url
13
+ from .exceptions import DependencyError
14
+ from .references import get_references, raise_if_occupied
@@ -19,4 +19,5 @@ from ..settlement import *
19
19
  from ..stability import *
20
20
 
21
21
  from ..post import *
22
- from ..result import *
22
+ from ..result import *
23
+ from ..display import *
@@ -26,6 +26,8 @@ session.mount("https://", adapter) # 如果你后续用HTTPS
26
26
 
27
27
  DEFAULT_PORT = 18080
28
28
  DEFAULT_URL = "http://localhost"
29
+ DEFAULT_TIMEOUT = 300
30
+ DEFAULT_SOLVE_TIMEOUT = 600
29
31
 
30
32
  def set_osis_url(url):
31
33
  '''
@@ -42,12 +44,19 @@ def set_osis_port(port):
42
44
  DEFAULT_PORT = port
43
45
 
44
46
  # ========== 通用客户端函数(复用连接池) ==========
45
- def osis_client(func_name: str, payload: dict, base_url=None) -> dict:
47
+ def osis_client(
48
+ func_name: str,
49
+ payload: dict,
50
+ base_url=None,
51
+ timeout: float | None = None,
52
+ ) -> dict:
46
53
  """
47
54
  通用 OSIS 接口客户端(复用连接池,高效批量调用)
48
55
  Args:
49
56
  func_name: C++ 接口名(如 "OSIS_Run")
50
57
  payload: 请求参数字典(自动序列化为 JSON)
58
+ base_url: url
59
+ timeout: HTTP 超时秒数,默认 DEFAULT_TIMEOUT
51
60
  Returns:
52
61
  异常时返回 (False, 错误信息)
53
62
  """
@@ -59,7 +68,7 @@ def osis_client(func_name: str, payload: dict, base_url=None) -> dict:
59
68
  url,
60
69
  data=json.dumps(payload, ensure_ascii=False).encode("utf-8"),
61
70
  headers={"Content-Type": "application/json; charset=utf-8"},
62
- timeout=300,
71
+ timeout=timeout if timeout is not None else DEFAULT_TIMEOUT,
63
72
  )
64
73
 
65
74
  data = None
@@ -19,7 +19,11 @@ from .client import osis_client
19
19
  # f.write(f"[{timestamp}] {text}\n")
20
20
  # f.close()
21
21
 
22
- def osis_run(strCmd: str="", mode: Literal["stash", "exec"]="exec") -> tuple[bool, str]:
22
+ def osis_run(
23
+ strCmd: str = "",
24
+ mode: Literal["stash", "exec"] = "exec",
25
+ timeout: float | None = None,
26
+ ) -> tuple[bool, str]:
23
27
  """
24
28
  http 模拟 C++ 原生 OSIS_Run 函数
25
29
  Args:
@@ -27,11 +31,16 @@ def osis_run(strCmd: str="", mode: Literal["stash", "exec"]="exec") -> tuple[boo
27
31
  mode: 运行模式,此参数为了同时执行多条命令提高效率
28
32
  * 使用 stash 仅会将命令流存到OSIS中,不会执行
29
33
  * 收到 exec 信号才会执行暂存包括当前的所有命令流。
34
+ timeout: HTTP 超时秒数,默认由 osis_client 决定
30
35
 
31
36
  Returns:
32
37
  tuple (bool, str): 是否成功,失败原因
33
38
  """
34
- response = osis_client("OSIS_Run", locals())
39
+ response = osis_client(
40
+ "OSIS_Run",
41
+ {"strCmd": strCmd, "mode": mode},
42
+ timeout=timeout,
43
+ )
35
44
  return response['success'], response['error']
36
45
 
37
46
  def _log(text, log_dir="pyosis_logs"):
@@ -41,6 +41,7 @@ from ..stability.manager import StabilityManager, stability_manager
41
41
  from ..dynamic.manager import DynamicManager, dynamic_manager
42
42
  from ..post.manager import PostManager, post_manager
43
43
  from ..result.manager import ResultManager, result_manager
44
+ from ..display.manager import DisplayManager, display_manager
44
45
  from ..general.interface import (
45
46
  osis_matrix,
46
47
  output_result_for_calc_book,
@@ -69,7 +70,7 @@ class OSISEngine:
69
70
  - tendon: 钢束管理器(含 prop/shape 子管理器)
70
71
  - live: 活载管理器(含 grade/lane/case 子管理器)
71
72
  - geometry: 几何管理器(三维样条曲线)
72
- - property: 属性管理器(坐标系、收缩徐变、阻尼等)
73
+ - prop: 属性管理器(property 坐标系、收缩徐变、阻尼等)
73
74
  - thickness: 厚度管理器(壳厚度特性)
74
75
  - control: 控制管理器(全局参数、分析设置)
75
76
  - project: 项目管理器(创建、打开、保存项目)
@@ -78,6 +79,7 @@ class OSISEngine:
78
79
  - dynamic: 动力分析管理器(荷载转换质量、模态、反应谱)
79
80
  - post: 后处理管理器(荷载组合、规范验算、结果显示)
80
81
  - result: 结果导出管理器(工况结果、包络结果、验算结果)
82
+ - display: 显示管理器(边界 / 荷载 / 钢束显隐等)
81
83
 
82
84
  通用操作可直接通过 engine 调用:
83
85
  - run(), solve(), replot(), clear(), clc()
@@ -114,6 +116,9 @@ class OSISEngine:
114
116
  ### 后处理 ###
115
117
  self._post = post_manager
116
118
  self._result = result_manager
119
+
120
+ ### 显示 ###
121
+ self._display = display_manager
117
122
 
118
123
  # OSIS端口与网址
119
124
  if port is None:
@@ -228,6 +233,13 @@ class OSISEngine:
228
233
  """结果导出管理器(工况结果、包络结果、验算结果)"""
229
234
  return self._result
230
235
 
236
+ ### 显示 ###
237
+
238
+ @property
239
+ def display(self) -> DisplayManager:
240
+ """显示管理器(边界 / 荷载 / 钢束显隐等)"""
241
+ return self._display
242
+
231
243
  # ──────────────────────────────────────────
232
244
  # 通用操作(直接暴露 general 和 core 的函数)
233
245
  # ──────────────────────────────────────────
@@ -246,9 +258,13 @@ class OSISEngine:
246
258
  if not ok:
247
259
  raise RuntimeError(f"执行失败: {err}")
248
260
 
249
- def solve(self) -> None:
250
- """求解工程"""
251
- ok, err = osis_solve()
261
+ def solve(self, timeout: float | None = None) -> None:
262
+ """求解工程
263
+
264
+ Args:
265
+ timeout: HTTP 超时秒数,默认 600(10 分钟)
266
+ """
267
+ ok, err = osis_solve(timeout=timeout)
252
268
  if not ok:
253
269
  raise RuntimeError(f"求解失败: {err}")
254
270
 
@@ -293,9 +309,14 @@ class OSISEngine:
293
309
  # 便捷方法(委托给 project manager)
294
310
  # ──────────────────────────────────────────
295
311
 
296
- def save_project(self) -> None:
297
- """保存当前项目"""
298
- self._project.save()
312
+ def save_project(self, filepath: str = "") -> None:
313
+ """保存项目
314
+
315
+ Args:
316
+ filepath: 工程文件路径。为空时使用当前项目路径;
317
+ 非空时使用传入路径。
318
+ """
319
+ self._project.save(filepath)
299
320
 
300
321
  def new_project(self, type: int = 1, filepath: str = "") -> None:
301
322
  """新建项目
@@ -314,6 +335,10 @@ class OSISEngine:
314
335
  """
315
336
  self._project.open(filepath)
316
337
 
338
+ def close(self) -> None:
339
+ """关闭 OSIS 软件"""
340
+ self._project.close()
341
+
317
342
  # ──────────────────────────────────────────
318
343
  # 便捷方法(委托给 control manager)
319
344
  # ──────────────────────────────────────────
@@ -0,0 +1,32 @@
1
+ """
2
+ pyosis 自定义异常
3
+ """
4
+
5
+ class DependencyError(RuntimeError):
6
+ """删除实体时存在依赖项
7
+
8
+ Attributes:
9
+ entity_type: 实体类型字符串,如 "Material"
10
+ id_value: 实体编号(int)或名称(str)
11
+ no: 按编号寻址时的编号,否则为 None
12
+ name: 按名称寻址时的名称,否则为 None
13
+ dependencies: 依赖关系字典
14
+ """
15
+ def __init__(self, entity_type: str, id_value: int | str, dependencies: dict[str, list]):
16
+ self.entity_type = entity_type
17
+ self.id_value = id_value
18
+ self.dependencies = dependencies
19
+ if isinstance(id_value, int):
20
+ self.no = id_value
21
+ self.name = None
22
+ label = f"#{id_value}"
23
+ else:
24
+ self.no = None
25
+ self.name = id_value
26
+ label = id_value
27
+
28
+ lines = [f"无法删除 {entity_type} {label},存在以下依赖:"]
29
+ for kind, refs in dependencies.items():
30
+ if refs:
31
+ lines.append(f" - {kind}: {refs}")
32
+ super().__init__("\n".join(lines))
@@ -0,0 +1,87 @@
1
+ """
2
+ 通用引用查询客户端封装
3
+
4
+ 后端 C++ 暴露 /GetReferences 接口,根据 entityType 字符串分派
5
+ 到对应 Info 类的 getRelated* 方法。
6
+ """
7
+ from __future__ import annotations
8
+ from typing import Literal
9
+ from .client import osis_client
10
+ from .exceptions import DependencyError
11
+
12
+ # 支持的实体类型(与 C++ GetReferences.cpp 中的 if-else 分支对齐)
13
+ EntityType = Literal[
14
+ "Material", "Section", "Node", "Element", "Boundary",
15
+ "TendonShape", "TendonProp", "LoadCase", "LiveGrade", "LiveLane",
16
+ "CoorSys", "CreepShrink", "PUCurve", "ShellThickness",
17
+ "Damping", "Spline",
18
+ ]
19
+
20
+
21
+ """
22
+ 通用引用查询客户端封装
23
+ 后端 /GetReferences 统一字符串协议:{entityType, idKey("no"|"name"), idValue}
24
+ """
25
+
26
+
27
+
28
+ def get_references(entity_type: str, *, no: int | None = None, name: str | None = None) -> dict[str, list]:
29
+ """查询某个实体被哪些其他实体引用
30
+
31
+ Args:
32
+ entity_type: 实体类型,如 "Material" / "Node" / "TendonShape" / "LoadCase"
33
+ no: 按编号寻址时传(Material/Section/Node/Element)
34
+ name: 按名称寻址时传(TendonShape/LoadCase/...)
35
+ no 与 name 二选一。
36
+
37
+ Returns:
38
+ 引用关系字典,如 {"elements":[101,102], "loads":["自重"], ...}
39
+ 无依赖时返回空字典。
40
+
41
+ Raises:
42
+ ValueError: no/name 都没传,或都传了
43
+ RuntimeError: 查询失败
44
+ """
45
+ if no is not None and name is not None:
46
+ raise ValueError("no 与 name 只能传一个")
47
+ if no is None and name is None:
48
+ raise ValueError("必须提供 no 或 name")
49
+
50
+ if no is not None:
51
+ id_key, id_value = "no", str(no)
52
+ else:
53
+ id_key, id_value = "name", name
54
+
55
+ resp = osis_client("GetReferences", {
56
+ "entityType": entity_type,
57
+ "idKey": id_key,
58
+ "idValue": id_value,
59
+ })
60
+ if not resp.get("success"):
61
+ raise RuntimeError(f"查询 {entity_type}({id_key}={id_value}) 引用失败: {resp.get('error')}")
62
+ return resp.get("data") or {}
63
+
64
+
65
+ def raise_if_occupied(
66
+ entity_type: str,
67
+ deps: dict[str, list],
68
+ *,
69
+ no: int | None = None,
70
+ name: str | None = None,
71
+ ) -> None:
72
+ """存在非空依赖时抛出 DependencyError。
73
+
74
+ Args:
75
+ entity_type: 实体类型,如 "Material" / "TendonShape"
76
+ deps: get_references / get_dependencies 返回的依赖字典
77
+ no: 按编号寻址时传
78
+ name: 按名称寻址时传
79
+ """
80
+ non_empty = {k: v for k, v in deps.items() if v}
81
+ if not non_empty:
82
+ return
83
+ if no is None and name is None:
84
+ raise ValueError("必须提供 no 或 name")
85
+ id_value = no if no is not None else name
86
+ raise DependencyError(entity_type, id_value, non_empty)
87
+
@@ -0,0 +1,8 @@
1
+ """
2
+ pyosis.display
3
+
4
+ 显示控制(显隐、视图方向、显示开关等)
5
+ """
6
+
7
+ from .interface import *
8
+ from .manager import DisplayManager, display_manager
@@ -0,0 +1,103 @@
1
+ """显示控制命令接口
2
+
3
+ 控制边界、荷载、钢束显隐,以及视图方向、显示开关等。
4
+ """
5
+
6
+ from typing import Literal, Sequence, Union
7
+
8
+ from ..core import REGISTRY
9
+
10
+
11
+ @REGISTRY.register("DispCtrl")
12
+ def osis_disp_ctrl(
13
+ eObject: Literal["bc", "boundary", "lg", "load", "td", "tendon"],
14
+ eType: str,
15
+ ids: Union[str, int, Sequence[Union[str, int]]],
16
+ bShow: Literal[0, 1] = 1,
17
+ ):
18
+ """控制边界 / 荷载 / 钢束的显示与隐藏。
19
+
20
+ 格式: ``dispctrl,<Object>,<Type>,<Number/Name...>,<0|1>``
21
+
22
+ Args:
23
+ eObject (str): 对象类型
24
+ * ``bc`` / ``boundary`` = 边界
25
+ * ``lg`` / ``load`` = 荷载
26
+ * ``td`` / ``tendon`` = 钢束
27
+ eType (str): 子类型
28
+ * 边界: ``all``, ``general``, ``mstslv``, ``release``, ``elstcspt``,
29
+ ``generalelstcspt``, ``rigid``, ``secfactor``
30
+ * 荷载: ``all``, ``gravity``, ``nforce``, ``line``, ``pointforce``,
31
+ ``pointmoment``, ``displacement``, ``initial``, ``utemp``, ``gtemp``,
32
+ ``pst``, ``cforce``, ``elementsurface``
33
+ * 钢束: 通常为 ``all``
34
+ ids: 编号或名称
35
+ * ``all`` = 全部
36
+ * 单个编号 / 名称,或多个组成的序列(如 ``[1, 2, "3to10"]``、``["T1", "T2"]``)
37
+ bShow (int): ``0`` = 隐藏,``1`` = 显示
38
+
39
+ Returns:
40
+ tuple (bool, str): 是否成功,失败原因
41
+
42
+ Examples:
43
+ >>> # 显示全部边界
44
+ >>> osis_disp_ctrl("bc", "all", "all", 1)
45
+ >>> # 显示一般边界 1、2、3to10
46
+ >>> osis_disp_ctrl("bc", "general", [1, 2, "3to10"], 1)
47
+ >>> # 显示全部节点力荷载
48
+ >>> osis_disp_ctrl("lg", "nforce", "all", 1)
49
+ >>> # 显示名为 DeadLoad 的荷载
50
+ >>> osis_disp_ctrl("lg", "all", "DeadLoad", 1)
51
+ >>> # 隐藏钢束 1、2、3to10
52
+ >>> osis_disp_ctrl("td", "all", [1, 2, "3to10"], 0)
53
+ >>> # 显示钢束 T1、T2
54
+ >>> osis_disp_ctrl("td", "all", ["T1", "T2"], 1)
55
+ """
56
+ pass
57
+
58
+
59
+ @REGISTRY.register("/control")
60
+ def osis_control(
61
+ eAction: str,
62
+ eArg: str | None = None,
63
+ ):
64
+ """视图 / 界面控制命令。
65
+
66
+ 格式: ``/control,<Action>[,<Arg>]``
67
+
68
+ Args:
69
+ eAction (str): 子命令
70
+ * ``view`` = 切换视图方向(配合 eArg)
71
+ * 其他如 ``quickCreateModel`` 等
72
+ eArg (str | None): 子命令参数
73
+ * 当 eAction 为 ``view`` 时: ``standard`` / ``top`` / ``right`` / ``front``
74
+
75
+ Returns:
76
+ tuple (bool, str): 是否成功,失败原因
77
+
78
+ Examples:
79
+ >>> osis_control("view", "standard")
80
+ >>> osis_control("view", "top")
81
+ >>> osis_control("view", "right")
82
+ >>> osis_control("view", "front")
83
+ """
84
+ pass
85
+
86
+
87
+ @REGISTRY.register("Plsm")
88
+ def osis_plsm(bFlag: Literal[0, 1] = 1):
89
+ """显示开关(Plsm)。
90
+
91
+ 格式: ``plsm,<0|1>``
92
+
93
+ Args:
94
+ bFlag (int): ``0`` = 关,``1`` = 开
95
+
96
+ Returns:
97
+ tuple (bool, str): 是否成功,失败原因
98
+
99
+ Examples:
100
+ >>> osis_plsm(1)
101
+ >>> osis_plsm(0)
102
+ """
103
+ pass
@@ -0,0 +1,115 @@
1
+ """显示管理器 - 控制显隐、视图方向与显示开关
2
+
3
+ 设计理念:
4
+ - 隐藏底层命令接口细节,提供原生 Python 风格 API
5
+ - 无状态设计,操作直接提交到 OSIS
6
+
7
+ 用法:
8
+ >>> from pyosis.display import display_manager
9
+ >>> display_manager.disp_ctrl("bc", "all", "all", 1)
10
+ >>> display_manager.set_view("top")
11
+ >>> display_manager.set_plsm(1)
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ from typing import Literal, Sequence, Union
17
+
18
+ from .interface import osis_control, osis_disp_ctrl, osis_plsm
19
+
20
+
21
+ class DisplayManager:
22
+ """显示管理器
23
+
24
+ 控制边界 / 荷载 / 钢束显隐、视图方向与显示开关。
25
+ """
26
+
27
+ def disp_ctrl(
28
+ self,
29
+ obj: Literal["bc", "boundary", "lg", "load", "td", "tendon"],
30
+ type: str,
31
+ ids: Union[str, int, Sequence[Union[str, int]]],
32
+ show: Literal[0, 1] = 1,
33
+ ) -> None:
34
+ """控制边界 / 荷载 / 钢束的显示与隐藏。
35
+
36
+ Args:
37
+ obj: 对象类型
38
+ * ``bc`` / ``boundary`` = 边界
39
+ * ``lg`` / ``load`` = 荷载
40
+ * ``td`` / ``tendon`` = 钢束
41
+ type: 子类型(``all`` 或具体类型,见 ``osis_disp_ctrl`` 文档)
42
+ ids: 编号或名称(``all`` / 单个 / 序列)
43
+ show: ``0`` = 隐藏,``1`` = 显示
44
+
45
+ Raises:
46
+ RuntimeError: 操作失败时抛出异常
47
+
48
+ Examples:
49
+ >>> display_manager.disp_ctrl("bc", "all", "all", 1)
50
+ >>> display_manager.disp_ctrl("bc", "general", [1, 2, "3to10"], 1)
51
+ >>> display_manager.disp_ctrl("lg", "nforce", "all", 1)
52
+ >>> display_manager.disp_ctrl("td", "all", ["T1", "T2"], 1)
53
+ """
54
+ ok, err = osis_disp_ctrl(obj, type, ids, show)
55
+ if not ok:
56
+ raise RuntimeError(f"显示控制失败: {err}")
57
+
58
+ def control(self, action: str, arg: str | None = None) -> None:
59
+ """视图 / 界面控制(对应 ``/control,...``)。
60
+
61
+ Args:
62
+ action: 子命令,如 ``view``、``quickCreateModel``
63
+ arg: 子命令参数;``view`` 时为 ``standard`` / ``top`` / ``right`` / ``front``
64
+
65
+ Raises:
66
+ RuntimeError: 操作失败时抛出异常
67
+ """
68
+ ok, err = osis_control(action, arg)
69
+ if not ok:
70
+ raise RuntimeError(f"界面控制失败: {err}")
71
+
72
+ def set_view(
73
+ self,
74
+ view: Literal["standard", "top", "right", "front"] = "standard",
75
+ ) -> None:
76
+ """切换视图方向。
77
+
78
+ Args:
79
+ view: ``standard`` / ``top`` / ``right`` / ``front``
80
+
81
+ Raises:
82
+ RuntimeError: 操作失败时抛出异常
83
+
84
+ Examples:
85
+ >>> display_manager.set_view("top")
86
+ >>> display_manager.set_view("front")
87
+ """
88
+ self.control("view", view)
89
+
90
+ def set_plsm(self, enabled: Literal[0, 1] = 1) -> None:
91
+ """显示开关(Plsm)。
92
+
93
+ Args:
94
+ enabled: ``0`` = 关,``1`` = 开
95
+
96
+ Raises:
97
+ RuntimeError: 操作失败时抛出异常
98
+
99
+ Examples:
100
+ >>> display_manager.set_plsm(1)
101
+ >>> display_manager.set_plsm(0)
102
+ """
103
+ ok, err = osis_plsm(enabled)
104
+ if not ok:
105
+ raise RuntimeError(f"设置 Plsm 失败: {err}")
106
+
107
+ def __repr__(self) -> str:
108
+ return "DisplayManager()"
109
+
110
+
111
+ # ═════════════════════════════════════════════
112
+ # 全局单例
113
+ # ═════════════════════════════════════════════
114
+
115
+ display_manager = DisplayManager()
@@ -579,7 +579,7 @@ class RspecAnalManager:
579
579
 
580
580
  def _load(self) -> list[RspecAnal]:
581
581
  """从服务端加载所有反应谱工况信息"""
582
- resp = osis_client("GetAllSeisRespSpecInfo", {})
582
+ resp = osis_client("GetAllRespSpecInfo", {})
583
583
  if not resp['success']:
584
584
  raise RuntimeError(f"{resp['error']}")
585
585
  rsp = [RspecAnal._from_dict(d) for d in resp.get("data", [])]
@@ -594,7 +594,7 @@ class RspecAnalManager:
594
594
  names = [str(name)]
595
595
  if not isinstance(names, list):
596
596
  raise TypeError(f"不支持的名称类型: {type(name)}")
597
- resp = osis_client("GetSeisRespSpecByNames", {"name": names})
597
+ resp = osis_client("GetRespSpecInfoByNames", {"name": names})
598
598
  if not resp['success']:
599
599
  raise RuntimeError(f"{resp['error']}")
600
600
  rsp = [RspecAnal._from_dict(d) if d else None for d in resp.get("data", [])]
@@ -15,6 +15,7 @@ from dataclasses import dataclass, field
15
15
  from typing import Any, Literal
16
16
  from enum import Enum
17
17
  from ..core.client import osis_client
18
+ from ..core import get_references, raise_if_occupied
18
19
  from .interface import (
19
20
  osis_element_beam3d,
20
21
  osis_element_truss,
@@ -555,6 +556,10 @@ class ElementManager:
555
556
  ele_no = [ele.no for ele in elements]
556
557
  return max(ele_no) + 1
557
558
 
559
+ def get_dependencies(self, no: int) -> dict[str, list]:
560
+ """查询单元被谁引用"""
561
+ return get_references("Element", no=no)
562
+
558
563
  # ── 增删改 ────────────────────────────────
559
564
  def create(self, no: int | None, type: str, *args: Any, **kwargs: Any) -> Element:
560
565
  """创建单元(便捷入口,内部转发到对应 create_* 方法)
@@ -699,7 +704,14 @@ class ElementManager:
699
704
  return self.get(no)
700
705
 
701
706
  def delete(self, no: int) -> None:
702
- """删除单元"""
707
+ """删除单元
708
+
709
+ Raises:
710
+ DependencyError: 存在依赖项时
711
+ RuntimeError: 删除失败时抛出异常
712
+ """
713
+ deps = self.get_dependencies(no)
714
+ raise_if_occupied("Element", deps, no=no)
703
715
  ok, err = osis_element_del(no)
704
716
  if not ok:
705
717
  raise RuntimeError(f"删除单元 {no} 失败: {err}")