Skip to content

Commit

Permalink
Fix and build python bindings
Browse files Browse the repository at this point in the history
Fixes the imported pythonix bindings to work with the current Nix
version and specifies the build expression for it
  • Loading branch information
infinisil committed Feb 2, 2023
1 parent 6018e85 commit 27993f4
Show file tree
Hide file tree
Showing 8 changed files with 67 additions and 27 deletions.
37 changes: 37 additions & 0 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,40 @@
postUnpack = "sourceRoot=$sourceRoot/perl";
});

passthru.python-bindings =
let
python = final.python3;
in python.pkgs.buildPythonPackage {
name = "nix";
format = "other";

src = self;
postUnpack = "sourceRoot=$sourceRoot/python";

nativeBuildInputs = [
final.buildPackages.ninja
(final.buildPackages.meson.override { python3 = python; })
final.buildPackages.pkgconfig
final.buildPackages.nix
];

strictDeps = true;

buildInputs = [
final.nix
final.boost
];

installCheckPhase = ''
export TEST_ROOT=$(mktemp -d)
export NIX_STATE_DIR=$TEST_ROOT/var/nix
export PYTHONPATH=$out/${python.sitePackages}
ninja test
'';
};

meta.platforms = systems;
};

Expand Down Expand Up @@ -442,6 +476,8 @@
# Perl bindings for various platforms.
perlBindings = nixpkgs.lib.genAttrs systems (system: self.packages.${system}.nix.perl-bindings);

pythonBindings = nixpkgs.lib.genAttrs systems (system: self.packages.${system}.nix.python-bindings);

