You're Invited:Meet the Socket Team at RSAC and BSidesSF 2026, March 23–26.RSVP
Socket
Book a DemoSign in
Socket

pytest-memray

Package Overview
Dependencies
Maintainers
2
Versions
12
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

pytest-memray - pypi Package Compare versions

Comparing version
1.3.2
to
1.4.0
+13
-0
docs/news.rst

@@ -8,2 +8,15 @@ Release History

v1.4.0 (2022-12-02)
-------------------
Features - 1.4.0
~~~~~~~~~~~~~~~~
- Allow to run tests marked with memray markers without having to provide "--memray" in the command line. (:issue:`57`)
- Add two new options that allow to customize the ammount of frames in allocation tracebacks as well as including hybrid stack traces. (:issue:`58`)
Bug Fixes - 1.4.0
~~~~~~~~~~~~~~~~~
- Fix pytest raising ``pytest.PytestReturnNotNoneWarning`` from test decorated with memray markers. (:issue:`60`)
v1.3.2 (2022-11-30)

@@ -10,0 +23,0 @@ -------------------

+5
-1
Metadata-Version: 2.1
Name: pytest-memray
Version: 1.3.2
Version: 1.4.0
Summary: A simple plugin to use with pytest

@@ -139,2 +139,4 @@ Project-URL: Bug Tracker, https://github.com/bloomberg/pytest-memray/issues

hex)
--stacks=STACKS - Show the N stack entries when showing tracebacks of memory allocations
--native - Show native frames when showing tracebacks of memory allocations (will be slower)

@@ -146,2 +148,4 @@ ## Configuration - INI

- `hide_memray_summary(bool)` - hide the memray summary at the end of the execution
- `stacks(int)` - Show the N stack entries when showing tracebacks of memory allocations
- `native(bool)`- Show native frames when showing tracebacks of memory allocations (will be slower)

@@ -148,0 +152,0 @@ ## License

@@ -97,2 +97,4 @@ <img src="https://raw.githubusercontent.com/bloomberg/pytest-memray/main/docs/_static/images/logo.png" width="70%" style="display: block; margin: 0 auto" alt="logo"/>

hex)
--stacks=STACKS - Show the N stack entries when showing tracebacks of memory allocations
--native - Show native frames when showing tracebacks of memory allocations (will be slower)

@@ -104,2 +106,4 @@ ## Configuration - INI

- `hide_memray_summary(bool)` - hide the memray summary at the end of the execution
- `stacks(int)` - Show the N stack entries when showing tracebacks of memory allocations
- `native(bool)`- Show native frames when showing tracebacks of memory allocations (will be slower)

@@ -106,0 +110,0 @@ ## License

+1
-1

@@ -1,1 +0,1 @@

__version__ = "1.3.2"
__version__ = "1.4.0"

@@ -5,7 +5,10 @@ from __future__ import annotations

from typing import Tuple
from typing import cast
from memray import AllocationRecord
from pytest import Config
from .utils import parse_memory_string
from .utils import sizeof_fmt
from .utils import value_or_ini

@@ -22,2 +25,4 @@ PytestSection = Tuple[str, str]

allocations: list[AllocationRecord]
num_stacks: int
native_stacks: bool

@@ -35,7 +40,18 @@ @property

size = record.size
stack_trace = record.stack_trace()
stack_trace = (
record.hybrid_stack_trace()
if self.native_stacks
else record.stack_trace()
)
if not stack_trace:
continue
(function, file, line), *_ = stack_trace
text_lines.append(f"\t- {function}:{file}:{line} -> {sizeof_fmt(size)}")
padding = " " * 4
text_lines.append(f"{padding}- {sizeof_fmt(size)} allocated here:")
stacks_left = self.num_stacks
for function, file, line in stack_trace:
if stacks_left <= 0:
break
text_lines.append(f"{padding*2}{function}:{file}:{line}")
stacks_left -= 1
return "memray-max-memory", "\n".join(text_lines)

@@ -52,3 +68,3 @@

def limit_memory(
limit: str, *, _allocations: list[AllocationRecord]
limit: str, *, _allocations: list[AllocationRecord], _config: Config
) -> _MemoryInfo | None:

@@ -60,3 +76,7 @@ """Limit memory used by the test."""

return None
return _MemoryInfo(max_memory, total_allocated_memory, _allocations)
num_stacks: int = cast(int, value_or_ini(_config, "stacks"))
native_stacks: bool = cast(bool, value_or_ini(_config, "native"))
return _MemoryInfo(
max_memory, total_allocated_memory, _allocations, num_stacks, native_stacks
)

@@ -63,0 +83,0 @@

@@ -38,3 +38,5 @@ from __future__ import annotations

from .utils import WriteEnabledDirectoryAction
from .utils import positive_int
from .utils import sizeof_fmt
from .utils import value_or_ini

@@ -126,2 +128,12 @@ MARKERS = {"limit_memory": limit_memory}

markers = {
marker.name
for marker in pyfuncitem.iter_markers()
if marker.name in MARKERS
}
if not markers and not value_or_ini(self.config, "memray"):
yield
return
def _build_bin_path() -> Path:

@@ -139,8 +151,11 @@ if self._tmp_dir is None:

native: bool = bool(value_or_ini(self.config, "native"))
@functools.wraps(func)
def wrapper(*args: Any, **kwargs: Any) -> object | None:
test_result: object | Any = None
try:
result_file = _build_bin_path()
with Tracker(result_file):
result: object | None = func(*args, **kwargs)
with Tracker(result_file, native_traces=native):
test_result = func(*args, **kwargs)
try:

