mad_accountant
mad_accountant

Reputation: 41

Class attribute not updating when using property decorators

I am trying to use property decorator to validate python object.

Following is my class

'''Contains all model classes. Each class corresponds to a database table'''

from validation import company_legal_type, max_len

class Company():
    '''A class to represent a company and its basic information'''
    
    def __init__(self, ref, name, currency, legal_type, business):
        self._ref = int(ref)
        self._name = name
        self._currency = str(currency) # i.e. The functional currency
        self._legal_type = str(legal_type)
        self._business = str(business)
    
    def __str__(self):
        return f"Company object for '{self._name}'"
    
    # Validate object attributes

    @property # Prevents change to ref after company object has been created
    def ref(self):
        return self._ref

    @property # The following two functions permit changes but set validation checks for name
    def name(self):
        return self._name
    
    @name.setter
    def name(self, value):
        if type(value) != str:
            raise TypeError("Company name must be a string.")
        if len(value) > max_len['company_name']:
            raise ValueError(f"Company name must not be longer than {str(max_len['company_name'])} characters.")

Following is validation.py

# data length validation
max_len = {
    'company_name': 200,
    'company_business': 200,
}

And finally here is how I am using the class:

# Import custom modules
from models import Company, Currency

company = Company(23, 'ABC Limited', 'PKR', 'pvt_ltd', 'manufacturing')    
company.name = 'ABCD Limited'

print(company.name)

This prints 'ABC Limited' instead of 'ABCD Limited'.

If I break a validation condition like use an integer instead of a string when updating company.name, it correctly results in an error. But if I break it when creating the object, no error is raised.

What am I doing wrong?

Upvotes: 0

Views: 428

Answers (1)

juanpa.arrivillaga
juanpa.arrivillaga

Reputation: 95873

The problem is your setter doesn't set anything. It merely raises errors on bad input. So you have to actually set something, or else how do you expect it to modify self._name? So:

@name.setter
def name(self, value):
    if type(value) != str:
        raise TypeError("Company name must be a string.")
    if len(value) > max_len['company_name']:
        raise ValueError(f"Company name must not be longer than {str(max_len['company_name'])} characters.")
    self._name = value

If I break a validation condition like use an integer instead of a string when updating company.name, it correctly results in an error. But if I break it when creating the object, no error is raised.

Because you don't use the property in __init__. Generally if you have validation property setters, you want to use those in __init__. So your __init__ should be something like:

def __init__(self, ref, name, currency, legal_type, business):
    self._ref = int(ref)
    self.name = name
    self._currency = str(currency) # i.e. The functional currency
    self._legal_type = str(legal_type)
    self._business = str(business)

Upvotes: 2

Related Questions