This thread contains a patchset. You're looking at the original emails,
but you may wish to use the patch review UI.
Review patch
8
[PATCH 0/8] python: miscellaneous improvements
Hi,
This is a series of patches that fixes some bugs in the Python module
implementation along with implementing the method `get_install_dir`.
tinyjson's `json_create()` failed with out of memory while running
tests. This is the first time I've noticed a failure here, so for now I
have bumped the allowed max fields to 2048. I have tested it on
archlinuxarm (Rpi4) only.
I'm planning to import some of meson's Python test suite after
implementing `install_sources` (ongoing), so I haven't added any test
cases for `get_install_dir` yet.
Thanks!
Seedo Paul (8):
add module specific options for python
mod/python: accept kwarg 'pure' for find_installation
tinyjson: bump max fields to 2048
mod/python: fix logic when discovering python_installation
find_installation: use `python3` as fallback when cmd is empty
mod/python: store install_paths from introspection
string: add missing include
mod/python: implement `get_install_dir`
include/lang/object.h | 2 +
include/lang/string.h | 2 +
src/external/tinyjson.c | 2 +-
src/functions/modules/python.c | 136 +++++++++++++++++++++++---
src/lang/object.c | 3 +
src/meson_opts.c | 6 +-
src/script/global_options.meson | 6 ++
tests/project/muon/python/meson.build | 6 ++
8 files changed, 144 insertions(+), 19 deletions(-)
base-commit: 20cafd21421d417b8964723b4c06cfa28d857814
--
2.45.0
[PATCH 1/8] add module specific options for python
---
src/meson_opts.c | 6 ++++ --
src/script/global_options.meson | 6 ++++++
2 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/src/meson_opts.c b/src/meson_opts.c
index e543b2f5..0f4a19f3 100644
--- a/src/meson_opts.c
+++ b/src/meson_opts.c
@@ -425,8 +425,10 @@ translate_meson_opts_setup(struct workspace *wk, char *argv[], uint32_t argc, st
{ "pkgconfig.relocatable", .ignore = true },
{ "prefer-static", false, "prefer_static" },
{ "python.install-env", true, .ignore = true },
- { "python.platlibdir", true, .ignore = true },
- { "python.purelibdir", true, .ignore = true },
+ { "python.bytecompile", true, .ignore = true },
+ { "python.platlibdir", true },
+ { "python.purelibdir", true },
+ { "python.allow_limited_api", true, .ignore = true },
{ "stdsplit", false, "stdsplit" },
{ "strip", false, "strip" },
{ "unity", true, "unity" },
diff --git a/src/script/global_options.meson b/src/script/global_options.meson
index 7d6cfd80..f5525d6c 100644
--- a/src/script/global_options.meson
+++ b/src/script/global_options.meson
@@ -144,6 +144,12 @@ option('cpp_rtti', type: 'boolean', value: true) # TODO
option('cpp_thread_count', type: 'integer', value: 4, min: 0) # TODO
option('cpp_winlibs', type: 'array', value: []) # TODO
+ # Python specific options
+ option('python.bytecompile', type: 'integer', value: 0, min: -1, max: 2)
+ option('python.purelibdir', type: 'string', value: '')
+ option('python.platlibdir', type: 'string', value: '')
+ option('python.allow_limited_api', type: 'boolean', value: true)
+
# muon-specific options. These are safe from being overridden because meson
# forbids . in an opiton name
--
2.45.0
[PATCH 2/8] mod/python: accept kwarg 'pure' for find_installation
---
include/lang/object.h | 1 +
src/functions/modules/python.c | 9 +++++++++
src/lang/object.c | 1 +
3 files changed, 11 insertions(+)
diff --git a/include/lang/object.h b/include/lang/object.h
index a904ce87..4eda958d 100644
--- a/include/lang/object.h
+++ b/include/lang/object.h
@@ -323,6 +323,7 @@ struct obj_external_program {
struct obj_python_installation {
obj prog;
+ bool pure;
obj language_version;
obj sysconfig_paths;
obj sysconfig_vars;
diff --git a/src/functions/modules/python.c b/src/functions/modules/python.c
index c0f56287..731dc39b 100644
--- a/src/functions/modules/python.c
+++ b/src/functions/modules/python.c
@@ -6,6 +6,7 @@
#include "coerce.h"
#include "compat.h"
+ #include "lang/object.h"
#include <string.h>
#include "embedded.h"
@@ -104,15 +105,22 @@ func_module_python_find_installation(struct workspace *wk, obj self, obj *res)
kw_required,
kw_disabler,
kw_modules,
+ kw_pure,
};
struct args_kw akw[] = { [kw_required] = { "required", tc_required_kw },
[kw_disabler] = { "disabler", obj_bool },
[kw_modules] = { "modules", TYPE_TAG_LISTIFY | obj_string },
+ [kw_pure] = { "pure", obj_bool },
0 };
if (!pop_args(wk, an, akw)) {
return false;
}
+ bool pure = false;
+ if (akw[kw_pure].set) {
+ pure = get_obj_bool(wk, akw[kw_pure].val);
+ }
+
enum requirement_type requirement;
if (!coerce_requirement(wk, &akw[kw_required], &requirement)) {
return false;
@@ -162,6 +170,7 @@ func_module_python_find_installation(struct workspace *wk, obj self, obj *res)
make_obj(wk, res, obj_python_installation);
struct obj_python_installation *python = get_obj_python_installation(wk, *res);
+ python->pure = pure;
make_obj(wk, &python->prog, obj_external_program);
struct obj_external_program *ep = get_obj_external_program(wk, python->prog);
ep->found = found;
diff --git a/src/lang/object.c b/src/lang/object.c
index 94b18351..ea9f0455 100644
--- a/src/lang/object.c
+++ b/src/lang/object.c
@@ -1969,6 +1969,7 @@ obj_to_s_opts(struct workspace *wk, obj o, struct sbuf *sb, struct obj_to_s_opts
obj_to_s_opts(wk, py->prog, sb, opts);
if (get_obj_external_program(wk, py->prog)->found) {
+ sbuf_pushf(wk, sb, ", pure: %s", py->pure ? "true" : "false");
sbuf_pushf(wk, sb, ", language_version: %s", get_cstr(wk, py->language_version));
sbuf_pushs(wk, sb, ", sysconfig_paths: ");
obj_to_s_opts(wk, py->sysconfig_paths, sb, opts);
--
2.45.0
[PATCH 4/8] mod/python: fix logic when discovering python_installation
Earlier, the following line threw an error saying "failed to introspect
python interpreter":
py = import('python')
py_nonexisting = import('a_nonexisting_python_cmd', required: false)
The fix is to return early when the interpreter is not found, without
introspecting the (non-existing) interpreter.
---
src/functions/modules/python.c | 40 +++++++++++++++++ ----------
tests/project/muon/python/meson.build | 6 ++++
2 files changed, 31 insertions(+), 15 deletions(-)
diff --git a/src/functions/modules/python.c b/src/functions/modules/python.c
index 731dc39b..ba9c3da2 100644
--- a/src/functions/modules/python.c
+++ b/src/functions/modules/python.c
@@ -97,6 +97,26 @@ iterate_required_module_list(struct workspace *wk, void *ctx, obj val)
return ir_err;
}
+ static bool
+ build_python_installation(struct workspace *wk, obj self, obj *res, struct sbuf cmd_path, bool found, bool pure)
+ {
+ make_obj(wk, res, obj_python_installation);
+ struct obj_python_installation *python = get_obj_python_installation(wk, *res);
+ python->pure = pure;
+ make_obj(wk, &python->prog, obj_external_program);
+ struct obj_external_program *ep = get_obj_external_program(wk, python->prog);
+ ep->found = found;
+ make_obj(wk, &ep->cmd_array, obj_array);
+ obj_array_push(wk, ep->cmd_array, sbuf_into_str(wk, &cmd_path));
+
+ if (found && !introspect_python_interpreter(wk, cmd_path.buf, python)) {
+ vm_error(wk, "failed to introspect python");
+ return false;
+ }
+
+ return true;
+ }
+
static bool
func_module_python_find_installation(struct workspace *wk, obj self, obj *res)
{
@@ -145,6 +165,10 @@ func_module_python_find_installation(struct workspace *wk, obj self, obj *res)
return true;
}
+ if (!found) {
+ return build_python_installation(wk, self, res, cmd_path, found, pure);
+ }
+
if (akw[kw_modules].set && found) {
bool all_present = obj_array_foreach(wk,
akw[kw_modules].val,
@@ -168,21 +192,7 @@ func_module_python_find_installation(struct workspace *wk, obj self, obj *res)
}
}
- make_obj(wk, res, obj_python_installation);
- struct obj_python_installation *python = get_obj_python_installation(wk, *res);
- python->pure = pure;
- make_obj(wk, &python->prog, obj_external_program);
- struct obj_external_program *ep = get_obj_external_program(wk, python->prog);
- ep->found = found;
- make_obj(wk, &ep->cmd_array, obj_array);
- obj_array_push(wk, ep->cmd_array, sbuf_into_str(wk, &cmd_path));
-
- if (!introspect_python_interpreter(wk, cmd_path.buf, python)) {
- vm_error(wk, "failed to introspect python");
- return false;
- }
-
- return true;
+ return build_python_installation(wk, self, res, cmd_path, found, pure);
}
static bool
diff --git a/tests/project/muon/python/meson.build b/tests/project/muon/python/meson.build
index 34088022..fab0f045 100644
--- a/tests/project/muon/python/meson.build
+++ b/tests/project/muon/python/meson.build
@@ -10,6 +10,12 @@ if py.language_version().version_compare('< 3.6')
error('Invalid Python version, only >= 3.6 is supported.')
endif
+ py_nonexisting = import('nonexisting_python_b075e5a', required: false)
+
+ if py_nonexisting.found()
+ error('Python installation found that is unlikely to exist.')
+ endif
+
# kwargs
pymod_with_modules = py_mod.find_installation(
'python3',
--
2.45.0
[PATCH 3/8] tinyjson: bump max fields to 2048
Python introspection failed recently in my tests due to out of memory,
so double the maximum permitted fields.
---
src/external/tinyjson.c | 2 + -
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/external/tinyjson.c b/src/external/tinyjson.c
index 36b82ed9..9250b634 100644
--- a/src/external/tinyjson.c
+++ b/src/external/tinyjson.c
@@ -13,7 +13,7 @@
#include "lang/string.h"
#include "log.h"
- #define TINYJSON_MAX_FIELDS 1024
+ #define TINYJSON_MAX_FIELDS 2048
static bool
build_dict_from_json(struct workspace *wk, const json_t *json, obj *res)
--
2.45.0
[PATCH 5/8] find_installation: use `python3` as fallback when cmd is empty
Otherwise, muon hits an assertion and crashes.
---
src/functions/modules/python.c | 5 ++++ -
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/src/functions/modules/python.c b/src/functions/modules/python.c
index ba9c3da2..643cacfb 100644
--- a/src/functions/modules/python.c
+++ b/src/functions/modules/python.c
@@ -150,7 +150,10 @@ func_module_python_find_installation(struct workspace *wk, obj self, obj *res)
const char *cmd = "python3";
if (an[0].set) {
- cmd = get_cstr(wk, an[0].val);
+ const char *pycmd = get_cstr(wk, an[0].val);
+ if (pycmd && *pycmd) {
+ cmd = pycmd;
+ }
}
SBUF(cmd_path);
--
2.45.0
[PATCH 6/8] mod/python: store install_paths from introspection
---
include/lang/object.h | 1 +
src/functions/modules/python.c | 5 +++++
src/lang/object.c | 2 ++
3 files changed, 8 insertions(+)
diff --git a/include/lang/object.h b/include/lang/object.h
index 4eda958d..241245ce 100644
--- a/include/lang/object.h
+++ b/include/lang/object.h
@@ -327,6 +327,7 @@ struct obj_python_installation {
obj language_version;
obj sysconfig_paths;
obj sysconfig_vars;
+ obj install_paths;
};
enum run_result_flags {
diff --git a/src/functions/modules/python.c b/src/functions/modules/python.c
index 643cacfb..4e9400a5 100644
--- a/src/functions/modules/python.c
+++ b/src/functions/modules/python.c
@@ -52,6 +52,11 @@ introspect_python_interpreter(struct workspace *wk, const char *path, struct obj
success = false;
goto end;
}
+
+ if (!obj_dict_index_str(wk, res_introspect, "install_paths", &python->install_paths)) {
+ success = false;
+ goto end;
+ }
end:
run_cmd_ctx_destroy(&cmd_ctx);
return success;
diff --git a/src/lang/object.c b/src/lang/object.c
index ea9f0455..9a609dfa 100644
--- a/src/lang/object.c
+++ b/src/lang/object.c
@@ -1975,6 +1975,8 @@ obj_to_s_opts(struct workspace *wk, obj o, struct sbuf *sb, struct obj_to_s_opts
obj_to_s_opts(wk, py->sysconfig_paths, sb, opts);
sbuf_pushs(wk, sb, ", sysconfig_vars: ");
obj_to_s_opts(wk, py->sysconfig_vars, sb, opts);
+ sbuf_pushs(wk, sb, ", install_paths: ");
+ obj_to_s_opts(wk, py->install_paths, sb, opts);
}
sbuf_pushs(wk, sb, ">");
--
2.45.0
[PATCH 7/8] string: add missing include
fixes #123
---
include/lang/string.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/include/lang/string.h b/include/lang/string.h
index 07d4351f..2ee16644 100644
--- a/include/lang/string.h
+++ b/include/lang/string.h
@@ -8,6 +8,8 @@
#include "compat.h"
+ #include <string.h>
+
#include "lang/object.h"
struct workspace;
--
2.45.0
[PATCH 8/8] mod/python: implement `get_install_dir`
---
src/functions/modules/python.c | 79 +++++++++++++++++++++++++++++++++ -
1 file changed, 78 insertions(+), 1 deletion(-)
diff --git a/src/functions/modules/python.c b/src/functions/modules/python.c
index 4e9400a5..7c092be9 100644
--- a/src/functions/modules/python.c
+++ b/src/functions/modules/python.c
@@ -7,12 +7,14 @@
#include "compat.h"
#include "lang/object.h"
- #include <string.h>
+ #include "options.h"
+ #include "platform/path.h"
#include "embedded.h"
#include "external/tinyjson.h"
#include "functions/external_program.h"
#include "functions/modules/python.h"
+ #include "install.h"
#include "lang/typecheck.h"
#include "platform/filesystem.h"
#include "platform/run_cmd.h"
@@ -320,6 +322,80 @@ func_python_installation_has_var(struct workspace *wk, obj self, obj *res)
return true;
}
+ static bool
+ get_install_dir(struct workspace *wk, obj self, bool pure, const char *subdir, obj *res)
+ {
+ SBUF(installdir);
+
+ obj prefix;
+ get_option_value(wk, current_project(wk), "prefix", &prefix);
+
+ struct obj_python_installation *py = get_obj_python_installation(wk, self);
+
+ if (pure) {
+ obj puredir;
+ get_option_value(wk, current_project(wk), "python.purelibdir", &puredir);
+ if (!str_eql(get_str(wk, puredir), &WKSTR(""))) {
+ path_push(wk, &installdir, get_cstr(wk, puredir));
+ } else {
+ if (!obj_dict_index_str(wk, py->install_paths, "purelib", &puredir)) {
+ return false;
+ }
+ path_join_absolute(wk, &installdir, get_cstr(wk, prefix), get_cstr(wk, puredir));
+ }
+ } else {
+ obj platdir;
+ get_option_value(wk, current_project(wk), "python.platlibdir", &platdir);
+ if (!str_eql(get_str(wk, platdir), &WKSTR(""))) {
+ path_push(wk, &installdir, get_cstr(wk, platdir));
+ } else {
+ if (!obj_dict_index_str(wk, py->install_paths, "platlib", &platdir)) {
+ return false;
+ }
+ path_join_absolute(wk, &installdir, get_cstr(wk, prefix), get_cstr(wk, platdir));
+ }
+ }
+
+ if (subdir) {
+ path_push(wk, &installdir, subdir);
+ }
+
+ *res = sbuf_into_str(wk, &installdir);
+
+ return true;
+ }
+
+ static bool
+ func_python_installation_get_install_dir(struct workspace *wk, obj self, obj *res)
+ {
+ enum kwargs {
+ kw_pure,
+ kw_subdir,
+ };
+ struct args_kw akw[] = {
+ [kw_pure] = { "pure", obj_bool },
+ [kw_subdir] = { "subdir", obj_string },
+ 0
+ };
+
+ if (!pop_args(wk, NULL, akw)) {
+ return false;
+ }
+
+ struct obj_python_installation *py = get_obj_python_installation(wk, self);
+ bool pure = py->pure;
+ if (akw[kw_pure].set) {
+ pure = get_obj_bool(wk, akw[kw_pure].val);
+ }
+
+ const char *subdir = NULL;
+ if (akw[kw_subdir].set) {
+ subdir = get_cstr(wk, akw[kw_subdir].val);
+ }
+
+ return get_install_dir(wk, self, pure, subdir, res);
+ }
+
static obj
python_self_transform(struct workspace *wk, obj self)
{
@@ -349,6 +425,7 @@ const struct func_impl impl_tbl_module_python3[] = {
struct func_impl impl_tbl_python_installation[] = {
[ARRAY_LEN(impl_tbl_external_program) - 1] = { "get_path", func_python_installation_get_path, tc_string },
+ { "get_install_dir", func_python_installation_get_install_dir, tc_string },
{ "get_variable", func_python_installation_get_var, tc_string },
{ "has_path", func_python_installation_has_path, tc_bool },
{ "has_variable", func_python_installation_has_var, tc_bool },
--
2.45.0