sysmlpy 0.70.0__tar.gz → 0.72.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/PKG-INFO +1 -1
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/pyproject.toml +1 -1
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/__init__.py +1 -1
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/semantic.py +388 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/traceability.py +73 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/usage.py +7 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/LICENSE +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/README.md +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/__main__.py +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/antlr/README.md +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/antlr/SysMLv2Lexer.interp +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/antlr/SysMLv2Lexer.py +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/antlr/SysMLv2Lexer.tokens +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/antlr/SysMLv2Parser.interp +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/antlr/SysMLv2Parser.py +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/antlr/SysMLv2Parser.tokens +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/antlr/SysMLv2ParserListener.py +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/antlr/SysMLv2ParserVisitor.py +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/antlr/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.interp +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/antlr/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.py +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/antlr/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.tokens +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/antlr_parser.py +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/antlr_visitor.py +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/boxes_view.py +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/definition.py +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/evaluator.py +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/examples/attribute_values.py +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/examples/part_attributes.py +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/examples/tuples_sequences.py +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/formatting.py +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/grammar/antlr4/README.md +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.g4 +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.interp +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.py +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.tokens +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/grammar/antlr4/SysMLv2Parser.g4 +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/grammar/antlr4/SysMLv2Parser.interp +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/grammar/antlr4/SysMLv2Parser.py +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/grammar/antlr4/SysMLv2Parser.tokens +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/grammar/antlr4/SysMLv2ParserListener.py +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/grammar/antlr4/SysMLv2ParserVisitor.py +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/grammar/antlr4/desc.xml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/grammar/antlr4/examples/camera.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/grammar/antlr4/examples/toaster-system.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/grammar/antlr4/examples/vehicle-model.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/grammar/antlr4/pom.xml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/grammar/classes.py +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/interchange.py +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/LICENSE +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/README.md +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/__init__.py +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/domain/Analysis/AnalysisTooling.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/domain/Analysis/SampledFunctions.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/domain/Analysis/StateSpaceRepresentation.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/domain/Analysis/TradeStudies.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/domain/Cause and Effect/CausationConnections.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/domain/Cause and Effect/CauseAndEffect.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/domain/Geometry/ShapeItems.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/domain/Geometry/SpatialItems.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/domain/Metadata/ImageMetadata.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/domain/Metadata/ModelingMetadata.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/domain/Metadata/ParametersOfInterestMetadata.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/domain/Metadata/RiskMetadata.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/domain/Quantities and Units/ISQ.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/domain/Quantities and Units/ISQAcoustics.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/domain/Quantities and Units/ISQAtomicNuclear.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/domain/Quantities and Units/ISQBase.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/domain/Quantities and Units/ISQCharacteristicNumbers.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/domain/Quantities and Units/ISQChemistryMolecular.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/domain/Quantities and Units/ISQCondensedMatter.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/domain/Quantities and Units/ISQElectromagnetism.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/domain/Quantities and Units/ISQInformation.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/domain/Quantities and Units/ISQLight.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/domain/Quantities and Units/ISQMechanics.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/domain/Quantities and Units/ISQSpaceTime.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/domain/Quantities and Units/ISQThermodynamics.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/domain/Quantities and Units/MeasurementRefCalculations.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/domain/Quantities and Units/MeasurementReferences.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/domain/Quantities and Units/Quantities.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/domain/Quantities and Units/QuantityCalculations.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/domain/Quantities and Units/SI.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/domain/Quantities and Units/SIPrefixes.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/domain/Quantities and Units/TensorCalculations.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/domain/Quantities and Units/Time.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/domain/Quantities and Units/USCustomaryUnits.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/domain/Quantities and Units/VectorCalculations.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/domain/Requirement Derivation/DerivationConnections.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/domain/Requirement Derivation/RequirementDerivation.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/kernel/Base.kerml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/kernel/BaseFunctions.kerml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/kernel/BooleanFunctions.kerml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/kernel/Clocks.kerml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/kernel/CollectionFunctions.kerml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/kernel/Collections.kerml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/kernel/ComplexFunctions.kerml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/kernel/ControlFunctions.kerml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/kernel/ControlPerformances.kerml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/kernel/DataFunctions.kerml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/kernel/FeatureReferencingPerformances.kerml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/kernel/IntegerFunctions.kerml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/kernel/KerML.kerml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/kernel/Links.kerml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/kernel/Metaobjects.kerml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/kernel/NaturalFunctions.kerml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/kernel/NumericalFunctions.kerml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/kernel/Objects.kerml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/kernel/Observation.kerml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/kernel/OccurrenceFunctions.kerml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/kernel/Occurrences.kerml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/kernel/Performances.kerml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/kernel/RationalFunctions.kerml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/kernel/RealFunctions.kerml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/kernel/ScalarFunctions.kerml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/kernel/ScalarValues.kerml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/kernel/SequenceFunctions.kerml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/kernel/SpatialFrames.kerml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/kernel/StatePerformances.kerml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/kernel/StringFunctions.kerml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/kernel/Transfers.kerml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/kernel/TransitionPerformances.kerml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/kernel/TrigFunctions.kerml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/kernel/Triggers.kerml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/kernel/VectorFunctions.kerml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/kernel/VectorValues.kerml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/systems/Actions.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/systems/Allocations.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/systems/AnalysisCases.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/systems/Attributes.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/systems/Calculations.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/systems/Cases.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/systems/Connections.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/systems/Constraints.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/systems/Flows.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/systems/Interfaces.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/systems/Items.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/systems/Metadata.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/systems/Parts.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/systems/Ports.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/systems/Requirements.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/systems/StandardViewDefinitions.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/systems/States.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/systems/SysML.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/systems/UseCases.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/systems/VerificationCases.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/systems/Views.sysml +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/lsp/__init__.py +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/lsp/__main__.py +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/lsp/protocol.py +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/lsp/server.py +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/lsp/stdio.py +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/navigate.py +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/plantuml.py +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/project.py +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/sim.py +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/spreadsheet.py +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/store.py +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/us_customary_units.txt +0 -0
- {sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/validator.py +0 -0
|
@@ -34,7 +34,7 @@ __all__ = [
|
|
|
34
34
|
"render_state_transition_view_svg", "boxes_view",
|
|
35
35
|
]
|
|
36
36
|
__author__ = "Jon Fox"
|
|
37
|
-
__version__ = "0.
|
|
37
|
+
__version__ = "0.72.0"
|
|
38
38
|
|
|
39
39
|
from sysmlpy.usage import (
|
|
40
40
|
Item, Attribute, Part, Port, Action, Reference, UseCase, Requirement, Interface, Message,
|
|
@@ -1236,6 +1236,139 @@ class ExpressionIdentifierCollector:
|
|
|
1236
1236
|
self._walk(child, results, child_scope)
|
|
1237
1237
|
|
|
1238
1238
|
|
|
1239
|
+
def _satisfy_by_ref(satisfy_dict: dict):
|
|
1240
|
+
"""The ``by <part>`` reference of a SatisfyRequirementUsage dict.
|
|
1241
|
+
|
|
1242
|
+
Shape: ``ssm`` = SatisfactionSubjectMember → SatisfactionParameter
|
|
1243
|
+
→ … → FeatureChainMember.memberElement (QualifiedName) whose last
|
|
1244
|
+
segment is the satisfying feature. ``ors.referencedFeature.names``
|
|
1245
|
+
carries the target requirement reference.
|
|
1246
|
+
"""
|
|
1247
|
+
ssm = satisfy_dict.get("ssm")
|
|
1248
|
+
if not isinstance(ssm, dict):
|
|
1249
|
+
return None
|
|
1250
|
+
members = _find_named_dicts(ssm, "FeatureChainMember")
|
|
1251
|
+
for m in members:
|
|
1252
|
+
me = m.get("memberElement") or {}
|
|
1253
|
+
names = me.get("names")
|
|
1254
|
+
if isinstance(names, list) and names:
|
|
1255
|
+
return "::".join(str(n) for n in names)
|
|
1256
|
+
return None
|
|
1257
|
+
|
|
1258
|
+
|
|
1259
|
+
def _find_named_dicts(node: Any, name: str) -> list:
|
|
1260
|
+
"""Locate every dict with ``dict["name"] == name`` in a tree."""
|
|
1261
|
+
out: list = []
|
|
1262
|
+
|
|
1263
|
+
def walk(n: Any) -> None:
|
|
1264
|
+
if isinstance(n, dict):
|
|
1265
|
+
if n.get("name") == name:
|
|
1266
|
+
out.append(n)
|
|
1267
|
+
for v in n.values():
|
|
1268
|
+
if isinstance(v, (dict, list)):
|
|
1269
|
+
walk(v)
|
|
1270
|
+
elif isinstance(n, list):
|
|
1271
|
+
for item in n:
|
|
1272
|
+
if isinstance(item, (dict, list)):
|
|
1273
|
+
walk(item)
|
|
1274
|
+
|
|
1275
|
+
walk(node)
|
|
1276
|
+
return out
|
|
1277
|
+
|
|
1278
|
+
|
|
1279
|
+
def _as_list_dicts(v: Any) -> list:
|
|
1280
|
+
"""Normalize an optional-dict-or-list relationship field to a list."""
|
|
1281
|
+
if isinstance(v, list):
|
|
1282
|
+
return [x for x in v if isinstance(x, dict)]
|
|
1283
|
+
if isinstance(v, dict):
|
|
1284
|
+
return [v]
|
|
1285
|
+
return []
|
|
1286
|
+
|
|
1287
|
+
|
|
1288
|
+
def _find_declared_name(d: dict):
|
|
1289
|
+
"""Bounded search for ``identification.declaredName`` in a usage/
|
|
1290
|
+
definition dict (the identification nesting varies by shape)."""
|
|
1291
|
+
frontier = [d]
|
|
1292
|
+
for _ in range(4):
|
|
1293
|
+
nxt = []
|
|
1294
|
+
for n in frontier:
|
|
1295
|
+
if not isinstance(n, dict):
|
|
1296
|
+
continue
|
|
1297
|
+
ident = n.get("identification")
|
|
1298
|
+
if isinstance(ident, dict):
|
|
1299
|
+
name = ident.get("declaredName")
|
|
1300
|
+
if name:
|
|
1301
|
+
return name
|
|
1302
|
+
for v in n.values():
|
|
1303
|
+
if isinstance(v, dict):
|
|
1304
|
+
nxt.append(v)
|
|
1305
|
+
elif isinstance(v, list):
|
|
1306
|
+
nxt.extend(x for x in v if isinstance(x, dict))
|
|
1307
|
+
frontier = nxt
|
|
1308
|
+
return None
|
|
1309
|
+
|
|
1310
|
+
|
|
1311
|
+
def _port_direction(port_usage: dict):
|
|
1312
|
+
"""The explicit direction keyword on a PortUsage dict, if any.
|
|
1313
|
+
|
|
1314
|
+
The prefix chain is
|
|
1315
|
+
``OccurrenceUsagePrefix → BasicUsagePrefix → RefPrefix.direction``
|
|
1316
|
+
where ``direction`` is ``{"in": ..., "out": ..., "inout": ...}`` —
|
|
1317
|
+
the present keyword is the non-empty string value.
|
|
1318
|
+
"""
|
|
1319
|
+
pre = port_usage.get("prefix")
|
|
1320
|
+
while isinstance(pre, dict):
|
|
1321
|
+
d = pre.get("direction")
|
|
1322
|
+
if isinstance(d, dict):
|
|
1323
|
+
for k in ("in", "out", "inout"):
|
|
1324
|
+
v = d.get(k)
|
|
1325
|
+
if isinstance(v, str) and v.strip():
|
|
1326
|
+
return k
|
|
1327
|
+
return None
|
|
1328
|
+
pre = pre.get("prefix")
|
|
1329
|
+
return None
|
|
1330
|
+
|
|
1331
|
+
|
|
1332
|
+
def _connector_end_chain(end: dict) -> list:
|
|
1333
|
+
"""Feature-chain segment names of a ConnectorEnd dict."""
|
|
1334
|
+
ors = end.get("ownedRelationship") if isinstance(end, dict) else None
|
|
1335
|
+
for rel in _as_list_dicts(ors):
|
|
1336
|
+
if rel.get("name") != "OwnedReferenceSubsetting":
|
|
1337
|
+
continue
|
|
1338
|
+
ofc_list = _as_list_dicts(rel.get("ownedRelatedElement"))
|
|
1339
|
+
ofc = ofc_list[0] if ofc_list else {}
|
|
1340
|
+
if ofc.get("name") != "OwnedFeatureChain":
|
|
1341
|
+
continue
|
|
1342
|
+
feat = ofc.get("feature") or {}
|
|
1343
|
+
names = []
|
|
1344
|
+
for chain_rel in _as_list_dicts(feat.get("ownedRelationship")):
|
|
1345
|
+
if chain_rel.get("name") != "OwnedFeatureChaining":
|
|
1346
|
+
continue
|
|
1347
|
+
cf = chain_rel.get("chainingFeature") or {}
|
|
1348
|
+
qn = cf.get("names")
|
|
1349
|
+
if isinstance(qn, list) and qn:
|
|
1350
|
+
names.append(str(qn[-1]))
|
|
1351
|
+
return names
|
|
1352
|
+
return []
|
|
1353
|
+
|
|
1354
|
+
|
|
1355
|
+
def _usage_typed_by(usage: dict):
|
|
1356
|
+
"""The last segment of a usage dict's OwnedFeatureTyping, if any.
|
|
1357
|
+
|
|
1358
|
+
The typing rides the declaration/specialization chain, which
|
|
1359
|
+
precedes the body in dict order, so a usage's own typing is found
|
|
1360
|
+
before any nested member's typing.
|
|
1361
|
+
"""
|
|
1362
|
+
for rel in _find_named_dicts(usage, "OwnedFeatureTyping"):
|
|
1363
|
+
ft = rel.get("type") or {}
|
|
1364
|
+
qn = ft.get("type") if isinstance(ft, dict) else None
|
|
1365
|
+
if isinstance(qn, dict):
|
|
1366
|
+
names = qn.get("names")
|
|
1367
|
+
if isinstance(names, list) and names:
|
|
1368
|
+
return str(names[-1])
|
|
1369
|
+
return None
|
|
1370
|
+
|
|
1371
|
+
|
|
1239
1372
|
def _find_payload_parameters(node: Any) -> list:
|
|
1240
1373
|
"""Locate every ``PayloadParameter`` dict in a grammar tree."""
|
|
1241
1374
|
out: list = []
|
|
@@ -2381,6 +2514,9 @@ class SemanticAnalyzer:
|
|
|
2381
2514
|
issues.extend(self._check_trigger_payloads(model, symtab, lib_roots))
|
|
2382
2515
|
issues.extend(self._check_requirement_coverage(model))
|
|
2383
2516
|
issues.extend(self._check_trace_targets(model, symtab, lib_roots))
|
|
2517
|
+
issues.extend(self._check_verify_targets(model, symtab, lib_roots))
|
|
2518
|
+
issues.extend(self._check_satisfy_parts(model, symtab, lib_roots))
|
|
2519
|
+
issues.extend(self._check_connector_directions(model))
|
|
2384
2520
|
|
|
2385
2521
|
# Step 6: Stylistic checks (warnings, not errors)
|
|
2386
2522
|
if style_checks:
|
|
@@ -3179,6 +3315,258 @@ class SemanticAnalyzer:
|
|
|
3179
3315
|
return table.lookup(parts[-1])
|
|
3180
3316
|
return None
|
|
3181
3317
|
|
|
3318
|
+
def _check_satisfy_parts(
|
|
3319
|
+
self,
|
|
3320
|
+
model: Any,
|
|
3321
|
+
symtab: "SymbolTable",
|
|
3322
|
+
lib_roots: list,
|
|
3323
|
+
) -> list[SemanticIssue]:
|
|
3324
|
+
"""Resolve ``satisfy <req> by <part>`` subjects (Goal 9).
|
|
3325
|
+
|
|
3326
|
+
The ``by`` reference names the satisfying part; both
|
|
3327
|
+
package-level satisfies (grammar ``SatisfyRequirementUsage``
|
|
3328
|
+
wrappers yielded by ``_walk_usages``) and satisfies nested
|
|
3329
|
+
inside requirement bodies (extracted from the requirement's
|
|
3330
|
+
grammar dict — the visitor surfaces nested verify members but
|
|
3331
|
+
not satisfy members) are checked. An unresolved by-part is a
|
|
3332
|
+
UNRESOLVED_SATISFY_PART error.
|
|
3333
|
+
"""
|
|
3334
|
+
issues: list[SemanticIssue] = []
|
|
3335
|
+
|
|
3336
|
+
def issue(obj, ref):
|
|
3337
|
+
issues.append(SemanticIssue(
|
|
3338
|
+
severity="error",
|
|
3339
|
+
code="UNRESOLVED_SATISFY_PART",
|
|
3340
|
+
message=(
|
|
3341
|
+
f"satisfy 'by {ref}' does not resolve to a "
|
|
3342
|
+
"defined part"),
|
|
3343
|
+
element=obj,
|
|
3344
|
+
reference=ref,
|
|
3345
|
+
))
|
|
3346
|
+
|
|
3347
|
+
for element, scope_path in self._walk_usages(model):
|
|
3348
|
+
gname = (element.grammar.__class__.__name__
|
|
3349
|
+
if getattr(element, "grammar", None) is not None else "")
|
|
3350
|
+
if gname == "SatisfyRequirementUsage":
|
|
3351
|
+
# package-level wrapper; .ssm dump is the by reference
|
|
3352
|
+
g = element.grammar
|
|
3353
|
+
ssm = getattr(g, "ssm", None)
|
|
3354
|
+
if ssm is None:
|
|
3355
|
+
continue
|
|
3356
|
+
ref = ssm.dump().strip().rstrip(";").strip()
|
|
3357
|
+
if not ref:
|
|
3358
|
+
continue
|
|
3359
|
+
if not self._is_resolved(ref, symtab, scope_path, lib_roots):
|
|
3360
|
+
issue(element, ref)
|
|
3361
|
+
continue
|
|
3362
|
+
if gname not in ("RequirementDefinition", "RequirementUsage"):
|
|
3363
|
+
continue
|
|
3364
|
+
# nested satisfy members: scan the requirement's grammar dict
|
|
3365
|
+
grammar = element.grammar
|
|
3366
|
+
if grammar is None:
|
|
3367
|
+
continue
|
|
3368
|
+
try:
|
|
3369
|
+
grammar_def = grammar.get_definition()
|
|
3370
|
+
except Exception:
|
|
3371
|
+
continue
|
|
3372
|
+
if not isinstance(grammar_def, dict):
|
|
3373
|
+
continue
|
|
3374
|
+
for sat in _find_named_dicts(
|
|
3375
|
+
grammar_def, "SatisfyRequirementUsage"):
|
|
3376
|
+
by_ref = _satisfy_by_ref(sat)
|
|
3377
|
+
if not by_ref:
|
|
3378
|
+
continue
|
|
3379
|
+
if not self._is_resolved(
|
|
3380
|
+
by_ref, symtab, scope_path, lib_roots):
|
|
3381
|
+
issue(element, by_ref)
|
|
3382
|
+
return issues
|
|
3383
|
+
|
|
3384
|
+
def _check_verify_targets(
|
|
3385
|
+
self,
|
|
3386
|
+
model: Any,
|
|
3387
|
+
symtab: "SymbolTable",
|
|
3388
|
+
lib_roots: list,
|
|
3389
|
+
) -> list[SemanticIssue]:
|
|
3390
|
+
"""Resolve ``verify <vc>`` members inside requirements (Goal 9).
|
|
3391
|
+
|
|
3392
|
+
``verify v1 : VC;`` in a requirement body parses as a
|
|
3393
|
+
VerifyRequirementUsage whose ``ors`` holds the referenced
|
|
3394
|
+
verification-case name. Notably the visitor drops the
|
|
3395
|
+
``: VC`` typing specialization entirely (``fsp`` is empty), so
|
|
3396
|
+
a typo'd verification-case *type* is invisible — but the
|
|
3397
|
+
member name reference is checkable: resolve it against the
|
|
3398
|
+
symbol table in the requirement's scope. Unresolved targets
|
|
3399
|
+
produce UNRESOLVED_VERIFY_TARGET errors (same contract as
|
|
3400
|
+
UNRESOLVED_TRACE_TARGET for satisfy).
|
|
3401
|
+
"""
|
|
3402
|
+
issues: list[SemanticIssue] = []
|
|
3403
|
+
for element, scope_path in self._walk_usages(model):
|
|
3404
|
+
# verify members live inside Requirement grammar trees
|
|
3405
|
+
# (no VerifyRequirementUsage object of their own)
|
|
3406
|
+
if type(element).__name__ != "Requirement":
|
|
3407
|
+
continue
|
|
3408
|
+
grammar = getattr(element, "grammar", None)
|
|
3409
|
+
if grammar is None:
|
|
3410
|
+
continue
|
|
3411
|
+
try:
|
|
3412
|
+
grammar_def = grammar.get_definition()
|
|
3413
|
+
except Exception:
|
|
3414
|
+
continue
|
|
3415
|
+
if not isinstance(grammar_def, dict):
|
|
3416
|
+
continue
|
|
3417
|
+
for vr in _find_named_dicts(grammar_def, "VerifyRequirementUsage"):
|
|
3418
|
+
ors = vr.get("ors")
|
|
3419
|
+
if not isinstance(ors, dict):
|
|
3420
|
+
continue
|
|
3421
|
+
rf = ors.get("referencedFeature") or {}
|
|
3422
|
+
# referencedFeature *is* the QualifiedName node here
|
|
3423
|
+
names = rf.get("names") if isinstance(rf, dict) else None
|
|
3424
|
+
if not names:
|
|
3425
|
+
continue
|
|
3426
|
+
ref = "::".join(str(n) for n in names)
|
|
3427
|
+
if self._is_resolved(ref, symtab, scope_path, lib_roots):
|
|
3428
|
+
continue
|
|
3429
|
+
issues.append(SemanticIssue(
|
|
3430
|
+
severity="error",
|
|
3431
|
+
code="UNRESOLVED_VERIFY_TARGET",
|
|
3432
|
+
message=(
|
|
3433
|
+
f"verify target '{ref}' in requirement "
|
|
3434
|
+
f"'{getattr(element, 'name', '<anonymous>')}' "
|
|
3435
|
+
"does not resolve to a defined element"),
|
|
3436
|
+
element=element,
|
|
3437
|
+
reference=ref,
|
|
3438
|
+
))
|
|
3439
|
+
return issues
|
|
3440
|
+
|
|
3441
|
+
def _check_connector_directions(self, model: Any) -> list[SemanticIssue]:
|
|
3442
|
+
"""Check connection-end port direction compatibility (Goal 9).
|
|
3443
|
+
|
|
3444
|
+
``connection c connect a.p1 to b.p2;`` — when both end ports
|
|
3445
|
+
carry explicit directions and neither is ``inout``, wiring
|
|
3446
|
+
``out`` to ``out`` or ``in`` to ``in`` flags
|
|
3447
|
+
CONNECTOR_DIRECTION_MISMATCH (warning — conjugated ports and
|
|
3448
|
+
exotic flow conventions exist, so this is advisory, not an
|
|
3449
|
+
error). Ends without a direction keyword, ``inout`` ends,
|
|
3450
|
+
chains deeper than two segments and unresolvable parts are
|
|
3451
|
+
skipped.
|
|
3452
|
+
"""
|
|
3453
|
+
issues: list[SemanticIssue] = []
|
|
3454
|
+
try:
|
|
3455
|
+
from sysmlpy.sim import load_model_grammar
|
|
3456
|
+
visit = load_model_grammar(model)
|
|
3457
|
+
except Exception:
|
|
3458
|
+
return issues
|
|
3459
|
+
|
|
3460
|
+
scope_ports: dict = {} # def/usage name -> {port: direction}
|
|
3461
|
+
part_typing: dict = {} # part usage name -> typed-by name
|
|
3462
|
+
member_typing: dict = {} # (container name, member) -> typed-by
|
|
3463
|
+
connections: list = [] # (name, scope_stack, [chain, ...])
|
|
3464
|
+
|
|
3465
|
+
def walk2(node, scope_stack):
|
|
3466
|
+
if isinstance(node, dict):
|
|
3467
|
+
nm = node.get("name")
|
|
3468
|
+
declared = _find_declared_name(node)
|
|
3469
|
+
new_stack = scope_stack
|
|
3470
|
+
if declared and isinstance(nm, str) and (
|
|
3471
|
+
nm.endswith("Usage") or nm.endswith("Definition")):
|
|
3472
|
+
if nm != "PortUsage":
|
|
3473
|
+
new_stack = scope_stack + [declared]
|
|
3474
|
+
if nm == "PortUsage":
|
|
3475
|
+
d = _port_direction(node)
|
|
3476
|
+
if d and scope_stack:
|
|
3477
|
+
scope_ports.setdefault(
|
|
3478
|
+
scope_stack[-1], {})[declared] = d
|
|
3479
|
+
elif nm == "ConnectionUsage":
|
|
3480
|
+
chains = []
|
|
3481
|
+
part = node.get("part") or {}
|
|
3482
|
+
bp = part.get("part") or {}
|
|
3483
|
+
for rel in _as_list_dicts(
|
|
3484
|
+
bp.get("ownedRelationship")):
|
|
3485
|
+
if rel.get("name") != "ConnectorEndMember":
|
|
3486
|
+
continue
|
|
3487
|
+
ends = _as_list_dicts(
|
|
3488
|
+
rel.get("ownedRelatedElement"))
|
|
3489
|
+
if not ends:
|
|
3490
|
+
continue
|
|
3491
|
+
chain = _connector_end_chain(ends[0])
|
|
3492
|
+
if chain:
|
|
3493
|
+
chains.append(chain)
|
|
3494
|
+
if len(chains) == 2:
|
|
3495
|
+
connections.append((declared, new_stack, chains))
|
|
3496
|
+
elif nm.endswith("Usage"):
|
|
3497
|
+
t = _usage_typed_by(node)
|
|
3498
|
+
if t:
|
|
3499
|
+
part_typing[declared] = t
|
|
3500
|
+
if scope_stack:
|
|
3501
|
+
member_typing[(scope_stack[-1],
|
|
3502
|
+
declared)] = t
|
|
3503
|
+
for k, v in node.items():
|
|
3504
|
+
if isinstance(v, (dict, list)):
|
|
3505
|
+
walk2(v, new_stack)
|
|
3506
|
+
elif isinstance(node, list):
|
|
3507
|
+
for x in node:
|
|
3508
|
+
walk2(x, scope_stack)
|
|
3509
|
+
|
|
3510
|
+
walk2(visit, [])
|
|
3511
|
+
|
|
3512
|
+
def end_direction(chain, scope_stack):
|
|
3513
|
+
if len(chain) == 2:
|
|
3514
|
+
part_name, port_name = chain
|
|
3515
|
+
t = part_typing.get(part_name)
|
|
3516
|
+
if t and port_name in scope_ports.get(t, {}):
|
|
3517
|
+
return scope_ports[t][port_name]
|
|
3518
|
+
return scope_ports.get(part_name, {}).get(port_name)
|
|
3519
|
+
if len(chain) == 1:
|
|
3520
|
+
port_name = chain[0]
|
|
3521
|
+
for scope in reversed(scope_stack):
|
|
3522
|
+
if port_name in scope_ports.get(scope, {}):
|
|
3523
|
+
return scope_ports[scope][port_name]
|
|
3524
|
+
t = part_typing.get(scope)
|
|
3525
|
+
if t and port_name in scope_ports.get(t, {}):
|
|
3526
|
+
return scope_ports[t][port_name]
|
|
3527
|
+
# deep chains (>=3 segments: bus.a.p3) — resolve segment by
|
|
3528
|
+
# segment: seg0 via the part's typing, middle segments via
|
|
3529
|
+
# member typing in the resolved container, final port via
|
|
3530
|
+
# the container's port directions.
|
|
3531
|
+
first = chain[0]
|
|
3532
|
+
cur = part_typing.get(first)
|
|
3533
|
+
if cur is None:
|
|
3534
|
+
for scope in reversed(scope_stack):
|
|
3535
|
+
t = member_typing.get((scope, first))
|
|
3536
|
+
if t:
|
|
3537
|
+
cur = t
|
|
3538
|
+
break
|
|
3539
|
+
if cur is None:
|
|
3540
|
+
return None
|
|
3541
|
+
for seg in chain[1:-1]:
|
|
3542
|
+
t = member_typing.get((cur, seg))
|
|
3543
|
+
if t is None:
|
|
3544
|
+
# members declared on the seg0 *usage* itself
|
|
3545
|
+
t = member_typing.get((first, seg))
|
|
3546
|
+
if t is None:
|
|
3547
|
+
return None
|
|
3548
|
+
cur = t
|
|
3549
|
+
return scope_ports.get(cur, {}).get(chain[-1])
|
|
3550
|
+
|
|
3551
|
+
for cname, cstack, chains in connections:
|
|
3552
|
+
d1 = end_direction(chains[0], cstack)
|
|
3553
|
+
d2 = end_direction(chains[1], cstack)
|
|
3554
|
+
if not d1 or not d2:
|
|
3555
|
+
continue
|
|
3556
|
+
if d1 == "inout" or d2 == "inout":
|
|
3557
|
+
continue
|
|
3558
|
+
if d1 == d2:
|
|
3559
|
+
issues.append(SemanticIssue(
|
|
3560
|
+
severity="warning",
|
|
3561
|
+
code="CONNECTOR_DIRECTION_MISMATCH",
|
|
3562
|
+
message=(
|
|
3563
|
+
f"Connection '{cname}' binds two '{d1}' ports "
|
|
3564
|
+
f"({chains[0][-1]} -> {chains[1][-1]}); a "
|
|
3565
|
+
"connection normally pairs 'out' with 'in'"),
|
|
3566
|
+
reference=cname,
|
|
3567
|
+
))
|
|
3568
|
+
return issues
|
|
3569
|
+
|
|
3182
3570
|
def _check_state_machines(self, model: Any) -> list[SemanticIssue]:
|
|
3183
3571
|
"""OCL well-formedness for ``state def`` machines (Goal 9).
|
|
3184
3572
|
|
|
@@ -224,6 +224,59 @@ def _qualified_name(obj) -> str:
|
|
|
224
224
|
return "::".join(reversed(segments))
|
|
225
225
|
|
|
226
226
|
|
|
227
|
+
def _find_named_dicts_local(node, name: str) -> list:
|
|
228
|
+
"""Locate every dict with ``dict["name"] == name`` in a tree.
|
|
229
|
+
|
|
230
|
+
Local copy of the semantic-module helper (semantic imports this
|
|
231
|
+
module, so a shared util would be circular).
|
|
232
|
+
"""
|
|
233
|
+
out: list = []
|
|
234
|
+
|
|
235
|
+
def walk(n):
|
|
236
|
+
if isinstance(n, dict):
|
|
237
|
+
if n.get("name") == name:
|
|
238
|
+
out.append(n)
|
|
239
|
+
for v in n.values():
|
|
240
|
+
if isinstance(v, (dict, list)):
|
|
241
|
+
walk(v)
|
|
242
|
+
elif isinstance(n, list):
|
|
243
|
+
for item in n:
|
|
244
|
+
if isinstance(item, (dict, list)):
|
|
245
|
+
walk(item)
|
|
246
|
+
|
|
247
|
+
walk(node)
|
|
248
|
+
return out
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
def _nested_satisfy_ref(satisfy_dict: dict):
|
|
252
|
+
"""``(target, by_part)`` of a SatisfyRequirementUsage dict.
|
|
253
|
+
|
|
254
|
+
``ors.referencedFeature.names`` carries the target requirement;
|
|
255
|
+
``ssm`` (SatisfactionSubjectMember) nests
|
|
256
|
+
FeatureChainMember.memberElement (QualifiedName) whose last
|
|
257
|
+
segment is the satisfying feature.
|
|
258
|
+
"""
|
|
259
|
+
ors = satisfy_dict.get("ors")
|
|
260
|
+
if not isinstance(ors, dict):
|
|
261
|
+
return None
|
|
262
|
+
rf = ors.get("referencedFeature") or {}
|
|
263
|
+
names = rf.get("names") if isinstance(rf, dict) else None
|
|
264
|
+
if not names:
|
|
265
|
+
return None
|
|
266
|
+
target = "::".join(str(n) for n in names)
|
|
267
|
+
|
|
268
|
+
ssm = satisfy_dict.get("ssm")
|
|
269
|
+
by_ref = None
|
|
270
|
+
if isinstance(ssm, dict):
|
|
271
|
+
for m in _find_named_dicts_local(ssm, "FeatureChainMember"):
|
|
272
|
+
me = m.get("memberElement") or {}
|
|
273
|
+
mnames = me.get("names")
|
|
274
|
+
if isinstance(mnames, list) and mnames:
|
|
275
|
+
by_ref = "::".join(str(n) for n in mnames)
|
|
276
|
+
break
|
|
277
|
+
return target, by_ref
|
|
278
|
+
|
|
279
|
+
|
|
227
280
|
def _last_segment(ref: str) -> str:
|
|
228
281
|
"""Last segment of a dotted/qualified reference (``Pkg::r1`` → ``r1``)."""
|
|
229
282
|
for sep in ("::", "."):
|
|
@@ -300,6 +353,26 @@ def extract_traceability(model) -> TraceabilityReport:
|
|
|
300
353
|
is_definition=(gclass == "RequirementDefinition"),
|
|
301
354
|
)
|
|
302
355
|
traces.append(trace)
|
|
356
|
+
# Nested satisfy members (``requirement top { satisfy top by v;
|
|
357
|
+
# }``) parse as SatisfyRequirementUsage dicts inside the
|
|
358
|
+
# requirement's grammar — the visitor handles nested *verify*
|
|
359
|
+
# members but not satisfy, so they are invisible to pass 2 and
|
|
360
|
+
# the requirement would read as uncovered. Record the edge.
|
|
361
|
+
if grammar is not None:
|
|
362
|
+
try:
|
|
363
|
+
grammar_def = grammar.get_definition()
|
|
364
|
+
except Exception:
|
|
365
|
+
grammar_def = None
|
|
366
|
+
if isinstance(grammar_def, dict):
|
|
367
|
+
for sat in _find_named_dicts_local(
|
|
368
|
+
grammar_def, "SatisfyRequirementUsage"):
|
|
369
|
+
ref = _nested_satisfy_ref(sat)
|
|
370
|
+
if ref is None:
|
|
371
|
+
continue
|
|
372
|
+
target, by_part = ref
|
|
373
|
+
if by_part and _last_segment(target) == name and (
|
|
374
|
+
by_part not in trace.satisfied_by):
|
|
375
|
+
trace.satisfied_by.append(by_part)
|
|
303
376
|
# Index by both the bare name and every suffix of the qualified
|
|
304
377
|
# name so `Pkg::req` / `req` / `Sub::req` references all resolve.
|
|
305
378
|
traces_by_name.setdefault(name, trace)
|
|
@@ -3239,6 +3239,13 @@ class Requirement(Usage):
|
|
|
3239
3239
|
c = Requirement(definition=True).load_from_grammar(target)
|
|
3240
3240
|
c.parent = self
|
|
3241
3241
|
self.children.append(c)
|
|
3242
|
+
elif target_cls in ("SatisfyRequirementUsage",
|
|
3243
|
+
"VerifyRequirementUsage"):
|
|
3244
|
+
# satisfy members are extracted from the grammar
|
|
3245
|
+
# dicts by traceability/semantic (nested verify
|
|
3246
|
+
# members ride _extract_verification_member); no
|
|
3247
|
+
# Requirement child belongs here.
|
|
3248
|
+
pass
|
|
3242
3249
|
elif target_cls and "Requirement" in target_cls:
|
|
3243
3250
|
print(f"[Requirement] Unhandled nested requirement type: {target_cls}")
|
|
3244
3251
|
|
|
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
|
{sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/antlr/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.interp
RENAMED
|
File without changes
|
{sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/antlr/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.py
RENAMED
|
File without changes
|
{sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/antlr/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.tokens
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
|
{sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/domain/Analysis/SampledFunctions.sysml
RENAMED
|
File without changes
|
{sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/domain/Analysis/StateSpaceRepresentation.sysml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/domain/Cause and Effect/CauseAndEffect.sysml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/domain/Metadata/ModelingMetadata.sysml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/domain/Quantities and Units/ISQAcoustics.sysml
RENAMED
|
File without changes
|
|
File without changes
|
{sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/domain/Quantities and Units/ISQBase.sysml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/domain/Quantities and Units/ISQLight.sysml
RENAMED
|
File without changes
|
{sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/domain/Quantities and Units/ISQMechanics.sysml
RENAMED
|
File without changes
|
{sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/domain/Quantities and Units/ISQSpaceTime.sysml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/domain/Quantities and Units/Quantities.sysml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/domain/Quantities and Units/SIPrefixes.sysml
RENAMED
|
File without changes
|
|
File without changes
|
{sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/domain/Quantities and Units/Time.sysml
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
|
{sysmlpy-0.70.0 → sysmlpy-0.72.0}/src/sysmlpy/library/kernel/FeatureReferencingPerformances.kerml
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
|
|
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
|