Lifecycle Management#

As Sopel grows and evolves, sometimes it needs to say goodbye to obsolete code and replace it. The solution can be new (and hopefully better) code, switching to an external library, or maybe putting the feature into an external plugin.

In any case, Sopel will always try to mark as deprecated what will be removed, indicating when it was deprecated, and when it should be removed. The goal is to help Sopel developers and plugin authors understand what must be done to adapt their code to a future version of Sopel:

Deprecated since 8.0, will be removed in 9.0: sopel.module has been
replaced by sopel.plugin
  File "/home/exirel/dev/sopel/sopel/module.py", line 46, in <module>
    deprecated(

This example above shows a deprecation warning for the sopel.module module that is deprecated: it shows when it was deprecated (Sopel 8.0), when it will be removed (Sopel 9.0), and how to fix that warning (use sopel.plugin).

Although this feature is primarily for use by Sopel developers, plugin authors can also take advantage of it with the sopel.lifecycle.deprecated() function documented below.

sopel.lifecycle#

Deprecation module for Sopel developers and plugin authors.

New in version 8.0: Previously in sopel.tools, the deprecated() function has been moved to this newly created module, as it can be used in every part of the Sopel codebase, including sopel.tools itself.

sopel.lifecycle.deprecated(
reason: str | None = None,
version: str | None = None,
removed_in: str | None = None,
warning_in: str | None = None,
stack_frame: int = -1,
func: Callable | None = None,
)#

Decorator to mark deprecated functions in Sopel’s API

Parameters:
  • reason – optional text added to the deprecation warning

  • version – optional version number when the decorated function is deprecated

  • removed_in – optional version number when the deprecated function will be removed

  • warning_in – optional version number when the decorated function should start emitting a warning when called

  • stack_frame – optional stack frame to output; defaults to -1; should almost always be negative

  • func – deprecated function

Returns:

a callable that depends on how the decorator is called; either the decorated function, or a decorator with the appropriate parameters

Any time the decorated func is called, a deprecation warning will be logged, with the last frame of the traceback. The optional warning_in argument suppresses the warning on Sopel versions older than that, allowing for multi-stage deprecation timelines.

The decorator can be used with or without arguments:

from sopel.lifecycle import deprecated

@deprecated
def func1():
    print('func 1')

@deprecated()
def func2():
    print('func 2')

@deprecated(reason='obsolete', version='7.0', removed_in='8.0')
def func3():
    print('func 3')

which will output the following in a console:

>>> func1()
Deprecated: func1
File "<stdin>", line 1, in <module>
func 1
>>> func2()
Deprecated: func2
File "<stdin>", line 1, in <module>
func 2
>>> func3()
Deprecated since 7.0, will be removed in 8.0: obsolete
File "<stdin>", line 1, in <module>
func 3

The stack_frame argument can be used to choose which stack frame is logged along with the message text. By default, this decorator logs the most recent stack frame (the last entry in the list, -1), corresponding to where the decorated function itself was called. However, in certain cases such as deprecating conditional behavior within an object constructor, it can be useful to show a less recent stack frame instead.

Note

This decorator can be also used on callables that are not functions, such as classes and callable objects.

New in version 7.0: Parameters reason, version, and removed_in.

New in version 7.1: The warning_in and stack_frame parameters.

Changed in version 8.0: Moved out of sopel.tools to resolve circular dependency issues.