Coverage for libs/sdc_etl_libs/api_helpers/apis/Ultipro/UltiproTimeManagement.py : 75%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
2import datetime
3from dateutil import parser
4import json
5import logging
6import requests
7import time
8from sdc_etl_libs.api_helpers.apis.Ultipro.Ultipro import Ultipro
9from sdc_etl_libs.sdc_dataframe.Dataframe import Dataframe
10from sdc_etl_libs.sdc_dataframe.SDCDataframeEnums import SDCDFTypes
11from sdc_etl_libs.sdc_file_helpers.SDCFileHelpers import SDCFileHelpers
12from sdc_etl_libs.sdc_data_schema.schema_validation import SchemaValidation
13from sdc_etl_libs.sdc_data_schema.schema_toolbox import SchemaToolbox
15logging.basicConfig(level=logging.INFO)
18class UltiproTimeManagement(Ultipro):
20 def __init__(self):
21 super().__init__()
22 self.rest_authenticate("tm_username", "tm_password")
24 def get_daily_filter(self, datetime_, days_, filter_field_list_):
25 """
26 Constructs a filter for Time Management calls using the list of supplied
27 fields. A start date and end date is set with the fields used with
28 "greater than or equal to" start date and "less than" end date. When
29 there is more than one field they are combined with 'or'.
31 :param datetime_: Datetime object tp serve as end date.
32 :param days_: Number of days to go back from datetime_ to set as start date.
33 :param filter_field_list_: List of fields to create complex filter with.
34 :return: URL filter as string.
35 """
37 if not isinstance(filter_field_list_, list):
38 raise Exception("fields_ must be a list for Time Management "
39 "get_daily_filter()")
41 if type(datetime_) == str:
42 datetime_ = parser.parse(datetime_)
44 startdate = (datetime_ - datetime.timedelta(days_)).strftime("%Y-%m-%d")
45 enddate = datetime_.strftime("%Y-%m-%d")
46 url_filter = \
47 " or ".join(f'({field} ge {startdate} '
48 f'and {field} le {enddate})' for field in filter_field_list_)
49 return url_filter
51 def process_endpoint(self, base_endpoint_url_, filter_, limit_=1000):
52 """
53 This function handles the pagination of the Ultipro API calls for
54 Time Management UTMOData Service.
56 :param base_endpoint_url_: base url for the api : string
57 :param filter_: filter for api endpoint: string
58 :param limit_: Number of records to return with each call. Default is 1,000.
59 :return: List of JSON values
60 """
62 data = []
64 if filter_ is not None:
65 requests_url = f"{base_endpoint_url_}?$filter={filter_}&$count=true"
66 else:
67 requests_url = f"{base_endpoint_url_}?&$count=true"
69 total_records = 1
70 skip = 0
72 while skip < total_records:
74 requests_url_with_pagination = requests_url + \
75 f"&$skip={skip}&$top={limit_}"
77 logging.info(requests_url_with_pagination)
79 response = requests.get(requests_url_with_pagination, auth=self.auth)
81 if response.status_code == 200:
82 try:
83 data_json = json.loads(response.content)
84 total_records = data_json["@odata.count"]
85 records = data_json["value"]
86 if skip == 0:
87 logging.info(f"Total records to grab: {total_records:,}")
88 skip += limit_
89 except Exception as e:
90 logging.error(e)
91 raise Exception(f"Unable to process data: {response.content}")
93 for item in records:
94 data.append(item)
96 logging.info(f"Grabbed {len(records):,} record(s) from page "
97 f"{int(skip/limit_)}. Progress: "
98 f"{len(data):,}/{total_records:,}")
100 elif response.status_code == 429:
101 seconds_to_wait = 120
102 logging.info(f"Too many requests made to API. "
103 f"Waiting {seconds_to_wait/60:,} minute(s) before retrying.")
104 time.sleep(seconds_to_wait)
105 continue
107 else:
108 raise Exception(
109 f"Failed to get access group data from api. "
110 f"Status: {response.status_code}")
112 return data
114 def get_data_from_endpoint(self, schema_name_, endpoint_name_,
115 filter_=None, limit_=1000):
116 """
117 Grabs data from API endpoint and returns a SDCDataframe object with
118 data loaded into the dataframe if data is avaliable.
120 :param schema_name_: Schema file name for SDCDataframe instance..
121 :param endpoint_name_: Name of API URL endpoint.
122 :param filter_: Filter to apply to API call.
123 :return: SDCDataframe object with data in dataframe.
124 """
126 data_schema = json.loads(open(SDCFileHelpers.get_file_path(
127 'schema', f"Ultipro/time_management/{schema_name_}.json")).read())
128 validation = SchemaValidation()
129 validated_schema = validation.validate_schema(data_schema)
130 validated_source_endpoint_schema = SchemaToolbox.get_endpoint_data_from_schema(validated_schema, "main_source")
131 self.base_url = validated_source_endpoint_schema["info"]["access"]["base_url"]
132 df = Dataframe(SDCDFTypes.PANDAS, validated_schema)
134 base_endpoint_url = self.base_url + f'/{endpoint_name_}'
136 data = self.process_endpoint(base_endpoint_url, filter_, limit_)
138 if len(data) >= 1:
139 df.load_data(data)
140 return df
141 else:
142 logging.warning("Received no data")
143 return None