Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions irods/manager/metadata_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,13 @@
def __init__(self, *_):
self._opts = _MetadataManager_opts_initializer.copy()
super().__init__(*_)
# For the iRODS-api keywords only (currently ADMIN_KW is the sole one used):
self.__kw = {}

@property
def use_timestamps(self):
return self._opts['timestamps']

__kw: Dict[str, Any] = {} # default (empty) keywords

def _updated_keywords(self, opts):
kw_ = self.__kw.copy()
kw_.update(opts)
Expand All @@ -52,18 +52,20 @@
return self.__kw.copy()

def __call__(self, **flags):
# Make a new shallow copy of the manager object, but update options from parameter list.
# Make a new shallow copy of the manager object, but duplicate options from parameter list as well as iRODS API
# flags (stored in the instance's private __kw member) to be applied in each call.
new_self = copy.copy(self)
new_self._opts = copy.copy(self._opts)
new_self.__kw = copy.copy(self.__kw)

Check failure on line 59 in irods/manager/metadata_manager.py

View workflow job for this annotation

GitHub Actions / ruff-lint / ruff-check

Ruff private-member-access

private-member-access: Private member accessed: `__kw` [check:private-member-access]

# Update the flags that do bookkeeping in the returned(new) manager object.
new_self._opts.update((key, val) for key, val in flags.items() if val is not None)

# Update the ADMIN_KW flag in the returned(new) object.
# For the new object, make ADMIN_KW flag or absence thereof reflect the admin option in _opts.
if new_self._opts.get('admin'):
self.__kw[kw.ADMIN_KW] = ""
new_self.__kw[kw.ADMIN_KW] = ""

Check failure on line 66 in irods/manager/metadata_manager.py

View workflow job for this annotation

GitHub Actions / ruff-lint / ruff-check

Ruff private-member-access

private-member-access: Private member accessed: `__kw` [check:private-member-access]
else:
self.__kw.pop(kw.ADMIN_KW, None)
new_self.__kw.pop(kw.ADMIN_KW, None)

Check failure on line 68 in irods/manager/metadata_manager.py

View workflow job for this annotation

GitHub Actions / ruff-lint / ruff-check

Ruff private-member-access

private-member-access: Private member accessed: `__kw` [check:private-member-access]

return new_self

Expand Down
54 changes: 54 additions & 0 deletions irods/test/meta_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -798,6 +798,60 @@
# data.metadata(admin = True) generates a cloned object but for the one change to "admin".
data.metadata.admin = True

def test_admin_mode_and_keyword_exhibit_no_stickyness__issue_833(self):
# Create a rodsuser, and a session for that roduser.
adm = self.sess
user = d = None
try:
# Create a test user.
user = adm.users.create("bobby", "rodsuser")
user.modify("password", "bpass")

# This is a convenience function to (re)instantiate the test iRODSSessions:
def new_session():
return iRODSSession(
port=adm.port,
zone=adm.zone,
host=adm.host,
user=user.name,
password="bpass",
)

with new_session() as ses1:
d = ses1.data_objects.create(data_name:="/{adm.zone}/home/{user.name}/testfile".format(**locals()))
d.metadata(admin=True)

with new_session() as ses2:
# Repeat the fetch of the data object using the new session, so we are clean of old references.
d = ses2.data_objects.get(data_name)

# In this use of set(), we expect not to end up applying ADMIN_KW in the underlying API call.
# (Doing so as a rodsuser would raise INSUFFICIENT_PRIVILEGE_LEVEL and the test would fail.)
d.metadata.set('a','b')

# Check that the option flag for use of ADMIN_KW is not set.
self.assertFalse(d.metadata.admin)

# This function calls into the same routine used by the client's metadata endpoint to calculate
# iRODS option keywords it will send in the API call. We use this exclusively for verifying the
# presence of the ADMIN_KW keyword at, effectively, the handoff point to the iRODS server.
get_call_keywords = lambda metacoll: metacoll._manager._updated_keywords((),)

Check failure on line 838 in irods/test/meta_test.py

View workflow job for this annotation

GitHub Actions / ruff-lint / ruff-check

Ruff private-member-access

private-member-access: Private member accessed: `_updated_keywords` [check:private-member-access]

Check failure on line 838 in irods/test/meta_test.py

View workflow job for this annotation

GitHub Actions / ruff-lint / ruff-check

Ruff private-member-access

private-member-access: Private member accessed: `_manager` [check:private-member-access]

Check failure on line 838 in irods/test/meta_test.py

View workflow job for this annotation

GitHub Actions / ruff-lint / ruff-check

Ruff lambda-assignment

lambda-assignment: Do not assign a `lambda` expression, use a `def` [check:lambda-assignment]

# Applying admin=True should result in API flags containing ADMIN_KW among the lookup keys.
md_modified=d.metadata(admin=True)
self.assertIn(kw.ADMIN_KW, get_call_keywords(md_modified))

# The modified admin setting should be reflected when reading it back from the object's
# internal options.
self.assertTrue(md_modified.admin)

# But the original (unmodified) source object should not reflect use of an ADMIN_KW.
self.assertNotIn(kw.ADMIN_KW, get_call_keywords(d.metadata)) # keyword updates not reflected in copied obj.

Check failure on line 849 in irods/test/meta_test.py

View workflow job for this annotation

GitHub Actions / ruff-lint / ruff-check

Ruff line-too-long

line-too-long: Line too long (123 > 120) [check:line-too-long]

Check failure on line 849 in irods/test/meta_test.py

View workflow job for this annotation

GitHub Actions / ruff-lint / ruff-format

Ruff format

Improper formatting
finally:
if d:
d.unlink(force=True)
if user:
user.remove()

if __name__ == "__main__":
# let the tests find the parent irods lib
Expand Down
Loading