sws-api-client 2.22.2__tar.gz → 2.23.0b2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {sws_api_client-2.22.2 → sws_api_client-2.23.0b2}/PKG-INFO +1 -1
- {sws_api_client-2.22.2 → sws_api_client-2.23.0b2}/pyproject.toml +1 -1
- {sws_api_client-2.22.2 → sws_api_client-2.23.0b2}/sws_api_client/__init__.py +1 -1
- {sws_api_client-2.22.2 → sws_api_client-2.23.0b2}/sws_api_client/files.py +93 -6
- {sws_api_client-2.22.2 → sws_api_client-2.23.0b2}/.gitignore +0 -0
- {sws_api_client-2.22.2 → sws_api_client-2.23.0b2}/LICENSE +0 -0
- {sws_api_client-2.22.2 → sws_api_client-2.23.0b2}/README.md +0 -0
- {sws_api_client-2.22.2 → sws_api_client-2.23.0b2}/sws_api_client/auth.py +0 -0
- {sws_api_client-2.22.2 → sws_api_client-2.23.0b2}/sws_api_client/campaign_manager.py +0 -0
- {sws_api_client-2.22.2 → sws_api_client-2.23.0b2}/sws_api_client/case_agnostic_model.py +0 -0
- {sws_api_client-2.22.2 → sws_api_client-2.23.0b2}/sws_api_client/codelist.py +0 -0
- {sws_api_client-2.22.2 → sws_api_client-2.23.0b2}/sws_api_client/data_retrieval.py +0 -0
- {sws_api_client-2.22.2 → sws_api_client-2.23.0b2}/sws_api_client/datasets.py +0 -0
- {sws_api_client-2.22.2 → sws_api_client-2.23.0b2}/sws_api_client/datatable.py +0 -0
- {sws_api_client-2.22.2 → sws_api_client-2.23.0b2}/sws_api_client/db.py +0 -0
- {sws_api_client-2.22.2 → sws_api_client-2.23.0b2}/sws_api_client/discover.py +0 -0
- {sws_api_client-2.22.2 → sws_api_client-2.23.0b2}/sws_api_client/flaglist.py +0 -0
- {sws_api_client-2.22.2 → sws_api_client-2.23.0b2}/sws_api_client/generic_models.py +0 -0
- {sws_api_client-2.22.2 → sws_api_client-2.23.0b2}/sws_api_client/harvester.py +0 -0
- {sws_api_client-2.22.2 → sws_api_client-2.23.0b2}/sws_api_client/mail.py +0 -0
- {sws_api_client-2.22.2 → sws_api_client-2.23.0b2}/sws_api_client/metadata_instances.py +0 -0
- {sws_api_client-2.22.2 → sws_api_client-2.23.0b2}/sws_api_client/plugins.py +0 -0
- {sws_api_client-2.22.2 → sws_api_client-2.23.0b2}/sws_api_client/s3.py +0 -0
- {sws_api_client-2.22.2 → sws_api_client-2.23.0b2}/sws_api_client/schemas/validation-report.schema.json +0 -0
- {sws_api_client-2.22.2 → sws_api_client-2.23.0b2}/sws_api_client/sessions.py +0 -0
- {sws_api_client-2.22.2 → sws_api_client-2.23.0b2}/sws_api_client/sws_api_client.py +0 -0
- {sws_api_client-2.22.2 → sws_api_client-2.23.0b2}/sws_api_client/tags.py +0 -0
- {sws_api_client-2.22.2 → sws_api_client-2.23.0b2}/sws_api_client/tasks.py +0 -0
- {sws_api_client-2.22.2 → sws_api_client-2.23.0b2}/sws_api_client/token.py +0 -0
- {sws_api_client-2.22.2 → sws_api_client-2.23.0b2}/sws_api_client/validation_report.py +0 -0
|
@@ -25,10 +25,10 @@ import os
|
|
|
25
25
|
import warnings
|
|
26
26
|
from datetime import datetime
|
|
27
27
|
from pathlib import Path
|
|
28
|
-
from typing import
|
|
28
|
+
from typing import Literal
|
|
29
29
|
|
|
30
30
|
import requests
|
|
31
|
-
from pydantic import
|
|
31
|
+
from pydantic import ValidationError
|
|
32
32
|
|
|
33
33
|
from sws_api_client.case_agnostic_model import CaseAgnosticModel
|
|
34
34
|
from sws_api_client.sws_api_client import SwsApiClient
|
|
@@ -39,6 +39,31 @@ logger = logging.getLogger(__name__)
|
|
|
39
39
|
FileObjectType = Literal["domain", "dataset", "datatable"]
|
|
40
40
|
|
|
41
41
|
|
|
42
|
+
DEFAULT_MIME = "application/octet-stream"
|
|
43
|
+
MIME_EXTENSIONS_LOOKUP = {
|
|
44
|
+
"txt": "text/plain",
|
|
45
|
+
"csv": "text/csv",
|
|
46
|
+
"json": "application/json",
|
|
47
|
+
"xml": "application/xml",
|
|
48
|
+
"zip": "application/zip",
|
|
49
|
+
"pdf": "application/pdf",
|
|
50
|
+
"xls": "application/vnd.ms-excel",
|
|
51
|
+
"xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
52
|
+
"doc": "application/msword",
|
|
53
|
+
"docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
54
|
+
"py": "text/x-python",
|
|
55
|
+
"r": "text/x-r",
|
|
56
|
+
"md": "text/markdown",
|
|
57
|
+
"ppt": "application/vnd.ms-powerpoint",
|
|
58
|
+
"pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
|
59
|
+
"png": "image/png",
|
|
60
|
+
"jpg": "image/jpeg",
|
|
61
|
+
"jpeg": "image/jpeg",
|
|
62
|
+
"gif": "image/gif",
|
|
63
|
+
"svg": "image/svg+xml",
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
|
|
42
67
|
class CreatorInfo(CaseAgnosticModel):
|
|
43
68
|
email: str | None = None
|
|
44
69
|
username: str | None = None
|
|
@@ -672,7 +697,9 @@ class Files:
|
|
|
672
697
|
|
|
673
698
|
# Check if local_path is a directory or ends with /
|
|
674
699
|
# If so, derive filename from remote path
|
|
675
|
-
if str(local_path).endswith("/") or (
|
|
700
|
+
if str(local_path).endswith("/") or (
|
|
701
|
+
local_path_obj.exists() and local_path_obj.is_dir()
|
|
702
|
+
):
|
|
676
703
|
remote_filename = os.path.basename(path)
|
|
677
704
|
local_path_obj = local_path_obj / remote_filename
|
|
678
705
|
|
|
@@ -681,13 +708,17 @@ class Files:
|
|
|
681
708
|
local_path_obj.parent.mkdir(parents=True, exist_ok=True)
|
|
682
709
|
|
|
683
710
|
# Download content from presigned URL and save to file
|
|
684
|
-
logger.debug(
|
|
711
|
+
logger.debug(
|
|
712
|
+
f"Downloading file from {signed_response.url} to {local_path_obj}"
|
|
713
|
+
)
|
|
685
714
|
resp = requests.get(signed_response.url)
|
|
686
715
|
resp.raise_for_status()
|
|
687
716
|
|
|
688
717
|
with open(local_path_obj, "wb") as f:
|
|
689
718
|
f.write(resp.content)
|
|
690
|
-
logger.info(
|
|
719
|
+
logger.info(
|
|
720
|
+
f"Downloaded '{path}' -> {local_path_obj} ({len(resp.content)} bytes)"
|
|
721
|
+
)
|
|
691
722
|
|
|
692
723
|
return signed_response
|
|
693
724
|
|
|
@@ -708,6 +739,63 @@ class Files:
|
|
|
708
739
|
response = self.sws_client.discoverable.post("session_api", url, data=body)
|
|
709
740
|
return SignedUploadUrlResponse(**response)
|
|
710
741
|
|
|
742
|
+
def _extract_file_extension(self, path: Path) -> str:
|
|
743
|
+
return "".join([c.lstrip(".") for c in path.suffixes])
|
|
744
|
+
|
|
745
|
+
def _get_content_type_from_file_extension(self, extension: str) -> str:
|
|
746
|
+
if extension not in MIME_EXTENSIONS_LOOKUP:
|
|
747
|
+
logger.warning(
|
|
748
|
+
"Unable to identify the content type for a file with extension %s. Defaulting to %s",
|
|
749
|
+
extension,
|
|
750
|
+
DEFAULT_MIME,
|
|
751
|
+
)
|
|
752
|
+
return MIME_EXTENSIONS_LOOKUP.get(extension, DEFAULT_MIME)
|
|
753
|
+
|
|
754
|
+
def _file_exists(
|
|
755
|
+
self, object_type: FileObjectType, object_id: str, *, path: str
|
|
756
|
+
) -> bool:
|
|
757
|
+
try:
|
|
758
|
+
response = self.list(
|
|
759
|
+
object_type=object_type, object_id=object_id, path=path
|
|
760
|
+
)
|
|
761
|
+
return path in [f.path for f in response.files]
|
|
762
|
+
except ValidationError:
|
|
763
|
+
logger.error("Unexpected response")
|
|
764
|
+
return False
|
|
765
|
+
|
|
766
|
+
def upload_file(
|
|
767
|
+
self,
|
|
768
|
+
object_type: FileObjectType,
|
|
769
|
+
object_id: str,
|
|
770
|
+
*,
|
|
771
|
+
path: str,
|
|
772
|
+
local_path: str,
|
|
773
|
+
new_version: bool = False,
|
|
774
|
+
) -> SignedUploadUrlResponse:
|
|
775
|
+
extension = self._extract_file_extension(Path(local_path))
|
|
776
|
+
content_type = self._get_content_type_from_file_extension(extension)
|
|
777
|
+
if not new_version:
|
|
778
|
+
file_exists = self._file_exists(
|
|
779
|
+
object_type=object_type, object_id=object_id, path=path
|
|
780
|
+
)
|
|
781
|
+
if file_exists:
|
|
782
|
+
raise FileExistsError(f"File already exists at {path}")
|
|
783
|
+
upload_response = self.upload_url(
|
|
784
|
+
object_type=object_type,
|
|
785
|
+
object_id=object_id,
|
|
786
|
+
path=path,
|
|
787
|
+
content_type=content_type,
|
|
788
|
+
)
|
|
789
|
+
with open(local_path, "rb") as f:
|
|
790
|
+
put_response = requests.put(
|
|
791
|
+
upload_response.url,
|
|
792
|
+
data=f,
|
|
793
|
+
headers=upload_response.requiredHeaders or {},
|
|
794
|
+
)
|
|
795
|
+
put_response.raise_for_status()
|
|
796
|
+
logger.info("Uploaded file %s at %s", local_path, path)
|
|
797
|
+
return upload_response
|
|
798
|
+
|
|
711
799
|
def create_folder_url(
|
|
712
800
|
self,
|
|
713
801
|
object_type: FileObjectType,
|
|
@@ -778,7 +866,6 @@ class Files:
|
|
|
778
866
|
"""Delete a specific S3 object version."""
|
|
779
867
|
url = f"/files/{object_type}/{object_id}/versions"
|
|
780
868
|
body = {"path": path, "versionId": version_id}
|
|
781
|
-
|
|
782
869
|
response = self.sws_client.discoverable.delete("session_api", url, data=body)
|
|
783
870
|
return DeleteVersionResponse(**response)
|
|
784
871
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|