fix: std.format accepts boolean for numeric conversion codes#233
Conversation
The official Jsonnet spec states that std.format follows Python's string formatting rules. In Python, bool is a subclass of int, so "%d" % True returns "1". This fix coerces boolean values to 0.0/1.0 before processing numeric conversion codes, matching Python's behavior.
But this is not a formatting rule, this is a type coercion rule Formatting itself has nothing to do with it if it just expects input value to be an instance of int; the same rule is currently followed in jrsonnet/cpp-jsonnet/go-jsonnet with the exception that bool is not a subclass of int |
|
in databricks/sjsonnet#1053 stephenamar-db @stephenamar-db revert to this kind of behavior and include the |
|
as I said in my revert, the documentation states that std.format follows the same rules as Python2, which implicitly converts booleans to 1/0. |
But it doesn't. %f accepts numbers, and bool is instanceof number in python (but not in jsonnet). No conversion happens on the formatting side, this just happens because of the unfortunate inheritance chain in the python language, and it is fine, as in jsonnet booleans are not accepted where the code expects numbers. |
|
You are right, it's not a conversion. My point still stands, if the documentation says that it follows the rules of python2 format, this includes treating booleans as integers. |
There is no such rule in python format Why borrow footguns and unexpected non-type-safe behavior from python, when this behavior can be easily replicated if really wanted? |
|
sjsonnet stuck in some weird state, because if folow the "rules" the way you propose, then this should be valid too: # Boolean is accepted as precision in python because bool extends int
"%.*f" % (False, 3.14159) == '3'
"%.*f" % (True, 3.14159) == '3.1'But it isn't the case for sjsonnet "%.*f" % [false, 3.14159]And I don't think it should, as this is dumb |
|
I think it would be best to standardize and refine the spec and documentation; there are indeed quite a few details that need clarification. |
|
fair point. Right now it's just back to the previous state. Maybe we'll rollforward behind a flag. |
|
Closing because of the reasons I already explained. |
|
thanks |
Summary
The official Jsonnet spec states:
In Python,
boolis a subclass ofint, so"%d" % Truereturns"1". However, jrsonnet currently rejects booleans for all numeric conversion codes withtype error: expected number, got boolean.This fix coerces
Val::Bool(true)toVal::Num(1.0)andVal::Bool(false)toVal::Num(0.0)before numeric conversion informat_code(), matching Python's behavior.The
%sconversion is intentionally left unchanged, as Python's"%s" % Truereturns"True"(not"1").Related upstream PRs: google/jsonnet#1328, google/go-jsonnet#884
Before / After
"%d" % true"1""1""%f" % false"0.000000""0.000000""%x" % true"1""1""%o" % true"1""1""%e" % true"1.000000e+00""1.000000e+00""%g" % true"1""1""%c" % true"\x01""\x01""%s" % true"True""true""true"(unchanged)Test plan
cargo test -p jrsonnet-evaluator-- 7/7 passed)bool->intbehavior for all numeric codes (%d,%o,%x,%e,%f,%g)%c(character code) matching Python%sconversion unaffected -- booleans still render as"true"/"false"