sysmlpy 0.76.0__tar.gz → 0.77.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 (159) hide show
  1. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/PKG-INFO +3 -1
  2. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/pyproject.toml +3 -1
  3. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/__init__.py +1 -1
  4. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/store.py +210 -91
  5. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/LICENSE +0 -0
  6. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/README.md +0 -0
  7. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/__main__.py +0 -0
  8. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/antlr/README.md +0 -0
  9. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/antlr/SysMLv2Lexer.interp +0 -0
  10. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/antlr/SysMLv2Lexer.py +0 -0
  11. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/antlr/SysMLv2Lexer.tokens +0 -0
  12. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/antlr/SysMLv2Parser.interp +0 -0
  13. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/antlr/SysMLv2Parser.py +0 -0
  14. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/antlr/SysMLv2Parser.tokens +0 -0
  15. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/antlr/SysMLv2ParserListener.py +0 -0
  16. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/antlr/SysMLv2ParserVisitor.py +0 -0
  17. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/antlr/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.interp +0 -0
  18. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/antlr/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.py +0 -0
  19. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/antlr/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.tokens +0 -0
  20. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/antlr_parser.py +0 -0
  21. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/antlr_visitor.py +0 -0
  22. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/boxes_view.py +0 -0
  23. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/definition.py +0 -0
  24. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/diff.py +0 -0
  25. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/evaluator.py +0 -0
  26. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/examples/attribute_values.py +0 -0
  27. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/examples/part_attributes.py +0 -0
  28. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/examples/tuples_sequences.py +0 -0
  29. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/formatting.py +0 -0
  30. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/grammar/antlr4/README.md +0 -0
  31. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.g4 +0 -0
  32. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.interp +0 -0
  33. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.py +0 -0
  34. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/grammar/antlr4/SysMLv2Lexer.tokens +0 -0
  35. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/grammar/antlr4/SysMLv2Parser.g4 +0 -0
  36. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/grammar/antlr4/SysMLv2Parser.interp +0 -0
  37. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/grammar/antlr4/SysMLv2Parser.py +0 -0
  38. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/grammar/antlr4/SysMLv2Parser.tokens +0 -0
  39. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/grammar/antlr4/SysMLv2ParserListener.py +0 -0
  40. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/grammar/antlr4/SysMLv2ParserVisitor.py +0 -0
  41. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/grammar/antlr4/desc.xml +0 -0
  42. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/grammar/antlr4/examples/camera.sysml +0 -0
  43. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/grammar/antlr4/examples/toaster-system.sysml +0 -0
  44. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/grammar/antlr4/examples/vehicle-model.sysml +0 -0
  45. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/grammar/antlr4/pom.xml +0 -0
  46. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/grammar/classes.py +0 -0
  47. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/interchange.py +0 -0
  48. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/LICENSE +0 -0
  49. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/README.md +0 -0
  50. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/__init__.py +0 -0
  51. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/domain/Analysis/AnalysisTooling.sysml +0 -0
  52. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/domain/Analysis/SampledFunctions.sysml +0 -0
  53. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/domain/Analysis/StateSpaceRepresentation.sysml +0 -0
  54. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/domain/Analysis/TradeStudies.sysml +0 -0
  55. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/domain/Cause and Effect/CausationConnections.sysml +0 -0
  56. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/domain/Cause and Effect/CauseAndEffect.sysml +0 -0
  57. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/domain/Geometry/ShapeItems.sysml +0 -0
  58. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/domain/Geometry/SpatialItems.sysml +0 -0
  59. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/domain/Metadata/ImageMetadata.sysml +0 -0
  60. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/domain/Metadata/ModelingMetadata.sysml +0 -0
  61. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/domain/Metadata/ParametersOfInterestMetadata.sysml +0 -0
  62. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/domain/Metadata/RiskMetadata.sysml +0 -0
  63. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/domain/Quantities and Units/ISQ.sysml +0 -0
  64. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/domain/Quantities and Units/ISQAcoustics.sysml +0 -0
  65. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/domain/Quantities and Units/ISQAtomicNuclear.sysml +0 -0
  66. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/domain/Quantities and Units/ISQBase.sysml +0 -0
  67. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/domain/Quantities and Units/ISQCharacteristicNumbers.sysml +0 -0
  68. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/domain/Quantities and Units/ISQChemistryMolecular.sysml +0 -0
  69. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/domain/Quantities and Units/ISQCondensedMatter.sysml +0 -0
  70. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/domain/Quantities and Units/ISQElectromagnetism.sysml +0 -0
  71. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/domain/Quantities and Units/ISQInformation.sysml +0 -0
  72. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/domain/Quantities and Units/ISQLight.sysml +0 -0
  73. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/domain/Quantities and Units/ISQMechanics.sysml +0 -0
  74. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/domain/Quantities and Units/ISQSpaceTime.sysml +0 -0
  75. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/domain/Quantities and Units/ISQThermodynamics.sysml +0 -0
  76. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/domain/Quantities and Units/MeasurementRefCalculations.sysml +0 -0
  77. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/domain/Quantities and Units/MeasurementReferences.sysml +0 -0
  78. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/domain/Quantities and Units/Quantities.sysml +0 -0
  79. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/domain/Quantities and Units/QuantityCalculations.sysml +0 -0
  80. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/domain/Quantities and Units/SI.sysml +0 -0
  81. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/domain/Quantities and Units/SIPrefixes.sysml +0 -0
  82. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/domain/Quantities and Units/TensorCalculations.sysml +0 -0
  83. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/domain/Quantities and Units/Time.sysml +0 -0
  84. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/domain/Quantities and Units/USCustomaryUnits.sysml +0 -0
  85. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/domain/Quantities and Units/VectorCalculations.sysml +0 -0
  86. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/domain/Requirement Derivation/DerivationConnections.sysml +0 -0
  87. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/domain/Requirement Derivation/RequirementDerivation.sysml +0 -0
  88. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/kernel/Base.kerml +0 -0
  89. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/kernel/BaseFunctions.kerml +0 -0
  90. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/kernel/BooleanFunctions.kerml +0 -0
  91. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/kernel/Clocks.kerml +0 -0
  92. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/kernel/CollectionFunctions.kerml +0 -0
  93. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/kernel/Collections.kerml +0 -0
  94. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/kernel/ComplexFunctions.kerml +0 -0
  95. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/kernel/ControlFunctions.kerml +0 -0
  96. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/kernel/ControlPerformances.kerml +0 -0
  97. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/kernel/DataFunctions.kerml +0 -0
  98. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/kernel/FeatureReferencingPerformances.kerml +0 -0
  99. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/kernel/IntegerFunctions.kerml +0 -0
  100. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/kernel/KerML.kerml +0 -0
  101. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/kernel/Links.kerml +0 -0
  102. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/kernel/Metaobjects.kerml +0 -0
  103. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/kernel/NaturalFunctions.kerml +0 -0
  104. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/kernel/NumericalFunctions.kerml +0 -0
  105. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/kernel/Objects.kerml +0 -0
  106. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/kernel/Observation.kerml +0 -0
  107. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/kernel/OccurrenceFunctions.kerml +0 -0
  108. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/kernel/Occurrences.kerml +0 -0
  109. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/kernel/Performances.kerml +0 -0
  110. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/kernel/RationalFunctions.kerml +0 -0
  111. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/kernel/RealFunctions.kerml +0 -0
  112. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/kernel/ScalarFunctions.kerml +0 -0
  113. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/kernel/ScalarValues.kerml +0 -0
  114. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/kernel/SequenceFunctions.kerml +0 -0
  115. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/kernel/SpatialFrames.kerml +0 -0
  116. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/kernel/StatePerformances.kerml +0 -0
  117. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/kernel/StringFunctions.kerml +0 -0
  118. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/kernel/Transfers.kerml +0 -0
  119. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/kernel/TransitionPerformances.kerml +0 -0
  120. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/kernel/TrigFunctions.kerml +0 -0
  121. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/kernel/Triggers.kerml +0 -0
  122. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/kernel/VectorFunctions.kerml +0 -0
  123. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/kernel/VectorValues.kerml +0 -0
  124. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/systems/Actions.sysml +0 -0
  125. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/systems/Allocations.sysml +0 -0
  126. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/systems/AnalysisCases.sysml +0 -0
  127. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/systems/Attributes.sysml +0 -0
  128. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/systems/Calculations.sysml +0 -0
  129. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/systems/Cases.sysml +0 -0
  130. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/systems/Connections.sysml +0 -0
  131. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/systems/Constraints.sysml +0 -0
  132. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/systems/Flows.sysml +0 -0
  133. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/systems/Interfaces.sysml +0 -0
  134. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/systems/Items.sysml +0 -0
  135. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/systems/Metadata.sysml +0 -0
  136. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/systems/Parts.sysml +0 -0
  137. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/systems/Ports.sysml +0 -0
  138. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/systems/Requirements.sysml +0 -0
  139. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/systems/StandardViewDefinitions.sysml +0 -0
  140. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/systems/States.sysml +0 -0
  141. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/systems/SysML.sysml +0 -0
  142. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/systems/UseCases.sysml +0 -0
  143. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/systems/VerificationCases.sysml +0 -0
  144. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/library/systems/Views.sysml +0 -0
  145. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/lsp/__init__.py +0 -0
  146. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/lsp/__main__.py +0 -0
  147. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/lsp/protocol.py +0 -0
  148. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/lsp/server.py +0 -0
  149. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/lsp/stdio.py +0 -0
  150. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/navigate.py +0 -0
  151. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/plantuml.py +0 -0
  152. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/project.py +0 -0
  153. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/semantic.py +0 -0
  154. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/sim.py +0 -0
  155. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/spreadsheet.py +0 -0
  156. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/traceability.py +0 -0
  157. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/us_customary_units.txt +0 -0
  158. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/usage.py +0 -0
  159. {sysmlpy-0.76.0 → sysmlpy-0.77.0}/src/sysmlpy/validator.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sysmlpy
