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

[BUGFIX] Fix GUI #533

Merged
merged 6 commits into from
Feb 15, 2025
Merged
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
5 changes: 3 additions & 2 deletions .github/workflows/python-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,16 @@ jobs:
- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install flake8 pytest
if [ -f environments/requirements.txt ]; then pip install -r environments/requirements.txt; fi
python -m pip install .
nam-hello-world
- name: Lint with flake8
run: |
python -m pip install flake8
# stop the build if there are Python syntax errors or undefined names
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
- name: Test with pytest
run: |
python -m pip install pytest pytest-mock
xvfb-run -a pytest
10 changes: 10 additions & 0 deletions docs/source/installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,13 @@ To update an existing installation:
.. code-block:: console

pip install --upgrade neural-amp-modeler

Local development installation
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

If you're interested in developing this package, there are Anaconda environment
definitions included in the ``environments/`` directory. Use the one that's
appropriate for the platform you're developing on. The
``.github/workflows/python-pckage.yml`` is also helpful if you want to be sure
that you're testing your developments in the same way that contributions will be
automatically tested (via GitHub Actions).
25 changes: 0 additions & 25 deletions environments/requirements.txt

This file was deleted.

18 changes: 17 additions & 1 deletion nam/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,26 @@ def removesuffix(s: str, suffix: str) -> str:
from pathlib import Path as _Path

from nam.train.full import main as _nam_full
from nam.train.gui import run as _nam_gui # noqa F401 Used as an entry point
from nam.train.gui import run as nam_gui # noqa F401 Used as an entry point
from nam.util import timestamp as _timestamp


def nam_hello_world():
"""
This is a minimal CLI entry point that's meant to be used to ensure that NAM
was installed successfully
"""
from nam import __version__
msg = f"""
Neural Amp Modeler

by Steven Atkinson

Version {__version__}
"""
print(msg)


def nam_full():
parser = _ArgumentParser()
parser.add_argument("data_config_path", type=str)
Expand Down
81 changes: 78 additions & 3 deletions nam/train/_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,68 @@
Version utility
"""

from typing import Optional as _Optional

from .._version import __version__


class IncomparableVersionError(ValueError):
"""
Error raised when two versions can't be compared.
"""

pass


class Version:
def __init__(self, major: int, minor: int, patch: int):
def __init__(self, major: int, minor: int, patch: int, dev: _Optional[str] = None):
self.major = major
self.minor = minor
self.patch = patch
self.dev = dev
self.dev_int = self._parse_dev_int(dev)

@classmethod
def from_string(cls, s: str):
major, minor, patch = [int(x) for x in s.split(".")]
return cls(major, minor, patch)
def special_case(s: str) -> _Optional[dict]:
"""
Regretful hacks
"""
# It seems like the git repo isn't accessible to setuptools_scm's version
# guesser, so it comes up with this during install:
if s == "0.1.dev1":
# This will be fine.
return {
"major": 0,
"minor": 1,
"patch": 0,
"dev": "dev1"
}
return None

if special_case(s) is not None:
return cls(**special_case(s))

# Typical
parts = s.split(".")
if len(parts) == 3: # e.g. "0.7.1"
dev = None
elif len(parts) == 4: # e.g. "0.7.1.dev7"
dev = parts[3]
else:
raise ValueError(f"Invalid version string {s}")
try:
major, minor, patch = [int(x) for x in parts[:3]]
except ValueError as e:
raise ValueError(f"Failed to parse version from string '{s}':\n{e}")
return cls(major=major, minor=minor, patch=patch, dev=dev)

def __eq__(self, other) -> bool:
return (
self.major == other.major
and self.minor == other.minor
and self.patch == other.patch
and self.dev == other.dev
)

def __lt__(self, other) -> bool:
Expand All @@ -36,10 +79,42 @@ def __lt__(self, other) -> bool:
return self.minor < other.minor
if self.patch != other.patch:
return self.patch < other.patch
if self.dev != other.dev:
# None is defined as least
if self.dev is None and other.dev is not None:
return True
elif self.dev is not None and other.dev is None:
return False
assert self.dev is not None
assert other.dev is not None
if self.dev_int is None:
raise IncomparableVersionError(
f"Version {str(self)} has incomparable dev version {self.dev}"
)
if other.dev_int is None:
raise IncomparableVersionError(
f"Version {str(other)} has incomparable dev version {other.dev}"
)
return self.dev_int < other.dev_int
raise RuntimeError(
f"Unhandled comparison between versions {str(self)} and {str(other)}"
)

def __str__(self) -> str:
return f"{self.major}.{self.minor}.{self.patch}"

def _parse_dev_int(self, dev: _Optional[str]) -> _Optional[int]:
"""
Turn the string into an int that can be compared if possible.
"""
if dev is None:
return None
if not isinstance(dev, str):
raise TypeError(f"Invalid dev string type {type(dev)}")
if not dev.startswith("dev") or len(dev) <= 3: # "misc", "dev", etc
return None
return int(dev.removeprefix("dev"))


PROTEUS_VERSION = Version(4, 0, 0)

Expand Down
5 changes: 5 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,16 @@ requires-python = ">=3.8"
dependencies = [
"auraloss==0.3.0",
"matplotlib",
"numpy<2",
"pydantic>=2.0.0",
"pytorch_lightning",
"scipy",
"sounddevice",
"tensorboard",
"torch",
# `transformers` is not required, but if you have it, it needs to be recent
# enough so I'm adding it.
"transformers>=4",
"tqdm",
"wavio>=0.0.5",
]
Expand All @@ -44,6 +48,7 @@ homepage = "https://github.com/sdatkinson/"
[project.scripts]
nam = "nam.cli:nam_gui"
nam-full = "nam.cli:nam_full"
nam-hello-world = "nam.cli:nam_hello_world"

[tool.setuptools_scm]
version_scheme = "guess-next-dev"
Expand Down
24 changes: 16 additions & 8 deletions tests/test_nam/test_train/test_gui/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,22 @@
from nam.train import gui


class TestPathButton(object):
def test_system_text_color(self):
"""
Issue 428
"""
top_level = tk.Toplevel()
label = tk.Label(master=top_level, text="My text", fg=gui._SYSTEM_TEXT_COLOR)
label.pack()
# class TestPathButton(object):
# def test_system_text_color(self):
# """
# Issue 428
# """
# top_level = tk.Toplevel()
# label = tk.Label(master=top_level, text="My text", fg=gui._SYSTEM_TEXT_COLOR)
# label.pack()


