Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions kernels-data/bindings/python/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ crate-type = ["cdylib"]

[dependencies]
pyo3 = { version = "0.26", features = ["abi3", "abi3-py38"] }
serde_json = "1"

[dependencies.kernels-data]
path = "../.."
Expand Down
271 changes: 271 additions & 0 deletions kernels-data/bindings/python/kernels_data.pyi
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
"""Type stubs for kernels_data module."""

import os
from collections.abc import Iterator
from enum import Enum
from pathlib import Path
from typing import Optional, final

__all__ = [
Expand All @@ -14,9 +16,14 @@ __all__ = [
"GitStatus",
"KernelBuilderVersion",
"KernelDependency",
"KernelLock",
"KernelPaths",
"KernelLocks",
"KernelName",
"KernelVersion",
"Metadata",
"NixKernelLock",
"NixKernelLocks",
"Digest",
"DigestViolation",
"DigestValidationError",
Expand Down Expand Up @@ -326,6 +333,270 @@ class KernelDependency:
def __eq__(self, value: object, /) -> bool: ...
def __hash__(self) -> int: ...

@final
class KernelLock:
"""A locked kernel revision."""

def __new__(cls, commit: str) -> "KernelLock":
"""Construct a lock from a commit.

Raises:
ValueError: If `commit` is not a full git object id.
"""
...

@property
def commit(self) -> str:
"""Locked commit of the kernel, as lowercase hexadecimal digits."""
...

@staticmethod
def from_json(s: str) -> "KernelLock":
"""Parse a `KernelLock` from a JSON string.

Raises:
ValueError: If the JSON cannot be parsed.
"""
...

def to_json(self) -> str:
"""Serialize the lock to a pretty-printed JSON string.

Raises:
ValueError: If the lock cannot be serialized.
"""
...

def __repr__(self) -> str: ...
def __eq__(self, value: object, /) -> bool: ...
def __hash__(self) -> int: ...

@final
class KernelLocks:
"""Multiple kernel locks keyed by the dependency they resolve.

Behaves as a read-only mapping from `KernelDependency` to `KernelLock`.
"""

def __new__(cls, locks: dict[KernelDependency, KernelLock]) -> "KernelLocks": ...
def __len__(self) -> int: ...
def __getitem__(self, dependency: KernelDependency, /) -> KernelLock:
"""Get the lock for `dependency`.

Raises:
KeyError: If the dependency is not locked.
"""
...

def __contains__(self, dependency: object, /) -> bool: ...
def __iter__(self) -> Iterator[KernelDependency]: ...
def get(
self, dependency: KernelDependency, default: Optional[KernelLock] = None
) -> Optional[KernelLock]:
"""Get the lock for `dependency`, or `default` if it is not locked."""
...

def keys(self) -> list[KernelDependency]:
"""Get the locked dependencies."""
...

def values(self) -> list[KernelLock]:
"""Get the kernel locks."""
...

def items(self) -> list[tuple[KernelDependency, KernelLock]]:
"""Get the (dependency, lock) pairs."""
...

@staticmethod
def from_json(s: str) -> "KernelLocks":
"""Parse a `KernelLocks` collection from a JSON string.

Raises:
ValueError: If the JSON cannot be parsed.
"""
...

def to_json(self) -> str:
"""Serialize the locks collection to a pretty-printed JSON string.

Raises:
ValueError: If the locks cannot be serialized.
"""
...

def __repr__(self) -> str: ...
def __eq__(self, value: object, /) -> bool: ...
def __hash__(self) -> int: ...

@final
class NixKernelLock:
"""A locked kernel revision with the SRI hash of the Nix output path."""

def __new__(cls, commit: str, hash: str) -> "NixKernelLock":
"""Construct a lock from a commit and a SRI hash.

Raises:
ValueError: If `commit` is not a full git object id.
"""
...

@property
def commit(self) -> str:
"""Locked commit of the kernel, as lowercase hexadecimal digits."""
...

@property
def hash(self) -> str:
"""SRI hash of the repository snapshot, as used by fixed-output derivations."""
...

@staticmethod
def from_json(s: str) -> "NixKernelLock":
"""Parse a `NixKernelLock` from a JSON string.

Raises:
ValueError: If the JSON cannot be parsed.
"""
...

def to_json(self) -> str:
"""Serialize the lock to a pretty-printed JSON string.

Raises:
ValueError: If the lock cannot be serialized.
"""
...

def __repr__(self) -> str: ...
def __eq__(self, value: object, /) -> bool: ...
def __hash__(self) -> int: ...

@final
class NixKernelLocks:
"""Multiple (Nix) kernel locks keyed by the dependency they resolve.

This data structure is used to store lock files to be consumed
by nix-builder.

Behaves as a read-only mapping from `KernelDependency` to `NixKernelLock`.
"""

def __new__(
cls, locks: dict[KernelDependency, NixKernelLock]
) -> "NixKernelLocks": ...
def __len__(self) -> int: ...
def __getitem__(self, dependency: KernelDependency, /) -> NixKernelLock:
"""Get the lock for `dependency`.

Raises:
KeyError: If the dependency is not locked.
"""
...

def __contains__(self, dependency: object, /) -> bool: ...
def __iter__(self) -> Iterator[KernelDependency]: ...
def get(
self, dependency: KernelDependency, default: Optional[NixKernelLock] = None
) -> Optional[NixKernelLock]:
"""Get the lock for `dependency`, or `default` if it is not locked."""
...

def keys(self) -> list[KernelDependency]:
"""Get the locked dependencies."""
...

def values(self) -> list[NixKernelLock]:
"""Get the kernel locks."""
...

def items(self) -> list[tuple[KernelDependency, NixKernelLock]]:
"""Get the (dependency, lock) pairs."""
...

@staticmethod
def from_json(s: str) -> "NixKernelLocks":
"""Parse a `NixKernelLocks` collection from a JSON string.

Raises:
ValueError: If the JSON cannot be parsed.
"""
...

def to_json(self) -> str:
"""Serialize the locks collection to a pretty-printed JSON string.

Raises:
ValueError: If the locks cannot be serialized.
"""
...

def __repr__(self) -> str: ...
def __eq__(self, value: object, /) -> bool: ...
def __hash__(self) -> int: ...

@final
class KernelPaths:
"""A collection of kernel paths keyed by the dependency they resolve.

Behaves as a read-only mapping from `KernelDependency` to `pathlib.Path`.
"""

def __new__(
cls, paths: dict[KernelDependency, os.PathLike[str] | str]
) -> "KernelPaths": ...
def __len__(self) -> int: ...
def __getitem__(self, dependency: KernelDependency, /) -> Path:
"""Get the path for `dependency`.

Raises:
KeyError: If the dependency has no path.
"""
...

def __contains__(self, dependency: object, /) -> bool: ...
def __iter__(self) -> Iterator[KernelDependency]: ...
def get(
self,
dependency: KernelDependency,
default: Optional[os.PathLike[str] | str] = None,
) -> Optional[Path]:
"""Get the path for `dependency`, or `default` if it has no path."""
...

def keys(self) -> list[KernelDependency]:
"""Get the dependencies."""
...

def values(self) -> list[Path]:
"""Get the kernel paths."""
...

def items(self) -> list[tuple[KernelDependency, Path]]:
"""Get the (dependency, path) pairs."""
...

@staticmethod
def from_json(s: str) -> "KernelPaths":
"""Parse a `KernelPaths` collection from a JSON string.

Raises:
ValueError: If the JSON cannot be parsed.
"""
...

def to_json(self) -> str:
"""Serialize the paths collection to a pretty-printed JSON string.

Raises:
ValueError: If the paths cannot be serialized.
"""
...

def __repr__(self) -> str: ...
def __eq__(self, value: object, /) -> bool: ...
def __hash__(self) -> int: ...

@final
class General:
"""General kernel configuration common to all backends."""
Expand Down
29 changes: 27 additions & 2 deletions kernels-data/bindings/python/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@ use pyo3::exceptions::{PyException, PyOSError, PyRuntimeError, PyValueError};
use pyo3::prelude::*;

mod config;
mod lock;

use config::{PyBuild, PyGeneral};
use lock::{PyKernelLock, PyKernelLocks, PyKernelPaths, PyNixKernelLock, PyNixKernelLocks};

/// A dotted numeric version (e.g. `12.8.0`). Trailing zeros are stripped
/// during normalization.
Expand Down Expand Up @@ -323,7 +325,7 @@ impl PyProvenance {

/// A kernel version: either a numeric version or a git revision string.
#[pyclass(name = "KernelVersion", frozen, eq, hash)]
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
enum PyKernelVersion {
Version { version: usize },
Revision { revision: String },
Expand All @@ -338,6 +340,15 @@ impl From<KernelVersion> for PyKernelVersion {
}
}

impl From<PyKernelVersion> for KernelVersion {
fn from(v: PyKernelVersion) -> Self {
match v {
PyKernelVersion::Version { version } => Self::Version(version),
PyKernelVersion::Revision { revision } => Self::Revision(revision),
}
}
}

#[pymethods]
impl PyKernelVersion {
fn __repr__(&self) -> String {
Expand All @@ -352,7 +363,7 @@ impl PyKernelVersion {

/// A dependency on another kernel.
#[pyclass(name = "KernelDependency", frozen, eq, hash)]
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub(crate) struct PyKernelDependency {
repo_id: String,
version: PyKernelVersion,
Expand All @@ -367,6 +378,15 @@ impl From<KernelDependency> for PyKernelDependency {
}
}

impl From<PyKernelDependency> for KernelDependency {
fn from(d: PyKernelDependency) -> Self {
Self {
repo_id: d.repo_id,
version: d.version.into(),
}
}
}

#[pymethods]
impl PyKernelDependency {
#[new]
Expand Down Expand Up @@ -759,6 +779,11 @@ fn kernels_data_py(m: &PyBound<'_, PyModule>) -> PyResult<()> {
m.add_class::<PyKernelName>()?;
m.add_class::<PyKernelVersion>()?;
m.add_class::<PyKernelDependency>()?;
m.add_class::<PyKernelLock>()?;
m.add_class::<PyKernelLocks>()?;
m.add_class::<PyNixKernelLock>()?;
m.add_class::<PyNixKernelLocks>()?;
m.add_class::<PyKernelPaths>()?;
m.add_class::<PyGeneral>()?;
m.add_class::<PyBuild>()?;
m.add_class::<PyMetadata>()?;
Expand Down
Loading
Loading