changeset 610:764d4185c76a

C-implementations of Configuration.getvarl_s() and Configuration.getvar()
author Franz Glasner <fzglas.hg@dom66.de>
date Wed, 12 Jan 2022 00:44:02 +0100
parents 9ad860d6ddc9
children db5a20f18030
files configmix/_speedups.c configmix/config.py
diffstat 2 files changed, 158 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- a/configmix/_speedups.c	Tue Jan 11 21:17:06 2022 +0100
+++ b/configmix/_speedups.c	Wed Jan 12 00:44:02 2022 +0100
@@ -1257,6 +1257,61 @@
 }
 
 
+static
+PyObject *
+fast_getvarl_s(PyObject *self, PyObject *args, PyObject *kwds)
+{
+    static char *kwlist[] = {"config", "path", "namespace", "default", NULL};
+
+    PyObject *config;
+    PyObject *path;
+    PyObject *namespace = NULL;
+    PyObject *default_ = NULL;
+
+    PyObject *res = NULL;
+    PyObject *tmp;
+
+    struct speedups_state *sstate;
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO!|$OO", kwlist, &config, &PyTuple_Type, &path, &namespace, &default_)) {
+
+        return NULL;
+    }
+    sstate = PyModule_GetState(self);
+    if (sstate == NULL) {
+        PyErr_SetString(PyExc_RuntimeError, "no module state available");
+        return NULL;
+    }
+
+    tmp = _fast_getvarl(config, path, namespace, NULL, sstate);
+    if (tmp == NULL) {
+        goto handle_possible_keyerror;
+    }
+    res = PyObject_CallMethod(config, "substitute_variables_in_obj", "O", tmp);
+    if (res == NULL) {
+        py_clear_ref(&tmp);
+        goto handle_possible_keyerror;
+    }
+    py_clear_ref(&tmp);
+    return res;
+
+handle_possible_keyerror:
+    if (PyErr_ExceptionMatches(PyExc_KeyError)) {
+        if ((default_ == NULL) || py_object_is(default_, sstate->MARKER)) {
+            /* fall through */
+        }
+        else {
+            PyErr_Clear();
+            return Py_NewRef(default_);
+        }
+    }
+    /* fall through */
+
+error:
+    return NULL;
+}
+
+
 /**
  * Combination of py_getvar_s and _py_getvar_s_with_cache_info
  */
@@ -1267,7 +1322,7 @@
     PyObject *varname_b;            /* always borrowed */
     PyObject *namespace_b;          /* always borrowed */
     PyObject *splitted = NULL;
-    PyObject *res = NULL;
+    PyObject *res;
     PyObject *tmp1;
     PyObject *tmp2;
 
@@ -1331,15 +1386,82 @@
         }
         else {
             PyErr_Clear();
-            Py_XDECREF(res);
             Py_XDECREF(splitted);
             return Py_NewRef(default_);
         }
     }
-    /* fall through */    
-    
+    /* fall through */
+
 error:
-    Py_XDECREF(res);
+    Py_XDECREF(splitted);
+    return NULL;
+}
+
+
+static
+PyObject *
+fast_getvar(PyObject *self, PyObject *args)
+{
+    PyObject *config;
+    PyObject *varname;
+    PyObject *default_;
+
+    PyObject *varname_b;            /* always borrowed */
+    PyObject *namespace_b;          /* always borrowed */
+    PyObject *splitted = NULL;
+    PyObject *res;
+    PyObject *tmp1;
+    struct speedups_state *sstate;
+
+    if (!PyArg_UnpackTuple(args, "config", 3, 3, &config, &varname, &default_)) {
+        return NULL;
+    }
+
+    splitted = fast_split_ns(self, varname);
+    if (splitted == NULL) {
+        goto error;
+    }
+    namespace_b = PyTuple_GetItem(splitted, 0);   /* borrowed */
+    varname_b = PyTuple_GetItem(splitted, 1);     /* borrowed */
+
+    sstate = PyModule_GetState(self);
+    if (sstate == NULL) {
+        PyErr_SetString(PyExc_RuntimeError, "no module state available");
+        goto error;
+    }
+
+    if (PyObject_Not(namespace_b)) {
+        tmp1 = _fast_pathstr2path(varname_b, NULL, sstate);
+        if (tmp1 == NULL) {
+            goto error;
+        }
+        res = _fast_getvarl(config, tmp1, NULL, default_, sstate);
+        if (res == NULL) {
+            py_clear_ref(&tmp1);
+            goto error;
+        }
+        py_clear_ref(&tmp1);
+    }
+    else {
+        tmp1 = PyTuple_New(1);
+        if (tmp1 == NULL) {
+            goto error;
+        }
+        PyTuple_SetItem(tmp1, 0, Py_NewRef(varname_b));
+        res = _fast_getvarl(config, tmp1, namespace_b, default_, sstate);
+        if (res == NULL) {tmp1 = _fast_pathstr2path(varname_b, NULL, sstate);
+        if (tmp1 == NULL) {
+            goto error;
+        }
+            py_clear_ref(&tmp1);
+            goto error;
+        }
+        py_clear_ref(&tmp1);
+    }
+    Py_DECREF(splitted);
+    return res;
+
+error:
     Py_XDECREF(splitted);
     return NULL;
 }
