Skip to content
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -181,3 +181,4 @@ CLAUDE.local.md
# package version
*_version.py
/docs/tutorials/SoundscapyResults.xlsx
CLAUDE.md
5 changes: 1 addition & 4 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,7 @@ repos:
rev: v1.5.5
hooks:
- id: forbid-tabs
- repo: https://github.com/pappasam/toml-sort
rev: v0.24.2
hooks:
- id: toml-sort-fix

# TODO(MitchellAcoustics): Enable linting pre-commit hooks
# https://github.com/MitchellAcoustics/Soundscapy/issues/114
# - repo: https://github.com/pre-commit/mirrors-mypy
Expand Down
88 changes: 88 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

Soundscapy is a Python library for analysing and visualising soundscape assessments. It supports survey data processing, circumplex (ISO) visualisation, binaural audio processing, and predicted soundscape perception via R-backed models.

## Commands

### Setup

```bash
uv sync --all-extras # Install all dependencies (core + audio + r/satp/spi)
uv sync # Core dependencies only (uses default groups: dev, docs, test)
uv sync --extra audio # Core + audio extras
uv sync --extra r # Core + R integration (rpy2)
```

### Testing

```bash
uv run pytest # Run all available tests (auto-skips missing dep modules)
uv run pytest test/test_surveys.py # Run a single test file
uv run pytest -k "test_name" # Run tests matching a pattern
uv run pytest --no-cov # Skip coverage measurement

# Tox environments for full multi-dep testing
uv run tox -e py312-core # Core only
uv run tox -e py312-audio # Core + audio
uv run tox -e py312-r # Core + R (requires R installed)
uv run tox -e py312-all # All extras
```

### Linting & Formatting

```bash
uv run ruff check . # Lint
uv run ruff check . --fix # Lint and auto-fix
uv run ruff format . # Format
```

### Docs

```bash
uv run mkdocs build # Build documentation
uv run mkdocs serve # Serve docs locally
```

## Architecture

### Source Layout (`src/soundscapy/`)

The package uses an `src/` layout with `importlib` import mode. Modules are split into **core** (always available) and **optional** (gated by extras):

- **Core**: `surveys/`, `plotting/`, `databases/` — always imported in `__init__.py`
- **Optional audio**: `audio/` — `try/except` import in `__init__.py`; requires `soundscapy[audio]`
- **Optional R-backed**: `spi/`, `satp/`, `r_wrapper/` — lazily loaded via module-level `__getattr__` (PEP 562) to avoid starting the R process on `import soundscapy`

### Key Modules

- **`surveys/`**: PAQ (Perceived Affective Quality) data processing, ISO coordinate calculations for the circumplex model (`ISOPleasant`, `ISOEventful` axes), data quality checks
- **`plotting/`**: `ISOPlot` — fluent API (method chaining) for circumplex plots using seaborn/matplotlib; also Likert scale plots
- **`databases/`**: Loaders for ISD (International Soundscape Database), SATP, and ARAUS datasets
- **`audio/`**: `Binaural` class (extends `acoustic_toolbox.Signal`) for psychoacoustic metrics from mosqito, maad, acoustic_toolbox
- **`satp/`**: `CircE` model — R-backed circumplex SEM analysis via `rpy2`; wraps the [CircE R package](https://github.com/MitchellAcoustics/CircE-R)
- **`spi/`**: Soundscape Perception Index using multi-skew normal distributions; also R-backed
- **`r_wrapper/`**: Low-level `rpy2` wrappers for CircE and SN (skew-normal) R packages

### Dependency System

Optional dependencies are managed at multiple levels:

1. **Module-level**: Each optional module's `__init__.py` imports its deps; failure surfaces clearly
2. **Package `__init__.py`**: Audio uses `try/except`; R modules use lazy `__getattr__`
3. **pytest**: `conftest.py` auto-skips collection for optional module directories (`audio/`, `r_wrapper/`, `spi/`, `satp/`) when deps are absent; use `@pytest.mark.optional_deps('group')` for integration tests

### Configuration

All tool config lives in `pyproject.toml` (ruff, mypy, pytest, coverage, setuptools-scm). Version is managed by `setuptools-scm` and written to `src/soundscapy/_version.py` — do not edit this file manually.

## Development Conventions

- **Branching**: feature branches → `dev` → `main` (only stable releases on `main`)
- **Commits**: Angular format (`feat:`, `fix:`, `docs:`, `refactor:`, `test:`, `chore:`)
- **R package testing**: The `sn` and `CircE` R packages must be installed separately via `pak` before running R-dependent tests (see `tox.ini` `commands_pre`)
- **xdoctest**: Doctests in source files run automatically with pytest via `--xdoctest`; write doctests using `Example:` sections
- **Logging**: Uses `loguru`; disabled by default for library use (`logger.disable("soundscapy")`). Expose via `soundscapy.enable_debug()` / `setup_logging()`
12 changes: 10 additions & 2 deletions src/soundscapy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
get_logger,
setup_logging,
)
from soundscapy.surveys import add_iso_coords, processing, rename_paqs
from soundscapy.surveys import add_iso_coords, ipsatize, processing, rename_paqs
from soundscapy.surveys.survey_utils import PAQ_IDS, PAQ_LABELS

__all__ = [
Expand All @@ -44,6 +44,7 @@
"disable_logging",
"enable_debug",
"get_logger",
"ipsatize",
"isd",
"iso_plot",
"jointplot",
Expand Down Expand Up @@ -107,7 +108,14 @@
}
)
_SATP_ATTRS: frozenset[str] = frozenset(
{"satp", "fit_circe", "CircModelE", "normalize_polar_angles"}
{
"satp",
"CircE",
"CircEResults",
"CircModelE",
"fit_circe",
"normalize_polar_angles",
}
)


Expand Down
2 changes: 2 additions & 0 deletions src/soundscapy/satp/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from soundscapy.satp import circe
from soundscapy.satp.circe import (
CircE,
CircEResults,
CircModelE,
fit_circe,
normalize_polar_angles,
Expand All @@ -29,6 +30,7 @@

__all__ = [
"CircE",
"CircEResults",
"CircModelE",
"circe",
"fit_circe",
Expand Down
Loading