polly-python 1.4.0__tar.gz → 2.0.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.4.0/polly_python.egg-info → polly_python-2.0.0}/PKG-INFO +2 -1
  2. polly_python-2.0.0/polly/__init__.py +1 -0
  3. {polly_python-1.4.0 → polly_python-2.0.0}/polly/helpers.py +54 -7
  4. {polly_python-1.4.0 → polly_python-2.0.0}/polly/pipelines.py +2 -1
  5. {polly_python-1.4.0 → polly_python-2.0.0}/polly/workspaces.py +10 -2
  6. {polly_python-1.4.0 → polly_python-2.0.0/polly_python.egg-info}/PKG-INFO +2 -1
  7. {polly_python-1.4.0 → polly_python-2.0.0}/polly_python.egg-info/requires.txt +1 -0
  8. {polly_python-1.4.0 → polly_python-2.0.0}/setup.cfg +1 -0
  9. {polly_python-1.4.0 → polly_python-2.0.0}/tests/test_workspaces.py +25 -0
  10. polly_python-1.4.0/polly/__init__.py +0 -1
  11. {polly_python-1.4.0 → polly_python-2.0.0}/LICENSE.md +0 -0
  12. {polly_python-1.4.0 → polly_python-2.0.0}/MANIFEST.in +0 -0
  13. {polly_python-1.4.0 → polly_python-2.0.0}/README.md +0 -0
  14. {polly_python-1.4.0 → polly_python-2.0.0}/polly/analyze.py +0 -0
  15. {polly_python-1.4.0 → polly_python-2.0.0}/polly/application_error_info.py +0 -0
  16. {polly_python-1.4.0 → polly_python-2.0.0}/polly/auth.py +0 -0
  17. {polly_python-1.4.0 → polly_python-2.0.0}/polly/bridge_cohort.py +0 -0
  18. {polly_python-1.4.0 → polly_python-2.0.0}/polly/cohort.py +0 -0
  19. {polly_python-1.4.0 → polly_python-2.0.0}/polly/constants.py +0 -0
  20. {polly_python-1.4.0 → polly_python-2.0.0}/polly/core_cohort.py +0 -0
  21. {polly_python-1.4.0 → polly_python-2.0.0}/polly/curation.py +0 -0
  22. {polly_python-1.4.0 → polly_python-2.0.0}/polly/data_management.py +0 -0
  23. {polly_python-1.4.0 → polly_python-2.0.0}/polly/errors.py +0 -0
  24. {polly_python-1.4.0 → polly_python-2.0.0}/polly/help.py +0 -0
  25. {polly_python-1.4.0 → polly_python-2.0.0}/polly/http_response_codes.py +0 -0
  26. {polly_python-1.4.0 → polly_python-2.0.0}/polly/index_schema_level_conversion_const.py +0 -0
  27. {polly_python-1.4.0 → polly_python-2.0.0}/polly/jobs.py +0 -0
  28. {polly_python-1.4.0 → polly_python-2.0.0}/polly/omixatlas.py +0 -0
  29. {polly_python-1.4.0 → polly_python-2.0.0}/polly/omixatlas_hlpr.py +0 -0
  30. {polly_python-1.4.0 → polly_python-2.0.0}/polly/s3_utils.py +0 -0
  31. {polly_python-1.4.0 → polly_python-2.0.0}/polly/session.py +0 -0
  32. {polly_python-1.4.0 → polly_python-2.0.0}/polly/threading_utils.py +0 -0
  33. {polly_python-1.4.0 → polly_python-2.0.0}/polly/tracking.py +0 -0
  34. {polly_python-1.4.0 → polly_python-2.0.0}/polly/validation.py +0 -0
  35. {polly_python-1.4.0 → polly_python-2.0.0}/polly/validation_hlpr.py +0 -0
  36. {polly_python-1.4.0 → polly_python-2.0.0}/polly_interfaces/IFiles.py +0 -0
  37. {polly_python-1.4.0 → polly_python-2.0.0}/polly_interfaces/IReporting.py +0 -0
  38. {polly_python-1.4.0 → polly_python-2.0.0}/polly_interfaces/ISchema.py +0 -0
  39. {polly_python-1.4.0 → polly_python-2.0.0}/polly_interfaces/__init__.py +0 -0
  40. {polly_python-1.4.0 → polly_python-2.0.0}/polly_python.egg-info/SOURCES.txt +0 -0
  41. {polly_python-1.4.0 → polly_python-2.0.0}/polly_python.egg-info/dependency_links.txt +0 -0
  42. {polly_python-1.4.0 → polly_python-2.0.0}/polly_python.egg-info/top_level.txt +0 -0
  43. {polly_python-1.4.0 → polly_python-2.0.0}/polly_services/__init__.py +0 -0
  44. {polly_python-1.4.0 → polly_python-2.0.0}/polly_services/dataset.py +0 -0
  45. {polly_python-1.4.0 → polly_python-2.0.0}/polly_services/files/__init__.py +0 -0
  46. {polly_python-1.4.0 → polly_python-2.0.0}/polly_services/files/files.py +0 -0
  47. {polly_python-1.4.0 → polly_python-2.0.0}/polly_services/files/files_hlpr.py +0 -0
  48. {polly_python-1.4.0 → polly_python-2.0.0}/polly_services/polly_services_hlpr.py +0 -0
  49. {polly_python-1.4.0 → polly_python-2.0.0}/polly_services/reporting/__init__.py +0 -0
  50. {polly_python-1.4.0 → polly_python-2.0.0}/polly_services/reporting/reporting.py +0 -0
  51. {polly_python-1.4.0 → polly_python-2.0.0}/polly_services/reporting/reporting_hlpr.py +0 -0
  52. {polly_python-1.4.0 → polly_python-2.0.0}/polly_services/schema/__init__.py +0 -0
  53. {polly_python-1.4.0 → polly_python-2.0.0}/polly_services/schema/schema.py +0 -0
  54. {polly_python-1.4.0 → polly_python-2.0.0}/polly_services/schema/schema_const.py +0 -0
  55. {polly_python-1.4.0 → polly_python-2.0.0}/polly_services/schema/schema_hlpr.py +0 -0
  56. {polly_python-1.4.0 → polly_python-2.0.0}/polly_services/schema/validate_schema_hlpr.py +0 -0
  57. {polly_python-1.4.0 → polly_python-2.0.0}/pyproject.toml +0 -0
  58. {polly_python-1.4.0 → polly_python-2.0.0}/setup.py +0 -0
  59. {polly_python-1.4.0 → polly_python-2.0.0}/tests/test_cohort.py +0 -0
  60. {polly_python-1.4.0 → polly_python-2.0.0}/tests/test_constants.py +0 -0
  61. {polly_python-1.4.0 → polly_python-2.0.0}/tests/test_curation.py +0 -0
  62. {polly_python-1.4.0 → polly_python-2.0.0}/tests/test_data_management.py +0 -0
  63. {polly_python-1.4.0 → polly_python-2.0.0}/tests/test_helpers.py +0 -0
  64. {polly_python-1.4.0 → polly_python-2.0.0}/tests/test_jobs.py +0 -0
  65. {polly_python-1.4.0 → polly_python-2.0.0}/tests/test_omixatlas.py +0 -0
  66. {polly_python-1.4.0 → polly_python-2.0.0}/tests/test_pipelines.py +0 -0
  67. {polly_python-1.4.0 → polly_python-2.0.0}/tests/test_s3_utils.py +0 -0
  68. {polly_python-1.4.0 → polly_python-2.0.0}/tests/test_schema_ux.py +0 -0
  69. {polly_python-1.4.0 → polly_python-2.0.0}/tests/test_threading_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: polly_python
