diff --git a/CMakeLists.txt b/CMakeLists.txt
index 1aadb3403c75832da402c28759a2331c8ef41ec0..baccc36f16e4a14457cc59f8da2d816382389625 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -31,6 +31,12 @@ endif()
 
 include("${JRL_CMAKE_MODULES}/base.cmake")
 include("${JRL_CMAKE_MODULES}/boost.cmake")
+include(CMakeDependentOption)
+
+cmake_dependent_option(
+  GENERATE_PYTHON_STUBS
+  "Generate the Python stubs associated to the Python library" OFF
+  BUILD_PYTHON_INTERFACE ON)
 
 set_default_cmake_build_type("Release")
 
diff --git a/python/ndcurves/CMakeLists.txt b/python/ndcurves/CMakeLists.txt
index 6d8836d1ec945862baf44ff6f79c95717d966741..6ee95141e212c735e2ab12261ae768937d523ab7 100644
--- a/python/ndcurves/CMakeLists.txt
+++ b/python/ndcurves/CMakeLists.txt
@@ -1,3 +1,7 @@
+if(GENERATE_PYTHON_STUBS)
+  include("${JRL_CMAKE_MODULES}/stubs.cmake")
+endif(GENERATE_PYTHON_STUBS)
+
 set(${PROJECT_NAME}_WRAP_SOURCES
     curves_python.cpp
     optimization_python.cpp
@@ -19,6 +23,12 @@ target_link_libraries(${wrap} PUBLIC ${PROJECT_NAME})
 target_link_libraries(${wrap} PUBLIC eigenpy::eigenpy)
 target_link_boost_python(${wrap} PUBLIC)
 
+if(GENERATE_PYTHON_STUBS)
+  load_stubgen()
+  generate_stubs(${CMAKE_CURRENT_BINARY_DIR} ${PROJECT_NAME} ${PYTHON_SITELIB}
+                 ${wrap})
+endif(GENERATE_PYTHON_STUBS)
+
 if(APPLE)
   # We need to change the extension for python bindings
   set_target_properties(${wrap} PROPERTIES SUFFIX ".so")
diff --git a/python/ndcurves/curves_python.cpp b/python/ndcurves/curves_python.cpp
index b92a58afe8e42b0e1305d3ca5793f46265a224be..89890294d2a5e813653ac27a443380f32c4c25f2 100644
--- a/python/ndcurves/curves_python.cpp
+++ b/python/ndcurves/curves_python.cpp
@@ -1325,7 +1325,7 @@ BOOST_PYTHON_MODULE(ndcurves) {
            "where T_{min} is equal toT_{max} of the actual piecewise curve.")
       .def("is_continuous", &piecewise_t::is_continuous,
            "Check if the curve is continuous at the given order.",
-           args("self,order"))
+           args("self", "order"))
       .def("convert_piecewise_curve_to_polynomial",
            &piecewise_t::convert_piecewise_curve_to_polynomial<polynomial_t>,
            "Convert a piecewise curve to to a piecewise polynomial curve")
@@ -1371,7 +1371,7 @@ BOOST_PYTHON_MODULE(ndcurves) {
            "where T_{min} is equal toT_{max} of the actual piecewise curve.")
       .def("is_continuous", &piecewise_bezier_t::is_continuous,
            "Check if the curve is continuous at the given order.",
-           args("self,order"))
+           args("self", "order"))
       .def("curve_at_index", &piecewise_bezier_t::curve_at_index)
       .def("curve_at_time", &piecewise_bezier_t::curve_at_time)
       .def("num_curves", &piecewise_bezier_t::num_curves)