# Binary tarball for various platforms, containing a Nix store
# with the closure of 'nix' package, and the second half of
# the installation script.
Expand Down Expand Up @@ -564,6 +600,7 @@
checks = forAllSystems (system: {
binaryTarball = self.hydraJobs.binaryTarball.${system};
perlBindings = self.hydraJobs.perlBindings.${system};
pythonBindings = self.hydraJobs.pythonBindings.${system};
installTests = self.hydraJobs.installTests.${system};
nixpkgsLibTests = self.hydraJobs.tests.nixpkgsLibTests.${system};
} // (nixpkgs.lib.optionalAttrs (builtins.elem system linux64BitSystems)) {
Expand Down
1 change: 1 addition & 0 deletions python/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.cache
1 change: 1 addition & 0 deletions python/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ project('python-nix', 'cpp',
python_mod = import('python3')
python_dep = dependency('python3', required : true)
nix_expr_dep = dependency('nix-expr', required: true)
nix_main_dep = dependency('nix-main', required: true)

python = python_mod.find_python()
test('python test', python, args : files('tests.py'))
Expand Down
3 changes: 2 additions & 1 deletion python/src/eval.cc
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@ static PyObject *_eval(const char *expression, PyObject *vars) {
if (!staticEnv) {
return nullptr;
}
auto staticEnvPointer = std::make_shared<nix::StaticEnv>(*staticEnv);

auto e = state.parseExprFromString(expression, ".", *staticEnv);
auto e = state.parseExprFromString(expression, ".", staticEnvPointer);
nix::Value v;
e->eval(state, *env, v);

Expand Down
2 changes: 1 addition & 1 deletion python/src/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ src = [
]

python_mod.extension_module('nix', src,
dependencies : [python_dep, nix_expr_dep],
dependencies : [python_dep, nix_expr_dep, nix_main_dep],
install: true,
install_dir: python_mod.sysconfig_path('platlib'),
cpp_args: ['-std=c++17', '-fvisibility=hidden'])
18 changes: 7 additions & 11 deletions python/src/nix-to-python.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@ PyObject *nixToPythonObject(nix::EvalState &state, nix::Value &v,
copyContext(v, context);
return PyUnicode_FromString(v.string.s);

case nix::nPath:
return PyUnicode_FromString(state.copyPathToStore(context, v.path).c_str());
case nix::nPath: {
auto p = state.copyPathToStore(context, v.path).to_string();
return PyUnicode_FromStringAndSize(p.data(), p.length());
}

case nix::nNull:
Py_RETURN_NONE;
Expand All @@ -36,19 +38,13 @@ PyObject *nixToPythonObject(nix::EvalState &state, nix::Value &v,
return (PyObject *)nullptr;
}

nix::StringSet names;

for (auto &j : *v.attrs) {
names.insert(j.name);
}
for (auto &j : names) {
nix::Attr &a(*v.attrs->find(state.symbols.create(j)));

auto value = nixToPythonObject(state, *a.value, context);
const std::string & name = state.symbols[j.name];
auto value = nixToPythonObject(state, *j.value, context);
if (!value) {
return nullptr;
}
PyDict_SetItemString(dict.get(), j.c_str(), value);
PyDict_SetItemString(dict.get(), name.c_str(), value);
}
return dict.release();
} else {
Expand Down
3 changes: 3 additions & 0 deletions python/src/python-module.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
#include <nix/config.h>

#include <eval.hh>
#include <globals.hh>
#include <shared.hh>

namespace pythonnix {

Expand All @@ -25,6 +27,7 @@ static struct PyModuleDef nixmodule = {
NixMethods};

extern "C" _public_ PyObject *PyInit_nix(void) {
nix::initNix();
nix::initGC();

PyObjPtr m(PyModule_Create(&nixmodule));
Expand Down
29 changes: 15 additions & 14 deletions python/src/python-to-nix.cc
Original file line number Diff line number Diff line change
Expand Up @@ -70,16 +70,16 @@ nix::Value *pythonToNixValue(nix::EvalState &state, PyObject *obj) {
auto v = state.allocValue();

if (obj == Py_True && obj == Py_False) {
nix::mkBool(*v, obj == Py_True);
v->mkBool(obj == Py_True);
} else if (obj == Py_None) {
nix::mkNull(*v);
v->mkNull();
} else if (PyBytes_Check(obj)) {
auto str = checkNullByte(PyBytes_AS_STRING(obj), PyBytes_GET_SIZE(obj));
if (!str) {
return nullptr;
}

nix::mkString(*v, str);
v->mkString(str);
} else if (PyUnicode_Check(obj)) {
Py_ssize_t size;
const char *utf8 = PyUnicode_AsUTF8AndSize(obj, &size);
Expand All @@ -88,13 +88,13 @@ nix::Value *pythonToNixValue(nix::EvalState &state, PyObject *obj) {
return nullptr;
}

nix::mkString(*v, utf8);
v->mkString(utf8);
} else if (PyFloat_Check(obj)) {
nix::mkFloat(*v, PyFloat_AS_DOUBLE(obj));
v->mkFloat(PyFloat_AS_DOUBLE(obj));
} else if (PyLong_Check(obj)) {
nix::mkInt(*v, PyLong_AsLong(obj));
v->mkInt(PyLong_AsLong(obj));
} else if (PyList_Check(obj)) {
state.mkList(*v, PyList_GET_SIZE(obj));
v->mkList(PyList_GET_SIZE(obj));
for (Py_ssize_t i = 0; i < PyList_GET_SIZE(obj); i++) {
auto val = pythonToNixValue(state, PyList_GET_ITEM(obj, i));
if (!val) {
Expand All @@ -103,7 +103,7 @@ nix::Value *pythonToNixValue(nix::EvalState &state, PyObject *obj) {
v->listElems()[i] = val;
}
} else if (PyTuple_Check(obj)) {
state.mkList(*v, PyTuple_GET_SIZE(obj));
v->mkList(PyTuple_GET_SIZE(obj));
for (Py_ssize_t i = 0; i < PyTuple_GET_SIZE(obj); i++) {
auto val = pythonToNixValue(state, PyTuple_GET_ITEM(obj, i));
if (!val) {
Expand All @@ -116,11 +116,12 @@ nix::Value *pythonToNixValue(nix::EvalState &state, PyObject *obj) {
if (!attrs) {
return nullptr;
}
state.mkAttrs(*v, attrs->size());
for (auto &attr : *attrs) {
v->attrs->push_back(nix::Attr(attr.first, attr.second));
auto attrsValue = attrs.value();
auto bindings = state.buildBindings(attrsValue.size());
for (auto &attr : attrsValue) {
bindings.insert(attr.first, attr.second);
}
v->attrs->sort();
v->mkAttrs(bindings);
}
return v;
}
Expand All @@ -133,7 +134,7 @@ std::optional<nix::StaticEnv> pythonToNixEnv(nix::EvalState &state,
*env = &state.allocEnv(vars ? PyDict_Size(vars) : 0);
(*env)->up = &state.baseEnv;

nix::StaticEnv staticEnv(false, &state.staticBaseEnv);
nix::StaticEnv staticEnv(false, state.staticBaseEnv.get());

if (!vars) {
return staticEnv;
Expand All @@ -150,7 +151,7 @@ std::optional<nix::StaticEnv> pythonToNixEnv(nix::EvalState &state,
if (!attrVal) {
return {};
}
staticEnv.vars[state.symbols.create(name)] = displ;
staticEnv.vars.emplace_back(state.symbols.create(name), displ);
(*env)->values[displ++] = attrVal;
}

Expand Down

0 comments on commit 27993f4

Please sign in to comment.