Source code for datamasque.client.files
from pathlib import Path
from typing import Optional, Type, TypeVar, Union
from datamasque.client.base import BaseClient, UploadFile, read_file_or_content
from datamasque.client.models.files import DataMasqueFile
FileTypeT = TypeVar("FileTypeT", bound=DataMasqueFile)
[docs]
class FileClient(BaseClient):
"""File-upload API methods. Mixed into `DataMasqueClient`."""
[docs]
def upload_file(
self,
file_type: Type[FileTypeT],
file_name: str,
file_path_or_content: Union[str, bytes, Path],
) -> FileTypeT:
"""
Uploads a file of the given type to the DataMasque server.
`file_type` must be a concrete subclass of `DataMasqueFile`
(`SeedFile`, `OracleWalletFile`, `SslZipFile`, `SnowflakeKeyFile`).
`file_path_or_content` may be a path (as `str` or `Path`), raw `bytes`, or a file-like object.
"""
name, content = read_file_or_content(file_path_or_content, file_name)
content.seek(0)
response = self.make_request(
"POST",
file_type.get_url(),
data={"name": file_name},
files=[
UploadFile(
field_name=file_type.get_content_param_name(),
filename=name,
content=content,
content_type="application/octet-stream",
),
],
)
return file_type.model_validate(response.json())
[docs]
def delete_file_if_exists(self, file: DataMasqueFile) -> None:
"""
Deletes a file. No-op if the file does not exist.
`file` must be an instance of a concrete subclass of `DataMasqueFile`.
The `file` must have its ID set.
"""
if file.id is None:
raise ValueError("File has not yet been created")
# file.get_url() ends with a slash so no need to insert one before the id
self._delete_if_exists(f"{file.get_url()}{file.id}/")
[docs]
def list_files_of_type(self, file_type: Type[FileTypeT]) -> list[FileTypeT]:
"""Returns all files of the given type (a concrete subclass of `DataMasqueFile`)."""
response = self.make_request("GET", file_type.get_url())
return [file_type.model_validate(file) for file in response.json()]
[docs]
def get_file_of_type_by_name(self, file_type: Type[FileTypeT], name: str) -> Optional[FileTypeT]:
"""
Looks for a file of the given type (a concrete subclass of `DataMasqueFile`) with the given `name`.
Returns it if found, otherwise `None`.
"""
matching_files = [f for f in self.list_files_of_type(file_type) if f.name == name]
return matching_files[0] if matching_files else None
[docs]
def upload_file_if_not_exists(self, file_type: Type[FileTypeT], file_path: Union[str, Path]) -> Optional[FileTypeT]:
"""
Upload a file only if one with the same name doesn't already exist.
Args:
file_type: A concrete subclass of `DataMasqueFile` (e.g., SeedFile, OracleWalletFile).
file_path: Path to the file to upload.
Returns:
The uploaded file object if a new file was uploaded, or None if a file
with the same name already exists.
"""
file_path = Path(file_path)
if self.get_file_of_type_by_name(file_type, file_path.name) is not None:
return None
return self.upload_file(file_type, file_path.name, file_path)