Metadata-Version: 2.4
Name: jetpack-launcher-py
Version: 0.1.0
Summary: Jetset launcher for Python services — OpenTelemetry + typed config with local/k8s parity
Project-URL: Homepage, https://github.com/getjetpack/jetpack-launcher-py
Project-URL: Issues, https://github.com/getjetpack/jetpack-launcher-py/issues
Author-email: Jetset <hello@getjetpack.cloud>
License: Apache-2.0
License-File: LICENSE
License-File: NOTICE
Keywords: jetset,kubernetes,observability,opentelemetry
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: System :: Monitoring
Requires-Python: >=3.10
Requires-Dist: opentelemetry-api>=1.27
Requires-Dist: opentelemetry-exporter-otlp-proto-grpc>=1.27
Requires-Dist: opentelemetry-exporter-otlp-proto-http>=1.27
Requires-Dist: opentelemetry-sdk>=1.27
Requires-Dist: opentelemetry-semantic-conventions>=0.48b0
Requires-Dist: pydantic-settings>=2.2
Requires-Dist: pydantic>=2.6
Requires-Dist: python-dotenv>=1.0
Provides-Extra: dev
Requires-Dist: mypy>=1.10; extra == 'dev'
Requires-Dist: ruff>=0.4; extra == 'dev'
Provides-Extra: test
Requires-Dist: pytest-cov>=4.1; extra == 'test'
Requires-Dist: pytest>=8.0; extra == 'test'
Description-Content-Type: text/markdown

# jetpack-launcher-py

[![CI](https://github.com/getjetpack/jetpack-launcher-py/actions/workflows/ci.yml/badge.svg)](https://github.com/getjetpack/jetpack-launcher-py/actions/workflows/ci.yml)
[![PyPI](https://img.shields.io/pypi/v/jetpack-launcher-py.svg)](https://pypi.org/project/jetpack-launcher-py/)
[![Python](https://img.shields.io/pypi/pyversions/jetpack-launcher-py.svg)](https://pypi.org/project/jetpack-launcher-py/)
[![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE)

One-line launcher for Python services on the Jetset platform. Wires
OpenTelemetry (traces + metrics + logs), typed configuration, structured
logging, and graceful shutdown — with the **same code path locally and in
Kubernetes**.

```bash
pip install jetpack-launcher-py
```

```python
from jetpack import init_jetpack

init_jetpack()
```

That's it. Whatever framework you're using, whatever cloud you're on,
whatever backend the platform team picked — the service code never has to
know.

## What it does at v0.1

- Detects runtime: local (laptop, docker) vs Kubernetes
- Loads `.env.local` and `.env.local-{flavor}` when running locally
- In k8s, reads env vars populated by ConfigMap + ExternalSecret — no
  filesystem reads
- Validates a typed `Config` (Pydantic) and fails fast on missing keys
- Builds an OpenTelemetry `Resource` with `service.*`, `deployment.*`, and
  `k8s.*` attributes
- Initializes Tracer / Meter / Logger providers with OTLP exporters
- Bridges stdlib `logging` to structured JSON + OTel Logs with
  `trace_id` / `span_id` auto-injection
- Registers SIGTERM + atexit handlers that flush telemetry before exit

## The env model — one mental model, two backends

```
LOCAL                              KUBERNETES
────────────────                   ───────────────────────────
.env.local            ←─ optional   ConfigMap (literals + ${param:…})
.env.local-{flavor}   ←─ optional   ExternalSecret (${secret:…})
        │                                   │
        ▼                                   ▼
                       os.environ
                            │
                            ▼
                    Config(BaseSettings)
                            │
                            ▼
                     your service code
```

The service reads `Config`. The launcher decides where the values came from.

### Detection rules

1. `JETPACK_RUNTIME=local|k8s` overrides everything
2. `KUBERNETES_SERVICE_HOST` set → k8s (set by kubelet)
3. otherwise → local

### Local env files (gitignored)

- `.env.local` — universal local overrides (often committed if it contains
  only non-secret defaults; otherwise gitignored)
- `.env.local-{flavor}` — flavor-specific, picked by `JETPACK_ENV` (default
  `dev`). Always gitignored.

```bash
JETPACK_ENV=dev  python -m src.main    # loads .env.local + .env.local-dev
JETPACK_ENV=prod python -m src.main    # loads .env.local + .env.local-prod
```

In k8s, `.env.local*` files are never read — the deployment supplies env
vars via `envFrom: [configMapRef, secretRef]` and the launcher detects k8s.

## Quick start

```bash
pip install jetpack-launcher-py
```

```python
# src/configs/loader.py — your service's typed config
from jetpack import JetpackConfig

class Config(JetpackConfig):
    DB_HOST: str | None = None
    DB_PORT: int | None = None
    # add more — Pydantic validates at startup
```

```python
# src/main.py
from jetpack import init_jetpack, get_tracer
from src.configs import Config

handle = init_jetpack(config_class=Config)
tracer = get_tracer(__name__)

with tracer.start_as_current_span("startup"):
    ...  # your service main loop
```

## Public API (stable)

```python
from jetpack import (
    init_jetpack,    # the one entry point
    JetpackConfig,   # base Config class — subclass for your service
    JetpackHandle,   # what init_jetpack returns
    Runtime,         # enum: LOCAL | K8S
    RuntimeInfo,     # detection result
    get_tracer,      # opentelemetry.trace.get_tracer
    get_meter,       # opentelemetry.metrics.get_meter
)
```

## Roadmap

- v0.2 — Flask & FastAPI adapters; resource detectors for ECS / GKE /
  Cloud Run
- v0.3 — Secret resolver plugin; PII redaction policy; `--dry-run` mode
- v0.4 — OpenFeature feature flag bootstrap
- v0.5 — HTTP client factory + JWT auth plugin
- v0.6 — AI cost / token tracking for OpenAI, Anthropic

See [CHANGELOG.md](CHANGELOG.md) for shipped releases.

## Contributing

See [CONTRIBUTING.md](CONTRIBUTING.md). Security reports go to
**security@getjetpack.cloud** — see [SECURITY.md](SECURITY.md).

## Releasing (maintainers only)

Releases are automated via GitHub Actions and PyPI Trusted Publishing:

1. Bump `version` in `pyproject.toml` and add a `## [x.y.z]` section in
   `CHANGELOG.md` describing the changes.
2. Commit and merge to `main`.
3. Tag and push:
   ```bash
   git tag v0.1.0
   git push origin v0.1.0
   ```
4. The `release.yml` workflow builds the distribution, publishes to
   TestPyPI for sanity-check, then publishes to PyPI and cuts a GitHub
   Release with auto-generated notes.

The first release requires a maintainer to configure PyPI Trusted
Publishing on both [pypi.org](https://pypi.org/manage/account/publishing/)
and [test.pypi.org](https://test.pypi.org/manage/account/publishing/)
pointing at this repo / `release.yml` / environments `pypi` and `testpypi`.

## License

Licensed under the **Apache License, Version 2.0** — see [LICENSE](LICENSE)
and [NOTICE](NOTICE). All contributions are accepted under the same terms.

Copyright © 2026 Jetset.
