pyrock-core 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pyrock_core-0.1.0/.gitignore +37 -0
- pyrock_core-0.1.0/CHANGELOG.md +113 -0
- pyrock_core-0.1.0/CONTRIBUTING.md +143 -0
- pyrock_core-0.1.0/DESIGN.md +1427 -0
- pyrock_core-0.1.0/LICENSE +21 -0
- pyrock_core-0.1.0/PKG-INFO +858 -0
- pyrock_core-0.1.0/README.md +828 -0
- pyrock_core-0.1.0/SECURITY.md +55 -0
- pyrock_core-0.1.0/examples/asgi_app.py +129 -0
- pyrock_core-0.1.0/examples/http_server.py +85 -0
- pyrock_core-0.1.0/examples/recipes/django_middleware.py +60 -0
- pyrock_core-0.1.0/examples/recipes/fastapi_app.py +61 -0
- pyrock_core-0.1.0/examples/recipes/flask_route.py +44 -0
- pyrock_core-0.1.0/examples/recipes/grpc_interceptors.py +114 -0
- pyrock_core-0.1.0/examples/recipes/httpx_hooks.py +43 -0
- pyrock_core-0.1.0/examples/recipes/requests_adapter.py +44 -0
- pyrock_core-0.1.0/examples/worker.py +68 -0
- pyrock_core-0.1.0/pyproject.toml +186 -0
- pyrock_core-0.1.0/scripts/tests/conftest.py +10 -0
- pyrock_core-0.1.0/scripts/tests/test_release.py +133 -0
- pyrock_core-0.1.0/scripts/tests/test_test_report.py +300 -0
- pyrock_core-0.1.0/src/pyrock/__init__.py +141 -0
- pyrock_core-0.1.0/src/pyrock/_bedrock.py +1147 -0
- pyrock_core-0.1.0/src/pyrock/_cloud.py +504 -0
- pyrock_core-0.1.0/src/pyrock/_compat.py +129 -0
- pyrock_core-0.1.0/src/pyrock/_context.py +171 -0
- pyrock_core-0.1.0/src/pyrock/_envdetect.py +412 -0
- pyrock_core-0.1.0/src/pyrock/_httpcore.py +268 -0
- pyrock_core-0.1.0/src/pyrock/_noop.py +98 -0
- pyrock_core-0.1.0/src/pyrock/_operation.py +1360 -0
- pyrock_core-0.1.0/src/pyrock/_push.py +254 -0
- pyrock_core-0.1.0/src/pyrock/_transport.py +77 -0
- pyrock_core-0.1.0/src/pyrock/_types.py +35 -0
- pyrock_core-0.1.0/src/pyrock/_version.py +10 -0
- pyrock_core-0.1.0/src/pyrock/asgi.py +269 -0
- pyrock_core-0.1.0/src/pyrock/attr.py +482 -0
- pyrock_core-0.1.0/src/pyrock/config.py +310 -0
- pyrock_core-0.1.0/src/pyrock/env.py +300 -0
- pyrock_core-0.1.0/src/pyrock/http.py +504 -0
- pyrock_core-0.1.0/src/pyrock/logs.py +669 -0
- pyrock_core-0.1.0/src/pyrock/metric/__init__.py +856 -0
- pyrock_core-0.1.0/src/pyrock/metric/prometheus.py +216 -0
- pyrock_core-0.1.0/src/pyrock/metric/runtime.py +358 -0
- pyrock_core-0.1.0/src/pyrock/privacy.py +582 -0
- pyrock_core-0.1.0/src/pyrock/profile/__init__.py +58 -0
- pyrock_core-0.1.0/src/pyrock/profile/_config.py +164 -0
- pyrock_core-0.1.0/src/pyrock/profile/_export.py +279 -0
- pyrock_core-0.1.0/src/pyrock/profile/_frames.py +91 -0
- pyrock_core-0.1.0/src/pyrock/profile/_heap.py +261 -0
- pyrock_core-0.1.0/src/pyrock/profile/_locks.py +337 -0
- pyrock_core-0.1.0/src/pyrock/profile/_otlp.py +270 -0
- pyrock_core-0.1.0/src/pyrock/profile/_pprof.py +208 -0
- pyrock_core-0.1.0/src/pyrock/profile/_sampler.py +345 -0
- pyrock_core-0.1.0/src/pyrock/profile/_stacks.py +85 -0
- pyrock_core-0.1.0/src/pyrock/profile/debug.py +149 -0
- pyrock_core-0.1.0/src/pyrock/py.typed +0 -0
- pyrock_core-0.1.0/src/pyrock/server.py +824 -0
- pyrock_core-0.1.0/src/pyrock/testing.py +397 -0
- pyrock_core-0.1.0/src/pyrock/trace/__init__.py +704 -0
- pyrock_core-0.1.0/src/pyrock/trace/http.py +155 -0
- pyrock_core-0.1.0/src/pyrock/trace/otlp/__init__.py +21 -0
- pyrock_core-0.1.0/src/pyrock/trace/otlp/_h2.py +1078 -0
- pyrock_core-0.1.0/src/pyrock/trace/otlp/_pb.py +308 -0
- pyrock_core-0.1.0/src/pyrock/trace/otlp/batch.py +272 -0
- pyrock_core-0.1.0/src/pyrock/trace/otlp/grpc.py +398 -0
- pyrock_core-0.1.0/src/pyrock/trace/otlp/http.py +228 -0
- pyrock_core-0.1.0/src/pyrock/trace/propagator.py +50 -0
- pyrock_core-0.1.0/src/pyrock/trace/sampler.py +156 -0
- pyrock_core-0.1.0/src/pyrock/trace/w3c.py +147 -0
- pyrock_core-0.1.0/src/pyrock/wsgi.py +247 -0
- pyrock_core-0.1.0/tests/__init__.py +0 -0
- pyrock_core-0.1.0/tests/conftest.py +103 -0
- pyrock_core-0.1.0/tests/e2e/__init__.py +1 -0
- pyrock_core-0.1.0/tests/e2e/_core_helpers.py +68 -0
- pyrock_core-0.1.0/tests/e2e/_export_helpers.py +130 -0
- pyrock_core-0.1.0/tests/e2e/_http_helpers.py +664 -0
- pyrock_core-0.1.0/tests/e2e/test_asgi.py +319 -0
- pyrock_core-0.1.0/tests/e2e/test_client.py +422 -0
- pyrock_core-0.1.0/tests/e2e/test_cloud.py +453 -0
- pyrock_core-0.1.0/tests/e2e/test_config_env.py +565 -0
- pyrock_core-0.1.0/tests/e2e/test_context.py +324 -0
- pyrock_core-0.1.0/tests/e2e/test_envdetect.py +231 -0
- pyrock_core-0.1.0/tests/e2e/test_fork.py +190 -0
- pyrock_core-0.1.0/tests/e2e/test_http_hardening.py +335 -0
- pyrock_core-0.1.0/tests/e2e/test_lifecycle.py +360 -0
- pyrock_core-0.1.0/tests/e2e/test_logging.py +425 -0
- pyrock_core-0.1.0/tests/e2e/test_metrics.py +535 -0
- pyrock_core-0.1.0/tests/e2e/test_noop.py +296 -0
- pyrock_core-0.1.0/tests/e2e/test_operations.py +804 -0
- pyrock_core-0.1.0/tests/e2e/test_privacy.py +475 -0
- pyrock_core-0.1.0/tests/e2e/test_profiles.py +504 -0
- pyrock_core-0.1.0/tests/e2e/test_propagation.py +475 -0
- pyrock_core-0.1.0/tests/e2e/test_server.py +434 -0
- pyrock_core-0.1.0/tests/e2e/test_steps_sources.py +315 -0
- pyrock_core-0.1.0/tests/e2e/test_trace_export.py +488 -0
- pyrock_core-0.1.0/tests/e2e/test_wsgi.py +290 -0
- pyrock_core-0.1.0/tests/structure/__init__.py +0 -0
- pyrock_core-0.1.0/tests/structure/test_import_cost.py +72 -0
- pyrock_core-0.1.0/tests/structure/test_structure.py +303 -0
- pyrock_core-0.1.0/tests/support/README.md +173 -0
- pyrock_core-0.1.0/tests/support/__init__.py +0 -0
- pyrock_core-0.1.0/tests/support/asgi_driver.py +295 -0
- pyrock_core-0.1.0/tests/support/collectors.py +606 -0
- pyrock_core-0.1.0/tests/support/logs.py +107 -0
- pyrock_core-0.1.0/tests/support/otlp_decode.py +181 -0
- pyrock_core-0.1.0/tests/support/prom.py +153 -0
- pyrock_core-0.1.0/tests/support/test_support.py +552 -0
- pyrock_core-0.1.0/tests/support/wsgi_driver.py +190 -0
- pyrock_core-0.1.0/tests/unit/__init__.py +0 -0
- pyrock_core-0.1.0/tests/unit/attr/__init__.py +0 -0
- pyrock_core-0.1.0/tests/unit/attr/test_attrs_event.py +194 -0
- pyrock_core-0.1.0/tests/unit/attr/test_errors.py +422 -0
- pyrock_core-0.1.0/tests/unit/attr/test_values.py +281 -0
- pyrock_core-0.1.0/tests/unit/cloud/__init__.py +0 -0
- pyrock_core-0.1.0/tests/unit/cloud/test_cloud_components.py +348 -0
- pyrock_core-0.1.0/tests/unit/cloud/test_review_fixes.py +224 -0
- pyrock_core-0.1.0/tests/unit/config/__init__.py +0 -0
- pyrock_core-0.1.0/tests/unit/config/test_config.py +391 -0
- pyrock_core-0.1.0/tests/unit/config/test_from_env.py +202 -0
- pyrock_core-0.1.0/tests/unit/core/__init__.py +0 -0
- pyrock_core-0.1.0/tests/unit/core/test_review_fixes.py +288 -0
- pyrock_core-0.1.0/tests/unit/env/__init__.py +0 -0
- pyrock_core-0.1.0/tests/unit/env/test_helpers.py +176 -0
- pyrock_core-0.1.0/tests/unit/env/test_parse.py +441 -0
- pyrock_core-0.1.0/tests/unit/logs/__init__.py +1 -0
- pyrock_core-0.1.0/tests/unit/logs/_helpers.py +105 -0
- pyrock_core-0.1.0/tests/unit/logs/test_canonical.py +146 -0
- pyrock_core-0.1.0/tests/unit/logs/test_handler.py +182 -0
- pyrock_core-0.1.0/tests/unit/logs/test_install.py +177 -0
- pyrock_core-0.1.0/tests/unit/logs/test_json_formatter.py +429 -0
- pyrock_core-0.1.0/tests/unit/logs/test_levels.py +46 -0
- pyrock_core-0.1.0/tests/unit/logs/test_text_formatter.py +79 -0
- pyrock_core-0.1.0/tests/unit/metric/__init__.py +1 -0
- pyrock_core-0.1.0/tests/unit/metric/_helpers.py +34 -0
- pyrock_core-0.1.0/tests/unit/metric/test_concurrency.py +183 -0
- pyrock_core-0.1.0/tests/unit/metric/test_prometheus.py +376 -0
- pyrock_core-0.1.0/tests/unit/metric/test_registry.py +452 -0
- pyrock_core-0.1.0/tests/unit/metric/test_runtime.py +404 -0
- pyrock_core-0.1.0/tests/unit/metric/test_types.py +349 -0
- pyrock_core-0.1.0/tests/unit/perf/__init__.py +0 -0
- pyrock_core-0.1.0/tests/unit/perf/test_policy_fast_path.py +210 -0
- pyrock_core-0.1.0/tests/unit/perf/test_span_finish.py +188 -0
- pyrock_core-0.1.0/tests/unit/privacy/__init__.py +0 -0
- pyrock_core-0.1.0/tests/unit/privacy/_helpers.py +68 -0
- pyrock_core-0.1.0/tests/unit/privacy/test_apply.py +492 -0
- pyrock_core-0.1.0/tests/unit/privacy/test_policy_type.py +111 -0
- pyrock_core-0.1.0/tests/unit/privacy/test_surfaces.py +270 -0
- pyrock_core-0.1.0/tests/unit/privacy/test_walker.py +355 -0
- pyrock_core-0.1.0/tests/unit/profile/__init__.py +1 -0
- pyrock_core-0.1.0/tests/unit/profile/_helpers.py +105 -0
- pyrock_core-0.1.0/tests/unit/profile/_proto.py +456 -0
- pyrock_core-0.1.0/tests/unit/profile/conftest.py +50 -0
- pyrock_core-0.1.0/tests/unit/profile/test_debug.py +154 -0
- pyrock_core-0.1.0/tests/unit/profile/test_export.py +507 -0
- pyrock_core-0.1.0/tests/unit/profile/test_fork_reset.py +282 -0
- pyrock_core-0.1.0/tests/unit/profile/test_heap.py +195 -0
- pyrock_core-0.1.0/tests/unit/profile/test_locks.py +479 -0
- pyrock_core-0.1.0/tests/unit/profile/test_otlp.py +299 -0
- pyrock_core-0.1.0/tests/unit/profile/test_pprof.py +209 -0
- pyrock_core-0.1.0/tests/unit/profile/test_sampler.py +440 -0
- pyrock_core-0.1.0/tests/unit/profile/test_stacks.py +164 -0
- pyrock_core-0.1.0/tests/unit/server/__init__.py +1 -0
- pyrock_core-0.1.0/tests/unit/server/test_apps.py +117 -0
- pyrock_core-0.1.0/tests/unit/server/test_config.py +107 -0
- pyrock_core-0.1.0/tests/unit/server/test_read_head.py +176 -0
- pyrock_core-0.1.0/tests/unit/server/test_review_fixes.py +211 -0
- pyrock_core-0.1.0/tests/unit/server/test_server.py +627 -0
- pyrock_core-0.1.0/tests/unit/trace/__init__.py +0 -0
- pyrock_core-0.1.0/tests/unit/trace/test_propagators.py +332 -0
- pyrock_core-0.1.0/tests/unit/trace/test_sampler.py +233 -0
- pyrock_core-0.1.0/tests/unit/trace/test_span_context.py +234 -0
- pyrock_core-0.1.0/tests/unit/trace/test_span_tracer.py +561 -0
- pyrock_core-0.1.0/tests/unit/trace/test_w3c.py +367 -0
- pyrock_core-0.1.0/tests/unit/trace_otlp/__init__.py +0 -0
- pyrock_core-0.1.0/tests/unit/trace_otlp/_h2server.py +609 -0
- pyrock_core-0.1.0/tests/unit/trace_otlp/_pbref.py +110 -0
- pyrock_core-0.1.0/tests/unit/trace_otlp/test_batch.py +541 -0
- pyrock_core-0.1.0/tests/unit/trace_otlp/test_batch_logging.py +154 -0
- pyrock_core-0.1.0/tests/unit/trace_otlp/test_grpc_exporter.py +375 -0
- pyrock_core-0.1.0/tests/unit/trace_otlp/test_h2_connection.py +452 -0
- pyrock_core-0.1.0/tests/unit/trace_otlp/test_h2_frames.py +315 -0
- pyrock_core-0.1.0/tests/unit/trace_otlp/test_hpack.py +555 -0
- pyrock_core-0.1.0/tests/unit/trace_otlp/test_http_exporter.py +395 -0
- pyrock_core-0.1.0/tests/unit/trace_otlp/test_parse_target.py +214 -0
- pyrock_core-0.1.0/tests/unit/trace_otlp/test_pb.py +472 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.so
|
|
5
|
+
*.egg-info/
|
|
6
|
+
.eggs/
|
|
7
|
+
build/
|
|
8
|
+
dist/
|
|
9
|
+
wheels/
|
|
10
|
+
|
|
11
|
+
# Environments and tools
|
|
12
|
+
.venv/
|
|
13
|
+
venv/
|
|
14
|
+
.python-version
|
|
15
|
+
.uv/
|
|
16
|
+
.mypy_cache/
|
|
17
|
+
.ruff_cache/
|
|
18
|
+
.pytest_cache/
|
|
19
|
+
.hypothesis/
|
|
20
|
+
.dmypy.json
|
|
21
|
+
|
|
22
|
+
# Coverage
|
|
23
|
+
.coverage
|
|
24
|
+
.coverage.*
|
|
25
|
+
coverage.xml
|
|
26
|
+
htmlcov/
|
|
27
|
+
|
|
28
|
+
# Profiles and editors
|
|
29
|
+
*.prof
|
|
30
|
+
*.pprof
|
|
31
|
+
.idea/
|
|
32
|
+
.vscode/
|
|
33
|
+
.DS_Store
|
|
34
|
+
|
|
35
|
+
# Profiler output
|
|
36
|
+
*.prof
|
|
37
|
+
prof.out
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
Notable changes to pyrock are recorded here. The format follows
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and releases use
|
|
5
|
+
[Semantic Versioning](https://semver.org/spec/v2.0.0.html). Because pyrock is
|
|
6
|
+
pre-1.0, minor releases may include intentional API or behavior changes; each
|
|
7
|
+
one is listed with a migration note.
|
|
8
|
+
|
|
9
|
+
## Unreleased
|
|
10
|
+
|
|
11
|
+
No changes yet.
|
|
12
|
+
|
|
13
|
+
## [0.1.0] - 2026-11-08
|
|
14
|
+
|
|
15
|
+
The initial release: a zero-dependency Python port of
|
|
16
|
+
[Bedrock](https://github.com/kzs0/bedrock) for CPython 3.11+, including the
|
|
17
|
+
free-threaded build.
|
|
18
|
+
|
|
19
|
+
Published on PyPI as `pyrock-core` (`pip install pyrock-core`); the import
|
|
20
|
+
package is `pyrock`. The name `pyrock` is taken on PyPI.
|
|
21
|
+
|
|
22
|
+
### Added
|
|
23
|
+
|
|
24
|
+
- Core API: `pyrock.init()`, `pyrock.Bedrock`, and `operation`, `step` and
|
|
25
|
+
`source` as sync/async context managers and as decorators for functions,
|
|
26
|
+
coroutines, generators and async generators. Also `start_operation` for a
|
|
27
|
+
manual lifecycle, `register`, `current`, `current_operation`,
|
|
28
|
+
`current_span` and `current_span_context`.
|
|
29
|
+
- Operation metrics with the same names as Go (`<name>_count`, `_successes`,
|
|
30
|
+
`_failures`, `_duration_ms`), labels declared up front with a `"_"` default,
|
|
31
|
+
static labels, and series and family limits.
|
|
32
|
+
- Success by default: an escaping exception marks failure and is re-raised;
|
|
33
|
+
`expected=` exceptions do not. Error attributes (`error`, `error.type`,
|
|
34
|
+
`error.fingerprint`, `error.chain`, `error.group.count`, `error.types`) come
|
|
35
|
+
from `attr.error`.
|
|
36
|
+
- `no_trace`, numbered duplicate span names, and preallocated noop objects
|
|
37
|
+
when nothing is active.
|
|
38
|
+
- Context helpers for threads: `bind`, `ContextThreadPoolExecutor` and
|
|
39
|
+
`pyrock.Thread` (with `context=`).
|
|
40
|
+
- Tracing: `Tracer`/`Span`/`SpanContext`, W3C Trace Context (`trace.w3c`), an
|
|
41
|
+
HTTP propagator, a `Propagator` protocol with `CompositePropagator`, and the
|
|
42
|
+
`AlwaysOn`, `AlwaysOff`, `Ratio` and `ParentBased` samplers.
|
|
43
|
+
- OTLP trace export over HTTP/JSON (`urllib`) and gRPC, through a minimal
|
|
44
|
+
in-house HTTP/2 client (TLS with ALPN or h2c) and a hand-written protobuf
|
|
45
|
+
encoder; a bounded batch processor with export statistics.
|
|
46
|
+
- Metrics: a thread-safe registry of counters, gauges and histograms with
|
|
47
|
+
`.labels()`, histogram timers, runtime metrics (`python_*`, `process_*`), and
|
|
48
|
+
validated Prometheus text exposition.
|
|
49
|
+
- Logging on stdlib `logging`: a JSON or text handler, `CorrelationFilter`,
|
|
50
|
+
the `debug`/`info`/`warning`/`warn`/`error`/`log` helpers, canonical
|
|
51
|
+
`operation.complete` records, and `log_install` modes (`root`, `pyrock`,
|
|
52
|
+
`none`).
|
|
53
|
+
- HTTP: WSGI and ASGI 3 middleware (opt-in websocket operations), stdlib
|
|
54
|
+
`http.server` instrumentation (`http.instrument_http_server`), and an
|
|
55
|
+
instrumented `urllib` client (`http.get`/`post`/`request`, `build_opener`,
|
|
56
|
+
`TracingHandler`) plus `inject_headers` for third-party clients.
|
|
57
|
+
- The observability server (`/metrics`, `/health`, `/ready`, optional
|
|
58
|
+
`/debug/pprof/*`) with Go's security defaults and a connection cap.
|
|
59
|
+
- Profiles: CPU, WALL, HEAP, THREADS (`GOROUTINE`), MUTEX and BLOCK, encoded
|
|
60
|
+
as OTLP Profiles (v0.2.0) and pprof, exported over HTTP
|
|
61
|
+
(`ProfileExportConfig`) and served by the optional `profile.debug` handler,
|
|
62
|
+
which works with `go tool pprof`. Instrumented `Lock`, `RLock`, `Condition`
|
|
63
|
+
and `Semaphore` feed MUTEX and BLOCK.
|
|
64
|
+
- The cloud backend (`pyrock.cloud`, `CloudConfig`): gRPC traces with
|
|
65
|
+
`x-bedrock-key`, retry with configurable `retry_backoff`, fan-out to a local
|
|
66
|
+
`trace_url`, metrics push and profile push.
|
|
67
|
+
- `privacy.Policy` enforced on spans, events, logs, metric labels and profile
|
|
68
|
+
labels.
|
|
69
|
+
- Environment detection (process, git, Kubernetes, container, AWS, GCP) under
|
|
70
|
+
a 500 ms budget.
|
|
71
|
+
- `Config` with `BEDROCK_*` environment variables in Go's syntax, plus the
|
|
72
|
+
Python-only `BEDROCK_LOG_INSTALL` and `BEDROCK_SERVER_MAX_CONNECTIONS`;
|
|
73
|
+
`ConfigError` lists every problem. `env.parse` reads typed dataclasses.
|
|
74
|
+
- `pyrock.testing.capture()` and the `pyrock_capture` pytest fixture
|
|
75
|
+
(registered by entry point; pyrock never imports pytest).
|
|
76
|
+
- Fork safety: an `os.register_at_fork` hook resets state and restarts
|
|
77
|
+
background threads in the child.
|
|
78
|
+
- Runnable stdlib examples (`examples/http_server.py`, `asgi_app.py`,
|
|
79
|
+
`worker.py`) and copy-in recipes for httpx, requests, grpcio, Flask, Django
|
|
80
|
+
and FastAPI.
|
|
81
|
+
- `README.md`, `CONTRIBUTING.md` and `SECURITY.md`; CI on Python 3.11–3.15
|
|
82
|
+
and 3.14t (`PYTHON_GIL=0`), a 3.14t stress job, macOS and Windows runs, the
|
|
83
|
+
compat suite (official OTLP protos, a real grpcio collector) and a
|
|
84
|
+
pure-wheel build check.
|
|
85
|
+
|
|
86
|
+
### Behavior decisions
|
|
87
|
+
|
|
88
|
+
These differ from Go Bedrock, or settle points the design left open:
|
|
89
|
+
|
|
90
|
+
- `Ratio` samples deterministically on the trace ID, and `ParentBased` drops
|
|
91
|
+
spans whose parent is unsampled.
|
|
92
|
+
- JSON log levels use Go's names (`DEBUG`, `INFO`, `WARN`, `ERROR`);
|
|
93
|
+
`CRITICAL` stays `CRITICAL`.
|
|
94
|
+
- Counters raise `ValueError` on negative or NaN increments. A different
|
|
95
|
+
`help` on re-registration is not a conflict (the first registration wins,
|
|
96
|
+
as in Go).
|
|
97
|
+
- Decorators always wrap and resolve the active instance at call time, so
|
|
98
|
+
functions decorated before `init()` are instrumented.
|
|
99
|
+
- Numbering applies only to siblings under the same operation or step; root
|
|
100
|
+
operations and direct children of a source are never numbered.
|
|
101
|
+
- There is no process-wide default instance and no monkey-patching of
|
|
102
|
+
`threading`. Middleware captures the instance at construction and activates
|
|
103
|
+
it per request. On interpreters that inherit context into new threads
|
|
104
|
+
(free-threaded 3.14), threads see the active instance.
|
|
105
|
+
- `http.user_agent`, `http.target` and `http.url` are emitted only when the
|
|
106
|
+
privacy policy allowlists them.
|
|
107
|
+
- `Config.log_level` takes level names only; the log helpers also take ints.
|
|
108
|
+
- `/debug/pprof` without a trailing slash is 404, and a CPU profile longer
|
|
109
|
+
than 30 s is rejected with 400, as in Go.
|
|
110
|
+
- CPU samples carry no asyncio task label; the profile exporter collects the
|
|
111
|
+
first profiles immediately on start.
|
|
112
|
+
- `Activation`, `MetricConflictError` and `MetricLimitError` can be imported
|
|
113
|
+
from `pyrock` but are not part of `__all__`.
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# Contributing to pyrock
|
|
2
|
+
|
|
3
|
+
Thanks for helping improve pyrock. Small, focused changes with tests and clear
|
|
4
|
+
compatibility notes are easiest to review.
|
|
5
|
+
|
|
6
|
+
## Before starting
|
|
7
|
+
|
|
8
|
+
Search the [issue tracker](https://github.com/kzs0/pyrock/issues) for related
|
|
9
|
+
work. Open an issue before a large feature, public API change or behavior
|
|
10
|
+
change, so the scope can be agreed before implementation. Security reports
|
|
11
|
+
must follow [SECURITY.md](SECURITY.md), not the public issue tracker.
|
|
12
|
+
|
|
13
|
+
You need [uv](https://docs.astral.sh/uv/). `uv sync` creates `.venv` with the
|
|
14
|
+
dev tools (pytest, coverage, ruff, mypy); uv installs any interpreter the
|
|
15
|
+
targets ask for. Clone your fork, create a topic branch, and keep unrelated
|
|
16
|
+
changes in separate pull requests.
|
|
17
|
+
|
|
18
|
+
## Rules for every change
|
|
19
|
+
|
|
20
|
+
- **Zero runtime dependencies.** Everything under `src/` imports only the
|
|
21
|
+
standard library; `[project.dependencies]` stays empty. A structural test
|
|
22
|
+
enforces this. Test-only packages belong in a dependency group (`compat`),
|
|
23
|
+
and their tests must skip cleanly when the packages are missing. Do not add
|
|
24
|
+
or update tool dependencies unless the change requires it and the pull
|
|
25
|
+
request explains the tradeoff.
|
|
26
|
+
- **Python 3.11 baseline.** Code must stay valid on 3.11: use
|
|
27
|
+
`from __future__ import annotations`, PEP 604 unions, `typing.Self` and
|
|
28
|
+
`dataclass(slots=True)`, and no 3.12+ syntax (`type X = ...`, PEP 695
|
|
29
|
+
generics). Newer stdlib APIs (for example `sys._is_gil_enabled`) are allowed
|
|
30
|
+
only behind feature detection in `pyrock._compat`.
|
|
31
|
+
- **Free-threaded safety.** Never rely on the GIL. Shared mutable state is
|
|
32
|
+
guarded by a `threading.Lock`; CI runs the suite on 3.14t with
|
|
33
|
+
`PYTHON_GIL=0` and repeats the concurrency-sensitive tests (`make stress`).
|
|
34
|
+
- **Keep the design.** No process-wide globals (state lives in
|
|
35
|
+
`contextvars`), no monkey-patching, controlled metric cardinality, and the
|
|
36
|
+
dependency boundaries in `tests/structure/test_structure.py`. Heavy modules
|
|
37
|
+
stay lazy, so `import pyrock` remains cheap.
|
|
38
|
+
- **Tests are the contract.** Test observable behavior (OTLP bytes, exposition
|
|
39
|
+
text, log JSON, HTTP responses), not internals. Do not weaken or rewrite an
|
|
40
|
+
existing test to make a change pass; if you believe a test is wrong, say so
|
|
41
|
+
in the pull request and change it deliberately, with a changelog entry.
|
|
42
|
+
Cover success, failure, boundary, cancellation and concurrency where
|
|
43
|
+
relevant.
|
|
44
|
+
- **Deterministic tests.** Wait on events, barriers and test servers, not
|
|
45
|
+
`time.sleep`. Bind every test server to `127.0.0.1:0`. Use the fakes in
|
|
46
|
+
`tests/support/`.
|
|
47
|
+
- **Docs.** Update `README.md` (and `DESIGN.md` when the design changes) and
|
|
48
|
+
the `Unreleased` section of [CHANGELOG.md](CHANGELOG.md) when behavior,
|
|
49
|
+
configuration or API changes.
|
|
50
|
+
|
|
51
|
+
## Validate
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
make fmt # ruff format + ruff check --fix
|
|
55
|
+
make ci # what CI's lint and coverage jobs run
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
`make ci` runs `ruff format --check`, `ruff check`, `mypy --strict src`, and
|
|
59
|
+
the full test suite under coverage with an 80% branch-coverage gate. Also run,
|
|
60
|
+
as relevant:
|
|
61
|
+
|
|
62
|
+
- `make matrix` for every supported interpreter (3.11 to 3.15 and 3.14t with
|
|
63
|
+
the GIL disabled);
|
|
64
|
+
- `make stress` after touching threads, fork handling, the batch processor or
|
|
65
|
+
the server;
|
|
66
|
+
- `make compat` after touching OTLP encoding or gRPC (official protos, a real
|
|
67
|
+
grpcio collector);
|
|
68
|
+
- `make build` after packaging changes (the wheel must stay pure Python with no
|
|
69
|
+
`Requires-Dist`).
|
|
70
|
+
|
|
71
|
+
CI runs the same commands on Linux for every interpreter, a 3.14t stress job,
|
|
72
|
+
3.14 on macOS and Windows, the compat suite and a wheel check.
|
|
73
|
+
|
|
74
|
+
## Compatibility
|
|
75
|
+
|
|
76
|
+
pyrock is below 1.0. Minor releases may contain intentional API or behavior
|
|
77
|
+
changes, but changes should still minimize disruption. A breaking change
|
|
78
|
+
needs:
|
|
79
|
+
|
|
80
|
+
- a clear reason and migration path;
|
|
81
|
+
- tests for the new contract;
|
|
82
|
+
- documentation updates; and
|
|
83
|
+
- an explicit changelog entry under `Changed`.
|
|
84
|
+
|
|
85
|
+
Wire compatibility with Go Bedrock (metric names, span attributes, log shape,
|
|
86
|
+
`BEDROCK_*` variables) is a feature. A deliberate difference must be listed in
|
|
87
|
+
the README's "Differences from Go Bedrock" section.
|
|
88
|
+
|
|
89
|
+
Bug fixes may reject input that was previously accepted incorrectly, or make
|
|
90
|
+
shutdown and network behavior stricter. Call these effects out so operators
|
|
91
|
+
can test their configuration before upgrading.
|
|
92
|
+
|
|
93
|
+
## Pull requests
|
|
94
|
+
|
|
95
|
+
Describe the problem, the chosen behavior, compatibility or security impact,
|
|
96
|
+
and the commands used to validate the change. Link related issues. Keep
|
|
97
|
+
commits reviewable; maintainers may squash or rebase when merging.
|
|
98
|
+
|
|
99
|
+
## Release process
|
|
100
|
+
|
|
101
|
+
Releases are maintainer-driven tags, published by the `Release` workflow
|
|
102
|
+
(`.github/workflows/release.yml`). For a release, a maintainer:
|
|
103
|
+
|
|
104
|
+
1. sets the version in `src/pyrock/_version.py` (`X.Y.Z`, or `X.Y.ZaN`,
|
|
105
|
+
`X.Y.ZbN` or `X.Y.ZrcN` for a prerelease) and moves the relevant
|
|
106
|
+
`Unreleased` entries to a dated `## [X.Y.Z] - YYYY-MM-DD` section;
|
|
107
|
+
2. verifies `make ci`, `make matrix` and `make compat` on the release commit
|
|
108
|
+
(`python3 scripts/release.py check vX.Y.Z` checks the version and
|
|
109
|
+
changelog locally);
|
|
110
|
+
3. merges the release change to `main`;
|
|
111
|
+
4. creates and pushes the tag `vX.Y.Z` (exactly `v` plus the version) on that
|
|
112
|
+
commit of `main`:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
git tag -a v0.1.0 -m "pyrock 0.1.0" <commit-on-main>
|
|
116
|
+
git push origin v0.1.0
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
5. lets the workflow run. It
|
|
120
|
+
- checks the tag matches the package version, the changelog has a dated
|
|
121
|
+
section for it, and the commit is on `main`;
|
|
122
|
+
- runs the full CI workflow as a gate;
|
|
123
|
+
- publishes the exact wheel and sdist CI built and checked to PyPI, using
|
|
124
|
+
trusted publishing (no API token is stored); and
|
|
125
|
+
- creates the GitHub Release with the changelog section as notes and the
|
|
126
|
+
distribution files attached, marked as a prerelease for `a`/`b`/`rc`
|
|
127
|
+
versions; and
|
|
128
|
+
6. starts a fresh `Unreleased` section and a `.dev0` version on `main`.
|
|
129
|
+
|
|
130
|
+
Release tags must point to `main`. Never move or reuse an existing tag;
|
|
131
|
+
publish a new patch version for corrections. A failed run can be re-run: each
|
|
132
|
+
publishing step is safe to repeat once its predecessor succeeded.
|
|
133
|
+
|
|
134
|
+
### One-time PyPI setup
|
|
135
|
+
|
|
136
|
+
PyPI trusted publishing has to be configured once, by a maintainer with a PyPI
|
|
137
|
+
account:
|
|
138
|
+
|
|
139
|
+
1. On PyPI, add a *pending* trusted publisher for the project `pyrock-core`
|
|
140
|
+
(Account settings → Publishing): owner `kzs0`, repository `pyrock`,
|
|
141
|
+
workflow `release.yml`, environment `pypi`.
|
|
142
|
+
2. On GitHub, create the `pypi` environment (Settings → Environments). Adding
|
|
143
|
+
required reviewers there makes every PyPI upload wait for an approval.
|