polly-python 1.6.0__tar.gz → 1.7.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. {polly_python-1.6.0/polly_python.egg-info → polly_python-1.7.0}/PKG-INFO +1 -1
  2. polly_python-1.7.0/polly/__init__.py +1 -0
  3. {polly_python-1.6.0 → polly_python-1.7.0}/polly/omixatlas.py +18 -0
  4. {polly_python-1.6.0 → polly_python-1.7.0/polly_python.egg-info}/PKG-INFO +1 -1
  5. {polly_python-1.6.0 → polly_python-1.7.0}/polly_services/reporting/reporting.py +101 -0
  6. {polly_python-1.6.0 → polly_python-1.7.0}/polly_services/reporting/reporting_hlpr.py +52 -0
  7. polly_python-1.6.0/polly/__init__.py +0 -1
  8. {polly_python-1.6.0 → polly_python-1.7.0}/LICENSE.md +0 -0
  9. {polly_python-1.6.0 → polly_python-1.7.0}/MANIFEST.in +0 -0
  10. {polly_python-1.6.0 → polly_python-1.7.0}/README.md +0 -0
  11. {polly_python-1.6.0 → polly_python-1.7.0}/polly/analyze.py +0 -0
  12. {polly_python-1.6.0 → polly_python-1.7.0}/polly/application_error_info.py +0 -0
  13. {polly_python-1.6.0 → polly_python-1.7.0}/polly/auth.py +0 -0
  14. {polly_python-1.6.0 → polly_python-1.7.0}/polly/bridge_cohort.py +0 -0
  15. {polly_python-1.6.0 → polly_python-1.7.0}/polly/cohort.py +0 -0
  16. {polly_python-1.6.0 → polly_python-1.7.0}/polly/constants.py +0 -0
  17. {polly_python-1.6.0 → polly_python-1.7.0}/polly/core_cohort.py +0 -0
  18. {polly_python-1.6.0 → polly_python-1.7.0}/polly/curation.py +0 -0
  19. {polly_python-1.6.0 → polly_python-1.7.0}/polly/data_management.py +0 -0
  20. {polly_python-1.6.0 → polly_python-1.7.0}/polly/errors.py +0 -0
  21. {polly_python-1.6.0 → polly_python-1.7.0}/polly/help.py +0 -0
  22. {polly_python-1.6.0 → polly_python-1.7.0}/polly/helpers.py +0 -0
  23. {polly_python-1.6.0 → polly_python-1.7.0}/polly/http_response_codes.py +0 -0
  24. {polly_python-1.6.0 → polly_python-1.7.0}/polly/index_schema_level_conversion_const.py +0 -0
  25. {polly_python-1.6.0 → polly_python-1.7.0}/polly/jobs.py +0 -0
  26. {polly_python-1.6.0 → polly_python-1.7.0}/polly/omixatlas_hlpr.py +0 -0
  27. {polly_python-1.6.0 → polly_python-1.7.0}/polly/pipelines.py +0 -0
  28. {polly_python-1.6.0 → polly_python-1.7.0}/polly/s3_utils.py +0 -0
  29. {polly_python-1.6.0 → polly_python-1.7.0}/polly/session.py +0 -0
  30. {polly_python-1.6.0 → polly_python-1.7.0}/polly/threading_utils.py +0 -0
  31. {polly_python-1.6.0 → polly_python-1.7.0}/polly/tracking.py +0 -0
  32. {polly_python-1.6.0 → polly_python-1.7.0}/polly/validation.py +0 -0
  33. {polly_python-1.6.0 → polly_python-1.7.0}/polly/validation_hlpr.py +0 -0
  34. {polly_python-1.6.0 → polly_python-1.7.0}/polly/workspaces.py +0 -0
  35. {polly_python-1.6.0 → polly_python-1.7.0}/polly_interfaces/IFiles.py +0 -0
  36. {polly_python-1.6.0 → polly_python-1.7.0}/polly_interfaces/IReporting.py +0 -0
  37. {polly_python-1.6.0 → polly_python-1.7.0}/polly_interfaces/ISchema.py +0 -0
  38. {polly_python-1.6.0 → polly_python-1.7.0}/polly_interfaces/__init__.py +0 -0
  39. {polly_python-1.6.0 → polly_python-1.7.0}/polly_python.egg-info/SOURCES.txt +0 -0
  40. {polly_python-1.6.0 → polly_python-1.7.0}/polly_python.egg-info/dependency_links.txt +0 -0
  41. {polly_python-1.6.0 → polly_python-1.7.0}/polly_python.egg-info/requires.txt +0 -0
  42. {polly_python-1.6.0 → polly_python-1.7.0}/polly_python.egg-info/top_level.txt +0 -0
  43. {polly_python-1.6.0 → polly_python-1.7.0}/polly_services/__init__.py +0 -0
  44. {polly_python-1.6.0 → polly_python-1.7.0}/polly_services/dataset.py +0 -0
  45. {polly_python-1.6.0 → polly_python-1.7.0}/polly_services/files/__init__.py +0 -0
  46. {polly_python-1.6.0 → polly_python-1.7.0}/polly_services/files/files.py +0 -0
  47. {polly_python-1.6.0 → polly_python-1.7.0}/polly_services/files/files_hlpr.py +0 -0
  48. {polly_python-1.6.0 → polly_python-1.7.0}/polly_services/polly_services_hlpr.py +0 -0
  49. {polly_python-1.6.0 → polly_python-1.7.0}/polly_services/reporting/__init__.py +0 -0
  50. {polly_python-1.6.0 → polly_python-1.7.0}/polly_services/schema/__init__.py +0 -0
  51. {polly_python-1.6.0 → polly_python-1.7.0}/polly_services/schema/schema.py +0 -0
  52. {polly_python-1.6.0 → polly_python-1.7.0}/polly_services/schema/schema_const.py +0 -0
  53. {polly_python-1.6.0 → polly_python-1.7.0}/polly_services/schema/schema_hlpr.py +0 -0
  54. {polly_python-1.6.0 → polly_python-1.7.0}/polly_services/schema/validate_schema_hlpr.py +0 -0
  55. {polly_python-1.6.0 → polly_python-1.7.0}/pyproject.toml +0 -0
  56. {polly_python-1.6.0 → polly_python-1.7.0}/setup.cfg +0 -0
  57. {polly_python-1.6.0 → polly_python-1.7.0}/setup.py +0 -0
  58. {polly_python-1.6.0 → polly_python-1.7.0}/tests/test_cohort.py +0 -0
  59. {polly_python-1.6.0 → polly_python-1.7.0}/tests/test_constants.py +0 -0
  60. {polly_python-1.6.0 → polly_python-1.7.0}/tests/test_curation.py +0 -0
  61. {polly_python-1.6.0 → polly_python-1.7.0}/tests/test_data_management.py +0 -0
  62. {polly_python-1.6.0 → polly_python-1.7.0}/tests/test_helpers.py +0 -0
  63. {polly_python-1.6.0 → polly_python-1.7.0}/tests/test_jobs.py +0 -0
  64. {polly_python-1.6.0 → polly_python-1.7.0}/tests/test_omixatlas.py +0 -0
  65. {polly_python-1.6.0 → polly_python-1.7.0}/tests/test_pipelines.py +0 -0
  66. {polly_python-1.6.0 → polly_python-1.7.0}/tests/test_s3_utils.py +0 -0
  67. {polly_python-1.6.0 → polly_python-1.7.0}/tests/test_schema_ux.py +0 -0
  68. {polly_python-1.6.0 → polly_python-1.7.0}/tests/test_threading_utils.py +0 -0
  69. {polly_python-1.6.0 → polly_python-1.7.0}/tests/test_workspaces.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: polly_python