@@ -164,3 +179,3 @@ metadata = FileReader(result_file).metadata

pyfuncitem.obj = func
return result
return test_result

@@ -191,4 +206,9 @@ pyfuncitem.obj = wrapper

func = reader.get_high_watermark_allocation_records
allocations = list(func(merge_threads=True))
res = marker_fn(*marker.args, **marker.kwargs, _allocations=allocations)
allocations = list((func(merge_threads=True)))
res = marker_fn(
*marker.args,
**marker.kwargs,
_allocations=allocations,
_config=self.config,
)
if res:

@@ -217,3 +237,5 @@ report.outcome = "failed"

) -> None:
if value_or_ini(self.config, "hide_memray_summary"):
if value_or_ini(self.config, "hide_memray_summary") or not value_or_ini(
self.config, "memray"
):
return

@@ -318,2 +340,15 @@

)
group.addoption(
"--stacks",
type=positive_int,
default=1,
help="Show the N stack entries when showing tracebacks of memory allocations",
)
group.addoption(
"--native",
action="store_true",
default=False,
help="Show native frames when showing tracebacks of memory allocations "
"(will be slower)",
)

@@ -326,2 +361,13 @@ parser.addini("memray", "Activate pytest.ini setting", type="bool")

)
parser.addini(
"stacks",
help="Show the N stack entries when showing tracebacks of memory allocations",
type="string",
)
parser.addini(
"native",
help="Show native frames when showing tracebacks of memory allocations "
"(will be slower)",
type="bool",
)
help_msg = "Show the N tests that allocate most memory (N=0 for all)"

@@ -331,9 +377,3 @@ parser.addini("most_allocations", help_msg)

def value_or_ini(config: Config, key: str) -> object:
return config.getvalue(key) or config.getini(key)
def pytest_configure(config: Config) -> None:
if not value_or_ini(config, "memray"):
return
pytest_memray = Manager(config)

@@ -340,0 +380,0 @@ config.pluginmanager.register(pytest_memray, "memray_manager")

from __future__ import annotations
import argparse
import os

@@ -11,3 +12,5 @@ import re

from pytest import Config
def sizeof_fmt(num: int | float, suffix: str = "B") -> str:

@@ -47,2 +50,12 @@ for unit in ["", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi"]:

def value_or_ini(config: Config, key: str) -> object:
value = config.getvalue(key)
if value:
return value
try:
return config.getini(key)
except (KeyError, ValueError):
return value
class WriteEnabledDirectoryAction(Action):

@@ -72,2 +85,9 @@ def __call__(

def positive_int(value: str) -> int:
the_int = int(value)
if the_int <= 0:
raise argparse.ArgumentTypeError(f"{value} is an invalid positive int value")
return the_int
__all__ = [

@@ -77,2 +97,4 @@ "WriteEnabledDirectoryAction",

"sizeof_fmt",
"value_or_ini",
"positive_int",
]

@@ -5,5 +5,7 @@ from __future__ import annotations

from types import SimpleNamespace
from unittest.mock import ANY
from unittest.mock import patch
import pytest
from memray import Tracker
from pytest import ExitCode

@@ -83,3 +85,3 @@ from pytest import Pytester

def test_limit_memory_marker_does_not_work_if_memray_inactive(
def test_limit_memory_marker_does_work_if_memray_not_passed(
pytester: Pytester,

@@ -102,3 +104,3 @@ ) -> None:

assert result.ret == ExitCode.OK
assert result.ret == ExitCode.TESTS_FAILED

@@ -154,2 +156,63 @@

@pytest.mark.parametrize("num_stacks", [1, 5, 100])
def test_memray_report_limit_number_stacks(num_stacks: int, pytester: Pytester) -> None:
pytester.makepyfile(
"""
import pytest
from memray._test import MemoryAllocator
allocator = MemoryAllocator()
def rec(n):
if n <= 1:
allocator.valloc(1024*2)
allocator.free()
return None
return rec(n - 1)
@pytest.mark.limit_memory("1kb")
def test_foo():
rec(10)
"""
)
result = pytester.runpytest("--memray", f"--stacks={num_stacks}")
assert result.ret == ExitCode.TESTS_FAILED
output = result.stdout.str()
assert "valloc:" in output
assert output.count("rec:") == min(num_stacks - 1, 10)
@pytest.mark.parametrize("native", [True, False])
def test_memray_report_native(native: bool, pytester: Pytester) -> None:
pytester.makepyfile(
"""
import pytest
from memray._test import MemoryAllocator
allocator = MemoryAllocator()
@pytest.mark.limit_memory("1kb")
def test_foo():
allocator.valloc(1024*2)
allocator.free()
"""
)
with patch("pytest_memray.plugin.Tracker", wraps=Tracker) as mock:
result = pytester.runpytest("--memray", *(["--native"] if native else []))
assert result.ret == ExitCode.TESTS_FAILED
output = result.stdout.str()
mock.assert_called_once_with(ANY, native_traces=native)
if native:
assert "MemoryAllocator_1" in output
else:
assert "MemoryAllocator_1" not in output
def test_memray_report(pytester: Pytester) -> None:

@@ -476,1 +539,18 @@ pytester.makepyfile(

assert result.ret == outcome
def test_memray_does_not_raise_warnings(pytester: Pytester) -> None:
pytester.makepyfile(
"""
import pytest
from memray._test import MemoryAllocator
allocator = MemoryAllocator()
@pytest.mark.limit_memory("1MB")
def test_memory_alloc_fails():
allocator.valloc(1234)
allocator.free()
"""
)
result = pytester.runpytest("-Werror", "--memray")
assert result.ret == ExitCode.OK