Skip to content
Open
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
51 changes: 51 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,57 @@ jobs:
- name: Check import produces no warnings
run: python -W error -c "import posthog"

openfeature-provider:
name: OpenFeature provider
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@85e6279cec87321a52edac9c87bce653a07cf6c2
with:
fetch-depth: 1

- name: Set up Python 3.12
uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55
with:
python-version: 3.12

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: The package declares support for Python 3.10 through 3.14 (requires-python plus classifiers in pyproject.toml), but this job only tests on 3.12. mypy targets 3.10, so type errors are caught, but nothing exercises the floor or ceiling at runtime. A 3.10-only incompatibility or a 3.14 behavior change would ship unverified.

The tests and import-check jobs already matrix across all five versions.

        strategy:
            matrix:
                python-version: ['3.10', '3.11', '3.12', '3.13', '3.14']
        steps:
            ...
            - name: Set up Python ${{ matrix.python-version }}
              uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55
              with:
                  python-version: ${{ matrix.python-version }}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree the matrix should mirror the tests/import-check jobs (3.10–3.14). I do not edit .github/workflows/** in this automated review-fix turn (guardrail), so I have left this for a maintainer to apply directly.


- name: Install uv
uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0
with:
enable-cache: true

- name: Install provider dependencies
shell: bash
working-directory: openfeature-provider
run: |
UV_PROJECT_ENVIRONMENT=$pythonLocation uv sync --extra dev

- name: Run provider tests
working-directory: openfeature-provider
run: |
uv run pytest --verbose

- name: Lint and type-check provider
working-directory: openfeature-provider
run: |
uv run ruff format --check .
uv run ruff check .
uv run mypy .

- name: Build and verify provider distribution
working-directory: openfeature-provider
run: |
uv build
uv run --with twine twine check dist/*

- name: Smoke test built wheel in a clean environment
working-directory: openfeature-provider
shell: bash
run: |
uv venv /tmp/of-smoke
uv pip install --python /tmp/of-smoke/bin/python dist/*.whl
/tmp/of-smoke/bin/python -c "from openfeature.contrib.provider.posthog import PostHogProvider; print(PostHogProvider)"

django5-integration:
name: Django 5 integration tests
runs-on: ubuntu-latest
Expand Down
47 changes: 47 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,53 @@ jobs:
env:
GITHUB_TOKEN: ${{ steps.releaser.outputs.token }}

# Publish the `openfeature-provider-posthog` distribution, but only when
# this release actually bumped it (a changeset targeting
# `pypi/openfeature-provider-posthog` was processed by Sampo, changing its
# version in openfeature-provider/pyproject.toml). Releases that only touch
# `posthog` skip these steps entirely, so the core release is unaffected.
# These run after the posthog publish/tag/release above so a provider issue
# can never block the main release.
#
# NOTE: the first provider release requires a PyPI trusted publisher to be
# registered for `openfeature-provider-posthog` (this workflow, environment
# "Release"), exactly like posthog/posthoganalytics.
- name: Detect openfeature-provider release
id: of-provider
if: steps.commit-release.outputs.commit-hash != ''
run: |
if git diff --name-only HEAD~1 HEAD -- openfeature-provider/pyproject.toml | grep -q .; then
version=$(python3 -c "import tomllib; print(tomllib.load(open('openfeature-provider/pyproject.toml','rb'))['project']['version'])")
echo "released=true" >> "$GITHUB_OUTPUT"
echo "version=$version" >> "$GITHUB_OUTPUT"
echo "openfeature-provider-posthog bumped to $version; will publish."
else
echo "released=false" >> "$GITHUB_OUTPUT"
echo "openfeature-provider-posthog not changed in this release; skipping."
fi

- name: Build openfeature-provider-posthog
if: steps.of-provider.outputs.released == 'true'
working-directory: openfeature-provider
run: uv build

- name: Publish openfeature-provider-posthog to PyPI
if: steps.of-provider.outputs.released == 'true'
uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # v1.13.0
with:
packages-dir: openfeature-provider/dist

- name: Tag openfeature-provider release
if: steps.of-provider.outputs.released == 'true'
env:
GH_TOKEN: ${{ steps.releaser.outputs.token }}
PROVIDER_VERSION: ${{ steps.of-provider.outputs.version }}
COMMIT_HASH: ${{ steps.commit-release.outputs.commit-hash }}
run: |
gh api "repos/${{ github.repository }}/git/refs" \
-f "ref=refs/tags/openfeature-provider-posthog-v${PROVIDER_VERSION}" \
-f "sha=${COMMIT_HASH}"

# Notify in case of a failure
- name: Send failure event to PostHog
if: ${{ failure() }}
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ SDK usage examples and code snippets live in the official documentation so they
- [Python library docs](https://posthog.com/docs/libraries/python)
- [Django framework docs](https://posthog.com/docs/libraries/django)
- [Flask framework docs](https://posthog.com/docs/libraries/flask)
- [OpenFeature provider](openfeature-provider/README.md) — use PostHog flags through the [OpenFeature](https://openfeature.dev) Python SDK

## Contributing

Expand Down
2 changes: 1 addition & 1 deletion mypy.ini
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ check_untyped_defs = True
warn_unreachable = True
strict_equality = True
ignore_missing_imports = True
exclude = env/.*|venv/.*|build/.*|examples/example-.*
exclude = env/.*|venv/.*|build/.*|examples/example-.*|openfeature-provider/.*

[mypy-django.*]
ignore_missing_imports = True
Expand Down
5 changes: 5 additions & 0 deletions openfeature-provider/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
*.pyc
__pycache__/
.pytest_cache/
.ruff_cache/
.mypy_cache/
5 changes: 5 additions & 0 deletions openfeature-provider/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Changelog

All notable changes to `openfeature-provider-posthog` are documented here. This
file is maintained by [Sampo](https://github.com/bruits/sampo) from changesets in
`.sampo/changesets/` that target `pypi/openfeature-provider-posthog`.
19 changes: 19 additions & 0 deletions openfeature-provider/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
Copyright (c) 2023 PostHog (part of Hiberly Inc)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
51 changes: 51 additions & 0 deletions openfeature-provider/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# PostHog provider for OpenFeature (Python)

@marandaneto marandaneto Jun 26, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'd move all install/snippets to https://posthog.com/docs/feature-flags and just point to the docs
single source of truth for docs, readme gets outdated

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 8f24613 — slimmed the README to a minimal quickstart and pointed to https://posthog.com/docs/feature-flags as the single source of truth. Kept only the OpenFeature-specific registration snippet + context mapping (not yet on the docs site); those can move there once the provider is documented.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done earlier in 8f24613 — README slimmed to a minimal quickstart pointing at https://posthog.com/docs/feature-flags as the source of truth.


Official [PostHog](https://posthog.com) provider for the
[OpenFeature](https://openfeature.dev) Python SDK. It resolves OpenFeature flag
evaluations through a configured `posthog.Posthog` client.

- **Distribution:** `openfeature-provider-posthog`
- **Import path:** `openfeature.contrib.provider.posthog`
- **License:** MIT

## Documentation

PostHog's feature-flag docs are the single source of truth for flag setup,
concepts, and usage: **https://posthog.com/docs/feature-flags**

## Install

```bash
pip install openfeature-provider-posthog
```

## Quickstart

```python
import posthog
from openfeature import api
from openfeature.evaluation_context import EvaluationContext
from openfeature.contrib.provider.posthog import PostHogProvider

client = posthog.Posthog("phc_project_api_key", host="https://us.i.posthog.com")
api.set_provider(PostHogProvider(client, default_distinct_id="anonymous"))

of_client = api.get_client()
ctx = EvaluationContext(targeting_key="user-123", attributes={"plan": "pro"})
enabled = of_client.get_boolean_value("my-flag", False, ctx)
```

The OpenFeature `targeting_key` maps to PostHog's `distinct_id`; other context
attributes become person properties, with reserved keys `groups` and
`group_properties` mapping to PostHog groups. You own the `Posthog` client
lifecycle — call `client.shutdown()` when done.

## Development

```bash
cd openfeature-provider
uv sync --extra dev
uv run pytest
uv run ruff check .
uv run mypy .
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from openfeature.contrib.provider.posthog.provider import PostHogProvider

__all__ = ["PostHogProvider"]
Loading
Loading