3
- Version: 1.6.0
3
+ Version: 1.7.0
4
4
  Summary: Polly SDK
5
5
  Home-page: https://github.com/ElucidataInc/polly-python
6
6
  Project-URL: Documentation, https://docs.elucidata.io
@@ -0,0 +1 @@
1
+ __version__ = "1.7.0"
@@ -1537,6 +1537,24 @@ class OmixAtlas:
1537
1537
  except Exception as err:
1538
1538
  raise err
1539
1539
 
1540
+ @Track.track_decorator
1541
+ def download_linked_reports(self, repo_key: str, dataset_id: str, folder_path: str):
1542
+ """Downloads Linked Reports to the repo
1543
+
1544
+ Args:
1545
+ repo_key (str): repo_name/repo_id of the repository for which to fetch the report
1546
+ dataset_id (str): dataset_id of the dataset which to fetch the reports.
1547
+ folder_path (str): local folder path where the files need to be downloaded
1548
+
1549
+ Returns:
1550
+ Downloads the datasets in the passed folder path
1551
+ """
1552
+ try:
1553
+ report_obj = Reporting()
1554
+ report_obj.download_linked_reports(self, repo_key, dataset_id, folder_path)
1555
+ except Exception as err:
1556
+ raise err
1557
+
1540
1558
  @Track.track_decorator
