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
8 changes: 4 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13"]
python-version: ["3.11", "3.12", "3.13"]
runs-on: [ubuntu-latest, macos-latest, windows-latest]

steps:
Expand All @@ -61,14 +61,14 @@ jobs:
with:
token: ${{ secrets.CODECOV_TOKEN }}

check_oldest:
test_oldest:
name: Check Oldest Dependencies
runs-on: ${{ matrix.runs-on }}
needs: [format]
strategy:
fail-fast: false
matrix:
python-version: ["3.10"]
python-version: ["3.11"]
runs-on: [ubuntu-latest]

steps:
Expand All @@ -92,7 +92,7 @@ jobs:
status:
name: CI Pass
runs-on: ubuntu-latest
needs: [format, tests, check_oldest]
needs: [format, tests, test_oldest]
if: always()
steps:
- name: All required jobs passed
Expand Down
2 changes: 1 addition & 1 deletion .python-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.10
3.11
11 changes: 7 additions & 4 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,23 @@ classifiers = [
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Topic :: Scientific/Engineering",
"Typing :: Typed",
]
dependencies = ["plum-dispatch>=2.5.1", "typing_extensions>=4.12.2"]
dependencies = [
"optype>=0.16.0",
"plum-dispatch>=2.5.1",
"typing_extensions>=4.12.2",
]
description = "dataclass tools, extended by multiple dispatch"
dynamic = ["version"]
license.file = "LICENSE"
name = "dataclassish"
readme = "README.md"
requires-python = ">=3.10"
requires-python = ">=3.11"

[project.urls]
"Bug Tracker" = "https://github.com/GalacticDynamics/dataclassish/issues"
Expand Down Expand Up @@ -84,7 +87,7 @@ disallow_incomplete_defs = false
disallow_untyped_defs = false
enable_error_code = ["ignore-without-code", "redundant-expr", "truthy-bool"]
files = ["src"]
python_version = "3.10"
python_version = "3.11"
strict = true
warn_unreachable = true
warn_unused_configs = true
Expand Down
3 changes: 1 addition & 2 deletions src/dataclassish/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
"field_items",
# Classes
"DataclassInstance",
"CanCopyReplace",
"F",
)

Expand All @@ -34,7 +33,7 @@
get_field,
replace,
)
from ._src.types import CanCopyReplace, DataclassInstance, F
from ._src.types import DataclassInstance, F
from ._version import version as __version__

# Register dispatches by importing the submodules
Expand Down
3 changes: 2 additions & 1 deletion src/dataclassish/_src/converters.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,14 @@
Any,
ClassVar,
Generic,
NotRequired,
Protocol,
TypedDict,
TypeVar,
cast,
overload,
)
from typing_extensions import NotRequired, dataclass_transform
from typing_extensions import dataclass_transform

ArgT = TypeVar("ArgT") # Input type
RetT = TypeVar("RetT") # Return type
Expand Down
3 changes: 1 addition & 2 deletions src/dataclassish/_src/flag_compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@

from collections.abc import Iterable
from dataclasses import Field
from typing import Any, cast
from typing_extensions import Never
from typing import Any, Never, cast

from plum import dispatch

Expand Down
12 changes: 7 additions & 5 deletions src/dataclassish/_src/register_copyreplace.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""Register dispatches for CanCopyReplace objects."""
"""Register dispatches for CanReplace objects."""

__all__: tuple[str, ...] = ()

Expand All @@ -7,17 +7,17 @@
from collections.abc import Mapping
from typing import Any

import optype as opt
from plum import dispatch

from .register_base import _recursive_replace_helper
from .types import CanCopyReplace

# ===================================================================
# Get field


@dispatch
def get_field(obj: CanCopyReplace, k: str, /) -> Any:
def get_field(obj: opt.copy.CanReplaceSelf, k: str, /) -> Any:
"""Get a field of a dataclass instance by name.

Examples:
Expand Down Expand Up @@ -65,7 +65,7 @@ def get_field(obj: CanCopyReplace, k: str, /) -> Any:


@dispatch
def replace(obj: CanCopyReplace, /, **kwargs: Any) -> CanCopyReplace:
def replace(obj: opt.copy.CanReplaceSelf, /, **kwargs: Any) -> opt.copy.CanReplaceSelf:
"""Replace the fields of an object.

Examples:
Expand Down Expand Up @@ -133,7 +133,9 @@ def replace(obj: CanCopyReplace, /, **kwargs: Any) -> CanCopyReplace:


@dispatch # type: ignore[no-redef]
def replace(obj: CanCopyReplace, fs: Mapping[str, Any], /) -> CanCopyReplace:
def replace(
obj: opt.copy.CanReplaceSelf, fs: Mapping[str, Any], /
) -> opt.copy.CanReplaceSelf:
"""Replace the fields of a dataclass instance.

Examples:
Expand Down
65 changes: 1 addition & 64 deletions src/dataclassish/_src/types.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
"""Data types for ``dataclassish``."""

__all__ = ("DataclassInstance", "CanCopyReplace", "F")
__all__ = ("DataclassInstance", "F")

from dataclasses import dataclass
from typing import Any, ClassVar, Generic, Protocol, TypeVar, runtime_checkable
from typing_extensions import Self


@runtime_checkable
Expand Down Expand Up @@ -72,65 +71,3 @@ class F(Generic[V]):
"""

value: V


# ===================================================================


@runtime_checkable
class CanCopyReplace(Protocol):
"""Protocol for objects that implement the ``__replace__`` method.

This is used by ``copy.replace`` (Python 3.13+) to replace fields of an
object. This is a generalization of the ``dataclasses.replace`` function.

Examples
--------
>>> from dataclassish import CanCopyReplace

>>> class Point:
... def __init__(self, x, y):
... self.x = x
... self.y = y
... def __replace__(self, **changes):
... return Point(**(self.__dict__ | changes))
... def __repr__(self):
... return f"Point(x={self.x}, y={self.y})"

>>> issubclass(Point, CanCopyReplace)
True

>>> point = Point(1.0, 2.0)
>>> isinstance(point, CanCopyReplace)
True

The ``__replace__`` method was introduced in Python 3.13 to bring
``dataclasses.replace``-like functionality to any implementing object. The
method is publicly exposed via the ``copy.replace`` function.

% invisible-code-block: python
%
% import sys

% skip: start if(sys.version_info < (3, 13), reason="py3.13+")

>>> import copy
>>> copy.replace(point, x=3.0)
Point(x=3.0, y=2.0)

% skip: end

"""

def __replace__(self: Self, /, **changes: Any) -> Self:
"""Replace the fields of the object.

This method should return a new object with the fields replaced.

Args:
**changes: Field names and their new values.

Returns:
A new object with the specified fields replaced.

"""
Loading