svc-infra 0.1.621__tar.gz → 0.1.622__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.
Potentially problematic release.
This version of svc-infra might be problematic. Click here for more details.
- {svc_infra-0.1.621 → svc_infra-0.1.622}/PKG-INFO +1 -1
- {svc_infra-0.1.621 → svc_infra-0.1.622}/pyproject.toml +1 -1
- svc_infra-0.1.622/src/svc_infra/cli/cmds/docs/docs_cmds.py +225 -0
- svc_infra-0.1.621/src/svc_infra/cli/cmds/docs/docs_cmds.py +0 -266
- {svc_infra-0.1.621 → svc_infra-0.1.622}/README.md +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/docs/acceptance-matrix.md +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/docs/acceptance.md +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/docs/adr/0002-background-jobs-and-scheduling.md +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/docs/adr/0003-webhooks-framework.md +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/docs/adr/0004-tenancy-model.md +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/docs/adr/0005-data-lifecycle.md +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/docs/adr/0006-ops-slos-and-metrics.md +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/docs/adr/0007-docs-and-sdks.md +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/docs/adr/0008-billing-primitives.md +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/docs/adr/0009-acceptance-harness.md +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/docs/api.md +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/docs/auth.md +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/docs/cache.md +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/docs/cli.md +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/docs/contributing.md +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/docs/data-lifecycle.md +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/docs/database.md +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/docs/docs-and-sdks.md +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/docs/environment.md +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/docs/idempotency.md +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/docs/jobs.md +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/docs/observability.md +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/docs/ops.md +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/docs/rate-limiting.md +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/docs/repo-review.md +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/docs/security.md +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/docs/tenancy.md +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/docs/webhooks.md +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/apf_payments/README.md +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/apf_payments/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/apf_payments/alembic.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/apf_payments/models.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/apf_payments/provider/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/apf_payments/provider/aiydan.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/apf_payments/provider/base.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/apf_payments/provider/registry.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/apf_payments/provider/stripe.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/apf_payments/schemas.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/apf_payments/service.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/apf_payments/settings.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/apf_payments/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/apf_payments/router.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/apf_payments/setup.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/auth/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/auth/_cookies.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/auth/add.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/auth/gaurd.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/auth/mfa/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/auth/mfa/models.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/auth/mfa/pre_auth.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/auth/mfa/router.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/auth/mfa/security.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/auth/mfa/utils.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/auth/mfa/verify.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/auth/policy.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/auth/providers.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/auth/routers/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/auth/routers/account.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/auth/routers/apikey_router.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/auth/routers/oauth_router.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/auth/routers/session_router.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/auth/security.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/auth/sender.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/auth/settings.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/auth/state.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/cache/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/cache/add.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/db/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/db/http.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/db/nosql/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/db/nosql/mongo/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/db/nosql/mongo/add.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/db/nosql/mongo/crud_router.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/db/nosql/mongo/health.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/db/sql/README.md +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/db/sql/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/db/sql/add.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/db/sql/crud_router.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/db/sql/health.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/db/sql/session.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/db/sql/users.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/dependencies/ratelimit.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/docs/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/docs/add.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/docs/landing.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/docs/scoped.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/dual/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/dual/dualize.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/dual/protected.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/dual/public.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/dual/router.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/dual/utils.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/dx.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/ease.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/http/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/http/concurrency.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/http/conditional.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/http/deprecation.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/middleware/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/middleware/debug.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/middleware/errors/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/middleware/errors/catchall.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/middleware/errors/exceptions.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/middleware/errors/handlers.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/middleware/idempotency.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/middleware/idempotency_store.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/middleware/optimistic_lock.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/middleware/ratelimit.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/middleware/ratelimit_store.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/middleware/request_id.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/middleware/request_size_limit.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/openapi/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/openapi/apply.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/openapi/conventions.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/openapi/models.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/openapi/mutators.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/openapi/pipeline.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/openapi/responses.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/openapi/security.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/ops/add.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/pagination.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/paths/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/paths/auth.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/paths/generic.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/paths/prefix.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/paths/user.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/routers/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/routers/ping.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/setup.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/tenancy/add.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/api/fastapi/tenancy/context.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/app/README.md +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/app/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/app/env.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/app/logging/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/app/logging/add.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/app/logging/filter.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/app/logging/formats.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/app/root.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/billing/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/billing/models.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/billing/service.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/bundled_docs/README.md +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/bundled_docs/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/bundled_docs/getting-started.md +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/cache/README.md +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/cache/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/cache/backend.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/cache/decorators.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/cache/demo.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/cache/keys.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/cache/recache.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/cache/resources.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/cache/tags.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/cache/ttl.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/cache/utils.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/cli/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/cli/__main__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/cli/cmds/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/cli/cmds/db/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/cli/cmds/db/nosql/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/cli/cmds/db/nosql/mongo/README.md +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/cli/cmds/db/nosql/mongo/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/cli/cmds/db/nosql/mongo/mongo_cmds.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/cli/cmds/db/nosql/mongo/mongo_scaffold_cmds.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/cli/cmds/db/sql/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/cli/cmds/db/sql/alembic_cmds.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/cli/cmds/db/sql/sql_export_cmds.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/cli/cmds/db/sql/sql_scaffold_cmds.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/cli/cmds/dx/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/cli/cmds/dx/dx_cmds.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/cli/cmds/help.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/cli/cmds/jobs/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/cli/cmds/jobs/jobs_cmds.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/cli/cmds/obs/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/cli/cmds/obs/obs_cmds.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/cli/cmds/sdk/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/cli/cmds/sdk/sdk_cmds.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/cli/foundation/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/cli/foundation/runner.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/cli/foundation/typer_bootstrap.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/data/add.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/data/backup.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/data/erasure.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/data/fixtures.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/data/retention.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/db/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/db/crud_schema.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/db/inbox.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/db/nosql/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/db/nosql/base.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/db/nosql/constants.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/db/nosql/core.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/db/nosql/indexes.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/db/nosql/management.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/db/nosql/mongo/README.md +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/db/nosql/mongo/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/db/nosql/mongo/client.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/db/nosql/mongo/settings.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/db/nosql/mongo/templates/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/db/nosql/mongo/templates/documents.py.tmpl +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/db/nosql/mongo/templates/resources.py.tmpl +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/db/nosql/mongo/templates/schemas.py.tmpl +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/db/nosql/repository.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/db/nosql/resource.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/db/nosql/scaffold.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/db/nosql/service.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/db/nosql/service_with_hooks.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/db/nosql/types.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/db/nosql/utils.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/db/outbox.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/db/sql/README.md +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/db/sql/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/db/sql/apikey.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/db/sql/authref.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/db/sql/base.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/db/sql/constants.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/db/sql/core.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/db/sql/management.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/db/sql/repository.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/db/sql/resource.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/db/sql/scaffold.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/db/sql/service.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/db/sql/service_with_hooks.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/db/sql/templates/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/db/sql/templates/models_schemas/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/db/sql/templates/models_schemas/auth/models.py.tmpl +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/db/sql/templates/models_schemas/auth/schemas.py.tmpl +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/db/sql/templates/models_schemas/entity/models.py.tmpl +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/db/sql/templates/models_schemas/entity/schemas.py.tmpl +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/db/sql/templates/setup/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/db/sql/templates/setup/alembic.ini.tmpl +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/db/sql/templates/setup/env_async.py.tmpl +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/db/sql/templates/setup/env_sync.py.tmpl +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/db/sql/templates/setup/script.py.mako.tmpl +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/db/sql/tenant.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/db/sql/types.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/db/sql/uniq.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/db/sql/uniq_hooks.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/db/sql/utils.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/db/sql/versioning.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/db/utils.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/dx/add.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/dx/changelog.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/dx/checks.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/jobs/builtins/outbox_processor.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/jobs/builtins/webhook_delivery.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/jobs/easy.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/jobs/loader.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/jobs/queue.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/jobs/redis_queue.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/jobs/scheduler.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/jobs/worker.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/mcp/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/mcp/svc_infra_mcp.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/obs/README.md +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/obs/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/obs/add.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/obs/cloud_dash.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/obs/grafana/dashboards/http-overview.json +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/obs/metrics/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/obs/metrics/asgi.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/obs/metrics/base.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/obs/metrics/http.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/obs/metrics/sqlalchemy.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/obs/metrics.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/obs/providers/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/obs/providers/compose_cloud/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/obs/providers/compose_cloud/templates/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/obs/providers/compose_cloud/templates/agent.yaml.tmpl +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/obs/providers/compose_cloud/templates/docker-compose.cloud.yml.tmpl +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/obs/providers/grafana/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/obs/providers/grafana/dashboards/00_overview.json +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/obs/providers/grafana/dashboards/10_http.json +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/obs/providers/grafana/dashboards/20_db.json +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/obs/providers/grafana/dashboards/30_runtime.json +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/obs/providers/grafana/dashboards/40_clients.json +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/obs/providers/grafana/dashboards/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/obs/providers/grafana/templates/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/obs/providers/grafana/templates/docker-compose.yml.tmpl +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/obs/providers/grafana/templates/prometheus.yml.tmpl +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/obs/providers/grafana/templates/provisioning/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/obs/providers/grafana/templates/provisioning/dashboards.yml +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/obs/providers/grafana/templates/provisioning/datasource.yml +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/obs/settings.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/obs/templates/grafana_dashboard.json +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/obs/templates/prometheus_rules.yml +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/obs/templates/sidecars/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/obs/templates/sidecars/compose/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/obs/templates/sidecars/compose/agent.yaml +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/obs/templates/sidecars/compose/docker-compose.yml +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/obs/templates/sidecars/fly/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/obs/templates/sidecars/fly/agent.yaml +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/obs/templates/sidecars/fly/fly.toml.fragment +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/obs/templates/sidecars/k8s/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/obs/templates/sidecars/k8s/configmap.yaml +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/obs/templates/sidecars/k8s/deployment.yaml +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/obs/templates/sidecars/railway/Dockerfile +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/obs/templates/sidecars/railway/README.md +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/obs/templates/sidecars/railway/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/obs/templates/sidecars/railway/agent.yaml +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/py.typed +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/security/add.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/security/audit.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/security/audit_service.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/security/headers.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/security/hibp.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/security/jwt_rotation.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/security/lockout.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/security/models.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/security/org_invites.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/security/passwords.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/security/permissions.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/security/session.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/security/signed_cookies.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/utils.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/webhooks/__init__.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/webhooks/add.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/webhooks/fastapi.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/webhooks/router.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/webhooks/service.py +0 -0
- {svc_infra-0.1.621 → svc_infra-0.1.622}/src/svc_infra/webhooks/signing.py +0 -0
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import importlib.util
|
|
4
|
+
import os
|
|
5
|
+
import sys
|
|
6
|
+
from importlib.metadata import PackageNotFoundError, distribution
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Dict, List
|
|
9
|
+
|
|
10
|
+
import click
|
|
11
|
+
import typer
|
|
12
|
+
from typer.core import TyperGroup
|
|
13
|
+
|
|
14
|
+
from svc_infra.app.root import resolve_project_root
|
|
15
|
+
|
|
16
|
+
# ---------- small helpers ----------
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _norm(name: str) -> str:
|
|
20
|
+
return name.strip().lower().replace(" ", "-").replace("_", "-")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _md_topics_in(dirpath: Path) -> Dict[str, Path]:
|
|
24
|
+
topics: Dict[str, Path] = {}
|
|
25
|
+
if dirpath.exists() and dirpath.is_dir():
|
|
26
|
+
for p in sorted(dirpath.glob("*.md")):
|
|
27
|
+
if p.is_file():
|
|
28
|
+
topics[_norm(p.stem)] = p
|
|
29
|
+
return topics
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
# ---------- where could docs live after install? ----------
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _candidate_docs_dirs(ctx: click.Context) -> List[Path]:
|
|
36
|
+
"""
|
|
37
|
+
Return likely directories that contain the shipped docs (*.md), ordered by priority.
|
|
38
|
+
Covers:
|
|
39
|
+
1) explicit --docs-dir / env var
|
|
40
|
+
2) in-repo (editable install): <repo>/docs relative to src/svc_infra
|
|
41
|
+
3) wheel installs: <site-packages>/docs
|
|
42
|
+
4) wheel .data area: <site-packages>/{name}-{ver}.data/**/docs
|
|
43
|
+
"""
|
|
44
|
+
out: List[Path] = []
|
|
45
|
+
|
|
46
|
+
# 1) explicit override (--docs-dir or env)
|
|
47
|
+
# Walk up parent contexts to see Typer's group option.
|
|
48
|
+
cur: click.Context | None = ctx
|
|
49
|
+
while cur is not None:
|
|
50
|
+
docs_dir_opt = (cur.params or {}).get("docs_dir")
|
|
51
|
+
if docs_dir_opt:
|
|
52
|
+
p = docs_dir_opt if isinstance(docs_dir_opt, Path) else Path(docs_dir_opt)
|
|
53
|
+
p = p.expanduser()
|
|
54
|
+
if p.exists():
|
|
55
|
+
out.append(p)
|
|
56
|
+
return out # explicit override wins
|
|
57
|
+
cur = cur.parent
|
|
58
|
+
|
|
59
|
+
env_dir = os.getenv("SVC_INFRA_DOCS_DIR")
|
|
60
|
+
if env_dir:
|
|
61
|
+
p = Path(env_dir).expanduser()
|
|
62
|
+
if p.exists():
|
|
63
|
+
out.append(p)
|
|
64
|
+
return out # explicit override wins
|
|
65
|
+
|
|
66
|
+
# locate installed package dir: .../site-packages/svc_infra
|
|
67
|
+
pkg_dir: Path | None = None
|
|
68
|
+
spec = importlib.util.find_spec("svc_infra")
|
|
69
|
+
if spec and spec.submodule_search_locations:
|
|
70
|
+
pkg_dir = Path(next(iter(spec.submodule_search_locations)))
|
|
71
|
+
|
|
72
|
+
# 2) in-repo editable install: src/svc_infra -> ../../docs
|
|
73
|
+
if pkg_dir:
|
|
74
|
+
repo_root_docs = pkg_dir.parent.parent / "docs"
|
|
75
|
+
if repo_root_docs.exists():
|
|
76
|
+
out.append(repo_root_docs)
|
|
77
|
+
|
|
78
|
+
# 3) wheel installs often end up with a top-level site-packages/docs
|
|
79
|
+
top_level_docs = pkg_dir.parent / "docs"
|
|
80
|
+
if top_level_docs.exists():
|
|
81
|
+
out.append(top_level_docs)
|
|
82
|
+
|
|
83
|
+
# 4) wheel .data layout: <site-packages>/{dist-name}-{version}.data/**/docs
|
|
84
|
+
# This catches Poetry's include=docs/**/* paths installed by pip.
|
|
85
|
+
# We compute sibling candidates off site-packages base.
|
|
86
|
+
site_pkgs: Path | None = pkg_dir.parent if pkg_dir else None
|
|
87
|
+
dist = None
|
|
88
|
+
for name in ("svc-infra", "svc_infra"):
|
|
89
|
+
try:
|
|
90
|
+
dist = distribution(name)
|
|
91
|
+
break
|
|
92
|
+
except PackageNotFoundError:
|
|
93
|
+
dist = None
|
|
94
|
+
|
|
95
|
+
if site_pkgs and dist is not None:
|
|
96
|
+
# normalized dist name (hyphen/underscore forms both happen in practice)
|
|
97
|
+
dist_name = dist.metadata.get("Name", "svc-infra")
|
|
98
|
+
dist_ver = dist.version
|
|
99
|
+
data_candidates = [
|
|
100
|
+
site_pkgs / f"{dist_name}-{dist_ver}.data",
|
|
101
|
+
site_pkgs / f"{dist_name.replace('-', '_')}-{dist_ver}.data",
|
|
102
|
+
site_pkgs / f"{dist_name.replace('_', '-')}-{dist_ver}.data",
|
|
103
|
+
]
|
|
104
|
+
for data_dir in data_candidates:
|
|
105
|
+
if not data_dir.exists():
|
|
106
|
+
continue
|
|
107
|
+
# common wheel data subfolders
|
|
108
|
+
for sub in ("purelib", "platlib", "data"):
|
|
109
|
+
d = data_dir / sub / "docs"
|
|
110
|
+
if d.exists():
|
|
111
|
+
out.append(d)
|
|
112
|
+
# fallback: search shallowly for any docs/ folder inside .data
|
|
113
|
+
for root, dirs, _files in os.walk(data_dir):
|
|
114
|
+
root_path = Path(root)
|
|
115
|
+
# limit depth (cheap)
|
|
116
|
+
if len(root_path.parts) - len(data_dir.parts) > 3:
|
|
117
|
+
dirs[:] = []
|
|
118
|
+
continue
|
|
119
|
+
if root_path.name == "docs":
|
|
120
|
+
out.append(root_path)
|
|
121
|
+
|
|
122
|
+
# 5) extremely defensive: scan sys.path entries that look like site-/dist-packages for top-level docs/
|
|
123
|
+
for entry in sys.path:
|
|
124
|
+
if not entry or ("site-packages" not in entry and "dist-packages" not in entry):
|
|
125
|
+
continue
|
|
126
|
+
p = Path(entry) / "docs"
|
|
127
|
+
if p.exists():
|
|
128
|
+
out.append(p)
|
|
129
|
+
|
|
130
|
+
# de-dup while preserving order
|
|
131
|
+
seen = set()
|
|
132
|
+
uniq: List[Path] = []
|
|
133
|
+
for p in out:
|
|
134
|
+
if p.exists():
|
|
135
|
+
key = str(p.resolve())
|
|
136
|
+
if key not in seen:
|
|
137
|
+
seen.add(key)
|
|
138
|
+
uniq.append(p)
|
|
139
|
+
return uniq
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def _discover_topics(ctx: click.Context) -> Dict[str, Path]:
|
|
143
|
+
topics: Dict[str, Path] = {}
|
|
144
|
+
for d in _candidate_docs_dirs(ctx):
|
|
145
|
+
found = _md_topics_in(d)
|
|
146
|
+
# do not override earlier (higher-priority) sources
|
|
147
|
+
for k, v in found.items():
|
|
148
|
+
topics.setdefault(k, v)
|
|
149
|
+
if topics:
|
|
150
|
+
# one dir with content is enough for most setups
|
|
151
|
+
# (comment out this break if you *want* deep merging)
|
|
152
|
+
break
|
|
153
|
+
return topics
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
# ---------- Typer group ----------
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
class DocsGroup(TyperGroup):
|
|
160
|
+
def list_commands(self, ctx: click.Context) -> List[str]:
|
|
161
|
+
topics = _discover_topics(ctx)
|
|
162
|
+
return sorted(topics.keys())
|
|
163
|
+
|
|
164
|
+
def get_command(self, ctx: click.Context, name: str) -> click.Command | None:
|
|
165
|
+
cmd = super().get_command(ctx, name)
|
|
166
|
+
if cmd is not None:
|
|
167
|
+
return cmd
|
|
168
|
+
|
|
169
|
+
key = _norm(name)
|
|
170
|
+
topics = _discover_topics(ctx)
|
|
171
|
+
if key in topics:
|
|
172
|
+
file_path = topics[key]
|
|
173
|
+
|
|
174
|
+
@click.command(name=name)
|
|
175
|
+
def _show() -> None:
|
|
176
|
+
click.echo(file_path.read_text(encoding="utf-8", errors="replace"))
|
|
177
|
+
|
|
178
|
+
return _show
|
|
179
|
+
|
|
180
|
+
return None
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def register(app: typer.Typer) -> None:
|
|
184
|
+
docs_app = typer.Typer(no_args_is_help=True, add_completion=False, cls=DocsGroup)
|
|
185
|
+
|
|
186
|
+
@docs_app.callback(invoke_without_command=True)
|
|
187
|
+
def _docs_options(
|
|
188
|
+
docs_dir: Path | None = typer.Option(
|
|
189
|
+
None,
|
|
190
|
+
"--docs-dir",
|
|
191
|
+
help="Path to a docs directory to read from (overrides packaged docs)",
|
|
192
|
+
),
|
|
193
|
+
topic: str | None = typer.Option(None, "--topic", help="Topic to show directly"),
|
|
194
|
+
) -> None:
|
|
195
|
+
if topic:
|
|
196
|
+
key = _norm(topic)
|
|
197
|
+
topics = _discover_topics(click.get_current_context())
|
|
198
|
+
if key in topics:
|
|
199
|
+
typer.echo(topics[key].read_text(encoding="utf-8", errors="replace"))
|
|
200
|
+
raise typer.Exit(code=0)
|
|
201
|
+
raise typer.BadParameter(f"Unknown topic: {topic}")
|
|
202
|
+
|
|
203
|
+
@docs_app.command("list", help="List available documentation topics")
|
|
204
|
+
def list_topics() -> None:
|
|
205
|
+
ctx = click.get_current_context()
|
|
206
|
+
root = resolve_project_root()
|
|
207
|
+
topics = _discover_topics(ctx)
|
|
208
|
+
|
|
209
|
+
for name, path in topics.items():
|
|
210
|
+
try:
|
|
211
|
+
rel = path.relative_to(root)
|
|
212
|
+
typer.echo(f"{name}\t{rel}")
|
|
213
|
+
except Exception:
|
|
214
|
+
typer.echo(f"{name}\t{path}")
|
|
215
|
+
|
|
216
|
+
@docs_app.command("show", help="Show docs for a topic (alternative to dynamic subcommand)")
|
|
217
|
+
def show(topic: str) -> None:
|
|
218
|
+
key = _norm(topic)
|
|
219
|
+
topics = _discover_topics(click.get_current_context())
|
|
220
|
+
if key in topics:
|
|
221
|
+
typer.echo(topics[key].read_text(encoding="utf-8", errors="replace"))
|
|
222
|
+
return
|
|
223
|
+
raise typer.BadParameter(f"Unknown topic: {topic}")
|
|
224
|
+
|
|
225
|
+
app.add_typer(docs_app, name="docs")
|
|
@@ -1,266 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import importlib.util
|
|
4
|
-
import os
|
|
5
|
-
import sys
|
|
6
|
-
from importlib.metadata import PackageNotFoundError, distribution
|
|
7
|
-
from pathlib import Path
|
|
8
|
-
from typing import Dict, List
|
|
9
|
-
|
|
10
|
-
import click
|
|
11
|
-
import typer
|
|
12
|
-
from typer.core import TyperGroup
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
def _norm(name: str) -> str:
|
|
16
|
-
"""Normalize a topic name for stable CLI commands.
|
|
17
|
-
|
|
18
|
-
- Lowercase
|
|
19
|
-
- Replace spaces and underscores with hyphens
|
|
20
|
-
- Strip leading/trailing whitespace
|
|
21
|
-
"""
|
|
22
|
-
return name.strip().lower().replace(" ", "-").replace("_", "-")
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
def _discover_fs_topics(docs_dir: Path) -> Dict[str, Path]:
|
|
26
|
-
topics: Dict[str, Path] = {}
|
|
27
|
-
if docs_dir.exists() and docs_dir.is_dir():
|
|
28
|
-
for p in sorted(docs_dir.glob("*.md")):
|
|
29
|
-
if p.is_file():
|
|
30
|
-
topics[_norm(p.stem)] = p
|
|
31
|
-
return topics
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
def _discover_pkg_topics() -> Dict[str, Path]:
|
|
35
|
-
"""Discover docs packaged under 'docs/' in the installed distribution.
|
|
36
|
-
|
|
37
|
-
Works in external projects without a local docs/ by inspecting the wheel
|
|
38
|
-
metadata and, as a fallback, searching for a top-level docs/ next to the
|
|
39
|
-
installed package directory in site-packages.
|
|
40
|
-
"""
|
|
41
|
-
topics: Dict[str, Path] = {}
|
|
42
|
-
|
|
43
|
-
# 1) Prefer distribution metadata (RECORD) for both hyphen/underscore names
|
|
44
|
-
dist = None
|
|
45
|
-
for name in ("svc-infra", "svc_infra"):
|
|
46
|
-
try:
|
|
47
|
-
dist = distribution(name)
|
|
48
|
-
break
|
|
49
|
-
except PackageNotFoundError:
|
|
50
|
-
dist = None
|
|
51
|
-
|
|
52
|
-
if dist is not None:
|
|
53
|
-
files = getattr(dist, "files", None) or []
|
|
54
|
-
for f in files:
|
|
55
|
-
s = str(f)
|
|
56
|
-
if not s.startswith("docs/") or not s.endswith(".md"):
|
|
57
|
-
continue
|
|
58
|
-
topic_name = _norm(Path(s).stem)
|
|
59
|
-
try:
|
|
60
|
-
abs_path = Path(dist.locate_file(f))
|
|
61
|
-
if abs_path.exists() and abs_path.is_file():
|
|
62
|
-
topics[topic_name] = abs_path
|
|
63
|
-
except Exception:
|
|
64
|
-
# Best effort; continue to next
|
|
65
|
-
continue
|
|
66
|
-
|
|
67
|
-
# 2) Fallback: site-packages sibling 'docs/' directory (and repo-root docs in editable installs)
|
|
68
|
-
try:
|
|
69
|
-
spec = importlib.util.find_spec("svc_infra")
|
|
70
|
-
if spec and spec.submodule_search_locations:
|
|
71
|
-
pkg_dir = Path(next(iter(spec.submodule_search_locations)))
|
|
72
|
-
candidates = [
|
|
73
|
-
pkg_dir.parent / "docs", # site-packages/docs OR src/docs
|
|
74
|
-
pkg_dir / "docs", # site-packages/svc_infra/docs OR src/svc_infra/docs
|
|
75
|
-
pkg_dir.parent.parent
|
|
76
|
-
/ "docs", # repo-root/docs when running editable from repo (src/svc_infra → ../../docs)
|
|
77
|
-
]
|
|
78
|
-
for candidate in candidates:
|
|
79
|
-
if candidate.exists() and candidate.is_dir():
|
|
80
|
-
for p in sorted(candidate.glob("*.md")):
|
|
81
|
-
if p.is_file():
|
|
82
|
-
topics.setdefault(_norm(p.stem), p)
|
|
83
|
-
# If one candidate had docs, that's sufficient
|
|
84
|
-
if any(k for k in topics):
|
|
85
|
-
break
|
|
86
|
-
except Exception:
|
|
87
|
-
# Optional fallback only
|
|
88
|
-
pass
|
|
89
|
-
|
|
90
|
-
# 3) Last-resort: scan sys.path entries that look like site-/dist-packages for a top-level docs/
|
|
91
|
-
# directory containing markdown files. This covers non-standard installs/editable modes.
|
|
92
|
-
try:
|
|
93
|
-
if not topics:
|
|
94
|
-
for entry in sys.path:
|
|
95
|
-
try:
|
|
96
|
-
if not entry or ("site-packages" not in entry and "dist-packages" not in entry):
|
|
97
|
-
continue
|
|
98
|
-
docs_dir = Path(entry) / "docs"
|
|
99
|
-
if docs_dir.exists() and docs_dir.is_dir():
|
|
100
|
-
found = _discover_fs_topics(docs_dir)
|
|
101
|
-
if found:
|
|
102
|
-
# Merge but do not override anything already found
|
|
103
|
-
for k, v in found.items():
|
|
104
|
-
topics.setdefault(k, v)
|
|
105
|
-
# If we found one valid docs dir, it's enough
|
|
106
|
-
break
|
|
107
|
-
except Exception:
|
|
108
|
-
continue
|
|
109
|
-
except Exception:
|
|
110
|
-
pass
|
|
111
|
-
|
|
112
|
-
# 4) Parse dist-info/RECORD or egg-info/SOURCES.txt to enumerate docs if available
|
|
113
|
-
try:
|
|
114
|
-
if not topics:
|
|
115
|
-
spec = importlib.util.find_spec("svc_infra")
|
|
116
|
-
base_dir: Path | None = None
|
|
117
|
-
if spec and spec.submodule_search_locations:
|
|
118
|
-
base_dir = Path(next(iter(spec.submodule_search_locations))).parent
|
|
119
|
-
# Fallback to first site-packages on sys.path
|
|
120
|
-
if base_dir is None:
|
|
121
|
-
for entry in sys.path:
|
|
122
|
-
if entry and "site-packages" in entry:
|
|
123
|
-
base_dir = Path(entry)
|
|
124
|
-
break
|
|
125
|
-
if base_dir and base_dir.exists():
|
|
126
|
-
# Check for both hyphen and underscore dist-info names
|
|
127
|
-
candidates = list(base_dir.glob("svc_infra-*.dist-info")) + list(
|
|
128
|
-
base_dir.glob("svc-infra-*.dist-info")
|
|
129
|
-
)
|
|
130
|
-
for di in candidates:
|
|
131
|
-
record = di / "RECORD"
|
|
132
|
-
if record.exists():
|
|
133
|
-
try:
|
|
134
|
-
for line in record.read_text(
|
|
135
|
-
encoding="utf-8", errors="ignore"
|
|
136
|
-
).splitlines():
|
|
137
|
-
rel = line.split(",", 1)[0]
|
|
138
|
-
if rel.startswith("docs/") and rel.endswith(".md"):
|
|
139
|
-
abs_p = base_dir / rel
|
|
140
|
-
if abs_p.exists() and abs_p.is_file():
|
|
141
|
-
topics.setdefault(_norm(Path(rel).stem), abs_p)
|
|
142
|
-
except Exception:
|
|
143
|
-
continue
|
|
144
|
-
# egg-info fallback
|
|
145
|
-
if not topics:
|
|
146
|
-
egg_candidates = list(base_dir.glob("svc_infra-*.egg-info")) + list(
|
|
147
|
-
base_dir.glob("svc-infra-*.egg-info")
|
|
148
|
-
)
|
|
149
|
-
for ei in egg_candidates:
|
|
150
|
-
sources = ei / "SOURCES.txt"
|
|
151
|
-
if sources.exists():
|
|
152
|
-
try:
|
|
153
|
-
for rel in sources.read_text(
|
|
154
|
-
encoding="utf-8", errors="ignore"
|
|
155
|
-
).splitlines():
|
|
156
|
-
rel = rel.strip()
|
|
157
|
-
if rel.startswith("docs/") and rel.endswith(".md"):
|
|
158
|
-
abs_p = base_dir / rel
|
|
159
|
-
if abs_p.exists() and abs_p.is_file():
|
|
160
|
-
topics.setdefault(_norm(Path(rel).stem), abs_p)
|
|
161
|
-
except Exception:
|
|
162
|
-
continue
|
|
163
|
-
except Exception:
|
|
164
|
-
pass
|
|
165
|
-
|
|
166
|
-
# 5) Deep fallback: recursively search site-packages/dist-packages for any 'docs' folder
|
|
167
|
-
# containing markdown files (limited depth to keep overhead reasonable).
|
|
168
|
-
try:
|
|
169
|
-
if not topics:
|
|
170
|
-
for entry in sys.path:
|
|
171
|
-
if not entry or ("site-packages" not in entry and "dist-packages" not in entry):
|
|
172
|
-
continue
|
|
173
|
-
base = Path(entry)
|
|
174
|
-
if not base.exists() or not base.is_dir():
|
|
175
|
-
continue
|
|
176
|
-
base_parts = len(base.parts)
|
|
177
|
-
for root, dirs, files in os.walk(base):
|
|
178
|
-
root_path = Path(root)
|
|
179
|
-
# Limit search depth to avoid expensive scans
|
|
180
|
-
if len(root_path.parts) - base_parts > 4:
|
|
181
|
-
# prune
|
|
182
|
-
dirs[:] = []
|
|
183
|
-
continue
|
|
184
|
-
if root_path.name == "docs":
|
|
185
|
-
for p in sorted(root_path.glob("*.md")):
|
|
186
|
-
if p.is_file():
|
|
187
|
-
topics.setdefault(_norm(p.stem), p)
|
|
188
|
-
# do not break; there might be multiple doc dirs
|
|
189
|
-
except Exception:
|
|
190
|
-
pass
|
|
191
|
-
|
|
192
|
-
return topics
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
def _resolve_docs_dir(ctx: click.Context) -> Path | None:
|
|
196
|
-
# Deprecated: we no longer read docs from arbitrary paths or env.
|
|
197
|
-
# All docs are sourced from the packaged svc-infra distribution only.
|
|
198
|
-
return None
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
class DocsGroup(TyperGroup):
|
|
202
|
-
def list_commands(self, ctx: click.Context) -> List[str]:
|
|
203
|
-
names: List[str] = list(super().list_commands(ctx) or [])
|
|
204
|
-
pkg = _discover_pkg_topics()
|
|
205
|
-
names.extend([k for k in pkg.keys()])
|
|
206
|
-
# Deduplicate and sort
|
|
207
|
-
return sorted({*names})
|
|
208
|
-
|
|
209
|
-
def get_command(self, ctx: click.Context, name: str) -> click.Command | None:
|
|
210
|
-
# Built-ins first (e.g., list, show)
|
|
211
|
-
cmd = super().get_command(ctx, name)
|
|
212
|
-
if cmd is not None:
|
|
213
|
-
return cmd
|
|
214
|
-
|
|
215
|
-
# Packaged topics only
|
|
216
|
-
pkg = _discover_pkg_topics()
|
|
217
|
-
if name in pkg:
|
|
218
|
-
file_path = pkg[name]
|
|
219
|
-
|
|
220
|
-
@click.command(name=name)
|
|
221
|
-
def _show_pkg() -> None:
|
|
222
|
-
click.echo(file_path.read_text(encoding="utf-8", errors="replace"))
|
|
223
|
-
|
|
224
|
-
return _show_pkg
|
|
225
|
-
|
|
226
|
-
return None
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
def register(app: typer.Typer) -> None:
|
|
230
|
-
"""Register the `docs` command group with dynamic topic subcommands."""
|
|
231
|
-
|
|
232
|
-
docs_app = typer.Typer(no_args_is_help=True, add_completion=False, cls=DocsGroup)
|
|
233
|
-
|
|
234
|
-
@docs_app.callback(invoke_without_command=True)
|
|
235
|
-
def _docs_options(
|
|
236
|
-
topic: str | None = typer.Option(None, "--topic", help="Topic to show directly"),
|
|
237
|
-
) -> None:
|
|
238
|
-
"""Support --topic at group level (packaged docs only)."""
|
|
239
|
-
if topic:
|
|
240
|
-
pkg = _discover_pkg_topics()
|
|
241
|
-
if topic in pkg:
|
|
242
|
-
typer.echo(pkg[topic].read_text(encoding="utf-8", errors="replace"))
|
|
243
|
-
raise typer.Exit(code=0)
|
|
244
|
-
raise typer.BadParameter(f"Unknown topic: {topic}")
|
|
245
|
-
|
|
246
|
-
@docs_app.command("list", help="List available documentation topics")
|
|
247
|
-
def list_topics() -> None:
|
|
248
|
-
pkg = _discover_pkg_topics()
|
|
249
|
-
|
|
250
|
-
# Print packaged topics only
|
|
251
|
-
def _print(name: str, path: Path) -> None:
|
|
252
|
-
typer.echo(f"{name}\t{path}")
|
|
253
|
-
|
|
254
|
-
for name, path in pkg.items():
|
|
255
|
-
_print(name, path)
|
|
256
|
-
|
|
257
|
-
# Also support a generic "show" command
|
|
258
|
-
@docs_app.command("show", help="Show docs for a topic (alternative to dynamic subcommand)")
|
|
259
|
-
def show(topic: str) -> None:
|
|
260
|
-
pkg = _discover_pkg_topics()
|
|
261
|
-
if topic in pkg:
|
|
262
|
-
typer.echo(pkg[topic].read_text(encoding="utf-8", errors="replace"))
|
|
263
|
-
return
|
|
264
|
-
raise typer.BadParameter(f"Unknown topic: {topic}")
|
|
265
|
-
|
|
266
|
-
app.add_typer(docs_app, name="docs")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|