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
35 changes: 35 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
## Description

<!-- Provide a brief description of the changes in this PR -->

## Type of Change

<!-- Check all that apply -->

- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] Documentation update
- [ ] Code refactoring
- [ ] Test improvements

## Testing

<!-- Describe the tests you ran and how to verify your changes -->

- [ ] Tests pass locally
- [ ] Added/updated tests for new functionality
- [ ] Manual testing completed

## Checklist

- [ ] Code follows the project's style guidelines
- [ ] Self-review completed
- [ ] Comments added for complex code sections
- [ ] Documentation updated (if applicable)
- [ ] No new warnings or errors introduced
- [ ] Changes are backward compatible (or migration path is documented)

## Additional Notes

<!-- Add any additional context, screenshots, or notes for reviewers -->
80 changes: 80 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
name: CI

on:
push:
branches: [main, master]
pull_request:
branches: [main, master]

jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.9", "3.10", "3.11", "3.12"]

steps:
- uses: actions/checkout@v4

- name: Install uv
uses: astral-sh/setup-uv@v4
with:
version: "latest"

- name: Set up Python ${{ matrix.python-version }}
run: uv python install ${{ matrix.python-version }}

- name: Install dependencies
run: uv sync --dev

- name: Run tests
run: uv run pytest tests/ -v --cov=google_docs_markdown --cov-report=xml --cov-report=term

- name: Upload coverage to Codecov
if: matrix.python-version == '3.12'
uses: codecov/codecov-action@v4
with:
file: ./coverage.xml
fail_ci_if_error: false

lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Install uv
uses: astral-sh/setup-uv@v4
with:
version: "latest"

- name: Set up Python
run: uv python install 3.12

- name: Install dependencies
run: uv sync --dev

- name: Run ruff linting
run: uv run ruff check . --output-format=github

- name: Run ruff formatting check
run: uv run ruff format --check .

# TODO: Uncomment this if we want to include static type checking
# type-check:
# runs-on: ubuntu-latest
# steps:
# - uses: actions/checkout@v4

# - name: Install uv
# uses: astral-sh/setup-uv@v4
# with:
# version: "latest"

# - name: Set up Python
# run: uv python install 3.12

# - name: Install dependencies
# run: uv sync --dev

