s3dgraphy 1.6.0.dev47__tar.gz → 1.6.0.dev49__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.
- {s3dgraphy-1.6.0.dev47/src/s3dgraphy.egg-info → s3dgraphy-1.6.0.dev49}/PKG-INFO +1 -1
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/pyproject.toml +1 -1
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/__init__.py +1 -1
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/api.py +16 -6
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/container.py +151 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/contract/connector.py +4 -3
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/crdt.py +154 -20
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/editorial.py +45 -3
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/importer/rdf_importer.py +3 -2
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/property_source.py +3 -1
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/publication.py +8 -1
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/sync/graph_projector.py +77 -23
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49/src/s3dgraphy.egg-info}/PKG-INFO +1 -1
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy.egg-info/SOURCES.txt +1 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_crdt.py +259 -1
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_editorial.py +28 -0
- s3dgraphy-1.6.0.dev49/tests/test_promote_keeps_proxy_type.py +44 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/LICENSE +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/MANIFEST.in +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/README.md +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/setup.cfg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/acquisition_descriptor.schema.json +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/acquisition_mappings/ercolano.json +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/acquisition_mappings/fs.json +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/acquisition_mappings/uri.json +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/datamodel_translations.json +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/em.ttl +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/em_document_types.json +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/em_extractor_types.json +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/em_palette_icons.json +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/em_qualia_types.json +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/em_qualia_types_additions.json +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/em_state_symbols.json +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/em_visual_rules.json +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/hdto_extension.ttl +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/new_qualia_template.json +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/node_registry.generated.json +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/outdated_s3dgraphy.ttl +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/outdated_s3dgraphy_nomapping.ttl +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/s3Dgraphy_connections_datamodel.json +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/s3Dgraphy_connections_datamodel.json.v155.bak +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/s3Dgraphy_node_datamodel.json +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/ActivityNodeGroup.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/EMNarrative.png +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/EMNarrative.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/EpochNode.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/ParadataNodeGroup.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/RSF.png +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/RSF.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/SE.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/SE_old.png +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/SE_old.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/SF.png +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/SF.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/TSU.png +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/US.png +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/US.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/USD.png +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/USD.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/USVn.png +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/USVn.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/USVs.png +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/USVs.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/UTR.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/VSF.png +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/VSF.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/author.png +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/author.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/author_ai.png +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/author_ai.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/combiner.png +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/combiner.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/container.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/continuity.png +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/continuity.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/document.png +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/document.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/dtc/00_transformation.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/dtc/01_topographicnetwork.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/dtc/02_pointcloud.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/dtc/03_mesh.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/dtc/04_points.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/dtc/05_lines.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/dtc/06_polygons.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/dtc/07_DEM.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/dtc/08_ortophoto.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/dtc/09_photos.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/dtc/10_laserscanner.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/dtc/11_device.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/dtc/11_device_computer.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/dtc/11_device_drone.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/dtc/11_device_gnss.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/dtc/11_device_optical.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/dtc/11_device_scanner.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/dtc/11_device_sensor.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/dtc/11_device_station.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/dtc/12_gnss_survey.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/dtc/13_field_drawing.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/dtc/14_recording_sheet.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/dtc/15_decimation.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/dtc/16_georeferencing.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/dtc/17_format_conversion.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/dtc/18_classification.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/dtc/19_vectorization.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/embargo.png +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/embargo.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/extractor.png +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/extractor.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/gcp_set.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/generic_node.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/geo_position.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/graph.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/license.png +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/license.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/link.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/narrative.png +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/narrative.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/play.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/property.png +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/property.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/proxy.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/registration_transform.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/representation_model.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/representation_model_doc.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/representation_model_sf.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/resource_file.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/semantic_shape.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/serSU.png +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/serSU.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/serUSD.png +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/serUSV.png +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/serUSVn.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/serUSVs.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/tileset.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/version_gltf.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/version_mesh.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/version_scene.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/2D/version_tiles.svg +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/3D/RSF.glb +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/3D/SF.glb +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/3D/TSU.glb +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/3D/US.glb +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/3D/USD.glb +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/3D/USVn.glb +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/3D/USVs.glb +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/3D/VSF.glb +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/3D/combiner.glb +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/3D/continuity.glb +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/3D/document.glb +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/3D/extractor.glb +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/3D/property.glb +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/3D/serSU.glb +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/3D/serUSD.glb +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/src/3D/serUSV.glb +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/JSON_config/version_for_cases.json +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/acquisition/__init__.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/acquisition/acquire.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/acquisition/descriptor.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/acquisition/mapping.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/ai_validation.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/annotation/__init__.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/annotation/migrate_reading.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/annotation/paradata.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/annotation/reading.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/authorities/__init__.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/authorities/resolver.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/authorities/snapshots/LICENSE +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/authorities/snapshots/chronontology.jsonld +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/authorities/snapshots/getty_aat.jsonld +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/authorities/snapshots/getty_tgn.jsonld +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/authorities/snapshots/periodo.jsonld +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/authorities/snapshots/provenance.json +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/classification.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/contract/__init__.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/contract/consumer.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/contract/core.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/contract/reference.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/data/StratiMiner_Extraction_Prompt.md +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/datamodel.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/diagnostics.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/dissemination.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/dtc/__init__.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/dtc/capture.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/dtc/corpus.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/dtc/devices.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/dtc/ingest.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/dtc/neighbourhood.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/dtc/residency.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/edges/__init__.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/edges/connection_resolver.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/edges/connections_loader.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/edges/edge.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/exporter/__init__.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/exporter/docx_exporter.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/exporter/emjson_exporter.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/exporter/graphml/__init__.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/exporter/graphml/canvas_generator.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/exporter/graphml/edge_generator.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/exporter/graphml/epoch_generator.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/exporter/graphml/graphml_exporter.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/exporter/graphml/graphml_patcher.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/exporter/graphml/group_node_generator.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/exporter/graphml/node_generator.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/exporter/graphml/node_registry.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/exporter/graphml/palette_resources.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/exporter/graphml/paradata_generator.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/exporter/graphml/paradata_image_generator.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/exporter/graphml/paradata_node_generators.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/exporter/graphml/table_node_generator.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/exporter/graphml/utils.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/exporter/html_exporter.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/exporter/ipynb_exporter.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/exporter/json_exporter.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/exporter/latex_exporter.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/exporter/rdf_exporter.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/exporter/unified_xlsx_exporter.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/geometry/__init__.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/geometry/aton.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/geometry/gltf.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/geometry/migrate.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/geometry/proxy.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/geometry/reading_glb.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/geometry/store_backed.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/geometry/wkt.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/graph.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/hdto.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/iiif.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/importer/__init__.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/importer/base_importer.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/importer/csv_importer.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/importer/emjson_importer.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/importer/fmpxml_importer.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/importer/import_graphml.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/importer/mapped_xlsx_importer.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/importer/metashape_project.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/importer/pyarchinit_importer.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/importer/qualia_importer.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/importer/sheet_header.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/importer/source_text.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/importer/unified_xlsx_importer.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/importer/xlsx_importer.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/importer/xml_importer.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/indices.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/labels.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/language.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/links.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/mappings/__init__.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/mappings/authoring.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/mappings/emdb/generic_specialfind_mapping.json +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/mappings/emdb/site_properties_mapping.json +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/mappings/emdb/usm_mapping.json +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/mappings/generic/excel_to_graphml_mapping.json +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/mappings/pyarchinit/pyarchinit_us_mapping.json +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/mappings/registry.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/mappings/source_list/em_sourcelist_it.json +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/mappings/source_list/source_list_mapping.json +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/mappings/template_emdb_mapping.json +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/mappings/template_pyarchinit_mapping.json +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/merge/__init__.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/merge/graph_merger.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/multigraph/__init__.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/multigraph/multigraph.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/narrative/__init__.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/narrative/bake.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/narrative/generation.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/narrative/query.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/narrative/registry.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/narrative/site_story.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/nodes/__init__.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/nodes/annotation_region_node.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/nodes/author_node.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/nodes/base_node.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/nodes/combiner_node.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/nodes/document_node.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/nodes/dtc_acquisition_node.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/nodes/dtc_device_node.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/nodes/dtc_node.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/nodes/dtc_process_node.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/nodes/embargo_node.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/nodes/epoch_node.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/nodes/extractor_node.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/nodes/geo_position_node.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/nodes/georeferencing_node.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/nodes/graph_node.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/nodes/group_node.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/nodes/hdt_node.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/nodes/heritage_entity_node.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/nodes/license_node.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/nodes/narrative_node.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/nodes/paradata_node.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/nodes/project_node.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/nodes/property_node.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/nodes/representation_node.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/nodes/resource_file_node.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/nodes/resource_node.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/nodes/semantic_shape_node.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/nodes/stratigraphic_node.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/nodes/study_node.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/nodes/translation_node.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/ownership.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/paradata_view.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/photogrammetry/__init__.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/photogrammetry/delta.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/project_tree.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/rapporti.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/resolvers/__init__.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/resolvers/builtin_rules.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/resolvers/property_resolver.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/resources/__init__.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/resources/addresses.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/resources/alignment.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/resources/files.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/resources/fs_backend.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/resources/locate.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/resources/minio_backend.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/resources/moved.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/resources/object_store.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/resources/resolver.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/resources/storage_rows.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/resources/tiles3tz.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/resources/versions.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/rights.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/shelf/__init__.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/shelf/core.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/spatiotemporal.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/stamp/__init__.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/stamp/absorb.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/stamp/emit.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/stamp/hints.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/stamp/identity.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/study.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/sync/__init__.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/sync/_db_handle.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/sync/_legacy_paradata_svgs.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/sync/_workspace.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/sync/conflict_resolver.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/sync/edge_registry.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/sync/graph_ingestor.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/sync/graphml_writer.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/sync/group_projector.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/sync/group_store.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/sync/ingest_result.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/sync/paradata_store.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/sync/pyarchinit_pg_importer.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/sync/rapporti.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/sync/uuid7.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/sync/vocab_provider_core.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/sync/vocab_types.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/sync/yed_classifier.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/sync/yed_detector.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/sync/yed_group_walker.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/sync/yed_import_pipeline.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/sync/yed_rapporti_policy.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/sync/yed_table_parser.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/templates/em_data_template.xlsx +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/templates/em_palette_template.graphml +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/temporal/__init__.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/temporal/inference_engine.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/tools/__init__.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/tools/consumer_drift.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/tools/datamodel_i18n.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/tools/deliverable_report.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/tools/glyph_sheet.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/tools/glyphs_from_svg.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/tools/node_finder.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/tools/sync_node_datamodel.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/tools/wheel_drift.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/transforms/__init__.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/transforms/aux_tracking.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/transforms/compact.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/transforms/materialize_continuity.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/translation.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/utils/__init__.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/utils/utils.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/utils/visual_layout.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy/zero_hour.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy.egg-info/dependency_links.txt +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy.egg-info/requires.txt +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/src/s3dgraphy.egg-info/top_level.txt +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_acquisition.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_acquisition_fs.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_add_resource.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_ai_validation_nodes.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_alternative_labels.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_api_surface.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_asset_dtc_protocol.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_asset_versions.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_aton_shapes.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_attach_only.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_authority_projection.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_authority_resolver.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_blend_locator.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_bucket_alignment.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_canonical_document_rename.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_canvas_metadata_import.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_capture_acquisition.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_capture_rdf_class.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_chronology_on_request.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_coating_unit.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_composite_node_name.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_connection_resolver.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_consumer_drift.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_container.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_container_layouts.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_containment_tpq.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_contract.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_contract_consumer.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_convert_command.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_cycle_message_is_cheap.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_datamodel_fingerprint.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_datamodel_i18n.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_deterministic_ids.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_dev29_em_sourcelist.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_dev29_file_set_stamp.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_dev29_graphml_without_a_database.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_dev29_image_set_texturing.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_dev29_not_georeferenced.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_dev29_one_act_n_outputs.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_dev29_ttl_round_trip.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_dev30_decisions.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_devices.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_dissemination_tombstones.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_dove_sta_il_testo.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_dtc_corpus.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_dtc_ingest.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_dtc_neighbourhood.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_dtc_projection.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_dtc_residency.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_edge_outside_graph.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_edge_ui_phrases.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_em_ttl_matches_the_datamodels.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_emjson_no_drawing_keys.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_emjson_roundtrip.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_emjson_schema_version.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_epoch_properties_and_sub_epochs.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_epoch_undated_import.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_explicit_node_type_marker.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_extracted_from_unit.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_filtered_import.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_fmpxml_importer.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_fs_backend.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_functional_units.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_georeference_scene.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_gltf_stitch.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_glyph_paths.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_graph_header_code.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_graph_helpers_indexed.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_graph_indices_alive.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_graph_indices_edges.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_graph_scope_migration.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_hdto_projection.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_hdto_study.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_header_key_aliases.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_i_generi_dei_passi.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_iiif.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_il_modo_d_accesso.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_il_modo_dal_relay.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_il_proprietario_si_legge.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_il_riallineamento.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_importer_edge_hygiene.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_ipynb_exporter.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_issue27_small_points.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_la_lingua_alla_nascita.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_la_lingua_dei_dati.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_la_lingua_nell_op.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_la_riga_d_intestazione.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_latex_exporter.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_le_traduzioni.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_lod_levels.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_lossless_roundtrip.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_mapping_authoring.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_mapping_csv_and_relations.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_masonry_unit.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_material_color.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_merge_conflicts.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_metashape_project.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_migrate_legacy_proxy.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_minio_backend.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_narrative_authorship.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_narrative_bake_docx.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_narrative_figures.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_narrative_generation.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_narrative_mentions.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_narrative_node.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_narrative_query.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_narrative_scaffolder.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_narrative_site_place.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_narrative_unvalidated_export.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_node_datamodel_registry.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_node_finder.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_node_type_map_integrity.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_one_resolver.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_one_spelling_writers.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_op_vocabulary.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_pg_importer.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_photogrammetry_delta.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_physical_relation_spellings.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_piu_indirizzi.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_promotion.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_property_as_source.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_property_owners.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_proxy_resource.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_proxy_retype.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_psx_locator.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_pyarchinit_tier2.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_qualia_dai_d7_d8.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_rdf_embedding.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_rdf_reverse_edges.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_rdf_roundtrip.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_reading_coords.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_reading_glb.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_reading_migration.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_reading_place.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_reading_rdf.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_recompute_warnings.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_release.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_reproject.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_resource_file_node.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_resource_files_implicit.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_resource_layer.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_resource_representations.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_resource_revision.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_resource_tier.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_reverse_edges.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_rm_container_node_group.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_semantic_purity.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_shelf.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_shelf_facets.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_shelf_hatting.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_shelf_role_uri_table.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_shipped_mappings.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_source_list_mapping.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_source_text.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_spatiotemporal_entities.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_stable_study_code.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_stamp.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_stamp_hints.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_stamp_title_description.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_storage_rows.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_store_backed_geometry.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_stratiminer_api.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_study_metadata.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_tileset_resource.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_ttl_roundtrip.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_unit_definition.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_verifica_provenance.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_version_for.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_visual_assets.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_wheel_drift.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_xlsx_containment_and_unknown_bounds.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_xlsx_importer_graph_init.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_xlsx_source_column.py +0 -0
- {s3dgraphy-1.6.0.dev47 → s3dgraphy-1.6.0.dev49}/tests/test_zero_hour.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: s3dgraphy
|
|
3
|
-
Version: 1.6.0.
|
|
3
|
+
Version: 1.6.0.dev49
|
|
4
4
|
Summary: 3D Stratigraphic Graph Management Library for archaeological and heritage applications
|
|
5
5
|
Author-email: Emanuel Demetrescu <emanuel.demetrescu@cnr.it>
|
|
6
6
|
Maintainer-email: Emanuel Demetrescu <emanuel.demetrescu@cnr.it>
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "s3dgraphy"
|
|
7
|
-
version = "1.6.0.
|
|
7
|
+
version = "1.6.0.dev49"
|
|
8
8
|
description = "3D Stratigraphic Graph Management Library for archaeological and heritage applications"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
|
@@ -646,6 +646,16 @@ def merge_containers(container, other):
|
|
|
646
646
|
return merge_into_container(container, other)
|
|
647
647
|
|
|
648
648
|
|
|
649
|
+
def merge_graphs(container, graph_ids: Optional[List[str]] = None):
|
|
650
|
+
"""One graph for the overall view of the graphs of ``container`` (all,
|
|
651
|
+
or ``graph_ids``): nodes united by id, edges deduplicated by
|
|
652
|
+
``(source, type, target)``, the links between them as edges. Returns
|
|
653
|
+
``(graph, report)``; the container is not touched. See
|
|
654
|
+
:func:`s3dgraphy.container.merge_graphs`."""
|
|
655
|
+
from .container import merge_graphs as _merge
|
|
656
|
+
return _merge(container, graph_ids)
|
|
657
|
+
|
|
658
|
+
|
|
649
659
|
# ── HDT-O: the study, its place, the heritage it is about ────────────────────
|
|
650
660
|
|
|
651
661
|
def declare_hdto(graph: Graph, *, study=None, place=None, about=None,
|
|
@@ -804,7 +814,7 @@ def set_field(node, field: str, value, *, author=None,
|
|
|
804
814
|
coming out of its tombstone.
|
|
805
815
|
"""
|
|
806
816
|
from .crdt import Clock, write_field
|
|
807
|
-
from .editorial import normalize_orcid,
|
|
817
|
+
from .editorial import normalize_orcid, now_op_iso
|
|
808
818
|
|
|
809
819
|
if field in ("data.lang", "data.from_lang") and value not in (None, ""):
|
|
810
820
|
# a node's language is a BCP 47 tag; an invalid one is refused, not stored
|
|
@@ -812,7 +822,7 @@ def set_field(node, field: str, value, *, author=None,
|
|
|
812
822
|
check_language_tag(value)
|
|
813
823
|
payload = _node_payload_view(node)
|
|
814
824
|
write_field(payload, field, value,
|
|
815
|
-
Clock(ts=at or
|
|
825
|
+
Clock(ts=at or now_op_iso(), by=normalize_orcid(author)))
|
|
816
826
|
_write_back(node, payload, field)
|
|
817
827
|
|
|
818
828
|
|
|
@@ -826,10 +836,10 @@ def clear_field(node, field: str, *, author=None,
|
|
|
826
836
|
correctly, and wrongly, hand the value back.
|
|
827
837
|
"""
|
|
828
838
|
from .crdt import Clock, clear_field as _clear
|
|
829
|
-
from .editorial import normalize_orcid,
|
|
839
|
+
from .editorial import normalize_orcid, now_op_iso
|
|
830
840
|
|
|
831
841
|
payload = _node_payload_view(node)
|
|
832
|
-
_clear(payload, field, Clock(ts=at or
|
|
842
|
+
_clear(payload, field, Clock(ts=at or now_op_iso(), by=normalize_orcid(author)))
|
|
833
843
|
_write_back(node, payload, field)
|
|
834
844
|
|
|
835
845
|
|
|
@@ -873,7 +883,7 @@ def stamp_field(node, field: str, *, by=None, at: Optional[str] = None) -> None:
|
|
|
873
883
|
but `set_field` is the one to use: it cannot be half-done.
|
|
874
884
|
"""
|
|
875
885
|
from .crdt import Clock, set_field_clock
|
|
876
|
-
from .editorial import normalize_orcid,
|
|
886
|
+
from .editorial import normalize_orcid, now_op_iso
|
|
877
887
|
|
|
878
888
|
data = getattr(node, "data", None)
|
|
879
889
|
if not isinstance(data, dict):
|
|
@@ -881,7 +891,7 @@ def stamp_field(node, field: str, *, by=None, at: Optional[str] = None) -> None:
|
|
|
881
891
|
node.data = data
|
|
882
892
|
payload = {"data": data}
|
|
883
893
|
set_field_clock(payload, field,
|
|
884
|
-
Clock(ts=at or
|
|
894
|
+
Clock(ts=at or now_op_iso(), by=normalize_orcid(by)))
|
|
885
895
|
|
|
886
896
|
|
|
887
897
|
def unstamped_fields(node) -> List[str]:
|
|
@@ -1030,3 +1030,154 @@ def merge_into_container(container: Container, other: Container) -> MergeReport:
|
|
|
1030
1030
|
# lie about how much has happened.
|
|
1031
1031
|
bump_version(container)
|
|
1032
1032
|
return report
|
|
1033
|
+
|
|
1034
|
+
|
|
1035
|
+
#: the id of the graph :func:`merge_graphs` returns
|
|
1036
|
+
MERGED_GRAPH_ID = "merged"
|
|
1037
|
+
|
|
1038
|
+
|
|
1039
|
+
def merge_graphs(container: Container,
|
|
1040
|
+
graph_ids: Optional[Iterable[str]] = None
|
|
1041
|
+
) -> Tuple[Graph, Dict[str, Any]]:
|
|
1042
|
+
"""One graph for the overall view of several graphs of ``container`` —
|
|
1043
|
+
the site whole again, after :meth:`GraphProjector.populate_container`
|
|
1044
|
+
made one graph per saggio (s3Dgraphy#36).
|
|
1045
|
+
|
|
1046
|
+
Each saggio is a study of its own (E.D., 12 Oct 2026): its graph carries
|
|
1047
|
+
a copy of the paradata it shares with the others (documents, authors,
|
|
1048
|
+
epochs, places), with the SAME id. Summing the graphs counts those twice;
|
|
1049
|
+
this does not:
|
|
1050
|
+
|
|
1051
|
+
* **nodes** united by id — the identity of a node shared between graphs
|
|
1052
|
+
is its id, never its label (two documents named «D.01» in two studies
|
|
1053
|
+
may be two documents, and stay two);
|
|
1054
|
+
* **edges** deduplicated by ``(source, type, target)``, the definition of
|
|
1055
|
+
«the same relation» :func:`_merge_graph_into` uses;
|
|
1056
|
+
* **links** (:mod:`s3dgraphy.links`) between two merged graphs become
|
|
1057
|
+
ordinary edges, with the link's id, type and attributes; a link whose
|
|
1058
|
+
other end is not among them stays out, and the report names it.
|
|
1059
|
+
|
|
1060
|
+
The first graph (in ``graph_ids`` order, else the container's) gives the
|
|
1061
|
+
version of a node; when another graph has the same id with different
|
|
1062
|
+
content (the editorial stamps aside, as in a merge), the report says so
|
|
1063
|
+
— node, graphs, which one was kept, which fields diverge. It does not
|
|
1064
|
+
choose in silence. The same for an edge whose attributes differ.
|
|
1065
|
+
|
|
1066
|
+
Reads only: the container, its graphs and their links are not touched
|
|
1067
|
+
(the merged graph holds copies), and nothing is written to file.
|
|
1068
|
+
|
|
1069
|
+
Returns ``(graph, report)``; ``report`` is a dict: ``graphs``,
|
|
1070
|
+
``nodes_in`` / ``nodes`` / ``nodes_merged`` (rows read, nodes kept, copies
|
|
1071
|
+
folded), the same three for ``edges``, ``links_resolved``,
|
|
1072
|
+
``links_unresolved`` (one sentence each), ``conflicts`` (nodes),
|
|
1073
|
+
``edge_conflicts``, ``warnings``.
|
|
1074
|
+
"""
|
|
1075
|
+
import copy
|
|
1076
|
+
from .links import links_of_graph
|
|
1077
|
+
|
|
1078
|
+
ids = list(graph_ids) if graph_ids is not None else container.graph_ids()
|
|
1079
|
+
unknown = [gid for gid in ids if gid not in container.graphs]
|
|
1080
|
+
if unknown:
|
|
1081
|
+
raise ValueError(f"no graph {', '.join(map(repr, unknown))} in this container")
|
|
1082
|
+
|
|
1083
|
+
merged = Graph(MERGED_GRAPH_ID, name="merged view")
|
|
1084
|
+
auto_geo = [n.node_id for n in merged.nodes]
|
|
1085
|
+
report: Dict[str, Any] = {
|
|
1086
|
+
"graphs": list(ids), "nodes_in": 0, "nodes": 0, "nodes_merged": 0,
|
|
1087
|
+
"edges_in": 0, "edges": 0, "edges_merged": 0,
|
|
1088
|
+
"links_resolved": 0, "links_unresolved": [],
|
|
1089
|
+
"conflicts": [], "edge_conflicts": [], "warnings": []}
|
|
1090
|
+
|
|
1091
|
+
nodes: Dict[str, Any] = {}
|
|
1092
|
+
origin: Dict[str, str] = {}
|
|
1093
|
+
content: Dict[str, Dict[str, Any]] = {}
|
|
1094
|
+
contested: Dict[str, Dict[str, Any]] = {}
|
|
1095
|
+
for gid in ids:
|
|
1096
|
+
for node in container.graphs[gid].nodes:
|
|
1097
|
+
report["nodes_in"] += 1
|
|
1098
|
+
snap = _content_of(_node_snapshot(node))
|
|
1099
|
+
if node.node_id not in nodes:
|
|
1100
|
+
nodes[node.node_id] = copy.deepcopy(node)
|
|
1101
|
+
origin[node.node_id] = gid
|
|
1102
|
+
content[node.node_id] = snap
|
|
1103
|
+
continue
|
|
1104
|
+
report["nodes_merged"] += 1
|
|
1105
|
+
if snap == content[node.node_id]:
|
|
1106
|
+
continue
|
|
1107
|
+
entry = contested.get(node.node_id)
|
|
1108
|
+
if entry is None:
|
|
1109
|
+
entry = contested[node.node_id] = {
|
|
1110
|
+
"node_id": node.node_id, "name": getattr(node, "name", None),
|
|
1111
|
+
"kept_from": origin[node.node_id],
|
|
1112
|
+
"graphs": [origin[node.node_id]], "fields": []}
|
|
1113
|
+
report["conflicts"].append(entry)
|
|
1114
|
+
entry["graphs"].append(gid)
|
|
1115
|
+
for name in _diverging_fields(content[node.node_id], snap):
|
|
1116
|
+
if name not in entry["fields"]:
|
|
1117
|
+
entry["fields"].append(name)
|
|
1118
|
+
|
|
1119
|
+
edges: Dict[Tuple[str, str, str], Any] = {}
|
|
1120
|
+
edge_origin: Dict[Tuple[str, str, str], str] = {}
|
|
1121
|
+
edge_ids = set()
|
|
1122
|
+
|
|
1123
|
+
def take(edge, gid: str) -> None:
|
|
1124
|
+
key = (edge.edge_source, edge.edge_type, edge.edge_target)
|
|
1125
|
+
attrs = getattr(edge, "attributes", None) or {}
|
|
1126
|
+
if key in edges:
|
|
1127
|
+
report["edges_merged"] += 1
|
|
1128
|
+
if attrs != (getattr(edges[key], "attributes", None) or {}):
|
|
1129
|
+
report["edge_conflicts"].append({
|
|
1130
|
+
"edge": list(key), "edge_id": edges[key].edge_id,
|
|
1131
|
+
"kept_from": edge_origin[key], "other": gid})
|
|
1132
|
+
return
|
|
1133
|
+
edge_id = edge.edge_id
|
|
1134
|
+
# two graphs may have minted the same id for two relations
|
|
1135
|
+
while edge_id in edge_ids:
|
|
1136
|
+
edge_id = f"{edge_id}_merged"
|
|
1137
|
+
kept = copy.deepcopy(edge)
|
|
1138
|
+
kept.edge_id = edge_id
|
|
1139
|
+
edges[key], edge_origin[key] = kept, gid
|
|
1140
|
+
edge_ids.add(edge_id)
|
|
1141
|
+
|
|
1142
|
+
for gid in ids:
|
|
1143
|
+
for edge in container.graphs[gid].edges:
|
|
1144
|
+
report["edges_in"] += 1
|
|
1145
|
+
take(edge, gid)
|
|
1146
|
+
|
|
1147
|
+
from .edges import Edge
|
|
1148
|
+
chosen = set(ids)
|
|
1149
|
+
for gid in ids:
|
|
1150
|
+
for link in links_of_graph(container.graphs[gid]):
|
|
1151
|
+
target = link["target"]
|
|
1152
|
+
where = f"link '{link['id']}' of the graph '{gid}'"
|
|
1153
|
+
if target["graph_id"] not in chosen:
|
|
1154
|
+
report["links_unresolved"].append(
|
|
1155
|
+
f"{where}: the graph '{target['graph_id']}' is not merged")
|
|
1156
|
+
continue
|
|
1157
|
+
if link["source"] not in nodes or target["node_id"] not in nodes:
|
|
1158
|
+
missing = (link["source"] if link["source"] not in nodes
|
|
1159
|
+
else target["node_id"])
|
|
1160
|
+
report["links_unresolved"].append(f"{where}: no node '{missing}'")
|
|
1161
|
+
continue
|
|
1162
|
+
try:
|
|
1163
|
+
edge = Edge(link["id"], link["source"], target["node_id"],
|
|
1164
|
+
link["edge_type"])
|
|
1165
|
+
except ValueError as exc:
|
|
1166
|
+
report["links_unresolved"].append(f"{where}: {exc}")
|
|
1167
|
+
continue
|
|
1168
|
+
edge.attributes = dict(link.get("attributes") or {})
|
|
1169
|
+
report["edges_in"] += 1
|
|
1170
|
+
report["links_resolved"] += 1
|
|
1171
|
+
take(edge, gid)
|
|
1172
|
+
|
|
1173
|
+
# Graph() makes a geo position of its own; the members bring theirs
|
|
1174
|
+
if any(getattr(n, "node_type", None) == "geo_position" for n in nodes.values()):
|
|
1175
|
+
for node_id in auto_geo:
|
|
1176
|
+
if node_id not in nodes:
|
|
1177
|
+
merged.remove_node(node_id)
|
|
1178
|
+
merged.nodes = list(merged.nodes) + [n for i, n in nodes.items()
|
|
1179
|
+
if merged.find_node_by_id(i) is None]
|
|
1180
|
+
merged.edges = list(edges.values())
|
|
1181
|
+
report["nodes"] = len(nodes)
|
|
1182
|
+
report["edges"] = len(edges)
|
|
1183
|
+
return merged, report
|
|
@@ -474,7 +474,7 @@ def apply_delta(section: Dict[str, Any], descriptor: ConnectorDescriptor,
|
|
|
474
474
|
so a rejected write cannot leave half a subgraph behind.
|
|
475
475
|
"""
|
|
476
476
|
from ..crdt import apply_op_to_section, make_op
|
|
477
|
-
from ..editorial import
|
|
477
|
+
from ..editorial import now_op_iso
|
|
478
478
|
|
|
479
479
|
verdict = guard_write(descriptor, capability, delta,
|
|
480
480
|
node_types={str(n.get("id")): str(n.get("node_type") or "")
|
|
@@ -488,8 +488,9 @@ def apply_delta(section: Dict[str, Any], descriptor: ConnectorDescriptor,
|
|
|
488
488
|
# in `data`) are written by the CRDT only when the op carries a clock —
|
|
489
489
|
# measured: without one, a write landed unattributed even though the author was
|
|
490
490
|
# right there. The identity and the clock are never typed by a caller
|
|
491
|
-
# (`editorial.py`'s rule), so the seam supplies the clock
|
|
492
|
-
|
|
491
|
+
# (`editorial.py`'s rule), so the seam supplies the clock — an operation's,
|
|
492
|
+
# to the millisecond (E.D., 12 Oct 2026); the CRDT keeps the stamps at the second.
|
|
493
|
+
at = at or now_op_iso()
|
|
493
494
|
applied = {"nodes": 0, "edges": 0}
|
|
494
495
|
refused: List[Dict[str, Any]] = []
|
|
495
496
|
|
|
@@ -17,7 +17,10 @@ Three pieces:
|
|
|
17
17
|
(AUDIT1). Comparison is by instant, then by author, lexicographically smaller
|
|
18
18
|
first. The tie-break is arbitrary and DECLARED (``tie-author``); what it must
|
|
19
19
|
never be is "whichever I saw last", because then two people merging the same two
|
|
20
|
-
files get different projects and no way to tell.
|
|
20
|
+
files get different projects and no way to tell. The SAME clock on two different
|
|
21
|
+
values (one hand, one instant: a connector's batch, a burst of renames) is
|
|
22
|
+
settled by the value itself (``tie-value``, :func:`tie_rank`) — measured on 12
|
|
23
|
+
Oct 2026, it used to be settled by arrival, and two copies kept two names.
|
|
21
24
|
|
|
22
25
|
**Tombstones.** A deletion is not an absence, it is a mark: ``data.removed =
|
|
23
26
|
{ts, by}``, inline, keeping the id. Views hide it; the merge SEES it. Without
|
|
@@ -73,7 +76,16 @@ OPS = ("add_node", "update_field", "remove_node", "add_edge", "remove_edge")
|
|
|
73
76
|
#: The incoming value is kept (P3's behaviour) and the reason
|
|
74
77
|
#: exists so nobody reads that as a judgement.
|
|
75
78
|
#: ``resurrected`` — an edit later than a deletion brought the node back.
|
|
76
|
-
|
|
79
|
+
#: ``tie-explicit``— same instant, same author, and only ONE side carries the
|
|
80
|
+
#: field's own clock (the other is dated by its node's stamp):
|
|
81
|
+
#: the field's own clock wins — a field is written on a node
|
|
82
|
+
#: that is already there.
|
|
83
|
+
#: ``tie-value`` — same instant, same author, both clocks the field's own, two
|
|
84
|
+
#: different values: the greater :func:`tie_rank` wins. Not a
|
|
85
|
+
#: judgement — the one choice every copy makes whatever order
|
|
86
|
+
#: the two arrive in.
|
|
87
|
+
FIELD_REASONS = ("newer", "tie-author", "unstamped", "resurrected",
|
|
88
|
+
"tie-explicit", "tie-value")
|
|
77
89
|
|
|
78
90
|
|
|
79
91
|
# ── clocks ───────────────────────────────────────────────────────────────────
|
|
@@ -157,13 +169,35 @@ def compare_clocks(a: Clock, b: Clock) -> Tuple[int, str]:
|
|
|
157
169
|
return (1, "tie-author") if ka < kb else (-1, "tie-author")
|
|
158
170
|
|
|
159
171
|
|
|
172
|
+
def editorial_clock(clock: Clock) -> Clock:
|
|
173
|
+
"""The clock as an EDITORIAL stamp records it: at the second.
|
|
174
|
+
|
|
175
|
+
Two precisions, one decision (E.D., 12 Oct 2026): the clock of an operation
|
|
176
|
+
(``op.ts``, ``field_clocks``, tombstones) is to the millisecond, because it
|
|
177
|
+
orders two hands; ``created_at`` / ``modified_at`` stay at the second
|
|
178
|
+
(:func:`s3dgraphy.editorial.now_iso`). Every stamp the CRDT writes from an
|
|
179
|
+
op's clock goes through here, and is compared at the second too — so two
|
|
180
|
+
hands in one second settle the stamp by the declared ``tie-author``, not by
|
|
181
|
+
arrival."""
|
|
182
|
+
if not clock.stamped:
|
|
183
|
+
return clock
|
|
184
|
+
from .editorial import normalize_instant
|
|
185
|
+
return Clock(ts=normalize_instant(clock.ts), by=clock.by)
|
|
186
|
+
|
|
187
|
+
|
|
160
188
|
def clock_order(a: Clock, b: Clock) -> int:
|
|
161
189
|
"""Just the ordering of two clocks (-1 / 0 / 1), without the reason."""
|
|
162
190
|
return compare_clocks(a, b)[0]
|
|
163
191
|
|
|
164
192
|
|
|
165
193
|
def newer(a: Clock, b: Clock) -> Clock:
|
|
166
|
-
|
|
194
|
+
order = clock_order(a, b)
|
|
195
|
+
if order == 0:
|
|
196
|
+
# the same instant may be spelt two ways ("…:00Z", "…:00.000Z": a clock
|
|
197
|
+
# at the second and one at the millisecond): ONE spelling, whichever
|
|
198
|
+
# side is asked, or two copies differ by bytes nobody wrote
|
|
199
|
+
return a if (a.ts or "", a.by or "") >= (b.ts or "", b.by or "") else b
|
|
200
|
+
return a if order > 0 else b
|
|
167
201
|
|
|
168
202
|
|
|
169
203
|
# ── reading a payload ────────────────────────────────────────────────────────
|
|
@@ -210,14 +244,17 @@ def field_clock(payload: Dict[str, Any], field_name: str) -> Clock:
|
|
|
210
244
|
"""
|
|
211
245
|
data = payload.get("data") if isinstance(payload.get("data"), dict) else {}
|
|
212
246
|
clocks = data.get(FIELD_CLOCKS_KEY)
|
|
247
|
+
# the two fallbacks are editorial stamps, so they are read at the second
|
|
248
|
+
# (`editorial_clock`) — as the CRDT writes them since 12 Oct 2026, and also
|
|
249
|
+
# when an older tool wrote one with its milliseconds
|
|
213
250
|
if isinstance(clocks, dict):
|
|
214
251
|
if field_name in clocks:
|
|
215
252
|
return Clock.from_dict(clocks[field_name])
|
|
216
253
|
if clocks:
|
|
217
254
|
born = creation_stamp(payload)
|
|
218
255
|
if born.stamped:
|
|
219
|
-
return born
|
|
220
|
-
return node_stamp(payload)
|
|
256
|
+
return editorial_clock(born)
|
|
257
|
+
return editorial_clock(node_stamp(payload))
|
|
221
258
|
|
|
222
259
|
|
|
223
260
|
def is_stale_copy(payload: Dict[str, Any], field_name: str) -> bool:
|
|
@@ -444,6 +481,32 @@ def canonical(value: Any) -> str:
|
|
|
444
481
|
ensure_ascii=False, default=str)
|
|
445
482
|
|
|
446
483
|
|
|
484
|
+
def tie_rank(value: Any, removed: bool = False) -> Tuple[int, bytes]:
|
|
485
|
+
"""Where a field's state stands when two states carry the SAME clock.
|
|
486
|
+
|
|
487
|
+
The rule of ``tie-value``: the greater rank wins. An emptying ranks BELOW
|
|
488
|
+
every value (at the same instant a value is kept rather than lost); values
|
|
489
|
+
rank by the UTF-8 bytes of their :func:`canonical` JSON, which is code-point
|
|
490
|
+
order. A twin in another language must compare code points too — not
|
|
491
|
+
UTF-16 units, which order an emoji before ``"\\uffff"``."""
|
|
492
|
+
if removed:
|
|
493
|
+
return (0, b"")
|
|
494
|
+
return (1, canonical(value).encode("utf-8"))
|
|
495
|
+
|
|
496
|
+
|
|
497
|
+
def _settle_tie(mine: Dict[str, Any], theirs: Dict[str, Any], name: str,
|
|
498
|
+
v_mine: Any, v_theirs: Any, mine_gone: bool,
|
|
499
|
+
theirs_gone: bool) -> Tuple[str, str]:
|
|
500
|
+
"""``(winning side, reason)`` for two different states of one field under
|
|
501
|
+
the SAME clock (instant and author): ``tie-explicit``, else ``tie-value``."""
|
|
502
|
+
explicit_mine = clock_source(mine, name) == "field_clock"
|
|
503
|
+
explicit_theirs = clock_source(theirs, name) == "field_clock"
|
|
504
|
+
if explicit_mine != explicit_theirs:
|
|
505
|
+
return ("mine" if explicit_mine else "theirs"), "tie-explicit"
|
|
506
|
+
return ("mine" if tie_rank(v_mine, mine_gone) > tie_rank(v_theirs, theirs_gone)
|
|
507
|
+
else "theirs"), "tie-value"
|
|
508
|
+
|
|
509
|
+
|
|
447
510
|
# ── the report ───────────────────────────────────────────────────────────────
|
|
448
511
|
|
|
449
512
|
@dataclass
|
|
@@ -501,11 +564,9 @@ def merge_payloads(mine: Dict[str, Any], theirs: Dict[str, Any]) -> MergeOutcome
|
|
|
501
564
|
"id": node_id,
|
|
502
565
|
# identity is not a register: a type is decided when the node is made.
|
|
503
566
|
# If the two disagree, the newer node stamp decides — and nothing else in
|
|
504
|
-
# this module lets identity race.
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
else mine.get("node_type")) or mine.get("node_type")
|
|
508
|
-
or theirs.get("node_type"),
|
|
567
|
+
# this module lets identity race. Under the same stamp the greater type
|
|
568
|
+
# name decides, so that the answer does not depend on which side is mine.
|
|
569
|
+
"node_type": _merge_type(mine, theirs),
|
|
509
570
|
}
|
|
510
571
|
outcome = MergeOutcome(payload=merged)
|
|
511
572
|
|
|
@@ -558,7 +619,12 @@ def merge_payloads(mine: Dict[str, Any], theirs: Dict[str, Any]) -> MergeOutcome
|
|
|
558
619
|
# the date did not decide: the incoming state is kept, as it always
|
|
559
620
|
# was, and the reason says the choice was not a judgement
|
|
560
621
|
win_side = "theirs"
|
|
561
|
-
elif order
|
|
622
|
+
elif order == 0:
|
|
623
|
+
# the SAME clock on two different states: the state decides, so
|
|
624
|
+
# that the result does not depend on which side is `mine`
|
|
625
|
+
win_side, reason = _settle_tie(mine, theirs, name, v_mine, v_theirs,
|
|
626
|
+
mine_gone, theirs_gone)
|
|
627
|
+
elif order > 0:
|
|
562
628
|
win_side = "mine"
|
|
563
629
|
else:
|
|
564
630
|
win_side = "theirs"
|
|
@@ -611,7 +677,8 @@ def merge_payloads(mine: Dict[str, Any], theirs: Dict[str, Any]) -> MergeOutcome
|
|
|
611
677
|
_merge_creation(merged, mine, theirs)
|
|
612
678
|
last = Clock()
|
|
613
679
|
for clock in list(winning_clocks.values()) + [node_stamp(mine), node_stamp(theirs)]:
|
|
614
|
-
|
|
680
|
+
# at the second, like every stamp an op leaves (`_stamp_payload`)
|
|
681
|
+
last = newer(last, editorial_clock(clock))
|
|
615
682
|
if last.stamped:
|
|
616
683
|
data = merged.setdefault("data", {})
|
|
617
684
|
data["modified_at"] = last.ts
|
|
@@ -645,6 +712,16 @@ def merge_payloads(mine: Dict[str, Any], theirs: Dict[str, Any]) -> MergeOutcome
|
|
|
645
712
|
return outcome
|
|
646
713
|
|
|
647
714
|
|
|
715
|
+
def _merge_type(mine: Dict[str, Any], theirs: Dict[str, Any]) -> Any:
|
|
716
|
+
a, b = mine.get("node_type"), theirs.get("node_type")
|
|
717
|
+
if not a or not b:
|
|
718
|
+
return a or b
|
|
719
|
+
order = clock_order(node_stamp(theirs), node_stamp(mine))
|
|
720
|
+
if order == 0:
|
|
721
|
+
return max(str(a), str(b))
|
|
722
|
+
return b if order > 0 else a
|
|
723
|
+
|
|
724
|
+
|
|
648
725
|
def _merge_creation(merged: Dict[str, Any], mine: Dict[str, Any],
|
|
649
726
|
theirs: Dict[str, Any]) -> None:
|
|
650
727
|
def creation(payload: Dict[str, Any]) -> Clock:
|
|
@@ -656,7 +733,14 @@ def _merge_creation(merged: Dict[str, Any], mine: Dict[str, Any],
|
|
|
656
733
|
a, b = creation(mine), creation(theirs)
|
|
657
734
|
if not a.stamped and not b.stamped:
|
|
658
735
|
return
|
|
659
|
-
|
|
736
|
+
if not b.stamped:
|
|
737
|
+
first = a
|
|
738
|
+
elif not a.stamped:
|
|
739
|
+
first = b
|
|
740
|
+
else:
|
|
741
|
+
order = clock_order(a, b)
|
|
742
|
+
# the earlier creation; under one clock, the one spelling `newer` picks
|
|
743
|
+
first = newer(a, b) if order == 0 else (a if order < 0 else b)
|
|
660
744
|
data = merged.setdefault("data", {})
|
|
661
745
|
data["created_at"] = first.ts
|
|
662
746
|
if first.by:
|
|
@@ -1160,12 +1244,49 @@ def apply_op_to_section(section: Dict[str, Any], op: Dict[str, Any], *,
|
|
|
1160
1244
|
wants_gone = op.get("remove") is True
|
|
1161
1245
|
same_value = (gone == wants_gone
|
|
1162
1246
|
and canonical(get_field(existing, name)) == canonical(op.get("value")))
|
|
1247
|
+
explicit = clock_source(existing, name) == "field_clock"
|
|
1248
|
+
if order == 0 and same_value and reason == "tie-author" and (
|
|
1249
|
+
not explicit or (newer(clock, current) is clock and clock.ts != current.ts)):
|
|
1250
|
+
# the same value under the same clock: no content moves, but the
|
|
1251
|
+
# field takes its OWN clock — against the node-stamp fallback it is
|
|
1252
|
+
# still a write, and without the record an emptying under the same
|
|
1253
|
+
# clock would win or lose by arrival (measured, 45 pairs in 20000);
|
|
1254
|
+
# or the same instant spelt otherwise ("…:00Z" and "…:00.000Z"),
|
|
1255
|
+
# where `newer` picks the one spelling
|
|
1256
|
+
set_field_clock(existing, name, clock, removed=gone)
|
|
1163
1257
|
if order < 0 or (order == 0 and same_value):
|
|
1164
|
-
# the state is newer (or this is the same op again): nothing moves
|
|
1258
|
+
# the state is newer (or this is the same op again): nothing moves…
|
|
1259
|
+
# but the last-hand stamp sees this op like every other. The stamp is
|
|
1260
|
+
# at the second and the field at the millisecond, so a stale op can
|
|
1261
|
+
# still TIE the stamp — and if only applied ops counted, who is
|
|
1262
|
+
# the last hand of that second would depend on the arrival (measured,
|
|
1263
|
+
# 348 pairs in 20000). Counted always, the stamp is the max of all.
|
|
1264
|
+
_stamp_payload(existing, clock, creation=False, auth=_op_auth(op)[0])
|
|
1165
1265
|
return OpResult(False, "stale" if order < 0 else "idempotent", node_id)
|
|
1166
1266
|
if order == 0 and not same_value and reason == "unstamped":
|
|
1167
1267
|
# no clocks anywhere: the arriving value is taken, and declared
|
|
1168
1268
|
pass
|
|
1269
|
+
if order == 0 and reason == "tie-author":
|
|
1270
|
+
# the SAME clock (instant and author) on a different state. Against
|
|
1271
|
+
# a node-stamp fallback the op's own clock wins (`tie-explicit`);
|
|
1272
|
+
# against the field's own clock the state decides (`tie-value`),
|
|
1273
|
+
# never the arrival — measured on 12 Oct 2026, a burst of renames in
|
|
1274
|
+
# one millisecond left the room on the last and EMStudio on the first
|
|
1275
|
+
if not explicit:
|
|
1276
|
+
reason = "tie-explicit"
|
|
1277
|
+
elif tie_rank(op.get("value"), wants_gone) < tie_rank(get_field(existing, name), gone):
|
|
1278
|
+
# the value stays; the node's last-hand stamp still sees this
|
|
1279
|
+
# instant, so its spelling does not depend on which op won
|
|
1280
|
+
_stamp_payload(existing, clock, creation=False, auth=_op_auth(op)[0])
|
|
1281
|
+
return OpResult(False, "tie-value", node_id, [FieldOutcome(
|
|
1282
|
+
node_id=node_id, field=name, reason="tie-value",
|
|
1283
|
+
winner={"by": current.by, "at": current.ts, "side": "state",
|
|
1284
|
+
"removed": gone},
|
|
1285
|
+
loser={"by": clock.by, "at": clock.ts, "side": "op",
|
|
1286
|
+
"removed": wants_gone},
|
|
1287
|
+
loser_value=None if wants_gone else op.get("value"))])
|
|
1288
|
+
else:
|
|
1289
|
+
reason = "tie-value"
|
|
1169
1290
|
loser_value = get_field(existing, name)
|
|
1170
1291
|
# ONE act, the same one `api.set_field` performs: a value with its clock,
|
|
1171
1292
|
# or an emptying with its tombstone. `remove: true` (or a null value with
|
|
@@ -1219,9 +1340,12 @@ def apply_op_to_section(section: Dict[str, Any], op: Dict[str, Any], *,
|
|
|
1219
1340
|
learned = _merge_declared(attrs, declared)
|
|
1220
1341
|
# the relation was created by its OLDEST add, whichever arrives
|
|
1221
1342
|
# first: without this two adds converge only in one order
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1343
|
+
# (a stamp, so at the second: `editorial_clock`)
|
|
1344
|
+
born = editorial_clock(Clock(ts=attrs.get("created_at"),
|
|
1345
|
+
by=attrs.get("created_by")))
|
|
1346
|
+
stamp = editorial_clock(clock)
|
|
1347
|
+
if stamp.stamped and (not born.stamped or clock_order(stamp, born) < 0):
|
|
1348
|
+
attrs.update({"created_at": stamp.ts, "created_by": stamp.by})
|
|
1225
1349
|
learned = True
|
|
1226
1350
|
mark = Clock.from_dict(attrs.get(REMOVED_KEY))
|
|
1227
1351
|
if mark.stamped and clock_order(clock, mark) > 0:
|
|
@@ -1234,7 +1358,8 @@ def apply_op_to_section(section: Dict[str, Any], op: Dict[str, Any], *,
|
|
|
1234
1358
|
else OpResult(False, "idempotent"))
|
|
1235
1359
|
attrs = dict(declared)
|
|
1236
1360
|
if clock.stamped:
|
|
1237
|
-
|
|
1361
|
+
stamp = editorial_clock(clock)
|
|
1362
|
+
attrs.update({"created_at": stamp.ts, "created_by": stamp.by})
|
|
1238
1363
|
if attrs:
|
|
1239
1364
|
edge["attributes"] = attrs
|
|
1240
1365
|
edges.append(edge)
|
|
@@ -1317,6 +1442,9 @@ def _stamp_payload(payload: Dict[str, Any], clock: Clock, *, creation: bool,
|
|
|
1317
1442
|
"""
|
|
1318
1443
|
if not clock.stamped:
|
|
1319
1444
|
return
|
|
1445
|
+
# the op's clock is to the millisecond; the stamps it leaves stay at the
|
|
1446
|
+
# second (E.D., 12 Oct 2026), compared as written — at the second
|
|
1447
|
+
clock = editorial_clock(clock)
|
|
1320
1448
|
data = payload.setdefault("data", {})
|
|
1321
1449
|
if creation and not data.get("created_at"):
|
|
1322
1450
|
data["created_at"] = clock.ts
|
|
@@ -1324,8 +1452,8 @@ def _stamp_payload(payload: Dict[str, Any], clock: Clock, *, creation: bool,
|
|
|
1324
1452
|
data["created_by"] = clock.by
|
|
1325
1453
|
if auth:
|
|
1326
1454
|
data["created_auth"] = dict(auth)
|
|
1327
|
-
current = node_stamp(payload)
|
|
1328
|
-
if
|
|
1455
|
+
current = editorial_clock(node_stamp(payload))
|
|
1456
|
+
if newer(clock, current) is clock:
|
|
1329
1457
|
data["modified_at"] = clock.ts
|
|
1330
1458
|
if clock.by:
|
|
1331
1459
|
data["modified_by"] = clock.by
|
|
@@ -1333,6 +1461,12 @@ def _stamp_payload(payload: Dict[str, Any], clock: Clock, *, creation: bool,
|
|
|
1333
1461
|
data["modified_auth"] = dict(auth)
|
|
1334
1462
|
else:
|
|
1335
1463
|
data.pop("modified_auth", None)
|
|
1464
|
+
else:
|
|
1465
|
+
# a later hand nobody named: the previous hand is not the last any
|
|
1466
|
+
# more, and leaving it beside this instant made a clock nobody had
|
|
1467
|
+
# — one that depended on the order (measured, 12 Oct 2026)
|
|
1468
|
+
data.pop("modified_by", None)
|
|
1469
|
+
data.pop("modified_auth", None)
|
|
1336
1470
|
|
|
1337
1471
|
|
|
1338
1472
|
def _op_auth(op: Dict[str, Any]):
|
|
@@ -91,14 +91,56 @@ def normalize_auth(value: Any) -> Optional[Dict[str, str]]:
|
|
|
91
91
|
def now_iso() -> str:
|
|
92
92
|
"""The current instant, UTC, second precision, ISO-8601 with a ``Z``.
|
|
93
93
|
|
|
94
|
-
Second precision on purpose: these stamps
|
|
95
|
-
this touched", and microseconds would only add noise to
|
|
96
|
-
em.json.
|
|
94
|
+
Second precision on purpose: these stamps (``created_at``, ``modified_at``)
|
|
95
|
+
answer "when was this touched", and microseconds would only add noise to
|
|
96
|
+
every diff of every em.json. What ORDERS two hands is the clock of an
|
|
97
|
+
operation, :func:`now_op_iso`.
|
|
97
98
|
"""
|
|
98
99
|
return datetime.now(timezone.utc).replace(microsecond=0).isoformat().replace(
|
|
99
100
|
"+00:00", "Z")
|
|
100
101
|
|
|
101
102
|
|
|
103
|
+
def _op_instant(moment: datetime) -> str:
|
|
104
|
+
return (moment.astimezone(timezone.utc).strftime("%Y-%m-%dT%H:%M:%S")
|
|
105
|
+
+ f".{moment.microsecond // 1000:03d}Z")
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def now_op_iso() -> str:
|
|
109
|
+
"""The clock of an OPERATION: UTC, MILLISECOND precision, ``…:SS.mmmZ``.
|
|
110
|
+
|
|
111
|
+
E.D., 12 Oct 2026: the clock that orders two hands — an op's ``ts``, a
|
|
112
|
+
field's ``data.field_clocks.*.ts``, a tombstone — goes to the millisecond.
|
|
113
|
+
Measured on the table that morning: at the second, a correction made 300 ms
|
|
114
|
+
after another, in the same second, lost to it five times out of five
|
|
115
|
+
(decided by the smaller ORCID), and nobody saw. The editorial stamps stay at
|
|
116
|
+
the second (:func:`now_iso`). A clock at the second is still read and
|
|
117
|
+
compared: ``…:00Z`` is the same instant as ``…:00.000Z`` and earlier than
|
|
118
|
+
``…:00.300Z``.
|
|
119
|
+
"""
|
|
120
|
+
return _op_instant(datetime.now(timezone.utc))
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def normalize_op_instant(value: Any) -> Optional[str]:
|
|
124
|
+
""":func:`normalize_instant` for an operation's clock: the UTC spellings
|
|
125
|
+
come back as ``…:SS.mmmZ``, keeping the milliseconds — or as ``…:SSZ`` when
|
|
126
|
+
there are none, so that a clock written at the second keeps its spelling.
|
|
127
|
+
(``…:00.000Z`` through rdflib comes back as ``…:00Z``: the same instant.)"""
|
|
128
|
+
if value is None:
|
|
129
|
+
return None
|
|
130
|
+
text = str(value).strip()
|
|
131
|
+
if not text:
|
|
132
|
+
return None
|
|
133
|
+
try:
|
|
134
|
+
parsed = datetime.fromisoformat(text.replace("Z", "+00:00"))
|
|
135
|
+
except ValueError:
|
|
136
|
+
return text
|
|
137
|
+
if parsed.tzinfo is None or parsed.utcoffset() != timezone.utc.utcoffset(None):
|
|
138
|
+
return text
|
|
139
|
+
if parsed.microsecond // 1000 == 0:
|
|
140
|
+
return normalize_instant(text)
|
|
141
|
+
return _op_instant(parsed)
|
|
142
|
+
|
|
143
|
+
|
|
102
144
|
def normalize_orcid(value: Any) -> Optional[str]:
|
|
103
145
|
"""Reduce whatever was given to the canonical iD, or ``None``.
|
|
104
146
|
|
|
@@ -1109,7 +1109,7 @@ class RDFImporter:
|
|
|
1109
1109
|
ORCID IRI is returned to its bare canonical form, which is what the
|
|
1110
1110
|
property graph stores.
|
|
1111
1111
|
"""
|
|
1112
|
-
from ..editorial import normalize_instant, normalize_orcid
|
|
1112
|
+
from ..editorial import normalize_instant, normalize_op_instant, normalize_orcid
|
|
1113
1113
|
|
|
1114
1114
|
out: Dict[str, Any] = {}
|
|
1115
1115
|
for key, pred in (("created_by", EM.createdBy),
|
|
@@ -1120,7 +1120,8 @@ class RDFImporter:
|
|
|
1120
1120
|
# P4.1 · the tombstone comes back as a tombstone
|
|
1121
1121
|
removed_at = self._one_literal(store, ref, EM.removedAt)
|
|
1122
1122
|
if removed_at:
|
|
1123
|
-
|
|
1123
|
+
# an operation's clock: its milliseconds come back with it
|
|
1124
|
+
mark = {"ts": normalize_op_instant(removed_at)}
|
|
1124
1125
|
removed_by = self._one_object_text(store, ref, EM.removedBy)
|
|
1125
1126
|
if removed_by:
|
|
1126
1127
|
mark["by"] = normalize_orcid(removed_by) or removed_by
|
|
@@ -508,7 +508,9 @@ def remove_keeping_trace(graph, node_id: str, *, by: Optional[str] = None,
|
|
|
508
508
|
if node is None:
|
|
509
509
|
raise KeyError(f"no node {node_id!r}")
|
|
510
510
|
deps = dependents_of(graph, node_id)
|
|
511
|
-
|
|
511
|
+
from .editorial import now_op_iso
|
|
512
|
+
# the CRDT's tombstone: an operation's clock, to the millisecond
|
|
513
|
+
_ensure_data(node)[REMOVED_KEY] = Clock(ts=at or now_op_iso(), by=by).as_dict()
|
|
512
514
|
return {"node": node_id, "removed": node.data[REMOVED_KEY], "dependents": deps}
|
|
513
515
|
|
|
514
516
|
|