gen3-dataops-toolkit 3.2.0__tar.gz → 3.3.0__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.
- {gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/PKG-INFO +2 -2
- {gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/pyproject.toml +2 -2
- {gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/validate/validate.py +86 -21
- {gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/README.md +0 -0
- {gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/__init__.py +0 -0
- {gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/cli/__init__.py +0 -0
- {gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/cli/_internal/__init__.py +0 -0
- {gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/cli/_internal/dispatch.py +0 -0
- {gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/cli/_internal/registry.py +0 -0
- {gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/cli/_internal/resolve.py +0 -0
- {gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/cli/_internal/runner.py +0 -0
- {gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/cli/_internal/safety.py +0 -0
- {gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/cli/config_cmds.py +0 -0
- {gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/cli/delete_cmds.py +0 -0
- {gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/cli/dict_cmds.py +0 -0
- {gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/cli/ec2_cmds.py +0 -0
- {gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/cli/indexd_cmds.py +0 -0
- {gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/cli/jobs.py +0 -0
- {gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/cli/k8s.py +0 -0
- {gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/cli/main.py +0 -0
- {gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/cli/metadata.py +0 -0
- {gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/cli/pipeline_cmds.py +0 -0
- {gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/cli/release_cmds.py +0 -0
- {gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/cli/synth.py +0 -0
- {gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/config.py +0 -0
- {gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/indexd/__init__.py +0 -0
- {gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/indexd/file_access.py +0 -0
- {gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/indexd/indexd_registrar.py +0 -0
- {gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/ingest/ingest.py +0 -0
- {gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/resolver.py +0 -0
- {gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/services/delete/delete_all_metadata_for_project.py +0 -0
- {gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/services/delete/delete_metadata.sh +0 -0
- {gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/services/delete/delete_metadata_by_guid.py +0 -0
- {gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/services/dictionary/deploy_dd.sh +0 -0
- {gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/services/dictionary/pull_dict.sh +0 -0
- {gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/services/dictionary/upload_dictionary.py +0 -0
- {gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/services/indexd/register_indexd.py +0 -0
- {gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/services/indexd/verify_file_access.py +0 -0
- {gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/services/k8s_ops/argocd_restart_etl.sh +0 -0
- {gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/services/k8s_ops/argocd_restart_ms.sh +0 -0
- {gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/services/k8s_ops/argocd_restart_schema.sh +0 -0
- {gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/services/k8s_ops/login_to_pod.sh +0 -0
- {gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/services/k8s_ops/restart_etl_and_ms.sh +0 -0
- {gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/services/synthetic_data/delete_synth_metadata_sheepdog.py +0 -0
- {gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/services/synthetic_data/full_deploy_dd_and_synth.sh +0 -0
- {gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/services/synthetic_data/generate_synth_metadata.sh +0 -0
- {gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/services/synthetic_data/upload_synth_metadata_sheepdog.py +0 -0
- {gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/services/upload/metadata/upload_all_studies.sh +0 -0
- {gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/services/upload/metadata/upload_metadata.py +0 -0
- {gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/upload/__init__.py +0 -0
- {gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/upload/metadata_deleter.py +0 -0
- {gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/upload/metadata_submitter.py +0 -0
- {gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/upload/upload_synthdata_s3.py +0 -0
- {gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/utils/athena_utils.py +0 -0
- {gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/utils/dbt_utils.py +0 -0
- {gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/utils/release_writer.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: gen3-dataops-toolkit
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.3.0
|
|
4
4
|
Summary: Gen3 DataOps toolkit (g3dt): operate SSM-published Gen3 data pipeline environments
|
|
5
5
|
License: Apache-2.0
|
|
6
6
|
Author: JoshuaHarris391
|
|
@@ -17,7 +17,7 @@ Requires-Dist: awswrangler (>=3.14.0,<4.0.0)
|
|
|
17
17
|
Requires-Dist: boto3
|
|
18
18
|
Requires-Dist: gen3 (>=4.27.4,<5.0.0)
|
|
19
19
|
Requires-Dist: gen3-metadata (>=1.4.0,<2.0.0)
|
|
20
|
-
Requires-Dist: gen3_validator (>=2.
|
|
20
|
+
Requires-Dist: gen3_validator (>=2.3.0,<3.0.0)
|
|
21
21
|
Requires-Dist: numpy (<2.0.0)
|
|
22
22
|
Requires-Dist: openpyxl (>=3.1.0)
|
|
23
23
|
Requires-Dist: pyarrow (>=14.0.0,<19.0.0)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "gen3-dataops-toolkit"
|
|
3
|
-
version = "3.
|
|
3
|
+
version = "3.3.0"
|
|
4
4
|
description = "Gen3 DataOps toolkit (g3dt): operate SSM-published Gen3 data pipeline environments"
|
|
5
5
|
authors = ["JoshuaHarris391 <harjo391@gmail.com>"]
|
|
6
6
|
readme = "README.md"
|
|
@@ -19,7 +19,7 @@ numpy = "<2.0.0"
|
|
|
19
19
|
pyyaml = ">=6.0.2,<7.0.0"
|
|
20
20
|
tzlocal = ">=5.3.1,<6.0.0"
|
|
21
21
|
gen3 = ">=4.27.4, <5.0.0"
|
|
22
|
-
gen3_validator = ">=2.
|
|
22
|
+
gen3_validator = ">=2.3.0,<3.0.0"
|
|
23
23
|
pytz = ">=2025.2,<2026.0"
|
|
24
24
|
s3fs = "2025.10.0"
|
|
25
25
|
pyjwt = ">=2.10.1,<3.0.0"
|
|
@@ -479,6 +479,49 @@ def truncate_linkage_results(linkage_results_dict: dict) -> dict:
|
|
|
479
479
|
return linkage_results_dict
|
|
480
480
|
|
|
481
481
|
|
|
482
|
+
#: The eight fields every result row carries, as emitted by
|
|
483
|
+
#: ``gen3_validator.validate.validate_object`` (FAIL rows) and
|
|
484
|
+
#: ``gen3_validator.validate.error_record`` (ERROR rows).
|
|
485
|
+
VALIDATION_RESULT_BASE_COLUMNS = [
|
|
486
|
+
"node",
|
|
487
|
+
"index",
|
|
488
|
+
"validation_result",
|
|
489
|
+
"invalid_key",
|
|
490
|
+
"schema_path",
|
|
491
|
+
"validator",
|
|
492
|
+
"validator_value",
|
|
493
|
+
"validation_error",
|
|
494
|
+
]
|
|
495
|
+
|
|
496
|
+
#: Full column contract of the results table, in write order.
|
|
497
|
+
VALIDATION_RESULT_COLUMNS = [
|
|
498
|
+
"validation_id",
|
|
499
|
+
"index",
|
|
500
|
+
"node",
|
|
501
|
+
"study_id",
|
|
502
|
+
"validation_result",
|
|
503
|
+
"invalid_key",
|
|
504
|
+
"schema_path",
|
|
505
|
+
"validator",
|
|
506
|
+
"validator_value",
|
|
507
|
+
"validation_error",
|
|
508
|
+
"schema_version",
|
|
509
|
+
]
|
|
510
|
+
|
|
511
|
+
#: Written when a study validates clean, so that every run leaves exactly one
|
|
512
|
+
#: gradeable row. Excluded by the validation gate — see
|
|
513
|
+
#: :func:`run_validation_gate`.
|
|
514
|
+
PASS_MARKER_ROW = {
|
|
515
|
+
"node": None,
|
|
516
|
+
"index": None,
|
|
517
|
+
"validation_result": "PASS",
|
|
518
|
+
"invalid_key": None,
|
|
519
|
+
"schema_path": None,
|
|
520
|
+
"validator": None,
|
|
521
|
+
"validator_value": None,
|
|
522
|
+
"validation_error": None,
|
|
523
|
+
}
|
|
524
|
+
|
|
482
525
|
#: validation_error patterns treated as known noise by the validation gate —
|
|
483
526
|
#: structural artefacts of the export (null-typed fields, extra export-side
|
|
484
527
|
#: properties, the Gen3 'programs' root requirement), not data quality issues.
|
|
@@ -497,9 +540,14 @@ def run_validation_gate(glue_database: str, athena_s3_output: str,
|
|
|
497
540
|
|
|
498
541
|
The gate looks at the most recent ``validation_id`` in the results table,
|
|
499
542
|
filters out the known-noise error patterns
|
|
500
|
-
(:data:`VALIDATION_GATE_IGNORED_ERRORS`) and synthetic
|
|
501
|
-
aggregates what remains. An empty result means the latest
|
|
502
|
-
is clean; any rows are genuine schema failures an operator
|
|
543
|
+
(:data:`VALIDATION_GATE_IGNORED_ERRORS`), PASS markers and synthetic
|
|
544
|
+
studies, and aggregates what remains. An empty result means the latest
|
|
545
|
+
validation run is clean; any rows are genuine schema failures an operator
|
|
546
|
+
must fix.
|
|
547
|
+
|
|
548
|
+
ERROR rows are deliberately NOT filtered out. A record whose node is absent
|
|
549
|
+
from the dictionary could not be checked at all, which is a failure to
|
|
550
|
+
validate rather than a clean result, and must hold the gate closed.
|
|
503
551
|
|
|
504
552
|
Callers (the validator Glue job) FAIL the run when rows come back, so the
|
|
505
553
|
validation Step Function goes red until the data is fixed and validation
|
|
@@ -523,6 +571,7 @@ WHERE validation_id = (
|
|
|
523
571
|
FROM "{glue_database}"."{results_table}"
|
|
524
572
|
)
|
|
525
573
|
{ignore_clauses}
|
|
574
|
+
AND validation_result <> 'PASS'
|
|
526
575
|
AND study_id NOT LIKE '%synthetic%'
|
|
527
576
|
GROUP BY node, study_id, invalid_key, validator_value, validation_error
|
|
528
577
|
ORDER BY node, study_id
|
|
@@ -567,6 +616,7 @@ def validate_pipeline(
|
|
|
567
616
|
resolver=None,
|
|
568
617
|
metadata_table: pd.DataFrame = None,
|
|
569
618
|
write_iceberg: bool = True,
|
|
619
|
+
results_table: str = "full_validation_results",
|
|
570
620
|
) -> pd.DataFrame:
|
|
571
621
|
"""
|
|
572
622
|
Orchestrate the validation workflow for a study: load + resolve schema, find the latest
|
|
@@ -592,9 +642,14 @@ def validate_pipeline(
|
|
|
592
642
|
write_iceberg: When False, skip the per-study Iceberg write and leave it
|
|
593
643
|
to the caller (who can concatenate several studies' results into a
|
|
594
644
|
single write). The CSV write-back always happens.
|
|
645
|
+
results_table: Table to write into when ``write_iceberg`` is True. Callers
|
|
646
|
+
validating an isolated warehouse (e.g. the CI databases) MUST pass
|
|
647
|
+
their own — the real and CI results must never share a table, since
|
|
648
|
+
the gate grades whichever run has the greatest validation_id.
|
|
595
649
|
|
|
596
650
|
Returns:
|
|
597
|
-
The study's validation results DataFrame.
|
|
651
|
+
The study's validation results DataFrame. Never empty: a study with no
|
|
652
|
+
failures yields a single PASS marker row.
|
|
598
653
|
|
|
599
654
|
Raises:
|
|
600
655
|
RuntimeError: When expected inputs are missing or a pipeline step fails.
|
|
@@ -663,24 +718,34 @@ def validate_pipeline(
|
|
|
663
718
|
logger.info("Getting Schema Version")
|
|
664
719
|
schema_version = resolver.get_schema_version(schema = schema)
|
|
665
720
|
|
|
666
|
-
|
|
721
|
+
if not results:
|
|
722
|
+
# No failures. Record the run anyway: the validation gate grades
|
|
723
|
+
# the greatest validation_id in the results table, so a clean run
|
|
724
|
+
# that writes nothing would leave the previous FAILING run as the
|
|
725
|
+
# latest and the gate could never go green no matter how many
|
|
726
|
+
# times the data was fixed. A PASS marker also guarantees the
|
|
727
|
+
# table exists after the first run, which is what stops a fresh
|
|
728
|
+
# environment reporting TABLE_NOT_FOUND.
|
|
729
|
+
logger.info("No validation failures for study '%s'; writing PASS marker.", study_id)
|
|
730
|
+
results = [PASS_MARKER_ROW.copy()]
|
|
731
|
+
|
|
732
|
+
# Build with an explicit column list rather than inferring it from the
|
|
733
|
+
# rows: pd.DataFrame([]) has NO columns, so the reindex below used to
|
|
734
|
+
# raise KeyError and surface as "Validation failed." — a clean study
|
|
735
|
+
# failing with the same message as a dirty one.
|
|
736
|
+
full_validation_results_df = pd.DataFrame(results, columns=VALIDATION_RESULT_BASE_COLUMNS)
|
|
667
737
|
full_validation_results_df["validation_id"] = latest_validation_id
|
|
668
738
|
full_validation_results_df["study_id"] = study_id
|
|
669
739
|
full_validation_results_df["schema_version"] = schema_version
|
|
670
|
-
|
|
671
|
-
full_validation_results_df = full_validation_results_df[
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
"validator",
|
|
680
|
-
"validator_value",
|
|
681
|
-
"validation_error",
|
|
682
|
-
"schema_version"
|
|
683
|
-
]]
|
|
740
|
+
|
|
741
|
+
full_validation_results_df = full_validation_results_df[VALIDATION_RESULT_COLUMNS]
|
|
742
|
+
|
|
743
|
+
# 'index' is the only numeric column. A PASS-only frame leaves it
|
|
744
|
+
# entirely null, which would infer a different Iceberg column type
|
|
745
|
+
# than a frame containing failures — and full_validation_results
|
|
746
|
+
# already exists in deployed environments. Pin it so both shapes
|
|
747
|
+
# write the same schema.
|
|
748
|
+
full_validation_results_df = full_validation_results_df.astype({"index": "Int64"})
|
|
684
749
|
|
|
685
750
|
logger.info("Validation completed (%s rows).", len(full_validation_results_df))
|
|
686
751
|
except Exception as e:
|
|
@@ -703,12 +768,12 @@ def validate_pipeline(
|
|
|
703
768
|
logger.info(
|
|
704
769
|
"Writing Parquet to Glue DB '%s', table '%s'.",
|
|
705
770
|
glue_database,
|
|
706
|
-
|
|
771
|
+
results_table,
|
|
707
772
|
)
|
|
708
773
|
write_iceberg_to_db(
|
|
709
774
|
df=full_validation_results_df,
|
|
710
775
|
database=glue_database,
|
|
711
|
-
table=
|
|
776
|
+
table=results_table,
|
|
712
777
|
athena_s3_output=athena_s3_output,
|
|
713
778
|
workgroup=workgroup,
|
|
714
779
|
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/cli/_internal/__init__.py
RENAMED
|
File without changes
|
{gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/cli/_internal/dispatch.py
RENAMED
|
File without changes
|
{gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/cli/_internal/registry.py
RENAMED
|
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
|
{gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/indexd/indexd_registrar.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/services/dictionary/deploy_dd.sh
RENAMED
|
File without changes
|
{gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/services/dictionary/pull_dict.sh
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/services/k8s_ops/login_to_pod.sh
RENAMED
|
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
|
{gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/upload/metadata_deleter.py
RENAMED
|
File without changes
|
{gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/upload/metadata_submitter.py
RENAMED
|
File without changes
|
{gen3_dataops_toolkit-3.2.0 → gen3_dataops_toolkit-3.3.0}/src/g3dt/upload/upload_synthdata_s3.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|