# - name: Run mypy type checking
# run: uv run mypy google_docs_markdown tests/
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,9 @@ ref/*

# macOS
.DS_Store

# Output files
output/

# Cursor
.cursor/
60 changes: 60 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
.PHONY: help test lint format type-check check all clean update-docs update-models update-api-reference update-all convert-test-docs

# When uv is on PATH, run tools via the project environment; otherwise use pytest/ruff from PATH (e.g. activated venv).
UV_RUN := $(if $(shell command -v uv 2>/dev/null),uv run,)

help:
@echo "Available commands:"
@echo " make test - Run tests with pytest"
@echo " make lint - Run ruff linter"
@echo " make format - Check code formatting with ruff"
@echo " make format-fix - Auto-fix formatting issues with ruff"
@echo " make type-check - Run mypy type checker"
@echo " make check - Run all checks (lint, format, type-check, test)"
@echo " make all - Same as 'make check'"
@echo " make clean - Clean cache files"

# Run tests with coverage
run-tests:
$(UV_RUN) pytest --cov=src --cov-branch --cov-report=term-missing

# Run integration tests
run-integration-tests:
$(UV_RUN) pytest -m integration

# Run linter
lint-check:
$(UV_RUN) ruff check .

# Auto-fix linting issues
lint-fix:
$(UV_RUN) ruff check --fix .

# Ruff unsafe fixes
lint-fix-unsafe:
$(UV_RUN) ruff check --fix --unsafe-fixes .

# Check formatting (without modifying files)
format-check:
$(UV_RUN) ruff format --check .

# Auto-fix formatting issues
format-fix:
$(UV_RUN) ruff format .

# Run all checks
test: format-fix lint-fix format-check lint-check run-tests

# Run all fixers
fix: lint-fix format-fix

# Alias for check
all: check

# Clean cache files
clean:
find . -type d -name "__pycache__" -exec rm -r {} + 2>/dev/null || true
find . -type d -name ".pytest_cache" -exec rm -r {} + 2>/dev/null || true
find . -type d -name ".mypy_cache" -exec rm -r {} + 2>/dev/null || true
find . -type d -name ".ruff_cache" -exec rm -r {} + 2>/dev/null || true
find . -type f -name "*.pyc" -delete 2>/dev/null || true
70 changes: 62 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,6 @@ management, and metadata edits while keeping a clean escape hatch to the raw API
pip install lexicon-python
```

Optional (for interactive playlist chooser):

```bash
pip install InquirerPy
```

## Quickstart

```python
Expand Down Expand Up @@ -305,20 +299,80 @@ For full payload schemas and endpoint details, refer to the Lexicon API docs:

## Development

### Setup

#### Pip

Ensure that you have Python 3.9+ installed locally.
To install all runtime and dev dependencies into a local virtual environment using pip:

```bash
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
```

#### uv

To use [uv](https://docs.astral.sh/uv/) to install all runtime and dev dependencies into a local virtual environment, simply install `uv` and run:

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

The lockfile (`uv.lock`) is checked in to ensure reproducible installs.

### Running Tests

```bash
# Unit tests
pytest
make run-tests

# Integration tests (requires Lexicon running)
# Note: Integration tests enforce an empty library state to avoid destructive edits on existing libraries.
# The fixture setup will back up the existing library, clear it for testing, and restore it afterward.
pytest -m integration
make run-integration-tests
```

### Linting and Formatting

The project uses [ruff](https://docs.astral.sh/ruff/) for both linting and
formatting.

`make test` runs the full suite: format, lint (with auto-fix), then tests.
`make fix` runs all auto-fixers (lint + format) without running tests.

```bash
make test # format-fix → lint-fix → format-check → lint-check → tests
make fix # lint-fix → format-fix
make clean # remove __pycache__, .pytest_cache, .ruff_cache, etc.
```

If you want to run the linters or formatters manually, you can use the following commands:

```bash
make lint-check # check for lint issues
make lint-fix # auto-fix lint issues
make format-check # check formatting
make format-fix # auto-fix formatting
```

### CI

GitHub Actions runs on every push to `main` and on pull requests
targeting those branches. The pipeline includes:

- **Tests** across Python 3.9, 3.10, 3.11, and 3.12
- **Lint and format checks** via ruff on Python 3.12

Before opening a PR, make sure `make test` passes locally.

### Pull Requests

A PR template is provided at `.github/pull_request_template.md`. When opening a
PR, fill in the description, check the relevant change-type boxes, and confirm
testing/checklist items.

## License

MIT (see `LICENSE`).
14 changes: 14 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,16 @@ dependencies = [
"typing_extensions>=4.0"
]

[dependency-groups]
dev = [
"pytest>=7.0",
"pytest-cov>=4.0",
"black>=23.0",
"ruff>=0.1.0",
"mypy>=1.0",
"ipython>=8.12.3",
]

[project.urls]
Homepage = "https://github.com/photonicvelocity/lexicon-python"

Expand All @@ -35,6 +45,10 @@ markers = [
]
addopts = "-m 'not integration'"

[tool.uv]
# Dev dependencies are specified in [dependency-groups]
default-groups = ["dev"]

[tool.pydocstyle]
convention = "numpy"

Expand Down
12 changes: 8 additions & 4 deletions src/lexicon/__init__.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
"""Public package surface for the lexicon Python client."""

from .client import DEFAULT_HOST, LEXICON_PORT, Lexicon
from .resources.tracks_types import * # noqa: F403
from .resources.playlists_types import * # noqa: F403
from .resources.tags_types import * # noqa: F403
from .resources.tag_categories_types import * # noqa: F403
from .resources.playlists_types import PlaylistResponse
from .resources.tag_categories_types import TagCategoryResponse
from .resources.tags_types import TagResponse
from .resources.tracks_types import (
CuePointResponse,
TempoMarkerResponse,
TrackResponse,
)

__all__ = [
"DEFAULT_HOST",
Expand Down
5 changes: 4 additions & 1 deletion src/lexicon/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from .resources.tags import Tags
from .resources.tracks import Tracks
from .tools import playlists as playlist_tools

DEFAULT_HOST = os.environ.get("LEXICON_HOST", "localhost")
LEXICON_PORT = int(os.environ.get("LEXICON_PORT", "48624"))

Expand Down Expand Up @@ -64,7 +65,9 @@ def __init__(

self.tracks: Tracks = Tracks(self)
self.playlists: Playlists = Playlists(self)
self.playlists.tracks = PlaylistTracks(self, tracks=self.tracks, playlists=self.playlists)
self.playlists.tracks = PlaylistTracks(
self, tracks=self.tracks, playlists=self.playlists
)
self.tags: Tags = Tags(self)
self.tags.categories = TagCategories(self)
self.tools = type("Tools", (), {})()
Expand Down
Loading
Loading