Source code for pyhandle.utilhandle
'''
This module provides some handle-related functions
that are needed across various modules of the
pyhandle library.
'''
from __future__ import absolute_import
import base64
from future.standard_library import install_aliases
install_aliases()
from urllib.parse import quote
from . import handleexceptions
from . import util
[docs]def remove_index_from_handle(handle_with_index):
'''
Returns index and handle separately, in a tuple.
:handle_with_index: The handle string with an index (e.g.
500:prefix/suffix)
:return: index and handle as a tuple, where index is integer.
'''
split = handle_with_index.split(':')
if len(split) == 2:
split[0] = int(split[0])
return split
elif len(split) == 1:
return (None, handle_with_index)
elif len(split) > 2:
raise handleexceptions.HandleSyntaxError(
msg='Too many colons',
handle=handle_with_index,
expected_syntax='index:prefix/suffix')
[docs]def check_handle_syntax(string):
'''
Checks the syntax of a handle without an index (are prefix
and suffix there, are there too many slashes?).
:string: The handle without index, as string prefix/suffix.
:raise: :exc:`~pyhandle.handleexceptions.handleexceptions.HandleSyntaxError`
:return: True. If it's not ok, exceptions are raised.
'''
expected = 'prefix/suffix'
try:
arr = string.split('/')
except AttributeError:
raise handleexceptions.HandleSyntaxError(msg='The provided handle is None', expected_syntax=expected)
if len(arr) < 2:
msg = 'No slash'
raise handleexceptions.HandleSyntaxError(msg=msg, handle=string, expected_syntax=expected)
if len(arr[0]) == 0:
msg = 'Empty prefix'
raise handleexceptions.HandleSyntaxError(msg=msg, handle=string, expected_syntax=expected)
if len(arr[1]) == 0:
msg = 'Empty suffix'
raise handleexceptions.HandleSyntaxError(msg=msg, handle=string, expected_syntax=expected)
if ':' in string:
if string.startswith('hdl:'): # Fixing https://github.com/EUDAT-B2HANDLE/PYHANDLE/issues/49
# TODO: Note: What about DOIs? -> Fixed in a different PR
# Note of caution: Handle Server won't accept REST API calls with hdl: prepended.
# It will respond with HTTP Status Code 400 and Response: {"responseCode":301,
# "message":"That prefix doesn't live here","handle":"hdl:21.14106/TESTTESTTEST"}
# The problem is prevented by removing any hdl: or doi: right before making the request.
return True
else:
check_handle_syntax_with_index(string, base_already_checked=True)
# TODO: Actually this is not a handle, but refers to a field inside a handle record, so
# to be strict, we should not accept this.
return True
[docs]def check_handle_syntax_with_index(string, base_already_checked=False):
'''
Checks the syntax of a handle with an index (is index there, is it an
integer?), and of the handle itself.
:string: The handle with index, as string index:prefix/suffix.
:raise: :exc:`~pyhandle.handleexceptions.handleexceptions.HandleSyntaxError`
:return: True. If it's not ok, exceptions are raised.
'''
expected = 'index:prefix/suffix'
try:
arr = string.split(':')
except AttributeError:
raise handleexceptions.HandleSyntaxError(msg='The provided handle is None.', expected_syntax=expected)
if len(arr) > 2:
msg = 'Too many colons'
raise handleexceptions.HandleSyntaxError(msg=msg, handle=string, expected_syntax=expected)
elif len(arr) < 2:
msg = 'No colon'
raise handleexceptions.HandleSyntaxError(msg=msg, handle=string, expected_syntax=expected)
try:
int(arr[0])
except ValueError:
if arr[0] == 'hdl:':
msg = 'Handle string starts with "hdl:", not with an index.'
raise handleexceptions.HandleSyntaxError(msg=msg, handle=string, expected_syntax=expected)
else:
msg = 'Index is not an integer'
raise handleexceptions.HandleSyntaxError(msg=msg, handle=string, expected_syntax=expected)
if not base_already_checked:
check_handle_syntax(string)
return True
[docs]def create_authentication_string(username, password):
'''
Creates an authentication string from the username and password.
:username: Username.
:password: Password.
:return: The encoded string.
'''
username_utf8 = username.encode('utf-8')
userpw_utf8 = password.encode('utf-8').decode('utf-8')
username_perc = quote(username_utf8)
authinfostring = username_perc + ':' + userpw_utf8
authinfostring_base64 = base64.b64encode(authinfostring.encode('utf-8')).decode('utf-8')
return authinfostring_base64
[docs]def make_request_log_message(**args):
'''
Creates a string containing all relevant information
about a request made to the Handle System, for
logging purposes.
:handle: The handle that the request is about.
:url: The url the request is sent to.
:headers: The headers sent along with the request.
:verify: Boolean parameter passed to the requests
module (https verification).
:resp: The request's response.
:op: The library operation during which the request
was sent.
:payload: Optional. The payload sent with the request.
:return: A formatted string.
'''
mandatory_args = ['op', 'handle', 'url', 'headers', 'verify', 'resp']
optional_args = ['payload']
util.check_presence_of_mandatory_args(args, mandatory_args)
util.add_missing_optional_args_with_value_none(args, optional_args)
space = '\n '
message = ''
message += '\n'+args['op']+' '+args['handle']
message += space+'URL: '+args['url']
message += space+'HEADERS: '+str(args['headers'])
message += space+'VERIFY: '+str(args['verify'])
if 'payload' in args.keys():
message += space+'PAYLOAD:'+space+str(args['payload'])
message += space+'RESPONSECODE: '+str(args['resp'].status_code)
message += space+'RESPONSE:'+space+str(args['resp'].content)
return message