complexipy 4.0.2__tar.gz → 4.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 (42) hide show
  1. {complexipy-4.0.2 → complexipy-4.2.0}/Cargo.lock +1 -1
  2. {complexipy-4.0.2 → complexipy-4.2.0}/Cargo.toml +1 -1
  3. {complexipy-4.0.2 → complexipy-4.2.0}/PKG-INFO +33 -4
  4. {complexipy-4.0.2 → complexipy-4.2.0}/README.md +32 -3
  5. {complexipy-4.0.2 → complexipy-4.2.0}/complexipy/__init__.py +2 -0
  6. {complexipy-4.0.2 → complexipy-4.2.0}/complexipy/main.py +31 -1
  7. {complexipy-4.0.2 → complexipy-4.2.0}/complexipy/utils.py +33 -7
  8. {complexipy-4.0.2 → complexipy-4.2.0}/complexipy.toml +2 -1
  9. {complexipy-4.0.2 → complexipy-4.2.0}/docs/index.md +28 -2
  10. {complexipy-4.0.2 → complexipy-4.2.0}/src/cognitive_complexity/mod.rs +118 -37
  11. {complexipy-4.0.2 → complexipy-4.2.0}/src/cognitive_complexity/utils.rs +25 -0
  12. {complexipy-4.0.2 → complexipy-4.2.0}/uv.lock +192 -146
  13. {complexipy-4.0.2 → complexipy-4.2.0}/vscode/complexipy/CHANGELOG.md +11 -1
  14. {complexipy-4.0.2 → complexipy-4.2.0}/vscode/complexipy/README.md +9 -0
  15. {complexipy-4.0.2 → complexipy-4.2.0}/vscode/complexipy/package.json +2 -2
  16. {complexipy-4.0.2 → complexipy-4.2.0}/.pre-commit-config.yaml +0 -0
  17. {complexipy-4.0.2 → complexipy-4.2.0}/LICENSE +0 -0
  18. {complexipy-4.0.2 → complexipy-4.2.0}/build-wasm.sh +0 -0
  19. {complexipy-4.0.2 → complexipy-4.2.0}/complexipy/_complexipy.pyi +0 -0
  20. {complexipy-4.0.2 → complexipy-4.2.0}/complexipy/api.py +0 -0
  21. {complexipy-4.0.2 → complexipy-4.2.0}/complexipy/error_handlers.py +0 -0
  22. {complexipy-4.0.2 → complexipy-4.2.0}/complexipy/py.typed +0 -0
  23. {complexipy-4.0.2 → complexipy-4.2.0}/complexipy/types.py +0 -0
  24. {complexipy-4.0.2 → complexipy-4.2.0}/docs/img/complexipy_icon.svg +0 -0
  25. {complexipy-4.0.2 → complexipy-4.2.0}/mkdocs.yml +0 -0
  26. {complexipy-4.0.2 → complexipy-4.2.0}/pyproject.toml +0 -0
  27. {complexipy-4.0.2 → complexipy-4.2.0}/serve-web-version.sh +0 -0
  28. {complexipy-4.0.2 → complexipy-4.2.0}/src/classes/mod.rs +0 -0
  29. {complexipy-4.0.2 → complexipy-4.2.0}/src/lib.rs +0 -0
  30. {complexipy-4.0.2 → complexipy-4.2.0}/src/wasm.rs +0 -0
  31. {complexipy-4.0.2 → complexipy-4.2.0}/vscode/complexipy/.vscode-test.mjs +0 -0
  32. {complexipy-4.0.2 → complexipy-4.2.0}/vscode/complexipy/.vscodeignore +0 -0
  33. {complexipy-4.0.2 → complexipy-4.2.0}/vscode/complexipy/LICENSE +0 -0
  34. {complexipy-4.0.2 → complexipy-4.2.0}/vscode/complexipy/eslint.config.mjs +0 -0
  35. {complexipy-4.0.2 → complexipy-4.2.0}/vscode/complexipy/extension.js +0 -0
  36. {complexipy-4.0.2 → complexipy-4.2.0}/vscode/complexipy/img/complexipy.png +0 -0
  37. {complexipy-4.0.2 → complexipy-4.2.0}/vscode/complexipy/img/complexipy_icon.png +0 -0
  38. {complexipy-4.0.2 → complexipy-4.2.0}/vscode/complexipy/img/complexipy_icon.svg +0 -0
  39. {complexipy-4.0.2 → complexipy-4.2.0}/vscode/complexipy/jsconfig.json +0 -0
  40. {complexipy-4.0.2 → complexipy-4.2.0}/vscode/complexipy/package-lock.json +0 -0
  41. {complexipy-4.0.2 → complexipy-4.2.0}/vscode/complexipy/test/extension.test.js +0 -0
  42. {complexipy-4.0.2 → complexipy-4.2.0}/vscode/complexipy/test/statusbar.test.js +0 -0
