gooddata-pipelines 1.48.1.dev1__py3-none-any.whl → 1.48.1.dev3__py3-none-any.whl

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.

Potentially problematic release.


This version of gooddata-pipelines might be problematic. Click here for more details.

@@ -158,25 +158,33 @@ class BackupInputProcessor:
158
158
  return all_workspaces
159
159
 
160
160
  def get_ids_to_backup(
161
- self, input_type: InputType, path_to_csv: str | None = None
161
+ self,
162
+ input_type: InputType,
163
+ path_to_csv: str | None = None,
164
+ workspace_ids: list[str] | None = None,
162
165
  ) -> list[str]:
163
166
  """Returns the list of workspace IDs to back up based on the input type."""
164
167
 
165
168
  if input_type in (InputType.LIST_OF_WORKSPACES, InputType.HIERARCHY):
166
- if path_to_csv is None:
169
+ if (path_to_csv is None) == (workspace_ids is None):
167
170
  raise ValueError(
168
- f"Path to CSV is required for this input type: {input_type.value}"
171
+ f"Path to CSV and list of workspace IDs must be specified exclusively for this input type: {input_type.value}"
169
172
  )
170
173
 
171
174
  # If we're backing up based on the list, simply read it from the CSV
175
+ list_of_parents = []
176
+ if path_to_csv is not None:
177
+ list_of_parents = self.csv_reader.read_backup_csv(path_to_csv)
178
+ if workspace_ids is not None:
179
+ list_of_parents = workspace_ids
180
+
172
181
  if input_type == InputType.LIST_OF_WORKSPACES:
173
- return self.csv_reader.read_backup_csv(path_to_csv)
182
+ return list_of_parents
174
183
  else:
175
184
  # For hierarchy backup, we read the CSV and treat it as a list of
176
185
  # parent workspace IDs. Then we retrieve the children of each parent,
177
186
  # including their children, and so on. The parent workspaces are
178
187
  # also included in the backup.
179
- list_of_parents = self.csv_reader.read_backup_csv(path_to_csv)
180
188
  list_of_children: list[str] = []
181
189
 
182
190
  for parent in list_of_parents:
@@ -373,29 +373,37 @@ class BackupManager:
373
373
 
374
374
  raise
375
375
 
376
- def backup_workspaces(self, path_to_csv: str) -> None:
376
+ def backup_workspaces(
377
+ self, path_to_csv: str | None, workspace_ids: list[str] | None
378
+ ) -> None:
377
379
  """Runs the backup process for a list of workspace IDs.
378
380
 
379
- Will read the list of workspace IDs from a CSV file and create backup for
380
- each workspace in storage specified in the configuration.
381
+ Will take the list of workspace IDs or read the list of
382
+ workspace IDs from a CSV file and create backup for each
383
+ workspace in storage specified in the configuration.
381
384
 
382
385
  Args:
383
386
  path_to_csv (str): Path to a CSV file containing a list of workspace IDs.
387
+ workspace_ids (list[str]): List of workspace IDs
384
388
  """
385
- self.backup(InputType.LIST_OF_WORKSPACES, path_to_csv)
389
+ self.backup(InputType.LIST_OF_WORKSPACES, path_to_csv, workspace_ids)
386
390
 
387
- def backup_hierarchies(self, path_to_csv: str) -> None:
391
+ def backup_hierarchies(
392
+ self, path_to_csv: str | None, workspace_ids: list[str] | None
393
+ ) -> None:
388
394
  """Runs the backup process for a list of hierarchies.
389
395
 
390
- Will read the list of workspace IDs from a CSV file and create backup for
391
- each those workspaces' hierarchies in storage specified in the configuration.
396
+ Will take the list of workspace IDs or read the list of workspace IDs
397
+ from a CSV file and create backup for each those workspaces' hierarchies
398
+ in storage specified in the configuration.
392
399
  Workspace hierarchy means the workspace itself and all its direct and
393
400
  indirect children.
394
401
 
395
402
  Args:
396
403
  path_to_csv (str): Path to a CSV file containing a list of workspace IDs.
404
+ workspace_ids (list[str]): List of workspace IDs
397
405
  """
398
- self.backup(InputType.HIERARCHY, path_to_csv)
406
+ self.backup(InputType.HIERARCHY, path_to_csv, workspace_ids)
399
407
 
400
408
  def backup_entire_organization(self) -> None:
