diff --git a/tests/test_api.py b/tests/test_api.py index c47e0ef34c..9e05306342 100755 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -105,8 +105,7 @@ def test_generic_read(self): path = os.path.join(self.repo_dir, 'metadata', metadata + '.json') metadata_obj = Metadata.from_file(path) with open(path, 'rb') as f: - metadata_str = f.read() - metadata_obj2 = JSONDeserializer().deserialize(metadata_str) + metadata_obj2 = Metadata.from_string(f.read()) # Assert that both methods instantiate the right inner class for # each metadata type and ... @@ -119,15 +118,17 @@ def test_generic_read(self): self.assertDictEqual( metadata_obj.to_dict(), metadata_obj2.to_dict()) - # Assert that it chokes correctly on an unknown metadata type bad_metadata_path = 'bad-metadata.json' bad_metadata = {'signed': {'_type': 'bad-metadata'}} + bad_string = json.dumps(bad_metadata).encode('utf-8') with open(bad_metadata_path, 'wb') as f: - f.write(json.dumps(bad_metadata).encode('utf-8')) + f.write(bad_string) with self.assertRaises(DeserializationError): Metadata.from_file(bad_metadata_path) + with self.assertRaises(DeserializationError): + Metadata.from_string(bad_string) os.remove(bad_metadata_path) diff --git a/tuf/api/metadata.py b/tuf/api/metadata.py index f579fd669c..16b92cc2d1 100644 --- a/tuf/api/metadata.py +++ b/tuf/api/metadata.py @@ -128,6 +128,32 @@ def from_file( A TUF Metadata object. """ + if storage_backend is None: + storage_backend = FilesystemBackend() + + with storage_backend.get(filename) as file_obj: + return cls.from_string(file_obj.read(), deserializer) + + @staticmethod + def from_string( + data: str, + deserializer: Optional[MetadataDeserializer] = None, + ) -> "Metadata": + """Loads TUF metadata from string. + + Arguments: + data: metadata content as string. + deserializer: Optional; A MetadataDeserializer instance that + implements deserialization. Default is JSONDeserializer. + + Raises: + tuf.api.serialization.DeserializationError: + The file cannot be deserialized. + + Returns: + A TUF Metadata object. + """ + if deserializer is None: # Use local scope import to avoid circular import errors # pylint: disable=import-outside-toplevel @@ -135,13 +161,7 @@ def from_file( deserializer = JSONDeserializer() - if storage_backend is None: - storage_backend = FilesystemBackend() - - with storage_backend.get(filename) as file_obj: - raw_data = file_obj.read() - - return deserializer.deserialize(raw_data) + return deserializer.deserialize(data) def to_dict(self) -> Dict[str, Any]: """Returns the dict representation of self. """