Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Python 3.13 #227

Open
wants to merge 19 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
python-version: "3.10"

- name: Install poetry
run: pip install urllib3==1.26.15 poetry==1.8.3
run: pip install urllib3==1.26.15 poetry==1.8.5

- name: Load cached venv
id: cached-poetry-dependencies
Expand All @@ -43,7 +43,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: [ "3.9", "3.10", "3.11", "3.12" ]
python-version: [ "3.9", "3.10", "3.11", "3.12", "3.13" ]

steps:
- uses: actions/checkout@v4
Expand All @@ -54,7 +54,7 @@ jobs:
python-version: ${{ matrix.python-version }}

- name: Install poetry
run: pip install urllib3==1.26.15 poetry==1.4.0
run: pip install urllib3==1.26.15 poetry==1.8.5

- name: Load cached venv
id: cached-poetry-dependencies
Expand Down
10 changes: 5 additions & 5 deletions .readthedocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,6 @@ build:
jobs:
pre_build:
- cp -r examples docs/source/
post_install:
- pip install --no-cache-dir poetry
- poetry export -f requirements.txt -o requirements.txt -E all --without-hashes
feldlime marked this conversation as resolved.
Show resolved Hide resolved
- pip install --no-cache-dir -r requirements.txt

sphinx:
builder: html
Expand All @@ -19,7 +15,11 @@ sphinx:

python:
install:
- requirements: docs/requirements.txt
- method: pip
path: .
extra_requirements:
- docs
- all

formats:
- pdf
845 changes: 796 additions & 49 deletions poetry.lock

Large diffs are not rendered by default.

