You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
== Why? ==
The use of Protocol was done with the intention of allowing third-party
duck-typed implementations of interface-style classes. But the mypy
static type analyzer yields errors if type inheritance is not explicit.
If third-party developers create duck-typed implementations without
inheriting from Builder, they'll hit mypy errors when their implicit
builder instance is used anywhere that expects the Builder type (e.g.
the BuildException constructor).
The only way to avoid the error is by explicitly inheriting from the
Protocol anyway:
class MyThirdPartyBuilder(Builder): # Still need to inherit!
...
So the Protocol doesn't actually enable true structural duck-typing in
practice with mypy—it still requires explicit inheritance. This defeats
the whole purpose of using Protocol over ABC.
The Protocol approach only provides value if:
- You're not using static type checkers, OR
- You mark the Protocol as @runtime_checkable and use it only for
runtime isinstance() checks, OR
- You're okay telling third-party developers "implement the interface
but also inherit from the Protocol" (which defeats the purpose)
This codebase cares about mypy compliance, so the Protocol provides
no practical benefit over ABC. Therefore, we may as well use:
from abc import ABC, abstractmethod
class Builder(ABC):
@AbstractMethod
def name(self) -> str: ...
# etc.
This is:
- Clearer in intent (you must inherit)
- Simpler to understand
- Identical in practice (since inheritance is required anyway for mypy)
The Protocol design was well-intentioned but doesn't deliver on its
promise in a type-checked codebase.
== Summary of Changes ==
1. Converted all Protocols to ABC:
- Builder(Protocol) → Builder(ABC)
- BuilderFactory(Protocol) → BuilderFactory(ABC)
- Scheme(Protocol) → Scheme(ABC)
- ScriptSyntax(Protocol) → ScriptSyntax(ABC)
2. Aligned Python Builder with Java's default methods:
In Builder ABC, these are now concrete default methods matching Java:
- rebuild() - calls delete() then build()
- file() - reads file and calls content()
- url() - fetches URL and calls content()
- log_debug() - subscribes output/error to stdout/stderr
All other methods remain abstract (require implementation).
3. Cleaned up BaseBuilder:
- Removed duplicate implementations now in Builder
- Made it much thinner - just stores configuration and implements
required abstract methods
Co-authored-by: Claude <noreply@anthropic.com>
0 commit comments