Skip to content
Open
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
64 changes: 64 additions & 0 deletions dictdiffer/__init__.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# SPDX-FileCopyrightText: 2026 HeeJae Chang.
# SPDX-License-Identifier: MIT

from typing import (
Hashable,
Iterable,
Iterator,
List,
Optional,
Tuple,
Type,
TypeVar,
Union,
)

from typing_extensions import Literal, TypeAlias

_DiffPath: TypeAlias = Union[str, List[object]]
_DiffPair: TypeAlias = Tuple[object, object]
_AddDiff: TypeAlias = Tuple[Literal["add"], _DiffPath, List[_DiffPair]]
_RemoveDiff: TypeAlias = Tuple[Literal["remove"], _DiffPath, List[_DiffPair]]
_ChangeDiff: TypeAlias = Tuple[Literal["change"], _DiffPath, _DiffPair]
_Diff: TypeAlias = Union[_AddDiff, _RemoveDiff, _ChangeDiff]
_PathTuple: TypeAlias = Tuple[Hashable, ...]

_DestinationT = TypeVar("_DestinationT")

from . import utils as utils
from . import version as version
from .utils import EPSILON, PathLimit, are_different
from .utils import dot_lookup as dot_lookup
from .version import __version__ as __version__

ADD: Literal["add"]
REMOVE: Literal["remove"]
CHANGE: Literal["change"]
DICT_TYPES: Tuple[Type[object], ...]
LIST_TYPES: Tuple[Type[object], ...]
SET_TYPES: Tuple[Type[object], ...]
HAS_NUMPY: bool
__all__ = ("diff", "patch", "swap", "revert", "dot_lookup", "__version__")

def diff(
first: object,
second: object,
node: Optional[List[object]] = ...,
ignore: Optional[Iterable[object]] = ...,
path_limit: Optional[Union[PathLimit, Iterable[Iterable[Hashable]]]] = ...,
expand: bool = ...,
tolerance: Optional[float] = ...,
absolute_tolerance: Optional[float] = ...,
dot_notation: bool = ...,
) -> Iterator[_Diff]: ...
def patch(
diff_result: Iterable[_Diff],
destination: _DestinationT,
in_place: bool = ...,
) -> _DestinationT: ...
def swap(diff_result: Iterable[_Diff]) -> Iterator[_Diff]: ...
def revert(
diff_result: Iterable[_Diff],
destination: _DestinationT,
in_place: bool = ...,
) -> _DestinationT: ...
26 changes: 26 additions & 0 deletions dictdiffer/conflict.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# SPDX-FileCopyrightText: 2026 HeeJae Chang.
# SPDX-License-Identifier: MIT

from typing import Iterable, List, Optional

from typing_extensions import Literal

from . import _Diff
from .utils import get_path as get_path
from .utils import is_super_path as is_super_path

class Conflict:
first_patch: _Diff
second_patch: _Diff
take: Optional[Literal["f", "s"]]
def __init__(self, patch1: _Diff, patch2: _Diff) -> None: ...
def take_patch(self) -> _Diff: ...
def __repr__(self) -> str: ...

class ConflictFinder:
conflicts: List[Conflict]
def find_conflicts(
self,
first_patches: Iterable[_Diff],
second_patches: Iterable[_Diff],
) -> List[Conflict]: ...
77 changes: 77 additions & 0 deletions dictdiffer/merge.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# SPDX-FileCopyrightText: 2026 HeeJae Chang.
# SPDX-License-Identifier: MIT

from typing import (
Generic,
Hashable,
Iterable,
List,
Mapping,
Optional,
Sequence,
TypeVar,
overload,
)

from typing_extensions import Literal

from . import _Diff, _PathTuple
from . import diff as diff
from .conflict import Conflict
from .conflict import ConflictFinder as ConflictFinder
from .resolve import Resolver as Resolver
from .resolve import UnresolvedConflictsException as UnresolvedConflictsException
from .resolve import _ResolutionAction
from .unify import Unifier as Unifier
from .utils import PathLimit as PathLimit

