sysmlpy 0.19.2__tar.gz → 0.20.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 (147) hide show
  1. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/PKG-INFO +33 -16
  2. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/README.md +32 -15
  3. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/pyproject.toml +2 -2
  4. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/__init__.py +1 -1
  5. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/antlr_visitor.py +7 -11
  6. sysmlpy-0.20.0/src/sysmlpy/semantic.py +1858 -0
  7. sysmlpy-0.19.2/src/sysmlpy/semantic.py +0 -672
  8. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/LICENSE +0 -0
  9. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/__main__.py +0 -0
  10. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/antlr/README.md +0 -0
  11. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/antlr/SysMLv2Lexer.interp +0 -0
  12. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/antlr/SysMLv2Lexer.py +0 -0
  13. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/antlr/SysMLv2Lexer.tokens +0 -0
  14. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/antlr/SysMLv2Parser.interp +0 -0
  15. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/antlr/SysMLv2Parser.py +0 -0
  16. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/antlr/SysMLv2Parser.tokens +0 -0
  17. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/antlr/SysMLv2ParserListener.py +0 -0
  18. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/antlr/SysMLv2ParserVisitor.py +0 -0
  19. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/antlr/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.interp +0 -0
  20. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/antlr/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.py +0 -0
  21. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/antlr/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.tokens +0 -0
  22. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/antlr_parser.py +0 -0
  23. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/definition.py +0 -0
  24. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/examples/attribute_values.py +0 -0
  25. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/examples/part_attributes.py +0 -0
  26. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/examples/tuples_sequences.py +0 -0
  27. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/formatting.py +0 -0
  28. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/grammar/antlr4/README.md +0 -0
  29. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.g4 +0 -0
  30. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.interp +0 -0
  31. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.py +0 -0
  32. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.tokens +0 -0
  33. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/grammar/antlr4/SysMLv2Parser.g4 +0 -0
  34. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/grammar/antlr4/SysMLv2Parser.interp +0 -0
  35. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/grammar/antlr4/SysMLv2Parser.py +0 -0
  36. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/grammar/antlr4/SysMLv2Parser.tokens +0 -0
  37. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/grammar/antlr4/SysMLv2ParserListener.py +0 -0
  38. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/grammar/antlr4/SysMLv2ParserVisitor.py +0 -0
  39. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/grammar/antlr4/desc.xml +0 -0
  40. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/grammar/antlr4/examples/camera.sysml +0 -0
  41. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/grammar/antlr4/examples/toaster-system.sysml +0 -0
  42. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/grammar/antlr4/examples/vehicle-model.sysml +0 -0
  43. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/grammar/antlr4/pom.xml +0 -0
  44. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/grammar/classes.py +0 -0
  45. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/LICENSE +0 -0
  46. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/README.md +0 -0
  47. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/__init__.py +0 -0
  48. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/domain/Analysis/AnalysisTooling.sysml +0 -0
  49. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/domain/Analysis/SampledFunctions.sysml +0 -0
  50. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/domain/Analysis/StateSpaceRepresentation.sysml +0 -0
  51. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/domain/Analysis/TradeStudies.sysml +0 -0
  52. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/domain/Cause and Effect/CausationConnections.sysml +0 -0
  53. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/domain/Cause and Effect/CauseAndEffect.sysml +0 -0
  54. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/domain/Geometry/ShapeItems.sysml +0 -0
  55. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/domain/Geometry/SpatialItems.sysml +0 -0
  56. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/domain/Metadata/ImageMetadata.sysml +0 -0
  57. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/domain/Metadata/ModelingMetadata.sysml +0 -0
  58. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/domain/Metadata/ParametersOfInterestMetadata.sysml +0 -0
  59. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/domain/Metadata/RiskMetadata.sysml +0 -0
  60. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/domain/Quantities and Units/ISQ.sysml +0 -0
  61. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/domain/Quantities and Units/ISQAcoustics.sysml +0 -0
  62. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/domain/Quantities and Units/ISQAtomicNuclear.sysml +0 -0
  63. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/domain/Quantities and Units/ISQBase.sysml +0 -0
  64. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/domain/Quantities and Units/ISQCharacteristicNumbers.sysml +0 -0
  65. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/domain/Quantities and Units/ISQChemistryMolecular.sysml +0 -0
  66. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/domain/Quantities and Units/ISQCondensedMatter.sysml +0 -0
  67. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/domain/Quantities and Units/ISQElectromagnetism.sysml +0 -0
  68. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/domain/Quantities and Units/ISQInformation.sysml +0 -0
  69. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/domain/Quantities and Units/ISQLight.sysml +0 -0
  70. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/domain/Quantities and Units/ISQMechanics.sysml +0 -0
  71. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/domain/Quantities and Units/ISQSpaceTime.sysml +0 -0
  72. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/domain/Quantities and Units/ISQThermodynamics.sysml +0 -0
  73. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/domain/Quantities and Units/MeasurementRefCalculations.sysml +0 -0
  74. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/domain/Quantities and Units/MeasurementReferences.sysml +0 -0
  75. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/domain/Quantities and Units/Quantities.sysml +0 -0
  76. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/domain/Quantities and Units/QuantityCalculations.sysml +0 -0
  77. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/domain/Quantities and Units/SI.sysml +0 -0
  78. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/domain/Quantities and Units/SIPrefixes.sysml +0 -0
  79. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/domain/Quantities and Units/TensorCalculations.sysml +0 -0
  80. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/domain/Quantities and Units/Time.sysml +0 -0
  81. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/domain/Quantities and Units/USCustomaryUnits.sysml +0 -0
  82. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/domain/Quantities and Units/VectorCalculations.sysml +0 -0
  83. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/domain/Requirement Derivation/DerivationConnections.sysml +0 -0
  84. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/domain/Requirement Derivation/RequirementDerivation.sysml +0 -0
  85. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/kernel/Base.kerml +0 -0
  86. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/kernel/BaseFunctions.kerml +0 -0
  87. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/kernel/BooleanFunctions.kerml +0 -0
  88. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/kernel/Clocks.kerml +0 -0
  89. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/kernel/CollectionFunctions.kerml +0 -0
  90. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/kernel/Collections.kerml +0 -0
  91. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/kernel/ComplexFunctions.kerml +0 -0
  92. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/kernel/ControlFunctions.kerml +0 -0
  93. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/kernel/ControlPerformances.kerml +0 -0
  94. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/kernel/DataFunctions.kerml +0 -0
  95. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/kernel/FeatureReferencingPerformances.kerml +0 -0
  96. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/kernel/IntegerFunctions.kerml +0 -0
  97. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/kernel/KerML.kerml +0 -0
  98. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/kernel/Links.kerml +0 -0
  99. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/kernel/Metaobjects.kerml +0 -0
  100. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/kernel/NaturalFunctions.kerml +0 -0
  101. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/kernel/NumericalFunctions.kerml +0 -0
  102. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/kernel/Objects.kerml +0 -0
  103. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/kernel/Observation.kerml +0 -0
  104. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/kernel/OccurrenceFunctions.kerml +0 -0
  105. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/kernel/Occurrences.kerml +0 -0
  106. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/kernel/Performances.kerml +0 -0
  107. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/kernel/RationalFunctions.kerml +0 -0
  108. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/kernel/RealFunctions.kerml +0 -0
  109. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/kernel/ScalarFunctions.kerml +0 -0
  110. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/kernel/ScalarValues.kerml +0 -0
  111. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/kernel/SequenceFunctions.kerml +0 -0
  112. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/kernel/SpatialFrames.kerml +0 -0
  113. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/kernel/StatePerformances.kerml +0 -0
  114. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/kernel/StringFunctions.kerml +0 -0
  115. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/kernel/Transfers.kerml +0 -0
  116. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/kernel/TransitionPerformances.kerml +0 -0
  117. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/kernel/TrigFunctions.kerml +0 -0
  118. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/kernel/Triggers.kerml +0 -0
  119. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/kernel/VectorFunctions.kerml +0 -0
  120. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/kernel/VectorValues.kerml +0 -0
  121. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/systems/Actions.sysml +0 -0
  122. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/systems/Allocations.sysml +0 -0
  123. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/systems/AnalysisCases.sysml +0 -0
  124. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/systems/Attributes.sysml +0 -0
  125. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/systems/Calculations.sysml +0 -0
  126. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/systems/Cases.sysml +0 -0
  127. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/systems/Connections.sysml +0 -0
  128. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/systems/Constraints.sysml +0 -0
  129. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/systems/Flows.sysml +0 -0
  130. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/systems/Interfaces.sysml +0 -0
  131. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/systems/Items.sysml +0 -0
  132. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/systems/Metadata.sysml +0 -0
  133. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/systems/Parts.sysml +0 -0
  134. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/systems/Ports.sysml +0 -0
  135. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/systems/Requirements.sysml +0 -0
  136. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/systems/StandardViewDefinitions.sysml +0 -0
  137. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/systems/States.sysml +0 -0
  138. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/systems/SysML.sysml +0 -0
  139. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/systems/UseCases.sysml +0 -0
  140. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/systems/VerificationCases.sysml +0 -0
  141. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/library/systems/Views.sysml +0 -0
  142. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/navigate.py +0 -0
  143. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/plantuml.py +0 -0
  144. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/store.py +0 -0
  145. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/us_customary_units.txt +0 -0
  146. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/usage.py +0 -0
  147. {sysmlpy-0.19.2 → sysmlpy-0.20.0}/src/sysmlpy/validator.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sysmlpy
3
- Version: 0.19.2
3
+ Version: 0.20.0
4
4
  Summary: SysML v2.0 Parser
5
5
  License: MIT License
6
6
 
@@ -58,6 +58,8 @@ The project had diverged so much from sysml2py that a new name, sysmlpy, was sel
58
58
 
59
59
  ![Lines of Code Over Time](loc_history.svg)
60
60
 
61
+ **v0.20.0:** Full OCL well-formedness validation suite. Supertype/inheritance resolution for subsetting references. Standard library symbol index scans 88 `.kerml`/`.sysml` files (~1,417 symbols). Import visibility enforcement (`private`/`public`/`protected`). Multiplicity bounds validation. Feature chain compatibility checking. Port and part definition type validation. Duplicate name detection. Cyclic specialization detection. 90 semantic tests, 288 total tests passing.
62
+
61
63
  **v0.19.0:** Semantic analysis engine with undefined symbol detection. Import resolution (namespace `::*`, membership, recursive `::*::**`). 530 tests passing. Symbol table with hierarchical scope resolution and qualified name lookup.
62
64
 
63
65
  **v0.17.0:** 100% test suite pass rate (487/487). Cayley graph database storage backend via HTTP API. Full grammar round-trip coverage (56/56 tests). Programmatic API consistency fixes. NetworkXStore bug fix.
