Config: switch from foreach iterator
An iterator is much more natural in python, so let's use that.
This commit is contained in:
parent
dcc9051a8c
commit
35386cbec2
@ -10,9 +10,17 @@ The Config type
|
|||||||
|
|
||||||
.. automethod:: pygit2.Config.get_system_config
|
.. automethod:: pygit2.Config.get_system_config
|
||||||
.. automethod:: pygit2.Config.get_global_config
|
.. automethod:: pygit2.Config.get_global_config
|
||||||
.. automethod:: pygit2.Config.foreach
|
|
||||||
.. automethod:: pygit2.Config.add_file
|
.. automethod:: pygit2.Config.add_file
|
||||||
.. automethod:: pygit2.Config.get_multivar
|
.. automethod:: pygit2.Config.get_multivar
|
||||||
.. automethod:: pygit2.Config.set_multivar
|
.. automethod:: pygit2.Config.set_multivar
|
||||||
|
|
||||||
The :class:`Config` Mapping interface.
|
The :class:`Config` Mapping interface.
|
||||||
|
|
||||||
|
Iterator
|
||||||
|
=========
|
||||||
|
|
||||||
|
The :class:`Config` class has an iterator which can be used to loop
|
||||||
|
through all the entries in the configuration. Each element is a tuple
|
||||||
|
containing the name and the value of each configuration variable. Be
|
||||||
|
aware that this may return multiple versions of each entry if they are
|
||||||
|
set multiple times in the configuration files.
|
||||||
|
140
src/config.c
140
src/config.c
@ -33,6 +33,7 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
extern PyTypeObject ConfigType;
|
extern PyTypeObject ConfigType;
|
||||||
|
extern PyTypeObject ConfigIterType;
|
||||||
|
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
@ -239,70 +240,6 @@ Config_setitem(Config *self, PyObject *py_key, PyObject *py_value)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
|
||||||
Config_foreach_callback_wrapper(const git_config_entry *entry, void *c_payload)
|
|
||||||
{
|
|
||||||
PyObject *args = (PyObject *)c_payload;
|
|
||||||
PyObject *py_callback = NULL;
|
|
||||||
PyObject *py_payload = NULL;
|
|
||||||
PyObject *py_result = NULL;
|
|
||||||
int c_result;
|
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "O|O", &py_callback, &py_payload))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (py_payload)
|
|
||||||
args = Py_BuildValue("ssO", entry->name, entry->value, py_payload);
|
|
||||||
else
|
|
||||||
args = Py_BuildValue("ss", entry->name, entry->value);
|
|
||||||
if (!args)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (!(py_result = PyObject_CallObject(py_callback, args)))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if ((c_result = PyLong_AsLong(py_result)) == -1)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
Py_CLEAR(args);
|
|
||||||
|
|
||||||
return c_result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
PyDoc_STRVAR(Config_foreach__doc__,
|
|
||||||
"foreach(callback[, payload]) -> int\n"
|
|
||||||
"\n"
|
|
||||||
"Perform an operation on each config variable.\n"
|
|
||||||
"\n"
|
|
||||||
"The callback must be of type Callable and receives the normalized name\n"
|
|
||||||
"and value of each variable in the config backend, and an optional payload\n"
|
|
||||||
"passed to this method. As soon as one of the callbacks returns an integer\n"
|
|
||||||
"other than 0, this function returns that value.");
|
|
||||||
|
|
||||||
PyObject *
|
|
||||||
Config_foreach(Config *self, PyObject *args)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
PyObject *py_callback;
|
|
||||||
PyObject *py_payload = NULL;
|
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "O|O", &py_callback, &py_payload))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (!PyCallable_Check(py_callback)) {
|
|
||||||
PyErr_SetString(PyExc_TypeError,
|
|
||||||
"Argument 'callback' is not callable");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = git_config_foreach(self->config, Config_foreach_callback_wrapper,
|
|
||||||
(void *)args);
|
|
||||||
|
|
||||||
return PyLong_FromLong((long)ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
PyDoc_STRVAR(Config_add_file__doc__,
|
PyDoc_STRVAR(Config_add_file__doc__,
|
||||||
"add_file(path, level=0, force=0)\n"
|
"add_file(path, level=0, force=0)\n"
|
||||||
"\n"
|
"\n"
|
||||||
@ -407,10 +344,28 @@ Config_set_multivar(Config *self, PyObject *args)
|
|||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
Config_iter(Config *self)
|
||||||
|
{
|
||||||
|
ConfigIter *iter;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
iter = PyObject_New(ConfigIter, &ConfigIterType);
|
||||||
|
if (!iter)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if ((err = git_config_iterator_new(&iter->iter, self->config)) < 0)
|
||||||
|
return Error_set(err);
|
||||||
|
|
||||||
|
Py_INCREF(self);
|
||||||
|
iter->owner = self;
|
||||||
|
|
||||||
|
return (PyObject*)iter;
|
||||||
|
}
|
||||||
|
|
||||||
PyMethodDef Config_methods[] = {
|
PyMethodDef Config_methods[] = {
|
||||||
METHOD(Config, get_system_config, METH_NOARGS | METH_STATIC),
|
METHOD(Config, get_system_config, METH_NOARGS | METH_STATIC),
|
||||||
METHOD(Config, get_global_config, METH_NOARGS | METH_STATIC),
|
METHOD(Config, get_global_config, METH_NOARGS | METH_STATIC),
|
||||||
METHOD(Config, foreach, METH_VARARGS),
|
|
||||||
METHOD(Config, add_file, METH_VARARGS | METH_KEYWORDS),
|
METHOD(Config, add_file, METH_VARARGS | METH_KEYWORDS),
|
||||||
METHOD(Config, get_multivar, METH_VARARGS),
|
METHOD(Config, get_multivar, METH_VARARGS),
|
||||||
METHOD(Config, set_multivar, METH_VARARGS),
|
METHOD(Config, set_multivar, METH_VARARGS),
|
||||||
@ -463,7 +418,7 @@ PyTypeObject ConfigType = {
|
|||||||
0, /* tp_clear */
|
0, /* tp_clear */
|
||||||
0, /* tp_richcompare */
|
0, /* tp_richcompare */
|
||||||
0, /* tp_weaklistoffset */
|
0, /* tp_weaklistoffset */
|
||||||
0, /* tp_iter */
|
(getiterfunc)Config_iter, /* tp_iter */
|
||||||
0, /* tp_iternext */
|
0, /* tp_iternext */
|
||||||
Config_methods, /* tp_methods */
|
Config_methods, /* tp_methods */
|
||||||
0, /* tp_members */
|
0, /* tp_members */
|
||||||
@ -477,3 +432,56 @@ PyTypeObject ConfigType = {
|
|||||||
0, /* tp_alloc */
|
0, /* tp_alloc */
|
||||||
0, /* tp_new */
|
0, /* tp_new */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
ConfigIter_dealloc(ConfigIter *self)
|
||||||
|
{
|
||||||
|
Py_CLEAR(self->owner);
|
||||||
|
git_config_iterator_free(self->iter);
|
||||||
|
PyObject_Del(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
ConfigIter_iternext(ConfigIter *self)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
git_config_entry *entry;
|
||||||
|
|
||||||
|
if ((err = git_config_next(&entry, self->iter)) < 0)
|
||||||
|
return Error_set(err);
|
||||||
|
|
||||||
|
return Py_BuildValue("ss", entry->name, entry->value);
|
||||||
|
}
|
||||||
|
|
||||||
|
PyDoc_STRVAR(ConfigIter__doc__, "Configuration iterator.");
|
||||||
|
|
||||||
|
PyTypeObject ConfigIterType = {
|
||||||
|
PyVarObject_HEAD_INIT(NULL, 0)
|
||||||
|
"_pygit2.ConfigIter", /* tp_name */
|
||||||
|
sizeof(ConfigIter), /* tp_basicsize */
|
||||||
|
0, /* tp_itemsize */
|
||||||
|
(destructor)ConfigIter_dealloc , /* tp_dealloc */
|
||||||
|
0, /* tp_print */
|
||||||
|
0, /* tp_getattr */
|
||||||
|
0, /* tp_setattr */
|
||||||
|
0, /* tp_compare */
|
||||||
|
0, /* tp_repr */
|
||||||
|
0, /* tp_as_number */
|
||||||
|
0, /* tp_as_sequence */
|
||||||
|
0, /* tp_as_mapping */
|
||||||
|
0, /* tp_hash */
|
||||||
|
0, /* tp_call */
|
||||||
|
0, /* tp_str */
|
||||||
|
0, /* tp_getattro */
|
||||||
|
0, /* tp_setattro */
|
||||||
|
0, /* tp_as_buffer */
|
||||||
|
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
|
||||||
|
ConfigIter__doc__, /* tp_doc */
|
||||||
|
0, /* tp_traverse */
|
||||||
|
0, /* tp_clear */
|
||||||
|
0, /* tp_richcompare */
|
||||||
|
0, /* tp_weaklistoffset */
|
||||||
|
PyObject_SelfIter, /* tp_iter */
|
||||||
|
(iternextfunc)ConfigIter_iternext, /* tp_iternext */
|
||||||
|
|
||||||
|
};
|
||||||
|
@ -56,6 +56,7 @@ extern PyTypeObject IndexEntryType;
|
|||||||
extern PyTypeObject IndexIterType;
|
extern PyTypeObject IndexIterType;
|
||||||
extern PyTypeObject WalkerType;
|
extern PyTypeObject WalkerType;
|
||||||
extern PyTypeObject ConfigType;
|
extern PyTypeObject ConfigType;
|
||||||
|
extern PyTypeObject ConfigIterType;
|
||||||
extern PyTypeObject ReferenceType;
|
extern PyTypeObject ReferenceType;
|
||||||
extern PyTypeObject RefLogIterType;
|
extern PyTypeObject RefLogIterType;
|
||||||
extern PyTypeObject RefLogEntryType;
|
extern PyTypeObject RefLogEntryType;
|
||||||
@ -412,7 +413,9 @@ moduleinit(PyObject* m)
|
|||||||
|
|
||||||
/* Config */
|
/* Config */
|
||||||
INIT_TYPE(ConfigType, NULL, PyType_GenericNew)
|
INIT_TYPE(ConfigType, NULL, PyType_GenericNew)
|
||||||
|
INIT_TYPE(ConfigIterType, NULL, PyType_GenericNew)
|
||||||
ADD_TYPE(m, Config)
|
ADD_TYPE(m, Config)
|
||||||
|
ADD_TYPE(m, ConfigIter)
|
||||||
|
|
||||||
/* Remotes */
|
/* Remotes */
|
||||||
INIT_TYPE(RemoteType, NULL, NULL)
|
INIT_TYPE(RemoteType, NULL, NULL)
|
||||||
|
@ -77,6 +77,11 @@ typedef struct {
|
|||||||
git_config* config;
|
git_config* config;
|
||||||
} Config;
|
} Config;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
PyObject_HEAD
|
||||||
|
Config *owner;
|
||||||
|
git_config_iterator *iter;
|
||||||
|
} ConfigIter;
|
||||||
|
|
||||||
/* git_note */
|
/* git_note */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -36,13 +36,6 @@ from . import utils
|
|||||||
|
|
||||||
CONFIG_FILENAME = "test_config"
|
CONFIG_FILENAME = "test_config"
|
||||||
|
|
||||||
|
|
||||||
def foreach_test_wrapper(key, name, lst):
|
|
||||||
lst[key] = name
|
|
||||||
return 0
|
|
||||||
foreach_test_wrapper.__test__ = False
|
|
||||||
|
|
||||||
|
|
||||||
class ConfigTest(utils.RepoTestCase):
|
class ConfigTest(utils.RepoTestCase):
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
@ -175,13 +168,15 @@ class ConfigTest(utils.RepoTestCase):
|
|||||||
for i in l:
|
for i in l:
|
||||||
self.assertEqual(i, 'foo-123456')
|
self.assertEqual(i, 'foo-123456')
|
||||||
|
|
||||||
def test_foreach(self):
|
def test_iterator(self):
|
||||||
config = self.repo.config
|
config = self.repo.config
|
||||||
lst = {}
|
lst = {}
|
||||||
config.foreach(foreach_test_wrapper, lst)
|
|
||||||
|
for name, value in config:
|
||||||
|
lst[name] = value
|
||||||
|
|
||||||
self.assertTrue('core.bare' in lst)
|
self.assertTrue('core.bare' in lst)
|
||||||
self.assertTrue(lst['core.bare'])
|
self.assertTrue(lst['core.bare'])
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
Loading…
Reference in New Issue
Block a user