From 3015e40a1c1c8868ec22efe35751e3d0d85bebd8 Mon Sep 17 00:00:00 2001 From: d-w-moore Date: Wed, 24 Jul 2024 06:59:20 -0400 Subject: [PATCH] [#533][#556] implement library features --- irods/api_number.py | 2 ++ irods/exception.py | 11 ++++++++++ irods/session.py | 15 +++++++++++-- irods/test/library_features_test.py | 33 +++++++++++++++++++++++++++++ 4 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 irods/test/library_features_test.py diff --git a/irods/api_number.py b/irods/api_number.py index 15930fa1..052456ba 100644 --- a/irods/api_number.py +++ b/irods/api_number.py @@ -157,6 +157,8 @@ "RM_COLL201_AN": 663, "OPEN_COLLECTION201_AN": 712, + "GET_LIBRARY_FEATURES_AN": 801, + # 1000 - 1059 - NETCDF API calls "NC_OPEN_AN": 1000, "NC_CREATE_AN": 1001, diff --git a/irods/exception.py b/irods/exception.py index c57a1eb2..628a1deb 100644 --- a/irods/exception.py +++ b/irods/exception.py @@ -69,6 +69,17 @@ class MultipleResultsFound(QueryException): pass +class NotImplementedInIRODSServer(RuntimeError): + def __init__(self, feature_description, required_iRODS_version = ()): + super(NotImplementedInIRODSServer,self).__init__(feature_description + ': Not supported by the connected iRODS server.') + self.required_iRODS_version = required_iRODS_version + def __str__(self): + nv = self.required_iRODS_version + return '{}{}'.format(self.args, ' [requires iRODS version: {nv}]'.format(**locals()) if nv else '') + def __repr__(self): + return self.__class__.__name__ + str(self) + + class iRODSExceptionMeta(type): codes = {} positive_code_error_message = "For {name}, a positive code of {attrs[code]} was declared." diff --git a/irods/session.py b/irods/session.py index f514ce5d..6bee2c31 100644 --- a/irods/session.py +++ b/irods/session.py @@ -21,8 +21,8 @@ from irods.manager.user_manager import UserManager, GroupManager from irods.manager.resource_manager import ResourceManager from irods.manager.zone_manager import ZoneManager -from irods.message import iRODSMessage -from irods.exception import NetworkException +from irods.message import (iRODSMessage, STR_PI) +from irods.exception import (NetworkException, NotImplementedInIRODSServer) from irods.password_obfuscation import decode from irods import NATIVE_AUTH_SCHEME, PAM_AUTH_SCHEMES from . import DEFAULT_CONNECTION_TIMEOUT @@ -61,6 +61,17 @@ class NonAnonymousLoginWithoutPassword(RuntimeError): pass class iRODSSession(object): + def library_features(self): + irods_version_needed = (4,3,1) + if self.server_version < irods_version_needed: + raise NotImplementedInIRODSServer('library_features', irods_version_needed) + message = iRODSMessage('RODS_API_REQ', int_info = api_number['GET_LIBRARY_FEATURES_AN']) + with self.pool.get_connection() as conn: + conn.send(message) + response = conn.recv() + msg = response.get_main_message( STR_PI ) + return json.loads(msg.myStr) + @property def env_file (self): return self._env_file diff --git a/irods/test/library_features_test.py b/irods/test/library_features_test.py new file mode 100644 index 00000000..f1795144 --- /dev/null +++ b/irods/test/library_features_test.py @@ -0,0 +1,33 @@ +#! /usr/bin/env python +from __future__ import absolute_import +import os +import sys +import unittest + +import irods.test.helpers as helpers + +class TestLibraryFeatures(unittest.TestCase): + + def setUp(self): + self.sess = helpers.make_session() + + def tearDown(self): + """Close connections.""" + self.sess.cleanup() + + def test_library_features__issue_556(self): + if self.sess.server_version < (4, 3, 1): + self.skipTest('Do not test library features before iRODS 4.3.1') + + features = self.sess.library_features() + + # Test that returned features are in the form of a Python dict object. + self.assertIsInstance(features, dict) + + # Test that features is populated by at least one item. + self.assertTrue(features) + +if __name__ == '__main__': + # let the tests find the parent irods lib + sys.path.insert(0, os.path.abspath('../..')) + unittest.main()