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

Overview page modules #532

Merged
merged 43 commits into from
Aug 14, 2023
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
5c34c3e
init script
milachae Aug 4, 2023
baafb65
added workflow linter + tests
milachae Aug 4, 2023
adb09ce
add requirements + fix tests
milachae Aug 4, 2023
4a0c398
simple module functions
milachae Aug 4, 2023
9f4d822
added filter option
milachae Aug 4, 2023
c69364b
working data fetching
milachae Aug 4, 2023
76798ad
display list of packages
Aug 7, 2023
afc6153
added data pickle test file
milachae Aug 7, 2023
90d7e55
adding comments
milachae Aug 7, 2023
722c1bc
adding markdown generator tests
milachae Aug 7, 2023
5b48d7c
improve MarkDown generator
milachae Aug 7, 2023
ca4927e
add dummy tests for module
milachae Aug 7, 2023
2921067
changed to 1 file
milachae Aug 7, 2023
8655c41
cleanup
milachae Aug 7, 2023
9aa9684
fix tests
milachae Aug 7, 2023
041a47d
Update workflow test
milachae Aug 8, 2023
b05396e
Remove files made by tests
milachae Aug 8, 2023
bf63315
adding comments
milachae Aug 8, 2023
31c75ae
adding tests
milachae Aug 8, 2023
24f9fd6
Apply typo suggestions
milachae Aug 9, 2023
8594510
update tests
milachae Aug 9, 2023
64015e6
remove commented lines
milachae Aug 9, 2023
4583515
remove commented line + indent fix
milachae Aug 9, 2023
dfa4342
fixing typos
milachae Aug 9, 2023
ebfe731
update tests
milachae Aug 9, 2023
f121a74
remove .pickle files from tests
milachae Aug 9, 2023
ffc46c4
update script/module_list/README.md
milachae Aug 9, 2023
58d300d
add swap tests
milachae Aug 10, 2023
20108ee
update README.md: 1st version testing
milachae Aug 10, 2023
cb34d74
Update README.md: version 2
milachae Aug 10, 2023
cb8885b
add license header
milachae Aug 10, 2023
09e197c
Merge branch 'main' into module_list
milachae Aug 10, 2023
5c606b5
Apply suggestions from code review
milachae Aug 11, 2023
f294575
update script workflow
milachae Aug 11, 2023
3850a21
apply code review suggestions
milachae Aug 11, 2023
5e33613
rename to module_overview
milachae Aug 11, 2023
d80202c
update test script
milachae Aug 11, 2023
e5b4536
fix argument error in lmod_mock script
milachae Aug 11, 2023
26b46d8
add code review suggestions
milachae Aug 11, 2023
6801b49
add prints
milachae Aug 11, 2023
e3af110
code revies suggestions
milachae Aug 14, 2023
8da6b1e
Apply suggestions from code review
milachae Aug 14, 2023
3bc8337
print message mentioning filename of module overview MarkDown file
boegel Aug 14, 2023
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
41 changes: 41 additions & 0 deletions .github/workflows/script_module_list.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: Run Linter and tests
milachae marked this conversation as resolved.
Show resolved Hide resolved
on: [push, pull_request]
# Declare default permissions as read only.
permissions: read-all
jobs:

flake8-lint:
runs-on: ubuntu-20.04
name: Lint
steps:
- name: Check out source repository
uses: actions/checkout@v3
- name: Set up Python environment
uses: actions/setup-python@v4
with:
python-version: "3.11"
- name: flake8 Lint
uses: py-actions/flake8@v2
with:
max-line-length: "120"
path: "scripts/module_list"
milachae marked this conversation as resolved.
Show resolved Hide resolved

pytest-tests:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.x'
milachae marked this conversation as resolved.
Show resolved Hide resolved
- name: Install dependencies
run: |
cd scripts/module_list
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Test with pytest
run: |
cd scripts/module_list
./test.sh
# pip install pytest pytest-cov
# pytest tests --doctest-modules --junitxml=junit/test-results.xml --cov=com --cov-report=xml --cov-report=html
milachae marked this conversation as resolved.
Show resolved Hide resolved
1 change: 1 addition & 0 deletions scripts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
scripts that can be used to automatically generate markdown files, can be found here.
milachae marked this conversation as resolved.
Show resolved Hide resolved
2 changes: 2 additions & 0 deletions scripts/module_list/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Module list
A script that generates a list (in markdown) of all available lmod modules.
milachae marked this conversation as resolved.
Show resolved Hide resolved
175 changes: 175 additions & 0 deletions scripts/module_list/module_overview.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
import os
import subprocess
from typing import Union, Tuple
from mdutils.mdutils import MdUtils
import numpy as np
milachae marked this conversation as resolved.
Show resolved Hide resolved


# --------------------------------------------------------------------------------------------------------
# Module bash API
milachae marked this conversation as resolved.
Show resolved Hide resolved
# --------------------------------------------------------------------------------------------------------

def module(*args, filter_fn=lambda x: x) -> np.ndarray:
"""
API to call the module command.
milachae marked this conversation as resolved.
Show resolved Hide resolved

@param args: Extra arguments for the module command.
@param filter_fn: Filter function on the ouput.
@return:
milachae marked this conversation as resolved.
Show resolved Hide resolved
"""
lmod = os.getenv('LMOD_CMD')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to implement in this PR, but we should add some error handling here.
What if $LMOD_CMD is not set (or points to a non-existing path)?
What if the exit code of the Lmod command is non-zero?

proc = subprocess.run(
[lmod, "python", "-t"] + list(args),
milachae marked this conversation as resolved.
Show resolved Hide resolved
encoding="utf-8",
stderr=subprocess.PIPE,
stdout=subprocess.PIPE
)
exec(proc.stdout)
return filter_fn(np.array(proc.stderr.split()))
milachae marked this conversation as resolved.
Show resolved Hide resolved


def module_avail(name: str = "", filter_fn=lambda x: x) -> np.ndarray:
"""
API to call the module avail command of Lmod.
milachae marked this conversation as resolved.
Show resolved Hide resolved

@param name: Possible module name.
milachae marked this conversation as resolved.
Show resolved Hide resolved
@param filter_fn: Filter on the output.
@return: List of all available modules of name, or all if name is not given.
"""
# return module(f"avail {name if name else ''}", filter_fn=filter_fn)
milachae marked this conversation as resolved.
Show resolved Hide resolved
return module("avail", name, filter_fn=filter_fn)


def module_swap(name: str) -> None:
"""
API to call swap command of module.
milachae marked this conversation as resolved.
Show resolved Hide resolved

@param name: Module you want to swap to.
milachae marked this conversation as resolved.
Show resolved Hide resolved
"""
module("swap", name)


# --------------------------------------------------------------------------------------------------------
# Fetch data
# --------------------------------------------------------------------------------------------------------

def filter_fn_gent_cluster(data: np.ndarray) -> np.ndarray:
"""
Filter function for the output of clusters.
milachae marked this conversation as resolved.
Show resolved Hide resolved
@param data: Output
@return: Filtered output
"""
return data[~np.char.endswith(data, ":") &
~np.char.startswith(data, "env/") &
~np.char.startswith(data, "cluster/default")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is good enough for now, but a better way to filter these would be to:

  • for each module, keep track of which location it was found in, so iterate over output of module avail line by line, and build up a dict with path as key, list of modules as value;
  • filter based on /etc/modulefiles/vsc (which covers env/* and cluster/*) to discriminate between software module and cluster modules;

]


def filter_fn_gent_modules(data: np.ndarray) -> np.ndarray:
"""
Filter function for the output of all modules.
milachae marked this conversation as resolved.
Show resolved Hide resolved
@param data: Output
@return: Filtered output
"""
return data[~np.char.endswith(data, ":") &
~np.char.startswith(data, "env/") &
~np.char.startswith(data, "cluster/")
]


def clusters_ugent() -> np.ndarray:
"""
Returns all the cluster names of the HPC at UGent.
@return: cluster names
"""

return module_avail(name="cluster/", filter_fn=filter_fn_gent_cluster)


def modules_ugent() -> dict:
"""
Returns all the module names that are installed on the HPC on UGent.
milachae marked this conversation as resolved.
Show resolved Hide resolved
They are grouped by cluster.
@return: Dictionary with all the modules per cluster
"""

data = {}
for cluster in clusters_ugent():
module_swap(cluster)
milachae marked this conversation as resolved.
Show resolved Hide resolved
data[cluster] = module_avail(filter_fn=filter_fn_gent_modules)
return data


# --------------------------------------------------------------------------------------------------------
# Util functions
# --------------------------------------------------------------------------------------------------------

def simplify_modules(data: Union[dict, list, np.ndarray]) -> Union[dict, list, np.ndarray]:
milachae marked this conversation as resolved.
Show resolved Hide resolved
"""
It removes the version of the modules and the duplicates.
milachae marked this conversation as resolved.
Show resolved Hide resolved

@param data: List of modules
@return: List of programs.
milachae marked this conversation as resolved.
Show resolved Hide resolved
"""

if isinstance(data, dict):
simplified_data = {}
for cluster in data:
simplified_data[cluster] = np.unique([entry.split("/")[0] for entry in data[cluster]])
else:
simplified_data = np.unique([entry.split("/")[0] for entry in data])
milachae marked this conversation as resolved.
Show resolved Hide resolved

return simplified_data


# --------------------------------------------------------------------------------------------------------
# Generate markdown
# --------------------------------------------------------------------------------------------------------

def generate_table_data(data: dict) -> Tuple[np.ndarray, int, int]:
milachae marked this conversation as resolved.
Show resolved Hide resolved
"""
Generate the data for the markdown table.
milachae marked this conversation as resolved.
Show resolved Hide resolved

@param data: Available data
@return: Returns tuple (Table data, #col, #row)
"""
data = simplify_modules(data)
all_modules = simplify_modules(np.concatenate(list(data.values())))

final = np.array([" "])
final = np.append(final, list(data.keys()))
milachae marked this conversation as resolved.
Show resolved Hide resolved

for package in all_modules:
final = np.append(final, package)

for cluster in data:
final = np.append(final, "X" if package in data[cluster] else " ")

return final, len(data.keys()) + 1, len(all_modules) + 1
milachae marked this conversation as resolved.
Show resolved Hide resolved


def generate_module_table(data: dict, md_file: MdUtils) -> None:
"""
Generate the general table of the overview.

@param data: Dict with all the data. Keys are the cluster names.
@param md_file: MdUtils object.
"""
structured, col, row = generate_table_data(data)
md_file.new_table(columns=col, rows=row, text=list(structured), text_align='center')


def generate_general_overview() -> None:
"""
Generate the general overview in a markdown file.
It generates a list of all the available software and indicates on which cluster it is available.
"""
md_file = MdUtils(file_name='Example_Markdown', title='Overview Moduls')
milachae marked this conversation as resolved.
Show resolved Hide resolved
data = modules_ugent()
generate_module_table(data, md_file)
md_file.create_md_file()


if __name__ == '__main__':
# Generate the overview
generate_general_overview()
5 changes: 5 additions & 0 deletions scripts/module_list/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
flake8
pytest
mdutils
numpy
setuptools
milachae marked this conversation as resolved.
Show resolved Hide resolved
1 change: 1 addition & 0 deletions scripts/module_list/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
PYTHONPATH=$PWD:$PYTHONPATH pytest -v -s
milachae marked this conversation as resolved.
Show resolved Hide resolved
Binary file added scripts/module_list/tests/data/data_all.pickle
Binary file not shown.
3 changes: 3 additions & 0 deletions scripts/module_list/tests/data/data_avail_cluster_simple.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/etc/modulefiles/vsc:
cluster/accelgor
cluster/victini
milachae marked this conversation as resolved.
Show resolved Hide resolved
29 changes: 29 additions & 0 deletions scripts/module_list/tests/data/data_avail_simple.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/apps/gent/RHEL8/zen2-ib/modules/all:
milachae marked this conversation as resolved.
Show resolved Hide resolved
ABAQUS/
ABAQUS/2021-hotfix-2132
ABAQUS/2022-hotfix-2214
ABAQUS/2022
ABAQUS/2023
ABINIT/
ABINIT/9.2.1-intel-2020a
ABINIT/9.4.1-intel-2020b
zstd/
zstd/1.4.4-GCCcore-9.3.0
zstd/1.4.5-GCCcore-10.2.0
zstd/1.4.9-GCCcore-10.3.0
zstd/1.5.0-GCCcore-11.2.0
zstd/1.5.2-GCCcore-11.3.0
zstd/1.5.2-GCCcore-12.2.0
/etc/modulefiles/vsc:
cluster/
cluster/accelgor
cluster/victini
env/slurm/
env/slurm/accelgor
env/slurm/victini
env/software/
env/software/accelgor
env/software/victini
env/vsc/
env/vsc/accelgor
env/vsc/victini
Binary file added scripts/module_list/tests/data/data_simple.pickle
Binary file not shown.
Loading