|
22 | 22 |
|
23 | 23 | All configuration is explicitly passed to the ConnectorController and other |
24 | 24 | components, eliminating reliance on implicit environment variables. |
| 25 | +
|
| 26 | +Configuration can be provided via environment variables or loaded from a |
| 27 | +dotenv file using the --env-file option. This allows you to easily switch |
| 28 | +between different environment configurations. |
| 29 | +
|
| 30 | +Usage: |
| 31 | + # Use existing environment variables |
| 32 | + python example_api_workflow.py |
| 33 | +
|
| 34 | + # Load configuration from a dotenv file |
| 35 | + python example_api_workflow.py --env-file ../dev-config/.env.dev.consumer |
25 | 36 | """ |
26 | 37 |
|
| 38 | +import argparse |
27 | 39 | import asyncio |
28 | 40 | import json |
29 | 41 | import logging |
| 42 | +import os |
30 | 43 | import pprint |
31 | 44 | from typing import Dict, Optional |
32 | 45 | from urllib.parse import urlparse |
|
45 | 58 |
|
46 | 59 | _logger = logging.getLogger(__name__) |
47 | 60 |
|
| 61 | +# Try to import dotenv, but degrade gracefully if not available |
| 62 | +try: |
| 63 | + from dotenv import load_dotenv |
| 64 | + |
| 65 | + _DOTENV_AVAILABLE = True |
| 66 | +except ImportError: |
| 67 | + _DOTENV_AVAILABLE = False |
| 68 | + _logger.debug("python-dotenv not available; --env-file option will be ignored") |
| 69 | + |
48 | 70 |
|
49 | 71 | @environ.config(prefix="") |
50 | 72 | class WorkflowConfig: |
@@ -87,7 +109,7 @@ class WorkflowConfig: |
87 | 109 | consumer_backend_url: str = environ.var(default="http://host.docker.internal:28000") |
88 | 110 |
|
89 | 111 | # Asset configuration |
90 | | - asset_id: str = environ.var(default="api-workflow-users") |
| 112 | + asset_id: str = environ.var(default="example-asset-managed-via-api") |
91 | 113 | data_source_url: str = environ.var(default="https://jsonplaceholder.typicode.com") |
92 | 114 | data_source_path: str = environ.var(default="/users") |
93 | 115 |
|
@@ -118,7 +140,8 @@ async def start_listening(self, protocol_url: str): |
118 | 140 | return |
119 | 141 |
|
120 | 142 | provider_host = urlparse(protocol_url).hostname |
121 | | - url = f"{self.config.consumer_backend_url}/pull/stream/provider/{provider_host}" |
| 143 | + base_url = self.config.consumer_backend_url.rstrip("/") |
| 144 | + url = f"{base_url}/pull/stream/provider/{provider_host}" |
122 | 145 |
|
123 | 146 | _logger.info("Connecting to SSE stream for provider: %s", provider_host) |
124 | 147 | self._connected_event.clear() |
@@ -450,7 +473,67 @@ async def main(config: WorkflowConfig): |
450 | 473 | return data |
451 | 474 |
|
452 | 475 |
|
| 476 | +def parse_args(): |
| 477 | + """Parse command line arguments.""" |
| 478 | + |
| 479 | + parser = argparse.ArgumentParser( |
| 480 | + description="EDC Management API Workflow Example", |
| 481 | + formatter_class=argparse.RawDescriptionHelpFormatter, |
| 482 | + epilog=""" |
| 483 | +Environment Configuration: |
| 484 | + Configuration can be provided via environment variables or a dotenv file. |
| 485 | + Use --env-file to load environment variables from a specific file. |
| 486 | + |
| 487 | + Example: |
| 488 | + python example_api_workflow.py --env-file ../dev-config/.env.dev.consumer |
| 489 | + """, |
| 490 | + ) |
| 491 | + |
| 492 | + parser.add_argument( |
| 493 | + "--env-file", |
| 494 | + type=str, |
| 495 | + help="Path to a dotenv file to load environment variables from. " |
| 496 | + "Requires python-dotenv to be installed.", |
| 497 | + metavar="PATH", |
| 498 | + ) |
| 499 | + |
| 500 | + return parser.parse_args() |
| 501 | + |
| 502 | + |
| 503 | +def load_env_file(env_file_path: str) -> bool: |
| 504 | + """Load environment variables from a dotenv file. |
| 505 | +
|
| 506 | + Args: |
| 507 | + env_file_path: Path to the dotenv file |
| 508 | +
|
| 509 | + Returns: |
| 510 | + True if the file was loaded successfully, False otherwise |
| 511 | + """ |
| 512 | + |
| 513 | + if not _DOTENV_AVAILABLE: |
| 514 | + _logger.warning( |
| 515 | + "Cannot load env file '%s': python-dotenv is not installed. " |
| 516 | + "Install it with: pip install python-dotenv", |
| 517 | + env_file_path, |
| 518 | + ) |
| 519 | + return False |
| 520 | + |
| 521 | + if not os.path.exists(env_file_path): |
| 522 | + _logger.error("Environment file not found: %s", env_file_path) |
| 523 | + return False |
| 524 | + |
| 525 | + _logger.info("Loading environment variables from: %s", env_file_path) |
| 526 | + load_dotenv(env_file_path, override=True) |
| 527 | + return True |
| 528 | + |
| 529 | + |
453 | 530 | if __name__ == "__main__": |
| 531 | + args = parse_args() |
| 532 | + |
| 533 | + # Load dotenv file if specified |
| 534 | + if args.env_file: |
| 535 | + load_env_file(args.env_file) |
| 536 | + |
454 | 537 | config: WorkflowConfig = WorkflowConfig.from_environ() |
455 | 538 | coloredlogs.install(level=config.log_level) |
456 | 539 | asyncio.run(main(config)) |
0 commit comments