diff --git a/src/runtime/python/pypgf.c b/src/runtime/python/pypgf.c index a24ab7f08..d000a8f51 100644 --- a/src/runtime/python/pypgf.c +++ b/src/runtime/python/pypgf.c @@ -372,6 +372,13 @@ static PyMethodDef PGF_methods[] = { "Create new transaction" }, + {"getGlobalFlag", (PyCFunction)PGF_getGlobalFlag, METH_VARARGS, + "Get the value of a global flag" + }, + {"getAbstractFlag", (PyCFunction)PGF_getAbstractFlag, METH_VARARGS, + "Get the value of an abstract flag" + }, + {NULL} /* Sentinel */ }; diff --git a/src/runtime/python/tests/test_transactions.py b/src/runtime/python/tests/test_transactions.py index 7e48179db..29203c7f1 100644 --- a/src/runtime/python/tests/test_transactions.py +++ b/src/runtime/python/tests/test_transactions.py @@ -128,3 +128,53 @@ def test_reduced_functions(gr6): def test_reduced_categories(gr6): assert gr6.categories == ["Float","Int","N","P","String"] + +# flags + +def test_global_flag_int(gr1): + val = 12345 + with pytest.raises(KeyError): + gr1.getGlobalFlag("intflag") + with gr1.newTransaction() as t: + t.setGlobalFlag("intflag", val) + assert gr1.getGlobalFlag("intflag") == val + +def test_global_flag_float(gr1): + val = math.e + with pytest.raises(KeyError): + gr1.getGlobalFlag("floatflag") + with gr1.newTransaction() as t: + t.setGlobalFlag("floatflag", val) + assert gr1.getGlobalFlag("floatflag") == val + +def test_global_flag_string(gr1): + val = "S" + with pytest.raises(KeyError): + gr1.getGlobalFlag("stringflag") + with gr1.newTransaction() as t: + t.setGlobalFlag("stringflag", val) + assert gr1.getGlobalFlag("stringflag") == val + +def test_abstract_flag_int(gr1): + val = -774763251095801167872 + with pytest.raises(KeyError): + gr1.getAbstractFlag("intflag") + with gr1.newTransaction() as t: + t.setAbstractFlag("intflag", val) + assert gr1.getAbstractFlag("intflag") == val + +def test_abstract_flag_float(gr1): + val = 0.1e-8 + with pytest.raises(KeyError): + gr1.getAbstractFlag("floatflag") + with gr1.newTransaction() as t: + t.setAbstractFlag("floatflag", val) + assert gr1.getAbstractFlag("floatflag") == val + +def test_abstract_flag_string(gr1): + val = "子曰:「學而時習之,不亦說乎?有朋自遠方來,不亦樂乎?" + with pytest.raises(KeyError): + gr1.getAbstractFlag("stringflag") + with gr1.newTransaction() as t: + t.setAbstractFlag("stringflag", val) + assert gr1.getAbstractFlag("stringflag") == val diff --git a/src/runtime/python/transactions.c b/src/runtime/python/transactions.c index 809af944e..84a675da7 100644 --- a/src/runtime/python/transactions.c +++ b/src/runtime/python/transactions.c @@ -63,6 +63,53 @@ PGF_newTransaction(PGFObject *self, PyObject *args) return trans; } +PyObject * +PGF_getGlobalFlag(PGFObject *self, PyObject *args) +{ + const char *s; + Py_ssize_t size; + if (!PyArg_ParseTuple(args, "s#", &s, &size)) + return NULL; + + PgfText *flagname = CString_AsPgfText(s, size); + + PgfExn err; + PgfLiteral lit = pgf_get_global_flag(self->db, self->revision, flagname, &unmarshaller, &err); + FreePgfText(flagname); + if (handleError(err) != PGF_EXN_NONE) { + return NULL; + } else if (lit == 0) { + PyErr_Format(PyExc_KeyError, "unknown global flag '%s'", s); + return NULL; + } + + return (PyObject *)lit; +} + + +PyObject * +PGF_getAbstractFlag(PGFObject *self, PyObject *args) +{ + const char *s; + Py_ssize_t size; + if (!PyArg_ParseTuple(args, "s#", &s, &size)) + return NULL; + + PgfText *flagname = CString_AsPgfText(s, size); + + PgfExn err; + PgfLiteral lit = pgf_get_abstract_flag(self->db, self->revision, flagname, &unmarshaller, &err); + FreePgfText(flagname); + if (handleError(err) != PGF_EXN_NONE) { + return NULL; + } else if (lit == 0) { + PyErr_Format(PyExc_KeyError, "unknown abstract flag '%s'", s); + return NULL; + } + + return (PyObject *)lit; +} + // ---------------------------------------------------------------------------- static void @@ -179,6 +226,56 @@ Transaction_dropCategory(TransactionObject *self, PyObject *args) Py_RETURN_NONE; } +static PyObject * +Transaction_setGlobalFlag(TransactionObject *self, PyObject *args) +{ + const char *s; + Py_ssize_t size; + PyObject *pyobj; + if (!PyArg_ParseTuple(args, "s#O", &s, &size, &pyobj)) + return NULL; + + PgfText *flagname = CString_AsPgfText(s, size); + if (!PyLong_Check(pyobj) && !PyFloat_Check(pyobj) && !PyUnicode_Check(pyobj)) { + PyErr_SetString(PyExc_TypeError, "flag value must be integer, float, or string"); + return NULL; + } + + PgfExn err; + pgf_set_global_flag(self->pgf->db, self->revision, flagname, (PgfLiteral) pyobj, &marshaller, &err); + FreePgfText(flagname); + if (handleError(err) != PGF_EXN_NONE) { + return NULL; + } + + Py_RETURN_NONE; +} + +static PyObject * +Transaction_setAbstractFlag(TransactionObject *self, PyObject *args) +{ + const char *s; + Py_ssize_t size; + PyObject *pyobj; + if (!PyArg_ParseTuple(args, "s#O", &s, &size, &pyobj)) + return NULL; + + PgfText *flagname = CString_AsPgfText(s, size); + if (!PyLong_Check(pyobj) && !PyFloat_Check(pyobj) && !PyUnicode_Check(pyobj)) { + PyErr_SetString(PyExc_TypeError, "flag value must be integer, float, or string"); + return NULL; + } + + PgfExn err; + pgf_set_abstract_flag(self->pgf->db, self->revision, flagname, (PgfLiteral) pyobj, &marshaller, &err); + FreePgfText(flagname); + if (handleError(err) != PGF_EXN_NONE) { + return NULL; + } + + Py_RETURN_NONE; +} + static TransactionObject * Transaction_enter(TransactionObject *self, PyObject *Py_UNUSED(ignored)) { @@ -242,13 +339,9 @@ static PyMethodDef Transaction_methods[] = { "Commit transaction" }, - {"__enter__", (PyCFunction)Transaction_enter, METH_NOARGS, - "" - }, - - {"__exit__", (PyCFunction)(void(*)(void))Transaction_exit, METH_FASTCALL, - "" - }, + // used in 'with'-syntax + {"__enter__", (PyCFunction)Transaction_enter, METH_NOARGS, ""}, + {"__exit__", (PyCFunction)(void(*)(void))Transaction_exit, METH_FASTCALL, ""}, {"createFunction", (PyCFunction)Transaction_createFunction, METH_VARARGS, "Create function" @@ -262,6 +355,13 @@ static PyMethodDef Transaction_methods[] = { {"dropCategory", (PyCFunction)Transaction_dropCategory, METH_VARARGS, "Drop category" }, + + {"setGlobalFlag", (PyCFunction)Transaction_setGlobalFlag, METH_VARARGS, + "Set a global flag" + }, + {"setAbstractFlag", (PyCFunction)Transaction_setAbstractFlag, METH_VARARGS, + "Set an abstract flag" + }, {NULL} /* Sentinel */ }; diff --git a/src/runtime/python/transactions.h b/src/runtime/python/transactions.h index 186ff1eda..af70d5e29 100644 --- a/src/runtime/python/transactions.h +++ b/src/runtime/python/transactions.h @@ -14,10 +14,11 @@ typedef struct { PyTypeObject pgf_TransactionType; -PyObject * -PGF_checkoutBranch(PGFObject *self, PyObject *args); +PyObject *PGF_checkoutBranch(PGFObject *self, PyObject *args); -TransactionObject * -PGF_newTransaction(PGFObject *self, PyObject *args); +TransactionObject *PGF_newTransaction(PGFObject *self, PyObject *args); + +PyObject *PGF_getGlobalFlag(PGFObject *self, PyObject *args); +PyObject *PGF_getAbstractFlag(PGFObject *self, PyObject *args); #endif // PYPGF_TRANSACTIONS_H_