diff --git a/mmengine/structures/base_data_element.py b/mmengine/structures/base_data_element.py index 67a31169..e2659647 100644 --- a/mmengine/structures/base_data_element.py +++ b/mmengine/structures/base_data_element.py @@ -1,5 +1,6 @@ # Copyright (c) OpenMMLab. All rights reserved. import copy +import sys from typing import Any, Iterator, Optional, Tuple, Type, Union import numpy as np @@ -458,7 +459,12 @@ class BaseDataElement: raise AttributeError( f'Cannot set {name} to be a field of data ' f'because {name} is already a metainfo field') - self._data_fields.add(name) + # The name only added to `data_fields`` when it is not the + # attribute related to property(methods decorated by @property). + if not isinstance( + getattr(type(self), + sys._getframe(1).f_code.co_name, None), property): + self._data_fields.add(name) super().__setattr__(name, value) # Tensor-like methods diff --git a/tests/test_structures/test_data_element.py b/tests/test_structures/test_data_element.py index 480d95b2..883ae401 100644 --- a/tests/test_structures/test_data_element.py +++ b/tests/test_structures/test_data_element.py @@ -9,6 +9,47 @@ import torch from mmengine.structures import BaseDataElement +class DetDataSample(BaseDataElement): + + @property + def proposals(self): + return self._proposals + + @proposals.setter + def proposals(self, value): + self.set_field(value=value, name='_proposals', dtype=BaseDataElement) + + @proposals.deleter + def proposals(self): + del self._proposals + + @property + def gt_instances(self): + return self._gt_instances + + @gt_instances.setter + def gt_instances(self, value): + self.set_field( + value=value, name='_gt_instances', dtype=BaseDataElement) + + @gt_instances.deleter + def gt_instances(self): + del self._gt_instances + + @property + def pred_instances(self): + return self._pred_instances + + @pred_instances.setter + def pred_instances(self, value): + self.set_field( + value=value, name='_pred_instances', dtype=BaseDataElement) + + @pred_instances.deleter + def pred_instances(self): + del self._pred_instances + + class TestBaseDataElement(TestCase): def setup_data(self): @@ -331,47 +372,6 @@ class TestBaseDataElement(TestCase): def test_inheritance(self): - class DetDataSample(BaseDataElement): - - @property - def proposals(self): - return self._proposals - - @proposals.setter - def proposals(self, value): - self.set_field( - value=value, name='_proposals', dtype=BaseDataElement) - - @proposals.deleter - def proposals(self): - del self._proposals - - @property - def gt_instances(self): - return self._gt_instances - - @gt_instances.setter - def gt_instances(self, value): - self.set_field( - value=value, name='_gt_instances', dtype=BaseDataElement) - - @gt_instances.deleter - def gt_instances(self): - del self._gt_instances - - @property - def pred_instances(self): - return self._pred_instances - - @pred_instances.setter - def pred_instances(self, value): - self.set_field( - value=value, name='_pred_instances', dtype=BaseDataElement) - - @pred_instances.deleter - def pred_instances(self): - del self._pred_instances - det_sample = DetDataSample() # test set @@ -415,6 +415,11 @@ class TestBaseDataElement(TestCase): # test_keys assert len(instances.keys()) == len(data.keys()) + det_sample = DetDataSample() + proposals = BaseDataElement(bboxes=torch.rand((5, 4))) + det_sample.proposals = proposals + assert '_proposals' not in det_sample.keys() + def test_items(self): # test_metainfo_items metainfo, data = self.setup_data() @@ -441,6 +446,13 @@ class TestBaseDataElement(TestCase): assert isinstance(dict_instances['gt_instances'], dict) assert isinstance(dict_instances['pred_instances'], dict) + det_sample = DetDataSample() + proposals = BaseDataElement(bboxes=torch.rand((5, 4))) + det_sample.proposals = proposals + dict_sample = det_sample.to_dict() + assert '_proposals' not in dict_sample + assert 'proposals' in dict_sample + def test_metainfo(self): # test metainfo property metainfo, data = self.setup_data()