@@ -235,7 +237,7 @@ print(tree.dump())
235
237
 
236
238
  ## Semantic Analysis
237
239
 
238
- sysmlpy includes a semantic analysis engine that detects undefined symbol references in parsed models. It builds a hierarchical symbol table from the model tree, resolves imports, and cross-references all type/subsetting/redefinition references.
240
+ sysmlpy includes a comprehensive semantic analysis engine that validates parsed models against SysML v2 well-formedness rules. Run `analyze(model)` to detect issues across six categories:
239
241
 
240
242
  ```python
241
243
  from sysmlpy import loads, analyze
@@ -257,23 +259,38 @@ for issue in issues:
257
259
  # → [error] UNDEFINED_SYMBOL: Undefined symbol 'Wheel' referenced in Part 'myWheel'
258
260
  ```
259
261
 
260
- ### Import Resolution
261
-
262
- The analyzer resolves three import patterns:
262
+ ### Symbol Resolution
263
263
 
264
- | Pattern | Example | Effect |
265
- |---------|---------|--------|
266
- | Namespace import | `import Types::*` | Makes all symbols from `Types` visible |
267
- | Membership import | `import Types::Engine` | Makes only `Engine` visible |
268
- | Recursive import | `import Types::*::**` | Imports from `Types` and all nested packages |
264
+ - **Undefined symbol detection** catches references to non-existent types, features, and packages
265
+ - **Qualified name resolution** — `P::A` and `Outer::Inner::DeepPart` resolve through scope chains
266
+ - **Inheritance resolution** subsetting/redefinition references resolve through supertype chains
267
+ - **Library symbol index** scans 88 `.kerml`/`.sysml` files (~1,417 symbols) from the bundled standard library
269
268
 