@@ -1398,7 +1398,7 @@ BOOST_PYTHON_MODULE(ndcurves) {
 
   class_<piecewise_linear_bezier_t, bases<curve_abc_t>,
          boost::shared_ptr<piecewise_linear_bezier_t> >(
-      "piecewise_bezier_linear", init<>())
+      "piecewise_bezier_linear", init<>(args("self")))
       .def("__init__",
            make_constructor(&wrapPiecewiseBezierLinearConstructor,
                             default_call_policies(), arg("curve")),
@@ -1412,7 +1412,7 @@ BOOST_PYTHON_MODULE(ndcurves) {
            "where T_{min} is equal toT_{max} of the actual piecewise curve.")
       .def("is_continuous", &piecewise_linear_bezier_t::is_continuous,
            "Check if the curve is continuous at the given order.",
-           args("self,order"))
+           args("self", "order"))
       .def("curve_at_index", &piecewise_linear_bezier_t::curve_at_index)
       .def("curve_at_time", &piecewise_linear_bezier_t::curve_at_time)
       .def("num_curves", &piecewise_linear_bezier_t::num_curves)
@@ -1453,10 +1453,10 @@ BOOST_PYTHON_MODULE(ndcurves) {
            "Add a new curve to piecewise curve, which should be defined in "
            "T_{min},T_{max}] "
            "where T_{min} is equal toT_{max} of the actual piecewise curve.",
-           args("self,curve"))
+           args("self", "curve"))
       .def("is_continuous", &piecewise_SE3_t::is_continuous,
            "Check if the curve is continuous at the given order.",
-           args("self,order"))
+           args("self", "order"))
       .def("curve_at_index", &piecewise_SE3_t::curve_at_index)
       .def("curve_at_time", &piecewise_SE3_t::curve_at_time)
       .def("num_curves", &piecewise_SE3_t::num_curves)
@@ -1497,8 +1497,8 @@ BOOST_PYTHON_MODULE(ndcurves) {
       "exact_cubic", init<>())
       .def("__init__", make_constructor(&wrapExactCubicConstructor))
       .def("__init__", make_constructor(&wrapExactCubicConstructorConstraint))
-      .def("getNumberSplines", &exact_cubic_t::getNumberSplines)
-      .def("getSplineAt", &exact_cubic_t::getSplineAt)
+      .def("getNumberSplines", &exact_cubic_t::getNumberSplines, args("self"))
+      .def("getSplineAt", &exact_cubic_t::getSplineAt, args("self", "index"))
       .def("saveAsText", &exact_cubic_t::saveAsText<exact_cubic_t>,
            bp::args("filename"), "Saves *this inside a text file.")
       .def("loadFromText", &exact_cubic_t::loadFromText<exact_cubic_t>,
@@ -1521,8 +1521,11 @@ BOOST_PYTHON_MODULE(ndcurves) {
   /** BEGIN cubic_hermite_spline **/
   class_<cubic_hermite_spline_t, bases<curve_abc_t>,
          boost::shared_ptr<cubic_hermite_spline_t> >("cubic_hermite_spline",
-                                                     init<>())
-      .def("__init__", make_constructor(&wrapCubicHermiteSplineConstructor))
+                                                     init<>(args("self")))
+      .def("__init__",
+           make_constructor(&wrapCubicHermiteSplineConstructor,
+                            bp::default_call_policies(),
+                            args("points", "tangents", "times")))
       .def("saveAsText",
            &cubic_hermite_spline_t::saveAsText<cubic_hermite_spline_t>,
            bp::args("filename"), "Saves *this inside a text file.")
@@ -1550,7 +1553,7 @@ BOOST_PYTHON_MODULE(ndcurves) {
   /** END cubic_hermite_spline **/
   /** BEGIN curve constraints**/
   class_<curve_constraints_t>("curve_constraints", init<>())
-      .def(bp::init<int>(bp::arg("dimension"), "Init with a given dimension."))
+      .def(bp::init<int>(args("self", "dimension"), "Init with a given dimension."))
       .add_property("init_vel", &get_init_vel, &set_init_vel)
       .add_property("init_acc", &get_init_acc, &set_init_acc)
       .add_property("init_jerk", &get_init_jerk, &set_init_jerk)