Menu

Tree [3a2555] default tip /
 History

Read Only access


File Date Author Commit
 _doc 2023-07-27 Anthon van der Neut Anthon van der Neut [dbcec8] allow filtering of subclasses
 .hgtags 2023-07-27 Anthon van der Neut Anthon van der Neut [3a2555] Added tag 0.3.0 for changeset dbcec88e5c4c
 README.rst 2023-07-26 Anthon van der Neut Anthon van der Neut [06fc6a] added icons, update package name
 _README.ryd 2023-07-26 Anthon van der Neut Anthon van der Neut [06fc6a] added icons, update package name
 __init__.py 2023-07-27 Anthon van der Neut Anthon van der Neut [dbcec8] allow filtering of subclasses
 setup.py 2023-07-27 Anthon van der Neut Anthon van der Neut [dbcec8] allow filtering of subclasses
 tox.ini 2023-07-27 Anthon van der Neut Anthon van der Neut [dbcec8] allow filtering of subclasses

Read Me

extend warnings.warn with callee parameter

https://sourceforge.net/p/ruamel-std-warnings/code/ci/default/tree/_doc/_static/license.svg?format=raw https://sourceforge.net/p/ruamel-std-warnings/code/ci/default/tree/_doc/_static/pypi.svg?format=raw https://sourceforge.net/p/oitnb/code/ci/default/tree/_doc/_static/oitnb.svg?format=raw

When you have some library, with some deprecated function X, you can use the stacklevel=2 parameter on warnings.warn to show the file-name and line-number of the routine calling X

But if you have some framework that calls the user provided code, either through plug-ins or by explicit registering, the stacklevel doesn't help you to complain about return values that are deprecated.

This library extends warnings.warn with a callee parameter. If this is provided stacklevel should not be provided and the value for callee should be a method or function for which the warning is raised.

The warning will usually be a PendingDeprecationWarning, a DeprecationWarning or a subclass of either.

As an example, if you have two files p0.py and p2.py both with content:

class PlugIn:
 def status(self):
     return {'result': 'ok'}

And a file p1.py:

class PlugIn:
    def status(self):
        return ['ok'] # this plug-in has been updated

And these files are in a subfolder plug_ins where your framework can find them. Then running:

import sys
from pathlib import Path
from importlib import import_module
import ruamel.std.warnings
import warnings

class DictReturnPendingDeprecationWarning(PendingDeprecationWarning):
    pass

class Driver:
    def __init__(self):
        self.plug_ins = []

    def load_plug_ins(self):
        sys.path.append('plug_ins')
        for file_name in Path('plug_ins').glob('p*.py'):
            mod = import_module(file_name.stem)
            self.plug_ins.append(mod.PlugIn())

    def check_status(self):
        for p in self.plug_ins:
            retval = p.status()
            if isinstance(retval, dict):
                # assume dict
                warnings.warn(
                   'callable should return list, not dict',
                   DictReturnPendingDeprecationWarning,
                   callee=p.status,
                )
            else:
                pass  # assume list

warnings.simplefilter('once', PendingDeprecationWarning)

def doit():
    driver = Driver()
    driver.load_plug_ins()
    for idx in range(2):
        driver.check_status()
    warnings.warn('almost done', PendingDeprecationWarning)

doit()

will result in:

/tmp/plug_ins/p0.py:2: DictReturnPendingDeprecationWarning: callable should return list, not dict
  def status(self):
/tmp/plug_ins/p2.py:2: DictReturnPendingDeprecationWarning: callable should return list, not dict
  def status(self):
/tmp/tmp_00.py:40: PendingDeprecationWarning: almost done
  warnings.warn('almost done', PendingDeprecationWarning)
Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.