nucliadb 4.0.0.post542__py3-none-any.whl → 6.2.1.post2777__py3-none-any.whl
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.
- migrations/0003_allfields_key.py +1 -35
- migrations/0009_upgrade_relations_and_texts_to_v2.py +4 -2
- migrations/0010_fix_corrupt_indexes.py +10 -10
- migrations/0011_materialize_labelset_ids.py +1 -16
- migrations/0012_rollover_shards.py +5 -10
- migrations/0014_rollover_shards.py +4 -5
- migrations/0015_targeted_rollover.py +5 -10
- migrations/0016_upgrade_to_paragraphs_v2.py +25 -28
- migrations/0017_multiple_writable_shards.py +2 -4
- migrations/0018_purge_orphan_kbslugs.py +5 -7
- migrations/0019_upgrade_to_paragraphs_v3.py +25 -28
- migrations/0020_drain_nodes_from_cluster.py +3 -3
- nucliadb/standalone/tests/unit/test_run.py → migrations/0021_overwrite_vectorsets_key.py +16 -19
- nucliadb/tests/unit/test_openapi.py → migrations/0022_fix_paragraph_deletion_bug.py +16 -11
- migrations/0023_backfill_pg_catalog.py +80 -0
- migrations/0025_assign_models_to_kbs_v2.py +113 -0
- migrations/0026_fix_high_cardinality_content_types.py +61 -0
- migrations/0027_rollover_texts3.py +73 -0
- nucliadb/ingest/fields/date.py → migrations/pg/0001_bootstrap.py +10 -12
- migrations/pg/0002_catalog.py +42 -0
- nucliadb/ingest/tests/unit/test_settings.py → migrations/pg/0003_catalog_kbid_index.py +5 -3
- nucliadb/common/cluster/base.py +30 -16
- nucliadb/common/cluster/discovery/base.py +6 -14
- nucliadb/common/cluster/discovery/k8s.py +9 -19
- nucliadb/common/cluster/discovery/manual.py +1 -3
- nucliadb/common/cluster/discovery/utils.py +1 -3
- nucliadb/common/cluster/grpc_node_dummy.py +3 -11
- nucliadb/common/cluster/index_node.py +10 -19
- nucliadb/common/cluster/manager.py +174 -59
- nucliadb/common/cluster/rebalance.py +27 -29
- nucliadb/common/cluster/rollover.py +353 -194
- nucliadb/common/cluster/settings.py +6 -0
- nucliadb/common/cluster/standalone/grpc_node_binding.py +13 -64
- nucliadb/common/cluster/standalone/index_node.py +4 -11
- nucliadb/common/cluster/standalone/service.py +2 -6
- nucliadb/common/cluster/standalone/utils.py +2 -6
- nucliadb/common/cluster/utils.py +29 -22
- nucliadb/common/constants.py +20 -0
- nucliadb/common/context/__init__.py +3 -0
- nucliadb/common/context/fastapi.py +8 -5
- nucliadb/{tests/knowledgeboxes/__init__.py → common/counters.py} +8 -2
- nucliadb/common/datamanagers/__init__.py +7 -1
- nucliadb/common/datamanagers/atomic.py +22 -4
- nucliadb/common/datamanagers/cluster.py +5 -5
- nucliadb/common/datamanagers/entities.py +6 -16
- nucliadb/common/datamanagers/fields.py +84 -0
- nucliadb/common/datamanagers/kb.py +83 -37
- nucliadb/common/datamanagers/labels.py +26 -56
- nucliadb/common/datamanagers/processing.py +2 -6
- nucliadb/common/datamanagers/resources.py +41 -103
- nucliadb/common/datamanagers/rollover.py +76 -15
- nucliadb/common/datamanagers/synonyms.py +1 -1
- nucliadb/common/datamanagers/utils.py +15 -6
- nucliadb/common/datamanagers/vectorsets.py +110 -0
- nucliadb/common/external_index_providers/base.py +257 -0
- nucliadb/{ingest/tests/unit/orm/test_orm_utils.py → common/external_index_providers/exceptions.py} +9 -8
- nucliadb/common/external_index_providers/manager.py +101 -0
- nucliadb/common/external_index_providers/pinecone.py +933 -0
- nucliadb/common/external_index_providers/settings.py +52 -0
- nucliadb/common/http_clients/auth.py +3 -6
- nucliadb/common/http_clients/processing.py +6 -11
- nucliadb/common/http_clients/utils.py +1 -3
- nucliadb/common/ids.py +240 -0
- nucliadb/common/locking.py +29 -7
- nucliadb/common/maindb/driver.py +11 -35
- nucliadb/common/maindb/exceptions.py +3 -0
- nucliadb/common/maindb/local.py +22 -9
- nucliadb/common/maindb/pg.py +206 -111
- nucliadb/common/maindb/utils.py +11 -42
- nucliadb/common/models_utils/from_proto.py +479 -0
- nucliadb/common/models_utils/to_proto.py +60 -0
- nucliadb/common/nidx.py +260 -0
- nucliadb/export_import/datamanager.py +25 -19
- nucliadb/export_import/exporter.py +5 -11
- nucliadb/export_import/importer.py +5 -7
- nucliadb/export_import/models.py +3 -3
- nucliadb/export_import/tasks.py +4 -4
- nucliadb/export_import/utils.py +25 -37
- nucliadb/health.py +1 -3
- nucliadb/ingest/app.py +15 -11
- nucliadb/ingest/consumer/auditing.py +21 -19
- nucliadb/ingest/consumer/consumer.py +82 -47
- nucliadb/ingest/consumer/materializer.py +5 -12
- nucliadb/ingest/consumer/pull.py +12 -27
- nucliadb/ingest/consumer/service.py +19 -17
- nucliadb/ingest/consumer/shard_creator.py +2 -4
- nucliadb/ingest/consumer/utils.py +1 -3
- nucliadb/ingest/fields/base.py +137 -105
- nucliadb/ingest/fields/conversation.py +18 -5
- nucliadb/ingest/fields/exceptions.py +1 -4
- nucliadb/ingest/fields/file.py +7 -16
- nucliadb/ingest/fields/link.py +5 -10
- nucliadb/ingest/fields/text.py +9 -4
- nucliadb/ingest/orm/brain.py +200 -213
- nucliadb/ingest/orm/broker_message.py +181 -0
- nucliadb/ingest/orm/entities.py +36 -51
- nucliadb/ingest/orm/exceptions.py +12 -0
- nucliadb/ingest/orm/knowledgebox.py +322 -197
- nucliadb/ingest/orm/processor/__init__.py +2 -700
- nucliadb/ingest/orm/processor/auditing.py +4 -23
- nucliadb/ingest/orm/processor/data_augmentation.py +164 -0
- nucliadb/ingest/orm/processor/pgcatalog.py +84 -0
- nucliadb/ingest/orm/processor/processor.py +752 -0
- nucliadb/ingest/orm/processor/sequence_manager.py +1 -1
- nucliadb/ingest/orm/resource.py +249 -402
- nucliadb/ingest/orm/utils.py +4 -4
- nucliadb/ingest/partitions.py +3 -9
- nucliadb/ingest/processing.py +64 -73
- nucliadb/ingest/py.typed +0 -0
- nucliadb/ingest/serialize.py +37 -167
- nucliadb/ingest/service/__init__.py +1 -3
- nucliadb/ingest/service/writer.py +185 -412
- nucliadb/ingest/settings.py +10 -20
- nucliadb/ingest/utils.py +3 -6
- nucliadb/learning_proxy.py +242 -55
- nucliadb/metrics_exporter.py +30 -19
- nucliadb/middleware/__init__.py +1 -3
- nucliadb/migrator/command.py +1 -3
- nucliadb/migrator/datamanager.py +13 -13
- nucliadb/migrator/migrator.py +47 -30
- nucliadb/migrator/utils.py +18 -10
- nucliadb/purge/__init__.py +139 -33
- nucliadb/purge/orphan_shards.py +7 -13
- nucliadb/reader/__init__.py +1 -3
- nucliadb/reader/api/models.py +1 -12
- nucliadb/reader/api/v1/__init__.py +0 -1
- nucliadb/reader/api/v1/download.py +21 -88
- nucliadb/reader/api/v1/export_import.py +1 -1
- nucliadb/reader/api/v1/knowledgebox.py +10 -10
- nucliadb/reader/api/v1/learning_config.py +2 -6
- nucliadb/reader/api/v1/resource.py +62 -88
- nucliadb/reader/api/v1/services.py +64 -83
- nucliadb/reader/app.py +12 -29
- nucliadb/reader/lifecycle.py +18 -4
- nucliadb/reader/py.typed +0 -0
- nucliadb/reader/reader/notifications.py +10 -28
- nucliadb/search/__init__.py +1 -3
- nucliadb/search/api/v1/__init__.py +1 -2
- nucliadb/search/api/v1/ask.py +17 -10
- nucliadb/search/api/v1/catalog.py +184 -0
- nucliadb/search/api/v1/feedback.py +16 -24
- nucliadb/search/api/v1/find.py +36 -36
- nucliadb/search/api/v1/knowledgebox.py +89 -60
- nucliadb/search/api/v1/resource/ask.py +2 -8
- nucliadb/search/api/v1/resource/search.py +49 -70
- nucliadb/search/api/v1/search.py +44 -210
- nucliadb/search/api/v1/suggest.py +39 -54
- nucliadb/search/app.py +12 -32
- nucliadb/search/lifecycle.py +10 -3
- nucliadb/search/predict.py +136 -187
- nucliadb/search/py.typed +0 -0
- nucliadb/search/requesters/utils.py +25 -58
- nucliadb/search/search/cache.py +149 -20
- nucliadb/search/search/chat/ask.py +571 -123
- nucliadb/search/{tests/unit/test_run.py → search/chat/exceptions.py} +14 -14
- nucliadb/search/search/chat/images.py +41 -17
- nucliadb/search/search/chat/prompt.py +817 -266
- nucliadb/search/search/chat/query.py +213 -309
- nucliadb/{tests/migrations/__init__.py → search/search/cut.py} +8 -8
- nucliadb/search/search/fetch.py +43 -36
- nucliadb/search/search/filters.py +9 -15
- nucliadb/search/search/find.py +214 -53
- nucliadb/search/search/find_merge.py +408 -391
- nucliadb/search/search/hydrator.py +191 -0
- nucliadb/search/search/merge.py +187 -223
- nucliadb/search/search/metrics.py +73 -2
- nucliadb/search/search/paragraphs.py +64 -106
- nucliadb/search/search/pgcatalog.py +233 -0
- nucliadb/search/search/predict_proxy.py +1 -1
- nucliadb/search/search/query.py +305 -150
- nucliadb/search/search/query_parser/exceptions.py +22 -0
- nucliadb/search/search/query_parser/models.py +101 -0
- nucliadb/search/search/query_parser/parser.py +183 -0
- nucliadb/search/search/rank_fusion.py +204 -0
- nucliadb/search/search/rerankers.py +270 -0
- nucliadb/search/search/shards.py +3 -32
- nucliadb/search/search/summarize.py +7 -18
- nucliadb/search/search/utils.py +27 -4
- nucliadb/search/settings.py +15 -1
- nucliadb/standalone/api_router.py +4 -10
- nucliadb/standalone/app.py +8 -14
- nucliadb/standalone/auth.py +7 -21
- nucliadb/standalone/config.py +7 -10
- nucliadb/standalone/lifecycle.py +26 -25
- nucliadb/standalone/migrations.py +1 -3
- nucliadb/standalone/purge.py +1 -1
- nucliadb/standalone/py.typed +0 -0
- nucliadb/standalone/run.py +3 -6
- nucliadb/standalone/settings.py +9 -16
- nucliadb/standalone/versions.py +15 -5
- nucliadb/tasks/consumer.py +8 -12
- nucliadb/tasks/producer.py +7 -6
- nucliadb/tests/config.py +53 -0
- nucliadb/train/__init__.py +1 -3
- nucliadb/train/api/utils.py +1 -2
- nucliadb/train/api/v1/shards.py +1 -1
- nucliadb/train/api/v1/trainset.py +2 -4
- nucliadb/train/app.py +10 -31
- nucliadb/train/generator.py +10 -19
- nucliadb/train/generators/field_classifier.py +7 -19
- nucliadb/train/generators/field_streaming.py +156 -0
- nucliadb/train/generators/image_classifier.py +12 -18
- nucliadb/train/generators/paragraph_classifier.py +5 -9
- nucliadb/train/generators/paragraph_streaming.py +6 -9
- nucliadb/train/generators/question_answer_streaming.py +19 -20
- nucliadb/train/generators/sentence_classifier.py +9 -15
- nucliadb/train/generators/token_classifier.py +48 -39
- nucliadb/train/generators/utils.py +14 -18
- nucliadb/train/lifecycle.py +7 -3
- nucliadb/train/nodes.py +23 -32
- nucliadb/train/py.typed +0 -0
- nucliadb/train/servicer.py +13 -21
- nucliadb/train/settings.py +2 -6
- nucliadb/train/types.py +13 -10
- nucliadb/train/upload.py +3 -6
- nucliadb/train/uploader.py +19 -23
- nucliadb/train/utils.py +1 -1
- nucliadb/writer/__init__.py +1 -3
- nucliadb/{ingest/fields/keywordset.py → writer/api/utils.py} +13 -10
- nucliadb/writer/api/v1/export_import.py +67 -14
- nucliadb/writer/api/v1/field.py +16 -269
- nucliadb/writer/api/v1/knowledgebox.py +218 -68
- nucliadb/writer/api/v1/resource.py +68 -88
- nucliadb/writer/api/v1/services.py +51 -70
- nucliadb/writer/api/v1/slug.py +61 -0
- nucliadb/writer/api/v1/transaction.py +67 -0
- nucliadb/writer/api/v1/upload.py +114 -113
- nucliadb/writer/app.py +6 -43
- nucliadb/writer/back_pressure.py +16 -38
- nucliadb/writer/exceptions.py +0 -4
- nucliadb/writer/lifecycle.py +21 -15
- nucliadb/writer/py.typed +0 -0
- nucliadb/writer/resource/audit.py +2 -1
- nucliadb/writer/resource/basic.py +48 -46
- nucliadb/writer/resource/field.py +25 -127
- nucliadb/writer/resource/origin.py +1 -2
- nucliadb/writer/settings.py +6 -2
- nucliadb/writer/tus/__init__.py +17 -15
- nucliadb/writer/tus/azure.py +111 -0
- nucliadb/writer/tus/dm.py +17 -5
- nucliadb/writer/tus/exceptions.py +1 -3
- nucliadb/writer/tus/gcs.py +49 -84
- nucliadb/writer/tus/local.py +21 -37
- nucliadb/writer/tus/s3.py +28 -68
- nucliadb/writer/tus/storage.py +5 -56
- nucliadb/writer/vectorsets.py +125 -0
- nucliadb-6.2.1.post2777.dist-info/METADATA +148 -0
- nucliadb-6.2.1.post2777.dist-info/RECORD +343 -0
- {nucliadb-4.0.0.post542.dist-info → nucliadb-6.2.1.post2777.dist-info}/WHEEL +1 -1
- nucliadb/common/maindb/redis.py +0 -194
- nucliadb/common/maindb/tikv.py +0 -433
- nucliadb/ingest/fields/layout.py +0 -58
- nucliadb/ingest/tests/conftest.py +0 -30
- nucliadb/ingest/tests/fixtures.py +0 -764
- nucliadb/ingest/tests/integration/consumer/__init__.py +0 -18
- nucliadb/ingest/tests/integration/consumer/test_auditing.py +0 -78
- nucliadb/ingest/tests/integration/consumer/test_materializer.py +0 -126
- nucliadb/ingest/tests/integration/consumer/test_pull.py +0 -144
- nucliadb/ingest/tests/integration/consumer/test_service.py +0 -81
- nucliadb/ingest/tests/integration/consumer/test_shard_creator.py +0 -68
- nucliadb/ingest/tests/integration/ingest/test_ingest.py +0 -684
- nucliadb/ingest/tests/integration/ingest/test_processing_engine.py +0 -95
- nucliadb/ingest/tests/integration/ingest/test_relations.py +0 -272
- nucliadb/ingest/tests/unit/consumer/__init__.py +0 -18
- nucliadb/ingest/tests/unit/consumer/test_auditing.py +0 -139
- nucliadb/ingest/tests/unit/consumer/test_consumer.py +0 -69
- nucliadb/ingest/tests/unit/consumer/test_pull.py +0 -60
- nucliadb/ingest/tests/unit/consumer/test_shard_creator.py +0 -140
- nucliadb/ingest/tests/unit/consumer/test_utils.py +0 -67
- nucliadb/ingest/tests/unit/orm/__init__.py +0 -19
- nucliadb/ingest/tests/unit/orm/test_brain.py +0 -247
- nucliadb/ingest/tests/unit/orm/test_brain_vectors.py +0 -74
- nucliadb/ingest/tests/unit/orm/test_processor.py +0 -131
- nucliadb/ingest/tests/unit/orm/test_resource.py +0 -331
- nucliadb/ingest/tests/unit/test_cache.py +0 -31
- nucliadb/ingest/tests/unit/test_partitions.py +0 -40
- nucliadb/ingest/tests/unit/test_processing.py +0 -171
- nucliadb/middleware/transaction.py +0 -117
- nucliadb/reader/api/v1/learning_collector.py +0 -63
- nucliadb/reader/tests/__init__.py +0 -19
- nucliadb/reader/tests/conftest.py +0 -31
- nucliadb/reader/tests/fixtures.py +0 -136
- nucliadb/reader/tests/test_list_resources.py +0 -75
- nucliadb/reader/tests/test_reader_file_download.py +0 -273
- nucliadb/reader/tests/test_reader_resource.py +0 -353
- nucliadb/reader/tests/test_reader_resource_field.py +0 -219
- nucliadb/search/api/v1/chat.py +0 -263
- nucliadb/search/api/v1/resource/chat.py +0 -174
- nucliadb/search/tests/__init__.py +0 -19
- nucliadb/search/tests/conftest.py +0 -33
- nucliadb/search/tests/fixtures.py +0 -199
- nucliadb/search/tests/node.py +0 -466
- nucliadb/search/tests/unit/__init__.py +0 -18
- nucliadb/search/tests/unit/api/__init__.py +0 -19
- nucliadb/search/tests/unit/api/v1/__init__.py +0 -19
- nucliadb/search/tests/unit/api/v1/resource/__init__.py +0 -19
- nucliadb/search/tests/unit/api/v1/resource/test_chat.py +0 -98
- nucliadb/search/tests/unit/api/v1/test_ask.py +0 -120
- nucliadb/search/tests/unit/api/v1/test_chat.py +0 -96
- nucliadb/search/tests/unit/api/v1/test_predict_proxy.py +0 -98
- nucliadb/search/tests/unit/api/v1/test_summarize.py +0 -99
- nucliadb/search/tests/unit/search/__init__.py +0 -18
- nucliadb/search/tests/unit/search/requesters/__init__.py +0 -18
- nucliadb/search/tests/unit/search/requesters/test_utils.py +0 -211
- nucliadb/search/tests/unit/search/search/__init__.py +0 -19
- nucliadb/search/tests/unit/search/search/test_shards.py +0 -45
- nucliadb/search/tests/unit/search/search/test_utils.py +0 -82
- nucliadb/search/tests/unit/search/test_chat_prompt.py +0 -270
- nucliadb/search/tests/unit/search/test_fetch.py +0 -108
- nucliadb/search/tests/unit/search/test_filters.py +0 -125
- nucliadb/search/tests/unit/search/test_paragraphs.py +0 -157
- nucliadb/search/tests/unit/search/test_predict_proxy.py +0 -106
- nucliadb/search/tests/unit/search/test_query.py +0 -153
- nucliadb/search/tests/unit/test_app.py +0 -79
- nucliadb/search/tests/unit/test_find_merge.py +0 -112
- nucliadb/search/tests/unit/test_merge.py +0 -34
- nucliadb/search/tests/unit/test_predict.py +0 -525
- nucliadb/standalone/tests/__init__.py +0 -19
- nucliadb/standalone/tests/conftest.py +0 -33
- nucliadb/standalone/tests/fixtures.py +0 -38
- nucliadb/standalone/tests/unit/__init__.py +0 -18
- nucliadb/standalone/tests/unit/test_api_router.py +0 -61
- nucliadb/standalone/tests/unit/test_auth.py +0 -169
- nucliadb/standalone/tests/unit/test_introspect.py +0 -35
- nucliadb/standalone/tests/unit/test_migrations.py +0 -63
- nucliadb/standalone/tests/unit/test_versions.py +0 -68
- nucliadb/tests/benchmarks/__init__.py +0 -19
- nucliadb/tests/benchmarks/test_search.py +0 -99
- nucliadb/tests/conftest.py +0 -32
- nucliadb/tests/fixtures.py +0 -735
- nucliadb/tests/knowledgeboxes/philosophy_books.py +0 -202
- nucliadb/tests/knowledgeboxes/ten_dummy_resources.py +0 -107
- nucliadb/tests/migrations/test_migration_0017.py +0 -76
- nucliadb/tests/migrations/test_migration_0018.py +0 -95
- nucliadb/tests/tikv.py +0 -240
- nucliadb/tests/unit/__init__.py +0 -19
- nucliadb/tests/unit/common/__init__.py +0 -19
- nucliadb/tests/unit/common/cluster/__init__.py +0 -19
- nucliadb/tests/unit/common/cluster/discovery/__init__.py +0 -19
- nucliadb/tests/unit/common/cluster/discovery/test_k8s.py +0 -172
- nucliadb/tests/unit/common/cluster/standalone/__init__.py +0 -18
- nucliadb/tests/unit/common/cluster/standalone/test_service.py +0 -114
- nucliadb/tests/unit/common/cluster/standalone/test_utils.py +0 -61
- nucliadb/tests/unit/common/cluster/test_cluster.py +0 -408
- nucliadb/tests/unit/common/cluster/test_kb_shard_manager.py +0 -173
- nucliadb/tests/unit/common/cluster/test_rebalance.py +0 -38
- nucliadb/tests/unit/common/cluster/test_rollover.py +0 -282
- nucliadb/tests/unit/common/maindb/__init__.py +0 -18
- nucliadb/tests/unit/common/maindb/test_driver.py +0 -127
- nucliadb/tests/unit/common/maindb/test_tikv.py +0 -53
- nucliadb/tests/unit/common/maindb/test_utils.py +0 -92
- nucliadb/tests/unit/common/test_context.py +0 -36
- nucliadb/tests/unit/export_import/__init__.py +0 -19
- nucliadb/tests/unit/export_import/test_datamanager.py +0 -37
- nucliadb/tests/unit/export_import/test_utils.py +0 -301
- nucliadb/tests/unit/migrator/__init__.py +0 -19
- nucliadb/tests/unit/migrator/test_migrator.py +0 -87
- nucliadb/tests/unit/tasks/__init__.py +0 -19
- nucliadb/tests/unit/tasks/conftest.py +0 -42
- nucliadb/tests/unit/tasks/test_consumer.py +0 -92
- nucliadb/tests/unit/tasks/test_producer.py +0 -95
- nucliadb/tests/unit/tasks/test_tasks.py +0 -58
- nucliadb/tests/unit/test_field_ids.py +0 -49
- nucliadb/tests/unit/test_health.py +0 -86
- nucliadb/tests/unit/test_kb_slugs.py +0 -54
- nucliadb/tests/unit/test_learning_proxy.py +0 -252
- nucliadb/tests/unit/test_metrics_exporter.py +0 -77
- nucliadb/tests/unit/test_purge.py +0 -136
- nucliadb/tests/utils/__init__.py +0 -74
- nucliadb/tests/utils/aiohttp_session.py +0 -44
- nucliadb/tests/utils/broker_messages/__init__.py +0 -171
- nucliadb/tests/utils/broker_messages/fields.py +0 -197
- nucliadb/tests/utils/broker_messages/helpers.py +0 -33
- nucliadb/tests/utils/entities.py +0 -78
- nucliadb/train/api/v1/check.py +0 -60
- nucliadb/train/tests/__init__.py +0 -19
- nucliadb/train/tests/conftest.py +0 -29
- nucliadb/train/tests/fixtures.py +0 -342
- nucliadb/train/tests/test_field_classification.py +0 -122
- nucliadb/train/tests/test_get_entities.py +0 -80
- nucliadb/train/tests/test_get_info.py +0 -51
- nucliadb/train/tests/test_get_ontology.py +0 -34
- nucliadb/train/tests/test_get_ontology_count.py +0 -63
- nucliadb/train/tests/test_image_classification.py +0 -221
- nucliadb/train/tests/test_list_fields.py +0 -39
- nucliadb/train/tests/test_list_paragraphs.py +0 -73
- nucliadb/train/tests/test_list_resources.py +0 -39
- nucliadb/train/tests/test_list_sentences.py +0 -71
- nucliadb/train/tests/test_paragraph_classification.py +0 -123
- nucliadb/train/tests/test_paragraph_streaming.py +0 -118
- nucliadb/train/tests/test_question_answer_streaming.py +0 -239
- nucliadb/train/tests/test_sentence_classification.py +0 -143
- nucliadb/train/tests/test_token_classification.py +0 -136
- nucliadb/train/tests/utils.py +0 -101
- nucliadb/writer/layouts/__init__.py +0 -51
- nucliadb/writer/layouts/v1.py +0 -59
- nucliadb/writer/tests/__init__.py +0 -19
- nucliadb/writer/tests/conftest.py +0 -31
- nucliadb/writer/tests/fixtures.py +0 -191
- nucliadb/writer/tests/test_fields.py +0 -475
- nucliadb/writer/tests/test_files.py +0 -740
- nucliadb/writer/tests/test_knowledgebox.py +0 -49
- nucliadb/writer/tests/test_reprocess_file_field.py +0 -133
- nucliadb/writer/tests/test_resources.py +0 -476
- nucliadb/writer/tests/test_service.py +0 -137
- nucliadb/writer/tests/test_tus.py +0 -203
- nucliadb/writer/tests/utils.py +0 -35
- nucliadb/writer/tus/pg.py +0 -125
- nucliadb-4.0.0.post542.dist-info/METADATA +0 -135
- nucliadb-4.0.0.post542.dist-info/RECORD +0 -462
- {nucliadb/ingest/tests → migrations/pg}/__init__.py +0 -0
- /nucliadb/{ingest/tests/integration → common/external_index_providers}/__init__.py +0 -0
- /nucliadb/{ingest/tests/integration/ingest → common/models_utils}/__init__.py +0 -0
- /nucliadb/{ingest/tests/unit → search/search/query_parser}/__init__.py +0 -0
- /nucliadb/{ingest/tests → tests}/vectors.py +0 -0
- {nucliadb-4.0.0.post542.dist-info → nucliadb-6.2.1.post2777.dist-info}/entry_points.txt +0 -0
- {nucliadb-4.0.0.post542.dist-info → nucliadb-6.2.1.post2777.dist-info}/top_level.txt +0 -0
- {nucliadb-4.0.0.post542.dist-info → nucliadb-6.2.1.post2777.dist-info}/zip-safe +0 -0
@@ -1,202 +0,0 @@
|
|
1
|
-
# Copyright (C) 2021 Bosutech XXI S.L.
|
2
|
-
#
|
3
|
-
# nucliadb is offered under the AGPL v3.0 and as commercial software.
|
4
|
-
# For commercial licensing, contact us at info@nuclia.com.
|
5
|
-
#
|
6
|
-
# AGPL:
|
7
|
-
# This program is free software: you can redistribute it and/or modify
|
8
|
-
# it under the terms of the GNU Affero General Public License as
|
9
|
-
# published by the Free Software Foundation, either version 3 of the
|
10
|
-
# License, or (at your option) any later version.
|
11
|
-
#
|
12
|
-
# This program is distributed in the hope that it will be useful,
|
13
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
-
# GNU Affero General Public License for more details.
|
16
|
-
#
|
17
|
-
# You should have received a copy of the GNU Affero General Public License
|
18
|
-
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
19
|
-
#
|
20
|
-
|
21
|
-
import pytest
|
22
|
-
from httpx import AsyncClient
|
23
|
-
|
24
|
-
|
25
|
-
@pytest.fixture(scope="function")
|
26
|
-
async def philosophy_books_kb(
|
27
|
-
nucliadb_manager: AsyncClient,
|
28
|
-
nucliadb_writer: AsyncClient,
|
29
|
-
):
|
30
|
-
payloads = [
|
31
|
-
{
|
32
|
-
"slug": "meditations",
|
33
|
-
"title": "Meditations",
|
34
|
-
"summary": (
|
35
|
-
"Series of personal writings by Marcus Aurelius recording his private notes to "
|
36
|
-
"himself and ideas on Stoic philosophy"
|
37
|
-
),
|
38
|
-
"usermetadata": {
|
39
|
-
"relations": [
|
40
|
-
{
|
41
|
-
"relation": "ENTITY",
|
42
|
-
"to": {
|
43
|
-
"type": "entity",
|
44
|
-
"value": "Marcus Aurelius",
|
45
|
-
"group": "PERSON",
|
46
|
-
},
|
47
|
-
}
|
48
|
-
]
|
49
|
-
},
|
50
|
-
},
|
51
|
-
{
|
52
|
-
"slug": "nicomachean-ethics",
|
53
|
-
"title": "Nicomachean Ethics",
|
54
|
-
"summary": (
|
55
|
-
"Aristotle's best-known work on ethics, the science of human life"
|
56
|
-
),
|
57
|
-
"usermetadata": {
|
58
|
-
"relations": [
|
59
|
-
{
|
60
|
-
"relation": "ENTITY",
|
61
|
-
"to": {
|
62
|
-
"type": "entity",
|
63
|
-
"value": "Aristotle",
|
64
|
-
"group": "PERSON",
|
65
|
-
},
|
66
|
-
}
|
67
|
-
]
|
68
|
-
},
|
69
|
-
},
|
70
|
-
{
|
71
|
-
"slug": "beyond-good-and-evil",
|
72
|
-
"title": "Beyond Good and Evil: Prelude to a philosophy of the Future",
|
73
|
-
"summary": (
|
74
|
-
"Nietzsche acuse past philosophers of lacking critical sense and blindly accepting "
|
75
|
-
"dogmatic premises in their consideration of morality"
|
76
|
-
),
|
77
|
-
"usermetadata": {
|
78
|
-
"relations": [
|
79
|
-
{
|
80
|
-
"relation": "ENTITY",
|
81
|
-
"to": {
|
82
|
-
"type": "entity",
|
83
|
-
"value": "Friedrich Nietzsche",
|
84
|
-
"group": "PERSON",
|
85
|
-
},
|
86
|
-
}
|
87
|
-
]
|
88
|
-
},
|
89
|
-
},
|
90
|
-
{
|
91
|
-
"slug": "meditations-on-first-philosophy",
|
92
|
-
"title": "Meditations on First Philosophy",
|
93
|
-
"summary": (
|
94
|
-
"Six meditations in which Descartes first discards all belief in things that are "
|
95
|
-
"not absolutely certain, and then tries to establish what can be known for sure"
|
96
|
-
),
|
97
|
-
"usermetadata": {
|
98
|
-
"relations": [
|
99
|
-
{
|
100
|
-
"relation": "ENTITY",
|
101
|
-
"to": {
|
102
|
-
"type": "entity",
|
103
|
-
"value": "René Descartes",
|
104
|
-
"group": "PERSON",
|
105
|
-
},
|
106
|
-
}
|
107
|
-
]
|
108
|
-
},
|
109
|
-
},
|
110
|
-
{
|
111
|
-
"slug": "the-principles-of-the-most-ancient-and-modern-philosophy",
|
112
|
-
"title": "The Principles of the most Ancient and Modern Philosophy",
|
113
|
-
"summary": (
|
114
|
-
"Conway's monistic view of the world as created from one substance"
|
115
|
-
),
|
116
|
-
"usermetadata": {
|
117
|
-
"relations": [
|
118
|
-
{
|
119
|
-
"relation": "ENTITY",
|
120
|
-
"to": {
|
121
|
-
"type": "entity",
|
122
|
-
"value": "Anne Conway",
|
123
|
-
"group": "PERSON",
|
124
|
-
},
|
125
|
-
}
|
126
|
-
]
|
127
|
-
},
|
128
|
-
},
|
129
|
-
{
|
130
|
-
"slug": "ethics",
|
131
|
-
"title": "Ethics",
|
132
|
-
"summary": (
|
133
|
-
"Spinoza puts forward a small number of definitions and axioms from which he "
|
134
|
-
"attempts to derive hundreds of propositions and corollaries"
|
135
|
-
),
|
136
|
-
"usermetadata": {
|
137
|
-
"relations": [
|
138
|
-
{
|
139
|
-
"relation": "ENTITY",
|
140
|
-
"to": {
|
141
|
-
"type": "entity",
|
142
|
-
"value": "Baruch Spinoza",
|
143
|
-
"group": "PERSON",
|
144
|
-
},
|
145
|
-
}
|
146
|
-
]
|
147
|
-
},
|
148
|
-
},
|
149
|
-
{
|
150
|
-
"slug": "critique-of-pure-reason",
|
151
|
-
"title": "Critique of Pure Reason",
|
152
|
-
"summary": ("Kant seeks to determine the limits and scope of metaphysics"),
|
153
|
-
"usermetadata": {
|
154
|
-
"relations": [
|
155
|
-
{
|
156
|
-
"relation": "ENTITY",
|
157
|
-
"to": {
|
158
|
-
"type": "entity",
|
159
|
-
"value": "Immanuel Kant",
|
160
|
-
"group": "PERSON",
|
161
|
-
},
|
162
|
-
}
|
163
|
-
]
|
164
|
-
},
|
165
|
-
},
|
166
|
-
{
|
167
|
-
"slug": "the-human-condition",
|
168
|
-
"title": "The Human Condition",
|
169
|
-
"summary": (
|
170
|
-
"Arendt differentiates political and social concepts, labor and work, and various "
|
171
|
-
"forms of actions; she then explores the implications of those distinctions"
|
172
|
-
),
|
173
|
-
"usermetadata": {
|
174
|
-
"relations": [
|
175
|
-
{
|
176
|
-
"relation": "ENTITY",
|
177
|
-
"to": {
|
178
|
-
"type": "entity",
|
179
|
-
"value": "Hannah Arendt",
|
180
|
-
"group": "PERSON",
|
181
|
-
},
|
182
|
-
}
|
183
|
-
]
|
184
|
-
},
|
185
|
-
},
|
186
|
-
]
|
187
|
-
|
188
|
-
resp = await nucliadb_manager.post("/kbs", json={"slug": "philosophy-books"})
|
189
|
-
assert resp.status_code == 201
|
190
|
-
kbid = resp.json().get("uuid")
|
191
|
-
|
192
|
-
for payload in payloads:
|
193
|
-
resp = await nucliadb_writer.post(
|
194
|
-
f"/kb/{kbid}/resources",
|
195
|
-
json=payload,
|
196
|
-
)
|
197
|
-
assert resp.status_code == 201
|
198
|
-
|
199
|
-
yield kbid
|
200
|
-
|
201
|
-
resp = await nucliadb_manager.delete(f"/kb/{kbid}")
|
202
|
-
assert resp.status_code == 200
|
@@ -1,107 +0,0 @@
|
|
1
|
-
# Copyright (C) 2021 Bosutech XXI S.L.
|
2
|
-
#
|
3
|
-
# nucliadb is offered under the AGPL v3.0 and as commercial software.
|
4
|
-
# For commercial licensing, contact us at info@nuclia.com.
|
5
|
-
#
|
6
|
-
# AGPL:
|
7
|
-
# This program is free software: you can redistribute it and/or modify
|
8
|
-
# it under the terms of the GNU Affero General Public License as
|
9
|
-
# published by the Free Software Foundation, either version 3 of the
|
10
|
-
# License, or (at your option) any later version.
|
11
|
-
#
|
12
|
-
# This program is distributed in the hope that it will be useful,
|
13
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
-
# GNU Affero General Public License for more details.
|
16
|
-
#
|
17
|
-
# You should have received a copy of the GNU Affero General Public License
|
18
|
-
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
19
|
-
#
|
20
|
-
import asyncio
|
21
|
-
|
22
|
-
import pytest
|
23
|
-
from httpx import AsyncClient
|
24
|
-
|
25
|
-
|
26
|
-
@pytest.fixture(scope="function")
|
27
|
-
async def ten_dummy_resources_kb(
|
28
|
-
nucliadb_manager: AsyncClient,
|
29
|
-
nucliadb_reader: AsyncClient,
|
30
|
-
nucliadb_writer: AsyncClient,
|
31
|
-
):
|
32
|
-
N_RESOURCES = 10
|
33
|
-
|
34
|
-
payloads = [
|
35
|
-
{
|
36
|
-
"slug": f"dummy-resource-{i}",
|
37
|
-
"title": f"Dummy resource {i}",
|
38
|
-
"summary": f"Dummy resource {i} summary",
|
39
|
-
}
|
40
|
-
for i in range(N_RESOURCES)
|
41
|
-
]
|
42
|
-
|
43
|
-
resp = await nucliadb_manager.post("/kbs", json={"slug": "ten-dummy-resources"})
|
44
|
-
assert resp.status_code == 201
|
45
|
-
kbid = resp.json().get("uuid")
|
46
|
-
|
47
|
-
for payload in payloads:
|
48
|
-
resp = await nucliadb_writer.post(
|
49
|
-
f"/kb/{kbid}/resources",
|
50
|
-
json=payload,
|
51
|
-
)
|
52
|
-
assert resp.status_code == 201
|
53
|
-
|
54
|
-
await asyncio.sleep(1)
|
55
|
-
|
56
|
-
resp = await nucliadb_reader.get(
|
57
|
-
f"/kb/{kbid}/resources",
|
58
|
-
)
|
59
|
-
assert resp.status_code == 200
|
60
|
-
body = resp.json()
|
61
|
-
assert len(body["resources"]) == N_RESOURCES
|
62
|
-
|
63
|
-
yield kbid
|
64
|
-
|
65
|
-
resp = await nucliadb_manager.delete(f"/kb/{kbid}")
|
66
|
-
assert resp.status_code == 200
|
67
|
-
|
68
|
-
|
69
|
-
@pytest.fixture(scope="function")
|
70
|
-
async def ten_quick_dummy_resources_kb(
|
71
|
-
nucliadb_manager: AsyncClient,
|
72
|
-
nucliadb_reader: AsyncClient,
|
73
|
-
nucliadb_writer: AsyncClient,
|
74
|
-
):
|
75
|
-
N_RESOURCES = 10
|
76
|
-
|
77
|
-
payloads = [
|
78
|
-
{
|
79
|
-
"slug": f"dummy-resource-{i}",
|
80
|
-
"title": f"Dummy resource {i}",
|
81
|
-
"summary": f"Dummy resource {i} summary",
|
82
|
-
}
|
83
|
-
for i in range(N_RESOURCES)
|
84
|
-
]
|
85
|
-
|
86
|
-
resp = await nucliadb_manager.post("/kbs", json={"slug": "ten-dummy-resources"})
|
87
|
-
assert resp.status_code == 201
|
88
|
-
kbid = resp.json().get("uuid")
|
89
|
-
|
90
|
-
for payload in payloads:
|
91
|
-
resp = await nucliadb_writer.post(
|
92
|
-
f"/kb/{kbid}/resources",
|
93
|
-
json=payload,
|
94
|
-
)
|
95
|
-
assert resp.status_code == 201
|
96
|
-
|
97
|
-
resp = await nucliadb_reader.get(
|
98
|
-
f"/kb/{kbid}/resources",
|
99
|
-
)
|
100
|
-
assert resp.status_code == 200
|
101
|
-
body = resp.json()
|
102
|
-
assert len(body["resources"]) == N_RESOURCES
|
103
|
-
|
104
|
-
yield kbid
|
105
|
-
|
106
|
-
resp = await nucliadb_manager.delete(f"/kb/{kbid}")
|
107
|
-
assert resp.status_code == 200
|
@@ -1,76 +0,0 @@
|
|
1
|
-
# Copyright (C) 2021 Bosutech XXI S.L.
|
2
|
-
#
|
3
|
-
# nucliadb is offered under the AGPL v3.0 and as commercial software.
|
4
|
-
# For commercial licensing, contact us at info@nuclia.com.
|
5
|
-
#
|
6
|
-
# AGPL:
|
7
|
-
# This program is free software: you can redistribute it and/or modify
|
8
|
-
# it under the terms of the GNU Affero General Public License as
|
9
|
-
# published by the Free Software Foundation, either version 3 of the
|
10
|
-
# License, or (at your option) any later version.
|
11
|
-
#
|
12
|
-
# This program is distributed in the hope that it will be useful,
|
13
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
-
# GNU Affero General Public License for more details.
|
16
|
-
#
|
17
|
-
# You should have received a copy of the GNU Affero General Public License
|
18
|
-
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
19
|
-
#
|
20
|
-
from unittest.mock import Mock
|
21
|
-
|
22
|
-
import pytest
|
23
|
-
|
24
|
-
from nucliadb.common import datamanagers
|
25
|
-
from nucliadb.common.maindb.driver import Driver
|
26
|
-
from nucliadb.migrator.models import Migration
|
27
|
-
from nucliadb.tests.migrations import get_migration
|
28
|
-
from nucliadb_protos import writer_pb2
|
29
|
-
|
30
|
-
migration: Migration = get_migration(17)
|
31
|
-
|
32
|
-
|
33
|
-
@pytest.mark.asyncio
|
34
|
-
async def test_migration_0017_kb(maindb_driver: Driver):
|
35
|
-
execution_context = Mock()
|
36
|
-
execution_context.kv_driver = maindb_driver
|
37
|
-
|
38
|
-
# setup a KB with the old format
|
39
|
-
kbid = "my-kbid"
|
40
|
-
async with maindb_driver.transaction() as txn:
|
41
|
-
shards = writer_pb2.Shards(
|
42
|
-
kbid=kbid,
|
43
|
-
shards=[
|
44
|
-
writer_pb2.ShardObject(
|
45
|
-
shard="shard-0",
|
46
|
-
replicas=[
|
47
|
-
writer_pb2.ShardReplica(),
|
48
|
-
writer_pb2.ShardReplica(),
|
49
|
-
],
|
50
|
-
),
|
51
|
-
writer_pb2.ShardObject(
|
52
|
-
shard="shard-1",
|
53
|
-
replicas=[
|
54
|
-
writer_pb2.ShardReplica(),
|
55
|
-
writer_pb2.ShardReplica(),
|
56
|
-
],
|
57
|
-
),
|
58
|
-
],
|
59
|
-
# this field is an index to shards list indicating which is the
|
60
|
-
# writable shard
|
61
|
-
actual=1,
|
62
|
-
)
|
63
|
-
await datamanagers.cluster.update_kb_shards(txn, kbid=kbid, shards=shards)
|
64
|
-
await txn.commit()
|
65
|
-
|
66
|
-
await migration.module.migrate_kb(execution_context, kbid)
|
67
|
-
|
68
|
-
async with maindb_driver.transaction(read_only=True) as txn:
|
69
|
-
migrated = await datamanagers.cluster.get_kb_shards(txn, kbid=kbid)
|
70
|
-
assert migrated is not None
|
71
|
-
|
72
|
-
# actual is the same
|
73
|
-
assert shards.actual == 1
|
74
|
-
|
75
|
-
# Writable shard now is pointed by `ShardObject.read_only` field
|
76
|
-
assert [True, False] == [shard.read_only for shard in migrated.shards]
|
@@ -1,95 +0,0 @@
|
|
1
|
-
# Copyright (C) 2021 Bosutech XXI S.L.
|
2
|
-
#
|
3
|
-
# nucliadb is offered under the AGPL v3.0 and as commercial software.
|
4
|
-
# For commercial licensing, contact us at info@nuclia.com.
|
5
|
-
#
|
6
|
-
# AGPL:
|
7
|
-
# This program is free software: you can redistribute it and/or modify
|
8
|
-
# it under the terms of the GNU Affero General Public License as
|
9
|
-
# published by the Free Software Foundation, either version 3 of the
|
10
|
-
# License, or (at your option) any later version.
|
11
|
-
#
|
12
|
-
# This program is distributed in the hope that it will be useful,
|
13
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
-
# GNU Affero General Public License for more details.
|
16
|
-
#
|
17
|
-
# You should have received a copy of the GNU Affero General Public License
|
18
|
-
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
19
|
-
#
|
20
|
-
from unittest.mock import AsyncMock, Mock, patch
|
21
|
-
|
22
|
-
import pytest
|
23
|
-
|
24
|
-
from nucliadb.common import datamanagers
|
25
|
-
from nucliadb.common.datamanagers.kb import KB_SLUGS
|
26
|
-
from nucliadb.common.maindb.driver import Driver
|
27
|
-
from nucliadb.ingest.orm.knowledgebox import KnowledgeBox
|
28
|
-
from nucliadb.migrator.models import Migration
|
29
|
-
from nucliadb.tests.migrations import get_migration
|
30
|
-
from nucliadb_protos import knowledgebox_pb2
|
31
|
-
|
32
|
-
migration: Migration = get_migration(18)
|
33
|
-
|
34
|
-
|
35
|
-
@pytest.mark.asyncio
|
36
|
-
async def test_migration_0018_global(maindb_driver: Driver):
|
37
|
-
execution_context = Mock()
|
38
|
-
execution_context.kv_driver = maindb_driver
|
39
|
-
|
40
|
-
with (
|
41
|
-
patch("nucliadb.ingest.orm.knowledgebox.get_storage", new=AsyncMock()),
|
42
|
-
patch(
|
43
|
-
"nucliadb.ingest.orm.knowledgebox.get_shard_manager",
|
44
|
-
new=Mock(return_value=AsyncMock()),
|
45
|
-
),
|
46
|
-
):
|
47
|
-
# setup some orphan /kbslugs keys and some real ones
|
48
|
-
async with maindb_driver.transaction() as txn:
|
49
|
-
fake_kb_slug = "fake-kb-slug"
|
50
|
-
fake_kb_id = "fake-kb-id"
|
51
|
-
key = KB_SLUGS.format(slug=fake_kb_slug)
|
52
|
-
await txn.set(key, fake_kb_id.encode())
|
53
|
-
assert not await datamanagers.kb.exists_kb(txn, kbid=fake_kb_id)
|
54
|
-
|
55
|
-
real_kb_slug = "real-kb-slug"
|
56
|
-
real_kb_id, failed = await KnowledgeBox.create(
|
57
|
-
txn,
|
58
|
-
slug=real_kb_slug,
|
59
|
-
semantic_model=knowledgebox_pb2.SemanticModelMetadata(),
|
60
|
-
)
|
61
|
-
assert not failed
|
62
|
-
assert await datamanagers.kb.exists_kb(txn, kbid=real_kb_id)
|
63
|
-
|
64
|
-
await txn.commit()
|
65
|
-
|
66
|
-
# tikv needs to open a second transaction to be able to read values from
|
67
|
-
# the first one using `scan_keys`
|
68
|
-
async with maindb_driver.transaction(read_only=True) as txn:
|
69
|
-
kb_slugs = [
|
70
|
-
kb_slug
|
71
|
-
async for kbid, kb_slug in datamanagers.kb.get_kbs(txn, prefix="")
|
72
|
-
]
|
73
|
-
assert len(kb_slugs) == 2
|
74
|
-
assert fake_kb_slug in kb_slugs
|
75
|
-
assert real_kb_slug in kb_slugs
|
76
|
-
|
77
|
-
# execute migration, removing orphan kbslug keys
|
78
|
-
await migration.module.migrate(execution_context)
|
79
|
-
|
80
|
-
async with maindb_driver.transaction(read_only=True) as txn:
|
81
|
-
assert not await datamanagers.kb.exists_kb(txn, kbid=fake_kb_id)
|
82
|
-
assert await datamanagers.kb.exists_kb(txn, kbid=real_kb_id)
|
83
|
-
|
84
|
-
value = await txn.get(KB_SLUGS.format(slug=fake_kb_slug))
|
85
|
-
assert value is None
|
86
|
-
|
87
|
-
value = await txn.get(KB_SLUGS.format(slug=real_kb_slug))
|
88
|
-
assert value is not None
|
89
|
-
assert value.decode() == real_kb_id
|
90
|
-
|
91
|
-
kb_slugs = [
|
92
|
-
kb_slug async for kbid, kb_slug in datamanagers.kb.get_kbs(txn, prefix="")
|
93
|
-
]
|
94
|
-
assert len(kb_slugs) == 1
|
95
|
-
assert real_kb_slug in kb_slugs
|