@@ -107,7 +107,7 @@ dependencies = [
107
107
 
108
108
  [[package]]
109
109
  name = "complexipy"
110
- version = "4.0.2"
110
+ version = "4.2.0"
111
111
  dependencies = [
112
112
  "console_error_panic_hook",
113
113
  "csv",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "complexipy"
3
- version = "4.0.2"
3
+ version = "4.2.0"
4
4
  edition = "2024"
5
5
  authors = ["Robin Quintero <rohaquinlop301@gmail.com>"]
6
6
  license = "MIT"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: complexipy
3
- Version: 4.0.2
3
+ Version: 4.2.0
4
4
  Classifier: Development Status :: 5 - Production/Stable
5
5
  Classifier: Environment :: Console
6
6
  Classifier: Intended Audience :: Developers
@@ -33,7 +33,7 @@ Project-URL: Repository, https://github.com/rohaquinlop/complexipy
33
33
  # complexipy
34
34
 
35
35
  <div align="center">
36
- <img src="docs/img/complexipy_icon.svg" alt="complexipy" width="120" height="120">
36
+ <img src="https://raw.githubusercontent.com/rohaquinlop/complexipy/refs/heads/main/docs/img/complexipy_icon.svg" alt="complexipy" width="120" height="120">
37
37
 
38
38
  <p><em>Blazingly fast cognitive complexity analysis for Python, written in Rust.</em></p>
39
39
 
@@ -86,6 +86,9 @@ complexipy . --max-complexity-allowed 10
86
86
 
87
87
  # Save results to JSON/CSV
88
88
  complexipy . --output-json --output-csv
89
+
90
+ # Analyze current directory while excluding specific files
91
+ complexipy . --exclude path/to/exclude.py --exclude path/to/other/exclude.py
89
92
  ```
90
93
 
91
94
  ### Python API
@@ -168,6 +171,7 @@ quiet = false
168
171
  ignore-complexity = false
169
172
  details = "normal"
170
173
  sort = "asc"
174
+ exclude = []
171
175
 
172
176
  [output]
173
177
  csv = true
@@ -183,6 +187,7 @@ quiet = false
183
187
  ignore-complexity = false
184
188
  details = "normal"
185
189
  sort = "asc"
190
+ exclude = []
186
191
 
187
192
  [tool.complexipy.output]
188
193
  csv = true
@@ -193,6 +198,7 @@ json = true
193
198
 
194
199
  | Flag | Description | Default |
195
200
  |------|-------------|---------|
201
+ | `--exclude` | Exclude entries relative to each provided path. Entries resolve to existing directories (prefix match) or files (exact match). Non-existent entries are ignored. | |
196
202
  | `--max-complexity-allowed` | Complexity threshold | `15` |
197
203
  | `--output-json` | Save results as JSON | `false` |
198
204
  | `--output-csv` | Save results as CSV | `false` |
@@ -200,6 +206,29 @@ json = true
200
206
  | `--sort <asc\|desc\|name>` | Sort results | `asc` |
201
207
  | `--quiet` | Suppress output | `false` |
202
208
  | `--ignore-complexity` | Don't exit with error on threshold breach | `false` |
209
+ | `--version` | Show installed complexipy version and exit | - |
210
+
211
+ Example:
212
+
213
+ ```
214
+ # Exclude only top-level 'tests' directory under the provided root
215
+ complexipy . --exclude tests
216
+ # This will not exclude './complexipy/utils.py' if you pass '--exclude utils' at repo root,
217
+ # because there is no './utils' directory or file at that level.
218
+ ```
219
+
220
+ ### Inline Ignores
221
+
222
+ You can explicitly ignore a known complex function inline, similar to Ruff's `C901` ignores:
223
+
224
+ ```python
225
+ def legacy_adapter(x, y): # noqa: complexipy (safe wrapper)
226
+ if x and y:
227
+ return x + y
228
+ return 0
229
+ ```
230
+
231
+ Place `# noqa: complexipy` on the function definition line (or the line immediately above). An optional reason can be provided in parentheses or plain text, it’s ignored by the parser.
203
232
 
204
233
  ## API Reference
205
234
 
@@ -225,11 +254,11 @@ FunctionComplexity:
225
254
 
226
255
  <div align="center">
227
256
 
257
+ <sub>Inspired by the <a href="https://www.sonarsource.com/resources/cognitive-complexity/">Cognitive Complexity</a> research by SonarSource, G. Ann Campbell</sub>
258
+
228
259
  **[Documentation](https://rohaquinlop.github.io/complexipy/) • [PyPI](https://pypi.org/project/complexipy/) • [GitHub](https://github.com/rohaquinlop/complexipy)**
229
260
 
230
261
  <sub>Built with ❤️ by <a href="https://github.com/rohaquinlop">@rohaquinlop</a> and <a href="https://github.com/rohaquinlop/complexipy/graphs/contributors">contributors</a></sub>
231
262
 
232
- <sub>Inspired by the <a href="https://www.sonarsource.com/resources/cognitive-complexity/">Cognitive Complexity</a> research by SonarSource</sub>
233
-
234
263
  </div>
235
264
 
@@ -1,7 +1,7 @@
1
1
  # complexipy
2
2
 
3
3
  <div align="center">
4
- <img src="docs/img/complexipy_icon.svg" alt="complexipy" width="120" height="120">
4
+ <img src="https://raw.githubusercontent.com/rohaquinlop/complexipy/refs/heads/main/docs/img/complexipy_icon.svg" alt="complexipy" width="120" height="120">
5
5
 
6
6
  <p><em>Blazingly fast cognitive complexity analysis for Python, written in Rust.</em></p>
7
7
 
@@ -54,6 +54,9 @@ complexipy . --max-complexity-allowed 10
54
54
 
55
55
  # Save results to JSON/CSV
56
56
  complexipy . --output-json --output-csv
57
+
58
+ # Analyze current directory while excluding specific files
59
+ complexipy . --exclude path/to/exclude.py --exclude path/to/other/exclude.py
57
60
  ```
58
61
 
59
62
  ### Python API
@@ -136,6 +139,7 @@ quiet = false
136
139
  ignore-complexity = false
137
140
  details = "normal"
138
141
  sort = "asc"
142
+ exclude = []
139
143
 
140
144
  [output]
141
145
  csv = true
@@ -151,6 +155,7 @@ quiet = false
151
155
  ignore-complexity = false
152
156
  details = "normal"
153
157
  sort = "asc"
158
+ exclude = []
154
159
 
155
160
  [tool.complexipy.output]
156
161
  csv = true
@@ -161,6 +166,7 @@ json = true
161
166
 
162
167
  | Flag | Description | Default |
163
168
  |------|-------------|---------|
169
+ | `--exclude` | Exclude entries relative to each provided path. Entries resolve to existing directories (prefix match) or files (exact match). Non-existent entries are ignored. | |
164
170
  | `--max-complexity-allowed` | Complexity threshold | `15` |
165
171
  | `--output-json` | Save results as JSON | `false` |
166
172
  | `--output-csv` | Save results as CSV | `false` |
@@ -168,6 +174,29 @@ json = true
168
174
  | `--sort <asc\|desc\|name>` | Sort results | `asc` |
169
175
  | `--quiet` | Suppress output | `false` |
170
176
  | `--ignore-complexity` | Don't exit with error on threshold breach | `false` |
177
+ | `--version` | Show installed complexipy version and exit | - |
178
+
179
+ Example:
180
+
181
+ ```
182
+ # Exclude only top-level 'tests' directory under the provided root
183
+ complexipy . --exclude tests
184
+ # This will not exclude './complexipy/utils.py' if you pass '--exclude utils' at repo root,
185
+ # because there is no './utils' directory or file at that level.
186
+ ```
187
+
188
+ ### Inline Ignores
189
+
190
+ You can explicitly ignore a known complex function inline, similar to Ruff's `C901` ignores:
191
+
192
+ ```python
193
+ def legacy_adapter(x, y): # noqa: complexipy (safe wrapper)
194
+ if x and y:
195
+ return x + y
196
+ return 0
197
+ ```
198
+
199
+ Place `# noqa: complexipy` on the function definition line (or the line immediately above). An optional reason can be provided in parentheses or plain text, it’s ignored by the parser.
171
200
 
172
201
  ## API Reference
173
202
 
@@ -193,10 +222,10 @@ FunctionComplexity:
193
222
 
194
223
  <div align="center">
195
224
 
225
+ <sub>Inspired by the <a href="https://www.sonarsource.com/resources/cognitive-complexity/">Cognitive Complexity</a> research by SonarSource, G. Ann Campbell</sub>
226
+
196
227
  **[Documentation](https://rohaquinlop.github.io/complexipy/) • [PyPI](https://pypi.org/project/complexipy/) • [GitHub](https://github.com/rohaquinlop/complexipy)**
197
228
 
198
229
  <sub>Built with ❤️ by <a href="https://github.com/rohaquinlop">@rohaquinlop</a> and <a href="https://github.com/rohaquinlop/complexipy/graphs/contributors">contributors</a></sub>
199
230
 
200
- <sub>Inspired by the <a href="https://www.sonarsource.com/resources/cognitive-complexity/">Cognitive Complexity</a> research by SonarSource</sub>
201
-
202
231
  </div>
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  from complexipy._complexipy import (
2
4
  CodeComplexity,
3
5
  FileComplexity,
@@ -25,6 +25,10 @@ from typing import (
25
25
  )
26
26
  import time
27
27
  import typer
28
+ from importlib.metadata import (
29
+ PackageNotFoundError,
30
+ version as pkg_version,
31
+ )
28
32
 
29
33
  app = typer.Typer(name="complexipy")
30
34
  console = Console()
@@ -32,12 +36,27 @@ INVOCATION_PATH = os.getcwd()
32
36
  TOML_CONFIG = get_complexipy_toml_config(INVOCATION_PATH)
33
37
 
34
38
 
39
+ def _version_callback(value: bool):
40
+ if value:
41
+ try:
42
+ console.print(pkg_version("complexipy"))
43
+ except PackageNotFoundError:
44
+ console.print("Unknown version")
45
+ raise typer.Exit()
46
+
47
+
35
48
  @app.command()
36
49
  def main(
37
50
  paths: Optional[List[str]] = typer.Argument(
38
51
  None,
39
52
  help="Paths to the directories or files to analyze, it can be a local paths or a git repository URL.",
40
53
  ),
54
+ exclude: Optional[List[str]] = typer.Option(
55
+ None,
56
+ "--exclude",
57
+ "-e",
58
+ help="Paths to the directories or files to exclude.",
59
+ ),
41
60
  max_complexity_allowed: Optional[int] = typer.Option(
42
61
  None,
43
62
  "--max-complexity-allowed",
@@ -80,6 +99,13 @@ def main(
80
99
  "-j",
81
100
  help="Output the results to a JSON file.",
82
101
  ),
102
+ version: bool = typer.Option( # type: ignore[assignment]
103
+ False,
104
+ "--version",
105
+ help="Show the complexipy version and exit.",
106
+ callback=_version_callback,
107
+ is_eager=True,
108
+ ),
83
109
  ):
84
110
  (
85
111
  paths,
@@ -90,6 +116,7 @@ def main(
90
116
  sort,
91
117
  output_csv,
92
118
  output_json,
119
+ exclude,
93
120
  ) = get_arguments_value(
94
121
  TOML_CONFIG,
95
122
  paths,
@@ -100,6 +127,7 @@ def main(
100
127
  sort,
101
128
  output_csv,
102
129
  output_json,
130
+ exclude,
103
131
  )
104
132
 
105
133
  if not quiet:
@@ -108,7 +136,9 @@ def main(
108
136
  else:
109
137
  console.rule(":octopus: complexipy")
110
138
  start_time = time.time()
111
- result: Tuple[List[FileComplexity], List[str]] = _complexipy.main(paths, quiet)
139
+ result: Tuple[List[FileComplexity], List[str]] = _complexipy.main(
140
+ paths, quiet, exclude
141
+ )
112
142
  files_complexities, failed_paths = result
113
143
  execution_time = time.time() - start_time
114
144
  output_csv_path = f"{INVOCATION_PATH}/complexipy.csv"
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  import os
2
4
  import sys
3
5
  from complexipy.types import DetailTypes, Sort, TOMLType
@@ -35,11 +37,32 @@ def get_brain_icon():
35
37
  return ":brain:"
36
38
 
37
39
 
38
- def load_values_from_toml_key(value: str) -> TOMLType:
39
- if value == "details":
40
- DetailTypes[value]
41
- if value == "sort":
42
- Sort[value]
40
+ def load_values_from_toml_key(key: str, value: TOMLType) -> TOMLType:
41
+ """Normalize TOML values to expected runtime types.
42
+
43
+ - Convert `details` and `sort` string values to their Enum variants.
44
+ - Ensure `paths` and `exclude` are lists when provided as strings.
45
+ """
46
+ if key == "details":
47
+ # Accept either Enum or string in TOML
48
+ if isinstance(value, DetailTypes):
49
+ return value
50
+ if isinstance(value, str):
51
+ return DetailTypes(value)
52
+ return value
53
+
54
+ if key == "sort":
55
+ if isinstance(value, Sort):
56
+ return value
57
+ if isinstance(value, str):
58
+ return Sort(value)
59
+ return value
60
+
61
+ if key in ("paths", "exclude"):
62
+ # Allow a single string, normalize to list for downstream processing
63
+ if isinstance(value, str):
64
+ return [value]
65
+ return value
43
66
 
44
67
  return value
45
68
 
@@ -69,7 +92,7 @@ def load_toml_config(invocation_path: str, config_file_name: str) -> TOMLType |
69
92
  return None
70
93
 
71
94
  for key, value in data.items():
72
- data[key] = load_values_from_toml_key(value)
95
+ data[key] = load_values_from_toml_key(key, value)
73
96
 
74
97
  return data
75
98
 
@@ -125,7 +148,8 @@ def get_arguments_value(
125
148
  sort_arg: Sort | None,
126
149
  output_csv: bool | None,
127
150
  output_json: bool | None,
128
- ) -> Tuple[List[str], int, bool, bool, DetailTypes, Sort, bool, bool]:
151
+ exclude: List[str] | None,
152
+ ) -> Tuple[List[str], int, bool, bool, DetailTypes, Sort, bool, bool, List[str]]:
129
153
  paths = get_argument_value(toml_config, "paths", paths)
130
154
  max_complexity_allowed = get_argument_value(
131
155
  toml_config, "max-complexity-allowed", max_complexity_allowed, 15
@@ -138,6 +162,7 @@ def get_arguments_value(
138
162
  sort_arg = get_argument_value(toml_config, "sort", sort_arg, Sort.asc)
139
163
  output_csv = get_argument_value(toml_config, "output-csv", output_csv, False)
140
164
  output_json = get_argument_value(toml_config, "output-json", output_json, False)
165
+ exclude = get_argument_value(toml_config, "exclude", exclude, [])
141
166
 
142
167
  return (
143
168
  paths,
@@ -148,6 +173,7 @@ def get_arguments_value(
148
173
  sort_arg,
149
174
  output_csv,
150
175
  output_json,
176
+ exclude,
151
177
  )
152
178
 
153
179
 
@@ -1,9 +1,10 @@
1
- paths = ["src", "complexipy"]
1
+ paths = ["."]
2
2
  max-complexity-allowed = 15
3
3
  quiet = false
4
4
  ignore-complexity = false
5
5
  details = "normal"
6
6
  sort = "asc"
7
+ exclude = ["tests"]
7
8
 
8
9
  [output]
9
10
  csv = false
@@ -67,6 +67,10 @@ complexipy . --max-complexity-allowed 10
67
67
 
68
68
  # Generate reports
69
69
  complexipy . --output-json --output-csv
70
+
71
+ # Analyze current directory while excluding specific files
72
+ complexipy . --exclude file_to_exclude.py --exclude path/to/other/exclude.py
73
+
70
74
  ```
71
75
 
72
76
  ### Python API
@@ -131,6 +135,7 @@ quiet = false
131
135
  ignore-complexity = false
132
136
  details = "normal"
133
137
  sort = "asc"
138
+ exclude = []
134
139
 
135
140
  [output]
136
141
  csv = true
@@ -148,6 +153,7 @@ quiet = false
148
153
  ignore-complexity = false
149
154
  details = "normal"
150
155
  sort = "asc"
156
+ exclude = []
151
157
 
152
158
  [tool.complexipy.output]
153
159
  csv = true
@@ -161,6 +167,7 @@ json = true
161
167
 
162
168
  | Option | Description | Default |
163
169
  |--------|-------------|---------|
170
+ | `--exclude` | Exclude entries relative to each provided path. Entries resolve to existing directories (prefix match) or files (exact match). Non-existent entries are ignored. | |
164
171
  | `--max-complexity-allowed <N>` | Complexity threshold for warnings | `15` |
165
172
  | `--output-json` | Export results to JSON | `false` |
166
173
  | `--output-csv` | Export results to CSV | `false` |
@@ -168,6 +175,7 @@ json = true
168
175
  | `--sort <asc\|desc\|name>` | Sort results by complexity or name | `asc` |
169
176
  | `--quiet` | Suppress terminal output | `false` |
170
177
  | `--ignore-complexity` | Don't exit with error on threshold breach | `false` |
178
+ | `--version` | Show installed complexipy version and exit | - |
171
179
 
172
180
  ### Examples
173
181
 
@@ -180,11 +188,29 @@ complexipy . --max-complexity-allowed 8 --output-json
180
188
 
181
189
  # Silent analysis sorted by name
182
190
  complexipy src/ --sort name --quiet
191
+
192
+ # Exclude specific paths relative to root
193
+ complexipy . --exclude tests --exclude utils
194
+ # Note: this excludes only './tests/**' and './utils/**' under '.',
195
+ # it does not exclude './complexipy/utils.py'.
183
196
  ```
184
197
 
185
198
  !!! tip "Exit Codes"
186
199
  complexipy returns exit code `1` when functions exceed the complexity threshold. Use `--ignore-complexity` to suppress this behavior in CI/CD pipelines.
187
200
 
201
+ ### Inline Ignores
202
+
203
+ You can explicitly ignore a known complex function inline, similar to Ruff's `C901` ignores:
204
+
205
+ ```python
206
+ def legacy_adapter(x, y): # noqa: complexipy (safe wrapper)
207
+ if x and y:
208
+ return x + y
209
+ return 0
210
+ ```
211
+
212
+ Place `# noqa: complexipy` on the function definition line (or the line immediately above). An optional reason can be provided in parentheses or plain text, it’s ignored by the parser.
213
+
188
214
  ## API Reference
189
215
 
190
216
  ### Functions
@@ -365,7 +391,7 @@ def process_orders(orders): # Base: 0
365
391
  ```bash
366
392
  $ complexipy example.py
367
393
 
368
- ───────────────────────────── 🐙 complexipy 4.0.0 ──────────────────────────────
394
+ ───────────────────────────── 🐙 complexipy ──────────────────────────────
369
395
  Summary
370
396
  ┏━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┓
371
397
  ┃ Path ┃ File ┃ Function ┃ Complexity ┃
@@ -384,7 +410,7 @@ $ complexipy example.py
384
410
 
385
411
  ## Links & Resources
386
412
 
387
- - **📚 [Research Paper](https://www.sonarsource.com/resources/cognitive-complexity/)** - Original cognitive complexity research by SonarSource
413
+ - **📚 [Research Paper](https://www.sonarsource.com/resources/cognitive-complexity/)** - Original cognitive complexity research by SonarSource, G. Ann Campbell
388
414
  - **🐙 [GitHub Repository](https://github.com/rohaquinlop/complexipy)** - Source code and issue tracking
389
415
  - **📦 [PyPI Package](https://pypi.org/project/complexipy/)** - Installation and version history
390
416
  - **🛠️ [GitHub Action](https://github.com/marketplace/actions/complexipy)** - CI/CD integration