diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..2de3629 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,106 @@ +name: tests (CPU) + +on: + push: + branches: [main] + pull_request: + branches: [main] + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + test: + name: Python ${{ matrix.python-version }} + runs-on: ubuntu-latest + timeout-minutes: 15 + + strategy: + fail-fast: false + matrix: + python-version: ["3.12", "3.13", "3.14"] + + steps: + - name: Check out repository + uses: actions/checkout@v4 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + cache: pip + + - name: Show environment + run: | + python --version + pip --version + + - name: Install package + run: | + python -m pip install --upgrade pip + pip install -e ".[safetensors]" + + - name: Show resolved dependencies + run: pip list + + - name: Verify package imports + run: python -c "import aether as ae; print('aether from', ae.__file__)" + + - name: Verify lazy namespace resolves + run: | + python - <<'PY' + import aether as ae + + names = [ + "Model", + "Conv2d", "Dense", "BatchNorm", + "MaxPool2d", "AvgPool2d", "GlobalAvgPool", + "Dropout", "SpatialDropout", + "ReLU", "LeakyReLU", + "AdamW", + "SoftmaxCategoricalCrossEntropy", + "CategoricalAccuracy", "RegressionAccuracy", + "Compose", "Rescale", "StandardScaler", "ToTensor", + "to_tensor", + ] + + missing = [n for n in names if not hasattr(ae, n)] + if missing: + raise SystemExit(f"lazy namespace failed to resolve: {missing}") + print(f"resolved {len(names)} public symbols") + PY + + - name: Verify required dependencies are declared + run: | + python - <<'PY' + import importlib.util + + for pkg in ("numpy", "safetensors"): + if importlib.util.find_spec(pkg) is None: + raise SystemExit( + f"{pkg} not installed - it is used by the test suite " + f"but missing from pyproject.toml dependencies" + ) + print("numpy and safetensors present") + PY + + - name: Confirm runner has no GPU backend + run: | + python - <<'PY' + import importlib.util + + if importlib.util.find_spec("cupy") is not None: + raise SystemExit( + "CuPy is installed on a CPU-only runner - this workflow " + "would report coverage it cannot actually verify" + ) + print("CuPy absent - GPU tests will be skipped") + PY + + - name: Run test suite + run: python -m unittest discover -s tests -v \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 7f9bc42..f8855f2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,14 +5,26 @@ build-backend = "setuptools.build_meta" [project] name = "aether-ml" version = "0.1.0" -requires-python = ">= 3.14" +requires-python = ">= 3.12" dependencies = [ "numpy", ] [project.optional-dependencies] +safetensors = ["safetensors>=0.8.0"] gpu-nvidia = ["cupy-cuda12x"] # CuPy wheel from PyPI -gpu-amd = [] # CuPy compiled inside aether-rocm.Dockerfile +gpu-amd = [] # CuPy compiled via ROCm container env + +notebooks = [ + "safetensors>=0.8.0", + "jupyterlab", + "matplotlib", +] + +dev = [ + "aether-ml[safetensors]", + "aether-ml[notebooks]", +] [tool.setuptools.packages.find] where = ["."]