Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
6 changes: 2 additions & 4 deletions pymc/pytensorf.py
Original file line number Diff line number Diff line change
Expand Up @@ -567,10 +567,8 @@ def __init__(self, f):
def __call__(self, state):
return self.f(**state)

def __getattr__(self, item):
"""Allow access to the original function attributes."""
# This is only reached if `__getattribute__` fails.
return getattr(self.f, item)
def dprint(self, **kwrags):
return self.f.dprint(**kwrags)


class CallableTensor:
Expand Down
29 changes: 28 additions & 1 deletion tests/test_pytensorf.py
Original file line number Diff line number Diff line change
Expand Up @@ -746,7 +746,7 @@ def test_hessian_sign_change_warning(func):
assert equal_computations([res_neg], [-res])


def test_point_func():
def test_point_func(capsys):
x, y = pt.vectors("x", "y")
outs = x * 2 + y**2
f = compile([x, y], outs)
Expand All @@ -758,3 +758,30 @@ def test_point_func():
dprint_res = point_f.dprint(file="str")
expected_dprint_res = point_f.f.dprint(file="str")
assert dprint_res == expected_dprint_res

point_f.dprint(print_shape=True)
captured = capsys.readouterr()

# The shape=(?,) arises because the inputs are dvector. This checks that the dprint works, and the print_shape
# kwargs was correctly forwarded
assert "shape=(?,)" in captured.out


def test_pickle_point_func():
Copy link
Member

Choose a reason for hiding this comment

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

Just to be sure this failed before?

Copy link
Member Author

@jessegrabowski jessegrabowski Jul 20, 2025

Choose a reason for hiding this comment

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

Yep

FAILED                         [100%]
tests/test_pytensorf.py:769 (test_pickle_point_func)
def test_pickle_point_func():
        """
        Regression test for https://github.com/pymc-devs/pymc/issues/7857
        """
        import cloudpickle
    
        x, y = pt.vectors("x", "y")
        outs = x * 2 + y**2
        f = compile([x, y], outs)
    
        point_f = PointFunc(f)
        point_f_pickled = cloudpickle.dumps(point_f)
>       point_f_unpickled = cloudpickle.loads(point_f_pickled)
                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

test_pytensorf.py:782: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../pymc/pytensorf.py:573: in __getattr__
    return getattr(self.f, item)
                   ^^^^^^
../pymc/pytensorf.py:573: in __getattr__
    return getattr(self.f, item)
                   ^^^^^^
../pymc/pytensorf.py:573: in __getattr__
    return getattr(self.f, item)
                   ^^^^^^
E   RecursionError: maximum recursion depth exceeded
!!! Recursion detected (same locals & position)

"""
Regression test for https://github.com/pymc-devs/pymc/issues/7857
"""
import cloudpickle

x, y = pt.vectors("x", "y")
outs = x * 2 + y**2
f = compile([x, y], outs)

point_f = PointFunc(f)
point_f_pickled = cloudpickle.dumps(point_f)
point_f_unpickled = cloudpickle.loads(point_f_pickled)

# Check that the function survived the round-trip
np.testing.assert_allclose(
point_f_unpickled({"y": [3], "x": [2]}), point_f({"y": [3], "x": [2]})
)
Loading