Skip to content

Commit b4461ac

Browse files
committed
numerous ruff revisions (squashed)
1 parent ce9cfe8 commit b4461ac

File tree

3 files changed

+57
-11
lines changed

3 files changed

+57
-11
lines changed

irods/manager/metadata_manager.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,8 @@ class InvalidAtomicAVURequest(Exception):
2929

3030
# This was necessarily made separate from the MetadataManager definition
3131
# in order to avoid infinite recursion in iRODSMetaCollection.__getattr__
32-
_MetadataManager_opts_initializer = {
33-
'admin':False,
34-
'timestamps':False,
35-
'iRODSMeta_type':iRODSMeta,
36-
'reload':True
37-
}
32+
_MetadataManager_opts_initializer = {'admin': False, 'timestamps': False, 'iRODSMeta_type': iRODSMeta, 'reload': True}
33+
3834

3935
class MetadataManager(Manager):
4036

irods/meta.py

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,16 +131,58 @@ def __init__(self, operation, avu, **kw):
131131

132132

133133
class iRODSMetaCollection:
134+
def __setattr__(self, name, value):
135+
"""
136+
Protect the virtual, read-only attributes such as 'admin', 'timestamps', etc.,
137+
from being written or created as concrete attributes, which would interfere with
138+
__getattr__'s intended operation for these cases.
139+
140+
Args:
141+
name: the name of the attribute to be written.
142+
value: the value to be written to the attribute.
143+
144+
Raises:
145+
AttributeError: on any attempt to write to these special attributes.
146+
"""
147+
from irods.manager.metadata_manager import _MetadataManager_opts_initializer
148+
149+
if name in _MetadataManager_opts_initializer:
150+
msg = (
151+
f"""The "{name}" attribute is a special one, settable only via a """
152+
f"""call on the object. For example: admin_view = data_obj.metadata({name}=<value>)"""
153+
)
154+
raise AttributeError(msg)
155+
156+
super().__setattr__(name, value)
157+
134158
def __getattr__(self, name):
159+
"""
160+
Expose certain settable flags (e.g. "admin", "timestamps") as virtual, read-only
161+
"attributes." The names of these special attributes appear as the keys of the
162+
_MetadataManager_opts_initializer dictionary.
163+
164+
Args:
165+
name: the name of the attribute to be fetched.
166+
167+
Returns:
168+
the value of the named attribute.
169+
170+
Raises:
171+
AttributeError: because this is the protocol for deferring to __getattr__'s
172+
default behavior for the case in which none of the special attribute keys are
173+
a match for 'name'.
174+
"""
135175
from irods.manager.metadata_manager import _MetadataManager_opts_initializer
176+
136177
# Separating _MetadataManager_opts_initializer from the MetadataManager class
137-
# prevents # the possibility of arbitrary access by copy.copy() to parts of
178+
# prevents the possibility of arbitrary access by copy.copy() to parts of
138179
# our object's state before they have been initialized, as it is known to do
139180
# by calling hasattr on the "__setstate__" attribute. The result of such
140181
# unfettered access is infinite recursion. See:
141182
# https://nedbatchelder.com/blog/201010/surprising_getattr_recursion
183+
142184
if name in _MetadataManager_opts_initializer:
143-
return self._manager._opts[name]
185+
return self._manager._opts[name] # noqa: SLF001
144186
raise AttributeError
145187

146188
def __call__(self, **opts):

irods/test/meta_test.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
iRODSMeta,
2222
)
2323
from irods.models import Collection, CollectionMeta, DataObject, ModelBase, Resource
24+
from irods.path import iRODSPath
2425
from irods.session import iRODSSession
2526
from irods.test import helpers
2627

@@ -820,8 +821,6 @@ def test_binary_avu_fields__issue_707(self):
820821
def test_cascading_changes_of_metadata_manager_options__issue_709(self):
821822
d = None
822823

823-
# def get_option(metacoll, key):
824-
# return metacoll._manager._opts[key]
825824
try:
826825
d = self.sess.data_objects.create(f'{self.coll.path}/issue_709_test_1')
827826
m = d.metadata
@@ -863,7 +862,16 @@ def test_reload_can_be_deactivated__issue_768(self):
863862
self.assertIn(item_1, items_reloaded)
864863
self.assertIn(item_2, items_reloaded)
865864

865+
def test_prevention_of_attribute_creation__issue_795(self):
866+
data_path = iRODSPath(self.coll_path, helpers.unique_name(datetime.datetime.now())) # noqa: DTZ005
867+
data = self.sess.data_objects.create(data_path)
868+
with self.assertRaises(AttributeError):
869+
# This should cause an error since "admin" is considered as a read-only attribute; whereas
870+
# data.metadata(admin = True) generates a cloned object but for the one change to "admin".
871+
data.metadata.admin = True
872+
873+
866874
if __name__ == "__main__":
867875
# let the tests find the parent irods lib
868876
sys.path.insert(0, os.path.abspath("../.."))
869-
unittest.main()
877+

0 commit comments

Comments
 (0)