Skip to content

Commit 91e85f7

Browse files
committed
Improve signature for doc and error messages
- In progress. py_converters for STL type to complete.
1 parent 8f04672 commit 91e85f7

File tree

17 files changed

+275
-78
lines changed

17 files changed

+275
-78
lines changed

src/c2py/converters/basic_types.hpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ namespace c2py {
4040

4141
// --- bool
4242
template <> struct py_converter<bool> {
43+
static constexpr const char *tp_name = "bool";
4344
static PyObject *c2py(bool b) {
4445
if (b)
4546
Py_RETURN_TRUE;
@@ -58,6 +59,9 @@ namespace c2py {
5859

5960
namespace details {
6061
template <typename I> struct py_converter_impl {
62+
63+
static constexpr const char *tp_name = "int";
64+
6165
static PyObject *c2py(I i) { return PyLong_FromLong(long(i)); }
6266
static I py2c(PyObject *ob) {
6367
if (PyLong_Check(ob)) { return I(PyLong_AsLong(ob)); }
@@ -97,6 +101,8 @@ namespace c2py {
97101
// --- byte
98102

99103
template <> struct py_converter<std::byte> {
104+
static constexpr const char *tp_name = "bytes";
105+
100106
static PyObject *c2py(std::byte b) { return PyBytes_FromStringAndSize(reinterpret_cast<char *>(&b), 1); } //NOLINT
101107
static std::byte py2c(PyObject *ob) { return static_cast<std::byte>(PyBytes_AsString(ob)[0]); } //NOLINT
102108
static bool is_convertible(PyObject *ob, bool raise_exception) {
@@ -109,6 +115,8 @@ namespace c2py {
109115
// --- double
110116

111117
template <> struct py_converter<double> {
118+
static constexpr const char *tp_name = "float";
119+
112120
static PyObject *c2py(double x) { return PyFloat_FromDouble(x); }
113121
static double py2c(PyObject *ob) {
114122
if (PyFloat_Check(ob) || PyLong_Check(ob)) { return PyFloat_AsDouble(ob); }

src/c2py/converters/stl/complex.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ namespace c2py {
2525
// --- complex
2626

2727
template <> struct py_converter<std::complex<double>> {
28+
29+
static constexpr const char *tp_name = "complex";
2830
static PyObject *c2py(std::complex<double> x) { return PyComplex_FromDoubles(x.real(), x.imag()); }
2931
static std::complex<double> py2c(PyObject *ob) {
3032
if (PyArray_CheckScalar(ob)) {

src/c2py/converters/stl/pair.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ namespace c2py {
2323

2424
template <typename T1, typename T2> struct py_converter<std::pair<T1, T2>> {
2525

26+
static std::string tp_name() {
27+
std::ostringstream out;
28+
out << "tuple[" << python_typename<T1>() << ", " << python_typename<T2>() << "]";
29+
return out.str();
30+
}
31+
2632
template <typename P> static PyObject *c2py(P &&p) {
2733
static_assert(is_instantiation_of_v<std::pair, std::decay_t<P>>, "Logic error");
2834
pyref x1 = cxx2py(std::get<0>(std::forward<P>(p)));

src/c2py/converters/stl/string.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ namespace c2py {
2222

2323
template <> struct py_converter<std::string> {
2424

25+
static constexpr const char *tp_name = "str";
26+
2527
static PyObject *c2py(std::string const &x) { return PyUnicode_FromString(x.c_str()); }
2628

2729
static std::string py2c(PyObject *ob) { return PyUnicode_AsUTF8(ob); }

src/c2py/converters/stl/tuple.hpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,15 @@ namespace c2py {
2626

2727
template <typename... Types> struct py_converter<std::tuple<Types...>> {
2828

29+
static std::string tp_name() {
30+
std::ostringstream out;
31+
std::string sep;
32+
out << "tuple[";
33+
((out << sep << python_typename<Types>(), sep = ", "), ...);
34+
out << "]";
35+
return out.str();
36+
}
37+
2938
private:
3039
using tuple_t = std::tuple<Types...>;
3140

src/c2py/converters/stl/vector.hpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,14 @@
1717
// Authors: Olivier Parcollet, Nils Wentzell
1818

1919
#pragma once
20+
#include <sstream>
2021
#include <vector>
2122
#include <string>
2223
#include <cstddef>
2324

2425
#include "./common.hpp"
2526
#include "../../py_converter.hpp"
2627
#include "../numpy_proxy.hpp"
27-
2828
namespace c2py {
2929

3030
// Convert vector to numpy_proxy, WARNING: Deep Copy
@@ -96,6 +96,12 @@ namespace c2py {
9696

9797
template <typename T> struct py_converter<std::vector<T>> {
9898

99+
static std::string tp_name() {
100+
std::ostringstream out;
101+
out << "[" << python_typename<T>() << "]";
102+
return out.str();
103+
}
104+
99105
template <typename V> static PyObject *c2py(V &&v) {
100106
static_assert(is_instantiation_of_v<std::vector, std::decay_t<V>>, "Logic error");
101107
using value_type = typename std::remove_reference_t<V>::value_type;

src/c2py/cpp_name.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ namespace c2py {
1414
// FIXME : constexpr when implemented in clang 2b
1515
template <typename T> static inline const std::string cpp_name = trim(replacenl(std::string{util::type_name<T>()})); // typeid(T).name();
1616

17+
template <typename T> static constexpr char *tp_name = nullptr; //NOLINT
18+
19+
// cLEAN THIS
1720
// FIXME : if the first option is not ok, we have to enumerate all basic types , etc...
1821
// And specialize for all converters ?
1922
//template <> inline const std::string cpp_name<int> = "int";
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#include "dispatcher.hpp"
2+
3+
namespace c2py {
4+
template <typename Eraser, bool Constructors>
5+
PyObject *dispatcher_t<Eraser, Constructors>::call_impl(PyObject *self, PyObject *args, PyObject *kwargs) const {
6+
7+
for (auto const &ov : ov_list)
8+
if (ov->is_callable(self, args, kwargs)) return ov->operator()(self, args, kwargs);
9+
10+
// The call has failed. We rerun, but raising the exception in each case, and report
11+
std::stringstream err;
12+
err << "[c2py] Can not call the function with the arguments\n";
13+
//if (self) err << " - " << PyUnicode_AsUTF8(pyref{PyObject_Str(self)}) << "\n";
14+
if (args) err << " " << PyUnicode_AsUTF8(pyref{PyObject_Str(args)}) << "\n";
15+
if (kwargs) err << " " << PyUnicode_AsUTF8(pyref{PyObject_Str(kwargs)}) << "\n";
16+
err << "The dispatch to C++ failed with the following error(s):\n";
17+
int c = 0;
18+
for (auto const &ov : ov_list) {
19+
++c;
20+
ov->is_callable(self, args, kwargs, true);
21+
err << "[" << c << "] " << ov->signature() << "\n -- " << c2py::get_python_error() << "\n\n";
22+
}
23+
PyErr_SetString(PyExc_TypeError, err.str().c_str());
24+
return nullptr;
25+
}
26+
27+
// overload doc (string) in case only one overload ...
28+
// FIXME : to make generated code simpler in most cases.
29+
template <typename Eraser, bool Constructors>
30+
[[nodiscard]] std::string dispatcher_t<Eraser, Constructors>::doc(std::initializer_list<const char *> const &docs) const {
31+
assert(docs.size() == ov_list.size()); // by construction for the automated tool
32+
std::stringstream fs;
33+
fs << "Dispatched C++ function\n";
34+
// should use itertools ?
35+
//for (auto &&[n, ov] : itertools::enumerate(ov_list)) { fs << "[" << n + 1 << "] " << ov->signature() << "\n"; }
36+
int n = 1;
37+
for (auto const &ov : ov_list) fs << "[" << n++ << "] " << ov->signature() << "\n";
38+
fs << "\n";
39+
for (auto const &x : docs) { fs << x << "\n"; }
40+
return fs.str();
41+
}
42+
43+
template struct dispatcher_t<pycfun_kw, false>;
44+
template struct dispatcher_t<pycfun_kw, true>;
45+
template struct dispatcher_t<pycfun23, false>;
46+
template struct dispatcher_t<pycfun23, true>;
47+
48+
} // namespace c2py

src/c2py/dyn_dispatch/dispatcher.hpp

Lines changed: 2 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -13,28 +13,7 @@ namespace c2py {
1313
template <typename... U> dispatcher_t(U &&...u) { ((void)ov_list.push_back(std::forward<U>(u)), ...); }
1414

1515
private:
16-
// impl detail of ()
17-
PyObject *call_impl(PyObject *self, PyObject *args, PyObject *kwargs) const {
18-
19-
for (auto const &ov : ov_list)
20-
if (ov->is_callable(self, args, kwargs)) return ov->operator()(self, args, kwargs);
21-
22-
// The call has failed. We rerun, but raising the exception in each case, and report
23-
std::stringstream err;
24-
err << "[c2py] Can not call the function with the arguments\n";
25-
//if (self) err << " - " << PyUnicode_AsUTF8(pyref{PyObject_Str(self)}) << "\n";
26-
if (args) err << " - " << PyUnicode_AsUTF8(pyref{PyObject_Str(args)}) << "\n";
27-
if (kwargs) err << " - " << PyUnicode_AsUTF8(pyref{PyObject_Str(kwargs)}) << "\n";
28-
err << "The dispatch to C++ failed with the following error(s):\n";
29-
int c = 0;
30-
for (auto const &ov : ov_list) {
31-
++c;
32-
ov->is_callable(self, args, kwargs, true);
33-
err << "[" << c << "] " << ov->signature() << "\n " << c2py::get_python_error() << "\n";
34-
}
35-
PyErr_SetString(PyExc_TypeError, err.str().c_str());
36-
return nullptr;
37-
}
16+
PyObject *call_impl(PyObject *self, PyObject *args, PyObject *kwargs) const;
3817

3918
public:
4019
// Call each overload. The first available is used.
@@ -56,18 +35,7 @@ namespace c2py {
5635

5736
// overload doc (string) in case only one overload ...
5837
// FIXME : to make generated code simpler in most cases.
59-
[[nodiscard]] std::string doc(std::initializer_list<const char *> const &docs) const {
60-
assert(docs.size() == ov_list.size()); // by construction for the automated tool
61-
std::stringstream fs;
62-
fs << "Dispatched C++ function\n";
63-
int i = 0;
64-
// FIXME : use format when in std
65-
for (auto const &x : docs) {
66-
fs << "[" << i + 1 << "] " << ov_list[i]->signature() << "\n\n" << x << "\n\n";
67-
++i;
68-
}
69-
return fs.str();
70-
}
38+
[[nodiscard]] std::string doc(std::initializer_list<const char *> const &docs) const;
7139
};
7240

7341
// ==============================

src/c2py/dyn_dispatch/pycfun_kw.cpp

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -85,10 +85,23 @@ bool c2py::pycfun_kw::is_callable(PyObject *, PyObject *args, PyObject *kwargs,
8585
// --------------------------------
8686

8787
std::string c2py::pycfun_kw::signature() const {
88-
auto res = "("
89-
+ join(
90-
c_arguments, [](auto &&a) { return a.name + ": " + trim(*a.type_name); }, ", ");
91-
return (this->rtype_name ? res + ") -> " + (*this->rtype_name) : res + ")");
88+
// splitting strategy to be improved
89+
auto sign = [&](bool split_lines) {
90+
const char *sep = split_lines ? ",\n " : ", ";
91+
auto res = join(
92+
c_arguments,
93+
[](argument_t const &a) {
94+
return a.name + ": " + trim(a.python_typename()) + (a.default_value_printer ? " = " + a.default_value_printer(a.default_value) : "");
95+
},
96+
sep);
97+
auto rtype_name = this->python_return_typename();
98+
return "(" + (!rtype_name.empty() ? res + ")\n -> " + rtype_name : res + ")");
99+
};
100+
auto res = sign(false);
101+
if (res.size() > 100)
102+
return sign(true);
103+
else
104+
return res;
92105
}
93106

94107
// --------------------------------

0 commit comments

Comments
 (0)