Skip to content

Commit

Permalink
Support for Python >3.13
Browse files Browse the repository at this point in the history
- Manually returning __dict__ of objects.
- Fixing incorrect assumption about object's dicts.
  • Loading branch information
liran-funaro committed Jan 12, 2025
1 parent 6c8bb80 commit b6730ad
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 17 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [ "3.10" ]
python-version: [ "3.12" ]

steps:
- uses: actions/checkout@v3
Expand All @@ -29,7 +29,7 @@ jobs:
flake8 objsize --count --select=E,F,W,C --show-source --max-complexity=10 --max-line-length=120 --statistics --per-file-ignores='__init__.py:F401'
- name: Lint with pylint
run: |
pylint objsize
pylint objsize -v
- name: Lint with mypy
run: |
mypy objsize --check-untyped-defs
Expand All @@ -38,7 +38,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [ "3.7", "3.8", "3.9", "3.10", "3.11", "3.12" ]
python-version: [ "3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14" ]

steps:
- uses: actions/checkout@v3
Expand Down
14 changes: 12 additions & 2 deletions objsize/traverse.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,18 @@ def shared_object_filter(obj: Any) -> bool:
return not safe_is_instance(obj, SharedObjectType)


default_get_referents = gc.get_referents
"""See https://docs.python.org/3/library/gc.html#gc.get_referents"""
def default_get_referents(*objs: Any) -> Iterable[Any]:
"""See https://docs.python.org/3/library/gc.html#gc.get_referents"""
yield from gc.get_referents(*objs)

# Starting from Python 3.12, c.get_referents(*objs) does not return the object's internal dict.
for obj in objs:
try:
yield obj.__dict__
except AttributeError:
pass


default_object_filter = shared_object_or_function_filter
"""By default, we filter shared objects, i.e., types, modules, functions, and lambdas"""
default_get_size = sys.getsizeof
Expand Down
21 changes: 9 additions & 12 deletions test_objsize.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@ def get_weakref_referents(*objs):
yield o.__repr__.__self__
except ReferenceError:
pass
else:
try:
yield o.__dict__
except AttributeError:
pass


##################################################################
Expand Down Expand Up @@ -217,15 +222,14 @@ class Foo(list):
pass

obj = Foo(get_unique_strings(5))
expected_sz = get_flat_list_expected_size(obj)
expected_sz = get_flat_list_expected_size(obj) + sys.getsizeof(obj.__dict__)
assert expected_sz == objsize.get_deep_size(obj)

wait_event = threading.Event()
obj_proxy = weakref.proxy(obj, lambda value: wait_event.set())
proxy_sz = sys.getsizeof(obj_proxy)
expected_with_proxy_sz = proxy_sz + expected_sz

assert proxy_sz == objsize.get_deep_size(obj_proxy)
assert expected_with_proxy_sz == objsize.get_deep_size(obj_proxy, get_referents_func=get_weakref_referents)
for cur_objsize in _test_all_update_techniques(get_referents_func=get_weakref_referents):
assert expected_with_proxy_sz == cur_objsize.get_deep_size(obj_proxy)
Expand Down Expand Up @@ -350,6 +354,7 @@ def __init__(self, x, y):
def test_namedtuple():
Point = namedtuple("Point", ["x", "y"])
point = Point(3, 4)
# namedtuple object does not contain a dict.
expected_size = sys.getsizeof(point) + sys.getsizeof(3) + sys.getsizeof(4)
assert expected_size == objsize.get_deep_size(point)

Expand All @@ -359,16 +364,7 @@ class MyPoint(namedtuple("MyPoint", ["x", "y"])):
pass

point = MyPoint(3, 4)
# namedtuple does not contain a dict.
# It is created on request and is not cached for later calls:
# >>> point = MyPoint(3, 4)
# >>> all_obj = {id(o) for o in gc.get_objects()}
# >>> id(point.__dict__) in all_obj
# False
# >>> all_obj = {id(o) for o in gc.get_objects()}
# >>> id(point.__dict__) in all_obj
# False
expected_size = sys.getsizeof(point) + sys.getsizeof(3) + sys.getsizeof(4)
expected_size = sys.getsizeof(point) + sys.getsizeof(point.__dict__) + sys.getsizeof(3) + sys.getsizeof(4)
assert expected_size == objsize.get_deep_size(point)


Expand All @@ -377,6 +373,7 @@ class MyPoint(namedtuple("MyPoint", ["x", "y"])):
__slots__ = ()

point = MyPoint(3, 4)
# slot object does not contain a dict.
expected_size = sys.getsizeof(point) + sys.getsizeof(3) + sys.getsizeof(4)
assert expected_size == objsize.get_deep_size(point)

Expand Down

0 comments on commit b6730ad

Please sign in to comment.