weaviate-cli 3.1.2__tar.gz → 3.1.4__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.
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/PKG-INFO +1 -1
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/weaviate_cli/commands/create.py +33 -2
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/weaviate_cli/commands/delete.py +8 -2
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/weaviate_cli/commands/update.py +1 -1
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/weaviate_cli/defaults.py +8 -4
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/weaviate_cli/managers/collection_manager.py +1 -1
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/weaviate_cli/managers/data_manager.py +67 -24
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/weaviate_cli/managers/tenant_manager.py +83 -34
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/weaviate_cli.egg-info/PKG-INFO +1 -1
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/.github/dependabot.yml +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/.github/workflows/main.yaml +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/.github/workflows/release.yaml +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/.gitignore +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/.pre-commit-config.yaml +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/CONTRIBUTING.md +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/Dockerfile +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/LICENSE +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/MANIFEST.in +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/Makefile +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/README.md +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/cli.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/publish.md +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/pyproject.toml +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/requirements-dev.txt +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/setup.cfg +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/setup.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/test/README.md +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/test/__init__.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/test/integration/test_integration.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/test/unittests/conftest.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/test/unittests/test_cli.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/test/unittests/test_defaults.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/test/unittests/test_managers/test_collection_manager.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/test/unittests/test_managers/test_config_manager.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/test/unittests/test_managers/test_data_manager.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/test/unittests/test_managers/test_node_manager.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/test/unittests/test_managers/test_shard_manager.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/test/unittests/test_utils.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/weaviate_cli/__init__.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/weaviate_cli/commands/__init__.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/weaviate_cli/commands/assign.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/weaviate_cli/commands/cancel.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/weaviate_cli/commands/get.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/weaviate_cli/commands/query.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/weaviate_cli/commands/restore.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/weaviate_cli/commands/revoke.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/weaviate_cli/completion/__init__.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/weaviate_cli/completion/complete.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/weaviate_cli/datasets/__init__.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/weaviate_cli/datasets/movies.json +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/weaviate_cli/managers/__init__.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/weaviate_cli/managers/backup_manager.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/weaviate_cli/managers/config_manager.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/weaviate_cli/managers/node_manager.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/weaviate_cli/managers/role_manager.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/weaviate_cli/managers/shard_manager.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/weaviate_cli/managers/user_manager.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/weaviate_cli/types/models.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/weaviate_cli/utils.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/weaviate_cli.egg-info/SOURCES.txt +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/weaviate_cli.egg-info/dependency_links.txt +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/weaviate_cli.egg-info/entry_points.txt +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/weaviate_cli.egg-info/not-zip-safe +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/weaviate_cli.egg-info/requires.txt +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/weaviate_cli.egg-info/top_level.txt +0 -0
|
@@ -183,20 +183,28 @@ def create_collection_cli(
|
|
|
183
183
|
@click.option(
|
|
184
184
|
"--tenant_suffix",
|
|
185
185
|
default=CreateTenantsDefaults.tenant_suffix,
|
|
186
|
-
help="The suffix to add to the tenant name (default: 'Tenant
|
|
186
|
+
help="The suffix to add to the tenant name (default: 'Tenant-').",
|
|
187
187
|
)
|
|
188
188
|
@click.option(
|
|
189
189
|
"--number_tenants",
|
|
190
190
|
default=CreateTenantsDefaults.number_tenants,
|
|
191
191
|
help="Number of tenants to create (default: 100).",
|
|
192
192
|
)
|
|
193
|
+
@click.option(
|
|
194
|
+
"--tenant_batch_size",
|
|
195
|
+
default=CreateTenantsDefaults.tenant_batch_size,
|
|
196
|
+
type=int,
|
|
197
|
+
help="Number of tenants to create in each batch (default: None, all tenants will be created in one batch).",
|
|
198
|
+
)
|
|
193
199
|
@click.option(
|
|
194
200
|
"--state",
|
|
195
201
|
default=CreateTenantsDefaults.state,
|
|
196
202
|
type=click.Choice(["hot", "active", "cold", "inactive", "frozen", "offloaded"]),
|
|
197
203
|
)
|
|
198
204
|
@click.pass_context
|
|
199
|
-
def create_tenants_cli(
|
|
205
|
+
def create_tenants_cli(
|
|
206
|
+
ctx, collection, tenant_suffix, number_tenants, tenant_batch_size, state
|
|
207
|
+
):
|
|
200
208
|
"""Create tenants in Weaviate."""
|
|
201
209
|
|
|
202
210
|
client = None
|
|
@@ -208,6 +216,7 @@ def create_tenants_cli(ctx, collection, tenant_suffix, number_tenants, state):
|
|
|
208
216
|
collection=collection,
|
|
209
217
|
tenant_suffix=tenant_suffix,
|
|
210
218
|
number_tenants=number_tenants,
|
|
219
|
+
tenant_batch_size=tenant_batch_size,
|
|
211
220
|
state=state,
|
|
212
221
|
)
|
|
213
222
|
except Exception as e:
|
|
@@ -301,6 +310,16 @@ def create_backup_cli(ctx, backend, backup_id, include, exclude, wait, cpu_for_b
|
|
|
301
310
|
default=CreateDataDefaults.auto_tenants,
|
|
302
311
|
help="Number of tenants for which we will send data. NOTE: Requires class with --auto_tenant_creation (default: 0).",
|
|
303
312
|
)
|
|
313
|
+
@click.option(
|
|
314
|
+
"--tenants",
|
|
315
|
+
default=None,
|
|
316
|
+
help="Comma separated list of tenants to send data to.",
|
|
317
|
+
)
|
|
318
|
+
@click.option(
|
|
319
|
+
"--tenant_suffix",
|
|
320
|
+
default=CreateTenantsDefaults.tenant_suffix,
|
|
321
|
+
help="The suffix to add to the tenant name (default: 'Tenant-'). Only used if --auto_tenants is provided.",
|
|
322
|
+
)
|
|
304
323
|
@click.option(
|
|
305
324
|
"--vector_dimensions",
|
|
306
325
|
default=CreateDataDefaults.vector_dimensions,
|
|
@@ -311,6 +330,12 @@ def create_backup_cli(ctx, backend, backup_id, include, exclude, wait, cpu_for_b
|
|
|
311
330
|
default=None,
|
|
312
331
|
help="UUID of the object to be used when the data is randomized. It requires --limit=1 and --randomize to be enabled.",
|
|
313
332
|
)
|
|
333
|
+
@click.option(
|
|
334
|
+
"--wait_for_indexing",
|
|
335
|
+
is_flag=True,
|
|
336
|
+
default=CreateDataDefaults.wait_for_indexing,
|
|
337
|
+
help="Wait for the indexing to complete before returning.",
|
|
338
|
+
)
|
|
314
339
|
@click.pass_context
|
|
315
340
|
def create_data_cli(
|
|
316
341
|
ctx,
|
|
@@ -319,8 +344,11 @@ def create_data_cli(
|
|
|
319
344
|
consistency_level,
|
|
320
345
|
randomize,
|
|
321
346
|
auto_tenants,
|
|
347
|
+
tenants,
|
|
348
|
+
tenant_suffix,
|
|
322
349
|
vector_dimensions,
|
|
323
350
|
uuid,
|
|
351
|
+
wait_for_indexing,
|
|
324
352
|
):
|
|
325
353
|
"""Ingest data into a collection in Weaviate."""
|
|
326
354
|
|
|
@@ -349,8 +377,11 @@ def create_data_cli(
|
|
|
349
377
|
consistency_level=consistency_level,
|
|
350
378
|
randomize=randomize,
|
|
351
379
|
auto_tenants=auto_tenants,
|
|
380
|
+
tenants_list=tenants.split(",") if tenants else None,
|
|
352
381
|
vector_dimensions=vector_dimensions,
|
|
353
382
|
uuid=uuid,
|
|
383
|
+
tenant_suffix=tenant_suffix,
|
|
384
|
+
wait_for_indexing=wait_for_indexing,
|
|
354
385
|
)
|
|
355
386
|
except Exception as e:
|
|
356
387
|
click.echo(f"Error: {e}")
|
|
@@ -60,7 +60,7 @@ def delete_collection_cli(ctx: click.Context, collection: str, all: bool) -> Non
|
|
|
60
60
|
@click.option(
|
|
61
61
|
"--tenant_suffix",
|
|
62
62
|
default=DeleteTenantsDefaults.tenant_suffix,
|
|
63
|
-
help="The suffix to add to the tenant name (default: 'Tenant
|
|
63
|
+
help="The suffix to add to the tenant name (default: 'Tenant-').",
|
|
64
64
|
)
|
|
65
65
|
@click.option(
|
|
66
66
|
"--number_tenants",
|
|
@@ -110,13 +110,18 @@ def delete_tenants_cli(
|
|
|
110
110
|
type=click.Choice(["quorum", "all", "one"]),
|
|
111
111
|
help="Consistency level (default: 'quorum').",
|
|
112
112
|
)
|
|
113
|
+
@click.option(
|
|
114
|
+
"--tenants",
|
|
115
|
+
default=None,
|
|
116
|
+
help="Comma separated list of tenants to delete data from.",
|
|
117
|
+
)
|
|
113
118
|
@click.option(
|
|
114
119
|
"--uuid",
|
|
115
120
|
default=DeleteDataDefaults.uuid,
|
|
116
121
|
help="UUID of the oject to be deleted. If provided, --limit will be ignored.",
|
|
117
122
|
)
|
|
118
123
|
@click.pass_context
|
|
119
|
-
def delete_data_cli(ctx, collection, limit, consistency_level, uuid):
|
|
124
|
+
def delete_data_cli(ctx, collection, limit, consistency_level, tenants, uuid):
|
|
120
125
|
"""Delete data from a collection in Weaviate."""
|
|
121
126
|
|
|
122
127
|
client = None
|
|
@@ -128,6 +133,7 @@ def delete_data_cli(ctx, collection, limit, consistency_level, uuid):
|
|
|
128
133
|
collection=collection,
|
|
129
134
|
limit=limit,
|
|
130
135
|
consistency_level=consistency_level,
|
|
136
|
+
tenants_list=tenants.split(",") if tenants else None,
|
|
131
137
|
uuid=uuid,
|
|
132
138
|
)
|
|
133
139
|
except Exception as e:
|
|
@@ -121,7 +121,7 @@ def update_collection_cli(
|
|
|
121
121
|
@click.option(
|
|
122
122
|
"--tenant_suffix",
|
|
123
123
|
default=UpdateTenantsDefaults.tenant_suffix,
|
|
124
|
-
help="The suffix to add to the tenant name (default: 'Tenant
|
|
124
|
+
help="The suffix to add to the tenant name (default: 'Tenant-').",
|
|
125
125
|
)
|
|
126
126
|
@click.option(
|
|
127
127
|
"--number_tenants",
|
|
@@ -30,6 +30,8 @@ PERMISSION_HELP_STRING = (
|
|
|
30
30
|
" --permission read_cluster"
|
|
31
31
|
)
|
|
32
32
|
|
|
33
|
+
MAX_OBJECTS_PER_BATCH = 5000
|
|
34
|
+
|
|
33
35
|
|
|
34
36
|
@dataclass
|
|
35
37
|
class CreateCollectionDefaults:
|
|
@@ -43,7 +45,7 @@ class CreateCollectionDefaults:
|
|
|
43
45
|
auto_tenant_creation: bool = False
|
|
44
46
|
auto_tenant_activation: bool = False
|
|
45
47
|
force_auto_schema: bool = False
|
|
46
|
-
shards: int =
|
|
48
|
+
shards: int = 0
|
|
47
49
|
vectorizer: Optional[str] = None
|
|
48
50
|
replication_deletion_strategy: str = "no_automated_resolution"
|
|
49
51
|
|
|
@@ -51,8 +53,9 @@ class CreateCollectionDefaults:
|
|
|
51
53
|
@dataclass
|
|
52
54
|
class CreateTenantsDefaults:
|
|
53
55
|
collection: str = "Movies"
|
|
54
|
-
tenant_suffix: str = "Tenant
|
|
56
|
+
tenant_suffix: str = "Tenant-"
|
|
55
57
|
number_tenants: int = 100
|
|
58
|
+
tenant_batch_size: Optional[int] = None
|
|
56
59
|
state: str = "active"
|
|
57
60
|
|
|
58
61
|
|
|
@@ -74,6 +77,7 @@ class CreateDataDefaults:
|
|
|
74
77
|
randomize: bool = False
|
|
75
78
|
auto_tenants: int = 0
|
|
76
79
|
vector_dimensions: int = 1536
|
|
80
|
+
wait_for_indexing: bool = False
|
|
77
81
|
|
|
78
82
|
|
|
79
83
|
@dataclass
|
|
@@ -97,7 +101,7 @@ class DeleteCollectionDefaults:
|
|
|
97
101
|
@dataclass
|
|
98
102
|
class DeleteTenantsDefaults:
|
|
99
103
|
collection: str = "Movies"
|
|
100
|
-
tenant_suffix: str = "Tenant
|
|
104
|
+
tenant_suffix: str = "Tenant-"
|
|
101
105
|
number_tenants: int = 100
|
|
102
106
|
|
|
103
107
|
|
|
@@ -183,7 +187,7 @@ class UpdateCollectionDefaults:
|
|
|
183
187
|
@dataclass
|
|
184
188
|
class UpdateTenantsDefaults:
|
|
185
189
|
collection: str = "Movies"
|
|
186
|
-
tenant_suffix: str = "Tenant
|
|
190
|
+
tenant_suffix: str = "Tenant-"
|
|
187
191
|
number_tenants: int = 100
|
|
188
192
|
state: str = "active"
|
|
189
193
|
|
|
@@ -234,7 +234,7 @@ class CollectionManager:
|
|
|
234
234
|
),
|
|
235
235
|
),
|
|
236
236
|
sharding_config=(
|
|
237
|
-
wvc.Configure.sharding(desired_count=shards) if shards >
|
|
237
|
+
wvc.Configure.sharding(desired_count=shards) if shards > 0 else None
|
|
238
238
|
),
|
|
239
239
|
multi_tenancy_config=wvc.Configure.multi_tenancy(
|
|
240
240
|
enabled=multitenant,
|
|
@@ -10,16 +10,20 @@ from weaviate.classes.query import MetadataQuery
|
|
|
10
10
|
from weaviate.collections.classes.tenants import TenantActivityStatus
|
|
11
11
|
from typing import Dict, List, Optional, Union, Any
|
|
12
12
|
import weaviate.classes.config as wvc
|
|
13
|
+
from weaviate.classes.query import Filter
|
|
13
14
|
from weaviate.collections import Collection
|
|
14
15
|
from datetime import datetime, timedelta
|
|
15
16
|
from weaviate_cli.defaults import (
|
|
17
|
+
MAX_OBJECTS_PER_BATCH,
|
|
16
18
|
CreateDataDefaults,
|
|
19
|
+
CreateTenantsDefaults,
|
|
17
20
|
QueryDataDefaults,
|
|
18
21
|
UpdateDataDefaults,
|
|
19
22
|
DeleteDataDefaults,
|
|
20
23
|
)
|
|
21
24
|
import importlib.resources as resources
|
|
22
25
|
from pathlib import Path
|
|
26
|
+
import math
|
|
23
27
|
|
|
24
28
|
PROPERTY_NAME_MAPPING = {
|
|
25
29
|
"releaseDate": "release_date",
|
|
@@ -203,10 +207,13 @@ class DataManager:
|
|
|
203
207
|
limit: int = CreateDataDefaults.limit,
|
|
204
208
|
consistency_level: str = CreateDataDefaults.consistency_level,
|
|
205
209
|
randomize: bool = CreateDataDefaults.randomize,
|
|
210
|
+
tenant_suffix: str = CreateTenantsDefaults.tenant_suffix,
|
|
206
211
|
auto_tenants: int = CreateDataDefaults.auto_tenants,
|
|
212
|
+
tenants_list: Optional[List[str]] = None,
|
|
207
213
|
vector_dimensions: Optional[int] = CreateDataDefaults.vector_dimensions,
|
|
208
214
|
uuid: Optional[str] = None,
|
|
209
215
|
named_vectors: Optional[List[str]] = None,
|
|
216
|
+
wait_for_indexing: bool = CreateDataDefaults.wait_for_indexing,
|
|
210
217
|
) -> Collection:
|
|
211
218
|
|
|
212
219
|
if not self.client.collections.exists(collection):
|
|
@@ -217,14 +224,19 @@ class DataManager:
|
|
|
217
224
|
|
|
218
225
|
col: Collection = self.client.collections.get(collection)
|
|
219
226
|
try:
|
|
220
|
-
|
|
227
|
+
existing_tenants = [key for key in col.tenants.get().keys()]
|
|
221
228
|
except Exception as e:
|
|
222
229
|
# Check if the error is due to multi-tenancy being disabled
|
|
223
230
|
if "multi-tenancy is not enabled" in str(e):
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
231
|
+
if (
|
|
232
|
+
tenants_list is not None
|
|
233
|
+
or auto_tenants != CreateDataDefaults.auto_tenants
|
|
234
|
+
):
|
|
235
|
+
raise Exception(
|
|
236
|
+
f"Collection '{col.name}' does not have multi-tenancy enabled. Adding data to tenants is not possible."
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
existing_tenants = ["None"]
|
|
228
240
|
else:
|
|
229
241
|
raise e
|
|
230
242
|
if (
|
|
@@ -241,16 +253,23 @@ class DataManager:
|
|
|
241
253
|
"all": wvc.ConsistencyLevel.ALL,
|
|
242
254
|
"one": wvc.ConsistencyLevel.ONE,
|
|
243
255
|
}
|
|
256
|
+
tenants = existing_tenants
|
|
244
257
|
if auto_tenants > 0:
|
|
245
|
-
if
|
|
246
|
-
|
|
258
|
+
if tenants_list is not None:
|
|
259
|
+
raise Exception(
|
|
260
|
+
f"Either --tenants or --auto_tenants must be provided, not both."
|
|
261
|
+
)
|
|
262
|
+
if existing_tenants == "None":
|
|
263
|
+
tenants = [f"{tenant_suffix}{i}" for i in range(1, auto_tenants + 1)]
|
|
247
264
|
else:
|
|
248
|
-
if len(
|
|
265
|
+
if len(existing_tenants) < auto_tenants:
|
|
249
266
|
tenants += [
|
|
250
|
-
f"
|
|
251
|
-
for i in range(len(
|
|
267
|
+
f"{tenant_suffix}{i}"
|
|
268
|
+
for i in range(len(existing_tenants) + 1, auto_tenants + 1)
|
|
252
269
|
]
|
|
253
|
-
|
|
270
|
+
else:
|
|
271
|
+
if tenants_list is not None:
|
|
272
|
+
tenants = tenants_list
|
|
254
273
|
for tenant in tenants:
|
|
255
274
|
if tenant == "None":
|
|
256
275
|
collection = self.__ingest_data(
|
|
@@ -273,7 +292,8 @@ class DataManager:
|
|
|
273
292
|
uuid,
|
|
274
293
|
named_vectors,
|
|
275
294
|
)
|
|
276
|
-
|
|
295
|
+
if wait_for_indexing:
|
|
296
|
+
collection.batch.wait_for_vector_indexing()
|
|
277
297
|
if len(collection) != limit:
|
|
278
298
|
click.echo(
|
|
279
299
|
f"Error occurred while ingesting data for tenant '{tenant}'. Check number of objects inserted."
|
|
@@ -402,25 +422,43 @@ class DataManager:
|
|
|
402
422
|
print(f"Object deleted: {uuid} into class '{collection.name}'")
|
|
403
423
|
return 1
|
|
404
424
|
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
425
|
+
# Calculate the number of full batches and handle any remaining objects
|
|
426
|
+
# Use math.ceil to ensure we process all objects, even if num_objects < MAX_OBJECTS_PER_BATCH
|
|
427
|
+
iterations = math.ceil(num_objects / MAX_OBJECTS_PER_BATCH)
|
|
428
|
+
deleted_objects = 0
|
|
429
|
+
|
|
430
|
+
for _ in range(iterations):
|
|
431
|
+
# Determine how many objects to fetch in this batch
|
|
432
|
+
batch_size = min(MAX_OBJECTS_PER_BATCH, num_objects - deleted_objects)
|
|
433
|
+
if batch_size <= 0:
|
|
434
|
+
break
|
|
435
|
+
|
|
436
|
+
res = collection.query.fetch_objects(limit=batch_size)
|
|
437
|
+
if len(res.objects) == 0:
|
|
438
|
+
click.echo(
|
|
439
|
+
f"No objects found in class '{collection.name}'. Insert objects first using <ingest data> command"
|
|
440
|
+
)
|
|
441
|
+
return deleted_objects
|
|
442
|
+
|
|
443
|
+
ids = [o.uuid for o in res.objects]
|
|
444
|
+
collection.with_consistency_level(cl).data.delete_many(
|
|
445
|
+
where=Filter.by_id().contains_any(ids)
|
|
409
446
|
)
|
|
410
|
-
|
|
411
|
-
data_objects = res.objects
|
|
447
|
+
deleted_objects += len(ids)
|
|
412
448
|
|
|
413
|
-
|
|
414
|
-
|
|
449
|
+
# If we've deleted fewer objects than expected, there might not be any more objects
|
|
450
|
+
if len(ids) < batch_size:
|
|
451
|
+
break
|
|
415
452
|
|
|
416
|
-
print(f"Deleted {
|
|
417
|
-
return
|
|
453
|
+
print(f"Deleted {deleted_objects} objects from class '{collection.name}'")
|
|
454
|
+
return deleted_objects
|
|
418
455
|
|
|
419
456
|
def delete_data(
|
|
420
457
|
self,
|
|
421
458
|
collection: str = DeleteDataDefaults.collection,
|
|
422
459
|
limit: int = DeleteDataDefaults.limit,
|
|
423
460
|
consistency_level: str = DeleteDataDefaults.consistency_level,
|
|
461
|
+
tenants_list: Optional[List[str]] = None,
|
|
424
462
|
uuid: Optional[str] = DeleteDataDefaults.uuid,
|
|
425
463
|
) -> None:
|
|
426
464
|
|
|
@@ -433,14 +471,14 @@ class DataManager:
|
|
|
433
471
|
|
|
434
472
|
col: Collection = self.client.collections.get(collection)
|
|
435
473
|
try:
|
|
436
|
-
|
|
474
|
+
existing_tenants = [key for key in col.tenants.get().keys()]
|
|
437
475
|
except Exception as e:
|
|
438
476
|
# Check if the error is due to multi-tenancy being disabled
|
|
439
477
|
if "multi-tenancy is not enabled" in str(e):
|
|
440
478
|
click.echo(
|
|
441
479
|
f"Collection '{col.name}' does not have multi-tenancy enabled. Skipping tenant information collection."
|
|
442
480
|
)
|
|
443
|
-
|
|
481
|
+
existing_tenants = ["None"]
|
|
444
482
|
|
|
445
483
|
cl_map = {
|
|
446
484
|
"quorum": wvc.ConsistencyLevel.QUORUM,
|
|
@@ -448,6 +486,11 @@ class DataManager:
|
|
|
448
486
|
"one": wvc.ConsistencyLevel.ONE,
|
|
449
487
|
}
|
|
450
488
|
|
|
489
|
+
if tenants_list is not None:
|
|
490
|
+
tenants = tenants_list
|
|
491
|
+
else:
|
|
492
|
+
tenants = existing_tenants
|
|
493
|
+
|
|
451
494
|
for tenant in tenants:
|
|
452
495
|
if tenant == "None":
|
|
453
496
|
ret = self.__delete_data(col, limit, cl_map[consistency_level], uuid)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from typing import Optional
|
|
1
2
|
import click
|
|
2
3
|
import semver
|
|
3
4
|
|
|
@@ -20,6 +21,7 @@ class TenantManager:
|
|
|
20
21
|
collection: str = CreateTenantsDefaults.collection,
|
|
21
22
|
tenant_suffix: str = CreateTenantsDefaults.tenant_suffix,
|
|
22
23
|
number_tenants: int = CreateTenantsDefaults.number_tenants,
|
|
24
|
+
tenant_batch_size: Optional[int] = CreateTenantsDefaults.tenant_batch_size,
|
|
23
25
|
state: str = CreateTenantsDefaults.state,
|
|
24
26
|
) -> None:
|
|
25
27
|
"""
|
|
@@ -33,11 +35,10 @@ class TenantManager:
|
|
|
33
35
|
|
|
34
36
|
Raises:
|
|
35
37
|
Exception: If the collection does not exist, multi-tenancy is not enabled,
|
|
36
|
-
|
|
38
|
+
or if there is a mismatch in tenant activity status.
|
|
37
39
|
"""
|
|
38
40
|
|
|
39
41
|
if not self.client.collections.exists(collection):
|
|
40
|
-
|
|
41
42
|
raise Exception(
|
|
42
43
|
f"Class '{collection}' does not exist in Weaviate. Create first using <create class>"
|
|
43
44
|
)
|
|
@@ -46,7 +47,6 @@ class TenantManager:
|
|
|
46
47
|
collection = self.client.collections.get(collection)
|
|
47
48
|
|
|
48
49
|
if not collection.config.get().multi_tenancy_config.enabled:
|
|
49
|
-
|
|
50
50
|
raise Exception(
|
|
51
51
|
f"Collection '{collection.name}' does not have multi-tenancy enabled. Recreate or modify the class with: <create class>"
|
|
52
52
|
)
|
|
@@ -61,45 +61,94 @@ class TenantManager:
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
existing_tenants = collection.tenants.get()
|
|
64
|
-
|
|
64
|
+
new_tenant_names = []
|
|
65
65
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
)
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
66
|
+
if existing_tenants:
|
|
67
|
+
# Check if existing tenants follow the same suffix pattern
|
|
68
|
+
existing_tenant_names = list(existing_tenants.keys())
|
|
69
|
+
for tenant_name in existing_tenant_names:
|
|
70
|
+
if tenant_name.startswith(tenant_suffix):
|
|
71
|
+
try:
|
|
72
|
+
# Try to extract the index part after the suffix
|
|
73
|
+
int(tenant_name[len(tenant_suffix) :])
|
|
74
|
+
except ValueError:
|
|
75
|
+
raise Exception(
|
|
76
|
+
f"Existing tenant '{tenant_name}' does not follow the expected pattern '{tenant_suffix}N' where N is a number. "
|
|
77
|
+
f"Please use a different tenant_suffix or delete existing tenants."
|
|
78
|
+
)
|
|
79
|
+
else:
|
|
80
|
+
raise Exception(
|
|
81
|
+
f"Existing tenant '{tenant_name}' does not use the provided tenant_suffix '{tenant_suffix}'. "
|
|
82
|
+
f"Please use the same tenant_suffix as existing tenants or delete existing tenants."
|
|
75
83
|
)
|
|
76
|
-
for i in range(number_tenants)
|
|
77
|
-
]
|
|
78
|
-
)
|
|
79
84
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
85
|
+
# Find the highest index among existing tenants
|
|
86
|
+
highest_index = -1
|
|
87
|
+
for tenant_name in existing_tenant_names:
|
|
88
|
+
try:
|
|
89
|
+
index = int(tenant_name[len(tenant_suffix) :])
|
|
90
|
+
highest_index = max(highest_index, index)
|
|
91
|
+
except ValueError:
|
|
92
|
+
continue
|
|
93
|
+
|
|
94
|
+
# Generate new tenant names starting from the next index
|
|
95
|
+
start_index = highest_index + 1
|
|
96
|
+
new_tenant_names = [
|
|
97
|
+
f"{tenant_suffix}{i}"
|
|
98
|
+
for i in range(start_index, start_index + number_tenants)
|
|
99
|
+
]
|
|
87
100
|
else:
|
|
88
|
-
|
|
89
|
-
|
|
101
|
+
# No existing tenants, create tenants starting from index 0
|
|
102
|
+
new_tenant_names = [f"{tenant_suffix}{i}" for i in range(number_tenants)]
|
|
103
|
+
|
|
104
|
+
# Create the new tenants
|
|
105
|
+
tenants = [
|
|
106
|
+
Tenant(
|
|
107
|
+
name=name,
|
|
108
|
+
activity_status=tenant_state_map[state],
|
|
90
109
|
)
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
if
|
|
110
|
+
for name in new_tenant_names
|
|
111
|
+
]
|
|
112
|
+
|
|
113
|
+
if tenants: # Only call create if there are tenants to create
|
|
114
|
+
if tenant_batch_size:
|
|
115
|
+
for i in range(0, len(tenants), tenant_batch_size):
|
|
116
|
+
batch = tenants[i : i + tenant_batch_size]
|
|
117
|
+
collection.tenants.create(batch)
|
|
118
|
+
else:
|
|
119
|
+
collection.tenants.create(tenants)
|
|
120
|
+
|
|
121
|
+
# Verify the newly created tenants
|
|
122
|
+
if version.compare(semver.Version.parse("1.25.0")) < 0:
|
|
123
|
+
created_tenants = {
|
|
124
|
+
name: tenant
|
|
125
|
+
for name, tenant in collection.tenants.get().items()
|
|
126
|
+
if name in new_tenant_names
|
|
127
|
+
}
|
|
128
|
+
else:
|
|
129
|
+
created_tenants = collection.tenants.get_by_names(new_tenant_names)
|
|
96
130
|
|
|
131
|
+
# Verify all requested tenants were created
|
|
132
|
+
if len(created_tenants) != len(new_tenant_names):
|
|
133
|
+
missing_tenants = set(new_tenant_names) - set(created_tenants.keys())
|
|
97
134
|
raise Exception(
|
|
98
|
-
f"
|
|
135
|
+
f"Not all requested tenants were created. Missing: {', '.join(missing_tenants)}"
|
|
99
136
|
)
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
137
|
+
|
|
138
|
+
# Verify tenant activity status
|
|
139
|
+
for tenant_name, tenant in created_tenants.items():
|
|
140
|
+
if tenant.activity_status != tenant_state_map[state]:
|
|
141
|
+
raise Exception(
|
|
142
|
+
f"Tenant '{tenant_name}' has activity status '{tenant.activity_status}', but expected '{tenant_state_map[state]}'"
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
click.echo(
|
|
146
|
+
f"{len(new_tenant_names)} tenants added with tenant status '{tenant_state_map[state]}' for collection '{collection.name}'"
|
|
147
|
+
)
|
|
148
|
+
else:
|
|
149
|
+
click.echo(
|
|
150
|
+
f"No new tenants were created for collection '{collection.name}'"
|
|
151
|
+
)
|
|
103
152
|
|
|
104
153
|
def delete_tenants(
|
|
105
154
|
self,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/test/unittests/test_managers/test_collection_manager.py
RENAMED
|
File without changes
|
{weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/test/unittests/test_managers/test_config_manager.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{weaviate_cli-3.1.2 → weaviate_cli-3.1.4}/test/unittests/test_managers/test_shard_manager.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|