2

Sometimes we need to mark a function parameter as deprecated, using a decorator.

For instance:

@deprecated_param(version="0.2.3",
                  reason="you may consider using *styles* instead.",
                  deprecated_args='color background_color')
def paragraph(text, color=None, background_color=None, styles=None):
    styles = styles or {}
    if color:
        styles['color'] = color
    if background_color:
        styles['background-color'] = background_color
    html_styles = " ".join("{k}: {v};".format(k=k, v=v) for k, v in styles.items())
    html_text = xml.sax.saxutils.escape(text)
    return ('<p styles="{html_styles}">{html_text}</p>'
            .format(html_styles=html_styles, html_text=html_text))

See https://github.com/tantale/deprecated/issues/8

I'm searching a good way to implement that.

Do you now any code examples in the Python Standard library or in famous open source projects (like Flask, Django, setuptools...)?

Laurent LAPORTE
  • 21,958
  • 6
  • 58
  • 103
  • https://stackoverflow.com/questions/49802412/how-to-implement-deprecation-in-python-with-argument-alias – qwr Aug 18 '23 at 14:38

1 Answers1

1

You can split deprecated_args into a set so that you can use set intersection to obtain the offending keyword arguments:

class deprecated_param:
    def __init__(self, deprecated_args, version, reason):
        self.deprecated_args = set(deprecated_args.split())
        self.version = version
        self.reason = reason

    def __call__(self, callable):
        def wrapper(*args, **kwargs):
            found = self.deprecated_args.intersection(kwargs)
            if found:
                raise TypeError("Parameter(s) %s deprecated since version %s; %s" % (
                    ', '.join(map("'{}'".format, found)), self.version, self.reason))
            return callable(*args, **kwargs)
        return wrapper

so that:

@deprecated_param(version="0.2.3",
                  reason="you may consider using *styles* instead.",
                  deprecated_args='color background_color')
def paragraph(text, color=None, background_color=None, styles=None):
    pass

paragraph('test')
paragraph('test', color='blue', background_color='white')

outputs:

TypeError: Parameter(s) 'color', 'background_color' deprecated since version 0.2.3; you may consider using *styles* instead.
blhsing
  • 91,368
  • 6
  • 71
  • 106
  • Actually, I am looking for a generic solution to implement that. But, first, I want to find some examples in the Python standard library and in popular open source libraries. What are the best practices, etc. – Laurent LAPORTE Mar 07 '19 at 07:27
  • 1
    Note that if the deprecated argument is provided by position, instead of by keyword, this will not catch it. – Will May 11 '20 at 19:09