673 lines
21 KiB
C
673 lines
21 KiB
C
/*
|
|
* Copyright 2010-2015 The pygit2 contributors
|
|
*
|
|
* This file is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License, version 2,
|
|
* as published by the Free Software Foundation.
|
|
*
|
|
* In addition to the permissions in the GNU General Public License,
|
|
* the authors give you unlimited permission to link the compiled
|
|
* version of this file into combinations with other programs,
|
|
* and to distribute those combinations without any restriction
|
|
* coming from the use of this file. (The General Public License
|
|
* restrictions do apply in other respects; for example, they cover
|
|
* modification of the file, and distribution when not linked into
|
|
* a combined executable.)
|
|
*
|
|
* This file is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; see the file COPYING. If not, write to
|
|
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
|
|
* Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#define PY_SSIZE_T_CLEAN
|
|
#include <Python.h>
|
|
#include <string.h>
|
|
#include "error.h"
|
|
#include "utils.h"
|
|
#include "repository.h"
|
|
#include "oid.h"
|
|
#include "tree.h"
|
|
#include "diff.h"
|
|
|
|
extern PyTypeObject TreeType;
|
|
extern PyTypeObject TreeEntryType;
|
|
extern PyTypeObject DiffType;
|
|
extern PyTypeObject TreeIterType;
|
|
extern PyTypeObject IndexType;
|
|
|
|
void
|
|
TreeEntry_dealloc(TreeEntry *self)
|
|
{
|
|
git_tree_entry_free((git_tree_entry*)self->entry);
|
|
PyObject_Del(self);
|
|
}
|
|
|
|
|
|
PyDoc_STRVAR(TreeEntry_filemode__doc__, "Filemode.");
|
|
|
|
PyObject *
|
|
TreeEntry_filemode__get__(TreeEntry *self)
|
|
{
|
|
return PyLong_FromLong(git_tree_entry_filemode(self->entry));
|
|
}
|
|
|
|
|
|
PyDoc_STRVAR(TreeEntry_name__doc__, "Name.");
|
|
|
|
PyObject *
|
|
TreeEntry_name__get__(TreeEntry *self)
|
|
{
|
|
return to_path(git_tree_entry_name(self->entry));
|
|
}
|
|
|
|
|
|
PyDoc_STRVAR(TreeEntry__name__doc__, "Name (bytes).");
|
|
|
|
PyObject *
|
|
TreeEntry__name__get__(TreeEntry *self)
|
|
{
|
|
return PyBytes_FromString(git_tree_entry_name(self->entry));
|
|
}
|
|
|
|
|
|
PyDoc_STRVAR(TreeEntry_type__doc__, "Type.");
|
|
|
|
PyObject *
|
|
TreeEntry_type__get__(TreeEntry *self)
|
|
{
|
|
return to_path(git_object_type2string(git_tree_entry_type(self->entry)));
|
|
}
|
|
|
|
|
|
PyDoc_STRVAR(TreeEntry_id__doc__, "Object id.");
|
|
|
|
PyObject *
|
|
TreeEntry_id__get__(TreeEntry *self)
|
|
{
|
|
const git_oid *oid;
|
|
|
|
oid = git_tree_entry_id(self->entry);
|
|
return git_oid_to_python(oid);
|
|
}
|
|
|
|
PyDoc_STRVAR(TreeEntry_oid__doc__, "Object id.\n"
|
|
"This attribute is deprecated. Please use 'id'");
|
|
|
|
PyObject *
|
|
TreeEntry_oid__get__(TreeEntry *self)
|
|
{
|
|
return TreeEntry_id__get__(self);
|
|
}
|
|
|
|
static int
|
|
compare_ids(TreeEntry *a, TreeEntry *b)
|
|
{
|
|
const git_oid *id_a, *id_b;
|
|
id_a = git_tree_entry_id(a->entry);
|
|
id_b = git_tree_entry_id(b->entry);
|
|
return git_oid_cmp(id_a, id_b);
|
|
}
|
|
|
|
PyObject *
|
|
TreeEntry_richcompare(PyObject *a, PyObject *b, int op)
|
|
{
|
|
PyObject *res;
|
|
TreeEntry *ta, *tb;
|
|
int cmp;
|
|
|
|
/* We only support comparing to another tree entry */
|
|
if (!PyObject_TypeCheck(b, &TreeEntryType)) {
|
|
Py_INCREF(Py_NotImplemented);
|
|
return Py_NotImplemented;
|
|
}
|
|
|
|
ta = (TreeEntry *) a;
|
|
tb = (TreeEntry *) b;
|
|
|
|
/* This is sorting order, if they sort equally, we still need to compare the ids */
|
|
cmp = git_tree_entry_cmp(ta->entry, tb->entry);
|
|
if (cmp == 0)
|
|
cmp = compare_ids(ta, tb);
|
|
|
|
switch (op) {
|
|
case Py_LT:
|
|
res = (cmp <= 0) ? Py_True: Py_False;
|
|
break;
|
|
case Py_LE:
|
|
res = (cmp < 0) ? Py_True: Py_False;
|
|
break;
|
|
case Py_EQ:
|
|
res = (cmp == 0) ? Py_True: Py_False;
|
|
break;
|
|
case Py_NE:
|
|
res = (cmp != 0) ? Py_True: Py_False;
|
|
break;
|
|
case Py_GT:
|
|
res = (cmp > 0) ? Py_True: Py_False;
|
|
break;
|
|
case Py_GE:
|
|
res = (cmp >= 0) ? Py_True: Py_False;
|
|
break;
|
|
default:
|
|
PyErr_Format(PyExc_RuntimeError, "Unexpected '%d' op", op);
|
|
return NULL;
|
|
}
|
|
|
|
Py_INCREF(res);
|
|
return res;
|
|
}
|
|
|
|
|
|
PyDoc_STRVAR(TreeEntry_hex__doc__, "Hex oid.");
|
|
|
|
PyObject *
|
|
TreeEntry_hex__get__(TreeEntry *self)
|
|
{
|
|
return git_oid_to_py_str(git_tree_entry_id(self->entry));
|
|
}
|
|
|
|
PyObject *
|
|
TreeEntry_repr(TreeEntry *self)
|
|
{
|
|
char str[GIT_OID_HEXSZ + 1] = { 0 };
|
|
const char *typename;
|
|
|
|
typename = git_object_type2string(git_tree_entry_type(self->entry));
|
|
git_oid_fmt(str, git_tree_entry_id(self->entry));
|
|
return PyString_FromFormat("pygit2.TreeEntry('%s', %s, %s)", git_tree_entry_name(self->entry), typename, str);
|
|
}
|
|
|
|
PyGetSetDef TreeEntry_getseters[] = {
|
|
GETTER(TreeEntry, filemode),
|
|
GETTER(TreeEntry, name),
|
|
GETTER(TreeEntry, _name),
|
|
GETTER(TreeEntry, oid),
|
|
GETTER(TreeEntry, id),
|
|
GETTER(TreeEntry, hex),
|
|
GETTER(TreeEntry, type),
|
|
{NULL}
|
|
};
|
|
|
|
PyDoc_STRVAR(TreeEntry__doc__, "TreeEntry objects.");
|
|
|
|
PyTypeObject TreeEntryType = {
|
|
PyVarObject_HEAD_INIT(NULL, 0)
|
|
"_pygit2.TreeEntry", /* tp_name */
|
|
sizeof(TreeEntry), /* tp_basicsize */
|
|
0, /* tp_itemsize */
|
|
(destructor)TreeEntry_dealloc, /* tp_dealloc */
|
|
0, /* tp_print */
|
|
0, /* tp_getattr */
|
|
0, /* tp_setattr */
|
|
0, /* tp_compare */
|
|
(reprfunc)TreeEntry_repr, /* 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, /* tp_flags */
|
|
TreeEntry__doc__, /* tp_doc */
|
|
0, /* tp_traverse */
|
|
0, /* tp_clear */
|
|
(richcmpfunc)TreeEntry_richcompare, /* tp_richcompare */
|
|
0, /* tp_weaklistoffset */
|
|
0, /* tp_iter */
|
|
0, /* tp_iternext */
|
|
0, /* tp_methods */
|
|
0, /* tp_members */
|
|
TreeEntry_getseters, /* tp_getset */
|
|
0, /* tp_base */
|
|
0, /* tp_dict */
|
|
0, /* tp_descr_get */
|
|
0, /* tp_descr_set */
|
|
0, /* tp_dictoffset */
|
|
0, /* tp_init */
|
|
0, /* tp_alloc */
|
|
0, /* tp_new */
|
|
};
|
|
|
|
Py_ssize_t
|
|
Tree_len(Tree *self)
|
|
{
|
|
assert(self->tree);
|
|
return (Py_ssize_t)git_tree_entrycount(self->tree);
|
|
}
|
|
|
|
int
|
|
Tree_contains(Tree *self, PyObject *py_name)
|
|
{
|
|
int err;
|
|
git_tree_entry *entry;
|
|
char *name;
|
|
|
|
name = py_path_to_c_str(py_name);
|
|
if (name == NULL)
|
|
return -1;
|
|
|
|
err = git_tree_entry_bypath(&entry, self->tree, name);
|
|
free(name);
|
|
|
|
if (err == GIT_ENOTFOUND)
|
|
return 0;
|
|
|
|
if (err < 0) {
|
|
Error_set(err);
|
|
return -1;
|
|
}
|
|
|
|
git_tree_entry_free(entry);
|
|
|
|
return 1;
|
|
}
|
|
|
|
TreeEntry *
|
|
wrap_tree_entry(const git_tree_entry *entry)
|
|
{
|
|
TreeEntry *py_entry;
|
|
|
|
py_entry = PyObject_New(TreeEntry, &TreeEntryType);
|
|
if (py_entry)
|
|
py_entry->entry = entry;
|
|
|
|
return py_entry;
|
|
}
|
|
|
|
int
|
|
Tree_fix_index(Tree *self, PyObject *py_index)
|
|
{
|
|
long index;
|
|
size_t len;
|
|
long slen;
|
|
|
|
index = PyLong_AsLong(py_index);
|
|
if (PyErr_Occurred())
|
|
return -1;
|
|
|
|
len = git_tree_entrycount(self->tree);
|
|
slen = (long)len;
|
|
if (index >= slen) {
|
|
PyErr_SetObject(PyExc_IndexError, py_index);
|
|
return -1;
|
|
}
|
|
else if (index < -slen) {
|
|
PyErr_SetObject(PyExc_IndexError, py_index);
|
|
return -1;
|
|
}
|
|
|
|
/* This function is called via mp_subscript, which doesn't do negative
|
|
* index rewriting, so we have to do it manually. */
|
|
if (index < 0)
|
|
index = len + index;
|
|
return (int)index;
|
|
}
|
|
|
|
PyObject *
|
|
Tree_iter(Tree *self)
|
|
{
|
|
TreeIter *iter;
|
|
|
|
iter = PyObject_New(TreeIter, &TreeIterType);
|
|
if (iter) {
|
|
Py_INCREF(self);
|
|
iter->owner = self;
|
|
iter->i = 0;
|
|
}
|
|
return (PyObject*)iter;
|
|
}
|
|
|
|
TreeEntry *
|
|
Tree_getitem_by_index(Tree *self, PyObject *py_index)
|
|
{
|
|
int index;
|
|
const git_tree_entry *entry_src;
|
|
git_tree_entry *entry;
|
|
|
|
index = Tree_fix_index(self, py_index);
|
|
if (PyErr_Occurred())
|
|
return NULL;
|
|
|
|
entry_src = git_tree_entry_byindex(self->tree, index);
|
|
if (!entry_src) {
|
|
PyErr_SetObject(PyExc_IndexError, py_index);
|
|
return NULL;
|
|
}
|
|
|
|
if (git_tree_entry_dup(&entry, entry_src) < 0) {
|
|
PyErr_SetNone(PyExc_MemoryError);
|
|
return NULL;
|
|
}
|
|
|
|
return wrap_tree_entry(entry);
|
|
}
|
|
|
|
TreeEntry *
|
|
Tree_getitem(Tree *self, PyObject *value)
|
|
{
|
|
char *path;
|
|
git_tree_entry *entry;
|
|
int err;
|
|
|
|
/* Case 1: integer */
|
|
if (PyLong_Check(value))
|
|
return Tree_getitem_by_index(self, value);
|
|
|
|
/* Case 2: byte or text string */
|
|
path = py_path_to_c_str(value);
|
|
if (path == NULL)
|
|
return NULL;
|
|
|
|
err = git_tree_entry_bypath(&entry, self->tree, path);
|
|
free(path);
|
|
|
|
if (err == GIT_ENOTFOUND) {
|
|
PyErr_SetObject(PyExc_KeyError, value);
|
|
return NULL;
|
|
}
|
|
|
|
if (err < 0)
|
|
return (TreeEntry*)Error_set(err);
|
|
|
|
/* git_tree_entry_dup is already done in git_tree_entry_bypath */
|
|
return wrap_tree_entry(entry);
|
|
}
|
|
|
|
|
|
PyDoc_STRVAR(Tree_diff_to_workdir__doc__,
|
|
"diff_to_workdir([flags, context_lines, interhunk_lines]) -> Diff\n"
|
|
"\n"
|
|
"Show the changes between the :py:class:`~pygit2.Tree` and the workdir.\n"
|
|
"\n"
|
|
"Arguments:\n"
|
|
"\n"
|
|
"flag: a GIT_DIFF_* constant.\n"
|
|
"\n"
|
|
"context_lines: the number of unchanged lines that define the boundary\n"
|
|
" of a hunk (and to display before and after)\n"
|
|
"\n"
|
|
"interhunk_lines: the maximum number of unchanged lines between hunk\n"
|
|
" boundaries before the hunks will be merged into a one.\n");
|
|
|
|
PyObject *
|
|
Tree_diff_to_workdir(Tree *self, PyObject *args)
|
|
{
|
|
git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
|
|
git_diff *diff;
|
|
Repository *py_repo;
|
|
int err;
|
|
|
|
if (!PyArg_ParseTuple(args, "|IHH", &opts.flags, &opts.context_lines,
|
|
&opts.interhunk_lines))
|
|
return NULL;
|
|
|
|
py_repo = self->repo;
|
|
err = git_diff_tree_to_workdir(&diff, py_repo->repo, self->tree, &opts);
|
|
if (err < 0)
|
|
return Error_set(err);
|
|
|
|
return wrap_diff(diff, py_repo);
|
|
}
|
|
|
|
|
|
PyDoc_STRVAR(Tree_diff_to_index__doc__,
|
|
"diff_to_index(index, [flags, context_lines, interhunk_lines]) -> Diff\n"
|
|
"\n"
|
|
"Show the changes between the index and a given :py:class:`~pygit2.Tree`.\n"
|
|
"\n"
|
|
"Arguments:\n"
|
|
"\n"
|
|
"tree: the :py:class:`~pygit2.Tree` to diff.\n"
|
|
"\n"
|
|
"flag: a GIT_DIFF_* constant.\n"
|
|
"\n"
|
|
"context_lines: the number of unchanged lines that define the boundary\n"
|
|
" of a hunk (and to display before and after)\n"
|
|
"\n"
|
|
"interhunk_lines: the maximum number of unchanged lines between hunk\n"
|
|
" boundaries before the hunks will be merged into a one.\n");
|
|
|
|
PyObject *
|
|
Tree_diff_to_index(Tree *self, PyObject *args, PyObject *kwds)
|
|
{
|
|
git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
|
|
git_diff *diff;
|
|
git_index *index;
|
|
char *buffer;
|
|
Py_ssize_t length;
|
|
Repository *py_repo;
|
|
PyObject *py_idx, *py_idx_ptr;
|
|
int err;
|
|
|
|
if (!PyArg_ParseTuple(args, "O|IHH", &py_idx, &opts.flags,
|
|
&opts.context_lines,
|
|
&opts.interhunk_lines))
|
|
return NULL;
|
|
|
|
/*
|
|
* This is a hack to check whether we're passed an index, as I
|
|
* haven't found a good way to grab a type object for
|
|
* pygit2.index.Index.
|
|
*/
|
|
if (!PyObject_GetAttrString(py_idx, "_index")) {
|
|
PyErr_SetString(PyExc_TypeError, "argument must be an Index");
|
|
return NULL;
|
|
}
|
|
py_idx_ptr = PyObject_GetAttrString(py_idx, "_pointer");
|
|
if (!py_idx_ptr)
|
|
return NULL;
|
|
|
|
/* Here we need to do the opposite conversion from the _pointer getters */
|
|
if (PyBytes_AsStringAndSize(py_idx_ptr, &buffer, &length))
|
|
return NULL;
|
|
|
|
if (length != sizeof(git_index *)) {
|
|
PyErr_SetString(PyExc_TypeError, "passed value is not a pointer");
|
|
return NULL;
|
|
}
|
|
|
|
/* the "buffer" contains the pointer */
|
|
index = *((git_index **) buffer);
|
|
|
|
py_repo = self->repo;
|
|
err = git_diff_tree_to_index(&diff, py_repo->repo, self->tree, index, &opts);
|
|
if (err < 0)
|
|
return Error_set(err);
|
|
|
|
return wrap_diff(diff, py_repo);
|
|
}
|
|
|
|
|
|
PyDoc_STRVAR(Tree_diff_to_tree__doc__,
|
|
"diff_to_tree([tree, flags, context_lines, interhunk_lines, swap]) -> Diff\n"
|
|
"\n"
|
|
"Show the changes between two trees\n"
|
|
"\n"
|
|
"Arguments:\n"
|
|
"\n"
|
|
"tree: the :py:class:`~pygit2.Tree` to diff. If no tree is given the empty\n"
|
|
" tree will be used instead.\n"
|
|
"\n"
|
|
"flag: a GIT_DIFF_* constant.\n"
|
|
"\n"
|
|
"context_lines: the number of unchanged lines that define the boundary\n"
|
|
" of a hunk (and to display before and after)\n"
|
|
"\n"
|
|
"interhunk_lines: the maximum number of unchanged lines between hunk\n"
|
|
" boundaries before the hunks will be merged into a one.\n"
|
|
"\n"
|
|
"swap: instead of diffing a to b. Diff b to a.\n");
|
|
|
|
PyObject *
|
|
Tree_diff_to_tree(Tree *self, PyObject *args, PyObject *kwds)
|
|
{
|
|
git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
|
|
git_diff *diff;
|
|
git_tree *from, *to, *tmp;
|
|
Repository *py_repo;
|
|
int err, swap = 0;
|
|
char *keywords[] = {"obj", "flags", "context_lines", "interhunk_lines",
|
|
"swap", NULL};
|
|
|
|
Tree *py_tree = NULL;
|
|
|
|
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O!IHHi", keywords,
|
|
&TreeType, &py_tree, &opts.flags,
|
|
&opts.context_lines,
|
|
&opts.interhunk_lines, &swap))
|
|
return NULL;
|
|
|
|
py_repo = self->repo;
|
|
to = (py_tree == NULL) ? NULL : py_tree->tree;
|
|
from = self->tree;
|
|
if (swap > 0) {
|
|
tmp = from;
|
|
from = to;
|
|
to = tmp;
|
|
}
|
|
|
|
err = git_diff_tree_to_tree(&diff, py_repo->repo, from, to, &opts);
|
|
if (err < 0)
|
|
return Error_set(err);
|
|
|
|
return wrap_diff(diff, py_repo);
|
|
}
|
|
|
|
|
|
PySequenceMethods Tree_as_sequence = {
|
|
0, /* sq_length */
|
|
0, /* sq_concat */
|
|
0, /* sq_repeat */
|
|
0, /* sq_item */
|
|
0, /* sq_slice */
|
|
0, /* sq_ass_item */
|
|
0, /* sq_ass_slice */
|
|
(objobjproc)Tree_contains, /* sq_contains */
|
|
};
|
|
|
|
PyMappingMethods Tree_as_mapping = {
|
|
(lenfunc)Tree_len, /* mp_length */
|
|
(binaryfunc)Tree_getitem, /* mp_subscript */
|
|
0, /* mp_ass_subscript */
|
|
};
|
|
|
|
PyMethodDef Tree_methods[] = {
|
|
METHOD(Tree, diff_to_tree, METH_VARARGS | METH_KEYWORDS),
|
|
METHOD(Tree, diff_to_workdir, METH_VARARGS),
|
|
METHOD(Tree, diff_to_index, METH_VARARGS | METH_KEYWORDS),
|
|
{NULL}
|
|
};
|
|
|
|
|
|
PyDoc_STRVAR(Tree__doc__, "Tree objects.");
|
|
|
|
PyTypeObject TreeType = {
|
|
PyVarObject_HEAD_INIT(NULL, 0)
|
|
"_pygit2.Tree", /* tp_name */
|
|
sizeof(Tree), /* tp_basicsize */
|
|
0, /* tp_itemsize */
|
|
0, /* tp_dealloc */
|
|
0, /* tp_print */
|
|
0, /* tp_getattr */
|
|
0, /* tp_setattr */
|
|
0, /* tp_compare */
|
|
0, /* tp_repr */
|
|
0, /* tp_as_number */
|
|
&Tree_as_sequence, /* tp_as_sequence */
|
|
&Tree_as_mapping, /* 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, /* tp_flags */
|
|
Tree__doc__, /* tp_doc */
|
|
0, /* tp_traverse */
|
|
0, /* tp_clear */
|
|
0, /* tp_richcompare */
|
|
0, /* tp_weaklistoffset */
|
|
(getiterfunc)Tree_iter, /* tp_iter */
|
|
0, /* tp_iternext */
|
|
Tree_methods, /* tp_methods */
|
|
0, /* tp_members */
|
|
0, /* tp_getset */
|
|
0, /* tp_base */
|
|
0, /* tp_dict */
|
|
0, /* tp_descr_get */
|
|
0, /* tp_descr_set */
|
|
0, /* tp_dictoffset */
|
|
0, /* tp_init */
|
|
0, /* tp_alloc */
|
|
0, /* tp_new */
|
|
};
|
|
|
|
|
|
void
|
|
TreeIter_dealloc(TreeIter *self)
|
|
{
|
|
Py_CLEAR(self->owner);
|
|
PyObject_Del(self);
|
|
}
|
|
|
|
TreeEntry *
|
|
TreeIter_iternext(TreeIter *self)
|
|
{
|
|
const git_tree_entry *entry_src;
|
|
git_tree_entry *entry;
|
|
|
|
entry_src = git_tree_entry_byindex(self->owner->tree, self->i);
|
|
if (!entry_src)
|
|
return NULL;
|
|
|
|
self->i += 1;
|
|
|
|
if (git_tree_entry_dup(&entry, entry_src) < 0) {
|
|
PyErr_SetNone(PyExc_MemoryError);
|
|
return NULL;
|
|
}
|
|
return wrap_tree_entry(entry);
|
|
}
|
|
|
|
|
|
PyDoc_STRVAR(TreeIter__doc__, "Tree iterator.");
|
|
|
|
PyTypeObject TreeIterType = {
|
|
PyVarObject_HEAD_INIT(NULL, 0)
|
|
"_pygit2.TreeIter", /* tp_name */
|
|
sizeof(TreeIter), /* tp_basicsize */
|
|
0, /* tp_itemsize */
|
|
(destructor)TreeIter_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, /* tp_flags */
|
|
TreeIter__doc__, /* tp_doc */
|
|
0, /* tp_traverse */
|
|
0, /* tp_clear */
|
|
0, /* tp_richcompare */
|
|
0, /* tp_weaklistoffset */
|
|
PyObject_SelfIter, /* tp_iter */
|
|
(iternextfunc)TreeIter_iternext, /* tp_iternext */
|
|
};
|