Skip to content

Commit b50dfb9

Browse files
committed
Patch json-bigint to preserve MLflow parsing behavior
Keep json-bigint using plain objects and numeric floats so frontend record parsing and metric formatting keep working without the Databricks fork. Signed-off-by: mprahl <mprahl@users.noreply.github.com>
1 parent 2d76fc0 commit b50dfb9

4 files changed

Lines changed: 81 additions & 3 deletions

File tree

mlflow/server/js/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@
5858
"immutable": "3.8.1",
5959
"invariant": "^2.2.4",
6060
"js-yaml": "^3.14.0",
61-
"json-bigint": "^1.0.0",
61+
"json-bigint": "patch:json-bigint@npm%3A1.0.0#yarn/patches/json-bigint-npm-1.0.0-mlflow.patch",
6262
"leaflet": "^1.5.1",
6363
"lodash": "^4.17.21",
6464
"mod-arch-core": "^1.6.0",

mlflow/server/js/src/common/utils/FetchUtils.test.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,26 @@ describe('FetchUtils', () => {
136136
await new Promise(setImmediate);
137137
expect(mockResolve).toHaveBeenCalledWith({ a: '11111111222222223333333344444445555555555' });
138138
});
139+
it('jsonBigIntResponseParser preserves plain object prototypes', async () => {
140+
const mockResponse = {
141+
text: () => Promise.resolve('{"a": {"b": 1}}'),
142+
};
143+
jsonBigIntResponseParser({ resolve: mockResolve, response: mockResponse });
144+
await new Promise(setImmediate);
145+
const parsed = mockResolve.mock.calls[0][0];
146+
expect(parsed.hasOwnProperty('a')).toBe(true);
147+
expect(parsed.a.hasOwnProperty('b')).toBe(true);
148+
});
149+
it('jsonBigIntResponseParser preserves high precision floats as numbers', async () => {
150+
const mockResponse = {
151+
text: () => Promise.resolve('{"a": 0.00011124613492593128}'),
152+
};
153+
jsonBigIntResponseParser({ resolve: mockResolve, response: mockResponse });
154+
await new Promise(setImmediate);
155+
const parsed = mockResolve.mock.calls[0][0];
156+
expect(typeof parsed.a).toBe('number');
157+
expect(parsed.a.toExponential(3)).toBe('1.112e-4');
158+
});
139159
it('yamlResponseParser', async () => {
140160
const mockResponse = {
141161
text: () => Promise.resolve('artifact_path: model_signature\nflavors:\n keras:\n data: data\n'),

mlflow/server/js/yarn.lock

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4892,7 +4892,7 @@ __metadata:
48924892
jest-canvas-mock: "npm:^2.2.0"
48934893
jest-localstorage-mock: "npm:^2.3.0"
48944894
js-yaml: "npm:^3.14.0"
4895-
json-bigint: "npm:^1.0.0"
4895+
json-bigint: "patch:json-bigint@npm%3A1.0.0#yarn/patches/json-bigint-npm-1.0.0-mlflow.patch"
48964896
knip: "npm:^5.30.2"
48974897
leaflet: "npm:^1.5.1"
48984898
lodash: "npm:^4.17.21"
@@ -23405,7 +23405,7 @@ __metadata:
2340523405
languageName: node
2340623406
linkType: hard
2340723407

23408-
"json-bigint@npm:^1.0.0":
23408+
"json-bigint@npm:1.0.0":
2340923409
version: 1.0.0
2341023410
resolution: "json-bigint@npm:1.0.0"
2341123411
dependencies:
@@ -23414,6 +23414,15 @@ __metadata:
2341423414
languageName: node
2341523415
linkType: hard
2341623416

23417+
"json-bigint@patch:json-bigint@npm%3A1.0.0#yarn/patches/json-bigint-npm-1.0.0-mlflow.patch::locator=%40mlflow%2Fmlflow%40workspace%3A.":
23418+
version: 1.0.0
23419+
resolution: "json-bigint@patch:json-bigint@npm%3A1.0.0#yarn/patches/json-bigint-npm-1.0.0-mlflow.patch::version=1.0.0&hash=61ac52&locator=%40mlflow%2Fmlflow%40workspace%3A."
23420+
dependencies:
23421+
bignumber.js: "npm:^9.0.0"
23422+
checksum: 10c0/d5f02a7423bf44af46adbe4e604fd295445ee4681249ad485997bb16209475869b44f6fbaec1309ee42b79606f6a3d9a6a787c64993e67cfb6d16fa6012f59cc
23423+
languageName: node
23424+
linkType: hard
23425+
2341723426
"json-parse-better-errors@npm:^1.0.2":
2341823427
version: 1.0.2
2341923428
resolution: "json-parse-better-errors@npm:1.0.2"
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
diff --git a/lib/parse.js b/lib/parse.js
2+
index bb4e5eb..39363cd 100644
3+
--- a/lib/parse.js
4+
+++ b/lib/parse.js
5+
@@ -207,19 +207,22 @@ var json_parse = function (options) {
6+
} else {
7+
if (BigNumber == null) BigNumber = require('bignumber.js');
8+
//if (number > 9007199254740992 || number < -9007199254740992)
9+
- // Bignumber has stricter check: everything with length > 15 digits disallowed
10+
- if (string.length > 15)
11+
- return _options.storeAsString
12+
- ? string
13+
- : _options.useNativeBigInt
14+
- ? BigInt(string)
15+
- : new BigNumber(string);
16+
- else
17+
- return !_options.alwaysParseAsBig
18+
- ? number
19+
- : _options.useNativeBigInt
20+
- ? BigInt(number)
21+
- : new BigNumber(number);
22+
+ if (_options.storeAsString) {
23+
+ if (number >= Number.MAX_SAFE_INTEGER || number <= Number.MIN_SAFE_INTEGER) {
24+
+ return string;
25+
+ }
26+
+ } else {
27+
+ // Bignumber has stricter check: everything with length > 15 digits disallowed
28+
+ if (string.length > 15)
29+
+ return _options.useNativeBigInt
30+
+ ? BigInt(string)
31+
+ : new BigNumber(string);
32+
+ }
33+
+ return !_options.alwaysParseAsBig
34+
+ ? number
35+
+ : _options.useNativeBigInt
36+
+ ? BigInt(number)
37+
+ : new BigNumber(number);
38+
}
39+
},
40+
string = function () {
41+
@@ -327,7 +330,7 @@ var json_parse = function (options) {
42+
// Parse an object value.
43+
44+
var key,
45+
- object = Object.create(null);
46+
+ object = {};
47+
48+
if (ch === '{') {
49+
next('{');

0 commit comments

Comments
 (0)