0

Considering below case,

ItemList Class:

# filename: item_list.py # locators dictionary is intentionally placed outside `ItemList` class locators = { 'item_id': 'css=tr:nth-of-type({item_num}) .id', 'item_title': 'css=tr:nth-of-type({item_num}) .alert-rules', # other properties } class ItemList(Item): # --- these are data descriptors --- # getting item_id value based on its item_num item_id = TextReadOnly(locators['item_id'].format(item_num=self.item_num)) # getting item_title value based on its item_num item_title = TextReadOnly(locators['item_title'].format(item_num=self.item_num)) def __init__(self, context, item_num=0): # self.item_num can't be passed to locators self.item_num = item_num super(ItemList, self).__init__( context ) 

In this case, I want to pass self.item_num value to item_num inside locators dictionary in ItemList class.

The reason is I want each of item_id and item_title refers to particular item_num.

I'm stuck on this part :

item_id = TextReadOnly(locators['item_id'].format(item_num=self.item_num)) item_title = TextReadOnly(locators['item_title'].format(item_num=self.item_num)) 

self.item_num value can't be passed to locators when instance is already made.

Implementation:

# filename: test.py # print item_id values from item_num=1 item_1 = ItemList(context, 1) print (‘Item_id_1: ’ + item_1.id) # print item_id values from item_num=2 item_2 = ItemList(context, 2) print (‘Item_id_2: ’ + item_2.id) # ^ no result produced from item_1.id and item_2.id because self.item_num value can't be passed to locators 

Is it possible to update data descriptor from instance variable?

How to pass instance variable value to data descriptor parameter?


Additional info:

I tried to call item_id and item_title as instance attribute but no luck. I noticed that data descriptor can’t be instance attribute from this post: Data descriptor should be a class attribute

Item Class:

# filename: item.py import abc class Item(Page): __metaclass__ = abc.ABCMeta def __init__(self, context): self.__context = context super(Item, self).__init__( self.__context.browser ) 

Descriptor:

# filename: text_read_only.py class TextReadOnly(object): def __init__(self, locator): self.__locator = locator def __get__(self, instance, owner=None): try: e = instance.find_element_by_locator(self.__locator) except AttributeError: e = instance.browser.find_element_by_locator(self.__locator) return e.text def __set__(self, instance, value): pass 
4
  • 1
    I think you are doing it wrong - the class attributes can't depend on instance attributes, as the class is initialized first. If you want item_id and item_title to vary per instance, why make them class attributes in the first place? Commented Aug 31, 2017 at 9:12
  • Hello @domoarrigato: I make item_id and item_title as class attributes because I want to use descriptor TextReadOnly. I noticed from this post that data descriptor should be a class attribute. Is there another approach to implement it? Commented Aug 31, 2017 at 9:17
  • 1
    If you want to keep them as class attributes, you can try to make them as "protected class properties", see [this][1] question to see how. In your specific case I think this is overkill, item_id and item_title look more like Instance Descriptors than Data Descriptors, so I'll make them as instance attributes. [1]: stackoverflow.com/questions/5189699/… Commented Aug 31, 2017 at 9:27
  • Hrabal and Domoarrigato: Thanks for both your answers. Those helped me to dig deeper about the concept of descriptor and instance attribute. I'll post the solution that worked for me. Commented Sep 21, 2017 at 16:53

1 Answer 1

0

I found this article and came up with solution to add the descriptors to an object.

This solution below worked for me:

  1. Add __getattribute__ and __setattr__ into Item Class

    # filename: item.py import abc class Item(Page): __metaclass__ = abc.ABCMeta def __init__(self, context): self.__context = context super(Item, self).__init__( self.__context.browser ) def __getattribute__(self, name): value = object.__getattribute__(self, name) if hasattr(value, '__get__'): value = value.__get__(self, self.__class__) return value def __setattr__(self, name, value): try: obj = object.__getattribute__(self, name) except AttributeError: pass else: if hasattr(obj, '__set__'): return obj.__set__(self, value) return object.__setattr__(self, name, value) 
  2. Move class attribute to instance attribute in ItemList constructor

    # filename: item_list.py # locators dictionary is intentionally placed outside `ItemList` class locators = { 'item_id': 'css=tr:nth-of-type({item_num}) .id', 'item_title': 'css=tr:nth-of-type({item_num}) .alert-rules', # other properties } class ItemList(Item): def __init__(self, context, item_num=0): self.item_num = item_num # self.item_num is able to be passed to locators self.item_id = TextReadOnly(locators['item_id'].format(item_num=self.item_num)) self.item_title = TextReadOnly(locators['item_title'].format(item_num=self.item_num)) super(ItemList, self).__init__( context ) 
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.