Maintain API Backward Compatibility

When changing code that affects a public interface (method signatures, CLI command arguments, plugin discovery, type/subscriptable behavior), treat it as an API contract: keep existing call patterns working, and ensure runtime semantics match the intended contract.

copy reviewer prompt

Prompt

Reviewer Prompt

When changing code that affects a public interface (method signatures, CLI command arguments, plugin discovery, type/subscriptable behavior), treat it as an API contract: keep existing call patterns working, and ensure runtime semantics match the intended contract.

Practical rules:

  • Preserve method/function signatures for externally-called APIs. If you need to change behavior, do it inside the body and/or accept/ignore parameters rather than removing them.
  • For new parameters/CLI shapes, explicitly define and implement the parsing rules (including list/dict-like variants) and add tests for those input forms.
  • For “interface-like” runtime behaviors (e.g., __class_getitem__ / subscripting), ensure the runtime object you return matches the expected semantics (e.g., types.GenericAlias) and add a small runtime test.
  • When behavior depends on Python/library versions (plugins, stdlib helpers), implement compatibility shims and test the relevant branches.

Example (signature stability):

class EagerResult:
    # Keep legacy parameters in the signature even if the internal behavior no longer needs them.
    def get(self, timeout=None, propagate=True, disable_sync_subtasks=True, **kwargs):
        if self.successful():
            return self.result
        if self.state in states.PROPAGATE_STATES:
            if propagate:
                raise self.result if isinstance(self.result, Exception) else Exception(self.result)
            return self.result

Example (CLI input contract parsing):

def revoke_by_stamped_header(state, header, terminate=False, signal=None, **kwargs):
    # Support either a list of headers or a list containing header=value pairs.
    headers = header if isinstance(header, list) else [header]
    parsed = []
    for h in headers:
        if '=' in h:
            k, v = h.split('=', 1)
            parsed.append((k, v))
        else:
            parsed.append(h)
    # ... use `parsed` with clear semantics

Add/adjust unit tests to lock in the contract (signature compatibility, parsing shapes, and runtime return types).

Source discussions