On this page

ProtocolCrafter๏ƒ

Use md.ProtocolCrafter from the public package namespace.

Implementation source

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.

Topic reference ยท Full contents