descriptron-core 2.1.2__tar.gz → 2.1.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/PKG-INFO +1 -1
- descriptron_core-2.1.3/pyproject.toml +82 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_llm_backend.py +5 -0
- descriptron_core-2.1.3/src/descriptron_core/tools/biorag_provenance_v1.py +230 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/run_full_pipeline_v2.py +116 -1
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/.gitignore +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/LICENSE +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/NOTICE +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/NOTICE.bak_pre_212_20260929_1100 +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/README.md +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/pyproject.toml.bak_pre_203_20260924_145320 +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/pyproject.toml.bak_pre_204_20260924_165335 +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/pyproject.toml.bak_pre_210_20260925_103754 +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/pyproject.toml.bak_pre_211_20260925_114912 +0 -0
- /descriptron_core-2.1.2/pyproject.toml → /descriptron_core-2.1.3/pyproject.toml.bak_pre_213_20260929_1414 +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/pyproject.toml.bak_pre_keys_20260924_165335 +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/__init__.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/cli.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/cli.py.bak_pre_keys_20260924_165335 +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/data/biorag_prompts/biorag_system_prompts_v1.txt +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/data/biorag_prompts/biorag_system_prompts_v2.txt +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/data/biorag_prompts/diaphorina_user_prompts.txt +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/data/biorag_prompts/ontologies/aism.obo +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/data/biorag_prompts/ontologies/pato.obo +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/data/biorag_prompts/schemas/sdd_1.1/SDD.xsd +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/data/biorag_prompts/schemas/sdd_1.1/SDD_EnumLib.xsd +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/data/biorag_prompts/schemas/sdd_1.1/SDD_TypeLib.xsd +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/data/biorag_prompts/schemas/sdd_1.1/UBIF_BasePattern.xsd +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/data/biorag_prompts/schemas/sdd_1.1/UBIF_CoreExtensions.xsd +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/data/biorag_prompts/schemas/sdd_1.1/UBIF_CoreOntology.xsd +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/data/biorag_prompts/schemas/sdd_1.1/UBIF_EnumLib.xsd +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/data/biorag_prompts/schemas/sdd_1.1/UBIF_LinneanCore.xsd +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/data/biorag_prompts/schemas/sdd_1.1/UBIF_TypeLib.xsd +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/data/biorag_prompts/schemas/sdd_1.1/w3c-schemata/xml.xsd +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/data/biorag_prompts/schemas/taxpub/sample_treatment_deposit_example.xml +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/data/biorag_prompts/schemas/taxpub/sample_zookeys_26056_tp.xml +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/data/biorag_prompts/schemas/taxpub/tax-treatment-NS0-v1_flat.dtd +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/data/biorag_prompts/taxon_profiles/TEMPLATE_taxon_profile.yaml +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/data/biorag_prompts/taxon_profiles/diaphorina_taxon_profile.yaml +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/FHS_and_CLAHE_V21.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_add_discrete_characters_v1.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_annotation_reorient_v1.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_annotation_screen_v1.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_autapomorphy_v1.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_calibrate_v1.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_calibration_figures_v1.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_character_gate_v1.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_character_reliability_v1.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_character_robustness_v1.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_collaborator_forms_v1.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_computed_sets_v1.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_confabulation_checker_v2.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_congruence_compare_v1.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_description_refiner_v1.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_descriptive_scoring_v1.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_feature_policy.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_frame_orientation_calibrate_v1.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_frame_orientation_v1.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_gate_compare_v1.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_graph_identify_v1.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_graph_support_figure_v1.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_homology_frame_v1.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_instrument_compare_v3.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_key_builder_v1.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_key_feature_filter_v2.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_key_fuzzy_figures_v1.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_key_fuzzy_v1.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_key_holdout_v1.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_key_jackknife_support_v1.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_label_conflict_check_v1.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_make_taxon_profile_v1.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_methods_summary_figure_v1.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_novelty_score_v1.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_ontology_annotator_v2.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_outgroup_batch_check_v1.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_outline_shape_v1.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_prompts/biorag_system_prompts_v1.txt +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_prompts/biorag_system_prompts_v2.txt +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_prompts/diaphorina_user_prompts.txt +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_prompts/ontologies/aism.obo +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_prompts/ontologies/pato.obo +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_prompts/schemas/sdd_1.1/SDD.xsd +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_prompts/schemas/sdd_1.1/SDD_EnumLib.xsd +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_prompts/schemas/sdd_1.1/SDD_TypeLib.xsd +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_prompts/schemas/sdd_1.1/UBIF_BasePattern.xsd +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_prompts/schemas/sdd_1.1/UBIF_CoreExtensions.xsd +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_prompts/schemas/sdd_1.1/UBIF_CoreOntology.xsd +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_prompts/schemas/sdd_1.1/UBIF_EnumLib.xsd +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_prompts/schemas/sdd_1.1/UBIF_LinneanCore.xsd +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_prompts/schemas/sdd_1.1/UBIF_TypeLib.xsd +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_prompts/schemas/sdd_1.1/w3c-schemata/xml.xsd +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_prompts/schemas/taxpub/sample_treatment_deposit_example.xml +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_prompts/schemas/taxpub/sample_zookeys_26056_tp.xml +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_prompts/schemas/taxpub/tax-treatment-NS0-v1_flat.dtd +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_prompts/taxon_profiles/TEMPLATE_taxon_profile.yaml +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_prompts/taxon_profiles/diaphorina_taxon_profile.yaml +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_rebuild_downstream_v1.sh +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_reliability_figures_v1.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_rename_species_v1.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_rerun_descriptive_tables_v1.sh +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_retest_compare_v1.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_specimen_id.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_subjective_checks_v1.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_type_material_v1.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_vlm_characters_v1.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_vlm_heatmap_figures_v1.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_vlm_reliability_figure_v1.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_vlm_roi_figures_v1.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biosyslit_rag_retrieval.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biosyslit_rag_retrieval_v2.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/build_monograph_exports_v1.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/build_species_treatment_docx_v2.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/coco_combiner_V13.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/coco_converter_v24.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/color_extraction_with_names-v8.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/color_phenomics_homology_v2_1.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/compile_specimen_data.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/descriptron_centerline.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/descriptron_coco_tools.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/descriptron_convert.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/descriptron_credentials.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/descriptron_joints.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/descriptron_metadata.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/descriptron_rosetta.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/descriptron_shape_stats.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/landmark_gpa_V1.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/landmark_gpa_V2.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/make_reproducibility_bundle.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/semi_landmark_and_kpts_procrustesV34_GPA.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/semi_landmark_and_kpts_procrustesV42_GPA.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/texture_phenomics_from_coco.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/texture_phenomics_homology.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/validate_centerline_lengths.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/validate_pipeline_gm_vs_geomorph.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/validate_semilandmarks_vs_geomorph.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/validate_shape_stats_vs_geomorph.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/validate_shape_stats_vs_rrpp.py +0 -0
- {descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/validate_texture_glcm.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: descriptron-core
|
|
3
|
-
Version: 2.1.
|
|
3
|
+
Version: 2.1.3
|
|
4
4
|
Summary: Evidence-tiered species descriptions, keys and audits from phenomic matrices
|
|
5
5
|
Project-URL: Homepage, https://github.com/alexrvandam/Descriptron
|
|
6
6
|
Project-URL: Repository, https://github.com/alexrvandam/Descriptron
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "descriptron-core"
|
|
7
|
+
version = "2.1.3"
|
|
8
|
+
description = "Evidence-tiered species descriptions, keys and audits from phenomic matrices"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
license = { text = "Apache-2.0" }
|
|
12
|
+
authors = [{ name = "Alex R. Van Dam" }]
|
|
13
|
+
keywords = ["taxonomy", "morphometrics", "phenomics", "species description", "COCO"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Programming Language :: Python :: 3",
|
|
16
|
+
"Topic :: Scientific/Engineering :: Bio-Informatics",
|
|
17
|
+
"Topic :: Scientific/Engineering :: Image Processing",
|
|
18
|
+
"Intended Audience :: Science/Research",
|
|
19
|
+
"License :: OSI Approved :: Apache Software License",
|
|
20
|
+
"Operating System :: OS Independent",
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
# Derived from the imports of the 62 programs in this package, not from memory:
|
|
24
|
+
# `python -m descriptron_core.cli --list` names them. No torch, no CUDA, no
|
|
25
|
+
# compiler — this installs in about a minute on Linux, macOS and Windows, and
|
|
26
|
+
# with the deposited COCO files it reproduces every analysis in the methods paper.
|
|
27
|
+
dependencies = [
|
|
28
|
+
"numpy>=1.23",
|
|
29
|
+
"pandas>=1.5",
|
|
30
|
+
"scipy>=1.9",
|
|
31
|
+
"matplotlib>=3.6",
|
|
32
|
+
"scikit-learn>=1.2",
|
|
33
|
+
"scikit-image>=0.20",
|
|
34
|
+
"opencv-python-headless>=4.7", # headless: the analysis half never opens a window
|
|
35
|
+
"pillow>=9",
|
|
36
|
+
"pycocotools>=2.0.6",
|
|
37
|
+
"seaborn>=0.12",
|
|
38
|
+
"statsmodels>=0.14",
|
|
39
|
+
"scikit-posthocs>=0.7",
|
|
40
|
+
"umap-learn>=0.5",
|
|
41
|
+
"networkx>=3",
|
|
42
|
+
"pyefd>=1.6",
|
|
43
|
+
"biopython>=1.81",
|
|
44
|
+
"PyYAML>=6",
|
|
45
|
+
"lxml>=4.9",
|
|
46
|
+
"openpyxl>=3.1",
|
|
47
|
+
"python-docx>=1.0", # treatment and monograph .docx export
|
|
48
|
+
]
|
|
49
|
+
|
|
50
|
+
[project.optional-dependencies]
|
|
51
|
+
# Only needed to *write* treatments. The audit, key, matrix, novelty scoring and
|
|
52
|
+
# delimitation are all deterministic and need no model at all.
|
|
53
|
+
llm = ["anthropic>=0.40"]
|
|
54
|
+
# literature retrieval (the RAG in BioRAG): BioSysLit treatments from Zenodo and your
|
|
55
|
+
# own PDFs. Keyword retrieval needs only the first two; sentence-embedding retrieval
|
|
56
|
+
# (`index --embeddings`) also needs sentence-transformers + faiss-cpu, which pull in torch.
|
|
57
|
+
rag = ["requests>=2.28", "pdfplumber>=0.10"]
|
|
58
|
+
rag-embeddings = ["requests>=2.28", "pdfplumber>=0.10", "sentence-transformers>=2.2", "faiss-cpu>=1.7"]
|
|
59
|
+
dev = ["pytest>=7", "build>=1", "twine>=5"]
|
|
60
|
+
|
|
61
|
+
[project.scripts]
|
|
62
|
+
descriptron = "descriptron_core.cli:main"
|
|
63
|
+
biorag-pipeline = "descriptron_core.cli:run_pipeline"
|
|
64
|
+
biorag-key = "descriptron_core.cli:run_key_builder"
|
|
65
|
+
biorag-audit = "descriptron_core.cli:run_confabulation_checker"
|
|
66
|
+
biorag-novelty = "descriptron_core.cli:run_novelty_score"
|
|
67
|
+
biorag-calibrate = "descriptron_core.cli:run_calibrate"
|
|
68
|
+
descriptron-keys = "descriptron_core.cli:run_keys"
|
|
69
|
+
|
|
70
|
+
[project.urls]
|
|
71
|
+
Homepage = "https://github.com/alexrvandam/Descriptron"
|
|
72
|
+
Repository = "https://github.com/alexrvandam/Descriptron"
|
|
73
|
+
Issues = "https://github.com/alexrvandam/Descriptron/issues"
|
|
74
|
+
|
|
75
|
+
[tool.hatch.build.targets.wheel]
|
|
76
|
+
packages = ["src/descriptron_core"]
|
|
77
|
+
|
|
78
|
+
# tools/ and data/ sit inside the package directory, so `packages` already ships
|
|
79
|
+
# them; a force-include here would add every file a second time and the build
|
|
80
|
+
# fails with "a second file is being added to the wheel archive at the same path".
|
|
81
|
+
[tool.hatch.build]
|
|
82
|
+
artifacts = ["src/descriptron_core/tools/**", "src/descriptron_core/data/**"]
|
{descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_llm_backend.py
RENAMED
|
@@ -82,6 +82,11 @@ class LLMResponse:
|
|
|
82
82
|
def _log_call(log_path: Optional[str], record: Dict):
|
|
83
83
|
if not log_path:
|
|
84
84
|
return
|
|
85
|
+
try: # when the call was made, for matching a call to a result
|
|
86
|
+
from datetime import datetime, timezone
|
|
87
|
+
record = {"time_utc": datetime.now(timezone.utc).isoformat(timespec="seconds"), **record}
|
|
88
|
+
except Exception:
|
|
89
|
+
pass
|
|
85
90
|
with _LOG_LOCK:
|
|
86
91
|
Path(log_path).parent.mkdir(parents=True, exist_ok=True)
|
|
87
92
|
with open(log_path, "a") as f:
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
biorag_provenance_v1.py — stamp every output with what produced it
|
|
4
|
+
==================================================================
|
|
5
|
+
|
|
6
|
+
A number in a manuscript is only checkable if a reader can get from it back to
|
|
7
|
+
the code and the inputs that made it. `manuscript_numbers_v18.tsv` already maps
|
|
8
|
+
each number to the report file that supplied it; this closes the remaining link,
|
|
9
|
+
from the report back to the script, the commit and the exact inputs.
|
|
10
|
+
|
|
11
|
+
Three lines in a script:
|
|
12
|
+
|
|
13
|
+
from biorag_provenance_v1 import stamp, write_json
|
|
14
|
+
...
|
|
15
|
+
write_json(out_dir / "report.json", payload) # adds "_provenance"
|
|
16
|
+
|
|
17
|
+
or, for anything that is not JSON (a CSV, a figure, a directory of tables):
|
|
18
|
+
|
|
19
|
+
stamp(out_dir, inputs=[args.matrix, args.coco]) # writes provenance.json
|
|
20
|
+
|
|
21
|
+
What is recorded: the script and its SHA-256, the git commit and whether the tree
|
|
22
|
+
was dirty, the full command line, the interpreter and platform, the run time in
|
|
23
|
+
UTC, and a SHA-256 for every named input file. Hashing the inputs is what makes
|
|
24
|
+
the record worth anything — "produced by version X from these exact files" is a
|
|
25
|
+
claim a sceptic can test, "produced by version X" is not.
|
|
26
|
+
|
|
27
|
+
Deliberately: no network, no imports beyond the standard library, and every
|
|
28
|
+
failure is swallowed. A provenance stamp must never be the reason an analysis
|
|
29
|
+
dies.
|
|
30
|
+
"""
|
|
31
|
+
from __future__ import annotations
|
|
32
|
+
|
|
33
|
+
import hashlib
|
|
34
|
+
import json
|
|
35
|
+
import os
|
|
36
|
+
import platform
|
|
37
|
+
import subprocess
|
|
38
|
+
import sys
|
|
39
|
+
from datetime import datetime, timezone
|
|
40
|
+
from pathlib import Path
|
|
41
|
+
|
|
42
|
+
__all__ = ["provenance", "stamp", "write_json", "sha256"]
|
|
43
|
+
|
|
44
|
+
_MAX_HASH_BYTES = 2_000_000_000 # 2 GB: beyond this, record the size only
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def sha256(path) -> str | None:
|
|
48
|
+
"""SHA-256 of a file, or None if it cannot be read. Never raises."""
|
|
49
|
+
try:
|
|
50
|
+
p = Path(path)
|
|
51
|
+
if not p.is_file():
|
|
52
|
+
return None
|
|
53
|
+
if p.stat().st_size > _MAX_HASH_BYTES:
|
|
54
|
+
return f"(not hashed: {p.stat().st_size} bytes)"
|
|
55
|
+
h = hashlib.sha256()
|
|
56
|
+
with open(p, "rb") as fh:
|
|
57
|
+
for chunk in iter(lambda: fh.read(1 << 20), b""):
|
|
58
|
+
h.update(chunk)
|
|
59
|
+
return h.hexdigest()
|
|
60
|
+
except Exception:
|
|
61
|
+
return None
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def _git(*args, cwd=None):
|
|
65
|
+
try:
|
|
66
|
+
out = subprocess.run(["git", *args], cwd=cwd, capture_output=True,
|
|
67
|
+
text=True, timeout=10)
|
|
68
|
+
return out.stdout.strip() if out.returncode == 0 else None
|
|
69
|
+
except Exception:
|
|
70
|
+
return None
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def provenance(inputs=None, script=None, extra=None) -> dict:
|
|
74
|
+
"""The record itself. Safe to call from anywhere; never raises."""
|
|
75
|
+
try:
|
|
76
|
+
script_path = Path(script or sys.argv[0]).resolve()
|
|
77
|
+
except Exception:
|
|
78
|
+
script_path = Path(sys.argv[0] if sys.argv else "unknown")
|
|
79
|
+
repo = script_path.parent if script_path.exists() else None
|
|
80
|
+
|
|
81
|
+
# Only report a commit if THIS FILE is tracked by that repository. The
|
|
82
|
+
# Descriptron scripts currently sit untracked inside a clone of
|
|
83
|
+
# facebookresearch/segment-anything-2, so a naive `git rev-parse HEAD` returns
|
|
84
|
+
# SAM2's commit — a hash that says nothing about the code that produced the
|
|
85
|
+
# output, and is worse than no hash because it looks authoritative.
|
|
86
|
+
commit = dirty = tracked = None
|
|
87
|
+
if repo is not None:
|
|
88
|
+
tracked = bool(_git("ls-files", "--error-unmatch", str(script_path), cwd=repo))
|
|
89
|
+
if tracked:
|
|
90
|
+
commit = _git("rev-parse", "HEAD", cwd=repo)
|
|
91
|
+
dirty = bool(_git("status", "--porcelain", "--", str(script_path), cwd=repo))
|
|
92
|
+
|
|
93
|
+
rec = {
|
|
94
|
+
"script": script_path.name,
|
|
95
|
+
"script_path": str(script_path),
|
|
96
|
+
"script_sha256": sha256(script_path),
|
|
97
|
+
"git_commit": commit,
|
|
98
|
+
"git_dirty": dirty,
|
|
99
|
+
# a run from an untracked tree cannot be pinned to a version; say so in
|
|
100
|
+
# the record rather than leaving a reader to infer it
|
|
101
|
+
"git_tracked": tracked,
|
|
102
|
+
"git_note": (None if commit else
|
|
103
|
+
"this script is NOT tracked by any git repository, so the output "
|
|
104
|
+
"cannot be tied to a version of the code"),
|
|
105
|
+
"command": " ".join(sys.argv),
|
|
106
|
+
"argv": list(sys.argv),
|
|
107
|
+
"cwd": os.getcwd(),
|
|
108
|
+
"python": sys.version.split()[0],
|
|
109
|
+
"platform": platform.platform(),
|
|
110
|
+
"hostname": platform.node(),
|
|
111
|
+
"run_utc": datetime.now(timezone.utc).isoformat(timespec="seconds"),
|
|
112
|
+
"inputs": {},
|
|
113
|
+
}
|
|
114
|
+
for item in (inputs or []):
|
|
115
|
+
if item is None:
|
|
116
|
+
continue
|
|
117
|
+
try:
|
|
118
|
+
rec["inputs"][str(item)] = sha256(item)
|
|
119
|
+
except Exception:
|
|
120
|
+
rec["inputs"][str(item)] = None
|
|
121
|
+
if extra:
|
|
122
|
+
rec["extra"] = extra
|
|
123
|
+
return rec
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def stamp(out_dir, inputs=None, script=None, extra=None, name="provenance.json"):
|
|
127
|
+
"""Write a provenance record beside an output that is not itself JSON."""
|
|
128
|
+
try:
|
|
129
|
+
d = Path(out_dir)
|
|
130
|
+
d.mkdir(parents=True, exist_ok=True)
|
|
131
|
+
rec = provenance(inputs=inputs, script=script, extra=extra)
|
|
132
|
+
(d / name).write_text(json.dumps(rec, indent=2))
|
|
133
|
+
return d / name
|
|
134
|
+
except Exception:
|
|
135
|
+
return None
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def write_json(path, payload, inputs=None, script=None, extra=None, indent=2):
|
|
139
|
+
"""json.dump with a `_provenance` key added. Drop-in for an existing dump."""
|
|
140
|
+
try:
|
|
141
|
+
rec = provenance(inputs=inputs, script=script, extra=extra)
|
|
142
|
+
if isinstance(payload, dict):
|
|
143
|
+
payload = {**payload, "_provenance": rec}
|
|
144
|
+
else:
|
|
145
|
+
payload = {"data": payload, "_provenance": rec}
|
|
146
|
+
except Exception:
|
|
147
|
+
pass
|
|
148
|
+
p = Path(path)
|
|
149
|
+
p.parent.mkdir(parents=True, exist_ok=True)
|
|
150
|
+
p.write_text(json.dumps(payload, indent=indent, default=str))
|
|
151
|
+
return p
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def verify(record_path) -> dict:
|
|
155
|
+
"""
|
|
156
|
+
Re-check a stamped record: does the script still hash the same, do the inputs
|
|
157
|
+
still hash the same? This is what a sceptical reader runs.
|
|
158
|
+
"""
|
|
159
|
+
rec = json.loads(Path(record_path).read_text())
|
|
160
|
+
rec = rec.get("_provenance", rec)
|
|
161
|
+
out = {"script": None, "inputs": {}, "ok": True}
|
|
162
|
+
now = sha256(rec.get("script_path"))
|
|
163
|
+
out["script"] = ("unchanged" if now and now == rec.get("script_sha256")
|
|
164
|
+
else "CHANGED or missing")
|
|
165
|
+
if out["script"] != "unchanged":
|
|
166
|
+
out["ok"] = False
|
|
167
|
+
for path, want in (rec.get("inputs") or {}).items():
|
|
168
|
+
got = sha256(path)
|
|
169
|
+
same = (got is not None and got == want)
|
|
170
|
+
out["inputs"][path] = "unchanged" if same else "CHANGED or missing"
|
|
171
|
+
if not same:
|
|
172
|
+
out["ok"] = False
|
|
173
|
+
# records written by run_full_pipeline_v2 also list what the step wrote
|
|
174
|
+
if isinstance(rec.get("outputs"), dict):
|
|
175
|
+
out["outputs"] = {}
|
|
176
|
+
for path, want in rec["outputs"].items():
|
|
177
|
+
if path.startswith("("):
|
|
178
|
+
continue
|
|
179
|
+
got = sha256(path)
|
|
180
|
+
same = (got is not None and got == want)
|
|
181
|
+
out["outputs"][path] = "unchanged" if same else "CHANGED or missing"
|
|
182
|
+
if not same:
|
|
183
|
+
out["ok"] = False
|
|
184
|
+
return out
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def which(result_file, search_dir) -> list:
|
|
188
|
+
"""Which pipeline step wrote this file? Hash it and look for the hash among the outputs of
|
|
189
|
+
every provenance record under search_dir. A match means this exact content was written by
|
|
190
|
+
that step; no match means the file was changed afterwards or made outside the pipeline."""
|
|
191
|
+
want = sha256(result_file)
|
|
192
|
+
hits = []
|
|
193
|
+
if want is None:
|
|
194
|
+
return hits
|
|
195
|
+
for rp in sorted(Path(search_dir).rglob("*provenance*.json")):
|
|
196
|
+
try:
|
|
197
|
+
rec = json.loads(rp.read_text())
|
|
198
|
+
except Exception:
|
|
199
|
+
continue
|
|
200
|
+
rec = rec.get("_provenance", rec)
|
|
201
|
+
outs = rec.get("outputs") or {}
|
|
202
|
+
if isinstance(outs, dict) and want in outs.values():
|
|
203
|
+
hits.append({"record": str(rp),
|
|
204
|
+
"step": (rec.get("extra") or {}).get("pipeline_step"),
|
|
205
|
+
"script": rec.get("script"), "script_sha256": rec.get("script_sha256"),
|
|
206
|
+
"git_commit": rec.get("git_commit"), "run_utc": rec.get("run_utc"),
|
|
207
|
+
"command": rec.get("command")})
|
|
208
|
+
return hits
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
if __name__ == "__main__":
|
|
212
|
+
import argparse
|
|
213
|
+
ap = argparse.ArgumentParser(description=__doc__,
|
|
214
|
+
formatter_class=argparse.RawDescriptionHelpFormatter)
|
|
215
|
+
ap.add_argument("--verify", help="a provenance.json (or a report with _provenance) to re-check")
|
|
216
|
+
ap.add_argument("--show", action="store_true", help="print a record for this invocation")
|
|
217
|
+
ap.add_argument("--which", help="a result file: find the provenance record of the step that wrote it")
|
|
218
|
+
ap.add_argument("--search", default=".", help="folder to search for provenance records (with --which)")
|
|
219
|
+
a = ap.parse_args()
|
|
220
|
+
if a.verify:
|
|
221
|
+
result = verify(a.verify)
|
|
222
|
+
print(json.dumps(result, indent=2))
|
|
223
|
+
sys.exit(0 if result["ok"] else 1)
|
|
224
|
+
if a.which:
|
|
225
|
+
hits = which(a.which, a.search)
|
|
226
|
+
print(json.dumps(hits, indent=2) if hits else
|
|
227
|
+
"no provenance record lists this exact file content (changed since, or not made by the pipeline)")
|
|
228
|
+
sys.exit(0 if hits else 1)
|
|
229
|
+
if a.show:
|
|
230
|
+
print(json.dumps(provenance(), indent=2))
|
{descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/run_full_pipeline_v2.py
RENAMED
|
@@ -164,6 +164,118 @@ def _has_keypoints(coco_json_path: str) -> bool:
|
|
|
164
164
|
return False
|
|
165
165
|
|
|
166
166
|
|
|
167
|
+
_OUT_FLAGS = ("--output_dir", "--output-dir", "--out_dir", "--out-dir", "--output_base", "--outdir")
|
|
168
|
+
_MAX_OUTPUT_FILES = 2000 # hash at most this many files written by one step
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def _dir_manifest(d: Path) -> Dict:
|
|
172
|
+
"""A cheap fingerprint of an input folder (e.g. thousands of images): names, sizes and
|
|
173
|
+
modification times of its files, hashed together. Contents are not read."""
|
|
174
|
+
import hashlib
|
|
175
|
+
h, n = hashlib.sha256(), 0
|
|
176
|
+
for p in sorted(d.rglob("*")):
|
|
177
|
+
if p.is_file():
|
|
178
|
+
st = p.stat()
|
|
179
|
+
h.update(f"{p.relative_to(d)}\t{st.st_size}\t{int(st.st_mtime)}\n".encode())
|
|
180
|
+
n += 1
|
|
181
|
+
return {"files": n, "manifest_sha256": h.hexdigest()}
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def _prov_import():
|
|
185
|
+
"""biorag_provenance_v1 sits beside this script (working tree, pip package, Docker)."""
|
|
186
|
+
if str(SCRIPT_DIR) not in sys.path:
|
|
187
|
+
sys.path.insert(0, str(SCRIPT_DIR))
|
|
188
|
+
import biorag_provenance_v1
|
|
189
|
+
return biorag_provenance_v1
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def _step_pre_state(cmd: List[str]) -> Dict:
|
|
193
|
+
"""Before a step runs: its script and every file or folder named on its command line."""
|
|
194
|
+
try:
|
|
195
|
+
sha256 = _prov_import().sha256
|
|
196
|
+
script = next((c for c in cmd if str(c).endswith(".py")), None)
|
|
197
|
+
files, folders = {}, {}
|
|
198
|
+
skip_next = False
|
|
199
|
+
for c in cmd[1:]:
|
|
200
|
+
if skip_next: # the step's output folder is not an input
|
|
201
|
+
skip_next = False
|
|
202
|
+
continue
|
|
203
|
+
if str(c) in _OUT_FLAGS:
|
|
204
|
+
skip_next = True
|
|
205
|
+
continue
|
|
206
|
+
p = Path(str(c))
|
|
207
|
+
if str(c).startswith("-") or str(c) == script or len(str(c)) > 4096:
|
|
208
|
+
continue
|
|
209
|
+
if p.is_file():
|
|
210
|
+
files[str(p)] = sha256(p)
|
|
211
|
+
elif p.is_dir():
|
|
212
|
+
folders[str(p)] = _dir_manifest(p)
|
|
213
|
+
return {"script": script, "files": files, "folders": folders}
|
|
214
|
+
except Exception as e: # never the reason a step fails
|
|
215
|
+
return {"error": f"{type(e).__name__}: {e}"}
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def _stamp_step(cmd: List[str], step_name: str, log_dir: Path, pre: Dict,
|
|
219
|
+
t0: float, elapsed: float, returncode: int) -> None:
|
|
220
|
+
"""Write <log_dir>/<step>.provenance.json (and provenance_<step>.json in the step's output
|
|
221
|
+
folder): the step script and its SHA-256, git commit if tracked, the command, a SHA-256 of
|
|
222
|
+
every input file named on the command line (taken BEFORE the step ran; files the step then
|
|
223
|
+
overwrote are listed under both inputs and outputs), a manifest of every input folder, and a
|
|
224
|
+
SHA-256 of every file the step wrote. Check later with
|
|
225
|
+
`descriptron biorag_provenance_v1 --verify <file>` (or `python biorag_provenance_v1.py ...` from the source tree). Never raises."""
|
|
226
|
+
try:
|
|
227
|
+
_pv = _prov_import()
|
|
228
|
+
provenance, sha256 = _pv.provenance, _pv.sha256
|
|
229
|
+
extra = {"pipeline_step": step_name, "exit_code": returncode,
|
|
230
|
+
"seconds": round(elapsed, 1), "python_bin": cmd[0] if cmd else None,
|
|
231
|
+
"input_folders": pre.get("folders", {}),
|
|
232
|
+
"pipeline_script": Path(__file__).name,
|
|
233
|
+
"pipeline_script_sha256": sha256(Path(__file__).resolve())}
|
|
234
|
+
try:
|
|
235
|
+
from importlib.metadata import version
|
|
236
|
+
extra["descriptron_packages"] = {}
|
|
237
|
+
for dist in ("descriptron", "descriptron-core", "descriptron-vision"):
|
|
238
|
+
try:
|
|
239
|
+
extra["descriptron_packages"][dist] = version(dist)
|
|
240
|
+
except Exception:
|
|
241
|
+
pass
|
|
242
|
+
except Exception:
|
|
243
|
+
pass
|
|
244
|
+
rec = provenance(inputs=list(pre.get("files", {})), script=pre.get("script"), extra=extra)
|
|
245
|
+
rec["command"] = " ".join(str(c) for c in cmd) # the step's command, not the pipeline's
|
|
246
|
+
rec["argv"] = [str(c) for c in cmd]
|
|
247
|
+
rec["inputs"] = pre.get("files", {}) # hashes as they were before the run
|
|
248
|
+
if pre.get("error"):
|
|
249
|
+
rec["pre_state_error"] = pre["error"]
|
|
250
|
+
out_dir = None
|
|
251
|
+
for i, c in enumerate(cmd[:-1]):
|
|
252
|
+
if str(c) in _OUT_FLAGS:
|
|
253
|
+
out_dir = Path(str(cmd[i + 1]))
|
|
254
|
+
break
|
|
255
|
+
outputs = {}
|
|
256
|
+
if out_dir is not None and out_dir.is_dir():
|
|
257
|
+
for p in sorted(out_dir.rglob("*")):
|
|
258
|
+
if len(outputs) >= _MAX_OUTPUT_FILES:
|
|
259
|
+
outputs["(truncated)"] = f"more than {_MAX_OUTPUT_FILES} files written"
|
|
260
|
+
break
|
|
261
|
+
# the pipeline's own bookkeeping (its running log, the step logs and every
|
|
262
|
+
# provenance record) keeps changing after the step and is not the step's output
|
|
263
|
+
if (p.is_file() and p.stat().st_mtime >= t0 - 1
|
|
264
|
+
and not p.name.startswith("provenance_")
|
|
265
|
+
and not p.name.endswith(".provenance.json")
|
|
266
|
+
and p.name != "pipeline_log.txt"
|
|
267
|
+
and log_dir.resolve() not in p.resolve().parents):
|
|
268
|
+
outputs[str(p)] = sha256(p)
|
|
269
|
+
rec["outputs"] = outputs
|
|
270
|
+
rec["output_dir"] = str(out_dir) if out_dir else None
|
|
271
|
+
text = json.dumps(rec, indent=2, default=str)
|
|
272
|
+
(log_dir / f"{step_name}.provenance.json").write_text(text)
|
|
273
|
+
if out_dir is not None and out_dir.is_dir():
|
|
274
|
+
(out_dir / f"provenance_{step_name}.json").write_text(text)
|
|
275
|
+
except Exception as e:
|
|
276
|
+
logger.warning(f" (provenance record not written: {type(e).__name__}: {e})")
|
|
277
|
+
|
|
278
|
+
|
|
167
279
|
def _run_step(cmd: List[str], step_name: str, log_dir: Path,
|
|
168
280
|
dry_run: bool = False) -> bool:
|
|
169
281
|
cmd_str = " \\\n ".join(cmd)
|
|
@@ -173,6 +285,7 @@ def _run_step(cmd: List[str], step_name: str, log_dir: Path,
|
|
|
173
285
|
logger.info(f" [DRY RUN] Skipping execution")
|
|
174
286
|
return True
|
|
175
287
|
|
|
288
|
+
pre = _step_pre_state(cmd) # provenance: hash the inputs before the step can change them
|
|
176
289
|
log_file = log_dir / f"{step_name}.log"
|
|
177
290
|
with open(log_file, "w") as lf:
|
|
178
291
|
lf.write(f"# {step_name}\n# {datetime.now().isoformat()}\n")
|
|
@@ -185,6 +298,8 @@ def _run_step(cmd: List[str], step_name: str, log_dir: Path,
|
|
|
185
298
|
)
|
|
186
299
|
elapsed = time.time() - t0
|
|
187
300
|
|
|
301
|
+
_stamp_step(cmd, step_name, log_dir, pre, t0, elapsed, result.returncode)
|
|
302
|
+
|
|
188
303
|
if result.returncode != 0:
|
|
189
304
|
logger.error(f" FAILED (exit code {result.returncode}, {elapsed:.0f}s)")
|
|
190
305
|
logger.error(f" See log: {log_file}")
|
|
@@ -1538,7 +1653,7 @@ def step_char_gate(cfg: Dict, python: str, log_dir: Path) -> bool:
|
|
|
1538
1653
|
# only what it was told to. "llm" is available and reads better, but measured on the Diaphorina
|
|
1539
1654
|
# treatments it also deleted statements about characters that had passed, in 47% of its edits —
|
|
1540
1655
|
# invisible to both the subsequence check and the numeric audit. See BIORAG_V2_README.md §9d.
|
|
1541
|
-
engine = cfg.get("gate_engine"
|
|
1656
|
+
engine = cfg.get("gate_engine") or "python" # argparse stores None when --gate_engine is not given
|
|
1542
1657
|
if engine == "llm" and cfg.get("llm_backend") == "none":
|
|
1543
1658
|
logger.info(" no LLM backend configured — editing by rule instead (--engine python)")
|
|
1544
1659
|
engine = "python"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{descriptron_core-2.1.2 → descriptron_core-2.1.3}/pyproject.toml.bak_pre_203_20260924_145320
RENAMED
|
File without changes
|
{descriptron_core-2.1.2 → descriptron_core-2.1.3}/pyproject.toml.bak_pre_204_20260924_165335
RENAMED
|
File without changes
|
{descriptron_core-2.1.2 → descriptron_core-2.1.3}/pyproject.toml.bak_pre_210_20260925_103754
RENAMED
|
File without changes
|
{descriptron_core-2.1.2 → descriptron_core-2.1.3}/pyproject.toml.bak_pre_211_20260925_114912
RENAMED
|
File without changes
|
|
File without changes
|
{descriptron_core-2.1.2 → descriptron_core-2.1.3}/pyproject.toml.bak_pre_keys_20260924_165335
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/FHS_and_CLAHE_V21.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_calibrate_v1.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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_key_fuzzy_v1.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
|
|
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
|
{descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/biorag_specimen_id.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
|
{descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/coco_combiner_V13.py
RENAMED
|
File without changes
|
{descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/coco_converter_v24.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/descriptron_convert.py
RENAMED
|
File without changes
|
|
File without changes
|
{descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/descriptron_joints.py
RENAMED
|
File without changes
|
{descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/descriptron_metadata.py
RENAMED
|
File without changes
|
{descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/descriptron_rosetta.py
RENAMED
|
File without changes
|
|
File without changes
|
{descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/landmark_gpa_V1.py
RENAMED
|
File without changes
|
{descriptron_core-2.1.2 → descriptron_core-2.1.3}/src/descriptron_core/tools/landmark_gpa_V2.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
|