@@ -1416,7 +1538,9 @@
     {"_fast_split_ns", fast_split_ns, METH_O, PyDoc_STR("C-implementation of configmix.config._split_ns")},
     {"_fast_interpolate_variables", fast_interpolate_variables, METH_VARARGS, PyDoc_STR("C-implementation of configmix.config.Configuration.interpolate_variables")},
     {"_fast_getvarl", (PyCFunction)fast_getvarl, METH_VARARGS | METH_KEYWORDS, PyDoc_STR("C-Implementation of configmix.config.Configuration.getvarl")},
-    {"_fast_getvar_s", fast_getvar_s, METH_VARARGS, PyDoc_STR("C-Implementation of configmix.config.Configuration.getvar_s")},    
+    {"_fast_getvarl_s", (PyCFunction)fast_getvarl_s, METH_VARARGS | METH_KEYWORDS, PyDoc_STR("C-Implementation of configmix.config.Configuration.getvarl_s")},
+    {"_fast_getvar", fast_getvar, METH_VARARGS, PyDoc_STR("C-Implementation of configmix.config.Configuration.getvar")},
+    {"_fast_getvar_s", fast_getvar_s, METH_VARARGS, PyDoc_STR("C-Implementation of configmix.config.Configuration.getvar_s")},
     {"_sync_MISSING", sync_MISSING, METH_O, PyDoc_STR("Internal function to easily sync the _MISSING object with configmix.config")},
     {"_sync_MARKER", sync_MARKER, METH_O, PyDoc_STR("Internal function to easily sync the _MARKER object with configmix.config")},
     {NULL, NULL, 0, NULL}
--- a/configmix/config.py	Tue Jan 11 21:17:06 2022 +0100
+++ b/configmix/config.py	Wed Jan 12 00:44:02 2022 +0100
@@ -33,7 +33,8 @@
 try:
     from ._speedups import (fast_unquote, fast_quote, fast_pathstr2path,
                             _fast_split_ns, _fast_split_filters,
-                            _fast_getvarl, _fast_getvar_s,
+                            _fast_getvarl, _fast_getvarl_s,
+                            _fast_getvar, _fast_getvar_s,
                             _fast_interpolate_variables,
                             _sync_MISSING, _sync_MARKER)
 except ImportError:
@@ -43,6 +44,8 @@
     _fast_split_ns = None
     _fast_split_filters = None
     _fast_getvarl = None
+    _fast_getvarl_s = None
+    _fast_getvar = None
     _fast_getvar_s = None
     _fast_interpolate_variables = None
     _sync_MISSING = None
@@ -607,7 +610,7 @@
         else:
             return default
 
-    def getvar(self, varname, default=_MARKER):
+    def py_getvar(self, varname, default=_MARKER):
         """Get a variable of the form ``[ns:][[key1.]key2.]name`` - including
         variables from other namespaces.
 
@@ -625,6 +628,17 @@
         else:
             return self.getvarl(varname, namespace=varns, default=default)
 
+    if _fast_getvar:
+
+        def fast_getvar(self, varname, default=_MARKER):
+            return _fast_getvar(self, varname, default);
+
+        getvar = fast_getvar
+
+    else:
+
+        getvar = py_getvar
+
     def getkeys(self, varname):
         """Yield all the keys of a variable value.
 
@@ -656,7 +670,7 @@
         else:
             return default
 
-    def getvarl_s(self, *path, **kwds):
+    def py_getvarl_s(self, *path, **kwds):
         """Get a variable - including variables from other namespaces.
 
         `path` and `namespace` are interpreted as in
@@ -678,6 +692,17 @@
             else:
                 return default
 
+    if _fast_getvarl_s:
+
+        def fast_getvarl_s(self, *path, **kwds):
+            return _fast_getvarl_s(self, path, **kwds)
+
+        getvarl_s = fast_getvarl_s
+
+    else:
+
+        getvarl_s = py_getvarl_s
+
     def getfirstvarl_s(self, *paths, **kwds):
         """A variant of :meth:`~.getfirstvarl` that does variable
         interpolation.