3
- Version: 0.76.0
3
+ Version: 0.77.0
4
4
  Summary:
5
5
  License-File: LICENSE
6
6
  Author: Jon R. Fox (mycr0ft)
@@ -13,6 +13,7 @@ Classifier: Programming Language :: Python :: 3.11
13
13
  Classifier: Programming Language :: Python :: 3.12
14
14
  Classifier: Programming Language :: Python :: 3.13
15
15
  Classifier: Programming Language :: Python :: 3.14
16
+ Provides-Extra: cayley
16
17
  Provides-Extra: graph
17
18
  Provides-Extra: kuzu
18
19
  Provides-Extra: sim
@@ -24,6 +25,7 @@ Requires-Dist: networkx (>=3.0) ; extra == "graph"
24
25
  Requires-Dist: openpyxl (>=3.1) ; extra == "xlsx"
25
26
  Requires-Dist: pint (>=0.24)
26
27
  Requires-Dist: pyyaml (>=6.0)
28
+ Requires-Dist: requests (>=2.31) ; extra == "cayley"
27
29
  Requires-Dist: transitions (>=0.9,<0.10) ; extra == "sim"
28
30
  Description-Content-Type: text/markdown
29
31
 
@@ -6,7 +6,7 @@ build-backend = "poetry.core.masonry.api"
6
6
 
