Skip to content

Commit 1b99719

Browse files
committed
Update python to match cpp version
1 parent ec03960 commit 1b99719

File tree

7 files changed

+99
-26
lines changed

7 files changed

+99
-26
lines changed

bazel/repositories.bzl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ load(
44
)
55

66
# NB: update_cpp_jsonnet.sh looks for these.
7-
CPP_JSONNET_SHA256 = "21ebdb2d9e3ac83f5ee80a94ef37112b412440407e2f3db8e8147544a64b8ae1"
8-
CPP_JSONNET_GITHASH = "ca2d672ffe4c243570671ee0cd62d887f123372e"
7+
CPP_JSONNET_SHA256 = "2f75785fcb66ac9d0fc05cbb8861263ec35a815bba574f0ec98462a74f6eed3d"
8+
CPP_JSONNET_GITHASH = "739d3ecafa2c6100ec97559751656a5e1f8488d4"
99

1010
def jsonnet_go_repositories():
1111
http_archive(

python/_jsonnet.c

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,6 @@ static struct JsonnetJsonValue *cpython_native_callback(
147147
void *ctx_, const struct JsonnetJsonValue * const *argv, int *succ)
148148
{
149149
const struct NativeCtx *ctx = ctx_;
150-
int i;
151150

152151
PyEval_RestoreThread(*ctx->py_thread);
153152

@@ -156,7 +155,7 @@ static struct JsonnetJsonValue *cpython_native_callback(
156155

157156
// Populate python function args.
158157
arglist = PyTuple_New(ctx->argc);
159-
for (i = 0; i < ctx->argc; ++i) {
158+
for (size_t i = 0; i < ctx->argc; ++i) {
160159
double d;
161160
const char *param_str = jsonnet_json_extract_string(ctx->vm, argv[i]);
162161
int param_null = jsonnet_json_extract_null(ctx->vm, argv[i]);
@@ -250,22 +249,21 @@ static int cpython_import_callback(void *ctx_, const char *base, const char *rel
250249
#if PY_MAJOR_VERSION >= 3
251250
if (!PyUnicode_Check(file_name) || !PyBytes_Check(file_content)) {
252251
#else
253-
if (!PyString_Check(file_name) || !PyString_Check(file_content)) {
252+
if (!PyString_Check(file_name) || !PyBytes_Check(file_content)) {
254253
#endif
255-
*buf = jsonnet_str_nonull(ctx->vm, "import_callback did not return (string, bytes)", buflen);
254+
*buf = jsonnet_str_nonull(ctx->vm, "import_callback did not return (string, bytes). Since 0.19.0 imports should be returned as bytes instead of as a string. You may want to call .encode() on your string.", buflen);
256255
success = 0;
257256
} else {
258-
const char *content_buf;
259-
const ssize_t content_len;
257+
char *content_buf;
258+
ssize_t content_len;
260259
#if PY_MAJOR_VERSION >= 3
261260
const char *found_here_cstr = PyUnicode_AsUTF8(file_name);
262-
PyBytes_AsStringAndSize(file_content, &content_buf, &content_len);
263261
#else
264262
const char *found_here_cstr = PyString_AsString(file_name);
265-
PyString_AsStringAndSize(file_content, &content_buf, &content_len);
266263
#endif
264+
PyBytes_AsStringAndSize(file_content, &content_buf, &content_len);
267265
*found_here = jsonnet_str(ctx->vm, found_here_cstr);
268-
*buflen = content_len - 1; // Python always adds a trailing null
266+
*buflen = content_len;
269267
*buf = jsonnet_realloc(ctx->vm, NULL, *buflen);
270268
memcpy(*buf, content_buf, *buflen);
271269
success = 1;
@@ -471,7 +469,8 @@ static int handle_native_callbacks(struct JsonnetVm *vm, PyObject *native_callba
471469
static PyObject* evaluate_file(PyObject* self, PyObject* args, PyObject *keywds)
472470
{
473471
const char *filename;
474-
char *out, *jpath_str;
472+
char *out;
473+
const char *jpath_str;
475474
unsigned max_stack = 500, gc_min_objects = 1000, max_trace = 20;
476475
double gc_growth_trigger = 2;
477476
int error;
@@ -560,7 +559,8 @@ static PyObject* evaluate_file(PyObject* self, PyObject* args, PyObject *keywds)
560559
static PyObject* evaluate_snippet(PyObject* self, PyObject* args, PyObject *keywds)
561560
{
562561
const char *filename, *src;
563-
char *out, *jpath_str;
562+
char *out;
563+
const char *jpath_str;
564564
unsigned max_stack = 500, gc_min_objects = 1000, max_trace = 20;
565565
double gc_growth_trigger = 2;
566566
int error;
@@ -654,7 +654,7 @@ static PyMethodDef module_methods[] = {
654654
};
655655

656656
#if PY_MAJOR_VERSION >= 3
657-
static struct PyModuleDef _gojsonnet =
657+
static struct PyModuleDef _module =
658658
{
659659
PyModuleDef_HEAD_INIT,
660660
"_gojsonnet",
@@ -665,11 +665,20 @@ static struct PyModuleDef _gojsonnet =
665665

666666
PyMODINIT_FUNC PyInit__gojsonnet(void)
667667
{
668-
return PyModule_Create(&_gojsonnet);
668+
PyObject *module = PyModule_Create(&_module);
669+
PyObject *version_str = PyUnicode_FromString(LIB_JSONNET_VERSION);
670+
if (PyModule_AddObject(module, "version", PyUnicode_FromString(LIB_JSONNET_VERSION)) < 0) {
671+
Py_XDECREF(version_str);
672+
}
673+
return module;
669674
}
670675
#else
671676
PyMODINIT_FUNC init_gojsonnet(void)
672677
{
673-
Py_InitModule3("_gojsonnet", module_methods, "A Python interface to Jsonnet.");
678+
PyObject *module = Py_InitModule3("_gojsonnet", module_methods, "A Python interface to Jsonnet.");
679+
PyObject *version_str = PyUnicode_FromString(LIB_JSONNET_VERSION);
680+
if (PyModule_AddObject(module, "version", PyString_FromString(LIB_JSONNET_VERSION)) < 0) {
681+
Py_XDECREF(version_str);
682+
}
674683
}
675684
#endif

python/_jsonnet_test.py

Lines changed: 70 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,12 @@
1313
# limitations under the License.
1414

1515
import os
16+
import sys
1617
import unittest
1718

1819
import _gojsonnet
1920

21+
2022
# Returns (full_path, contents) if the file was successfully retrieved,
2123
# (full_path, None) if file not found, or throws an exception when the path
2224
# is invalid or an IO error occured.
@@ -39,14 +41,16 @@ def try_path_cached(cache, dir, rel):
3941
cache[full_path] = f.read().encode()
4042
return full_path, cache[full_path]
4143

42-
43-
def import_callback(dir, rel):
44+
def import_callback_encode(dir, rel):
4445
cache = {}
4546
full_path, content = try_path_cached(cache, dir, rel)
4647
if content:
4748
return full_path, content
4849
raise RuntimeError('File not found')
4950

51+
def import_callback_empty_file_encode(dir, rel):
52+
return dir, b''
53+
5054

5155
# Test native extensions
5256
def concat(a, b):
@@ -81,39 +85,96 @@ def setUp(self):
8185
with open(self.input_filename, "r") as infile:
8286
self.input_snippet = infile.read()
8387

84-
def test_evaluate_file(self):
88+
def test_version(self):
89+
self.assertEqual(type(_gojsonnet.version), str)
90+
91+
def test_evaluate_file_encode(self):
8592
json_str = _gojsonnet.evaluate_file(
8693
self.input_filename,
87-
import_callback=import_callback,
94+
import_callback=import_callback_encode,
8895
native_callbacks=native_callbacks,
8996
)
9097
self.assertEqual(json_str, "true\n")
9198

92-
def test_evaluate_snippet(self):
99+
def test_evaluate_snippet_encode(self):
93100
json_str = _gojsonnet.evaluate_snippet(
94101
self.test_filename,
95102
self.input_snippet,
96-
import_callback=import_callback,
103+
import_callback=import_callback_encode,
97104
native_callbacks=native_callbacks,
98105
)
99106
self.assertEqual(json_str, "true\n")
100107

101-
def test_import(self):
108+
def test_evaluate_snippet_encode(self):
109+
json_str = _gojsonnet.evaluate_snippet(
110+
self.test_filename,
111+
self.input_snippet,
112+
import_callback=import_callback_encode,
113+
native_callbacks=native_callbacks,
114+
)
115+
self.assertEqual(json_str, "true\n")
116+
117+
def test_import_encode(self):
102118
json_str = _gojsonnet.evaluate_snippet(
103119
self.test_filename,
104120
"import 'trivial.jsonnet'",
105-
import_callback=import_callback,
121+
import_callback=import_callback_encode,
106122
native_callbacks=native_callbacks,
107123
)
108124
self.assertEqual(json_str, "42\n")
109125

126+
def test_import_no_eol_encode(self):
127+
json_str = _gojsonnet.evaluate_snippet(
128+
self.test_filename,
129+
"import 'trivial_no_eol.jsonnet'",
130+
import_callback=import_callback_encode,
131+
native_callbacks=native_callbacks,
132+
)
133+
self.assertEqual(json_str, "42\n")
134+
135+
def test_import_binary_encode(self):
136+
json_str = _gojsonnet.evaluate_snippet(
137+
self.test_filename,
138+
"importbin 'binary123.bin'",
139+
import_callback=import_callback_encode,
140+
native_callbacks=native_callbacks,
141+
)
142+
self.assertEqual(json_str, "[\n 1,\n 2,\n 3\n]\n")
143+
144+
def test_import_binary_sentinel_encode(self):
145+
json_str = _gojsonnet.evaluate_snippet(
146+
self.test_filename,
147+
"importbin 'binary1230123.bin'",
148+
import_callback=import_callback_encode,
149+
native_callbacks=native_callbacks,
150+
)
151+
self.assertEqual(json_str, "[\n 1,\n 2,\n 3,\n 0,\n 1,\n 2,\n 3\n]\n")
152+
153+
def test_import_str_empty_file_encode(self):
154+
json_str = _gojsonnet.evaluate_snippet(
155+
self.test_filename,
156+
"importstr 'binary123.bin'",
157+
import_callback=import_callback_empty_file_encode,
158+
native_callbacks=native_callbacks,
159+
)
160+
self.assertEqual(json_str, "\"\"\n")
161+
162+
def test_import_binary_empty_file_encode(self):
163+
json_str = _gojsonnet.evaluate_snippet(
164+
self.test_filename,
165+
"importbin 'binary123.bin'",
166+
import_callback=import_callback_empty_file_encode,
167+
native_callbacks=native_callbacks,
168+
)
169+
self.assertEqual(json_str, "[ ]\n")
170+
110171
def test_double_import(self):
111172
json_str = _gojsonnet.evaluate_snippet(
112173
self.test_filename,
113174
"local x = import 'trivial.jsonnet';\n" +
114175
"local y = import 'trivial.jsonnet';\n" +
115176
"x + y",
116-
import_callback=import_callback,
177+
import_callback=import_callback_encode,
117178
native_callbacks=native_callbacks,
118179
)
119180
self.assertEqual(json_str, "84\n")

python/testdata/binary123.bin

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+


python/testdata/binary1230123.bin

7 Bytes
Binary file not shown.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// used for testing imports
2+
42

0 commit comments

Comments
 (0)