onec-interactive-runtime-core 0.1.19__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 (87) hide show
  1. onec_interactive_runtime_core-0.1.19.dist-info/METADATA +12 -0
  2. onec_interactive_runtime_core-0.1.19.dist-info/RECORD +87 -0
  3. onec_interactive_runtime_core-0.1.19.dist-info/WHEEL +4 -0
  4. onec_interactive_runtime_core-0.1.19.dist-info/licenses/COPYRIGHT +9 -0
  5. onec_interactive_runtime_core-0.1.19.dist-info/licenses/LICENSE +232 -0
  6. onec_interactive_runtime_core-0.1.19.dist-info/licenses/THIRD_PARTY_NOTICES.txt +32 -0
  7. onec_runtime/AGENTS.md +7 -0
  8. onec_runtime/__init__.py +3 -0
  9. onec_runtime/artifacts.py +59 -0
  10. onec_runtime/bootstrap.py +310 -0
  11. onec_runtime/breakpoint_workspace.py +249 -0
  12. onec_runtime/bsl/__init__.py +139 -0
  13. onec_runtime/bsl/diagnostics.py +1046 -0
  14. onec_runtime/bsl/full_ast_worker_projection.py +522 -0
  15. onec_runtime/bsl/generated_semantic_parser.py +6322 -0
  16. onec_runtime/bsl/lexer.py +164 -0
  17. onec_runtime/bsl/module_catalog.py +420 -0
  18. onec_runtime/bsl/module_delta.py +1079 -0
  19. onec_runtime/bsl/module_universe.py +1877 -0
  20. onec_runtime/bsl/notebook_cells.py +232 -0
  21. onec_runtime/bsl/notebook_method_globals.py +74 -0
  22. onec_runtime/bsl/notebook_methods.py +175 -0
  23. onec_runtime/bsl/parser_artifact_identity.py +119 -0
  24. onec_runtime/bsl/parser_target.py +388 -0
  25. onec_runtime/bsl/preprocessor.py +16 -0
  26. onec_runtime/bsl/semantic_lowering.py +1539 -0
  27. onec_runtime/bsl/source_maps.py +2411 -0
  28. onec_runtime/bsl/worker_dependency_resolver.py +289 -0
  29. onec_runtime/bsl/worker_preprocessor.py +247 -0
  30. onec_runtime/bsl/worker_projection_model.py +137 -0
  31. onec_runtime/bsl/worker_reload_source_map.py +1697 -0
  32. onec_runtime/capture.py +113 -0
  33. onec_runtime/capture_source.py +453 -0
  34. onec_runtime/compact_table.py +376 -0
  35. onec_runtime/compact_table_backend.py +500 -0
  36. onec_runtime/config.py +198 -0
  37. onec_runtime/configurator_agent.py +520 -0
  38. onec_runtime/controller_worker.py +400 -0
  39. onec_runtime/credentials.py +18 -0
  40. onec_runtime/epf_container.py +196 -0
  41. onec_runtime/errors.py +205 -0
  42. onec_runtime/experiment.py +130 -0
  43. onec_runtime/extension_bundle.py +944 -0
  44. onec_runtime/extension_lifecycle.py +402 -0
  45. onec_runtime/extension_state.py +222 -0
  46. onec_runtime/fault_injection.py +30 -0
  47. onec_runtime/kernel.py +179 -0
  48. onec_runtime/lease.py +123 -0
  49. onec_runtime/observation.py +287 -0
  50. onec_runtime/performance_profile.py +245 -0
  51. onec_runtime/privacy.py +263 -0
  52. onec_runtime/processes.py +265 -0
  53. onec_runtime/prototype_runtime.py +2644 -0
  54. onec_runtime/rdbg/__init__.py +1 -0
  55. onec_runtime/rdbg/models.py +130 -0
  56. onec_runtime/rdbg/reconnect.py +59 -0
  57. onec_runtime/rdbg/session.py +913 -0
  58. onec_runtime/rdbg/transport.py +138 -0
  59. onec_runtime/rdbg/xml_codec.py +980 -0
  60. onec_runtime/recovery.py +106 -0
  61. onec_runtime/recovery_journal.py +79 -0
  62. onec_runtime/resources/extension/OnecInteractiveRuntime.cfe +0 -0
  63. onec_runtime/resources/extension/extension-manifest.json +108 -0
  64. onec_runtime/runtime_api.py +5272 -0
  65. onec_runtime/runtime_contracts.py +196 -0
  66. onec_runtime/server_worker.py +2034 -0
  67. onec_runtime/session.py +2123 -0
  68. onec_runtime/startup_diagnostics.py +45 -0
  69. onec_runtime/stop_routing.py +65 -0
  70. onec_runtime/supervised_processes.py +232 -0
  71. onec_runtime/supervised_runtime.py +512 -0
  72. onec_runtime/supervisor.py +363 -0
  73. onec_runtime/supervisor_model.py +148 -0
  74. onec_runtime/supervisor_protocol.py +77 -0
  75. onec_runtime/table_materialization.py +471 -0
  76. onec_runtime/table_transfer_backend.py +203 -0
  77. onec_runtime/table_value.py +311 -0
  78. onec_runtime/toolchain.py +730 -0
  79. onec_runtime/value_materialization.py +432 -0
  80. onec_runtime/value_transfer_backend.py +199 -0
  81. onec_runtime/worker_breakpoints.py +1431 -0
  82. onec_runtime/worker_epf.py +313 -0
  83. onec_runtime/worker_epf_template.py +53 -0
  84. onec_runtime/worker_stage_protocol.py +516 -0
  85. onec_runtime/worker_universe.py +3772 -0
  86. onec_runtime_build/__init__.py +1 -0
  87. onec_runtime_build/parser_target_development.py +116 -0