def test_get_current_version():
"""
Make sure this at least runs!
See #516
"""
v = gui._get_current_version()


if __name__ == "__main__":
Expand Down
46 changes: 46 additions & 0 deletions tests/test_nam/test_train/test_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,32 @@
# Created Date: Saturday April 29th 2023
# Author: Steven Atkinson (steven@atkinson.mn)

"""
Tests for version class
"""

import pytest as _pytest

from nam.train import _version


def test_dev_int():
"""
Assert that dev_int is properly parsed
"""
assert _version.Version(0, 0, 0).dev_int is None
assert _version.Version(0, 0, 0, "dev").dev_int is None
assert _version.Version(0, 0, 0, "misc").dev_int is None
assert _version.Version(0, 0, 0, "dev11").dev_int == 11


def test_eq():
assert _version.Version(0, 0, 0) == _version.Version(0, 0, 0)
assert _version.Version(0, 0, 0) != _version.Version(0, 0, 1)
assert _version.Version(0, 0, 0) != _version.Version(0, 1, 0)
assert _version.Version(0, 0, 0) != _version.Version(1, 0, 0)
assert _version.Version(0, 0, 0) != _version.Version(0, 0, 0, dev="dev0")
assert _version.Version(0, 0, 0) != _version.Version(0, 0, 0, dev="dev1")


def test_lt():
Expand All @@ -20,3 +38,31 @@ def test_lt():
assert _version.Version(1, 2, 3) < _version.Version(2, 0, 0)

assert not _version.Version(1, 2, 3) < _version.Version(0, 4, 5)


def test_lt_incomparable():
"""
Assert that the error is properly raised for incomparable versions
"""
with _pytest.raises(_version.IncomparableVersionError):
_version.Version(0, 0, 0, "incomparable") < _version.Version(0, 0, 0, "dev1")


def test_current_version():
"""
Test that the current version is valid
"""
from nam import __version__

# First off, assert that the current version can be understood by _version.Version.
# Broken by PR 516 (pyproject.toml)--watch out!
v = _version.Version.from_string(__version__)

# Check comparisons like used in GUI:
assert _version.Version(0, 0, 0) != v
assert _version.Version(0, 0, 0) < v
# Just checking both orders. If we're actually at this version, then fine, move it up!
high_major_version_that_we_will_probably_never_get_to = 1000
assert v < _version.Version(
high_major_version_that_we_will_probably_never_get_to, 0, 0
)
1 change: 1 addition & 0 deletions tests/test_nam/test_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import nam as _nam


def test_has_version():
assert hasattr(_nam, "__version__")

Expand Down