From 0a0f92146a49bf0c73ef43a0d8ba9460c6ec08ad Mon Sep 17 00:00:00 2001 From: Adam Fourney Date: Wed, 16 Oct 2024 17:02:40 -0700 Subject: [PATCH] Added contributing instructions. --- .gitignore | 4 +- CONTRIBUTING.md | 32 ++++++ README.md | 3 + src/aprstastic/__about__.py | 2 +- src/aprstastic/_config.py | 16 +-- src/aprstastic/_config_const.py | 2 +- tests/test_config.py | 152 +++++++++++++++++++++++++ tests/test_data/test_aprstastic_1.yaml | 27 +++++ tests/test_data/test_aprstastic_2.yaml | 28 +++++ 9 files changed, 253 insertions(+), 13 deletions(-) create mode 100644 CONTRIBUTING.md create mode 100644 tests/test_config.py create mode 100644 tests/test_data/test_aprstastic_1.yaml create mode 100644 tests/test_data/test_aprstastic_2.yaml diff --git a/.gitignore b/.gitignore index 1e15b1c..28ddda8 100644 --- a/.gitignore +++ b/.gitignore @@ -162,4 +162,6 @@ cython_debug/ #.idea/ # project - specific -config.yml +tests/test_data/precompiled_registrations.json +tests/test_data/registrations.db +tests/test_data/aprstastic.yaml diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..2b1ae3f --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,32 @@ +# CONTRIBUTING + +Code contributions are welcome and appreciated. Just submit a PR! + +The current build environment uses `pre-commit`, and `hatch`. + +### Environment setup: + +```console +pip install hatch +git clone git@github.com:afourney/aprstastic.git +cd aprstastic +pre-commit install + +# Optionally run the pre-commit scripts at any time +pre-commit run --all-files +``` + +### Running and testing: + +From the aprstastic directory: + +```console +hatch shell + +# Running +python -m aprstastic + + +# Testing +hatch test +``` diff --git a/README.md b/README.md index 8fb1de4..f2e8cbb 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,9 @@ > [!WARNING] > Legal operation of this software requires an amateur radio license and a valid call sign. +> [!NOTE] +> Code contributions are welcomed and appreciated. See [CONTRIBUTING.md](https://github.com/afourney/aprstastic/blob/main/CONTRIBUTING.md) for details. + ## New! :fire: 2-minute [YouTube demo](https://www.youtube.com/watch?v=qUvpZUwl-cY) diff --git a/src/aprstastic/__about__.py b/src/aprstastic/__about__.py index f0f5b66..b6c0eee 100644 --- a/src/aprstastic/__about__.py +++ b/src/aprstastic/__about__.py @@ -1,4 +1,4 @@ # SPDX-FileCopyrightText: 2024-present Adam Fourney # # SPDX-License-Identifier: MIT -__version__ = "0.0.1a12" +__version__ = "0.0.1a14" diff --git a/src/aprstastic/_config.py b/src/aprstastic/_config.py index 0a5093f..328b9d4 100644 --- a/src/aprstastic/_config.py +++ b/src/aprstastic/_config.py @@ -61,14 +61,12 @@ def init_config(): # Try to get the data directory data_dir = config.get("data_dir") - if data_dir is None: + if data_dir is None or data_dir.strip() == "": data_dir = os.path.join( os.path.dirname(os.path.abspath(config_path)), DATA_SUBDIR ) - elif data_dir.strip() == "": - data_dir = os.path.join(os.getcwd(), DATA_SUBDIR) - else: - data_dir = os.path.expanduser(data_dir) + elif not os.path.isabs(data_dir): + data_dir = os.path.join(os.path.dirname(os.path.abspath(config_path)), data_dir) logger.debug(f"data directory: {data_dir}") os.makedirs(data_dir, exist_ok=True) @@ -76,14 +74,12 @@ def init_config(): # Try to get the logging directory logs_dir = config.get("logs_dir") - if logs_dir is None: + if logs_dir is None or logs_dir.strip() == "": logs_dir = os.path.join( os.path.dirname(os.path.abspath(config_path)), LOGS_SUBDIR ) - elif logs_dir.strip() == "": - logs_dir = os.path.join(os.getcwd(), LOGS_SUBDIR) - else: - logs_dir = os.path.expanduser(logs_dir) + elif not os.path.isabs(logs_dir): + logs_dir = os.path.join(os.path.dirname(os.path.abspath(config_path)), logs_dir) logger.debug(f"logs directory: {logs_dir}") os.makedirs(logs_dir, exist_ok=True) diff --git a/src/aprstastic/_config_const.py b/src/aprstastic/_config_const.py index c701ee7..57589f1 100644 --- a/src/aprstastic/_config_const.py +++ b/src/aprstastic/_config_const.py @@ -26,7 +26,7 @@ # Where should logs be stored? # If null, (or commented out), store logs in the `logs` dir, sibling to this file. -#log_dir: null +#logs_dir: null # Where should data be stored? diff --git a/tests/test_config.py b/tests/test_config.py new file mode 100644 index 0000000..05c08fa --- /dev/null +++ b/tests/test_config.py @@ -0,0 +1,152 @@ +# SPDX-FileCopyrightText: 2024-present Adam Fourney +# +# SPDX-License-Identifier: MIT +import os +import json +import time +import shutil + +from aprstastic._config import ( + ConfigError, + init_config, + CONFIG_FILE_NAME, + LOGS_SUBDIR, + DATA_SUBDIR, + DEFAULT_CALL_SIGN, +) + + +TEST_CONFIG_FILE_NAME_1 = "test_aprstastic_1.yaml" +TEST_CONFIG_FILE_NAME_2 = "test_aprstastic_2.yaml" +config_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "test_data") + +# Monkey patch the default directory +import aprstastic._config + +aprstastic._config.DEFAULT_DATA_DIR = config_dir + +logs_dir = os.path.join(config_dir, LOGS_SUBDIR) +data_dir = os.path.join(config_dir, DATA_SUBDIR) + + +def test_initialize_config(): + config_file = os.path.join(config_dir, CONFIG_FILE_NAME) + + # Start fresh + if os.path.isfile(config_file): + os.unlink(config_file) + + assert not os.path.isfile(config_file) + + cwd = os.path.abspath(os.getcwd()) + error_msg = None + try: + os.chdir(config_dir) + + # Initialize the config + config = init_config() + + except ConfigError as e: + error_msg = str(e) + finally: + os.chdir(cwd) + + # Make sure the sample config exists now + assert os.path.isfile(config_file) + # assert os.path.isdir(logs_dir) + # assert os.path.isdir(data_dir) + + # Make sure the correct error was thrown + assert "A sample configuration was written" in error_msg + + # Try loading it again, and check that the correct error was thrown the second time + try: + os.chdir(config_dir) + config = init_config() + except ConfigError as e: + error_msg = str(e) + finally: + os.chdir(cwd) + assert "appears to be the sample config" in error_msg + + +def test_load_config(): + config_file = os.path.join(config_dir, CONFIG_FILE_NAME) + test_config_file_1 = os.path.join(config_dir, TEST_CONFIG_FILE_NAME_1) + test_config_file_2 = os.path.join(config_dir, TEST_CONFIG_FILE_NAME_2) + + mylogs_dir = os.path.join(config_dir, "mylogs") + mydata_dir = os.path.join(config_dir, "mydata") + + # Install our test config #1 + shutil.copyfile(test_config_file_1, config_file) + + # Load the config + cwd = os.path.abspath(os.getcwd()) + error_msg = None + try: + os.chdir(config_dir) + config = init_config() + finally: + os.chdir(cwd) + + # Check that it looks right + assert config == json.loads( + """ +{ + "gateway": { + "call_sign": "N0CALL-1", + "aprsis_passcode": 12345, + "meshtastic_interface": { + "type": "serial" + }, + "beacon_registrations": true, + "data_dir": "%s", + "logs_dir": "%s" + }, + "licensed_operators": {} +} +""" + % (data_dir, logs_dir) + ) + + # Install our test config #2 + shutil.copyfile(test_config_file_2, config_file) + + # Load the config + cwd = os.path.abspath(os.getcwd()) + error_msg = None + try: + os.chdir(config_dir) + config = init_config() + finally: + os.chdir(cwd) + + # Check that it looks right + assert config == json.loads( + """ +{ + "gateway": { + "call_sign": "N0CALL-2", + "aprsis_passcode": 12345, + "meshtastic_interface": { + "type": "serial" + }, + "beacon_registrations": false, + "data_dir": "%s", + "logs_dir": "%s" + }, + "licensed_operators": {} +} +""" + % (mydata_dir, mylogs_dir) + ) + + +########################## +if __name__ == "__main__": + import logging + + logging.basicConfig(level=logging.DEBUG) + test_initialize_config() + test_load_config() diff --git a/tests/test_data/test_aprstastic_1.yaml b/tests/test_data/test_aprstastic_1.yaml new file mode 100644 index 0000000..bf251ff --- /dev/null +++ b/tests/test_data/test_aprstastic_1.yaml @@ -0,0 +1,27 @@ +# +# APRSTASTIC CONFIGURATION FILE (version: 1) +# Be sure to at least modify 'call_sign' and 'aprsis_passcode'. +# + +# Radio call sign of the gateway itself (analogy, iGate's call sign) +call_sign: N0CALL-1 + +# APRS-IS passcode. Search Google for how to get this +aprsis_passcode: 12345 + +# Only serial devices are supported right now. +# If 'device' is null (or commented out), an attempt will be made to +# detected it automatically. +meshtastic_interface: + type: serial +# device: /dev/ttyACM0 + +# Beacon new registrations to APRS-IS to facilitate discovery +beacon_registrations: true +# Where should logs be stored? +# If null, (or commented out), store logs in the `logs` dir, sibling to this file. +#logs_dir: null + +# Where should data be stored? +# If null, (or commented out), store data in the `data` dir, sibling to this file. +#data_dir: null diff --git a/tests/test_data/test_aprstastic_2.yaml b/tests/test_data/test_aprstastic_2.yaml new file mode 100644 index 0000000..7d541f8 --- /dev/null +++ b/tests/test_data/test_aprstastic_2.yaml @@ -0,0 +1,28 @@ +# +# APRSTASTIC CONFIGURATION FILE (version: 1) +# Be sure to at least modify 'call_sign' and 'aprsis_passcode'. +# + +# Radio call sign of the gateway itself (analogy, iGate's call sign) +call_sign: N0CALL-2 + +# APRS-IS passcode. Search Google for how to get this +aprsis_passcode: 12345 + +# Only serial devices are supported right now. +# If 'device' is null (or commented out), an attempt will be made to +# detected it automatically. +meshtastic_interface: + type: serial +# device: /dev/ttyACM0 + +# Beacon new registrations to APRS-IS to facilitate discovery +beacon_registrations: false + +# Where should logs be stored? +# If null, (or commented out), store logs in the `logs` dir, sibling to this file. +logs_dir: mylogs + +# Where should data be stored? +# If null, (or commented out), store data in the `data` dir, sibling to this file. +data_dir: mydata