Skip to content

Commit 9da3096

Browse files
authored
Merge branch 'main' into dependabot/pip/pytest-asyncio-1.3.0
2 parents e006ed4 + fe354d7 commit 9da3096

12 files changed

Lines changed: 232 additions & 93 deletions

File tree

CONTRIBUTING.md

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,12 @@
11
### Setup
22

3-
We recommend that you use a virtual environment to contribute to the client.
4-
5-
To create a virtual environment, activate it, and install dependencies, run the following shell code:
3+
The development requirements are listed in the `requirements-devel.txt` file. Install them to your virtual environment with:
64

75
```shell
8-
python3 -m venv .venv
9-
source .venv/bin/activate
106
pip install -r requirements-devel.txt
117
```
128

13-
To activate your virtual environment, run `source .venv/bin/activate`.
14-
15-
The newest client versions sometimes require upcoming Weaviate core features. We recommend using Docker (see https://weaviate.io/developers/weaviate/installation/docker-compose) to run a local instance of the `latest Weaviate core <https://hub.docker.com/r/semitechnologies/weaviate/tags>`_ for client development.
9+
The newest client versions sometimes require upcoming Weaviate core features. We recommend using Docker (see https://docs.weaviate.io/deploy/installation-guides/docker-installation) to run a local instance of the `latest Weaviate core <https://hub.docker.com/r/semitechnologies/weaviate/tags>`_ for client development.
1610

1711
#### Installation
1812

@@ -34,10 +28,16 @@ You can install a particular branch directly from GitHub with:
3428
pip install git+https://github.com/weaviate/weaviate-python-client.git@BRANCH_NAME
3529
```
3630

31+
If any static analysis tools such as Pylance fail, try installing the package with:
32+
`--config-settings editable_mode=compat` suffix. (e.g. `pip install -e . --config-settings editable_mode=compat`)
3733

3834
### Testing
3935

40-
> Note: We use [pytest](https://docs.pytest.org) to write tests for new client code. However, many older tests use [unittest](https://docs.python.org/3/library/unittest.html). These commands run the `pytest` and `unittest` tests.
36+
To set up the testing environment, install the test requirements with:
37+
38+
```shell
39+
pip install -r requirements-test.txt
40+
```
4141

4242
There are three kinds of tests:
4343
- Unit tests test individual client components.
@@ -67,9 +67,10 @@ pytest test
6767
> We strongly recommend using [pre-commit](https://pre-commit.com/) to automatically run all linters locally on each commit. Install `pre-commit` on your system, and then enable it with `pre-commit install`.
6868
6969
We use the following tools to ensure a high code quality:
70-
- black (formatter), run with `black $FOLDER_WITH_CHANGES`
71-
- flake8 with plugins. Run with `flake8 $FOLDER_WITH_CHANGES`. Note that all plugins are listed in the `requirements.txt` file and are installed in the first step.
70+
- ruff (formatter), run with `ruff format $FOLDER_WITH_CHANGES`
71+
- flake8 with plugins. Run with `flake8 $FOLDER_WITH_CHANGES`.
7272

73+
Note that all plugins are listed in the `requirements-devel.txt` file and are installed in the first step.
7374

7475
### Creating a Pull Request
7576

RELEASING.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
## How to create releases
2+
3+
### Step 1: Prepare for release
4+
1. Pull latest main
5+
- Merge any pending PRs
6+
2. Determine what the next version should be, following semantic versioning
7+
3. Create a new branch for the changelog
8+
4. Add a changelog entry to `docs/changelog.rst`
9+
- `gh pr list --repo weaviate/weaviate-python-client --state merged --search "merged:>=YYYY-MM-DD"` where `YYYY-MM-DD` is the last release date
10+
- Only add the relevant entries to the changelog
11+
- Examples - [minor release](https://github.com/weaviate/weaviate-python-client/releases/tag/v4.18.0), [patch release](https://github.com/weaviate/weaviate-python-client/releases/tag/v4.16.10)
12+
5. Merge back to main
13+
6. Pull main
14+
15+
### Step 2: Create release
16+
Option 1: With GH CLI
17+
1. `gh release create <VERSION_TAG>` (e.g. `gh release create v4.18.1`)
18+
19+
Option 2: With git + GH web UI
20+
1. git tag VERSION
21+
- `git tag -a v4.18.1 -m "v4.18.1"
22+
2. `git push --tags`
23+
3. Create a release [from the GH repo](https://docs.github.com/en/repositories/releasing-projects-on-github/managing-releases-in-a-repository?tool=webui#creating-a-release)
24+
25+
### Step 3: Monitor pipeline
26+
1. Monitor the CICD pipeline
27+
1. When all tests pass, the release will be pushed to PyPI automatically
28+
29+
### Notes:
30+
- The package version is updated automatically (see setup.cfg)

docs/changelog.rst

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,22 @@
11
Changelog
22
=========
33

4+
5+
Version 4.19.2
6+
--------------
7+
This patch version includes:
8+
- Revert merging #1915; not yet merged into Weaviate server
9+
10+
11+
Version 4.19.1
12+
--------------
13+
This patch version includes:
14+
15+
- Voyage-multimodal-3.5 support in #1915 by @fzowl
16+
- multi2multivec-weaviate support in #1859 by @augustas1
17+
- Internal repo documentation improvements in #1879 by @databyjp
18+
19+
420
Version 4.19.0
521
--------------
622
This minor version includes:

publishing.md

Lines changed: 0 additions & 15 deletions
This file was deleted.

requirements-test.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ pytest-benchmark==5.1.0
55
pytest-profiling==1.8.1
66
coverage==7.10.7
77
pytest-xdist==3.7.0
8-
werkzeug==3.1.4
8+
werkzeug==3.1.5
99
pytest-httpserver==1.1.3
1010
py-spy==0.4.1
1111

test/README.md

Lines changed: 1 addition & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1 @@
1-
# Unit tests for Weaviate Python client
2-
---
3-
Unit tests for weaviate package. Each module should have its own sub-directory in the `test` directory. Each test file should begin with `test_<fine_name>.py` and `test` directory should not be renamed, these are mandatory requirements for the `unittest` to parse and run all unittests.
4-
5-
The `util.py` contains helper functions for unit testing.
6-
7-
---
8-
## Run one file unittest
9-
In order to unit test a single file, you can run the following command:
10-
```
11-
python -m unittest path_to_file_dir.file
12-
```
13-
E.g. if you run it from repo root folder:
14-
```bash
15-
python -m unittest test.gql.test_get -v # -v is optional, -v = verbose
16-
```
17-
## Run whole package unittest
18-
In order to unit test the whole package, you can run the following command:
19-
```bash
20-
python -m unittest -v # -v is optional, -v = verbose
21-
```
22-
23-
# Coverage test
24-
---
25-
Coverage test for weaviate package. Coverage test can be performed using the existing unit test. It runs all the unit tests in order to find which parts of the code have been executed, thus it can be used instead of the Unit test.
26-
Coverage test is performed by the `coverage` package that should be installed with the `development-requirements.txt`. For more information on what and how to run coverage tests visit this [link](https://coverage.readthedocs.io/en/coverage-5.3.1/ "coverage.readthedocs.io").
27-
28-
---
29-
30-
## Run coverage test for one file
31-
Coverage test for one file can be performed using the following command:
32-
```bash
33-
coverage run -m unittest path_to_the_file_dir.file -v # -v is optional, -v = verbose
34-
```
35-
E.g. if you run it from repo root folder:
36-
```bash
37-
coverage run -m unittest test.gql.test_get -v # -v is optional, -v = verbose
38-
```
39-
40-
## Run whole package coverage test
41-
In order to unit test the whole package, you can run the following command:
42-
```bash
43-
coverage run -m unittest -v # -v is optional, -v = verbose
44-
```
45-
## Show coverage report
46-
To get the coverage report run the following command.
47-
```bash
48-
coverage report -m --skip-covered # --skip-covered = skip 100% covered files, -m = show missing lines
49-
```
50-
51-
# Linting
52-
---
53-
Lint the files that are modified before commiting. The linting is done by `pylint`.
54-
55-
To lint a file/module/package run the following command:
56-
```bash
57-
pylint path_to_the_file_or_module
58-
```
59-
E.g. if you run it from repo root folder:
60-
```bash
61-
pylint weaviate # for the whole package
62-
pylint weaviate/batch # for the module batch
63-
pylint weaviate/connect/connection.py # for the connection.py file
64-
```
1+
Refer to [CONTRIBUTING.md](CONTRIBUTING.md) file for instructions on how to run the tests.

test/collection/test_config.py

Lines changed: 104 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from datetime import timedelta
12
from typing import List, Union
23

34
import pytest
@@ -11,6 +12,7 @@
1112
Vectorizers,
1213
_CollectionConfigCreate,
1314
_GenerativeProvider,
15+
_ObjectTTLConfig,
1416
_RerankerProvider,
1517
_VectorizerConfigCreate,
1618
)
@@ -19,7 +21,6 @@
1921
Multi2VecField,
2022
VectorDistances,
2123
)
22-
2324
from weaviate.collections.classes.config_vectors import _VectorConfigCreate
2425

2526
DEFAULTS = {
@@ -2118,6 +2119,24 @@ def test_config_with_named_vectors(
21182119
}
21192120
},
21202121
),
2122+
(
2123+
[Configure.MultiVectors.multi2vec_weaviate(name="test", image_field="prop")],
2124+
{
2125+
"test": {
2126+
"vectorizer": {
2127+
"multi2multivec-weaviate": {
2128+
"imageFields": ["prop"],
2129+
}
2130+
},
2131+
"vectorIndexConfig": {
2132+
"multivector": {
2133+
"enabled": True,
2134+
},
2135+
},
2136+
"vectorIndexType": "hnsw",
2137+
}
2138+
},
2139+
),
21212140
(
21222141
[Configure.Vectors.text2vec_gpt4all(name="test", source_properties=["prop"])],
21232142
{
@@ -2502,3 +2521,87 @@ def test_config_with_vectors(vector_config: List[_VectorConfigCreate], expected:
25022521
"class": "Test",
25032522
"vectorConfig": expected,
25042523
}
2524+
2525+
2526+
TEST_OBJECT_TTL_CONFIG_TO_DICT_PARAMETERS = [
2527+
# delete_by_creation_time
2528+
(
2529+
_ObjectTTLConfig(
2530+
enabled=True,
2531+
time_to_live=timedelta(hours=24),
2532+
filter_expired_objects=True,
2533+
delete_on="creationTime",
2534+
),
2535+
{
2536+
"enabled": True,
2537+
"timeToLive": 86400,
2538+
"filterExpiredObjects": True,
2539+
"deleteOn": "creationTime",
2540+
},
2541+
),
2542+
# delete_by_update_time
2543+
(
2544+
_ObjectTTLConfig(
2545+
enabled=True,
2546+
time_to_live=timedelta(days=7),
2547+
filter_expired_objects=False,
2548+
delete_on="updateTime",
2549+
),
2550+
{
2551+
"enabled": True,
2552+
"timeToLive": 604800,
2553+
"filterExpiredObjects": False,
2554+
"deleteOn": "updateTime",
2555+
},
2556+
),
2557+
# delete_by_date_property
2558+
(
2559+
_ObjectTTLConfig(
2560+
enabled=True,
2561+
time_to_live=timedelta(hours=1, minutes=30),
2562+
filter_expired_objects=True,
2563+
delete_on="releaseDate",
2564+
),
2565+
{
2566+
"enabled": True,
2567+
"timeToLive": 5400,
2568+
"filterExpiredObjects": True,
2569+
"deleteOn": "releaseDate",
2570+
},
2571+
),
2572+
# None time_to_live
2573+
(
2574+
_ObjectTTLConfig(
2575+
enabled=True,
2576+
time_to_live=None,
2577+
filter_expired_objects=False,
2578+
delete_on="creationTime",
2579+
),
2580+
{
2581+
"enabled": True,
2582+
"filterExpiredObjects": False,
2583+
"deleteOn": "creationTime",
2584+
},
2585+
),
2586+
# negative offset (delete_by_date_property with offset before date)
2587+
(
2588+
_ObjectTTLConfig(
2589+
enabled=True,
2590+
time_to_live=timedelta(seconds=-3600),
2591+
filter_expired_objects=True,
2592+
delete_on="eventDate",
2593+
),
2594+
{
2595+
"enabled": True,
2596+
"timeToLive": -3600,
2597+
"filterExpiredObjects": True,
2598+
"deleteOn": "eventDate",
2599+
},
2600+
),
2601+
]
2602+
2603+
2604+
@pytest.mark.parametrize("ttl_config,expected", TEST_OBJECT_TTL_CONFIG_TO_DICT_PARAMETERS)
2605+
def test_object_ttl_config_to_dict(ttl_config: _ObjectTTLConfig, expected: dict) -> None:
2606+
"""Test that _ObjectTTLConfig.to_dict() properly converts timedelta to seconds."""
2607+
assert ttl_config.to_dict() == expected

weaviate/backup/backup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ class BackupStatusReturn(BaseModel):
8484
status: BackupStatus
8585
path: str
8686
backup_id: str = Field(alias="id")
87+
size: float = Field(default=0)
8788

8889

8990
class BackupReturn(BackupStatusReturn):

weaviate/collections/classes/config_base.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from abc import abstractmethod
22
from dataclasses import dataclass
3+
from datetime import timedelta
34
from enum import Enum
45
from typing import Any, Dict, cast
56

@@ -59,6 +60,9 @@ def to_dict(self) -> dict:
5960
if isinstance(v, Enum):
6061
out[key] = v.value
6162
continue
63+
if isinstance(v, timedelta):
64+
out[key] = int(v.total_seconds())
65+
continue
6266
if isinstance(v, dict):
6367
out[key] = {
6468
k: v.to_dict() if isinstance(v, _ConfigBase) else v for k, v in v.items()

weaviate/collections/classes/config_vectorizers.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@
7575
WeaviateModel: TypeAlias = Literal[
7676
"Snowflake/snowflake-arctic-embed-l-v2.0", "Snowflake/snowflake-arctic-embed-m-v1.5"
7777
]
78+
WeaviateMultimodalModel: TypeAlias = Literal["ModernVBERT/colmodernvbert"]
7879

7980

8081
class Vectorizers(str, Enum):
@@ -131,6 +132,7 @@ class Vectorizers(str, Enum):
131132
MULTI2VEC_COHERE = "multi2vec-cohere"
132133
MULTI2VEC_JINAAI = "multi2vec-jinaai"
133134
MULTI2MULTI_JINAAI = "multi2multivec-jinaai"
135+
MULTI2MULTI_WEAVIATE = "multi2multivec-weaviate"
134136
MULTI2VEC_BIND = "multi2vec-bind"
135137
MULTI2VEC_PALM = "multi2vec-palm" # change to google once 1.27 is the lowest supported version
136138
MULTI2VEC_VOYAGEAI = "multi2vec-voyageai"
@@ -513,6 +515,20 @@ def _to_dict(self) -> Dict[str, Any]:
513515
return ret_dict
514516

515517

518+
class _Multi2MultiVecWeaviateConfig(_Multi2VecBase):
519+
vectorizer: Union[Vectorizers, _EnumLikeStr] = Field(
520+
default=Vectorizers.MULTI2MULTI_WEAVIATE, frozen=True, exclude=True
521+
)
522+
baseURL: Optional[AnyHttpUrl]
523+
model: Optional[str]
524+
525+
def _to_dict(self) -> Dict[str, Any]:
526+
ret_dict = super()._to_dict()
527+
if self.baseURL is not None:
528+
ret_dict["baseURL"] = self.baseURL.unicode_string()
529+
return ret_dict
530+
531+
516532
class _Multi2VecClipConfig(_Multi2VecBase):
517533
vectorizer: Union[Vectorizers, _EnumLikeStr] = Field(
518534
default=Vectorizers.MULTI2VEC_CLIP, frozen=True, exclude=True

0 commit comments

Comments
 (0)