From 64c9c3c9c974dbb1ebb096e029dbe49a067d559e Mon Sep 17 00:00:00 2001 From: Simeon Warner Date: Thu, 12 Dec 2024 13:30:04 -0500 Subject: [PATCH] Tidy layout_nnnn_tuple_tree --- ocfl/layout_0003_hash_and_id_n_tuple.py | 24 ++++++++ ocfl/layout_nnnn_tuple_tree.py | 50 ++++++++++++++-- tests/test_layout_0003-hash-and-id-n-tuple.py | 1 - tests/test_layout_nnnn_tuple_tree.py | 60 ++++++++++++------- 4 files changed, 106 insertions(+), 29 deletions(-) diff --git a/ocfl/layout_0003_hash_and_id_n_tuple.py b/ocfl/layout_0003_hash_and_id_n_tuple.py index 7bf634f..8fdbd78 100644 --- a/ocfl/layout_0003_hash_and_id_n_tuple.py +++ b/ocfl/layout_0003_hash_and_id_n_tuple.py @@ -72,6 +72,14 @@ def check_digest_algorithm(self, value): Type: string Constraints: Must not be empty Default: sha256 + + Argument: + value (str): digest algorithm name + + Raises: + LayoutException: if the digest algorithm is not supported + + Sets the digest_algorithm property of this object as a side effect. """ if value is None: raise LayoutException("digestAlgorithm parameter must be specified") @@ -91,6 +99,14 @@ def check_tuple_size(self, value): Type: number Constraints: An integer between 0 and 32 inclusive Default: 3 + + Argument: + value (int): integer value for tuple size in characters + + Raises: + LayoutException: if the tuple size is not allowed + + Sets the tuple_size property of this object as a side effect. """ if value is None: raise LayoutException("tupleSize parameter must be specified") @@ -107,6 +123,14 @@ def check_number_of_tuples(self, value): Type: number Constraints: An integer between 0 and 32 inclusive Default: 3 + + Argument: + value (int): integer value for number of tuples + + Raises: + LayoutException: if the number of tuples is not allowed + + Sets the number_of_tuples property of this object as a side effect. """ if value is None: raise LayoutException("numberOfTuples parameter must be specified") diff --git a/ocfl/layout_nnnn_tuple_tree.py b/ocfl/layout_nnnn_tuple_tree.py index cfd6e06..1b26994 100644 --- a/ocfl/layout_nnnn_tuple_tree.py +++ b/ocfl/layout_nnnn_tuple_tree.py @@ -44,8 +44,16 @@ def check_tuple_size(self, value): Description: Indicates the size of the segments (in characters) that the digest is split into Type: number - Constraints: An integer between 0 and 32 inclusive - Default: 3 + Constraints: An integer between 2 and 6 inclusive + Default: 2 + + Argument: + value (int): integer value for tuple size in characters + + Raises: + LayoutException: if the tuple size is not allowed + + Sets the tuple_size property of this object as a side effect. """ if value is None: raise LayoutException("tupleSize parameter must be specified") @@ -54,15 +62,45 @@ def check_tuple_size(self, value): self.tuple_size = value def encode(self, identifier): - """Pairtree encode identifier.""" + """Pairtree encode identifier. + + Argument: + identifier (str): object identifier to encode + + Returns: + str: encoded identifier + """ return id_encode(identifier) def decode(self, identifier): - """Pairtree decode identifier.""" + """Pairtree decode identifier. + + Argument: + identifier (str): object identifier to decode + + Returns: + str: decoded identifier + """ return id_decode(identifier) def identifier_to_path(self, identifier): - """Convert identifier to path relative to root.""" + """Convert identifier to path relative to root. + + Argument: + identifier (str): object identifier + + Returns: + str: object path for this layout + + Raises: + LayoutException: if the identifier cannot be converted to a valid + object path. Currently just a check for blank + + Uses Layout.encode() to generate a safe directory name from any + identifier. + """ + if identifier == "": + raise LayoutException("Identifier '%s' unsafe for %s layout" % (identifier, self.NAME)) identifier = self.encode(identifier) id_remains = identifier segments = [] @@ -72,4 +110,4 @@ def identifier_to_path(self, identifier): segments.append(id_remains) # the statement means that segments will always have at least one element # Use full identifier to encapsulate segments.append(identifier) - return os.path.join(*segments) # pylint: disable=no-value-for-parameter + return os.path.join(*segments) diff --git a/tests/test_layout_0003-hash-and-id-n-tuple.py b/tests/test_layout_0003-hash-and-id-n-tuple.py index d99ade0..5cf1c36 100644 --- a/tests/test_layout_0003-hash-and-id-n-tuple.py +++ b/tests/test_layout_0003-hash-and-id-n-tuple.py @@ -97,7 +97,6 @@ def test_check_full_config(self): "numberOfTuples": 9}, require_extension_name=False) - def test_config(self): """Test config property.""" layout = Layout_0003_Hash_And_Id_N_Tuple() diff --git a/tests/test_layout_nnnn_tuple_tree.py b/tests/test_layout_nnnn_tuple_tree.py index 74c1d91..b3e9cd3 100644 --- a/tests/test_layout_nnnn_tuple_tree.py +++ b/tests/test_layout_nnnn_tuple_tree.py @@ -1,34 +1,50 @@ -"""Digest tests.""" +"""Layout_NNNN_Tuple_Tree layout tests.""" import unittest +from ocfl.layout import LayoutException from ocfl.layout_nnnn_tuple_tree import Layout_NNNN_Tuple_Tree class TestAll(unittest.TestCase): """TestAll class to run tests.""" - def test01_encode(self): + def test_encode(self): """Test encode.""" - tt = Layout_NNNN_Tuple_Tree() - self.assertEqual(tt.encode(""), "") - self.assertEqual(tt.encode("a"), "a") - self.assertEqual(tt.encode("a/b:?"), "a=b+^3f") + layout = Layout_NNNN_Tuple_Tree() + self.assertEqual(layout.encode(""), "") + self.assertEqual(layout.encode("a"), "a") + self.assertEqual(layout.encode("a/b:?"), "a=b+^3f") - def test02_decode(self): + def test_decode(self): """Test decode.""" - tt = Layout_NNNN_Tuple_Tree() - self.assertEqual(tt.decode(""), "") - self.assertEqual(tt.decode("a"), "a") - self.assertEqual(tt.decode("a=b+^3f"), "a/b:?") + layout = Layout_NNNN_Tuple_Tree() + self.assertEqual(layout.decode(""), "") + self.assertEqual(layout.decode("a"), "a") + self.assertEqual(layout.decode("a=b+^3f"), "a/b:?") - def test03_identifier_to_path(self): + def test_config(self): + """Test config property.""" + layout = Layout_NNNN_Tuple_Tree() + self.assertEqual(set(layout.config.keys()), set(("extensionName", "tupleSize"))) + + def test_check_tuple_size(self): + """Test check_tuple_size method.""" + layout = Layout_NNNN_Tuple_Tree() + self.assertRaises(LayoutException, layout.check_tuple_size, None) + self.assertRaises(LayoutException, layout.check_tuple_size, "string-not-num") + self.assertRaises(LayoutException, layout.check_tuple_size, 1) + self.assertRaises(LayoutException, layout.check_tuple_size, 7) + self.assertEqual(layout.check_tuple_size(4), None) + self.assertEqual(layout.tuple_size, 4) + + def test_identifier_to_path(self): """Test path creation.""" - tt = Layout_NNNN_Tuple_Tree(tuple_size=2) - self.assertEqual(tt.identifier_to_path(""), "") - self.assertEqual(tt.identifier_to_path("a"), "a/a") - self.assertEqual(tt.identifier_to_path("ab"), "ab/ab") - self.assertEqual(tt.identifier_to_path("abc"), "ab/c/abc") - self.assertEqual(tt.identifier_to_path("abcde"), "ab/cd/e/abcde") - tt = Layout_NNNN_Tuple_Tree(tuple_size=3) - self.assertEqual(tt.identifier_to_path("abcdefg"), "abc/def/g/abcdefg") - self.assertEqual(tt.identifier_to_path("abcdefgh"), "abc/def/gh/abcdefgh") - self.assertEqual(tt.identifier_to_path("abcdefghi"), "abc/def/ghi/abcdefghi") + layout = Layout_NNNN_Tuple_Tree(tuple_size=2) + self.assertRaises(LayoutException, layout.identifier_to_path, "") + self.assertEqual(layout.identifier_to_path("a"), "a/a") + self.assertEqual(layout.identifier_to_path("ab"), "ab/ab") + self.assertEqual(layout.identifier_to_path("abc"), "ab/c/abc") + self.assertEqual(layout.identifier_to_path("abcde"), "ab/cd/e/abcde") + layout = Layout_NNNN_Tuple_Tree(tuple_size=3) + self.assertEqual(layout.identifier_to_path("abcdefg"), "abc/def/g/abcdefg") + self.assertEqual(layout.identifier_to_path("abcdefgh"), "abc/def/gh/abcdefgh") + self.assertEqual(layout.identifier_to_path("abcdefghi"), "abc/def/ghi/abcdefghi")