_DataT = TypeVar("_DataT")
_InfoT = TypeVar("_InfoT")
_ConstructorDataT = TypeVar("_ConstructorDataT")
_ConstructorInfoT = TypeVar("_ConstructorInfoT")

class Merger(Generic[_DataT, _InfoT]):
lca: _DataT
first: _DataT
second: _DataT
path_limit: PathLimit
ignore: Optional[Iterable[object]]
actions: Mapping[_PathTuple, _ResolutionAction[_InfoT]]
additional_info: _InfoT
conflict_finder: ConflictFinder
resolver: Resolver[_InfoT]
unifier: Unifier
conflicts: List[Conflict]
unresolved_conflicts: List[Conflict]
first_patches: List[_Diff]
second_patches: List[_Diff]
unified_patches: List[_Diff]

@overload
def __init__(
self: Merger[_ConstructorDataT, None],
lca: _ConstructorDataT,
first: _ConstructorDataT,
second: _ConstructorDataT,
actions: Mapping[_PathTuple, _ResolutionAction[None]],
path_limits: Iterable[Iterable[Hashable]] = ...,
additional_info: None = ...,
ignore: Optional[Iterable[object]] = ...,
) -> None: ...
@overload
def __init__(
self: Merger[_ConstructorDataT, _ConstructorInfoT],
lca: _ConstructorDataT,
first: _ConstructorDataT,
second: _ConstructorDataT,
actions: Mapping[_PathTuple, _ResolutionAction[_ConstructorInfoT]],
path_limits: Iterable[Iterable[Hashable]] = ...,
additional_info: _ConstructorInfoT = ...,
ignore: Optional[Iterable[object]] = ...,
) -> None: ...
def run(self) -> None: ...
def continue_run(self, picks: Sequence[Literal["f", "s"]]) -> None: ...
def extract_patches(self) -> None: ...
def find_conflicts(self) -> None: ...
def resolve_conflicts(self) -> None: ...
def unify_patches(self) -> None: ...
Empty file added dictdiffer/py.typed
Empty file.
53 changes: 53 additions & 0 deletions dictdiffer/resolve.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# SPDX-FileCopyrightText: 2026 HeeJae Chang.
# SPDX-License-Identifier: MIT

from typing import Callable, Generic, List, Mapping, Sequence, TypeVar, overload

from typing_extensions import Literal, TypeAlias

from . import _Diff, _PathTuple
from .conflict import Conflict
from .utils import get_path as get_path

_InfoT = TypeVar("_InfoT")
_ResolutionAction: TypeAlias = Callable[
[Conflict, List[_Diff], List[_Diff], _InfoT],
bool,
]

class UnresolvedConflictsException(Exception):
message: str
content: List[Conflict]
def __init__(self, unresolved_conflicts: List[Conflict]) -> None: ...
def __repr__(self) -> str: ...
def __str__(self) -> str: ...

class NoFurtherResolutionException(Exception): ...

class Resolver(Generic[_InfoT]):
actions: Mapping[_PathTuple, _ResolutionAction[_InfoT]]
additional_info: _InfoT
unresolved_conflicts: List[Conflict]

@overload
def __init__(
self: Resolver[None],
actions: Mapping[_PathTuple, _ResolutionAction[None]],
additional_info: None = ...,
) -> None: ...
@overload
def __init__(
self,
actions: Mapping[_PathTuple, _ResolutionAction[_InfoT]],
additional_info: _InfoT,
) -> None: ...
def resolve_conflicts(
self,
first_patches: List[_Diff],
second_patches: List[_Diff],
conflicts: Sequence[Conflict],
) -> None: ...
def manual_resolve_conflicts(
self,
picks: Sequence[Literal["f", "s"]],
) -> None: ...
19 changes: 19 additions & 0 deletions dictdiffer/testing.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# SPDX-FileCopyrightText: 2026 HeeJae Chang.
# SPDX-License-Identifier: MIT

