Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update for handling changes in Zenodo API #154

Merged
merged 6 commits into from
Nov 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions HISTORY.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
=======
History
=======
2023.11.11 -- Incorporating changes to Zenodo
* Zenodo updated and made small changes to their API, which required changes in
SEAMM.
* Consolidated all private information about the user and their keys for Zenodo in
~/.seammrc

2023.11.7 -- Bugfix: initialization of Dashboard
* Fixed a crash that occurred the very first time submitting to the Dashboard.

Expand Down
7 changes: 5 additions & 2 deletions seamm/flowchart.py
Original file line number Diff line number Diff line change
Expand Up @@ -520,9 +520,10 @@ def reset_metadata(self, **kwargs):
"description": "",
"keywords": [],
"creators": [],
"grants": [],
}
# See if the user info is in the SEAMM.ini file...
path = Path("~/SEAMM/seamm.ini").expanduser()
# See if the user info is in the .seammrc file...
path = Path("~/.seammrc").expanduser()
if path.exists:
config = configparser.ConfigParser()
config.read(path)
Expand All @@ -534,6 +535,8 @@ def reset_metadata(self, **kwargs):
if key in user:
author[key] = user[key]
self.metadata["creators"].append(author)
if "grants" in user:
self.metadata["grants"] = user["grants"].split()

self.metadata.update(kwargs)

Expand Down
33 changes: 33 additions & 0 deletions seamm/seammrc.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,39 @@ def remove_section(self, section):

def _save(self):
with open(self.path, "w") as fd:
# Added commented sections if they don't exist
if "USER" not in self:
fd.write(
"""
# [USER]
# Default user and grant information for flowcharts

# name = Last, First
# ORCID = xxxx-xxxx-xxxx-xxxx
# affiliation = Your instititution
# grants = <as DOIs like Zenodo uses, e.g 10.13039/100000001::2136142 10.13...>
"""
)
if "ZENODO" not in self:
fd.write(
"""
# [ZENODO]
# API token for Zenodo

# token = xxxx....
"""
)
if "SANDBOX" not in self:
fd.write(
"""
# [SANDBOX]
# API token for Zenodo's sandbox

# token = xxxxx....
"""
)

# And write the config file data
self._config.write(fd)

def re_read(self):
Expand Down
58 changes: 38 additions & 20 deletions seamm/tk_open.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import json
import logging
from pathlib import Path
import pprint # noqa: F401
import tkinter as tk
from tkinter.scrolledtext import ScrolledText
import tkinter.ttk as ttk
Expand All @@ -21,6 +22,7 @@
import seamm_widgets as sw

logger = logging.getLogger(__name__)
# logger.setLevel("DEBUG")

# "operators": (
# "must be",
Expand Down Expand Up @@ -540,7 +542,7 @@ def open(self):
self.config.set("SEAMM open", "source", source)
if source == "Zenodo" or source == "Zenodo sandbox":
if len(selected) > 0:
record = self._data[selected[0]]
record = self._data[selected[0]]["record"]
data = record.get_file("flowchart.flow")
return {"data": data, "source": source}
elif "previous jobs" == source:
Expand Down Expand Up @@ -667,14 +669,14 @@ def search_zenodo_for_flowcharts(self, sandbox=False):
else:
if operator == "after":
query += (
f" (+keywords:seamm-flowchart AND {pre}{zf}[{date} TO *]"
f' (+keywords:"seamm-flowchart" AND {pre}{zf}[{date} TO *]'
)
elif operator == "before":
query += (
f" (+keywords:seamm-flowchart AND {pre}{zf}[* TO {date}]"
f' (+keywords:"seamm-flowchart" AND {pre}{zf}[* TO {date}]'
)
elif operator == "on":
query += f" (+keywords:seamm-flowchart AND {pre}{zf}{date}"
query += f' (+keywords:"seamm-flowchart" AND {pre}{zf}{date}'
elif operator == "between":
try:
date2 = dateutil.parser.parse(value2).isoformat()
Expand All @@ -689,33 +691,33 @@ def search_zenodo_for_flowcharts(self, sandbox=False):
)
else:
query += (
f" (+keywords:seamm-flowchart AND {pre}{zf}[{date} to "
f"{date2}])"
f' (+keywords:"seamm-flowchart" AND {pre}{zf}[{date} to'
f" {date2}])"
)
else:
raise RuntimeError(f"Don't recognize operator '{operator}'")
else:
if operator == "is":
query += f" (+keywords:seamm-flowchart AND {pre}{zf}/{value}/)"
query += f' (+keywords:"seamm-flowchart" AND {pre}{zf}/{value}/)'
elif operator == "is like":
query += f" (+keywords:seamm-flowchart AND {pre}{zf}{value}~)"
query += f' (+keywords:"seamm-flowchart" AND {pre}{zf}{value}~)'
elif operator == "contains":
query += f" (+keywords:seamm-flowchart AND {pre}{zf}{value})"
query += f' (+keywords:"seamm-flowchart" AND {pre}{zf}{value})'
elif operator == "contains like":
query += f" (+keywords:seamm-flowchart AND {pre}{zf}{value}~)"
query += f' (+keywords:"seamm-flowchart" AND {pre}{zf}{value}~)'
elif operator == "is not":
query += f" (+keywords:seamm-flowchart AND -{zf}/{value}/)"
query += f' (+keywords:"seamm-flowchart" AND -{zf}/{value}/)'
elif operator == "is not like":
query += f" (+keywords:seamm-flowchart AND -{zf}{value}~)"
query += f' (+keywords:"seamm-flowchart" AND -{zf}{value}~)'
elif operator == "does not contain":
query += f" (+keywords:seamm-flowchart AND -{zf}{value})"
query += f' (+keywords:"seamm-flowchart" AND -{zf}{value})'
elif operator == "does not contain like":
query += f" (+keywords:seamm-flowchart AND -{zf}{value}~)"
query += f' (+keywords:"seamm-flowchart" AND -{zf}{value}~)'
else:
raise RuntimeError(f"Don't recognize operator '{operator}'")

