# FAQ

## How do I add a tutorial notebook?

Add the Jupytext `.py` notebook to the appropriate directory under
`notebooks/`, then add its filename to that directory’s `index.md` to place it
in the ordered tutorial list.

## Where does my new learner go?

You should add your new learner to the appropriate directory:

- Classifiers go in `src/capymoa/classifier`.
- Regressors go in `src/capymoa/regressor`.
- Anomaly detectors go in `src/capymoa/anomaly`.
- Semi-supervised classifiers go in `src/capymoa/ssl/classifier`.

Each standalone learner should be in its own file, prefixed with `_` to indicate that they are not meant to be imported directly. Instead, they are imported by an `__init__.py` file. The `__init__.py` file is a special file that tells Python to treat the directory as a package.

For example, to add a new classifier class called `MyNewLearner`, you should implement it in `src/capymoa/classifier/_my_new_learner.py` and add it to the `src/capymoa/classifier/__init__.py` file. The `__init__.py` will look like this:

```python
from ._my_new_learner import MyNewLearner

...
__all__ = ["MyNewLearner", ...]
```

The prefix and init files allow users to import all classifiers, regressors,
or semi-supervised from one package while splitting the code into multiple files. You can, for example, import your new learner with the following:

```python
from capymoa.classifier import MyNewLearner
```

## What does a learner implement?

A learner should implement the appropriate interface:

* [`capymoa.base.Classifier`](../api/modules/capymoa.base.Classifier.md#capymoa.base.Classifier) for classifiers.
* [`capymoa.base.Regressor`](../api/modules/capymoa.base.Regressor.md#capymoa.base.Regressor) for regressors.
* [`capymoa.base.AnomalyDetector`](../api/modules/capymoa.base.AnomalyDetector.md#capymoa.base.AnomalyDetector) for anomaly detectors.
* [`capymoa.base.ClassifierSSL`](../api/modules/capymoa.base.ClassifierSSL.md#capymoa.base.ClassifierSSL) for semi-supervised classifiers.
* [`capymoa.base.Classifier`](../api/modules/capymoa.base.Classifier.md#capymoa.base.Classifier) for online continual learning classifiers.
  Optionally also inheriting from [`capymoa.ocl.events.Handler`](../api/modules/capymoa.ocl.events.Handler.md#capymoa.ocl.events.Handler) to
  subscribe to task-boundary events (for example
  `capymoa.ocl.evaluation.events.TrainTaskBegin` and
  `capymoa.ocl.evaluation.events.TestTaskBegin`).

If your method is a wrapper around a MOA learner, you should use the appropriate
base class:

* [`capymoa.base.MOAClassifier`](../api/modules/capymoa.base.MOAClassifier.md#capymoa.base.MOAClassifier) for classifiers.
* [`capymoa.base.MOARegressor`](../api/modules/capymoa.base.MOARegressor.md#capymoa.base.MOARegressor) for regressors.
* [`capymoa.base.MOAAnomalyDetector`](../api/modules/capymoa.base.MOAAnomalyDetector.md#capymoa.base.MOAAnomalyDetector) for anomaly detectors.

## How do I test my new learner?

You should add a test to ensure your learner achieves and continues to achieve
the expected performance in future versions. CapyMOA provides parameterised
tests for classifiers, regressors, and semi-supervised classifiers. You should
not need to write any new test code. Instead, you should add your test’s
parameters to the appropriate test file:

- `tests/test_classifiers.py` for classifiers.
- `tests/test_ssl_classifiers.py` for semi-supervised classifiers.
- `tests/ocl/test_learners.py` for online continual learning learners.
- `tests/test_regressors.py` for regressors.
- `tests/test_anomaly.py` for anomaly detectors.

To run your tests, use the following command:

```bash
python -m pytest -k MyNewLearner
```

The `-k MyNewLearner` flag tells PyTest to run tests containing `MyNewLearner` in the test ID.

* If you want to add documented exemplar usage of your learner, you can add doctests.
  See the [testing guide](tests.md) for more information.
* If you need custom test code for your learner, you can add a new test file in
  `tests`.

## How do I document my new learner?

You should add a docstring to your learner that describes the learner and its
parameters. The docstring should be in the Sphinx format. Check the
[documentation guide](docs.md) for more information and an example.

## How do I fix failing automated checks?

When a pull request is opened, automated checks are triggered to prevent breaking changes and maintain code quality. These checks are configured in the `.github/workflows/pr.yml` file using [GitHub Actions](https://docs.github.com/en/actions). The workflow runs tests, linters, and documentation builds automatically.

If a check fails, review the error messages and try to reproduce the issue locally. If you need help, ask in the pull request or join the Discord server.

**Automated Checks:**

- **Tests:**
  - **PyTest** (`invoke test.pytest`): Runs all unit tests in the `/tests` directory. See the [PyTest guide](tests.md#pytest).
  - **Doctest** (`invoke test.doctest`): Runs documentation tests. See the [doctest guide](tests.md#doctest).
- **Code Style:**
  - **Formatting** (`invoke fmt`): Checks code formatting and style.
- **Documentation:**
  - **Render Notebooks** (`invoke docs.nb`): Executes all notebooks in `/notebooks` to ensure they run without errors, and caches their outputs. See the [notebook guide](docs.md#notebooks).
  - **Build** (`invoke docs.build`): Verifies that the documentation builds successfully, using the cached notebook outputs. See the [documentation guide](docs.md).

## How do I format my code?

`invoke fmt` will format and check your code using `ruff`. Ruff is installed as part of
the [development dependencies](../setup/developer.md). Formatting helps make diff reviews
easier and keeps the codebase consistent.

## How do I write a commit message?

Don’t worry about this too much as reviewers will **squash and merge** your PR with
a meaningful commit message using the [conventional
commit](https://www.conventionalcommits.org) style. We use this style to automate
versioning and changelog generation.
