Skip to content

Commit

Permalink
bugfixes
Browse files Browse the repository at this point in the history
  • Loading branch information
matthiasprobst committed Dec 13, 2023
1 parent 5f87a2e commit 03b61a8
Show file tree
Hide file tree
Showing 6 changed files with 91 additions and 59 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ jobs:

- name: Run pytest coverage
env:
ZENODO_API_TOKEN: ${{ secrets.ZENODO_API_TOKEN }}
ZENODO_SANDBOX_API_TOKEN: ${{ secrets.ZENODO_SANDBOX_API_TOKEN }}
run: pytest --cov --cov-report=xml

- name: Upload coverage to Codecov
Expand Down
20 changes: 15 additions & 5 deletions h5rdmtoolbox/database/zenodo/config.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import warnings

import appdirs
import configparser
import os
Expand All @@ -22,10 +24,13 @@ def _parse_ini_file(zenodo_ini_filename: Union[str, pathlib.Path]):
def get_api_token(sandbox: bool,
zenodo_ini_filename: Union[str, pathlib.Path] = None):
"""Read the Zenodo API token from the config file."""
env_token = os.environ.get('ZENODO_API_TOKEN', None)
if sandbox:
env_token = os.environ.get('ZENODO_SANDBOX_API_TOKEN', None)
else:
env_token = os.environ.get('ZENODO_API_TOKEN', None)
if env_token is not None:
env_token = env_token.strip()
logger.debug('Took token from environment variable ZENODO_API_TOKEN.')
logger.debug('Took token from environment variable ZENODO_SANDBOX_API_TOKEN.')
return env_token
zenodo_ini_filename = _parse_ini_file(zenodo_ini_filename)
config = configparser.ConfigParser()
Expand All @@ -35,9 +40,14 @@ def get_api_token(sandbox: bool,
else:
api_token = config['zenodo']['api_token']
if not api_token:
raise ValueError(f'No API token found in {zenodo_ini_filename}. Please verify the correctness of the file '
f'{zenodo_ini_filename}. The api_token entry must be in the section [zenodo] or '
f'[zenodo:sandbox].')
warnings.warn(f'No API token found in {zenodo_ini_filename}. '
f'Accessing Zenodo without API token may work, but if not it is because '
f'of the missing api_token.')
api_token = ''
# if not api_token:
# raise ValueError(f'No API token found in {zenodo_ini_filename}. Please verify the correctness of the file '
# f'{zenodo_ini_filename}. The api_token entry must be in the section [zenodo] or '
# f'[zenodo:sandbox].')
return api_token


Expand Down
119 changes: 69 additions & 50 deletions h5rdmtoolbox/database/zenodo/deposit.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ class AbstractZenodoRecord(abc.ABC):
"""An abstract Zenodo record."""
base_url = None

def __init__(self, metadata: Metadata, deposit_id: Union[int, None] = None):
def __init__(self,
deposit_id: Union[int, None] = None,
metadata: Metadata = None):
if self.base_url is None:
raise ValueError('The base_url must be set.')
self.deposit_id = deposit_id
Expand Down Expand Up @@ -66,34 +68,40 @@ def get_filenames(self):


class ZenodoRecordInterface(AbstractZenodoRecord):
"""A Zenodo record interface."""

def __init__(self,
metadata: Metadata,
deposit_id: Union[int, None] = None,
file_or_filenames: Union[List[Union[str, pathlib.Path]], None] = None):
self.deposit_id = int(deposit_id)
self.metadata = metadata
self.filenames = []
metadata: Metadata = None):
self.deposit_id = deposit_id
self._metadata = metadata

if file_or_filenames is not None:
if isinstance(file_or_filenames, (str, pathlib.Path)):
self.add_file(file_or_filenames)
elif isinstance(file_or_filenames, (tuple, list)):
self.add_file(*file_or_filenames)
else:
raise TypeError(
'file_or_filenames must be a string, pathlib.Path, or a list of strings or pathlib.Path. '
f'Got {type(file_or_filenames)} instead.')
@property
def metadata(self):
if self._metadata is None:
raise ValueError('The metadata must be set.')
return self._metadata

@metadata.setter
def metadata(self, value: Metadata):
if not isinstance(value, Metadata):
raise TypeError('The metadata must be a Metadata object.')
self._metadata = value

def _get(self, raise_for_status: bool = False):
"""Get the deposit from Zenodo."""
if self.deposit_id is None:
raise ValueError('The deposit_id must be set.')
base_url = self.base_url + f'/{self.deposit_id}'
r = requests.get(
base_url,
params={'access_token': self.api_token}
)
if not self.api_token:
r = requests.get(
base_url,
)
else:
r = requests.get(
base_url,
params={'access_token': self.api_token}
)
if raise_for_status:
r.raise_for_status()
return r
Expand Down Expand Up @@ -128,36 +136,31 @@ def create(self):
self.deposit_id = r.json()['id']
else:
assert self.deposit_id == r.json()['id']
self._push_files()
return self.deposit_id

def _push_files(self):
"""Push the files to the deposit."""

bucket_url = self._get().json()["links"]["bucket"]
for filename in self.filenames:
logger.debug(f'adding file "{filename}" to deposit "{self.deposit_id}"')
with open(filename, "rb") as fp:
r = requests.put(
"%s/%s" % (bucket_url, filename.name),
data=fp,
params={"access_token": self.api_token},
)
r.raise_for_status()

