mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-31 18:59:08 +00:00
feat: add deprecation dumpster
This commit is contained in:
127
erpnext/deprecation_dumpster.py
Normal file
127
erpnext/deprecation_dumpster.py
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
"""
|
||||||
|
Welcome to the Deprecation Dumpster: Where Old Code Goes to Party! 🎉🗑️
|
||||||
|
|
||||||
|
This file is the final resting place (or should we say, "retirement home"?) for all the deprecated functions and methods of the ERPNext app. It's like a code nursing home, but with more monkey-patching and less bingo.
|
||||||
|
|
||||||
|
Each function or method that checks in here comes with its own personalized decorator, complete with:
|
||||||
|
1. The date it was marked for deprecation (its "over the hill" birthday)
|
||||||
|
2. The ERPNext version in which it will be removed (its "graduation" to the great codebase in the sky)
|
||||||
|
3. A user-facing note on alternative solutions (its "parting wisdom")
|
||||||
|
|
||||||
|
Warning: The global namespace herein is more patched up than a sailor's favorite pair of jeans. Proceed with caution and a sense of humor!
|
||||||
|
|
||||||
|
Remember, deprecated doesn't mean useless - it just means these functions are enjoying their golden years before their final bow. Treat them with respect, and maybe bring them some virtual prune juice.
|
||||||
|
|
||||||
|
Enjoy your stay in the Deprecation Dumpster, where every function gets a second chance to shine (or at least, to not break everything).
|
||||||
|
"""
|
||||||
|
|
||||||
|
import inspect
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import warnings
|
||||||
|
|
||||||
|
|
||||||
|
def colorize(text, color_code):
|
||||||
|
if sys.stdout.isatty():
|
||||||
|
return f"\033[{color_code}m{text}\033[0m"
|
||||||
|
return text
|
||||||
|
|
||||||
|
|
||||||
|
class Color:
|
||||||
|
RED = 91
|
||||||
|
YELLOW = 93
|
||||||
|
CYAN = 96
|
||||||
|
|
||||||
|
|
||||||
|
class ERPNextDeprecationWarning(Warning):
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
# since python 3.13, PEP 702
|
||||||
|
from warnings import deprecated as _deprecated
|
||||||
|
except ImportError:
|
||||||
|
import functools
|
||||||
|
import warnings
|
||||||
|
from collections.abc import Callable
|
||||||
|
from typing import Optional, TypeVar, Union, overload
|
||||||
|
|
||||||
|
T = TypeVar("T", bound=Callable)
|
||||||
|
|
||||||
|
def _deprecated(message: str, category=ERPNextDeprecationWarning, stacklevel=1) -> Callable[[T], T]:
|
||||||
|
def decorator(func: T) -> T:
|
||||||
|
@functools.wraps(func)
|
||||||
|
def wrapper(*args, **kwargs):
|
||||||
|
if message:
|
||||||
|
warning_msg = f"{func.__name__} is deprecated.\n{message}"
|
||||||
|
else:
|
||||||
|
warning_msg = f"{func.__name__} is deprecated."
|
||||||
|
warnings.warn(warning_msg, category=category, stacklevel=stacklevel + 1)
|
||||||
|
return func(*args, **kwargs)
|
||||||
|
|
||||||
|
return wrapper
|
||||||
|
wrapper.__deprecated__ = True # hint for the type checker
|
||||||
|
|
||||||
|
return decorator
|
||||||
|
|
||||||
|
|
||||||
|
def deprecated(original: str, marked: str, graduation: str, msg: str, stacklevel: int = 1):
|
||||||
|
"""Decorator to wrap a function/method as deprecated.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
- original: frappe.utils.make_esc (fully qualified)
|
||||||
|
- marked: 2024-09-13 (the date it has been marked)
|
||||||
|
- graduation: v17 (generally: current version + 2)
|
||||||
|
- msg: additional instructions
|
||||||
|
"""
|
||||||
|
|
||||||
|
def decorator(func):
|
||||||
|
# Get the filename of the caller
|
||||||
|
frame = inspect.currentframe()
|
||||||
|
caller_filepath = frame.f_back.f_code.co_filename
|
||||||
|
if os.path.basename(caller_filepath) != "deprecation_dumpster.py":
|
||||||
|
raise RuntimeError(
|
||||||
|
colorize("The deprecated function ", Color.YELLOW)
|
||||||
|
+ colorize(func.__name__, Color.CYAN)
|
||||||
|
+ colorize(" can only be called from ", Color.YELLOW)
|
||||||
|
+ colorize("erpnext/deprecation_dumpster.py\n", Color.CYAN)
|
||||||
|
+ colorize("Move the entire function there and import it back via adding\n ", Color.YELLOW)
|
||||||
|
+ colorize(f"from erpnext.deprecation_dumpster import {func.__name__}\n", Color.CYAN)
|
||||||
|
+ colorize("to file\n ", Color.YELLOW)
|
||||||
|
+ colorize(caller_filepath, Color.CYAN)
|
||||||
|
)
|
||||||
|
|
||||||
|
func.__name__ = original
|
||||||
|
wrapper = _deprecated(
|
||||||
|
colorize(f"It was marked on {marked} for removal from {graduation} with note: ", Color.RED)
|
||||||
|
+ colorize(f"{msg}", Color.YELLOW),
|
||||||
|
stacklevel=stacklevel,
|
||||||
|
)
|
||||||
|
|
||||||
|
return functools.update_wrapper(wrapper, func)(func)
|
||||||
|
|
||||||
|
return decorator
|
||||||
|
|
||||||
|
|
||||||
|
def deprecation_warning(marked: str, graduation: str, msg: str):
|
||||||
|
"""Warn in-place from a deprecated code path, for objects use `@deprecated` decorator from the deprectation_dumpster"
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
- marked: 2024-09-13 (the date it has been marked)
|
||||||
|
- graduation: v17 (generally: current version + 2)
|
||||||
|
- msg: additional instructions
|
||||||
|
"""
|
||||||
|
|
||||||
|
warnings.warn(
|
||||||
|
colorize(
|
||||||
|
f"This codepath was marked (DATE: {marked}) deprecated"
|
||||||
|
f" for removal (from {graduation} onwards); note:\n ",
|
||||||
|
Color.RED,
|
||||||
|
)
|
||||||
|
+ colorize(f"{msg}\n", Color.YELLOW),
|
||||||
|
category=ERPNextDeprecationWarning,
|
||||||
|
stacklevel=2,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
### Party starts here
|
||||||
Reference in New Issue
Block a user