We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Interfaces with Protocols and ABCs step 16 of 26
Restrict One Method to String Builders with Self Types
In the type hints track, you gave a fluent query builder Self return
types. A chain of calls on a subclass then kept the subclass's own methods.
This exercise adds two things. The builder's methods return a new builder
instead of changing the old one, and one method works only on builders of
strings.
QueryBuilder[T] is generic, and T records what kind of value the query
is about. The starter annotates each method as returning
"QueryBuilder[T]", so a chain on an AuditedQueryBuilder loses its
audit() method. Submit the starter, and mypy reports:
L35:9 [attr-defined]
"QueryBuilder[str]" has no attribute "audit"
Return Self from a method that builds a new object
Self stands for the class of the object you call the method on. The
method does not have to return self itself. where builds a new builder with
type(self)(...), which has the same class as self, so Self fits. The same
goes for the class method from_table, which calls cls(table).
Allow a method on string builders only
LIKE matches text, so like should type-check only on a
QueryBuilder[str]. Give like its own type parameter, and annotate
self with it:
def like[S: QueryBuilder[str]](self: S, pattern: str) -> S:
S: QueryBuilder[str] means S can be QueryBuilder[str] or any subclass
of it. On a QueryBuilder[int], mypy rejects the call with
Invalid self argument "QueryBuilder[int]" to attribute function "like".
Returning S keeps the class of self, so audit() still works after
like on an AuditedQueryBuilder[str]. At runtime every builder still has
a like method. Only mypy rejects the call.
What to write
Import Self from typing, and change only these annotations:
from_table,whereandlimitreturnSelf.likehas the signature above.
Keep the method bodies, the constructor, AuditedQueryBuilder and solve
as they are. Do not use Any or cast to get past mypy.
The bodies already do the right thing. Each method returns a new builder of
the same class with one more clause, and leaves the old builder unchanged.
build() joins the clauses into one string with no escaping, so never use
it on input you do not trust.
What the driver returns
solve(table, pattern, limit) builds one chain on a string builder, one on
an integer builder and one on an audited string builder. For
table="users", pattern="pat" and limit=5, it returns:
[
"SELECT * FROM users WHERE a = 1 LIKE 'pat' LIMIT 5",
"SELECT * FROM users WHERE id = 2 LIMIT 5",
"AUDIT[SELECT * FROM users WHERE b = 3 LIKE 'pat']",
]
The starter already returns these strings, so mypy is what this exercise
grades. The third chain type-checks only when both where and like keep
the subclass.
Your code, saved here
Sign in to access your accepted solutions and saved draft history. You can keep reading the lesson without an account.
Sign in to your accountStuck?
Python reference solution
Sign in to track your attempts toward unlocking the reference solution.