def delete(self):
"""Delete the deposit on Zenodo."""
logger.debug(f'getting deposit "{self.deposit_id}"')
r = requests.get(
f'https://sandbox.zenodo.org/api/deposit/depositions/{self.deposit_id}',
params={'access_token': self.api_token}
)
if not self.api_token:
r = requests.get(
f'https://sandbox.zenodo.org/api/deposit/depositions/{self.deposit_id}',
)
else:
r = requests.get(
f'https://sandbox.zenodo.org/api/deposit/depositions/{self.deposit_id}',
params={'access_token': self.api_token}
)
r.raise_for_status()
logger.debug('deleting deposit {self.deposit_id}')
r = requests.delete(
'https://sandbox.zenodo.org/api/deposit/depositions/{}'.format(r.json()['id']),
params={'access_token': self.api_token}
)
if not self.api_token:
r = requests.delete(
'https://sandbox.zenodo.org/api/deposit/depositions/{}'.format(r.json()['id']),
)
else:
r = requests.delete(
'https://sandbox.zenodo.org/api/deposit/depositions/{}'.format(r.json()['id']),
params={'access_token': self.api_token}
)
r.raise_for_status()

def update(self):
Expand All @@ -170,8 +173,16 @@ def add_file(self, filename):
"""Add a file to the deposit."""
filename = pathlib.Path(filename)
if not filename.exists():
raise FileNotFoundError(f'{filename} does not exist.')
self.filenames.append(filename)
raise FileNotFoundError(f'File "{filename}" does not exist.')
bucket_url = self._get().json()["links"]["bucket"]
logger.debug(f'adding file "{filename}" to deposit "{self.deposit_id}"')
with open(filename, "rb") as fp:
r = requests.put(
"%s/%s" % (bucket_url, filename.name),
data=fp,
params={"access_token": self.api_token},
)
r.raise_for_status()

def get_filenames(self):
"""Get a list of all filenames."""
Expand All @@ -191,8 +202,11 @@ def download_files(self, target_folder: Union[str, pathlib.Path] = None):
target_folder = pathlib.Path(target_folder)
fname = f["filename"]
target_filename = target_folder / fname
bucket_dict = requests.get(f['links']['self'],
params={'access_token': self.api_token}).json()
if not self.api_token:
bucket_dict = requests.get(f['links']['self']).json()
else:
bucket_dict = requests.get(f['links']['self'],
params={'access_token': self.api_token}).json()
logger.debug(f'downloading file "{fname}" to "{target_filename}"')
download_files.append(target_filename)
with open(target_filename, 'wb') as file:
Expand All @@ -212,20 +226,25 @@ def download_file(self, name, target_folder: Union[str, pathlib.Path] = None):
if f['filename'] == name:
fname = f["filename"]
target_filename = target_folder / fname
bucket_dict = requests.get(f['links']['self'],
params={'access_token': self.api_token}).json()
if not self.api_token:
bucket_dict = requests.get(f['links']['self']).json()
else:
bucket_dict = requests.get(f['links']['self'],
params={'access_token': self.api_token}).json()
logger.debug(f'downloading file "{fname}" to "{target_filename}"')
with open(target_filename, 'wb') as file:
file.write(requests.get(bucket_dict['links']['self']).content)
return target_filename


class ZenodoRecord(ZenodoRecordInterface):
"""A Zenodo record in the production environment."""
base_url = 'https://zenodo.org/api/deposit/depositions'

@property
def api_token(self):
return self.api_token(sandbox=False)
def api_token(self) -> str:
"""Get the API token for the production environment."""
return get_api_token(sandbox=False)


class ZenodoSandboxRecord(ZenodoRecordInterface):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ def setUp(self) -> None:
def test_adding_transformation(self):

snt = h5tbx.conventions.standard_names.StandardNameTable.from_zenodo(doi=8276716)
from h5rdmtoolbox.database.zenodo.deposit import ZenodoRecord
z = ZenodoRecord(deposit_id=8276716)
self.assertTrue(z.exists())

# check if the problem really exists:
with self.assertRaises(errors.StandardNameError):
Expand Down
4 changes: 2 additions & 2 deletions tests/conventions/test_conventions.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,13 @@ def test_upload_convention(self):
publication_date=datetime.now(),
)
zsr = ZenodoSandboxRecord(deposit_id=ZENODO_TUTORIAL_CONVENTION_DEPOSIT_ID,
metadata=meta,
file_or_filenames=cv_yaml_filename)
metadata=meta)
if not zsr.exists():
zsr.deposit_id = None
zsr.create()
else:
zsr.update()
zsr.add_file(cv_yaml_filename)

# download file from zenodo deposit:
self.assertEqual(1, len(zsr.get_filenames()))
Expand Down
2 changes: 1 addition & 1 deletion tests/database/test_zenodo.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ def test_create_new_deposit(self):
self.assertFalse(zsr.exists())
with open('testfile.txt', 'w') as f:
f.write('This is a test file.')
zsr.add_file('testfile.txt')
zsr.create()
zsr.add_file('testfile.txt')
zsr.create() # call it again. does it crash?
pathlib.Path('testfile.txt').unlink()
self.assertTrue(zsr.exists())
Expand Down

0 comments on commit 03b61a8

Please sign in to comment.