diff --git a/.sampo/changesets/ardent-earl-tuoni.md b/.sampo/changesets/ardent-earl-tuoni.md new file mode 100644 index 00000000..6c5929b7 --- /dev/null +++ b/.sampo/changesets/ardent-earl-tuoni.md @@ -0,0 +1,5 @@ +--- +pypi/posthog: patch +--- + +Fix internal imports for posthoganalytics mirror diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..8a53f11d --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,50 @@ +# AGENTS.md + +Guidance for coding agents working in `posthog-python`. + +## Repo context + +- This repository contains the PostHog Python SDK, published as `posthog`. +- The main runtime package is `posthog/`; tests live under `posthog/test/`. +- The project uses `uv` for local development. See `CONTRIBUTING.md` for setup. +- Keep edits targeted and follow existing patterns. Prefer adding or updating tests near the behavior you change. + +## Validation + +Useful checks: + +```bash +uv run ruff format --check . +uv run ruff check . +uv run mypy --no-site-packages --config-file mypy.ini . | uv run mypy-baseline filter +uv run pytest --verbose --timeout=30 +uv run python -W error -c "import posthog" +``` + +For focused changes, run the smallest relevant `uv run pytest ...` command first. + +If public API surface changes, update/check `references/public_api_snapshot.txt` with: + +```bash +make public_api_snapshot +make public_api_check +``` + +## `posthoganalytics` mirror package + +This repo also publishes `posthoganalytics`, a generated mirror of `posthog` used by the PostHog app. The mirror is created by copying `posthog/` to `posthoganalytics/` and rewriting absolute imports such as `from posthog.foo import ...` to `from posthoganalytics.foo import ...`. + +Important when editing SDK-internal code: + +- Prefer relative imports for imports within the SDK package, especially in runtime modules under `posthog/`. + - Good: `from .client import Client`, `from .exception_utils import extract_exception_properties` + - Risky: `from posthog.client import Client` +- Absolute `posthog...` imports inside SDK modules can break the `posthoganalytics` mirror when it is imported inside an application that also has its own `posthog` package/module on `sys.path`. +- Test mirror-sensitive changes by running the normal focused tests and, when relevant, `make prep_local` to generate a local `posthoganalytics` copy for testing in the PostHog app. +- Do not commit generated `posthoganalytics/` directories; they are build/local artifacts. + +## Release/build notes + +- `make build_release` builds the `posthog` distribution. +- `make build_release_analytics` builds the `posthoganalytics` distribution and temporarily rewrites/copies package files; ensure the working tree is clean before and after running it. +- Release flow publishes both packages; see `RELEASING.md`. diff --git a/posthog/contexts.py b/posthog/contexts.py index bb643b1f..a5ccae37 100644 --- a/posthog/contexts.py +++ b/posthog/contexts.py @@ -138,15 +138,14 @@ def _default_capture_exceptions(client: Optional["Client"] = None) -> bool: if client is not None: return client.enable_exception_autocapture - import posthog + from . import default_client, enable_exception_autocapture - default_client = getattr(posthog, "default_client", None) if default_client is not None: client_default = getattr(default_client, "enable_exception_autocapture", None) if isinstance(client_default, bool): return client_default - return posthog.enable_exception_autocapture + return enable_exception_autocapture @contextmanager @@ -197,7 +196,7 @@ def new_context( Category: Contexts """ - from posthog import capture_exception + from . import capture_exception current_context = _get_current_context() resolved_capture_exceptions = ( diff --git a/posthog/integrations/celery.py b/posthog/integrations/celery.py index e81600e0..0dde6c34 100644 --- a/posthog/integrations/celery.py +++ b/posthog/integrations/celery.py @@ -69,8 +69,8 @@ import time from typing import Any, Callable, Optional -from posthog import contexts -from posthog.client import Client +from .. import contexts +from ..client import Client CONTEXT_DISTINCT_ID_HEADER = "X-POSTHOG-DISTINCT-ID" @@ -198,9 +198,9 @@ def shutdown(self) -> None: if self.client: self.client.flush() else: - import posthog + from .. import flush - posthog.flush() + flush() self.uninstrument() self._shut_down = True diff --git a/posthog/integrations/django.py b/posthog/integrations/django.py index 98dc8faa..37cc7210 100644 --- a/posthog/integrations/django.py +++ b/posthog/integrations/django.py @@ -1,8 +1,8 @@ import re from typing import TYPE_CHECKING, Optional, cast -from posthog import contexts -from posthog.client import Client +from .. import contexts +from ..client import Client try: from asgiref.sync import iscoroutinefunction, markcoroutinefunction