@@ -0,0 +1,45 @@
1
+ """Bounded, allowlisted explanations for native 1C startup logs."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pathlib import Path
6
+
7
+
8
+ def startup_log_hint(log_path: Path) -> str | None:
9
+ """Classify known 1C failures without copying private log text into errors."""
10
+ try:
11
+ with log_path.open("rb") as stream:
12
+ payload = stream.read(64 * 1024)
13
+ except OSError:
14
+ return None
15
+ if payload.startswith((b"\xff\xfe", b"\xfe\xff")):
16
+ text = payload.decode("utf-16", errors="replace")
17
+ else:
18
+ text = payload.decode("utf-8-sig", errors="replace")
19
+ if "\ufffd" in text:
20
+ text = payload.decode("cp1251", errors="replace")
21
+ lowered = text.casefold()
22
+ if (
23
+ "ошибка программного лицензирования" in lowered
24
+ and "не предусматривает возможность запуска сервера 1с:предприятия" in lowered
25
+ ):
26
+ return (
27
+ "используемая лицензия 1С не разрешает запуск сервера "
28
+ "1С:Предприятия; проверьте серверную лицензию"
29
+ )
30
+ if (
31
+ "error locking infobase for configuration" in lowered
32
+ or "ошибка блокировки информационной базы" in lowered
33
+ ):
34
+ return "база заблокирована; закройте Конфигуратор для этой базы и повторите запуск"
35
+ if (
36
+ "the infobase user is not authenticated" in lowered
37
+ or "пользователь иб не идентифицирован" in lowered
38
+ ):
39
+ return "пользователь ИБ не прошёл аутентификацию; проверьте username и password"
40
+ if (
41
+ "the infobase is not found" in lowered
42
+ or "информационная база не найдена" in lowered
43
+ ):
44
+ return "информационная база не найдена; проверьте путь File или адрес и имя Srvr/Ref"
45
+ return None
@@ -0,0 +1,65 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from enum import Enum
5
+
6
+ from onec_runtime.rdbg.models import ModuleLocation, StopEvent
7
+
8
+
9
+ class StopReason(Enum):
10
+ MAIN_SERVICE = "main_service"
11
+ CAPTURE = "capture"
12
+ USER_BREAKPOINT = "user_breakpoint"
13
+ PAUSE = "pause"
14
+ EXCEPTION = "exception"
15
+ UNKNOWN = "unknown"
16
+
17
+
18
+ @dataclass(frozen=True, slots=True)
19
+ class BreakpointRegistry:
20
+ service: ModuleLocation
21
+ captures: tuple[ModuleLocation, ...] = ()
22
+ users: tuple[ModuleLocation, ...] = ()
23
+
24
+ def __post_init__(self) -> None:
25
+ locations = self.full_locations
26
+ if len(set(locations)) != len(locations):
27
+ raise ValueError("Breakpoint registry groups overlap")
28
+
29
+ @property
30
+ def full_locations(self) -> tuple[ModuleLocation, ...]:
31
+ return (self.service, *self.captures, *self.users)
32
+
33
+ @property
34
+ def evaluation_locations(self) -> tuple[ModuleLocation, ...]:
35
+ return (self.service, *self.users)
36
+
37
+
38
+ @dataclass(frozen=True, slots=True)
39
+ class ClassifiedStop:
40
+ event: StopEvent
41
+ reason: StopReason
42
+
43
+
44
+ def classify_stop(
45
+ event: StopEvent,
46
+ registry: BreakpointRegistry,
47
+ *,
48
+ worker_locations: tuple[ModuleLocation, ...] = (),
49
+ ) -> ClassifiedStop:
50
+ if event.runtime_error:
51
+ reason = StopReason.EXCEPTION
52
+ elif event.suspended_by_other is True:
53
+ reason = StopReason.PAUSE
54
+ elif event.stop_by_breakpoint is True:
55
+ if event.location == registry.service:
56
+ reason = StopReason.MAIN_SERVICE
57
+ elif event.location in registry.captures:
58
+ reason = StopReason.CAPTURE
59
+ elif event.location in registry.users or event.location in worker_locations:
60
+ reason = StopReason.USER_BREAKPOINT
61
+ else:
62
+ reason = StopReason.UNKNOWN
63
+ else:
64
+ reason = StopReason.UNKNOWN
65
+ return ClassifiedStop(event, reason)
@@ -0,0 +1,232 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Callable
4
+ from dataclasses import fields
5
+ from enum import Enum
6
+ import multiprocessing
7
+ from multiprocessing.connection import Connection
8
+ from pathlib import Path
9
+ from time import monotonic
10
+ from uuid import UUID
11
+
12
+ from onec_runtime.config import RuntimeConfig
13
+ from onec_runtime.errors import (
14
+ CommandTimeout,
15
+ InvalidMessageSequence,
16
+ ProcessStartError,
17
+ )
18
+ from onec_runtime.processes import FileModeProcesses
19
+ from onec_runtime.supervisor_protocol import (
20
+ ControlMessage,
21
+ MessageKind,
22
+ MessageReceiver,
23
+ )
24
+
25
+
26
+ def _is_data_only(value: object, seen: set[int] | None = None) -> bool:
27
+ value_type = type(value)
28
+ if value_type in {
29
+ type(None),
30
+ bool,
31
+ int,
32
+ float,
33
+ str,
34
+ bytes,
35
+ type(Path()),
36
+ UUID,
37
+ }:
38
+ return True
39
+
40
+ seen = seen if seen is not None else set()
41
+ identity = id(value)
42
+ if identity in seen:
43
+ return False
44
+ seen.add(identity)
45
+ try:
46
+ if value_type is dict:
47
+ return all(
48
+ _is_data_only(key, seen) and _is_data_only(item, seen)
49
+ for key, item in value.items()
50
+ )
51
+ if value_type in {list, tuple, set, frozenset}:
52
+ return all(_is_data_only(item, seen) for item in value)
53
+ if value_type is RuntimeConfig:
54
+ return all(
55
+ _is_data_only(getattr(value, field.name), seen)
56
+ for field in fields(RuntimeConfig)
57
+ )
58
+ return False
59
+ finally:
60
+ seen.remove(identity)
61
+
62
+
63
+ class _ControllerStartupState(Enum):
64
+ WAITING_FOR_DEBUG_READY = "waiting_for_debug_ready"
65
+ READY = "ready"
66
+ FAILED = "failed"
67
+
68
+
69
+ class SupervisedGenerationProcesses:
70
+ """Parent-owned OS processes and Controller IPC for one generation."""
71
+
72
+ def __init__(
73
+ self,
74
+ config: RuntimeConfig,
75
+ generation_id: int,
76
+ worker_target: Callable[..., None],
77
+ worker_args: tuple[object, ...],
78
+ ) -> None:
79
+ if not _is_data_only(worker_args):
80
+ raise TypeError("Worker arguments must contain data-only driver inputs")
81
+ self._config = config
82
+ self._generation_id = generation_id
83
+ self._worker_target = worker_target
84
+ self._worker_args = worker_args
85
+ self._file_processes = FileModeProcesses(config)
86
+ self._context = multiprocessing.get_context("spawn")
87
+ self._parent_connection, self._child_connection = self._context.Pipe()
88
+ self._controller: multiprocessing.Process | None = None
89
+ self._controller_started = False
90
+ self._controller_exit_code: int | None = None
91
+ self._startup_state = _ControllerStartupState.WAITING_FOR_DEBUG_READY
92
+ self._receiver = MessageReceiver(generation_id)
93
+
94
+ @property
95
+ def controller_pid(self) -> int | None:
96
+ if self._controller is None or not self._controller.is_alive():
97
+ return None
98
+ return self._controller.pid
99
+
100
+ @property
101
+ def dbgs_pid(self) -> int | None:
102
+ owned = self._file_processes.debug_server
103
+ return owned.pid if owned is not None else None
104
+
105
+ @property
106
+ def onec_pid(self) -> int | None:
107
+ owned = self._file_processes.debuggee
108
+ return owned.pid if owned is not None else None
109
+
110
+ def start_debug_server(self) -> int:
111
+ return self._file_processes.start_debug_server()
112
+
113
+ def start_controller(self, debug_port: int, run_dir: Path) -> None:
114
+ if self._controller_started:
115
+ raise ProcessStartError("Controller is already owned by this generation")
116
+ process = self._context.Process(
117
+ target=self._worker_target,
118
+ args=(
119
+ self._generation_id,
120
+ self._child_connection,
121
+ debug_port,
122
+ run_dir,
123
+ *self._worker_args,
124
+ ),
125
+ name=f"onec-controller-{self._generation_id}",
126
+ )
127
+ self._controller = process
128
+ try:
129
+ process.start()
130
+ self._controller_started = True
131
+ except BaseException:
132
+ self._controller = None
133
+ raise
134
+ finally:
135
+ self._child_connection.close()
136
+
137
+ def start_debuggee(self, debug_port: int) -> None:
138
+ if self._startup_state is not _ControllerStartupState.READY:
139
+ raise InvalidMessageSequence(
140
+ "Controller must publish DEBUG_READY before the debuggee starts"
141
+ )
142
+ self._file_processes.start_debuggee(
143
+ debug_port,
144
+ execute_external=False,
145
+ thick_client=False,
146
+ )
147
+
148
+ def send(self, message: ControlMessage) -> None:
149
+ self._parent_connection.send(message)
150
+
151
+ def receive(self, timeout_s: float) -> ControlMessage:
152
+ if not self._parent_connection.poll(timeout_s):
153
+ raise CommandTimeout(
154
+ f"Controller did not publish a message within {timeout_s} seconds"
155
+ )
156
+ message = self._parent_connection.recv()
157
+ if not isinstance(message, ControlMessage):
158
+ self._fail_startup()
159
+ raise InvalidMessageSequence("Controller sent a non-protocol message")
160
+ try:
161
+ self._receiver.accept(message)
162
+ except InvalidMessageSequence:
163
+ self._fail_startup()
164
+ raise
165
+ if self._startup_state is _ControllerStartupState.FAILED:
166
+ raise InvalidMessageSequence("Controller startup already failed")
167
+ if self._startup_state is _ControllerStartupState.WAITING_FOR_DEBUG_READY:
168
+ if message.kind is not MessageKind.DEBUG_READY:
169
+ self._startup_state = _ControllerStartupState.FAILED
170
+ raise InvalidMessageSequence(
171
+ "Controller first message must be DEBUG_READY"
172
+ )
173
+ self._startup_state = _ControllerStartupState.READY
174
+ elif message.kind is MessageKind.DEBUG_READY:
175
+ raise InvalidMessageSequence("Controller sent duplicate DEBUG_READY")
176
+ return message
177
+
178
+ def controller_exitcode(self) -> int | None:
179
+ self._reap_controller()
180
+ return (
181
+ self._controller_exit_code
182
+ if self._controller is None
183
+ else self._controller.exitcode
184
+ )
185
+
186
+ def terminate_controller(self, timeout_s: float) -> None:
187
+ deadline = monotonic() + max(0.0, timeout_s)
188
+ process = self._controller
189
+ if process is not None:
190
+ if process.is_alive():
191
+ process.terminate()
192
+ process.join(max(0.0, deadline - monotonic()))
193
+ if process.is_alive():
194
+ process.kill()
195
+ process.join(max(0.0, deadline - monotonic()))
196
+ self._reap_controller()
197
+ self._close_connections()
198
+
199
+ def terminate_onec(self, timeout_s: float) -> None:
200
+ self._file_processes.close_debuggee(timeout_s)
201
+
202
+ def terminate_dbgs(self, timeout_s: float) -> None:
203
+ self._file_processes.close_debug_server(timeout_s)
204
+
205
+ def all_stopped(self) -> bool:
206
+ self._reap_controller()
207
+ return (
208
+ self._controller is None
209
+ and self._file_processes.debuggee is None
210
+ and self._file_processes.debug_server is None
211
+ )
212
+
213
+ def _reap_controller(self) -> None:
214
+ process = self._controller
215
+ if process is None or process.exitcode is None:
216
+ return
217
+ process.join(timeout=0)
218
+ self._controller_exit_code = process.exitcode
219
+ process.close()
220
+ self._controller = None
221
+ self._close_connections()
222
+
223
+ def _close_connections(self) -> None:
224
+ for connection in (self._parent_connection, self._child_connection):
225
+ try:
226
+ connection.close()
227
+ except OSError:
228
+ pass
229
+
230
+ def _fail_startup(self) -> None:
231
+ if self._startup_state is _ControllerStartupState.WAITING_FOR_DEBUG_READY:
232
+ self._startup_state = _ControllerStartupState.FAILED