34 changes: 23 additions & 11 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ classifiers = [
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3",
"Topic :: Software Development :: Libraries :: Python Modules",
"Intended Audience :: Science/Research",
Expand All @@ -52,13 +53,20 @@ packages = [


[tool.poetry.dependencies]
python = ">=3.9, <3.13"
python = ">=3.9, <3.14"
numpy = [
{version = ">=1.22, <2.0.0", python = "<3.12"},
{version = ">=1.26, <2.0.0", python = "3.12"} # numpy <1.26 fails to install on Python 3.12
{version = ">=1.26, <2.0.0", python = "3.12"}, # numpy <1.26 fails to install on Python 3.12
{version = ">=2.1.0, <3.0.0", python = ">=3.13"} # numpy <2.1 fails to install on Python 3.13
]
pandas = [
{version = ">=1.5.0, <3.0.0", python = "<3.13"},
{version = ">=2.2.3, <3.0.0", python = ">=3.13"} # pandas <2.2.3 fails to install on Python 3.13
]
scipy = [
{version = "^1.10.1, <1.13", python = "<3.13"}, # in 1.13 were introduced significant changes breaking our logic
chezou marked this conversation as resolved.
Show resolved Hide resolved
{version = ">=1.14.1, <2.0.0", python = ">=3.13"} # scipy <1.13 fails to install on Python 3.13
]
pandas = ">=1.5.0, <3.0.0"
scipy = "^1.10.1, <1.13" # in 1.13 were introduced significant changes breaking our logic
tqdm = "^4.27.0"
implicit = "^0.7.1"
attrs = ">=19.1.0,<24.0.0"
Expand All @@ -76,15 +84,19 @@ nmslib-metabrainz = {version = "^2.1.3", python = ">=3.11, <3.13", optional = tr

# The latest torch version available for MacOSX + x86_64 is 2.2.2
torch = [
{version = ">=1.6.0, <2.3.0", markers = "sys_platform == 'darwin' and platform_machine == 'x86_64'", optional = true},
{version = ">=1.6.0, <3.0.0", optional = true}
{version = ">=1.6.0, <2.3.0", python = "<3.13", markers = "sys_platform == 'darwin' and platform_machine == 'x86_64'", optional = true},
{version = ">=1.6.0, <3.0.0", python = "<3.13", optional = true},
]
pytorch-lightning = {version = ">=1.6.0, <3.0.0", optional = true}
pytorch-lightning = {version = ">=1.6.0, <3.0.0", python = "<3.13", optional = true}

ipywidgets = {version = ">=7.7,<8.2", optional = true}
plotly = {version="^5.22.0", optional = true}
nbformat = {version = ">=4.2.0", optional = true}

sphinx = {version = "5.1.1", optional = true}
nbsphinx = {version = "0.8.9", optional = true}
sphinx-rtd-theme = {version = "1.0.0", optional = true}


[tool.poetry.extras]
lightfm = ["rectools-lightfm"]
Expand All @@ -97,16 +109,17 @@ all = [
"torch", "pytorch-lightning",
"ipywidgets", "plotly", "nbformat",
]
docs = ["sphinx", "nbsphinx", "sphinx-rtd-theme"]
chezou marked this conversation as resolved.
Show resolved Hide resolved


[tool.poetry.group.dev.dependencies]
black = "24.4.2"
black = "24.10.0"
isort = "5.13.2"
pylint = "3.1.0"
mypy = "1.13.0"
flake8 = "7.0.0"
bandit = "1.7.8"
pytest = "8.1.1"
pytest = "8.3.3"
radon = "6.0.1"
coverage = "7.5.0"
autopep8 = "2.1.0"
Expand All @@ -119,10 +132,9 @@ pytest-mock = "3.14.0"
click = "8.1.7"
gitpython = "3.1.43"


[tool.black]
line-length = 120
target-version = ["py39", "py310", "py311", "py312"]
target-version = ["py39", "py310", "py311", "py312", "py313"]


[build-system]
Expand Down
3 changes: 2 additions & 1 deletion rectools/metrics/intersection.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from typing import Dict, Hashable, Optional, Union
from collections.abc import Hashable
from typing import Dict, Optional, Union

import attr
import numpy as np
Expand Down
17 changes: 15 additions & 2 deletions tests/dataset/test_torch_dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,28 @@
# limitations under the License.

# pylint: disable=attribute-defined-outside-init,consider-using-enumerate
import sys

import numpy as np
import pandas as pd
import pytest
import torch

try:
import torch
except ImportError:
pass

from scipy import sparse

from rectools.columns import Columns
from rectools.dataset import Dataset
from rectools.dataset.torch_datasets import DSSMItemDataset, DSSMTrainDataset, DSSMUserDataset

try:
from rectools.dataset.torch_datasets import DSSMItemDataset, DSSMTrainDataset, DSSMUserDataset
except ModuleNotFoundError:
pass

pytestmark = pytest.mark.skipif(sys.version_info >= (3, 13), reason="`torch` is not compatible with Python >= 3.13")


class WithFixtures:
Expand Down
29 changes: 25 additions & 4 deletions tests/models/test_dssm.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +12,46 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import sys
import typing as tp

import numpy as np
import pandas as pd
import pytest
from lightning_fabric import seed_everything

try:
from lightning_fabric import seed_everything
except ImportError:
pass

try:
import pytorch_lightning # noqa # pylint: disable=unused-import

filter_decorator = pytest.mark.filterwarnings("ignore::pytorch_lightning.utilities.warnings.PossibleUserWarning")
chezou marked this conversation as resolved.
Show resolved Hide resolved
except ImportError:

def filter_decorator(func): # type: ignore
return func


from rectools.columns import Columns
from rectools.dataset import Dataset
from rectools.exceptions import NotFittedError
from rectools.models import DSSMModel
from rectools.models.dssm import DSSM

try:
from rectools.models import DSSMModel
from rectools.models.dssm import DSSM
except ModuleNotFoundError:
pass
from rectools.models.vector import ImplicitRanker
from tests.models.utils import assert_dumps_loads_do_not_change_model, assert_second_fit_refits_model

from .data import INTERACTIONS

pytestmark = pytest.mark.skipif(sys.version_info >= (3, 13), reason="`torch` is not compatible with Python >= 3.13")


@pytest.mark.filterwarnings("ignore::pytorch_lightning.utilities.warnings.PossibleUserWarning")
@filter_decorator
@pytest.mark.filterwarnings("ignore::UserWarning")
class TestDSSMModel:
def setup_method(self) -> None:
Expand Down
28 changes: 24 additions & 4 deletions tests/models/test_implicit_knn.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ def test_with_whitelist(self, dataset: Dataset, filter_viewed: bool, expected: p
pd.DataFrame(
{
Columns.TargetItem: [11, 11, 12, 12],
Columns.Item: [12, 15, 11, 14],
Columns.Item: [12, 14, 11, 14],
Columns.Rank: [1, 2, 1, 2],
}
),
Expand All @@ -154,10 +154,30 @@ def test_with_whitelist(self, dataset: Dataset, filter_viewed: bool, expected: p
),
),
)
def test_i2i(
self, dataset: Dataset, filter_itself: bool, whitelist: tp.Optional[np.ndarray], expected: pd.DataFrame
) -> None:
def test_i2i(self, filter_itself: bool, whitelist: tp.Optional[np.ndarray], expected: pd.DataFrame) -> None:
base_model = TFIDFRecommender(K=5, num_threads=2)
# Recreate dataset to prevent same co-occurrence count between (11, 14) and (11, 15)
# which leads to different results in the test in Python 3.13
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean for the default dataset the results in python 3.8-3.12 and 3.13 are different?
Do you have any idea why is this happening?
Probably the problem is not with the python itself, but with some of the dependencies?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the behavior of implicit ItemKNN changes due to the changes in the similarity matrix.

Considering the cosign similarity, co-occurrence between 11-14 and 11-15 are both 2 times, thus it causes flakiness.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let us take some time to examine this case carefully

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@feldlime Do you need more time?

I think the original dataset can be a bit flaky because the cosine similarities for both two are the same.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Didn't have time to work on this, I'll take another 2-3 weeks

interactions = pd.DataFrame(
[
[10, 11],
[10, 12],
[10, 14],
[20, 11],
[20, 12],
[20, 13],
[30, 11],
[30, 12],
[30, 14],
[40, 11],
[40, 15],
[40, 17],
],
columns=Columns.UserItem,
)
interactions[Columns.Weight] = 1
interactions[Columns.Datetime] = "2021-09-09"
dataset = Dataset.construct(interactions)
model = ImplicitItemKNNWrapperModel(model=base_model).fit(dataset)
actual = model.recommend_to_items(
target_items=np.array([11, 12]),
Expand Down
2 changes: 2 additions & 0 deletions tests/models/test_serialization.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import sys
import typing as tp
from tempfile import NamedTemporaryFile

Expand Down Expand Up @@ -155,6 +156,7 @@ def test_fails_on_incorrect_model_cls(self, mode: tp.Literal["pydantic", "dict"]
with pytest.raises(ValidationError):
model_from_config(config)

@pytest.mark.skipif(sys.version_info >= (3, 13), reason="`torch` is not compatible with Python 3.13")
@pytest.mark.parametrize("model_cls", ("rectools.models.DSSMModel", DSSMModel))
def test_fails_on_model_cls_without_from_config_support(self, model_cls: tp.Any) -> None:
config = {"cls": model_cls}
Expand Down
13 changes: 11 additions & 2 deletions tests/tools/test_ann.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,22 @@
# limitations under the License.

import pickle
from typing import Callable, Dict, Hashable, List, Union
import sys
from collections.abc import Hashable
from typing import Callable, Dict, List, Union

import numpy as np
import pytest

from rectools.dataset import IdMap
from rectools.tools import ItemToItemAnnRecommender, UserToItemAnnRecommender

try:
from rectools.tools import ItemToItemAnnRecommender, UserToItemAnnRecommender
except ImportError:
pass


pytestmark = pytest.mark.skipif(sys.version_info >= (3, 13), reason="`nsmlib` is not compatible with Python >= 3.13")


class TestItemToItemAnnRecommender:
Expand Down
Loading