Skip to content
Open
Show file tree
Hide file tree
Changes from 3 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
1 change: 1 addition & 0 deletions __init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from pymc.printing import print_value
47 changes: 47 additions & 0 deletions printing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# pymc/printing.py

"""Helper utilities for debugging PyMC models."""

from pytensor.printing import Print

__all__ = ["print_value"]
Comment on lines +1 to +7
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file is added at the repository root as printing.py, but the package module that users/tests import is pymc/printing.py (which already exists). As a result, from pymc.printing import print_value will not find this function, and the helper won’t be available as pm.print_value. Move this helper into pymc/printing.py (and export it via that module’s __all__) and remove the root-level printing.py to avoid confusion/shadowing.

Copilot uses AI. Check for mistakes.


def print_value(var, name=None):
"""Print the value of a variable each time it is computed during sampling.

This wraps the variable in a ``pytensor.printing.Print`` op, which is a
pass-through that prints the variable's value as a side effect whenever it
is evaluated.

.. warning::
This may significantly affect sampling performance. Use only for
debugging purposes.

Parameters
----------
var : TensorVariable
The PyMC variable to debug-print.
name : str, optional
Label shown in the printed output. Defaults to ``var.name``.

Returns
-------
TensorVariable
The same variable, wrapped in a Print op (value is unchanged).

Examples
--------
.. code-block:: python

import pymc as pm

with pm.Model():
mu = pm.Normal("mu", mu=0, sigma=1)
mu = pm.print_value(mu, name="mu") # prints mu during sampling
obs = pm.Normal("obs", mu=mu, sigma=1, observed=[1, 2, 3])
idata = pm.sample()
"""
if name is None:
name = getattr(var, "name", "value")
return Print(name)(var)
2 changes: 1 addition & 1 deletion pymc/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,5 +78,5 @@ def __set_compiler_flags():
from pymc.util import drop_warning_stat
from pymc.variational import *
from pymc.vartypes import *

from pymc.printing import print_value
__version__ = _version.get_versions()["version"]
39 changes: 39 additions & 0 deletions tests/test_print_value.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# tests/test_printing.py

import pymc as pm
import pytensor.tensor as pt
from pytensor.printing import Print
from pymc.printing import print_value


def test_print_value_is_passthrough():
"""print_value should not change the variable's value."""
x = pt.vector("x")
x_printed = print_value(x, name="test_x")

import pytensor
import numpy as np

f = pytensor.function([x], x_printed)
result = f([1.0, 2.0, 3.0])
np.testing.assert_array_equal(result, [1.0, 2.0, 3.0])


def test_print_value_default_name():
"""print_value should use var.name if no name is given."""
x = pt.vector("my_var")
x_printed = print_value(x)
# The Print op's message should match the variable name
assert x_printed.owner.op.message == "my_var"


def test_print_value_custom_name():
"""print_value should use the custom name when provided."""
x = pt.vector("x")
x_printed = print_value(x, name="custom_label")
assert x_printed.owner.op.message == "custom_label"


def test_print_value_accessible_from_pm():
"""print_value should be accessible as pm.print_value."""
assert hasattr(pm, "print_value")
Loading