Fix usage of callable_deprecation on LazyObject that was breaking CW 3.24 (or something like that)
So, brace yourself, it's a little bit complicated (don't hesitate to reach me for more explanation).
So, it goes like that:
- I've introduced the usage of the
@wraps
decorator from functools.wraps in logilab.common.deprecation.callable_deprecated because this is a good practice - turns out if broke francearchives code
- which is because it uses an old version of CW
- in this old version of CW, logilab.common.modutils.LazyObject is used (well, inherited) here https://forge.extranet.logilab.fr/cubicweb/cubicweb/blob/3.24.0/cubicweb/schemas/__init__.py#L51
- LazyObject all you to do something like
exists = LazyObject("os.path", "exists")
and up untilexists
is used, the import is not triggered - here "used" means "access attributes or call it"
- so, CW uses (My)LazyObject to prepare to import a bunch of cubes (but not importing them) and mark them as callable_deprecated
- this allow to raise a deprecation warning if they are used but not add those cubes as dependencies in CW
Now, why is it a problem? Well ...
- turns out:
functools.@wraps
actually try to access a bunch of attributes on the wrapped callable to grab__name__
, 'dict, '__doc__
to avoid breaking a bunch of stuff - going back to before, you might have guessed it: by trying to access those attributes,
functools.@wraps
triggers the import of those objects - which in turns breaks everything because this is supposed to be a lazy import and so it was supposed to handle the case where those dependencies weren't installed
- and you get an ImportError and your code doesn't work anymore
So, this MR:
- recreate the behavior of functools.wraps but in a lazy way to solve this issue
- it also ensure that we never access attributes of the decorated callable before this decorated callable is actually called
- document LazyObject because pffff
I think it's the first time I had to debug one exception that triggered 3-4 other exceptions ^^'
Also protip: uses pdbpp instead of pdb, it allows to access hidden frames.