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
94 changes: 76 additions & 18 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,35 +1,93 @@
# Contributing Guide
# Contributing

We welcome all contributions!
## Local setup

## Type checking

We use MyPy for type checking.
Python 3.9+ is supported; CI tests 3.9–3.13. From a cloned checkout:

```bash
make type-check
python3.13 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install -e . -r requirements.txt -r requirements_dev.txt
```

## Tests
Alternatively, use `uv venv --python 3.13 .venv` and `uv pip install` with the
same dependencies. Configure your editor to use `.venv/bin/python`. Unit tests
need no GrowthBook credentials or running server.

## Checks

Run the test suite with
With the virtual environment active, run from the repository root:

```bash
make test
pytest -q
mypy
flake8 . --extend-exclude=.venv --count --select=E9,F63,F7,F82 --show-source --statistics
```

## Linting
For typing changes, also run Pyright with the version pinned in CI:

```bash
npm install -g pyright@1.1.403
pyright
pytest tests/test_typing.py -q
```

Lint the code with flake8
`make test` and `make type-check` wrap pytest and MyPy. `make coverage` produces
an HTML report. `make lint` uses older rules and fails on existing style issues;
the flake8 command above matches CI's blocking check.

## Working on the SDK

- `growthbook/core.py` contains evaluation shared by the sync `GrowthBook`
(`growthbook.py`) and async `GrowthBookClient` (`growthbook_client.py`). Test
both clients, including loading and refresh when payload handling changes.
- Keep library code compatible with Python 3.9 and add type annotations.
Public API changes should include typing regressions in `tests/typing/`.
- Mock external HTTP calls and close clients created in tests. Async tests use
`@pytest.mark.asyncio`; async fixtures use `@pytest_asyncio.fixture`.
- Follow the [JavaScript reference SDK](https://github.com/growthbook/growthbook/tree/main/packages/sdk-js)
for evaluation behavior. Preserve Python-local cases when syncing
`tests/cases.json` with the shared corpus.

For evaluation or corpus changes, check parity with JS `main` (requires network):

```bash
make lint
python tests/scripts/check_corpus_freshness.py
```

## Releasing
Use `--js-source /path/to/cases.json` for a local reference. Missing or changed
shared cases fail unless listed with a reason in `tests/scripts/corpus_skiplist.json`.

For performance changes, compare both checkouts using the same interpreter and
machine. Benchmark commands and integration checks are in
[tests/scripts/README.md](tests/scripts/README.md).

## Pull requests

Discuss public API changes in an issue first. Branch from `main`, include
regression tests and relevant usage docs, and run the checks above. Describe
behavior changes, compatibility concerns, and validation in the PR.

Use conventional commit subjects (`feat:`, `fix:`, etc.); Release Please uses
them to determine versions and changelog entries. Keep the merge or squash
subject consistent with the change.

## Releases

The [Release Please workflow](.github/workflows/release-please.yml) creates a
release PR after changes reach `main`. Merging that PR creates the tag and
GitHub release, then tests, builds, and publishes the package to PyPI.

`setup.py` reads the version from `growthbook/__init__.py`. Contributors normally
leave version and changelog updates to Release Please. The legacy `make release`
command uploads directly to PyPI; it is not a verification command.

## Help

- [SDK docs](https://docs.growthbook.io/lib/python)
- [Issues](https://github.com/growthbook/growthbook-python/issues)
- [Slack](https://slack.growthbook.io?ref=contributing)

1. Bump the version in `setup.cfg` and `setup.py`
2. Merge code to `main`
3. Create a new release on GitHub with your version as the tag (e.g. `v0.2.0`)
4. Run `make dist` to create a distribution file
5. Run `make release` to upload to pypi
Report vulnerabilities to security@growthbook.io. Follow the
[Code of Conduct](https://github.com/growthbook/growthbook/blob/main/CODE_OF_CONDUCT.md).
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,31 @@ gb = GrowthBook(

Note: When doing this, you do not need to specify your `api_host` or `client_key` and you don't need to call `gb.load_features()`.

### Saved group references

Both `GrowthBook` and `GrowthBookClient` support `savedGroupReferencesV2` for
local evaluation. The `savedGroups` payload map can contain legacy ID arrays
or typed entries:

```json
{
"savedGroups": {
"beta": {"type": "list", "attributeKey": "id", "values": ["u1", "u2"]},
"power": {"type": "condition", "condition": {"plan": "pro"}}
}
}
```

A rule references either type with `{"$savedGroup": {"id": "beta"}}`. List
references can override `attributeKey`; condition groups can reference other
groups, with cycle detection. Legacy `$inGroup` and `$notInGroup` also accept
typed list entries.

When loading a payload yourself, use `gb.set_payload(payload)` or
`await client.set_payload(payload)` to load both features and saved groups.
Receiving v2 payloads requires a registered SDK version with this capability
and **All Saved Groups** under the SDK Connection's **Pass Saved Groups by reference**.

## GrowthBook class

The GrowthBook constructor has the following parameters:
Expand Down
Loading
Loading