Python (v4)
The Python client is currently in beta, and we want to hear from you. You can test the new client locally, or on paid instances of Weaviate Cloud Services (WCS). It is not yet available on the free (sandbox) tier of WCS. If you notice any bugs, or have any feedback, please let us know on this forum thread
Overviewβ
This page describes the v4
Python client for Weaviate.
The full set of features is covered in the client documentation pages. This page covers key ideas and aspects of the new Python client.
Key changes from v3
β
This client is also called the collections
client, because it adds new collection-level (previously called "class") interactions.
This client also includes numerous additional Python classes to provide IDE assistance and typing help. You can import them individually, like so:
from weaviate.classes import Property, ConfigFactory, DataObject
But it may be convenient to import the whole set of classes like this.
import weaviate.classes as wvc
Installationβ
The Python library is available on PyPI.org. The package can be installed using pip. The client is developed and tested for Python 3.8 to 3.12.
Install the client with the following command:
pip install --pre -U "weaviate-client==4.*"
Requirementsβ
Weaviate versionβ
The API may change on the client-side and the server-side, especially during the beta period. Accordingly, we encourage you to use the latest version of the Python client and the Weaviate server.
The v4
client is designed for use with Weaviate 1.22
and higher to take advantage of the gRPC API. If you are using an older version of Weaviate, or otherwise unable to use gRPC, please use the v3
client, or the legacy instantiation method through the weaviate.Client
class which is still available.
Please refer to the v3
client documentation if you are using this instantiation method.
gRPC portβ
A port for gRPC must be open on your Weaviate server. If you are running Weaviate locally, you can open the default port (50051
) by adding the following to your docker-compose.yml
file:
ports:
- "8080:8080"
- "50051:50051"
WCS availabilityβ
You can test the new client locally, or on paid instances of Weaviate Cloud Services (WCS). It is not yet available on the free (sandbox) tier of WCS.
Instantiationβ
You can instantiate the client using one of multiple methods. For example, you can use one of the following helper connect
functions:
weaviate.connect_to_wcs()
weaviate.connect_to_local()
weaviate.connect_to_embedded()
weaviate.connect_to_custom()
See the examples below:
- WCS
- Local
- Embedded
- Custom
Note: As of December 2023, WCS sandboxes are not compatible with the v4
client.
import weaviate
client = weaviate.connect_to_wcs(
cluster_url="YOUR_WCS_URL",
auth_credentials=weaviate.AuthApiKey("YOUR_API_KEY")
)
import weaviate
client = weaviate.connect_to_local() # Connect with default parameters
import weaviate
client = weaviate.connect_to_embedded() # Connect with default parameters
import weaviate
client = weaviate.connect_to_custom(
http_host="YOUR_HTTP_HOST",
http_port="YOUR_HTTP_PORT",
http_secure=True,
grpc_host="YOUR_gRPC_HOST",
grpc_port="YOUR_gRPC_PORT",
grpc_secure=True,
headers={
"X-OpenAI-Api-Key": os.environ["OPENAI_APIKEY"] # Or any other inference API keys
}
)
Or, you can instantiate a weaviate.WeaviateClient
object directly.
API keys for external API useβ
You can pass on API keys for services such as Cohere, OpenAI and so on through additional headers. For example:
import weaviate
import os
client = weaviate.connect_to_local(
port=8080,
grpc_port=50051,
headers={"X-OpenAI-Api": os.environ["OPENAI_APIKEY"]}
)
Timeout valuesβ
You can set timeout values for the client as a tuple (connection timeout & read timeout time) in seconds.
import weaviate
client = weaviate.connect_to_local(port=8080, grpc_port=50051, timeout=(5, 15))
Authenticationβ
Some helper connect
functions allow you to pass on authentication credentials.
For example, the connect_to_wcs
method allows for a WCS api key or OIDC authentication credentials to be passed in.
- API Key
- OIDC Credentials
import weaviate
client = weaviate.connect_to_wcs(
cluster_url="YOUR_WCS_URL",
auth_credentials=weaviate.AuthApiKey("YOUR_API_KEY")
)
import weaviate
client = weaviate.connect_to_wcs(
cluster_url="YOUR_WCS_URL",
auth_credentials=weaviate.AuthClientPassword(
username=os.environ["MY_USERNAME"],
password=os.environ["MY_PASSWORD"]
)
)
The client also supports OIDC authentication with Client Credentials flow and Refresh Token flow. They are available through the AuthClientCredentials
and AuthBearerToken
classes respectively.
If a particular helper function does not support the desired workflow, directly instantiate the WeaviateClient
object.
Advanced: Direct instantiationβ
You can also instantiate a client (WeaviateClient
) object directly and pass on custom parameters. This is the most flexible way to instantiate the client.
import weaviate
client = weaviate.WeaviateClient(
connection_params=weaviate.ConnectionParams.from_params(
http_host="YOUR_HTTP_HOST",
http_port="YOUR_HTTP_PORT",
http_secure=True,
grpc_host="YOUR_gRPC_HOST",
grpc_port="YOUR_gRPC_PORT",
grpc_secure=True,
),
auth_client_secret=weaviate.AuthApiKey("YOUR_APIKEY"),
additional_headers={
"X-OpenAI-Api-Key": os.environ["OPENAI_APIKEY"]
},
additional_config=weaviate.AdditionalConfig(
startup_period=10,
timeout=(5, 15)
),
)
V3 Client
instantiationβ
You can instantiate a v3
style Client
object using the weaviate.Client
class. This is the legacy instantiation method, and is still available for backwards compatibility.
Please refer to the v3
client documentation if you are using this instantiation method.
Working with collectionsβ
Instantiate a collectionβ
You can instantiate a collection object by creating a collection, or by retrieving an existing collection.
- Create a collection
- Get a collection
import weaviate
import weaviate.classes as wvc
client = weaviate.connect_to_local()
collection = client.collections.create(
name="TestArticle",
vectorizer_config=wvc.Configure.Vectorizer.text2vec_openai(),
properties=[
wvc.Property(
name="title",
data_type=wvc.DataType.TEXT
)
]
)
import weaviate
import weaviate.classes as wvc
client = weaviate.connect_to_local()
collection = client.collections.get("TestArticle")
Collection submodulesβ
Operations in the v4
client are grouped into submodules. The key submodules for interacting with objects are:
data
: CUD operations (read operations are inquery
)query
: Search operationsgenerate
: Retrieval augmented generation operations- Build on top of
query
operations
- Build on top of
aggregate
: Aggregation operationsquery_group_by
: Object-level group by operationsaggregate_group_by
: Aggregation-level group by operations
data
β
The data
submodule contains all object-level CUD operations, including:
insert
for creating objects.- This function takes the object properties as a dictionary.
insert_many
for batch creating multiple objects.- This function takes the object properties as a dictionary or as a
DataObject
instance.
- This function takes the object properties as a dictionary or as a
update
for updating objects (forPATCH
operations).replace
for replacing objects (forPUT
operations).delete_by_id
for deleting objects by ID.delete_many
for batch deletion.reference_xxx
for reference operations, includingreference_add
,reference_add_many
,reference_update
andreference_delete
.
See some examples below. Note that each function will return varying types of objects.
insert_many
sends one requestAs of 4.4b1
, insert_many
will send one request for the entire function call.
We are evaluating modifing this to send multiple requests by matches in the future.
- Insert
- Delete by id
- Insert many
- Delete many
questions = client.collections.get("JeopardyQuestion")
tmp_uuid = questions.data.insert(
properties={
"question": "This is the capital of Australia."
}
)
questions = client.collections.get("JeopardyQuestion")
deleted = questions.data.delete_by_id(uuid=tmp_uuid)
questions = client.collections.get("JeopardyQuestion")
properties = [{"question": f"Test Question"} for i in range(5)]
response = questions.data.insert_many(properties)
from weaviate.classes import Filter
questions = client.collections.get("JeopardyQuestion")
response = questions.data.delete_many(
where=Filter(path="question").equal("Test Question")
)
query
β
The query
submodule contains all object-level query operations, including fetch_objects
for retrieving objects without additional search parameters, bm25
for keyword search, near_<xxx>
for vector search operators, hybrid
for hybrid search and so on.
These queries return a _QueryReturn
object, which contains a list of _Object
objects.
- BM25
- Near text
questions = client.collections.get("JeopardyQuestion")
response = questions.query.bm25(
query="animal",
limit=2
)
for o in response.objects:
print(o.properties) # Object properties
questions = client.collections.get("JeopardyQuestion")
response = questions.query.near_text(
query="animal",
limit=2
)
for o in response.objects:
print(o.properties) # Object properties
You can further specify:
- Whether to include the object vector (via
include_vector
)- Default is
False
- Default is
- Which properties to include (via
return_properties
)- All properties are returned by default
- Which metadata to include
- No metadata is returned by default
Each object includes its UUID as well as all properties by default.
For example:
- Default
- Customized returns
questions = client.collections.get("JeopardyQuestion")
response = questions.query.bm25(
query="animal",
limit=2
)
for o in response.objects:
print(o.properties) # All properties by default
print(o.uuid) # UUID included by default
print(o.vector) # No vector
print(o.metadata) # No metadata
questions = client.collections.get("JeopardyQuestion")
response = questions.query.bm25(
query="animal",
include_vector=True,
return_properties=["question"],
return_metadata=wvc.MetadataQuery(distance=True),
limit=2
)
for o in response.objects:
print(o.properties) # Selected properties only
print(o.uuid) # UUID included by default
print(o.vector) # With vector
print(o.metadata) # With selected metadata
generate
β
The RAG / generative search functionality is a two-step process involving a search followed by prompting a large language model. Therefore, function names are shared across the query
and generate
submodules, with additional parameters available in the generate
submodule.
- Generate
- Query
questions = client.collections.get("JeopardyQuestion")
response = questions.generate.bm25(
query="animal",
limit=2,
grouped_task="What do these animals have in common?",
single_prompt="Translate the following into French: {answer}"
)
print(response.generated) # Generated text from grouped task
for o in response.objects:
print(o.generated) # Generated text from single prompt
print(o.properties) # Object properties
questions = client.collections.get("JeopardyQuestion")
response = questions.query.bm25(
query="animal",
limit=2
)
for o in response.objects:
print(o.properties) # Object properties
Outputs of the generate
submodule queries include generate
attributes at the top level for the grouped_task
tasks, while generate
attributes attached with each object contain results from single_prompt
tasks.
aggregate
β
To use the aggregate
submodule, supply one or more ways to aggregate the data. For example, they could be by a count of objects matching the criteria, or by a metric aggregating the objects' properties.
- Count
- Metric
questions = client.collections.get("JeopardyQuestion")
response = questions.aggregate.over_all(
filters=wvc.Filter(path="question").like("*animal*"),
total_count=True
)
print(response.total_count)
questions = client.collections.get("JeopardyQuestion")
response = questions.aggregate.near_text(
query="animal",
object_limit=5,
return_metrics=wvc.Metrics("points").integer(mean=True)
)
print(response.properties)
query_group_by
β
Results of a query can be grouped by a property as shown here.
The results are organized by both their individual objects as well as the group.
- The
objects
attribute is a list of objects, each containing abelongs_to_group
property to indicate which group it belongs to. - The
group
attribute is a dictionary with each key indicating the value of the group, and the value being a list of objects belonging to that group.
questions = client.collections.get("JeopardyQuestion")
response = questions.query_group_by.near_text(
query="animal",
distance=0.2,
group_by_property="points",
number_of_groups=3,
objects_per_group=5
)
for k, v in response.groups.items(): # View by group
print(k, v)
for o in response.objects: # View by object
print(o)
aggregate_group_by
β
Results of a query can be grouped and aggregated as shown here.
The results are organized the group, returning a list of groups.
questions = client.collections.get("JeopardyQuestion")
response = questions.aggregate_group_by.near_text(
query="animal",
distance=0.2,
group_by="points",
return_metrics=wvc.Metrics("points").integer(mean=True)
)
for o in response:
print(o)
Collection iterator (cursor
API)β
The v4
client adds a Pythonic iterator method for each collection. This wraps the cursor
API and allows you to iterate over all objects in a collection.
This will fetch all objects in the questions
collection, including its properties.
all_objects = [question for question in questions.iterator()]
You can specify what properties to retrieve. This will only fetch the title
property.
all_object_answer_ids = [question for question in questions.iterator(return_properties=["answer"])]
You can also specify what metadata to retrieve. This will only fetch the creation_time_unix
metadata.
all_object_ids = [question for question in questions.iterator(return_metadata=wvc.MetadataQuery(creation_time_unix=True))] # Only return IDs
Note that as the cursor
API inherently requires the object UUID for indexing, the uuid
metadata is always retrieved.
Data model / genericsβ
You can choose to provide a generic type to a query or data operation. This can be beneficial as the generic class is used to extract the return properties and statically type the response.
from typing import TypedDict
questions = client.collections.get("JeopardyQuestion")
class Question(TypedDict):
question: str
answer: str
points: int
response = questions.query.fetch_objects(
limit=2,
return_properties=Question, # Your generic class is used to extract the return properties and statically type the response
return_metadata=wvc.MetadataQuery(creation_time_unix=True) # MetaDataQuery object is used to specify the metadata to be returned in the response
)
Best practices and notesβ
Thread-safetyβ
While the Python client is fundamentally designed to be thread-safe, it's important to note that due to its dependency on the requests
library, complete thread safety isn't guaranteed.
This is an area that we are looking to improve in the future.
Please be particularly aware that the batching algorithm within our client is not thread-safe. Keeping this in mind will help ensure smoother, more predictable operations when using our Python client in multi-threaded environments.
If you are performing batching in a multi-threaded scenario, ensure that only one of the threads is performing the batching workflow at any given time. No two threads can use the same client.batch
object at one time.
Response object structureβ
Each query response object typically include multiple attributes. Consider this query.
questions = client.collections.get("JeopardyQuestion")
response = questions.generate.near_text(
query="history",
limit=2,
single_prompt="Translate this into French {question}",
grouped_task="Summarize this into a sentence",
return_metadata=wvc.MetadataQuery(
distance=True,
creation_time_unix=True
)
)
print(response)
Each response includes attributes such as objects
and generated
. Then, each object in objects
include multiple attributes such as uuid
, vector
, properties
, metadata
and generated
.
_GenerativeReturn(objects=[_GenerativeObject(uuid=UUID('f448a778-78bb-5565-9b3b-fd4aed03dad0'), metadata=_MetadataReturn(creation_time_unix=1701373868665, last_update_time_unix=None, distance=0.19842731952667236, certainty=None, score=None, explain_score=None, is_consistent=None), properties={'points': 100.0, 'answer': 'Greyhound', 'air_date': '1996-11-15T00:00:00Z', 'round': 'Jeopardy!', 'question': 'A Hibbing, Minn. museum traces the history of this bus company founded there in 1914 using Hupmobiles'}, vector=None, generated="Un musΓ©e Γ Hibbing, dans le Minnesota, retrace l'histoire de cette compagnie de bus fondΓ©e en 1914 en utilisant des Hupmobiles."), _GenerativeObject(uuid=UUID('28ec4a1a-c68e-5cff-b392-f74bf26aef62'), metadata=_MetadataReturn(creation_time_unix=1701373868664, last_update_time_unix=None, distance=0.2006242275238037, certainty=None, score=None, explain_score=None, is_consistent=None), properties={'points': 200.0, 'air_date': '1996-03-26T00:00:00Z', 'answer': 'Harvard', 'round': 'Double Jeopardy!', 'question': "1995 marked the 200th anniversary of this university's Hasty Pudding Club"}, vector=None, generated='1995 a marquΓ© le 200e anniversaire du Hasty Pudding Club de cette universitΓ©.')], generated="The Greyhound bus company, founded in Hibbing, Minn. in 1914, is traced in a museum using Hupmobiles, while Harvard University's Hasty Pudding Club celebrated its 200th anniversary in 1995.")
To limit the response payload, you can specify which properties and metadata to return.
Additionally, to view the response object in a more readable format, you can use the json.dumps()
function as shown below
import json
questions = client.collections.get("JeopardyQuestion")
response = questions.query.fetch_objects(limit=1)
# Print result object properties
for o in response.objects:
print(json.dumps(o.properties, indent=2))
This is the formatted output.
{
"points": 100.0,
"answer": "Jonah",
"air_date": "2001-01-10T00:00:00Z",
"round": "Jeopardy!",
"question": "This prophet passed the time he spent inside a fish offering up prayers"
}
Tab completion in Jupyter notebooksβ
If you use a browser to run the Python client with a Jupyter notebook, press Tab
for code completion while you edit. If you use VSCode to run your Jupyter notebook, press control
+ space
for code completion.
Client releasesβ
This chart matches Weaviate database releases with Weaviate client releases. It lists the most recent database version when each client version was released.
The chart includes point releases for the most recent major and minor versions of the client. Earlier client releases have less detailed version information.
Weaviate Version | Release Date | Python | TypeScript | Go | Java |
---|---|---|---|---|---|
1.21.3 | 2023-09-13 | 3.24.1 | 1.5.0 | 4.10.0 | 4.3.0 |
1.21.2 | 2023-08-30 | 3.23.1 | " | " | " |
1.21.1 | 2023-08-22 | 3.23.0 | " | " | " |
1.21.0 | 2023-08-17 | 3.22.1 | 1.4.0 | 4.9.0 | 4.2.1 |
1.20.0 | 2023-07-06 | 3.22.0 | " | " | 4.2.0 |
1.19.0 | 2023-05-04 | 3.17.0 | 1.1.01 | 4.7.1 | 4.0.1 |
1.18.0 | 2023-03-07 | 3.13.0 | 2.14.5 | 4.6.2 | 3.6.4 |
1.17.0 | 2022-12-20 | 3.9.0 | 2.14.0 | 4.5.0 | 3.5.0 |
1.16.0 | 2022-10-31 | 3.8.0 | 2.13.0 | 4.4.0 | 3.4.0 |
1.15.0 | 2022-09-07 | " | 2.12.0 | 4.3.0 | 3.3.0 |
1.14.0 | 2022-07-07 | 3.6.0 | 2.11.0 | 4.2.0 | 3.2.0 |
1.13.0 | 2022-05-03 | 3.4.2 | 2.9.0 | 4.0.0 | 2.4.0 |
1.12.0 | 2022-04-05 | 3.4.0 | 2.8.0 | 3.0.0 | " |
1.11.0 | 2022-03-14 | 3.2.5 | 2.7.0 | 2.6.0 | 2.3.0 |
1.10.0 | 2022-01-27 | " | 2.5.0 | 2.4.1 | 2.1.1 |
1.9.0 | 2021-12-10 | " | " | 2.4.0 | 2.1.0 |
1.8.0 | 2021-11-30 | " | " | " | " |
1.7.0 | 2021-09-01 | 3.1.1 | 2.4.0 | 2.3.0 | 1.1.0 |
1.6.0 | 2021-08-11 | 2.4.0 | 2.3.0 | 2.2.0 | " |
1.5.0 | 2021-07-13 | " | " | " | " |
1.4.0 | 2021-06-09 | " | " | " | " |
1.3.0 | 2021-04-23 | " | 2.1.0 | 2.1.0 | 1.0.0 |
1.2.0 | 2021-03-15 | 2.2.0 | 2.0.0 | 1.1.0 | - |
1.1.0 | 2021-02-10 | 2.1.0 | " | " | - |
1.0.0 | 2021-01-14 | 2.0.0 | " | " | - |
- The TypeScript client replaced the JavaScript client on 2023-03-17.β©
Change logsβ
For more detailed information on client updates, check the change logs. The logs are hosted here: