rushti 2.3.1__tar.gz → 2.3.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {rushti-2.3.1/src/rushti.egg-info → rushti-2.3.2}/PKG-INFO +1 -1
- {rushti-2.3.1 → rushti-2.3.2}/pyproject.toml +1 -1
- {rushti-2.3.1 → rushti-2.3.2}/src/rushti/__init__.py +1 -1
- {rushti-2.3.1 → rushti-2.3.2}/src/rushti/tm1_objects.py +87 -11
- {rushti-2.3.1 → rushti-2.3.2/src/rushti.egg-info}/PKG-INFO +1 -1
- {rushti-2.3.1 → rushti-2.3.2}/LICENSE +0 -0
- {rushti-2.3.1 → rushti-2.3.2}/README.md +0 -0
- {rushti-2.3.1 → rushti-2.3.2}/setup.cfg +0 -0
- {rushti-2.3.1 → rushti-2.3.2}/src/rushti/_shlex_utils.py +0 -0
- {rushti-2.3.1 → rushti-2.3.2}/src/rushti/app_paths.py +0 -0
- {rushti-2.3.1 → rushti-2.3.2}/src/rushti/checkpoint.py +0 -0
- {rushti-2.3.1 → rushti-2.3.2}/src/rushti/cli.py +0 -0
- {rushti-2.3.1 → rushti-2.3.2}/src/rushti/commands/__init__.py +0 -0
- {rushti-2.3.1 → rushti-2.3.2}/src/rushti/commands/build.py +0 -0
- {rushti-2.3.1 → rushti-2.3.2}/src/rushti/commands/db.py +0 -0
- {rushti-2.3.1 → rushti-2.3.2}/src/rushti/commands/resume.py +0 -0
- {rushti-2.3.1 → rushti-2.3.2}/src/rushti/commands/stats/__init__.py +0 -0
- {rushti-2.3.1 → rushti-2.3.2}/src/rushti/commands/stats/analyze.py +0 -0
- {rushti-2.3.1 → rushti-2.3.2}/src/rushti/commands/stats/export.py +0 -0
- {rushti-2.3.1 → rushti-2.3.2}/src/rushti/commands/stats/list.py +0 -0
- {rushti-2.3.1 → rushti-2.3.2}/src/rushti/commands/stats/optimize.py +0 -0
- {rushti-2.3.1 → rushti-2.3.2}/src/rushti/commands/stats/visualize.py +0 -0
- {rushti-2.3.1 → rushti-2.3.2}/src/rushti/commands/tasks/__init__.py +0 -0
- {rushti-2.3.1 → rushti-2.3.2}/src/rushti/commands/tasks/expand.py +0 -0
- {rushti-2.3.1 → rushti-2.3.2}/src/rushti/commands/tasks/export.py +0 -0
- {rushti-2.3.1 → rushti-2.3.2}/src/rushti/commands/tasks/push.py +0 -0
- {rushti-2.3.1 → rushti-2.3.2}/src/rushti/commands/tasks/validate.py +0 -0
- {rushti-2.3.1 → rushti-2.3.2}/src/rushti/commands/tasks/visualize.py +0 -0
- {rushti-2.3.1 → rushti-2.3.2}/src/rushti/contention_analyzer.py +0 -0
- {rushti-2.3.1 → rushti-2.3.2}/src/rushti/dag.py +0 -0
- {rushti-2.3.1 → rushti-2.3.2}/src/rushti/dashboard.py +0 -0
- {rushti-2.3.1 → rushti-2.3.2}/src/rushti/db_admin.py +0 -0
- {rushti-2.3.1 → rushti-2.3.2}/src/rushti/exclusive.py +0 -0
- {rushti-2.3.1 → rushti-2.3.2}/src/rushti/execution.py +0 -0
- {rushti-2.3.1 → rushti-2.3.2}/src/rushti/logging.py +0 -0
- {rushti-2.3.1 → rushti-2.3.2}/src/rushti/logging_setup.py +0 -0
- {rushti-2.3.1 → rushti-2.3.2}/src/rushti/messages.py +0 -0
- {rushti-2.3.1 → rushti-2.3.2}/src/rushti/optimization_report.py +0 -0
- {rushti-2.3.1 → rushti-2.3.2}/src/rushti/optimizer.py +0 -0
- {rushti-2.3.1 → rushti-2.3.2}/src/rushti/parsing.py +0 -0
- {rushti-2.3.1 → rushti-2.3.2}/src/rushti/results_writer.py +0 -0
- {rushti-2.3.1 → rushti-2.3.2}/src/rushti/settings.py +0 -0
- {rushti-2.3.1 → rushti-2.3.2}/src/rushti/stats/__init__.py +0 -0
- {rushti-2.3.1 → rushti-2.3.2}/src/rushti/stats/dynamodb.py +0 -0
- {rushti-2.3.1 → rushti-2.3.2}/src/rushti/stats/paths.py +0 -0
- {rushti-2.3.1 → rushti-2.3.2}/src/rushti/stats/repository.py +0 -0
- {rushti-2.3.1 → rushti-2.3.2}/src/rushti/stats/signature.py +0 -0
- {rushti-2.3.1 → rushti-2.3.2}/src/rushti/stats/sqlite.py +0 -0
- {rushti-2.3.1 → rushti-2.3.2}/src/rushti/task.py +0 -0
- {rushti-2.3.1 → rushti-2.3.2}/src/rushti/taskfile.py +0 -0
- {rushti-2.3.1 → rushti-2.3.2}/src/rushti/taskfile_ops.py +0 -0
- {rushti-2.3.1 → rushti-2.3.2}/src/rushti/templates/__init__.py +0 -0
- {rushti-2.3.1 → rushti-2.3.2}/src/rushti/templates/visualization.html +0 -0
- {rushti-2.3.1 → rushti-2.3.2}/src/rushti/tm1_build.py +0 -0
- {rushti-2.3.1 → rushti-2.3.2}/src/rushti/tm1_integration.py +0 -0
- {rushti-2.3.1 → rushti-2.3.2}/src/rushti/utils.py +0 -0
- {rushti-2.3.1 → rushti-2.3.2}/src/rushti/visualization_template.py +0 -0
- {rushti-2.3.1 → rushti-2.3.2}/src/rushti.egg-info/SOURCES.txt +0 -0
- {rushti-2.3.1 → rushti-2.3.2}/src/rushti.egg-info/dependency_links.txt +0 -0
- {rushti-2.3.1 → rushti-2.3.2}/src/rushti.egg-info/entry_points.txt +0 -0
- {rushti-2.3.1 → rushti-2.3.2}/src/rushti.egg-info/requires.txt +0 -0
- {rushti-2.3.1 → rushti-2.3.2}/src/rushti.egg-info/top_level.txt +0 -0
|
@@ -5,7 +5,7 @@ This package provides tools for executing TM1 TI processes in parallel
|
|
|
5
5
|
with dependency management, checkpoint/resume support, and execution logging.
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
|
-
__version__ = "2.3.
|
|
8
|
+
__version__ = "2.3.2"
|
|
9
9
|
__app_name__ = "RushTI"
|
|
10
10
|
|
|
11
11
|
# Core exports for programmatic use
|
|
@@ -150,6 +150,8 @@ nProcessReturnCode = 0;
|
|
|
150
150
|
nErrors = 0;
|
|
151
151
|
nMetadataRecordCount= 0;
|
|
152
152
|
nDataRecordCount = 0;
|
|
153
|
+
nHeaderChecked = 0;
|
|
154
|
+
nDataHeaderChecked = 0;
|
|
153
155
|
|
|
154
156
|
### Process Specific Constants
|
|
155
157
|
cFileSrc = pSourceFile;
|
|
@@ -220,7 +222,9 @@ CubeSetLogChanges( cCubeTgt, 0 );
|
|
|
220
222
|
If( nErrors = 0 );
|
|
221
223
|
DatasourceType = 'CHARACTERDELIMITED';
|
|
222
224
|
DatasourceNameForServer = cFileSrc;
|
|
223
|
-
|
|
225
|
+
# 0 (not 1): the header row is consumed as the first record so the
|
|
226
|
+
# metadata tab can validate it against the expected columns (issue #169).
|
|
227
|
+
DatasourceASCIIHeaderRecords = 0;
|
|
224
228
|
DatasourceASCIIDelimiter=',';
|
|
225
229
|
DatasourceASCIIDecimalSeparator='.';
|
|
226
230
|
DatasourceASCIIThousandSeparator='';
|
|
@@ -290,6 +294,8 @@ nProcessReturnCode = 0;
|
|
|
290
294
|
nErrors = 0;
|
|
291
295
|
nMetadataRecordCount= 0;
|
|
292
296
|
nDataRecordCount = 0;
|
|
297
|
+
nHeaderChecked = 0;
|
|
298
|
+
nDataHeaderChecked = 0;
|
|
293
299
|
|
|
294
300
|
### Process Specific Constants
|
|
295
301
|
cFileSrc = pSourceFile;
|
|
@@ -356,7 +362,9 @@ EndIf;
|
|
|
356
362
|
If( nErrors = 0 );
|
|
357
363
|
DatasourceType = 'CHARACTERDELIMITED';
|
|
358
364
|
DatasourceNameForServer = cFileSrc;
|
|
359
|
-
|
|
365
|
+
# 0 (not 1): the header row is consumed as the first record so the
|
|
366
|
+
# metadata tab can validate it against the expected columns (issue #169).
|
|
367
|
+
DatasourceASCIIHeaderRecords = 0;
|
|
360
368
|
DatasourceASCIIDelimiter=',';
|
|
361
369
|
DatasourceASCIIDecimalSeparator='.';
|
|
362
370
|
DatasourceASCIIThousandSeparator='';
|
|
@@ -366,10 +374,17 @@ EndIf;
|
|
|
366
374
|
#################################################################################################
|
|
367
375
|
"""
|
|
368
376
|
|
|
369
|
-
|
|
377
|
+
# Marker pair TM1 Architect uses to inject auto-generated variable/parameter
|
|
378
|
+
# code at the top of a tab. Kept as the first lines of every generated
|
|
379
|
+
# procedure so the process round-trips cleanly if later opened in Architect.
|
|
380
|
+
_GENERATED_STATEMENTS_MARKER = """#****Begin: Generated Statements***
|
|
370
381
|
#****End: Generated Statements****
|
|
382
|
+
"""
|
|
371
383
|
|
|
372
|
-
|
|
384
|
+
# Body of the metadata tab. The header-validation preamble is generated from
|
|
385
|
+
# PROCESS_VARIABLES and prepended in ``build_metadata_procedure`` so it stays
|
|
386
|
+
# in lockstep with the CSV column contract (see issue #169).
|
|
387
|
+
_PROCESS_METADATA_BODY = r"""If( pLogOutput >= 1 );
|
|
373
388
|
nMetadataRecordCount = nMetadataRecordCount + 1;
|
|
374
389
|
EndIf;
|
|
375
390
|
|
|
@@ -388,10 +403,9 @@ if (DimensionElementExists(pRunId_Dim, vrun_id) = 0);
|
|
|
388
403
|
DimensionElementInsertDirect(pRunId_Dim, '', vrun_id, 'N');
|
|
389
404
|
endif;"""
|
|
390
405
|
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
If( pLogOutput >= 1 );
|
|
406
|
+
# Body of the data tab. The header-skip preamble is prepended in
|
|
407
|
+
# ``build_data_procedure`` so the CSV header row is not written to the cube.
|
|
408
|
+
_PROCESS_DATA_BODY = r"""If( pLogOutput >= 1 );
|
|
395
409
|
nDataRecordCount = nDataRecordCount + 1;
|
|
396
410
|
EndIf;
|
|
397
411
|
|
|
@@ -544,8 +558,9 @@ PROCESS_PARAMETERS = [
|
|
|
544
558
|
# declaration list. Must match the column order produced by
|
|
545
559
|
# ``rushti.tm1_integration.upload_results_to_tm1`` (which inserts
|
|
546
560
|
# ``workflow`` and ``run_id`` ahead of the columns built by
|
|
547
|
-
# ``build_results_dataframe``). Mismatched ordering
|
|
548
|
-
# the
|
|
561
|
+
# ``build_results_dataframe``). Mismatched ordering scrambles the loaded
|
|
562
|
+
# payload; the metadata-tab header check generated from this list turns a
|
|
563
|
+
# stale-process mismatch into a hard error instead (see issue #169).
|
|
549
564
|
PROCESS_VARIABLES = [
|
|
550
565
|
"vworkflow",
|
|
551
566
|
"vrun_id",
|
|
@@ -571,12 +586,73 @@ PROCESS_VARIABLES = [
|
|
|
571
586
|
"vsucceed_on_minor_errors",
|
|
572
587
|
]
|
|
573
588
|
|
|
589
|
+
|
|
590
|
+
def build_metadata_procedure() -> str:
|
|
591
|
+
"""Assemble the ``}rushti.load.results`` metadata tab.
|
|
592
|
+
|
|
593
|
+
Prepends a header-validation preamble generated from ``PROCESS_VARIABLES``
|
|
594
|
+
so it stays in lockstep with the CSV column contract. The loader maps CSV
|
|
595
|
+
columns to variables positionally; with ``asciiHeaderRecords=0`` the CSV
|
|
596
|
+
header row is the first source record, so validating each column name
|
|
597
|
+
against the variable it feeds makes a process left stale by an in-place
|
|
598
|
+
rushti upgrade fail loudly instead of silently writing values to the wrong
|
|
599
|
+
measures (issue #169). Re-run ``rushti build`` to refresh a stale process.
|
|
600
|
+
"""
|
|
601
|
+
checks = "\n".join(
|
|
602
|
+
f" If( {var} @<> '{var[1:]}' );\n"
|
|
603
|
+
f" sHeaderError = sHeaderError | ' {var[1:]}';\n"
|
|
604
|
+
f" EndIf;"
|
|
605
|
+
for var in PROCESS_VARIABLES
|
|
606
|
+
)
|
|
607
|
+
preamble = f"""### Validate the CSV header against the columns this process expects.
|
|
608
|
+
### The loader maps columns to variables positionally, so a process built by
|
|
609
|
+
### an older rushti scrambles measures (issue #169). Fail loudly on mismatch
|
|
610
|
+
### and skip the header so it is not loaded as data.
|
|
611
|
+
If( nHeaderChecked = 0 );
|
|
612
|
+
nHeaderChecked = 1;
|
|
613
|
+
sHeaderError = '';
|
|
614
|
+
{checks}
|
|
615
|
+
If( Trim( sHeaderError ) @<> '' );
|
|
616
|
+
nErrors = nErrors + 1;
|
|
617
|
+
sMessage = Expand( 'Results CSV header does not match the columns }}rushti.load.results expects (mismatched:%sHeaderError% ). This process is out of date with the rushti version that produced the file - re-run: rushti build --tm1-instance <instance>.' );
|
|
618
|
+
LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );
|
|
619
|
+
ProcessQuit;
|
|
620
|
+
EndIf;
|
|
621
|
+
ItemSkip;
|
|
622
|
+
EndIf;
|
|
623
|
+
|
|
624
|
+
"""
|
|
625
|
+
return _GENERATED_STATEMENTS_MARKER + "\n" + preamble + _PROCESS_METADATA_BODY
|
|
626
|
+
|
|
627
|
+
|
|
628
|
+
def build_data_procedure() -> str:
|
|
629
|
+
"""Assemble the ``}rushti.load.results`` data tab.
|
|
630
|
+
|
|
631
|
+
Skips the CSV header row (validated in the metadata tab) so it is not
|
|
632
|
+
written to the cube, then delegates to the static body. See issue #169.
|
|
633
|
+
"""
|
|
634
|
+
preamble = """### Skip the CSV header row (asciiHeaderRecords=0; validated in the
|
|
635
|
+
### metadata tab). See issue #169.
|
|
636
|
+
If( nDataHeaderChecked = 0 );
|
|
637
|
+
nDataHeaderChecked = 1;
|
|
638
|
+
ItemSkip;
|
|
639
|
+
EndIf;
|
|
640
|
+
|
|
641
|
+
"""
|
|
642
|
+
return _GENERATED_STATEMENTS_MARKER + "\n" + preamble + _PROCESS_DATA_BODY
|
|
643
|
+
|
|
644
|
+
|
|
645
|
+
PROCESS_METADATA = build_metadata_procedure()
|
|
646
|
+
PROCESS_DATA = build_data_procedure()
|
|
647
|
+
|
|
574
648
|
PROCESS_DATASOURCE = {
|
|
575
649
|
"Type": "ASCII",
|
|
576
650
|
"asciiDecimalSeparator": ".",
|
|
577
651
|
"asciiDelimiterChar": ",",
|
|
578
652
|
"asciiDelimiterType": "Character",
|
|
579
|
-
|
|
653
|
+
# 0: the header row is validated (not skipped) by the metadata tab; see
|
|
654
|
+
# the DatasourceASCIIHeaderRecords note in the prolog and issue #169.
|
|
655
|
+
"asciiHeaderRecords": 0,
|
|
580
656
|
"asciiQuoteCharacter": '"',
|
|
581
657
|
"asciiThousandSeparator": ",",
|
|
582
658
|
"dataSourceNameForClient": "",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|