Skip to content

Commit

Permalink
Merge pull request #63 from DynamicsAndNeuralSystems/jmoo2880-YAML-re…
Browse files Browse the repository at this point in the history
…structure

Add optional dependency checks + SPI filter function
  • Loading branch information
joshuabmoore authored Mar 15, 2024
2 parents 8f297ca + 4fdce16 commit 9b9a80b
Show file tree
Hide file tree
Showing 14 changed files with 2,501 additions and 2,331 deletions.
14 changes: 9 additions & 5 deletions .github/workflows/run_unit_tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,35 @@ on:
push:

jobs:
build:
test-ubuntu:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.8", "3.9"]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Setup python ${{ matrix.python-version }}
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: 'pip'
- name: Install octave
run: |
sudo apt-get update
sudo apt-get install -y build-essential octave
- name: Install dependencies
- name: Install pyspi dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install .
- name: Run pyspi calculator unit tests
- name: Run pyspi calculator/utils unit tests
run: |
pytest -v ./tests/test_calc.py
pytest -v ./tests/test_utils.py
- name: Run pyspi SPI unit tests
run: |
pytest -v ./tests/test_SPIs.py


2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "pyspi"
version = "0.4.2"
version = "1.0.0"
authors = [
{ name ="Oliver M. Cliff", email="[email protected]"},
]
Expand Down
66 changes: 56 additions & 10 deletions pyspi/calculator.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

# From this package
from .data import Data
from .utils import convert_mdf_to_ddf
from .utils import convert_mdf_to_ddf, check_optional_deps


class Calculator:
Expand All @@ -31,15 +31,17 @@ class Calculator:
labels (array_like, optional):
Any set of strings by which you want to label the calculator. This can be useful later for classification purposes, defaults to None.
subset (str, optional):
A pre-configured subset of SPIs to use. Options are "all", "fast", "sonnet", "octaveless", or "fabfour", defaults to "all".
A pre-configured subset of SPIs to use. Options are "all", "fast", "sonnet", or "fabfour", defaults to "all".
configfile (str, optional):
The location of the YAML configuration file for a user-defined subset. See :ref:`Using a reduced SPI set`, defaults to :code:`'</path/to/pyspi>/pyspi/config.yaml'`
"""
_optional_dependencies = None

def __init__(
self, dataset=None, name=None, labels=None, subset="all", configfile=None
):
self._spis = {}
self._excluded_spis = list()

# Define configfile by subset if it was not specified
if configfile is None:
Expand All @@ -55,17 +57,20 @@ def __init__(
configfile = (
os.path.dirname(os.path.abspath(__file__)) + "/fabfour_config.yaml"
)
elif subset == "octaveless":
configfile = (
os.path.dirname(os.path.abspath(__file__)) + "/octaveless_config.yaml"
)
# If no configfile was provided but the subset was not one of the above (or the default 'all'), raise an error
elif subset != "all":
raise ValueError(
f"Subset '{subset}' does not exist. Try 'all' (default), 'fast', 'sonnet', 'octaveless', or 'fabfour'."
f"Subset '{subset}' does not exist. Try 'all' (default), 'fast', 'sonnet', or 'fabfour'."
)
else:
configfile = os.path.dirname(os.path.abspath(__file__)) + "/config.yaml"

# add dependency checks here if the calculator is being instantiated for the first time
if not Calculator._optional_dependencies:
# check if optional dependencies exist
print("Checking if optional dependencies exist...")
Calculator._optional_dependencies = check_optional_deps()

self._load_yaml(configfile)

duplicates = [
Expand All @@ -79,7 +84,38 @@ def __init__(
self._name = name
self._labels = labels

print("Number of SPIs: {}".format(len(self.spis)))
print(f"="*100)
print(f"Number of SPIs: {len(self.spis)}\n")
if len(self._excluded_spis) > 0:
missing_deps = [dep for dep, is_met in self._optional_dependencies.items() if not is_met]
print("**** SPI Initialisation Warning ****")
print("\nSome dependencies were not detected, which has led to the exclusion of certain SPIs:")
print("\nMissing Dependencies:")

for dep in missing_deps:
print(f"- {dep}")

print(f"\nAs a result, a total of {len(self._excluded_spis)} SPI(s) have been excluded:\n")

dependency_groups = {}
for spi in self._excluded_spis:
for dep in spi[1]:
if dep not in dependency_groups:
dependency_groups[dep] = []
dependency_groups[dep].append(spi[0])

for dep, spis in dependency_groups.items():
print(f"\nDependency - {dep} - affects {len(spis)} SPI(s)")
print("Excluded SPIs:")
for spi in spis:
print(f" - {spi}")

print(f"\n" + "="*100)
print("\nOPTIONS TO PROCEED:\n")
print(f" 1) Install the following dependencies to access all SPIs: [{', '.join(missing_deps)}]")
callable_name = "{Calculator/CalculatorFrame}"
print(f" 2) Continue with a reduced set of {self.n_spis} SPIs by calling {callable_name}.compute(). \n")
print(f"="*100 + "\n")

if dataset is not None:
self.load_dataset(dataset)
Expand Down Expand Up @@ -180,10 +216,20 @@ def _load_yaml(self, document):
print("*** Importing module {}".format(module_name))
module = importlib.import_module(module_name, __package__)
for fcn in yf[module_name]:
deps = yf[module_name][fcn].get('dependencies')
if deps is not None:
all_deps_met = all(Calculator._optional_dependencies.get(dep, False) for dep in deps)
if not all_deps_met:
current_base_spi = yf[module_name][fcn]
print(f"Optional dependencies: {deps} not met. Skipping {len(current_base_spi.get('configs'))} SPI(s):")
for params in current_base_spi.get('configs'):
print(f"*SKIPPING SPI: {module_name}.{fcn}(x,y,{params})...")
self._excluded_spis.append([f"{fcn}(x,y,{params})", deps])
continue
try:
for params in yf[module_name][fcn]:
for params in yf[module_name][fcn].get('configs'):
print(
f"[{self.n_spis}] Adding SPI {module_name}.{fcn}(x,y,{params})..."
f"[{self.n_spis}] Adding SPI {module_name}.{fcn}(x,y,{params})"
)
spi = getattr(module, fcn)(**params)
self._spis[spi.identifier] = spi
Expand Down
Loading

0 comments on commit 9b9a80b

Please sign in to comment.