On this page
- ProtocolCrafter
ProtocolCrafterProtocolCrafter.cleanup()ProtocolCrafter.idProtocolCrafter.craft_protocol_code()ProtocolCrafter.craft_protocol_module_code_from_source_file()ProtocolCrafter.write_protocol_module_from_source_file()ProtocolCrafter.craft_joined_protocol_module_code()ProtocolCrafter.write_joined_protocol_module()ProtocolCrafter.add_protocol_to_interface_file()ProtocolCrafter.remove_protocol_from_interface_file()
ProtocolCrafter๏
Use md.ProtocolCrafter from the public package namespace.
- class ProtocolCrafter[source]๏
- Purpose:
Generate protocol code from a target class or object and maintain protocol blocks inside interface files.
- IT WRITES TO DISK - the unusual part:
Most of this codebase reads source; this one MODIFIES it. The write_protocol_module_from_source_file(...) and bounded block-update paths edit interface files in place. That makes it the sharpest tool in utilities/, and the reason its updates are BOUNDED: it rewrites a delimited region rather than a whole file, so hand-written code around the generated block survives regeneration.
- Registration:
MELDER KERNEL - guarded. Melder owns code-generation policy. It is nonetheless exported for direct use: guarding and exposure are orthogonal, and this is a tool a user calls rather than one Melder injects.
- Subsystem Context:
The only member of utilities/ai_native_support_tools/, and one of the two AI-native surfaces in utilities/ alongside ClassSurfaceAstDescriber. The pairing is natural: the describer READS a class surface into a structured answer, this one WRITES a class surface out as a Protocol. Same reflection, opposite direction.
- System Context:
Exported from the package root, so an agent that has import melder can reach it directly. It serves the interface discipline the repository follows - concrete types plus TYPE_CHECKING imports by default, with Protocols written only where structure genuinely is the contract - by making the Protocol half mechanical instead of hand-maintained.
Contract:
Accepts either a class object or a concrete instance as the target.
Produces one @runtime_checkable protocol block whose name is the target class name prefixed with I.
Mirrors class and method docstrings when present and generates fallback docstrings when they are missing.
Mirrors attributes from class annotations/class-level values and, for object inputs, current instance state.
Mirrors methods as protocol stubs with ... bodies.
When include_inheritance=True, walks the target MRO and mirrors inherited members too.
File-update helpers are bounded to append/remove behavior for protocol blocks; they do not attempt broad import rewriting or arbitrary file refactors.
- Threading:
Public operations execute under the instance RLock so generation and file updates remain grouped and deterministic in a nogil runtime.
- Lifecycle:
Cleanup is idempotent and only releases the crafter's local state.
AGENT_ACCESS: public
- AGENT_PURPOSE:
access: public. Generates @runtime_checkable Protocol code from a class/object (craft_protocol_code) and maintains bounded protocol blocks in interface files (write_protocol_module_from_source_file). Exported for direct use; guarded, so call it - do not bind it. It WRITES to disk, editing a delimited region only.
- cleanup() None[source]๏
Idempotently clear the protocol crafter state.
Contract:
IDEMPOTENT under double-checked locking.
Owns no external resources, so cleanup releases identity only - it does not touch any module it previously wrote.
- Threading:
Double-checked around the crafter lock.
- Lifecycle / Cleanup:
Safe to call more than once and from more than one thread.
- Returns:
None.
- property id: str๏
Return the stable identifier for this protocol crafter instance.
Contract:
Identifies this crafter instance; stable for its life.
- Threading:
Reads under self._lock, so the result is a coherent snapshot.
- Lifecycle / Cleanup:
Guarded by check_cleaned().
- Raises:
RuntimeError -- If the object has been cleaned.
- Returns:
Stable protocol crafter identifier.
- Return type:
str
- craft_protocol_code(target: object, *, include_inheritance: bool = False) str[source]๏
Generate one protocol code block from a target class or object.
- Parameters:
target -- Target class object or concrete instance to mirror into protocol form.
include_inheritance -- True to include members from the full non-object MRO. False to mirror only the direct target class plus current instance state when an object instance is provided.
- Returns:
Generated @runtime_checkable protocol code block.
- Return type:
str
- Raises:
TypeError -- If target is None or cannot be normalized to a class.
- craft_protocol_module_code_from_source_file(source_file_path: str | Path, class_name: str, *, protocol_name: str | None = None) str[source]๏
Build one complete protocol-module string from a source file and class.
- Parameters:
source_file_path -- Path to the Python source file that defines the target class.
class_name -- Exact class name to mirror into protocol form.
protocol_name -- Optional explicit protocol class name. Defaults to I<class>.
- Returns:
Fully formed protocol-module source text.
- Return type:
str
- Raises:
ValueError -- If the file cannot be parsed or the class is not found.
- write_protocol_module_from_source_file(source_file_path: str | Path, class_name: str, output_directory: str | Path, *, protocol_name: str | None = None) Path[source]๏
Write one generated protocol module into a chosen directory.
- Parameters:
source_file_path -- Path to the Python source file that defines the target class.
class_name -- Exact class name to mirror into protocol form.
output_directory -- Directory that will receive the generated protocol module.
protocol_name -- Optional explicit protocol class name. Defaults to I<class>.
Contract:
DEFAULTS THE PROTOCOL NAME to I + the class name when none is supplied, so Foo becomes IFoo unless you override it.
WRITES TO DISK: it crafts the module text and then persists it, so this is not a pure computation. Use the craft_... method when you want the text without a file.
Overwrites an existing file at the resolved output path.
- Threading:
Reads under self._lock, so the result is a coherent snapshot.
- Lifecycle / Cleanup:
Guarded by check_cleaned().
- Raises:
RuntimeError -- If the object has been cleaned.
- Returns:
Written protocol-module path.
- Return type:
Path
- craft_joined_protocol_module_code(targets: Sequence[tuple[str | Path, str]], protocol_name: str) str[source]๏
Build one protocol module from the shared surface of multiple classes.
- Parameters:
targets -- (source_file_path, class_name) tuples to compare.
protocol_name -- Protocol class name to emit for the shared surface.
- Returns:
Fully formed shared protocol-module source text.
- Return type:
str
- Raises:
ValueError -- If fewer than two targets are supplied or a class cannot be located.
- write_joined_protocol_module(targets: Sequence[tuple[str | Path, str]], protocol_name: str, output_directory: str | Path) Path[source]๏
Write one joined protocol module into a chosen directory.
- Parameters:
targets -- (source_file_path, class_name) tuples to compare.
protocol_name -- Protocol class name to emit for the shared surface.
output_directory -- Directory that will receive the generated protocol module.
Contract:
Crafts ONE protocol module covering SEVERAL targets, so the protocol name is required rather than derived - there is no single class to derive it from.
WRITES TO DISK, like its single-source counterpart, and overwrites an existing file at the resolved output path.
- Threading:
Reads under self._lock, so the result is a coherent snapshot.
- Lifecycle / Cleanup:
Guarded by check_cleaned().
- Raises:
RuntimeError -- If the object has been cleaned.
- Returns:
Written protocol-module path.
- Return type:
Path
- add_protocol_to_interface_file(interface_file_path: str | Path, protocol_code: str) str[source]๏
Append one generated protocol block into an interface file.
- Parameters:
interface_file_path -- Path to the target interface file.
protocol_code -- Generated protocol code block to append.
- Returns:
Updated file contents after the append.
- Return type:
str
- Raises:
ValueError -- If protocol_code is empty or the target protocol already exists in the file.
- remove_protocol_from_interface_file(interface_file_path: str | Path, protocol_name: str) str[source]๏
Remove one protocol block from an interface file.
- Parameters:
interface_file_path -- Path to the target interface file.
protocol_name -- Exact protocol class name to remove.
- Returns:
Updated file contents after removal.
- Return type:
str
- Raises:
ValueError -- If protocol_name is empty or the protocol block is not found.