docstring-generator-ext 1.0.2__tar.gz → 1.0.3a5__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: docstring_generator_ext
3
- Version: 1.0.2
3
+ Version: 1.0.3a5
4
4
  Summary: Generate Docstrings with type-hint information.
5
5
  Author-email: FelixTheC <fberndt87@gmail.com>
6
6
  Classifier: Environment :: Console
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: docstring_generator_ext
3
- Version: 1.0.2
3
+ Version: 1.0.3a5
4
4
  Summary: Generate Docstrings with type-hint information.
5
5
  Author-email: FelixTheC <fberndt87@gmail.com>
6
6
  Classifier: Environment :: Console
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "docstring_generator_ext"
3
- version = "1.0.2"
3
+ version = "1.0.3a5"
4
4
  description = "Generate Docstrings with type-hint information."
5
5
  authors = [
6
6
  { name = "FelixTheC", email = "fberndt87@gmail.com" },
@@ -41,5 +41,9 @@ archs = ["x86_64"]
41
41
  [tool.cibuildwheel.macos]
42
42
  archs = ["x86_64", "arm64"]
43
43
 
44
+ [tool.cibuildwheel.macos.environment]
45
+ MACOSX_DEPLOYMENT_TARGET = "13.3"
46
+ CXXFLAGS = "-std=c++20"
47
+
44
48
  [tool.cibuildwheel.windows]
45
49
  archs = ["AMD64"]
@@ -1,9 +1,10 @@
1
1
  #include "docstringFormat.hpp"
2
2
  #include <algorithm>
3
- #include <sstream>
4
- #include <map>
3
+ #include <format>
5
4
  #include <fstream>
6
5
  #include <iostream>
6
+ #include <map>
7
+ #include <sstream>
7
8
 
8
9
  #include <pybind11/pybind11.h>
9
10
  namespace py = pybind11;
@@ -107,7 +108,7 @@ void FunctionParameter::update_description(const std::string &descr) noexcept {
107
108
  std::stringstream sstream;
108
109
  sstream << kind;
109
110
 
110
- auto kind_name = sstream.str();
111
+ const auto kind_name = sstream.str();
111
112
  auto start_pos = descr.find(kind_name) + kind_name.size() + 2;
112
113
 
113
114
  if (descr.find(kind_name) == std::string::npos)
@@ -119,7 +120,7 @@ void FunctionParameter::update_description(const std::string &descr) noexcept {
119
120
  end_pos = descr.find("default") - 2;
120
121
  }
121
122
 
122
- auto new_description = descr.substr(start_pos, end_pos - start_pos);
123
+ const auto new_description = descr.substr(start_pos, end_pos - start_pos);
123
124
  description = remove_whitespace(remove_trailing_whitespace(new_description));
124
125
  }
125
126
 
@@ -143,13 +144,13 @@ void FunctionParameter::update_rest_description(const std::string &descr) noexce
143
144
  end_pos = descr.find(kind_param);
144
145
  }
145
146
 
147
+ auto new_description = descr.substr(start_pos);
148
+
146
149
  if (end_pos != std::string::npos) {
147
- auto new_description = descr.substr(start_pos, end_pos - start_pos);
148
- description = remove_whitespace(remove_trailing_whitespace(new_description));
149
- } else {
150
- auto new_description = descr.substr(start_pos);
151
- description = remove_whitespace(remove_trailing_whitespace(new_description));
150
+ new_description = descr.substr(start_pos, end_pos - start_pos);
152
151
  }
152
+
153
+ description = remove_whitespace(remove_trailing_whitespace(new_description));
153
154
  }
154
155
 
155
156
  [[nodiscard]] int FunctionInfo::get_file_write_position() const noexcept {
@@ -167,7 +168,7 @@ void FunctionParameter::update_rest_description(const std::string &descr) noexce
167
168
  return 0;
168
169
  }
169
170
 
