Contributing¶
We are glad to welcome any contributor.
Report bugs or propose enhancements through the GitHub issue tracker. The code lives at https://github.com/django-opensearch/django-opensearch-models.
Getting set up¶
The project uses uv. It manages the virtual environment, the interpreter and the lockfile, so there is nothing to create by hand:
$ uv sync --dev
Running the tests¶
Most of the suite runs without a server:
$ uv run python runtests.py
$ uv run python runtests.py tests.test_fields # a single module
The integration tests need a running OpenSearch cluster. Use a throwaway container, never a
development cluster — the tests create, populate and delete indices, and OSTestCase mutates the
global document registry:
$ docker run -d --name dosm-test-os -p 9201:9200 \
-e discovery.type=single-node \
-e DISABLE_INSTALL_DEMO_CONFIG=true \
-e "plugins.security.disabled=true" \
opensearchproject/opensearch:3.8.0
$ export OPENSEARCH_URL=http://127.0.0.1:9201 OPENSEARCH_REQUIRED=1
$ uv run python runtests.py
Important
Set OPENSEARCH_REQUIRED=1. The integration tests are guarded by
unittest.skipUnless(is_os_online()), so without it an unreachable cluster produces a fully green
run that executed zero integration tests.
Run one thing at a time against a cluster. OSTestCase renames indices in the registry during
setUp and strips the suffix in tearDown, so two concurrent runs collide and produce accumulated
suffixes such as car_index_os_test_os_test — failures that look like code bugs and are not.
That also rules out tox run-parallel.
The signal processors¶
There are two, and CI runs both. A change that only passes one is not finished:
$ uv run python runtests.py
$ uv run python runtests.py --signal-processor celery
The full matrix¶
tox drives every supported combination of Python, Django and OpenSearch server:
$ uv run --frozen --no-default-groups --group tox tox run # everything
$ uv run --frozen --no-default-groups --group tox tox run -e py314-dj61
Other environments: lint, build, docs, coverage, and lowest, which installs the declared
dependency floors instead of the lockfile.
Working on the documentation¶
The docs are Sphinx with
MyST Markdown sources, themed with
furo. Every page under docs/source/ is .md; reStructuredText is
not registered as a source suffix, so a .rst file added there is silently ignored.
Live preview¶
The fastest loop. It builds the site, serves it, and rebuilds on every save:
$ uv run --frozen --no-default-groups --group tox tox run -e docs-serve
Then open http://127.0.0.1:8000. The browser reloads itself when a build finishes.
One-off build¶
What CI and Read the Docs run:
$ uv run --frozen --no-default-groups --group tox tox run -e docs
Important
Warnings are errors (-W), here and on Read the Docs. A broken cross-reference, a heading that no
longer matches the anchor pointing at it, or a toctree entry for a file that does not exist all
fail the build rather than quietly degrading the published site. Fix the first warning and rebuild;
--keep-going means the rest are reported in the same run.
Checking links¶
External links are not checked by the normal build. Run the link checker before changing many of them:
$ uv run --frozen --no-default-groups --group tox tox run -e docs-linkcheck
It reports broken for dead links and redirect for ones that have moved. Redirects are not
failures, but a permanent one is worth following in the source.
Code samples are linted¶
ruff format formats Python code blocks inside Markdown, so samples are held to the same style as
the source tree. A sample that is not valid Python fails tox -e lint:
$ uv run --frozen --no-default-groups --group tox tox run -e lint
Write samples that would actually run. If a snippet needs an elision, use ... — it parses.
The README is the single source¶
The project overview, the supported-version table and the end-to-end example live in README.md
between HTML comment markers, and the docs include those regions rather than restating them:
```{include} ../../README.md
:start-after: <!-- overview-start -->
:end-before: <!-- overview-end -->
```
The marker pairs are overview, requirements and example. Sphinx tracks the dependency, so
editing README.md rebuilds the pages that include it — index.md and quickstart.md — and
docs-serve watches it too. Never copy text out of a marked region into a page; change it in the
README and both surfaces follow.
Cross-references¶
Links between pages are ordinary relative Markdown links: [Settings](settings.md), or
[Settings](settings.md#opensearch_autosync) for a heading.
Headings containing backticks or underscores generate anchors that are easy to get wrong. Give
those an explicit target instead and reference it with {ref}:
(post-index-signal)=
## The `post_index` signal
then from any page:
{ref}`post_index <post-index-signal>`
Before you push¶
The documentation must match the API. If your change adds, renames or alters a setting, a Document
hook, a field class, a signal or a search_index flag, update the page that documents it in the
same commit — see the pages listed in the table below.
Page |
Covers |
|---|---|
|
The end-to-end happy path and its common traps. |
|
|
|
Field classes, the Django-field mapping table, relationships, analyzers. |
|
Index objects, alias rebuilds, |
|
One section per setting. |
|
Every |
Known gaps¶
Support for
--using(a second OpenSearch cluster) in the management commands.Management commands for mapping-level operations, such as
update_mapping.Generating
ObjectField/NestedFieldproperties from aDocumentclass.More examples, and better documentation for testing with
OSTestCase.