Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
78d381e
data: make lenskit.data._items private (#947)
mdekstrand Apr 6, 2026
01a0f92
data: make data.adapt private + fix class name (#947)
mdekstrand Apr 6, 2026
c8cffd9
data: make arrow private
mdekstrand Apr 6, 2026
9b29cbe
data: use modern types for arrow
mdekstrand Apr 6, 2026
8e4973e
data: make attributes private
mdekstrand Apr 6, 2026
26cacba
data: rename AttributeSet to EntityAttribute (#946)
mdekstrand Apr 6, 2026
69bed8b
make batches private
mdekstrand Apr 6, 2026
d02f41a
data: rename BatchIter to BatchedRange
mdekstrand Apr 6, 2026
a6521f0
data: make builder private
mdekstrand Apr 6, 2026
ff2c051
data: make checks private
mdekstrand Apr 6, 2026
64ea0c7
data: make container private
mdekstrand Apr 6, 2026
a199aa8
data: make dataset private (#947)
mdekstrand Apr 6, 2026
abb274c
data: clean up matrix + don't re-export matrix types
mdekstrand Apr 6, 2026
5204e13
data: make mtarray private
mdekstrand Apr 6, 2026
032b1a8
data: remove MTArray exports
mdekstrand Apr 6, 2026
db09a4b
data: make query private
mdekstrand Apr 6, 2026
d28b9f2
data: make entities private
mdekstrand Apr 6, 2026
b32056e
data: make relationships private (#947)
mdekstrand Apr 6, 2026
0654359
data: make summary private
mdekstrand Apr 6, 2026
125de3d
data: make vocab private (#947)
mdekstrand Apr 6, 2026
2397678
data: make collection private
mdekstrand Apr 6, 2026
de54f99
data: fix docs and type for GenericKey type
mdekstrand Apr 6, 2026
6291e2e
data: remove excess T type
mdekstrand Apr 6, 2026
959e56b
data: clean up some more types
mdekstrand Apr 6, 2026
ed7417c
data: clean up builder types
mdekstrand Apr 6, 2026
90050b1
parallel/ray: remove extraneous type var
mdekstrand Apr 6, 2026
5db2250
data: export DataContainer
mdekstrand Apr 6, 2026
b4b1795
data: clean up types a bit
mdekstrand Apr 6, 2026
c7e65f0
set minimum Python version
mdekstrand Apr 6, 2026
8cec799
update mindep
mdekstrand Apr 6, 2026
95d17a4
set package python version
mdekstrand Apr 6, 2026
20f0721
min python3.12
mdekstrand Apr 6, 2026
8f687b6
increase docs python
mdekstrand Apr 6, 2026
6b2ee3f
fix test py ver
mdekstrand Apr 6, 2026
86d9f25
lint pyver
mdekstrand Apr 6, 2026
6c3ec66
data: use old-style type var for UIPair
mdekstrand Apr 6, 2026
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
2 changes: 1 addition & 1 deletion .github/workflows/check-sources.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ jobs:
- name: 🕶️ Install uv
uses: astral-sh/setup-uv@v7
with:
python-version: "3.12"
python-version: "3.14"
activate-environment: true

- name: Install packages
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
- name: 🕶️ Install uv
uses: astral-sh/setup-uv@v7
with:
python-version: "3.12"
python-version: "3.14"
activate-environment: true

- name: 📦 Set up Python dependencies
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
- name: 🕶️ Install uv
uses: astral-sh/setup-uv@v7
with:
python-version: "3.12"
python-version: "3.12.5"
activate-environment: true

- name: Install dependencies
Expand Down Expand Up @@ -100,7 +100,7 @@ jobs:

- uses: actions/setup-python@v5
with:
python-version: "3.12"
python-version: "3.12.5"
architecture: ${{matrix.plat.pyarch}}

- name: Build wheels
Expand Down Expand Up @@ -145,7 +145,7 @@ jobs:
- name: 🕶️ Install uv
uses: astral-sh/setup-uv@v7
with:
python-version: "3.12"
python-version: "3.12.5"
activate-environment: true

- name: Set up Rclone configuration
Expand Down
14 changes: 7 additions & 7 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
fail-fast: false
matrix:
python:
- "3.12"
- "3.12.5"
- "3.13"
- "3.14"
- "3.14t"
Expand Down Expand Up @@ -118,7 +118,7 @@ jobs:

- name: 📦 Set up Python dependencies
run: |
uv sync -p 3.12
uv sync -p 3.12.5

- name: 🏃🏻‍➡️ Test LKPY
run: |
Expand Down Expand Up @@ -157,7 +157,7 @@ jobs:
- name: 🕶️ Install uv
uses: astral-sh/setup-uv@v7
with:
python-version: "3.12"
python-version: "3.12.5"
activate-environment: true

- name: 📦 Set up Python dependencies
Expand Down Expand Up @@ -209,7 +209,7 @@ jobs:
- name: 🕶️ Install uv
uses: astral-sh/setup-uv@v7
with:
python-version: "3.12"
python-version: "3.12.5"
activate-environment: true

- name: 📦 Set up Python dependencies
Expand Down Expand Up @@ -263,7 +263,7 @@ jobs:
- name: 🕶️ Install uv
uses: astral-sh/setup-uv@v7
with:
python-version: "3.12"
python-version: "3.12.5"
activate-environment: true

- name: 📦 Set up Python dependencies (Unix)
Expand Down Expand Up @@ -326,7 +326,7 @@ jobs:
- name: 🕶️ Install uv
uses: astral-sh/setup-uv@v7
with:
python-version: "3.12"
python-version: "3.12.5"
activate-environment: true

- name: 📦 Set up Python dependencies (Unix)
Expand Down Expand Up @@ -399,7 +399,7 @@ jobs:
- name: 🕶️ Install uv
uses: astral-sh/setup-uv@v7
with:
python-version: "3.12"
python-version: "3.12.5"
activate-environment: true

- name: 📦 Set up Python dependencies
Expand Down
9 changes: 7 additions & 2 deletions docs/releases/2026.rst
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,13 @@ Breaking Changes
- Many submodules (such as most modules under :mod:`lenskit.pipeline`) have been
renamed to be private modules. Code importing from their original locations
will need to be updated to import from the higher-level module (:issue:`947`).
- LensKit now requires Python 3.12 or newer, along with NumPy 2.x, Pandas 2.3 or
newer, and SciPy 1.13 or newer (see :ref:`dep-policy`, :pr:`954`).
- The ``AttributeSet`` class has been renamed to
:class:`~lenskit.data.EntityAttribute` (:issue:`946`), to better clarify its
design and role.
- LensKit now requires Python 3.12.5 or newer, along with NumPy 2.x, Pandas 2.3
or newer, and SciPy 1.13 or newer (see :ref:`dep-policy`, :pr:`954`). Earlier
versions of Python 3.12 have a bug in the standard library that affects
LensKit.
- We no longer publish 32-bit binary wheels.
- Removed ``DecomposedMetric``, as the :class:`~lenskit.metrics.Metric` interface
is now decomposed. All metrics based on listwise measurements or intermediate
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ classifiers = [
"Operating System :: OS Independent",
"Intended Audience :: Science/Research",
]
requires-python = ">= 3.12"
requires-python = ">= 3.12.5"
readme = "README.md"
license = "MIT"
license-files = ["LICENSE.md"]
Expand Down
2 changes: 1 addition & 1 deletion src/lenskit/basic/composite.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

import numpy as np

from lenskit.data.items import ItemList
from lenskit.data import ItemList
from lenskit.pipeline import Component, Lazy

_logger = logging.getLogger(__name__)
Expand Down
3 changes: 1 addition & 2 deletions src/lenskit/basic/history.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@
import pandas as pd
from typing_extensions import override

from lenskit.data import Dataset, ItemList, QueryInput, RecQuery
from lenskit.data.dataset import MatrixRelationshipSet
from lenskit.data import Dataset, ItemList, MatrixRelationshipSet, QueryInput, RecQuery
from lenskit.diagnostics import DataError
from lenskit.logging import get_logger, trace
from lenskit.pipeline import Component
Expand Down
3 changes: 1 addition & 2 deletions src/lenskit/basic/random.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@
import numpy as np
from pydantic import BaseModel

from lenskit.data import ItemList
from lenskit.data.query import QueryInput, RecQuery
from lenskit.data import ItemList, QueryInput, RecQuery
from lenskit.pipeline import Component
from lenskit.random import DerivableSeed, RNGFactory, derivable_rng

Expand Down
4 changes: 2 additions & 2 deletions src/lenskit/cli/data/describe.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@
from rich.console import Console
from rich.markdown import Markdown

from lenskit.data import Dataset
from lenskit.data._summary import save_stats
from lenskit.data.amazon import load_amazon_ratings
from lenskit.data.dataset import Dataset
from lenskit.data.movielens import load_movielens
from lenskit.data.summary import save_stats
from lenskit.logging import get_logger

_log = get_logger(__name__)
Expand Down
2 changes: 1 addition & 1 deletion src/lenskit/cli/data/split.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

import click

from lenskit.data.dataset import Dataset
from lenskit.data import Dataset
from lenskit.logging import get_logger
from lenskit.splitting import sample_records, split_global_time, split_temporal_fraction

Expand Down
3 changes: 1 addition & 2 deletions src/lenskit/cli/data/subset.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@

import click

from lenskit.data import ItemListCollection
from lenskit.data.dataset import Dataset
from lenskit.data import Dataset, ItemListCollection
from lenskit.logging import get_logger
from lenskit.random import random_generator

Expand Down
41 changes: 20 additions & 21 deletions src/lenskit/data/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,40 +12,41 @@

from lenskit.diagnostics import FieldError

from .adapt import from_interactions_df
from .amazon import load_amazon_ratings
from .attributes import AttributeSet
from .batches import BatchIter
from .builder import DatasetBuilder
from .collection import (
from ._adapt import from_interactions_df
from ._attributes import EntityAttribute
from ._batches import BatchedRange
from ._builder import DatasetBuilder
from ._collection import (
GenericKey,
ItemListCollection,
ItemListCollector,
ListILC,
MutableItemListCollection,
QueryIDKey,
UserIDKey,
key_dict,
)
from .dataset import Dataset, EntitySet, MatrixRelationshipSet, RelationshipSet
from .items import ItemList
from .matrix import COOStructure, CSRStructure
from ._container import DataContainer
from ._dataset import Dataset
from ._entities import EntitySet
from ._items import ItemList
from ._query import QueryInput, QueryItemSource, RecQuery
from ._relationships import MatrixRelationshipSet, RelationshipSet
from ._vocab import Vocabulary
from .amazon import load_amazon_ratings
from .movielens import load_movielens, load_movielens_df
from .msweb import load_ms_web
from .mtarray import MTArray, MTFloatArray, MTGenericArray, MTIntArray
from .query import QueryInput, RecQuery
from .types import ID, NPID, FeedbackType
from .vocab import Vocabulary

__all__ = [
"Dataset",
"DatasetBuilder",
"DataContainer",
"EntitySet",
"RelationshipSet",
"MatrixRelationshipSet",
"AttributeSet",
"DatasetBuilder",
"EntityAttribute",
"FieldError",
"CSRStructure",
"COOStructure",
"from_interactions_df",
"ID",
"NPID",
Expand All @@ -58,16 +59,14 @@
"UserIDKey",
"QueryIDKey",
"GenericKey",
"key_dict",
"load_movielens",
"load_movielens_df",
"load_amazon_ratings",
"load_ms_web",
"MTArray",
"MTFloatArray",
"MTGenericArray",
"MTIntArray",
"Vocabulary",
"RecQuery",
"QueryInput",
"BatchIter",
"QueryItemSource",
"BatchedRange",
]
22 changes: 10 additions & 12 deletions src/lenskit/data/adapt.py → src/lenskit/data/_adapt.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,25 +18,18 @@
Iterable,
Literal,
Optional,
TypeAlias,
TypeVar,
)

import numpy as np
import pandas as pd

from .builder import DatasetBuilder
from .dataset import Dataset
from ._builder import DatasetBuilder
from ._dataset import Dataset
from ._vocab import Vocabulary
from .types import ID, AliasedColumn, Column, IDSequence
from .vocab import Vocabulary

DF_FORMAT: TypeAlias = Literal["numpy", "pandas", "torch"]
MAT_FORMAT: TypeAlias = Literal["scipy", "torch", "pandas", "structure"]
MAT_AGG: TypeAlias = Literal["count", "sum", "mean", "first", "last"]
LAYOUT: TypeAlias = Literal["csr", "coo"]
ACTION_FIELDS: TypeAlias = Literal["ratings", "timestamps"] | str
type ACTION_FIELDS = Literal["ratings", "timestamps"] | str

K = TypeVar("K")
_log = logging.getLogger(__name__)


Expand Down Expand Up @@ -165,7 +158,12 @@ def from_interactions_df(
dsb.add_entities("item", items)

dsb.add_interactions(
"rating", df, entities=["user", "item"], missing=missing, allow_repeats=False, default=True
class_name,
df,
entities=["user", "item"],
missing=missing,
allow_repeats=False,
default=True,
)

return dsb.build()
Expand Down
30 changes: 15 additions & 15 deletions src/lenskit/data/arrow.py → src/lenskit/data/_arrow.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,24 @@
# SPDX-License-Identifier: MIT

"""
Arryw utility functions.
Arrow utility functions.
"""

from functools import partial
from typing import Any

import numpy as np
import pyarrow as pa
import pyarrow.compute as pc
import torch
from typing_extensions import Callable, Literal, TypeAlias, TypeVar, overload
from typing_extensions import Callable, Literal, overload

from .mtarray import MTArray
from ._mtarray import MTArray

A = TypeVar("A", bound=pa.Array, default=pa.Array)
Selector: TypeAlias = Callable[[MTArray | A | None], A | None]
type Selector[A] = Callable[[MTArray | A | None], A | None]


def get_indexer(sel) -> Selector:
def get_indexer(sel) -> Selector[Any]:
"""
Get a selector that will apply the specified indexer. This allows
one indexer to be applied to multiple arrays.
Expand Down Expand Up @@ -62,10 +62,10 @@ def arrow_to_format(array: pa.Array, format: Literal["arrow", "numpy", "torch"])


@overload
def arrow_slice(sel: slice, array: MTArray | A) -> A: ...
def arrow_slice[A](sel: slice, array: MTArray | A) -> A: ...
@overload
def arrow_slice(sel: slice, array: MTArray | A | None) -> A | None: ...
def arrow_slice(sel: slice, array: MTArray | A | None) -> A | None:
def arrow_slice[A](sel: slice, array: MTArray | A | None) -> A | None: ...
def arrow_slice[A](sel: slice, array: MTArray | A | None) -> A | None:
"""
Slice an Arrow array.
"""
Expand All @@ -90,10 +90,10 @@ def arrow_slice(sel: slice, array: MTArray | A | None) -> A | None:


@overload
def arrow_take(sel: pa.Int32Array, array: MTArray | A) -> A: ...
def arrow_take[A](sel: pa.Int32Array, array: MTArray | A) -> A: ...
@overload
def arrow_take(sel: pa.Int32Array, array: MTArray | A | None) -> A | None: ...
def arrow_take(sel: pa.Int32Array, array: MTArray | A | None) -> A | None:
def arrow_take[A](sel: pa.Int32Array, array: MTArray | A | None) -> A | None: ...
def arrow_take[A](sel: pa.Int32Array, array: MTArray | A | None) -> A | None:
"""
Select from an Arrow array by integer indices.
"""
Expand All @@ -107,10 +107,10 @@ def arrow_take(sel: pa.Int32Array, array: MTArray | A | None) -> A | None:


@overload
def arrow_filter(sel: pa.BooleanArray, array: MTArray | A) -> A: ...
def arrow_filter[A](sel: pa.BooleanArray, array: MTArray | A) -> A: ...
@overload
def arrow_filter(sel: pa.BooleanArray, array: MTArray | A | None) -> A | None: ...
def arrow_filter(sel: pa.BooleanArray, array: MTArray | A | None) -> A | None:
def arrow_filter[A](sel: pa.BooleanArray, array: MTArray | A | None) -> A | None: ...
def arrow_filter[A](sel: pa.BooleanArray, array: MTArray | A | None) -> A | None:
"""
Select from an Arrow array by integer indices.
"""
Expand Down
Loading
Loading