3
- Version: 1.4.0
3
+ Version: 2.0.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
@@ -17,6 +17,7 @@ Requires-Dist: mixpanel==4.10.0
17
17
  Requires-Dist: Deprecated>=1.2.12
18
18
  Requires-Dist: pytest>=6.2.5
19
19
  Requires-Dist: cryptography<=38.0.0,>=37.0.1
20
+ Requires-Dist: numpy==1.26.4
20
21
  Requires-Dist: plotly<5.0.0,>=4.8.1; python_version > "3.6" and python_version < "3.7"
21
22
  Requires-Dist: plotly>=5.0.0; python_version >= "3.7"
22
23
  Requires-Dist: pandas<1.2.0,>=1.1.0; python_version > "3.6" and python_version < "3.7"
@@ -0,0 +1 @@
1
+ __version__ = "2.0.0"
@@ -29,6 +29,7 @@ import pandas as pd
29
29
  import polly.http_response_codes as http_codes
30
30
  from polly.tracking import Track
31
31
  import polly.constants as const
32
+ import string
32
33
 
33
34
 
34
35
  def get_platform_value_from_env(
@@ -54,7 +55,9 @@ def make_path(prefix: any, postfix: any) -> str:
54
55
  if not prefix:
55
56
  raise InvalidParameterException("prefix")
56
57
  if not postfix:
57
- raise InvalidParameterException("postfix")
58
+ raise InvalidParameterException(
59
+ 'path can\'t be empty. if u want to push to root then make path as "/"'
60
+ )
58
61
  return os.path.normpath(f"{prefix}/{postfix}")
59
62
 
60
63
 
@@ -149,22 +152,60 @@ def display_df_from_list(val_list: list, column_name_in_df: str):
149
152
 
150
153
  def upload_to_S3(cloud_path: str, local_path: str, credentials: dict) -> None:
151
154
  """
152
- Function to upload file/folder to S3 cloud path
155
+ Uploads a file or folder to a specified S3 cloud path.
153
156
  """
154
157
  access_key_id = credentials["AccessKeyId"]
155
158
  secret_access_key = credentials["SecretAccessKey"]
156
159
  session_token = credentials["SessionToken"]
160
+
161
+ # use these extras for all CloudPaths
157
162
  client = S3Client(
158
163
  aws_access_key_id=access_key_id,
159
164
  aws_secret_access_key=secret_access_key,
160
165
  aws_session_token=session_token,
161
166
  extra_args={"ContentType": "text/html"},
162
167
  )
163
- # use these extras for all CloudPaths
168
+
169
+ # Behavior:
170
+ # 1. Validation of cloud_path:
171
+ # - If any part of the cloud_path contains directory names starting with special characters,
172
+ # the function will not consider them as valid unless they already exist in the S3 bucket.
173
+ # - The function will iterate through the cloud_path, checking each segment. If it encounters
174
+ # a segment starting with a special character that does not already exist in the S3 bucket,
175
+ # it will raise an error.
176
+
177
+ # Example:
178
+ # - Given a cloud_path of 'a/b/c/#/d/e':
179
+ # 1. if path not exists already, The function first checks if the path '{s3}/a/b/c/#/d' exists and that 'e'
180
+ # does not start with a special character.
181
+ # 2. If '{s3}/a/b/c/#/d' not exists, it checks '{s3}/a/b/c/#' and ensures 'd' does not start with a special character.
182
+ # 3. This process continues until a exist path is found or the directory start with special character.
183
+ # - If the cloud_path is invalid, the function raises an exception.
184
+ # - Once a valid path is determined, the file or folder is uploaded to this path in the S3 bucket.
164
185
  client.set_as_default_client()
165
186
  source_path = client.CloudPath(cloud_path)
187
+ splt_char = os.path.sep
188
+ punctuation_chars = set(string.punctuation)
166
189
  if not source_path.exists():
190
+ # if path is S3://UserDataBucket/12345/path
191
+ # then path split will be [S3, , UserDataBucket, 12345, path]
192
+ path_split = cloud_path.split("/")
193
+ # s3 path have length = 4, so ignore that and checking path after that
194
+ while len(path_split) > 4:
195
+ cloud_path = splt_char.join(path_split[: len(path_split) - 1])
196
+ if (
197
+ path_split[len(path_split) - 1]
198
+ and path_split[len(path_split) - 1][0] in punctuation_chars
199
+ ):
200
+ raise InvalidParameterException(
201
+ f"path can't start with {path_split[len(path_split)-1][0]}"
202
+ )
203
+ new_source_path = client.CloudPath(cloud_path)
204
+ if new_source_path.exists():
205
+ break
206
+ path_split = cloud_path.split("/")
167
207
  source_path.mkdir()
208
+
168
209
  try:
169
210
  source_path.upload_from(local_path, force_overwrite_to_cloud=True)
170
211
  except ClientError as e:
@@ -172,7 +213,11 @@ def upload_to_S3(cloud_path: str, local_path: str, credentials: dict) -> None:
172
213
 
173
214
 
174
215
  def download_from_S3(
175
- cloud_path: str, workspace_path: str, credentials: dict, destination_path: str
216
+ cloud_path: str,
217
+ workspace_path: str,
218
+ credentials: dict,
219
+ destination_path: str,
220
+ copy_workspace_path: bool,
176
221
  ) -> None:
177
222
  """
178
223
  Function to download file/folder from workspaces
@@ -195,13 +240,15 @@ def download_from_S3(
195
240
  except ClientError as e:
196
241
  raise OperationFailedException(e)
197
242
  else:
198
- if not cloud_path.endswith("/"):
199
- cloud_path += "/"
200
243
  source_path = client.CloudPath(cloud_path)
201
244
  if not source_path.is_dir():
202
245
  raise InvalidPathException
203
246
  try:
204
- destination_path = f"{make_path(destination_path,workspace_path)}"
247
+ # If copy_workspace_path is True, append workspace_path to destination_path to copy the directory structure.
248
+ # ex- make_path('/home/user/project/', 'folder1/folder2') = '/home/user/project/folder1/folder2'
249
+ if copy_workspace_path is True:
250
+ destination_path = f"{make_path(destination_path,workspace_path)}"
251
+
205
252
  source_path.copytree(destination_path, force_overwrite_to_cloud=True)
206
253
  except ClientError as e:
207
254
  raise OperationFailedException(e)
@@ -195,8 +195,9 @@ class Pipelines:
195
195
  """
196
196
  This function is used to create a Pipeline run.\n
197
197
  A run is a collection of jobs, this functions creates an empty run in which the jobs can be added.
198
+
198
199
  Args:
199
- pipeline_id (str): pipeline_id for which the run is to be created.
200
+ pipeline_id (str): pipeline_id for which the run is to be created
200
201
  run_name (str): name of the run
201
202
  priority (str): priority of the run, can be low | medium | high
202
203
  tags (dict): a dict of key-value pair with tag_name -> tag_value mapping
@@ -270,6 +270,7 @@ initialize a object that can use all function and methods of Workspaces class.
270
270
  if not isExists:
271
271
  raise InvalidPathException
272
272
  # check for access rights for the workspace_id
273
+ workspace_path = workspace_path.strip()
273
274
  access_workspace = helpers.workspaces_permission_check(self, workspace_id)
274
275
  if not access_workspace:
275
276
  raise AccessDeniedError(
@@ -284,7 +285,11 @@ initialize a object that can use all function and methods of Workspaces class.
284
285
 
285
286
  @Track.track_decorator
286
287
  def download_from_workspaces(
287
- self, workspace_id: int, workspace_path: str, local_path: str
288
+ self,
289
+ workspace_id: int,
290
+ workspace_path: str,
291
+ local_path: str,
292
+ copy_workspace_path: bool = True,
288
293
  ) -> None:
289
294
  """
290
295
  Function to download files/folders from workspaces.
@@ -292,6 +297,7 @@ initialize a object that can use all function and methods of Workspaces class.
292
297
  Args:
293
298
  workspace_id (int) : Id of the workspace where file needs to uploaded
294
299
  workspace_path (str) : Downloaded file on workspace. The workspace path should be prefixed with "polly://"
300
+ copy_workspace_path (bool) : Flag indicating whether the workspace path needs to copied in the working directory
295
301
  Returns:
296
302
  None
297
303
  Raises:
@@ -315,7 +321,9 @@ initialize a object that can use all function and methods of Workspaces class.
315
321
  if workspace_path.startswith("polly://"):
316
322
  workspace_path = workspace_path.split("polly://")[1]
317
323
  s3_path, credentials = self._s3_util(workspace_id, workspace_path)
318
- helpers.download_from_S3(s3_path, workspace_path, credentials, local_path)
324
+ helpers.download_from_S3(
325
+ s3_path, workspace_path, credentials, local_path, copy_workspace_path
326
+ )
319
327
  logging.basicConfig(level=logging.INFO)
320
328
  logging.info(f"Download successful to path={local_path}")
321
329
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: polly_python
3
- Version: 1.4.0
3
+ Version: 2.0.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
@@ -17,6 +17,7 @@ Requires-Dist: mixpanel==4.10.0
17
17
  Requires-Dist: Deprecated>=1.2.12
18
18
  Requires-Dist: pytest>=6.2.5
19
19
  Requires-Dist: cryptography<=38.0.0,>=37.0.1
20
+ Requires-Dist: numpy==1.26.4
20
21
  Requires-Dist: plotly<5.0.0,>=4.8.1; python_version > "3.6" and python_version < "3.7"
21
22
  Requires-Dist: plotly>=5.0.0; python_version >= "3.7"
22
23
  Requires-Dist: pandas<1.2.0,>=1.1.0; python_version > "3.6" and python_version < "3.7"
@@ -7,6 +7,7 @@ mixpanel==4.10.0
7
7
  Deprecated>=1.2.12
8
8
  pytest>=6.2.5
9
9
  cryptography<=38.0.0,>=37.0.1
10
+ numpy==1.26.4
10
11
  requests==2.25.1
11
12
 
12
13
  [:python_version > "3.6" and python_version < "3.7"]
@@ -24,6 +24,7 @@ install_requires =
24
24
  Deprecated >= 1.2.12
25
25
  pytest >= 6.2.5
26
26
  cryptography >= 37.0.1, <= 38.0.0
27
+ numpy == 1.26.4
27
28
  plotly <5.0.0, >=4.8.1 ; python_version > '3.6' and python_version < '3.7'
28
29
  plotly >= 5.0.0 ; python_version >= '3.7'
29
30
  pandas >= 1.1.0, < 1.2.0 ; python_version > '3.6' and python_version < '3.7'
@@ -194,6 +194,31 @@ def test_download_from_workspaces(mocker, mock_workspaces_permission_check_fixtu
194
194
  valid_workspace_id, invalid_workspace_path, local_path
195
195
  )
196
196
 
197
+ exclude_path_result = obj.download_from_workspaces(
198
+ valid_workspace_id, valid_workspace_path, local_path, copy_workspace_path=False
199
+ )
200
+ assert exclude_path_result is None
201
+ with pytest.raises(
202
+ InvalidParameterException,
203
+ match=r".* Invalid Parameters .*",
204
+ ):
205
+ obj.download_from_workspaces(
206
+ invalid_workspace_id,
207
+ valid_workspace_path,
208
+ local_path,
209
+ copy_workspace_path=False,
210
+ )
211
+ with pytest.raises(
212
+ InvalidParameterException,
213
+ match=r".* Invalid Parameters .*",
214
+ ):
215
+ obj.download_from_workspaces(
216
+ valid_workspace_id,
217
+ invalid_workspace_path,
218
+ local_path,
219
+ copy_workspace_path=False,
220
+ )
221
+
197
222
 
198
223
  def test_sync_data(mocker, mock_workspaces_permission_check_fixture):
199
224
  obj = workspaces.Workspaces(token)
@@ -1 +0,0 @@
1
- __version__ = "1.4.0"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes