great-expectations-cloud 20250902.0.dev1__tar.gz → 20250903.0.dev0__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 (33) hide show
  1. {great_expectations_cloud-20250902.0.dev1 → great_expectations_cloud-20250903.0.dev0}/PKG-INFO +1 -1
  2. {great_expectations_cloud-20250902.0.dev1 → great_expectations_cloud-20250903.0.dev0}/great_expectations_cloud/agent/agent.py +50 -24
  3. {great_expectations_cloud-20250902.0.dev1 → great_expectations_cloud-20250903.0.dev0}/great_expectations_cloud/agent/models.py +1 -0
  4. {great_expectations_cloud-20250902.0.dev1 → great_expectations_cloud-20250903.0.dev0}/pyproject.toml +1 -1
  5. {great_expectations_cloud-20250902.0.dev1 → great_expectations_cloud-20250903.0.dev0}/LICENSE +0 -0
  6. {great_expectations_cloud-20250902.0.dev1 → great_expectations_cloud-20250903.0.dev0}/README.md +0 -0
  7. {great_expectations_cloud-20250902.0.dev1 → great_expectations_cloud-20250903.0.dev0}/great_expectations_cloud/__init__.py +0 -0
  8. {great_expectations_cloud-20250902.0.dev1 → great_expectations_cloud-20250903.0.dev0}/great_expectations_cloud/agent/__init__.py +0 -0
  9. {great_expectations_cloud-20250902.0.dev1 → great_expectations_cloud-20250903.0.dev0}/great_expectations_cloud/agent/actions/__init__.py +0 -0
  10. {great_expectations_cloud-20250902.0.dev1 → great_expectations_cloud-20250903.0.dev0}/great_expectations_cloud/agent/actions/agent_action.py +0 -0
  11. {great_expectations_cloud-20250902.0.dev1 → great_expectations_cloud-20250903.0.dev0}/great_expectations_cloud/agent/actions/draft_datasource_config_action.py +0 -0
  12. {great_expectations_cloud-20250902.0.dev1 → great_expectations_cloud-20250903.0.dev0}/great_expectations_cloud/agent/actions/generate_data_quality_check_expectations_action.py +0 -0
  13. {great_expectations_cloud-20250902.0.dev1 → great_expectations_cloud-20250903.0.dev0}/great_expectations_cloud/agent/actions/list_asset_names.py +0 -0
  14. {great_expectations_cloud-20250902.0.dev1 → great_expectations_cloud-20250903.0.dev0}/great_expectations_cloud/agent/actions/run_checkpoint.py +0 -0
  15. {great_expectations_cloud-20250902.0.dev1 → great_expectations_cloud-20250903.0.dev0}/great_expectations_cloud/agent/actions/run_metric_list_action.py +0 -0
  16. {great_expectations_cloud-20250902.0.dev1 → great_expectations_cloud-20250903.0.dev0}/great_expectations_cloud/agent/actions/run_scheduled_checkpoint.py +0 -0
  17. {great_expectations_cloud-20250902.0.dev1 → great_expectations_cloud-20250903.0.dev0}/great_expectations_cloud/agent/actions/run_window_checkpoint.py +0 -0
  18. {great_expectations_cloud-20250902.0.dev1 → great_expectations_cloud-20250903.0.dev0}/great_expectations_cloud/agent/actions/unknown.py +0 -0
  19. {great_expectations_cloud-20250902.0.dev1 → great_expectations_cloud-20250903.0.dev0}/great_expectations_cloud/agent/actions/utils.py +0 -0
  20. {great_expectations_cloud-20250902.0.dev1 → great_expectations_cloud-20250903.0.dev0}/great_expectations_cloud/agent/agent_warnings.py +0 -0
  21. {great_expectations_cloud-20250902.0.dev1 → great_expectations_cloud-20250903.0.dev0}/great_expectations_cloud/agent/cli.py +0 -0
  22. {great_expectations_cloud-20250902.0.dev1 → great_expectations_cloud-20250903.0.dev0}/great_expectations_cloud/agent/config.py +0 -0
  23. {great_expectations_cloud-20250902.0.dev1 → great_expectations_cloud-20250903.0.dev0}/great_expectations_cloud/agent/constants.py +0 -0
  24. {great_expectations_cloud-20250902.0.dev1 → great_expectations_cloud-20250903.0.dev0}/great_expectations_cloud/agent/event_handler.py +0 -0
  25. {great_expectations_cloud-20250902.0.dev1 → great_expectations_cloud-20250903.0.dev0}/great_expectations_cloud/agent/exceptions.py +0 -0
  26. {great_expectations_cloud-20250902.0.dev1 → great_expectations_cloud-20250903.0.dev0}/great_expectations_cloud/agent/message_service/__init__.py +0 -0
  27. {great_expectations_cloud-20250902.0.dev1 → great_expectations_cloud-20250903.0.dev0}/great_expectations_cloud/agent/message_service/asyncio_rabbit_mq_client.py +0 -0
  28. {great_expectations_cloud-20250902.0.dev1 → great_expectations_cloud-20250903.0.dev0}/great_expectations_cloud/agent/message_service/subscriber.py +0 -0
  29. {great_expectations_cloud-20250902.0.dev1 → great_expectations_cloud-20250903.0.dev0}/great_expectations_cloud/agent/run.py +0 -0
  30. {great_expectations_cloud-20250902.0.dev1 → great_expectations_cloud-20250903.0.dev0}/great_expectations_cloud/agent/utils.py +0 -0
  31. {great_expectations_cloud-20250902.0.dev1 → great_expectations_cloud-20250903.0.dev0}/great_expectations_cloud/logging/README.md +0 -0
  32. {great_expectations_cloud-20250902.0.dev1 → great_expectations_cloud-20250903.0.dev0}/great_expectations_cloud/logging/logging_cfg.py +0 -0
  33. {great_expectations_cloud-20250902.0.dev1 → great_expectations_cloud-20250903.0.dev0}/great_expectations_cloud/py.typed +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: great_expectations_cloud
3
- Version: 20250902.0.dev1
3
+ Version: 20250903.0.dev0
4
4
  Summary: Great Expectations Cloud
5
5
  License: Proprietary
6
6
  Author: The Great Expectations Team
@@ -16,6 +16,8 @@ from uuid import UUID
16
16
 
17
17
  import orjson
18
18
  import requests
19
+ from great_expectations import __version__
20
+ from great_expectations.core import http
19
21
  from great_expectations.core.http import create_session
20
22
  from great_expectations.data_context.cloud_constants import CLOUD_DEFAULT_BASE_URL
21
23
  from great_expectations.data_context.data_context.context_factory import get_context
@@ -150,19 +152,7 @@ class GXAgent:
150
152
  "great_expectations_version": great_expectations_version,
151
153
  },
152
154
  )
153
- LOGGER.debug("Loading a DataContext - this might take a moment.")
154
-
155
- with warnings.catch_warnings():
156
- # suppress warnings about GX version
157
- warnings.filterwarnings("ignore", message="You are using great_expectations version")
158
- self._context: CloudDataContext = get_context(
159
- cloud_mode=True,
160
- user_agent_str=self.user_agent_str,
161
- )
162
- self._configure_progress_bars(data_context=self._context)
163
- LOGGER.debug("DataContext is ready.")
164
-
165
- self._set_http_session_headers(data_context=self._context)
155
+ # DataContext is created per job in get_data_context
166
156
 
167
157
  # Create a thread pool with a single worker, so we can run long-lived
168
158
  # GX processes and maintain our connection to the broker. Note that
@@ -263,6 +253,7 @@ class GXAgent:
263
253
  "event_type": event_context.event.type,
264
254
  "correlation_id": event_context.correlation_id,
265
255
  "organization_id": self.get_organization_id(event_context),
256
+ "workspace_id": str(self.get_workspace_id(event_context)),
266
257
  "schedule_id": event_context.event.schedule_id
267
258
  if isinstance(event_context.event, ScheduledEventBase)
268
259
  else None,
@@ -287,8 +278,19 @@ class GXAgent:
287
278
  self._current_task.add_done_callback(on_exit_callback)
288
279
 
289
280
  def get_data_context(self, event_context: EventContext) -> CloudDataContext:
290
- """Helper method to get a DataContext Agent. Overridden in GX-Runner."""
291
- return self._context
281
+ """Create a new CloudDataContext for each job using the event's workspace_id."""
282
+ with warnings.catch_warnings():
283
+ warnings.filterwarnings("ignore", message="You are using great_expectations version")
284
+ # Validate presence of workspace_id (required), even if not passed directly to get_context
285
+ if getattr(event_context.event, "workspace_id", None) is None:
286
+ raise GXAgentError()
287
+
288
+ context: CloudDataContext = get_context(
289
+ cloud_mode=True,
290
+ user_agent_str=self.user_agent_str,
291
+ )
292
+ self._configure_progress_bars(data_context=context)
293
+ return context
292
294
 
293
295
  def get_organization_id(self, event_context: EventContext) -> UUID:
294
296
  """Helper method to get the organization ID. Overridden in GX-Runner."""
@@ -298,6 +300,13 @@ class GXAgent:
298
300
  """Helper method to get the auth key. Overridden in GX-Runner."""
299
301
  return self._get_config().gx_cloud_access_token
300
302
 
303
+ def get_workspace_id(self, event_context: EventContext) -> UUID:
304
+ """Helper method to get the workspace ID from the event."""
305
+ workspace_id: UUID | None = getattr(event_context.event, "workspace_id", None)
306
+ if workspace_id is None:
307
+ raise GXAgentError()
308
+ return workspace_id
309
+
301
310
  def _set_sentry_tags(self, even_context: EventContext) -> None:
302
311
  """Used by GX-Runner to set tags for Sentry logging. No-op in the Agent."""
303
312
  pass
@@ -320,14 +329,18 @@ class GXAgent:
320
329
  )
321
330
 
322
331
  org_id = self.get_organization_id(event_context)
332
+ workspace_id = self.get_workspace_id(event_context)
323
333
  base_url = self._get_config().gx_cloud_base_url
324
334
  auth_key = self.get_auth_key()
325
335
 
326
336
  if isinstance(event_context.event, ScheduledEventBase):
327
- self._create_scheduled_job_and_set_started(event_context, org_id)
337
+ self._create_scheduled_job_and_set_started(event_context, org_id, workspace_id)
328
338
  else:
329
339
  self._update_status(
330
- correlation_id=event_context.correlation_id, status=JobStarted(), org_id=org_id
340
+ correlation_id=event_context.correlation_id,
341
+ status=JobStarted(),
342
+ org_id=org_id,
343
+ workspace_id=workspace_id,
331
344
  )
332
345
  LOGGER.info(
333
346
  "Starting job",
@@ -335,6 +348,7 @@ class GXAgent:
335
348
  "event_type": event_context.event.type,
336
349
  "correlation_id": event_context.correlation_id,
337
350
  "organization_id": str(org_id),
351
+ "workspace_id": str(workspace_id),
338
352
  "schedule_id": event_context.event.schedule_id
339
353
  if isinstance(event_context.event, ScheduledEventBase)
340
354
  else None,
@@ -366,6 +380,7 @@ class GXAgent:
366
380
  # warning: this method will not be executed in the main thread
367
381
 
368
382
  org_id = self.get_organization_id(event_context)
383
+ workspace_id = self.get_workspace_id(event_context)
369
384
 
370
385
  # get results or errors from the thread
371
386
  error = future.exception()
@@ -385,6 +400,7 @@ class GXAgent:
385
400
  "event_type": event_context.event.type,
386
401
  "id": event_context.correlation_id,
387
402
  "organization_id": str(org_id),
403
+ "workspace_id": str(workspace_id),
388
404
  "schedule_id": event_context.event.schedule_id
389
405
  if isinstance(event_context.event, ScheduledEventBase)
390
406
  else None,
@@ -405,6 +421,7 @@ class GXAgent:
405
421
  result.job_duration.total_seconds() if result.job_duration else None
406
422
  ),
407
423
  "organization_id": str(org_id),
424
+ "workspace_id": str(workspace_id),
408
425
  "schedule_id": event_context.event.schedule_id
409
426
  if isinstance(event_context.event, ScheduledEventBase)
410
427
  else None,
@@ -419,12 +436,16 @@ class GXAgent:
419
436
  "event_type": event_context.event.type,
420
437
  "correlation_id": event_context.correlation_id,
421
438
  "organization_id": str(org_id),
439
+ "workspace_id": str(workspace_id),
422
440
  },
423
441
  )
424
442
 
425
443
  try:
426
444
  self._update_status(
427
- correlation_id=event_context.correlation_id, status=status, org_id=org_id
445
+ correlation_id=event_context.correlation_id,
446
+ status=status,
447
+ org_id=org_id,
448
+ workspace_id=workspace_id,
428
449
  )
429
450
  except Exception:
430
451
  LOGGER.exception(
@@ -433,6 +454,7 @@ class GXAgent:
433
454
  "correlation_id": event_context.correlation_id,
434
455
  "status": str(status),
435
456
  "organization_id": str(org_id),
457
+ "workspace_id": str(workspace_id),
436
458
  },
437
459
  )
438
460
  # We do not want to cause an infinite loop of errors
@@ -552,7 +574,9 @@ class GXAgent:
552
574
  )
553
575
  )
554
576
 
555
- def _update_status(self, correlation_id: str, status: JobStatus, org_id: UUID) -> None:
577
+ def _update_status(
578
+ self, correlation_id: str, status: JobStatus, org_id: UUID, workspace_id: UUID
579
+ ) -> None:
556
580
  """Update GX Cloud on the status of a job.
557
581
 
558
582
  Args:
@@ -565,11 +589,12 @@ class GXAgent:
565
589
  "correlation_id": correlation_id,
566
590
  "status": str(status),
567
591
  "organization_id": str(org_id),
592
+ "workspace_id": str(workspace_id),
568
593
  },
569
594
  )
570
595
  agent_sessions_url = urljoin(
571
596
  self._get_config().gx_cloud_base_url,
572
- f"/api/v1/organizations/{org_id}/agent-jobs/{correlation_id}",
597
+ f"/api/v1/organizations/{org_id}/workspaces/{workspace_id}/agent-jobs/{correlation_id}",
573
598
  )
574
599
  with create_session(access_token=self.get_auth_key()) as session:
575
600
  data = UpdateJobStatusRequest(data=status).json()
@@ -580,6 +605,7 @@ class GXAgent:
580
605
  "correlation_id": correlation_id,
581
606
  "status": str(status),
582
607
  "organization_id": str(org_id),
608
+ "workspace_id": str(workspace_id),
583
609
  },
584
610
  )
585
611
  GXAgent._log_http_error(
@@ -587,7 +613,7 @@ class GXAgent:
587
613
  )
588
614
 
589
615
  def _create_scheduled_job_and_set_started(
590
- self, event_context: EventContext, org_id: UUID
616
+ self, event_context: EventContext, org_id: UUID, workspace_id: UUID
591
617
  ) -> None:
592
618
  """Create a job in GX Cloud for scheduled events.
593
619
 
@@ -609,13 +635,14 @@ class GXAgent:
609
635
  "correlation_id": str(event_context.correlation_id),
610
636
  "event_type": str(event_context.event.type),
611
637
  "organization_id": str(org_id),
638
+ "workspace_id": str(workspace_id),
612
639
  "schedule_id": str(event_context.event.schedule_id),
613
640
  },
614
641
  )
615
642
 
616
643
  agent_sessions_url = urljoin(
617
644
  self._get_config().gx_cloud_base_url,
618
- f"/api/v1/organizations/{org_id}/agent-jobs",
645
+ f"/api/v1/organizations/{org_id}/workspaces/{workspace_id}/agent-jobs",
619
646
  )
620
647
  data = CreateScheduledJobAndSetJobStarted(
621
648
  type="run_scheduled_checkpoint.received",
@@ -636,6 +663,7 @@ class GXAgent:
636
663
  "event_type": str(event_context.event.type),
637
664
  "organization_id": str(org_id),
638
665
  "schedule_id": str(event_context.event.schedule_id),
666
+ "workspace_id": str(workspace_id),
639
667
  },
640
668
  )
641
669
  GXAgent._log_http_error(
@@ -686,8 +714,6 @@ class GXAgent:
686
714
  Note: the Agent-Job-Id header value will be set for all GX Cloud request until this method is
687
715
  called again.
688
716
  """
689
- from great_expectations import __version__ # noqa: PLC0415
690
- from great_expectations.core import http # noqa: PLC0415
691
717
 
692
718
  header_name = self.get_header_name()
693
719
  user_agent_header_value = self.user_agent_str
@@ -39,6 +39,7 @@ class AgentBaseExtraIgnore(BaseModel):
39
39
  class EventBase(AgentBaseExtraIgnore):
40
40
  type: str
41
41
  organization_id: Optional[UUID] = None # noqa: UP045
42
+ workspace_id: UUID
42
43
 
43
44
 
44
45
  class ScheduledEventBase(EventBase):
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "great_expectations_cloud"
3
- version = "20250902.0.dev1"
3
+ version = "20250903.0.dev0"
4
4
 
5
5
  description = "Great Expectations Cloud"
6
6
  authors = ["The Great Expectations Team <team@greatexpectations.io>"]