Get Rid Of Deprecated Code¶
When your system relies on any 3rd party code, from time to time, you need to deal with deprecation. Addressing those issues usually doesn't seem urgent. Until you realize that you need to sort out a bunch of deprecated functions in order to get a security update.
Tackling those deprecations via rules instead of simple text replacement or editor macros provides several advantages:
- More flexibility: Catch occurrences of the deprecated function or parameter in various formats, not just exact matches.
- Well-documented steps. This might come handy when a replacement doesn't work as expected and you need to tweak your rules.
- Ensure that no future code will be added using the deprecated functionality.
The examples in this guide use some functions from the standard library and
pandas
. You can use them as templates to deal with the deprecated stuff in
your internal libraries.
Deprecating A Library¶
If you want to deprecate a whole library, check out our recipe Flag Dependencies to a Library.
Replacing A Renamed Function¶
If the deprecated function got replaced by a function with the same arguments, you can define a pattern to update all occurrences:
rules:
- id: warn-to-warning
description: Replace `logger.warn` with `warning`
pattern: logger.warn(${args*})
replacement: logger.warning(${args})
Provide Background Info About The Deprecation¶
You can use the optional explanation
field to provide more info about when and
why this function got deprecated. You can also include a link to the
documentation. Or a Slack thread if it's an internal package and the deprecation
was less formal :-)
rules:
- id: warn-to-warning
description: Replace `logger.warn` with `warning`
pattern: logger.warn(${args*})
replacement: logger.warning(${args})
explanation: |
`warn` is deprecated and functionally identical to `warning`.
https://docs.python.org/3/library/logging.html#logging.Logger.warning
Replace A Deprecated Method¶
You can use a similar syntax to replace a deprecated a method call on an object:
rules:
- id: deprecated-styler-set-na-rep
description: The method `Styler.set_na_rep()` has been deprecated
pattern: ${styler}.set_na_rep(${na_rep})
replacement: ${styler}.format(na_rep=${na_rep})
explanation: |
See the pandas docs:
- [Deprecate Styler.set_na_rep](https://pandas.pydata.org/pandas-docs/dev/reference/api/pandas.io.formats.style.Styler.set_na_rep.html)
- [`Styler.format()` docs](https://pandas.pydata.org/pandas-docs/dev/reference/api/pandas.io.formats.style.Styler.format.html#pandas.io.formats.style.Styler.format)
Caveat: This pattern will match every occassion when a .set_na_rep()
method is
called on any object. With specific method names like set_na_rep
that might be
safe, but don't create such rules with method names that are used by many
different types. When in doubt, create a rule without a replacement and evaluate
how big the signal vs noise ratio is.
Flagging A Deprecated Parameter¶
Sometimes, only a parameter of a function or a method gets deprecated. In these cases, you can create a rule that spots the usages of this parameter:
rules:
- id: deprecated-csv-prefix
description: Argument `prefix` for `read_csv` has been deprecated
pattern: pandas.read_csv(..., prefix=${pre}, ...)
explanation: |
See the [pandas docs for read_csv](https://pandas.pydata.org/docs/reference/api/pandas.read_csv.html)
tests:
- match: |
import pandas
df = pandas.read_csv("data.csv", prefix="ab")
- match: |
import pandas as pd
df = pd.read_csv("data.csv", prefix="ab")
- no-match: |
import pandas as pd
df = pd.read_csv("data.csv")
Note that this will only match if the parameter is called with a keyword argument.
Replacing A Deprecated Bool Parameter¶
If the deprecated parameter is a bool
, you often have different replacements
for the True
and False
values. In these cases, you can create 2 rules.
For example, in pandas 1.4.0, the squeeze
parameter of pandas.read_csv()
got
deprecated:
squeeze=True
: "Append.squeeze("columns")
to the call toread_csv
to squeeze the data." (see the pandas docs for read_csv)squeeze=False
:False
is the default value. => You can omit this argument.
You can translate this into 2 rules like this:
# 2 rules to deprecate the squeeze parameter for pandas.read_csv()
rules:
- id: deprecated_csv_squeeze_false
description: The parameter `squeeze` for `pandas.read_csv()` has been deprecated
pattern: pd.read_csv(${before*}, squeeze=False, ${after*})
replacement: pd.read_csv(${before}, ${after})
explanation: |
False is the default value for squeeze.
You can just omit this argument.
- id: deprecated-csv-squeeze-true
description: The parameter `squeeze` for `pandas.read_csv()` has been deprecated
pattern: pd.read_csv(${before*}, squeeze=True, ${after*})
replacement: pd.read_csv(${before}, ${after}).squeeze("columns")
explanation: |
Instead of squeeze=True,
append `.squeeze("columns")` to the call.
See the [pandas docs for read_csv](https://pandas.pydata.org/docs/reference/api/pandas.read_csv.html)
Note that the 2 rules can have the same description
, but they both need to
have a unique id
.
Note about imports: The rules above assume that you always import pandas
with
import pandas as pd
. If your codebase uses multiple aliases for pandas
, you
need to define multiple rules.
Remove An Obsolete Step From A Workflow¶
Let's say before creating an account, you need to execute some validation. This
used to be a separate function call, but now it has been incorporated into
create_account
. To avoid executing the same validations twice, you want to
remove the obsolete call.
rules:
- id: remove-separate-account-validation
description: Remove call to validate before account creation
pattern: |
validate_account_data(${account_data})
create_account(${account_data})
replacement: create_account(${account_data})
explanation: '`create_account` now calls the validation'
General Good Practices¶
- If it's obvious how the deprecated function should be replaced, create a rule
with a
replacement
. If the new implementation needs to be figured out by a human, create a rule without areplacement
. - Consider your function's signature. Does it support positional arguments? Keyword arguments?
- For more complex cases, create multiple rules. You can group them by using the same description. You can also add comments to your YAML file.
- Use the
explanation
field to provide background info about the deprecation. E.g. links to documentation, relevant conversations etc.