170
- void FunctionInfo::update_descriptions(DocstringFormatStyle &formatStyle) noexcept {
171
+ void FunctionInfo::update_descriptions(const DocstringFormatStyle &formatStyle) noexcept {
171
172
  for (size_t idx = 0; idx < args.size(); ++idx) {
172
173
  size_t start_pos;
173
174
 
@@ -194,7 +195,7 @@ void FunctionInfo::update_descriptions(DocstringFormatStyle &formatStyle) noexce
194
195
 
195
196
  [[ nodiscard ]] std::string DocstringFormat::docstring() noexcept {
196
197
  std::stringstream sstream;
197
- auto current_pytab = get_tabs();
198
+ const auto current_pytab = get_tabs();
198
199
 
199
200
  sstream << current_pytab << R"(""")";
200
201
  if (functionInfo.docstring.docstring.empty()) {
@@ -202,6 +203,7 @@ void FunctionInfo::update_descriptions(DocstringFormatStyle &formatStyle) noexce
202
203
  }
203
204
  sstream << docstringArgs();
204
205
  sstream << docstringReturn();
206
+ sstream << docstringExceptions();
205
207
 
206
208
  sstream << current_pytab << R"(""")";
207
209
  if (functionInfo.docstring.docstring.empty()) {
@@ -251,9 +253,7 @@ std::string GoogleDocstring::docstringArgs() noexcept {
251
253
  }
252
254
 
253
255
  sstream << "Args:\n";
254
- std::for_each(
255
- functionInfo.args.begin(),
256
- functionInfo.args.end(),
256
+ std::ranges::for_each(functionInfo.args,
257
257
  [&sstream, &current_py_tab](const FunctionParameter &val) {
258
258
  sstream << current_py_tab << val.name;
259
259
  if (!val.type.empty()) {
@@ -264,14 +264,12 @@ std::string GoogleDocstring::docstringArgs() noexcept {
264
264
  sstream << ")";
265
265
  }
266
266
 
267
- if (val.description.empty()) {
268
- sstream << " : " << val.kind << "\n";
269
- } else {
270
- sstream << " : " << val.kind << ". " << val.description << "\n";
267
+ if (!val.description.empty()) {
268
+ sstream << ": " << val.description;
271
269
  }
272
270
 
273
271
  if (!val.default_value.empty()) {
274
- sstream << current_py_tab << PY_TAB << "(default is " << val.default_value << ")\n";
272
+ sstream << " (default is " << val.default_value << ")\n";
275
273
  }
276
274
  }
277
275
  );
@@ -283,9 +281,9 @@ std::string GoogleDocstring::docstringReturn() noexcept {
283
281
  std::stringstream sstream;
284
282
  auto current_py_tab = get_tabs();
285
283
 
286
- sstream << "\n";
287
-
288
284
  if (!functionInfo.returns.description.empty() || !functionInfo.returns.type.empty()) {
285
+ sstream << "\n";
286
+
289
287
  if (PY_TAB != current_py_tab) {
290
288
  sstream << PY_TAB;
291
289
  } else {
@@ -295,10 +293,46 @@ std::string GoogleDocstring::docstringReturn() noexcept {
295
293
 
296
294
  sstream << "Returns:\n";
297
295
  sstream << current_py_tab;
296
+
298
297
  if (!functionInfo.returns.type.empty()) {
299
- sstream << "( " << functionInfo.returns.type << " ) : ";
298
+ sstream << functionInfo.returns.type << ": ";
299
+ }
300
+ if (!functionInfo.returns.description.empty()) {
301
+ sstream << functionInfo.returns.description;
302
+ }
303
+ } else {
304
+ sstream << "";
305
+ }
306
+
307
+ return sstream.str();
308
+ }
309
+
310
+ std::string GoogleDocstring::docstringExceptions() noexcept {
311
+ if (functionInfo.exceptions.empty())
312
+ return "\n";
313
+
314
+ std::stringstream sstream;
315
+ auto current_py_tab = get_tabs();
316
+
317
+ sstream << "\n";
318
+
319
+ if (PY_TAB != current_py_tab) {
320
+ sstream << PY_TAB;
321
+ } else {
322
+ sstream << PY_TAB;
323
+ current_py_tab = PY_TAB + PY_TAB;
324
+ }
325
+
326
+ sstream << "Raises:\n";
327
+ sstream << current_py_tab;
328
+
329
+ for (const auto &[name, description] : functionInfo.exceptions) {
330
+ if (!name.empty()) {
331
+ sstream << name << ": ";
332
+ }
333
+ if (!description.empty()) {
334
+ sstream << description;
300
335
  }
301
- sstream << functionInfo.returns.description << "\n";
302
336
 
303
337
  sstream << "\n";
304
338
  }
@@ -367,10 +401,23 @@ std::string reStructuredDocstring::docstringReturn() noexcept {
367
401
  const auto current_py_tab = get_tabs();
368
402
 
369
403
  if (!functionInfo.returns.description.empty()) {
370
- sstream << current_py_tab << ":returns:" << functionInfo.returns.description << "\n";
404
+ sstream << current_py_tab << ":returns: " << functionInfo.returns.description << "\n";
371
405
  }
372
406
  if (!functionInfo.returns.type.empty()) {
373
- sstream << current_py_tab << ":rtype:" << functionInfo.returns.type << "\n";
407
+ sstream << current_py_tab << ":rtype: " << functionInfo.returns.type << "\n";
408
+ }
409
+ return sstream.str();
410
+ }
411
+
412
+ std::string reStructuredDocstring::docstringExceptions() noexcept {
413
+ if (functionInfo.exceptions.empty())
414
+ return "";
415
+
416
+ std::stringstream sstream;
417
+ const auto current_py_tab = get_tabs();
418
+
419
+ for (const auto &[name, description] : functionInfo.exceptions) {
420
+ sstream << current_py_tab << ":raises " << name << ": " << description << "\n";
374
421
  }
375
422
  return sstream.str();
376
423
  }
@@ -404,7 +451,11 @@ std::string NumpyDocstring::docstringArgs() noexcept {
404
451
  [&docstream, &current_py_tab](const FunctionParameter &val) {
405
452
  std::stringstream sstream;
406
453
 
407
- sstream << current_py_tab << val.name;
454
+ if (val.name.empty())
455
+ sstream << current_py_tab << "PLACEHOLDER";
456
+ else
457
+ sstream << current_py_tab << val.name;
458
+
408
459
  sstream << " :";
409
460
 
410
461
  if (!val.type.empty()) {
@@ -456,7 +507,33 @@ std::string NumpyDocstring::docstringReturn() noexcept {
456
507
  sstream << current_py_tab << PY_TAB << functionInfo.returns.description;
457
508
  }
458
509
 
510
+ if (!functionInfo.returns.type.empty() || !functionInfo.returns.description.empty())
511
+ sstream << "\n";
512
+
513
+ return sstream.str();
514
+ }
515
+
516
+ std::string NumpyDocstring::docstringExceptions() noexcept {
517
+ if (functionInfo.exceptions.empty())
518
+ return "";
519
+
520
+ std::stringstream sstream;
521
+ const auto current_py_tab = get_tabs();
522
+
459
523
  sstream << "\n";
524
+ sstream << current_py_tab << "Raises\n";
525
+ sstream << current_py_tab << "-------\n";
526
+
527
+ for (const auto &[name, description]: functionInfo.exceptions) {
528
+ if (!name.empty()) {
529
+ sstream << current_py_tab << name;
530
+ sstream << "\n";
531
+ }
532
+ if (!description.empty()) {
533
+ sstream << current_py_tab << PY_TAB << description;
534
+ }
535
+ sstream << "\n";
536
+ }
460
537
 
461
538
  return sstream.str();
462
539
  }
@@ -464,7 +541,7 @@ std::string NumpyDocstring::docstringReturn() noexcept {
464
541
  void write_to_file_position(
465
542
  std::vector<FunctionInfo> &&infos,
466
543
  const std::string &file_path,
467
- DocstringFormatStyle &formatStyle
544
+ const DocstringFormatStyle &formatStyle
468
545
  ) noexcept;
469
546
 
470
547
  FunctionDocstring get_docstring(const py::object &obj, const py::module &ast_module) noexcept {
@@ -656,7 +733,7 @@ std::vector<FunctionParameter> generate_function_parameters(
656
733
  annotation_str = parse_ast_obj(annotation, ast_module);
657
734
  }
658
735
 
659
- std::string parameter_name = py::cast<std::string>(py::getattr(vararg, "arg"));
736
+ auto parameter_name = py::cast<std::string>(py::getattr(vararg, "arg"));
660
737
  result.emplace_back(
661
738
  FunctionParameter{
662
739
  parameter_name,
@@ -678,7 +755,7 @@ std::vector<FunctionParameter> generate_function_parameters(
678
755
  annotation_str = parse_ast_obj(annotation, ast_module);
679
756
  }
680
757
 
681
- std::string parameter_name = py::cast<std::string>(py::getattr(elem, "arg"));
758
+ auto parameter_name = py::cast<std::string>(py::getattr(elem, "arg"));
682
759
  result.emplace_back(
683
760
  FunctionParameter{
684
761
  parameter_name,
@@ -700,7 +777,7 @@ std::vector<FunctionParameter> generate_function_parameters(
700
777
  annotation_str = parse_ast_obj(annotation, ast_module);
701
778
  }
702
779
 
703
- std::string parameter_name = py::cast<std::string>(py::getattr(kwarg, "arg"));
780
+ auto parameter_name = py::cast<std::string>(py::getattr(kwarg, "arg"));
704
781
  result.emplace_back(
705
782
  FunctionParameter{
706
783
  parameter_name,
@@ -805,8 +882,77 @@ void get_docstring_arg_descr(FunctionInfo &functionInfo) noexcept {
805
882
  }
806
883
  }
807
884
 
885
+ void get_exception(const pybind11::object &function_body, py::module &ast_module, std::vector<FunctionException> &exception_names, const py::object &parent = py::none()) {
886
+ py::iterator iter = py::iter(function_body);
887
+ for (auto &obj: iter) {
888
+ if (py::hasattr(obj, "body")) {
889
+ const auto inner = py::getattr(obj, "body");
890
+ if (py::isinstance(obj, ast_module.attr("If"))) {
891
+ auto parent_node = py::reinterpret_borrow<py::object>(obj);
892
+ get_exception(inner, ast_module, exception_names, parent_node);
893
+ }
894
+ else
895
+ get_exception(inner, ast_module, exception_names);
896
+ }
897
+
898
+ if (py::isinstance(obj, ast_module.attr("Try"))) {
899
+ auto handlers = py::getattr(obj, "handlers");
900
+ py::iterator handlers_iter = py::iter(handlers);
901
+ for (const auto &handler : handlers_iter) {
902
+ const auto parent_node = py::reinterpret_borrow<py::object>(handler);
903
+ const auto inner = py::getattr(handler, "body");
904
+ get_exception(inner, ast_module, exception_names, parent_node);
905
+ }
906
+ }
907
+
908
+ if (py::isinstance(obj, ast_module.attr("Raise"))) {
909
+ // when `exc` is None this means we're re-raising the exception
910
+ if (py::getattr(obj, "exc").is(py::none())) {
911
+ if (!parent.is(py::none())) {
912
+ if (py::hasattr(parent, "type")) {
913
+ const auto exception_type = py::getattr(parent, "type");
914
+ if (py::hasattr(exception_type, "id")) {
915
+ const auto exception_name = py::cast<std::string>(py::getattr(exception_type, "id"));
916
+ exception_names.emplace_back(FunctionException{.name=exception_name, .description="Re-raising this handled exception"});
917
+ }
918
+ }
919
+ }
920
+ } else {
921
+ try {
922
+ const auto exception_object = py::getattr(py::getattr(obj, "exc"), "func");
923
+ if (py::hasattr(exception_object, "id")) {
924
+ const auto exception_name = py::cast<std::string>(py::getattr(exception_object, "id"));
925
+ std::string exception_description = "If a certain condition is met.";
926
+
927
+ if (!parent.is(py::none())) {
928
+ if (py::hasattr(parent, "test")) {
929
+ const auto val = py::cast<std::string>(ast_module.attr("unparse")(py::getattr(parent, "test")));
930
+ // Should theoretical not be empty, cause we parse an "If" expression
931
+ if (!val.empty()) {
932
+ exception_description = std::format("If {}", val);
933
+ }
934
+ } else if (py::hasattr(parent, "type")) {
935
+ const auto exception_type = py::getattr(parent, "type");
936
+ if (py::hasattr(exception_type, "id")) {
937
+ const auto main_exception_name = py::cast<std::string>(py::getattr(exception_type, "id"));
938
+ if (!main_exception_name.empty())
939
+ exception_description = std::format("Re-Raised from {}", main_exception_name);
940
+ }
941
+ }
942
+ }
943
+
944
+ if (!exception_name.empty())
945
+ exception_names.emplace_back(FunctionException{.name=exception_name, .description=exception_description});
946
+ }
947
+ } catch (const std::exception &) {
948
+ py::print("Could not extract exception.");
949
+ }
950
+ }
951
+ }
952
+ }
953
+ }
954
+
808
955
  void parse_file(std::string &file_path, DocstringFormatStyle &formatStyle) {
809
- std::string file_path_cache = file_path;
810
956
  py::module ast_module = py::module_::import("ast");
811
957
  py::object generator_result = ast_module.attr("walk")(ast_module.attr("parse")(read_file(file_path)));
812
958
  py::iterator iter = py::iter(generator_result);
@@ -814,7 +960,14 @@ void parse_file(std::string &file_path, DocstringFormatStyle &formatStyle) {
814
960
  std::vector<FunctionInfo> infos{};
815
961
 
816
962
  for (auto &obj: iter) {
817
- if (py::isinstance(obj, ast_module.attr("FunctionDef"))) {
963
+ if (py::isinstance(obj, ast_module.attr("FunctionDef")) || py::isinstance(obj, ast_module.attr("AsyncFunctionDef"))) {
964
+ std::vector<FunctionException> function_exceptions{};
965
+
966
+ if (py::hasattr(obj, "body")) {
967
+ auto inner = py::getattr(obj, "body");
968
+ get_exception(inner, ast_module, function_exceptions);
969
+ }
970
+
818
971
  auto name = py::cast<std::string>(py::getattr(obj, "name"));
819
972
  auto offset = py::cast<uint32_t>(py::getattr(obj, "col_offset"));
820
973
 
@@ -840,13 +993,17 @@ void parse_file(std::string &file_path, DocstringFormatStyle &formatStyle) {
840
993
  auto f_args = generate_function_parameters(args, ast_module);
841
994
 
842
995
  FunctionInfo functionInfo{
843
- f_args,
844
- offset,
845
- doc_str,
846
- functionReturn,
847
-
996
+ .args=f_args,
997
+ .offset=offset,
998
+ .docstring=doc_str,
999
+ .returns=functionReturn,
1000
+ .exceptions={}
848
1001
  };
849
1002
 
1003
+ for (auto &exception: function_exceptions) {
1004
+ functionInfo.exceptions.insert(exception);
1005
+ }
1006
+
850
1007
  get_docstring_arg_descr(functionInfo);
851
1008
  functionInfo.update_descriptions(formatStyle);
852
1009
 
@@ -854,21 +1011,21 @@ void parse_file(std::string &file_path, DocstringFormatStyle &formatStyle) {
854
1011
  }
855
1012
  }
856
1013
 
857
- std::sort(
858
- infos.begin(),
859
- infos.end(),
860
- [](FunctionInfo &left, FunctionInfo &right) {
1014
+ std::ranges::sort(infos,
1015
+ [](const FunctionInfo &left, const FunctionInfo &right) {
861
1016
  return left.get_file_write_position() > right.get_file_write_position();
862
1017
  }
863
1018
  );
864
1019
 
1020
+ #ifndef DRY_RUN
865
1021
  write_to_file_position(std::move(infos), file_path, formatStyle);
1022
+ #endif
866
1023
  }
867
1024
 
868
1025
  void write_to_file_position(
869
1026
  std::vector<FunctionInfo> &&infos,
870
1027
  const std::string &file_path,
871
- DocstringFormatStyle &formatStyle
1028
+ const DocstringFormatStyle &formatStyle
872
1029
  ) noexcept {
873
1030
  std::fstream file;
874
1031
 
@@ -921,9 +1078,7 @@ void write_to_file_position(
921
1078
 
922
1079
  file.open(file_path, std::ios::out);
923
1080
 
924
- std::for_each(
925
- lines.begin(),
926
- lines.end(),
1081
+ std::ranges::for_each(lines,
927
1082
  [&file](const auto &line) {
928
1083
  file << line;
929
1084
  if (line[line.size() - 1] != '\n') {
@@ -2,6 +2,7 @@
2
2
  #define DOCSTRING_GENERATOR_EXT_DOCSTRINGFORMAT_HPP
3
3
 
4
4
  #include <memory>
5
+ #include <set>
5
6
  #include <string>
6
7
  #include <vector>
7
8
 
@@ -54,14 +55,22 @@ struct FunctionDocstring {
54
55
  std::string docstring;
55
56
  };
56
57
 
58
+ struct FunctionException {
59
+ std::string name;
60
+ std::string description;
61
+
62
+ auto operator<=>(const FunctionException&) const = default;
63
+ };
64
+
57
65
  struct FunctionInfo {
58
66
  std::vector<FunctionParameter> args{};
59
67
  uint32_t offset{};
60
68
  FunctionDocstring docstring;
61
69
  FunctionReturn returns;
70
+ std::set<FunctionException> exceptions {};
62
71
 
63
72
  [[nodiscard]] int get_file_write_position() const noexcept;
64
- void update_descriptions(DocstringFormatStyle &formatStyle) noexcept;
73
+ void update_descriptions(const DocstringFormatStyle &formatStyle) noexcept;
65
74
  };
66
75
 
67
76
  struct DocstringFormat {
@@ -69,6 +78,7 @@ struct DocstringFormat {
69
78
 
70
79
  virtual std::string docstringArgs() noexcept = 0;
71
80
  virtual std::string docstringReturn() noexcept = 0;
81
+ virtual std::string docstringExceptions() noexcept = 0;
72
82
  virtual void check_current_docstring() noexcept = 0;
73
83
 
74
84
  virtual ~DocstringFormat() = default;
@@ -81,18 +91,21 @@ struct GoogleDocstring : DocstringFormat {
81
91
  void check_current_docstring() noexcept override;
82
92
  std::string docstringArgs() noexcept override;
83
93
  std::string docstringReturn() noexcept override;
94
+ std::string docstringExceptions() noexcept override;
84
95
  };
85
96
 
86
97
  struct reStructuredDocstring : DocstringFormat {
87
98
  void check_current_docstring() noexcept override;
88
99
  std::string docstringArgs() noexcept override;
89
100
  std::string docstringReturn() noexcept override;
101
+ std::string docstringExceptions() noexcept override;
90
102
  };
91
103
 
92
104
  struct NumpyDocstring : DocstringFormat {
93
105
  void check_current_docstring() noexcept override;
94
106
  std::string docstringArgs() noexcept override;
95
107
  std::string docstringReturn() noexcept override;
108
+ std::string docstringExceptions() noexcept override;
96
109
  };
97
110
 
98
111
  std::string read_file(const std::string &file_path);