270
- ### Symbol Resolution
269
+ ### Import Resolution
271
270
 
272
- - **Hierarchical scopes**: Each package and definition creates a child scope
273
- - **Parent chain lookup**: References resolve through parent scopes
274
- - **Qualified names**: `P::A` and `Outer::Inner::DeepPart` resolve correctly
275
- - **Cross-package**: `import A::B::*` works across arbitrary package depth
276
- - **Library whitelist**: 80+ standard library symbols (`ScalarValues::Integer`, `ISQ::LengthValue`, etc.) are pre-recognized
271
+ The analyzer resolves three import patterns with visibility enforcement:
272
+
273
+ | Pattern | Example | Visibility | Effect |
274
+ |---------|---------|------------|--------|
275
+ | Namespace import | `import Types::*` | `private` (default) | Makes all symbols from `Types` visible in current scope only |
276
+ | Membership import | `import Types::Engine` | `private` | Makes only `Engine` visible in current scope |
277
+ | Recursive import | `import Types::*::**` | `private` | Imports from `Types` and all nested packages |
278
+ | Public import | `public import Types::*` | `public` | Re-exports symbols to sibling and child scopes |
279
+ | Protected import | `protected import Types::*` | `protected` | Visible to child scopes only, not re-exported |
280
+
281
+ ### OCL Well-Formedness Checks
282
+
283
+ | Code | Rule | Description |
284
+ |------|------|-------------|
285
+ | `DUPLICATE_NAME` | Namespace.duplicate_names | No two members may share the same name in a scope |
286
+ | `CYCLIC_SPECIALIZATION` | Type.no_cyclic_specialization | A type cannot directly or indirectly specialize itself |
287
+ | `INCOMPATIBLE_SUBSETTING` | Feature.subsetting_compatible | A subsetting feature must reference a defined feature in the inheritance chain |
288
+ | `INCOMPATIBLE_REDEFINITION` | Feature.redefinition_compatible | A redefining feature must reference a defined feature in the inheritance chain |
289
+ | `INCOMPATIBLE_PART_DEFINITION` | Part.definition_compatible | A part usage must be typed by a PartDefinition |
290
+ | `INCOMPATIBLE_PORT_DEFINITION` | Port.definition_compatible | A port usage must be typed by a PortDefinition |
291
+ | `INCOMPATIBLE_FEATURE_CHAIN` | Feature.chaining_compatible | Chained features (`a.b.c`) must have compatible types at each step |
292
+ | `INVALID_MULTIPLICITY_BOUNDS` | Multiplicity.bounds_valid | Lower bound must be ≤ upper bound (`[5..2]` is invalid) |
293
+ | `UNRESOLVED_IMPORT` | — | Import target does not exist in the model |
277
294
 
278
295
  ## Storage Backends
279
296
 
@@ -14,6 +14,8 @@ The project had diverged so much from sysml2py that a new name, sysmlpy, was sel
14
14
 
15
15
  ![Lines of Code Over Time](loc_history.svg)
16
16
 
