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
10 changes: 9 additions & 1 deletion dspy/functional/functional.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,12 +98,20 @@ def __init__(self, signature, instructions=None, *, max_retries=3, wrap_json=Fal
explain_errors: If True, the model will try to explain the errors it encounters.
"""
super().__init__()
self.signature = ensure_signature(signature, instructions)
signature = ensure_signature(signature, instructions)
self.predictor = dspy.Predict(signature, _parse_values=False)
self.max_retries = max_retries
self.wrap_json = wrap_json
self.explain_errors = explain_errors

@property
def signature(self) -> dspy.Signature:
return self.predictor.signature

@signature.setter
Copy link

@fireking77 fireking77 Oct 20, 2024

Choose a reason for hiding this comment

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

If you want to ensure that this value is not set outside the object initialization (bootstrapping), I would remove the setter to prevent anyone from using it to set the value. Of course, the tests should still pass.

In summary, if you don't plan to use it, the setter is unnecessary.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Unfortunately we have to keep self.signature being readable and settable, otherwise it could break people's existing code.

def signature(self, value: dspy.Signature):
self.predictor.signature = value

def copy(self) -> "TypedPredictor":
return TypedPredictor(
self.signature,
Expand Down
20 changes: 20 additions & 0 deletions tests/functional/test_functional.py
Original file line number Diff line number Diff line change
Expand Up @@ -822,3 +822,23 @@ def check_cateogry(self):

pred = predictor(input_data="What is the best animal?", allowed_categories=["cat", "dog"])
assert pred.category == "dog"

def test_save_type_predictor(tmp_path):
class MySignature(dspy.Signature):
"""I am a benigh signature."""
question: str = dspy.InputField()
answer: str = dspy.OutputField()

class CustomModel(dspy.Module):
def __init__(self):
self.predictor = dspy.TypedPredictor(MySignature)

save_path = tmp_path / "state.json"
model = CustomModel()
model.predictor.signature = MySignature.with_instructions("I am a malicious signature.")
model.save(save_path)

loaded = CustomModel()
assert loaded.predictor.signature.instructions == "I am a benigh signature."
loaded.load(save_path)
assert loaded.predictor.signature.instructions == "I am a malicious signature."
Loading