17 #include <unordered_map>
18 #include <unordered_set>
25 py::handle((PyObject*)py::detail::get_internals().static_property_type);
28 const std::string& class_name,
29 const std::string& function_name,
30 const std::unordered_map<std::string, std::string>&
31 map_parameter_body_docs) {
33 PyObject* module = pybind_module.ptr();
34 PyObject* class_obj = PyObject_GetAttrString(module, class_name.c_str());
35 if (class_obj ==
nullptr) {
39 PyObject* class_method_obj =
40 PyObject_GetAttrString(class_obj, function_name.c_str());
41 if (class_method_obj ==
nullptr) {
48 PyCFunctionObject* f =
nullptr;
49 if (Py_TYPE(class_method_obj) == &PyInstanceMethod_Type) {
50 PyInstanceMethodObject* class_method =
51 (PyInstanceMethodObject*)class_method_obj;
52 f = (PyCFunctionObject*)class_method->func;
54 if (Py_TYPE(class_method_obj) == &PyCFunction_Type) {
56 f = (PyCFunctionObject*)class_method_obj;
58 if (f ==
nullptr || Py_TYPE(f) != &PyCFunction_Type) {
68 if (map_parameter_body_docs.count(ad.
name_) > 0) {
69 ad.
body_ = map_parameter_body_docs.at(ad.
name_);
77 const std::string& function_name,
78 const std::unordered_map<std::string, std::string>&
79 map_parameter_body_docs) {
81 PyObject* module = pybind_module.ptr();
82 PyObject* f_obj = PyObject_GetAttrString(module, function_name.c_str());
83 if (f_obj ==
nullptr) {
87 if (Py_TYPE(f_obj) != &PyCFunction_Type) {
90 PyCFunctionObject* f = (PyCFunctionObject*)f_obj;
98 if (map_parameter_body_docs.count(ad.
name_) > 0) {
99 ad.
body_ = map_parameter_body_docs.at(ad.
name_);
107 : pybind_doc_(pybind_doc) {
120 if (parenthesis_pos != std::string::npos) {
124 size_t preamble_end =
pybind_doc_.find(
"Overloaded function.");
125 if (preamble_end == std::string::npos) {
126 return parenthesis_pos;
128 preamble_end += strlen(
"Overloaded function.");
136 size_t summary_end_pos = std::string::npos;
137 if (arrow_pos != std::string::npos) {
139 size_t result_type_pos = arrow_pos + 4;
140 size_t summary_start_pos =
146 if (summary_end_pos == std::string::npos)
149 summary_end_pos -= 3;
150 size_t summary_len = summary_end_pos - summary_start_pos;
151 if (summary_len > 0) {
152 std::string summary =
153 pybind_doc_.substr(summary_start_pos, summary_len);
157 return summary_end_pos;
169 for (
const std::string& argument_token : argument_tokens) {
177 if (arrow_pos != std::string::npos && arrow_pos >
doc_pos_[0]) {
178 size_t result_type_pos = arrow_pos + 4;
191 std::ostringstream rc;
192 std::string indent =
" ";
193 size_t n_overload = 1;
203 for (
size_t i = 0; i < overload.argument_docs_.size(); ++i) {
204 const ArgumentDoc& argument_doc = overload.argument_docs_[i];
205 rc << argument_doc.
name_;
209 if (i != overload.argument_docs_.size() - 1) {
218 if (overload.summary_ !=
"") {
224 if (overload.argument_docs_.size() != 0 &&
225 !(overload.argument_docs_.size() == 1 &&
226 overload.argument_docs_[0].name_ ==
"self")) {
229 for (
const ArgumentDoc& argument_doc : overload.argument_docs_) {
230 if (argument_doc.
name_ ==
"self") {
233 rc << indent << argument_doc.
name_ <<
" ("
234 << argument_doc.
type_;
240 rc <<
", default=" << argument_doc.
default_;
243 if (argument_doc.
body_ !=
"") {
244 rc <<
": " << argument_doc.
body_;
250 bool prev_line_is_listing =
false;
251 for (std::string& line : lines) {
253 if (line[0] ==
'-') {
255 if (!prev_line_is_listing) {
258 prev_line_is_listing =
true;
260 prev_line_is_listing =
false;
262 rc << indent << indent << line <<
std::endl;
271 if (
name_ !=
"__init__") {
274 rc << indent << overload.return_doc_.type_;
275 if (overload.return_doc_.body_ !=
"") {
276 rc <<
": " << overload.return_doc_.body_;
285 const std::string& white_space) {
294 std::regex rgx_with_default(
295 "([A-Za-z_][A-Za-z\\d_]*): "
296 "([A-Za-z_][A-Za-z\\d_:\\.\\[\\]\\(\\) ,]*) = (.*)");
298 if (std::regex_search(argument_token, matches, rgx_with_default)) {
299 argument_doc.
name_ = matches[1].str();
300 argument_doc.
type_ = matches[2].str();
301 argument_doc.
default_ = matches[3].str();
305 size_t default_start_pos = matches.position(3);
306 if (default_start_pos + argument_doc.
default_.size() <
307 argument_token.size()) {
310 argument_token.size() - default_start_pos);
311 argument_doc.
default_ =
"(with default value)";
317 std::regex rgx_without_default(
318 "([A-Za-z_][A-Za-z\\d_]*): "
319 "([A-Za-z_][A-Za-z\\d_:\\.\\[\\]\\(\\) ,]*)");
320 if (std::regex_search(argument_token, matches, rgx_without_default)) {
321 argument_doc.
name_ = matches[1].str();
322 argument_doc.
type_ = matches[2].str();
330 const std::string& pybind_doc) {
336 std::string str = pybind_doc;
337 size_t parenthesis_pos = str.find(
"(");
338 if (parenthesis_pos == std::string::npos) {
341 str.replace(parenthesis_pos + 1, 0,
", ");
345 std::regex pattern(
"(, [A-Za-z_][A-Za-z\\d_]*:)");
347 std::string::const_iterator start_iter(str.cbegin());
348 std::vector<size_t> argument_start_positions;
349 while (std::regex_search(start_iter, str.cend(), res, pattern)) {
350 size_t pos = res.position(0) + (start_iter - str.cbegin());
351 start_iter = res.suffix().first;
353 argument_start_positions.push_back(pos + 2);
359 std::vector<size_t> argument_end_positions;
360 for (
size_t i = 0; i + 1 < argument_start_positions.size(); ++i) {
361 argument_end_positions.push_back(argument_start_positions[i + 1] - 2);
363 std::size_t arrow_pos = str.rfind(
") -> ");
364 if (arrow_pos == std::string::npos) {
367 argument_end_positions.push_back(arrow_pos);
370 std::vector<std::string> argument_tokens;
371 for (
size_t i = 0; i < argument_start_positions.size(); ++i) {
372 std::string token = str.substr(
373 argument_start_positions[i],
374 argument_end_positions[i] - argument_start_positions[i]);
375 argument_tokens.push_back(token);
377 return argument_tokens;
std::string long_default_
static std::vector< std::string > GetArgumentTokens(const std::string &pybind_doc)
std::vector< OverloadDocs > overload_docs_
std::string ToGoogleDocString() const
Generate Google style python docstring.
FunctionDoc(const std::string &pybind_doc)
void ParseReturn()
Parse function return.
static ArgumentDoc ParseArgumentToken(const std::string &argument_token)
Parse individual argument token and returns a ArgumentDoc.
size_t ParseFunctionName()
static std::string StringCleanAll(std::string &s, const std::string &white_space=" \t\n")
Runs all string cleanup functions.
void ParseArguments()
Parse ArgumentDoc for each argument.
Helper functions for the ml ops.
QTextStream & endl(QTextStream &stream)
void ClassMethodDocInject(py::module &pybind_module, const std::string &class_name, const std::string &function_name, const std::unordered_map< std::string, std::string > &map_parameter_body_docs)
py::handle static_property
void FunctionDocInject(py::module &pybind_module, const std::string &function_name, const std::unordered_map< std::string, std::string > &map_parameter_body_docs)
size_t WordLength(const std::string &doc, size_t start_pos, const std::string &valid_chars="_")
void SplitString(std::vector< std::string > &tokens, const std::string &str, const std::string &delimiters=" ", bool trim_empty_str=true)
std::string & StripString(std::string &str, const std::string &chars="\t\n\v\f\r ")
Generic file read and write utility for python interface.