diff --git a/TODO.txt b/TODO.txt index 99d24f4..d151325 100644 --- a/TODO.txt +++ b/TODO.txt @@ -1,6 +1,4 @@ Signature ========= - Implement equality interface -- Return unicode for the email -- Implement interface to access the name/email as bytes - In Repository's create_commit/create_tag check signatures encoding is right diff --git a/pygit2.c b/pygit2.c index 874e667..cda16b6 100644 --- a/pygit2.c +++ b/pygit2.c @@ -44,7 +44,19 @@ #define PyString_Size PyBytes_Size #endif +/* Utilities */ +static PyObject * +to_str(const char *value, const char *encoding, const char *errors) +{ + if (encoding == NULL) + encoding = "utf-8"; + return PyUnicode_Decode(value, strlen(value), encoding, errors); +} +#define to_bytes(value) PyString_FromString(value) + + +/* Python objects */ typedef struct { PyObject_HEAD git_repository *repo; @@ -358,15 +370,11 @@ py_str_to_c_str(PyObject *value, const char *encoding) return NULL; } -#define c_str_to_py_str(c_str) \ - PyUnicode_DecodeUTF8(c_str, strlen(c_str), "strict") - #define py_path_to_c_str(py_path) \ py_str_to_c_str(py_path, Py_FileSystemDefaultEncoding) #define c_str_to_py_path(c_str) \ - PyUnicode_Decode(c_str, strlen(c_str), \ - Py_FileSystemDefaultEncoding, "strict") + to_str(c_str, Py_FileSystemDefaultEncoding, "strict") static int @@ -1136,9 +1144,7 @@ Commit_get_message(Commit *commit) message = git_commit_message(commit->commit); encoding = git_commit_message_encoding(commit->commit); - if (encoding == NULL) - encoding = "utf-8"; - return PyUnicode_Decode(message, strlen(message), encoding, "strict"); + return to_str(message, encoding, "strict"); } static PyObject * @@ -1676,7 +1682,7 @@ Tag_get_name(Tag *self) name = git_tag_name(self->tag); if (!name) Py_RETURN_NONE; - return c_str_to_py_str(name); + return to_str(name, "utf-8", "strict"); } static PyObject * @@ -1696,7 +1702,7 @@ Tag_get_message(Tag *self) message = git_tag_message(self->tag); if (!message) Py_RETURN_NONE; - return c_str_to_py_str(message); + return to_str(message, "utf-8", "strict"); } static PyGetSetDef Tag_getseters[] = { @@ -2645,24 +2651,39 @@ Signature_dealloc(Signature *self) } static PyObject * -Signature_get_name(Signature *self) +Signature_get_encoding(Signature *self) { const char *encoding; - git_object *object; encoding = self->encoding; if (encoding == NULL) encoding = "utf-8"; - return PyUnicode_Decode(self->signature->name, - strlen(self->signature->name), - encoding, "strict"); + return PyUnicode_DecodeASCII(encoding, strlen(encoding), "strict"); +} + +static PyObject * +Signature_get_raw_name(Signature *self) +{ + return to_bytes(self->signature->name); +} + +static PyObject * +Signature_get_raw_email(Signature *self) +{ + return to_bytes(self->signature->email); +} + +static PyObject * +Signature_get_name(Signature *self) +{ + return to_str(self->signature->name, self->encoding, "strict"); } static PyObject * Signature_get_email(Signature *self) { - return PyString_FromString(self->signature->email); + return to_str(self->signature->email, self->encoding, "strict"); } static PyObject * @@ -2678,6 +2699,9 @@ Signature_get_offset(Signature *self) } static PyGetSetDef Signature_getseters[] = { + {"_encoding", (getter)Signature_get_encoding, NULL, "encoding", NULL}, + {"_name", (getter)Signature_get_raw_name, NULL, "Name (bytes)", NULL}, + {"_email", (getter)Signature_get_raw_email, NULL, "Email (bytes)", NULL}, {"name", (getter)Signature_get_name, NULL, "Name", NULL}, {"email", (getter)Signature_get_email, NULL, "Email", NULL}, {"time", (getter)Signature_get_time, NULL, "Time", NULL}, diff --git a/test/__init__.py b/test/__init__.py index 2379757..1864663 100644 --- a/test/__init__.py +++ b/test/__init__.py @@ -36,7 +36,7 @@ import unittest names = ['blob', 'commit', 'index', 'refs', 'repository', 'revwalk', 'tag', - 'tree', 'status'] + 'tree', 'signature', 'status'] def test_suite(): modules = ['test.test_%s' % n for n in names] return unittest.defaultTestLoader.loadTestsFromNames(modules) diff --git a/test/test_signature.py b/test/test_signature.py new file mode 100644 index 0000000..cebbf1b --- /dev/null +++ b/test/test_signature.py @@ -0,0 +1,57 @@ +# -*- coding: UTF-8 -*- +# +# Copyright 2011 J. David Ibáñez +# +# 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. + +from __future__ import absolute_import +from __future__ import unicode_literals +import unittest + +from pygit2 import Signature +from .utils import NoRepoTestCase + + +__author__ = 'jdavid.ibp@gmail.com (J. David Ibáñez)' + + + +class SignatureTest(NoRepoTestCase): + + def test_default(self): + signature = Signature('Foo Ibáñez', 'foo@example.com', 1322174594, 60) + encoding = signature._encoding + self.assertEqual(signature.name, signature._name.decode(encoding)) + self.assertEqual(signature.name.encode(encoding), signature._name) + + def test_latin1(self): + encoding = 'iso-8859-1' + signature = Signature('Foo Ibáñez', 'foo@example.com', 1322174594, 60, + encoding) + self.assertEqual(signature.name, signature._name.decode(encoding)) + self.assertEqual(signature.name.encode(encoding), signature._name) + + +if __name__ == '__main__': + unittest.main()