7
7
  [project]
8
8
  name = "sysmlpy"
9
- version = "0.76.0"
9
+ version = "0.77.0"
10
10
  description = ""
11
11
  authors = [{ name = "Jon R. Fox (mycr0ft)", email = "jon.fox@drfox.com" }]
12
12
  readme = "README.md"
@@ -22,12 +22,14 @@ kuzu = { version = ">=0.7,<0.12", optional = true }
22
22
  openpyxl = { version = ">=3.1", optional = true }
23
23
  arrow = "^1.4.0"
24
24
  transitions = {version = "^0.9", optional = true}
25
+ requests = { version = ">=2.31", optional = true }
25
26
 
26
27
  [tool.poetry.extras]
27
28
  graph = ["networkx"]
28
29
  kuzu = ["kuzu"]
29
30
  xlsx = ["openpyxl"]
30
31
  sim = ["transitions"]
32
+ cayley = ["requests"]
31
33
 
32
34
  [tool.poetry.scripts]
33
35
  sysmlpy = "sysmlpy.__main__:main"
@@ -34,7 +34,7 @@ __all__ = [
34
34
  "render_state_transition_view_svg", "boxes_view",
35
35
  ]
36
36
  __author__ = "Jon Fox"
37
- __version__ = "0.76.0"
37
+ __version__ = "0.77.0"
38
38
 
