deriva-cli 0.8.2__tar.gz → 0.8.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.
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/PKG-INFO +1 -1
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/archimate/manager.py +29 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/archimate/views.py +56 -23
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/archimate/xml_export.py +32 -8
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/database/__init__.py +2 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/database/manager.py +19 -1
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/graph/manager.py +2 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/graph/models.py +39 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/repository/manager.py +5 -20
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/cli/cli.py +5 -1
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/cli/commands/config.py +12 -1
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/cli/commands/repo.py +1 -1
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/cli/commands/run.py +4 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/analysis/semantic_matching.py +16 -4
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/derivation/base.py +14 -1
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/derivation/detail_level.py +5 -3
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/derivation/element_base.py +21 -6
- deriva_cli-0.8.3/deriva/modules/derivation/levels.py +224 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/derivation/refine/__init__.py +2 -0
- deriva_cli-0.8.3/deriva/modules/derivation/refine/abstraction_levels.py +261 -0
- deriva_cli-0.8.3/deriva/modules/extraction/build_modules.py +254 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/extraction/data_entities.py +22 -6
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/extraction/deployable_units.py +8 -2
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/extraction/deployments.py +16 -2
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/extraction/step_tags.py +4 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/services/__init__.py +3 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/services/config.py +19 -21
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/services/derivation.py +55 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/services/export_bundle.py +5 -0
- deriva_cli-0.8.3/deriva/services/export_levels.py +117 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/services/extraction.py +138 -3
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/services/session.py +9 -3
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/pyproject.toml +1 -1
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/pyproject.toml.orig +1 -1
- deriva_cli-0.8.2/deriva/services/export_levels.py +0 -71
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/LICENSE +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/archimate/README.md +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/archimate/__init__.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/archimate/archimate_xsd/documentation/Diagram.html +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/archimate/archimate_xsd/documentation/View.html +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/archimate/archimate_xsd/documentation/model.html +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/archimate/archimate_xsd/examples/archimate3_Diagram.xsd +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/archimate/archimate_xsd/examples/archimate3_Model.xsd +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/archimate/archimate_xsd/examples/archimate3_View.xsd +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/archimate/archimate_xsd/schemas/archimate3_Diagram.xsd +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/archimate/archimate_xsd/schemas/archimate3_Model.xsd +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/archimate/archimate_xsd/schemas/archimate3_View.xsd +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/archimate/archimate_xsd/snippets/Interoperability testing snippet-1.xml +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/archimate/archimate_xsd/snippets/Interoperability testing snippet-10.xml +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/archimate/archimate_xsd/snippets/Interoperability testing snippet-2.xml +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/archimate/archimate_xsd/snippets/Interoperability testing snippet-3.xml +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/archimate/archimate_xsd/snippets/Interoperability testing snippet-4.xml +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/archimate/archimate_xsd/snippets/Interoperability testing snippet-5.xml +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/archimate/archimate_xsd/snippets/Interoperability testing snippet-7.xml +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/archimate/archimate_xsd/snippets/Interoperability testing snippet-8.xml +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/archimate/archimate_xsd/snippets/Interoperability testing snippet-9.xml +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/archimate/models.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/archimate/validation.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/database/README.md +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/database/data/derivation_config.json +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/database/data/derivation_patterns.json +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/database/data/extraction_config.json +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/database/data/file_types.json +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/database/data/function_models/pcf-8.0-cross-industry.csv +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/database/data/system_settings.json +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/database/db_tool.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/database/scripts/7_extraction_params.sql +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/database/scripts/schema.sql +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/grafeo/__init__.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/grafeo/manager.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/graph/README.md +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/graph/__init__.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/graph/cache.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/graph/metamodel.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/llm/README.md +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/llm/__init__.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/llm/cache.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/llm/manager.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/llm/model_registry.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/llm/models.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/llm/rate_limiter.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/llm/retry.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/llm/schemas.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/nlp/__init__.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/nlp/extract.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/nlp/language.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/nlp/manager.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/nlp/models.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/nlp/phrases.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/nlp/settings.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/nlp/text.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/nlp/translate.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/repository/README.md +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/repository/__init__.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/repository/models.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/treesitter/__init__.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/treesitter/cdk.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/treesitter/languages/__init__.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/treesitter/languages/base.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/treesitter/languages/bms.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/treesitter/languages/cobol.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/treesitter/languages/csharp.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/treesitter/languages/java.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/treesitter/languages/javascript.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/treesitter/languages/jcl.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/treesitter/languages/python.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/treesitter/languages/sql.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/treesitter/languages/structural.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/treesitter/manager.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/adapters/treesitter/models.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/cli/README.md +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/cli/__init__.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/cli/commands/__init__.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/cli/commands/graph.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/cli/progress.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/common/__init__.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/common/cache_utils.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/common/chunking.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/common/document_reader.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/common/exceptions.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/common/file_utils.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/common/json_utils.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/common/llm_utils.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/common/logging.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/common/naming.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/common/ocel.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/common/paths.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/common/schema_utils.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/common/settings.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/common/time_utils.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/common/timing.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/common/types.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/__init__.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/analysis/__init__.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/analysis/consistency.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/analysis/conventions.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/analysis/cross_repo_analysis.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/analysis/deviation.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/analysis/fit_analysis.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/analysis/model_quality.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/analysis/run_consistency.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/analysis/stability_analysis.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/analysis/types.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/derivation/__init__.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/derivation/application_component.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/derivation/application_interface.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/derivation/application_service.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/derivation/business_actor.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/derivation/business_event.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/derivation/business_function.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/derivation/business_object.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/derivation/business_process.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/derivation/component_services.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/derivation/data_object.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/derivation/device.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/derivation/function_model.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/derivation/node.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/derivation/prep.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/derivation/refine/base.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/derivation/refine/cross_layer.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/derivation/refine/duplicate_elements.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/derivation/refine/duplicate_relationships.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/derivation/refine/graph_relationships.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/derivation/refine/joint.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/derivation/refine/joint_consistency.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/derivation/refine/normalization.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/derivation/refine/orphan_elements.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/derivation/refine/structural_consistency.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/derivation/system_software.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/derivation/technology_service.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/extraction/__init__.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/extraction/base.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/extraction/business_concept.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/extraction/classification.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/extraction/concept_candidates.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/extraction/cooperation.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/extraction/data_domains.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/extraction/directory.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/extraction/directory_classification.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/extraction/edges.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/extraction/external_dependency.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/extraction/file.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/extraction/lifecycles.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/extraction/method.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/extraction/repository.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/extraction/roles.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/extraction/technologies.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/extraction/technology_candidates.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/extraction/test.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/modules/extraction/type_definition.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/services/about.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/services/config_models.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/services/llm_log.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/services/model_configs.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/services/ontology.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/services/overfit.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/services/pipeline.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/deriva/services/trace.py +0 -0
- {deriva_cli-0.8.2 → deriva_cli-0.8.3}/packages/README-deriva-cli.md +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: deriva-cli
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.3
|
|
4
4
|
Summary: Deriva is a research project aimed at enabling digital architects by automating the derivation of enterprise architecture models. Deriva uses dual knowledge graphs, heuristics and LLM's.
|
|
5
5
|
Keywords: archimate,enterprise-architecture,code-analysis,llm,grafeo,fastapi
|
|
6
6
|
Author: S. T. Grond
|
|
@@ -577,6 +577,35 @@ class ArchimateManager:
|
|
|
577
577
|
key=lambda e: str(e["identifier"]),
|
|
578
578
|
)
|
|
579
579
|
|
|
580
|
+
def update_element_properties(self, updates: dict[str, dict[str, Any]]) -> int:
|
|
581
|
+
"""Merge keys into the properties of elements (identifier -> keys), leaving their other keys; returns how many changed."""
|
|
582
|
+
if self.db is None:
|
|
583
|
+
raise RuntimeError("Not connected to grafeo. Call connect() first.")
|
|
584
|
+
changed = 0
|
|
585
|
+
for identifier, keys in sorted(updates.items()):
|
|
586
|
+
rows = self.db.execute(f"MATCH (e:`{self.namespace}` {{identifier: $identifier}}) RETURN e.properties AS properties", {"identifier": identifier})
|
|
587
|
+
if not rows:
|
|
588
|
+
continue
|
|
589
|
+
merged = {**(rows[0].get("properties") or {}), **keys}
|
|
590
|
+
self.db.execute_write(f"MATCH (e:`{self.namespace}` {{identifier: $identifier}}) SET e.properties = $properties", {"identifier": identifier, "properties": merged})
|
|
591
|
+
changed += 1
|
|
592
|
+
return changed
|
|
593
|
+
|
|
594
|
+
def update_relationship_properties(self, updates: dict[str, dict[str, Any]]) -> int:
|
|
595
|
+
"""Merge keys into the properties of relationships (identifier -> keys), in place; returns how many changed."""
|
|
596
|
+
if self.db is None:
|
|
597
|
+
raise RuntimeError("Not connected to grafeo. Call connect() first.")
|
|
598
|
+
changed = 0
|
|
599
|
+
for identifier, keys in sorted(updates.items()):
|
|
600
|
+
match = f"MATCH (:`{self.namespace}`)-[r {{identifier: $identifier}}]->(:`{self.namespace}`)"
|
|
601
|
+
rows = self.db.execute(f"{match} RETURN r.properties AS properties", {"identifier": identifier})
|
|
602
|
+
if not rows:
|
|
603
|
+
continue
|
|
604
|
+
merged = {**(rows[0].get("properties") or {}), **keys}
|
|
605
|
+
self.db.execute_write(f"{match} SET r.properties = $properties", {"identifier": identifier, "properties": merged})
|
|
606
|
+
changed += 1
|
|
607
|
+
return changed
|
|
608
|
+
|
|
580
609
|
def delete_relationship(self, identifier: str) -> bool:
|
|
581
610
|
"""Delete a relationship by identifier.
|
|
582
611
|
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"""Generated views (pure): ArchiMate viewpoints per level with a deterministic band layout.
|
|
2
2
|
|
|
3
|
-
Each viewpoint (ArchiMate 3.2 Specification, chapter 13) shows the
|
|
4
|
-
|
|
3
|
+
Each viewpoint (ArchiMate 3.2 Specification, chapter 13) shows the elements of its types on its level (enterprise or
|
|
4
|
+
solution, from the element's ``levels``) and the relationships on that level; a cross-level link is in no view. A
|
|
5
|
+
detail variant shows the solution elements of its types with their detail elements (property ``level`` = detail). The layout puts the
|
|
5
6
|
layers in horizontal bands (business, application, technology) and the elements of a band in a grid, ordered by
|
|
6
7
|
type and name, each detail element right after its parent, so the same model gives the same view in every run.
|
|
7
8
|
"""
|
|
@@ -12,23 +13,32 @@ from dataclasses import dataclass, field
|
|
|
12
13
|
|
|
13
14
|
from .models import Element, Relationship, layer_of
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
("
|
|
20
|
-
("
|
|
21
|
-
("
|
|
16
|
+
ENTERPRISE, SOLUTION, DETAIL = "enterprise", "solution", "detail"
|
|
17
|
+
DEPLOYMENT = frozenset({"ApplicationComponent", "Node", "Device", "SystemSoftware", "TechnologyService"})
|
|
18
|
+
# (view name, viewpoint, element types, level), in export order
|
|
19
|
+
VIEWPOINTS: tuple[tuple[str, str, frozenset[str] | None, str], ...] = (
|
|
20
|
+
("Layered (enterprise)", "Layered", None, ENTERPRISE),
|
|
21
|
+
("Application Cooperation (enterprise)", "Application Cooperation", frozenset({"ApplicationComponent", "ApplicationInterface", "ApplicationService"}), ENTERPRISE),
|
|
22
|
+
("Information Structure (enterprise)", "Information Structure", frozenset({"BusinessObject", "DataObject"}), ENTERPRISE),
|
|
23
|
+
("Implementation and Deployment (enterprise)", "Implementation and Deployment", DEPLOYMENT, ENTERPRISE),
|
|
22
24
|
(
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
frozenset({"
|
|
26
|
-
|
|
25
|
+
"Business (enterprise)",
|
|
26
|
+
"Business Process Cooperation",
|
|
27
|
+
frozenset({"BusinessActor", "BusinessProcess", "BusinessFunction", "BusinessEvent", "ApplicationService"}),
|
|
28
|
+
ENTERPRISE,
|
|
27
29
|
),
|
|
28
|
-
("
|
|
30
|
+
("Application Structure (solution)", "Application Structure", frozenset({"ApplicationComponent"}), SOLUTION),
|
|
31
|
+
("Application Cooperation (solution)", "Application Cooperation", frozenset({"ApplicationComponent", "ApplicationInterface"}), SOLUTION),
|
|
32
|
+
("Information Structure (solution)", "Information Structure", frozenset({"DataObject"}), SOLUTION),
|
|
33
|
+
("Implementation and Deployment (solution)", "Implementation and Deployment", DEPLOYMENT, SOLUTION),
|
|
34
|
+
("Information Structure (detail)", "Information Structure", frozenset({"DataObject"}), DETAIL),
|
|
35
|
+
("Implementation and Deployment (detail)", "Implementation and Deployment", DEPLOYMENT | {"Artifact"}, DETAIL),
|
|
36
|
+
# The interfaces with their members (endpoints, pages, jobs); components are left out, their members are above
|
|
37
|
+
("Application Interfaces (detail)", "Application Cooperation", frozenset({"ApplicationInterface"}), DETAIL),
|
|
29
38
|
)
|
|
39
|
+
|
|
30
40
|
# A view needs an element of its anchor types (the Business view: a business element, not application services alone)
|
|
31
|
-
ANCHORS = {"Business": frozenset({"BusinessActor", "BusinessProcess", "BusinessFunction", "BusinessEvent"})}
|
|
41
|
+
ANCHORS = {"Business (enterprise)": frozenset({"BusinessActor", "BusinessProcess", "BusinessFunction", "BusinessEvent"})}
|
|
32
42
|
BANDS = ("Business", "Application", "Technology", "Other")
|
|
33
43
|
TYPE_ORDER = (
|
|
34
44
|
"BusinessActor", "BusinessFunction", "BusinessProcess", "BusinessEvent", "BusinessObject",
|
|
@@ -61,7 +71,7 @@ class View:
|
|
|
61
71
|
identifier: str
|
|
62
72
|
name: str
|
|
63
73
|
viewpoint: str
|
|
64
|
-
level: str =
|
|
74
|
+
level: str = ENTERPRISE # enterprise, solution or detail (a detail view shows the detail elements too)
|
|
65
75
|
nodes: list[ViewNode] = field(default_factory=list)
|
|
66
76
|
connections: list[ViewConnection] = field(default_factory=list)
|
|
67
77
|
|
|
@@ -70,6 +80,23 @@ def _level(e: Element) -> str:
|
|
|
70
80
|
return str((e.properties or {}).get("level") or "architect")
|
|
71
81
|
|
|
72
82
|
|
|
83
|
+
def _levels(properties: dict | None) -> frozenset[str]:
|
|
84
|
+
"""The levels of an element or relationship: ``level`` detail, else ``levels`` (empty: a cross-level link), else the
|
|
85
|
+
enterprise level (a model from before the levels)."""
|
|
86
|
+
properties = properties or {}
|
|
87
|
+
if properties.get("level") == DETAIL:
|
|
88
|
+
return frozenset({DETAIL})
|
|
89
|
+
levels = properties.get("levels")
|
|
90
|
+
if isinstance(levels, list):
|
|
91
|
+
return frozenset(str(v) for v in levels)
|
|
92
|
+
return frozenset() if properties.get("cross_level") else frozenset({ENTERPRISE})
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def _on(level: str, levels: frozenset[str]) -> bool:
|
|
96
|
+
"""Whether something on ``levels`` belongs in a view of ``level`` (a detail view: the solution level and the detail)."""
|
|
97
|
+
return bool(levels & ({SOLUTION, DETAIL} if level == DETAIL else {level}))
|
|
98
|
+
|
|
99
|
+
|
|
73
100
|
def _order(e: Element) -> tuple[int, str, str]:
|
|
74
101
|
return (TYPE_ORDER.index(e.element_type) if e.element_type in TYPE_ORDER else len(TYPE_ORDER), e.name.casefold(), e.identifier)
|
|
75
102
|
|
|
@@ -102,19 +129,25 @@ def _layout(view: View, shown: list[Element]) -> None:
|
|
|
102
129
|
y += BAND_GAP
|
|
103
130
|
|
|
104
131
|
|
|
105
|
-
def build_views(elements: list[Element], relationships: list[Relationship]) -> list[View]:
|
|
106
|
-
"""The views of the model, one per viewpoint that has elements, in VIEWPOINTS order.
|
|
132
|
+
def build_views(elements: list[Element], relationships: list[Relationship], relationship_levels: dict[str, frozenset[str]] | None = None) -> list[View]:
|
|
133
|
+
"""The views of the model, one per viewpoint that has elements on its level, in VIEWPOINTS order.
|
|
134
|
+
|
|
135
|
+
Args:
|
|
136
|
+
relationship_levels: Relationship id -> its levels, where the relationship's own properties do not say (the
|
|
137
|
+
export's detail relationships); else from the properties
|
|
138
|
+
"""
|
|
107
139
|
views: list[View] = []
|
|
108
|
-
for number, (name, viewpoint, types,
|
|
109
|
-
shown = [e for e in elements if (types is None or e.element_type in types) and (
|
|
140
|
+
for number, (name, viewpoint, types, level) in enumerate(VIEWPOINTS, 1):
|
|
141
|
+
shown = [e for e in elements if (types is None or e.element_type in types) and _on(level, _levels(e.properties))]
|
|
110
142
|
anchors = ANCHORS.get(name)
|
|
111
|
-
if not shown or (anchors and not any(e.element_type in anchors for e in shown)) or (
|
|
143
|
+
if not shown or (anchors and not any(e.element_type in anchors for e in shown)) or (level == DETAIL and not any(_level(e) == DETAIL for e in shown)):
|
|
112
144
|
continue
|
|
113
|
-
view = View(identifier=f"view-{number}", name=name, viewpoint=viewpoint, level=
|
|
145
|
+
view = View(identifier=f"view-{number}", name=name, viewpoint=viewpoint, level=level)
|
|
114
146
|
_layout(view, shown)
|
|
115
147
|
node_of = {n.element: n.identifier for n in view.nodes}
|
|
116
148
|
for r in sorted(relationships, key=lambda r: r.identifier):
|
|
117
|
-
|
|
149
|
+
on = (relationship_levels or {}).get(r.identifier) or _levels(r.properties)
|
|
150
|
+
if r.source in node_of and r.target in node_of and _on(level, on):
|
|
118
151
|
connection = ViewConnection(identifier=f"{view.identifier}-c-{r.identifier}", relationship=r.identifier, source=node_of[r.source], target=node_of[r.target])
|
|
119
152
|
view.connections.append(connection)
|
|
120
153
|
views.append(view)
|
|
@@ -51,6 +51,7 @@ class ArchiMateXMLExporter:
|
|
|
51
51
|
model_id: str = "model-001",
|
|
52
52
|
properties: Mapping[str, Mapping[str, str]] | None = None,
|
|
53
53
|
views: Sequence[View] | None = None,
|
|
54
|
+
relationship_properties: Mapping[str, Mapping[str, str]] | None = None,
|
|
54
55
|
) -> None:
|
|
55
56
|
"""
|
|
56
57
|
Export ArchiMate model to XML file.
|
|
@@ -63,6 +64,7 @@ class ArchiMateXMLExporter:
|
|
|
63
64
|
model_id: Unique identifier for the model
|
|
64
65
|
properties: Exported properties per element id (e.g. ``level``), declared as propertyDefinitions
|
|
65
66
|
views: Diagrams to export (see ``views.build_views``)
|
|
67
|
+
relationship_properties: Exported properties per relationship id, declared with the element ones
|
|
66
68
|
"""
|
|
67
69
|
# Create root model element
|
|
68
70
|
root = etree.Element(
|
|
@@ -83,7 +85,8 @@ class ArchiMateXMLExporter:
|
|
|
83
85
|
self._add_metadata(root)
|
|
84
86
|
|
|
85
87
|
properties = properties or {}
|
|
86
|
-
|
|
88
|
+
relationship_properties = relationship_properties or {}
|
|
89
|
+
keys = sorted({key for values in [*properties.values(), *relationship_properties.values()] for key, value in values.items() if value})
|
|
87
90
|
definition_of = {key: f"propid-{key}" for key in keys}
|
|
88
91
|
|
|
89
92
|
# Add elements section
|
|
@@ -96,7 +99,7 @@ class ArchiMateXMLExporter:
|
|
|
96
99
|
if relationships:
|
|
97
100
|
rels_section = etree.SubElement(root, "relationships")
|
|
98
101
|
for relationship in relationships:
|
|
99
|
-
self._add_relationship(rels_section, relationship)
|
|
102
|
+
self._add_relationship(rels_section, relationship, relationship_properties.get(relationship.identifier, {}), definition_of)
|
|
100
103
|
|
|
101
104
|
# The exchange format's order: elements, relationships, organizations, propertyDefinitions, views
|
|
102
105
|
if keys:
|
|
@@ -105,7 +108,7 @@ class ArchiMateXMLExporter:
|
|
|
105
108
|
definition = etree.SubElement(definitions, "propertyDefinition", attrib={"identifier": definition_of[key], "type": "string"})
|
|
106
109
|
etree.SubElement(definition, "name").text = key
|
|
107
110
|
if views:
|
|
108
|
-
self._add_views(root, views)
|
|
111
|
+
self._add_views(root, views, definition_of.get("level"))
|
|
109
112
|
|
|
110
113
|
# Write to file
|
|
111
114
|
tree = etree.ElementTree(root)
|
|
@@ -190,8 +193,9 @@ class ArchiMateXMLExporter:
|
|
|
190
193
|
value_elem.set(f"{{{self.XML_NS}}}lang", "en")
|
|
191
194
|
value_elem.text = value
|
|
192
195
|
|
|
193
|
-
def _add_views(self, root: etree.Element, views: Sequence[View]) -> None:
|
|
194
|
-
"""Add the diagrams: element nodes with their bounds, relationship connections between them
|
|
196
|
+
def _add_views(self, root: etree.Element, views: Sequence[View], level_definition: str | None = None) -> None:
|
|
197
|
+
"""Add the diagrams: element nodes with their bounds, relationship connections between them, and each view's
|
|
198
|
+
level as a property where the model declares one."""
|
|
195
199
|
diagrams = etree.SubElement(etree.SubElement(root, "views"), "diagrams")
|
|
196
200
|
for view in views:
|
|
197
201
|
diagram = etree.SubElement(
|
|
@@ -202,6 +206,11 @@ class ArchiMateXMLExporter:
|
|
|
202
206
|
name_elem = etree.SubElement(diagram, "name")
|
|
203
207
|
name_elem.set(f"{{{self.XML_NS}}}lang", "en")
|
|
204
208
|
name_elem.text = view.name
|
|
209
|
+
if level_definition:
|
|
210
|
+
prop = etree.SubElement(etree.SubElement(diagram, "properties"), "property", attrib={"propertyDefinitionRef": level_definition})
|
|
211
|
+
value_elem = etree.SubElement(prop, "value")
|
|
212
|
+
value_elem.set(f"{{{self.XML_NS}}}lang", "en")
|
|
213
|
+
value_elem.text = view.level
|
|
205
214
|
for node in view.nodes:
|
|
206
215
|
etree.SubElement(
|
|
207
216
|
diagram,
|
|
@@ -229,13 +238,21 @@ class ArchiMateXMLExporter:
|
|
|
229
238
|
},
|
|
230
239
|
)
|
|
231
240
|
|
|
232
|
-
def _add_relationship(
|
|
241
|
+
def _add_relationship(
|
|
242
|
+
self,
|
|
243
|
+
parent: etree.Element,
|
|
244
|
+
relationship: Relationship,
|
|
245
|
+
properties: Mapping[str, str] | None = None,
|
|
246
|
+
definition_of: Mapping[str, str] | None = None,
|
|
247
|
+
) -> None:
|
|
233
248
|
"""
|
|
234
249
|
Add a relationship to the XML tree.
|
|
235
250
|
|
|
236
251
|
Args:
|
|
237
252
|
parent: Parent XML element
|
|
238
253
|
relationship: ArchiMate relationship to add
|
|
254
|
+
properties: The relationship's exported properties (key -> value)
|
|
255
|
+
definition_of: propertyDefinition identifier per key
|
|
239
256
|
"""
|
|
240
257
|
rel = etree.SubElement(
|
|
241
258
|
parent,
|
|
@@ -258,8 +275,15 @@ class ArchiMateXMLExporter:
|
|
|
258
275
|
doc_elem = etree.SubElement(rel, "documentation")
|
|
259
276
|
doc_elem.text = relationship.documentation
|
|
260
277
|
|
|
261
|
-
#
|
|
262
|
-
|
|
278
|
+
# Only the properties passed in are exported (each needs a model-level propertyDefinition), after name and documentation
|
|
279
|
+
shown = sorted((key, value) for key, value in (properties or {}).items() if value and key in (definition_of or {}))
|
|
280
|
+
if shown and definition_of:
|
|
281
|
+
props = etree.SubElement(rel, "properties")
|
|
282
|
+
for key, value in shown:
|
|
283
|
+
prop = etree.SubElement(props, "property", attrib={"propertyDefinitionRef": definition_of[key]})
|
|
284
|
+
value_elem = etree.SubElement(prop, "value")
|
|
285
|
+
value_elem.set(f"{{{self.XML_NS}}}lang", "en")
|
|
286
|
+
value_elem.text = str(value)
|
|
263
287
|
|
|
264
288
|
def export_to_string(
|
|
265
289
|
self,
|
|
@@ -30,6 +30,7 @@ from .db_tool import export_all as export_database
|
|
|
30
30
|
from .db_tool import import_all as import_database
|
|
31
31
|
from .manager import (
|
|
32
32
|
DB_PATH,
|
|
33
|
+
ConfigDatabaseBusy,
|
|
33
34
|
ensure_database,
|
|
34
35
|
get_connection,
|
|
35
36
|
init_database,
|
|
@@ -43,6 +44,7 @@ FUNCTION_MODELS_DIR = DATA_DIR / "function_models"
|
|
|
43
44
|
|
|
44
45
|
__all__ = [
|
|
45
46
|
"FUNCTION_MODELS_DIR",
|
|
47
|
+
"ConfigDatabaseBusy",
|
|
46
48
|
"ensure_database",
|
|
47
49
|
"get_connection",
|
|
48
50
|
"init_database",
|
|
@@ -28,6 +28,14 @@ SCRIPTS_DIR = Path(__file__).parent / "scripts"
|
|
|
28
28
|
DATA_DIR = Path(__file__).parent / "data"
|
|
29
29
|
|
|
30
30
|
|
|
31
|
+
# How DuckDB reports a database file another process holds (Windows; Linux and macOS)
|
|
32
|
+
_LOCK_MESSAGES = ("being used by another process", "Could not set lock", "Conflicting lock")
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class ConfigDatabaseBusy(RuntimeError):
|
|
36
|
+
"""The config database is open in another process (DuckDB allows one writer)."""
|
|
37
|
+
|
|
38
|
+
|
|
31
39
|
def get_connection(read_only: bool = False) -> duckdb.DuckDBPyConnection:
|
|
32
40
|
"""Get a connection to the database.
|
|
33
41
|
|
|
@@ -37,11 +45,21 @@ def get_connection(read_only: bool = False) -> duckdb.DuckDBPyConnection:
|
|
|
37
45
|
|
|
38
46
|
Returns:
|
|
39
47
|
DuckDB connection
|
|
48
|
+
|
|
49
|
+
Raises:
|
|
50
|
+
ConfigDatabaseBusy: Another process (the studio, another CLI run) holds the database
|
|
40
51
|
"""
|
|
41
52
|
# A fresh install has no database yet: create it from the schema and the shipped seed data
|
|
42
53
|
if not DB_PATH.exists():
|
|
43
54
|
ensure_database(DB_PATH)
|
|
44
|
-
|
|
55
|
+
try:
|
|
56
|
+
return duckdb.connect(str(DB_PATH), read_only=read_only)
|
|
57
|
+
except duckdb.IOException as e:
|
|
58
|
+
if any(message in str(e) for message in _LOCK_MESSAGES):
|
|
59
|
+
raise ConfigDatabaseBusy(
|
|
60
|
+
f"The config database {DB_PATH} is open in another Deriva process (the studio or another deriva-cli run). Close it, or wait for it to finish, then try again."
|
|
61
|
+
) from e
|
|
62
|
+
raise
|
|
45
63
|
|
|
46
64
|
|
|
47
65
|
def run_sql_file(filepath: Path, conn: duckdb.DuckDBPyConnection | None = None) -> int:
|
|
@@ -36,6 +36,7 @@ from deriva.common.ocel import create_edge_id
|
|
|
36
36
|
from deriva.common.settings import GraphSettings
|
|
37
37
|
|
|
38
38
|
from .models import (
|
|
39
|
+
BuildModuleNode,
|
|
39
40
|
BusinessConceptNode,
|
|
40
41
|
DataDomainNode,
|
|
41
42
|
DataEntityNode,
|
|
@@ -72,6 +73,7 @@ GraphNode = (
|
|
|
72
73
|
| ServiceNode
|
|
73
74
|
| ExternalDependencyNode
|
|
74
75
|
| DeployableUnitNode
|
|
76
|
+
| BuildModuleNode
|
|
75
77
|
| DataEntityNode
|
|
76
78
|
| DataDomainNode
|
|
77
79
|
| EnvironmentNode
|
|
@@ -506,6 +506,45 @@ class ExternalDependencyNode:
|
|
|
506
506
|
}
|
|
507
507
|
|
|
508
508
|
|
|
509
|
+
@dataclass
|
|
510
|
+
class BuildModuleNode:
|
|
511
|
+
"""A build module (a folder with a build manifest and code of its own) or a parent system (an aggregator manifest
|
|
512
|
+
that lists modules). Its own files hang below it by ``INCLUDES``, nested modules by ``NESTS``; a deployable unit
|
|
513
|
+
``BUILDS`` the modules in its folder."""
|
|
514
|
+
|
|
515
|
+
name: str
|
|
516
|
+
path: str
|
|
517
|
+
manifest: str
|
|
518
|
+
repository_name: str
|
|
519
|
+
is_module: bool = False
|
|
520
|
+
is_system: bool = False
|
|
521
|
+
members: list[str] = field(default_factory=list) # For a system: the module paths its manifest lists
|
|
522
|
+
same_as: str | None = None # The unit whose folder it is (one unit there, no module inside): one element with it
|
|
523
|
+
excluded: str | None = None # Why it is no application component (infrastructure-as-code, test-only)
|
|
524
|
+
|
|
525
|
+
def generate_id(self) -> str:
|
|
526
|
+
"""Generate a unique ID for this node."""
|
|
527
|
+
return f"BuildModule_{self.path}"
|
|
528
|
+
|
|
529
|
+
def to_dict(self) -> dict:
|
|
530
|
+
"""Convert to dictionary for graph storage."""
|
|
531
|
+
return {
|
|
532
|
+
"name": self.name,
|
|
533
|
+
"path": self.path,
|
|
534
|
+
"manifest": self.manifest,
|
|
535
|
+
"isModule": self.is_module,
|
|
536
|
+
"isSystem": self.is_system,
|
|
537
|
+
"members": list(self.members),
|
|
538
|
+
"sameAs": self.same_as,
|
|
539
|
+
"excluded": self.excluded,
|
|
540
|
+
# Its structural name as the one candidate of the closed-set naming (no naming call)
|
|
541
|
+
"nameCandidates": [self.name],
|
|
542
|
+
# Module ids carry no prefix the graph manager reads the repository from
|
|
543
|
+
"repository_name": self.repository_name,
|
|
544
|
+
"type": "BuildModule",
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
|
|
509
548
|
@dataclass
|
|
510
549
|
class DeployableUnitNode:
|
|
511
550
|
"""A deployable unit: what runs on its own (a container, a declared entry point, a mainframe application).
|
|
@@ -37,6 +37,7 @@ from typing import Any
|
|
|
37
37
|
import yaml
|
|
38
38
|
|
|
39
39
|
from deriva.common.paths import resolve
|
|
40
|
+
from deriva.common.settings import RepositorySettings
|
|
40
41
|
|
|
41
42
|
from .models import (
|
|
42
43
|
CloneError,
|
|
@@ -494,22 +495,6 @@ def _extract_file_structure(repo_path: Path) -> FileNode:
|
|
|
494
495
|
# =============================================================================
|
|
495
496
|
|
|
496
497
|
|
|
497
|
-
def _load_config() -> dict:
|
|
498
|
-
"""Load configuration from config.yaml file."""
|
|
499
|
-
config_path = Path(__file__).parent / "config.yaml"
|
|
500
|
-
default_config = {"workspace_dir": "workspace/repositories"}
|
|
501
|
-
|
|
502
|
-
if not config_path.exists():
|
|
503
|
-
return default_config
|
|
504
|
-
|
|
505
|
-
try:
|
|
506
|
-
with open(config_path) as f:
|
|
507
|
-
config = yaml.safe_load(f) or {}
|
|
508
|
-
return {**default_config, **config}
|
|
509
|
-
except Exception:
|
|
510
|
-
return default_config
|
|
511
|
-
|
|
512
|
-
|
|
513
498
|
# =============================================================================
|
|
514
499
|
# Repository Manager
|
|
515
500
|
# =============================================================================
|
|
@@ -535,12 +520,12 @@ class RepoManager:
|
|
|
535
520
|
"""Initialize the Repository Manager.
|
|
536
521
|
|
|
537
522
|
Args:
|
|
538
|
-
workspace_dir: Directory where repositories will be stored.
|
|
539
|
-
|
|
523
|
+
workspace_dir: Directory where repositories will be stored. Defaults to the
|
|
524
|
+
REPOSITORY_WORKSPACE_DIR setting (workspace/repositories), relative
|
|
525
|
+
to the Deriva home folder, the same folder the session lists.
|
|
540
526
|
"""
|
|
541
527
|
if workspace_dir is None:
|
|
542
|
-
|
|
543
|
-
workspace_dir = config.get("workspace_dir", "workspace/repositories")
|
|
528
|
+
workspace_dir = RepositorySettings().workspace_dir
|
|
544
529
|
|
|
545
530
|
ws_path = Path(workspace_dir)
|
|
546
531
|
if not ws_path.is_absolute():
|
|
@@ -37,7 +37,7 @@ from deriva.cli.commands.run import (
|
|
|
37
37
|
_print_pipeline_result,
|
|
38
38
|
)
|
|
39
39
|
from deriva.cli.progress import create_progress_reporter
|
|
40
|
-
from deriva.services import about, derivation
|
|
40
|
+
from deriva.services import ConfigDatabaseBusy, about, derivation
|
|
41
41
|
from deriva.services.session import PipelineSession
|
|
42
42
|
|
|
43
43
|
# Create main app
|
|
@@ -371,6 +371,10 @@ def main() -> int:
|
|
|
371
371
|
return 0
|
|
372
372
|
except SystemExit as e:
|
|
373
373
|
return e.code if isinstance(e.code, int) else 1
|
|
374
|
+
except ConfigDatabaseBusy as e:
|
|
375
|
+
# The studio or another run holds the config database: say so in one line, without a traceback
|
|
376
|
+
typer.echo(f"Error: {e}", err=True)
|
|
377
|
+
return 1
|
|
374
378
|
|
|
375
379
|
|
|
376
380
|
if __name__ == "__main__":
|
|
@@ -233,11 +233,18 @@ def config_update(
|
|
|
233
233
|
int | None,
|
|
234
234
|
typer.Option("--max-candidates", help="Maximum candidates for derivation"),
|
|
235
235
|
] = None,
|
|
236
|
+
sequence: Annotated[
|
|
237
|
+
int | None,
|
|
238
|
+
typer.Option("--sequence", min=0, help="New place in its phase (derivation only)"),
|
|
239
|
+
] = None,
|
|
236
240
|
) -> None:
|
|
237
241
|
"""Update a configuration with versioning."""
|
|
238
242
|
if step_type not in ("extraction", "derivation"):
|
|
239
243
|
typer.echo("Error: step_type must be 'extraction' or 'derivation'", err=True)
|
|
240
244
|
raise typer.Exit(1)
|
|
245
|
+
if sequence is not None and step_type != "derivation":
|
|
246
|
+
typer.echo("Error: --sequence moves derivation steps only", err=True)
|
|
247
|
+
raise typer.Exit(1)
|
|
241
248
|
|
|
242
249
|
# Read instruction from file if provided
|
|
243
250
|
if instruction_file:
|
|
@@ -286,6 +293,7 @@ def config_update(
|
|
|
286
293
|
batch_size=batch_size,
|
|
287
294
|
max_candidates=max_candidates,
|
|
288
295
|
temperature=temperature,
|
|
296
|
+
sequence=sequence,
|
|
289
297
|
)
|
|
290
298
|
elif step_type == "extraction":
|
|
291
299
|
result = config.create_extraction_config_version(
|
|
@@ -307,6 +315,8 @@ def config_update(
|
|
|
307
315
|
typer.echo(f" Version: {result['old_version']} -> {result['new_version']}")
|
|
308
316
|
if params:
|
|
309
317
|
typer.echo(" Params: updated")
|
|
318
|
+
if sequence is not None:
|
|
319
|
+
typer.echo(f" Sequence: {sequence}")
|
|
310
320
|
else:
|
|
311
321
|
typer.echo(f"Error: {result.get('error', 'Unknown error')}", err=True)
|
|
312
322
|
raise typer.Exit(1)
|
|
@@ -330,7 +340,8 @@ def config_sequence(
|
|
|
330
340
|
"""Update the execution sequence of derivation steps.
|
|
331
341
|
|
|
332
342
|
Reorders steps based on the provided order list. Each step's sequence
|
|
333
|
-
number is set to its position in the list (1-indexed)
|
|
343
|
+
number is set to its position in the list (1-indexed); a step that moves
|
|
344
|
+
gets a new config version, so every reorder is recorded.
|
|
334
345
|
|
|
335
346
|
Example (ArchiMate bottom-up: Technology -> Application -> Business):
|
|
336
347
|
|
|
@@ -56,7 +56,7 @@ def repo_list(
|
|
|
56
56
|
typer.echo("\nNo repositories found.")
|
|
57
57
|
typer.echo(f"Workspace: {session.workspace_dir}")
|
|
58
58
|
typer.echo("\nClone a repository with:")
|
|
59
|
-
typer.echo(" deriva repo clone <url>")
|
|
59
|
+
typer.echo(" deriva-cli repo clone <url>")
|
|
60
60
|
return
|
|
61
61
|
|
|
62
62
|
typer.echo(f"\n{'=' * 60}")
|
|
@@ -102,6 +102,10 @@ def _print_pipeline_result(result: dict) -> None:
|
|
|
102
102
|
|
|
103
103
|
if result.get("errors"):
|
|
104
104
|
typer.echo(f"\nTotal errors: {len(result['errors'])}")
|
|
105
|
+
for err in result["errors"][:10]:
|
|
106
|
+
typer.echo(f" - {err}")
|
|
107
|
+
if len(result["errors"]) > 10:
|
|
108
|
+
typer.echo(f" ... and {len(result['errors']) - 10} more")
|
|
105
109
|
|
|
106
110
|
|
|
107
111
|
@app.callback(invoke_without_command=True)
|
|
@@ -334,17 +334,29 @@ def parse_exchange_format_xml(
|
|
|
334
334
|
# The level property's definition, if the file declares one
|
|
335
335
|
level_refs = {d.get("identifier") for d in root.iterfind(f"{_tag('propertyDefinitions')}/{_tag('propertyDefinition')}") if d.findtext(_tag("name")) == "level"}
|
|
336
336
|
|
|
337
|
-
def
|
|
337
|
+
def _levels_of(elem: ET.Element) -> set[str]:
|
|
338
|
+
"""The element's levels: a set written as one value; "architect" (earlier exports) is enterprise; none: enterprise."""
|
|
338
339
|
for prop in elem.iterfind(f"{_tag('properties')}/{_tag('property')}"):
|
|
339
340
|
if prop.get("propertyDefinitionRef") in level_refs:
|
|
340
|
-
|
|
341
|
-
|
|
341
|
+
text: str = prop.findtext(_tag("value")) or ""
|
|
342
|
+
values = set(text.split())
|
|
343
|
+
if not values:
|
|
344
|
+
values = {"enterprise"}
|
|
345
|
+
if "architect" in values:
|
|
346
|
+
values = (values - {"architect"}) | {"enterprise"}
|
|
347
|
+
return {str(v) for v in values}
|
|
348
|
+
return {"enterprise"}
|
|
349
|
+
|
|
350
|
+
def _at_level(elem: ET.Element) -> bool:
|
|
351
|
+
levels = _levels_of(elem)
|
|
352
|
+
# "architect": every derived element (any level but detail)
|
|
353
|
+
return bool(levels - {"detail"}) if level == "architect" else level in levels
|
|
342
354
|
|
|
343
355
|
# Find elements section
|
|
344
356
|
elements_section = root.find(_tag("elements"))
|
|
345
357
|
if elements_section is not None:
|
|
346
358
|
for elem in elements_section:
|
|
347
|
-
if level is not None and
|
|
359
|
+
if level is not None and not _at_level(elem):
|
|
348
360
|
continue
|
|
349
361
|
elem_type = elem.get("{http://www.w3.org/2001/XMLSchema-instance}type", "")
|
|
350
362
|
elem_id = elem.get("identifier", "")
|
|
@@ -15,6 +15,7 @@ import json
|
|
|
15
15
|
import logging
|
|
16
16
|
import re
|
|
17
17
|
from collections import defaultdict
|
|
18
|
+
from collections.abc import Iterable
|
|
18
19
|
from dataclasses import dataclass, field
|
|
19
20
|
from typing import TYPE_CHECKING, Any, cast
|
|
20
21
|
|
|
@@ -2306,6 +2307,9 @@ class RoleConfig:
|
|
|
2306
2307
|
# element_per "unit" only: roles a deployable unit shows itself, (unit property, role key). A unit whose
|
|
2307
2308
|
# property lists files (such as webEntries) gets that role's element with those files as members, no call
|
|
2308
2309
|
unit_roles: tuple[tuple[str, str], ...] = ()
|
|
2310
|
+
# Graph labels in the order their candidates claim a structure name (two candidates with one structure name: the
|
|
2311
|
+
# earlier label keeps it, so a unit is never left out for a module beside it); empty: the step's ranking decides
|
|
2312
|
+
name_priority: tuple[str, ...] = ()
|
|
2309
2313
|
|
|
2310
2314
|
|
|
2311
2315
|
ROLE_SCHEMA: dict[str, Any] = {
|
|
@@ -2449,6 +2453,15 @@ def element_identifier(element_type: str, source_id: str) -> str:
|
|
|
2449
2453
|
return sanitize_identifier(f"{prefix}_{tail}")
|
|
2450
2454
|
|
|
2451
2455
|
|
|
2456
|
+
def candidate_identifier(element_type: str, source_id: str, sources: Iterable[str]) -> str:
|
|
2457
|
+
"""``element_identifier`` among the step's candidate sources: a module whose plain identifier is a unit's (the
|
|
2458
|
+
unit's folder, with modules inside) keeps its kind in it, so the unit keeps the plain one."""
|
|
2459
|
+
identifier = element_identifier(element_type, source_id)
|
|
2460
|
+
if source_id.startswith("module::") and any(s.startswith(UNIT_PREFIX) and element_identifier(element_type, s) == identifier for s in sources):
|
|
2461
|
+
return sanitize_identifier(f"{identifier.split('_', 1)[0]}_module::{source_id.split('::', 2)[2]}")
|
|
2462
|
+
return identifier
|
|
2463
|
+
|
|
2464
|
+
|
|
2452
2465
|
def build_element(
|
|
2453
2466
|
derived: dict[str, Any],
|
|
2454
2467
|
element_type: str,
|
|
@@ -2486,7 +2499,7 @@ def build_element(
|
|
|
2486
2499
|
if not name:
|
|
2487
2500
|
return {"success": False, "errors": [f"Empty name for source {source_id!r}"]}
|
|
2488
2501
|
|
|
2489
|
-
identifier =
|
|
2502
|
+
identifier = candidate_identifier(element_type, source_id, source_names)
|
|
2490
2503
|
# Clamp confidence to [0.0, 1.0] range (LLM may return out-of-range values)
|
|
2491
2504
|
confidence = clamp_confidence(derived.get("confidence"))
|
|
2492
2505
|
|
|
@@ -5,7 +5,7 @@ The architect level is the derived model. Its members, kept as lineage, become d
|
|
|
5
5
|
- a data domain (DataObject) composes its entities (DataObject);
|
|
6
6
|
- a channel interface (ApplicationInterface) composes its endpoint members (ApplicationInterface);
|
|
7
7
|
- the environment (Node) is assigned to an artifact per deployed container, which realizes the component of the
|
|
8
|
-
unit it deploys;
|
|
8
|
+
unit it deploys; where the deployment is a service node of its own, that node is assigned to the artifact;
|
|
9
9
|
- a mainframe unit (ApplicationComponent) composes its programs (ApplicationComponent);
|
|
10
10
|
- a lifecycle's states stay a property of its process (the hand-off states are already events).
|
|
11
11
|
|
|
@@ -46,6 +46,7 @@ def detail_level(elements: list[dict[str, Any]], lineage: DetailLineage) -> Deta
|
|
|
46
46
|
out = DetailLevel()
|
|
47
47
|
seen: set[str] = set()
|
|
48
48
|
component_of = {str((e.get("properties") or {}).get("source")): e["identifier"] for e in elements if e.get("element_type") == "ApplicationComponent"}
|
|
49
|
+
service_node = {str((e.get("properties") or {}).get("source")): e["identifier"] for e in elements if e.get("element_type") == "Node"}
|
|
49
50
|
|
|
50
51
|
def member(element_type: str, identity: str, name: str, parent: str, source: str) -> str:
|
|
51
52
|
identifier = element_identifier(element_type, f"detail::{identity}")
|
|
@@ -69,8 +70,9 @@ def detail_level(elements: list[dict[str, Any]], lineage: DetailLineage) -> Deta
|
|
|
69
70
|
out.relationships.append(_relationship("Composition", parent, child))
|
|
70
71
|
elif kind == "Node":
|
|
71
72
|
for deployment, name, unit in lineage.deployments.get(source, []):
|
|
72
|
-
|
|
73
|
-
|
|
73
|
+
holder = service_node.get(deployment, parent)
|
|
74
|
+
artifact = member("Artifact", deployment, name, holder, deployment)
|
|
75
|
+
out.relationships.append(_relationship("Assignment", holder, artifact))
|
|
74
76
|
if unit and unit in component_of:
|
|
75
77
|
out.relationships.append(_relationship("Realization", artifact, component_of[unit]))
|
|
76
78
|
elif kind == "ApplicationComponent":
|