wexample-pseudocode 9.1.2__tar.gz → 9.2.0__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.
Files changed (48) hide show
  1. {wexample_pseudocode-9.1.2 → wexample_pseudocode-9.2.0}/PKG-INFO +4 -4
  2. {wexample_pseudocode-9.1.2 → wexample_pseudocode-9.2.0}/README.md +2 -2
  3. {wexample_pseudocode-9.1.2 → wexample_pseudocode-9.2.0}/pyproject.toml +2 -2
  4. {wexample_pseudocode-9.1.2 → wexample_pseudocode-9.2.0}/src/wexample_pseudocode/common/docstring.py +6 -3
  5. {wexample_pseudocode-9.1.2 → wexample_pseudocode-9.2.0}/src/wexample_pseudocode/common/type_normalizer.py +3 -3
  6. {wexample_pseudocode-9.1.2 → wexample_pseudocode-9.2.0}/src/wexample_pseudocode/config/class_config.py +7 -6
  7. {wexample_pseudocode-9.1.2 → wexample_pseudocode-9.2.0}/src/wexample_pseudocode/config/class_method_config.py +10 -10
  8. {wexample_pseudocode-9.1.2 → wexample_pseudocode-9.2.0}/src/wexample_pseudocode/config/function_config.py +6 -9
  9. {wexample_pseudocode-9.1.2 → wexample_pseudocode-9.2.0}/src/wexample_pseudocode/generator/code_generator.py +1 -4
  10. {wexample_pseudocode-9.1.2 → wexample_pseudocode-9.2.0}/src/wexample_pseudocode/generator/pseudocode_generator.py +1 -4
  11. {wexample_pseudocode-9.1.2 → wexample_pseudocode-9.2.0}/src/wexample_pseudocode/parser/function_parser.py +2 -2
  12. {wexample_pseudocode-9.1.2 → wexample_pseudocode-9.2.0}/src/wexample_pseudocode/__init__.py +0 -0
  13. {wexample_pseudocode-9.1.2 → wexample_pseudocode-9.2.0}/src/wexample_pseudocode/common/__init__.py +0 -0
  14. {wexample_pseudocode-9.1.2 → wexample_pseudocode-9.2.0}/src/wexample_pseudocode/config/__init__.py +0 -0
  15. {wexample_pseudocode-9.1.2 → wexample_pseudocode-9.2.0}/src/wexample_pseudocode/config/class_property_config.py +0 -0
  16. {wexample_pseudocode-9.1.2 → wexample_pseudocode-9.2.0}/src/wexample_pseudocode/config/constant_config.py +0 -0
  17. {wexample_pseudocode-9.1.2 → wexample_pseudocode-9.2.0}/src/wexample_pseudocode/config/doc_comment_config.py +0 -0
  18. {wexample_pseudocode-9.1.2 → wexample_pseudocode-9.2.0}/src/wexample_pseudocode/config/doc_comment_parameter_config.py +0 -0
  19. {wexample_pseudocode-9.1.2 → wexample_pseudocode-9.2.0}/src/wexample_pseudocode/config/doc_comment_return_config.py +0 -0
  20. {wexample_pseudocode-9.1.2 → wexample_pseudocode-9.2.0}/src/wexample_pseudocode/config/function_parameter_config.py +0 -0
  21. {wexample_pseudocode-9.1.2 → wexample_pseudocode-9.2.0}/src/wexample_pseudocode/config/generator_config.py +0 -0
  22. {wexample_pseudocode-9.1.2 → wexample_pseudocode-9.2.0}/src/wexample_pseudocode/config/method_parameter_config.py +0 -0
  23. {wexample_pseudocode-9.1.2 → wexample_pseudocode-9.2.0}/src/wexample_pseudocode/generator/__init__.py +0 -0
  24. {wexample_pseudocode-9.1.2 → wexample_pseudocode-9.2.0}/src/wexample_pseudocode/generator/abstract_generator.py +0 -0
  25. {wexample_pseudocode-9.1.2 → wexample_pseudocode-9.2.0}/src/wexample_pseudocode/parser/__init__.py +0 -0
  26. {wexample_pseudocode-9.1.2 → wexample_pseudocode-9.2.0}/src/wexample_pseudocode/parser/class_parser.py +0 -0
  27. {wexample_pseudocode-9.1.2 → wexample_pseudocode-9.2.0}/src/wexample_pseudocode/parser/module_parser.py +0 -0
  28. {wexample_pseudocode-9.1.2 → wexample_pseudocode-9.2.0}/src/wexample_pseudocode/py.typed +0 -0
  29. {wexample_pseudocode-9.1.2 → wexample_pseudocode-9.2.0}/tests/conftest.py +0 -0
  30. {wexample_pseudocode-9.1.2 → wexample_pseudocode-9.2.0}/tests/resources/__init__.py +0 -0
  31. {wexample_pseudocode-9.1.2 → wexample_pseudocode-9.2.0}/tests/resources/item/__init__.py +0 -0
  32. {wexample_pseudocode-9.1.2 → wexample_pseudocode-9.2.0}/tests/resources/item/class/__init__.py +0 -0
  33. {wexample_pseudocode-9.1.2 → wexample_pseudocode-9.2.0}/tests/resources/item/class/basic_calculator.py.txt +0 -0
  34. {wexample_pseudocode-9.1.2 → wexample_pseudocode-9.2.0}/tests/resources/item/class/basic_calculator.yml +0 -0
  35. {wexample_pseudocode-9.1.2 → wexample_pseudocode-9.2.0}/tests/resources/item/constant/__init__.py +0 -0
  36. {wexample_pseudocode-9.1.2 → wexample_pseudocode-9.2.0}/tests/resources/item/constant/constant_using_const.py.txt +0 -0
  37. {wexample_pseudocode-9.1.2 → wexample_pseudocode-9.2.0}/tests/resources/item/constant/constant_using_const.yml +0 -0
  38. {wexample_pseudocode-9.1.2 → wexample_pseudocode-9.2.0}/tests/resources/item/function/__init__.py +0 -0
  39. {wexample_pseudocode-9.1.2 → wexample_pseudocode-9.2.0}/tests/resources/item/function/basic_function.py.txt +0 -0
  40. {wexample_pseudocode-9.1.2 → wexample_pseudocode-9.2.0}/tests/resources/item/function/basic_function.yml +0 -0
  41. {wexample_pseudocode-9.1.2 → wexample_pseudocode-9.2.0}/tests/resources/item/function/complex_function.py.txt +0 -0
  42. {wexample_pseudocode-9.1.2 → wexample_pseudocode-9.2.0}/tests/resources/item/function/complex_function.yml +0 -0
  43. {wexample_pseudocode-9.1.2 → wexample_pseudocode-9.2.0}/tests/test_class_basic_calculator.py +0 -0
  44. {wexample_pseudocode-9.1.2 → wexample_pseudocode-9.2.0}/tests/test_code_generator_class_basic_calculator.py +0 -0
  45. {wexample_pseudocode-9.1.2 → wexample_pseudocode-9.2.0}/tests/test_code_generator_constant.py +0 -0
  46. {wexample_pseudocode-9.1.2 → wexample_pseudocode-9.2.0}/tests/test_constant_using_const.py +0 -0
  47. {wexample_pseudocode-9.1.2 → wexample_pseudocode-9.2.0}/tests/test_function_items.py +0 -0
  48. {wexample_pseudocode-9.1.2 → wexample_pseudocode-9.2.0}/tests/test_php_yaml_compat.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: wexample-pseudocode
