Skip to content

← Error Handling with Exceptions, Retries and Warnings step 17 of 20

Medium Framework

Report Calls to Deprecated Functions

Before you remove a deprecated function, you want a list of every place that still uses it. In this exercise you build that list. You get a table that says which names are deprecated, and a list of the places that use each name. The input is already worked out for you, so you do not parse any Python.

deprecation_report(
    {"old": "use new", "new": None},
    [("app", "old"), ("app", "new"), ("app", "old")],
)
# ["app: error: old is deprecated: use new  [deprecated]"]

What to write

deprecation_report(module_symbols, usages) -> list[str]:

  • module_symbols maps each name to its deprecation message, or to None when the name is not deprecated. Any string means deprecated, even the empty string "".
  • usages holds (caller, symbol) pairs in the order they were found. Both are plain strings.
  • Go through usages in order. If a symbol is missing from module_symbols, raise KeyError(symbol) at once, even if earlier usages were fine.
  • Skip symbols whose message is None.
  • Write one line for each distinct (caller, symbol) pair. The same pair used three times gives one line. Two deprecated symbols used by the same caller give two lines.
  • Sort the lines by caller, then by symbol, in Python's default string order. In that order uppercase letters come before lowercase ones, so "Client" sorts before "make_client".
  • Format each line exactly like this, with two spaces before [deprecated]:
{caller}: error: {symbol} is deprecated: {message}  [deprecated]

The format copies the style of the mypy message in the article Deprecate a Function Without Breaking Callers.

solve(module_symbols, usages) -> dict[str, object] calls deprecation_report and returns a dictionary with three keys:

Key Report built Unknown symbol
outcome "ok" "unknown-symbol"
symbol None The first unknown symbol
diagnostics The sorted lines An empty list

Catch the KeyError in solve to build the unknown-symbol report. Take the name from exc.args[0], because str(exc) puts quotes around it. Discard any lines found before the unknown symbol.

Edge cases

  • Empty usages gives an "ok" report with no lines, even when the table has deprecated names.
  • A deprecated name that nobody uses gives no line.

The exercise runs on Python 3.13 or later, to match the @deprecated decorator from the article. Your code does not need the decorator.