sysmlpy 0.71.0__tar.gz → 0.73.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.
Files changed (158) hide show
  1. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/PKG-INFO +1 -1
  2. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/pyproject.toml +1 -1
  3. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/__init__.py +1 -1
  4. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/semantic.py +314 -16
  5. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/traceability.py +73 -0
  6. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/usage.py +7 -0
  7. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/LICENSE +0 -0
  8. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/README.md +0 -0
  9. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/__main__.py +0 -0
  10. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/antlr/README.md +0 -0
  11. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/antlr/SysMLv2Lexer.interp +0 -0
  12. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/antlr/SysMLv2Lexer.py +0 -0
  13. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/antlr/SysMLv2Lexer.tokens +0 -0
  14. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/antlr/SysMLv2Parser.interp +0 -0
  15. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/antlr/SysMLv2Parser.py +0 -0
  16. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/antlr/SysMLv2Parser.tokens +0 -0
  17. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/antlr/SysMLv2ParserListener.py +0 -0
  18. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/antlr/SysMLv2ParserVisitor.py +0 -0
  19. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/antlr/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.interp +0 -0
  20. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/antlr/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.py +0 -0
  21. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/antlr/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.tokens +0 -0
  22. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/antlr_parser.py +0 -0
  23. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/antlr_visitor.py +0 -0
  24. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/boxes_view.py +0 -0
  25. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/definition.py +0 -0
  26. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/evaluator.py +0 -0
  27. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/examples/attribute_values.py +0 -0
  28. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/examples/part_attributes.py +0 -0
  29. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/examples/tuples_sequences.py +0 -0
  30. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/formatting.py +0 -0
  31. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/grammar/antlr4/README.md +0 -0
  32. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.g4 +0 -0
  33. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.interp +0 -0
  34. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.py +0 -0
  35. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.tokens +0 -0
  36. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/grammar/antlr4/SysMLv2Parser.g4 +0 -0
  37. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/grammar/antlr4/SysMLv2Parser.interp +0 -0
  38. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/grammar/antlr4/SysMLv2Parser.py +0 -0
  39. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/grammar/antlr4/SysMLv2Parser.tokens +0 -0
  40. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/grammar/antlr4/SysMLv2ParserListener.py +0 -0
  41. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/grammar/antlr4/SysMLv2ParserVisitor.py +0 -0
  42. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/grammar/antlr4/desc.xml +0 -0
  43. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/grammar/antlr4/examples/camera.sysml +0 -0
  44. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/grammar/antlr4/examples/toaster-system.sysml +0 -0
  45. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/grammar/antlr4/examples/vehicle-model.sysml +0 -0
  46. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/grammar/antlr4/pom.xml +0 -0
  47. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/grammar/classes.py +0 -0
  48. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/interchange.py +0 -0
  49. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/LICENSE +0 -0
  50. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/README.md +0 -0
  51. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/__init__.py +0 -0
  52. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/domain/Analysis/AnalysisTooling.sysml +0 -0
  53. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/domain/Analysis/SampledFunctions.sysml +0 -0
  54. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/domain/Analysis/StateSpaceRepresentation.sysml +0 -0
  55. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/domain/Analysis/TradeStudies.sysml +0 -0
  56. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/domain/Cause and Effect/CausationConnections.sysml +0 -0
  57. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/domain/Cause and Effect/CauseAndEffect.sysml +0 -0
  58. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/domain/Geometry/ShapeItems.sysml +0 -0
  59. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/domain/Geometry/SpatialItems.sysml +0 -0
  60. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/domain/Metadata/ImageMetadata.sysml +0 -0
  61. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/domain/Metadata/ModelingMetadata.sysml +0 -0
  62. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/domain/Metadata/ParametersOfInterestMetadata.sysml +0 -0
  63. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/domain/Metadata/RiskMetadata.sysml +0 -0
  64. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/domain/Quantities and Units/ISQ.sysml +0 -0
  65. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/domain/Quantities and Units/ISQAcoustics.sysml +0 -0
  66. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/domain/Quantities and Units/ISQAtomicNuclear.sysml +0 -0
  67. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/domain/Quantities and Units/ISQBase.sysml +0 -0
  68. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/domain/Quantities and Units/ISQCharacteristicNumbers.sysml +0 -0
  69. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/domain/Quantities and Units/ISQChemistryMolecular.sysml +0 -0
  70. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/domain/Quantities and Units/ISQCondensedMatter.sysml +0 -0
  71. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/domain/Quantities and Units/ISQElectromagnetism.sysml +0 -0
  72. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/domain/Quantities and Units/ISQInformation.sysml +0 -0
  73. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/domain/Quantities and Units/ISQLight.sysml +0 -0
  74. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/domain/Quantities and Units/ISQMechanics.sysml +0 -0
  75. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/domain/Quantities and Units/ISQSpaceTime.sysml +0 -0
  76. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/domain/Quantities and Units/ISQThermodynamics.sysml +0 -0
  77. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/domain/Quantities and Units/MeasurementRefCalculations.sysml +0 -0
  78. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/domain/Quantities and Units/MeasurementReferences.sysml +0 -0
  79. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/domain/Quantities and Units/Quantities.sysml +0 -0
  80. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/domain/Quantities and Units/QuantityCalculations.sysml +0 -0
  81. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/domain/Quantities and Units/SI.sysml +0 -0
  82. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/domain/Quantities and Units/SIPrefixes.sysml +0 -0
  83. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/domain/Quantities and Units/TensorCalculations.sysml +0 -0
  84. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/domain/Quantities and Units/Time.sysml +0 -0
  85. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/domain/Quantities and Units/USCustomaryUnits.sysml +0 -0
  86. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/domain/Quantities and Units/VectorCalculations.sysml +0 -0
  87. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/domain/Requirement Derivation/DerivationConnections.sysml +0 -0
  88. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/domain/Requirement Derivation/RequirementDerivation.sysml +0 -0
  89. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/kernel/Base.kerml +0 -0
  90. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/kernel/BaseFunctions.kerml +0 -0
  91. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/kernel/BooleanFunctions.kerml +0 -0
  92. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/kernel/Clocks.kerml +0 -0
  93. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/kernel/CollectionFunctions.kerml +0 -0
  94. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/kernel/Collections.kerml +0 -0
  95. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/kernel/ComplexFunctions.kerml +0 -0
  96. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/kernel/ControlFunctions.kerml +0 -0
  97. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/kernel/ControlPerformances.kerml +0 -0
  98. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/kernel/DataFunctions.kerml +0 -0
  99. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/kernel/FeatureReferencingPerformances.kerml +0 -0
  100. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/kernel/IntegerFunctions.kerml +0 -0
  101. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/kernel/KerML.kerml +0 -0
  102. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/kernel/Links.kerml +0 -0
  103. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/kernel/Metaobjects.kerml +0 -0
  104. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/kernel/NaturalFunctions.kerml +0 -0
  105. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/kernel/NumericalFunctions.kerml +0 -0
  106. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/kernel/Objects.kerml +0 -0
  107. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/kernel/Observation.kerml +0 -0
  108. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/kernel/OccurrenceFunctions.kerml +0 -0
  109. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/kernel/Occurrences.kerml +0 -0
  110. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/kernel/Performances.kerml +0 -0
  111. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/kernel/RationalFunctions.kerml +0 -0
  112. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/kernel/RealFunctions.kerml +0 -0
  113. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/kernel/ScalarFunctions.kerml +0 -0
  114. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/kernel/ScalarValues.kerml +0 -0
  115. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/kernel/SequenceFunctions.kerml +0 -0
  116. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/kernel/SpatialFrames.kerml +0 -0
  117. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/kernel/StatePerformances.kerml +0 -0
  118. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/kernel/StringFunctions.kerml +0 -0
  119. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/kernel/Transfers.kerml +0 -0
  120. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/kernel/TransitionPerformances.kerml +0 -0
  121. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/kernel/TrigFunctions.kerml +0 -0
  122. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/kernel/Triggers.kerml +0 -0
  123. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/kernel/VectorFunctions.kerml +0 -0
  124. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/kernel/VectorValues.kerml +0 -0
  125. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/systems/Actions.sysml +0 -0
  126. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/systems/Allocations.sysml +0 -0
  127. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/systems/AnalysisCases.sysml +0 -0
  128. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/systems/Attributes.sysml +0 -0
  129. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/systems/Calculations.sysml +0 -0
  130. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/systems/Cases.sysml +0 -0
  131. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/systems/Connections.sysml +0 -0
  132. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/systems/Constraints.sysml +0 -0
  133. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/systems/Flows.sysml +0 -0
  134. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/systems/Interfaces.sysml +0 -0
  135. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/systems/Items.sysml +0 -0
  136. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/systems/Metadata.sysml +0 -0
  137. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/systems/Parts.sysml +0 -0
  138. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/systems/Ports.sysml +0 -0
  139. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/systems/Requirements.sysml +0 -0
  140. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/systems/StandardViewDefinitions.sysml +0 -0
  141. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/systems/States.sysml +0 -0
  142. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/systems/SysML.sysml +0 -0
  143. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/systems/UseCases.sysml +0 -0
  144. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/systems/VerificationCases.sysml +0 -0
  145. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/library/systems/Views.sysml +0 -0
  146. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/lsp/__init__.py +0 -0
  147. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/lsp/__main__.py +0 -0
  148. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/lsp/protocol.py +0 -0
  149. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/lsp/server.py +0 -0
  150. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/lsp/stdio.py +0 -0
  151. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/navigate.py +0 -0
  152. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/plantuml.py +0 -0
  153. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/project.py +0 -0
  154. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/sim.py +0 -0
  155. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/spreadsheet.py +0 -0
  156. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/store.py +0 -0
  157. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/us_customary_units.txt +0 -0
  158. {sysmlpy-0.71.0 → sysmlpy-0.73.0}/src/sysmlpy/validator.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sysmlpy
