Extended Inspect - view and modify memory structs of runtime objects.
Project description
einspect
Extended Inspections for CPython
Documentation
- View and modify memory structures of live objects.
- Able to mutate immutable objects like tuples and ints.
- Modify slot functions or attributes of built-in types.
- Fully typed, extensible framework in pure Python.
Check detailed states of built-in objects
from einspect import view
ls = [1, 2, 3]
v = view(ls)
print(v.info())
PyListObject(at 0x2833738):
ob_refcnt: Py_ssize_t = 5
ob_type: *PyTypeObject = &[list]
ob_item: **PyObject = &[&[1], &[2], &[3]]
allocated: Py_ssize_t = 4
Mutate tuples, strings, ints, or other immutable types
TupleView and StrView supports all MutableSequence methods (append, extend, insert, pop, remove, reverse, clear).
from einspect import view
tup = (1, 2)
v = view(tup)
v[1] = 500
print(tup) # (1, 500)
v.append(3)
print(tup) # (1, 500, 3)
del v[:2]
print(tup) # (3,)
print(v.pop()) # 3
v.extend([1, 2])
print(tup) # (1, 2)
v.clear()
print(tup) # ()
from einspect import view
text = "hello"
v = view(text)
v[1] = "3"
v[4:] = "o~"
v.append("!")
print(text) # h3llo~!
v.reverse()
print(text) # !~oll3h
from einspect import view
n = 500
view(n).value = 10
print(500) # 10
print(500 == 10) # True
Modify attributes of built-in types, get original attributes with orig
from einspect import view, orig
v = view(int)
v["__name__"] = "custom_int"
v["__iter__"] = lambda s: iter(range(s))
v["__repr__"] = lambda s: "custom: " + orig(int).__repr__(s)
print(int)
for i in 3:
print(i)
<class 'custom_int'>
custom: 0
custom: 1
custom: 2
Implement methods on built-in types with @impl
from einspect import impl, orig
@impl(int)
def __add__(self, other):
other = int(other)
return orig(int).__add__(self, other)
print(50 + "25") # 75
Move objects in memory
from einspect import view
s = "meaning of life"
v = view(s)
with v.unsafe():
v <<= 42
print("meaning of life") # 42
print("meaning of life" == 42) # True
Fully typed interface
Table of Contents
Views
Using the einspect.view
constructor
This is the recommended and simplest way to create a View
onto an object. Equivalent to constructing a specific View
subtype from einspect.views
, except the choice of subtype is automatic based on object type.
from einspect import view
print(view(1))
print(view("hello"))
print(view([1, 2]))
print(view((1, 2)))
IntView(<PyLongObject at 0x102058920>) StrView(<PyUnicodeObject at 0x100f12ab0>) ListView(<PyListObject at 0x10124f800>) TupleView(<PyTupleObject at 0x100f19a00>)
Inspecting struct attributes
Attributes of the underlying C Struct of objects can be accessed through the view's properties.
from einspect import view
ls = [1, 2]
v = view(ls)
# Inherited from PyObject
print(v.ref_count) # ob_refcnt
print(v.type) # ob_type
# Inherited from PyVarObject
print(v.size) # ob_size
# From PyListObject
print(v.item) # ob_item
print(v.allocated) # allocated
4 <class 'tuple'> 3 <einspect.structs.c_long_Array_3 object at 0x105038ed0>
2. Writing to view attributes
Writing to these attributes will affect the underlying object of the view.
Note that most memory-unsafe attribute modifications require entering an unsafe context manager with View.unsafe()
with v.unsafe():
v.size -= 1
print(obj)
(1, 2)
Since items
is an array of integer pointers to python objects, they can be replaced by id()
addresses to modify
index items in the tuple.
from einspect import view
tup = (100, 200)
with view(tup).unsafe() as v:
s = "dog"
v.item[0] = id(s)
print(tup)
('dog', 200) >> Process finished with exit code 139 (interrupted by signal 11: SIGSEGV)
So here we did set the item at index 0 with our new item, the string "dog"
, but this also caused a segmentation fault.
Note that the act of setting an item in containers like tuples and lists "steals" a reference to the object, even
if we only supplied the address pointer.
To make this safe, we will have to manually increment a ref-count before the new item is assigned. To do this we can
either create a view
of our new item, and increment its ref_count += 1
, or use the apis from einspect.api
, which
are pre-typed implementations of ctypes.pythonapi
methods.
from einspect import view
from einspect.api import Py
tup = (100, 200)
with view(tup).unsafe() as v:
a = "bird"
Py.IncRef(a)
v.item[0] = id(a)
b = "kitten"
Py.IncRef(b)
v.item[1] = id(b)
print(tup)
('bird', 'kitten')
🎉 No more seg-faults, and we just successfully set both items in an otherwise immutable tuple.
To make the above routine easier, you can access an abstraction by simply indexing the view.
from einspect import view
tup = ("a", "b", "c")
v = view(tup)
v[0] = 123
v[1] = "hm"
v[2] = "🤔"
print(tup)
(123, 'hm', '🤔')
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file einspect-0.4.10.tar.gz
.
File metadata
- Download URL: einspect-0.4.10.tar.gz
- Upload date:
- Size: 42.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.3.0 CPython/3.11.1 Linux/5.15.0-1031-azure
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 90852779cf64dbb0df236b5902d1eb7275ccbd25b3586d8a1869fa388a297b9b |
|
MD5 | 40f5b21cd28a0da4e71b9d3741e8e1b3 |
|
BLAKE2b-256 | 5f4075020ed916ffac74d57ac4a234aa348ec0041b58ff717e602e9b1bd66734 |
File details
Details for the file einspect-0.4.10-py3-none-any.whl
.
File metadata
- Download URL: einspect-0.4.10-py3-none-any.whl
- Upload date:
- Size: 56.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.3.0 CPython/3.11.1 Linux/5.15.0-1031-azure
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 718a1bb35f0fac816526962bdeb2c7c9b638da2159418768e900a20ca9465b8b |
|
MD5 | 86f169d49eaa92634c3f1c2c891309be |
|
BLAKE2b-256 | 3fc50f7183456967278ca3cde420b5fdd9f9f88118eaa19fc02399fde01c715e |