Search code examples
pythonrefactoringdeprecatedbuilder-pattern

Python: Throw warning when class is instantiated outside builder


I have a class which constructor is getting overly complicated so I wanted to use a builder pattern to manage all the construction steps.

The thing is an important part of the application depends on the old way of instantiating the class, so I can't just replace them all in one go. I have used a decorator to mark some methods as deprecated, but I'd like to throw a warning if the class is being instantiated outside of the builder class.

To give a little more context, the constructor of the original class (Inverter) looks like this:

    def __init__(self, inverter_id: str, location: Tuple[str, str], plant_id: str,
                 customer_id: str, power_threshold: float = 0, resolution: int = 5,
                 **kwargs):
        """
        Creates a new inverter object.
        :param inverter_id:
            unique identifier of the inverter.
        """
        # metrics initialization
        self._customer_id = customer_id
        self._plant_id = plant_id
        self._expected_power = DataFrame()
        self._generated_power = DataFrame()
        self._total_pr = 0.0
        self._specific_performance = 0.0
        self._active_pr = 0.0
        self._generated_energy = 0.0
        self._expected_energy = 0.0
        self.__operational_time = {}
        self.__off_time = {}
        self.__savings = 0.0

        # parameters initialization
        self._power_threshold = power_threshold
        self._resolution = 5
        self._energy_rate = kwargs['energy_rate']
        self._lines = []
        # identification
        self._id = inverter_id
        self._location = location
        self._resolution = resolution

        # data storing
        self._inverter_electric_data = None
        self._inverter_environmental_data = None
        self._inverter_metadata = None

And many of the parameters are then feeded to the class by other methods, and the idea would be to feed those values to the builder class like:

inverter = InverterBuilder().set_id("some_id").build()

My initial idea was to add a deprecation warning to the constructor but that would make the builder throw the warning too.

So, is there a way to throw a warning when the original class constructor is called from outside of the builder class?

For example, throw a warning if someone does:

inverter = Inverter(...)

As an additional note, I'm using the deprecation library to mark the methods as deprecated.


Solution

  • Your original __init__ already takes a **kwargs argument - use it.

    ...
        def __init__(self, inverter_id: str, location: Tuple[str, str], plant_id: str,
                     customer_id: str, power_threshold: float = 0, resolution: int = 5,
                     **kwargs):
            """
            Creates a new inverter object.
            :param inverter_id:
                unique identifier of the inverter.
            """
            ...
            if kwargs.get('invokewarning',True):
                #issue warning
    

    Then the builder can pass invokewarning=False.

    I imagine there are a few other ways to solve this.