184 lines
5.5 KiB
Python
184 lines
5.5 KiB
Python
import functools
|
|
import inspect
|
|
import os
|
|
import warnings
|
|
from typing import Any, Callable, Set
|
|
|
|
|
|
class SupervisionWarnings(Warning):
|
|
"""Supervision warning category.
|
|
Set the deprecation warnings visibility for Supervision library.
|
|
You can set the environment variable SUPERVISON_DEPRECATION_WARNING to '0' to
|
|
disable the deprecation warnings.
|
|
"""
|
|
|
|
pass
|
|
|
|
|
|
def format_warning(msg, category, filename, lineno, line=None):
|
|
"""
|
|
Format a warning the same way as the default formatter, but also include the
|
|
category name in the output.
|
|
"""
|
|
return f"{category.__name__}: {msg}\n"
|
|
|
|
|
|
warnings.formatwarning = format_warning
|
|
|
|
if os.getenv("SUPERVISON_DEPRECATION_WARNING") == "0":
|
|
warnings.simplefilter("ignore", SupervisionWarnings)
|
|
else:
|
|
warnings.simplefilter("always", SupervisionWarnings)
|
|
|
|
|
|
def deprecated_parameter(
|
|
old_parameter: str,
|
|
new_parameter: str,
|
|
map_function: Callable = lambda x: x,
|
|
warning_message: str = "Warning: '{old_parameter}' in '{function_name}' is "
|
|
"deprecated: use '{new_parameter}' instead.",
|
|
**message_kwargs,
|
|
):
|
|
"""
|
|
A decorator to mark a function's parameter as deprecated and issue a warning when
|
|
used.
|
|
|
|
Parameters:
|
|
old_parameter (str): The name of the deprecated parameter.
|
|
new_parameter (str): The name of the parameter that should be used instead.
|
|
map_function (Callable, optional): A function used to map the value of the old
|
|
parameter to the new parameter. Defaults to the identity function.
|
|
warning_message (str, optional): The warning message to be displayed when the
|
|
deprecated parameter is used. Defaults to a generic warning message with
|
|
placeholders for the old parameter, new parameter, and function name.
|
|
**message_kwargs: Additional keyword arguments that can be used to customize
|
|
the warning message.
|
|
|
|
Returns:
|
|
Callable: A decorator function that can be applied to mark a function's
|
|
parameter as deprecated.
|
|
|
|
Examples:
|
|
```python
|
|
@deprecated_parameter(
|
|
old_parameter=<OLD_PARAMETER_NAME>,
|
|
new_parameter=<NEW_PARAMETER_NAME>
|
|
)
|
|
def example_function(<NEW_PARAMETER_NAME>):
|
|
pass
|
|
|
|
# call function using deprecated parameter
|
|
example_function(<OLD_PARAMETER_NAME>=<OLD_PARAMETER_VALUE>)
|
|
```
|
|
"""
|
|
|
|
def decorator(func):
|
|
@functools.wraps(func)
|
|
def wrapper(*args, **kwargs):
|
|
if old_parameter in kwargs:
|
|
if args and hasattr(args[0], "__class__"):
|
|
class_name = args[0].__class__.__name__
|
|
function_name = f"{class_name}.{func.__name__}"
|
|
else:
|
|
function_name = func.__name__
|
|
|
|
warnings.warn(
|
|
message=warning_message.format(
|
|
function_name=function_name,
|
|
old_parameter=old_parameter,
|
|
new_parameter=new_parameter,
|
|
**message_kwargs,
|
|
),
|
|
category=SupervisionWarnings,
|
|
stacklevel=2,
|
|
)
|
|
|
|
kwargs[new_parameter] = map_function(kwargs.pop(old_parameter))
|
|
|
|
return func(*args, **kwargs)
|
|
|
|
return wrapper
|
|
|
|
return decorator
|
|
|
|
|
|
def deprecated(reason: str):
|
|
def decorator(func):
|
|
@functools.wraps(func)
|
|
def wrapper(*args, **kwargs):
|
|
warnings.warn(
|
|
f"{func.__name__} is deprecated: {reason}",
|
|
category=SupervisionWarnings,
|
|
stacklevel=2,
|
|
)
|
|
return func(*args, **kwargs)
|
|
|
|
return wrapper
|
|
|
|
return decorator
|
|
|
|
|
|
class classproperty(property):
|
|
"""
|
|
A decorator that combines @classmethod and @property.
|
|
It allows a method to be accessed as a property of the class,
|
|
rather than an instance, similar to a classmethod.
|
|
|
|
Usage:
|
|
@classproperty
|
|
def my_method(cls):
|
|
...
|
|
"""
|
|
|
|
def __get__(self, owner_self: object, owner_cls: type) -> object:
|
|
"""
|
|
Override the __get__ method to return the result of the function call.
|
|
|
|
Args:
|
|
owner_self: The instance through which the attribute was accessed, or None.
|
|
owner_cls: The class through which the attribute was accessed.
|
|
|
|
Returns:
|
|
The result of calling the function stored in 'fget' with 'owner_cls'.
|
|
"""
|
|
return self.fget(owner_cls)
|
|
|
|
|
|
def get_instance_variables(instance: Any, include_properties=False) -> Set[str]:
|
|
"""
|
|
Get the public variables of a class instance.
|
|
|
|
Args:
|
|
instance (Any): The instance of a class
|
|
include_properties (bool): Whether to include properties in the result
|
|
|
|
Usage:
|
|
```python
|
|
detections = Detections(xyxy=np.array([1,2,3,4]))
|
|
variables = get_class_variables(detections)
|
|
# ["xyxy", "mask", "confidence", ..., "data"]
|
|
```
|
|
"""
|
|
if isinstance(instance, type):
|
|
raise ValueError("Only class instances are supported, not classes.")
|
|
|
|
fields = set(
|
|
(
|
|
name
|
|
for name, val in inspect.getmembers(instance)
|
|
if not callable(val) and not name.startswith("_")
|
|
)
|
|
)
|
|
|
|
if not include_properties:
|
|
properties = set(
|
|
(
|
|
name
|
|
for name, val in inspect.getmembers(instance.__class__)
|
|
if isinstance(val, property)
|
|
)
|
|
)
|
|
fields -= properties
|
|
|
|
return fields
|