# Contributing to Moku Python package

## Quickstart for Dev users
If you need to use development versions of this package, not actively contribute to it, you can install directly from git. Replace `<branch>` with the branch you want to install from if you need to e.g. test `next`.
```bash
# or uv pip install ...
pip install --upgrade git+ssh://git@git.liquidinstruments.com:client/libmoku.git@<branch>#subdirectory=python-client
```

## Development Environment Setup

### Prerequisites
- Python >= 3.8
- [uv](https://docs.astral.sh/uv/) - Fast Python package installer and resolver

Install uv if you haven't already (you may need to restart your terminal after installing):

```bash
# macOS/Linux
curl -LsSf https://astral.sh/uv/install.sh | sh

# Windows
powershell -c "irm https://astral.sh/uv/install.ps1 | iex"

# Or via pip
pip install uv
```

### Setting up your development environment

It's strongly recommended to use a dedicated virtual environment for development. This allows you to keep the publicly released package installed for day-to-day work while testing development versions.

#### Option 1: Using uv sync (recommended)

```bash
# Navigate to the python directory
cd python-client

# Create venv, install package in editable mode with all dev dependencies
uv sync --dev

# [Optional] Install with neural network support as well
uv sync --dev --extra neuralnetwork

# Activate the virtual environment
source .venv/bin/activate  # On Windows: .venv\Scripts\activate
```

The `uv sync` command:
- Creates a `.venv` directory if it doesn't exist
- Installs the package in editable mode
- Installs all dependencies from `uv.lock` for reproducible builds
- Keeps dependencies in sync with `pyproject.toml`

#### Option 2: Using pyenv with uv

```bash
# Install a specific Python version
pyenv install 3.12

# Use it for this project
cd /path/to/moku-python
pyenv local 3.12

# Now use uv sync (will use the pyenv Python)
uv sync --dev
```

### Working with the editable install

With `uv sync`, the package is automatically installed in editable mode, meaning changes to the source code are immediately reflected without reinstalling. To test a new version or branch:

1. Check out the branch you want to test
2. Your editable install automatically picks up the changes
3. Note: If you have long-running Python interpreters (e.g., Jupyter kernels), restart them or force a package re-import using `importlib`

If dependencies changed, sync them:

```bash
uv sync --dev
```

### Adding dependencies

Use `uv add` to add dependencies, which automatically updates `pyproject.toml`, `uv.lock`, and installs them:

```bash
# Add a main dependency
uv add newpackage

# Add a dependency with version constraint
uv add "newpackage>=1.0,<2.0"

# Add an optional dependency (e.g., for neuralnetwork extra)
uv add --optional neuralnetwork tensorflow

# Add a development dependency
uv add --dev newdevtool
```

Alternatively, you can manually edit `pyproject.toml`:

- **Main dependencies**: Add to `[project] dependencies = [...]`
- **Optional dependencies**: Add to `[project.optional-dependencies]` under the appropriate group
- **Dev dependencies**: Add to `[dependency-groups] dev = [...]`

Then sync and update the lockfile:

```bash
uv sync --dev
```

All dependencies must be compatible across all groups.

### Code formatting and linting

The project uses Ruff for code formatting and linting, managed through pre-commit hooks.

#### Setting up pre-commit hooks

After setting up your development environment, install the pre-commit hooks:

```bash
pre-commit install
```

Now the hooks will run automatically on every commit, checking and formatting your code.

#### Running checks manually

You can also run the checks manually at any time:

```bash
# Run all pre-commit hooks on all files
pre-commit run --all-files

# Or run ruff commands directly
ruff format moku/
ruff check --fix moku/
```

The pre-commit hooks will:
1. Run `ruff check --fix` to lint and auto-fix issues
2. Run `ruff format` to format code consistently

## Release Process

See https://packaging.python.org/en/latest/tutorials/packaging-projects/ for more details.

### Version bumping

Update the version number in `pyproject.toml`:

```toml
[project]
version = "4.0.4"
```

### Building and publishing

```bash
cd /path/to/moku-python

# Use the lowest supported Python version (3.8) for testing compatibility
# Install Python 3.8 if needed
pyenv install 3.8

# Switch to Python 3.8 for this project
pyenv local 3.8

# Verify the version
python --version  # Should show Python 3.8.x

# Build the distribution packages (wheel and sdist)
uv build
# This produces wheels and source distributions in ./dist/

# Upload to Test PyPI first
# Use the "PyPI TEST" "Moku upload token" from Keeper when prompted
uv publish --publish-url https://test.pypi.org/legacy/

# Test the installation from Test PyPI
uv pip install --index-url https://test.pypi.org/simple/ --no-deps moku

# Verify everything works correctly with your test installation
# Test importing, basic functionality, etc.

# Upload to production PyPI
# Use the "PyPI" "Moku upload token" from Keeper when prompted
uv publish

# Done!
```

**Note**: `uv build` automatically uses the build backend specified in `pyproject.toml` (hatchling), and `uv publish` handles authentication and uploading to PyPI.