3
- Version: 9.1.2
3
+ Version: 9.2.0
4
4
  Summary: Code creation and maintenance tools
5
5
  Author-Email: weeger <contact@wexample.com>
6
6
  License: MIT
@@ -11,7 +11,7 @@ Project-URL: homepage, https://github.com/wexample/python-pseudocode
11
11
  Requires-Python: >=3.10
12
12
  Requires-Dist: attrs>=23.1.0
13
13
  Requires-Dist: cattrs>=23.1.0
14
- Requires-Dist: wexample-helpers>=16.0.0
14
+ Requires-Dist: wexample-helpers>=16.2.0
15
15
  Provides-Extra: dev
16
16
  Requires-Dist: pytest; extra == "dev"
17
17
  Requires-Dist: pytest-cov; extra == "dev"
@@ -19,7 +19,7 @@ Description-Content-Type: text/markdown
19
19
 
20
20
  # pseudocode
21
21
 
22
- Version: 9.1.2
22
+ Version: 9.2.0
23
23
 
24
24
  Code creation and maintenance tools
25
25
 
@@ -101,7 +101,7 @@ Visit the [Wexample Suite documentation](https://docs.wexample.com) for the comp
101
101
 
102
102
  - attrs: >=23.1.0
103
103
  - cattrs: >=23.1.0
104
- - wexample-helpers: >=16.0.0
104
+ - wexample-helpers: >=16.2.0
105
105
 
106
106
  ## Versioning & Compatibility Policy
107
107
 
@@ -1,6 +1,6 @@
1
1
  # pseudocode
2
2
 
3
- Version: 9.1.2
3
+ Version: 9.2.0
4
4
 
5
5
  Code creation and maintenance tools
6
6
 
@@ -82,7 +82,7 @@ Visit the [Wexample Suite documentation](https://docs.wexample.com) for the comp
82
82
 
83
83
  - attrs: >=23.1.0
84
84
  - cattrs: >=23.1.0
85
- - wexample-helpers: >=16.0.0
85
+ - wexample-helpers: >=16.2.0
86
86
 
87
87
  ## Versioning & Compatibility Policy
88
88
 
@@ -6,7 +6,7 @@ build-backend = "pdm.backend"
6
6
 
7
7
  [project]
8
8
  name = "wexample-pseudocode"
9
- version = "9.1.2"
9
+ version = "9.2.0"
10
10
  description = "Code creation and maintenance tools"
11
11
  authors = [
12
12
  { name = "weeger", email = "contact@wexample.com" },
@@ -20,7 +20,7 @@ classifiers = [
20
20
  dependencies = [
21
21
  "attrs>=23.1.0",
22
22
  "cattrs>=23.1.0",
23
- "wexample-helpers>=16.0.0",
23
+ "wexample-helpers>=16.2.0",
24
24
  ]
25
25
 
26
26
  [project.readme]
@@ -40,7 +40,10 @@ def parse_docstring(doc: str | None) -> dict[str, dict[str, str]]:
40
40
  except StopIteration:
41
41
  return
42
42
  i = idx + 1
43
- while i < len(lines):
43
+ n = len(lines)
44
+ is_params = header.startswith("args") or header.startswith("parameters")
45
+ is_returns = header.startswith("returns")
46
+ while i < n:
44
47
  s = lines[i].strip()
45
48
  if not s:
46
49
  i += 1
@@ -52,10 +55,10 @@ def parse_docstring(doc: str | None) -> dict[str, dict[str, str]]:
52
55
  name, desc = s.split(":", 1)
53
56
  name = name.strip()
54
57
  desc = desc.strip()
55
- if header.startswith("args") or header.startswith("parameters"):
58
+ if is_params:
56
59
  if name:
57
60
  result["params"][name] = desc
58
- elif header.startswith("returns"):
61
+ elif is_returns:
59
62
  if desc and "description" not in result["return"]:
60
63
  result["return"]["description"] = (
61
64
  f"{name}: {desc}" if name else desc
@@ -20,7 +20,7 @@ def normalize_type(type_str: str | None) -> str | None:
20
20
  if t in {"list", "List", "Sequence", "MutableSequence", "dict", "Dict", "Mapping"}:
21
21
  return "array"
22
22
 
23
- if t in {"Callable"}:
23
+ if t == "Callable":
24
24
  return "callable"
25
25
 
26
26
  # Primitives stay as-is
@@ -38,8 +38,8 @@ def to_python_type(type_str: str | None) -> str | None:
38
38
  return "list"
39
39
  if t == "callable":
40
40
  return "typing.Callable"
41
- if t in {"mixed"}:
41
+ if t == "mixed":
42
42
  return "typing.Any"
43
- if t in {"void"}:
43
+ if t == "void":
44
44
  return None
45
45
  return t
@@ -56,15 +56,16 @@ class ClassConfig:
56
56
 
57
57
  def to_code(self) -> str:
58
58
  lines: list[str] = [f"class {self.name}:"]
59
+ _append = lines.append
59
60
  if self.description:
60
- lines.append(f' """{self.description}"""')
61
- lines.append("")
61
+ _append(f' """{self.description}"""')
62
+ _append("")
62
63
  for p in self.properties:
63
- lines.append(" " + p.to_code())
64
+ _append(" " + p.to_code())
64
65
  if self.properties and self.methods:
65
- lines.append("")
66
+ _append("")
66
67
  for m in self.methods:
67
- lines.append(m.to_code(indent=" "))
68
+ _append(m.to_code(indent=" "))
68
69
  if not self.properties and not self.methods and not self.description:
69
- lines.append(" pass")
70
+ _append(" pass")
70
71
  return "\n".join(lines)
@@ -22,21 +22,21 @@ class ClassMethodConfig:
22
22
  MethodParameterConfig,
23
23
  )
24
24
 
25
- params = []
26
- for p in data.get("parameters") or []:
27
- params.append(
28
- MethodParameterConfig(
29
- name=p.get("name"),
30
- type=p.get("type"),
31
- description=p.get("description"),
32
- )
25
+ params = [
26
+ MethodParameterConfig(
27
+ name=p.get("name"),
28
+ type=p.get("type"),
29
+ description=p.get("description"),
33
30
  )
31
+ for p in data.get("parameters") or []
32
+ ]
33
+ return_data = data.get("return") or {}
34
34
  return cls(
35
35
  name=data.get("name"),
36
36
  description=data.get("description"),
37
37
  parameters=params,
38
- return_type=(data.get("return") or {}).get("type"),
39
- return_description=(data.get("return") or {}).get("description"),
38
+ return_type=return_data.get("type"),
39
+ return_description=return_data.get("description"),
40
40
  )
41
41
 
42
42
  def to_code(self, indent: str = " ") -> str:
@@ -42,16 +42,13 @@ class FunctionConfig:
42
42
  FunctionParameterConfig.from_config(p)
43
43
  for p in (data.get("parameters") or [])
44
44
  ]
45
+ ret_val = data.get("return")
45
46
  ret_type = None
46
- if "return" in data:
47
- ret_type = (
48
- (data["return"] or {}).get("type")
49
- if isinstance(data["return"], dict)
50
- else data["return"]
51
- )
47
+ if ret_val is not None:
48
+ ret_type = ret_val.get("type") if isinstance(ret_val, dict) else ret_val
52
49
  ret_desc = None
53
- if isinstance(data.get("return"), dict):
54
- ret_desc = data["return"].get("description")
50
+ if isinstance(ret_val, dict):
51
+ ret_desc = ret_val.get("description")
55
52
  return cls(
56
53
  name=data.get("name"),
57
54
  description=data.get("description"),
@@ -89,7 +86,7 @@ class FunctionConfig:
89
86
  inner_block: list[str] = [first]
90
87
  if rest:
91
88
  inner_block.append("")
92
- inner_block.extend([" " + line for line in rest])
89
+ inner_block.extend(" " + line for line in rest)
93
90
  doc = '"""' + "\n".join(inner_block) + "\n " + '"""'
94
91
  body_lines.append(doc)
95
92
  body_lines.append("pass")
@@ -33,10 +33,7 @@ class CodeGenerator(AbstractGenerator):
33
33
 
34
34
  def generate(self, input_text: str) -> str:
35
35
  configs = self._generate_config(input_text)
36
- output = ""
37
- for cfg in configs:
38
- output += cfg.to_code() + "\n"
39
- return output
36
+ return "".join(cfg.to_code() + "\n" for cfg in configs)
40
37
 
41
38
  # Implement abstract method (not used directly in CodeGenerator flow)
42
39
  def generate_config_data(self, source_code: str) -> dict[str, Any]:
@@ -116,10 +116,7 @@ class PseudocodeGenerator(AbstractGenerator):
116
116
  if getattr(p, "has_default", False):
117
117
  default_val = _literal_eval_safe(p.default)
118
118
  # explicit None default (null)
119
- if (
120
- isinstance(getattr(p, "default", None), type(None))
121
- or default_val is None
122
- ):
119
+ if getattr(p, "default", None) is None or default_val is None:
123
120
  pd["optional"] = True
124
121
  pd["default"] = None
125
122
  else:
@@ -36,13 +36,13 @@ def parse_module_functions(source_code: str) -> Iterable[FunctionItem]:
36
36
  return_type=_annotation_to_str(node.returns),
37
37
  return_description=parsed.get("return", {}).get("description"),
38
38
  )
39
- total_args = [a for a in node.args.args]
39
+ total_args = node.args.args
40
40
  num_defaults = len(node.args.defaults)
41
41
  split_index = len(total_args) - num_defaults
42
42
  for i, arg in enumerate(total_args):
43
43
  if arg.arg == "self":
44
44
  continue
45
- has_default = i >= split_index and num_defaults > 0
45
+ has_default = i >= split_index
46
46
  default = None
47
47
  if has_default:
48
48
  default = node.args.defaults[i - split_index]