from typing import Hashable, Iterable, List, Optional, Union

from . import diff as diff
from .utils import PathLimit

def assert_no_diff(
first: object,
second: object,
node: Optional[List[object]] = ...,
ignore: Optional[Iterable[object]] = ...,
path_limit: Optional[Union[PathLimit, Iterable[Iterable[Hashable]]]] = ...,
expand: bool = ...,
tolerance: Optional[float] = ...,
absolute_tolerance: Optional[float] = ...,
dot_notation: bool = ...,
) -> None: ...
18 changes: 18 additions & 0 deletions dictdiffer/unify.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# SPDX-FileCopyrightText: 2026 HeeJae Chang.
# SPDX-License-Identifier: MIT

from typing import Iterable, List

from . import _Diff
from .conflict import Conflict
from .utils import get_path as get_path
from .utils import nested_hash as nested_hash

class Unifier:
unified_patches: List[_Diff]
def unify(
self,
first_patches: List[_Diff],
second_patches: List[_Diff],
conflicts: Iterable[Conflict],
) -> List[_Diff]: ...
87 changes: 87 additions & 0 deletions dictdiffer/utils.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# SPDX-FileCopyrightText: 2026 HeeJae Chang.
# SPDX-License-Identifier: MIT

from typing import (
Dict,
Generic,
Hashable,
Iterable,
List,
Mapping,
Optional,
Sequence,
Set,
Tuple,
Type,
TypeVar,
Union,
overload,
)

from typing_extensions import Literal, TypeAlias

from . import _Diff, _DiffPair, _DiffPath, _PathTuple

_ValueT = TypeVar("_ValueT")
_SourceT = TypeVar("_SourceT")
_PathPatch: TypeAlias = Tuple[str, _DiffPath, Sequence[_DiffPair]]
_PathLimitTree: TypeAlias = Dict[
Hashable,
Union[bool, "_PathLimitTree"],
]

num_types: Tuple[Type[int], Type[float]]
EPSILON: float

class WildcardDict(Dict[_PathTuple, _ValueT], Generic[_ValueT]):
star_keys: Set[_PathTuple]
plus_keys: Set[_PathTuple]

@overload
def __init__(self, values: None = ...) -> None: ...
@overload
def __init__(self, values: Mapping[_PathTuple, _ValueT]) -> None: ...
def __getitem__(self, key: _PathTuple) -> _ValueT: ...
def __setitem__(self, key: _PathTuple, value: _ValueT) -> None: ...
def query_path(self, key: _PathTuple) -> _PathTuple: ...

class PathLimit:
final_key: Hashable
dict: _PathLimitTree
def __init__(
self,
path_limits: Iterable[Iterable[Hashable]] = ...,
final_key: Optional[Hashable] = ...,
) -> None: ...
def path_is_limit(self, key_path: Iterable[Hashable]) -> bool: ...

def create_dotted_node(node: Sequence[object]) -> Union[str, List[object]]: ...
def get_path(patch: Union[_Diff, _PathPatch]) -> Tuple[object, ...]: ...
def is_super_path(path1: Iterable[object], path2: Iterable[object]) -> bool: ...
def nested_hash(obj: object) -> Optional[int]: ...

@overload
def dot_lookup(
source: _SourceT,
lookup: None,
parent: bool = ...,
) -> _SourceT: ...
@overload
def dot_lookup(
source: _SourceT,
lookup: Literal[""],
parent: bool = ...,
) -> _SourceT: ...
@overload
def dot_lookup(
source: object,
lookup: Union[str, List[object]],
parent: bool = ...,
) -> object: ...

def are_different(
first: object,
second: object,
tolerance: Optional[float],
absolute_tolerance: Optional[float] = ...,
) -> bool: ...
4 changes: 4 additions & 0 deletions dictdiffer/version.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# SPDX-FileCopyrightText: 2026 HeeJae Chang.
# SPDX-License-Identifier: MIT

__version__: str