weaviate-cli 3.1.2__tar.gz → 3.1.3__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.3}/PKG-INFO +1 -1
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/weaviate_cli/commands/create.py +25 -2
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/weaviate_cli/commands/delete.py +8 -2
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/weaviate_cli/commands/update.py +1 -1
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/weaviate_cli/defaults.py +7 -4
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/weaviate_cli/managers/collection_manager.py +1 -1
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/weaviate_cli/managers/data_manager.py +65 -24
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/weaviate_cli/managers/tenant_manager.py +83 -34
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/weaviate_cli.egg-info/PKG-INFO +1 -1
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/.github/dependabot.yml +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/.github/workflows/main.yaml +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/.github/workflows/release.yaml +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/.gitignore +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/.pre-commit-config.yaml +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/CONTRIBUTING.md +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/Dockerfile +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/LICENSE +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/MANIFEST.in +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/Makefile +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/README.md +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/cli.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/publish.md +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/pyproject.toml +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/requirements-dev.txt +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/setup.cfg +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/setup.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/test/README.md +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/test/__init__.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/test/integration/test_integration.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/test/unittests/conftest.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/test/unittests/test_cli.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/test/unittests/test_defaults.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/test/unittests/test_managers/test_collection_manager.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/test/unittests/test_managers/test_config_manager.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/test/unittests/test_managers/test_data_manager.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/test/unittests/test_managers/test_node_manager.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/test/unittests/test_managers/test_shard_manager.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/test/unittests/test_utils.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/weaviate_cli/__init__.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/weaviate_cli/commands/__init__.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/weaviate_cli/commands/assign.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/weaviate_cli/commands/cancel.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/weaviate_cli/commands/get.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/weaviate_cli/commands/query.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/weaviate_cli/commands/restore.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/weaviate_cli/commands/revoke.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/weaviate_cli/completion/__init__.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/weaviate_cli/completion/complete.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/weaviate_cli/datasets/__init__.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/weaviate_cli/datasets/movies.json +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/weaviate_cli/managers/__init__.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/weaviate_cli/managers/backup_manager.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/weaviate_cli/managers/config_manager.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/weaviate_cli/managers/node_manager.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/weaviate_cli/managers/role_manager.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/weaviate_cli/managers/shard_manager.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/weaviate_cli/managers/user_manager.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/weaviate_cli/types/models.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/weaviate_cli/utils.py +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/weaviate_cli.egg-info/SOURCES.txt +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/weaviate_cli.egg-info/dependency_links.txt +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/weaviate_cli.egg-info/entry_points.txt +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/weaviate_cli.egg-info/not-zip-safe +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/weaviate_cli.egg-info/requires.txt +0 -0
- {weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/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,
|
|
@@ -319,6 +338,8 @@ def create_data_cli(
|
|
|
319
338
|
consistency_level,
|
|
320
339
|
randomize,
|
|
321
340
|
auto_tenants,
|
|
341
|
+
tenants,
|
|
342
|
+
tenant_suffix,
|
|
322
343
|
vector_dimensions,
|
|
323
344
|
uuid,
|
|
324
345
|
):
|
|
@@ -349,8 +370,10 @@ def create_data_cli(
|
|
|
349
370
|
consistency_level=consistency_level,
|
|
350
371
|
randomize=randomize,
|
|
351
372
|
auto_tenants=auto_tenants,
|
|
373
|
+
tenants_list=tenants.split(",") if tenants else None,
|
|
352
374
|
vector_dimensions=vector_dimensions,
|
|
353
375
|
uuid=uuid,
|
|
376
|
+
tenant_suffix=tenant_suffix,
|
|
354
377
|
)
|
|
355
378
|
except Exception as e:
|
|
356
379
|
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
|
|
|
@@ -97,7 +100,7 @@ class DeleteCollectionDefaults:
|
|
|
97
100
|
@dataclass
|
|
98
101
|
class DeleteTenantsDefaults:
|
|
99
102
|
collection: str = "Movies"
|
|
100
|
-
tenant_suffix: str = "Tenant
|
|
103
|
+
tenant_suffix: str = "Tenant-"
|
|
101
104
|
number_tenants: int = 100
|
|
102
105
|
|
|
103
106
|
|
|
@@ -183,7 +186,7 @@ class UpdateCollectionDefaults:
|
|
|
183
186
|
@dataclass
|
|
184
187
|
class UpdateTenantsDefaults:
|
|
185
188
|
collection: str = "Movies"
|
|
186
|
-
tenant_suffix: str = "Tenant
|
|
189
|
+
tenant_suffix: str = "Tenant-"
|
|
187
190
|
number_tenants: int = 100
|
|
188
191
|
state: str = "active"
|
|
189
192
|
|
|
@@ -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,7 +207,9 @@ 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,
|
|
@@ -217,14 +223,19 @@ class DataManager:
|
|
|
217
223
|
|
|
218
224
|
col: Collection = self.client.collections.get(collection)
|
|
219
225
|
try:
|
|
220
|
-
|
|
226
|
+
existing_tenants = [key for key in col.tenants.get().keys()]
|
|
221
227
|
except Exception as e:
|
|
222
228
|
# Check if the error is due to multi-tenancy being disabled
|
|
223
229
|
if "multi-tenancy is not enabled" in str(e):
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
230
|
+
if (
|
|
231
|
+
tenants_list is not None
|
|
232
|
+
or auto_tenants != CreateDataDefaults.auto_tenants
|
|
233
|
+
):
|
|
234
|
+
raise Exception(
|
|
235
|
+
f"Collection '{col.name}' does not have multi-tenancy enabled. Adding data to tenants is not possible."
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
existing_tenants = ["None"]
|
|
228
239
|
else:
|
|
229
240
|
raise e
|
|
230
241
|
if (
|
|
@@ -241,16 +252,23 @@ class DataManager:
|
|
|
241
252
|
"all": wvc.ConsistencyLevel.ALL,
|
|
242
253
|
"one": wvc.ConsistencyLevel.ONE,
|
|
243
254
|
}
|
|
255
|
+
tenants = existing_tenants
|
|
244
256
|
if auto_tenants > 0:
|
|
245
|
-
if
|
|
246
|
-
|
|
257
|
+
if tenants_list is not None:
|
|
258
|
+
raise Exception(
|
|
259
|
+
f"Either --tenants or --auto_tenants must be provided, not both."
|
|
260
|
+
)
|
|
261
|
+
if existing_tenants == "None":
|
|
262
|
+
tenants = [f"{tenant_suffix}{i}" for i in range(1, auto_tenants + 1)]
|
|
247
263
|
else:
|
|
248
|
-
if len(
|
|
264
|
+
if len(existing_tenants) < auto_tenants:
|
|
249
265
|
tenants += [
|
|
250
|
-
f"
|
|
251
|
-
for i in range(len(
|
|
266
|
+
f"{tenant_suffix}{i}"
|
|
267
|
+
for i in range(len(existing_tenants) + 1, auto_tenants + 1)
|
|
252
268
|
]
|
|
253
|
-
|
|
269
|
+
else:
|
|
270
|
+
if tenants_list is not None:
|
|
271
|
+
tenants = tenants_list
|
|
254
272
|
for tenant in tenants:
|
|
255
273
|
if tenant == "None":
|
|
256
274
|
collection = self.__ingest_data(
|
|
@@ -273,7 +291,7 @@ class DataManager:
|
|
|
273
291
|
uuid,
|
|
274
292
|
named_vectors,
|
|
275
293
|
)
|
|
276
|
-
|
|
294
|
+
collection.batch.wait_for_vector_indexing()
|
|
277
295
|
if len(collection) != limit:
|
|
278
296
|
click.echo(
|
|
279
297
|
f"Error occurred while ingesting data for tenant '{tenant}'. Check number of objects inserted."
|
|
@@ -402,25 +420,43 @@ class DataManager:
|
|
|
402
420
|
print(f"Object deleted: {uuid} into class '{collection.name}'")
|
|
403
421
|
return 1
|
|
404
422
|
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
423
|
+
# Calculate the number of full batches and handle any remaining objects
|
|
424
|
+
# Use math.ceil to ensure we process all objects, even if num_objects < MAX_OBJECTS_PER_BATCH
|
|
425
|
+
iterations = math.ceil(num_objects / MAX_OBJECTS_PER_BATCH)
|
|
426
|
+
deleted_objects = 0
|
|
427
|
+
|
|
428
|
+
for _ in range(iterations):
|
|
429
|
+
# Determine how many objects to fetch in this batch
|
|
430
|
+
batch_size = min(MAX_OBJECTS_PER_BATCH, num_objects - deleted_objects)
|
|
431
|
+
if batch_size <= 0:
|
|
432
|
+
break
|
|
433
|
+
|
|
434
|
+
res = collection.query.fetch_objects(limit=batch_size)
|
|
435
|
+
if len(res.objects) == 0:
|
|
436
|
+
click.echo(
|
|
437
|
+
f"No objects found in class '{collection.name}'. Insert objects first using <ingest data> command"
|
|
438
|
+
)
|
|
439
|
+
return deleted_objects
|
|
440
|
+
|
|
441
|
+
ids = [o.uuid for o in res.objects]
|
|
442
|
+
collection.with_consistency_level(cl).data.delete_many(
|
|
443
|
+
where=Filter.by_id().contains_any(ids)
|
|
409
444
|
)
|
|
410
|
-
|
|
411
|
-
data_objects = res.objects
|
|
445
|
+
deleted_objects += len(ids)
|
|
412
446
|
|
|
413
|
-
|
|
414
|
-
|
|
447
|
+
# If we've deleted fewer objects than expected, there might not be any more objects
|
|
448
|
+
if len(ids) < batch_size:
|
|
449
|
+
break
|
|
415
450
|
|
|
416
|
-
print(f"Deleted {
|
|
417
|
-
return
|
|
451
|
+
print(f"Deleted {deleted_objects} objects from class '{collection.name}'")
|
|
452
|
+
return deleted_objects
|
|
418
453
|
|
|
419
454
|
def delete_data(
|
|
420
455
|
self,
|
|
421
456
|
collection: str = DeleteDataDefaults.collection,
|
|
422
457
|
limit: int = DeleteDataDefaults.limit,
|
|
423
458
|
consistency_level: str = DeleteDataDefaults.consistency_level,
|
|
459
|
+
tenants_list: Optional[List[str]] = None,
|
|
424
460
|
uuid: Optional[str] = DeleteDataDefaults.uuid,
|
|
425
461
|
) -> None:
|
|
426
462
|
|
|
@@ -433,14 +469,14 @@ class DataManager:
|
|
|
433
469
|
|
|
434
470
|
col: Collection = self.client.collections.get(collection)
|
|
435
471
|
try:
|
|
436
|
-
|
|
472
|
+
existing_tenants = [key for key in col.tenants.get().keys()]
|
|
437
473
|
except Exception as e:
|
|
438
474
|
# Check if the error is due to multi-tenancy being disabled
|
|
439
475
|
if "multi-tenancy is not enabled" in str(e):
|
|
440
476
|
click.echo(
|
|
441
477
|
f"Collection '{col.name}' does not have multi-tenancy enabled. Skipping tenant information collection."
|
|
442
478
|
)
|
|
443
|
-
|
|
479
|
+
existing_tenants = ["None"]
|
|
444
480
|
|
|
445
481
|
cl_map = {
|
|
446
482
|
"quorum": wvc.ConsistencyLevel.QUORUM,
|
|
@@ -448,6 +484,11 @@ class DataManager:
|
|
|
448
484
|
"one": wvc.ConsistencyLevel.ONE,
|
|
449
485
|
}
|
|
450
486
|
|
|
487
|
+
if tenants_list is not None:
|
|
488
|
+
tenants = tenants_list
|
|
489
|
+
else:
|
|
490
|
+
tenants = existing_tenants
|
|
491
|
+
|
|
451
492
|
for tenant in tenants:
|
|
452
493
|
if tenant == "None":
|
|
453
494
|
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.3}/test/unittests/test_managers/test_collection_manager.py
RENAMED
|
File without changes
|
{weaviate_cli-3.1.2 → weaviate_cli-3.1.3}/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.3}/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
|