netbox-data-import 2.7.0__tar.gz → 2.9.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.
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/PKG-INFO +2 -1
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/__init__.py +4 -3
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/adapters.py +1 -1
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/cable_disclosure.py +207 -133
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/cable_target.py +332 -196
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/catalog.py +12 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/contact_resolution.py +5 -4
- netbox_data_import-2.9.0/netbox_data_import/device_identity.py +106 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/field_keys.py +23 -2
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/forms.py +8 -0
- netbox_data_import-2.9.0/netbox_data_import/identity.py +100 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/import_engine.py +24 -6
- netbox_data_import-2.9.0/netbox_data_import/migrations/0042_tracelocationresolution.py +41 -0
- netbox_data_import-2.9.0/netbox_data_import/migrations/0043_decision_source_spelling.py +37 -0
- netbox_data_import-2.9.0/netbox_data_import/migrations/0044_cableimportsource_segment_index_unknown.py +17 -0
- netbox_data_import-2.9.0/netbox_data_import/migrations/0045_rekey_name_identities.py +357 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/models.py +97 -3
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/netbox_reader.py +29 -22
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/object_permissions.py +4 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/plan.py +33 -4
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/profile_yaml.py +40 -14
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/proposal_decisions.py +10 -12
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/proposal_presentation.py +17 -6
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/proposal_tasks.py +2 -2
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/review_workspace.py +203 -37
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/source_trace.py +1 -1
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/static/netbox_data_import/js/split_name_modal.js +11 -5
- netbox_data_import-2.9.0/netbox_data_import/static/netbox_data_import/js/trace_picker.js +328 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/target_modules.py +38 -53
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/templates/netbox_data_import/import_preview.html +1 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/templates/netbox_data_import/trace_workspace.html +135 -16
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/termination_proposal.py +11 -12
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/helpers.py +35 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_adapter_config_migration.py +4 -8
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_atomic_exits.py +8 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_branching_refusal.py +6 -1
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_cable_module.py +740 -14
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_configuration_surfaces.py +35 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_contact_sync.py +8 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_cutover_edge_contracts.py +16 -9
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_device_module.py +14 -2
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_digest_indexed_models.py +5 -2
- netbox_data_import-2.9.0/netbox_data_import/tests/test_exception_text_exposure.py +477 -0
- netbox_data_import-2.9.0/netbox_data_import/tests/test_identity.py +233 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_import_cutover.py +66 -6
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_import_engine.py +3 -1
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_import_plan.py +41 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_installation_docs.py +16 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_job_plan_cleanup_migration.py +3 -5
- netbox_data_import-2.9.0/netbox_data_import/tests/test_mapping_identity_preview.py +116 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_migrations.py +6 -34
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_module_boundaries.py +242 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_netbox_reader.py +78 -0
- netbox_data_import-2.9.0/netbox_data_import/tests/test_policy_fingerprint_refusal.py +242 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_proposal_decisions.py +26 -3
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_proposal_tasks.py +79 -5
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_proposal_workspace.py +227 -6
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_rack_module.py +1 -1
- netbox_data_import-2.9.0/netbox_data_import/tests/test_rekey_name_identities_migration.py +548 -0
- netbox_data_import-2.9.0/netbox_data_import/tests/test_split_replacement_acknowledgement.py +179 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_tags_migration.py +5 -5
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_target_field_catalog.py +3 -2
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_trace_decisions.py +68 -4
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_trace_device_resolution.py +237 -63
- netbox_data_import-2.9.0/netbox_data_import/tests/test_trace_location_resolution.py +1283 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_trace_workspace.py +822 -35
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_views.py +191 -38
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/trace_device_resolution.py +202 -191
- netbox_data_import-2.9.0/netbox_data_import/trace_location_resolution.py +219 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/trace_workbook.py +2 -1
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/urls.py +10 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/values.py +0 -6
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/views.py +539 -197
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import.egg-info/PKG-INFO +2 -1
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import.egg-info/SOURCES.txt +14 -3
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/pyproject.toml +2 -1
- netbox_data_import-2.7.0/netbox_data_import/device_identity.py +0 -77
- netbox_data_import-2.7.0/netbox_data_import/static/netbox_data_import/js/trace_device_picker.js +0 -130
- netbox_data_import-2.7.0/netbox_data_import/static/netbox_data_import/js/trace_picker_search.js +0 -63
- netbox_data_import-2.7.0/netbox_data_import/static/netbox_data_import/js/trace_termination_picker.js +0 -126
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/LICENSE +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/README.md +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/_dns_worker.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/adapter_config.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/adapter_forms.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/api/__init__.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/api/serializers.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/api/urls.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/api/views.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/branching.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/cable_policy.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/device_field_review.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/filters.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/flat_workbook.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/graphql/__init__.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/graphql/filters.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/graphql/schema.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/graphql/types.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/inference_adapter.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/inference_backend.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/inference_connection_test.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/inference_credentials.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/inference_settings.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/inference_transport.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/inference_trust.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/ip_assignment.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/jobs.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/migrations/0001_initial.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/migrations/0002_importjob.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/migrations/0003_remove_classrolemapping_unique_class_role_mapping_per_profile_and_more.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/migrations/0004_features.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/migrations/0005_deviceexistingmatch.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/migrations/0006_deviceexistingmatch_asset_tag.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/migrations/0007_manufacturermapping.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/migrations/0008_unique_constraints.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/migrations/0009_add_rack_type_to_classrolemapping.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/migrations/0010_alter_manufacturermapping_id.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/migrations/0011_importprofile_capture_extra_data.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/migrations/0012_classrolemapping_rack_type_related_name.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/migrations/0013_remove_columnmapping_unique_target.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/migrations/0014_alter_columnmapping_target_field_and_more.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/migrations/0015_cleanup_duplicate_device_matches.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/migrations/0016_deviceexistingmatch_ndi_devicematch_profile_device.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/migrations/0017_native_contact_sync.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/migrations/0018_ignoredfielddifference.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/migrations/0019_deviceimportsource.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/migrations/0020_migrate_import_source_custom_field.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/migrations/0021_importprofile_adapter_config.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/migrations/0022_migrate_profile_adapter_config.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/migrations/0023_drop_moved_profile_columns.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/migrations/0024_rename_importjob_importexecution.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/migrations/0025_remove_importexecution_dry_run_and_more.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/migrations/0026_alter_sourcedocument_profile.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/migrations/0027_cableclassmapping_terminationresolution.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/migrations/0028_cableimportsource.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/migrations/0029_alter_cableimportsource_from_text_and_more.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/migrations/0030_remove_device_type_creation_config.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/migrations/0031_inferencebackend.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/migrations/0032_inference_timeout_floor.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/migrations/0033_resolutionproposal.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/migrations/0034_tracedeviceresolution.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/migrations/0035_retire_superseded_proposals.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/migrations/0036_resolutionproposal_job.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/migrations/0037_cablesegmentoverride.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/migrations/0038_cable_tag_integrity.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/migrations/0039_remove_job_plan_copies.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/migrations/0040_move_tags_to_tagged_items.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/migrations/0041_remove_importprofile_tags_and_more.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/migrations/__init__.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/navigation.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/preview_row_actions.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/proposal_contract.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/proposal_jobs.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/proposal_response.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/resolution_proposals.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/signals.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/source_resolution.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/static/netbox_data_import/js/conflict_modal.js +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/static/netbox_data_import/js/contact_candidate_modal.js +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/static/netbox_data_import/js/preview_row_actions.js +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/static/netbox_data_import/js/preview_row_controls.js +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/static/netbox_data_import/js/sync_row_modal.js +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/static/netbox_data_import/js/trace_proposals.js +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tables.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/target_runtime.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/template_content.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/templates/netbox_data_import/_import_progress.html +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/templates/netbox_data_import/_proposal_action.html +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/templates/netbox_data_import/_proposal_card.html +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/templates/netbox_data_import/analysis.html +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/templates/netbox_data_import/branch_refused.html +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/templates/netbox_data_import/branch_refused_anonymous.html +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/templates/netbox_data_import/bulk_yaml_import.html +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/templates/netbox_data_import/cableclassmapping_edit.html +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/templates/netbox_data_import/classrolemapping_edit.html +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/templates/netbox_data_import/columnmapping_edit.html +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/templates/netbox_data_import/columntransformrule_edit.html +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/templates/netbox_data_import/device_import_data.html +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/templates/netbox_data_import/device_import_data_main_only.html +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/templates/netbox_data_import/devicetypemapping_edit.html +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/templates/netbox_data_import/import_profile_yaml.html +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/templates/netbox_data_import/import_progress.html +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/templates/netbox_data_import/import_results.html +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/templates/netbox_data_import/import_setup.html +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/templates/netbox_data_import/importexecution_list.html +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/templates/netbox_data_import/importprofile.html +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/templates/netbox_data_import/importprofile_edit.html +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/templates/netbox_data_import/importprofile_list.html +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/templates/netbox_data_import/inc/branch_refusal_card.html +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/templates/netbox_data_import/inferencebackend.html +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/templates/netbox_data_import/source_resolution_list.html +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/__init__.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/conftest.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/fixtures/combined_name.xlsx +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/fixtures/sample_workbook.xlsx +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/fixtures/trace_copper.xlsx +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/fixtures/trace_fiber.xlsx +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/inference_http.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/isolated_settings.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/mixins.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/mock_discipline.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/netbox_configuration.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/parallel.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/plugins_config.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/redaction.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/snapshot_guard.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_adapter_config.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_api.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_branching.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_branching_absent.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_ci_configuration.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_comment_style.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_configuration_docs.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_conflict_row_actions.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_contact_resolution_ajax.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_contact_role_suggestion.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_devcontainer_e2e.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_execution_audit.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_graphql_filters.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_helpers.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_import_change_log.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_import_execution.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_import_source_migration.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_inference_adapter.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_inference_backend.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_inference_connection_test.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_inference_credentials.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_inference_secret_containment.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_inference_settings.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_inference_trust.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_ip_target.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_markdown_tables.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_misc_coverage.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_mock_discipline.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_model_base_conventions.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_models.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_navigation.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_object_permission_writer.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_parallel_test_setup.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_placement_reference_locks.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_plugins_config.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_policy_write_refusals.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_preview_assets.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_preview_state_ownership.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_pristine_preview_rows.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_profile_policy_crud_scoping.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_proposal_jobs.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_proposal_response.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_quick_action_input_bounds.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_quick_action_object_permissions.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_quick_action_profile_id.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_release_metadata.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_remove_device_type_creation_config_migration.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_resolution_proposal_api.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_resolution_proposals.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_retire_superseded_proposals_migration.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_review_actions.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_review_resolutions.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_review_workspace.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_serial_display.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_snapshot_guard.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_source_adapter.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_source_trace_contract.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_standard_views.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_tag_assignments.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_target_module_edge_contracts.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_text_encoding.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_trace_workbook.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_views_coverage2.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/tests/test_views_extra.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/trace_schema.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/transform_regex.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/utils.py +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import.egg-info/dependency_links.txt +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import.egg-info/requires.txt +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import.egg-info/top_level.txt +0 -0
- {netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: netbox-data-import
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.9.0
|
|
4
4
|
Summary: NetBox plugin for importing data from external DCIM systems
|
|
5
5
|
Author: Marcin Zieba
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -10,6 +10,7 @@ Project-URL: Changelog, https://github.com/marcinpsk/netbox-data-import-plugin/b
|
|
|
10
10
|
Classifier: Programming Language :: Python :: 3
|
|
11
11
|
Classifier: Programming Language :: Python :: 3.12
|
|
12
12
|
Classifier: Programming Language :: Python :: 3.13
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
13
14
|
Classifier: Framework :: Django
|
|
14
15
|
Requires-Python: >=3.12.0
|
|
15
16
|
Description-Content-Type: text/markdown
|
|
@@ -4,7 +4,7 @@ from typing import Any
|
|
|
4
4
|
|
|
5
5
|
from netbox.plugins import PluginConfig
|
|
6
6
|
|
|
7
|
-
__version__ = "2.
|
|
7
|
+
__version__ = "2.9.0"
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
class NetBoxDataImportConfig(PluginConfig):
|
|
@@ -41,11 +41,12 @@ class NetBoxDataImportConfig(PluginConfig):
|
|
|
41
41
|
raise ImproperlyConfigured(f"Plugin {cls.__module__} has an invalid configuration: {exc}") from exc
|
|
42
42
|
|
|
43
43
|
def ready(self):
|
|
44
|
-
"""Import the modules NetBox does not load, and register
|
|
44
|
+
"""Import the modules NetBox does not load, and register the Cable display vocabulary and netbox-branching."""
|
|
45
45
|
super().ready()
|
|
46
46
|
|
|
47
|
-
from . import branching, jobs, termination_proposal
|
|
47
|
+
from . import branching, cable_disclosure, jobs, termination_proposal
|
|
48
48
|
|
|
49
|
+
cable_disclosure.register()
|
|
49
50
|
branching.register()
|
|
50
51
|
|
|
51
52
|
|
|
@@ -17,7 +17,7 @@ from dataclasses import dataclass, field, replace
|
|
|
17
17
|
from typing import TYPE_CHECKING
|
|
18
18
|
|
|
19
19
|
from .catalog import OutputKind, has_implemented_module
|
|
20
|
-
from .
|
|
20
|
+
from .identity import identity_text
|
|
21
21
|
|
|
22
22
|
if TYPE_CHECKING:
|
|
23
23
|
from .source_trace import SourceTrace
|
{netbox_data_import-2.7.0 → netbox_data_import-2.9.0}/netbox_data_import/cable_disclosure.py
RENAMED
|
@@ -4,99 +4,86 @@
|
|
|
4
4
|
|
|
5
5
|
from dataclasses import replace
|
|
6
6
|
from types import MappingProxyType
|
|
7
|
+
from typing import NamedTuple
|
|
8
|
+
|
|
9
|
+
from .catalog import TargetModuleKey
|
|
10
|
+
from .field_keys import CABLE_END_KINDS
|
|
11
|
+
from .plan import ImportPlan, register_diagnostic_display
|
|
7
12
|
|
|
8
13
|
CABLE_ROW = "dcim.cable"
|
|
9
14
|
CABLE_CLASS_MAPPING_ROW = "netbox_data_import.cableclassmapping"
|
|
10
15
|
CABLE_SEGMENT_OVERRIDE_ROW = "netbox_data_import.cablesegmentoverride"
|
|
16
|
+
DEVICE_HIDDEN = "a Device you cannot view"
|
|
17
|
+
DEVICE_ROW = "dcim.device"
|
|
11
18
|
DISCLOSURE_SOURCE = "disclosure_source"
|
|
12
19
|
POLICY_HIDDEN = "a policy you cannot view"
|
|
13
20
|
POLICY_VISIBLE = "policy_visible"
|
|
14
|
-
|
|
21
|
+
TERMINATION_HIDDEN = "a termination you cannot view"
|
|
22
|
+
TERMINATION_SOURCES = "termination_sources"
|
|
23
|
+
|
|
24
|
+
# A segment names its two planned ends apart, so one hidden end leaves the other readable.
|
|
25
|
+
SEGMENT_END_SOURCES = MappingProxyType({"left": "left_sources", "right": "right_sources"})
|
|
15
26
|
|
|
16
27
|
_REFERENCE_FIELDS = frozenset({"device", "cards", "port", "port_class"})
|
|
28
|
+
# These codes replace the source `port` with the NetBox port they resolved.
|
|
29
|
+
_RESOLVED_PORT_FIELDS = _REFERENCE_FIELDS - {"port"}
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class _DisplaySchema(NamedTuple):
|
|
33
|
+
"""The display fields one diagnostic may carry, grouped by the row that authorizes them."""
|
|
34
|
+
|
|
35
|
+
public: frozenset
|
|
36
|
+
cable: frozenset = frozenset()
|
|
37
|
+
policy: frozenset = frozenset()
|
|
38
|
+
termination: frozenset = frozenset()
|
|
39
|
+
|
|
17
40
|
|
|
18
41
|
_DIAGNOSTIC_DISCLOSURE_FIELDS = MappingProxyType(
|
|
19
42
|
{
|
|
20
|
-
"cable.ambiguous_mapped_peer": (
|
|
21
|
-
"cable.attribute_drift": (
|
|
22
|
-
frozenset({"segment_index"}),
|
|
23
|
-
frozenset({"cable", "status", "type", "profile", "label"}),
|
|
24
|
-
frozenset(),
|
|
25
|
-
),
|
|
26
|
-
"cable.cableclass_unmapped": (frozenset({"segment_index", "cable_class"}), frozenset(), frozenset()),
|
|
27
|
-
"cable.media_family_mismatch": (
|
|
28
|
-
frozenset(),
|
|
29
|
-
frozenset({"segments"}),
|
|
30
|
-
frozenset({"segments"}),
|
|
43
|
+
"cable.ambiguous_mapped_peer": _DisplaySchema(_RESOLVED_PORT_FIELDS, termination=frozenset({"port", "peers"})),
|
|
44
|
+
"cable.attribute_drift": _DisplaySchema(
|
|
45
|
+
frozenset({"segment_index"}), cable=frozenset({"cable", "status", "type", "profile", "label"})
|
|
31
46
|
),
|
|
32
|
-
"cable.
|
|
33
|
-
|
|
34
|
-
frozenset({"
|
|
35
|
-
frozenset(),
|
|
47
|
+
"cable.cableclass_unmapped": _DisplaySchema(frozenset({"segment_index", "cable_class"})),
|
|
48
|
+
"cable.incompatible_terminations": _DisplaySchema(
|
|
49
|
+
frozenset({"segment_index", "left_field_key", "right_field_key"}),
|
|
50
|
+
termination=frozenset({"left_model", "right_model"}),
|
|
36
51
|
),
|
|
37
|
-
"cable.
|
|
38
|
-
|
|
39
|
-
frozenset(),
|
|
40
|
-
frozenset(),
|
|
52
|
+
"cable.media_family_mismatch": _DisplaySchema(
|
|
53
|
+
frozenset(), cable=frozenset({"segments"}), policy=frozenset({"segments"})
|
|
41
54
|
),
|
|
42
|
-
"cable.
|
|
43
|
-
|
|
44
|
-
frozenset(),
|
|
45
|
-
frozenset(),
|
|
55
|
+
"cable.multi_termination_conflict": _DisplaySchema(
|
|
56
|
+
frozenset({"segment_index"}), cable=frozenset({"cable"}), termination=frozenset({"port"})
|
|
46
57
|
),
|
|
47
|
-
"cable.
|
|
48
|
-
_REFERENCE_FIELDS
|
|
49
|
-
frozenset({"cable"}),
|
|
50
|
-
frozenset(),
|
|
58
|
+
"cable.pass_through_not_mapped": _DisplaySchema(
|
|
59
|
+
_REFERENCE_FIELDS, termination=frozenset({"entry", "exit", "mapped"})
|
|
51
60
|
),
|
|
52
|
-
"cable.
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
frozenset(),
|
|
61
|
+
"cable.pass_through_verified": _DisplaySchema(_REFERENCE_FIELDS, termination=frozenset({"entry", "exit"})),
|
|
62
|
+
"cable.permission_denied": _DisplaySchema(_REFERENCE_FIELDS | {"permission"}, cable=frozenset({"cable"})),
|
|
63
|
+
"cable.planned_termination_conflict": _DisplaySchema(
|
|
64
|
+
frozenset({"segment_index", "competing_trace"}), termination=frozenset({"termination"})
|
|
56
65
|
),
|
|
57
|
-
"cable.policy_stale": (frozenset({"segment_index", "cable_class"})
|
|
58
|
-
"cable.profile_incompatible": (frozenset({"segment_index", "cable_class"})
|
|
59
|
-
"cable.resolved_segment_conflict": (
|
|
60
|
-
frozenset({"segment_index", "terminations"}),
|
|
61
|
-
frozenset(),
|
|
62
|
-
frozenset({"cable_type", "cable_profile"}),
|
|
63
|
-
),
|
|
64
|
-
"cable.same_port_continuation": (_REFERENCE_FIELDS | {"peer"}, frozenset(), frozenset()),
|
|
65
|
-
"cable.segment_override_lost": (
|
|
66
|
-
frozenset({"segment_index"}),
|
|
67
|
-
frozenset(),
|
|
68
|
-
frozenset({"cable_type", "cable_profile"}),
|
|
69
|
-
),
|
|
70
|
-
"cable.segment_reused": (
|
|
66
|
+
"cable.policy_stale": _DisplaySchema(frozenset({"segment_index", "cable_class"})),
|
|
67
|
+
"cable.profile_incompatible": _DisplaySchema(frozenset({"segment_index", "cable_class"})),
|
|
68
|
+
"cable.resolved_segment_conflict": _DisplaySchema(
|
|
71
69
|
frozenset({"segment_index"}),
|
|
72
|
-
frozenset({"
|
|
73
|
-
frozenset(),
|
|
74
|
-
),
|
|
75
|
-
"cable.segment_self_connection": (
|
|
76
|
-
frozenset({"segment_index", "cable_class", "termination"}),
|
|
77
|
-
frozenset(),
|
|
78
|
-
frozenset(),
|
|
70
|
+
policy=frozenset({"cable_type", "cable_profile"}),
|
|
71
|
+
termination=frozenset({"terminations"}),
|
|
79
72
|
),
|
|
80
|
-
"cable.
|
|
81
|
-
|
|
82
|
-
frozenset(),
|
|
83
|
-
frozenset(),
|
|
73
|
+
"cable.same_port_continuation": _DisplaySchema(_RESOLVED_PORT_FIELDS, termination=frozenset({"port", "peer"})),
|
|
74
|
+
"cable.segment_override_lost": _DisplaySchema(
|
|
75
|
+
frozenset({"segment_index"}), policy=frozenset({"cable_type", "cable_profile"})
|
|
84
76
|
),
|
|
85
|
-
"cable.
|
|
86
|
-
|
|
87
|
-
frozenset({"
|
|
88
|
-
frozenset(),
|
|
77
|
+
"cable.segment_reused": _DisplaySchema(frozenset({"segment_index"}), cable=frozenset({"cable"})),
|
|
78
|
+
"cable.segment_self_connection": _DisplaySchema(
|
|
79
|
+
frozenset({"segment_index", "cable_class"}), termination=frozenset({"termination"})
|
|
89
80
|
),
|
|
90
|
-
"cable.
|
|
91
|
-
|
|
92
|
-
frozenset(),
|
|
93
|
-
frozenset(),
|
|
94
|
-
),
|
|
95
|
-
"cable.unsupported_termination_kind": (
|
|
96
|
-
_REFERENCE_FIELDS | {"selected_object_type"},
|
|
97
|
-
frozenset(),
|
|
98
|
-
frozenset(),
|
|
81
|
+
"cable.termination_kind_mismatch": _DisplaySchema(_REFERENCE_FIELDS | {"claimed_kind", "selected_object_type"}),
|
|
82
|
+
"cable.termination_occupied": _DisplaySchema(
|
|
83
|
+
frozenset({"segment_index"}), cable=frozenset({"cable"}), termination=frozenset({"port"})
|
|
99
84
|
),
|
|
85
|
+
"cable.termination_unresolved": _DisplaySchema(_REFERENCE_FIELDS),
|
|
86
|
+
"cable.unsupported_termination_kind": _DisplaySchema(_REFERENCE_FIELDS | {"selected_object_type"}),
|
|
100
87
|
}
|
|
101
88
|
)
|
|
102
89
|
|
|
@@ -105,11 +92,15 @@ CABLE_DIAGNOSTIC_FIELDS = MappingProxyType(
|
|
|
105
92
|
)
|
|
106
93
|
|
|
107
94
|
CABLE_DIAGNOSTIC_DISCLOSURES = MappingProxyType(
|
|
108
|
-
{code: fields
|
|
95
|
+
{code: fields.cable for code, fields in _DIAGNOSTIC_DISCLOSURE_FIELDS.items() if fields.cable}
|
|
109
96
|
)
|
|
110
97
|
|
|
111
98
|
POLICY_DIAGNOSTIC_DISCLOSURES = MappingProxyType(
|
|
112
|
-
{code: fields
|
|
99
|
+
{code: fields.policy for code, fields in _DIAGNOSTIC_DISCLOSURE_FIELDS.items() if fields.policy}
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
TERMINATION_DIAGNOSTIC_DISCLOSURES = MappingProxyType(
|
|
103
|
+
{code: fields.termination for code, fields in _DIAGNOSTIC_DISCLOSURE_FIELDS.items() if fields.termination}
|
|
113
104
|
)
|
|
114
105
|
|
|
115
106
|
|
|
@@ -118,6 +109,21 @@ def disclosure_source(row_kind: str, row_pk: int) -> dict:
|
|
|
118
109
|
return {"kind": row_kind, "pk": row_pk}
|
|
119
110
|
|
|
120
111
|
|
|
112
|
+
def device_source(device_id: int) -> dict:
|
|
113
|
+
"""Return the source a display needs when it names one resolved Device."""
|
|
114
|
+
return disclosure_source(DEVICE_ROW, device_id)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def segment_end_sources(port: tuple[str, int], device_id: int) -> list:
|
|
118
|
+
"""Return the rows that authorize one planned segment end, which names its Device and its port."""
|
|
119
|
+
return [disclosure_source(*port), device_source(device_id)]
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def termination_sources(*terminations) -> dict:
|
|
123
|
+
"""Return the sources a display needs when it names the given resolved terminations."""
|
|
124
|
+
return {TERMINATION_SOURCES: [disclosure_source(label, object_id) for label, object_id in terminations]}
|
|
125
|
+
|
|
126
|
+
|
|
121
127
|
def disclosed_cable(cable) -> dict:
|
|
122
128
|
"""Return the fields a planner may record for one visible Cable."""
|
|
123
129
|
return {
|
|
@@ -159,12 +165,10 @@ def policy_row_is_disclosed(display: dict, row) -> bool:
|
|
|
159
165
|
|
|
160
166
|
def validate_diagnostic_disclosures(code: str, display: dict) -> None:
|
|
161
167
|
"""Reject diagnostic display fields that bypass the shared disclosure vocabulary."""
|
|
162
|
-
if not code.startswith("cable."):
|
|
163
|
-
return
|
|
164
168
|
fields = _DIAGNOSTIC_DISCLOSURE_FIELDS.get(code)
|
|
165
169
|
if fields is None:
|
|
166
170
|
raise ValueError(f"Diagnostic '{code}' has no registered display schema.")
|
|
167
|
-
public, cable, policy = fields
|
|
171
|
+
public, cable, policy, termination = fields
|
|
168
172
|
if code == "cable.media_family_mismatch":
|
|
169
173
|
_validate_media_segments(display)
|
|
170
174
|
return
|
|
@@ -173,10 +177,19 @@ def validate_diagnostic_disclosures(code: str, display: dict) -> None:
|
|
|
173
177
|
metadata.update({DISCLOSURE_SOURCE, "cable_visible"})
|
|
174
178
|
if policy:
|
|
175
179
|
metadata.update({DISCLOSURE_SOURCE, POLICY_VISIBLE})
|
|
176
|
-
|
|
180
|
+
if termination:
|
|
181
|
+
metadata.add(TERMINATION_SOURCES)
|
|
182
|
+
if not _well_formed_termination_sources(display.get(TERMINATION_SOURCES)):
|
|
183
|
+
raise ValueError(f"Diagnostic '{code}' names terminations without their sources.")
|
|
184
|
+
unknown = set(display) - set(public) - set(cable) - set(policy) - set(termination) - metadata
|
|
177
185
|
if unknown:
|
|
178
186
|
names = ", ".join(sorted(unknown))
|
|
179
187
|
raise ValueError(f"Diagnostic '{code}' has unregistered display fields: {names}.")
|
|
188
|
+
_validate_row_flags(code, display, cable, policy)
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def _validate_row_flags(code: str, display: dict, cable: frozenset, policy: frozenset) -> None:
|
|
192
|
+
"""Reject Cable and policy fields whose visibility flag and source disagree."""
|
|
180
193
|
source = display.get(DISCLOSURE_SOURCE)
|
|
181
194
|
if set(display) & set(cable) or "cable_visible" in display:
|
|
182
195
|
visible = display.get("cable_visible")
|
|
@@ -225,27 +238,74 @@ def _source_pk(value, row_kind: str) -> int | None:
|
|
|
225
238
|
return row_pk if isinstance(row_pk, int) and not isinstance(row_pk, bool) else None
|
|
226
239
|
|
|
227
240
|
|
|
228
|
-
def _source_is_visible(value, row_kinds
|
|
241
|
+
def _source_is_visible(value, row_kinds, visible_row_ids: dict[str, set[int]]) -> bool:
|
|
229
242
|
"""Return whether one well-formed source names a row visible in its expected kind."""
|
|
230
243
|
return any(
|
|
231
|
-
(row_pk := _source_pk(value, row_kind)) is not None and row_pk in visible_row_ids
|
|
244
|
+
(row_pk := _source_pk(value, row_kind)) is not None and row_pk in visible_row_ids.get(row_kind, ())
|
|
232
245
|
for row_kind in row_kinds
|
|
233
246
|
)
|
|
234
247
|
|
|
235
248
|
|
|
249
|
+
def _well_formed_termination_sources(sources) -> bool:
|
|
250
|
+
"""Return whether *sources* is a nonempty list of sources that each name a Cable End Kind row."""
|
|
251
|
+
return (
|
|
252
|
+
isinstance(sources, list)
|
|
253
|
+
and bool(sources)
|
|
254
|
+
and all(any(_source_pk(source, kind) is not None for kind in CABLE_END_KINDS) for source in sources)
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def _terminations_are_visible(sources, visible_row_ids: dict[str, set[int]]) -> bool:
|
|
259
|
+
"""Return whether every termination one display names is live and visible."""
|
|
260
|
+
return _well_formed_termination_sources(sources) and all(
|
|
261
|
+
_source_is_visible(source, CABLE_END_KINDS, visible_row_ids) for source in sources
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
def _identity_key(identity) -> tuple[str, int] | None:
|
|
266
|
+
"""Return the Cable End Kind row one plan identity names, or None for any other identity."""
|
|
267
|
+
label, _, object_id = str(identity).rpartition(":")
|
|
268
|
+
if label not in CABLE_END_KINDS or not object_id.isdigit():
|
|
269
|
+
return None
|
|
270
|
+
return label, int(object_id)
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
def _row_sources(value: dict) -> list:
|
|
274
|
+
"""Return every row source one display mapping carries."""
|
|
275
|
+
sources = [value.get(DISCLOSURE_SOURCE)]
|
|
276
|
+
for key in (TERMINATION_SOURCES, *SEGMENT_END_SOURCES.values()):
|
|
277
|
+
listed = value.get(key)
|
|
278
|
+
# A frozen plan holds a list as a tuple.
|
|
279
|
+
if isinstance(listed, (list, tuple)):
|
|
280
|
+
sources.extend(listed)
|
|
281
|
+
return sources
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
def _end_is_visible(sources, visible_row_ids: dict[str, set[int]]) -> bool:
|
|
285
|
+
"""Return whether a planned end's port and Device are both live and visible."""
|
|
286
|
+
return (
|
|
287
|
+
isinstance(sources, (list, tuple))
|
|
288
|
+
and len(sources) == 2
|
|
289
|
+
and _source_is_visible(sources[0], CABLE_END_KINDS, visible_row_ids)
|
|
290
|
+
and _source_is_visible(sources[1], (DEVICE_ROW,), visible_row_ids)
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
|
|
236
294
|
def _row_ids(units) -> dict[str, set[int]]:
|
|
237
295
|
row_ids: dict[str, set[int]] = {
|
|
238
296
|
CABLE_ROW: set(),
|
|
239
297
|
CABLE_CLASS_MAPPING_ROW: set(),
|
|
240
298
|
CABLE_SEGMENT_OVERRIDE_ROW: set(),
|
|
299
|
+
DEVICE_ROW: set(),
|
|
300
|
+
**{kind: set() for kind in sorted(CABLE_END_KINDS)},
|
|
241
301
|
}
|
|
242
302
|
|
|
243
303
|
def collect(value) -> None:
|
|
244
304
|
if isinstance(value, dict):
|
|
245
|
-
source
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
305
|
+
for source in _row_sources(value):
|
|
306
|
+
for row_kind, ids in row_ids.items():
|
|
307
|
+
if row_pk := _source_pk(source, row_kind):
|
|
308
|
+
ids.add(row_pk)
|
|
249
309
|
for child in value.values():
|
|
250
310
|
collect(child)
|
|
251
311
|
elif isinstance(value, (list, tuple)):
|
|
@@ -256,6 +316,9 @@ def _row_ids(units) -> dict[str, set[int]]:
|
|
|
256
316
|
collect(unit.display)
|
|
257
317
|
for diagnostic in unit.diagnostics:
|
|
258
318
|
collect(diagnostic.display)
|
|
319
|
+
for identity in diagnostic.identities:
|
|
320
|
+
if key := _identity_key(identity):
|
|
321
|
+
row_ids[key[0]].add(key[1])
|
|
259
322
|
return row_ids
|
|
260
323
|
|
|
261
324
|
|
|
@@ -299,43 +362,32 @@ def _media_segment(segment: dict, visible_row_ids: dict[str, set[int]]) -> dict:
|
|
|
299
362
|
}
|
|
300
363
|
|
|
301
364
|
|
|
302
|
-
def
|
|
303
|
-
|
|
365
|
+
def _redact_terminations(display: dict, keys: frozenset[str]) -> dict:
|
|
366
|
+
for key in keys & set(display):
|
|
367
|
+
display[key] = [] if isinstance(display[key], list) else TERMINATION_HIDDEN
|
|
368
|
+
display.pop(TERMINATION_SOURCES, None)
|
|
369
|
+
return display
|
|
304
370
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
family = cable_media_family_label(segment["family"])
|
|
313
|
-
statement = f"segment {position} is {cable_type_label(segment['cable_type'])} ({family})"
|
|
314
|
-
if segment["retained"]:
|
|
315
|
-
statement += ", on the Cable this import keeps"
|
|
316
|
-
statements.append(statement)
|
|
317
|
-
remedy = (
|
|
318
|
-
"Correct those Cables in NetBox, then re-read."
|
|
319
|
-
if all(segment["retained"] for segment in segments)
|
|
320
|
-
else "Force the segment that states the wrong medium, or correct the source."
|
|
371
|
+
|
|
372
|
+
def _visible_identities(identities, visible_row_ids: dict[str, set[int]]) -> tuple:
|
|
373
|
+
"""Return the identities a viewer may read: a hidden or deleted termination drops out."""
|
|
374
|
+
return tuple(
|
|
375
|
+
identity
|
|
376
|
+
for identity in identities
|
|
377
|
+
if (key := _identity_key(identity)) is None or key[1] in visible_row_ids.get(key[0], ())
|
|
321
378
|
)
|
|
322
|
-
return f"Verified pass-throughs join these segments, and {'; '.join(statements)}. {remedy}"
|
|
323
379
|
|
|
324
380
|
|
|
325
381
|
def _diagnostic(diagnostic, visible_row_ids: dict[str, set[int]]):
|
|
326
382
|
display = diagnostic.to_dict()["display"]
|
|
327
383
|
if diagnostic.code == "cable.media_family_mismatch":
|
|
328
|
-
segments = [_media_segment(segment, visible_row_ids) for segment in display["segments"]]
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
)
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
if display.get("cable_visible") is True and not _source_is_visible(
|
|
336
|
-
display.get(DISCLOSURE_SOURCE), (CABLE_ROW,), visible_row_ids
|
|
337
|
-
):
|
|
338
|
-
display = _redact_cable(display, keys)
|
|
384
|
+
display["segments"] = [_media_segment(segment, visible_row_ids) for segment in display["segments"]]
|
|
385
|
+
elif (
|
|
386
|
+
(keys := CABLE_DIAGNOSTIC_DISCLOSURES.get(diagnostic.code))
|
|
387
|
+
and display.get("cable_visible") is True
|
|
388
|
+
and not _source_is_visible(display.get(DISCLOSURE_SOURCE), (CABLE_ROW,), visible_row_ids)
|
|
389
|
+
):
|
|
390
|
+
display = _redact_cable(display, keys)
|
|
339
391
|
if (
|
|
340
392
|
diagnostic.code in POLICY_DIAGNOSTIC_DISCLOSURES
|
|
341
393
|
and display.get(POLICY_VISIBLE) is True
|
|
@@ -346,13 +398,10 @@ def _diagnostic(diagnostic, visible_row_ids: dict[str, set[int]]):
|
|
|
346
398
|
)
|
|
347
399
|
):
|
|
348
400
|
display = _redact_policy(display)
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
from .cable_policy import cable_media_family_label
|
|
354
|
-
|
|
355
|
-
return cable_media_family_label(family)
|
|
401
|
+
keys = TERMINATION_DIAGNOSTIC_DISCLOSURES.get(diagnostic.code)
|
|
402
|
+
if keys and not _terminations_are_visible(display.get(TERMINATION_SOURCES), visible_row_ids):
|
|
403
|
+
display = _redact_terminations(display, keys)
|
|
404
|
+
return replace(diagnostic, display=display, identities=_visible_identities(diagnostic.identities, visible_row_ids))
|
|
356
405
|
|
|
357
406
|
|
|
358
407
|
def _unit(unit, visible_row_ids: dict[str, set[int]]):
|
|
@@ -380,28 +429,41 @@ def _unit(unit, visible_row_ids: dict[str, set[int]]):
|
|
|
380
429
|
):
|
|
381
430
|
policy.pop(DISCLOSURE_SOURCE, None)
|
|
382
431
|
policy.update(_redact_policy(policy))
|
|
432
|
+
for question in trace.get("devices") or ():
|
|
433
|
+
if question.get("selected") and not _source_is_visible(
|
|
434
|
+
question.get(DISCLOSURE_SOURCE), (DEVICE_ROW,), visible_row_ids
|
|
435
|
+
):
|
|
436
|
+
question.pop(DISCLOSURE_SOURCE, None)
|
|
437
|
+
question["selected"] = DEVICE_HIDDEN
|
|
438
|
+
for field in trace.get("terminations") or ():
|
|
439
|
+
if field.get("selected") and not _source_is_visible(
|
|
440
|
+
field.get(DISCLOSURE_SOURCE), CABLE_END_KINDS, visible_row_ids
|
|
441
|
+
):
|
|
442
|
+
field.pop(DISCLOSURE_SOURCE, None)
|
|
443
|
+
field.update(selected=TERMINATION_HIDDEN, selected_type="")
|
|
444
|
+
for segment in trace.get("segments") or ():
|
|
445
|
+
# Only a planned segment names NetBox ports; an unplanned one repeats the source text.
|
|
446
|
+
if not segment.get("segment_key"):
|
|
447
|
+
continue
|
|
448
|
+
for end, source_key in SEGMENT_END_SOURCES.items():
|
|
449
|
+
if not _end_is_visible(segment.get(source_key), visible_row_ids):
|
|
450
|
+
segment.pop(source_key, None)
|
|
451
|
+
segment[end] = TERMINATION_HIDDEN
|
|
383
452
|
diagnostics = tuple(_diagnostic(item, visible_row_ids) for item in unit.diagnostics)
|
|
384
453
|
return replace(unit, diagnostics=diagnostics, display=display)
|
|
385
454
|
|
|
386
455
|
|
|
387
456
|
def present_units(units, viewer) -> tuple:
|
|
388
|
-
"""Return presentation copies after one live
|
|
457
|
+
"""Return presentation copies after one live visibility query per referenced row kind."""
|
|
389
458
|
if viewer is None:
|
|
390
459
|
raise TypeError("ReviewWorkspace requires a live viewer.")
|
|
391
460
|
units = tuple(units)
|
|
392
|
-
from
|
|
393
|
-
|
|
394
|
-
from .models import CableClassMapping, CableSegmentOverride
|
|
461
|
+
from django.apps import apps
|
|
395
462
|
|
|
396
463
|
row_ids = _row_ids(units)
|
|
397
|
-
models = {
|
|
398
|
-
CABLE_ROW: Cable,
|
|
399
|
-
CABLE_CLASS_MAPPING_ROW: CableClassMapping,
|
|
400
|
-
CABLE_SEGMENT_OVERRIDE_ROW: CableSegmentOverride,
|
|
401
|
-
}
|
|
402
464
|
visible = {}
|
|
403
|
-
for row_kind,
|
|
404
|
-
|
|
465
|
+
for row_kind, ids in row_ids.items():
|
|
466
|
+
model = apps.get_model(row_kind)
|
|
405
467
|
visible[row_kind] = (
|
|
406
468
|
set(model.objects.restrict(viewer, "view").filter(pk__in=sorted(ids)).values_list("pk", flat=True))
|
|
407
469
|
if ids
|
|
@@ -412,8 +474,6 @@ def present_units(units, viewer) -> tuple:
|
|
|
412
474
|
|
|
413
475
|
def redact_deleted_cables(plan_data: dict) -> dict:
|
|
414
476
|
"""Return an execution copy whose deleted Cable rows authorize no stored display text."""
|
|
415
|
-
from .plan import ImportPlan
|
|
416
|
-
|
|
417
477
|
plan = ImportPlan.from_dict(plan_data)
|
|
418
478
|
visible = _row_ids(plan.units)
|
|
419
479
|
deleted_ids = {
|
|
@@ -427,22 +487,36 @@ def redact_deleted_cables(plan_data: dict) -> dict:
|
|
|
427
487
|
return replace(plan, units=units).to_dict()
|
|
428
488
|
|
|
429
489
|
|
|
490
|
+
def register() -> None:
|
|
491
|
+
"""Register the Cable display vocabulary, so a cached plan with an unknown Cable display field is refused."""
|
|
492
|
+
register_diagnostic_display(TargetModuleKey.CABLE, validate_diagnostic_disclosures)
|
|
493
|
+
|
|
494
|
+
|
|
430
495
|
__all__ = (
|
|
431
496
|
"CABLE_CLASS_MAPPING_ROW",
|
|
432
497
|
"CABLE_DIAGNOSTIC_DISCLOSURES",
|
|
433
498
|
"CABLE_DIAGNOSTIC_FIELDS",
|
|
434
499
|
"CABLE_ROW",
|
|
435
500
|
"CABLE_SEGMENT_OVERRIDE_ROW",
|
|
501
|
+
"DEVICE_HIDDEN",
|
|
502
|
+
"DEVICE_ROW",
|
|
436
503
|
"DISCLOSURE_SOURCE",
|
|
437
504
|
"POLICY_DIAGNOSTIC_DISCLOSURES",
|
|
438
505
|
"POLICY_HIDDEN",
|
|
439
506
|
"POLICY_VISIBLE",
|
|
440
|
-
"
|
|
507
|
+
"SEGMENT_END_SOURCES",
|
|
508
|
+
"TERMINATION_DIAGNOSTIC_DISCLOSURES",
|
|
509
|
+
"TERMINATION_HIDDEN",
|
|
510
|
+
"TERMINATION_SOURCES",
|
|
511
|
+
"device_source",
|
|
441
512
|
"disclosed_cable",
|
|
442
513
|
"disclosed_policy",
|
|
443
514
|
"disclosure_source",
|
|
444
515
|
"policy_row_is_disclosed",
|
|
445
516
|
"present_units",
|
|
446
517
|
"redact_deleted_cables",
|
|
518
|
+
"register",
|
|
519
|
+
"segment_end_sources",
|
|
520
|
+
"termination_sources",
|
|
447
521
|
"validate_diagnostic_disclosures",
|
|
448
522
|
)
|