Skip to content

Commit 79dca9c

Browse files
authored
Move command line options to configuration file (#534)
2 parents 3a61035 + 16aeae8 commit 79dca9c

File tree

7 files changed

+40
-53
lines changed

7 files changed

+40
-53
lines changed

docker-compose.dev.yaml

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,7 @@ services:
33
stdin_open: true
44
volumes:
55
- ./src:/app:ro
6-
command: >
7-
python main.py
8-
--build-db if-absent
9-
--reload
6+
command: python main.py
107

118
fill-db-with-examples:
129
volumes:

docker-compose.yaml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,7 @@ services:
1414
- ES_PASSWORD=$ES_PASSWORD
1515
ports:
1616
- ${AIOD_REST_PORT}:8000
17-
command: >
18-
python main.py
19-
--build-db if-absent
17+
command: python main.py
2018
healthcheck:
2119
test: ["CMD", "python", "-c", "import requests; requests.get('http://localhost:8000')"]
2220
start_interval: 1s

docs/hosting/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ Then run the startup commands again (either `up.sh` or `docker compose`).
112112
### Creating the Database
113113

114114
By default, the server will create a database on the provided MySQL server if it does not yet exist.
115-
You can change this behavior through the **build-db** command-line parameter,
115+
You can change this behavior through the **build-database** configuration parameter in `src/config.override.toml`,
116116
it takes the following options:
117117

118118
* never: *never* creates the database, not even if there does not exist one yet.

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[project]
22
name = "aiod_metadata_catalogue"
33
description = "A Metadata Catalogue for AI on Demand "
4-
version = "1.4.20250529"
4+
version = "1.4.20250530"
55
requires-python = ">=3.11"
66
authors = [
77
{ name = "Adrián Alcolea" },

src/config.default.toml

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,26 @@ database = "aiod"
99
username = "root"
1010
password = "ok"
1111

12+
# One of: 'never', 'if-absent', or 'drop-then-build'
13+
# Determines if the database is created:
14+
# - never:
15+
# *never* creates the database, not even if there does not exist one yet.
16+
# Use this only if you expect the database to be created through other means, such
17+
# as MySQL group replication.
18+
# - if-absent:
19+
# Creates a database only if none exists.
20+
# - drop-then-build:
21+
# Drops the database on startup to recreate it from scratch.
22+
# THIS REMOVES ALL DATA PERMANENTLY. NO RECOVERY POSSIBLE.
23+
build_database = "if-absent"
24+
1225
# Additional options for development
1326
[dev]
14-
reload = true
27+
reload = false
1528
request_timeout = 10 # seconds
1629
log_level = "INFO" # Python log levels: https://docs.python.org/3/library/logging.html#logging-levels
30+
disable_reviews = false # set to true to automatically publish submissions
31+
url_prefix = ""
1732

1833
# Authentication and authorization
1934
[keycloak]

src/config.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,5 @@ def _merge_configurations(
3232
CONFIG = _merge_configurations(DEFAULT_CONFIG, OVERRIDE_CONFIG)
3333
DB_CONFIG = CONFIG.get("database", {})
3434
KEYCLOAK_CONFIG = CONFIG.get("keycloak", {})
35+
DEV_CONFIG = CONFIG.get("dev", {})
3536
REQUEST_TIMEOUT = CONFIG.get("dev", {}).get("request_timeout", None)

src/main.py

Lines changed: 19 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
from starlette.requests import Request
1818

1919
from authentication import get_user_or_raise, KeycloakUser, assert_required_settings_configured
20-
from config import KEYCLOAK_CONFIG
20+
from config import KEYCLOAK_CONFIG, DB_CONFIG, DEV_CONFIG
2121
from database.deletion.triggers import create_delete_triggers
2222
import database.authorization # noqa # Trigger registration of User, Permission -> likely obsolete when couple with aiod_entry is done
2323
from database.model.concept.concept import AIoDConcept
@@ -39,38 +39,6 @@
3939
from setup_logger import setup_logger
4040

4141

42-
def _parse_args() -> argparse.Namespace:
43-
# TODO: refactor configuration (https://github.com/aiondemand/AIOD-rest-api/issues/82)
44-
parser = argparse.ArgumentParser(description="Please refer to the README.")
45-
parser.add_argument("--url-prefix", default="", help="Prefix for the api url.")
46-
parser.add_argument(
47-
"--build-db",
48-
default="if-absent",
49-
choices=["never", "if-absent", "drop-then-build"],
50-
help="""
51-
Determines if the database is created:\n
52-
- never: *never* creates the database, not even if there does not exist one yet.
53-
Use this only if you expect the database to be created through other means, such
54-
as MySQL group replication.\n
55-
- if-absent: Creates a database only if none exists.\n
56-
- drop-then-build: Drops the database on startup to recreate it from scratch.
57-
THIS REMOVES ALL DATA PERMANENTLY. NO RECOVERY POSSIBLE.
58-
""",
59-
)
60-
parser.add_argument(
61-
"--reload",
62-
action=argparse.BooleanOptionalAction,
63-
help="Use `--reload` for FastAPI.",
64-
)
65-
parser.add_argument(
66-
"--disable-reviews",
67-
action="store_true",
68-
help="Use --disable-reviews to disable the review process for new assets."
69-
"This does not affect the state of assets already created or under review.",
70-
)
71-
return parser.parse_args()
72-
73-
7442
def add_routes(app: FastAPI, url_prefix=""):
7543
"""Add routes to the FastAPI application"""
7644

@@ -121,9 +89,9 @@ def counts() -> dict:
12189
def create_app() -> FastAPI:
12290
"""Create the FastAPI application, complete with routes."""
12391
setup_logger()
124-
args = _parse_args()
12592
assert_required_settings_configured()
126-
if args.build_db == "never":
93+
build_database_setting = DB_CONFIG.get("build_database", "never")
94+
if build_database_setting == "never":
12795
if not database_exists():
12896
logging.warning(
12997
"AI-on-Demand database does not exist on the MySQL server, "
@@ -132,14 +100,15 @@ def create_app() -> FastAPI:
132100
"this likely means that you will get errors or undefined behavior."
133101
)
134102
else:
135-
build_database(args)
103+
drop_database = build_database_setting == "drop-then-build"
104+
build_database(drop_database=drop_database)
136105

137106
pyproject_toml = pkg_resources.get_distribution("aiod_metadata_catalogue")
138-
app = build_app(args.url_prefix, pyproject_toml.version)
107+
app = build_app(url_prefix=DEV_CONFIG.get("url_prefix", ""), version=pyproject_toml.version)
139108
return app
140109

141110

142-
def build_app(url_prefix: str = "", version: str = "dev"):
111+
def build_app(*, url_prefix: str = "", version: str = "dev"):
143112
app = FastAPI(
144113
openapi_url=f"{url_prefix}/openapi.json",
145114
docs_url=f"{url_prefix}/docs",
@@ -197,16 +166,15 @@ async def add_sunset_header(request: Request, call_next):
197166
return app
198167

199168

200-
def build_database(args):
201-
drop_database = args.build_db == "drop-then-build"
169+
def build_database(drop_database: bool = False):
202170
create_database(delete_first=drop_database)
203171
SQLModel.metadata.create_all(EngineSingleton().engine, checkfirst=True)
204172
with DbSession() as session:
205173
triggers = create_delete_triggers(AIoDConcept)
206174
for trigger in triggers:
207175
session.execute(trigger)
208176

209-
if args.disable_reviews:
177+
if DEV_CONFIG.get("disable_reviews", False):
210178
disable_review_process(session)
211179
else:
212180
enable_review_process(session)
@@ -220,11 +188,19 @@ def build_database(args):
220188

221189
def main():
222190
"""Run the application. Placed in a separate function, to avoid having global variables"""
223-
args = _parse_args()
191+
192+
# TODO: unify configuration and environment file? GH#82
193+
# This parsing allows users to see the message on `--help` or incorrect (old) invocations.
194+
msg = (
195+
"Configuration options can be set in the configuration file. "
196+
"Please refer to the documentation pages."
197+
)
198+
argparse.ArgumentParser(description=msg).parse_args()
199+
224200
uvicorn.run(
225201
"main:create_app",
226202
host="0.0.0.0", # noqa: S104 # required to make the interface available outside of docker
227-
reload=args.reload,
203+
reload=DEV_CONFIG.get("reload", False),
228204
factory=True,
229205
)
230206

0 commit comments

Comments
 (0)