@@ -246,13 +246,30 @@ def test_sample_rate_conversion_from_env():
246246 config = ScoutConfig ()
247247 with mock .patch .dict (os .environ , {"SCOUT_SAMPLE_RATE" : "50" }):
248248 value = config .value ("sample_rate" )
249- assert isinstance (value , int )
250- assert value == 50
249+ assert isinstance (value , float )
250+ assert value == 0.50 # 50 is converted to 0.50 for backwards compatibility
251251
252252
253253@pytest .mark .parametrize (
254254 "original, converted" ,
255- [("0" , 0 ), ("50" , 50 ), ("100" , 100 ), ("x" , 100 )],
255+ [
256+ # Float values (0-1 range)
257+ ("0" , 0.0 ),
258+ ("0.5" , 0.5 ),
259+ ("1" , 1.0 ),
260+ ("0.001" , 0.001 ),
261+ # Integer percentages (> 1, backwards compatibility)
262+ ("50" , 0.50 ),
263+ ("100" , 1.0 ),
264+ ("1" , 1.0 ),
265+ ("1.5" , 0.015 ), # 1.5% -> 0.015
266+ # Edge cases
267+ ("x" , 1.0 ), # Invalid defaults to 1.0
268+ (None , None ), # None is preserved
269+ # Clamping
270+ ("-2.5" , 0.0 ), # Negative values clamped to 0
271+ ("150" , 1.0 ), # > 100% clamped to 1.0
272+ ],
256273)
257274def test_sample_rate_conversion_from_python (original , converted ):
258275 ScoutConfig .set (sample_rate = original )
@@ -270,14 +287,21 @@ def test_endpoint_sampling_conversion_from_env():
270287 ):
271288 value = config .value ("sample_endpoints" )
272289 assert isinstance (value , dict )
273- assert value == {"endpoint" : 40 , "test" : 0 }
290+ assert value == {"endpoint" : 0. 40 , "test" : 0.0 } # Converted to floats
274291
275292
276293@pytest .mark .parametrize (
277294 "original, converted" ,
278295 [
279- ("/endpoint:40,/test:0" , {"endpoint" : 40 , "test" : 0 }),
280- ({"endpoint" : 40 , "test" : 0 }, {"endpoint" : 40 , "test" : 0 }),
296+ # String format with percentages (backwards compat)
297+ ("/endpoint:40,/test:0" , {"endpoint" : 0.40 , "test" : 0.0 }),
298+ # Dict format with percentages (backwards compat)
299+ ({"endpoint" : 40 , "test" : 0 }, {"endpoint" : 0.40 , "test" : 0.0 }),
300+ # Dict format with floats
301+ ({"endpoint" : 0.40 , "test" : 0.0 }, {"endpoint" : 0.40 , "test" : 0.0 }),
302+ # String format with floats
303+ ("/endpoint:0.5,/test:0.001" , {"endpoint" : 0.5 , "test" : 0.001 }),
304+ # Empty
281305 ("" , {}),
282306 (object (), {}),
283307 ],
@@ -296,14 +320,21 @@ def test_job_sampling_conversion_from_env():
296320 with mock .patch .dict (os .environ , {"SCOUT_SAMPLE_JOBS" : "job1:30,job2:70" }):
297321 value = config .value ("sample_jobs" )
298322 assert isinstance (value , dict )
299- assert value == {"job1" : 30 , "job2" : 70 }
323+ assert value == {"job1" : 0. 30 , "job2" : 0. 70 } # Converted to floats
300324
301325
302326@pytest .mark .parametrize (
303327 "original, converted" ,
304328 [
305- ("job1:30,job2:70" , {"job1" : 30 , "job2" : 70 }),
306- ({"job1" : 30 , "job2" : 70 }, {"job1" : 30 , "job2" : 70 }),
329+ # String format with percentages (backwards compat)
330+ ("job1:30,job2:70" , {"job1" : 0.30 , "job2" : 0.70 }),
331+ # Dict format with percentages (backwards compat)
332+ ({"job1" : 30 , "job2" : 70 }, {"job1" : 0.30 , "job2" : 0.70 }),
333+ # Dict format with floats
334+ ({"job1" : 0.30 , "job2" : 0.70 }, {"job1" : 0.30 , "job2" : 0.70 }),
335+ # String format with floats
336+ ("job1:0.5,job2:0.001" , {"job1" : 0.5 , "job2" : 0.001 }),
337+ # Empty
307338 ("" , {}),
308339 (object (), {}),
309340 ],
@@ -315,3 +346,44 @@ def test_job_sampling_conversion_from_python(original, converted):
315346 assert config .value ("sample_jobs" ) == converted
316347 finally :
317348 ScoutConfig .reset_all ()
349+
350+
351+ # Additional tests for nullable sample rates
352+ @pytest .mark .parametrize (
353+ "original, converted" ,
354+ [
355+ (None , None ),
356+ ("0" , 0.0 ),
357+ ("0.5" , 0.5 ),
358+ ("50" , 0.50 ),
359+ ("100" , 1.0 ),
360+ ],
361+ )
362+ def test_endpoint_sample_rate_nullable (original , converted ):
363+ """Test that endpoint_sample_rate allows None and converts other values."""
364+ ScoutConfig .set (endpoint_sample_rate = original )
365+ config = ScoutConfig ()
366+ try :
367+ assert config .value ("endpoint_sample_rate" ) == converted
368+ finally :
369+ ScoutConfig .reset_all ()
370+
371+
372+ @pytest .mark .parametrize (
373+ "original, converted" ,
374+ [
375+ (None , None ),
376+ ("0" , 0.0 ),
377+ ("0.5" , 0.5 ),
378+ ("50" , 0.50 ),
379+ ("100" , 1.0 ),
380+ ],
381+ )
382+ def test_job_sample_rate_nullable (original , converted ):
383+ """Test that job_sample_rate allows None and converts other values."""
384+ ScoutConfig .set (job_sample_rate = original )
385+ config = ScoutConfig ()
386+ try :
387+ assert config .value ("job_sample_rate" ) == converted
388+ finally :
389+ ScoutConfig .reset_all ()
0 commit comments