{"id":49764169,"url":"https://github.com/quonfig/sdk-python","last_synced_at":"2026-05-11T10:14:35.392Z","repository":{"id":352296771,"uuid":"1207974796","full_name":"quonfig/sdk-python","owner":"quonfig","description":"Quonfig SDK for Python — feature flags, live config, and dynamic log levels","archived":false,"fork":false,"pushed_at":"2026-05-03T19:23:01.000Z","size":554,"stargazers_count":0,"open_issues_count":8,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-03T21:16:40.464Z","etag":null,"topics":["configuration","feature-flag","feature-flags","python","quonfig","sdk"],"latest_commit_sha":null,"homepage":"https://quonfig.com","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/quonfig.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-11T16:46:06.000Z","updated_at":"2026-05-03T19:20:52.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/quonfig/sdk-python","commit_stats":null,"previous_names":["quonfig/sdk-python"],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/quonfig/sdk-python","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/quonfig%2Fsdk-python","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/quonfig%2Fsdk-python/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/quonfig%2Fsdk-python/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/quonfig%2Fsdk-python/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/quonfig","download_url":"https://codeload.github.com/quonfig/sdk-python/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/quonfig%2Fsdk-python/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32890181,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-10T13:40:02.631Z","status":"online","status_checked_at":"2026-05-11T02:00:05.975Z","response_time":120,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["configuration","feature-flag","feature-flags","python","quonfig","sdk"],"created_at":"2026-05-11T10:14:33.229Z","updated_at":"2026-05-11T10:14:35.384Z","avatar_url":"https://github.com/quonfig.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# quonfig\n\nPython SDK for Quonfig.\n\n## Install\n\n```bash\npip install quonfig\n```\n\n## Usage\n\n```python\nfrom quonfig import Quonfig\n\nclient = Quonfig(sdk_key=\"sdk-...\")\nclient.init()\n\nvalue = client.get_string(\"my.key\", default=\"fallback\")\nenabled = client.is_feature_enabled(\"my.flag\")\n```\n\n## Context\n\n```python\n# Per-call context\nresult = client.get_string(\"my.key\", contexts={\"user\": {\"plan\": \"pro\"}})\n\n# Bound context (for request handlers etc.)\nuser_client = client.with_context({\"user\": {\"id\": \"u123\", \"plan\": \"pro\"}})\nenabled = user_client.is_feature_enabled(\"my.flag\")\n\n# Thread-local scoped context\nwith client.scoped_context({\"user\": {\"id\": \"u123\"}}):\n    enabled = client.is_feature_enabled(\"my.flag\")\n```\n\n## Dynamic log levels\n\n```python\nfrom quonfig import Quonfig\n\nclient = Quonfig(\n    sdk_key=\"sdk-...\",\n    logger_key=\"log-level.my-app\",  # config that drives per-logger rules\n).init()\n\n# Convenience form — SDK injects { \"quonfig-sdk-logging\": { \"key\": \"my_app.auth\" } }\n# into context so a single config can route by logger path.\nif client.should_log(logger_path=\"my_app.auth\", desired_level=\"INFO\"):\n    print(\"auth event\")\n\n# Primitive form — for callers that want explicit control over the config key.\n# No auto-prefixing: pass the full stored key.\nif client.should_log(config_key=\"log-level.my-app\", desired_level=\"DEBUG\"):\n    print(\"debug event\")\n```\n\n`logger_path` is passed through verbatim — the SDK does not normalize it, so\ncallers can author config rules against whatever shape their host language\nprefers (dotted, double-colon, slash, etc.).\n\n### Dynamic log levels with stdlib `logging`\n\nAttach `QuonfigLoggerFilter` to any logger or handler and the SDK will gate\nrecords against `logger_key`. The record's `name` flows into context verbatim\nas `quonfig-sdk-logging.key`, so a single config can drive per-logger rules.\n\n```python\nimport logging\nfrom quonfig import Quonfig, QuonfigLoggerFilter\n\nclient = Quonfig(sdk_key=\"sdk-...\", logger_key=\"log-level.my-app\").init()\n\nroot = logging.getLogger()\nroot.addFilter(QuonfigLoggerFilter(client))\n```\n\n### Dynamic log levels with `structlog`\n\n`QuonfigLoggerProcessor` is a structlog processor. Place it after\n`structlog.stdlib.add_log_level` so the level is populated on the event dict.\n\n```python\nimport structlog\nfrom quonfig import Quonfig, QuonfigLoggerProcessor\n\nclient = Quonfig(sdk_key=\"sdk-...\", logger_key=\"log-level.my-app\").init()\n\nstructlog.configure(\n    processors=[\n        structlog.stdlib.add_log_level,\n        QuonfigLoggerProcessor(client),\n        structlog.processors.JSONRenderer(),\n    ],\n)\n```\n\n`structlog` is an optional dependency — `QuonfigLoggerProcessor` raises\n`ImportError` with an install hint if it isn't available. The stdlib filter\nhas no optional-dep concern.\n\n## Datadir mode (local files)\n\n```python\nimport os\n\nclient = Quonfig(datadir=\"/path/to/workspace\", environment=\"production\")\nclient.init()\n```\n\n## Configuration\n\n| Param | Env var | Default |\n|-------|---------|---------|\n| `sdk_key` | `QUONFIG_SDK_KEY` | required for API mode |\n| `api_urls` | -- (derived from `QUONFIG_DOMAIN`) | `[\"https://primary.quonfig.com\", \"https://secondary.quonfig.com\"]` |\n| `telemetry_url` | -- (derived from `QUONFIG_DOMAIN`) | `https://telemetry.quonfig.com` |\n| `environment` | `QUONFIG_ENVIRONMENT` | `\"\"` |\n| `datadir` | `QUONFIG_DIR` | `None` |\n| `init_timeout` | -- | `10.0` |\n| `on_init_failure` | -- | `\"raise\"` |\n| `on_no_default` | -- | `\"error\"` |\n| `logger_key` | -- | `None` |\n\n### `QUONFIG_DOMAIN`\n\nA single env var governs the api, sse, and telemetry URL defaults:\n\n| Env var | Default | Effect |\n|---------|---------|--------|\n| `QUONFIG_DOMAIN` | `quonfig.com` | Sets `api_urls` to `https://primary.${DOMAIN}` + `https://secondary.${DOMAIN}` and `telemetry_url` to `https://telemetry.${DOMAIN}`. SSE host is derived by prepending `stream.` to the api host. |\n\nResolution order (highest wins):\n\n1. Explicit `api_urls=` / `telemetry_url=` kwargs (local-dev escape hatch).\n2. `QUONFIG_DOMAIN` env var.\n3. Hardcoded default `quonfig.com`.\n\nThe previously-supported `QUONFIG_API_URL`, `QUONFIG_API_URLS`, and\n`QUONFIG_TELEMETRY_URL` env vars have been removed.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fquonfig%2Fsdk-python","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fquonfig%2Fsdk-python","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fquonfig%2Fsdk-python/lists"}