Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds ability to set alternate local folder for config/metadata directory #111

Merged
merged 7 commits into from
Nov 29, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 13 additions & 6 deletions cli.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import ftplib
import io
import sys
import pydantic
import tum_esm_utils

import click
import pydantic
import em27_metadata
import tum_esm_utils

_RETRIEVAL_ENTRYPOINT = tum_esm_utils.files.rel_to_abs_path("src", "retrieval", "main.py")
dostuffthatmatters marked this conversation as resolved.
Show resolved Hide resolved

Expand All @@ -16,8 +17,10 @@

def _check_config_validity() -> None:
import src
from src import utils
try:
src.types.Config.load()
config_path = utils.environment.get_config_path()
src.types.Config.load(config_path)
click.echo(click.style("Config is valid", fg="green", bold=True))
except pydantic.ValidationError as e:
click.echo(
Expand Down Expand Up @@ -123,7 +126,9 @@ def request_ginput_status() -> None:
_check_config_validity()

import src # import here so that the CLI is more reactive
config = src.types.Config.load()
from src import utils
config_path = utils.environment.get_config_path()
config = src.types.Config.load(config_path)
dostuffthatmatters marked this conversation as resolved.
Show resolved Hide resolved
assert config.profiles is not None, "No profiles config found"
with ftplib.FTP(
host="ccycle.gps.caltech.edu",
Expand Down Expand Up @@ -151,12 +156,14 @@ def run_bundle() -> None:
def print_data_report() -> None:
_check_config_validity()

import src # import here so that the CLI is more reactive
import rich.console
import src # import here so that the CLI is more reactive
from src import utils

console = rich.console.Console()
console.print("Loading config")
config = src.types.Config.load()
config_path = utils.environment.get_config_path()
config = src.types.Config.load(config_path)
dostuffthatmatters marked this conversation as resolved.
Show resolved Hide resolved

# load metadata interface
console.print("Loading metadata")
Expand Down
2 changes: 2 additions & 0 deletions docs/pages/guides/configuration.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { Callout } from "nextra/components";

The `config/config.json` file configures all steps of the pipeline. You can use the `config/config.template.json` file as a template to create your own configuration file.

For setting up alternate locations for the `config.json` file, see the [metadata section](/guides/metadata).

<Callout type="info" emoji="💡">

The full schema specification and description of each parameter can be found [in the API Reference section](/api-reference/configuration).
Expand Down
14 changes: 14 additions & 0 deletions docs/pages/guides/metadata.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,20 @@ To configure the pipeline with the metadata, you have two options: Save them loc

For this option, you can save the three files `locations.json`, `sensors.json`, and `campaigns.json` to the `config/` directory of the pipeline directory. Be sure to include all the files - even if you don't have any campaigns, save an empty list to `campaigns.json`.

Alternatively, you can store these files locally in a location outside of this repository. This is achieved by setting the environment variable `ERP_CONFIG_DIR` to the full path of the alternate location (ERP is short for EM27 Retrieval Pipeline). Note that this should be the same directory that contains the `config.json` file. If this environment variable is not set, the default location the pipeline will look for these files is `config/`. When setting an alternate config directory, it is not necessary to touch the file `config/config.template.json` (this file is version-controlled).

dostuffthatmatters marked this conversation as resolved.
Show resolved Hide resolved
cfleur marked this conversation as resolved.
Show resolved Hide resolved
For example, directly setting the environment variable:
```
export ERP_CONFIG_DIR=<path-to-local-config-dir>
```

For example, sourcing a `.env` file:
```
set -a && . <path-to-.env-file> && set +a
```

Check the set environment variables with `export -p`.

### Option 2: GitHub Repository

**1. Create a repository**
Expand Down
548 changes: 288 additions & 260 deletions pdm.lock

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion src/bundle/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ def run(
) -> None:
if config is None:
print("Loading configuration")
config = types.Config.load()
config_path = utils.environment.get_config_path()
config = types.Config.load(config_path)
dostuffthatmatters marked this conversation as resolved.
Show resolved Hide resolved

assert config.bundles is not None, "no bundle targets found"
assert len(config.bundles) > 0, "no bundle targets found"
Expand Down
8 changes: 5 additions & 3 deletions src/profiles/main.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import ftplib
import os
import sys

import tum_esm_utils
import ftplib

sys.path.append(tum_esm_utils.files.rel_to_abs_path("../.."))
from src import types, profiles
from src import types, profiles, utils


def run() -> None:
config = types.Config.load()
config_path = utils.environment.get_config_path()
config = types.Config.load(config_path)
dostuffthatmatters marked this conversation as resolved.
Show resolved Hide resolved
assert config.profiles is not None, "No profiles config found"

for variant in ["GGG2014", "GGG2020"]:
Expand Down
3 changes: 2 additions & 1 deletion src/retrieval/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ def run() -> None:

# load config
try:
config = types.Config.load()
config_path = utils.environment.get_config_path()
config = types.Config.load(config_path)
dostuffthatmatters marked this conversation as resolved.
Show resolved Hide resolved
main_logger.info("Config is valid")
except Exception as e:
main_logger.exception(e, "Config file invalid")
Expand Down
2 changes: 1 addition & 1 deletion src/utils/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
from . import functions, metadata, report, semaphores, text
from . import environment, functions, metadata, report, semaphores, text
19 changes: 19 additions & 0 deletions src/utils/environment.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import os

import tum_esm_utils


CONFIG_DIR_KEY = "ERP_CONFIG_DIR"
dostuffthatmatters marked this conversation as resolved.
Show resolved Hide resolved


def get_config_dir() -> str:
default_config_dir = tum_esm_utils.files.rel_to_abs_path("../../config")
return os.getenv(CONFIG_DIR_KEY, default_config_dir)


def get_config_path() -> str:
default_config_dir = get_config_dir()
return os.path.join(
os.getenv(CONFIG_DIR_KEY, default_config_dir),
"config.json"
)
8 changes: 5 additions & 3 deletions src/utils/metadata.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
from typing import Optional
import os
from typing import Optional

import em27_metadata
import tum_esm_utils

CONFIG_DIR = tum_esm_utils.files.rel_to_abs_path("../../config")
from src import utils


CONFIG_DIR = utils.environment.get_config_dir()

def load_local_em27_metadata_interface() -> Optional[em27_metadata.EM27MetadataInterface]:
assert os.path.isdir(CONFIG_DIR)
Expand Down
6 changes: 4 additions & 2 deletions tests/integration/test_config.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import pytest
import src

import src
from src import utils

@pytest.mark.order(2)
@pytest.mark.integration
def test_config() -> None:
src.types.Config.load()
config_path = utils.environment.get_config_path()
src.types.Config.load(config_path)
6 changes: 4 additions & 2 deletions tests/integration/test_metadata_connection.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import pytest
import em27_metadata
import src

import src
from src import utils

@pytest.mark.order(3)
@pytest.mark.integration
def test_metadata_connection() -> None:
config = src.types.Config.load()
config_path = utils.environment.get_config_path()
config = src.types.Config.load(config_path)
dostuffthatmatters marked this conversation as resolved.
Show resolved Hide resolved
if config.general.metadata is None:
pytest.skip("Remote metadata not configured")
else:
Expand Down
7 changes: 4 additions & 3 deletions tests/integration/test_profiles_connection.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import pytest
import ftplib
import warnings
import src

import src
from src import utils

@pytest.mark.order(3)
@pytest.mark.integration
def test_profiles_connection() -> None:
config = src.types.Config.load()
config_path = utils.environment.get_config_path()
config = src.types.Config.load(config_path)
dostuffthatmatters marked this conversation as resolved.
Show resolved Hide resolved
dostuffthatmatters marked this conversation as resolved.
Show resolved Hide resolved
if config.profiles is None:
return
with ftplib.FTP(
Expand Down
6 changes: 4 additions & 2 deletions tests/repository/test_local_metadata.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
from typing import Generator
import os
import pytest
import tum_esm_utils

import src
from src import utils


CONFIG_DIR = tum_esm_utils.files.rel_to_abs_path("../../config")
CONFIG_DIR = utils.environment.get_config_dir()
LOCATIONS_PATH = os.path.join(CONFIG_DIR, "locations.json")
SENSORS_PATH = os.path.join(CONFIG_DIR, "sensors.json")
CAMPAIGNS_PATH = os.path.join(CONFIG_DIR, "campaigns.json")
Expand Down