Skip to content

Commit 097cd37

Browse files
gnetsanetNetsanet Gebremedhinchenmoneygithub
authored
[docs] Add Google-style docstrings for Signature.prepend/append/insert/delete (#8945)
* docs(signature): add Google-style docstring for with_instructions (refs #8926) * docs(signature): docstrings for prepend/append/insert/delete (Fixes #8944) * docs(signature): unify backticks and finalize with_instructions docstring per style guide * docs(signature): fix mkdocs rendering and make example runnable per review feedback * Single backtick: instructions. * unify backticks and remove ambigous statements. * docs(signature): add runnable code examples for prepend, append, insert, and delete; completes Signature class docstrings (fixes issues #8942 and #8944) * Removed double backticks. * Removes the unnecessary assert statements. * Fixes the unintentional formatting change. * docs(signature): clarify insert docstring per reviewer feedback * nit --------- Co-authored-by: Netsanet Gebremedhin <[email protected]> Co-authored-by: chenmoneygithub <[email protected]>
1 parent e9c36ab commit 097cd37

File tree

1 file changed

+133
-1
lines changed

1 file changed

+133
-1
lines changed

dspy/signatures/signature.py

Lines changed: 133 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,31 @@ class Signature(BaseModel, metaclass=SignatureMeta):
245245

246246
@classmethod
247247
def with_instructions(cls, instructions: str) -> type["Signature"]:
248+
"""Return a new Signature class with identical fields and new instructions.
249+
250+
This method does not mutate `cls`. It constructs a fresh Signature
251+
class using the current fields and the provided `instructions`.
252+
253+
Args:
254+
instructions (str): Instruction text to attach to the new signature.
255+
256+
Returns:
257+
A new Signature class whose fields match `cls.fields`
258+
and whose instructions equal `instructions`.
259+
260+
Example:
261+
```python
262+
import dspy
263+
264+
class MySig(dspy.Signature):
265+
input_text: str = dspy.InputField(desc="Input text")
266+
output_text: str = dspy.OutputField(desc="Output text")
267+
268+
NewSig = MySig.with_instructions("Translate to French.")
269+
assert NewSig is not MySig
270+
assert NewSig.instructions == "Translate to French."
271+
```
272+
"""
248273
return Signature(cls.fields, instructions)
249274

250275
@classmethod
@@ -275,14 +300,87 @@ def with_updated_fields(cls, name: str, type_: type | None = None, **kwargs: dic
275300

276301
@classmethod
277302
def prepend(cls, name, field, type_=None) -> type["Signature"]:
303+
"""Insert a field at index 0 of the `inputs` or `outputs` section.
304+
305+
Args:
306+
name (str): Field name to add.
307+
field: `InputField` or `OutputField` instance to insert.
308+
type_ (type | None): Optional explicit type annotation. If `type_` is `None`, the effective type is
309+
resolved by `insert`.
310+
311+
Returns:
312+
A new `Signature` class with the field inserted first.
313+
314+
Example:
315+
```python
316+
import dspy
317+
318+
class MySig(dspy.Signature):
319+
input_text: str = dspy.InputField(desc="Input sentence")
320+
output_text: str = dspy.OutputField(desc="Translated sentence")
321+
322+
NewSig = MySig.prepend("context", dspy.InputField(desc="Context for translation"))
323+
print(list(NewSig.fields.keys()))
324+
```
325+
"""
278326
return cls.insert(0, name, field, type_)
279327

280328
@classmethod
281329
def append(cls, name, field, type_=None) -> type["Signature"]:
330+
"""Insert a field at the end of the `inputs` or `outputs` section.
331+
332+
Args:
333+
name (str): Field name to add.
334+
field: `InputField` or `OutputField` instance to insert.
335+
type_ (type | None): Optional explicit type annotation. If `type_` is `None`, the effective type is
336+
resolved by `insert`.
337+
338+
Returns:
339+
A new Signature class with the field appended.
340+
341+
Example:
342+
```python
343+
import dspy
344+
345+
class MySig(dspy.Signature):
346+
input_text: str = dspy.InputField(desc="Input sentence")
347+
output_text: str = dspy.OutputField(desc="Translated sentence")
348+
349+
NewSig = MySig.append("confidence", dspy.OutputField(desc="Translation confidence"))
350+
print(list(NewSig.fields.keys()))
351+
```
352+
"""
282353
return cls.insert(-1, name, field, type_)
283354

284355
@classmethod
285356
def delete(cls, name) -> type["Signature"]:
357+
"""Return a new Signature class without the given field.
358+
359+
If `name` is not present, the fields are unchanged (no error raised).
360+
361+
Args:
362+
name (str): Field name to remove.
363+
364+
Returns:
365+
A new Signature class with the field removed (or unchanged if the field was absent).
366+
367+
Example:
368+
```python
369+
import dspy
370+
371+
class MySig(dspy.Signature):
372+
input_text: str = dspy.InputField(desc="Input sentence")
373+
temp_field: str = dspy.InputField(desc="Temporary debug field")
374+
output_text: str = dspy.OutputField(desc="Translated sentence")
375+
376+
NewSig = MySig.delete("temp_field")
377+
print(list(NewSig.fields.keys()))
378+
379+
# No error is raised if the field is not present
380+
Unchanged = NewSig.delete("nonexistent")
381+
print(list(Unchanged.fields.keys()))
382+
```
383+
"""
286384
fields = dict(cls.fields)
287385

288386
fields.pop(name, None)
@@ -291,6 +389,38 @@ def delete(cls, name) -> type["Signature"]:
291389

292390
@classmethod
293391
def insert(cls, index: int, name: str, field, type_: type | None = None) -> type["Signature"]:
392+
"""Insert a field at a specific position among inputs or outputs.
393+
394+
Negative indices are supported (e.g., `-1` appends). If `type_` is omitted, the field's
395+
existing `annotation` is used; if that is missing, `str` is used.
396+
397+
Args:
398+
index (int): Insertion position within the chosen section; negatives append.
399+
name (str): Field name to add.
400+
field: InputField or OutputField instance to insert.
401+
type_ (type | None): Optional explicit type annotation.
402+
403+
Returns:
404+
A new Signature class with the field inserted.
405+
406+
Raises:
407+
ValueError: If `index` falls outside the valid range for the chosen section.
408+
409+
Example:
410+
```python
411+
import dspy
412+
413+
class MySig(dspy.Signature):
414+
input_text: str = dspy.InputField(desc="Input sentence")
415+
output_text: str = dspy.OutputField(desc="Translated sentence")
416+
417+
NewSig = MySig.insert(0, "context", dspy.InputField(desc="Context for translation"))
418+
print(list(NewSig.fields.keys()))
419+
420+
NewSig2 = NewSig.insert(-1, "confidence", dspy.OutputField(desc="Translation confidence"))
421+
print(list(NewSig2.fields.keys()))
422+
```
423+
"""
294424
# It's possible to set the type as annotation=type in pydantic.Field(...)
295425
# But this may be annoying for users, so we allow them to pass the type
296426
if type_ is None:
@@ -430,7 +560,9 @@ class MyType:
430560
# program of thought and teleprompters, so we just silently default to string.
431561
if type_ is None:
432562
type_ = str
433-
if not isinstance(type_, (type, typing._GenericAlias, types.GenericAlias, typing._SpecialForm, types.UnionType)):
563+
if not isinstance(
564+
type_, (type, typing._GenericAlias, types.GenericAlias, typing._SpecialForm, types.UnionType)
565+
):
434566
raise ValueError(f"Field types must be types, but received: {type_} of type {type(type_)}.")
435567
if not isinstance(field, FieldInfo):
436568
raise ValueError(f"Field values must be Field instances, but received: {field}.")

0 commit comments

Comments
 (0)