summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2020-06-29 22:37:58 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2020-06-29 22:37:58 (GMT)
commitd3d57aa61bb44fd0bdad460c8c173743ca808733 (patch)
treea427000cc26a7af91b8a1b42e80aeddd4212edd4
parentd436818deded4064c5476111f980189836b360c7 (diff)
Improved some common helpers inside the Python API.
-rw-r--r--plugins/pychrysalide/common/fnv1a.c36
-rw-r--r--plugins/pychrysalide/common/module.c8
-rw-r--r--plugins/pychrysalide/common/pathname.c53
-rw-r--r--tests/common/fnv1a.py25
-rw-r--r--tests/common/pathname.py33
5 files changed, 113 insertions, 42 deletions
diff --git a/plugins/pychrysalide/common/fnv1a.c b/plugins/pychrysalide/common/fnv1a.c
index c24eb6e..381af78 100644
--- a/plugins/pychrysalide/common/fnv1a.c
+++ b/plugins/pychrysalide/common/fnv1a.c
@@ -36,6 +36,14 @@
+#define FNV1A_DOC \
+ "Python version for Chrysalide of the Fowler-Noll-Vo" \
+ " hash function.\n" \
+ "\n" \
+ "There is no constructor for this class: its methods" \
+ " are static methods only."
+
+
/* Détermine l'empreinte FNV1a d'une chaîne de caractères. */
static PyObject *py_fnv1a_hash(PyObject *, PyObject *);
@@ -61,6 +69,13 @@ static PyObject *py_fnv1a_hash(PyObject *self, PyObject *args)
int ret; /* Bilan de lecture des args. */
fnv64_t value; /* Empreinte calculée */
+#define FNV1A_HASH_METHOD PYTHON_METHOD_DEF \
+( \
+ hash, "str, /", \
+ METH_VARARGS | METH_STATIC, py_fnv1a, \
+ "Compute the FNV-1a hash from a given string." \
+)
+
ret = PyArg_ParseTuple(args, "s", &str);
if (!ret) return NULL;
@@ -88,27 +103,24 @@ static PyObject *py_fnv1a_hash(PyObject *self, PyObject *args)
PyTypeObject *get_python_fnv1a_type(void)
{
static PyMethodDef py_fnv1a_methods[] = {
-
- { "hash", py_fnv1a_hash,
- METH_VARARGS | METH_STATIC,
- "hash(str, /)\n--\n\nCompute the FNV-1a hash from a given string."
- },
+ FNV1A_HASH_METHOD,
{ NULL }
-
};
static PyTypeObject py_fnv1a_type = {
PyVarObject_HEAD_INIT(NULL, 0)
- .tp_name = "pychrysalide.core.fnv1a",
- .tp_basicsize = sizeof(PyObject),
+ .tp_name = "pychrysalide.common.fnv1a",
+ .tp_basicsize = sizeof(PyObject),
+
+ .tp_flags = Py_TPFLAGS_DEFAULT,
- .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IS_ABSTRACT,
+ .tp_doc = FNV1A_DOC,
- .tp_doc = "Python version for Chrysalide of the Fowler-Noll-Vo hash function.",
+ .tp_methods = py_fnv1a_methods,
- .tp_methods = py_fnv1a_methods
+ .tp_new = no_python_constructor_allowed,
};
@@ -138,8 +150,6 @@ bool ensure_python_fnv1a_is_registered(void)
if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
{
- //type->tp_new = PyType_GenericNew;
-
if (PyType_Ready(type) != 0)
return false;
diff --git a/plugins/pychrysalide/common/module.c b/plugins/pychrysalide/common/module.c
index e8cda4f..7f7cbb7 100644
--- a/plugins/pychrysalide/common/module.c
+++ b/plugins/pychrysalide/common/module.c
@@ -50,12 +50,18 @@ bool add_common_module(PyObject *super)
bool result; /* Bilan à retourner */
PyObject *module; /* Sous-module mis en place */
+#define PYCHRYSALIDE_COMMON_DOC \
+ "This module provides some tiny helpers for different use cases.\n" \
+ "\n" \
+ "The code for these features is shared between various parts of" \
+ " Chrysalide."
+
static PyModuleDef py_chrysalide_common_module = {
.m_base = PyModuleDef_HEAD_INIT,
.m_name = "pychrysalide.common",
- .m_doc = "Python module for Chrysalide.common",
+ .m_doc = PYCHRYSALIDE_COMMON_DOC,
.m_size = -1,
diff --git a/plugins/pychrysalide/common/pathname.c b/plugins/pychrysalide/common/pathname.c
index 8a18ae3..c83c27d 100644
--- a/plugins/pychrysalide/common/pathname.c
+++ b/plugins/pychrysalide/common/pathname.c
@@ -40,6 +40,13 @@
+#define PYTHON_PATHNAME_DOC \
+ "Path manipulations in Python for Chrysalide.\n" \
+ "\n" \
+ "There is no constructor for this class: its methods" \
+ " are static methods only."
+
+
/* Calcule le chemin relatif entre deux fichiers donnés. */
static PyObject *py_build_relative_filename(PyObject *, PyObject *);
@@ -69,6 +76,15 @@ static PyObject *py_build_relative_filename(PyObject *self, PyObject *args)
int ret; /* Bilan de lecture des args. */
char *relative; /* Chemin d'accès construit */
+#define BUILD_RELATIVE_FILENAME_METHOD PYTHON_METHOD_DEF \
+( \
+ build_relative_filename, "ref, target", \
+ METH_VARARGS | METH_STATIC, py, \
+ "Compute the relative path between two files.\n" \
+ "\n" \
+ "Both arguments must be strings." \
+)
+
ret = PyArg_ParseTuple(args, "ss", &ref, &target);
if (!ret) return NULL;
@@ -104,6 +120,15 @@ static PyObject *py_build_absolute_filename(PyObject *self, PyObject *args)
int ret; /* Bilan de lecture des args. */
char *relative; /* Chemin d'accès construit */
+#define BUILD_ABSOLUTE_FILENAME_METHOD PYTHON_METHOD_DEF \
+( \
+ build_absolute_filename, "ref, target", \
+ METH_VARARGS | METH_STATIC, py, \
+ "Compute the absolute path for a file.\n" \
+ "\n" \
+ "Both arguments must be strings." \
+)
+
ret = PyArg_ParseTuple(args, "ss", &ref, &target);
if (!ret) return NULL;
@@ -117,9 +142,7 @@ static PyObject *py_build_absolute_filename(PyObject *self, PyObject *args)
else
{
result = PyUnicode_FromString(relative);
-
free(relative);
-
}
return result;
@@ -142,31 +165,25 @@ static PyObject *py_build_absolute_filename(PyObject *self, PyObject *args)
PyTypeObject *get_python_pathname_type(void)
{
static PyMethodDef py_pathname_methods[] = {
-
- { "build_relative_filename", py_build_relative_filename,
- METH_VARARGS | METH_STATIC,
- "build_relative_filename(ref, target, /)\n--\n\nCompute the relative path between two files."
- },
- { "build_absolute_filename", py_build_absolute_filename,
- METH_VARARGS | METH_STATIC,
- "build_absolute_filename(ref, target, /)\n--\n\nCompute the absolute path for a file."
- },
+ BUILD_RELATIVE_FILENAME_METHOD,
+ BUILD_ABSOLUTE_FILENAME_METHOD,
{ NULL }
-
};
static PyTypeObject py_pathname_type = {
PyVarObject_HEAD_INIT(NULL, 0)
- .tp_name = "pychrysalide.core.pathname",
- .tp_basicsize = sizeof(PyObject),
+ .tp_name = "pychrysalide.common.pathname",
+ .tp_basicsize = sizeof(PyObject),
- .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IS_ABSTRACT,
+ .tp_flags = Py_TPFLAGS_DEFAULT,
- .tp_doc = "Path manipulations in Python for Chrysalide.",
+ .tp_doc = PYTHON_PATHNAME_DOC,
- .tp_methods = py_pathname_methods
+ .tp_methods = py_pathname_methods,
+
+ .tp_new = no_python_constructor_allowed,
};
@@ -196,8 +213,6 @@ bool ensure_python_pathname_is_registered(void)
if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
{
- //type->tp_new = PyType_GenericNew;
-
if (PyType_Ready(type) != 0)
return false;
diff --git a/tests/common/fnv1a.py b/tests/common/fnv1a.py
new file mode 100644
index 0000000..2013afa
--- /dev/null
+++ b/tests/common/fnv1a.py
@@ -0,0 +1,25 @@
+
+from chrysacase import ChrysalideTestCase
+from pychrysalide.common import fnv1a
+
+
+class TestFnv1a(ChrysalideTestCase):
+ """TestCase for common.fnv1a*"""
+
+ def testFnv1aConstructor(self):
+ """Check that no constructor is available for the fnv1a class."""
+
+ with self.assertRaisesRegex(NotImplementedError, 'Chrysalide does not allow building this kind of object from Python'):
+ instance = fnv1a()
+
+
+ def testFnv1aSamples(self):
+ """Compute some Fnv1a hashs."""
+
+ # Test cases from http://isthe.com/chongo/src/fnv/test_fnv.c
+
+ val = fnv1a.hash('')
+ self.assertEqual(val, 0xcbf29ce484222325)
+
+ val = fnv1a.hash('chongo was here!\n')
+ self.assertEqual(val, 0x46810940eff5f915)
diff --git a/tests/common/pathname.py b/tests/common/pathname.py
index 3692434..00a084b 100644
--- a/tests/common/pathname.py
+++ b/tests/common/pathname.py
@@ -1,21 +1,15 @@
-#!/usr/bin/python3-dbg
-# -*- coding: utf-8 -*-
-
-
-# Tests minimalistes pour valider la construction de chemins relatifs et absolus.
-
from chrysacase import ChrysalideTestCase
from pychrysalide.common import pathname
-class TestPathNames(ChrysalideTestCase):
- """TestCase for common.pathname.build*"""
+class TestPathnames(ChrysalideTestCase):
+ """TestCase for common.pathname*"""
@classmethod
def setUpClass(cls):
- super(TestPathNames, cls).setUpClass()
+ super(TestPathnames, cls).setUpClass()
cls._tests = [
{
@@ -93,3 +87,24 @@ class TestPathNames(ChrysalideTestCase):
with self.assertRaisesRegex(Exception, 'Relative path is too deep.'):
got = build_absolute('/a/b', '../../c')
+
+
+ def testPathnameConstructor(self):
+ """Check that no constructor is available for the pathname class."""
+
+ with self.assertRaisesRegex(NotImplementedError, 'Chrysalide does not allow building this kind of object from Python'):
+
+ instance = pathname()
+
+
+ def testPathnameSamples(self):
+ """Play with some path samples."""
+
+ filename = pathname.build_absolute_filename('/tmp/deep', '../myfile')
+ self.assertEqual(filename, '/myfile')
+
+ filename = pathname.build_absolute_filename('/tmp/deep/', '../myfile')
+ self.assertEqual(filename, '/tmp/myfile')
+
+ filename = pathname.build_relative_filename('/tmp/deep', '/myfile')
+ self.assertEqual(filename, '../myfile')