From ab5a6bc95334049aa70977f58cea67f59fcbb74e Mon Sep 17 00:00:00 2001 From: Mitchel Cabuloy Date: Wed, 9 Jul 2025 09:08:32 +0800 Subject: [PATCH] Handle blank database URLs --- dslr/cli.py | 6 +++++- dslr/config.py | 6 ++++++ tests/test_cli.py | 47 ++++++++++++++++++++++++----------------------- 3 files changed, 35 insertions(+), 24 deletions(-) diff --git a/dslr/cli.py b/dslr/cli.py index 89a060d..0a759c1 100644 --- a/dslr/cli.py +++ b/dslr/cli.py @@ -70,7 +70,11 @@ def cli(url, debug): } # Update the settings singleton - settings.initialize(**config) + try: + settings.initialize(**config) + except ValueError as e: + eprint(e, style="red") + sys.exit(1) @cli.command() diff --git a/dslr/config.py b/dslr/config.py index 87e4478..281be89 100644 --- a/dslr/config.py +++ b/dslr/config.py @@ -23,6 +23,12 @@ def initialize(self, *, url: str, debug: bool): self.url = url self.debug = debug + if not self.url: + raise ValueError( + "No database URL specified. Please pass it via the --url option, " + 'the DATABASE_URL environment variable, or a "dslr.toml" file.' + ) + parsed = urlparse(url) self.db = DatabaseConnection( diff --git a/tests/test_cli.py b/tests/test_cli.py index 8e88ca2..0a664f9 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -257,13 +257,16 @@ def test_db_option(self, mock_cli_settings, mock_get_snapshots): url="postgres://cli:pw@test:5432/my_db", ) - @mock.patch("dslr.cli.settings") - def test_settings_preference_order(self, mock_cli_settings, mock_get_snapshots): - # No options passed (e.g. PG environment variables are used) + @mock.patch.dict(os.environ, {}, clear=True) + def test_no_url(self, mock_get_snapshots): runner = CliRunner() result = runner.invoke(cli.cli, ["list"]) - self.assertEqual(result.exit_code, 0) + self.assertEqual(result.exit_code, 1) + self.assertIn("No database URL specified", result.output) + + @mock.patch("dslr.cli.settings") + def test_settings_preference_order(self, mock_cli_settings, mock_get_snapshots): # DATABASE_URL environment variable is used with mock.patch.dict( os.environ, {"DATABASE_URL": "postgres://envvar:pw@test:5432/my_db"} @@ -272,31 +275,29 @@ def test_settings_preference_order(self, mock_cli_settings, mock_get_snapshots): result = runner.invoke(cli.cli, ["list"]) self.assertEqual(result.exit_code, 0) - # TOML file is used - with mock.patch( - "builtins.open", - mock.mock_open(read_data=b"url = 'postgres://toml:pw@test:5432/my_db'"), - ): - runner = CliRunner() - result = runner.invoke(cli.cli, ["list"]) - self.assertEqual(result.exit_code, 0) - - # --url option is used - runner = CliRunner() - result = runner.invoke( - cli.cli, - ["--url", "postgres://cli:pw@test:5432/my_db", "list"], - ) - self.assertEqual(result.exit_code, 0) + # TOML file is used + with mock.patch( + "builtins.open", + mock.mock_open(read_data=b"url = 'postgres://toml:pw@test:5432/my_db'"), + ): + runner = CliRunner() + result = runner.invoke(cli.cli, ["list"]) + self.assertEqual(result.exit_code, 0) + + # --url option is used + runner = CliRunner() + result = runner.invoke( + cli.cli, + ["--url", "postgres://cli:pw@test:5432/my_db", "list"], + ) + self.assertEqual(result.exit_code, 0) # Check that the correct order of settings is used - self.assertEqual(4, mock_cli_settings.initialize.call_count) + self.assertEqual(3, mock_cli_settings.initialize.call_count) self.assertEqual( mock_cli_settings.initialize.call_args_list, [ - # Nothing is passed - mock.call(debug=False, url=""), # DATABASE_URL is present so use that mock.call(debug=False, url="postgres://envvar:pw@test:5432/my_db"), # TOML is present, so use that over DATABASE_URL