Skip to content

Commit

Permalink
Merge pull request #33 from EUDAT-B2SAFE/devel
Browse files Browse the repository at this point in the history
Release version 1.0.4
  • Loading branch information
merretbuurman authored Feb 4, 2021
2 parents 3c621ed + d8e1139 commit 1f3e075
Show file tree
Hide file tree
Showing 7 changed files with 505 additions and 45 deletions.
33 changes: 32 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,18 @@ For more details about the library you can build the documention using [Sphinx](
python setup.py build_sphinx
```


# Link to documentation


Check out the documentation [here](https://eudat-b2safe.github.io/PYHANDLE/).

(You can find the source here in this repository at [/docs/source/index.rst](./docs/source/index.rst)!)


# License

Copyright 2015-2017, Deutsches Klimarechenzentrum GmbH, GRNET S.A., SURFsara
Copyright 2015-2021, Deutsches Klimarechenzentrum GmbH, GRNET S.A., SURFsara

The PYHANDLE library is licensed under the Apache License,
Version 2.0 (the "License"); you may not use this product except in
Expand All @@ -50,7 +59,29 @@ Copyright 2015-2017, Deutsches Klimarechenzentrum GmbH, GRNET S.A., SURFsara
limitations under the License.


# Some usage notes

(to be migrated to documentation)


* `register_handle_kv(handle, **kv-pairs)` allows to pass (additionally to the handle name) key-value pairs.

* `register_handle_json(handle, list_of_entries, ...)` allow to pass JSON snippets instead of key-value pairs, so you can specify the indices. An entry looks like this: `{'index':index, 'type':entrytype, 'data':data}`. This is the format in which the changes are communicated to the handle server via its REST interface. An entry of type `HS_ADMIN` will be added if you do not provide one.

* `register_handle(...)` allows to pass (additionally to the handle name) a mandatory URL, and optionally a CHECKSUM, and more types as key-value pairs. Old method, made for legacy reasons, as this library was created to replace an earlier library that had a method with specifically this signature.

* `generate_and_register_handle(prefix, ...)` is a similar legacy method. Instead, just use `generate_PID_name(prefix)` to create a handle name and use one of the above.


# How to run the unit tests

The simplest way (tested with python 3.7.1):

```bash
python setup.py test
```

Also look at `pyhandle/tests/README.md`.



11 changes: 11 additions & 0 deletions pyhandle/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
__version__ = "1.0.4"
# Version 1.0.4 of 2021-02-04 including some pull requests from 2020.
# The version number had been made 1.0.4 already in 2020, but
# no release was done back then.

# The version as used in setup.py and docs/source/conf.py.

Expand All @@ -8,3 +11,11 @@
# (The first comment - empty or not - would be appended to
# the package name, the next non-empty comment would be
# printed as description).

from . import clientcredentials
from . import handleclient

# Make sure that a single "import pyhandle" allows the use of
# relevant submodules!
# See
# https://github.com/psf/requests/blob/master/requests/__init__.py#L120
2 changes: 0 additions & 2 deletions pyhandle/client/batchhandleclient.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@

from .. import util

logging.basicConfig(level=logging.INFO)

LOGGER = logging.getLogger(__name__)
LOGGER.addHandler(util.NullHandler())

Expand Down
122 changes: 98 additions & 24 deletions pyhandle/client/resthandleclient.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import uuid
import logging
import datetime
import copy
import requests # This import is needed for mocking in unit tests.

from past.builtins import xrange
Expand Down Expand Up @@ -371,10 +372,15 @@ def generate_and_register_handle(self, prefix, location, checksum=None, **extrat
LOGGER.debug('generate_and_register_handle...')

handle = self.generate_PID_name(prefix)
handle = self.register_handle(

if not location is None:
extratypes["URL"] = location

if not checksum is None:
extratypes["CHECKSUM"] = checksum

handle = self.register_handle_kv(
handle,
location,
checksum,
overwrite=True,
**extratypes
)
Expand Down Expand Up @@ -590,20 +596,58 @@ def delete_handle(self, handle, *other):
else:
raise GenericHandleError(op=op, handle=handle, response=resp)



def register_handle_json(self, handle, list_of_entries, overwrite=False):
'''
entry = {'index':index, 'type':entrytype, 'data':data}
# Optional 'ttl'
'''

# If already exists and can't be overwritten:
if overwrite == False:
handlerecord_json = self.retrieve_handle_record_json(handle)
if handlerecord_json is not None:
msg = 'Could not register handle'
LOGGER.error(msg + ', as it already exists.')
raise HandleAlreadyExistsException(handle=handle, msg=msg)

# So we don't modify the caller's list:
list_of_entries = copy.deepcopy(list_of_entries)

# Create admin entry
keys = []
for entry in list_of_entries:
keys.append(entry['type'])

if not 'HS_ADMIN' in keys:
adminentry = self.__create_admin_entry(
self.__handleowner,
self.__HS_ADMIN_permissions,
self.__make_another_index(list_of_entries, hs_admin=True),
handle
)
list_of_entries.append(adminentry)

# Create record itself and put to server:
return self.__handle_registering(handle, list_of_entries, overwrite)

def register_handle(self, handle, location, checksum=None, additional_URLs=None, overwrite=False, **extratypes):
'''
Registers a new Handle with given name. If the handle already exists
and overwrite is not set to True, the method will throw an
exception.
Note: This is just a wrapper for register_handle_kv. It was made for
legacy reasons, as this library was created to replace an earlier
library that had a method with specifically this signature.
:param handle: The full name of the handle to be registered (prefix
and suffix)
:param location: The URL of the data entity to be referenced
:param checksum: Optional. The checksum string.
:param extratypes: Optional. Additional key value pairs such as: additional_URLs for 10320/loc
:param additional_URLs: Optional. A list of URLs (as strings) to be
added to the handle record as 10320/LOC entry.
added to the handle record as 10320/LOC entry. Note: This is currently
not implemented.
:param overwrite: Optional. If set to True, an existing handle record
will be overwritten. Defaults to False.
:raises: :exc:`~pyhandle.handleexceptions.HandleAlreadyExistsException` Only if overwrite is not set or
Expand All @@ -612,7 +656,44 @@ def register_handle(self, handle, location, checksum=None, additional_URLs=None,
:raises: :exc:`~pyhandle.handleexceptions.HandleSyntaxError`
:return: The handle name.
'''
LOGGER.debug('register_handle...')

if extratypes is None:
extratypes = {}

if not location is None:
extratypes["URL"] = location

if not checksum is None:
extratypes["CHECKSUM"] = checksum

if additional_URLs is not None:
raise NotImplementedError('No support for argument "additional_URLs"!')

return self.register_handle_kv(
handle,
overwrite,
**extratypes
)

def register_handle_kv(self, handle, overwrite=False, **kv_pairs):
'''
Registers a new Handle with given name. If the handle already exists
and overwrite is not set to True, the method will throw an
exception.
:param handle: The full name of the handle to be registered (prefix
and suffix)
:param extratypes: Optional, but highly recommended. The key value pairs
to be included in the record, e.g. URL, CHECKSUM, ...
:param overwrite: Optional. If set to True, an existing handle record
will be overwritten. Defaults to False.
:raises: :exc:`~pyhandle.handleexceptions.HandleAlreadyExistsException` Only if overwrite is not set or
set to False.
:raises: :exc:`~pyhandle.handleexceptions.HandleAuthenticationError`
:raises: :exc:`~pyhandle.handleexceptions.HandleSyntaxError`
:return: The handle name.
'''
LOGGER.debug('register_handle_kv...')

# If already exists and can't be overwritten:
if overwrite == False:
Expand All @@ -633,29 +714,20 @@ def register_handle(self, handle, location, checksum=None, additional_URLs=None,
list_of_entries.append(adminentry)

# Create other entries
entry_URL = self.__create_entry(
'URL',
location,
self.__make_another_index(list_of_entries, url=True)
)
list_of_entries.append(entry_URL)
if checksum is not None:
entryChecksum = self.__create_entry(
'CHECKSUM',
checksum,
self.__make_another_index(list_of_entries)
)
list_of_entries.append(entryChecksum)
if extratypes is not None:
for key, value in extratypes.items():
if kv_pairs is not None:
for key, value in kv_pairs.items():
is_url = True if key == 'URL' else False
entry = self.__create_entry(
key,
value,
self.__make_another_index(list_of_entries)
self.__make_another_index(list_of_entries, is_url)
)
list_of_entries.append(entry)

# Create record itself and put to server
# Create record itself and put to server:
return self.__handle_registering(handle, list_of_entries, overwrite)

def __handle_registering(self, handle, list_of_entries, overwrite):
op = 'registering handle'
resp, put_payload = self.__send_handle_put_request(
handle,
Expand Down Expand Up @@ -947,9 +1019,11 @@ def __create_admin_entry(self, handleowner, permissions, index, handle, ttl=None
# If the handle owner is specified, use it. Otherwise, use 200:0.NA/prefix
# With the prefix taken from the handle that is being created, not from anywhere else.
if handleowner is None:
adminindex = '200'
adminindex = '200' # TODO Why string, not integer?
prefix = handle.split('/')[0]
adminhandle = '0.NA/' + prefix
# TODO: Why is adminindex string, not integer? When I retrieve from
# HandleSystem API, the JSON has an int there.
else:
adminindex, adminhandle = utilhandle.remove_index_from_handle(handleowner)

Expand Down
Loading

0 comments on commit 1f3e075

Please sign in to comment.