39
39
  from sysmlpy.usage import (
40
40
  Item, Attribute, Part, Port, Action, Reference, UseCase, Requirement, Interface, Message,
@@ -1678,7 +1678,18 @@ class CayleyStore(Store):
1678
1678
  This backend communicates with a running Cayley server over HTTP,
1679
1679
  supporting both in-memory and persistent backends (BoltDB, LevelDB, etc.).
1680
1680
 
1681
- Requires: A running Cayley server (Docker or binary).
1681
+ Requires: A running Cayley server (Docker or binary):
1682
+
1683
+ podman run -d --name cayley -p 64210:64210 \
1684
+ docker.io/cayleygraph/cayley
1685
+
1686
+ (BoltDB backend persisted inside the container; stop with
1687
+ ``podman stop cayley``, restart with ``podman start cayley``.)
1688
+
1689
+ Since v0.77.0 stored subjects are label-namespaced
1690
+ (``<label>:<element_id>``), so multiple stores can share one
1691
+ server without query bleed (Cayley gizmo queries are otherwise
1692
+ quad-label-blind).
1682
1693
 
1683
1694
  Usage:
1684
1695
  # Default connection
@@ -1780,14 +1791,38 @@ class CayleyStore(Store):
1780
1791
  ----------
1781
1792
  quads : list[dict]
1782
1793
  List of quad dicts to delete.
1794
+
1795
+ Note
1796
+ ----
1797
+ Cayley's delete endpoint is ``/api/v1/delete``. Posting quads
1798
+ to ``/api/v1/write`` *adds* them (a no-op for quads that
1799
+ already exist — which is how this bug hid: nothing was ever
1800
+ removed and nothing visibly changed).
1783
1801
  """
1784
1802
  session = self._get_session()
1785
1803
  resp = session.post(
1786
- f"{self._base_url}/api/v1/write",
1804
+ f"{self._base_url}/api/v1/delete",
1787
1805
  json=quads
1788
1806
  )
1789
1807
  resp.raise_for_status()
1790
1808
 
1809
+ def _k(self, element_id: str) -> str:
1810
+ """Internal (label-namespaced) subject key for *element_id*.
1811
+
1812
+ Cayley's gizmo queries (``g.V(id)`` and traversals) are
1813
+ quad-label-blind: two stores using different labels but the
1814
+ same subject IDs would see each other's quads. Prefixing the
1815
+ stored subject with the store label namespaces the graph
1816
+ (``<label>:<element_id>``) so every query is naturally
1817
+ scoped; the public API keeps unprefixed IDs.
1818
+ """
1819
+ return f"{self._label}:{element_id}"
1820
+
1821
+ @staticmethod
1822
+ def _u(key: str) -> str:
1823
+ """Strip the label namespace from an internal subject key."""
1824
+ return key.split(":", 1)[1] if ":" in key else key
1825
+
1791
1826
  def _escape(self, value: str) -> str:
1792
1827
  """Escape a value for use in a Gizmo query string."""
1793
1828
  return value.replace("\\", "\\\\").replace('"', '\\"')
@@ -1811,27 +1846,57 @@ class CayleyStore(Store):
1811
1846
  import json
1812
1847
  quads = []
1813
1848
 
1849
+ # Overwrite semantics (parity with InMemoryStore / NetworkXStore,
1850
+ # where put() replaces the data dict): first remove this
1851
+ # element's existing marker and property quads. Relationship
1852
+ # edges are kept — re-adding an identical edge quad is a no-op,
1853
+ # and edges must survive re-put of an element.
1854
+ key = self._k(element_id)
1855
+ try:
1856
+ old_preds = self._query(
1857
+ f'g.V("{key}").outPredicates().all()'
1858
+ )
1859
+ stale = []
1860
+ for pr in old_preds:
1861
+ pred_name = pr.get("id", "")
1862
+ if pred_name in (REL_PARENT_CHILD, REL_TYPED_BY,
1863
+ REL_SPECIALIZES):
1864
+ continue # keep relationship edges
1865
+ for obj in self._query(
1866
+ f'g.V("{key}").out("{pred_name}").all()'
1867
+ ):
1868
+ stale.append({
1869
+ "subject": key,
1870
+ "predicate": pred_name,
1871
+ "object": obj.get("id", ""),
1872
+ "label": self._label
1873
+ })
1874
+ if stale:
1875
+ self._delete_quads(stale)
1876
+ except RuntimeError:
1877
+ pass
1878
+
1814
1879
  # Mark this as an element node with store label
1815
1880
  quads.append({
1816
- "subject": element_id,
1881
+ "subject": key,
1817
1882
  "predicate": "_is_element",
1818
1883
  "object": "true",
1819
1884
  "label": self._label
1820
1885
  })
1821
1886
  quads.append({
1822
- "subject": element_id,
1887
+ "subject": key,
1823
1888
  "predicate": "_store_label",
1824
1889
  "object": self._label,
1825
1890
  "label": self._label
1826
1891
  })
1827
1892
 
1828
1893
  # Store element properties as quads
1829
- for key, value in data.items():
1894
+ for pname, value in data.items():
1830
1895
  if isinstance(value, (dict, list)):
1831
1896
  value = json.dumps(value)
1832
1897
  quads.append({
1833
- "subject": element_id,
1834
- "predicate": key,
1898
+ "subject": key,
1899
+ "predicate": pname,
1835
1900
  "object": str(value),
1836
1901
  "label": self._label
1837
1902
  })
@@ -1841,9 +1906,9 @@ class CayleyStore(Store):
1841
1906
  # Add relationship edge
1842
1907
  if parent_id is not None:
1843
1908
  self._write([{
1844
- "subject": parent_id,
1909
+ "subject": self._k(parent_id),
1845
1910
  "predicate": rel_type,
1846
- "object": element_id,
1911
+ "object": key,
1847
1912
  "label": self._label
1848
1913
  }])
1849
1914
 
@@ -1861,33 +1926,24 @@ class CayleyStore(Store):
1861
1926
  Element attributes dict, or None if not found.
1862
1927
  """
1863
1928
  import json
1864
- results = self._query(f'g.V("{element_id}").out().all()')
1865
- if not results:
1929
+ key = self._k(element_id)
1930
+ if not self.has(element_id):
1866
1931
  return None
1932
+ pred_obj = self._query(f'g.V("{key}").outPredicates().all()')
1867
1933
 
1868
1934
  data = {}
1869
- for result in results:
1870
- # Results are like {"id": "name"}, {"id": "Wheel"}, etc.
1871
- # We need to get the predicate too
1872
- pass
1873
-
1874
- # Better approach: get all predicates and objects
1875
- results = self._query(f'g.V("{element_id}").tag("subj").out().save("pred", "key").all()')
1876
- # Actually, let's use a simpler approach
1877
- results = self._query(f'g.V("{element_id}").out().all()')
1878
-
1879
- # Get predicate-object pairs
1880
- pred_obj = self._query(
1881
- f'g.V("{element_id}").outPredicates().all()'
1882
- )
1883
-
1884
- # Reconstruct data from individual queries
1885
1935
  for pred_result in pred_obj:
1886
1936
  pred = pred_result.get("id", "")
1887
- if pred in ("id",):
1937
+ if pred in ("id", "_is_element", "_store_label",
1938
+ REL_PARENT_CHILD, REL_TYPED_BY, REL_SPECIALIZES):
1939
+ # Internal markers and relationship edges are not
1940
+ # element data — edges are exposed via children() /
1941
+ # parents() / relationships() instead (parity with
1942
+ # InMemoryStore / NetworkXStore, where get() returns
1943
+ # exactly the put() data dict).
1888
1944
  continue
1889
1945
  obj_results = self._query(
1890
- f'g.V("{element_id}").out("{pred}").all()'
1946
+ f'g.V("{key}").out("{pred}").all()'
1891
1947
  )
1892
1948
  if obj_results:
1893
1949
  val = obj_results[0].get("id", "")
@@ -1903,10 +1959,9 @@ class CayleyStore(Store):
1903
1959
  def delete(self, element_id: str) -> bool:
1904
1960
  """Remove an element and all its incident quads.
1905
1961
 
1906
- Note: Cayley's HTTP API has limited delete support. This method
1907
- marks the element as deleted by removing its _is_element quad.
1908
- The element will no longer appear in ids() or has() results,
1909
- but orphaned property quads may remain.
1962
+ Deletes the element's marker quads, property quads and
1963
+ outgoing relationship edges, plus any incoming relationship
1964
+ edges, via Cayley's ``/api/v1/delete`` endpoint.
1910
1965
 
1911
1966
  Parameters
1912
1967
  ----------
@@ -1921,26 +1976,20 @@ class CayleyStore(Store):
1921
1976
  if not self.has(element_id):
1922
1977
  return False
1923
1978
 
1924
- # Delete the _is_element quad to mark as deleted
1925
- # Cayley HTTP API doesn't support true deletion, so we use soft delete
1926
- quads_to_delete = [{
1927
- "subject": element_id,
1928
- "predicate": "_is_element",
1929
- "object": "true",
1930
- "label": self._label
1931
- }]
1979
+ key = self._k(element_id)
1980
+ quads_to_delete = []
1932
1981
 
1933
- # Try to delete outgoing property quads
1982
+ # Outgoing quads: markers, properties, outbound rel edges
1934
1983
  try:
1935
- preds = self._query(f'g.V("{element_id}").outPredicates().all()')
1984
+ preds = self._query(f'g.V("{key}").outPredicates().all()')
1936
1985
  for pred in preds:
1937
1986
  p = pred.get("id", "")
1938
- if p == "_is_element":
1939
- continue
1940
- objs = self._query(f'g.V("{element_id}").out("{p}").all()')
1987
+ objs = self._query(
1988
+ f'g.V("{key}").out("{p}").all()'
1989
+ )
1941
1990
  for obj in objs:
1942
1991
  quads_to_delete.append({
1943
- "subject": element_id,
1992
+ "subject": key,
1944
1993
  "predicate": p,
1945
1994
  "object": obj.get("id", ""),
1946
1995
  "label": self._label
@@ -1948,9 +1997,29 @@ class CayleyStore(Store):
1948
1997
  except RuntimeError:
1949
1998
  pass
1950
1999
 
1951
- # Note: Cayley HTTP API doesn't actually delete quads via /api/v1/write
1952
- # We rely on the _is_element marker for logical deletion
1953
- # The quads remain in the database but the element is hidden from queries
2000
+ # Incoming relationship edges (parent -> element): without this
2001
+ # parents()/children() would keep returning ghost links.
2002
+ try:
2003
+ in_preds = self._query(
2004
+ f'g.V("{key}").inPredicates().all()'
2005
+ )
2006
+ for pred in in_preds:
2007
+ p = pred.get("id", "")
2008
+ parents = self._query(
2009
+ f'g.V("{key}").in("{p}").all()'
2010
+ )
2011
+ for parent in parents:
2012
+ quads_to_delete.append({
2013
+ "subject": parent.get("id", ""),
2014
+ "predicate": p,
2015
+ "object": key,
2016
+ "label": self._label
2017
+ })
2018
+ except RuntimeError:
2019
+ pass
2020
+
2021
+ if quads_to_delete:
2022
+ self._delete_quads(quads_to_delete)
1954
2023
  return True
1955
2024
 
1956
2025
  def children(self, parent_id: str, rel_type: str = REL_PARENT_CHILD) -> list[str]:
@@ -1968,10 +2037,11 @@ class CayleyStore(Store):
1968
2037
  list[str]
1969
2038
  List of child element IDs.
1970
2039
  """
2040
+ key = self._k(parent_id)
1971
2041
  results = self._query(
1972
- f'g.V("{parent_id}").out("{rel_type}").has("_store_label", "{self._label}").all()'
2042
+ f'g.V("{key}").out("{rel_type}").has("_store_label", "{self._label}").all()'
1973
2043
  )
1974
- return [r.get("id", "") for r in results]
2044
+ return [self._u(r.get("id", "")) for r in results]
1975
2045
 
1976
2046
  def parents(self, child_id: str, rel_type: Optional[str] = None) -> list[str]:
1977
2047
  """Get parent element IDs connected by incoming edges.
@@ -1988,15 +2058,16 @@ class CayleyStore(Store):
1988
2058
  list[str]
1989
2059
  List of parent element IDs.
1990
2060
  """
2061
+ key = self._k(child_id)
1991
2062
  if rel_type:
1992
2063
  results = self._query(
1993
- f'g.V().out("{rel_type}").is("{child_id}").has("_store_label", "{self._label}").all()'
2064
+ f'g.V().out("{rel_type}").is("{key}").has("_store_label", "{self._label}").all()'
1994
2065
  )
1995
2066
  else:
1996
2067
  results = self._query(
1997
- f'g.V("{child_id}").in().has("_store_label", "{self._label}").all()'
2068
+ f'g.V("{key}").in().has("_store_label", "{self._label}").all()'
1998
2069
  )
1999
- return [r.get("id", "") for r in results]
2070
+ return [self._u(r.get("id", "")) for r in results]
2000
2071
 
2001
2072
  def relationships(self, element_id: str,
2002
2073
  rel_type: Optional[str] = None,
@@ -2027,49 +2098,55 @@ class CayleyStore(Store):
2027
2098
 
2028
2099
  edges = []
2029
2100
 
2101
+ key = self._k(element_id)
2102
+
2030
2103
  if direction in ("out", "both"):
2031
2104
  if rel_type:
2032
2105
  results = self._query(
2033
- f'g.V("{element_id}").out("{rel_type}").all()'
2106
+ f'g.V("{key}").out("{rel_type}").all()'
2034
2107
  )
2035
2108
  for r in results:
2036
- edges.append((r.get("id", ""), rel_type, {"rel_type": rel_type}))
2109
+ edges.append((self._u(r.get("id", "")), rel_type,
2110
+ {"rel_type": rel_type}))
2037
2111
  else:
2038
2112
  # Get all outgoing edges, filter to known relationship types
2039
2113
  results = self._query(
2040
- f'g.V("{element_id}").outPredicates().all()'
2114
+ f'g.V("{key}").outPredicates().all()'
2041
2115
  )
2042
2116
  for pred in results:
2043
2117
  p = pred.get("id", "")
2044
2118
  if p not in known_rel_types:
2045
2119
  continue
2046
2120
  targets = self._query(
2047
- f'g.V("{element_id}").out("{p}").all()'
2121
+ f'g.V("{key}").out("{p}").all()'
2048
2122
  )
2049
2123
  for t in targets:
2050
- edges.append((t.get("id", ""), p, {"rel_type": p}))
2124
+ edges.append((self._u(t.get("id", "")), p,
2125
+ {"rel_type": p}))
2051
2126
 
2052
2127
  if direction in ("in", "both"):
2053
2128
  if rel_type:
2054
2129
  results = self._query(
2055
- f'g.V().out("{rel_type}").is("{element_id}").all()'
2130
+ f'g.V().out("{rel_type}").is("{key}").all()'
2056
2131
  )
2057
2132
  for r in results:
2058
- edges.append((r.get("id", ""), rel_type, {"rel_type": rel_type}))
2133
+ edges.append((self._u(r.get("id", "")), rel_type,
2134
+ {"rel_type": rel_type}))
2059
2135
  else:
2060
2136
  # Get all incoming edges, filter to known relationship types
2061
2137
  results = self._query(
2062
- f'g.V("{element_id}").inPredicates().all()'
2138
+ f'g.V("{key}").inPredicates().all()'
2063
2139
  )
2064
2140
  for pred in results:
2065
2141
  p = pred.get("id", "")
2066
2142
  if p not in known_rel_types:
2067
2143
  continue
2068
2144
  sources = self._query(
2069
- f'g.V("{element_id}").in("{p}").all()'
2145
+ f'g.V("{key}").in("{p}").all()'
2070
2146
  )
2071
- for s in sources:
2072
- edges.append((s.get("id", ""), p, {"rel_type": p}))
2147
+ for src in sources:
2148
+ edges.append((self._u(src.get("id", "")), p,
2149
+ {"rel_type": p}))
2073
2150
 
2074
2151
  return edges
2075
2152
 
@@ -2087,18 +2164,49 @@ class CayleyStore(Store):
2087
2164
  List of matching element IDs.
2088
2165
  """
2089
2166
  if not filters:
2090
- return self._query(
2167
+ results = self._query(
2091
2168
  f'g.V().has("_store_label", "{self._label}").all()'
2092
2169
  )
2170
+ return [self._u(r.get("id", "")) for r in results]
2171
+
2172
+ # Glob filters ('*' in the 'name' value) cannot be expressed as
2173
+ # has() constraints (Cayley matches literally), so take the
2174
+ # client-side fnmatch path for parity with NetworkXStore,
2175
+ # KuzuStore and InMemoryStore (Goal 10 batch 3).
2176
+ has_glob = any(k == "name" and "*" in str(v)
2177
+ for k, v in filters.items())
2178
+
2179
+ if has_glob:
2180
+ results = []
2181
+ import fnmatch
2182
+ for r in self._query(
2183
+ f'g.V().has("_store_label", "{self._label}").all()'
2184
+ ):
2185
+ eid = self._u(r.get("id", ""))
2186
+ data = self.get(eid) or {}
2187
+ match = True
2188
+ for key, value in filters.items():
2189
+ if key == "name" and "*" in str(value):
2190
+ if not fnmatch.fnmatch(
2191
+ data.get("name", ""), str(value)
2192
+ ):
2193
+ match = False
2194
+ break
2195
+ elif data.get(key) != value:
2196
+ match = False
2197
+ break
2198
+ if match:
2199
+ results.append(eid)
2200
+ return results
2093
2201
 
2094
2202
  # Build query with has() constraints, including store label filter
2095
2203
  conditions = [f'.has("_store_label", "{self._label}")']
2096
- for key, value in filters.items():
2097
- conditions.append(f'.has("{key}", "{value}")')
2204
+ for fkey, value in filters.items():
2205
+ conditions.append(f'.has("{fkey}", "{value}")')
2098
2206
 
2099
2207
  query = "g.V()" + "".join(conditions) + ".all()"
2100
2208
  results = self._query(query)
2101
- return [r.get("id", "") for r in results]
2209
+ return [self._u(r.get("id", "")) for r in results]
2102
2210
 
2103
2211
  def has(self, element_id: str) -> bool:
2104
2212
  """Check if an element exists in the graph.
@@ -2115,7 +2223,7 @@ class CayleyStore(Store):
2115
2223
  """
2116
2224
  try:
2117
2225
  results = self._query(
2118
- f'g.V("{element_id}").has("_store_label", "{self._label}").all()'
2226
+ f'g.V("{self._k(element_id)}").has("_store_label", "{self._label}").all()'
2119
2227
  )
2120
2228
  return len(results) > 0 if results else False
2121
2229
  except RuntimeError:
@@ -2129,12 +2237,9 @@ class CayleyStore(Store):
2129
2237
  int
2130
2238
  Number of elements.
2131
2239
  """
2132
- results = self._query("g.V().count()")
2133
- if results and results[0]:
2134
- val = results[0].get("id", 0)
2135
- if val is not None:
2136
- return int(val)
2137
- # Fallback: count manually
2240
+ # g.V().count() would count the whole database (all stores'
2241
+ # labels plus literal object nodes); count this store's
2242
+ # elements only.
2138
2243
  return len(list(self.ids()))
2139
2244
 
2140
2245
  def ids(self) -> Iterator[str]:
@@ -2149,22 +2254,27 @@ class CayleyStore(Store):
2149
2254
  f'g.V().has("_store_label", "{self._label}").all()'
2150
2255
  )
2151
2256
  for r in results:
2152
- yield r.get("id", "")
2257
+ yield self._u(r.get("id", ""))
2153
2258
 
2154
2259
  def clear(self) -> None:
2155
2260
  """Remove all quads with the store's label."""
2156
- # Delete all quads with our label by iterating and deleting
2157
- results = self._query_label("g.V().all()")
2261
+ # Iterate this store's elements (label-scoped via the
2262
+ # _store_label marker quad; subjects carry the "<label>:"
2263
+ # namespace) and delete their out-quads. g.V().all() would
2264
+ # also match other stores' quads.
2265
+ results = self._query(
2266
+ f'g.V().has("_store_label", "{self._label}").all()'
2267
+ )
2158
2268
  quads_to_delete = []
2159
2269
  for r in results:
2160
- eid = r.get("id", "")
2161
- preds = self._query(f'g.V("{eid}").outPredicates().all()')
2270
+ key = r.get("id", "") # already label-namespaced
2271
+ preds = self._query(f'g.V("{key}").outPredicates().all()')
2162
2272
  for pred in preds:
2163
2273
  p = pred.get("id", "")
2164
- objs = self._query(f'g.V("{eid}").out("{p}").all()')
2274
+ objs = self._query(f'g.V("{key}").out("{p}").all()')
2165
2275
  for obj in objs:
2166
2276
  quads_to_delete.append({
2167
- "subject": eid,
2277
+ "subject": key,
2168
2278
  "predicate": p,
2169
2279
  "object": obj.get("id", ""),
2170
2280
  "label": self._label
@@ -2177,17 +2287,19 @@ class CayleyStore(Store):
2177
2287
 
2178
2288
  def descendants(self, root_id: str, rel_type: str = REL_PARENT_CHILD) -> list[str]:
2179
2289
  """Return all descendants via recursive traversal."""
2290
+ key = self._k(root_id)
2180
2291
  results = self._query(
2181
- f'g.V("{root_id}").followRecursive(g.Morphism().out("{rel_type}")).all()'
2292
+ f'g.V("{key}").followRecursive(g.Morphism().out("{rel_type}")).all()'
2182
2293
  )
2183
- return [r.get("id", "") for r in results]
2294
+ return [self._u(r.get("id", "")) for r in results]
2184
2295
 
2185
2296
  def ancestors(self, leaf_id: str, rel_type: str = REL_PARENT_CHILD) -> list[str]:
2186
2297
  """Return all ancestors via reverse recursive traversal."""
2298
+ key = self._k(leaf_id)
2187
2299
  results = self._query(
2188
- f'g.V("{leaf_id}").followRecursive(g.Morphism().in("{rel_type}")).all()'
2300
+ f'g.V("{key}").followRecursive(g.Morphism().in("{rel_type}")).all()'
2189
2301
  )
2190
- return [r.get("id", "") for r in results]
2302
+ return [self._u(r.get("id", "")) for r in results]
2191
2303
 
2192
2304
  def path(self, source_id: str, target_id: str,
2193
2305
  rel_type: str = REL_PARENT_CHILD) -> Optional[list[str]]:
@@ -2294,12 +2406,19 @@ class CayleyStore(Store):
2294
2406
  if data is not None:
2295
2407
  new_store.put(eid, data)
2296
2408
 
2409
+ # Re-create the edges that stay inside the subgraph. Written
2410
+ # directly as quads: a second put(eid, {}, ...) would erase the
2411
+ # properties just stored (put() replaces the data dict), and
2412
+ # the old parent_id=eid created bogus self-edges.
2297
2413
  for eid in element_ids:
2298
2414
  for target, rt, _ in self.relationships(eid, direction="out"):
2299
2415
  if target in element_ids:
2300
- new_store.put(eid, {}, parent_id=eid, rel_type=rt)
2301
- # Fix: add the edge separately
2302
- pass
2416
+ new_store._write([{
2417
+ "subject": new_store._k(eid),
2418
+ "predicate": rt,
2419
+ "object": new_store._k(target),
2420
+ "label": new_store._label,
2421
+ }])
2303
2422
 
2304
2423
  return new_store
2305
2424
 
File without changes
File without changes
File without changes
File without changes
File without changes