1541
1559
  def delete_linked_report(
1542
1560
  self, repo_key: str, dataset_id: str, report_id: str
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: polly_python
3
- Version: 1.6.0
3
+ Version: 1.7.0
4
4
  Summary: Polly SDK
5
5
  Home-page: https://github.com/ElucidataInc/polly-python
6
6
  Project-URL: Documentation, https://docs.elucidata.io
@@ -1,12 +1,19 @@
1
+ import os
1
2
  from polly_interfaces.IReporting import IReporting
2
3
  from polly.errors import error_handler, InvalidParameterException
3
4
  import json
5
+ import urllib.parse
4
6
  import pandas as pd
5
7
  from polly import helpers
6
8
  from datetime import datetime
7
9
  from urllib.parse import urlparse
8
10
  from polly_services import polly_services_hlpr
9
11
  from polly_services.reporting import reporting_hlpr
12
+ from polly.errors import (
13
+ InvalidParameterException,
14
+ error_handler,
15
+ InvalidDirectoryPath,
16
+ )
10
17
 
11
18
 
12
19
  class Reporting(IReporting):
@@ -268,6 +275,100 @@ class Reporting(IReporting):
268
275
  pd.set_option("display.max_colwidth", None)
269
276
  return df
270
277
 
278
+ def download_linked_reports(
279
+ self, polly_session, repo_key: str, dataset_id: str, local_folder_path: str
280
+ ):
281
+ """Download linked reports to the local path
282
+
283
+ Args:
284
+ polly_session : polly_session variable
285
+ repo_key (str): repo_key for the omixatlas
286
+ dataset_id (str): dataset_id for the repo
287
+ local_folder_path (str): _description_
288
+ """
289
+ # sanity check of variables
290
+ if not (repo_key and isinstance(repo_key, str)):
291
+ raise InvalidParameterException("repo_key")
292
+ if not (dataset_id and isinstance(dataset_id, str)):
293
+ raise InvalidParameterException("dataset_id")
294
+
295
+ isExists = os.path.isdir(local_folder_path)
296
+ if not isExists:
297
+ raise InvalidDirectoryPath(local_folder_path)
298
+
299
+ # get the resultant dataframe from fetch_linked_reports function
300
+ df = self.fetch_linked_reports(polly_session, repo_key, dataset_id)
301
+
302
+ if df is None:
303
+ print("No reports to download")
304
+ return
305
+
306
+ urls_list = []
307
+ # iterate on the DF and get the report_ids
308
+ for index, row in df.iterrows():
309
+ # print(row)
310
+ urls_list.append(row["URL"])
311
+
312
+ files_signed_urls_list = []
313
+
314
+ file_id_list = []
315
+
316
+ for url in urls_list:
317
+ parsed_url = urllib.parse.urlparse(url)
318
+
319
+ # Extract the query string parameters
320
+ query_params = urllib.parse.parse_qs(parsed_url.query)
321
+
322
+ # Get the value of the 'id' parameter
323
+ # id will be list here
324
+ file_id = query_params.get("id")
325
+
326
+ # Print the extracted ID
327
+ if file_id:
328
+ # Assuming 'id' exists and has only one value
329
+ file_id_list.append(file_id[0])
330
+ else:
331
+ print(f"ID not found in the file URL: {url}")
332
+
333
+ # call the API on the report_id to get list of all signed urls
334
+ for file_id in file_id_list:
335
+ params = {"action": "file_download"}
336
+ url = f"{polly_session.base_url}/shared-files/{file_id}"
337
+
338
+ response = polly_session.session.get(url, params=params)
339
+ error_handler(response)
340
+ response_json = response.json()
341
+
342
+ # structure of response
343
+ """
344
+ {
345
+ "data":{
346
+ "type":"file",
347
+ "id":"15374/renamed - another.xlsx",
348
+ "attributes":{
349
+ "s3_key":"15374/renamed - another.xlsx",
350
+ "last_modified":"2024-04-11 04:28:35.000000",
351
+ "size":"8.94 KB",
352
+ "file_name":""
353
+ },
354
+ "links":{
355
+ "self":"/projects/15374/files/renamed%20-%20another.xlsx",
356
+ "signed_url": "<signed_url>"
357
+ }
358
+ }
359
+ }
360
+ """
361
+ signed_url_val = response_json.get("data").get("links").get("signed_url")
362
+ files_signed_urls_list.append(signed_url_val)
363
+
364
+ try:
365
+ # iterate over signed urls and download it in the provided local file path
366
+ reporting_hlpr.download_from_s3_signedUrls(
367
+ files_signed_urls_list, local_folder_path
368
+ )
369
+ except Exception as err:
370
+ raise err
371
+
271
372
  def delete_linked_report(
272
373
  self, polly_session, repo_key: str, dataset_id: str, report_id: str
273
374
  ):
@@ -1,10 +1,13 @@
1
1
  import json
2
+ import os
2
3
  import urllib
3
4
  from polly import helpers
4
5
  from cloudpathlib import S3Client
5
6
  from polly.errors import error_handler
6
7
  from urllib.parse import quote
7
8
  from polly.errors import paramException, AccessDeniedError
9
+ from tqdm import tqdm
10
+ import requests
8
11
 
9
12
 
10
13
  def verify_workspace_path(cloud_path: str, credentials: dict) -> tuple:
@@ -232,3 +235,52 @@ def split_workspace_path(absolute_path: str) -> tuple:
232
235
  for item in range(2, len(contents)):
233
236
  workspace_path = helpers.make_path(workspace_path, contents[item])
234
237
  return workspace_id, workspace_path
238
+
239
+
240
+ def download_from_s3_signedUrls(urls: str, local_folder: str):
241
+ """
242
+ Downloads files from a list of AWS signed URLs to a local folder.
243
+
244
+ Args:
245
+ urls: A list of strings containing the AWS signed URLs.
246
+ local_folder: The path to the local folder where files will be downloaded.
247
+ """
248
+ # Create directory if it doesn't exist
249
+ os.makedirs(local_folder, exist_ok=True)
250
+
251
+ for url in urls:
252
+ parsed_url = urllib.parse.urlparse(url)
253
+ path = parsed_url.path
254
+ filename = os.path.basename(path)
255
+ # print(filename)
256
+ print(f"Starting report download {filename}")
257
+ local_path = os.path.join(local_folder, filename)
258
+
259
+ try:
260
+ response = requests.get(url, stream=True)
261
+ error_handler(response)
262
+
263
+ # tqdm implement
264
+ with open(local_path, "wb") as f:
265
+ chunk_size = 4096
266
+ total_size = int(response.headers.get('Content-Length', 0))
267
+
268
+ # Create a progress bar with total size (if available)
269
+ pbar = tqdm(
270
+ total=total_size,
271
+ unit='B',
272
+ unit_scale=True,
273
+ unit_divisor=4096
274
+ )
275
+
276
+ for chunk in response.iter_content(chunk_size=chunk_size):
277
+ if chunk: # Filter out keep-alive new chunks
278
+ f.write(chunk)
279
+ pbar.update(len(chunk)) # Update progress bar with downloaded chunk size
280
+
281
+ pbar.close() # Close the progress bar after download
282
+ print()
283
+
284
+
285
+ except requests.exceptions.RequestException as e:
286
+ print(f"Error downloading {filename} from s3: {e}")
@@ -1 +0,0 @@
1
- __version__ = "1.6.0"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes