Coverage for application/util/functions.py: 97%
32 statements
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-23 02:22 +0000
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-23 02:22 +0000
1import re
2from datetime import datetime, timedelta
3from typing import Dict, Optional
6def parse_datetime(timestamp: str) -> datetime:
7 """
8 Returns a datetime object given a timestamp string.
10 :param str timestamp: The timestamp to parse.
11 :return datetime: The timestamp parsed as a datetime object.
12 """
13 if '.' in timestamp:
14 return datetime.strptime(timestamp, '%Y-%m-%dT%H:%M:%S.%fZ')
15 return datetime.strptime(timestamp, '%Y-%m-%dT%H:%M:%SZ')
18def extract_recorded_datetime(json_object: Dict) -> Optional[datetime]:
19 """
20 Returns a datetime object of the recorded timestamp given a JSON annotation record.
22 :param Dict json_object: An annotation record.
23 :return datetime: A datetime object of the timestamp from the json object.
24 """
25 if not json_object:
26 return None
27 if '.' in json_object['recorded_timestamp']:
28 timestamp = datetime.strptime(json_object['recorded_timestamp'], '%Y-%m-%dT%H:%M:%S.%fZ')
29 if timestamp.microsecond >= 500000:
30 return timestamp.replace(microsecond=0) + timedelta(seconds=1)
31 return timestamp.replace(microsecond=0)
32 return datetime.strptime(json_object['recorded_timestamp'], '%Y-%m-%dT%H:%M:%SZ')
35def get_association(annotation: Dict, link_name: str) -> dict:
36 """
37 Obtains an association value from the annotation data structure.
39 :param Dict annotation: The complete annotation dictionary.
40 :param str link_name: The specific key we want to get the value for.
41 :return dict: The matching value dict.
42 """
43 if 'associations' not in annotation.keys():
44 return {}
45 for association in annotation['associations']:
46 if association['link_name'] == link_name:
47 return association
48 return {}
51def format_annotator(annotator: str) -> str:
52 """
53 Format VARS annotator name. Most are formatted as "FirstnameLastname", with some exceptions.
55 :param str annotator: VARS username to format
56 :return str: Formatted name
57 """
58 if annotator == 'hcarlson':
59 return 'Harold Carlson'
60 else:
61 return re.sub('([a-zA-Z]+)([A-Z])', r'\1 \2', annotator)
64def flatten_taxa_tree(tree: Dict, flat: Dict):
65 """
66 Recursive function taking a taxonomy tree returned from WoRMS API and flattening it into a single dictionary.
68 :param Dict tree: The nested taxon tree from WoRMS.
69 :param Dict flat: The newly created flat taxon tree.
70 """
71 flat[tree['rank'].lower()] = tree['scientificname']
72 if tree['child'] is not None:
73 flatten_taxa_tree(tree['child'], flat)
74 return flat