PyLinks 0.0.0.dev47__tar.gz → 0.0.0.dev48__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.
- {pylinks-0.0.0.dev47 → pylinks-0.0.0.dev48}/PKG-INFO +3 -3
- {pylinks-0.0.0.dev47 → pylinks-0.0.0.dev48}/pyproject.toml +3 -3
- {pylinks-0.0.0.dev47 → pylinks-0.0.0.dev48}/src/PyLinks.egg-info/PKG-INFO +3 -3
- pylinks-0.0.0.dev48/src/PyLinks.egg-info/requires.txt +3 -0
- {pylinks-0.0.0.dev47 → pylinks-0.0.0.dev48}/src/pylinks/api/github.py +132 -36
- {pylinks-0.0.0.dev47 → pylinks-0.0.0.dev48}/src/pylinks/api/zenodo.py +107 -22
- {pylinks-0.0.0.dev47 → pylinks-0.0.0.dev48}/src/pylinks/exception/api.py +10 -4
- {pylinks-0.0.0.dev47 → pylinks-0.0.0.dev48}/src/pylinks/http.py +2 -2
- pylinks-0.0.0.dev47/src/PyLinks.egg-info/requires.txt +0 -3
- {pylinks-0.0.0.dev47 → pylinks-0.0.0.dev48}/README.md +0 -0
- {pylinks-0.0.0.dev47 → pylinks-0.0.0.dev48}/setup.cfg +0 -0
- {pylinks-0.0.0.dev47 → pylinks-0.0.0.dev48}/src/PyLinks.egg-info/SOURCES.txt +0 -0
- {pylinks-0.0.0.dev47 → pylinks-0.0.0.dev48}/src/PyLinks.egg-info/dependency_links.txt +0 -0
- {pylinks-0.0.0.dev47 → pylinks-0.0.0.dev48}/src/PyLinks.egg-info/not-zip-safe +0 -0
- {pylinks-0.0.0.dev47 → pylinks-0.0.0.dev48}/src/PyLinks.egg-info/top_level.txt +0 -0
- {pylinks-0.0.0.dev47 → pylinks-0.0.0.dev48}/src/pylinks/__init__.py +0 -0
- {pylinks-0.0.0.dev47 → pylinks-0.0.0.dev48}/src/pylinks/_settings.py +0 -0
- {pylinks-0.0.0.dev47 → pylinks-0.0.0.dev48}/src/pylinks/api/__init__.py +0 -0
- {pylinks-0.0.0.dev47 → pylinks-0.0.0.dev48}/src/pylinks/api/doi.py +0 -0
- {pylinks-0.0.0.dev47 → pylinks-0.0.0.dev48}/src/pylinks/api/orcid.py +0 -0
- {pylinks-0.0.0.dev47 → pylinks-0.0.0.dev48}/src/pylinks/exception/__init__.py +0 -0
- {pylinks-0.0.0.dev47 → pylinks-0.0.0.dev48}/src/pylinks/exception/base.py +0 -0
- {pylinks-0.0.0.dev47 → pylinks-0.0.0.dev48}/src/pylinks/exception/media_type.py +0 -0
- {pylinks-0.0.0.dev47 → pylinks-0.0.0.dev48}/src/pylinks/exception/uri.py +0 -0
- {pylinks-0.0.0.dev47 → pylinks-0.0.0.dev48}/src/pylinks/media_type.py +0 -0
- {pylinks-0.0.0.dev47 → pylinks-0.0.0.dev48}/src/pylinks/site/__init__.py +0 -0
- {pylinks-0.0.0.dev47 → pylinks-0.0.0.dev48}/src/pylinks/site/binder.py +0 -0
- {pylinks-0.0.0.dev47 → pylinks-0.0.0.dev48}/src/pylinks/site/conda.py +0 -0
- {pylinks-0.0.0.dev47 → pylinks-0.0.0.dev48}/src/pylinks/site/github.py +0 -0
- {pylinks-0.0.0.dev47 → pylinks-0.0.0.dev48}/src/pylinks/site/lib_io.py +0 -0
- {pylinks-0.0.0.dev47 → pylinks-0.0.0.dev48}/src/pylinks/site/pypi.py +0 -0
- {pylinks-0.0.0.dev47 → pylinks-0.0.0.dev48}/src/pylinks/site/readthedocs.py +0 -0
- {pylinks-0.0.0.dev47 → pylinks-0.0.0.dev48}/src/pylinks/string.py +0 -0
- {pylinks-0.0.0.dev47 → pylinks-0.0.0.dev48}/src/pylinks/uri/__init__.py +0 -0
- {pylinks-0.0.0.dev47 → pylinks-0.0.0.dev48}/src/pylinks/uri/data.py +0 -0
- {pylinks-0.0.0.dev47 → pylinks-0.0.0.dev48}/src/pylinks/url.py +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: PyLinks
|
|
3
|
-
Version: 0.0.0.
|
|
3
|
+
Version: 0.0.0.dev48
|
|
4
4
|
Requires-Python: >=3.10
|
|
5
5
|
Requires-Dist: requests<3,>=2.31.0
|
|
6
|
-
Requires-Dist: ExceptionMan==0.0.0.
|
|
7
|
-
Requires-Dist: MDit==0.0.0.
|
|
6
|
+
Requires-Dist: ExceptionMan==0.0.0.dev35
|
|
7
|
+
Requires-Dist: MDit==0.0.0.dev35
|
|
@@ -17,12 +17,12 @@ namespaces = true
|
|
|
17
17
|
# ----------------------------------------- Project Metadata -------------------------------------
|
|
18
18
|
#
|
|
19
19
|
[project]
|
|
20
|
-
version = "0.0.0.
|
|
20
|
+
version = "0.0.0.dev48"
|
|
21
21
|
name = "PyLinks"
|
|
22
22
|
dependencies = [
|
|
23
23
|
"requests >= 2.31.0, < 3",
|
|
24
|
-
"ExceptionMan == 0.0.0.
|
|
25
|
-
"MDit == 0.0.0.
|
|
24
|
+
"ExceptionMan == 0.0.0.dev35",
|
|
25
|
+
"MDit == 0.0.0.dev35",
|
|
26
26
|
]
|
|
27
27
|
requires-python = ">=3.10"
|
|
28
28
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: PyLinks
|
|
3
|
-
Version: 0.0.0.
|
|
3
|
+
Version: 0.0.0.dev48
|
|
4
4
|
Requires-Python: >=3.10
|
|
5
5
|
Requires-Dist: requests<3,>=2.31.0
|
|
6
|
-
Requires-Dist: ExceptionMan==0.0.0.
|
|
7
|
-
Requires-Dist: MDit==0.0.0.
|
|
6
|
+
Requires-Dist: ExceptionMan==0.0.0.dev35
|
|
7
|
+
Requires-Dist: MDit==0.0.0.dev35
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# Standard libraries
|
|
2
|
-
from
|
|
2
|
+
from __future__ import annotations as _annotations
|
|
3
|
+
from typing import TYPE_CHECKING as _TYPE_CHECKING
|
|
3
4
|
from pathlib import Path
|
|
4
5
|
import re
|
|
5
6
|
import mimetypes
|
|
@@ -7,6 +8,9 @@ import mimetypes
|
|
|
7
8
|
# Non-standard libraries
|
|
8
9
|
import pylinks as _pylinks
|
|
9
10
|
|
|
11
|
+
if _TYPE_CHECKING:
|
|
12
|
+
from typing import Optional, Literal, Any
|
|
13
|
+
|
|
10
14
|
|
|
11
15
|
class GitHub:
|
|
12
16
|
"""GitHub API
|
|
@@ -38,13 +42,22 @@ class GitHub:
|
|
|
38
42
|
def graphql_query(
|
|
39
43
|
self,
|
|
40
44
|
query: str,
|
|
45
|
+
variables: dict[str, tuple[Any, str, bool]] | None = None,
|
|
41
46
|
extra_headers: dict | None = None,
|
|
42
47
|
) -> dict:
|
|
43
48
|
headers = self._headers | extra_headers if extra_headers else self._headers
|
|
49
|
+
if variables:
|
|
50
|
+
args = ", ".join(
|
|
51
|
+
f"${name}:{typ}{"!" if required else ""}" for name, (_, typ, required) in variables.items()
|
|
52
|
+
)
|
|
53
|
+
sig = f"query({args})"
|
|
54
|
+
else:
|
|
55
|
+
sig = "query"
|
|
44
56
|
response = _pylinks.http.graphql_query(
|
|
45
57
|
url=self._endpoint["api"] / "graphql",
|
|
46
|
-
query=f"{{{query}}}",
|
|
58
|
+
query=f"{sig} {{{query}}}",
|
|
47
59
|
headers=headers,
|
|
60
|
+
variables={name: value for name, (value, _, _) in variables.items()} if variables else None
|
|
48
61
|
)
|
|
49
62
|
return response
|
|
50
63
|
|
|
@@ -169,10 +182,12 @@ class Repo:
|
|
|
169
182
|
def _graphql_query(
|
|
170
183
|
self,
|
|
171
184
|
payload: str,
|
|
185
|
+
variables: dict[str, tuple[Any, str, bool]] | None = None,
|
|
172
186
|
extra_headers: dict | None = None,
|
|
173
187
|
) -> dict:
|
|
174
188
|
return self._github.graphql_query(
|
|
175
189
|
query=f'repository(name: "{self._name}", owner: "{self._username}") {{{payload}}}',
|
|
190
|
+
variables=variables,
|
|
176
191
|
extra_headers=extra_headers,
|
|
177
192
|
)["repository"]
|
|
178
193
|
|
|
@@ -620,6 +635,8 @@ class Repo:
|
|
|
620
635
|
self,
|
|
621
636
|
number: int,
|
|
622
637
|
count: int = 0,
|
|
638
|
+
cursor_before: str | None = None,
|
|
639
|
+
cursor_after: str | None = None,
|
|
623
640
|
sort: Literal["first", "last"] = "last",
|
|
624
641
|
) -> list[dict]:
|
|
625
642
|
"""
|
|
@@ -640,20 +657,52 @@ class Repo:
|
|
|
640
657
|
----------
|
|
641
658
|
- [GitHub API Docs](https://docs.github.com/en/rest/pulls/commits?apiVersion=2022-11-28#list-commits-on-a-pull-request)
|
|
642
659
|
"""
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
660
|
+
def post_process():
|
|
661
|
+
out = []
|
|
662
|
+
for datum in data:
|
|
663
|
+
commits = datum["pullRequest"]["commits"]["nodes"]
|
|
664
|
+
if sort == "last":
|
|
665
|
+
commits = reversed(commits)
|
|
666
|
+
for commit in commits:
|
|
667
|
+
commit["commit"]["authors"] = commit["commit"]["authors"]["nodes"]
|
|
668
|
+
out.append(commit)
|
|
669
|
+
return out
|
|
670
|
+
|
|
671
|
+
git_actor_fields = "{name, email, date user {id, login}}"
|
|
672
|
+
commit_fields = f"{{abbreviatedOid, additions, deletions, authors(first: 100) {{nodes {git_actor_fields}}}, committer {git_actor_fields}, authoredByCommitter, authoredDate, committedDate, message, messageBody, messageHeadline, oid, id, resourcePath, url}}"
|
|
673
|
+
page_info_fields = "pageInfo {startCursor, endCursor, hasNextPage, hasPreviousPage}"
|
|
674
|
+
commits_args = ["after: $after", "before: $before", f"{sort}: {100 if count <= 0 else min(count, 100)}"]
|
|
675
|
+
commits_fields = f"nodes {{id, resourcePath, url, commit {commit_fields} }}"
|
|
676
|
+
commits_sig = f"commits({", ".join(commits_args)})"
|
|
677
|
+
payload = f"pullRequest(number: {number}) {{ {commits_sig} {{ {commits_fields} {page_info_fields} }} }}"
|
|
678
|
+
variables = {
|
|
679
|
+
"after": (cursor_after, "String", False),
|
|
680
|
+
"before": (cursor_before, "String", False),
|
|
681
|
+
}
|
|
682
|
+
data = [self._graphql_query(payload, variables)]
|
|
683
|
+
total_downloaded = 100
|
|
648
684
|
while True:
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
685
|
+
page_info = data[-1]["pullRequest"]["commits"]["pageInfo"]
|
|
686
|
+
if count <= 0:
|
|
687
|
+
must_continue = page_info["hasNextPage" if sort == "first" else "hasPreviousPage"]
|
|
688
|
+
if not must_continue:
|
|
689
|
+
return post_process()
|
|
690
|
+
elif total_downloaded >= count:
|
|
691
|
+
return post_process()
|
|
692
|
+
else:
|
|
693
|
+
variables[sort] = page_info["endCursor" if sort == "first" else "startCursor"]
|
|
694
|
+
data.append(self._graphql_query(payload, variables))
|
|
695
|
+
total_downloaded += 100
|
|
696
|
+
|
|
697
|
+
# commits = []
|
|
698
|
+
# page = 1
|
|
699
|
+
# while True:
|
|
700
|
+
# response = self._rest_query(f"pulls/{number}/commits?per_page=100&page={page}")
|
|
701
|
+
# commits.extend(response)
|
|
702
|
+
# page += 1
|
|
703
|
+
# if len(response) < 100:
|
|
704
|
+
# break
|
|
705
|
+
# return commits
|
|
657
706
|
|
|
658
707
|
def pull_create(
|
|
659
708
|
self,
|
|
@@ -1046,15 +1095,22 @@ class Repo:
|
|
|
1046
1095
|
raise ValueError("At least one of 'new_name', 'color', or 'description' must be specified.")
|
|
1047
1096
|
return self._rest_query(query=f"labels/{name}", verb="PATCH", json=data)
|
|
1048
1097
|
|
|
1098
|
+
def release_get(self, release_id: int) -> dict:
|
|
1099
|
+
return self._rest_query(query=f"releases/{release_id}")
|
|
1100
|
+
|
|
1101
|
+
def release_delete(self, release_id: int) -> None:
|
|
1102
|
+
self._rest_query(query=f"releases/{release_id}", verb="DELETE", response_type=None)
|
|
1103
|
+
return
|
|
1104
|
+
|
|
1049
1105
|
def release_create(
|
|
1050
1106
|
self,
|
|
1051
1107
|
tag_name: str,
|
|
1052
|
-
name: str,
|
|
1053
|
-
body: str,
|
|
1054
|
-
target_commitish: str =
|
|
1108
|
+
name: str | None = None,
|
|
1109
|
+
body: str | None = None,
|
|
1110
|
+
target_commitish: str | None = None,
|
|
1055
1111
|
draft: bool = False,
|
|
1056
1112
|
prerelease: bool = False,
|
|
1057
|
-
discussion_category_name: str =
|
|
1113
|
+
discussion_category_name: str | None = None,
|
|
1058
1114
|
generate_release_notes: bool = False,
|
|
1059
1115
|
make_latest: Literal['true', 'false', 'legacy'] = 'true'
|
|
1060
1116
|
):
|
|
@@ -1094,22 +1150,62 @@ class Repo:
|
|
|
1094
1150
|
----------
|
|
1095
1151
|
[GitHub API Docs](https://docs.github.com/en/rest/releases/releases?apiVersion=2022-11-28#create-a-release)
|
|
1096
1152
|
"""
|
|
1097
|
-
data = {
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1153
|
+
data = {k: v for k, v in locals().items() if k != "self" and v is not None}
|
|
1154
|
+
return self._rest_query(query=f"releases", verb="POST", json=data)
|
|
1155
|
+
|
|
1156
|
+
def release_update(
|
|
1157
|
+
self,
|
|
1158
|
+
release_id: int,
|
|
1159
|
+
tag_name: str | None = None,
|
|
1160
|
+
name: str | None = None,
|
|
1161
|
+
body: str | None = None,
|
|
1162
|
+
target_commitish: str | None = None,
|
|
1163
|
+
draft: bool | None = None,
|
|
1164
|
+
prerelease: bool | None = None,
|
|
1165
|
+
discussion_category_name: str | None = None,
|
|
1166
|
+
make_latest: Literal['true', 'false', 'legacy'] | None = None
|
|
1167
|
+
):
|
|
1168
|
+
"""Update a release.
|
|
1169
|
+
|
|
1170
|
+
Parameters
|
|
1171
|
+
----------
|
|
1172
|
+
tag_name : str
|
|
1173
|
+
The name of the tag.
|
|
1174
|
+
name : str
|
|
1175
|
+
The name of the release.
|
|
1176
|
+
body : str
|
|
1177
|
+
The body of the release post, i.e. text describing the release.
|
|
1178
|
+
target_commitish : str, optional
|
|
1179
|
+
The commitish value that determines where the Git tag is created from.
|
|
1180
|
+
Can be any branch or commit SHA. Unused if the Git tag already exists.
|
|
1181
|
+
The default is the repository's default branch.
|
|
1182
|
+
draft : bool, optional
|
|
1183
|
+
`True` to create a draft (unpublished) release, `False` to create a published one.
|
|
1184
|
+
prerelease : bool, default: False
|
|
1185
|
+
`True` to identify the release as a prerelease, `False` to identify it as a full release.
|
|
1186
|
+
discussion_category_name : str, optional
|
|
1187
|
+
The name of the discussion category for the release, to be created and linked to the release.
|
|
1188
|
+
The value must be a category that already exists in the repository.
|
|
1189
|
+
make_latest : {'true', 'false', 'legacy'}, optional
|
|
1190
|
+
Whether this release should be set as the latest release for the repository.
|
|
1191
|
+
Drafts and prereleases cannot be set as latest.
|
|
1192
|
+
Defaults to 'true' for newly published releases.
|
|
1193
|
+
'legacy' specifies that the latest release should be determined based on
|
|
1194
|
+
the release creation date and higher semantic version.
|
|
1195
|
+
|
|
1196
|
+
References
|
|
1197
|
+
----------
|
|
1198
|
+
[GitHub API Docs](https://docs.github.com/en/rest/releases/releases?apiVersion=2022-11-28#create-a-release)
|
|
1199
|
+
"""
|
|
1200
|
+
data = {k: v for k, v in locals().items() if k not in ("self", "release_id") and v is not None}
|
|
1201
|
+
return self._rest_query(query=f"releases/{release_id}", verb="PATCH", json=data)
|
|
1202
|
+
|
|
1203
|
+
def release_asset_list(self, release_id: int) -> list[dict]:
|
|
1204
|
+
return self._rest_query(query=f"releases/{release_id}/assets")
|
|
1205
|
+
|
|
1206
|
+
def release_asset_delete(self, asset_id: int) -> None:
|
|
1207
|
+
self._rest_query(query=f"releases/assets/{asset_id}", verb="DELETE", response_type=None)
|
|
1208
|
+
return
|
|
1113
1209
|
|
|
1114
1210
|
def release_asset_upload(
|
|
1115
1211
|
self,
|
|
@@ -1701,7 +1797,7 @@ class Repo:
|
|
|
1701
1797
|
"""
|
|
1702
1798
|
payload = "branchProtectionRules(first: 100) {nodes {id, pattern}}"
|
|
1703
1799
|
data = self._graphql_query(payload)
|
|
1704
|
-
return data["
|
|
1800
|
+
return data["branchProtectionRules"]["nodes"]
|
|
1705
1801
|
|
|
1706
1802
|
def branch_protection_rule_create(
|
|
1707
1803
|
self,
|
|
@@ -18,37 +18,90 @@ class Zenodo:
|
|
|
18
18
|
"""
|
|
19
19
|
def __init__(self, token: str, sandbox: bool = False):
|
|
20
20
|
self._sandbox = sandbox
|
|
21
|
-
self._url = _pylinks.url.create(
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
self._url = _pylinks.url.create(
|
|
22
|
+
"https://sandbox.zenodo.org/api" if sandbox else "https://zenodo.org/api"
|
|
23
|
+
)
|
|
24
|
+
self._headers = {"Authorization": f"Bearer {token}"}
|
|
24
25
|
return
|
|
25
26
|
|
|
26
27
|
def rest_query(
|
|
27
28
|
self,
|
|
28
29
|
query: str,
|
|
29
30
|
verb: Literal["GET", "POST", "PUT", "PATCH", "OPTIONS", "DELETE"] = "GET",
|
|
31
|
+
params: dict | None = None,
|
|
30
32
|
data = None,
|
|
31
33
|
json = None,
|
|
32
34
|
content_type: str | None = "application/json",
|
|
33
|
-
|
|
35
|
+
response_type: Literal["str", "json", "bytes"] | None = "json"
|
|
34
36
|
) -> dict | list:
|
|
35
|
-
sandbox = sandbox if sandbox is not None else self._sandbox
|
|
36
|
-
base_url = self._url_sandbox if sandbox else self._url
|
|
37
37
|
content_header = {"Content-Type": content_type} if content_type else {}
|
|
38
38
|
return _pylinks.http.request(
|
|
39
|
-
url=
|
|
39
|
+
url=self._url / query,
|
|
40
40
|
verb=verb,
|
|
41
|
+
params=params,
|
|
41
42
|
data=data,
|
|
42
43
|
json=json,
|
|
43
44
|
headers=self._headers | content_header,
|
|
44
|
-
response_type=
|
|
45
|
+
response_type=response_type, # All responses are JSON (https://developers.zenodo.org/#responses)
|
|
45
46
|
)
|
|
46
47
|
|
|
47
|
-
def
|
|
48
|
+
def create_and_publish(
|
|
48
49
|
self,
|
|
49
|
-
metadata: dict
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
metadata: dict,
|
|
51
|
+
files: list[str | _Path | tuple[str | _Path, str]],
|
|
52
|
+
previous_id: str | int | None = None
|
|
53
|
+
):
|
|
54
|
+
def add_files(bucket_id: str):
|
|
55
|
+
for file in files:
|
|
56
|
+
if not isinstance(file, (str, _Path)):
|
|
57
|
+
filepath = file[0]
|
|
58
|
+
name = file[1]
|
|
59
|
+
else:
|
|
60
|
+
filepath = file
|
|
61
|
+
name = None
|
|
62
|
+
self.file_create(
|
|
63
|
+
bucket_id=bucket_id,
|
|
64
|
+
filepath=filepath,
|
|
65
|
+
name=name,
|
|
66
|
+
)
|
|
67
|
+
return
|
|
68
|
+
|
|
69
|
+
if not previous_id:
|
|
70
|
+
new_depo = self.deposition_create(metadata=metadata)
|
|
71
|
+
add_files(bucket_id=new_depo["links"]["bucket"])
|
|
72
|
+
return self.deposition_publish(new_depo["id"])
|
|
73
|
+
new_ver = self.deposition_new_version(deposition_id=previous_id)
|
|
74
|
+
for previous_file in new_ver["files"]:
|
|
75
|
+
self.file_delete(deposition_id=new_ver["id"], file_id=previous_file["id"])
|
|
76
|
+
add_files(new_ver["links"]["bucket"])
|
|
77
|
+
return self.deposition_publish(new_ver["id"])
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def deposition_list(
|
|
81
|
+
self,
|
|
82
|
+
query: str | None = None,
|
|
83
|
+
status: Literal["draft", "published"] | None = None,
|
|
84
|
+
sort: Literal["bestmatch", "mostrecent", "-bestmatch", "-mostrecent"] | None = None,
|
|
85
|
+
page: int | None = None,
|
|
86
|
+
size: int | None = None,
|
|
87
|
+
all_versions: bool | None = None,
|
|
88
|
+
):
|
|
89
|
+
params = {k: v for k, v in locals().items() if k not in ("self", "query") and v}
|
|
90
|
+
if query:
|
|
91
|
+
params["q"] = query
|
|
92
|
+
return self.rest_query(
|
|
93
|
+
"deposit/depositions",
|
|
94
|
+
verb="GET",
|
|
95
|
+
params=params,
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
def deposition_retrieve(self, deposition_id: str | int):
|
|
99
|
+
return self.rest_query(
|
|
100
|
+
f"deposit/depositions/{deposition_id}",
|
|
101
|
+
verb="GET",
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
def deposition_create(self, metadata: dict | None = None) -> dict:
|
|
52
105
|
"""Create a new deposition.
|
|
53
106
|
|
|
54
107
|
Returns
|
|
@@ -91,25 +144,51 @@ class Zenodo:
|
|
|
91
144
|
return self.rest_query(
|
|
92
145
|
query="deposit/depositions",
|
|
93
146
|
verb="POST",
|
|
94
|
-
json=metadata
|
|
95
|
-
sandbox=sandbox,
|
|
147
|
+
json={"metadata": metadata} if metadata else {},
|
|
96
148
|
)
|
|
97
149
|
|
|
98
|
-
def
|
|
150
|
+
def deposition_new_version(self, deposition_id: int | str):
|
|
151
|
+
"""Create a new version of a deposition as a draft."""
|
|
152
|
+
return self.rest_query(
|
|
153
|
+
query=f"deposit/depositions/{deposition_id}/actions/newversion",
|
|
154
|
+
verb="POST",
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
def deposition_update(self, deposition_id: int | str, metadata: dict):
|
|
158
|
+
"""Update and existing deposition."""
|
|
159
|
+
return self.rest_query(
|
|
160
|
+
query=f"deposit/depositions/{deposition_id}",
|
|
161
|
+
verb="PUT",
|
|
162
|
+
json={"metadata": metadata},
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
def deposition_publish(self, deposition_id: int | str) -> dict:
|
|
99
166
|
"""Publish a deposition."""
|
|
100
167
|
return self.rest_query(
|
|
101
168
|
query=f"deposit/depositions/{deposition_id}/actions/publish",
|
|
102
169
|
verb="POST",
|
|
103
170
|
)
|
|
104
171
|
|
|
172
|
+
def file_list(self, deposition_id: str | int):
|
|
173
|
+
return self.rest_query(
|
|
174
|
+
f"deposit/depositions/{deposition_id}/files",
|
|
175
|
+
verb="GET"
|
|
176
|
+
)
|
|
177
|
+
|
|
105
178
|
def file_create(
|
|
106
179
|
self,
|
|
107
|
-
|
|
180
|
+
bucket_id: str,
|
|
108
181
|
filepath: str | _Path,
|
|
109
|
-
|
|
182
|
+
name: str | None = None,
|
|
110
183
|
) -> dict:
|
|
111
184
|
"""Upload a file to a Zenodo bucket.
|
|
112
185
|
|
|
186
|
+
Parameters
|
|
187
|
+
----------
|
|
188
|
+
bucket_id
|
|
189
|
+
Bucket ID (e.g., `"d7524553-7f8c-4632-bffb-8bea6a90b88b"`)
|
|
190
|
+
or bucket URL (e.g., `"https://zenodo.org/api/files/d7524553-7f8c-4632-bffb-8bea6a90b88b"`)
|
|
191
|
+
|
|
113
192
|
Returns
|
|
114
193
|
-------
|
|
115
194
|
|
|
@@ -134,14 +213,20 @@ class Zenodo:
|
|
|
134
213
|
}
|
|
135
214
|
:::
|
|
136
215
|
"""
|
|
137
|
-
|
|
138
|
-
bucket_url = _pylinks.url.create(bucket_url)
|
|
216
|
+
bucket_id = bucket_id.removeprefix(f"{self._url}/files/")
|
|
139
217
|
filepath = _Path(filepath)
|
|
140
|
-
|
|
218
|
+
name = name or filepath.name
|
|
141
219
|
with open(filepath, "rb") as file:
|
|
142
220
|
return self.rest_query(
|
|
143
|
-
query=
|
|
221
|
+
query=f"files/{bucket_id}/{name}",
|
|
144
222
|
verb="PUT",
|
|
145
223
|
data=file,
|
|
146
224
|
content_type=None,
|
|
147
|
-
)
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
def file_delete(self, deposition_id: str | int, file_id: str | int):
|
|
228
|
+
return self.rest_query(
|
|
229
|
+
f"deposit/depositions/{deposition_id}/files/{file_id}",
|
|
230
|
+
verb="DELETE",
|
|
231
|
+
response_type=None,
|
|
232
|
+
)
|
|
@@ -101,7 +101,7 @@ class GraphQLResponseError(WebAPIError):
|
|
|
101
101
|
Exception class for GraphQL
|
|
102
102
|
"""
|
|
103
103
|
|
|
104
|
-
def __init__(self, response: dict):
|
|
104
|
+
def __init__(self, response: dict, query: str):
|
|
105
105
|
if "errors" in response:
|
|
106
106
|
intro = "GraphQL response contains errors."
|
|
107
107
|
elif "data" not in response:
|
|
@@ -109,10 +109,16 @@ class GraphQLResponseError(WebAPIError):
|
|
|
109
109
|
super().__init__(
|
|
110
110
|
title="GraphQL Response Error",
|
|
111
111
|
intro=intro,
|
|
112
|
-
details=_mdit.
|
|
113
|
-
|
|
114
|
-
|
|
112
|
+
details=_mdit.block_container(
|
|
113
|
+
_mdit.element.code_block(
|
|
114
|
+
json.dumps(response, indent=3), language="json", caption="GraphQL Response"
|
|
115
|
+
),
|
|
116
|
+
_mdit.element.code_block(
|
|
117
|
+
query, language="graphql", caption="GraphQL Query"
|
|
118
|
+
),
|
|
119
|
+
)
|
|
115
120
|
)
|
|
121
|
+
self.query = query
|
|
116
122
|
return
|
|
117
123
|
|
|
118
124
|
|
|
@@ -277,9 +277,9 @@ def graphql_query(
|
|
|
277
277
|
if isinstance(response, dict):
|
|
278
278
|
error_title = "GraphQL API Error"
|
|
279
279
|
if "errors" in response:
|
|
280
|
-
raise _exception.GraphQLResponseError(response)
|
|
280
|
+
raise _exception.GraphQLResponseError(response, query)
|
|
281
281
|
elif "data" not in response:
|
|
282
|
-
raise _exception.GraphQLResponseError(response)
|
|
282
|
+
raise _exception.GraphQLResponseError(response, query)
|
|
283
283
|
else:
|
|
284
284
|
response = response["data"]
|
|
285
285
|
return response
|
|
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
|
|
File without changes
|