diff --git a/gridappsd-field-bus-lib/gridappsd_field_bus/forwarder.py b/gridappsd-field-bus-lib/gridappsd_field_bus/forwarder.py index c744c9e..79b0c75 100644 --- a/gridappsd-field-bus-lib/gridappsd_field_bus/forwarder.py +++ b/gridappsd-field-bus-lib/gridappsd_field_bus/forwarder.py @@ -1,20 +1,47 @@ import time +from dotenv import load_dotenv import click import yaml import os +import urllib from gridappsd_field_bus import MessageBusDefinition from gridappsd_field_bus.field_interface.field_proxy_forwarder import FieldProxyForwarder @click.command() -@click.option('--username', required=True, help='Username for the connection.') -@click.option('--password', required=True, help='Password for the connection.') -@click.option('--connection_url', required=True, help='Connection URL.') +@click.option('--username', + default=lambda: os.getenv("GRIDAPPSD_USER"), + metavar='USERNAME', + type=str, + help='Username for the connection.', + show_default="from environment variable GRIDAPPSD_USER") +@click.option('--password', + metavar='PASSWORD', + type=str, + default=lambda: os.getenv("GRIDAPPSD_PASSWORD"), + help='Password for the connection.', + show_default="from environment variable GRIDAPPSD_PASSWORD") +@click.option('--connection_url', + default=lambda: os.getenv("GRIDAPPSD_ADDRESS"), + type=str, + metavar='URL', + show_default="from environment variable GRIDAPPSD_ADDRESS", + help='Connection URL.') def start_forwarder(username, password, connection_url): """Start the field proxy forwarder with either a YAML configuration or cmd-line arguments.""" + required = [username, password, connection_url] + if not all(required): + click.echo("Username, password, and connection URL must be provided either through environment variables or command-line arguments.") + click.Abort() + + parsed = urllib.parse.urlparse(connection_url) + if not (parsed.hostname and parsed.port): + click.echo("Invalid connection URL. It must include both hostname and port.") + click.Abort() + # Use command-line arguments click.echo(f"Using command line arguments: {username}, {password}, {connection_url}") @@ -25,4 +52,5 @@ def start_forwarder(username, password, connection_url): if __name__ == '__main__': + load_dotenv() start_forwarder() \ No newline at end of file diff --git a/gridappsd-field-bus-lib/pyproject.toml b/gridappsd-field-bus-lib/pyproject.toml index b1be42b..5ac3c68 100644 --- a/gridappsd-field-bus-lib/pyproject.toml +++ b/gridappsd-field-bus-lib/pyproject.toml @@ -27,7 +27,6 @@ python = ">=3.10,<4.0" gridappsd-python = ">=2025.3.1a1" cim-graph = ">=0.2.2a4" click = "^8.1.8" -"python-dotenv" = "^1.0.1" [tool.poetry.scripts] # Add things in the form diff --git a/gridappsd-python-lib/example.env b/gridappsd-python-lib/example.env new file mode 100644 index 0000000..d3cd3c7 --- /dev/null +++ b/gridappsd-python-lib/example.env @@ -0,0 +1,4 @@ +GRIDAPPSD_USER= +GRIDAPPSD_PASSWORD= +GRIDAPPSD_ADDRESS = tcp://127.0.0.1:61613 +DATABASE = powergridmodel diff --git a/gridappsd-python-lib/gridappsd/__main__.py b/gridappsd-python-lib/gridappsd/__main__.py index 9a3ed57..fe35629 100644 --- a/gridappsd-python-lib/gridappsd/__main__.py +++ b/gridappsd-python-lib/gridappsd/__main__.py @@ -44,10 +44,12 @@ from argparse import ArgumentParser from time import sleep import yaml +from dotenv import load_dotenv +from pathlib import Path from gridappsd import GridAPPSD -assert sys.version_info >= (3, 6), "Minimum version is python 3.6" +assert sys.version_info >= (3, 10), "Minimum version is python 3.10" logging.basicConfig(stream=sys.stdout, level=logging.INFO, @@ -65,7 +67,9 @@ "--run-simulation", type=argparse.FileType('r'), help="Start running a simulation from a passed simulation file.") - + group.add_argument("--env", required=False, type=str, + default=".env", + help="Load environment variables from a .env file.") opts = parser.parse_args() if opts.run_simulation: @@ -75,6 +79,15 @@ def next_timestep(simulation, timestep): sleep(1) simulation.resume() + if opts.env: + _log.info(f"Loading environment variables from {opts.env}") + env_path = Path(opts.env).expanduser() + if env_path.is_file(): + load_dotenv(opts.env) + else: + _log.error(f"Environment file {opts.env} not found. Skipping loading.") + sys.exit(1) + gappsd = GridAPPSD() run_args = yaml.safe_load(opts.run_simulation) diff --git a/gridappsd-python-lib/pyproject.toml b/gridappsd-python-lib/pyproject.toml index 6caa2e1..7050a0e 100644 --- a/gridappsd-python-lib/pyproject.toml +++ b/gridappsd-python-lib/pyproject.toml @@ -35,6 +35,8 @@ pytz = "^2022.7" dateutils = "^0.6.7" stomp-py = "6.0.0" requests = "2.28.2" +dotenv = "^0.9.9" +loguru = "^0.7.3" [tool.poetry.group.dev.dependencies] pytest = "^8.3.4" diff --git a/pyproject.toml b/pyproject.toml index 0eb9d67..8299e6e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,6 +20,7 @@ readme = "README.md" [tool.poetry.dependencies] python = ">=3.10,<4.0" + [build-system] requires = ["poetry-core>=2.0.0"] build-backend = "poetry.core.masonry.api"