3
- Version: 0.71.0
3
+ Version: 0.73.0
4
4
  Summary:
5
5
  License-File: LICENSE
6
6
  Author: Jon R. Fox (mycr0ft)
@@ -6,7 +6,7 @@ build-backend = "poetry.core.masonry.api"
6
6
 
7
7
  [project]
8
8
  name = "sysmlpy"
9
- version = "0.71.0"
9
+ version = "0.73.0"
10
10
  description = ""
11
11
  authors = [{ name = "Jon R. Fox (mycr0ft)", email = "jon.fox@drfox.com" }]
12
12
  readme = "README.md"
@@ -34,7 +34,7 @@ __all__ = [
34
34
  "render_state_transition_view_svg", "boxes_view",
35
35
  ]
36
36
  __author__ = "Jon Fox"
37
- __version__ = "0.71.0"
37
+ __version__ = "0.73.0"
38
38
 
39
39
  from sysmlpy.usage import (
40
40
  Item, Attribute, Part, Port, Action, Reference, UseCase, Requirement, Interface, Message,
@@ -1236,6 +1236,26 @@ 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
+
1239
1259
  def _find_named_dicts(node: Any, name: str) -> list:
1240
1260
  """Locate every dict with ``dict["name"] == name`` in a tree."""
1241
1261
  out: list = []
@@ -2495,6 +2515,7 @@ class SemanticAnalyzer:
2495
2515
  issues.extend(self._check_requirement_coverage(model))
2496
2516
  issues.extend(self._check_trace_targets(model, symtab, lib_roots))
2497
2517
  issues.extend(self._check_verify_targets(model, symtab, lib_roots))
2518
+ issues.extend(self._check_satisfy_parts(model, symtab, lib_roots))
2498
2519
  issues.extend(self._check_connector_directions(model))
2499
2520
 
2500
2521
  # Step 6: Stylistic checks (warnings, not errors)
@@ -3294,6 +3315,193 @@ class SemanticAnalyzer:
3294
3315
  return table.lookup(parts[-1])
3295
3316
  return None
3296
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
+ # superclassifier map for subject-type compatibility: walk
3348
+ # part/item definitions and collect ``:>`` targets
3349
+ supertypes: dict = {}
3350
+ for element, scope_path in self._walk_usages(model):
3351
+ if type(element).__name__ not in ("Part", "Item"):
3352
+ continue
3353
+ if not getattr(element, "is_definition", False):
3354
+ continue
3355
+ grammar = getattr(element, "grammar", None)
3356
+ if grammar is None:
3357
+ continue
3358
+ try:
3359
+ d = grammar.get_definition()
3360
+ except Exception:
3361
+ continue
3362
+ if not isinstance(d, dict):
3363
+ continue
3364
+ defn = d.get("definition") or {}
3365
+ decl = defn.get("declaration") or {}
3366
+ scp = decl.get("subclassificationpart") or {}
3367
+ sups = set()
3368
+ for rel in _as_list_dicts(scp.get("ownedRelationship")):
3369
+ if rel.get("name") != "OwnedSubclassification":
3370
+ continue
3371
+ sc = rel.get("superclassifier") or {}
3372
+ names = sc.get("names")
3373
+ if isinstance(names, list) and names:
3374
+ sups.add("::".join(str(n) for n in names))
3375
+ if sups and element.name:
3376
+ supertypes.setdefault(element.name, set()).update(sups)
3377
+
3378
+ def _is_subtype(sub: str, sup: str, seen=None) -> bool:
3379
+ if sub == sup:
3380
+ return True
3381
+ if seen is None:
3382
+ seen = set()
3383
+ if sub in seen:
3384
+ return False
3385
+ seen.add(sub)
3386
+ for st in supertypes.get(sub, ()):
3387
+ if _is_subtype(st, sup, seen):
3388
+ return True
3389
+ return False
3390
+
3391
+ def subject_issue(req_name, subj_type, part_name, part_type):
3392
+ issues.append(SemanticIssue(
3393
+ severity="warning",
3394
+ code="SATISFY_SUBJECT_TYPE_MISMATCH",
3395
+ message=(
3396
+ f"satisfy 'by {part_name}' ({part_type}) is not "
3397
+ f"related to requirement '{req_name}' subject "
3398
+ f"type '{subj_type}'"),
3399
+ reference=req_name,
3400
+ ))
3401
+
3402
+ for element, scope_path in self._walk_usages(model):
3403
+ gname = (element.grammar.__class__.__name__
3404
+ if getattr(element, "grammar", None) is not None else "")
3405
+ if gname == "SatisfyRequirementUsage":
3406
+ # package-level wrapper; .ssm dump is the by reference,
3407
+ # .ors dump the target requirement
3408
+ g = element.grammar
3409
+ ssm = getattr(g, "ssm", None)
3410
+ if ssm is None:
3411
+ continue
3412
+ ref = ssm.dump().strip().rstrip(";").strip()
3413
+ if not ref:
3414
+ continue
3415
+ if not self._is_resolved(ref, symtab, scope_path, lib_roots):
3416
+ issue(element, ref)
3417
+ ors = getattr(g, "ors", None)
3418
+ target = ors.dump().strip().rstrip(";").strip() \
3419
+ if ors is not None else None
3420
+ if target:
3421
+ self._check_subject_type(
3422
+ element, target, ref, symtab, scope_path,
3423
+ lib_roots, supertypes, _is_subtype,
3424
+ subject_issue)
3425
+ continue
3426
+ if gname not in ("RequirementDefinition", "RequirementUsage"):
3427
+ continue
3428
+ # nested satisfy members: scan the requirement's grammar dict
3429
+ grammar = element.grammar
3430
+ if grammar is None:
3431
+ continue
3432
+ try:
3433
+ grammar_def = grammar.get_definition()
3434
+ except Exception:
3435
+ continue
3436
+ if not isinstance(grammar_def, dict):
3437
+ continue
3438
+ for sat in _find_named_dicts(
3439
+ grammar_def, "SatisfyRequirementUsage"):
3440
+ by_ref = _satisfy_by_ref(sat)
3441
+ if not by_ref:
3442
+ continue
3443
+ if not self._is_resolved(
3444
+ by_ref, symtab, scope_path, lib_roots):
3445
+ issue(element, by_ref)
3446
+ ors = sat.get("ors") or {}
3447
+ rf = ors.get("referencedFeature") or {}
3448
+ names = rf.get("names") if isinstance(rf, dict) else None
3449
+ if names:
3450
+ target = "::".join(str(n) for n in names)
3451
+ self._check_subject_type(
3452
+ element, target, by_ref, symtab, scope_path,
3453
+ lib_roots, supertypes, _is_subtype,
3454
+ subject_issue)
3455
+ return issues
3456
+
3457
+ def _check_subject_type(
3458
+ self,
3459
+ satisfy_obj: Any,
3460
+ target_ref: str,
3461
+ by_ref: str,
3462
+ symtab: "SymbolTable",
3463
+ scope_path: list[str],
3464
+ lib_roots: list,
3465
+ supertypes: dict,
3466
+ is_subtype,
3467
+ issue_fn,
3468
+ ) -> None:
3469
+ """SATISFY_SUBJECT_TYPE_MISMATCH (warning, conservative).
3470
+
3471
+ ``satisfy <req> by <part>`` binds *part* as the satisfying
3472
+ element of *req*'s subject. When both the subject's type and
3473
+ the by-part's type are known model definitions and neither is
3474
+ a (transitive) specialization of the other, flag a warning.
3475
+ Anything unresolvable — library types, untyped parts,
3476
+ requirements without a typed subject — is skipped.
3477
+ """
3478
+ target = self._resolve_element(target_ref, symtab, scope_path)
3479
+ if target is None:
3480
+ return
3481
+ subject = getattr(target, "subject", None)
3482
+ if not subject:
3483
+ return
3484
+ subj_type = subject[1]
3485
+ if not subj_type or subj_type not in supertypes and (
3486
+ subj_type not in getattr(symtab, "_definition_features",
3487
+ {})):
3488
+ return
3489
+ by_el = self._resolve_element(by_ref, symtab, scope_path)
3490
+ if by_el is None:
3491
+ return
3492
+ part_type = self._get_element_type(by_el)
3493
+ if not part_type:
3494
+ return
3495
+ # both sides must be model-known (skip library typings)
3496
+ if part_type not in supertypes and (
3497
+ part_type not in getattr(symtab, "_definition_features",
3498
+ {})):
3499
+ return
3500
+ if is_subtype(part_type, subj_type) or is_subtype(
3501
+ subj_type, part_type):
3502
+ return
3503
+ issue_fn(target_ref, subj_type, by_ref, part_type)
3504
+
3297
3505
  def _check_verify_targets(
3298
3506
  self,
3299
3507
  model: Any,
@@ -3370,8 +3578,10 @@ class SemanticAnalyzer:
3370
3578
  except Exception:
3371
3579
  return issues
3372
3580
 
3373
- scope_ports: dict = {} # def/usage name -> {port: direction}
3581
+ scope_ports: dict = {} # def/usage name -> {port: direction|None}
3374
3582
  part_typing: dict = {} # part usage name -> typed-by name
3583
+ member_typing: dict = {} # (container name, member) -> typed-by
3584
+ supertypes: dict = {} # def name -> {superclassifier names}
3375
3585
  connections: list = [] # (name, scope_stack, [chain, ...])
3376
3586
 
3377
3587
  def walk2(node, scope_stack):
@@ -3383,11 +3593,39 @@ class SemanticAnalyzer:
3383
3593
  nm.endswith("Usage") or nm.endswith("Definition")):
3384
3594
  if nm != "PortUsage":
3385
3595
  new_stack = scope_stack + [declared]
3596
+ if nm.endswith("Definition"):
3597
+ # superclassifiers (``part def A :> B``) ride the
3598
+ # definition dict's declaration.subclassificationpart
3599
+ sups = set()
3600
+ defn = node.get("definition") or {}
3601
+ decl = defn.get("declaration") or {}
3602
+ scp = decl.get("subclassificationpart") or {}
3603
+ for rel in _as_list_dicts(
3604
+ scp.get("ownedRelationship")):
3605
+ if rel.get("name") != "OwnedSubclassification":
3606
+ continue
3607
+ sc = rel.get("superclassifier") or {}
3608
+ names = sc.get("names")
3609
+ if isinstance(names, list) and names:
3610
+ sups.add("::".join(
3611
+ str(n) for n in names))
3612
+ if sups:
3613
+ supertypes.setdefault(declared, set()).update(
3614
+ sups)
3386
3615
  if nm == "PortUsage":
3387
3616
  d = _port_direction(node)
3388
- if d and scope_stack:
3617
+ if scope_stack:
3618
+ # record even undirected ports: existence
3619
+ # drives end resolution, None direction
3620
+ # just skips the direction check
3389
3621
  scope_ports.setdefault(
3390
3622
  scope_stack[-1], {})[declared] = d
3623
+ t = _usage_typed_by(node)
3624
+ if t:
3625
+ part_typing[declared] = t
3626
+ if scope_stack:
3627
+ member_typing[(scope_stack[-1],
3628
+ declared)] = t
3391
3629
  elif nm == "ConnectionUsage":
3392
3630
  chains = []
3393
3631
  part = node.get("part") or {}
@@ -3409,6 +3647,9 @@ class SemanticAnalyzer:
3409
3647
  t = _usage_typed_by(node)
3410
3648
  if t:
3411
3649
  part_typing[declared] = t
3650
+ if scope_stack:
3651
+ member_typing[(scope_stack[-1],
3652
+ declared)] = t
3412
3653
  for k, v in node.items():
3413
3654
  if isinstance(v, (dict, list)):
3414
3655
  walk2(v, new_stack)
@@ -3418,26 +3659,83 @@ class SemanticAnalyzer:
3418
3659
 
3419
3660
  walk2(visit, [])
3420
3661
 
3421
- def end_direction(chain, scope_stack):
3422
- if len(chain) == 2:
3423
- part_name, port_name = chain
3424
- t = part_typing.get(part_name)
3425
- if t and port_name in scope_ports.get(t, {}):
3426
- return scope_ports[t][port_name]
3427
- return scope_ports.get(part_name, {}).get(port_name)
3662
+ def end_resolve(chain, scope_stack):
3663
+ """(direction|None, fully_resolved) for an end chain.
3664
+
3665
+ ``fully_resolved`` is False only when a segment provably
3666
+ does not exist in a *known, non-specializing* container —
3667
+ containers typed by library defs, unknown names and
3668
+ subclasses (inherited members) resolve as "present but
3669
+ direction-unknown" to stay conservative.
3670
+ """
3671
+ if not chain:
3672
+ return None, True
3428
3673
  if len(chain) == 1:
3429
3674
  port_name = chain[0]
3430
3675
  for scope in reversed(scope_stack):
3431
- if port_name in scope_ports.get(scope, {}):
3432
- return scope_ports[scope][port_name]
3676
+ ports = scope_ports.get(scope)
3677
+ if ports is not None and port_name in ports:
3678
+ return ports[port_name], True
3433
3679
  t = part_typing.get(scope)
3434
- if t and port_name in scope_ports.get(t, {}):
3435
- return scope_ports[t][port_name]
3436
- return None
3680
+ if t:
3681
+ ports = scope_ports.get(t)
3682
+ if ports is not None and port_name in ports:
3683
+ return ports[port_name], True
3684
+ if t not in supertypes and t not in scope_ports:
3685
+ # known library/external type: cannot
3686
+ # verify members
3687
+ return None, True
3688
+ return None, False
3689
+ first = chain[0]
3690
+ cur = part_typing.get(first)
3691
+ if cur is None:
3692
+ for scope in reversed(scope_stack):
3693
+ t = member_typing.get((scope, first))
3694
+ if t:
3695
+ cur = t
3696
+ break
3697
+ if cur is None:
3698
+ return None, False
3699
+ for seg in chain[1:-1]:
3700
+ t = member_typing.get((cur, seg))
3701
+ if t is None:
3702
+ # members declared on the seg0 *usage* itself
3703
+ t = member_typing.get((first, seg))
3704
+ if t is None:
3705
+ return None, cur in supertypes or (
3706
+ cur not in scope_ports
3707
+ and cur not in part_typing)
3708
+ cur = t
3709
+ ports = scope_ports.get(cur)
3710
+ if ports is not None and chain[-1] in ports:
3711
+ return ports[chain[-1]], True
3712
+ if cur in supertypes:
3713
+ return None, True # inherited port possible
3714
+ if cur in scope_ports:
3715
+ return None, False # known container, no such port
3716
+ return None, True # external/library type: skip
3437
3717
 
3438
3718
  for cname, cstack, chains in connections:
3439
- d1 = end_direction(chains[0], cstack)
3440
- d2 = end_direction(chains[1], cstack)
3719
+ d1, r1 = end_resolve(chains[0], cstack)
3720
+ d2, r2 = end_resolve(chains[1], cstack)
3721
+ if not r1:
3722
+ issues.append(SemanticIssue(
3723
+ severity="error",
3724
+ code="UNRESOLVED_CONNECTOR_END",
3725
+ message=(
3726
+ f"Connection '{cname}' end "
3727
+ f"'{'.'.join(chains[0])}' does not resolve"),
3728
+ reference=cname,
3729
+ ))
3730
+ if not r2:
3731
+ issues.append(SemanticIssue(
3732
+ severity="error",
3733
+ code="UNRESOLVED_CONNECTOR_END",
3734
+ message=(
3735
+ f"Connection '{cname}' end "
3736
+ f"'{'.'.join(chains[1])}' does not resolve"),
3737
+ reference=cname,
3738
+ ))
3441
3739
  if not d1 or not d2:
3442
3740
  continue
3443
3741
  if d1 == "inout" or d2 == "inout":
@@ -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