chronaxis 0.1.0.dev0__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.
- chronaxis/__init__.py +72 -0
- chronaxis/__main__.py +12 -0
- chronaxis/analysis_cli.py +181 -0
- chronaxis/batch/__init__.py +14 -0
- chronaxis/batch/api.py +46 -0
- chronaxis/batch/cli.py +48 -0
- chronaxis/batch/config.py +37 -0
- chronaxis/batch/models.py +202 -0
- chronaxis/batch/process_transport.py +149 -0
- chronaxis/batch/process_tree.py +72 -0
- chronaxis/batch/publication.py +41 -0
- chronaxis/batch/runner.py +236 -0
- chronaxis/batch/templates.py +42 -0
- chronaxis/can_dependencies.py +42 -0
- chronaxis/cli.py +193 -0
- chronaxis/configuration/__init__.py +46 -0
- chronaxis/configuration/cli.py +41 -0
- chronaxis/configuration/diagnostics.py +107 -0
- chronaxis/configuration/explanation.py +233 -0
- chronaxis/configuration/file_tools.py +140 -0
- chronaxis/configuration/imports.py +144 -0
- chronaxis/configuration/initialization.py +36 -0
- chronaxis/configuration/json_parser.py +114 -0
- chronaxis/configuration/models.py +74 -0
- chronaxis/configuration/origins.py +90 -0
- chronaxis/configuration/overrides.py +55 -0
- chronaxis/configuration/resolution.py +150 -0
- chronaxis/configuration/template_catalog.py +68 -0
- chronaxis/configuration/templates/batch/analysis-annotated.yaml +18 -0
- chronaxis/configuration/templates/batch/analysis-minimal.yaml +18 -0
- chronaxis/configuration/templates/batch/annotated.yaml +6 -0
- chronaxis/configuration/templates/batch/minimal.yaml +6 -0
- chronaxis/configuration/templates/can-asc/annotated.yaml +18 -0
- chronaxis/configuration/templates/can-asc/minimal.yaml +18 -0
- chronaxis/configuration/templates/can-blf/annotated.yaml +18 -0
- chronaxis/configuration/templates/can-blf/minimal.yaml +18 -0
- chronaxis/configuration/templates/can-export/annotated.yaml +23 -0
- chronaxis/configuration/templates/can-export/minimal.yaml +23 -0
- chronaxis/configuration/templates/catalog.json +233 -0
- chronaxis/configuration/templates/charge-session/annotated.yaml +38 -0
- chronaxis/configuration/templates/charge-session/minimal.yaml +38 -0
- chronaxis/configuration/templates/command-response/annotated.yaml +32 -0
- chronaxis/configuration/templates/command-response/minimal.yaml +36 -0
- chronaxis/configuration/templates/fault-window/annotated.yaml +25 -0
- chronaxis/configuration/templates/fault-window/minimal.yaml +27 -0
- chronaxis/configuration/templates/ini-mapping/annotated.yaml +20 -0
- chronaxis/configuration/templates/ini-mapping/minimal.yaml +20 -0
- chronaxis/configuration/templates/raw-can-csv/annotated.yaml +34 -0
- chronaxis/configuration/templates/raw-can-csv/minimal.yaml +35 -0
- chronaxis/configuration/templates/shared/charge-session.asc +5 -0
- chronaxis/configuration/templates/shared/command-response.asc +8 -0
- chronaxis/configuration/templates/shared/fault-window.asc +5 -0
- chronaxis/configuration/templates/shared/power.asc +7 -0
- chronaxis/configuration/templates/shared/sample.asc +6 -0
- chronaxis/configuration/templates/shared/sample.blf +0 -0
- chronaxis/configuration/templates/shared/sample.csv +5 -0
- chronaxis/configuration/templates/shared/sample.dbc +11 -0
- chronaxis/configuration/templates/shared/signals.csv +6 -0
- chronaxis/configuration/templates/shared/source.ini +5 -0
- chronaxis/configuration/templates/shared/stability.asc +9 -0
- chronaxis/configuration/templates/shared/teaching.dbc +27 -0
- chronaxis/configuration/templates/shared/threshold.asc +7 -0
- chronaxis/configuration/templates/signal-csv/annotated.yaml +27 -0
- chronaxis/configuration/templates/signal-csv/minimal.yaml +27 -0
- chronaxis/configuration/templates/signal-export/annotated.yaml +27 -0
- chronaxis/configuration/templates/signal-export/minimal.yaml +29 -0
- chronaxis/configuration/templates/stability/annotated.yaml +35 -0
- chronaxis/configuration/templates/stability/minimal.yaml +35 -0
- chronaxis/configuration/templates/threshold/annotated.yaml +22 -0
- chronaxis/configuration/templates/threshold/minimal.yaml +22 -0
- chronaxis/configuration/yaml_parser.py +125 -0
- chronaxis/core/__init__.py +71 -0
- chronaxis/core/binding.py +449 -0
- chronaxis/core/calculation_series_join.py +106 -0
- chronaxis/core/calculations.py +435 -0
- chronaxis/core/calculations_memory_numpy.py +136 -0
- chronaxis/core/calculations_memory_reference.py +165 -0
- chronaxis/core/calculations_numpy.py +298 -0
- chronaxis/core/calculations_reference.py +294 -0
- chronaxis/core/condition_evidence.py +182 -0
- chronaxis/core/conditional_integral_result.py +43 -0
- chronaxis/core/conditional_integral_terms.py +146 -0
- chronaxis/core/conditional_integral_terms_numpy.py +148 -0
- chronaxis/core/conditional_integral_terms_reference.py +111 -0
- chronaxis/core/conditional_time_reduction.py +118 -0
- chronaxis/core/conditional_time_reduction_numpy.py +223 -0
- chronaxis/core/conditional_time_reduction_reference.py +213 -0
- chronaxis/core/declarations.py +192 -0
- chronaxis/core/decoded_binding.py +197 -0
- chronaxis/core/direct_message.py +387 -0
- chronaxis/core/export_interpolation.py +54 -0
- chronaxis/core/expression.py +642 -0
- chronaxis/core/expression_numpy.py +314 -0
- chronaxis/core/expression_reference.py +272 -0
- chronaxis/core/integral_result.py +53 -0
- chronaxis/core/integral_sum.py +77 -0
- chronaxis/core/integral_sum_numpy.py +224 -0
- chronaxis/core/integral_sum_reference.py +148 -0
- chronaxis/core/integral_terms.py +119 -0
- chronaxis/core/integral_terms_numpy.py +127 -0
- chronaxis/core/integral_terms_reference.py +91 -0
- chronaxis/core/mean_weights_numpy.py +29 -0
- chronaxis/core/mean_weights_reference.py +27 -0
- chronaxis/core/message_binding.py +305 -0
- chronaxis/core/models.py +485 -0
- chronaxis/core/normalize_numpy.py +396 -0
- chronaxis/core/numeric.py +472 -0
- chronaxis/core/numeric_numpy.py +440 -0
- chronaxis/core/record_intervals.py +115 -0
- chronaxis/core/sample_reduction.py +161 -0
- chronaxis/core/sample_reduction_numpy.py +160 -0
- chronaxis/core/sample_reduction_reference.py +154 -0
- chronaxis/core/selection.py +74 -0
- chronaxis/core/sequence.py +160 -0
- chronaxis/core/sequence_reference.py +248 -0
- chronaxis/core/stability.py +249 -0
- chronaxis/core/start_end.py +169 -0
- chronaxis/core/state.py +494 -0
- chronaxis/core/state_numpy.py +296 -0
- chronaxis/core/temporal.py +373 -0
- chronaxis/core/temporal_clock.py +25 -0
- chronaxis/core/temporal_memory_numpy.py +163 -0
- chronaxis/core/temporal_memory_reference.py +161 -0
- chronaxis/core/temporal_numpy.py +345 -0
- chronaxis/core/temporal_reference.py +304 -0
- chronaxis/core/time_reduction.py +190 -0
- chronaxis/core/time_reduction_numpy.py +205 -0
- chronaxis/core/time_reduction_reference.py +203 -0
- chronaxis/core/types.py +105 -0
- chronaxis/core/units.py +81 -0
- chronaxis/core/validation.py +94 -0
- chronaxis/core/window_delta.py +123 -0
- chronaxis/core/window_delta_numpy.py +78 -0
- chronaxis/core/window_delta_reference.py +69 -0
- chronaxis/core/windows.py +224 -0
- chronaxis/core/windows_numpy.py +78 -0
- chronaxis/core/windows_reference.py +61 -0
- chronaxis/execution/__init__.py +6 -0
- chronaxis/execution/batch_signal_groups.py +122 -0
- chronaxis/execution/bindings.py +296 -0
- chronaxis/execution/boundaries.py +568 -0
- chronaxis/execution/calculation_blocks.py +338 -0
- chronaxis/execution/calculation_values.py +55 -0
- chronaxis/execution/can_batch_reader.py +356 -0
- chronaxis/execution/can_reader.py +948 -0
- chronaxis/execution/can_reference_template.py +61 -0
- chronaxis/execution/condition_evidence.py +370 -0
- chronaxis/execution/conditional_integral_facts.py +310 -0
- chronaxis/execution/conditional_integral_reduction.py +216 -0
- chronaxis/execution/csv_observation.py +524 -0
- chronaxis/execution/csv_reader.py +662 -0
- chronaxis/execution/current_message_calculation.py +225 -0
- chronaxis/execution/driver_expression.py +274 -0
- chronaxis/execution/expressions.py +618 -0
- chronaxis/execution/frame_capture.py +245 -0
- chronaxis/execution/groups.py +236 -0
- chronaxis/execution/historical_conditional_blocks.py +264 -0
- chronaxis/execution/historical_conditional_integral.py +226 -0
- chronaxis/execution/historical_conditional_time_calculation.py +368 -0
- chronaxis/execution/historical_integral.py +219 -0
- chronaxis/execution/historical_observation.py +372 -0
- chronaxis/execution/historical_sample_calculation.py +338 -0
- chronaxis/execution/historical_selection_rows.py +300 -0
- chronaxis/execution/historical_time_calculation.py +341 -0
- chronaxis/execution/history.py +572 -0
- chronaxis/execution/history_records.py +225 -0
- chronaxis/execution/hold.py +448 -0
- chronaxis/execution/integral_facts.py +311 -0
- chronaxis/execution/integral_reduction.py +216 -0
- chronaxis/execution/legacy_frame_samples.py +94 -0
- chronaxis/execution/memory_reader.py +247 -0
- chronaxis/execution/message_bindings.py +293 -0
- chronaxis/execution/message_delivery.py +37 -0
- chronaxis/execution/observed_ingestion.py +551 -0
- chronaxis/execution/raw_signal_groups.py +192 -0
- chronaxis/execution/record_alarm_duration.py +114 -0
- chronaxis/execution/record_delta_condition.py +167 -0
- chronaxis/execution/record_diagnostics.py +87 -0
- chronaxis/execution/record_event_durations.py +143 -0
- chronaxis/execution/record_export_samples.py +94 -0
- chronaxis/execution/record_exports.py +155 -0
- chronaxis/execution/record_integral.py +196 -0
- chronaxis/execution/record_point_buffer.py +101 -0
- chronaxis/execution/record_rule_timeline.py +344 -0
- chronaxis/execution/record_sample.py +46 -0
- chronaxis/execution/record_sample_series.py +29 -0
- chronaxis/execution/record_scope_calculations.py +290 -0
- chronaxis/execution/record_selection.py +62 -0
- chronaxis/execution/record_sequences.py +199 -0
- chronaxis/execution/record_session_calculations.py +778 -0
- chronaxis/execution/record_signal_export.py +133 -0
- chronaxis/execution/record_source_cursor.py +295 -0
- chronaxis/execution/record_time_calculation.py +322 -0
- chronaxis/execution/record_time_indexes.py +143 -0
- chronaxis/execution/record_value_history.py +160 -0
- chronaxis/execution/record_windows.py +229 -0
- chronaxis/execution/required_expression.py +52 -0
- chronaxis/execution/retained_metadata.py +71 -0
- chronaxis/execution/run_session.py +402 -0
- chronaxis/execution/scanned_signal_proof.py +550 -0
- chronaxis/execution/signal_validity.py +40 -0
- chronaxis/execution/state.py +280 -0
- chronaxis/execution/temporal_buffer.py +508 -0
- chronaxis/execution/text_can_reader.py +359 -0
- chronaxis/execution/timeline.py +309 -0
- chronaxis/execution/timeline_multi.py +415 -0
- chronaxis/execution/window_delta_events.py +220 -0
- chronaxis/execution/window_replay.py +350 -0
- chronaxis/execution/windows.py +173 -0
- chronaxis/guide/README.md +70 -0
- chronaxis/guide/api/AnalysisError.md +14 -0
- chronaxis/guide/api/AnalysisPlan.md +96 -0
- chronaxis/guide/api/AnalysisResult.md +398 -0
- chronaxis/guide/api/AnalysisRunner.md +155 -0
- chronaxis/guide/api/BatchJob.md +19 -0
- chronaxis/guide/api/BatchJobResult.md +61 -0
- chronaxis/guide/api/BatchPlan.md +48 -0
- chronaxis/guide/api/BatchReport.md +108 -0
- chronaxis/guide/api/BatchRunner.md +84 -0
- chronaxis/guide/api/OutputManifest.md +23 -0
- chronaxis/guide/api/PlanFragment.md +47 -0
- chronaxis/guide/api/PlanValidationError.md +98 -0
- chronaxis/guide/api/PresetSpec.md +63 -0
- chronaxis/guide/api/ResultClosedError.md +14 -0
- chronaxis/guide/api/RunMetadata.md +100 -0
- chronaxis/guide/api/TimeConversion.md +29 -0
- chronaxis/guide/api/TimeOverflowError.md +17 -0
- chronaxis/guide/api/build_preset.md +36 -0
- chronaxis/guide/api/checked_add_ns.md +30 -0
- chronaxis/guide/api/convert_time.md +40 -0
- chronaxis/guide/api/explain_analysis_plan.md +38 -0
- chronaxis/guide/api/index.json +185 -0
- chronaxis/guide/api/load_analysis_plan.md +34 -0
- chronaxis/guide/api/load_batch_plan.md +36 -0
- chronaxis/guide/api/parse_datetime_ns.md +35 -0
- chronaxis/guide/api/parse_duration.md +30 -0
- chronaxis/guide/api/resolve_preset_roles.md +37 -0
- chronaxis/guide/api/run_batch.md +38 -0
- chronaxis/guide/api/shift_times_reference.md +33 -0
- chronaxis/guide/api/time_deltas_reference.md +37 -0
- chronaxis/guide/api/validate_analysis_plan.md +38 -0
- chronaxis/guide/en/README.md +74 -0
- chronaxis/guide/en/api/AnalysisError.md +14 -0
- chronaxis/guide/en/api/AnalysisPlan.md +93 -0
- chronaxis/guide/en/api/AnalysisResult.md +398 -0
- chronaxis/guide/en/api/AnalysisRunner.md +191 -0
- chronaxis/guide/en/api/BatchJob.md +17 -0
- chronaxis/guide/en/api/BatchJobResult.md +43 -0
- chronaxis/guide/en/api/BatchPlan.md +37 -0
- chronaxis/guide/en/api/BatchReport.md +52 -0
- chronaxis/guide/en/api/BatchRunner.md +51 -0
- chronaxis/guide/en/api/OutputManifest.md +23 -0
- chronaxis/guide/en/api/PlanFragment.md +33 -0
- chronaxis/guide/en/api/PlanValidationError.md +58 -0
- chronaxis/guide/en/api/PresetSpec.md +51 -0
- chronaxis/guide/en/api/ResultClosedError.md +14 -0
- chronaxis/guide/en/api/RunMetadata.md +100 -0
- chronaxis/guide/en/api/TimeConversion.md +23 -0
- chronaxis/guide/en/api/TimeOverflowError.md +14 -0
- chronaxis/guide/en/api/build_preset.md +23 -0
- chronaxis/guide/en/api/checked_add_ns.md +21 -0
- chronaxis/guide/en/api/convert_time.md +25 -0
- chronaxis/guide/en/api/explain_analysis_plan.md +30 -0
- chronaxis/guide/en/api/index.json +185 -0
- chronaxis/guide/en/api/load_analysis_plan.md +27 -0
- chronaxis/guide/en/api/load_batch_plan.md +28 -0
- chronaxis/guide/en/api/parse_datetime_ns.md +23 -0
- chronaxis/guide/en/api/parse_duration.md +20 -0
- chronaxis/guide/en/api/resolve_preset_roles.md +23 -0
- chronaxis/guide/en/api/run_batch.md +39 -0
- chronaxis/guide/en/api/shift_times_reference.md +21 -0
- chronaxis/guide/en/api/time_deltas_reference.md +22 -0
- chronaxis/guide/en/api/validate_analysis_plan.md +29 -0
- chronaxis/guide/en/fields/analysis/calculations-all-1.json +345 -0
- chronaxis/guide/en/fields/analysis/calculations-all-2.json +300 -0
- chronaxis/guide/en/fields/analysis/calculations-all-3.json +84 -0
- chronaxis/guide/en/fields/analysis/config_version-all-1.json +24 -0
- chronaxis/guide/en/fields/analysis/dataset-all-1.json +344 -0
- chronaxis/guide/en/fields/analysis/derived-all-1.json +147 -0
- chronaxis/guide/en/fields/analysis/diagnostics-all-1.json +69 -0
- chronaxis/guide/en/fields/analysis/execution-all-1.json +167 -0
- chronaxis/guide/en/fields/analysis/imports-all-1.json +39 -0
- chronaxis/guide/en/fields/analysis/intervals-all-1.json +173 -0
- chronaxis/guide/en/fields/analysis/message_calculations-all-1.json +345 -0
- chronaxis/guide/en/fields/analysis/message_calculations-all-2.json +270 -0
- chronaxis/guide/en/fields/analysis/metadata-all-1.json +24 -0
- chronaxis/guide/en/fields/analysis/outputs-all-1.json +332 -0
- chronaxis/guide/en/fields/analysis/outputs-all-2.json +319 -0
- chronaxis/guide/en/fields/analysis/outputs-all-3.json +321 -0
- chronaxis/guide/en/fields/analysis/outputs-all-4.json +236 -0
- chronaxis/guide/en/fields/analysis/outputs-all-5.json +246 -0
- chronaxis/guide/en/fields/analysis/outputs-all-6.json +214 -0
- chronaxis/guide/en/fields/analysis/overrides-all-1.json +104 -0
- chronaxis/guide/en/fields/analysis/presets-charge_session-1.json +398 -0
- chronaxis/guide/en/fields/analysis/presets-charge_session-2.json +114 -0
- chronaxis/guide/en/fields/analysis/presets-command_response-1.json +376 -0
- chronaxis/guide/en/fields/analysis/presets-fault_context-1.json +285 -0
- chronaxis/guide/en/fields/analysis/presets-threshold_excursion-1.json +317 -0
- chronaxis/guide/en/fields/analysis/rules-condition_duration-1.json +344 -0
- chronaxis/guide/en/fields/analysis/rules-condition_duration-2.json +27 -0
- chronaxis/guide/en/fields/analysis/rules-debounce-1.json +335 -0
- chronaxis/guide/en/fields/analysis/rules-falling_edge-1.json +317 -0
- chronaxis/guide/en/fields/analysis/rules-hysteresis-1.json +334 -0
- chronaxis/guide/en/fields/analysis/rules-hysteresis-2.json +27 -0
- chronaxis/guide/en/fields/analysis/rules-rising_edge-1.json +317 -0
- chronaxis/guide/en/fields/analysis/rules-start_end-1.json +333 -0
- chronaxis/guide/en/fields/analysis/rules-start_end-2.json +60 -0
- chronaxis/guide/en/fields/analysis/rules-start_only-1.json +334 -0
- chronaxis/guide/en/fields/analysis/rules-window_delta-1.json +338 -0
- chronaxis/guide/en/fields/analysis/rules-window_delta-2.json +96 -0
- chronaxis/guide/en/fields/analysis/sequences-all-1.json +378 -0
- chronaxis/guide/en/fields/analysis/sequences-all-2.json +70 -0
- chronaxis/guide/en/fields/analysis/signals-variant-1-1.json +349 -0
- chronaxis/guide/en/fields/analysis/signals-variant-1-2.json +297 -0
- chronaxis/guide/en/fields/analysis/signals-variant-1-3.json +323 -0
- chronaxis/guide/en/fields/analysis/signals-variant-1-4.json +192 -0
- chronaxis/guide/en/fields/analysis/signals-variant-2-1.json +327 -0
- chronaxis/guide/en/fields/analysis/signals-variant-2-2.json +312 -0
- chronaxis/guide/en/fields/analysis/signals-variant-2-3.json +294 -0
- chronaxis/guide/en/fields/analysis/signals-variant-2-4.json +253 -0
- chronaxis/guide/en/fields/analysis/signals-variant-2-5.json +44 -0
- chronaxis/guide/en/fields/analysis/sources-can_asc-1.json +318 -0
- chronaxis/guide/en/fields/analysis/sources-can_asc-2.json +310 -0
- chronaxis/guide/en/fields/analysis/sources-can_asc-3.json +311 -0
- chronaxis/guide/en/fields/analysis/sources-can_asc-4.json +69 -0
- chronaxis/guide/en/fields/analysis/sources-can_blf-1.json +317 -0
- chronaxis/guide/en/fields/analysis/sources-can_blf-2.json +310 -0
- chronaxis/guide/en/fields/analysis/sources-can_blf-3.json +317 -0
- chronaxis/guide/en/fields/analysis/sources-memory-1.json +332 -0
- chronaxis/guide/en/fields/analysis/sources-memory-2.json +125 -0
- chronaxis/guide/en/fields/analysis/sources-raw_can_csv-1.json +330 -0
- chronaxis/guide/en/fields/analysis/sources-raw_can_csv-10.json +233 -0
- chronaxis/guide/en/fields/analysis/sources-raw_can_csv-11.json +225 -0
- chronaxis/guide/en/fields/analysis/sources-raw_can_csv-12.json +228 -0
- chronaxis/guide/en/fields/analysis/sources-raw_can_csv-13.json +226 -0
- chronaxis/guide/en/fields/analysis/sources-raw_can_csv-14.json +230 -0
- chronaxis/guide/en/fields/analysis/sources-raw_can_csv-15.json +227 -0
- chronaxis/guide/en/fields/analysis/sources-raw_can_csv-16.json +230 -0
- chronaxis/guide/en/fields/analysis/sources-raw_can_csv-17.json +238 -0
- chronaxis/guide/en/fields/analysis/sources-raw_can_csv-18.json +239 -0
- chronaxis/guide/en/fields/analysis/sources-raw_can_csv-19.json +233 -0
- chronaxis/guide/en/fields/analysis/sources-raw_can_csv-2.json +310 -0
- chronaxis/guide/en/fields/analysis/sources-raw_can_csv-20.json +242 -0
- chronaxis/guide/en/fields/analysis/sources-raw_can_csv-21.json +230 -0
- chronaxis/guide/en/fields/analysis/sources-raw_can_csv-22.json +228 -0
- chronaxis/guide/en/fields/analysis/sources-raw_can_csv-23.json +230 -0
- chronaxis/guide/en/fields/analysis/sources-raw_can_csv-24.json +223 -0
- chronaxis/guide/en/fields/analysis/sources-raw_can_csv-25.json +290 -0
- chronaxis/guide/en/fields/analysis/sources-raw_can_csv-26.json +131 -0
- chronaxis/guide/en/fields/analysis/sources-raw_can_csv-3.json +297 -0
- chronaxis/guide/en/fields/analysis/sources-raw_can_csv-4.json +226 -0
- chronaxis/guide/en/fields/analysis/sources-raw_can_csv-5.json +230 -0
- chronaxis/guide/en/fields/analysis/sources-raw_can_csv-6.json +227 -0
- chronaxis/guide/en/fields/analysis/sources-raw_can_csv-7.json +230 -0
- chronaxis/guide/en/fields/analysis/sources-raw_can_csv-8.json +238 -0
- chronaxis/guide/en/fields/analysis/sources-raw_can_csv-9.json +239 -0
- chronaxis/guide/en/fields/analysis/sources-signal_csv-1.json +331 -0
- chronaxis/guide/en/fields/analysis/sources-signal_csv-2.json +307 -0
- chronaxis/guide/en/fields/analysis/sources-signal_csv-3.json +315 -0
- chronaxis/guide/en/fields/analysis/sources-variant-6-1.json +319 -0
- chronaxis/guide/en/fields/analysis/sources-variant-6-2.json +307 -0
- chronaxis/guide/en/fields/analysis/sources-variant-6-3.json +312 -0
- chronaxis/guide/en/fields/analysis/sources-variant-6-4.json +113 -0
- chronaxis/guide/en/fields/analysis/windows-all-1.json +361 -0
- chronaxis/guide/en/fields/analysis/windows-all-2.json +187 -0
- chronaxis/guide/en/fields/batch/backend-all-1.json +26 -0
- chronaxis/guide/en/fields/batch/batch_version-all-1.json +22 -0
- chronaxis/guide/en/fields/batch/fail_fast-all-1.json +22 -0
- chronaxis/guide/en/fields/batch/inputs-all-1.json +161 -0
- chronaxis/guide/en/fields/batch/jobs-all-1.json +58 -0
- chronaxis/guide/en/fields/batch/process_count-all-1.json +23 -0
- chronaxis/guide/en/fields/batch/source-all-1.json +22 -0
- chronaxis/guide/en/fields/batch/template-all-1.json +22 -0
- chronaxis/guide/en/fields/definitions/derived-all-1.json +121 -0
- chronaxis/guide/en/fields/definitions/signals-all-1.json +336 -0
- chronaxis/guide/en/fields/definitions/signals-all-2.json +307 -0
- chronaxis/guide/en/fields/definitions/signals-all-3.json +290 -0
- chronaxis/guide/en/fields/definitions/signals-all-4.json +347 -0
- chronaxis/guide/en/fields/definitions/signals-all-5.json +297 -0
- chronaxis/guide/en/fields/definitions/signals-all-6.json +259 -0
- chronaxis/guide/en/fields/definitions/signals-all-7.json +117 -0
- chronaxis/guide/en/fields/definitions/sources-all-1.json +332 -0
- chronaxis/guide/en/fields/definitions/sources-all-10.json +306 -0
- chronaxis/guide/en/fields/definitions/sources-all-11.json +294 -0
- chronaxis/guide/en/fields/definitions/sources-all-12.json +212 -0
- chronaxis/guide/en/fields/definitions/sources-all-13.json +217 -0
- chronaxis/guide/en/fields/definitions/sources-all-14.json +213 -0
- chronaxis/guide/en/fields/definitions/sources-all-15.json +214 -0
- chronaxis/guide/en/fields/definitions/sources-all-16.json +215 -0
- chronaxis/guide/en/fields/definitions/sources-all-17.json +213 -0
- chronaxis/guide/en/fields/definitions/sources-all-18.json +214 -0
- chronaxis/guide/en/fields/definitions/sources-all-19.json +213 -0
- chronaxis/guide/en/fields/definitions/sources-all-2.json +323 -0
- chronaxis/guide/en/fields/definitions/sources-all-20.json +217 -0
- chronaxis/guide/en/fields/definitions/sources-all-21.json +210 -0
- chronaxis/guide/en/fields/definitions/sources-all-22.json +214 -0
- chronaxis/guide/en/fields/definitions/sources-all-23.json +218 -0
- chronaxis/guide/en/fields/definitions/sources-all-24.json +209 -0
- chronaxis/guide/en/fields/definitions/sources-all-25.json +215 -0
- chronaxis/guide/en/fields/definitions/sources-all-26.json +218 -0
- chronaxis/guide/en/fields/definitions/sources-all-27.json +224 -0
- chronaxis/guide/en/fields/definitions/sources-all-28.json +215 -0
- chronaxis/guide/en/fields/definitions/sources-all-29.json +205 -0
- chronaxis/guide/en/fields/definitions/sources-all-3.json +303 -0
- chronaxis/guide/en/fields/definitions/sources-all-30.json +298 -0
- chronaxis/guide/en/fields/definitions/sources-all-31.json +315 -0
- chronaxis/guide/en/fields/definitions/sources-all-32.json +306 -0
- chronaxis/guide/en/fields/definitions/sources-all-33.json +209 -0
- chronaxis/guide/en/fields/definitions/sources-all-4.json +336 -0
- chronaxis/guide/en/fields/definitions/sources-all-5.json +299 -0
- chronaxis/guide/en/fields/definitions/sources-all-6.json +307 -0
- chronaxis/guide/en/fields/definitions/sources-all-7.json +320 -0
- chronaxis/guide/en/fields/definitions/sources-all-8.json +303 -0
- chronaxis/guide/en/fields/definitions/sources-all-9.json +315 -0
- chronaxis/guide/en/fields/index.json +3450 -0
- chronaxis/guide/en/fields/mapping/aliases-all-1.json +91 -0
- chronaxis/guide/en/fields/mapping/analysis-all-1.json +382 -0
- chronaxis/guide/en/fields/mapping/analysis-all-10.json +301 -0
- chronaxis/guide/en/fields/mapping/analysis-all-11.json +312 -0
- chronaxis/guide/en/fields/mapping/analysis-all-12.json +311 -0
- chronaxis/guide/en/fields/mapping/analysis-all-13.json +314 -0
- chronaxis/guide/en/fields/mapping/analysis-all-14.json +310 -0
- chronaxis/guide/en/fields/mapping/analysis-all-15.json +297 -0
- chronaxis/guide/en/fields/mapping/analysis-all-16.json +226 -0
- chronaxis/guide/en/fields/mapping/analysis-all-17.json +230 -0
- chronaxis/guide/en/fields/mapping/analysis-all-18.json +227 -0
- chronaxis/guide/en/fields/mapping/analysis-all-19.json +230 -0
- chronaxis/guide/en/fields/mapping/analysis-all-2.json +323 -0
- chronaxis/guide/en/fields/mapping/analysis-all-20.json +221 -0
- chronaxis/guide/en/fields/mapping/analysis-all-21.json +237 -0
- chronaxis/guide/en/fields/mapping/analysis-all-22.json +233 -0
- chronaxis/guide/en/fields/mapping/analysis-all-23.json +222 -0
- chronaxis/guide/en/fields/mapping/analysis-all-24.json +231 -0
- chronaxis/guide/en/fields/mapping/analysis-all-25.json +225 -0
- chronaxis/guide/en/fields/mapping/analysis-all-26.json +230 -0
- chronaxis/guide/en/fields/mapping/analysis-all-27.json +228 -0
- chronaxis/guide/en/fields/mapping/analysis-all-28.json +230 -0
- chronaxis/guide/en/fields/mapping/analysis-all-29.json +223 -0
- chronaxis/guide/en/fields/mapping/analysis-all-3.json +318 -0
- chronaxis/guide/en/fields/mapping/analysis-all-30.json +233 -0
- chronaxis/guide/en/fields/mapping/analysis-all-31.json +218 -0
- chronaxis/guide/en/fields/mapping/analysis-all-32.json +239 -0
- chronaxis/guide/en/fields/mapping/analysis-all-33.json +233 -0
- chronaxis/guide/en/fields/mapping/analysis-all-34.json +225 -0
- chronaxis/guide/en/fields/mapping/analysis-all-35.json +228 -0
- chronaxis/guide/en/fields/mapping/analysis-all-36.json +226 -0
- chronaxis/guide/en/fields/mapping/analysis-all-37.json +244 -0
- chronaxis/guide/en/fields/mapping/analysis-all-38.json +326 -0
- chronaxis/guide/en/fields/mapping/analysis-all-39.json +299 -0
- chronaxis/guide/en/fields/mapping/analysis-all-4.json +297 -0
- chronaxis/guide/en/fields/mapping/analysis-all-40.json +311 -0
- chronaxis/guide/en/fields/mapping/analysis-all-41.json +310 -0
- chronaxis/guide/en/fields/mapping/analysis-all-42.json +346 -0
- chronaxis/guide/en/fields/mapping/analysis-all-43.json +267 -0
- chronaxis/guide/en/fields/mapping/analysis-all-44.json +327 -0
- chronaxis/guide/en/fields/mapping/analysis-all-45.json +279 -0
- chronaxis/guide/en/fields/mapping/analysis-all-46.json +327 -0
- chronaxis/guide/en/fields/mapping/analysis-all-47.json +312 -0
- chronaxis/guide/en/fields/mapping/analysis-all-48.json +294 -0
- chronaxis/guide/en/fields/mapping/analysis-all-49.json +253 -0
- chronaxis/guide/en/fields/mapping/analysis-all-5.json +312 -0
- chronaxis/guide/en/fields/mapping/analysis-all-50.json +346 -0
- chronaxis/guide/en/fields/mapping/analysis-all-51.json +324 -0
- chronaxis/guide/en/fields/mapping/analysis-all-52.json +335 -0
- chronaxis/guide/en/fields/mapping/analysis-all-53.json +317 -0
- chronaxis/guide/en/fields/mapping/analysis-all-54.json +316 -0
- chronaxis/guide/en/fields/mapping/analysis-all-55.json +302 -0
- chronaxis/guide/en/fields/mapping/analysis-all-56.json +319 -0
- chronaxis/guide/en/fields/mapping/analysis-all-57.json +334 -0
- chronaxis/guide/en/fields/mapping/analysis-all-58.json +333 -0
- chronaxis/guide/en/fields/mapping/analysis-all-59.json +359 -0
- chronaxis/guide/en/fields/mapping/analysis-all-6.json +327 -0
- chronaxis/guide/en/fields/mapping/analysis-all-60.json +303 -0
- chronaxis/guide/en/fields/mapping/analysis-all-61.json +326 -0
- chronaxis/guide/en/fields/mapping/analysis-all-62.json +301 -0
- chronaxis/guide/en/fields/mapping/analysis-all-63.json +326 -0
- chronaxis/guide/en/fields/mapping/analysis-all-64.json +367 -0
- chronaxis/guide/en/fields/mapping/analysis-all-65.json +334 -0
- chronaxis/guide/en/fields/mapping/analysis-all-66.json +358 -0
- chronaxis/guide/en/fields/mapping/analysis-all-67.json +349 -0
- chronaxis/guide/en/fields/mapping/analysis-all-68.json +331 -0
- chronaxis/guide/en/fields/mapping/analysis-all-69.json +304 -0
- chronaxis/guide/en/fields/mapping/analysis-all-7.json +303 -0
- chronaxis/guide/en/fields/mapping/analysis-all-70.json +349 -0
- chronaxis/guide/en/fields/mapping/analysis-all-71.json +288 -0
- chronaxis/guide/en/fields/mapping/analysis-all-72.json +316 -0
- chronaxis/guide/en/fields/mapping/analysis-all-73.json +266 -0
- chronaxis/guide/en/fields/mapping/analysis-all-74.json +227 -0
- chronaxis/guide/en/fields/mapping/analysis-all-75.json +239 -0
- chronaxis/guide/en/fields/mapping/analysis-all-76.json +274 -0
- chronaxis/guide/en/fields/mapping/analysis-all-77.json +380 -0
- chronaxis/guide/en/fields/mapping/analysis-all-78.json +313 -0
- chronaxis/guide/en/fields/mapping/analysis-all-79.json +338 -0
- chronaxis/guide/en/fields/mapping/analysis-all-8.json +292 -0
- chronaxis/guide/en/fields/mapping/analysis-all-80.json +304 -0
- chronaxis/guide/en/fields/mapping/analysis-all-81.json +140 -0
- chronaxis/guide/en/fields/mapping/analysis-all-9.json +332 -0
- chronaxis/guide/en/fields/mapping/io_policy-all-1.json +19 -0
- chronaxis/guide/en/fields/mapping/mapping_version-all-1.json +19 -0
- chronaxis/guide/en/fields/mapping/path_base-all-1.json +19 -0
- chronaxis/guide/en/fields/mapping/sections-all-1.json +402 -0
- chronaxis/guide/en/fields/mapping/sections-all-2.json +232 -0
- chronaxis/guide/en/semantics.md +70 -0
- chronaxis/guide/en/tasks.json +290 -0
- chronaxis/guide/en/workflow.md +41 -0
- chronaxis/guide/examples/analysis-imports.yaml +22 -0
- chronaxis/guide/examples/analysis.yaml +23 -0
- chronaxis/guide/examples/batch-minimal.yaml +3 -0
- chronaxis/guide/examples/conditional-energy.yaml +36 -0
- chronaxis/guide/examples/data/activity.csv +6 -0
- chronaxis/guide/examples/data/can/activity.asc +11 -0
- chronaxis/guide/examples/data/can/calculation-minimal.asc +6 -0
- chronaxis/guide/examples/data/can/conditional-energy/part-1.asc +92 -0
- chronaxis/guide/examples/data/can/conditional-energy/part-2.asc +36 -0
- chronaxis/guide/examples/data/can/conditional-energy/signals.dbc +10 -0
- chronaxis/guide/examples/data/can/execution-comparison.asc +12 -0
- chronaxis/guide/examples/data/can/execution-report.asc +4 -0
- chronaxis/guide/examples/data/can/expression-extended.asc +11 -0
- chronaxis/guide/examples/data/can/interval-actual.asc +6 -0
- chronaxis/guide/examples/data/can/preset-charge-energy.asc +15 -0
- chronaxis/guide/examples/data/can/preset-charge-minimal.asc +11 -0
- chronaxis/guide/examples/data/can/preset-command-automatic.asc +11 -0
- chronaxis/guide/examples/data/can/preset-fault-context.asc +7 -0
- chronaxis/guide/examples/data/can/preset-threshold-delay.asc +7 -0
- chronaxis/guide/examples/data/can/preset-threshold-partial.asc +7 -0
- chronaxis/guide/examples/data/can/quality.asc +6 -0
- chronaxis/guide/examples/data/can/quickstart-parts/part1.asc +4 -0
- chronaxis/guide/examples/data/can/quickstart-parts/part2.asc +3 -0
- chronaxis/guide/examples/data/can/quickstart.asc +6 -0
- chronaxis/guide/examples/data/can/rule-condition_duration-extended.asc +35 -0
- chronaxis/guide/examples/data/can/rule-condition_duration-minimal.asc +19 -0
- chronaxis/guide/examples/data/can/rule-debounce-extended.asc +19 -0
- chronaxis/guide/examples/data/can/rule-falling_edge-extended.asc +35 -0
- chronaxis/guide/examples/data/can/rule-hysteresis-extended.asc +19 -0
- chronaxis/guide/examples/data/can/rule-start_end-extended.asc +35 -0
- chronaxis/guide/examples/data/can/rule-start_only-extended.asc +19 -0
- chronaxis/guide/examples/data/can/rule-window_delta-extended.asc +19 -0
- chronaxis/guide/examples/data/can/sequence-outcomes.asc +19 -0
- chronaxis/guide/examples/data/can/signal-types.asc +13 -0
- chronaxis/guide/examples/data/can/start-end.asc +30 -0
- chronaxis/guide/examples/data/can/teaching-base.asc +58 -0
- chronaxis/guide/examples/data/can/teaching.dbc +53 -0
- chronaxis/guide/examples/data/joint-current.csv +5 -0
- chronaxis/guide/examples/data/joint.asc +5 -0
- chronaxis/guide/examples/data/joint.dbc +7 -0
- chronaxis/guide/examples/data/message-clean.asc +6 -0
- chronaxis/guide/examples/data/message-direction.asc +7 -0
- chronaxis/guide/examples/data/message-direction.dbc +7 -0
- chronaxis/guide/examples/data/power.blf +0 -0
- chronaxis/guide/examples/data/power.dbc +6 -0
- chronaxis/guide/examples/data/quality.csv +5 -0
- chronaxis/guide/examples/data/raw-can-example.csv +5 -0
- chronaxis/guide/examples/data/signal-types.csv +5 -0
- chronaxis/guide/examples/data/signals.csv +6 -0
- chronaxis/guide/examples/data/timing.asc +6 -0
- chronaxis/guide/examples/data/timing.dbc +11 -0
- chronaxis/guide/examples/export-can-minimal.yaml +24 -0
- chronaxis/guide/examples/input-csv-minimal.yaml +23 -0
- chronaxis/guide/examples/preset-charge-energy.yaml +41 -0
- chronaxis/guide/examples/preset-charge-minimal.yaml +31 -0
- chronaxis/guide/examples/preset-fault-context.yaml +27 -0
- chronaxis/guide/examples/quality.yaml +19 -0
- chronaxis/guide/examples/sequence-outcomes.yaml +39 -0
- chronaxis/guide/examples/shared/definitions.yaml +14 -0
- chronaxis/guide/examples/signal-enum-minimal.yaml +19 -0
- chronaxis/guide/examples/signal-number-conversion.yaml +24 -0
- chronaxis/guide/examples/window-merged.yaml +28 -0
- chronaxis/guide/fields/analysis/calculations-all-1.json +360 -0
- chronaxis/guide/fields/analysis/calculations-all-2.json +299 -0
- chronaxis/guide/fields/analysis/calculations-all-3.json +70 -0
- chronaxis/guide/fields/analysis/config_version-all-1.json +24 -0
- chronaxis/guide/fields/analysis/dataset-all-1.json +344 -0
- chronaxis/guide/fields/analysis/derived-all-1.json +147 -0
- chronaxis/guide/fields/analysis/diagnostics-all-1.json +69 -0
- chronaxis/guide/fields/analysis/execution-all-1.json +167 -0
- chronaxis/guide/fields/analysis/imports-all-1.json +39 -0
- chronaxis/guide/fields/analysis/intervals-all-1.json +173 -0
- chronaxis/guide/fields/analysis/message_calculations-all-1.json +360 -0
- chronaxis/guide/fields/analysis/message_calculations-all-2.json +255 -0
- chronaxis/guide/fields/analysis/metadata-all-1.json +24 -0
- chronaxis/guide/fields/analysis/outputs-all-1.json +349 -0
- chronaxis/guide/fields/analysis/outputs-all-2.json +302 -0
- chronaxis/guide/fields/analysis/outputs-all-3.json +321 -0
- chronaxis/guide/fields/analysis/outputs-all-4.json +253 -0
- chronaxis/guide/fields/analysis/outputs-all-5.json +244 -0
- chronaxis/guide/fields/analysis/outputs-all-6.json +199 -0
- chronaxis/guide/fields/analysis/overrides-all-1.json +104 -0
- chronaxis/guide/fields/analysis/presets-charge_session-1.json +398 -0
- chronaxis/guide/fields/analysis/presets-charge_session-2.json +114 -0
- chronaxis/guide/fields/analysis/presets-command_response-1.json +376 -0
- chronaxis/guide/fields/analysis/presets-fault_context-1.json +285 -0
- chronaxis/guide/fields/analysis/presets-threshold_excursion-1.json +317 -0
- chronaxis/guide/fields/analysis/rules-condition_duration-1.json +344 -0
- chronaxis/guide/fields/analysis/rules-condition_duration-2.json +27 -0
- chronaxis/guide/fields/analysis/rules-debounce-1.json +335 -0
- chronaxis/guide/fields/analysis/rules-falling_edge-1.json +317 -0
- chronaxis/guide/fields/analysis/rules-hysteresis-1.json +334 -0
- chronaxis/guide/fields/analysis/rules-hysteresis-2.json +27 -0
- chronaxis/guide/fields/analysis/rules-rising_edge-1.json +317 -0
- chronaxis/guide/fields/analysis/rules-start_end-1.json +349 -0
- chronaxis/guide/fields/analysis/rules-start_end-2.json +44 -0
- chronaxis/guide/fields/analysis/rules-start_only-1.json +334 -0
- chronaxis/guide/fields/analysis/rules-window_delta-1.json +356 -0
- chronaxis/guide/fields/analysis/rules-window_delta-2.json +78 -0
- chronaxis/guide/fields/analysis/sequences-all-1.json +394 -0
- chronaxis/guide/fields/analysis/sequences-all-2.json +54 -0
- chronaxis/guide/fields/analysis/signals-variant-1-1.json +349 -0
- chronaxis/guide/fields/analysis/signals-variant-1-2.json +297 -0
- chronaxis/guide/fields/analysis/signals-variant-1-3.json +340 -0
- chronaxis/guide/fields/analysis/signals-variant-1-4.json +175 -0
- chronaxis/guide/fields/analysis/signals-variant-2-1.json +327 -0
- chronaxis/guide/fields/analysis/signals-variant-2-2.json +335 -0
- chronaxis/guide/fields/analysis/signals-variant-2-3.json +289 -0
- chronaxis/guide/fields/analysis/signals-variant-2-4.json +270 -0
- chronaxis/guide/fields/analysis/sources-can_asc-1.json +318 -0
- chronaxis/guide/fields/analysis/sources-can_asc-2.json +310 -0
- chronaxis/guide/fields/analysis/sources-can_asc-3.json +311 -0
- chronaxis/guide/fields/analysis/sources-can_asc-4.json +69 -0
- chronaxis/guide/fields/analysis/sources-can_blf-1.json +317 -0
- chronaxis/guide/fields/analysis/sources-can_blf-2.json +310 -0
- chronaxis/guide/fields/analysis/sources-can_blf-3.json +317 -0
- chronaxis/guide/fields/analysis/sources-memory-1.json +347 -0
- chronaxis/guide/fields/analysis/sources-memory-2.json +110 -0
- chronaxis/guide/fields/analysis/sources-raw_can_csv-1.json +330 -0
- chronaxis/guide/fields/analysis/sources-raw_can_csv-10.json +233 -0
- chronaxis/guide/fields/analysis/sources-raw_can_csv-11.json +225 -0
- chronaxis/guide/fields/analysis/sources-raw_can_csv-12.json +228 -0
- chronaxis/guide/fields/analysis/sources-raw_can_csv-13.json +226 -0
- chronaxis/guide/fields/analysis/sources-raw_can_csv-14.json +230 -0
- chronaxis/guide/fields/analysis/sources-raw_can_csv-15.json +227 -0
- chronaxis/guide/fields/analysis/sources-raw_can_csv-16.json +230 -0
- chronaxis/guide/fields/analysis/sources-raw_can_csv-17.json +238 -0
- chronaxis/guide/fields/analysis/sources-raw_can_csv-18.json +239 -0
- chronaxis/guide/fields/analysis/sources-raw_can_csv-19.json +233 -0
- chronaxis/guide/fields/analysis/sources-raw_can_csv-2.json +310 -0
- chronaxis/guide/fields/analysis/sources-raw_can_csv-20.json +242 -0
- chronaxis/guide/fields/analysis/sources-raw_can_csv-21.json +230 -0
- chronaxis/guide/fields/analysis/sources-raw_can_csv-22.json +228 -0
- chronaxis/guide/fields/analysis/sources-raw_can_csv-23.json +230 -0
- chronaxis/guide/fields/analysis/sources-raw_can_csv-24.json +223 -0
- chronaxis/guide/fields/analysis/sources-raw_can_csv-25.json +290 -0
- chronaxis/guide/fields/analysis/sources-raw_can_csv-26.json +131 -0
- chronaxis/guide/fields/analysis/sources-raw_can_csv-3.json +297 -0
- chronaxis/guide/fields/analysis/sources-raw_can_csv-4.json +226 -0
- chronaxis/guide/fields/analysis/sources-raw_can_csv-5.json +230 -0
- chronaxis/guide/fields/analysis/sources-raw_can_csv-6.json +227 -0
- chronaxis/guide/fields/analysis/sources-raw_can_csv-7.json +230 -0
- chronaxis/guide/fields/analysis/sources-raw_can_csv-8.json +238 -0
- chronaxis/guide/fields/analysis/sources-raw_can_csv-9.json +239 -0
- chronaxis/guide/fields/analysis/sources-signal_csv-1.json +331 -0
- chronaxis/guide/fields/analysis/sources-signal_csv-2.json +327 -0
- chronaxis/guide/fields/analysis/sources-signal_csv-3.json +295 -0
- chronaxis/guide/fields/analysis/sources-variant-6-1.json +319 -0
- chronaxis/guide/fields/analysis/sources-variant-6-2.json +327 -0
- chronaxis/guide/fields/analysis/sources-variant-6-3.json +314 -0
- chronaxis/guide/fields/analysis/sources-variant-6-4.json +91 -0
- chronaxis/guide/fields/analysis/windows-all-1.json +361 -0
- chronaxis/guide/fields/analysis/windows-all-2.json +187 -0
- chronaxis/guide/fields/batch/backend-all-1.json +26 -0
- chronaxis/guide/fields/batch/batch_version-all-1.json +22 -0
- chronaxis/guide/fields/batch/fail_fast-all-1.json +22 -0
- chronaxis/guide/fields/batch/inputs-all-1.json +161 -0
- chronaxis/guide/fields/batch/jobs-all-1.json +58 -0
- chronaxis/guide/fields/batch/process_count-all-1.json +23 -0
- chronaxis/guide/fields/batch/source-all-1.json +22 -0
- chronaxis/guide/fields/batch/template-all-1.json +22 -0
- chronaxis/guide/fields/definitions/derived-all-1.json +121 -0
- chronaxis/guide/fields/definitions/signals-all-1.json +336 -0
- chronaxis/guide/fields/definitions/signals-all-2.json +307 -0
- chronaxis/guide/fields/definitions/signals-all-3.json +305 -0
- chronaxis/guide/fields/definitions/signals-all-4.json +352 -0
- chronaxis/guide/fields/definitions/signals-all-5.json +311 -0
- chronaxis/guide/fields/definitions/signals-all-6.json +254 -0
- chronaxis/guide/fields/definitions/signals-all-7.json +88 -0
- chronaxis/guide/fields/definitions/sources-all-1.json +332 -0
- chronaxis/guide/fields/definitions/sources-all-10.json +307 -0
- chronaxis/guide/fields/definitions/sources-all-11.json +280 -0
- chronaxis/guide/fields/definitions/sources-all-12.json +209 -0
- chronaxis/guide/fields/definitions/sources-all-13.json +219 -0
- chronaxis/guide/fields/definitions/sources-all-14.json +213 -0
- chronaxis/guide/fields/definitions/sources-all-15.json +212 -0
- chronaxis/guide/fields/definitions/sources-all-16.json +232 -0
- chronaxis/guide/fields/definitions/sources-all-17.json +213 -0
- chronaxis/guide/fields/definitions/sources-all-18.json +212 -0
- chronaxis/guide/fields/definitions/sources-all-19.json +217 -0
- chronaxis/guide/fields/definitions/sources-all-2.json +336 -0
- chronaxis/guide/fields/definitions/sources-all-20.json +228 -0
- chronaxis/guide/fields/definitions/sources-all-21.json +212 -0
- chronaxis/guide/fields/definitions/sources-all-22.json +232 -0
- chronaxis/guide/fields/definitions/sources-all-23.json +213 -0
- chronaxis/guide/fields/definitions/sources-all-24.json +212 -0
- chronaxis/guide/fields/definitions/sources-all-25.json +217 -0
- chronaxis/guide/fields/definitions/sources-all-26.json +228 -0
- chronaxis/guide/fields/definitions/sources-all-27.json +212 -0
- chronaxis/guide/fields/definitions/sources-all-28.json +217 -0
- chronaxis/guide/fields/definitions/sources-all-29.json +227 -0
- chronaxis/guide/fields/definitions/sources-all-3.json +306 -0
- chronaxis/guide/fields/definitions/sources-all-30.json +333 -0
- chronaxis/guide/fields/definitions/sources-all-31.json +302 -0
- chronaxis/guide/fields/definitions/sources-all-32.json +319 -0
- chronaxis/guide/fields/definitions/sources-all-33.json +89 -0
- chronaxis/guide/fields/definitions/sources-all-4.json +336 -0
- chronaxis/guide/fields/definitions/sources-all-5.json +313 -0
- chronaxis/guide/fields/definitions/sources-all-6.json +292 -0
- chronaxis/guide/fields/definitions/sources-all-7.json +319 -0
- chronaxis/guide/fields/definitions/sources-all-8.json +315 -0
- chronaxis/guide/fields/definitions/sources-all-9.json +318 -0
- chronaxis/guide/fields/index.json +3432 -0
- chronaxis/guide/fields/mapping/aliases-all-1.json +91 -0
- chronaxis/guide/fields/mapping/analysis-all-1.json +382 -0
- chronaxis/guide/fields/mapping/analysis-all-10.json +307 -0
- chronaxis/guide/fields/mapping/analysis-all-11.json +311 -0
- chronaxis/guide/fields/mapping/analysis-all-12.json +329 -0
- chronaxis/guide/fields/mapping/analysis-all-13.json +294 -0
- chronaxis/guide/fields/mapping/analysis-all-14.json +311 -0
- chronaxis/guide/fields/mapping/analysis-all-15.json +280 -0
- chronaxis/guide/fields/mapping/analysis-all-16.json +227 -0
- chronaxis/guide/fields/mapping/analysis-all-17.json +230 -0
- chronaxis/guide/fields/mapping/analysis-all-18.json +221 -0
- chronaxis/guide/fields/mapping/analysis-all-19.json +237 -0
- chronaxis/guide/fields/mapping/analysis-all-2.json +342 -0
- chronaxis/guide/fields/mapping/analysis-all-20.json +233 -0
- chronaxis/guide/fields/mapping/analysis-all-21.json +244 -0
- chronaxis/guide/fields/mapping/analysis-all-22.json +228 -0
- chronaxis/guide/fields/mapping/analysis-all-23.json +226 -0
- chronaxis/guide/fields/mapping/analysis-all-24.json +230 -0
- chronaxis/guide/fields/mapping/analysis-all-25.json +227 -0
- chronaxis/guide/fields/mapping/analysis-all-26.json +230 -0
- chronaxis/guide/fields/mapping/analysis-all-27.json +221 -0
- chronaxis/guide/fields/mapping/analysis-all-28.json +237 -0
- chronaxis/guide/fields/mapping/analysis-all-29.json +233 -0
- chronaxis/guide/fields/mapping/analysis-all-3.json +322 -0
- chronaxis/guide/fields/mapping/analysis-all-30.json +244 -0
- chronaxis/guide/fields/mapping/analysis-all-31.json +228 -0
- chronaxis/guide/fields/mapping/analysis-all-32.json +226 -0
- chronaxis/guide/fields/mapping/analysis-all-33.json +230 -0
- chronaxis/guide/fields/mapping/analysis-all-34.json +227 -0
- chronaxis/guide/fields/mapping/analysis-all-35.json +230 -0
- chronaxis/guide/fields/mapping/analysis-all-36.json +221 -0
- chronaxis/guide/fields/mapping/analysis-all-37.json +291 -0
- chronaxis/guide/fields/mapping/analysis-all-38.json +315 -0
- chronaxis/guide/fields/mapping/analysis-all-39.json +304 -0
- chronaxis/guide/fields/mapping/analysis-all-4.json +312 -0
- chronaxis/guide/fields/mapping/analysis-all-40.json +307 -0
- chronaxis/guide/fields/mapping/analysis-all-41.json +292 -0
- chronaxis/guide/fields/mapping/analysis-all-42.json +333 -0
- chronaxis/guide/fields/mapping/analysis-all-43.json +296 -0
- chronaxis/guide/fields/mapping/analysis-all-44.json +322 -0
- chronaxis/guide/fields/mapping/analysis-all-45.json +298 -0
- chronaxis/guide/fields/mapping/analysis-all-46.json +347 -0
- chronaxis/guide/fields/mapping/analysis-all-47.json +302 -0
- chronaxis/guide/fields/mapping/analysis-all-48.json +263 -0
- chronaxis/guide/fields/mapping/analysis-all-49.json +301 -0
- chronaxis/guide/fields/mapping/analysis-all-5.json +313 -0
- chronaxis/guide/fields/mapping/analysis-all-50.json +336 -0
- chronaxis/guide/fields/mapping/analysis-all-51.json +335 -0
- chronaxis/guide/fields/mapping/analysis-all-52.json +335 -0
- chronaxis/guide/fields/mapping/analysis-all-53.json +334 -0
- chronaxis/guide/fields/mapping/analysis-all-54.json +339 -0
- chronaxis/guide/fields/mapping/analysis-all-55.json +335 -0
- chronaxis/guide/fields/mapping/analysis-all-56.json +336 -0
- chronaxis/guide/fields/mapping/analysis-all-57.json +335 -0
- chronaxis/guide/fields/mapping/analysis-all-58.json +333 -0
- chronaxis/guide/fields/mapping/analysis-all-59.json +325 -0
- chronaxis/guide/fields/mapping/analysis-all-6.json +323 -0
- chronaxis/guide/fields/mapping/analysis-all-60.json +334 -0
- chronaxis/guide/fields/mapping/analysis-all-61.json +311 -0
- chronaxis/guide/fields/mapping/analysis-all-62.json +289 -0
- chronaxis/guide/fields/mapping/analysis-all-63.json +383 -0
- chronaxis/guide/fields/mapping/analysis-all-64.json +357 -0
- chronaxis/guide/fields/mapping/analysis-all-65.json +375 -0
- chronaxis/guide/fields/mapping/analysis-all-66.json +351 -0
- chronaxis/guide/fields/mapping/analysis-all-67.json +346 -0
- chronaxis/guide/fields/mapping/analysis-all-68.json +317 -0
- chronaxis/guide/fields/mapping/analysis-all-69.json +313 -0
- chronaxis/guide/fields/mapping/analysis-all-7.json +306 -0
- chronaxis/guide/fields/mapping/analysis-all-70.json +326 -0
- chronaxis/guide/fields/mapping/analysis-all-71.json +316 -0
- chronaxis/guide/fields/mapping/analysis-all-72.json +264 -0
- chronaxis/guide/fields/mapping/analysis-all-73.json +228 -0
- chronaxis/guide/fields/mapping/analysis-all-74.json +241 -0
- chronaxis/guide/fields/mapping/analysis-all-75.json +273 -0
- chronaxis/guide/fields/mapping/analysis-all-76.json +382 -0
- chronaxis/guide/fields/mapping/analysis-all-77.json +328 -0
- chronaxis/guide/fields/mapping/analysis-all-78.json +338 -0
- chronaxis/guide/fields/mapping/analysis-all-79.json +304 -0
- chronaxis/guide/fields/mapping/analysis-all-8.json +309 -0
- chronaxis/guide/fields/mapping/analysis-all-80.json +140 -0
- chronaxis/guide/fields/mapping/analysis-all-9.json +329 -0
- chronaxis/guide/fields/mapping/io_policy-all-1.json +19 -0
- chronaxis/guide/fields/mapping/mapping_version-all-1.json +19 -0
- chronaxis/guide/fields/mapping/path_base-all-1.json +19 -0
- chronaxis/guide/fields/mapping/sections-all-1.json +402 -0
- chronaxis/guide/fields/mapping/sections-all-2.json +232 -0
- chronaxis/guide/lookup.py +90 -0
- chronaxis/guide/manifest.json +614 -0
- chronaxis/guide/run_analysis.py +34 -0
- chronaxis/guide/schemas/analysis.schema.json +8451 -0
- chronaxis/guide/schemas/batch-v1.schema.json +172 -0
- chronaxis/guide/schemas/definitions.schema.json +29 -0
- chronaxis/guide/schemas/legacy-import-v1.schema.json +143 -0
- chronaxis/guide/semantics.md +62 -0
- chronaxis/guide/tasks.json +290 -0
- chronaxis/guide/workflow.md +38 -0
- chronaxis/legacy/__init__.py +46 -0
- chronaxis/legacy/batch_read.py +412 -0
- chronaxis/legacy/batch_validation.py +134 -0
- chronaxis/legacy/batch_wire.py +264 -0
- chronaxis/legacy/batch_worker.py +417 -0
- chronaxis/legacy/binding.py +154 -0
- chronaxis/legacy/dbc_cycles.py +47 -0
- chronaxis/legacy/decode_policy.py +28 -0
- chronaxis/legacy/disjunction.py +79 -0
- chronaxis/legacy/export_worker.py +147 -0
- chronaxis/legacy/export_write.py +378 -0
- chronaxis/legacy/message_store.py +562 -0
- chronaxis/legacy/process_read.py +526 -0
- chronaxis/legacy/raw_store.py +341 -0
- chronaxis/legacy/records.py +709 -0
- chronaxis/legacy/required_records.py +122 -0
- chronaxis/legacy/sum.py +403 -0
- chronaxis/legacy/sum_numpy.py +43 -0
- chronaxis/legacy/updates.py +277 -0
- chronaxis/legacy/vendor/sclicer_functions_v1/can_processor.py +138 -0
- chronaxis/legacy/vendor/sclicer_functions_v1/file_processor.py +218 -0
- chronaxis/legacy/vendor/sclicer_functions_v1/utils.py +447 -0
- chronaxis/legacy/worker.py +352 -0
- chronaxis/migration/__init__.py +11 -0
- chronaxis/migration/api.py +270 -0
- chronaxis/migration/ini.py +110 -0
- chronaxis/migration/legacy_sum.py +304 -0
- chronaxis/migration/models.py +83 -0
- chronaxis/migration/publication.py +230 -0
- chronaxis/migration/sclicer.py +241 -0
- chronaxis/migration/slope.py +78 -0
- chronaxis/migration/start_end.py +48 -0
- chronaxis/planning/__init__.py +19 -0
- chronaxis/planning/channels.py +30 -0
- chronaxis/planning/checks.py +447 -0
- chronaxis/planning/config_groups.py +215 -0
- chronaxis/planning/dbc_defaults.py +88 -0
- chronaxis/planning/export_options.py +247 -0
- chronaxis/planning/input_defaults.py +62 -0
- chronaxis/planning/input_paths.py +124 -0
- chronaxis/planning/input_requirements.py +250 -0
- chronaxis/planning/inputs.py +306 -0
- chronaxis/planning/intervals.py +242 -0
- chronaxis/planning/legacy_execution.py +38 -0
- chronaxis/planning/message_calculations.py +171 -0
- chronaxis/planning/models.py +369 -0
- chronaxis/planning/nodes.py +355 -0
- chronaxis/planning/plan.py +294 -0
- chronaxis/planning/preset_models.py +211 -0
- chronaxis/planning/record_execution.py +76 -0
- chronaxis/planning/reports.py +523 -0
- chronaxis/planning/sequences.py +91 -0
- chronaxis/planning/signal_groups.py +61 -0
- chronaxis/planning/signal_validity.py +46 -0
- chronaxis/planning/text_inputs.py +110 -0
- chronaxis/presets.py +270 -0
- chronaxis/results/__init__.py +34 -0
- chronaxis/results/analysis_outcome.py +67 -0
- chronaxis/results/artifact_exports.py +212 -0
- chronaxis/results/binding_metadata.py +54 -0
- chronaxis/results/budget.py +138 -0
- chronaxis/results/can_metadata.py +247 -0
- chronaxis/results/codec.py +246 -0
- chronaxis/results/errors.py +25 -0
- chronaxis/results/export_files.py +216 -0
- chronaxis/results/frame_exports.py +299 -0
- chronaxis/results/frame_patch.py +186 -0
- chronaxis/results/frame_rebuild.py +458 -0
- chronaxis/results/frame_sort.py +223 -0
- chronaxis/results/input_diagnostics.py +51 -0
- chronaxis/results/manifest.py +343 -0
- chronaxis/results/merge_runs.py +207 -0
- chronaxis/results/owned_directory.py +32 -0
- chronaxis/results/raw_exports.py +689 -0
- chronaxis/results/readable.py +355 -0
- chronaxis/results/readable_format.py +94 -0
- chronaxis/results/result.py +734 -0
- chronaxis/results/rows.py +57 -0
- chronaxis/results/signal_exports.py +209 -0
- chronaxis/results/signal_grid.py +219 -0
- chronaxis/results/spool.py +421 -0
- chronaxis/results/summary.py +350 -0
- chronaxis/results/text_can_metadata.py +64 -0
- chronaxis/results/threshold_metadata.py +105 -0
- chronaxis/runner.py +121 -0
- chronaxis/sources/__init__.py +23 -0
- chronaxis/sources/asc.py +412 -0
- chronaxis/sources/blf.py +101 -0
- chronaxis/sources/can_spec.py +179 -0
- chronaxis/sources/can_updates.py +160 -0
- chronaxis/sources/csv_spec.py +133 -0
- chronaxis/sources/descriptions.py +65 -0
- chronaxis/sources/memory.py +299 -0
- chronaxis/sources/models.py +497 -0
- chronaxis/sources/packing.py +170 -0
- chronaxis/sources/protocol.py +221 -0
- chronaxis/sources/raw_can.py +62 -0
- chronaxis/sources/raw_csv.py +470 -0
- chronaxis/sources/raw_csv_layout.py +310 -0
- chronaxis/sources/signal_csv.py +608 -0
- chronaxis/sources/text_can_decode.py +421 -0
- chronaxis/sources/text_can_ref.py +48 -0
- chronaxis/sources/text_can_spec.py +61 -0
- chronaxis/timebase/__init__.py +19 -0
- chronaxis/timebase/conversion.py +364 -0
- chronaxis/timebase/numpy_ops.py +104 -0
- chronaxis/user_guide.py +81 -0
- chronaxis-0.1.0.dev0.dist-info/METADATA +172 -0
- chronaxis-0.1.0.dev0.dist-info/RECORD +917 -0
- chronaxis-0.1.0.dev0.dist-info/WHEEL +5 -0
- chronaxis-0.1.0.dev0.dist-info/entry_points.txt +2 -0
- chronaxis-0.1.0.dev0.dist-info/licenses/LICENSE +21 -0
- chronaxis-0.1.0.dev0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
"""传递独立计划快照和小型结果,保留工作进程中的失败清理责任。
|
|
2
|
+
|
|
3
|
+
管道仅连接本次创建的可信子进程,不读取外部序列化对象。计划重建后核对身份,
|
|
4
|
+
大型结果在子进程内写出并关闭。清理失败的进程暂停接活,由报告句柄远程重试。
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from dataclasses import replace
|
|
8
|
+
import multiprocessing
|
|
9
|
+
import os
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
import signal
|
|
12
|
+
from threading import Event
|
|
13
|
+
|
|
14
|
+
from ..planning.plan import AnalysisPlan
|
|
15
|
+
from ..planning.checks import json_value
|
|
16
|
+
from .models import BatchJob, BatchJobResult, CleanupHandle
|
|
17
|
+
from .process_tree import ProcessTree
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def job_packet(job):
|
|
21
|
+
"""提取无活动资源的计划。参数: BatchJob。返回: 原生dict。异常: 配置转换错误。"""
|
|
22
|
+
if isinstance(job.plan, Path):
|
|
23
|
+
return dict(job_id=job.job_id, path=str(job.plan.absolute()))
|
|
24
|
+
return dict(job_id=job.job_id, config=json_value(job.plan.raw_config),
|
|
25
|
+
base_dir=str(job.plan.base_dir), identity=job.plan.identity)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def restore_job(packet):
|
|
29
|
+
"""恢复独立计划。参数: 本进程收到的声明。返回: BatchJob。异常: 重建或身份不一致。"""
|
|
30
|
+
if 'path' in packet:
|
|
31
|
+
return BatchJob(packet['job_id'], Path(packet['path']))
|
|
32
|
+
plan = AnalysisPlan.from_dict(packet['config'], base_dir=packet['base_dir'])
|
|
33
|
+
if plan.identity != packet['identity']:
|
|
34
|
+
raise ValueError('跨进程重建后的计划身份不一致')
|
|
35
|
+
return BatchJob(packet['job_id'], plan)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def worker_main(connection):
|
|
39
|
+
"""处理run/cleanup/close命令。参数: 私有管道。返回: None。异常: 断管退出,父进程负责树清理。"""
|
|
40
|
+
from .runner import _run_job, _diagnostics
|
|
41
|
+
# Ctrl+C只由调度主进程接收,正在写结果的工作进程继续完整收尾。
|
|
42
|
+
signal.signal(signal.SIGINT, signal.SIG_IGN)
|
|
43
|
+
recovery = None
|
|
44
|
+
try:
|
|
45
|
+
while True:
|
|
46
|
+
command = connection.recv()
|
|
47
|
+
if command[0] == 'close':
|
|
48
|
+
if recovery is not None:
|
|
49
|
+
recovery.close()
|
|
50
|
+
return
|
|
51
|
+
if command[0] == 'cleanup':
|
|
52
|
+
try:
|
|
53
|
+
if recovery is not None:
|
|
54
|
+
recovery.close()
|
|
55
|
+
recovery = None
|
|
56
|
+
connection.send(('cleaned', None))
|
|
57
|
+
except BaseException as error:
|
|
58
|
+
connection.send(('cleanup_failed', _diagnostics(error)))
|
|
59
|
+
continue
|
|
60
|
+
if recovery is not None:
|
|
61
|
+
raise RuntimeError('存在未关闭资源的工作进程不能接收新任务')
|
|
62
|
+
_, packet, directory, backend = command
|
|
63
|
+
try:
|
|
64
|
+
job = restore_job(packet)
|
|
65
|
+
outcome = _run_job(job, Path(directory), backend, Event(), Event())
|
|
66
|
+
except BaseException as error:
|
|
67
|
+
outcome = BatchJobResult(packet['job_id'], 'failed',
|
|
68
|
+
plan_path=packet.get('path'), error_type=type(error).__name__,
|
|
69
|
+
error_message=str(error), error_chain=_diagnostics(error))
|
|
70
|
+
recovery = outcome.recovery
|
|
71
|
+
pending = recovery is not None and not recovery.closed
|
|
72
|
+
# 只发送冻结的纯结果字段;CleanupHandle的原资源必须留在拥有它的进程。
|
|
73
|
+
connection.send(('result', replace(outcome, recovery=None, worker_pid=os.getpid()), pending))
|
|
74
|
+
except EOFError:
|
|
75
|
+
if recovery is not None:
|
|
76
|
+
recovery.close()
|
|
77
|
+
finally:
|
|
78
|
+
connection.close()
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class ProcessWorker:
|
|
82
|
+
"""保存一个可复用工作进程、私有管道及其后代的清理责任。"""
|
|
83
|
+
|
|
84
|
+
def __init__(self):
|
|
85
|
+
"""启动等待命令的spawn进程。参数: 无。返回: 新对象。异常: 启动/树登记失败立即回收。"""
|
|
86
|
+
context = multiprocessing.get_context('spawn')
|
|
87
|
+
self.connection, child = context.Pipe()
|
|
88
|
+
self.process = context.Process(target=worker_main, args=(child,), daemon=False)
|
|
89
|
+
self.tree = None
|
|
90
|
+
self.closed = False
|
|
91
|
+
self.pending = False
|
|
92
|
+
try:
|
|
93
|
+
self.process.start()
|
|
94
|
+
self.tree = ProcessTree(self.process.pid)
|
|
95
|
+
except BaseException:
|
|
96
|
+
if self.process.pid is not None:
|
|
97
|
+
self.process.terminate()
|
|
98
|
+
self.process.join()
|
|
99
|
+
self.connection.close()
|
|
100
|
+
self.process.close()
|
|
101
|
+
raise
|
|
102
|
+
finally:
|
|
103
|
+
child.close()
|
|
104
|
+
self.pid = self.process.pid
|
|
105
|
+
|
|
106
|
+
def submit(self, job, directory, backend):
|
|
107
|
+
"""发送独立任务。参数: job/目录/后端。返回: None。异常: 转换或通信错误。"""
|
|
108
|
+
self.connection.send(('run', job_packet(job), str(directory), backend))
|
|
109
|
+
|
|
110
|
+
def ready(self):
|
|
111
|
+
"""查询结果或异常退出。参数: 无。返回: bool。异常: 原管道错误。"""
|
|
112
|
+
try:
|
|
113
|
+
return self.connection.poll() or not self.process.is_alive()
|
|
114
|
+
except (EOFError, OSError) as error:
|
|
115
|
+
raise ChildProcessError('分析工作进程管道已断开,PID=' + str(self.pid)) from error
|
|
116
|
+
|
|
117
|
+
def receive(self):
|
|
118
|
+
"""取结果并挂远程恢复句柄。参数: 无。返回: BatchJobResult。异常: 进程死亡或协议错误。"""
|
|
119
|
+
if not self.connection.poll():
|
|
120
|
+
raise ChildProcessError('分析工作进程异常退出,PID=' + str(self.pid))
|
|
121
|
+
try:
|
|
122
|
+
kind, result, self.pending = self.connection.recv()
|
|
123
|
+
except EOFError as error:
|
|
124
|
+
raise ChildProcessError('分析工作进程断开,PID=' + str(self.pid)) from error
|
|
125
|
+
if kind != 'result' or not isinstance(result, BatchJobResult):
|
|
126
|
+
raise RuntimeError('批量工作进程返回无效结果')
|
|
127
|
+
return replace(result, recovery=CleanupHandle(self) if self.pending else None)
|
|
128
|
+
|
|
129
|
+
def close(self):
|
|
130
|
+
"""重试远程清理后关闭进程树。参数: 无。返回: None。异常: 清理失败保留全部所有者。"""
|
|
131
|
+
if self.closed:
|
|
132
|
+
return
|
|
133
|
+
if self.process.is_alive():
|
|
134
|
+
if self.pending:
|
|
135
|
+
self.connection.send(('cleanup',))
|
|
136
|
+
kind, detail = self.connection.recv()
|
|
137
|
+
if kind != 'cleaned':
|
|
138
|
+
raise RuntimeError('工作进程资源尚未关闭:' + '; '.join(detail))
|
|
139
|
+
self.pending = False
|
|
140
|
+
self.connection.send(('close',))
|
|
141
|
+
self.process.join()
|
|
142
|
+
else:
|
|
143
|
+
self.process.join()
|
|
144
|
+
# 工作进程已退出后关闭作业,清除故障残余的CAN读取后代。
|
|
145
|
+
if self.tree is not None:
|
|
146
|
+
self.tree.close()
|
|
147
|
+
self.connection.close()
|
|
148
|
+
self.process.close()
|
|
149
|
+
self.closed = True
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"""将批量工作进程及其CAN读取子进程纳入同一个Windows作业对象。
|
|
2
|
+
|
|
3
|
+
主进程持有唯一作业句柄;工作进程先等待派发,归属登记成功后才运行用户计划。
|
|
4
|
+
关闭作业会结束残余后代,避免工作进程异常退出留下读取进程。不修改旧读取器。
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import ctypes
|
|
8
|
+
from ctypes import wintypes
|
|
9
|
+
import os
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class _BasicLimits(ctypes.Structure):
|
|
13
|
+
"""对应Windows基本作业限制结构;仅设置关闭句柄时结束整个作业。"""
|
|
14
|
+
|
|
15
|
+
_fields_ = [('per_process', ctypes.c_longlong), ('per_job', ctypes.c_longlong),
|
|
16
|
+
('flags', wintypes.DWORD), ('min_ws', ctypes.c_size_t),
|
|
17
|
+
('max_ws', ctypes.c_size_t), ('active_limit', wintypes.DWORD),
|
|
18
|
+
('affinity', ctypes.c_size_t), ('priority', wintypes.DWORD),
|
|
19
|
+
('scheduling', wintypes.DWORD)]
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class _ExtendedLimits(ctypes.Structure):
|
|
23
|
+
"""对应Windows扩展作业限制,未使用的资源额度保持零值。"""
|
|
24
|
+
|
|
25
|
+
_fields_ = [('basic', _BasicLimits), ('io', ctypes.c_ulonglong * 6),
|
|
26
|
+
('process_memory', ctypes.c_size_t), ('job_memory', ctypes.c_size_t),
|
|
27
|
+
('peak_process', ctypes.c_size_t), ('peak_job', ctypes.c_size_t)]
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class ProcessTree:
|
|
31
|
+
"""持有一个工作进程树的关闭责任;当前公开结果发布仅支持Windows。"""
|
|
32
|
+
|
|
33
|
+
def __init__(self, pid):
|
|
34
|
+
"""登记实际PID。参数: pid已启动但尚未派发的进程。返回: 新对象。异常: 平台或系统错误。"""
|
|
35
|
+
if os.name != 'nt':
|
|
36
|
+
raise NotImplementedError('批量进程树清理目前只验收Windows')
|
|
37
|
+
api = ctypes.WinDLL('kernel32', use_last_error=True)
|
|
38
|
+
api.CreateJobObjectW.argtypes = [ctypes.c_void_p, wintypes.LPCWSTR]
|
|
39
|
+
api.CreateJobObjectW.restype = wintypes.HANDLE
|
|
40
|
+
api.SetInformationJobObject.argtypes = [wintypes.HANDLE, ctypes.c_int, ctypes.c_void_p, wintypes.DWORD]
|
|
41
|
+
api.SetInformationJobObject.restype = wintypes.BOOL
|
|
42
|
+
api.OpenProcess.argtypes = [wintypes.DWORD, wintypes.BOOL, wintypes.DWORD]
|
|
43
|
+
api.OpenProcess.restype = wintypes.HANDLE
|
|
44
|
+
api.AssignProcessToJobObject.argtypes = [wintypes.HANDLE, wintypes.HANDLE]
|
|
45
|
+
api.AssignProcessToJobObject.restype = wintypes.BOOL
|
|
46
|
+
api.CloseHandle.argtypes = [wintypes.HANDLE]
|
|
47
|
+
api.CloseHandle.restype = wintypes.BOOL
|
|
48
|
+
self._api, self._handle = api, api.CreateJobObjectW(None, None)
|
|
49
|
+
if not self._handle:
|
|
50
|
+
raise ctypes.WinError(ctypes.get_last_error())
|
|
51
|
+
process = None
|
|
52
|
+
try:
|
|
53
|
+
limits = _ExtendedLimits()
|
|
54
|
+
limits.basic.flags = 0x2000 # JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;不授予后代脱离权限。
|
|
55
|
+
if not api.SetInformationJobObject(self._handle, 9, ctypes.byref(limits), ctypes.sizeof(limits)):
|
|
56
|
+
raise ctypes.WinError(ctypes.get_last_error())
|
|
57
|
+
process = api.OpenProcess(0x0101, False, pid) # SET_QUOTA | TERMINATE,用于作业分配。
|
|
58
|
+
if not process or not api.AssignProcessToJobObject(self._handle, process):
|
|
59
|
+
raise ctypes.WinError(ctypes.get_last_error())
|
|
60
|
+
except BaseException:
|
|
61
|
+
self.close()
|
|
62
|
+
raise
|
|
63
|
+
finally:
|
|
64
|
+
if process:
|
|
65
|
+
api.CloseHandle(process)
|
|
66
|
+
|
|
67
|
+
def close(self):
|
|
68
|
+
"""关闭树句柄,终止残余后代。参数: 无。返回: None。异常: 关闭失败仍保留句柄供重试。"""
|
|
69
|
+
if self._handle:
|
|
70
|
+
if not self._api.CloseHandle(self._handle):
|
|
71
|
+
raise ctypes.WinError(ctypes.get_last_error())
|
|
72
|
+
self._handle = None
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"""关闭批量汇总JSON后独占安装正式报告,保留各任务已发布的独立输出。
|
|
2
|
+
|
|
3
|
+
报告只汇总状态、身份和错误,不合并指标或把失败会话当作零结果。沿现有结果
|
|
4
|
+
发布的Windows平台范围使用不覆盖rename;其他平台明确拒绝,失败暂存保留。
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import json
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
import platform
|
|
10
|
+
from uuid import uuid4
|
|
11
|
+
from .models import BatchReport
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def write_batch_report(report: BatchReport) -> Path:
|
|
15
|
+
"""发布固定汇总文件。参数: report实际结果。返回: batch_report.json路径。
|
|
16
|
+
|
|
17
|
+
异常: 类型、只读路径、未支持平台、已有目标或原文件错误;关闭失败不安装正式文件。
|
|
18
|
+
副作用: 只写本批目录的唯一暂存文件,失败不删除任务结果或覆盖已有报告。
|
|
19
|
+
"""
|
|
20
|
+
if not isinstance(report, BatchReport):
|
|
21
|
+
raise TypeError('需要BatchReport')
|
|
22
|
+
root = report.output_dir.absolute()
|
|
23
|
+
# 本函数也可独立调用;不能仅依赖调度器已经检查过模型中的路径。
|
|
24
|
+
if any(p.casefold() == 'refprojects' for p in (*root.parts, *root.resolve().parts)):
|
|
25
|
+
raise ValueError('批量报告不能位于RefProjects')
|
|
26
|
+
if platform.system() != 'Windows':
|
|
27
|
+
raise NotImplementedError('批量报告原子发布目前只验收Windows')
|
|
28
|
+
destination = root / 'batch_report.json'
|
|
29
|
+
try:
|
|
30
|
+
destination.lstat()
|
|
31
|
+
except FileNotFoundError:
|
|
32
|
+
pass
|
|
33
|
+
else:
|
|
34
|
+
raise FileExistsError('批量报告已存在,拒绝覆盖:' + str(destination))
|
|
35
|
+
temporary = root / ('.batch-report-' + uuid4().hex + '.incomplete.json')
|
|
36
|
+
# 编码、写入和真实close全部成功才安装;Windows rename在目标已存在时拒绝。
|
|
37
|
+
with temporary.open('x', encoding='utf-8', newline='') as stream:
|
|
38
|
+
json.dump(report.to_dict(), stream, ensure_ascii=False, allow_nan=False, indent=2)
|
|
39
|
+
stream.write('\n')
|
|
40
|
+
temporary.rename(destination)
|
|
41
|
+
return destination
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
"""在外层多进程执行独立计划,复用公共AnalysisRunner完成分析、发布和关闭。
|
|
2
|
+
|
|
3
|
+
每个任务拥有自己的RunSession、预算和目录;不拆分一个会话的时间轴,不共用
|
|
4
|
+
活动、迟滞或配对状态。最多process_count个future在途,未开始的任务不读计划文件。
|
|
5
|
+
取消或fail_fast停止派发,已经开始的任务正常完成关闭;不向工作进程注入异常。
|
|
6
|
+
只承诺每任务原有预算及同时运行数,不承诺全进程RSS或固定进程数带来的性能收益。
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from dataclasses import replace
|
|
10
|
+
import time
|
|
11
|
+
import os
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
from threading import Event
|
|
14
|
+
from time import perf_counter
|
|
15
|
+
|
|
16
|
+
from ..planning import load_analysis_plan
|
|
17
|
+
from ..planning.plan import AnalysisPlan
|
|
18
|
+
from ..runner import AnalysisRunner
|
|
19
|
+
from ..results.spool import _cleanup_owner
|
|
20
|
+
from .models import BatchJob, BatchJobResult, BatchReport, CleanupHandle
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _new_root(value) -> Path:
|
|
24
|
+
"""检查批量新目录。参数: value为str/Path。返回: 绝对Path。异常: 类型/已有/只读路径错误。"""
|
|
25
|
+
if not isinstance(value, (str, Path)):
|
|
26
|
+
raise TypeError('批量输出需要str或Path')
|
|
27
|
+
path = Path(value).absolute()
|
|
28
|
+
# 检查词法和实际路径;悬空链接也按已存在拒绝,不能跟随到其目标。
|
|
29
|
+
if any(p.casefold() == 'refprojects' for p in (*path.parts, *path.resolve().parts)):
|
|
30
|
+
raise ValueError('批量输出不能位于RefProjects')
|
|
31
|
+
try:
|
|
32
|
+
path.lstat()
|
|
33
|
+
except FileNotFoundError:
|
|
34
|
+
return path
|
|
35
|
+
raise FileExistsError('批量输出已存在:' + str(path))
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _facts(job, plan=None) -> dict:
|
|
39
|
+
"""区分配置和输入事实。参数: job原声明;plan可选已加载计划。返回: 字段dict。异常: 无。"""
|
|
40
|
+
loaded = plan if plan is not None else job.plan if isinstance(job.plan, AnalysisPlan) else None
|
|
41
|
+
result = dict(job_id=job.job_id, plan_path=str(job.plan.absolute()) if isinstance(job.plan, Path) else None)
|
|
42
|
+
if loaded is not None:
|
|
43
|
+
result.update(plan_identity=loaded.identity, dataset_id=loaded.dataset.dataset_id,
|
|
44
|
+
entity_id=loaded.dataset.entity, session_id=loaded.dataset.session_id,
|
|
45
|
+
memory_budget_bytes=loaded.execution.memory_budget_bytes)
|
|
46
|
+
return result
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _diagnostics(error) -> tuple[str, ...]:
|
|
50
|
+
"""保留有限异常链而不持有栈。参数: error原异常。返回: 文本tuple。异常: 原异常格式错误。"""
|
|
51
|
+
seen, details = set(), []
|
|
52
|
+
while error is not None and id(error) not in seen:
|
|
53
|
+
seen.add(id(error))
|
|
54
|
+
details.append(type(error).__name__ + ': ' + str(error))
|
|
55
|
+
details.extend(getattr(error, '__notes__', ()))
|
|
56
|
+
error = error.__cause__
|
|
57
|
+
return tuple(details)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _cancelled(job, reason) -> BatchJobResult:
|
|
61
|
+
"""记录未启动取消。参数: job原声明;reason原因。返回: 取消结果。异常: 无,不读取计划。"""
|
|
62
|
+
return BatchJobResult(**_facts(job), status='cancelled', error_type='not_started', error_message=reason)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def _report(root, jobs, results, process_count, fail_fast, cancelled, label, reason) -> BatchReport:
|
|
66
|
+
"""补齐未启动项。参数: 原声明/结果及调度选项。返回: 完整报告。异常: 模型错误。"""
|
|
67
|
+
outcomes = tuple(_cancelled(job, reason) if value is None else value
|
|
68
|
+
for job, value in zip(jobs, results))
|
|
69
|
+
# worker中的真实KeyboardInterrupt也属于取消请求,不只记录主线程的Event。
|
|
70
|
+
requested = cancelled or any(j.error_type in ('KeyboardInterrupt', 'SystemExit') for j in outcomes)
|
|
71
|
+
return BatchReport(root, outcomes, process_count, fail_fast, requested, label)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def _run_job(job, directory, backend, stop, cancel) -> BatchJobResult:
|
|
75
|
+
"""执行一个独立任务并关闭所有资源。
|
|
76
|
+
|
|
77
|
+
参数: job为BatchJob;directory为独占新子目录;backend为覆盖;stop/cancel为Event。
|
|
78
|
+
返回: 含实际发布和身份的最终结果;恢复失败保最高owner,不把异常栈留在结果中。
|
|
79
|
+
异常: 普通分析/发布/取消转换成该任务结果;无法构造结果的内部错误交由调度器收尾。
|
|
80
|
+
"""
|
|
81
|
+
if stop.is_set() or cancel.is_set():
|
|
82
|
+
return _cancelled(job, '任务启动前已停止派发')
|
|
83
|
+
started = perf_counter()
|
|
84
|
+
plan = result = manifest = recovery = None
|
|
85
|
+
metadata = {'worker_pid': os.getpid()}
|
|
86
|
+
try:
|
|
87
|
+
# 路径计划到本任务实际开始才加载,未派发的坏文件不会影响其他任务。
|
|
88
|
+
plan = job.plan if isinstance(job.plan, AnalysisPlan) else load_analysis_plan(job.plan)
|
|
89
|
+
directory.mkdir(parents=True, exist_ok=False)
|
|
90
|
+
result = AnalysisRunner(backend).run(plan, work_dir=directory / 'work')
|
|
91
|
+
metadata.update(input_identity=result.metadata.input_identity, run_id=result.metadata.run_id)
|
|
92
|
+
manifest = result.write(directory / 'output')
|
|
93
|
+
metadata['output_dir'] = manifest.output_dir
|
|
94
|
+
result.close()
|
|
95
|
+
return BatchJobResult(**_facts(job, plan), **metadata, status='completed',
|
|
96
|
+
elapsed_seconds=perf_counter() - started)
|
|
97
|
+
except BaseException as error:
|
|
98
|
+
# 结果已经返回后由本层负责close;未返回的运行恢复owner继续沿AnalysisRunner原协议。
|
|
99
|
+
if result is not None:
|
|
100
|
+
_cleanup_owner(result, error, 'batch_cleanup_owner', '批量任务结果')
|
|
101
|
+
owner = getattr(error, 'batch_cleanup_owner', None)
|
|
102
|
+
if owner is None:
|
|
103
|
+
owner = getattr(error, 'runner_cleanup_owner', None)
|
|
104
|
+
# AnalysisRunner可能保留已经成功关闭的恢复属性;只有仍实际持有资源才转交报告。
|
|
105
|
+
if owner is not None and not (getattr(owner, 'closed', False) or getattr(owner, '_closed', False)):
|
|
106
|
+
recovery = CleanupHandle(owner)
|
|
107
|
+
cancelled = isinstance(error, (KeyboardInterrupt, SystemExit))
|
|
108
|
+
# 资源耗尽或真实取消应停止新派发;普通业务失败由fail_fast决定是否停止。
|
|
109
|
+
if cancelled or isinstance(error, MemoryError):
|
|
110
|
+
stop.set()
|
|
111
|
+
return BatchJobResult(**_facts(job, plan), **metadata,
|
|
112
|
+
status='cancelled' if cancelled else 'failed',
|
|
113
|
+
error_type=type(error).__name__, error_message=str(error),
|
|
114
|
+
error_chain=_diagnostics(error), recovery=recovery,
|
|
115
|
+
elapsed_seconds=perf_counter() - started)
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def _pause():
|
|
119
|
+
"""让出调度CPU等待下一次结果。参数: 无。返回: None。异常: 主进程取消。"""
|
|
120
|
+
time.sleep(0.01)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
class BatchRunner:
|
|
124
|
+
"""通过有限spawn工作进程执行独立任务;同一任务的连续文件保持原顺序。"""
|
|
125
|
+
|
|
126
|
+
def __init__(self, process_count=1, *, fail_fast=False, backend=None):
|
|
127
|
+
"""配置调度。参数: process_count正整数;fail_fast布尔;backend可选计算实现。
|
|
128
|
+
|
|
129
|
+
返回: None。异常: 参数不合法;构造时不启动进程或读取业务输入。
|
|
130
|
+
"""
|
|
131
|
+
if type(process_count) is not int or process_count < 1:
|
|
132
|
+
raise ValueError('process_count需要正原生int')
|
|
133
|
+
if type(fail_fast) is not bool:
|
|
134
|
+
raise TypeError('fail_fast需要bool')
|
|
135
|
+
AnalysisRunner(backend)
|
|
136
|
+
self.process_count, self.fail_fast, self.backend = process_count, fail_fast, backend
|
|
137
|
+
|
|
138
|
+
def run(self, jobs, output_dir, *, cancel_event=None, device_label='pending') -> BatchReport:
|
|
139
|
+
"""运行独立任务,原声明顺序返回报告。
|
|
140
|
+
|
|
141
|
+
参数: jobs为BatchJob tuple;output_dir全新目录;cancel_event可选threading.Event;
|
|
142
|
+
device_label为报告来源标签。返回: BatchReport,close可重试子进程内失败清理。
|
|
143
|
+
异常: 声明和路径错误在启动前拒绝;调度基础设施错误携带batch_report。
|
|
144
|
+
副作用: 启动最多process_count个工作进程,每任务独立发布;取消只阻止未派发任务。
|
|
145
|
+
"""
|
|
146
|
+
from .process_transport import ProcessWorker
|
|
147
|
+
if type(jobs) is not tuple or any(not isinstance(j, BatchJob) for j in jobs):
|
|
148
|
+
raise TypeError('批量任务需要BatchJob tuple')
|
|
149
|
+
if len({j.job_id.casefold() for j in jobs}) != len(jobs):
|
|
150
|
+
raise ValueError('批量job_id不能重复,大小写冲突也拒绝')
|
|
151
|
+
if cancel_event is not None and not isinstance(cancel_event, Event):
|
|
152
|
+
raise TypeError('cancel_event需要threading.Event')
|
|
153
|
+
if type(device_label) is not str or not device_label.strip():
|
|
154
|
+
raise ValueError('device_label需要非空文本')
|
|
155
|
+
root = _new_root(output_dir)
|
|
156
|
+
root.mkdir(parents=True, exist_ok=False)
|
|
157
|
+
cancel = Event() if cancel_event is None else cancel_event
|
|
158
|
+
workers, free, active, last_job = [], [], {}, {}
|
|
159
|
+
results = [None] * len(jobs)
|
|
160
|
+
next_job, stopped, interrupted, infrastructure = 0, False, False, None
|
|
161
|
+
while next_job < len(jobs) or active:
|
|
162
|
+
try:
|
|
163
|
+
if cancel.is_set():
|
|
164
|
+
stopped = True
|
|
165
|
+
# 先收齐本轮已完成结果再派发,避免观察到失败后继续启动下一任务。
|
|
166
|
+
for worker, index in list(active.items()):
|
|
167
|
+
try:
|
|
168
|
+
if not worker.ready():
|
|
169
|
+
continue
|
|
170
|
+
outcome = worker.receive()
|
|
171
|
+
except Exception as error:
|
|
172
|
+
outcome = BatchJobResult(**_facts(jobs[index]), status='failed',
|
|
173
|
+
worker_pid=worker.pid, error_type=type(error).__name__,
|
|
174
|
+
error_message=str(error), error_chain=_diagnostics(error))
|
|
175
|
+
infrastructure = infrastructure or error
|
|
176
|
+
stopped = True
|
|
177
|
+
results[index] = outcome
|
|
178
|
+
del active[worker]
|
|
179
|
+
if self.fail_fast and outcome.status == 'failed':
|
|
180
|
+
stopped = True
|
|
181
|
+
if outcome.error_type in ('MemoryError', 'KeyboardInterrupt', 'SystemExit'):
|
|
182
|
+
stopped = True
|
|
183
|
+
if not worker.pending:
|
|
184
|
+
free.append(worker)
|
|
185
|
+
while not stopped and next_job < len(jobs):
|
|
186
|
+
if cancel.is_set():
|
|
187
|
+
stopped = True
|
|
188
|
+
break
|
|
189
|
+
if free:
|
|
190
|
+
worker = free.pop()
|
|
191
|
+
elif len(workers) < min(self.process_count, len(jobs)):
|
|
192
|
+
worker = ProcessWorker()
|
|
193
|
+
workers.append(worker)
|
|
194
|
+
else:
|
|
195
|
+
break
|
|
196
|
+
index = next_job
|
|
197
|
+
try:
|
|
198
|
+
worker.submit(jobs[index], root / jobs[index].job_id, self.backend)
|
|
199
|
+
except Exception as error:
|
|
200
|
+
results[index] = BatchJobResult(**_facts(jobs[index]), status='failed',
|
|
201
|
+
worker_pid=worker.pid, error_type=type(error).__name__, error_message=str(error))
|
|
202
|
+
infrastructure = infrastructure or error
|
|
203
|
+
stopped = True
|
|
204
|
+
break
|
|
205
|
+
active[worker], last_job[worker] = index, index
|
|
206
|
+
next_job += 1
|
|
207
|
+
if not active:
|
|
208
|
+
# 所有工作进程若都因未完成清理而暂停,剩余任务不再派发。
|
|
209
|
+
break
|
|
210
|
+
_pause()
|
|
211
|
+
except KeyboardInterrupt:
|
|
212
|
+
interrupted, stopped = True, True
|
|
213
|
+
except Exception as error:
|
|
214
|
+
infrastructure, stopped = infrastructure or error, True
|
|
215
|
+
# 在途任务已结束;持续关闭失败留远程owner,不因结束调度而丢掉恢复入口。
|
|
216
|
+
for worker in workers:
|
|
217
|
+
if worker.pending:
|
|
218
|
+
continue
|
|
219
|
+
try:
|
|
220
|
+
worker.close()
|
|
221
|
+
except BaseException as error:
|
|
222
|
+
index = last_job.get(worker)
|
|
223
|
+
if index is not None:
|
|
224
|
+
results[index] = replace(results[index], status='failed',
|
|
225
|
+
error_type=type(error).__name__, error_message=str(error),
|
|
226
|
+
recovery=CleanupHandle(worker))
|
|
227
|
+
infrastructure = infrastructure or error
|
|
228
|
+
reason = '用户取消,尚未启动' if cancel.is_set() or interrupted else '失败或未完成清理后停止派发'
|
|
229
|
+
report = _report(root, jobs, results, self.process_count, self.fail_fast,
|
|
230
|
+
cancel.is_set() or interrupted, device_label, reason)
|
|
231
|
+
report = replace(report, worker_process_count=len(workers))
|
|
232
|
+
if infrastructure is not None:
|
|
233
|
+
report = replace(report, infrastructure_error=type(infrastructure).__name__ + ': ' + str(infrastructure))
|
|
234
|
+
infrastructure.batch_report = report
|
|
235
|
+
raise infrastructure
|
|
236
|
+
return report
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""把一个分析模板应用于明确输入集合,每个文件形成独立任务,不读取日志。
|
|
2
|
+
|
|
3
|
+
路径按模板目录解释;输入目录按批量配置目录解释。复用已有自然序和4096文件限制,
|
|
4
|
+
来源有多个候选时要求source,绝不把连续会话自动拆开。本入口由用户显式选择。
|
|
5
|
+
"""
|
|
6
|
+
from copy import deepcopy
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
from ..configuration import load_configuration
|
|
10
|
+
from ..configuration.imports import expand_document_imports
|
|
11
|
+
from ..planning.checks import PlanValidationError, text_at
|
|
12
|
+
from ..planning.input_paths import expand_source_files
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def template_jobs(raw, base):
|
|
16
|
+
"""参数为批量对象和路径基准;返回独立BatchJob列表。配置错误抛PlanValidationError,不写文件。"""
|
|
17
|
+
from .models import BatchJob
|
|
18
|
+
from ..planning.plan import AnalysisPlan
|
|
19
|
+
path=base/Path(text_at(raw['template'],'$.template'))
|
|
20
|
+
path=path.absolute()
|
|
21
|
+
template=expand_document_imports(load_configuration(path)).data
|
|
22
|
+
sources=template.get('sources',[]) if type(template) is dict else []
|
|
23
|
+
if type(sources) is not list or any(type(source) is not dict for source in sources):
|
|
24
|
+
raise PlanValidationError('$.template','模板sources必须为来源对象数组')
|
|
25
|
+
selector=raw.get('source')
|
|
26
|
+
if selector is not None:selector=text_at(selector,'$.source',identifier=True)
|
|
27
|
+
candidates=[i for i,s in enumerate(sources) if selector is None or s.get('name',f'source_{i+1}')==selector]
|
|
28
|
+
if len(candidates)!=1:
|
|
29
|
+
raise PlanValidationError('$.source','模板必须能唯一确定要替换文件的来源;多来源时填写source')
|
|
30
|
+
index=candidates[0]
|
|
31
|
+
selected=sources[index]
|
|
32
|
+
if selected.get('source_type')=='memory':
|
|
33
|
+
raise PlanValidationError('$.source','目录批量模板不能替换内存来源')
|
|
34
|
+
files,shifts=expand_source_files(dict(paths=raw['inputs'],source_type=selected.get('source_type')),base,'$.inputs')
|
|
35
|
+
jobs=[]
|
|
36
|
+
for number,file in enumerate(files,1):
|
|
37
|
+
config=deepcopy(template);source=config['sources'][index]
|
|
38
|
+
for key in ('path','paths','offsets'):source.pop(key,None)
|
|
39
|
+
source['path']=str(file)
|
|
40
|
+
if shifts is not None:source['paths']=[dict(path=source.pop('path'),offset=shifts[number-1])]
|
|
41
|
+
jobs.append(BatchJob(f'job_{number}',AnalysisPlan.from_dict(config,base_dir=path.parent)))
|
|
42
|
+
return jobs
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""在真正使用 CAN 库时给出缺依赖诊断,已安装的库仍按需导入。
|
|
2
|
+
|
|
3
|
+
输入为固定支持的模块名,输出为原模块;仅包装缺少模块的异常,其他导入错误
|
|
4
|
+
继续原样报告。不安装依赖、不读取输入、不修改 reader/decoder 的调用顺序。
|
|
5
|
+
"""
|
|
6
|
+
from importlib import import_module
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
CAN_INSTALL_HINT = (
|
|
10
|
+
'请在运行分析的同一个 Python 环境重新安装本地 wheel,默认会安装 CAN 依赖:'
|
|
11
|
+
'python -m pip install "./chronaxis-0.1.0.dev0-py3-none-any.whl"。'
|
|
12
|
+
'将文件路径替换为实际收到的安装包;离线时需备齐该 wheel 声明版本的依赖。'
|
|
13
|
+
'不要通过修改信号字段解决环境缺依赖,也不要仅安装未核实版本的 cantools。'
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class CANDependencyError(ImportError):
|
|
18
|
+
"""保留缺失模块名与机器码的 CAN 环境错误,不冒充配置值错误。"""
|
|
19
|
+
|
|
20
|
+
code = 'dependency_missing'
|
|
21
|
+
|
|
22
|
+
def __init__(self, module_name):
|
|
23
|
+
"""保存缺项及安装建议。参数: module_name 为缺失模块名。返回: None。异常: 无。"""
|
|
24
|
+
self.module_name = module_name
|
|
25
|
+
self.hint = CAN_INSTALL_HINT
|
|
26
|
+
super().__init__(f'缺少 CAN 读取/解码依赖:{module_name}。{self.hint}')
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def import_can_dependency(module_name):
|
|
30
|
+
"""按既有调用点导入实际需要的 CAN 库。
|
|
31
|
+
|
|
32
|
+
参数: module_name 为 can、cantools 或 natsort。
|
|
33
|
+
返回: 原 Python 模块。异常: CANDependencyError 表示模块或其依赖缺失;
|
|
34
|
+
其他 ImportError 原样传播,避免将损坏或不兼容安装误报成信号错误。
|
|
35
|
+
"""
|
|
36
|
+
if module_name not in ('can', 'cantools', 'natsort'):
|
|
37
|
+
raise ValueError('不是已声明的 CAN 依赖')
|
|
38
|
+
try:
|
|
39
|
+
return import_module(module_name)
|
|
40
|
+
except ModuleNotFoundError as error:
|
|
41
|
+
# 间接依赖也可能缺失;保留具体名字供定位完整安装问题。
|
|
42
|
+
raise CANDependencyError(error.name or module_name) from error
|