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

added a configuration file and library #62

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
22 changes: 22 additions & 0 deletions definitions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
"""This file contains definitions that will be used throughout the entire
project
"""

from __future__ import annotations

from pathlib import Path
from enum import Enum, auto

PROJECT_ROOT = Path(__file__).parent


class Subsystems(Enum):
"""enum of the simulated subsystems."""

ADCS = auto()
DFGM = auto()
DUMMY = auto()
EPS = auto()
IRIS = auto()
UHF_TO_GS = auto()
UHF_TO_OBC = auto()
21 changes: 21 additions & 0 deletions docs/definitions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Definitions Module

## Overview

This module contains immutable definitions that are shared
throughout the project. Things such as the root path of the
project directory on any file system, and `enum` that
represents the different simulated subsystems.

## Content

### PROJECT_ROOT

This is a `pathlib.Path` object that contains the path to
the root of the project. This value is dynamic, as it
will update between machines.

### Subsystems

This `enum` contains the fixed grouping of subsystems
supported by this project.
24 changes: 24 additions & 0 deletions docs/simconfig.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Simconfig Module

## Overview

This is a helper library that can read the `simulated_config.ini`
configuration files.

## Usage

### Obtaining root config

The following Python snippet is how the configuration
dictionary can be obtained from the configuration file
in the root.

```python
from simconfig import get_simulated_config
from definitions import TEST_PATH, Subsystems

config_dictionary = get_simulated_config(TEST_PATH, Subsystems.ADCS)

config_dictionary
# {"port": "61200"}
```
23 changes: 23 additions & 0 deletions docs/testing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Testing

## Dependencies

| Module name | version |
| --- | --- |
| Python | >=3.10 |
| pytest | |

## Running Tests

To run tests in this repository, navigate to the project root, and run the
following command:
```bash
pytest
```

## Writing Tests

Simply add a new file with a name that starts with the word `test` in the
`test` directory. You do not need to import `pytest`, only the module
that you are trying to test. To get a quick overview of python modules,
refer to [this document](https://docs.python.org/3.10/tutorial/modules.html).
52 changes: 52 additions & 0 deletions simconfig/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
"""This library provides the tools required to read configuration from the filesystem.
Using the INI format as it has broad compatabilities.
"""

from __future__ import annotations

from configparser import ConfigParser
from pathlib import Path

from definitions import Subsystems


def get_simulated_config(
config_file_path: Path, subsystem: Subsystems
) -> dict[str, str]:
"""This function will read the configuration
file defined by config_file_path and obtain
the configuration for the defined subsystem.
"""
config = ConfigParser()
config.read(config_file_path)

subsystem_name = subsystem.name.lower()
return dict(config[subsystem_name])


def make_fresh_config(file_path: Path) -> None:
"""This function creates a new subsystem_config.ini file, in the case that
a reset must occur.

Will create configuration for all the subsystems that are defined in the
definitions.py file.
"""
config = ConfigParser()
for index, subsystem in enumerate(Subsystems):
config[subsystem.name.lower()] = _make_default_subsystem_values(index)

with open(file_path, "w", encoding="utf-8") as configfile:
config.write(configfile)


def _make_default_subsystem_values(i: int) -> dict[str, str]:
"""This makes the default port for the simulated subsystem. Takes a port
offset as parameter.

NOTE:
- Left as a function for potential future extensions.
- The port is in the ephemeral range.
"""
sim_port = 61200 + i

return {"port": str(sim_port)}
21 changes: 21 additions & 0 deletions simulated_config.ini
waridh marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
[adcs]
port = 1803

[dfgm]
port = 1802

[dummy]
port = 1807

[eps]
port = 61201

[iris]
port = 1806

[uhf_to_gs]
port = 1235

[uhf_to_obc]
port = 1234

Empty file added test/__init__.py
Empty file.
66 changes: 66 additions & 0 deletions test/test_sim_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
"""Tests for the config reader helper library"""

from __future__ import annotations

from configparser import ConfigParser

import definitions
from simconfig import get_simulated_config, make_fresh_config

TEST_PATH = definitions.PROJECT_ROOT / "test.ini"


def test_make_default_simconfig() -> None:
"""Tests if we could make a clean configuration file"""
checks = tuple(x.name.lower() for x in definitions.Subsystems)
make_fresh_config(TEST_PATH)
read_config = ConfigParser()
read_config.read(TEST_PATH)

for index, subsystem in enumerate(checks):
config_port = read_config[subsystem]["port"]
# There is a hardcoded testing value for the port. At risk of change
assert int(config_port) == 61200 + index, f"{subsystem}"

TEST_PATH.unlink()


def test_obtain_default_ports() -> None:
"""Testing if we could read from the config file, and
obtain the ports"""
checks = tuple(x for x in definitions.Subsystems)
make_fresh_config(TEST_PATH)
read_config = ConfigParser()
read_config.read(TEST_PATH)

for index, subsystem in enumerate(checks):
config_dict = get_simulated_config(TEST_PATH, subsystem)
# There is a hardcoded testing value for the port. At risk of change
assert (
"port" in config_dict
), f"Missing port for {subsystem.name}, a required field"
assert int(config_dict["port"]) == 61200 + index, f"{subsystem}"

TEST_PATH.unlink()


def test_root_defaults() -> None:
"""Tests the default value of the config file at the root"""
config_path = definitions.PROJECT_ROOT / "simulated_config.ini"
expected = {
definitions.Subsystems.ADCS: 1803,
definitions.Subsystems.UHF_TO_GS: 1235,
definitions.Subsystems.UHF_TO_OBC: 1234,
definitions.Subsystems.DFGM: 1802,
definitions.Subsystems.IRIS: 1806,
definitions.Subsystems.DUMMY: 1807,
}

for subsys, expected_port in expected.items():
found_port = get_simulated_config(config_path, subsys)["port"]
assert (
found_port is not None
), "Expected port for {subsys.name} to exist, but found None"
assert (
int(found_port) == expected_port
), "Expected to see {expected_port}, but got {found_port}"
Loading