if len(query) == 0:
query = "+keywords:seamm-flowchart"
query = '+keywords:"seamm-flowchart"'

logger.debug(f"query = {query}")

Expand All @@ -727,6 +729,7 @@ def search_zenodo_for_flowcharts(self, sandbox=False):

# Find all related records using conceptrecid
concepts = {}
logger.debug(f"Records {n_hits=}")
for record in records:
concept_id = record["conceptrecid"]
if concept_id not in concepts:
Expand All @@ -735,22 +738,32 @@ def search_zenodo_for_flowcharts(self, sandbox=False):
version = record["metadata"]["relations"]["version"][0]["index"]
data[version] = record

logger.debug("\n" + pprint.pformat(concepts))
logger.debug("--------\n\n")

# Remove any current data
self.clear_tree()
self._data = {}
tree = self["tree"]
for concept_id, data in concepts.items():
first = True
count = len(data)
for version in sorted(data.keys(), reverse=True):
record = data[version]
if first:
first = False
iid = tree.insert("", "end", text=record.title)
self._data[iid] = record
self._data[iid] = {
"count": count,
"record": record,
}
if len(data) > 1:
text = f"Version {version + 1}: {record.title}"
jid = tree.insert(iid, "end", text=text)
self._data[jid] = record
self._data[jid] = {
"count": count,
"record": record,
}

def select_record(self, event):
"""The user clicked on the tree-view ... handle the selected record."""
Expand All @@ -762,16 +775,21 @@ def select_record(self, event):
source = self["source"].get()

if "Zenodo" in source:
data = self._data[selected[0]]["metadata"]
tmp = self._data[selected[0]]
count = tmp["count"]
data = tmp["record"]["metadata"]
logger.debug("\n\nZenodo source, data =")
logger.debug("\n" + pprint.pformat(data))
logger.debug("-------")
self["title"].configure(text=data["title"])
self["description"].delete("1.0", "end")
self["description"].insert("1.0", data["description"])
info = data["relations"]["version"][0]
if "publication_data" in data:
date = data["publication_data"]
version = f"Version {info['index'] + 1} of {info['count']} -- {date}"
version = f"Version {info['index'] + 1} of {count} -- {date}"
else:
version = f"Version {info['index'] + 1} of {info['count']}"
version = f"Version {info['index'] + 1} of {count}"
self["version"].configure(text=version)
elif "previous jobs" == source:
job = self._data[selected[0]]
Expand Down
2 changes: 2 additions & 0 deletions seamm/tk_publish.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,8 @@ def publish_flowchart_to_zenodo(self, sandbox=False):
record.title = metadata["title"]
record.description = metadata["description"]
record.keywords = ["seamm-flowchart", *metadata["keywords"]]
if "grants" in metadata:
record.grants = [{"id": g} for g in metadata["grants"]]

# Update the metadata at Zenodo
record.update_metadata()
Expand Down
10 changes: 10 additions & 0 deletions seamm/tk_start_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"""The start node in a flowchart"""

import copy
import pprint # noqa: F401
import tkinter as tk
import tkinter.ttk as ttk

Expand Down Expand Up @@ -74,6 +75,8 @@ def update_widgets(self):
self["description"].delete("1.0", tk.END)
self["description"].insert("1.0", metadata["description"])
self["keywords"].set(", ".join(metadata["keywords"]))
if "grants" in metadata:
self["grants"].set(", ".join(metadata["grants"]))

# layout the authors
self._author_data = copy.deepcopy(metadata["creators"])
Expand Down Expand Up @@ -156,6 +159,13 @@ def create_frame(self, parent_widget):
w.grid(row=row, column=0, sticky=tk.EW)
row += 1

# grants
w = self["grants"] = sw.LabeledEntry(
frame, labeltext="Grants (DOIs, comma separated):", width=100
)
w.grid(row=row, column=0, sticky=tk.EW)
row += 1

# authors
w = self["authors label"] = ttk.Label(frame, text="Authors")
w.grid(row=row, column=0)
Expand Down
Loading