@@ -41,14 +41,14 @@ with Replane(
4141 sdk_key = " rp_..." ,
4242) as replane:
4343 # Get a simple config value
44- rate_limit = replane.configs[" rate-limit " ]
44+ rate_limit = replane.configs[" rate_limit " ]
4545
4646 # Get with context for override evaluation
4747 user_client = replane.with_context({" user_id" : user.id, " plan" : user.plan})
48- feature_enabled = user_client.configs[" new-feature " ]
48+ feature_enabled = user_client.configs[" new_feature " ]
4949
5050 # Get with fallback default
51- timeout = replane.configs.get(" request-timeout " , 30 )
51+ timeout = replane.configs.get(" request_timeout " , 30 )
5252```
5353
5454### Asynchronous Client
@@ -63,7 +63,7 @@ async with AsyncReplane(
6363 sdk_key = " rp_..." ,
6464) as replane:
6565 # Access configs from local cache
66- rate_limit = replane.configs[" rate-limit " ]
66+ rate_limit = replane.configs[" rate_limit " ]
6767
6868 # With context
6969 enabled = replane.with_context({" plan" : " premium" }).configs[" feature" ]
@@ -89,9 +89,9 @@ replane.connect(
8989)
9090
9191# Use configs
92- rate_limit = replane.configs[" rate-limit " ]
92+ rate_limit = replane.configs[" rate_limit " ]
9393user_client = replane.with_context({" user_id" : " 123" })
94- feature = user_client.configs[" feature-flag " ]
94+ feature = user_client.configs[" feature_flag " ]
9595
9696# Don't forget to close when done
9797replane.close()
@@ -111,23 +111,23 @@ with Replane[Configs](
111111 sdk_key = " rp_..." ,
112112) as replane:
113113 # Access configs with dictionary-style notation
114- settings = replane.configs[" app-settings " ]
114+ settings = replane.configs[" app_settings " ]
115115
116116 # Full type safety - IDE knows the structure of settings
117117 print (settings[" max_upload_size_mb" ])
118118 print (settings[" allowed_file_types" ])
119119
120120 # Check if config exists
121- if " feature-flag " in replane.configs:
122- flag = replane.configs[" feature-flag " ]
121+ if " feature_flag " in replane.configs:
122+ flag = replane.configs[" feature_flag " ]
123123
124124 # Safe access with default
125125 timeout = replane.configs.get(" timeout" , 30 )
126126```
127127
128128The ` .configs ` property provides:
129129
130- - ** Dictionary-style access** with ` replane.configs["config-name "] `
130+ - ** Dictionary-style access** with ` replane.configs["config_name "] `
131131- ** Type inference** when using generated TypedDict types
132132- ** Override evaluation** using the default context
133133- ** Familiar dict methods** : ` .get() ` , ` .keys() ` , ` in ` operator
@@ -146,12 +146,12 @@ replane = Replane(
146146
147147 # Default values used if server is unavailable during init
148148 defaults = {
149- " rate-limit " : 100 ,
150- " feature-enabled " : False ,
149+ " rate_limit " : 100 ,
150+ " feature_enabled " : False ,
151151 },
152152
153153 # Configs that must exist (raises error if missing)
154- required = [" rate-limit " , " feature-enabled " ],
154+ required = [" rate_limit " , " feature_enabled " ],
155155
156156 # Timeouts in milliseconds
157157 request_timeout_ms = 2000 ,
@@ -181,7 +181,7 @@ context = {
181181}
182182
183183# Overrides are evaluated locally using with_context()
184- value = replane.with_context(context).configs[" feature-flag " ]
184+ value = replane.with_context(context).configs[" feature_flag " ]
185185```
186186
187187### Scoped Clients with ` with_context() `
@@ -200,8 +200,8 @@ with Replane(
200200 })
201201
202202 # All operations use the merged context
203- rate_limit = user_client.configs[" rate-limit " ]
204- settings = user_client.configs[" app-settings " ]
203+ rate_limit = user_client.configs[" rate_limit " ]
204+ settings = user_client.configs[" app_settings " ]
205205
206206 # Can be chained for additional context
207207 request_client = user_client.with_context({" region" : request.region})
@@ -221,15 +221,15 @@ with Replane(
221221 # Create a client with fallback defaults
222222 safe_client = replane.with_defaults({
223223 " timeout" : 30 ,
224- " max-retries " : 3 ,
224+ " max_retries " : 3 ,
225225 })
226226
227227 # Returns the default if config doesn't exist
228228 timeout = safe_client.configs[" timeout" ] # 30 if not configured
229229
230230 # Chain with with_context() for both features
231231 user_client = replane.with_context({" plan" : " premium" }).with_defaults({
232- " rate-limit " : 1000 ,
232+ " rate_limit " : 1000 ,
233233 })
234234```
235235
@@ -242,20 +242,20 @@ Explicit defaults in `.configs.get()` take precedence over scoped defaults.
242242``` python
243243# Server config has 10% rollout based on user_id
244244# Same user always gets same result (deterministic hashing)
245- enabled = replane.with_context({" user_id" : user.id}).configs[" new-checkout " ]
245+ enabled = replane.with_context({" user_id" : user.id}).configs[" new_checkout " ]
246246```
247247
248248** Plan-based features** :
249249
250250``` python
251- max_items = replane.with_context({" plan" : user.plan}).configs[" max-items " ]
251+ max_items = replane.with_context({" plan" : user.plan}).configs[" max_items " ]
252252# Returns different values for free/pro/enterprise plans
253253```
254254
255255** Geographic targeting** :
256256
257257``` python
258- content = replane.with_context({" country" : request.country}).configs[" homepage-banner " ]
258+ content = replane.with_context({" country" : request.country}).configs[" homepage_banner " ]
259259```
260260
261261## Subscribing to Changes
@@ -273,7 +273,7 @@ unsubscribe = replane.subscribe(on_any_change)
273273def on_feature_change (config ):
274274 update_feature_state(config.value)
275275
276- unsubscribe_feature = replane.subscribe_config(" my-feature " , on_feature_change)
276+ unsubscribe_feature = replane.subscribe_config(" my_feature " , on_feature_change)
277277
278278# Later: stop receiving updates
279279unsubscribe()
@@ -301,7 +301,7 @@ from replane import (
301301)
302302
303303try :
304- value = replane.configs[" my-config " ]
304+ value = replane.configs[" my_config " ]
305305except KeyError as e:
306306 print (f " Config not found: { e} " )
307307except TimeoutError as e:
@@ -321,11 +321,11 @@ from replane.testing import create_test_client, InMemoryReplaneClient
321321
322322# Simple usage
323323replane = create_test_client({
324- " feature-enabled " : True ,
325- " rate-limit " : 100 ,
324+ " feature_enabled " : True ,
325+ " rate_limit " : 100 ,
326326})
327327
328- assert replane.configs[" feature-enabled " ] is True
328+ assert replane.configs[" feature_enabled " ] is True
329329
330330# With overrides
331331replane = InMemoryReplaneClient()
@@ -354,13 +354,13 @@ from replane.testing import create_test_client
354354@pytest.fixture
355355def replane_client ():
356356 return create_test_client({
357- " feature-flags " : {" dark-mode " : True , " new-ui" : False },
358- " rate-limits " : {" default" : 100 , " premium" : 1000 },
357+ " feature_flags " : {" dark_mode " : True , " new-ui" : False },
358+ " rate_limits " : {" default" : 100 , " premium" : 1000 },
359359 })
360360
361361def test_feature_flag (replane_client ):
362- flags = replane_client.configs[" feature-flags " ]
363- assert flags[" dark-mode " ] is True
362+ flags = replane_client.configs[" feature_flags " ]
363+ assert flags[" dark_mode " ] is True
364364```
365365
366366## Manual Lifecycle Management
@@ -420,7 +420,7 @@ Replane = Annotated[AsyncReplane, Depends(get_replane)]
420420
421421@app.get (" /items" )
422422async def get_items (replane : Replane):
423- max_items = replane.with_context({" plan" : " free" }).configs[" max-items " ]
423+ max_items = replane.with_context({" plan" : " free" }).configs[" max_items " ]
424424 return {" max_items" : max_items}
425425```
426426
@@ -444,7 +444,7 @@ def init_replane():
444444
445445@app.route (" /items" )
446446def get_items ():
447- max_items = _replane.configs[" max-items " ]
447+ max_items = _replane.configs[" max_items " ]
448448 return {" max_items" : max_items}
449449```
450450
0 commit comments