Skip to content

Commit c528fc3

Browse files
authored
Merge pull request #85 from ionite34/fix-typeview-restore
2 parents cf58702 + 615d579 commit c528fc3

File tree

6 files changed

+59
-9
lines changed

6 files changed

+59
-9
lines changed

docs/source/conf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
project = "einspect"
1616
copyright = "2023, Ionite"
1717
author = "Ionite"
18-
release = "v0.5.15"
18+
release = "v0.5.16"
1919

2020

2121
# -- General configuration ---------------------------------------------------

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "einspect"
3-
version = "0.5.15"
3+
version = "0.5.16"
44
packages = [{ include = "einspect", from = "src" }]
55
description = "Extended Inspect - view and modify memory structs of runtime objects."
66
authors = ["ionite34 <dev@ionite.io>"]

src/einspect/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from einspect.views.view_type import impl
99

1010
__all__ = ("view", "unsafe", "impl", "orig", "ptr", "NULL", "__version__")
11-
__version__ = "0.5.15"
11+
__version__ = "0.5.16"
1212

1313
unsafe = global_unsafe
1414

src/einspect/type_orig.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,14 @@ def add_impls(type_: type, *attrs: str) -> None:
6666
attrs_set.update(attrs)
6767

6868

69+
def remove_impls(type_: type, *attrs: str) -> None:
70+
"""Remove a set of implemented attributes from the cache."""
71+
attrs_set = wk_dict_getitem(_impls, type_)
72+
if attrs_set is not None:
73+
for attr in attrs:
74+
attrs_set.discard(attr)
75+
76+
6977
def try_cache_attr(
7078
type_: type,
7179
name: str,
@@ -133,6 +141,16 @@ def get_type_cache(type_: type) -> dict[str, Any]:
133141
) from None
134142

135143

144+
def get_impls(type_: type) -> set[str]:
145+
"""Get the impls cache for the type."""
146+
try:
147+
return wk_dict_getitem(_impls, type_)
148+
except KeyError:
149+
raise KeyError(
150+
f"Original attributes cache was not found for type {type_!r}"
151+
) from None
152+
153+
136154
def normalize_slot_attr(attr: object | TypeNewWrapper) -> Any:
137155
"""Normalize a slot attribute to its original value."""
138156
if isinstance(attr, TypeNewWrapper):

src/einspect/views/view_type.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,11 @@
2424
MISSING,
2525
add_impls,
2626
get_cache,
27-
get_type_cache,
27+
get_impls,
2828
in_cache,
2929
in_impls,
3030
normalize_slot_attr,
31+
remove_impls,
3132
try_cache_attr,
3233
)
3334
from einspect.views.view_base import REF_DEFAULT, VarView
@@ -352,26 +353,25 @@ def restore(self, *names: str | Callable) -> None:
352353

353354
if not names:
354355
# Restore all attributes
355-
type_cache = get_type_cache(type_)
356-
for name, attr in type_cache.items():
357-
self[name] = normalize_slot_attr(attr)
358-
return type_
356+
names = get_impls(type_)
359357

360358
# Normalize names of stuff like properties and class methods
361359
names = [get_func_name(n) if callable(n) else n for n in names]
362360
# Check all names exist first
363361
for name in names:
364-
if in_cache(type_, name):
362+
if in_impls(type_, name) and in_cache(type_, name):
365363
attr = get_cache(type_, name)
366364
# MISSING is a special case, it means there is no original attribute
367365
if attr is MISSING:
368366
# Same as no attribute, delete it
369367
del self[name]
368+
remove_impls(type_, name)
370369
else:
371370
self[name] = normalize_slot_attr(attr)
372371
# If in impl record, and not in cache, remove the attribute
373372
elif in_impls(type_, name):
374373
del self[name]
374+
remove_impls(type_, name)
375375
else:
376376
raise AttributeError(
377377
f"{type_.__name__!r} has no original attribute {name!r}"

tests/test_impl_sp.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,38 @@
44
import pytest
55

66
from einspect import impl, orig, view
7+
from einspect.type_orig import _impls
8+
9+
10+
@pytest.mark.run_in_subprocess
11+
def test_impl_restore():
12+
# Clear impls cache
13+
backup_impls = _impls.copy()
14+
_impls.clear()
15+
16+
@impl(int)
17+
def __repr__(self):
18+
return "repr"
19+
20+
@impl(int)
21+
def x(self):
22+
return "x"
23+
24+
n = 5
25+
assert repr(n) == "repr"
26+
# noinspection PyUnresolvedReferences
27+
assert n.x() == "x"
28+
29+
view(int).restore()
30+
31+
assert repr(n) == "5"
32+
with pytest.raises(AttributeError):
33+
# noinspection PyUnresolvedReferences
34+
_ = n.x()
35+
36+
# Restore impls cache
37+
_impls.clear()
38+
_impls.update(backup_impls)
739

840

941
@pytest.mark.run_in_subprocess

0 commit comments

Comments
 (0)