From bc0cfd612b6034ca0ae8f99fd1eb28cfbd1b61ea Mon Sep 17 00:00:00 2001 From: lwjohnst Date: Sun, 27 Sep 2026 17:26:22 +0200 Subject: [PATCH 1/8] =?UTF-8?q?chore:=20=E2=99=BB=EF=B8=8F=20add=20env=20e?= =?UTF-8?q?xample=20file?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.example | 1 + .gitignore | 1 + src/questionnaire_data/common/dotenv.py | 4 +++- 3 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 .env.example diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..d24e358 --- /dev/null +++ b/.env.example @@ -0,0 +1 @@ +REDCAP_OPEN_API_KEY= diff --git a/.gitignore b/.gitignore index eb3eac4..e182fe0 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,7 @@ venv/ ENV/ env.bak/ venv.bak/ +!.env.example # Python specific content venv diff --git a/src/questionnaire_data/common/dotenv.py b/src/questionnaire_data/common/dotenv.py index 19bfc62..7bd4591 100644 --- a/src/questionnaire_data/common/dotenv.py +++ b/src/questionnaire_data/common/dotenv.py @@ -6,6 +6,8 @@ def load_env_vars() -> None: First, env vars are loaded from the shared project folder on GenomeDK. Then, they are overwritten by values from the local .env file (if this exists). + Otherwise it will use the default, though empty, `.env.example`. """ - load_dotenv("/faststorage/project/sdca-dpnext-study/env/.quest-env") + load_dotenv(".env.example") + load_dotenv("/faststorage/project/sdca-dpnext-study/env/.quest-env", override=True) load_dotenv(".env", override=True) From 67cbc49d0520198521d5661f6ed2d84cbf20e718 Mon Sep 17 00:00:00 2001 From: lwjohnst Date: Sun, 27 Sep 2026 17:44:59 +0200 Subject: [PATCH 2/8] =?UTF-8?q?chore:=20=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB?= =?UTF-8?q?=20skip=20raw=20tasks=20if=20API=20key=20is=20empty?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/questionnaire_data/build.py | 5 ++++- src/questionnaire_data/common/redcap.py | 16 ++++++++++++++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/questionnaire_data/build.py b/src/questionnaire_data/build.py index 20ef068..ce200ed 100644 --- a/src/questionnaire_data/build.py +++ b/src/questionnaire_data/build.py @@ -28,7 +28,10 @@ def _hash_properties(props: sp.SproutProperties) -> str: ).hexdigest() -@mark.metadata +@mark.skipif( + common.redcap.is_empty_env(), reason="API env key is not present, so skipping." +) +@mark.raw def task_download_metadata( raw_metadata_path: Annotated[Path, Product] = RAW_METADATA_PATH, ) -> None: diff --git a/src/questionnaire_data/common/redcap.py b/src/questionnaire_data/common/redcap.py index 3e92f0e..b2e08c3 100644 --- a/src/questionnaire_data/common/redcap.py +++ b/src/questionnaire_data/common/redcap.py @@ -1,6 +1,6 @@ import os from dataclasses import dataclass -from typing import Any, Literal +from typing import Any, Literal, Optional import requests @@ -23,7 +23,7 @@ def get( api_config: APIConfig = API_CONFIG, ) -> requests.Response: """Send a request to the REDCap API.""" - token = os.environ.get(api_config.env_key) + token = _get_env(api_config) if not token: raise RuntimeError(f"{api_config.env_key} environment variable is not set.") @@ -46,3 +46,15 @@ def get_json( } response = get(request_data) return response.json() + + +def is_empty_env() -> bool: + """Check if env is empty.""" + return _get_env(API_CONFIG) is None + + +def _get_env(api_config: APIConfig) -> Optional[str]: + env_var = os.environ.get(api_config.env_key) + if env_var == "": + env_var = None + return env_var From 1755c3221286fb88c3aeb53ae0325565518e3ebc Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 27 Sep 2026 15:46:46 +0000 Subject: [PATCH 3/8] =?UTF-8?q?chore:=20=E2=9C=8F=EF=B8=8F=20automatic=20p?= =?UTF-8?q?re-commit=20hook=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/questionnaire_data/common/redcap.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/questionnaire_data/common/redcap.py b/src/questionnaire_data/common/redcap.py index b2e08c3..339424d 100644 --- a/src/questionnaire_data/common/redcap.py +++ b/src/questionnaire_data/common/redcap.py @@ -1,6 +1,6 @@ import os from dataclasses import dataclass -from typing import Any, Literal, Optional +from typing import Any, Literal import requests @@ -53,7 +53,7 @@ def is_empty_env() -> bool: return _get_env(API_CONFIG) is None -def _get_env(api_config: APIConfig) -> Optional[str]: +def _get_env(api_config: APIConfig) -> str | None: env_var = os.environ.get(api_config.env_key) if env_var == "": env_var = None From 983dba5a7a7827331cdc965de982f6f2b1b0314d Mon Sep 17 00:00:00 2001 From: lwjohnst Date: Sun, 27 Sep 2026 17:44:59 +0200 Subject: [PATCH 4/8] =?UTF-8?q?chore:=20=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB?= =?UTF-8?q?=20skip=20raw=20tasks=20if=20API=20key=20is=20empty?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/questionnaire_data/build.py | 5 ++++- src/questionnaire_data/common/redcap.py | 16 ++++++++++++++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/questionnaire_data/build.py b/src/questionnaire_data/build.py index 20ef068..ce200ed 100644 --- a/src/questionnaire_data/build.py +++ b/src/questionnaire_data/build.py @@ -28,7 +28,10 @@ def _hash_properties(props: sp.SproutProperties) -> str: ).hexdigest() -@mark.metadata +@mark.skipif( + common.redcap.is_empty_env(), reason="API env key is not present, so skipping." +) +@mark.raw def task_download_metadata( raw_metadata_path: Annotated[Path, Product] = RAW_METADATA_PATH, ) -> None: diff --git a/src/questionnaire_data/common/redcap.py b/src/questionnaire_data/common/redcap.py index 3e92f0e..b2e08c3 100644 --- a/src/questionnaire_data/common/redcap.py +++ b/src/questionnaire_data/common/redcap.py @@ -1,6 +1,6 @@ import os from dataclasses import dataclass -from typing import Any, Literal +from typing import Any, Literal, Optional import requests @@ -23,7 +23,7 @@ def get( api_config: APIConfig = API_CONFIG, ) -> requests.Response: """Send a request to the REDCap API.""" - token = os.environ.get(api_config.env_key) + token = _get_env(api_config) if not token: raise RuntimeError(f"{api_config.env_key} environment variable is not set.") @@ -46,3 +46,15 @@ def get_json( } response = get(request_data) return response.json() + + +def is_empty_env() -> bool: + """Check if env is empty.""" + return _get_env(API_CONFIG) is None + + +def _get_env(api_config: APIConfig) -> Optional[str]: + env_var = os.environ.get(api_config.env_key) + if env_var == "": + env_var = None + return env_var From 0a16217365fcb5e4433b004b703d5fb19dfb9f93 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 27 Sep 2026 15:46:46 +0000 Subject: [PATCH 5/8] =?UTF-8?q?chore:=20=E2=9C=8F=EF=B8=8F=20automatic=20p?= =?UTF-8?q?re-commit=20hook=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/questionnaire_data/common/redcap.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/questionnaire_data/common/redcap.py b/src/questionnaire_data/common/redcap.py index b2e08c3..339424d 100644 --- a/src/questionnaire_data/common/redcap.py +++ b/src/questionnaire_data/common/redcap.py @@ -1,6 +1,6 @@ import os from dataclasses import dataclass -from typing import Any, Literal, Optional +from typing import Any, Literal import requests @@ -53,7 +53,7 @@ def is_empty_env() -> bool: return _get_env(API_CONFIG) is None -def _get_env(api_config: APIConfig) -> Optional[str]: +def _get_env(api_config: APIConfig) -> str | None: env_var = os.environ.get(api_config.env_key) if env_var == "": env_var = None From 6dc92a03d0608a3b63976dcbf2e7f8d7c9a78b0c Mon Sep 17 00:00:00 2001 From: lwjohnst Date: Sun, 27 Sep 2026 17:49:51 +0200 Subject: [PATCH 6/8] =?UTF-8?q?revert:=20=E2=8F=AA=EF=B8=8F=20use=20Option?= =?UTF-8?q?al,=20fixed=20from=20pre-commit=20change?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/questionnaire_data/common/redcap.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/questionnaire_data/common/redcap.py b/src/questionnaire_data/common/redcap.py index 339424d..b2e08c3 100644 --- a/src/questionnaire_data/common/redcap.py +++ b/src/questionnaire_data/common/redcap.py @@ -1,6 +1,6 @@ import os from dataclasses import dataclass -from typing import Any, Literal +from typing import Any, Literal, Optional import requests @@ -53,7 +53,7 @@ def is_empty_env() -> bool: return _get_env(API_CONFIG) is None -def _get_env(api_config: APIConfig) -> str | None: +def _get_env(api_config: APIConfig) -> Optional[str]: env_var = os.environ.get(api_config.env_key) if env_var == "": env_var = None From 0cd43b482dea9e161837e406b95b1a18f757c1a9 Mon Sep 17 00:00:00 2001 From: "Luke W. Johnston" Date: Mon, 28 Sep 2026 10:36:41 +0200 Subject: [PATCH 7/8] chore: edits from review Co-authored-by: martonvago <57952344+martonvago@users.noreply.github.com> --- src/questionnaire_data/build.py | 2 +- src/questionnaire_data/common/redcap.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/questionnaire_data/build.py b/src/questionnaire_data/build.py index ce200ed..d73030d 100644 --- a/src/questionnaire_data/build.py +++ b/src/questionnaire_data/build.py @@ -29,7 +29,7 @@ def _hash_properties(props: sp.SproutProperties) -> str: @mark.skipif( - common.redcap.is_empty_env(), reason="API env key is not present, so skipping." + common.redcap.is_empty_env(), reason="API key is not present in the environment, so skipping." ) @mark.raw def task_download_metadata( diff --git a/src/questionnaire_data/common/redcap.py b/src/questionnaire_data/common/redcap.py index b2e08c3..ca66069 100644 --- a/src/questionnaire_data/common/redcap.py +++ b/src/questionnaire_data/common/redcap.py @@ -48,12 +48,12 @@ def get_json( return response.json() -def is_empty_env() -> bool: +def is_empty_api_key() -> bool: """Check if env is empty.""" return _get_env(API_CONFIG) is None -def _get_env(api_config: APIConfig) -> Optional[str]: +def _get_api_key(api_config: APIConfig) -> Optional[str]: env_var = os.environ.get(api_config.env_key) if env_var == "": env_var = None From add994caa8cb5e27bbc04332c9d52882085516dd Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 28 Sep 2026 08:36:49 +0000 Subject: [PATCH 8/8] =?UTF-8?q?chore:=20=E2=9C=8F=EF=B8=8F=20automatic=20p?= =?UTF-8?q?re-commit=20hook=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/questionnaire_data/build.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/questionnaire_data/build.py b/src/questionnaire_data/build.py index d73030d..9ebefdb 100644 --- a/src/questionnaire_data/build.py +++ b/src/questionnaire_data/build.py @@ -29,7 +29,8 @@ def _hash_properties(props: sp.SproutProperties) -> str: @mark.skipif( - common.redcap.is_empty_env(), reason="API key is not present in the environment, so skipping." + common.redcap.is_empty_env(), + reason="API key is not present in the environment, so skipping.", ) @mark.raw def task_download_metadata(