401
409
  """Runs the backup process for the entire organization.
@@ -406,12 +414,17 @@ class BackupManager:
406
414
  self.backup(InputType.ORGANIZATION)
407
415
 
408
416
  def backup(
409
- self, input_type: InputType, path_to_csv: str | None = None
417
+ self,
418
+ input_type: InputType,
419
+ path_to_csv: str | None = None,
420
+ workspace_ids: list[str] | None = None,
410
421
  ) -> None:
411
422
  """Runs the backup process with selected input type."""
412
423
  try:
413
424
  workspaces_to_export: list[str] = self.loader.get_ids_to_backup(
414
- input_type, path_to_csv
425
+ input_type,
426
+ path_to_csv,
427
+ workspace_ids,
415
428
  )
416
429
  batches = self.split_to_batches(
417
430
  workspaces_to_export, self.config.batch_size
@@ -1,7 +1,7 @@
1
1
  # (C) 2025 GoodData Corporation
2
2
 
3
3
  from enum import Enum
4
- from typing import Annotated, TypeAlias
4
+ from typing import Annotated, TypeAlias, Optional
5
5
 
6
6
  import yaml
7
7
  from pydantic import BaseModel, Field
@@ -22,6 +22,9 @@ class S3StorageConfig(BaseModel):
22
22
  backup_path: str
23
23
  bucket: str
24
24
  profile: str = "default"
25
+ aws_access_key_id: Optional[str] = None
26
+ aws_secret_access_key: Optional[str] = None
27
+ aws_default_region: Optional[str] = None
25
28
 
26
29
 
27
30
  class LocalStorageConfig(BaseModel):
@@ -21,8 +21,7 @@ class S3Storage(BackupStorage):
21
21
  raise ValueError("S3 storage config is required")
22
22
 
23
23
  self._config = conf.storage
24
- self._profile = self._config.profile
25
- self._session = self._create_boto_session(self._profile)
24
+ self._session = self._create_boto_session(self._config)
26
25
  self._resource = self._session.resource("s3")
27
26
  self._bucket = self._resource.Bucket(self._config.bucket) # type: ignore [missing library stubs]
28
27
  suffix = "/" if not self._config.backup_path.endswith("/") else ""
@@ -30,9 +29,25 @@ class S3Storage(BackupStorage):
30
29
 
31
30
  self._verify_connection()
32
31
 
33
- def _create_boto_session(self, profile: str) -> boto3.Session:
32
+ def _create_boto_session(self, config: S3StorageConfig) -> boto3.Session:
33
+ if config.aws_access_key_id and config.aws_secret_access_key:
34
+ if not config.aws_default_region:
35
+ self.logger.warning(
36
+ "No AWS region specified. Defaulting to us-east-1."
37
+ )
38
+ try:
39
+ return boto3.Session(
40
+ aws_access_key_id=config.aws_access_key_id,
41
+ aws_secret_access_key=config.aws_secret_access_key,
42
+ region_name=config.aws_default_region,
43
+ )
44
+ except Exception:
45
+ self.logger.warning(
46
+ "Failed to create boto3 session with supplied credentials. Falling back to profile..."
47
+ )
48
+
34
49
  try:
35
- return boto3.Session(profile_name=profile)
50
+ return boto3.Session(profile_name=config.profile)
36
51
  except Exception:
37
52
  self.logger.warning(
38
53
  'AWS profile "[default]" not found. Trying other fallback methods...'
@@ -1,13 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gooddata-pipelines
3
- Version: 1.48.1.dev1
3
+ Version: 1.48.1.dev3
4
4
  Author-email: GoodData <support@gooddata.com>
5
5
  License: MIT
6
6
  License-File: LICENSE.txt
7
7
  Requires-Python: >=3.10
8
8
  Requires-Dist: boto3-stubs<2.0.0,>=1.39.3
9
9
  Requires-Dist: boto3<2.0.0,>=1.39.3
10
- Requires-Dist: gooddata-sdk~=1.48.1.dev1
10
+ Requires-Dist: gooddata-sdk~=1.48.1.dev3
11
11
  Requires-Dist: pydantic<3.0.0,>=2.11.3
12
12
  Requires-Dist: requests<3.0.0,>=2.32.3
13
13
  Requires-Dist: types-pyyaml<7.0.0,>=6.0.12.20250326
@@ -22,9 +22,9 @@ Description-Content-Type: text/markdown
22
22
 
23
23
  # GoodData Pipelines
24
24
 
25
- A high level library for automating the lifecycle of GoodData Cloud (GDC).
25
+ A high-level library for automating the lifecycle of GoodData Cloud (GDC).
26
26
 
27
- You can use the package to manage following resoursec in GDC:
27
+ You can use the package to manage following resources in GDC:
28
28
 
29
29
  1. Provisioning (create, update, delete)
30
30
  - User profiles
@@ -36,7 +36,7 @@ You can use the package to manage following resoursec in GDC:
36
36
  1. _[PLANNED]:_ Custom fields management
37
37
  - extend the Logical Data Model of a child workspace
38
38
 
39
- In case you are not interested in incorporating a library in your own program, but would like to use a ready-made script, consider having a look at [GoodData Productivity Tools](https://github.com/gooddata/gooddata-productivity-tools).
39
+ In case you are not interested in incorporating a library in your own program but would like to use a ready-made script, consider having a look at [GoodData Productivity Tools](https://github.com/gooddata/gooddata-productivity-tools).
40
40
 
41
41
  ## Provisioning
42
42
 
@@ -53,23 +53,20 @@ import os
53
53
  from csv import DictReader
54
54
  from pathlib import Path
55
55
 
56
- # Import the Entity Provisioner class and corresponing model from gooddata_pipelines library
56
+ # Import the Entity Provisioner class and corresponding model from gooddata_pipelines library
57
57
  from gooddata_pipelines import UserFullLoad, UserProvisioner
58
+ from gooddata_pipelines.logger.logger import LogObserver
58
59
 
59
- # Optional: you can set up logging and subscribe it to the Provisioner
60
- from utils.logger import setup_logging
61
-
62
- setup_logging()
60
+ # Optionally, subscribe a standard Python logger to the LogObserver
61
+ import logging
63
62
  logger = logging.getLogger(__name__)
63
+ LogObserver().subscribe(logger)
64
64
 
65
65
  # Create the Provisioner instance - you can also create the instance from a GDC yaml profile
66
66
  provisioner = UserProvisioner(
67
67
  host=os.environ["GDC_HOSTNAME"], token=os.environ["GDC_AUTH_TOKEN"]
68
68
  )
69
69
 
70
- # Optional: subscribe to logs
71
- provisioner.logger.subscribe(logger)
72
-
73
70
  # Load your data from your data source
74
71
  source_data_path: Path = Path("path/to/some.csv")
75
72
  source_data_reader = DictReader(source_data_path.read_text().splitlines())
@@ -82,4 +79,4 @@ full_load_data: list[UserFullLoad] = UserFullLoad.from_list_of_dicts(
82
79
  provisioner.full_load(full_load_data)
83
80
  ```
84
81
 
85
- Ready made scripts covering the basic use cases can be found here in the [GoodData Productivity Tools](https://github.com/gooddata/gooddata-productivity-tools) repository
82
+ Ready-made scripts covering the basic use cases can be found here in the [GoodData Productivity Tools](https://github.com/gooddata/gooddata-productivity-tools) repository
@@ -8,18 +8,18 @@ gooddata_pipelines/api/gooddata_api_wrapper.py,sha256=t7dFrXJ6X4yXS9XDthOmvd2Cyz
8
8
  gooddata_pipelines/api/gooddata_sdk.py,sha256=wd5O4e9BQLWUawt6odrs5a51nqFGthBkvqh9WOiW36Q,13734
9
9
  gooddata_pipelines/api/utils.py,sha256=3QY_aYH17I9THoCINE3l-n5oj52k-gNeT1wv6Z_VxN8,1433
10
10
  gooddata_pipelines/backup_and_restore/__init__.py,sha256=-BG28PGDbalLyZGQjpFG0pjdIvtf25ut0r8ZwZVbi4s,32
11
- gooddata_pipelines/backup_and_restore/backup_input_processor.py,sha256=1-Sh0n4DrBrQ7M3Hzq_iiNe-2cxQx0KDu4QdDok618I,7667
12
- gooddata_pipelines/backup_and_restore/backup_manager.py,sha256=NS3dKc6C7VVfuFQxG0opQitcc23GwCntbLirAhWQei0,15441
11
+ gooddata_pipelines/backup_and_restore/backup_input_processor.py,sha256=ex1tGwETdHDDBRJ_DGKZsZbH6uoRuOrbGbKOC976H5s,7940
12
+ gooddata_pipelines/backup_and_restore/backup_manager.py,sha256=MZJIdaWp3KlhUFv0V0lh495X-LHGUsNSEsrxKfvuHgE,15898
13
13
  gooddata_pipelines/backup_and_restore/constants.py,sha256=AO4H6ngsLMs4bCV-RcT7xIi-VZu3smgZWA_3P7lVsQc,907
14
14
  gooddata_pipelines/backup_and_restore/csv_reader.py,sha256=0Kw7mJT7REj3Gjqfsc6YT9MbhcqfCGNB_SKBwzTI1rk,1268
15
15
  gooddata_pipelines/backup_and_restore/models/__init__.py,sha256=-BG28PGDbalLyZGQjpFG0pjdIvtf25ut0r8ZwZVbi4s,32
16
16
  gooddata_pipelines/backup_and_restore/models/input_type.py,sha256=CBKJigKdmZ-NJD9MSfNhq89bo86W0AqCMMoyonbd1QA,239
17
- gooddata_pipelines/backup_and_restore/models/storage.py,sha256=hIIj5CETEroaMTqezzj0ze0eMpPQrzoj5pyp_HBC-xk,1390
17
+ gooddata_pipelines/backup_and_restore/models/storage.py,sha256=DcFH8iWz7LtZZIXoiScZ9ztG6uZHeI9-vLsD07FFnFY,1537
18
18
  gooddata_pipelines/backup_and_restore/models/workspace_response.py,sha256=eQbYLgRQc17IRG0yPTAJVrD-Xs05SzuwtzoNrPT2DoY,833
19
19
  gooddata_pipelines/backup_and_restore/storage/__init__.py,sha256=-BG28PGDbalLyZGQjpFG0pjdIvtf25ut0r8ZwZVbi4s,32
20
20
  gooddata_pipelines/backup_and_restore/storage/base_storage.py,sha256=67wdItlG3neExeb_eCUDQhswdUB62X5Nyj9sOImB_Hg,487
21
21
  gooddata_pipelines/backup_and_restore/storage/local_storage.py,sha256=NvhPRzRAvuSpc5qCDyPqZaMB0i1jeZOZczaSwjUSGEg,1155
22
- gooddata_pipelines/backup_and_restore/storage/s3_storage.py,sha256=STA0J-xaP7QQefyYK3OncqwcvWfrtJRRB--5PBfEKDU,2608
22
+ gooddata_pipelines/backup_and_restore/storage/s3_storage.py,sha256=iRtMtDq_C1b_JBL92P9DP4t-BtIdIlmf7hMDE7a02Ps,3284
23
23
  gooddata_pipelines/logger/__init__.py,sha256=W-fJvMStnsDUY52AYFhx_LnS2cSCFNf3bB47Iew2j04,129
24
24
  gooddata_pipelines/logger/logger.py,sha256=yIMdvqsmOSGQLI4U_tQwxX5E2q_FXUu0Ko7Hv39slFM,3549
25
25
  gooddata_pipelines/provisioning/__init__.py,sha256=RZDEiv8nla4Jwa2TZXUdp1NSxg2_-lLqz4h7k2c4v5Y,854
@@ -48,7 +48,7 @@ gooddata_pipelines/provisioning/utils/__init__.py,sha256=-BG28PGDbalLyZGQjpFG0pj
48
48
  gooddata_pipelines/provisioning/utils/context_objects.py,sha256=sM22hMsxE0XLI1TU0Vs-2kK0vf4YrB1musoAg__4bjc,936
49
49
  gooddata_pipelines/provisioning/utils/exceptions.py,sha256=1WnAOlPhqOf0xRcvn70lxAlLb8Oo6m6WCYS4hj9uzDU,3630
50
50
  gooddata_pipelines/provisioning/utils/utils.py,sha256=_Tk-mFgbIGpCixDCF9e-3ZYd-g5Jb3SJiLSH465k4jY,2846
51
- gooddata_pipelines-1.48.1.dev1.dist-info/METADATA,sha256=jrqTSbfrm5L3YQ7Uqi4_T4llqFJ3QbR5_G_OUSCbU3Q,3773
52
- gooddata_pipelines-1.48.1.dev1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
53
- gooddata_pipelines-1.48.1.dev1.dist-info/licenses/LICENSE.txt,sha256=PNC7WXGIo6OKkNoPLRxlVrw6jaLcjSTUsSxy9Xcu9Jo,560365
54
- gooddata_pipelines-1.48.1.dev1.dist-info/RECORD,,
51
+ gooddata_pipelines-1.48.1.dev3.dist-info/METADATA,sha256=OFkLoPEtFhiA8JmlGqSt3PXEwMTCTiknrgm0ym47flA,3750
52
+ gooddata_pipelines-1.48.1.dev3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
53
+ gooddata_pipelines-1.48.1.dev3.dist-info/licenses/LICENSE.txt,sha256=PNC7WXGIo6OKkNoPLRxlVrw6jaLcjSTUsSxy9Xcu9Jo,560365
54
+ gooddata_pipelines-1.48.1.dev3.dist-info/RECORD,,