17
+ **v0.20.0:** Full OCL well-formedness validation suite. Supertype/inheritance resolution for subsetting references. Standard library symbol index scans 88 `.kerml`/`.sysml` files (~1,417 symbols). Import visibility enforcement (`private`/`public`/`protected`). Multiplicity bounds validation. Feature chain compatibility checking. Port and part definition type validation. Duplicate name detection. Cyclic specialization detection. 90 semantic tests, 288 total tests passing.
18
+
17
19
  **v0.19.0:** Semantic analysis engine with undefined symbol detection. Import resolution (namespace `::*`, membership, recursive `::*::**`). 530 tests passing. Symbol table with hierarchical scope resolution and qualified name lookup.
18
20
 
19
21
  **v0.17.0:** 100% test suite pass rate (487/487). Cayley graph database storage backend via HTTP API. Full grammar round-trip coverage (56/56 tests). Programmatic API consistency fixes. NetworkXStore bug fix.
@@ -191,7 +193,7 @@ print(tree.dump())
191
193
 
192
194
  ## Semantic Analysis
193
195
 
194
- sysmlpy includes a semantic analysis engine that detects undefined symbol references in parsed models. It builds a hierarchical symbol table from the model tree, resolves imports, and cross-references all type/subsetting/redefinition references.
196
+ sysmlpy includes a comprehensive semantic analysis engine that validates parsed models against SysML v2 well-formedness rules. Run `analyze(model)` to detect issues across six categories:
195
197
 
196
198
  ```python
197
199
  from sysmlpy import loads, analyze
@@ -213,23 +215,38 @@ for issue in issues:
213
215
  # → [error] UNDEFINED_SYMBOL: Undefined symbol 'Wheel' referenced in Part 'myWheel'
214
216
  ```
215
217
 
216
- ### Import Resolution
217
-
218
- The analyzer resolves three import patterns:
218
+ ### Symbol Resolution
219
219
 
220
- | Pattern | Example | Effect |
221
- |---------|---------|--------|
222
- | Namespace import | `import Types::*` | Makes all symbols from `Types` visible |
223
- | Membership import | `import Types::Engine` | Makes only `Engine` visible |
224
- | Recursive import | `import Types::*::**` | Imports from `Types` and all nested packages |
220
+ - **Undefined symbol detection** catches references to non-existent types, features, and packages
221
+ - **Qualified name resolution** — `P::A` and `Outer::Inner::DeepPart` resolve through scope chains
222
+ - **Inheritance resolution** subsetting/redefinition references resolve through supertype chains
223
+ - **Library symbol index** scans 88 `.kerml`/`.sysml` files (~1,417 symbols) from the bundled standard library
225
224
 
226
- ### Symbol Resolution
225
+ ### Import Resolution
227
226
 
228
- - **Hierarchical scopes**: Each package and definition creates a child scope
229
- - **Parent chain lookup**: References resolve through parent scopes
230
- - **Qualified names**: `P::A` and `Outer::Inner::DeepPart` resolve correctly
231
- - **Cross-package**: `import A::B::*` works across arbitrary package depth
232
- - **Library whitelist**: 80+ standard library symbols (`ScalarValues::Integer`, `ISQ::LengthValue`, etc.) are pre-recognized
227
+ The analyzer resolves three import patterns with visibility enforcement:
228
+
229
+ | Pattern | Example | Visibility | Effect |
230
+ |---------|---------|------------|--------|
231
+ | Namespace import | `import Types::*` | `private` (default) | Makes all symbols from `Types` visible in current scope only |
232
+ | Membership import | `import Types::Engine` | `private` | Makes only `Engine` visible in current scope |
233
+ | Recursive import | `import Types::*::**` | `private` | Imports from `Types` and all nested packages |
234
+ | Public import | `public import Types::*` | `public` | Re-exports symbols to sibling and child scopes |
235
+ | Protected import | `protected import Types::*` | `protected` | Visible to child scopes only, not re-exported |
236
+
237
+ ### OCL Well-Formedness Checks
238
+
239
+ | Code | Rule | Description |
240
+ |------|------|-------------|
241
+ | `DUPLICATE_NAME` | Namespace.duplicate_names | No two members may share the same name in a scope |
242
+ | `CYCLIC_SPECIALIZATION` | Type.no_cyclic_specialization | A type cannot directly or indirectly specialize itself |
243
+ | `INCOMPATIBLE_SUBSETTING` | Feature.subsetting_compatible | A subsetting feature must reference a defined feature in the inheritance chain |
244
+ | `INCOMPATIBLE_REDEFINITION` | Feature.redefinition_compatible | A redefining feature must reference a defined feature in the inheritance chain |
245
+ | `INCOMPATIBLE_PART_DEFINITION` | Part.definition_compatible | A part usage must be typed by a PartDefinition |
246
+ | `INCOMPATIBLE_PORT_DEFINITION` | Port.definition_compatible | A port usage must be typed by a PortDefinition |
247
+ | `INCOMPATIBLE_FEATURE_CHAIN` | Feature.chaining_compatible | Chained features (`a.b.c`) must have compatible types at each step |
248
+ | `INVALID_MULTIPLICITY_BOUNDS` | Multiplicity.bounds_valid | Lower bound must be ≤ upper bound (`[5..2]` is invalid) |
249
+ | `UNRESOLVED_IMPORT` | — | Import target does not exist in the model |
233
250
 
234
251
  ## Storage Backends
235
252
 
@@ -6,7 +6,7 @@ build-backend = "poetry.core.masonry.api"
6
6
 
7
7
  [project]
8
8
  name = "sysmlpy"
9
- version = "0.19.2"
9
+ version = "0.20.0"
10
10
  description = "SysML v2.0 Parser"
11
11
  authors = [
12
12
  { name="Jon R. Fox (mycr0ft)", email="jon.fox@drfox.com" },
@@ -114,7 +114,7 @@ build_command = "pip install poetry && poetry build"
114
114
 
115
115
  [tool.poetry]
116
116
  name = "sysmlpy"
117
- version = "0.19.2"
117
+ version = "0.20.0"
118
118
  description = ""
119
119
  authors = ["Jon R. Fox (mycr0ft) <jon.fox@drfox.com>"]
120
120
  readme = "README.md"
@@ -15,7 +15,7 @@ __all__ = [
15
15
  "analyze", "SemanticIssue", "SemanticAnalyzer",
16
16
  ]
17
17
  __author__ = "Jon Fox"
18
- __version__ = "0.19.2"
18
+ __version__ = "0.20.0"
19
19
 
20
20
  from sysmlpy.usage import (
21
21
  Item, Attribute, Part, Port, Action, Reference, UseCase, Requirement, Interface, Message,
@@ -10215,12 +10215,16 @@ def _build_full_specialization_from_ctx(ctx):
10215
10215
  return None
10216
10216
 
10217
10217
  specs = fsp.featureSpecialization() if hasattr(fsp, 'featureSpecialization') else []
10218
- if not specs:
10219
- return None
10220
-
10221
10218
  if not isinstance(specs, list):
10222
10219
  specs = [specs]
10223
10220
 
10221
+ # Extract multiplicity first (before the early return check)
10222
+ multiplicity = _get_multiplicity_part(fsp)
10223
+
10224
+ # Only return None if there are neither specializations nor multiplicity
10225
+ if not specs and multiplicity is None:
10226
+ return None
10227
+
10224
10228
  specialization_list = []
10225
10229
 
10226
10230
  for spec in specs:
@@ -10348,14 +10352,6 @@ def _build_full_specialization_from_ctx(ctx):
10348
10352
  }
10349
10353
  })
10350
10354
 
10351
- if not specialization_list and fsp is None:
10352
- return None
10353
-
10354
- multiplicity = _get_multiplicity_part(fsp)
10355
-
10356
- if not specialization_list and multiplicity is None:
10357
- return None
10358
-
10359
10355
  return {
10360
10356
  "name": "FeatureSpecializationPart",
10361
10357
  "specialization": specialization_list,